floem_winit/platform_impl/linux/
mod.rs

1#![cfg(free_unix)]
2
3#[cfg(all(not(x11_platform), not(wayland_platform)))]
4compile_error!("Please select a feature to build for unix: `x11`, `wayland`");
5
6use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
7use std::sync::Arc;
8use std::time::Duration;
9use std::{collections::VecDeque, env, fmt};
10#[cfg(x11_platform)]
11use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Mutex};
12
13#[cfg(x11_platform)]
14use once_cell::sync::Lazy;
15use smol_str::SmolStr;
16
17#[cfg(x11_platform)]
18use crate::platform::x11::XlibErrorHook;
19use crate::{
20    dpi::{PhysicalPosition, PhysicalSize, Position, Size},
21    error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError},
22    event::KeyEvent,
23    event_loop::{
24        AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed,
25        EventLoopWindowTarget as RootELW,
26    },
27    icon::Icon,
28    keyboard::{Key, PhysicalKey},
29    platform::{
30        modifier_supplement::KeyEventExtModifierSupplement, pump_events::PumpStatus,
31        scancode::PhysicalKeyExtScancode,
32    },
33    window::{
34        ActivationToken, CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme,
35        UserAttentionType, WindowAttributes, WindowButtons, WindowLevel,
36    },
37};
38#[cfg(x11_platform)]
39pub use x11::XNotSupported;
40#[cfg(x11_platform)]
41use x11::{util::WindowType as XWindowType, X11Error, XConnection, XError};
42
43pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
44pub(crate) use crate::platform_impl::Fullscreen;
45
46pub mod common;
47#[cfg(wayland_platform)]
48pub mod wayland;
49#[cfg(x11_platform)]
50pub mod x11;
51
52#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
53pub(crate) enum Backend {
54    #[cfg(x11_platform)]
55    X,
56    #[cfg(wayland_platform)]
57    Wayland,
58}
59
60#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
61pub(crate) struct PlatformSpecificEventLoopAttributes {
62    pub(crate) forced_backend: Option<Backend>,
63    pub(crate) any_thread: bool,
64}
65
66#[derive(Debug, Clone, PartialEq, Eq)]
67pub struct ApplicationName {
68    pub general: String,
69    pub instance: String,
70}
71
72impl ApplicationName {
73    pub fn new(general: String, instance: String) -> Self {
74        Self { general, instance }
75    }
76}
77
78#[derive(Clone)]
79pub struct PlatformSpecificWindowBuilderAttributes {
80    pub name: Option<ApplicationName>,
81    pub activation_token: Option<ActivationToken>,
82    #[cfg(x11_platform)]
83    pub x11: X11WindowBuilderAttributes,
84}
85
86#[derive(Clone)]
87#[cfg(x11_platform)]
88pub struct X11WindowBuilderAttributes {
89    pub visual_id: Option<x11rb::protocol::xproto::Visualid>,
90    pub screen_id: Option<i32>,
91    pub base_size: Option<Size>,
92    pub override_redirect: bool,
93    pub x11_window_types: Vec<XWindowType>,
94
95    /// The parent window to embed this window into.
96    pub embed_window: Option<x11rb::protocol::xproto::Window>,
97}
98
99impl Default for PlatformSpecificWindowBuilderAttributes {
100    fn default() -> Self {
101        Self {
102            name: None,
103            activation_token: None,
104            #[cfg(x11_platform)]
105            x11: X11WindowBuilderAttributes {
106                visual_id: None,
107                screen_id: None,
108                base_size: None,
109                override_redirect: false,
110                x11_window_types: vec![XWindowType::Normal],
111                embed_window: None,
112            },
113        }
114    }
115}
116
117#[cfg(x11_platform)]
118pub(crate) static X11_BACKEND: Lazy<Mutex<Result<Arc<XConnection>, XNotSupported>>> =
119    Lazy::new(|| Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)));
120
121#[derive(Debug, Clone)]
122pub enum OsError {
123    Misc(&'static str),
124    #[cfg(x11_platform)]
125    XError(Arc<X11Error>),
126    #[cfg(wayland_platform)]
127    WaylandError(Arc<wayland::WaylandError>),
128}
129
130impl fmt::Display for OsError {
131    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
132        match *self {
133            OsError::Misc(e) => _f.pad(e),
134            #[cfg(x11_platform)]
135            OsError::XError(ref e) => fmt::Display::fmt(e, _f),
136            #[cfg(wayland_platform)]
137            OsError::WaylandError(ref e) => fmt::Display::fmt(e, _f),
138        }
139    }
140}
141
142pub(crate) enum Window {
143    #[cfg(x11_platform)]
144    X(x11::Window),
145    #[cfg(wayland_platform)]
146    Wayland(wayland::Window),
147}
148
149#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
150pub struct WindowId(u64);
151
152impl From<WindowId> for u64 {
153    fn from(window_id: WindowId) -> Self {
154        window_id.0
155    }
156}
157
158impl From<u64> for WindowId {
159    fn from(raw_id: u64) -> Self {
160        Self(raw_id)
161    }
162}
163
164impl WindowId {
165    pub const unsafe fn dummy() -> Self {
166        Self(0)
167    }
168}
169
170#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
171pub enum DeviceId {
172    #[cfg(x11_platform)]
173    X(x11::DeviceId),
174    #[cfg(wayland_platform)]
175    Wayland(wayland::DeviceId),
176}
177
178impl DeviceId {
179    pub const unsafe fn dummy() -> Self {
180        #[cfg(wayland_platform)]
181        return DeviceId::Wayland(unsafe { wayland::DeviceId::dummy() });
182        #[cfg(all(not(wayland_platform), x11_platform))]
183        return DeviceId::X(unsafe { x11::DeviceId::dummy() });
184    }
185}
186
187#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
188pub enum MonitorHandle {
189    #[cfg(x11_platform)]
190    X(x11::MonitorHandle),
191    #[cfg(wayland_platform)]
192    Wayland(wayland::MonitorHandle),
193}
194
195/// `x11_or_wayland!(match expr; Enum(foo) => foo.something())`
196/// expands to the equivalent of
197/// ```ignore
198/// match self {
199///    Enum::X(foo) => foo.something(),
200///    Enum::Wayland(foo) => foo.something(),
201/// }
202/// ```
203/// The result can be converted to another enum by adding `; as AnotherEnum`
204macro_rules! x11_or_wayland {
205    (match $what:expr; $enum:ident ( $($c1:tt)* ) => $x:expr; as $enum2:ident ) => {
206        match $what {
207            #[cfg(x11_platform)]
208            $enum::X($($c1)*) => $enum2::X($x),
209            #[cfg(wayland_platform)]
210            $enum::Wayland($($c1)*) => $enum2::Wayland($x),
211        }
212    };
213    (match $what:expr; $enum:ident ( $($c1:tt)* ) => $x:expr) => {
214        match $what {
215            #[cfg(x11_platform)]
216            $enum::X($($c1)*) => $x,
217            #[cfg(wayland_platform)]
218            $enum::Wayland($($c1)*) => $x,
219        }
220    };
221}
222
223impl MonitorHandle {
224    #[inline]
225    pub fn name(&self) -> Option<String> {
226        x11_or_wayland!(match self; MonitorHandle(m) => m.name())
227    }
228
229    #[inline]
230    pub fn native_identifier(&self) -> u32 {
231        x11_or_wayland!(match self; MonitorHandle(m) => m.native_identifier())
232    }
233
234    #[inline]
235    pub fn size(&self) -> PhysicalSize<u32> {
236        x11_or_wayland!(match self; MonitorHandle(m) => m.size())
237    }
238
239    #[inline]
240    pub fn position(&self) -> PhysicalPosition<i32> {
241        x11_or_wayland!(match self; MonitorHandle(m) => m.position())
242    }
243
244    #[inline]
245    pub fn refresh_rate_millihertz(&self) -> Option<u32> {
246        x11_or_wayland!(match self; MonitorHandle(m) => m.refresh_rate_millihertz())
247    }
248
249    #[inline]
250    pub fn scale_factor(&self) -> f64 {
251        x11_or_wayland!(match self; MonitorHandle(m) => m.scale_factor() as _)
252    }
253
254    #[inline]
255    pub fn video_modes(&self) -> Box<dyn Iterator<Item = VideoMode>> {
256        x11_or_wayland!(match self; MonitorHandle(m) => Box::new(m.video_modes()))
257    }
258}
259
260#[derive(Debug, Clone, PartialEq, Eq, Hash)]
261pub enum VideoMode {
262    #[cfg(x11_platform)]
263    X(x11::VideoMode),
264    #[cfg(wayland_platform)]
265    Wayland(wayland::VideoMode),
266}
267
268impl VideoMode {
269    #[inline]
270    pub fn size(&self) -> PhysicalSize<u32> {
271        x11_or_wayland!(match self; VideoMode(m) => m.size())
272    }
273
274    #[inline]
275    pub fn bit_depth(&self) -> u16 {
276        x11_or_wayland!(match self; VideoMode(m) => m.bit_depth())
277    }
278
279    #[inline]
280    pub fn refresh_rate_millihertz(&self) -> u32 {
281        x11_or_wayland!(match self; VideoMode(m) => m.refresh_rate_millihertz())
282    }
283
284    #[inline]
285    pub fn monitor(&self) -> MonitorHandle {
286        x11_or_wayland!(match self; VideoMode(m) => m.monitor(); as MonitorHandle)
287    }
288}
289
290impl Window {
291    #[inline]
292    pub(crate) fn new<T>(
293        window_target: &EventLoopWindowTarget<T>,
294        attribs: WindowAttributes,
295        pl_attribs: PlatformSpecificWindowBuilderAttributes,
296    ) -> Result<Self, RootOsError> {
297        match *window_target {
298            #[cfg(wayland_platform)]
299            EventLoopWindowTarget::Wayland(ref window_target) => {
300                wayland::Window::new(window_target, attribs, pl_attribs).map(Window::Wayland)
301            }
302            #[cfg(x11_platform)]
303            EventLoopWindowTarget::X(ref window_target) => {
304                x11::Window::new(window_target, attribs, pl_attribs).map(Window::X)
305            }
306        }
307    }
308
309    pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Self) + Send + 'static) {
310        f(self)
311    }
312
313    pub(crate) fn maybe_wait_on_main<R: Send>(&self, f: impl FnOnce(&Self) -> R + Send) -> R {
314        f(self)
315    }
316
317    #[inline]
318    pub fn id(&self) -> WindowId {
319        x11_or_wayland!(match self; Window(w) => w.id())
320    }
321
322    #[inline]
323    pub fn set_title(&self, title: &str) {
324        x11_or_wayland!(match self; Window(w) => w.set_title(title));
325    }
326
327    #[inline]
328    pub fn set_transparent(&self, transparent: bool) {
329        x11_or_wayland!(match self; Window(w) => w.set_transparent(transparent));
330    }
331
332    #[inline]
333    pub fn set_blur(&self, blur: bool) {
334        x11_or_wayland!(match self; Window(w) => w.set_blur(blur));
335    }
336
337    #[inline]
338    pub fn set_visible(&self, visible: bool) {
339        x11_or_wayland!(match self; Window(w) => w.set_visible(visible))
340    }
341
342    #[inline]
343    pub fn is_visible(&self) -> Option<bool> {
344        x11_or_wayland!(match self; Window(w) => w.is_visible())
345    }
346
347    #[inline]
348    pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
349        x11_or_wayland!(match self; Window(w) => w.outer_position())
350    }
351
352    #[inline]
353    pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
354        x11_or_wayland!(match self; Window(w) => w.inner_position())
355    }
356
357    #[inline]
358    pub fn set_outer_position(&self, position: Position) {
359        x11_or_wayland!(match self; Window(w) => w.set_outer_position(position))
360    }
361
362    #[inline]
363    pub fn inner_size(&self) -> PhysicalSize<u32> {
364        x11_or_wayland!(match self; Window(w) => w.inner_size())
365    }
366
367    #[inline]
368    pub fn outer_size(&self) -> PhysicalSize<u32> {
369        x11_or_wayland!(match self; Window(w) => w.outer_size())
370    }
371
372    #[inline]
373    pub fn request_inner_size(&self, size: Size) -> Option<PhysicalSize<u32>> {
374        x11_or_wayland!(match self; Window(w) => w.request_inner_size(size))
375    }
376
377    #[inline]
378    pub(crate) fn request_activation_token(&self) -> Result<AsyncRequestSerial, NotSupportedError> {
379        x11_or_wayland!(match self; Window(w) => w.request_activation_token())
380    }
381
382    #[inline]
383    pub fn set_min_inner_size(&self, dimensions: Option<Size>) {
384        x11_or_wayland!(match self; Window(w) => w.set_min_inner_size(dimensions))
385    }
386
387    #[inline]
388    pub fn set_max_inner_size(&self, dimensions: Option<Size>) {
389        x11_or_wayland!(match self; Window(w) => w.set_max_inner_size(dimensions))
390    }
391
392    #[inline]
393    pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
394        x11_or_wayland!(match self; Window(w) => w.resize_increments())
395    }
396
397    #[inline]
398    pub fn set_resize_increments(&self, increments: Option<Size>) {
399        x11_or_wayland!(match self; Window(w) => w.set_resize_increments(increments))
400    }
401
402    #[inline]
403    pub fn set_resizable(&self, resizable: bool) {
404        x11_or_wayland!(match self; Window(w) => w.set_resizable(resizable))
405    }
406
407    #[inline]
408    pub fn is_resizable(&self) -> bool {
409        x11_or_wayland!(match self; Window(w) => w.is_resizable())
410    }
411
412    #[inline]
413    pub fn set_enabled_buttons(&self, buttons: WindowButtons) {
414        x11_or_wayland!(match self; Window(w) => w.set_enabled_buttons(buttons))
415    }
416
417    #[inline]
418    pub fn enabled_buttons(&self) -> WindowButtons {
419        x11_or_wayland!(match self; Window(w) => w.enabled_buttons())
420    }
421
422    #[inline]
423    pub fn set_cursor_icon(&self, cursor: CursorIcon) {
424        x11_or_wayland!(match self; Window(w) => w.set_cursor_icon(cursor))
425    }
426
427    #[inline]
428    pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
429        x11_or_wayland!(match self; Window(window) => window.set_cursor_grab(mode))
430    }
431
432    #[inline]
433    pub fn set_cursor_visible(&self, visible: bool) {
434        x11_or_wayland!(match self; Window(window) => window.set_cursor_visible(visible))
435    }
436
437    #[inline]
438    pub fn drag_window(&self) -> Result<(), ExternalError> {
439        x11_or_wayland!(match self; Window(window) => window.drag_window())
440    }
441
442    #[inline]
443    pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
444        x11_or_wayland!(match self; Window(window) => window.drag_resize_window(direction))
445    }
446
447    #[inline]
448    pub fn show_window_menu(&self, position: Position) {
449        x11_or_wayland!(match self; Window(w) => w.show_window_menu(position))
450    }
451
452    #[inline]
453    pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> {
454        x11_or_wayland!(match self; Window(w) => w.set_cursor_hittest(hittest))
455    }
456
457    #[inline]
458    pub fn scale_factor(&self) -> f64 {
459        x11_or_wayland!(match self; Window(w) => w.scale_factor())
460    }
461
462    #[inline]
463    pub fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> {
464        x11_or_wayland!(match self; Window(w) => w.set_cursor_position(position))
465    }
466
467    #[inline]
468    pub fn set_maximized(&self, maximized: bool) {
469        x11_or_wayland!(match self; Window(w) => w.set_maximized(maximized))
470    }
471
472    #[inline]
473    pub fn is_maximized(&self) -> bool {
474        x11_or_wayland!(match self; Window(w) => w.is_maximized())
475    }
476
477    #[inline]
478    pub fn set_minimized(&self, minimized: bool) {
479        x11_or_wayland!(match self; Window(w) => w.set_minimized(minimized))
480    }
481
482    #[inline]
483    pub fn is_minimized(&self) -> Option<bool> {
484        x11_or_wayland!(match self; Window(w) => w.is_minimized())
485    }
486
487    #[inline]
488    pub(crate) fn fullscreen(&self) -> Option<Fullscreen> {
489        x11_or_wayland!(match self; Window(w) => w.fullscreen())
490    }
491
492    #[inline]
493    pub(crate) fn set_fullscreen(&self, monitor: Option<Fullscreen>) {
494        x11_or_wayland!(match self; Window(w) => w.set_fullscreen(monitor))
495    }
496
497    #[inline]
498    pub fn set_decorations(&self, decorations: bool) {
499        x11_or_wayland!(match self; Window(w) => w.set_decorations(decorations))
500    }
501
502    #[inline]
503    pub fn is_decorated(&self) -> bool {
504        x11_or_wayland!(match self; Window(w) => w.is_decorated())
505    }
506
507    #[inline]
508    pub fn set_window_level(&self, level: WindowLevel) {
509        x11_or_wayland!(match self; Window(w) => w.set_window_level(level))
510    }
511
512    #[inline]
513    pub fn set_window_icon(&self, window_icon: Option<Icon>) {
514        x11_or_wayland!(match self; Window(w) => w.set_window_icon(window_icon.map(|icon| icon.inner)))
515    }
516
517    #[inline]
518    pub fn set_ime_cursor_area(&self, position: Position, size: Size) {
519        x11_or_wayland!(match self; Window(w) => w.set_ime_cursor_area(position, size))
520    }
521
522    #[inline]
523    pub fn reset_dead_keys(&self) {
524        common::xkb_state::reset_dead_keys()
525    }
526
527    #[inline]
528    pub fn set_ime_allowed(&self, allowed: bool) {
529        x11_or_wayland!(match self; Window(w) => w.set_ime_allowed(allowed))
530    }
531
532    #[inline]
533    pub fn set_ime_purpose(&self, purpose: ImePurpose) {
534        x11_or_wayland!(match self; Window(w) => w.set_ime_purpose(purpose))
535    }
536
537    #[inline]
538    pub fn focus_window(&self) {
539        x11_or_wayland!(match self; Window(w) => w.focus_window())
540    }
541    pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
542        x11_or_wayland!(match self; Window(w) => w.request_user_attention(request_type))
543    }
544
545    #[inline]
546    pub fn request_redraw(&self) {
547        x11_or_wayland!(match self; Window(w) => w.request_redraw())
548    }
549
550    #[inline]
551    pub fn pre_present_notify(&self) {
552        x11_or_wayland!(match self; Window(w) => w.pre_present_notify())
553    }
554
555    #[inline]
556    pub fn current_monitor(&self) -> Option<MonitorHandle> {
557        Some(x11_or_wayland!(match self; Window(w) => w.current_monitor()?; as MonitorHandle))
558    }
559
560    #[inline]
561    pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
562        match self {
563            #[cfg(x11_platform)]
564            Window::X(ref window) => window
565                .available_monitors()
566                .into_iter()
567                .map(MonitorHandle::X)
568                .collect(),
569            #[cfg(wayland_platform)]
570            Window::Wayland(ref window) => window
571                .available_monitors()
572                .into_iter()
573                .map(MonitorHandle::Wayland)
574                .collect(),
575        }
576    }
577
578    #[inline]
579    pub fn primary_monitor(&self) -> Option<MonitorHandle> {
580        Some(x11_or_wayland!(match self; Window(w) => w.primary_monitor()?; as MonitorHandle))
581    }
582
583    #[cfg(feature = "rwh_04")]
584    #[inline]
585    pub fn raw_window_handle_rwh_04(&self) -> rwh_04::RawWindowHandle {
586        x11_or_wayland!(match self; Window(window) => window.raw_window_handle_rwh_04())
587    }
588
589    #[cfg(feature = "rwh_05")]
590    #[inline]
591    pub fn raw_window_handle_rwh_05(&self) -> rwh_05::RawWindowHandle {
592        x11_or_wayland!(match self; Window(window) => window.raw_window_handle_rwh_05())
593    }
594
595    #[cfg(feature = "rwh_05")]
596    #[inline]
597    pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
598        x11_or_wayland!(match self; Window(window) => window.raw_display_handle_rwh_05())
599    }
600
601    #[cfg(feature = "rwh_06")]
602    #[inline]
603    pub fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
604        x11_or_wayland!(match self; Window(window) => window.raw_window_handle_rwh_06())
605    }
606
607    #[cfg(feature = "rwh_06")]
608    #[inline]
609    pub fn raw_display_handle_rwh_06(
610        &self,
611    ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
612        x11_or_wayland!(match self; Window(window) => window.raw_display_handle_rwh_06())
613    }
614
615    #[inline]
616    pub fn set_theme(&self, theme: Option<Theme>) {
617        x11_or_wayland!(match self; Window(window) => window.set_theme(theme))
618    }
619
620    #[inline]
621    pub fn theme(&self) -> Option<Theme> {
622        x11_or_wayland!(match self; Window(window) => window.theme())
623    }
624
625    pub fn set_content_protected(&self, protected: bool) {
626        x11_or_wayland!(match self; Window(window) => window.set_content_protected(protected))
627    }
628
629    #[inline]
630    pub fn has_focus(&self) -> bool {
631        x11_or_wayland!(match self; Window(window) => window.has_focus())
632    }
633
634    pub fn title(&self) -> String {
635        x11_or_wayland!(match self; Window(window) => window.title())
636    }
637}
638
639#[derive(Debug, Clone, Eq, PartialEq, Hash)]
640pub struct KeyEventExtra {
641    pub key_without_modifiers: Key,
642    pub text_with_all_modifiers: Option<SmolStr>,
643}
644
645impl KeyEventExtModifierSupplement for KeyEvent {
646    #[inline]
647    fn text_with_all_modifiers(&self) -> Option<&str> {
648        self.platform_specific
649            .text_with_all_modifiers
650            .as_ref()
651            .map(|s| s.as_str())
652    }
653
654    #[inline]
655    fn key_without_modifiers(&self) -> Key {
656        self.platform_specific.key_without_modifiers.clone()
657    }
658}
659
660impl PhysicalKeyExtScancode for PhysicalKey {
661    fn from_scancode(scancode: u32) -> PhysicalKey {
662        common::keymap::scancode_to_keycode(scancode)
663    }
664
665    fn to_scancode(self) -> Option<u32> {
666        common::keymap::physicalkey_to_scancode(self)
667    }
668}
669
670/// Hooks for X11 errors.
671#[cfg(x11_platform)]
672pub(crate) static mut XLIB_ERROR_HOOKS: Lazy<Mutex<Vec<XlibErrorHook>>> =
673    Lazy::new(|| Mutex::new(Vec::new()));
674
675#[cfg(x11_platform)]
676unsafe extern "C" fn x_error_callback(
677    display: *mut x11::ffi::Display,
678    event: *mut x11::ffi::XErrorEvent,
679) -> c_int {
680    let xconn_lock = X11_BACKEND.lock().unwrap();
681    if let Ok(ref xconn) = *xconn_lock {
682        // Call all the hooks.
683        let mut error_handled = false;
684        for hook in unsafe { XLIB_ERROR_HOOKS.lock() }.unwrap().iter() {
685            error_handled |= hook(display as *mut _, event as *mut _);
686        }
687
688        // `assume_init` is safe here because the array consists of `MaybeUninit` values,
689        // which do not require initialization.
690        let mut buf: [MaybeUninit<c_char>; 1024] = unsafe { MaybeUninit::uninit().assume_init() };
691        unsafe {
692            (xconn.xlib.XGetErrorText)(
693                display,
694                (*event).error_code as c_int,
695                buf.as_mut_ptr() as *mut c_char,
696                buf.len() as c_int,
697            )
698        };
699        let description =
700            unsafe { CStr::from_ptr(buf.as_ptr() as *const c_char) }.to_string_lossy();
701
702        let error = unsafe {
703            XError {
704                description: description.into_owned(),
705                error_code: (*event).error_code,
706                request_code: (*event).request_code,
707                minor_code: (*event).minor_code,
708            }
709        };
710
711        // Don't log error.
712        if !error_handled {
713            error!("X11 error: {:#?}", error);
714            // XXX only update the error, if it wasn't handled by any of the hooks.
715            *xconn.latest_error.lock().unwrap() = Some(error);
716        }
717    }
718    // Fun fact: this return value is completely ignored.
719    0
720}
721
722pub enum EventLoop<T: 'static> {
723    #[cfg(wayland_platform)]
724    Wayland(Box<wayland::EventLoop<T>>),
725    #[cfg(x11_platform)]
726    X(x11::EventLoop<T>),
727}
728
729pub enum EventLoopProxy<T: 'static> {
730    #[cfg(x11_platform)]
731    X(x11::EventLoopProxy<T>),
732    #[cfg(wayland_platform)]
733    Wayland(wayland::EventLoopProxy<T>),
734}
735
736impl<T: 'static> Clone for EventLoopProxy<T> {
737    fn clone(&self) -> Self {
738        x11_or_wayland!(match self; EventLoopProxy(proxy) => proxy.clone(); as EventLoopProxy)
739    }
740}
741
742impl<T: 'static> EventLoop<T> {
743    pub(crate) fn new(
744        attributes: &PlatformSpecificEventLoopAttributes,
745    ) -> Result<Self, EventLoopError> {
746        if !attributes.any_thread && !is_main_thread() {
747            panic!(
748                "Initializing the event loop outside of the main thread is a significant \
749                 cross-platform compatibility hazard. If you absolutely need to create an \
750                 EventLoop on a different thread, you can use the \
751                 `EventLoopBuilderExtUnix::any_thread` function."
752            );
753        }
754
755        // NOTE: Wayland first because of X11 could be present under Wayland as well. Empty
756        // variables are also treated as not set.
757        let backend = match (
758            attributes.forced_backend,
759            env::var("WAYLAND_DISPLAY")
760                .map(|var| !var.is_empty())
761                .unwrap_or(false),
762            env::var("DISPLAY")
763                .map(|var| !var.is_empty())
764                .unwrap_or(false),
765        ) {
766            // User is forcing a backend.
767            (Some(backend), _, _) => backend,
768            // Wayland is present.
769            #[cfg(wayland_platform)]
770            (None, true, _) => Backend::Wayland,
771            // X11 is present.
772            #[cfg(x11_platform)]
773            (None, _, true) => Backend::X,
774            // No backend is present.
775            _ => {
776                return Err(EventLoopError::Os(os_error!(OsError::Misc(
777                    "neither WAYLAND_DISPLAY nor DISPLAY is set."
778                ))));
779            }
780        };
781
782        // Create the display based on the backend.
783        match backend {
784            #[cfg(wayland_platform)]
785            Backend::Wayland => EventLoop::new_wayland_any_thread().map_err(Into::into),
786            #[cfg(x11_platform)]
787            Backend::X => Ok(EventLoop::new_x11_any_thread().unwrap()),
788        }
789    }
790
791    #[cfg(wayland_platform)]
792    fn new_wayland_any_thread() -> Result<EventLoop<T>, EventLoopError> {
793        wayland::EventLoop::new().map(|evlp| EventLoop::Wayland(Box::new(evlp)))
794    }
795
796    #[cfg(x11_platform)]
797    fn new_x11_any_thread() -> Result<EventLoop<T>, XNotSupported> {
798        let xconn = match X11_BACKEND.lock().unwrap().as_ref() {
799            Ok(xconn) => xconn.clone(),
800            Err(err) => return Err(err.clone()),
801        };
802
803        Ok(EventLoop::X(x11::EventLoop::new(xconn)))
804    }
805
806    pub fn create_proxy(&self) -> EventLoopProxy<T> {
807        x11_or_wayland!(match self; EventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy)
808    }
809
810    pub fn run<F>(mut self, callback: F) -> Result<(), EventLoopError>
811    where
812        F: FnMut(crate::event::Event<T>, &RootELW<T>),
813    {
814        self.run_on_demand(callback)
815    }
816
817    pub fn run_on_demand<F>(&mut self, callback: F) -> Result<(), EventLoopError>
818    where
819        F: FnMut(crate::event::Event<T>, &RootELW<T>),
820    {
821        x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_on_demand(callback))
822    }
823
824    pub fn pump_events<F>(&mut self, timeout: Option<Duration>, callback: F) -> PumpStatus
825    where
826        F: FnMut(crate::event::Event<T>, &RootELW<T>),
827    {
828        x11_or_wayland!(match self; EventLoop(evlp) => evlp.pump_events(timeout, callback))
829    }
830
831    pub fn window_target(&self) -> &crate::event_loop::EventLoopWindowTarget<T> {
832        x11_or_wayland!(match self; EventLoop(evlp) => evlp.window_target())
833    }
834}
835
836impl<T> AsFd for EventLoop<T> {
837    fn as_fd(&self) -> BorrowedFd<'_> {
838        x11_or_wayland!(match self; EventLoop(evlp) => evlp.as_fd())
839    }
840}
841
842impl<T> AsRawFd for EventLoop<T> {
843    fn as_raw_fd(&self) -> RawFd {
844        x11_or_wayland!(match self; EventLoop(evlp) => evlp.as_raw_fd())
845    }
846}
847
848impl<T: 'static> EventLoopProxy<T> {
849    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
850        x11_or_wayland!(match self; EventLoopProxy(proxy) => proxy.send_event(event))
851    }
852}
853
854pub enum EventLoopWindowTarget<T> {
855    #[cfg(wayland_platform)]
856    Wayland(wayland::EventLoopWindowTarget<T>),
857    #[cfg(x11_platform)]
858    X(x11::EventLoopWindowTarget<T>),
859}
860
861impl<T> EventLoopWindowTarget<T> {
862    #[inline]
863    pub fn is_wayland(&self) -> bool {
864        match *self {
865            #[cfg(wayland_platform)]
866            EventLoopWindowTarget::Wayland(_) => true,
867            #[cfg(x11_platform)]
868            _ => false,
869        }
870    }
871
872    #[inline]
873    pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
874        match *self {
875            #[cfg(wayland_platform)]
876            EventLoopWindowTarget::Wayland(ref evlp) => evlp
877                .available_monitors()
878                .map(MonitorHandle::Wayland)
879                .collect(),
880            #[cfg(x11_platform)]
881            EventLoopWindowTarget::X(ref evlp) => {
882                evlp.available_monitors().map(MonitorHandle::X).collect()
883            }
884        }
885    }
886
887    #[inline]
888    pub fn primary_monitor(&self) -> Option<MonitorHandle> {
889        Some(
890            x11_or_wayland!(match self; EventLoopWindowTarget(evlp) => evlp.primary_monitor()?; as MonitorHandle),
891        )
892    }
893
894    #[inline]
895    pub fn listen_device_events(&self, allowed: DeviceEvents) {
896        x11_or_wayland!(match self; Self(evlp) => evlp.listen_device_events(allowed))
897    }
898
899    #[cfg(feature = "rwh_05")]
900    #[inline]
901    pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
902        x11_or_wayland!(match self; Self(evlp) => evlp.raw_display_handle_rwh_05())
903    }
904
905    #[cfg(feature = "rwh_06")]
906    #[inline]
907    pub fn raw_display_handle_rwh_06(
908        &self,
909    ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
910        x11_or_wayland!(match self; Self(evlp) => evlp.raw_display_handle_rwh_06())
911    }
912
913    pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
914        x11_or_wayland!(match self; Self(evlp) => evlp.set_control_flow(control_flow))
915    }
916
917    pub(crate) fn control_flow(&self) -> ControlFlow {
918        x11_or_wayland!(match self; Self(evlp) => evlp.control_flow())
919    }
920
921    pub(crate) fn exit(&self) {
922        x11_or_wayland!(match self; Self(evlp) => evlp.exit())
923    }
924
925    pub(crate) fn exiting(&self) -> bool {
926        x11_or_wayland!(match self; Self(evlp) => evlp.exiting())
927    }
928
929    fn set_exit_code(&self, code: i32) {
930        x11_or_wayland!(match self; Self(evlp) => evlp.set_exit_code(code))
931    }
932
933    fn exit_code(&self) -> Option<i32> {
934        x11_or_wayland!(match self; Self(evlp) => evlp.exit_code())
935    }
936}
937
938/// Returns the minimum `Option<Duration>`, taking into account that `None`
939/// equates to an infinite timeout, not a zero timeout (so can't just use
940/// `Option::min`)
941fn min_timeout(a: Option<Duration>, b: Option<Duration>) -> Option<Duration> {
942    a.map_or(b, |a_timeout| {
943        b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout)))
944    })
945}
946
947#[cfg(target_os = "linux")]
948fn is_main_thread() -> bool {
949    rustix::thread::gettid() == rustix::process::getpid()
950}
951
952#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
953fn is_main_thread() -> bool {
954    use libc::pthread_main_np;
955
956    unsafe { pthread_main_np() == 1 }
957}
958
959#[cfg(target_os = "netbsd")]
960fn is_main_thread() -> bool {
961    std::thread::current().name() == Some("main")
962}
963
964pub struct Menu(usize);
965
966impl Menu {
967    pub fn new() -> Menu {
968        Menu(0)
969    }
970
971    pub fn new_for_popup() -> Menu {
972        Menu(0)
973    }
974
975    pub fn add_dropdown(&mut self, menu: Menu, text: &str, enabled: bool) {}
976
977    pub fn add_item(&mut self, id: u32, text: &str, selected: Option<bool>, enabled: bool) {}
978
979    pub fn add_separator(&mut self) {}
980}