| 1 | //! Window startup notification to handle window raising. |
| 2 | //! |
| 3 | //! The [`ActivationToken`] is essential to ensure that your newly |
| 4 | //! created window will obtain the focus, otherwise the user could |
| 5 | //! be requered to click on the window. |
| 6 | //! |
| 7 | //! Such token is usually delivered via the environment variable and |
| 8 | //! could be read from it with the [`EventLoopExtStartupNotify::read_token_from_env`]. |
| 9 | //! |
| 10 | //! Such token must also be reset after reading it from your environment with |
| 11 | //! [`reset_activation_token_env`] otherwise child processes could inherit it. |
| 12 | //! |
| 13 | //! When starting a new child process with a newly obtained [`ActivationToken`] from |
| 14 | //! [`WindowExtStartupNotify::request_activation_token`] the [`set_activation_token_env`] |
| 15 | //! must be used to propagate it to the child |
| 16 | //! |
| 17 | //! To ensure the delivery of such token by other processes to you, the user should |
| 18 | //! set `StartupNotify=true` inside the `.desktop` file of their application. |
| 19 | //! |
| 20 | //! The specification could be found [`here`]. |
| 21 | //! |
| 22 | //! [`here`]: https://specifications.freedesktop.org/startup-notification-spec/startup-notification-latest.txt |
| 23 | |
| 24 | use std::env; |
| 25 | |
| 26 | use crate::error::NotSupportedError; |
| 27 | use crate::event_loop::{ActiveEventLoop, AsyncRequestSerial}; |
| 28 | use crate::window::{ActivationToken, Window, WindowAttributes}; |
| 29 | |
| 30 | /// The variable which is used mostly on X11. |
| 31 | const X11_VAR: &str = "DESKTOP_STARTUP_ID" ; |
| 32 | |
| 33 | /// The variable which is used mostly on Wayland. |
| 34 | const WAYLAND_VAR: &str = "XDG_ACTIVATION_TOKEN" ; |
| 35 | |
| 36 | pub trait EventLoopExtStartupNotify { |
| 37 | /// Read the token from the environment. |
| 38 | /// |
| 39 | /// It's recommended **to unset** this environment variable for child processes. |
| 40 | fn read_token_from_env(&self) -> Option<ActivationToken>; |
| 41 | } |
| 42 | |
| 43 | pub trait WindowExtStartupNotify { |
| 44 | /// Request a new activation token. |
| 45 | /// |
| 46 | /// The token will be delivered inside |
| 47 | fn request_activation_token(&self) -> Result<AsyncRequestSerial, NotSupportedError>; |
| 48 | } |
| 49 | |
| 50 | pub trait WindowAttributesExtStartupNotify { |
| 51 | /// Use this [`ActivationToken`] during window creation. |
| 52 | /// |
| 53 | /// Not using such a token upon a window could make your window not gaining |
| 54 | /// focus until the user clicks on the window. |
| 55 | fn with_activation_token(self, token: ActivationToken) -> Self; |
| 56 | } |
| 57 | |
| 58 | impl EventLoopExtStartupNotify for ActiveEventLoop { |
| 59 | fn read_token_from_env(&self) -> Option<ActivationToken> { |
| 60 | matchOption self.p { |
| 61 | #[cfg (wayland_platform)] |
| 62 | crate::platform_impl::ActiveEventLoop::Wayland(_) => env::var(WAYLAND_VAR), |
| 63 | #[cfg (x11_platform)] |
| 64 | crate::platform_impl::ActiveEventLoop::X(_) => env::var(X11_VAR), |
| 65 | } |
| 66 | .ok() |
| 67 | .map(ActivationToken::from_raw) |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | impl WindowExtStartupNotify for Window { |
| 72 | fn request_activation_token(&self) -> Result<AsyncRequestSerial, NotSupportedError> { |
| 73 | self.window.request_activation_token() |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | impl WindowAttributesExtStartupNotify for WindowAttributes { |
| 78 | fn with_activation_token(mut self, token: ActivationToken) -> Self { |
| 79 | self.platform_specific.activation_token = Some(token); |
| 80 | self |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | /// Remove the activation environment variables from the current process. |
| 85 | /// |
| 86 | /// This is wise to do before running child processes, |
| 87 | /// which may not to support the activation token. |
| 88 | pub fn reset_activation_token_env() { |
| 89 | env::remove_var(X11_VAR); |
| 90 | env::remove_var(WAYLAND_VAR); |
| 91 | } |
| 92 | |
| 93 | /// Set environment variables responsible for activation token. |
| 94 | /// |
| 95 | /// This could be used before running daemon processes. |
| 96 | pub fn set_activation_token_env(token: ActivationToken) { |
| 97 | env::set_var(X11_VAR, &token.token); |
| 98 | env::set_var(WAYLAND_VAR, value:token.token); |
| 99 | } |
| 100 | |