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