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