Skip to main content

winit_x11/
event_loop.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::atomic::{AtomicBool, Ordering};
9use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
10use std::sync::{Arc, LazyLock, Mutex, Weak};
11use std::time::{Duration, Instant};
12use std::{fmt, mem, ptr, slice, str};
13
14use calloop::generic::Generic;
15use calloop::ping::Ping;
16use calloop::{EventLoop as Loop, Readiness};
17use libc::{LC_CTYPE, setlocale};
18use tracing::warn;
19use winit_common::xkb::Context;
20use winit_core::application::ApplicationHandler;
21use winit_core::cursor::{CustomCursor as CoreCustomCursor, CustomCursorSource};
22use winit_core::data_transfer::{DataTransfer, DataTransferId, TransferType};
23use winit_core::error::{EventLoopError, NotSupportedError, RequestError};
24use winit_core::event::{DeviceId, StartCause, WindowEvent};
25use winit_core::event_loop::pump_events::PumpStatus;
26use winit_core::event_loop::{
27    ActiveEventLoop as RootActiveEventLoop, AsyncRequestSerial, ControlFlow, DeviceEvents,
28    DndAction, EventLoopProvider, EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider,
29    OwnedDisplayHandle as CoreOwnedDisplayHandle,
30};
31use winit_core::monitor::MonitorHandle as CoreMonitorHandle;
32use winit_core::window::{Theme, Window as CoreWindow, WindowAttributes, WindowId};
33use x11rb::connection::RequestConnection;
34use x11rb::errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError};
35use x11rb::protocol::xinput::{self, ConnectionExt as _};
36use x11rb::protocol::{ErrorKind, xkb, xproto};
37use x11rb::x11_utils::X11Error as LogicalError;
38use x11rb::xcb_ffi::ReplyOrIdError;
39
40use crate::atoms::{
41    _NET_WM_PING, _NET_WM_SYNC_REQUEST, ABS_PRESSURE, ABS_TILT_X, ABS_TILT_Y, Atoms,
42    WM_DELETE_WINDOW,
43};
44use crate::dnd::Dnd;
45use crate::event_processor::{EventProcessor, MAX_MOD_REPLAY_LEN};
46use crate::ime::{self, Ime, ImeCreationError, ImeSender};
47use crate::util::{self, CustomCursor};
48use crate::window::{UnownedWindow, Window};
49use crate::xdisplay::{XConnection, XError, XNotSupported};
50use crate::{Selection, SelectionType, XlibErrorHook, ffi, xsettings};
51
52// Xinput constants not defined in x11rb
53pub(crate) const ALL_DEVICES: u16 = 0;
54pub(crate) const ALL_MASTER_DEVICES: u16 = 1;
55pub(crate) const ICONIC_STATE: u32 = 3;
56
57/// The underlying x11rb connection that we are using.
58type X11rbConnection = x11rb::xcb_ffi::XCBConnection;
59
60type X11Source = Generic<BorrowedFd<'static>>;
61
62pub(crate) static X11_BACKEND: LazyLock<Mutex<Result<Arc<XConnection>, XNotSupported>>> =
63    LazyLock::new(|| Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)));
64
65/// Hooks for X11 errors.
66pub(crate) static XLIB_ERROR_HOOKS: Mutex<Vec<XlibErrorHook>> = Mutex::new(Vec::new());
67
68unsafe extern "C" fn x_error_callback(
69    display: *mut ffi::Display,
70    event: *mut ffi::XErrorEvent,
71) -> c_int {
72    let xconn_lock = X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner());
73    if let Ok(ref xconn) = *xconn_lock {
74        // Call all the hooks.
75        let mut error_handled = false;
76        for hook in XLIB_ERROR_HOOKS.lock().unwrap().iter() {
77            error_handled |= hook(display as *mut _, event as *mut _);
78        }
79
80        // `assume_init` is safe here because the array consists of `MaybeUninit` values,
81        // which do not require initialization.
82        let mut buf: [MaybeUninit<c_char>; 1024] = unsafe { MaybeUninit::uninit().assume_init() };
83        unsafe {
84            (xconn.xlib.XGetErrorText)(
85                display,
86                (*event).error_code as c_int,
87                buf.as_mut_ptr() as *mut c_char,
88                buf.len() as c_int,
89            )
90        };
91        let description =
92            unsafe { CStr::from_ptr(buf.as_ptr() as *const c_char) }.to_string_lossy();
93
94        let error = unsafe {
95            XError {
96                description: description.into_owned(),
97                error_code: (*event).error_code,
98                request_code: (*event).request_code,
99                minor_code: (*event).minor_code,
100            }
101        };
102
103        // Don't log error.
104        if !error_handled {
105            tracing::error!("X11 error: {:#?}", error);
106            // XXX only update the error, if it wasn't handled by any of the hooks.
107            *xconn.latest_error.lock().unwrap() = Some(error);
108        }
109    }
110    // Fun fact: this return value is completely ignored.
111    0
112}
113
114#[derive(Debug)]
115pub(crate) struct WakeSender<T> {
116    sender: Sender<T>,
117    waker: Ping,
118}
119
120impl<T> Clone for WakeSender<T> {
121    fn clone(&self) -> Self {
122        Self { sender: self.sender.clone(), waker: self.waker.clone() }
123    }
124}
125
126impl<T> WakeSender<T> {
127    pub fn send(&self, t: T) {
128        let res = self.sender.send(t);
129        if res.is_ok() {
130            self.waker.ping();
131        }
132    }
133}
134
135#[derive(Debug)]
136struct PeekableReceiver<T> {
137    recv: Receiver<T>,
138    first: Option<T>,
139}
140
141impl<T> PeekableReceiver<T> {
142    pub fn from_recv(recv: Receiver<T>) -> Self {
143        Self { recv, first: None }
144    }
145
146    pub fn has_incoming(&mut self) -> bool {
147        if self.first.is_some() {
148            return true;
149        }
150
151        match self.recv.try_recv() {
152            Ok(v) => {
153                self.first = Some(v);
154                true
155            },
156            Err(TryRecvError::Empty) => false,
157            Err(TryRecvError::Disconnected) => {
158                warn!("Channel was disconnected when checking incoming");
159                false
160            },
161        }
162    }
163
164    pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
165        if let Some(first) = self.first.take() {
166            return Ok(first);
167        }
168        self.recv.try_recv()
169    }
170}
171
172#[derive(Debug)]
173pub struct ActiveEventLoop {
174    pub(crate) xconn: Arc<XConnection>,
175    pub(crate) dnd: RefCell<Dnd>,
176    pub(crate) wm_delete_window: xproto::Atom,
177    pub(crate) net_wm_ping: xproto::Atom,
178    pub(crate) net_wm_sync_request: xproto::Atom,
179    pub(crate) ime_sender: ImeSender,
180    control_flow: Cell<ControlFlow>,
181    exit: Cell<Option<i32>>,
182    pub(crate) root: xproto::Window,
183    pub(crate) ime: Option<RefCell<Ime>>,
184    pub(crate) windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
185    pub(crate) redraw_sender: WakeSender<WindowId>,
186    pub(crate) activation_sender: WakeSender<ActivationItem>,
187    event_loop_proxy: CoreEventLoopProxy,
188    device_events: Cell<DeviceEvents>,
189}
190
191#[derive(Debug)]
192pub struct EventLoop {
193    loop_running: bool,
194    event_loop: Loop<'static, EventLoopState>,
195    event_processor: EventProcessor,
196    redraw_receiver: PeekableReceiver<WindowId>,
197    activation_receiver: PeekableReceiver<ActivationItem>,
198
199    /// The current state of the event loop.
200    state: EventLoopState,
201}
202
203pub(crate) type ActivationItem = (WindowId, winit_core::event_loop::AsyncRequestSerial);
204
205#[derive(Debug)]
206struct EventLoopState {
207    /// The latest readiness state for the x11 file descriptor
208    x11_readiness: Readiness,
209
210    /// User requested a wake up.
211    proxy_wake_up: bool,
212}
213
214impl EventLoop {
215    pub fn new() -> Result<EventLoop, EventLoopError> {
216        static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
217        if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
218            // Required?
219            return Err(EventLoopError::RecreationAttempt);
220        }
221
222        let xconn = match X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()).as_ref() {
223            Ok(xconn) => xconn.clone(),
224            Err(XNotSupported::ExtensionNotSupported(reason)) => {
225                return Err(NotSupportedError::new(reason).into());
226            },
227            Err(err) => return Err(os_error!(err.clone()).into()),
228        };
229
230        let root = xconn.default_root().root;
231        let atoms = xconn.atoms();
232
233        let wm_delete_window = atoms[WM_DELETE_WINDOW];
234        let net_wm_ping = atoms[_NET_WM_PING];
235        let net_wm_sync_request = atoms[_NET_WM_SYNC_REQUEST];
236
237        let dnd = Dnd::new(Arc::clone(&xconn)).into();
238
239        let (ime_sender, ime_receiver) = mpsc::channel();
240        let (ime_event_sender, ime_event_receiver) = mpsc::channel();
241        // Input methods will open successfully without setting the locale, but it won't be
242        // possible to actually commit pre-edit sequences.
243        unsafe {
244            // Remember default locale to restore it if target locale is unsupported
245            // by Xlib
246            let default_locale = setlocale(LC_CTYPE, ptr::null());
247            setlocale(LC_CTYPE, c"".as_ptr() as *const _);
248
249            // Check if set locale is supported by Xlib.
250            // If not, calls to some Xlib functions like `XSetLocaleModifiers`
251            // will fail.
252            let locale_supported = (xconn.xlib.XSupportsLocale)() == 1;
253            if !locale_supported {
254                let unsupported_locale = setlocale(LC_CTYPE, ptr::null());
255                warn!(
256                    "Unsupported locale \"{}\". Restoring default locale \"{}\".",
257                    CStr::from_ptr(unsupported_locale).to_string_lossy(),
258                    CStr::from_ptr(default_locale).to_string_lossy()
259                );
260                // Restore default locale
261                setlocale(LC_CTYPE, default_locale);
262            }
263        }
264
265        let ime = Ime::new(Arc::clone(&xconn), ime_event_sender);
266        if let Err(ImeCreationError::OpenFailure(state)) = ime.as_ref() {
267            warn!("Failed to open input method: {state:#?}");
268        } else if let Err(err) = ime.as_ref() {
269            warn!("Failed to set input method destruction callback: {err:?}");
270        }
271
272        let ime = ime.ok().map(RefCell::new);
273
274        let randr_event_offset = xconn.select_xrandr_input(root).map_err(|err| match err {
275            X11Error::MissingExtension(_) => EventLoopError::NotSupported(NotSupportedError::new(
276                "the X11 backend requires XRandR 1.2 or newer",
277            )),
278            error => os_error!(error).into(),
279        })?;
280
281        let xi2ext = xconn
282            .xcb_connection()
283            .extension_information(xinput::X11_EXTENSION_NAME)
284            .map_err(|err| os_error!(X11Error::from(err)))?
285            .ok_or_else(|| {
286                NotSupportedError::new("the X11 backend requires XInput 2.0 or newer")
287            })?;
288        let xkbext = xconn
289            .xcb_connection()
290            .extension_information(xkb::X11_EXTENSION_NAME)
291            .map_err(|err| os_error!(X11Error::from(err)))?
292            .ok_or_else(|| NotSupportedError::new("the X11 backend requires XKB 1.0 or newer"))?;
293
294        // Check for XInput2 support.
295        xconn
296            .xcb_connection()
297            .xinput_xi_query_version(2, 3)
298            .map_err(|err| os_error!(X11Error::from(err)))?
299            .reply()
300            .map_err(|err| match err {
301                ReplyError::X11Error(error) if error.error_kind == ErrorKind::Request => {
302                    EventLoopError::NotSupported(NotSupportedError::new(
303                        "the X11 backend requires XInput 2.0 or newer",
304                    ))
305                },
306                error => os_error!(X11Error::from(error)).into(),
307            })?;
308
309        xconn.update_cached_wm_info(root);
310
311        // Create an event loop.
312        let event_loop =
313            Loop::<EventLoopState>::try_new().expect("Failed to initialize the event loop");
314        let handle = event_loop.handle();
315
316        // Create the X11 event dispatcher.
317        let source = X11Source::new(
318            // SAFETY: xcb owns the FD and outlives the source.
319            unsafe { BorrowedFd::borrow_raw(xconn.xcb_connection().as_raw_fd()) },
320            calloop::Interest::READ,
321            calloop::Mode::Level,
322        );
323        handle
324            .insert_source(source, |readiness, _, state| {
325                state.x11_readiness = readiness;
326                Ok(calloop::PostAction::Continue)
327            })
328            .expect("Failed to register the X11 event dispatcher");
329
330        let (waker, waker_source) =
331            calloop::ping::make_ping().expect("Failed to create event loop waker");
332        event_loop
333            .handle()
334            .insert_source(waker_source, move |_, _, _| {
335                // No extra handling is required, we just need to wake-up.
336            })
337            .expect("Failed to register the event loop waker source");
338
339        // Create a channel for handling redraw requests.
340        let (redraw_sender, redraw_channel) = mpsc::channel();
341
342        // Create a channel for sending activation tokens.
343        let (activation_token_sender, activation_token_channel) = mpsc::channel();
344
345        // Create a channel for sending user events.
346        let (user_waker, user_waker_source) =
347            calloop::ping::make_ping().expect("Failed to create user event loop waker.");
348        event_loop
349            .handle()
350            .insert_source(user_waker_source, move |_, _, state| {
351                // No extra handling is required, we just need to wake-up.
352                state.proxy_wake_up = true;
353            })
354            .expect("Failed to register the event loop waker source");
355        let event_loop_proxy = EventLoopProxy::new(user_waker);
356
357        let xkb_context = Context::from_x11_xkb(xconn.xcb_connection().get_raw_xcb_connection())
358            .map_err(|_| NotSupportedError::new("the X11 backend requires XKB 1.0 or newer"))?;
359
360        let mut xmodmap = util::ModifierKeymap::new();
361        xmodmap.reload_from_x_connection(&xconn);
362
363        let window_target = ActiveEventLoop {
364            ime,
365            dnd,
366            root,
367            control_flow: Cell::new(ControlFlow::default()),
368            exit: Cell::new(None),
369            windows: Default::default(),
370            ime_sender,
371            xconn,
372            wm_delete_window,
373            net_wm_ping,
374            net_wm_sync_request,
375            redraw_sender: WakeSender {
376                sender: redraw_sender, // not used again so no clone
377                waker: waker.clone(),
378            },
379            activation_sender: WakeSender {
380                sender: activation_token_sender, // not used again so no clone
381                waker: waker.clone(),
382            },
383            event_loop_proxy: event_loop_proxy.into(),
384            device_events: Default::default(),
385        };
386
387        // Set initial device event filter.
388        window_target.update_listen_device_events(true);
389
390        let event_processor = EventProcessor {
391            target: window_target,
392            devices: Default::default(),
393            randr_event_offset,
394            ime_receiver,
395            ime_event_receiver,
396            xi2ext,
397            xfiltered_modifiers: VecDeque::with_capacity(MAX_MOD_REPLAY_LEN),
398            xmodmap,
399            xkbext,
400            xkb_context,
401            num_touch: 0,
402            held_key_press: None,
403            first_touch: None,
404            active_window: None,
405            modifiers: Default::default(),
406            is_composing: false,
407        };
408
409        // Register for device hotplug events
410        // (The request buffer is flushed during `init_device`)
411        event_processor
412            .target
413            .xconn
414            .select_xinput_events(
415                root,
416                ALL_DEVICES,
417                x11rb::protocol::xinput::XIEventMask::HIERARCHY,
418            )
419            .expect_then_ignore_error("Failed to register for XInput2 device hotplug events");
420
421        event_processor
422            .target
423            .xconn
424            .select_xkb_events(
425                0x100, // Use the "core keyboard device"
426                xkb::EventType::NEW_KEYBOARD_NOTIFY
427                    | xkb::EventType::MAP_NOTIFY
428                    | xkb::EventType::STATE_NOTIFY,
429            )
430            .map_err(|err| os_error!(err))?;
431
432        event_processor.init_device(ALL_DEVICES);
433
434        let event_loop = EventLoop {
435            loop_running: false,
436            event_loop,
437            event_processor,
438            redraw_receiver: PeekableReceiver::from_recv(redraw_channel),
439            activation_receiver: PeekableReceiver::from_recv(activation_token_channel),
440            state: EventLoopState { x11_readiness: Readiness::EMPTY, proxy_wake_up: false },
441        };
442
443        Ok(event_loop)
444    }
445
446    pub fn window_target(&self) -> &dyn RootActiveEventLoop {
447        &self.event_processor.target
448    }
449
450    pub fn run_app_on_demand<A: ApplicationHandler>(
451        &mut self,
452        mut app: A,
453    ) -> Result<(), EventLoopError> {
454        self.event_processor.target.clear_exit();
455        let exit = loop {
456            match self.pump_app_events(None, &mut app) {
457                PumpStatus::Exit(0) => {
458                    break Ok(());
459                },
460                PumpStatus::Exit(code) => {
461                    break Err(EventLoopError::ExitFailure(code));
462                },
463                _ => {
464                    continue;
465                },
466            }
467        };
468
469        // Applications aren't allowed to carry windows between separate
470        // `run_on_demand` calls but if they have only just dropped their
471        // windows we need to make sure those last requests are sent to the
472        // X Server.
473        self.event_processor
474            .target
475            .x_connection()
476            .sync_with_server()
477            .map_err(|x_err| EventLoopError::Os(os_error!(X11Error::Xlib(x_err))))?;
478
479        exit
480    }
481
482    pub fn pump_app_events<A: ApplicationHandler>(
483        &mut self,
484        timeout: Option<Duration>,
485        mut app: A,
486    ) -> PumpStatus {
487        if !self.loop_running {
488            self.loop_running = true;
489
490            // run the initial loop iteration
491            self.single_iteration(&mut app, StartCause::Init);
492        }
493
494        // Consider the possibility that the `StartCause::Init` iteration could
495        // request to Exit.
496        if !self.exiting() {
497            self.poll_events_with_timeout(timeout, &mut app);
498        }
499        if let Some(code) = self.exit_code() {
500            self.loop_running = false;
501
502            PumpStatus::Exit(code)
503        } else {
504            PumpStatus::Continue
505        }
506    }
507
508    fn has_pending(&mut self) -> bool {
509        self.event_processor.poll()
510            || self.state.proxy_wake_up
511            || self.redraw_receiver.has_incoming()
512    }
513
514    fn poll_events_with_timeout<A: ApplicationHandler>(
515        &mut self,
516        mut timeout: Option<Duration>,
517        app: &mut A,
518    ) {
519        let start = Instant::now();
520
521        let has_pending = self.has_pending();
522
523        timeout = if has_pending {
524            // If we already have work to do then we don't want to block on the next poll.
525            Some(Duration::ZERO)
526        } else {
527            let control_flow_timeout = match self.control_flow() {
528                ControlFlow::Wait => None,
529                ControlFlow::Poll => Some(Duration::ZERO),
530                ControlFlow::WaitUntil(wait_deadline) => {
531                    Some(wait_deadline.saturating_duration_since(start))
532                },
533            };
534
535            min_timeout(control_flow_timeout, timeout)
536        };
537
538        self.state.x11_readiness = Readiness::EMPTY;
539        if let Err(error) =
540            self.event_loop.dispatch(timeout, &mut self.state).map_err(std::io::Error::from)
541        {
542            tracing::error!("Failed to poll for events: {error:?}");
543            let exit_code = error.raw_os_error().unwrap_or(1);
544            self.set_exit_code(exit_code);
545            return;
546        }
547
548        // NB: `StartCause::Init` is handled as a special case and doesn't need
549        // to be considered here
550        let cause = match self.control_flow() {
551            ControlFlow::Poll => StartCause::Poll,
552            ControlFlow::Wait => StartCause::WaitCancelled { start, requested_resume: None },
553            ControlFlow::WaitUntil(deadline) => {
554                if Instant::now() < deadline {
555                    StartCause::WaitCancelled { start, requested_resume: Some(deadline) }
556                } else {
557                    StartCause::ResumeTimeReached { start, requested_resume: deadline }
558                }
559            },
560        };
561
562        // False positive / spurious wake ups could lead to us spamming
563        // redundant iterations of the event loop with no new events to
564        // dispatch.
565        //
566        // If there's no readable event source then we just double check if we
567        // have any pending `_receiver` events and if not we return without
568        // running a loop iteration.
569        // If we don't have any pending `_receiver`
570        if !self.has_pending()
571            && !matches!(&cause, StartCause::ResumeTimeReached { .. } | StartCause::Poll)
572            && timeout.is_none()
573        {
574            return;
575        }
576
577        self.single_iteration(app, cause);
578    }
579
580    fn single_iteration<A: ApplicationHandler>(&mut self, app: &mut A, cause: StartCause) {
581        app.new_events(&self.event_processor.target, cause);
582
583        // NB: For consistency all platforms must call `can_create_surfaces` even though X11
584        // applications don't themselves have a formal surface destroy/create lifecycle.
585        if cause == StartCause::Init {
586            app.can_create_surfaces(&self.event_processor.target)
587        }
588
589        // Process all pending events
590        self.drain_events(app);
591
592        // Empty activation tokens.
593        while let Ok((window_id, serial)) = self.activation_receiver.try_recv() {
594            let token = self
595                .event_processor
596                .with_window(window_id.into_raw() as xproto::Window, |window| {
597                    window.generate_activation_token()
598                });
599
600            match token {
601                Some(Ok(token)) => {
602                    let event = WindowEvent::ActivationTokenDone {
603                        serial,
604                        token: winit_core::window::ActivationToken::from_raw(token),
605                    };
606                    app.window_event(&self.event_processor.target, window_id, event);
607                },
608                Some(Err(e)) => {
609                    tracing::error!("Failed to get activation token: {}", e);
610                },
611                None => {},
612            }
613        }
614
615        // Empty the user event buffer
616        if mem::take(&mut self.state.proxy_wake_up) {
617            app.proxy_wake_up(&self.event_processor.target);
618        }
619
620        // Empty the redraw requests
621        {
622            let mut windows = HashSet::new();
623
624            while let Ok(window_id) = self.redraw_receiver.try_recv() {
625                windows.insert(window_id);
626            }
627
628            for window_id in windows {
629                app.window_event(
630                    &self.event_processor.target,
631                    window_id,
632                    WindowEvent::RedrawRequested,
633                );
634            }
635        }
636
637        // This is always the last event we dispatch before poll again
638        app.about_to_wait(&self.event_processor.target);
639    }
640
641    fn drain_events<A: ApplicationHandler>(&mut self, app: &mut A) {
642        let mut xev = MaybeUninit::uninit();
643
644        while let Some(xev) = self.event_processor.poll_one_event(&mut xev) {
645            self.event_processor.process_event(xev, app);
646        }
647    }
648
649    fn control_flow(&self) -> ControlFlow {
650        self.event_processor.target.control_flow()
651    }
652
653    fn exiting(&self) -> bool {
654        self.event_processor.target.exiting()
655    }
656
657    fn set_exit_code(&self, code: i32) {
658        self.event_processor.target.set_exit_code(code);
659    }
660
661    fn exit_code(&self) -> Option<i32> {
662        self.event_processor.target.exit_code()
663    }
664}
665
666impl EventLoopProvider for EventLoop {
667    fn run_app<A: ApplicationHandler + 'static>(
668        mut self,
669        mut app: A,
670    ) -> Result<(), EventLoopError> {
671        let result = self.run_app_on_demand(&mut app);
672        // SAFETY: unsure that the state is dropped before the exit from the event loop.
673        drop(app);
674        result
675    }
676
677    fn create_proxy(&self) -> CoreEventLoopProxy {
678        self.window_target().create_proxy()
679    }
680
681    fn owned_display_handle(&self) -> CoreOwnedDisplayHandle {
682        self.window_target().owned_display_handle()
683    }
684
685    fn listen_device_events(&self, allowed: DeviceEvents) {
686        self.window_target().listen_device_events(allowed);
687    }
688
689    fn set_control_flow(&self, control_flow: ControlFlow) {
690        self.window_target().set_control_flow(control_flow);
691    }
692
693    fn create_custom_cursor(
694        &self,
695        custom_cursor: CustomCursorSource,
696    ) -> Result<CoreCustomCursor, RequestError> {
697        self.window_target().create_custom_cursor(custom_cursor)
698    }
699}
700
701impl AsFd for EventLoop {
702    fn as_fd(&self) -> BorrowedFd<'_> {
703        self.event_loop.as_fd()
704    }
705}
706
707impl AsRawFd for EventLoop {
708    fn as_raw_fd(&self) -> RawFd {
709        self.event_loop.as_raw_fd()
710    }
711}
712
713impl ActiveEventLoop {
714    /// Returns the `XConnection` of this events loop.
715    #[inline]
716    pub(crate) fn x_connection(&self) -> &Arc<XConnection> {
717        &self.xconn
718    }
719
720    /// Update the device event based on window focus.
721    pub fn update_listen_device_events(&self, focus: bool) {
722        let device_events = self.device_events.get() == DeviceEvents::Always
723            || (focus && self.device_events.get() == DeviceEvents::WhenFocused);
724
725        let mut mask = xinput::XIEventMask::from(0u32);
726        if device_events {
727            mask = xinput::XIEventMask::RAW_MOTION
728                | xinput::XIEventMask::RAW_BUTTON_PRESS
729                | xinput::XIEventMask::RAW_BUTTON_RELEASE
730                | xinput::XIEventMask::RAW_KEY_PRESS
731                | xinput::XIEventMask::RAW_KEY_RELEASE;
732        }
733
734        self.xconn
735            .select_xinput_events(self.root, ALL_MASTER_DEVICES, mask)
736            .expect_then_ignore_error("Failed to update device event filter");
737    }
738
739    pub(crate) fn clear_exit(&self) {
740        self.exit.set(None)
741    }
742
743    pub(crate) fn set_exit_code(&self, code: i32) {
744        self.exit.set(Some(code))
745    }
746
747    pub(crate) fn exit_code(&self) -> Option<i32> {
748        self.exit.get()
749    }
750}
751
752impl RootActiveEventLoop for ActiveEventLoop {
753    fn create_proxy(&self) -> CoreEventLoopProxy {
754        self.event_loop_proxy.clone()
755    }
756
757    fn create_window(
758        &self,
759        window_attributes: WindowAttributes,
760    ) -> Result<Box<dyn CoreWindow>, RequestError> {
761        Ok(Box::new(Window::new(self, window_attributes)?))
762    }
763
764    fn create_custom_cursor(
765        &self,
766        custom_cursor: CustomCursorSource,
767    ) -> Result<CoreCustomCursor, RequestError> {
768        Ok(CoreCustomCursor(Arc::new(CustomCursor::new(self, custom_cursor)?)))
769    }
770
771    fn available_monitors(&self) -> Box<dyn Iterator<Item = CoreMonitorHandle>> {
772        Box::new(
773            self.xconn
774                .available_monitors()
775                .into_iter()
776                .flatten()
777                .map(|monitor| CoreMonitorHandle(Arc::new(monitor))),
778        )
779    }
780
781    fn primary_monitor(&self) -> Option<CoreMonitorHandle> {
782        self.xconn.primary_monitor().ok().map(|monitor| CoreMonitorHandle(Arc::new(monitor)))
783    }
784
785    fn system_theme(&self) -> Option<Theme> {
786        None
787    }
788
789    fn listen_device_events(&self, allowed: DeviceEvents) {
790        self.device_events.set(allowed);
791    }
792
793    fn set_control_flow(&self, control_flow: ControlFlow) {
794        self.control_flow.set(control_flow)
795    }
796
797    fn control_flow(&self) -> ControlFlow {
798        self.control_flow.get()
799    }
800
801    fn exit(&self) {
802        self.exit.set(Some(0))
803    }
804
805    fn exiting(&self) -> bool {
806        self.exit.get().is_some()
807    }
808
809    fn owned_display_handle(&self) -> CoreOwnedDisplayHandle {
810        CoreOwnedDisplayHandle::new(self.x_connection().clone())
811    }
812
813    fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
814        self
815    }
816
817    fn data_transfer(&self, id: DataTransferId) -> Result<Box<dyn DataTransfer>, RequestError> {
818        let dnd = self.dnd.borrow();
819
820        if dnd.state().is_none_or(|state| state.transfer_id != id) {
821            return Err(RequestError::Ignored);
822        }
823
824        let Some(state) = dnd.state() else {
825            return Err(RequestError::Ignored);
826        };
827
828        Ok(Box::new(Selection::new(state.types.clone())))
829    }
830
831    fn fetch_data_transfer(
832        &self,
833        id: DataTransferId,
834        type_: &dyn TransferType,
835    ) -> Result<AsyncRequestSerial, RequestError> {
836        let mut dnd = self.dnd.borrow_mut();
837
838        let serial = AsyncRequestSerial::get();
839
840        let type_ = type_
841            .cast_ref::<SelectionType>()
842            .or_else(|| dnd.find_type_by_hint(type_.hint()?))
843            .cloned()
844            .ok_or(RequestError::NotSupported(NotSupportedError::new("Unknown type hint")))?;
845
846        let new_convert_selection = {
847            let Some(state) = dnd.state_mut() else {
848                return Err(RequestError::Ignored);
849            };
850
851            if state.transfer_id != id {
852                return Err(RequestError::NotSupported(NotSupportedError::new(
853                    "Unknown data transfer",
854                )));
855            }
856
857            // If it's non-empty, assume that we're still waiting on some other fetch operation.
858            // The `SelectionNotify` handler will send a new `convert_selection` event if any
859            // more are on the stack.
860            let should_emit_convert_selection = state.pending_fetch_types.is_empty();
861
862            let atom = type_.atom();
863
864            state.pending_fetch_types.push_back((serial, type_));
865
866            should_emit_convert_selection.then_some((
867                state.target_window,
868                self.xconn.timestamp(),
869                atom,
870            ))
871        };
872
873        if let Some((window, time, new_type)) = new_convert_selection {
874            // This results in the `SelectionNotify` event
875            dnd.convert_selection(window, time, new_type);
876        }
877
878        Ok(serial)
879    }
880
881    fn set_valid_dnd_actions(
882        &self,
883        id: DataTransferId,
884        actions: &[DndAction],
885    ) -> Result<(), RequestError> {
886        let mut dnd = self.dnd.borrow_mut();
887
888        let Some(state) = dnd.state_mut() else {
889            return Err(os_error!(UnknownDataTransfer(id)).into());
890        };
891
892        if state.transfer_id != id {
893            return Err(os_error!(UnknownDataTransfer(id)).into());
894        }
895
896        state.accepted = !actions.is_empty();
897
898        Ok(())
899    }
900}
901
902impl rwh_06::HasDisplayHandle for ActiveEventLoop {
903    fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
904        self.xconn.display_handle()
905    }
906}
907
908/// An operation was attempted on a data transfer ID, but that ID was invalid.
909#[derive(Debug, Copy, Clone, PartialEq, Eq)]
910pub struct UnknownDataTransfer(pub DataTransferId);
911
912impl fmt::Display for UnknownDataTransfer {
913    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
914        let id = self.0.into_raw();
915        write!(f, "Unknown data transfer with ID {id}")
916    }
917}
918
919impl std::error::Error for UnknownDataTransfer {}
920
921pub(crate) struct DeviceInfo<'a> {
922    xconn: &'a XConnection,
923    info: *const ffi::XIDeviceInfo,
924    count: usize,
925}
926
927impl<'a> DeviceInfo<'a> {
928    pub(crate) fn get(xconn: &'a XConnection, device: c_int) -> Option<Self> {
929        unsafe {
930            let mut count = 0;
931            let info = (xconn.xinput2.XIQueryDevice)(xconn.display, device, &mut count);
932            xconn.check_errors().ok()?;
933
934            if info.is_null() || count == 0 {
935                None
936            } else {
937                Some(DeviceInfo { xconn, info, count: count as usize })
938            }
939        }
940    }
941}
942
943impl Drop for DeviceInfo<'_> {
944    fn drop(&mut self) {
945        assert!(!self.info.is_null());
946        unsafe { (self.xconn.xinput2.XIFreeDeviceInfo)(self.info as *mut _) };
947    }
948}
949
950impl Deref for DeviceInfo<'_> {
951    type Target = [ffi::XIDeviceInfo];
952
953    fn deref(&self) -> &Self::Target {
954        unsafe { slice::from_raw_parts(self.info, self.count) }
955    }
956}
957
958#[derive(Clone, Debug)]
959pub struct EventLoopProxy {
960    ping: Ping,
961}
962
963impl EventLoopProxyProvider for EventLoopProxy {
964    fn wake_up(&self) {
965        self.ping.ping();
966    }
967}
968
969impl EventLoopProxy {
970    fn new(ping: Ping) -> Self {
971        Self { ping }
972    }
973}
974
975impl From<EventLoopProxy> for CoreEventLoopProxy {
976    fn from(value: EventLoopProxy) -> Self {
977        CoreEventLoopProxy::new(Arc::new(value))
978    }
979}
980
981/// Generic sum error type for X11 errors.
982#[derive(Debug)]
983pub enum X11Error {
984    /// An error from the Xlib library.
985    Xlib(XError),
986
987    /// An error that occurred while trying to connect to the X server.
988    Connect(ConnectError),
989
990    /// An error that occurred over the connection medium.
991    Connection(ConnectionError),
992
993    /// An error that occurred logically on the X11 end.
994    X11(LogicalError),
995
996    /// The XID range has been exhausted.
997    XidsExhausted(IdsExhausted),
998
999    /// Got `null` from an Xlib function without a reason.
1000    UnexpectedNull(&'static str),
1001
1002    /// Got an invalid activation token.
1003    InvalidActivationToken(Vec<u8>),
1004
1005    /// An extension that we rely on is not available.
1006    MissingExtension(&'static str),
1007
1008    /// Could not find a matching X11 visual for this visualid
1009    NoSuchVisual(xproto::Visualid),
1010
1011    /// Unable to parse xsettings.
1012    XsettingsParse(xsettings::ParserError),
1013
1014    /// Failed to get property.
1015    GetProperty(util::GetPropertyError),
1016
1017    /// Could not find an ARGB32 pict format.
1018    NoArgb32Format,
1019}
1020
1021impl fmt::Display for X11Error {
1022    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1023        match self {
1024            X11Error::Xlib(e) => write!(f, "Xlib error: {e}"),
1025            X11Error::Connect(e) => write!(f, "X11 connection error: {e}"),
1026            X11Error::Connection(e) => write!(f, "X11 connection error: {e}"),
1027            X11Error::XidsExhausted(e) => write!(f, "XID range exhausted: {e}"),
1028            X11Error::GetProperty(e) => write!(f, "Failed to get X property {e}"),
1029            X11Error::X11(e) => write!(f, "X11 error: {e:?}"),
1030            X11Error::UnexpectedNull(s) => write!(f, "Xlib function returned null: {s}"),
1031            X11Error::InvalidActivationToken(s) => write!(
1032                f,
1033                "Invalid activation token: {}",
1034                std::str::from_utf8(s).unwrap_or("<invalid utf8>")
1035            ),
1036            X11Error::MissingExtension(s) => write!(f, "Missing X11 extension: {s}"),
1037            X11Error::NoSuchVisual(visualid) => {
1038                write!(f, "Could not find a matching X11 visual for ID `{visualid:x}`")
1039            },
1040            X11Error::XsettingsParse(err) => {
1041                write!(f, "Failed to parse xsettings: {err:?}")
1042            },
1043            X11Error::NoArgb32Format => {
1044                f.write_str("winit only supports X11 displays with ARGB32 picture formats")
1045            },
1046        }
1047    }
1048}
1049
1050impl std::error::Error for X11Error {
1051    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1052        match self {
1053            X11Error::Xlib(e) => Some(e),
1054            X11Error::Connect(e) => Some(e),
1055            X11Error::Connection(e) => Some(e),
1056            X11Error::XidsExhausted(e) => Some(e),
1057            _ => None,
1058        }
1059    }
1060}
1061
1062impl From<XError> for X11Error {
1063    fn from(e: XError) -> Self {
1064        X11Error::Xlib(e)
1065    }
1066}
1067
1068impl From<ConnectError> for X11Error {
1069    fn from(e: ConnectError) -> Self {
1070        X11Error::Connect(e)
1071    }
1072}
1073
1074impl From<ConnectionError> for X11Error {
1075    fn from(e: ConnectionError) -> Self {
1076        X11Error::Connection(e)
1077    }
1078}
1079
1080impl From<LogicalError> for X11Error {
1081    fn from(e: LogicalError) -> Self {
1082        X11Error::X11(e)
1083    }
1084}
1085
1086impl From<ReplyError> for X11Error {
1087    fn from(value: ReplyError) -> Self {
1088        match value {
1089            ReplyError::ConnectionError(e) => e.into(),
1090            ReplyError::X11Error(e) => e.into(),
1091        }
1092    }
1093}
1094
1095impl From<ime::ImeContextCreationError> for X11Error {
1096    fn from(value: ime::ImeContextCreationError) -> Self {
1097        match value {
1098            ime::ImeContextCreationError::XError(e) => e.into(),
1099            ime::ImeContextCreationError::Null => Self::UnexpectedNull("XOpenIM"),
1100        }
1101    }
1102}
1103
1104impl From<ReplyOrIdError> for X11Error {
1105    fn from(value: ReplyOrIdError) -> Self {
1106        match value {
1107            ReplyOrIdError::ConnectionError(e) => e.into(),
1108            ReplyOrIdError::X11Error(e) => e.into(),
1109            ReplyOrIdError::IdsExhausted => Self::XidsExhausted(IdsExhausted),
1110        }
1111    }
1112}
1113
1114impl From<xsettings::ParserError> for X11Error {
1115    fn from(value: xsettings::ParserError) -> Self {
1116        Self::XsettingsParse(value)
1117    }
1118}
1119
1120impl From<util::GetPropertyError> for X11Error {
1121    fn from(value: util::GetPropertyError) -> Self {
1122        Self::GetProperty(value)
1123    }
1124}
1125
1126/// Type alias for a void cookie.
1127pub(crate) type VoidCookie<'a> = x11rb::cookie::VoidCookie<'a, X11rbConnection>;
1128
1129/// Extension trait for `Result<VoidCookie, E>`.
1130pub(crate) trait CookieResultExt {
1131    /// Unwrap the send error and ignore the result.
1132    fn expect_then_ignore_error(self, msg: &str);
1133}
1134
1135impl<E: fmt::Debug> CookieResultExt for Result<VoidCookie<'_>, E> {
1136    fn expect_then_ignore_error(self, msg: &str) {
1137        self.expect(msg).ignore_error()
1138    }
1139}
1140
1141pub(crate) fn mkwid(w: xproto::Window) -> winit_core::window::WindowId {
1142    winit_core::window::WindowId::from_raw(w as _)
1143}
1144
1145pub(crate) fn mkdid(w: xinput::DeviceId) -> DeviceId {
1146    DeviceId::from_raw(w as i64)
1147}
1148
1149#[derive(Debug)]
1150pub struct Device {
1151    _name: String,
1152    pub(crate) scroll_axes: Vec<(i32, ScrollAxis)>,
1153    // For master devices, this is the paired device (pointer <-> keyboard).
1154    // For slave devices, this is the master.
1155    pub(crate) attachment: c_int,
1156    pub(crate) r#type: DeviceType,
1157}
1158
1159#[derive(Clone, Copy, Debug)]
1160pub(crate) enum DeviceType {
1161    Mouse,
1162    Touch,
1163    Pen,
1164    Eraser,
1165}
1166
1167#[derive(Debug, Copy, Clone)]
1168pub(crate) struct ScrollAxis {
1169    pub(crate) increment: f64,
1170    pub(crate) orientation: ScrollOrientation,
1171    pub(crate) position: f64,
1172}
1173
1174#[derive(Debug, Copy, Clone)]
1175pub(crate) enum ScrollOrientation {
1176    Vertical,
1177    Horizontal,
1178}
1179
1180impl Device {
1181    pub(crate) fn new(info: &ffi::XIDeviceInfo, atoms: &Atoms) -> Self {
1182        let name = unsafe { CStr::from_ptr(info.name).to_string_lossy() };
1183        let mut scroll_axes = Vec::new();
1184        let mut r#type = None;
1185
1186        if Device::physical_device(info) {
1187            // Identify scroll axes
1188            for &class_ptr in Device::classes(info) {
1189                let ty = unsafe { (*class_ptr)._type };
1190                if ty == ffi::XIScrollClass {
1191                    let info = unsafe { &*(class_ptr as *const ffi::XIScrollClassInfo) };
1192                    scroll_axes.push((info.number, ScrollAxis {
1193                        increment: info.increment,
1194                        orientation: match info.scroll_type {
1195                            ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal,
1196                            ffi::XIScrollTypeVertical => ScrollOrientation::Vertical,
1197                            _ => unreachable!(),
1198                        },
1199                        position: 0.0,
1200                    }));
1201                } else if ty == ffi::XITouchClass {
1202                    r#type = Some(DeviceType::Touch);
1203                } else if r#type.is_none() && ty == ffi::XIValuatorClass {
1204                    let info = unsafe { &*(class_ptr as *const ffi::XIValuatorClassInfo) };
1205                    let atom = info.label as xproto::Atom;
1206
1207                    // Absolute X/Y axes alone do not identify a stylus:
1208                    // emulated pointing devices in virtual machines (the
1209                    // QEMU/VMware/VirtualBox USB tablets, and thus any
1210                    // desktop accessed through SPICE or similar viewers)
1211                    // expose Abs X/Y without pressure or tilt. Treating them
1212                    // as pens makes the mouse-only event filters drop all
1213                    // their motion and button input. Only pressure and tilt
1214                    // axes indicate actual stylus hardware.
1215                    if atom == atoms[ABS_PRESSURE]
1216                        || atom == atoms[ABS_TILT_X]
1217                        || atom == atoms[ABS_TILT_Y]
1218                    {
1219                        if name.contains("eraser") {
1220                            r#type = Some(DeviceType::Eraser);
1221                        } else {
1222                            r#type = Some(DeviceType::Pen);
1223                        }
1224                    }
1225                }
1226            }
1227        }
1228
1229        let mut device = Device {
1230            _name: name.into_owned(),
1231            scroll_axes,
1232            attachment: info.attachment,
1233            r#type: r#type.unwrap_or(DeviceType::Mouse),
1234        };
1235        device.reset_scroll_position(info);
1236        device
1237    }
1238
1239    pub(crate) fn reset_scroll_position(&mut self, info: &ffi::XIDeviceInfo) {
1240        if Device::physical_device(info) {
1241            for &class_ptr in Device::classes(info) {
1242                let ty = unsafe { (*class_ptr)._type };
1243                if ty == ffi::XIValuatorClass {
1244                    let info = unsafe { &*(class_ptr as *const ffi::XIValuatorClassInfo) };
1245                    if let Some(&mut (_, ref mut axis)) =
1246                        self.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == info.number)
1247                    {
1248                        axis.position = info.value;
1249                    }
1250                }
1251            }
1252        }
1253    }
1254
1255    #[inline]
1256    fn physical_device(info: &ffi::XIDeviceInfo) -> bool {
1257        info._use == ffi::XISlaveKeyboard
1258            || info._use == ffi::XISlavePointer
1259            || info._use == ffi::XIFloatingSlave
1260    }
1261
1262    #[inline]
1263    fn classes(info: &ffi::XIDeviceInfo) -> &[*const ffi::XIAnyClassInfo] {
1264        unsafe {
1265            slice::from_raw_parts(
1266                info.classes as *const *const ffi::XIAnyClassInfo,
1267                info.num_classes as usize,
1268            )
1269        }
1270    }
1271}
1272
1273/// Convert the raw X11 representation for a 32-bit floating point to a double.
1274#[inline]
1275pub(crate) fn xinput_fp1616_to_float(fp: xinput::Fp1616) -> f64 {
1276    (fp as f64) / ((1 << 16) as f64)
1277}
1278
1279/// Returns the minimum `Option<Duration>`, taking into account that `None`
1280/// equates to an infinite timeout, not a zero timeout (so can't just use
1281/// `Option::min`)
1282fn min_timeout(a: Option<Duration>, b: Option<Duration>) -> Option<Duration> {
1283    a.map_or(b, |a_timeout| b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout))))
1284}