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