winit/platform/
startup_notify.rs

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
24use std::env;
25
26use crate::error::{NotSupportedError, RequestError};
27use crate::event_loop::{ActiveEventLoop, AsyncRequestSerial};
28#[cfg(wayland_platform)]
29use crate::platform::wayland::ActiveEventLoopExtWayland;
30use crate::window::{ActivationToken, Window, WindowAttributes};
31
32/// The variable which is used mostly on X11.
33const X11_VAR: &str = "DESKTOP_STARTUP_ID";
34
35/// The variable which is used mostly on Wayland.
36const WAYLAND_VAR: &str = "XDG_ACTIVATION_TOKEN";
37
38pub trait EventLoopExtStartupNotify {
39    /// Read the token from the environment.
40    ///
41    /// It's recommended **to unset** this environment variable for child processes.
42    fn read_token_from_env(&self) -> Option<ActivationToken>;
43}
44
45pub trait WindowExtStartupNotify {
46    /// Request a new activation token.
47    ///
48    /// The token will be delivered inside
49    fn request_activation_token(&self) -> Result<AsyncRequestSerial, RequestError>;
50}
51
52pub trait WindowAttributesExtStartupNotify {
53    /// Use this [`ActivationToken`] during window creation.
54    ///
55    /// Not using such a token upon a window could make your window not gaining
56    /// focus until the user clicks on the window.
57    fn with_activation_token(self, token: ActivationToken) -> Self;
58}
59
60impl EventLoopExtStartupNotify for dyn ActiveEventLoop + '_ {
61    fn read_token_from_env(&self) -> Option<ActivationToken> {
62        #[cfg(x11_platform)]
63        let _is_wayland = false;
64        #[cfg(wayland_platform)]
65        let _is_wayland = self.is_wayland();
66
67        if _is_wayland {
68            env::var(WAYLAND_VAR).ok().map(ActivationToken::_new)
69        } else {
70            env::var(X11_VAR).ok().map(ActivationToken::_new)
71        }
72    }
73}
74
75impl WindowExtStartupNotify for dyn Window + '_ {
76    fn request_activation_token(&self) -> Result<AsyncRequestSerial, RequestError> {
77        #[cfg(wayland_platform)]
78        if let Some(window) = self.as_any().downcast_ref::<crate::platform_impl::wayland::Window>()
79        {
80            return window.request_activation_token();
81        }
82
83        #[cfg(x11_platform)]
84        if let Some(window) =
85            self.as_any().downcast_ref::<crate::platform_impl::x11::window::Window>()
86        {
87            return window.request_activation_token();
88        }
89
90        Err(NotSupportedError::new("startup notify is not supported").into())
91    }
92}
93
94impl WindowAttributesExtStartupNotify for WindowAttributes {
95    fn with_activation_token(mut self, token: ActivationToken) -> Self {
96        self.platform_specific.activation_token = Some(token);
97        self
98    }
99}
100
101/// Remove the activation environment variables from the current process.
102///
103/// This is wise to do before running child processes,
104/// which may not to support the activation token.
105pub fn reset_activation_token_env() {
106    env::remove_var(X11_VAR);
107    env::remove_var(WAYLAND_VAR);
108}
109
110/// Set environment variables responsible for activation token.
111///
112/// This could be used before running daemon processes.
113pub fn set_activation_token_env(token: ActivationToken) {
114    env::set_var(X11_VAR, &token._token);
115    env::set_var(WAYLAND_VAR, token._token);
116}