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