winit/platform_impl/linux/x11/
mod.rs

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