winit/platform_impl/linux/x11/
mod.rs

1use std::cell::{Cell, RefCell};
2use std::collections::{HashMap, HashSet, VecDeque};
3use std::ffi::CStr;
4use std::marker::PhantomData;
5use std::mem::MaybeUninit;
6use std::ops::Deref;
7use std::os::raw::*;
8use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
9use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
10use std::sync::{Arc, Weak};
11use std::time::{Duration, Instant};
12use std::{fmt, ptr, slice, str};
13
14use calloop::generic::Generic;
15use calloop::ping::Ping;
16use calloop::{EventLoop as Loop, Readiness};
17use libc::{setlocale, LC_CTYPE};
18use tracing::warn;
19
20use x11rb::connection::RequestConnection;
21use x11rb::errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError};
22use x11rb::protocol::xinput::{self, ConnectionExt as _};
23use x11rb::protocol::xkb;
24use x11rb::protocol::xproto::{self, ConnectionExt as _};
25use x11rb::x11_utils::X11Error as LogicalError;
26use x11rb::xcb_ffi::ReplyOrIdError;
27
28use crate::error::{EventLoopError, OsError as RootOsError};
29use crate::event::{Event, StartCause, WindowEvent};
30use crate::event_loop::{ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents, EventLoopClosed};
31use crate::platform::pump_events::PumpStatus;
32use crate::platform_impl::common::xkb::Context;
33use crate::platform_impl::platform::{min_timeout, WindowId};
34use crate::platform_impl::{
35    ActiveEventLoop as PlatformActiveEventLoop, OsError, PlatformCustomCursor,
36};
37use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource, WindowAttributes};
38
39mod activation;
40mod atoms;
41mod dnd;
42mod event_processor;
43pub mod ffi;
44mod ime;
45mod monitor;
46mod util;
47mod window;
48mod xdisplay;
49mod xsettings;
50
51pub use util::CustomCursor;
52
53use atoms::*;
54use dnd::{Dnd, DndState};
55use event_processor::{EventProcessor, MAX_MOD_REPLAY_LEN};
56use ime::{Ime, ImeCreationError, ImeReceiver, ImeRequest, ImeSender};
57pub(crate) use monitor::{MonitorHandle, VideoModeHandle};
58use window::UnownedWindow;
59pub(crate) use xdisplay::{XConnection, XError, XNotSupported};
60
61// Xinput constants not defined in x11rb
62const ALL_DEVICES: u16 = 0;
63const ALL_MASTER_DEVICES: u16 = 1;
64const ICONIC_STATE: u32 = 3;
65
66/// The underlying x11rb connection that we are using.
67type X11rbConnection = x11rb::xcb_ffi::XCBConnection;
68
69type X11Source = Generic<BorrowedFd<'static>>;
70
71struct WakeSender<T> {
72    sender: Sender<T>,
73    waker: Ping,
74}
75
76impl<T> Clone for WakeSender<T> {
77    fn clone(&self) -> Self {
78        Self { sender: self.sender.clone(), waker: self.waker.clone() }
79    }
80}
81
82impl<T> WakeSender<T> {
83    pub fn send(&self, t: T) -> Result<(), EventLoopClosed<T>> {
84        let res = self.sender.send(t).map_err(|e| EventLoopClosed(e.0));
85        if res.is_ok() {
86            self.waker.ping();
87        }
88        res
89    }
90}
91
92struct PeekableReceiver<T> {
93    recv: Receiver<T>,
94    first: Option<T>,
95}
96
97impl<T> PeekableReceiver<T> {
98    pub fn from_recv(recv: Receiver<T>) -> Self {
99        Self { recv, first: None }
100    }
101
102    pub fn has_incoming(&mut self) -> bool {
103        if self.first.is_some() {
104            return true;
105        }
106
107        match self.recv.try_recv() {
108            Ok(v) => {
109                self.first = Some(v);
110                true
111            },
112            Err(TryRecvError::Empty) => false,
113            Err(TryRecvError::Disconnected) => {
114                warn!("Channel was disconnected when checking incoming");
115                false
116            },
117        }
118    }
119
120    pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
121        if let Some(first) = self.first.take() {
122            return Ok(first);
123        }
124        self.recv.try_recv()
125    }
126}
127
128pub struct ActiveEventLoop {
129    xconn: Arc<XConnection>,
130    wm_delete_window: xproto::Atom,
131    net_wm_ping: xproto::Atom,
132    ime_sender: ImeSender,
133    control_flow: Cell<ControlFlow>,
134    exit: Cell<Option<i32>>,
135    root: xproto::Window,
136    ime: Option<RefCell<Ime>>,
137    windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
138    redraw_sender: WakeSender<WindowId>,
139    activation_sender: WakeSender<ActivationToken>,
140    device_events: Cell<DeviceEvents>,
141}
142
143pub struct EventLoop<T: 'static> {
144    loop_running: bool,
145    event_loop: Loop<'static, EventLoopState>,
146    waker: calloop::ping::Ping,
147    event_processor: EventProcessor,
148    redraw_receiver: PeekableReceiver<WindowId>,
149    user_receiver: PeekableReceiver<T>,
150    activation_receiver: PeekableReceiver<ActivationToken>,
151    user_sender: Sender<T>,
152
153    /// The current state of the event loop.
154    state: EventLoopState,
155}
156
157type ActivationToken = (WindowId, crate::event_loop::AsyncRequestSerial);
158
159struct EventLoopState {
160    /// The latest readiness state for the x11 file descriptor
161    x11_readiness: Readiness,
162}
163
164pub struct EventLoopProxy<T: 'static> {
165    user_sender: WakeSender<T>,
166}
167
168impl<T: 'static> Clone for EventLoopProxy<T> {
169    fn clone(&self) -> Self {
170        EventLoopProxy { user_sender: self.user_sender.clone() }
171    }
172}
173
174impl<T: 'static> EventLoop<T> {
175    pub(crate) fn new(xconn: Arc<XConnection>) -> EventLoop<T> {
176        let root = xconn.default_root().root;
177        let atoms = xconn.atoms();
178
179        let wm_delete_window = atoms[WM_DELETE_WINDOW];
180        let net_wm_ping = atoms[_NET_WM_PING];
181
182        let dnd = Dnd::new(Arc::clone(&xconn))
183            .expect("Failed to call XInternAtoms when initializing drag and drop");
184
185        let (ime_sender, ime_receiver) = mpsc::channel();
186        let (ime_event_sender, ime_event_receiver) = mpsc::channel();
187        // Input methods will open successfully without setting the locale, but it won't be
188        // possible to actually commit pre-edit sequences.
189        unsafe {
190            // Remember default locale to restore it if target locale is unsupported
191            // by Xlib
192            let default_locale = setlocale(LC_CTYPE, ptr::null());
193            setlocale(LC_CTYPE, b"\0".as_ptr() as *const _);
194
195            // Check if set locale is supported by Xlib.
196            // If not, calls to some Xlib functions like `XSetLocaleModifiers`
197            // will fail.
198            let locale_supported = (xconn.xlib.XSupportsLocale)() == 1;
199            if !locale_supported {
200                let unsupported_locale = setlocale(LC_CTYPE, ptr::null());
201                warn!(
202                    "Unsupported locale \"{}\". Restoring default locale \"{}\".",
203                    CStr::from_ptr(unsupported_locale).to_string_lossy(),
204                    CStr::from_ptr(default_locale).to_string_lossy()
205                );
206                // Restore default locale
207                setlocale(LC_CTYPE, default_locale);
208            }
209        }
210
211        let ime = Ime::new(Arc::clone(&xconn), ime_event_sender);
212        if let Err(ImeCreationError::OpenFailure(state)) = ime.as_ref() {
213            warn!("Failed to open input method: {state:#?}");
214        } else if let Err(err) = ime.as_ref() {
215            warn!("Failed to set input method destruction callback: {err:?}");
216        }
217
218        let ime = ime.ok().map(RefCell::new);
219
220        let randr_event_offset =
221            xconn.select_xrandr_input(root).expect("Failed to query XRandR extension");
222
223        let xi2ext = xconn
224            .xcb_connection()
225            .extension_information(xinput::X11_EXTENSION_NAME)
226            .expect("Failed to query XInput extension")
227            .expect("X server missing XInput extension");
228        let xkbext = xconn
229            .xcb_connection()
230            .extension_information(xkb::X11_EXTENSION_NAME)
231            .expect("Failed to query XKB extension")
232            .expect("X server missing XKB extension");
233
234        // Check for XInput2 support.
235        xconn
236            .xcb_connection()
237            .xinput_xi_query_version(2, 3)
238            .expect("Failed to send XInput2 query version request")
239            .reply()
240            .expect("Error while checking for XInput2 query version reply");
241
242        xconn.update_cached_wm_info(root);
243
244        // Create an event loop.
245        let event_loop =
246            Loop::<EventLoopState>::try_new().expect("Failed to initialize the event loop");
247        let handle = event_loop.handle();
248
249        // Create the X11 event dispatcher.
250        let source = X11Source::new(
251            // SAFETY: xcb owns the FD and outlives the source.
252            unsafe { BorrowedFd::borrow_raw(xconn.xcb_connection().as_raw_fd()) },
253            calloop::Interest::READ,
254            calloop::Mode::Level,
255        );
256        handle
257            .insert_source(source, |readiness, _, state| {
258                state.x11_readiness = readiness;
259                Ok(calloop::PostAction::Continue)
260            })
261            .expect("Failed to register the X11 event dispatcher");
262
263        let (waker, waker_source) =
264            calloop::ping::make_ping().expect("Failed to create event loop waker");
265        event_loop
266            .handle()
267            .insert_source(waker_source, move |_, _, _| {
268                // No extra handling is required, we just need to wake-up.
269            })
270            .expect("Failed to register the event loop waker source");
271
272        // Create a channel for handling redraw requests.
273        let (redraw_sender, redraw_channel) = mpsc::channel();
274
275        // Create a channel for sending activation tokens.
276        let (activation_token_sender, activation_token_channel) = mpsc::channel();
277
278        // Create a channel for sending user events.
279        let (user_sender, user_channel) = mpsc::channel();
280
281        let xkb_context =
282            Context::from_x11_xkb(xconn.xcb_connection().get_raw_xcb_connection()).unwrap();
283
284        let mut xmodmap = util::ModifierKeymap::new();
285        xmodmap.reload_from_x_connection(&xconn);
286
287        let window_target = ActiveEventLoop {
288            ime,
289            root,
290            control_flow: Cell::new(ControlFlow::default()),
291            exit: Cell::new(None),
292            windows: Default::default(),
293            ime_sender,
294            xconn,
295            wm_delete_window,
296            net_wm_ping,
297            redraw_sender: WakeSender {
298                sender: redraw_sender, // not used again so no clone
299                waker: waker.clone(),
300            },
301            activation_sender: WakeSender {
302                sender: activation_token_sender, // not used again so no clone
303                waker: waker.clone(),
304            },
305            device_events: Default::default(),
306        };
307
308        // Set initial device event filter.
309        window_target.update_listen_device_events(true);
310
311        let root_window_target =
312            RootAEL { p: PlatformActiveEventLoop::X(window_target), _marker: PhantomData };
313
314        let event_processor = EventProcessor {
315            target: root_window_target,
316            dnd,
317            devices: Default::default(),
318            randr_event_offset,
319            ime_receiver,
320            ime_event_receiver,
321            xi2ext,
322            xfiltered_modifiers: VecDeque::with_capacity(MAX_MOD_REPLAY_LEN),
323            xmodmap,
324            xkbext,
325            xkb_context,
326            num_touch: 0,
327            held_key_press: None,
328            first_touch: None,
329            active_window: None,
330            modifiers: Default::default(),
331            is_composing: false,
332        };
333
334        // Register for device hotplug events
335        // (The request buffer is flushed during `init_device`)
336        let xconn = &EventProcessor::window_target(&event_processor.target).xconn;
337
338        xconn
339            .select_xinput_events(
340                root,
341                ALL_DEVICES,
342                x11rb::protocol::xinput::XIEventMask::HIERARCHY,
343            )
344            .expect_then_ignore_error("Failed to register for XInput2 device hotplug events");
345
346        xconn
347            .select_xkb_events(
348                0x100, // Use the "core keyboard device"
349                xkb::EventType::NEW_KEYBOARD_NOTIFY
350                    | xkb::EventType::MAP_NOTIFY
351                    | xkb::EventType::STATE_NOTIFY,
352            )
353            .unwrap();
354
355        event_processor.init_device(ALL_DEVICES);
356
357        EventLoop {
358            loop_running: false,
359            event_loop,
360            waker,
361            event_processor,
362            redraw_receiver: PeekableReceiver::from_recv(redraw_channel),
363            activation_receiver: PeekableReceiver::from_recv(activation_token_channel),
364            user_receiver: PeekableReceiver::from_recv(user_channel),
365            user_sender,
366            state: EventLoopState { x11_readiness: Readiness::EMPTY },
367        }
368    }
369
370    pub fn create_proxy(&self) -> EventLoopProxy<T> {
371        EventLoopProxy {
372            user_sender: WakeSender { sender: self.user_sender.clone(), waker: self.waker.clone() },
373        }
374    }
375
376    pub(crate) fn window_target(&self) -> &RootAEL {
377        &self.event_processor.target
378    }
379
380    pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
381    where
382        F: FnMut(Event<T>, &RootAEL),
383    {
384        let exit = loop {
385            match self.pump_events(None, &mut event_handler) {
386                PumpStatus::Exit(0) => {
387                    break Ok(());
388                },
389                PumpStatus::Exit(code) => {
390                    break Err(EventLoopError::ExitFailure(code));
391                },
392                _ => {
393                    continue;
394                },
395            }
396        };
397
398        // Applications aren't allowed to carry windows between separate
399        // `run_on_demand` calls but if they have only just dropped their
400        // windows we need to make sure those last requests are sent to the
401        // X Server.
402        let wt = EventProcessor::window_target(&self.event_processor.target);
403        wt.x_connection().sync_with_server().map_err(|x_err| {
404            EventLoopError::Os(os_error!(OsError::XError(Arc::new(X11Error::Xlib(x_err)))))
405        })?;
406
407        exit
408    }
409
410    pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus
411    where
412        F: FnMut(Event<T>, &RootAEL),
413    {
414        if !self.loop_running {
415            self.loop_running = true;
416
417            // run the initial loop iteration
418            self.single_iteration(&mut callback, StartCause::Init);
419        }
420
421        // Consider the possibility that the `StartCause::Init` iteration could
422        // request to Exit.
423        if !self.exiting() {
424            self.poll_events_with_timeout(timeout, &mut callback);
425        }
426        if let Some(code) = self.exit_code() {
427            self.loop_running = false;
428
429            callback(Event::LoopExiting, self.window_target());
430
431            PumpStatus::Exit(code)
432        } else {
433            PumpStatus::Continue
434        }
435    }
436
437    fn has_pending(&mut self) -> bool {
438        self.event_processor.poll()
439            || self.user_receiver.has_incoming()
440            || self.redraw_receiver.has_incoming()
441    }
442
443    pub fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F)
444    where
445        F: FnMut(Event<T>, &RootAEL),
446    {
447        let start = Instant::now();
448
449        let has_pending = self.has_pending();
450
451        timeout = if has_pending {
452            // If we already have work to do then we don't want to block on the next poll.
453            Some(Duration::ZERO)
454        } else {
455            let control_flow_timeout = match self.control_flow() {
456                ControlFlow::Wait => None,
457                ControlFlow::Poll => Some(Duration::ZERO),
458                ControlFlow::WaitUntil(wait_deadline) => {
459                    Some(wait_deadline.saturating_duration_since(start))
460                },
461            };
462
463            min_timeout(control_flow_timeout, timeout)
464        };
465
466        self.state.x11_readiness = Readiness::EMPTY;
467        if let Err(error) =
468            self.event_loop.dispatch(timeout, &mut self.state).map_err(std::io::Error::from)
469        {
470            tracing::error!("Failed to poll for events: {error:?}");
471            let exit_code = error.raw_os_error().unwrap_or(1);
472            self.set_exit_code(exit_code);
473            return;
474        }
475
476        // NB: `StartCause::Init` is handled as a special case and doesn't need
477        // to be considered here
478        let cause = match self.control_flow() {
479            ControlFlow::Poll => StartCause::Poll,
480            ControlFlow::Wait => StartCause::WaitCancelled { start, requested_resume: None },
481            ControlFlow::WaitUntil(deadline) => {
482                if Instant::now() < deadline {
483                    StartCause::WaitCancelled { start, requested_resume: Some(deadline) }
484                } else {
485                    StartCause::ResumeTimeReached { start, requested_resume: deadline }
486                }
487            },
488        };
489
490        // False positive / spurious wake ups could lead to us spamming
491        // redundant iterations of the event loop with no new events to
492        // dispatch.
493        //
494        // If there's no readable event source then we just double check if we
495        // have any pending `_receiver` events and if not we return without
496        // running a loop iteration.
497        // If we don't have any pending `_receiver`
498        if !self.has_pending()
499            && !matches!(&cause, StartCause::ResumeTimeReached { .. } | StartCause::Poll)
500            && timeout.is_none()
501        {
502            return;
503        }
504
505        self.single_iteration(&mut callback, cause);
506    }
507
508    fn single_iteration<F>(&mut self, callback: &mut F, cause: StartCause)
509    where
510        F: FnMut(Event<T>, &RootAEL),
511    {
512        callback(Event::NewEvents(cause), &self.event_processor.target);
513
514        // NB: For consistency all platforms must emit a 'resumed' event even though X11
515        // applications don't themselves have a formal suspend/resume lifecycle.
516        if cause == StartCause::Init {
517            callback(Event::Resumed, &self.event_processor.target);
518        }
519
520        // Process all pending events
521        self.drain_events(callback);
522
523        // Empty activation tokens.
524        while let Ok((window_id, serial)) = self.activation_receiver.try_recv() {
525            let token = self.event_processor.with_window(window_id.0 as xproto::Window, |window| {
526                window.generate_activation_token()
527            });
528
529            match token {
530                Some(Ok(token)) => {
531                    let event = Event::WindowEvent {
532                        window_id: crate::window::WindowId(window_id),
533                        event: WindowEvent::ActivationTokenDone {
534                            serial,
535                            token: crate::window::ActivationToken::from_raw(token),
536                        },
537                    };
538                    callback(event, &self.event_processor.target)
539                },
540                Some(Err(e)) => {
541                    tracing::error!("Failed to get activation token: {}", e);
542                },
543                None => {},
544            }
545        }
546
547        // Empty the user event buffer
548        {
549            while let Ok(event) = self.user_receiver.try_recv() {
550                callback(Event::UserEvent(event), &self.event_processor.target);
551            }
552        }
553
554        // Empty the redraw requests
555        {
556            let mut windows = HashSet::new();
557
558            while let Ok(window_id) = self.redraw_receiver.try_recv() {
559                windows.insert(window_id);
560            }
561
562            for window_id in windows {
563                let window_id = crate::window::WindowId(window_id);
564                callback(
565                    Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested },
566                    &self.event_processor.target,
567                );
568            }
569        }
570
571        // This is always the last event we dispatch before poll again
572        {
573            callback(Event::AboutToWait, &self.event_processor.target);
574        }
575    }
576
577    fn drain_events<F>(&mut self, callback: &mut F)
578    where
579        F: FnMut(Event<T>, &RootAEL),
580    {
581        let mut xev = MaybeUninit::uninit();
582
583        while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
584            let mut xev = unsafe { xev.assume_init() };
585            self.event_processor.process_event(&mut xev, |window_target, event| {
586                if let Event::WindowEvent {
587                    window_id: crate::window::WindowId(wid),
588                    event: WindowEvent::RedrawRequested,
589                } = event
590                {
591                    let window_target = EventProcessor::window_target(window_target);
592                    window_target.redraw_sender.send(wid).unwrap();
593                } else {
594                    callback(event, window_target);
595                }
596            });
597        }
598    }
599
600    fn control_flow(&self) -> ControlFlow {
601        let window_target = EventProcessor::window_target(&self.event_processor.target);
602        window_target.control_flow()
603    }
604
605    fn exiting(&self) -> bool {
606        let window_target = EventProcessor::window_target(&self.event_processor.target);
607        window_target.exiting()
608    }
609
610    fn set_exit_code(&self, code: i32) {
611        let window_target = EventProcessor::window_target(&self.event_processor.target);
612        window_target.set_exit_code(code);
613    }
614
615    fn exit_code(&self) -> Option<i32> {
616        let window_target = EventProcessor::window_target(&self.event_processor.target);
617        window_target.exit_code()
618    }
619}
620
621impl<T> AsFd for EventLoop<T> {
622    fn as_fd(&self) -> BorrowedFd<'_> {
623        self.event_loop.as_fd()
624    }
625}
626
627impl<T> AsRawFd for EventLoop<T> {
628    fn as_raw_fd(&self) -> RawFd {
629        self.event_loop.as_raw_fd()
630    }
631}
632
633impl ActiveEventLoop {
634    /// Returns the `XConnection` of this events loop.
635    #[inline]
636    pub(crate) fn x_connection(&self) -> &Arc<XConnection> {
637        &self.xconn
638    }
639
640    pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
641        self.xconn.available_monitors().into_iter().flatten()
642    }
643
644    pub fn primary_monitor(&self) -> Option<MonitorHandle> {
645        self.xconn.primary_monitor().ok()
646    }
647
648    pub(crate) fn create_custom_cursor(&self, cursor: CustomCursorSource) -> RootCustomCursor {
649        RootCustomCursor { inner: PlatformCustomCursor::X(CustomCursor::new(self, cursor.inner)) }
650    }
651
652    pub fn listen_device_events(&self, allowed: DeviceEvents) {
653        self.device_events.set(allowed);
654    }
655
656    /// Update the device event based on window focus.
657    pub fn update_listen_device_events(&self, focus: bool) {
658        let device_events = self.device_events.get() == DeviceEvents::Always
659            || (focus && self.device_events.get() == DeviceEvents::WhenFocused);
660
661        let mut mask = xinput::XIEventMask::from(0u32);
662        if device_events {
663            mask = xinput::XIEventMask::RAW_MOTION
664                | xinput::XIEventMask::RAW_BUTTON_PRESS
665                | xinput::XIEventMask::RAW_BUTTON_RELEASE
666                | xinput::XIEventMask::RAW_KEY_PRESS
667                | xinput::XIEventMask::RAW_KEY_RELEASE;
668        }
669
670        self.xconn
671            .select_xinput_events(self.root, ALL_MASTER_DEVICES, mask)
672            .expect_then_ignore_error("Failed to update device event filter");
673    }
674
675    #[cfg(feature = "rwh_05")]
676    pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
677        let mut display_handle = rwh_05::XlibDisplayHandle::empty();
678        display_handle.display = self.xconn.display as *mut _;
679        display_handle.screen = self.xconn.default_screen_index() as c_int;
680        display_handle.into()
681    }
682
683    #[cfg(feature = "rwh_06")]
684    pub fn raw_display_handle_rwh_06(
685        &self,
686    ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
687        let display_handle = rwh_06::XlibDisplayHandle::new(
688            // SAFETY: display will never be null
689            Some(
690                std::ptr::NonNull::new(self.xconn.display as *mut _)
691                    .expect("X11 display should never be null"),
692            ),
693            self.xconn.default_screen_index() as c_int,
694        );
695        Ok(display_handle.into())
696    }
697
698    pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
699        self.control_flow.set(control_flow)
700    }
701
702    pub(crate) fn control_flow(&self) -> ControlFlow {
703        self.control_flow.get()
704    }
705
706    pub(crate) fn exit(&self) {
707        self.exit.set(Some(0))
708    }
709
710    pub(crate) fn clear_exit(&self) {
711        self.exit.set(None)
712    }
713
714    pub(crate) fn exiting(&self) -> bool {
715        self.exit.get().is_some()
716    }
717
718    pub(crate) fn set_exit_code(&self, code: i32) {
719        self.exit.set(Some(code))
720    }
721
722    pub(crate) fn exit_code(&self) -> Option<i32> {
723        self.exit.get()
724    }
725}
726
727impl<T: 'static> EventLoopProxy<T> {
728    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
729        self.user_sender.send(event).map_err(|e| EventLoopClosed(e.0))
730    }
731}
732
733struct DeviceInfo<'a> {
734    xconn: &'a XConnection,
735    info: *const ffi::XIDeviceInfo,
736    count: usize,
737}
738
739impl<'a> DeviceInfo<'a> {
740    fn get(xconn: &'a XConnection, device: c_int) -> Option<Self> {
741        unsafe {
742            let mut count = 0;
743            let info = (xconn.xinput2.XIQueryDevice)(xconn.display, device, &mut count);
744            xconn.check_errors().ok()?;
745
746            if info.is_null() || count == 0 {
747                None
748            } else {
749                Some(DeviceInfo { xconn, info, count: count as usize })
750            }
751        }
752    }
753}
754
755impl Drop for DeviceInfo<'_> {
756    fn drop(&mut self) {
757        assert!(!self.info.is_null());
758        unsafe { (self.xconn.xinput2.XIFreeDeviceInfo)(self.info as *mut _) };
759    }
760}
761
762impl Deref for DeviceInfo<'_> {
763    type Target = [ffi::XIDeviceInfo];
764
765    fn deref(&self) -> &Self::Target {
766        unsafe { slice::from_raw_parts(self.info, self.count) }
767    }
768}
769
770#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
771pub struct DeviceId(xinput::DeviceId);
772
773impl DeviceId {
774    #[allow(unused)]
775    pub const fn dummy() -> Self {
776        DeviceId(0)
777    }
778}
779
780pub(crate) struct Window(Arc<UnownedWindow>);
781
782impl Deref for Window {
783    type Target = UnownedWindow;
784
785    #[inline]
786    fn deref(&self) -> &UnownedWindow {
787        &self.0
788    }
789}
790
791impl Window {
792    pub(crate) fn new(
793        event_loop: &ActiveEventLoop,
794        attribs: WindowAttributes,
795    ) -> Result<Self, RootOsError> {
796        let window = Arc::new(UnownedWindow::new(event_loop, attribs)?);
797        event_loop.windows.borrow_mut().insert(window.id(), Arc::downgrade(&window));
798        Ok(Window(window))
799    }
800}
801
802impl Drop for Window {
803    fn drop(&mut self) {
804        let window = self.deref();
805        let xconn = &window.xconn;
806
807        if let Ok(c) = xconn.xcb_connection().destroy_window(window.id().0 as xproto::Window) {
808            c.ignore_error();
809        }
810    }
811}
812
813/// Generic sum error type for X11 errors.
814#[derive(Debug)]
815pub enum X11Error {
816    /// An error from the Xlib library.
817    Xlib(XError),
818
819    /// An error that occurred while trying to connect to the X server.
820    Connect(ConnectError),
821
822    /// An error that occurred over the connection medium.
823    Connection(ConnectionError),
824
825    /// An error that occurred logically on the X11 end.
826    X11(LogicalError),
827
828    /// The XID range has been exhausted.
829    XidsExhausted(IdsExhausted),
830
831    /// Got `null` from an Xlib function without a reason.
832    UnexpectedNull(&'static str),
833
834    /// Got an invalid activation token.
835    InvalidActivationToken(Vec<u8>),
836
837    /// An extension that we rely on is not available.
838    MissingExtension(&'static str),
839
840    /// Could not find a matching X11 visual for this visualid
841    NoSuchVisual(xproto::Visualid),
842
843    /// Unable to parse xsettings.
844    XsettingsParse(xsettings::ParserError),
845
846    /// Failed to get property.
847    GetProperty(util::GetPropertyError),
848}
849
850impl fmt::Display for X11Error {
851    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
852        match self {
853            X11Error::Xlib(e) => write!(f, "Xlib error: {e}"),
854            X11Error::Connect(e) => write!(f, "X11 connection error: {e}"),
855            X11Error::Connection(e) => write!(f, "X11 connection error: {e}"),
856            X11Error::XidsExhausted(e) => write!(f, "XID range exhausted: {e}"),
857            X11Error::GetProperty(e) => write!(f, "Failed to get X property {e}"),
858            X11Error::X11(e) => write!(f, "X11 error: {e:?}"),
859            X11Error::UnexpectedNull(s) => write!(f, "Xlib function returned null: {s}"),
860            X11Error::InvalidActivationToken(s) => write!(
861                f,
862                "Invalid activation token: {}",
863                std::str::from_utf8(s).unwrap_or("<invalid utf8>")
864            ),
865            X11Error::MissingExtension(s) => write!(f, "Missing X11 extension: {s}"),
866            X11Error::NoSuchVisual(visualid) => {
867                write!(f, "Could not find a matching X11 visual for ID `{visualid:x}`")
868            },
869            X11Error::XsettingsParse(err) => {
870                write!(f, "Failed to parse xsettings: {err:?}")
871            },
872        }
873    }
874}
875
876impl std::error::Error for X11Error {
877    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
878        match self {
879            X11Error::Xlib(e) => Some(e),
880            X11Error::Connect(e) => Some(e),
881            X11Error::Connection(e) => Some(e),
882            X11Error::XidsExhausted(e) => Some(e),
883            _ => None,
884        }
885    }
886}
887
888impl From<XError> for X11Error {
889    fn from(e: XError) -> Self {
890        X11Error::Xlib(e)
891    }
892}
893
894impl From<ConnectError> for X11Error {
895    fn from(e: ConnectError) -> Self {
896        X11Error::Connect(e)
897    }
898}
899
900impl From<ConnectionError> for X11Error {
901    fn from(e: ConnectionError) -> Self {
902        X11Error::Connection(e)
903    }
904}
905
906impl From<LogicalError> for X11Error {
907    fn from(e: LogicalError) -> Self {
908        X11Error::X11(e)
909    }
910}
911
912impl From<ReplyError> for X11Error {
913    fn from(value: ReplyError) -> Self {
914        match value {
915            ReplyError::ConnectionError(e) => e.into(),
916            ReplyError::X11Error(e) => e.into(),
917        }
918    }
919}
920
921impl From<ime::ImeContextCreationError> for X11Error {
922    fn from(value: ime::ImeContextCreationError) -> Self {
923        match value {
924            ime::ImeContextCreationError::XError(e) => e.into(),
925            ime::ImeContextCreationError::Null => Self::UnexpectedNull("XOpenIM"),
926        }
927    }
928}
929
930impl From<ReplyOrIdError> for X11Error {
931    fn from(value: ReplyOrIdError) -> Self {
932        match value {
933            ReplyOrIdError::ConnectionError(e) => e.into(),
934            ReplyOrIdError::X11Error(e) => e.into(),
935            ReplyOrIdError::IdsExhausted => Self::XidsExhausted(IdsExhausted),
936        }
937    }
938}
939
940impl From<xsettings::ParserError> for X11Error {
941    fn from(value: xsettings::ParserError) -> Self {
942        Self::XsettingsParse(value)
943    }
944}
945
946impl From<util::GetPropertyError> for X11Error {
947    fn from(value: util::GetPropertyError) -> Self {
948        Self::GetProperty(value)
949    }
950}
951
952/// Type alias for a void cookie.
953type VoidCookie<'a> = x11rb::cookie::VoidCookie<'a, X11rbConnection>;
954
955/// Extension trait for `Result<VoidCookie, E>`.
956trait CookieResultExt {
957    /// Unwrap the send error and ignore the result.
958    fn expect_then_ignore_error(self, msg: &str);
959}
960
961impl<E: fmt::Debug> CookieResultExt for Result<VoidCookie<'_>, E> {
962    fn expect_then_ignore_error(self, msg: &str) {
963        self.expect(msg).ignore_error()
964    }
965}
966
967fn mkwid(w: xproto::Window) -> crate::window::WindowId {
968    crate::window::WindowId(crate::platform_impl::platform::WindowId(w as _))
969}
970fn mkdid(w: xinput::DeviceId) -> crate::event::DeviceId {
971    crate::event::DeviceId(crate::platform_impl::DeviceId::X(DeviceId(w)))
972}
973
974#[derive(Debug)]
975pub struct Device {
976    _name: String,
977    scroll_axes: Vec<(i32, ScrollAxis)>,
978    // For master devices, this is the paired device (pointer <-> keyboard).
979    // For slave devices, this is the master.
980    attachment: c_int,
981}
982
983#[derive(Debug, Copy, Clone)]
984struct ScrollAxis {
985    increment: f64,
986    orientation: ScrollOrientation,
987    position: f64,
988}
989
990#[derive(Debug, Copy, Clone)]
991enum ScrollOrientation {
992    Vertical,
993    Horizontal,
994}
995
996impl Device {
997    fn new(info: &ffi::XIDeviceInfo) -> Self {
998        let name = unsafe { CStr::from_ptr(info.name).to_string_lossy() };
999        let mut scroll_axes = Vec::new();
1000
1001        if Device::physical_device(info) {
1002            // Identify scroll axes
1003            for &class_ptr in Device::classes(info) {
1004                let ty = unsafe { (*class_ptr)._type };
1005                if ty == ffi::XIScrollClass {
1006                    let info = unsafe { &*(class_ptr as *const ffi::XIScrollClassInfo) };
1007                    scroll_axes.push((info.number, ScrollAxis {
1008                        increment: info.increment,
1009                        orientation: match info.scroll_type {
1010                            ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal,
1011                            ffi::XIScrollTypeVertical => ScrollOrientation::Vertical,
1012                            _ => unreachable!(),
1013                        },
1014                        position: 0.0,
1015                    }));
1016                }
1017            }
1018        }
1019
1020        let mut device =
1021            Device { _name: name.into_owned(), scroll_axes, attachment: info.attachment };
1022        device.reset_scroll_position(info);
1023        device
1024    }
1025
1026    fn reset_scroll_position(&mut self, info: &ffi::XIDeviceInfo) {
1027        if Device::physical_device(info) {
1028            for &class_ptr in Device::classes(info) {
1029                let ty = unsafe { (*class_ptr)._type };
1030                if ty == ffi::XIValuatorClass {
1031                    let info = unsafe { &*(class_ptr as *const ffi::XIValuatorClassInfo) };
1032                    if let Some(&mut (_, ref mut axis)) =
1033                        self.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == info.number)
1034                    {
1035                        axis.position = info.value;
1036                    }
1037                }
1038            }
1039        }
1040    }
1041
1042    #[inline]
1043    fn physical_device(info: &ffi::XIDeviceInfo) -> bool {
1044        info._use == ffi::XISlaveKeyboard
1045            || info._use == ffi::XISlavePointer
1046            || info._use == ffi::XIFloatingSlave
1047    }
1048
1049    #[inline]
1050    fn classes(info: &ffi::XIDeviceInfo) -> &[*const ffi::XIAnyClassInfo] {
1051        unsafe {
1052            slice::from_raw_parts(
1053                info.classes as *const *const ffi::XIAnyClassInfo,
1054                info.num_classes as usize,
1055            )
1056        }
1057    }
1058}
1059
1060/// Convert the raw X11 representation for a 32-bit floating point to a double.
1061#[inline]
1062fn xinput_fp1616_to_float(fp: xinput::Fp1616) -> f64 {
1063    (fp as f64) / ((1 << 16) as f64)
1064}