1 #![cfg(any(
2     target_os = "linux",
3     target_os = "dragonfly",
4     target_os = "freebsd",
5     target_os = "netbsd",
6     target_os = "openbsd"
7 ))]
8 
9 use std::os::raw;
10 #[cfg(feature = "x11")]
11 use std::{ptr, sync::Arc};
12 
13 use crate::{
14     event_loop::{EventLoop, EventLoopWindowTarget},
15     monitor::MonitorHandle,
16     window::{Window, WindowBuilder},
17 };
18 
19 #[cfg(feature = "x11")]
20 use crate::dpi::Size;
21 #[cfg(feature = "x11")]
22 use crate::platform_impl::x11::{ffi::XVisualInfo, XConnection};
23 use crate::platform_impl::{
24     EventLoop as LinuxEventLoop, EventLoopWindowTarget as LinuxEventLoopWindowTarget,
25     Window as LinuxWindow,
26 };
27 
28 // TODO: stupid hack so that glutin can do its work
29 #[doc(hidden)]
30 #[cfg(feature = "x11")]
31 pub use crate::platform_impl::x11;
32 #[cfg(feature = "x11")]
33 pub use crate::platform_impl::{x11::util::WindowType as XWindowType, XNotSupported};
34 
35 /// Additional methods on `EventLoopWindowTarget` that are specific to Unix.
36 pub trait EventLoopWindowTargetExtUnix {
37     /// True if the `EventLoopWindowTarget` uses Wayland.
38     #[cfg(feature = "wayland")]
is_wayland(&self) -> bool39     fn is_wayland(&self) -> bool;
40 
41     /// True if the `EventLoopWindowTarget` uses X11.
42     #[cfg(feature = "x11")]
is_x11(&self) -> bool43     fn is_x11(&self) -> bool;
44 
45     #[doc(hidden)]
46     #[cfg(feature = "x11")]
xlib_xconnection(&self) -> Option<Arc<XConnection>>47     fn xlib_xconnection(&self) -> Option<Arc<XConnection>>;
48 
49     /// Returns a pointer to the `wl_display` object of wayland that is used by this
50     /// `EventLoopWindowTarget`.
51     ///
52     /// Returns `None` if the `EventLoop` doesn't use wayland (if it uses xlib for example).
53     ///
54     /// The pointer will become invalid when the winit `EventLoop` is destroyed.
55     #[cfg(feature = "wayland")]
wayland_display(&self) -> Option<*mut raw::c_void>56     fn wayland_display(&self) -> Option<*mut raw::c_void>;
57 }
58 
59 impl<T> EventLoopWindowTargetExtUnix for EventLoopWindowTarget<T> {
60     #[inline]
61     #[cfg(feature = "wayland")]
is_wayland(&self) -> bool62     fn is_wayland(&self) -> bool {
63         self.p.is_wayland()
64     }
65 
66     #[inline]
67     #[cfg(feature = "x11")]
is_x11(&self) -> bool68     fn is_x11(&self) -> bool {
69         !self.p.is_wayland()
70     }
71 
72     #[inline]
73     #[doc(hidden)]
74     #[cfg(feature = "x11")]
xlib_xconnection(&self) -> Option<Arc<XConnection>>75     fn xlib_xconnection(&self) -> Option<Arc<XConnection>> {
76         match self.p {
77             LinuxEventLoopWindowTarget::X(ref e) => Some(e.x_connection().clone()),
78             #[cfg(feature = "wayland")]
79             _ => None,
80         }
81     }
82 
83     #[inline]
84     #[cfg(feature = "wayland")]
wayland_display(&self) -> Option<*mut raw::c_void>85     fn wayland_display(&self) -> Option<*mut raw::c_void> {
86         match self.p {
87             LinuxEventLoopWindowTarget::Wayland(ref p) => {
88                 Some(p.display().get_display_ptr() as *mut _)
89             }
90             #[cfg(feature = "x11")]
91             _ => None,
92         }
93     }
94 }
95 
96 /// Additional methods on `EventLoop` that are specific to Unix.
97 pub trait EventLoopExtUnix {
98     /// Builds a new `EventLoop` that is forced to use X11.
99     ///
100     /// # Panics
101     ///
102     /// If called outside the main thread. To initialize an X11 event loop outside
103     /// the main thread, use [`new_x11_any_thread`](#tymethod.new_x11_any_thread).
104     #[cfg(feature = "x11")]
new_x11() -> Result<Self, XNotSupported> where Self: Sized105     fn new_x11() -> Result<Self, XNotSupported>
106     where
107         Self: Sized;
108 
109     /// Builds a new `EventLoop` that is forced to use Wayland.
110     ///
111     /// # Panics
112     ///
113     /// If called outside the main thread. To initialize a Wayland event loop outside
114     /// the main thread, use [`new_wayland_any_thread`](#tymethod.new_wayland_any_thread).
115     #[cfg(feature = "wayland")]
new_wayland() -> Self where Self: Sized116     fn new_wayland() -> Self
117     where
118         Self: Sized;
119 
120     /// Builds a new `EventLoop` on any thread.
121     ///
122     /// This method bypasses the cross-platform compatibility requirement
123     /// that `EventLoop` be created on the main thread.
new_any_thread() -> Self where Self: Sized124     fn new_any_thread() -> Self
125     where
126         Self: Sized;
127 
128     /// Builds a new X11 `EventLoop` on any thread.
129     ///
130     /// This method bypasses the cross-platform compatibility requirement
131     /// that `EventLoop` be created on the main thread.
132     #[cfg(feature = "x11")]
new_x11_any_thread() -> Result<Self, XNotSupported> where Self: Sized133     fn new_x11_any_thread() -> Result<Self, XNotSupported>
134     where
135         Self: Sized;
136 
137     /// Builds a new Wayland `EventLoop` on any thread.
138     ///
139     /// This method bypasses the cross-platform compatibility requirement
140     /// that `EventLoop` be created on the main thread.
141     #[cfg(feature = "wayland")]
new_wayland_any_thread() -> Self where Self: Sized142     fn new_wayland_any_thread() -> Self
143     where
144         Self: Sized;
145 }
146 
wrap_ev<T>(event_loop: LinuxEventLoop<T>) -> EventLoop<T>147 fn wrap_ev<T>(event_loop: LinuxEventLoop<T>) -> EventLoop<T> {
148     EventLoop {
149         event_loop,
150         _marker: std::marker::PhantomData,
151     }
152 }
153 
154 impl<T> EventLoopExtUnix for EventLoop<T> {
155     #[inline]
new_any_thread() -> Self156     fn new_any_thread() -> Self {
157         wrap_ev(LinuxEventLoop::new_any_thread())
158     }
159 
160     #[inline]
161     #[cfg(feature = "x11")]
new_x11_any_thread() -> Result<Self, XNotSupported>162     fn new_x11_any_thread() -> Result<Self, XNotSupported> {
163         LinuxEventLoop::new_x11_any_thread().map(wrap_ev)
164     }
165 
166     #[inline]
167     #[cfg(feature = "wayland")]
new_wayland_any_thread() -> Self168     fn new_wayland_any_thread() -> Self {
169         wrap_ev(
170             LinuxEventLoop::new_wayland_any_thread()
171                 // TODO: propagate
172                 .expect("failed to open Wayland connection"),
173         )
174     }
175 
176     #[inline]
177     #[cfg(feature = "x11")]
new_x11() -> Result<Self, XNotSupported>178     fn new_x11() -> Result<Self, XNotSupported> {
179         LinuxEventLoop::new_x11().map(wrap_ev)
180     }
181 
182     #[inline]
183     #[cfg(feature = "wayland")]
new_wayland() -> Self184     fn new_wayland() -> Self {
185         wrap_ev(
186             LinuxEventLoop::new_wayland()
187                 // TODO: propagate
188                 .expect("failed to open Wayland connection"),
189         )
190     }
191 }
192 
193 /// Additional methods on `Window` that are specific to Unix.
194 pub trait WindowExtUnix {
195     /// Returns the ID of the `Window` xlib object that is used by this window.
196     ///
197     /// Returns `None` if the window doesn't use xlib (if it uses wayland for example).
198     #[cfg(feature = "x11")]
xlib_window(&self) -> Option<raw::c_ulong>199     fn xlib_window(&self) -> Option<raw::c_ulong>;
200 
201     /// Returns a pointer to the `Display` object of xlib that is used by this window.
202     ///
203     /// Returns `None` if the window doesn't use xlib (if it uses wayland for example).
204     ///
205     /// The pointer will become invalid when the glutin `Window` is destroyed.
206     #[cfg(feature = "x11")]
xlib_display(&self) -> Option<*mut raw::c_void>207     fn xlib_display(&self) -> Option<*mut raw::c_void>;
208 
209     #[cfg(feature = "x11")]
xlib_screen_id(&self) -> Option<raw::c_int>210     fn xlib_screen_id(&self) -> Option<raw::c_int>;
211 
212     #[doc(hidden)]
213     #[cfg(feature = "x11")]
xlib_xconnection(&self) -> Option<Arc<XConnection>>214     fn xlib_xconnection(&self) -> Option<Arc<XConnection>>;
215 
216     /// This function returns the underlying `xcb_connection_t` of an xlib `Display`.
217     ///
218     /// Returns `None` if the window doesn't use xlib (if it uses wayland for example).
219     ///
220     /// The pointer will become invalid when the glutin `Window` is destroyed.
221     #[cfg(feature = "x11")]
xcb_connection(&self) -> Option<*mut raw::c_void>222     fn xcb_connection(&self) -> Option<*mut raw::c_void>;
223 
224     /// Returns a pointer to the `wl_surface` object of wayland that is used by this window.
225     ///
226     /// Returns `None` if the window doesn't use wayland (if it uses xlib for example).
227     ///
228     /// The pointer will become invalid when the glutin `Window` is destroyed.
229     #[cfg(feature = "wayland")]
wayland_surface(&self) -> Option<*mut raw::c_void>230     fn wayland_surface(&self) -> Option<*mut raw::c_void>;
231 
232     /// Returns a pointer to the `wl_display` object of wayland that is used by this window.
233     ///
234     /// Returns `None` if the window doesn't use wayland (if it uses xlib for example).
235     ///
236     /// The pointer will become invalid when the glutin `Window` is destroyed.
237     #[cfg(feature = "wayland")]
wayland_display(&self) -> Option<*mut raw::c_void>238     fn wayland_display(&self) -> Option<*mut raw::c_void>;
239 
240     /// Sets the color theme of the client side window decorations on wayland
241     #[cfg(feature = "wayland")]
set_wayland_theme<T: Theme>(&self, theme: T)242     fn set_wayland_theme<T: Theme>(&self, theme: T);
243 
244     /// Check if the window is ready for drawing
245     ///
246     /// It is a remnant of a previous implementation detail for the
247     /// wayland backend, and is no longer relevant.
248     ///
249     /// Always return true.
250     #[deprecated]
is_ready(&self) -> bool251     fn is_ready(&self) -> bool;
252 }
253 
254 impl WindowExtUnix for Window {
255     #[inline]
256     #[cfg(feature = "x11")]
xlib_window(&self) -> Option<raw::c_ulong>257     fn xlib_window(&self) -> Option<raw::c_ulong> {
258         match self.window {
259             LinuxWindow::X(ref w) => Some(w.xlib_window()),
260             #[cfg(feature = "wayland")]
261             _ => None,
262         }
263     }
264 
265     #[inline]
266     #[cfg(feature = "x11")]
xlib_display(&self) -> Option<*mut raw::c_void>267     fn xlib_display(&self) -> Option<*mut raw::c_void> {
268         match self.window {
269             LinuxWindow::X(ref w) => Some(w.xlib_display()),
270             #[cfg(feature = "wayland")]
271             _ => None,
272         }
273     }
274 
275     #[inline]
276     #[cfg(feature = "x11")]
xlib_screen_id(&self) -> Option<raw::c_int>277     fn xlib_screen_id(&self) -> Option<raw::c_int> {
278         match self.window {
279             LinuxWindow::X(ref w) => Some(w.xlib_screen_id()),
280             #[cfg(feature = "wayland")]
281             _ => None,
282         }
283     }
284 
285     #[inline]
286     #[doc(hidden)]
287     #[cfg(feature = "x11")]
xlib_xconnection(&self) -> Option<Arc<XConnection>>288     fn xlib_xconnection(&self) -> Option<Arc<XConnection>> {
289         match self.window {
290             LinuxWindow::X(ref w) => Some(w.xlib_xconnection()),
291             #[cfg(feature = "wayland")]
292             _ => None,
293         }
294     }
295 
296     #[inline]
297     #[cfg(feature = "x11")]
xcb_connection(&self) -> Option<*mut raw::c_void>298     fn xcb_connection(&self) -> Option<*mut raw::c_void> {
299         match self.window {
300             LinuxWindow::X(ref w) => Some(w.xcb_connection()),
301             #[cfg(feature = "wayland")]
302             _ => None,
303         }
304     }
305 
306     #[inline]
307     #[cfg(feature = "wayland")]
wayland_surface(&self) -> Option<*mut raw::c_void>308     fn wayland_surface(&self) -> Option<*mut raw::c_void> {
309         match self.window {
310             LinuxWindow::Wayland(ref w) => Some(w.surface().as_ref().c_ptr() as *mut _),
311             #[cfg(feature = "x11")]
312             _ => None,
313         }
314     }
315 
316     #[inline]
317     #[cfg(feature = "wayland")]
wayland_display(&self) -> Option<*mut raw::c_void>318     fn wayland_display(&self) -> Option<*mut raw::c_void> {
319         match self.window {
320             LinuxWindow::Wayland(ref w) => Some(w.display().get_display_ptr() as *mut _),
321             #[cfg(feature = "x11")]
322             _ => None,
323         }
324     }
325 
326     #[inline]
327     #[cfg(feature = "wayland")]
set_wayland_theme<T: Theme>(&self, theme: T)328     fn set_wayland_theme<T: Theme>(&self, theme: T) {
329         match self.window {
330             LinuxWindow::Wayland(ref w) => w.set_theme(theme),
331             #[cfg(feature = "x11")]
332             _ => {}
333         }
334     }
335 
336     #[inline]
is_ready(&self) -> bool337     fn is_ready(&self) -> bool {
338         true
339     }
340 }
341 
342 /// Additional methods on `WindowBuilder` that are specific to Unix.
343 pub trait WindowBuilderExtUnix {
344     #[cfg(feature = "x11")]
with_x11_visual<T>(self, visual_infos: *const T) -> Self345     fn with_x11_visual<T>(self, visual_infos: *const T) -> Self;
346     #[cfg(feature = "x11")]
with_x11_screen(self, screen_id: i32) -> Self347     fn with_x11_screen(self, screen_id: i32) -> Self;
348 
349     /// Build window with `WM_CLASS` hint; defaults to the name of the binary. Only relevant on X11.
350     #[cfg(feature = "x11")]
with_class(self, class: String, instance: String) -> Self351     fn with_class(self, class: String, instance: String) -> Self;
352     /// Build window with override-redirect flag; defaults to false. Only relevant on X11.
353     #[cfg(feature = "x11")]
with_override_redirect(self, override_redirect: bool) -> Self354     fn with_override_redirect(self, override_redirect: bool) -> Self;
355     /// Build window with `_NET_WM_WINDOW_TYPE` hints; defaults to `Normal`. Only relevant on X11.
356     #[cfg(feature = "x11")]
with_x11_window_type(self, x11_window_type: Vec<XWindowType>) -> Self357     fn with_x11_window_type(self, x11_window_type: Vec<XWindowType>) -> Self;
358     /// Build window with `_GTK_THEME_VARIANT` hint set to the specified value. Currently only relevant on X11.
359     #[cfg(feature = "x11")]
with_gtk_theme_variant(self, variant: String) -> Self360     fn with_gtk_theme_variant(self, variant: String) -> Self;
361     /// Build window with resize increment hint. Only implemented on X11.
362     #[cfg(feature = "x11")]
with_resize_increments<S: Into<Size>>(self, increments: S) -> Self363     fn with_resize_increments<S: Into<Size>>(self, increments: S) -> Self;
364     /// Build window with base size hint. Only implemented on X11.
365     #[cfg(feature = "x11")]
with_base_size<S: Into<Size>>(self, base_size: S) -> Self366     fn with_base_size<S: Into<Size>>(self, base_size: S) -> Self;
367 
368     /// Build window with a given application ID. It should match the `.desktop` file distributed with
369     /// your program. Only relevant on Wayland.
370     ///
371     /// For details about application ID conventions, see the
372     /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id)
373     #[cfg(feature = "wayland")]
with_app_id(self, app_id: String) -> Self374     fn with_app_id(self, app_id: String) -> Self;
375 }
376 
377 impl WindowBuilderExtUnix for WindowBuilder {
378     #[inline]
379     #[cfg(feature = "x11")]
with_x11_visual<T>(mut self, visual_infos: *const T) -> Self380     fn with_x11_visual<T>(mut self, visual_infos: *const T) -> Self {
381         {
382             self.platform_specific.visual_infos =
383                 Some(unsafe { ptr::read(visual_infos as *const XVisualInfo) });
384         }
385         self
386     }
387 
388     #[inline]
389     #[cfg(feature = "x11")]
with_x11_screen(mut self, screen_id: i32) -> Self390     fn with_x11_screen(mut self, screen_id: i32) -> Self {
391         self.platform_specific.screen_id = Some(screen_id);
392         self
393     }
394 
395     #[inline]
396     #[cfg(feature = "x11")]
with_class(mut self, instance: String, class: String) -> Self397     fn with_class(mut self, instance: String, class: String) -> Self {
398         self.platform_specific.class = Some((instance, class));
399         self
400     }
401 
402     #[inline]
403     #[cfg(feature = "x11")]
with_override_redirect(mut self, override_redirect: bool) -> Self404     fn with_override_redirect(mut self, override_redirect: bool) -> Self {
405         self.platform_specific.override_redirect = override_redirect;
406         self
407     }
408 
409     #[inline]
410     #[cfg(feature = "x11")]
with_x11_window_type(mut self, x11_window_types: Vec<XWindowType>) -> Self411     fn with_x11_window_type(mut self, x11_window_types: Vec<XWindowType>) -> Self {
412         self.platform_specific.x11_window_types = x11_window_types;
413         self
414     }
415 
416     #[inline]
417     #[cfg(feature = "x11")]
with_gtk_theme_variant(mut self, variant: String) -> Self418     fn with_gtk_theme_variant(mut self, variant: String) -> Self {
419         self.platform_specific.gtk_theme_variant = Some(variant);
420         self
421     }
422 
423     #[inline]
424     #[cfg(feature = "x11")]
with_resize_increments<S: Into<Size>>(mut self, increments: S) -> Self425     fn with_resize_increments<S: Into<Size>>(mut self, increments: S) -> Self {
426         self.platform_specific.resize_increments = Some(increments.into());
427         self
428     }
429 
430     #[inline]
431     #[cfg(feature = "x11")]
with_base_size<S: Into<Size>>(mut self, base_size: S) -> Self432     fn with_base_size<S: Into<Size>>(mut self, base_size: S) -> Self {
433         self.platform_specific.base_size = Some(base_size.into());
434         self
435     }
436 
437     #[inline]
438     #[cfg(feature = "wayland")]
with_app_id(mut self, app_id: String) -> Self439     fn with_app_id(mut self, app_id: String) -> Self {
440         self.platform_specific.app_id = Some(app_id);
441         self
442     }
443 }
444 
445 /// Additional methods on `MonitorHandle` that are specific to Linux.
446 pub trait MonitorHandleExtUnix {
447     /// Returns the inner identifier of the monitor.
native_id(&self) -> u32448     fn native_id(&self) -> u32;
449 }
450 
451 impl MonitorHandleExtUnix for MonitorHandle {
452     #[inline]
native_id(&self) -> u32453     fn native_id(&self) -> u32 {
454         self.inner.native_identifier()
455     }
456 }
457 
458 /// A theme for a Wayland's client side decorations.
459 #[cfg(feature = "wayland")]
460 pub trait Theme: Send + 'static {
461     /// Title bar color.
element_color(&self, element: Element, window_active: bool) -> ARGBColor462     fn element_color(&self, element: Element, window_active: bool) -> ARGBColor;
463 
464     /// Color for a given button part.
button_color( &self, button: Button, state: ButtonState, foreground: bool, window_active: bool, ) -> ARGBColor465     fn button_color(
466         &self,
467         button: Button,
468         state: ButtonState,
469         foreground: bool,
470         window_active: bool,
471     ) -> ARGBColor;
472 
473     /// Font name and the size for the title bar.
474     ///
475     /// By default the font is `sans-serif` at the size of 17.
476     ///
477     /// Returning `None` means that title won't be drawn.
font(&self) -> Option<(String, f32)>478     fn font(&self) -> Option<(String, f32)> {
479         // Not having any title isn't something desirable for the users, so setting it to
480         // something generic.
481         Some((String::from("sans-serif"), 17.))
482     }
483 }
484 
485 /// A button on Wayland's client side decorations.
486 #[cfg(feature = "wayland")]
487 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
488 pub enum Button {
489     /// Button that maximizes the window.
490     Maximize,
491 
492     /// Button that minimizes the window.
493     Minimize,
494 
495     /// Button that closes the window.
496     Close,
497 }
498 
499 /// A button state of the button on Wayland's client side decorations.
500 #[cfg(feature = "wayland")]
501 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
502 pub enum ButtonState {
503     /// Button is being hovered over by pointer.
504     Hovered,
505     /// Button is not being hovered over by pointer.
506     Idle,
507     /// Button is disabled.
508     Disabled,
509 }
510 
511 #[cfg(feature = "wayland")]
512 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
513 pub enum Element {
514     /// Bar itself.
515     Bar,
516 
517     /// Separator between window and title bar.
518     Separator,
519 
520     /// Title bar text.
521     Text,
522 }
523 
524 #[cfg(feature = "wayland")]
525 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
526 pub struct ARGBColor {
527     pub a: u8,
528     pub r: u8,
529     pub g: u8,
530     pub b: u8,
531 }
532