async_winit/platform/
x11.rs

1/*
2
3`async-winit` is free software: you can redistribute it and/or modify it under the terms of one of
4the following licenses:
5
6* GNU Lesser General Public License as published by the Free Software Foundation, either
7  version 3 of the License, or (at your option) any later version.
8* Mozilla Public License as published by the Mozilla Foundation, version 2.
9
10`async-winit` is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
11the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General
12Public License and the Patron License for more details.
13
14You should have received a copy of the GNU Lesser General Public License and the Mozilla
15Public License along with `async-winit`. If not, see <https://www.gnu.org/licenses/>.
16
17*/
18
19// This file is partially derived from `winit`, which was originally created by Pierre Krieger and
20// contributers. It was originally released under the MIT license.
21
22//! X11-specific code.
23
24use super::__private as sealed;
25use crate::event_loop::{EventLoopBuilder, EventLoopWindowTarget};
26use crate::sync::ThreadSafety;
27use crate::window::{Window, WindowBuilder};
28
29use std::os::raw;
30
31use winit::dpi::Size;
32use winit::platform::x11::{EventLoopBuilderExtX11 as _, WindowExtX11 as _};
33
34#[doc(inline)]
35pub use winit::platform::x11::{register_xlib_error_hook, XWindowType, XlibErrorHook};
36
37/// Additional methods on [`EventLoopWindowTarget`] that are specific to X11.
38///
39/// [`EventLoopWindowTarget`]: crate::event_loop::EventLoopWindowTarget
40pub trait EventLoopWindowTargetExtX11: sealed::EventLoopWindowTargetPrivate {
41    /// True if the [`EventLoopWindowTarget`] uses X11.
42    fn is_x11(&self) -> bool;
43}
44
45impl<TS: ThreadSafety> EventLoopWindowTargetExtX11 for EventLoopWindowTarget<TS> {
46    #[inline]
47    fn is_x11(&self) -> bool {
48        !self.is_wayland
49    }
50}
51
52/// Additional methods on [`EventLoopBuilder`] that are specific to X11.
53///
54/// [`EventLoopBuilder`]: crate::event_loop::EventLoopBuilder
55pub trait EventLoopBuilderExtX11: sealed::EventLoopBuilderPrivate {
56    /// Force using X11.
57    fn with_x11(&mut self) -> &mut Self;
58
59    /// Whether to allow the event loop to be created off of the main thread.
60    ///
61    /// By default, the window is only allowed to be created on the main
62    /// thread, to make platform compatibility easier.
63    fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
64}
65
66impl EventLoopBuilderExtX11 for EventLoopBuilder {
67    #[inline]
68    fn with_x11(&mut self) -> &mut Self {
69        self.inner.with_x11();
70        self
71    }
72
73    #[inline]
74    fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
75        self.inner.with_any_thread(any_thread);
76        self
77    }
78}
79
80/// Additional methods on [`Window`] that are specific to X11.
81///
82/// [`Window`]: crate::window::Window
83pub trait WindowExtX11: sealed::WindowPrivate {
84    /// Returns the ID of the [`Window`] xlib object that is used by this window.
85    ///
86    /// Returns `None` if the window doesn't use xlib (if it uses wayland for example).
87    fn xlib_window(&self) -> Option<raw::c_ulong>;
88
89    /// Returns a pointer to the `Display` object of xlib that is used by this window.
90    ///
91    /// Returns `None` if the window doesn't use xlib (if it uses wayland for example).
92    ///
93    /// The pointer will become invalid when the [`Window`] is destroyed.
94    fn xlib_display(&self) -> Option<*mut raw::c_void>;
95
96    fn xlib_screen_id(&self) -> Option<raw::c_int>;
97
98    /// This function returns the underlying `xcb_connection_t` of an xlib `Display`.
99    ///
100    /// Returns `None` if the window doesn't use xlib (if it uses wayland for example).
101    ///
102    /// The pointer will become invalid when the [`Window`] is destroyed.
103    fn xcb_connection(&self) -> Option<*mut raw::c_void>;
104}
105
106impl<TS: ThreadSafety> WindowExtX11 for Window<TS> {
107    fn xcb_connection(&self) -> Option<*mut raw::c_void> {
108        self.window().xcb_connection()
109    }
110
111    fn xlib_display(&self) -> Option<*mut raw::c_void> {
112        self.window().xlib_display()
113    }
114
115    fn xlib_screen_id(&self) -> Option<raw::c_int> {
116        self.window().xlib_screen_id()
117    }
118
119    fn xlib_window(&self) -> Option<raw::c_ulong> {
120        self.window().xlib_window()
121    }
122}
123
124/// Additional methods on [`WindowBuilder`] that are specific to X11.
125///
126/// [`WindowBuilder`]: crate::window::WindowBuilder
127pub trait WindowBuilderExtX11: sealed::WindowBuilderPrivate {
128    fn with_x11_screen(self, screen_id: i32) -> Self;
129
130    /// Build window with the given `general` and `instance` names.
131    ///
132    /// The `general` sets general class of `WM_CLASS(STRING)`, while `instance` set the
133    /// instance part of it. The resulted property looks like `WM_CLASS(STRING) = "general", "instance"`.
134    ///
135    /// For details about application ID conventions, see the
136    /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id)
137    fn with_name(self, general: impl Into<String>, instance: impl Into<String>) -> Self;
138
139    /// Build window with override-redirect flag; defaults to false. Only relevant on X11.
140    fn with_override_redirect(self, override_redirect: bool) -> Self;
141
142    /// Build window with `_NET_WM_WINDOW_TYPE` hints; defaults to `Normal`. Only relevant on X11.
143    fn with_x11_window_type(self, x11_window_type: Vec<XWindowType>) -> Self;
144
145    /// Build window with base size hint. Only implemented on X11.
146    ///
147    /// ```no_run
148    /// # use winit::dpi::{LogicalSize, PhysicalSize};
149    /// # use winit::window::WindowBuilder;
150    /// # use winit::platform::x11::WindowBuilderExtX11;
151    /// // Specify the size in logical dimensions like this:
152    /// WindowBuilder::new().with_base_size(LogicalSize::new(400.0, 200.0));
153    ///
154    /// // Or specify the size in physical dimensions like this:
155    /// WindowBuilder::new().with_base_size(PhysicalSize::new(400, 200));
156    /// ```
157    fn with_base_size<S: Into<Size>>(self, base_size: S) -> Self;
158}
159
160impl WindowBuilderExtX11 for WindowBuilder {
161    fn with_x11_screen(mut self, screen_id: i32) -> Self {
162        self.platform.set_x11_screen_id(screen_id);
163        self
164    }
165
166    fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self {
167        self.platform
168            .set_x11_name((general.into(), instance.into()));
169        self
170    }
171
172    fn with_override_redirect(mut self, override_redirect: bool) -> Self {
173        self.platform.set_x11_override_redirect(override_redirect);
174        self
175    }
176
177    fn with_x11_window_type(mut self, x11_window_type: Vec<XWindowType>) -> Self {
178        self.platform.set_x11_window_type(x11_window_type);
179        self
180    }
181
182    fn with_base_size<S: Into<Size>>(mut self, base_size: S) -> Self {
183        self.platform.set_x11_base_size(base_size.into());
184        self
185    }
186}
187
188#[derive(Default)]
189pub(crate) struct PlatformSpecific {
190    pub x11_window_type: Vec<XWindowType>,
191    pub x11_name: Option<(String, String)>,
192    pub x11_screen_id: Option<i32>,
193    pub x11_override_redirect: bool,
194    pub x11_base_size: Option<Size>,
195}
196
197impl PlatformSpecific {
198    pub(crate) fn set_x11_window_type(&mut self, x11_window_type: Vec<XWindowType>) {
199        self.x11_window_type = x11_window_type;
200    }
201
202    pub(crate) fn set_x11_name(&mut self, x11_name: (String, String)) {
203        self.x11_name = Some(x11_name);
204    }
205
206    pub(crate) fn set_x11_screen_id(&mut self, x11_screen_id: i32) {
207        self.x11_screen_id = Some(x11_screen_id);
208    }
209
210    pub(crate) fn set_x11_override_redirect(&mut self, x11_override_redirect: bool) {
211        self.x11_override_redirect = x11_override_redirect;
212    }
213
214    pub(crate) fn set_x11_base_size(&mut self, x11_base_size: Size) {
215        self.x11_base_size = Some(x11_base_size);
216    }
217
218    pub(crate) fn apply_to(
219        self,
220        window_builder: winit::window::WindowBuilder,
221    ) -> winit::window::WindowBuilder {
222        use winit::platform::x11::WindowBuilderExtX11 as _;
223
224        let mut window_builder = window_builder;
225        if let Some(screen_id) = self.x11_screen_id {
226            window_builder = window_builder.with_x11_screen(screen_id);
227        }
228        if self.x11_override_redirect {
229            window_builder = window_builder.with_override_redirect(true);
230        }
231        if !self.x11_window_type.is_empty() {
232            window_builder = window_builder.with_x11_window_type(self.x11_window_type);
233        }
234        if let Some(base_size) = self.x11_base_size {
235            window_builder = window_builder.with_base_size(base_size);
236        }
237        window_builder
238    }
239}