floem_winit/platform/
x11.rs

1use crate::{
2    event_loop::{EventLoopBuilder, EventLoopWindowTarget},
3    monitor::MonitorHandle,
4    window::{Window, WindowBuilder},
5};
6
7use crate::dpi::Size;
8use crate::platform_impl::{ApplicationName, Backend, XLIB_ERROR_HOOKS};
9
10pub use crate::platform_impl::{x11::util::WindowType as XWindowType, XNotSupported};
11
12/// The first argument in the provided hook will be the pointer to `XDisplay`
13/// and the second one the pointer to [`XErrorEvent`]. The returned `bool` is an
14/// indicator whether the error was handled by the callback.
15///
16/// [`XErrorEvent`]: https://linux.die.net/man/3/xerrorevent
17pub type XlibErrorHook =
18    Box<dyn Fn(*mut std::ffi::c_void, *mut std::ffi::c_void) -> bool + Send + Sync>;
19
20/// A unique identifer for an X11 visual.
21pub type XVisualID = u32;
22
23/// A unique identifier for an X11 window.
24pub type XWindow = u32;
25
26/// Hook to winit's xlib error handling callback.
27///
28/// This method is provided as a safe way to handle the errors comming from X11
29/// when using xlib in external crates, like glutin for GLX access. Trying to
30/// handle errors by speculating with `XSetErrorHandler` is [`unsafe`].
31///
32/// **Be aware that your hook is always invoked and returning `true` from it will
33/// prevent `winit` from getting the error itself. It's wise to always return
34/// `false` if you're not initiated the `Sync`.**
35///
36/// [`unsafe`]: https://www.remlab.net/op/xlib.shtml
37#[inline]
38pub fn register_xlib_error_hook(hook: XlibErrorHook) {
39    // Append new hook.
40    unsafe {
41        XLIB_ERROR_HOOKS.lock().unwrap().push(hook);
42    }
43}
44
45/// Additional methods on [`EventLoopWindowTarget`] that are specific to X11.
46pub trait EventLoopWindowTargetExtX11 {
47    /// True if the [`EventLoopWindowTarget`] uses X11.
48    fn is_x11(&self) -> bool;
49}
50
51impl<T> EventLoopWindowTargetExtX11 for EventLoopWindowTarget<T> {
52    #[inline]
53    fn is_x11(&self) -> bool {
54        !self.p.is_wayland()
55    }
56}
57
58/// Additional methods on [`EventLoopBuilder`] that are specific to X11.
59pub trait EventLoopBuilderExtX11 {
60    /// Force using X11.
61    fn with_x11(&mut self) -> &mut Self;
62
63    /// Whether to allow the event loop to be created off of the main thread.
64    ///
65    /// By default, the window is only allowed to be created on the main
66    /// thread, to make platform compatibility easier.
67    fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
68}
69
70impl<T> EventLoopBuilderExtX11 for EventLoopBuilder<T> {
71    #[inline]
72    fn with_x11(&mut self) -> &mut Self {
73        self.platform_specific.forced_backend = Some(Backend::X);
74        self
75    }
76
77    #[inline]
78    fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
79        self.platform_specific.any_thread = any_thread;
80        self
81    }
82}
83
84/// Additional methods on [`Window`] that are specific to X11.
85pub trait WindowExtX11 {}
86
87impl WindowExtX11 for Window {}
88
89/// Additional methods on [`WindowBuilder`] that are specific to X11.
90pub trait WindowBuilderExtX11 {
91    /// Create this window with a specific X11 visual.
92    fn with_x11_visual(self, visual_id: XVisualID) -> Self;
93
94    fn with_x11_screen(self, screen_id: i32) -> Self;
95
96    /// Build window with the given `general` and `instance` names.
97    ///
98    /// The `general` sets general class of `WM_CLASS(STRING)`, while `instance` set the
99    /// instance part of it. The resulted property looks like `WM_CLASS(STRING) = "general", "instance"`.
100    ///
101    /// For details about application ID conventions, see the
102    /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id)
103    fn with_name(self, general: impl Into<String>, instance: impl Into<String>) -> Self;
104
105    /// Build window with override-redirect flag; defaults to false. Only relevant on X11.
106    fn with_override_redirect(self, override_redirect: bool) -> Self;
107
108    /// Build window with `_NET_WM_WINDOW_TYPE` hints; defaults to `Normal`. Only relevant on X11.
109    fn with_x11_window_type(self, x11_window_type: Vec<XWindowType>) -> Self;
110
111    /// Build window with base size hint. Only implemented on X11.
112    ///
113    /// ```
114    /// # use winit::dpi::{LogicalSize, PhysicalSize};
115    /// # use winit::window::WindowBuilder;
116    /// # use winit::platform::x11::WindowBuilderExtX11;
117    /// // Specify the size in logical dimensions like this:
118    /// WindowBuilder::new().with_base_size(LogicalSize::new(400.0, 200.0));
119    ///
120    /// // Or specify the size in physical dimensions like this:
121    /// WindowBuilder::new().with_base_size(PhysicalSize::new(400, 200));
122    /// ```
123    fn with_base_size<S: Into<Size>>(self, base_size: S) -> Self;
124
125    /// Embed this window into another parent window.
126    ///
127    /// # Example
128    ///
129    /// ```no_run
130    /// use winit::window::WindowBuilder;
131    /// use winit::platform::x11::{XWindow, WindowBuilderExtX11};
132    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
133    /// let event_loop = winit::event_loop::EventLoop::new().unwrap();
134    /// let parent_window_id = std::env::args().nth(1).unwrap().parse::<XWindow>()?;
135    /// let window = WindowBuilder::new()
136    ///     .with_embed_parent_window(parent_window_id)
137    ///     .build(&event_loop)?;
138    /// # Ok(()) }
139    /// ```
140    fn with_embed_parent_window(self, parent_window_id: XWindow) -> Self;
141}
142
143impl WindowBuilderExtX11 for WindowBuilder {
144    #[inline]
145    fn with_x11_visual(mut self, visual_id: XVisualID) -> Self {
146        self.platform_specific.x11.visual_id = Some(visual_id);
147        self
148    }
149
150    #[inline]
151    fn with_x11_screen(mut self, screen_id: i32) -> Self {
152        self.platform_specific.x11.screen_id = Some(screen_id);
153        self
154    }
155
156    #[inline]
157    fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self {
158        self.platform_specific.name = Some(ApplicationName::new(general.into(), instance.into()));
159        self
160    }
161
162    #[inline]
163    fn with_override_redirect(mut self, override_redirect: bool) -> Self {
164        self.platform_specific.x11.override_redirect = override_redirect;
165        self
166    }
167
168    #[inline]
169    fn with_x11_window_type(mut self, x11_window_types: Vec<XWindowType>) -> Self {
170        self.platform_specific.x11.x11_window_types = x11_window_types;
171        self
172    }
173
174    #[inline]
175    fn with_base_size<S: Into<Size>>(mut self, base_size: S) -> Self {
176        self.platform_specific.x11.base_size = Some(base_size.into());
177        self
178    }
179
180    #[inline]
181    fn with_embed_parent_window(mut self, parent_window_id: XWindow) -> Self {
182        self.platform_specific.x11.embed_window = Some(parent_window_id);
183        self
184    }
185}
186
187/// Additional methods on `MonitorHandle` that are specific to X11.
188pub trait MonitorHandleExtX11 {
189    /// Returns the inner identifier of the monitor.
190    fn native_id(&self) -> u32;
191}
192
193impl MonitorHandleExtX11 for MonitorHandle {
194    #[inline]
195    fn native_id(&self) -> u32 {
196        self.inner.native_identifier()
197    }
198}