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