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::error::{EventLoopError, RequestError};
23use winit_core::event::{DeviceId, StartCause, WindowEvent};
24use winit_core::event_loop::pump_events::PumpStatus;
25use winit_core::event_loop::{
26 ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
27 EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider,
28 OwnedDisplayHandle as CoreOwnedDisplayHandle,
29};
30use winit_core::monitor::MonitorHandle as CoreMonitorHandle;
31use winit_core::window::{Theme, Window as CoreWindow, WindowAttributes, WindowId};
32use x11rb::connection::RequestConnection;
33use x11rb::errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError};
34use x11rb::protocol::xinput::{self, ConnectionExt as _};
35use x11rb::protocol::{xkb, xproto};
36use x11rb::x11_utils::X11Error as LogicalError;
37use x11rb::xcb_ffi::ReplyOrIdError;
38
39use crate::atoms::*;
40use crate::dnd::Dnd;
41use crate::event_processor::{EventProcessor, MAX_MOD_REPLAY_LEN};
42use crate::ime::{self, Ime, ImeCreationError, ImeSender};
43use crate::util::{self, CustomCursor};
44use crate::window::{UnownedWindow, Window};
45use crate::xdisplay::{XConnection, XError, XNotSupported};
46use crate::{XlibErrorHook, ffi, xsettings};
47
48pub(crate) const ALL_DEVICES: u16 = 0;
50pub(crate) const ALL_MASTER_DEVICES: u16 = 1;
51pub(crate) const ICONIC_STATE: u32 = 3;
52
53type X11rbConnection = x11rb::xcb_ffi::XCBConnection;
55
56type X11Source = Generic<BorrowedFd<'static>>;
57
58pub(crate) static X11_BACKEND: LazyLock<Mutex<Result<Arc<XConnection>, XNotSupported>>> =
59 LazyLock::new(|| Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)));
60
61pub(crate) static XLIB_ERROR_HOOKS: Mutex<Vec<XlibErrorHook>> = Mutex::new(Vec::new());
63
64unsafe extern "C" fn x_error_callback(
65 display: *mut ffi::Display,
66 event: *mut ffi::XErrorEvent,
67) -> c_int {
68 let xconn_lock = X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner());
69 if let Ok(ref xconn) = *xconn_lock {
70 let mut error_handled = false;
72 for hook in XLIB_ERROR_HOOKS.lock().unwrap().iter() {
73 error_handled |= hook(display as *mut _, event as *mut _);
74 }
75
76 let mut buf: [MaybeUninit<c_char>; 1024] = unsafe { MaybeUninit::uninit().assume_init() };
79 unsafe {
80 (xconn.xlib.XGetErrorText)(
81 display,
82 (*event).error_code as c_int,
83 buf.as_mut_ptr() as *mut c_char,
84 buf.len() as c_int,
85 )
86 };
87 let description =
88 unsafe { CStr::from_ptr(buf.as_ptr() as *const c_char) }.to_string_lossy();
89
90 let error = unsafe {
91 XError {
92 description: description.into_owned(),
93 error_code: (*event).error_code,
94 request_code: (*event).request_code,
95 minor_code: (*event).minor_code,
96 }
97 };
98
99 if !error_handled {
101 tracing::error!("X11 error: {:#?}", error);
102 *xconn.latest_error.lock().unwrap() = Some(error);
104 }
105 }
106 0
108}
109
110#[derive(Debug)]
111pub(crate) struct WakeSender<T> {
112 sender: Sender<T>,
113 waker: Ping,
114}
115
116impl<T> Clone for WakeSender<T> {
117 fn clone(&self) -> Self {
118 Self { sender: self.sender.clone(), waker: self.waker.clone() }
119 }
120}
121
122impl<T> WakeSender<T> {
123 pub fn send(&self, t: T) {
124 let res = self.sender.send(t);
125 if res.is_ok() {
126 self.waker.ping();
127 }
128 }
129}
130
131#[derive(Debug)]
132struct PeekableReceiver<T> {
133 recv: Receiver<T>,
134 first: Option<T>,
135}
136
137impl<T> PeekableReceiver<T> {
138 pub fn from_recv(recv: Receiver<T>) -> Self {
139 Self { recv, first: None }
140 }
141
142 pub fn has_incoming(&mut self) -> bool {
143 if self.first.is_some() {
144 return true;
145 }
146
147 match self.recv.try_recv() {
148 Ok(v) => {
149 self.first = Some(v);
150 true
151 },
152 Err(TryRecvError::Empty) => false,
153 Err(TryRecvError::Disconnected) => {
154 warn!("Channel was disconnected when checking incoming");
155 false
156 },
157 }
158 }
159
160 pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
161 if let Some(first) = self.first.take() {
162 return Ok(first);
163 }
164 self.recv.try_recv()
165 }
166}
167
168#[derive(Debug)]
169pub struct ActiveEventLoop {
170 pub(crate) xconn: Arc<XConnection>,
171 pub(crate) wm_delete_window: xproto::Atom,
172 pub(crate) net_wm_ping: xproto::Atom,
173 pub(crate) net_wm_sync_request: xproto::Atom,
174 pub(crate) ime_sender: ImeSender,
175 control_flow: Cell<ControlFlow>,
176 exit: Cell<Option<i32>>,
177 pub(crate) root: xproto::Window,
178 pub(crate) ime: Option<RefCell<Ime>>,
179 pub(crate) windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
180 pub(crate) redraw_sender: WakeSender<WindowId>,
181 pub(crate) activation_sender: WakeSender<ActivationItem>,
182 event_loop_proxy: CoreEventLoopProxy,
183 device_events: Cell<DeviceEvents>,
184}
185
186#[derive(Debug)]
187pub struct EventLoop {
188 loop_running: bool,
189 event_loop: Loop<'static, EventLoopState>,
190 event_processor: EventProcessor,
191 redraw_receiver: PeekableReceiver<WindowId>,
192 activation_receiver: PeekableReceiver<ActivationItem>,
193
194 state: EventLoopState,
196}
197
198pub(crate) type ActivationItem = (WindowId, winit_core::event_loop::AsyncRequestSerial);
199
200#[derive(Debug)]
201struct EventLoopState {
202 x11_readiness: Readiness,
204
205 proxy_wake_up: bool,
207}
208
209impl EventLoop {
210 pub fn new() -> Result<EventLoop, EventLoopError> {
211 static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
212 if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
213 return Err(EventLoopError::RecreationAttempt);
215 }
216
217 let xconn = match X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()).as_ref() {
218 Ok(xconn) => xconn.clone(),
219 Err(err) => return Err(os_error!(err.clone()).into()),
220 };
221
222 let root = xconn.default_root().root;
223 let atoms = xconn.atoms();
224
225 let wm_delete_window = atoms[WM_DELETE_WINDOW];
226 let net_wm_ping = atoms[_NET_WM_PING];
227 let net_wm_sync_request = atoms[_NET_WM_SYNC_REQUEST];
228
229 let dnd = Dnd::new(Arc::clone(&xconn))
230 .expect("Failed to call XInternAtoms when initializing drag and drop");
231
232 let (ime_sender, ime_receiver) = mpsc::channel();
233 let (ime_event_sender, ime_event_receiver) = mpsc::channel();
234 unsafe {
237 let default_locale = setlocale(LC_CTYPE, ptr::null());
240 setlocale(LC_CTYPE, c"".as_ptr() as *const _);
241
242 let locale_supported = (xconn.xlib.XSupportsLocale)() == 1;
246 if !locale_supported {
247 let unsupported_locale = setlocale(LC_CTYPE, ptr::null());
248 warn!(
249 "Unsupported locale \"{}\". Restoring default locale \"{}\".",
250 CStr::from_ptr(unsupported_locale).to_string_lossy(),
251 CStr::from_ptr(default_locale).to_string_lossy()
252 );
253 setlocale(LC_CTYPE, default_locale);
255 }
256 }
257
258 let ime = Ime::new(Arc::clone(&xconn), ime_event_sender);
259 if let Err(ImeCreationError::OpenFailure(state)) = ime.as_ref() {
260 warn!("Failed to open input method: {state:#?}");
261 } else if let Err(err) = ime.as_ref() {
262 warn!("Failed to set input method destruction callback: {err:?}");
263 }
264
265 let ime = ime.ok().map(RefCell::new);
266
267 let randr_event_offset =
268 xconn.select_xrandr_input(root).expect("Failed to query XRandR extension");
269
270 let xi2ext = xconn
271 .xcb_connection()
272 .extension_information(xinput::X11_EXTENSION_NAME)
273 .expect("Failed to query XInput extension")
274 .expect("X server missing XInput extension");
275 let xkbext = xconn
276 .xcb_connection()
277 .extension_information(xkb::X11_EXTENSION_NAME)
278 .expect("Failed to query XKB extension")
279 .expect("X server missing XKB extension");
280
281 xconn
283 .xcb_connection()
284 .xinput_xi_query_version(2, 3)
285 .expect("Failed to send XInput2 query version request")
286 .reply()
287 .expect("Error while checking for XInput2 query version reply");
288
289 xconn.update_cached_wm_info(root);
290
291 let event_loop =
293 Loop::<EventLoopState>::try_new().expect("Failed to initialize the event loop");
294 let handle = event_loop.handle();
295
296 let source = X11Source::new(
298 unsafe { BorrowedFd::borrow_raw(xconn.xcb_connection().as_raw_fd()) },
300 calloop::Interest::READ,
301 calloop::Mode::Level,
302 );
303 handle
304 .insert_source(source, |readiness, _, state| {
305 state.x11_readiness = readiness;
306 Ok(calloop::PostAction::Continue)
307 })
308 .expect("Failed to register the X11 event dispatcher");
309
310 let (waker, waker_source) =
311 calloop::ping::make_ping().expect("Failed to create event loop waker");
312 event_loop
313 .handle()
314 .insert_source(waker_source, move |_, _, _| {
315 })
317 .expect("Failed to register the event loop waker source");
318
319 let (redraw_sender, redraw_channel) = mpsc::channel();
321
322 let (activation_token_sender, activation_token_channel) = mpsc::channel();
324
325 let (user_waker, user_waker_source) =
327 calloop::ping::make_ping().expect("Failed to create user event loop waker.");
328 event_loop
329 .handle()
330 .insert_source(user_waker_source, move |_, _, state| {
331 state.proxy_wake_up = true;
333 })
334 .expect("Failed to register the event loop waker source");
335 let event_loop_proxy = EventLoopProxy::new(user_waker);
336
337 let xkb_context =
338 Context::from_x11_xkb(xconn.xcb_connection().get_raw_xcb_connection()).unwrap();
339
340 let mut xmodmap = util::ModifierKeymap::new();
341 xmodmap.reload_from_x_connection(&xconn);
342
343 let window_target = ActiveEventLoop {
344 ime,
345 root,
346 control_flow: Cell::new(ControlFlow::default()),
347 exit: Cell::new(None),
348 windows: Default::default(),
349 ime_sender,
350 xconn,
351 wm_delete_window,
352 net_wm_ping,
353 net_wm_sync_request,
354 redraw_sender: WakeSender {
355 sender: redraw_sender, waker: waker.clone(),
357 },
358 activation_sender: WakeSender {
359 sender: activation_token_sender, waker: waker.clone(),
361 },
362 event_loop_proxy: event_loop_proxy.into(),
363 device_events: Default::default(),
364 };
365
366 window_target.update_listen_device_events(true);
368
369 let event_processor = EventProcessor {
370 target: window_target,
371 dnd,
372 devices: Default::default(),
373 randr_event_offset,
374 ime_receiver,
375 ime_event_receiver,
376 xi2ext,
377 xfiltered_modifiers: VecDeque::with_capacity(MAX_MOD_REPLAY_LEN),
378 xmodmap,
379 xkbext,
380 xkb_context,
381 num_touch: 0,
382 held_key_press: None,
383 first_touch: None,
384 active_window: None,
385 modifiers: Default::default(),
386 is_composing: false,
387 };
388
389 event_processor
392 .target
393 .xconn
394 .select_xinput_events(
395 root,
396 ALL_DEVICES,
397 x11rb::protocol::xinput::XIEventMask::HIERARCHY,
398 )
399 .expect_then_ignore_error("Failed to register for XInput2 device hotplug events");
400
401 event_processor
402 .target
403 .xconn
404 .select_xkb_events(
405 0x100, xkb::EventType::NEW_KEYBOARD_NOTIFY
407 | xkb::EventType::MAP_NOTIFY
408 | xkb::EventType::STATE_NOTIFY,
409 )
410 .unwrap();
411
412 event_processor.init_device(ALL_DEVICES);
413
414 let event_loop = EventLoop {
415 loop_running: false,
416 event_loop,
417 event_processor,
418 redraw_receiver: PeekableReceiver::from_recv(redraw_channel),
419 activation_receiver: PeekableReceiver::from_recv(activation_token_channel),
420 state: EventLoopState { x11_readiness: Readiness::EMPTY, proxy_wake_up: false },
421 };
422
423 Ok(event_loop)
424 }
425
426 pub fn window_target(&self) -> &dyn RootActiveEventLoop {
427 &self.event_processor.target
428 }
429
430 pub fn run_app_on_demand<A: ApplicationHandler>(
431 &mut self,
432 mut app: A,
433 ) -> Result<(), EventLoopError> {
434 self.event_processor.target.clear_exit();
435 let exit = loop {
436 match self.pump_app_events(None, &mut app) {
437 PumpStatus::Exit(0) => {
438 break Ok(());
439 },
440 PumpStatus::Exit(code) => {
441 break Err(EventLoopError::ExitFailure(code));
442 },
443 _ => {
444 continue;
445 },
446 }
447 };
448
449 self.event_processor
454 .target
455 .x_connection()
456 .sync_with_server()
457 .map_err(|x_err| EventLoopError::Os(os_error!(X11Error::Xlib(x_err))))?;
458
459 exit
460 }
461
462 pub fn pump_app_events<A: ApplicationHandler>(
463 &mut self,
464 timeout: Option<Duration>,
465 mut app: A,
466 ) -> PumpStatus {
467 if !self.loop_running {
468 self.loop_running = true;
469
470 self.single_iteration(&mut app, StartCause::Init);
472 }
473
474 if !self.exiting() {
477 self.poll_events_with_timeout(timeout, &mut app);
478 }
479 if let Some(code) = self.exit_code() {
480 self.loop_running = false;
481
482 PumpStatus::Exit(code)
483 } else {
484 PumpStatus::Continue
485 }
486 }
487
488 fn has_pending(&mut self) -> bool {
489 self.event_processor.poll()
490 || self.state.proxy_wake_up
491 || self.redraw_receiver.has_incoming()
492 }
493
494 fn poll_events_with_timeout<A: ApplicationHandler>(
495 &mut self,
496 mut timeout: Option<Duration>,
497 app: &mut A,
498 ) {
499 let start = Instant::now();
500
501 let has_pending = self.has_pending();
502
503 timeout = if has_pending {
504 Some(Duration::ZERO)
506 } else {
507 let control_flow_timeout = match self.control_flow() {
508 ControlFlow::Wait => None,
509 ControlFlow::Poll => Some(Duration::ZERO),
510 ControlFlow::WaitUntil(wait_deadline) => {
511 Some(wait_deadline.saturating_duration_since(start))
512 },
513 };
514
515 min_timeout(control_flow_timeout, timeout)
516 };
517
518 self.state.x11_readiness = Readiness::EMPTY;
519 if let Err(error) =
520 self.event_loop.dispatch(timeout, &mut self.state).map_err(std::io::Error::from)
521 {
522 tracing::error!("Failed to poll for events: {error:?}");
523 let exit_code = error.raw_os_error().unwrap_or(1);
524 self.set_exit_code(exit_code);
525 return;
526 }
527
528 let cause = match self.control_flow() {
531 ControlFlow::Poll => StartCause::Poll,
532 ControlFlow::Wait => StartCause::WaitCancelled { start, requested_resume: None },
533 ControlFlow::WaitUntil(deadline) => {
534 if Instant::now() < deadline {
535 StartCause::WaitCancelled { start, requested_resume: Some(deadline) }
536 } else {
537 StartCause::ResumeTimeReached { start, requested_resume: deadline }
538 }
539 },
540 };
541
542 if !self.has_pending()
551 && !matches!(&cause, StartCause::ResumeTimeReached { .. } | StartCause::Poll)
552 && timeout.is_none()
553 {
554 return;
555 }
556
557 self.single_iteration(app, cause);
558 }
559
560 fn single_iteration<A: ApplicationHandler>(&mut self, app: &mut A, cause: StartCause) {
561 app.new_events(&self.event_processor.target, cause);
562
563 if cause == StartCause::Init {
566 app.can_create_surfaces(&self.event_processor.target)
567 }
568
569 self.drain_events(app);
571
572 while let Ok((window_id, serial)) = self.activation_receiver.try_recv() {
574 let token = self
575 .event_processor
576 .with_window(window_id.into_raw() as xproto::Window, |window| {
577 window.generate_activation_token()
578 });
579
580 match token {
581 Some(Ok(token)) => {
582 let event = WindowEvent::ActivationTokenDone {
583 serial,
584 token: winit_core::window::ActivationToken::from_raw(token),
585 };
586 app.window_event(&self.event_processor.target, window_id, event);
587 },
588 Some(Err(e)) => {
589 tracing::error!("Failed to get activation token: {}", e);
590 },
591 None => {},
592 }
593 }
594
595 if mem::take(&mut self.state.proxy_wake_up) {
597 app.proxy_wake_up(&self.event_processor.target);
598 }
599
600 {
602 let mut windows = HashSet::new();
603
604 while let Ok(window_id) = self.redraw_receiver.try_recv() {
605 windows.insert(window_id);
606 }
607
608 for window_id in windows {
609 app.window_event(
610 &self.event_processor.target,
611 window_id,
612 WindowEvent::RedrawRequested,
613 );
614 }
615 }
616
617 app.about_to_wait(&self.event_processor.target);
619 }
620
621 fn drain_events<A: ApplicationHandler>(&mut self, app: &mut A) {
622 let mut xev = MaybeUninit::uninit();
623
624 while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
625 let mut xev = unsafe { xev.assume_init() };
626 self.event_processor.process_event(&mut xev, app);
627 }
628 }
629
630 fn control_flow(&self) -> ControlFlow {
631 self.event_processor.target.control_flow()
632 }
633
634 fn exiting(&self) -> bool {
635 self.event_processor.target.exiting()
636 }
637
638 fn set_exit_code(&self, code: i32) {
639 self.event_processor.target.set_exit_code(code);
640 }
641
642 fn exit_code(&self) -> Option<i32> {
643 self.event_processor.target.exit_code()
644 }
645}
646
647impl AsFd for EventLoop {
648 fn as_fd(&self) -> BorrowedFd<'_> {
649 self.event_loop.as_fd()
650 }
651}
652
653impl AsRawFd for EventLoop {
654 fn as_raw_fd(&self) -> RawFd {
655 self.event_loop.as_raw_fd()
656 }
657}
658
659impl ActiveEventLoop {
660 #[inline]
662 pub(crate) fn x_connection(&self) -> &Arc<XConnection> {
663 &self.xconn
664 }
665
666 pub fn update_listen_device_events(&self, focus: bool) {
668 let device_events = self.device_events.get() == DeviceEvents::Always
669 || (focus && self.device_events.get() == DeviceEvents::WhenFocused);
670
671 let mut mask = xinput::XIEventMask::from(0u32);
672 if device_events {
673 mask = xinput::XIEventMask::RAW_MOTION
674 | xinput::XIEventMask::RAW_BUTTON_PRESS
675 | xinput::XIEventMask::RAW_BUTTON_RELEASE
676 | xinput::XIEventMask::RAW_KEY_PRESS
677 | xinput::XIEventMask::RAW_KEY_RELEASE;
678 }
679
680 self.xconn
681 .select_xinput_events(self.root, ALL_MASTER_DEVICES, mask)
682 .expect_then_ignore_error("Failed to update device event filter");
683 }
684
685 pub(crate) fn clear_exit(&self) {
686 self.exit.set(None)
687 }
688
689 pub(crate) fn set_exit_code(&self, code: i32) {
690 self.exit.set(Some(code))
691 }
692
693 pub(crate) fn exit_code(&self) -> Option<i32> {
694 self.exit.get()
695 }
696}
697
698impl RootActiveEventLoop for ActiveEventLoop {
699 fn create_proxy(&self) -> CoreEventLoopProxy {
700 self.event_loop_proxy.clone()
701 }
702
703 fn create_window(
704 &self,
705 window_attributes: WindowAttributes,
706 ) -> Result<Box<dyn CoreWindow>, RequestError> {
707 Ok(Box::new(Window::new(self, window_attributes)?))
708 }
709
710 fn create_custom_cursor(
711 &self,
712 custom_cursor: CustomCursorSource,
713 ) -> Result<CoreCustomCursor, RequestError> {
714 Ok(CoreCustomCursor(Arc::new(CustomCursor::new(self, custom_cursor)?)))
715 }
716
717 fn available_monitors(&self) -> Box<dyn Iterator<Item = CoreMonitorHandle>> {
718 Box::new(
719 self.xconn
720 .available_monitors()
721 .into_iter()
722 .flatten()
723 .map(|monitor| CoreMonitorHandle(Arc::new(monitor))),
724 )
725 }
726
727 fn primary_monitor(&self) -> Option<CoreMonitorHandle> {
728 self.xconn.primary_monitor().ok().map(|monitor| CoreMonitorHandle(Arc::new(monitor)))
729 }
730
731 fn system_theme(&self) -> Option<Theme> {
732 None
733 }
734
735 fn listen_device_events(&self, allowed: DeviceEvents) {
736 self.device_events.set(allowed);
737 }
738
739 fn set_control_flow(&self, control_flow: ControlFlow) {
740 self.control_flow.set(control_flow)
741 }
742
743 fn control_flow(&self) -> ControlFlow {
744 self.control_flow.get()
745 }
746
747 fn exit(&self) {
748 self.exit.set(Some(0))
749 }
750
751 fn exiting(&self) -> bool {
752 self.exit.get().is_some()
753 }
754
755 fn owned_display_handle(&self) -> CoreOwnedDisplayHandle {
756 CoreOwnedDisplayHandle::new(self.x_connection().clone())
757 }
758
759 fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
760 self
761 }
762}
763
764impl rwh_06::HasDisplayHandle for ActiveEventLoop {
765 fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
766 self.xconn.display_handle()
767 }
768}
769
770pub(crate) struct DeviceInfo<'a> {
771 xconn: &'a XConnection,
772 info: *const ffi::XIDeviceInfo,
773 count: usize,
774}
775
776impl<'a> DeviceInfo<'a> {
777 pub(crate) fn get(xconn: &'a XConnection, device: c_int) -> Option<Self> {
778 unsafe {
779 let mut count = 0;
780 let info = (xconn.xinput2.XIQueryDevice)(xconn.display, device, &mut count);
781 xconn.check_errors().ok()?;
782
783 if info.is_null() || count == 0 {
784 None
785 } else {
786 Some(DeviceInfo { xconn, info, count: count as usize })
787 }
788 }
789 }
790}
791
792impl Drop for DeviceInfo<'_> {
793 fn drop(&mut self) {
794 assert!(!self.info.is_null());
795 unsafe { (self.xconn.xinput2.XIFreeDeviceInfo)(self.info as *mut _) };
796 }
797}
798
799impl Deref for DeviceInfo<'_> {
800 type Target = [ffi::XIDeviceInfo];
801
802 fn deref(&self) -> &Self::Target {
803 unsafe { slice::from_raw_parts(self.info, self.count) }
804 }
805}
806
807#[derive(Clone, Debug)]
808pub struct EventLoopProxy {
809 ping: Ping,
810}
811
812impl EventLoopProxyProvider for EventLoopProxy {
813 fn wake_up(&self) {
814 self.ping.ping();
815 }
816}
817
818impl EventLoopProxy {
819 fn new(ping: Ping) -> Self {
820 Self { ping }
821 }
822}
823
824impl From<EventLoopProxy> for CoreEventLoopProxy {
825 fn from(value: EventLoopProxy) -> Self {
826 CoreEventLoopProxy::new(Arc::new(value))
827 }
828}
829
830#[derive(Debug)]
832pub enum X11Error {
833 Xlib(XError),
835
836 Connect(ConnectError),
838
839 Connection(ConnectionError),
841
842 X11(LogicalError),
844
845 XidsExhausted(IdsExhausted),
847
848 UnexpectedNull(&'static str),
850
851 InvalidActivationToken(Vec<u8>),
853
854 MissingExtension(&'static str),
856
857 NoSuchVisual(xproto::Visualid),
859
860 XsettingsParse(xsettings::ParserError),
862
863 GetProperty(util::GetPropertyError),
865
866 NoArgb32Format,
868}
869
870impl fmt::Display for X11Error {
871 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
872 match self {
873 X11Error::Xlib(e) => write!(f, "Xlib error: {e}"),
874 X11Error::Connect(e) => write!(f, "X11 connection error: {e}"),
875 X11Error::Connection(e) => write!(f, "X11 connection error: {e}"),
876 X11Error::XidsExhausted(e) => write!(f, "XID range exhausted: {e}"),
877 X11Error::GetProperty(e) => write!(f, "Failed to get X property {e}"),
878 X11Error::X11(e) => write!(f, "X11 error: {e:?}"),
879 X11Error::UnexpectedNull(s) => write!(f, "Xlib function returned null: {s}"),
880 X11Error::InvalidActivationToken(s) => write!(
881 f,
882 "Invalid activation token: {}",
883 std::str::from_utf8(s).unwrap_or("<invalid utf8>")
884 ),
885 X11Error::MissingExtension(s) => write!(f, "Missing X11 extension: {s}"),
886 X11Error::NoSuchVisual(visualid) => {
887 write!(f, "Could not find a matching X11 visual for ID `{visualid:x}`")
888 },
889 X11Error::XsettingsParse(err) => {
890 write!(f, "Failed to parse xsettings: {err:?}")
891 },
892 X11Error::NoArgb32Format => {
893 f.write_str("winit only supports X11 displays with ARGB32 picture formats")
894 },
895 }
896 }
897}
898
899impl std::error::Error for X11Error {
900 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
901 match self {
902 X11Error::Xlib(e) => Some(e),
903 X11Error::Connect(e) => Some(e),
904 X11Error::Connection(e) => Some(e),
905 X11Error::XidsExhausted(e) => Some(e),
906 _ => None,
907 }
908 }
909}
910
911impl From<XError> for X11Error {
912 fn from(e: XError) -> Self {
913 X11Error::Xlib(e)
914 }
915}
916
917impl From<ConnectError> for X11Error {
918 fn from(e: ConnectError) -> Self {
919 X11Error::Connect(e)
920 }
921}
922
923impl From<ConnectionError> for X11Error {
924 fn from(e: ConnectionError) -> Self {
925 X11Error::Connection(e)
926 }
927}
928
929impl From<LogicalError> for X11Error {
930 fn from(e: LogicalError) -> Self {
931 X11Error::X11(e)
932 }
933}
934
935impl From<ReplyError> for X11Error {
936 fn from(value: ReplyError) -> Self {
937 match value {
938 ReplyError::ConnectionError(e) => e.into(),
939 ReplyError::X11Error(e) => e.into(),
940 }
941 }
942}
943
944impl From<ime::ImeContextCreationError> for X11Error {
945 fn from(value: ime::ImeContextCreationError) -> Self {
946 match value {
947 ime::ImeContextCreationError::XError(e) => e.into(),
948 ime::ImeContextCreationError::Null => Self::UnexpectedNull("XOpenIM"),
949 }
950 }
951}
952
953impl From<ReplyOrIdError> for X11Error {
954 fn from(value: ReplyOrIdError) -> Self {
955 match value {
956 ReplyOrIdError::ConnectionError(e) => e.into(),
957 ReplyOrIdError::X11Error(e) => e.into(),
958 ReplyOrIdError::IdsExhausted => Self::XidsExhausted(IdsExhausted),
959 }
960 }
961}
962
963impl From<xsettings::ParserError> for X11Error {
964 fn from(value: xsettings::ParserError) -> Self {
965 Self::XsettingsParse(value)
966 }
967}
968
969impl From<util::GetPropertyError> for X11Error {
970 fn from(value: util::GetPropertyError) -> Self {
971 Self::GetProperty(value)
972 }
973}
974
975pub(crate) type VoidCookie<'a> = x11rb::cookie::VoidCookie<'a, X11rbConnection>;
977
978pub(crate) trait CookieResultExt {
980 fn expect_then_ignore_error(self, msg: &str);
982}
983
984impl<E: fmt::Debug> CookieResultExt for Result<VoidCookie<'_>, E> {
985 fn expect_then_ignore_error(self, msg: &str) {
986 self.expect(msg).ignore_error()
987 }
988}
989
990pub(crate) fn mkwid(w: xproto::Window) -> winit_core::window::WindowId {
991 winit_core::window::WindowId::from_raw(w as _)
992}
993
994pub(crate) fn mkdid(w: xinput::DeviceId) -> DeviceId {
995 DeviceId::from_raw(w as i64)
996}
997
998#[derive(Debug)]
999pub struct Device {
1000 _name: String,
1001 pub(crate) scroll_axes: Vec<(i32, ScrollAxis)>,
1002 pub(crate) attachment: c_int,
1005 pub(crate) r#type: DeviceType,
1006}
1007
1008#[derive(Clone, Copy, Debug)]
1009pub(crate) enum DeviceType {
1010 Mouse,
1011 Touch,
1012 Pen,
1013 Eraser,
1014}
1015
1016#[derive(Debug, Copy, Clone)]
1017pub(crate) struct ScrollAxis {
1018 pub(crate) increment: f64,
1019 pub(crate) orientation: ScrollOrientation,
1020 pub(crate) position: f64,
1021}
1022
1023#[derive(Debug, Copy, Clone)]
1024pub(crate) enum ScrollOrientation {
1025 Vertical,
1026 Horizontal,
1027}
1028
1029impl Device {
1030 pub(crate) fn new(info: &ffi::XIDeviceInfo, atoms: &Atoms) -> Self {
1031 let name = unsafe { CStr::from_ptr(info.name).to_string_lossy() };
1032 let mut scroll_axes = Vec::new();
1033 let mut r#type = None;
1034
1035 if Device::physical_device(info) {
1036 for &class_ptr in Device::classes(info) {
1038 let ty = unsafe { (*class_ptr)._type };
1039 if ty == ffi::XIScrollClass {
1040 let info = unsafe { &*(class_ptr as *const ffi::XIScrollClassInfo) };
1041 scroll_axes.push((info.number, ScrollAxis {
1042 increment: info.increment,
1043 orientation: match info.scroll_type {
1044 ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal,
1045 ffi::XIScrollTypeVertical => ScrollOrientation::Vertical,
1046 _ => unreachable!(),
1047 },
1048 position: 0.0,
1049 }));
1050 } else if ty == ffi::XITouchClass {
1051 r#type = Some(DeviceType::Touch);
1052 } else if r#type.is_none() && ty == ffi::XIValuatorClass {
1053 let info = unsafe { &*(class_ptr as *const ffi::XIValuatorClassInfo) };
1054 let atom = info.label as xproto::Atom;
1055
1056 if atom == atoms[ABS_X]
1057 || atom == atoms[ABS_Y]
1058 || atom == atoms[ABS_PRESSURE]
1059 || atom == atoms[ABS_TILT_X]
1060 || atom == atoms[ABS_TILT_Y]
1061 {
1062 if name.contains("eraser") {
1063 r#type = Some(DeviceType::Eraser);
1064 } else {
1065 r#type = Some(DeviceType::Pen);
1066 }
1067 }
1068 }
1069 }
1070 }
1071
1072 let mut device = Device {
1073 _name: name.into_owned(),
1074 scroll_axes,
1075 attachment: info.attachment,
1076 r#type: r#type.unwrap_or(DeviceType::Mouse),
1077 };
1078 device.reset_scroll_position(info);
1079 device
1080 }
1081
1082 pub(crate) fn reset_scroll_position(&mut self, info: &ffi::XIDeviceInfo) {
1083 if Device::physical_device(info) {
1084 for &class_ptr in Device::classes(info) {
1085 let ty = unsafe { (*class_ptr)._type };
1086 if ty == ffi::XIValuatorClass {
1087 let info = unsafe { &*(class_ptr as *const ffi::XIValuatorClassInfo) };
1088 if let Some(&mut (_, ref mut axis)) =
1089 self.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == info.number)
1090 {
1091 axis.position = info.value;
1092 }
1093 }
1094 }
1095 }
1096 }
1097
1098 #[inline]
1099 fn physical_device(info: &ffi::XIDeviceInfo) -> bool {
1100 info._use == ffi::XISlaveKeyboard
1101 || info._use == ffi::XISlavePointer
1102 || info._use == ffi::XIFloatingSlave
1103 }
1104
1105 #[inline]
1106 fn classes(info: &ffi::XIDeviceInfo) -> &[*const ffi::XIAnyClassInfo] {
1107 unsafe {
1108 slice::from_raw_parts(
1109 info.classes as *const *const ffi::XIAnyClassInfo,
1110 info.num_classes as usize,
1111 )
1112 }
1113 }
1114}
1115
1116#[inline]
1118pub(crate) fn xinput_fp1616_to_float(fp: xinput::Fp1616) -> f64 {
1119 (fp as f64) / ((1 << 16) as f64)
1120}
1121
1122fn min_timeout(a: Option<Duration>, b: Option<Duration>) -> Option<Duration> {
1126 a.map_or(b, |a_timeout| b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout))))
1127}