winit/platform/x11.rs
1//! # X11
2#[cfg(feature = "serde")]
3use serde::{Deserialize, Serialize};
4
5use crate::dpi::Size;
6use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder};
7use crate::monitor::MonitorHandle;
8use crate::window::{Window as CoreWindow, WindowAttributes};
9
10/// X window type. Maps directly to
11/// [`_NET_WM_WINDOW_TYPE`](https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html).
12#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
13#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14pub enum WindowType {
15 /// A desktop feature. This can include a single window containing desktop icons with the same
16 /// dimensions as the screen, allowing the desktop environment to have full control of the
17 /// desktop, without the need for proxying root window clicks.
18 Desktop,
19 /// A dock or panel feature. Typically a Window Manager would keep such windows on top of all
20 /// other windows.
21 Dock,
22 /// Toolbar windows. "Torn off" from the main application.
23 Toolbar,
24 /// Pinnable menu windows. "Torn off" from the main application.
25 Menu,
26 /// A small persistent utility window, such as a palette or toolbox.
27 Utility,
28 /// The window is a splash screen displayed as an application is starting up.
29 Splash,
30 /// This is a dialog window.
31 Dialog,
32 /// A dropdown menu that usually appears when the user clicks on an item in a menu bar.
33 /// This property is typically used on override-redirect windows.
34 DropdownMenu,
35 /// A popup menu that usually appears when the user right clicks on an object.
36 /// This property is typically used on override-redirect windows.
37 PopupMenu,
38 /// A tooltip window. Usually used to show additional information when hovering over an object
39 /// with the cursor. This property is typically used on override-redirect windows.
40 Tooltip,
41 /// The window is a notification.
42 /// This property is typically used on override-redirect windows.
43 Notification,
44 /// This should be used on the windows that are popped up by combo boxes.
45 /// This property is typically used on override-redirect windows.
46 Combo,
47 /// This indicates the window is being dragged.
48 /// This property is typically used on override-redirect windows.
49 Dnd,
50 /// This is a normal, top-level window.
51 #[default]
52 Normal,
53}
54
55/// The first argument in the provided hook will be the pointer to `XDisplay`
56/// and the second one the pointer to [`XErrorEvent`]. The returned `bool` is an
57/// indicator whether the error was handled by the callback.
58///
59/// [`XErrorEvent`]: https://linux.die.net/man/3/xerrorevent
60pub type XlibErrorHook =
61 Box<dyn Fn(*mut std::ffi::c_void, *mut std::ffi::c_void) -> bool + Send + Sync>;
62
63/// A unique identifier for an X11 visual.
64pub type XVisualID = u32;
65
66/// A unique identifier for an X11 window.
67pub type XWindow = u32;
68
69/// Hook to winit's xlib error handling callback.
70///
71/// This method is provided as a safe way to handle the errors coming from X11
72/// when using xlib in external crates, like glutin for GLX access. Trying to
73/// handle errors by speculating with `XSetErrorHandler` is [`unsafe`].
74///
75/// **Be aware that your hook is always invoked and returning `true` from it will
76/// prevent `winit` from getting the error itself. It's wise to always return
77/// `false` if you're not initiated the `Sync`.**
78///
79/// [`unsafe`]: https://www.remlab.net/op/xlib.shtml
80#[inline]
81pub fn register_xlib_error_hook(hook: XlibErrorHook) {
82 // Append new hook.
83 crate::platform_impl::XLIB_ERROR_HOOKS.lock().unwrap().push(hook);
84}
85
86/// Additional methods on [`ActiveEventLoop`] that are specific to X11.
87pub trait ActiveEventLoopExtX11 {
88 /// True if the [`ActiveEventLoop`] uses X11.
89 fn is_x11(&self) -> bool;
90}
91
92impl ActiveEventLoopExtX11 for dyn ActiveEventLoop + '_ {
93 #[inline]
94 fn is_x11(&self) -> bool {
95 self.as_any().downcast_ref::<crate::platform_impl::x11::ActiveEventLoop>().is_some()
96 }
97}
98
99/// Additional methods on [`EventLoop`] that are specific to X11.
100pub trait EventLoopExtX11 {
101 /// True if the [`EventLoop`] uses X11.
102 fn is_x11(&self) -> bool;
103}
104
105impl EventLoopExtX11 for EventLoop {
106 #[inline]
107 fn is_x11(&self) -> bool {
108 !self.event_loop.is_wayland()
109 }
110}
111
112/// Additional methods on [`EventLoopBuilder`] that are specific to X11.
113pub trait EventLoopBuilderExtX11 {
114 /// Force using X11.
115 fn with_x11(&mut self) -> &mut Self;
116
117 /// Whether to allow the event loop to be created off of the main thread.
118 ///
119 /// By default, the window is only allowed to be created on the main
120 /// thread, to make platform compatibility easier.
121 fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
122}
123
124impl EventLoopBuilderExtX11 for EventLoopBuilder {
125 #[inline]
126 fn with_x11(&mut self) -> &mut Self {
127 self.platform_specific.forced_backend = Some(crate::platform_impl::Backend::X);
128 self
129 }
130
131 #[inline]
132 fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
133 self.platform_specific.any_thread = any_thread;
134 self
135 }
136}
137
138/// Additional methods on [`Window`] that are specific to X11.
139///
140/// [`Window`]: crate::window::Window
141pub trait WindowExtX11 {}
142
143impl WindowExtX11 for dyn CoreWindow {}
144
145/// Additional methods on [`WindowAttributes`] that are specific to X11.
146pub trait WindowAttributesExtX11 {
147 /// Create this window with a specific X11 visual.
148 fn with_x11_visual(self, visual_id: XVisualID) -> Self;
149
150 fn with_x11_screen(self, screen_id: i32) -> Self;
151
152 /// Build window with the given `general` and `instance` names.
153 ///
154 /// The `general` sets general class of `WM_CLASS(STRING)`, while `instance` set the
155 /// instance part of it. The resulted property looks like `WM_CLASS(STRING) = "instance",
156 /// "general"`.
157 ///
158 /// For details about application ID conventions, see the
159 /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id)
160 fn with_name(self, general: impl Into<String>, instance: impl Into<String>) -> Self;
161
162 /// Build window with override-redirect flag; defaults to false.
163 fn with_override_redirect(self, override_redirect: bool) -> Self;
164
165 /// Build window with `_NET_WM_WINDOW_TYPE` hints; defaults to `Normal`.
166 fn with_x11_window_type(self, x11_window_type: Vec<WindowType>) -> Self;
167
168 /// Build window with base size hint.
169 ///
170 /// ```
171 /// # use winit::dpi::{LogicalSize, PhysicalSize};
172 /// # use winit::window::{Window, WindowAttributes};
173 /// # use winit::platform::x11::WindowAttributesExtX11;
174 /// // Specify the size in logical dimensions like this:
175 /// WindowAttributes::default().with_base_size(LogicalSize::new(400.0, 200.0));
176 ///
177 /// // Or specify the size in physical dimensions like this:
178 /// WindowAttributes::default().with_base_size(PhysicalSize::new(400, 200));
179 /// ```
180 fn with_base_size<S: Into<Size>>(self, base_size: S) -> Self;
181
182 /// Embed this window into another parent window.
183 ///
184 /// # Example
185 ///
186 /// ```no_run
187 /// use winit::window::{Window, WindowAttributes};
188 /// use winit::event_loop::ActiveEventLoop;
189 /// use winit::platform::x11::{XWindow, WindowAttributesExtX11};
190 /// # fn create_window(event_loop: &dyn ActiveEventLoop) -> Result<(), Box<dyn std::error::Error>> {
191 /// let parent_window_id = std::env::args().nth(1).unwrap().parse::<XWindow>()?;
192 /// let window_attributes = WindowAttributes::default().with_embed_parent_window(parent_window_id);
193 /// let window = event_loop.create_window(window_attributes)?;
194 /// # Ok(()) }
195 /// ```
196 fn with_embed_parent_window(self, parent_window_id: XWindow) -> Self;
197}
198
199impl WindowAttributesExtX11 for WindowAttributes {
200 #[inline]
201 fn with_x11_visual(mut self, visual_id: XVisualID) -> Self {
202 self.platform_specific.x11.visual_id = Some(visual_id);
203 self
204 }
205
206 #[inline]
207 fn with_x11_screen(mut self, screen_id: i32) -> Self {
208 self.platform_specific.x11.screen_id = Some(screen_id);
209 self
210 }
211
212 #[inline]
213 fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self {
214 self.platform_specific.name =
215 Some(crate::platform_impl::ApplicationName::new(general.into(), instance.into()));
216 self
217 }
218
219 #[inline]
220 fn with_override_redirect(mut self, override_redirect: bool) -> Self {
221 self.platform_specific.x11.override_redirect = override_redirect;
222 self
223 }
224
225 #[inline]
226 fn with_x11_window_type(mut self, x11_window_types: Vec<WindowType>) -> Self {
227 self.platform_specific.x11.x11_window_types = x11_window_types;
228 self
229 }
230
231 #[inline]
232 fn with_base_size<S: Into<Size>>(mut self, base_size: S) -> Self {
233 self.platform_specific.x11.base_size = Some(base_size.into());
234 self
235 }
236
237 #[inline]
238 fn with_embed_parent_window(mut self, parent_window_id: XWindow) -> Self {
239 self.platform_specific.x11.embed_window = Some(parent_window_id);
240 self
241 }
242}
243
244/// Additional methods on `MonitorHandle` that are specific to X11.
245pub trait MonitorHandleExtX11 {
246 /// Returns the inner identifier of the monitor.
247 fn native_id(&self) -> u32;
248}
249
250impl MonitorHandleExtX11 for MonitorHandle {
251 #[inline]
252 fn native_id(&self) -> u32 {
253 self.inner.native_identifier()
254 }
255}