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
52pub(crate) const ALL_DEVICES: u16 = 0;
54pub(crate) const ALL_MASTER_DEVICES: u16 = 1;
55pub(crate) const ICONIC_STATE: u32 = 3;
56
57type 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
65pub(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 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 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 if !error_handled {
105 tracing::error!("X11 error: {:#?}", error);
106 *xconn.latest_error.lock().unwrap() = Some(error);
108 }
109 }
110 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 state: EventLoopState,
201}
202
203pub(crate) type ActivationItem = (WindowId, winit_core::event_loop::AsyncRequestSerial);
204
205#[derive(Debug)]
206struct EventLoopState {
207 x11_readiness: Readiness,
209
210 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 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 unsafe {
244 let default_locale = setlocale(LC_CTYPE, ptr::null());
247 setlocale(LC_CTYPE, c"".as_ptr() as *const _);
248
249 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 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 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 let event_loop =
313 Loop::<EventLoopState>::try_new().expect("Failed to initialize the event loop");
314 let handle = event_loop.handle();
315
316 let source = X11Source::new(
318 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 })
337 .expect("Failed to register the event loop waker source");
338
339 let (redraw_sender, redraw_channel) = mpsc::channel();
341
342 let (activation_token_sender, activation_token_channel) = mpsc::channel();
344
345 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 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, waker: waker.clone(),
378 },
379 activation_sender: WakeSender {
380 sender: activation_token_sender, waker: waker.clone(),
382 },
383 event_loop_proxy: event_loop_proxy.into(),
384 device_events: Default::default(),
385 };
386
387 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 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, 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 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 self.single_iteration(&mut app, StartCause::Init);
492 }
493
494 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 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 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 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 if cause == StartCause::Init {
586 app.can_create_surfaces(&self.event_processor.target)
587 }
588
589 self.drain_events(app);
591
592 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 if mem::take(&mut self.state.proxy_wake_up) {
617 app.proxy_wake_up(&self.event_processor.target);
618 }
619
620 {
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 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 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 #[inline]
716 pub(crate) fn x_connection(&self) -> &Arc<XConnection> {
717 &self.xconn
718 }
719
720 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 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 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#[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#[derive(Debug)]
983pub enum X11Error {
984 Xlib(XError),
986
987 Connect(ConnectError),
989
990 Connection(ConnectionError),
992
993 X11(LogicalError),
995
996 XidsExhausted(IdsExhausted),
998
999 UnexpectedNull(&'static str),
1001
1002 InvalidActivationToken(Vec<u8>),
1004
1005 MissingExtension(&'static str),
1007
1008 NoSuchVisual(xproto::Visualid),
1010
1011 XsettingsParse(xsettings::ParserError),
1013
1014 GetProperty(util::GetPropertyError),
1016
1017 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
1126pub(crate) type VoidCookie<'a> = x11rb::cookie::VoidCookie<'a, X11rbConnection>;
1128
1129pub(crate) trait CookieResultExt {
1131 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 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 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 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#[inline]
1275pub(crate) fn xinput_fp1616_to_float(fp: xinput::Fp1616) -> f64 {
1276 (fp as f64) / ((1 << 16) as f64)
1277}
1278
1279fn 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}