1#![cfg(x11_platform)]
2
3use std::cell::{Cell, RefCell};
4use std::collections::{HashMap, HashSet, VecDeque};
5use std::ffi::CStr;
6use std::fmt;
7use std::marker::PhantomData;
8use std::mem::MaybeUninit;
9use std::ops::Deref;
10use std::os::raw::*;
11use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
12use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
13use std::sync::{Arc, Weak};
14use std::time::{Duration, Instant};
15use std::{ptr, slice, str};
16
17pub use self::xdisplay::{XError, XNotSupported};
18
19use calloop::generic::Generic;
20use calloop::EventLoop as Loop;
21use calloop::{ping::Ping, Readiness};
22use libc::{setlocale, LC_CTYPE};
23use log::warn;
24
25use x11rb::connection::RequestConnection;
26use x11rb::errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError};
27use x11rb::protocol::xinput::{self, ConnectionExt as _};
28use x11rb::protocol::xkb;
29use x11rb::protocol::xproto::{self, ConnectionExt as _};
30use x11rb::x11_utils::X11Error as LogicalError;
31use x11rb::xcb_ffi::ReplyOrIdError;
32
33use super::{ControlFlow, OsError};
34use crate::{
35 error::{EventLoopError, OsError as RootOsError},
36 event::{Event, StartCause, WindowEvent},
37 event_loop::{DeviceEvents, EventLoopClosed, EventLoopWindowTarget as RootELW},
38 platform::pump_events::PumpStatus,
39 platform_impl::common::xkb::Context,
40 platform_impl::{
41 platform::{min_timeout, WindowId},
42 PlatformSpecificWindowBuilderAttributes,
43 },
44 window::WindowAttributes,
45};
46
47mod activation;
48mod atoms;
49mod dnd;
50mod event_processor;
51pub mod ffi;
52mod ime;
53mod monitor;
54pub mod util;
55mod window;
56mod xdisplay;
57mod xsettings;
58
59use atoms::*;
60use dnd::{Dnd, DndState};
61use event_processor::{EventProcessor, MAX_MOD_REPLAY_LEN};
62use ime::{Ime, ImeCreationError, ImeReceiver, ImeRequest, ImeSender};
63pub(crate) use monitor::{MonitorHandle, VideoMode};
64use window::UnownedWindow;
65pub(crate) use xdisplay::XConnection;
66
67// Xinput constants not defined in x11rb
68const ALL_DEVICES: u16 = 0;
69const ALL_MASTER_DEVICES: u16 = 1;
70const ICONIC_STATE: u32 = 3;
71
72/// The underlying x11rb connection that we are using.
73type X11rbConnection = x11rb::xcb_ffi::XCBConnection;
74
75type X11Source = Generic<BorrowedFd<'static>>;
76
77struct WakeSender<T> {
78 sender: Sender<T>,
79 waker: Ping,
80}
81
82impl<T> Clone for WakeSender<T> {
83 fn clone(&self) -> Self {
84 Self {
85 sender: self.sender.clone(),
86 waker: self.waker.clone(),
87 }
88 }
89}
90
91impl<T> WakeSender<T> {
92 pub fn send(&self, t: T) -> Result<(), EventLoopClosed<T>> {
93 let res: Result<(), EventLoopClosed<…>> = self.sender.send(t).map_err(|e: SendError| EventLoopClosed(e.0));
94 if res.is_ok() {
95 self.waker.ping();
96 }
97 res
98 }
99}
100
101struct PeekableReceiver<T> {
102 recv: Receiver<T>,
103 first: Option<T>,
104}
105
106impl<T> PeekableReceiver<T> {
107 pub fn from_recv(recv: Receiver<T>) -> Self {
108 Self { recv, first: None }
109 }
110 pub fn has_incoming(&mut self) -> bool {
111 if self.first.is_some() {
112 return true;
113 }
114
115 match self.recv.try_recv() {
116 Ok(v) => {
117 self.first = Some(v);
118 true
119 }
120 Err(TryRecvError::Empty) => false,
121 Err(TryRecvError::Disconnected) => {
122 warn!("Channel was disconnected when checking incoming");
123 false
124 }
125 }
126 }
127 pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
128 if let Some(first) = self.first.take() {
129 return Ok(first);
130 }
131 self.recv.try_recv()
132 }
133}
134
135pub struct EventLoopWindowTarget<T> {
136 xconn: Arc<XConnection>,
137 wm_delete_window: xproto::Atom,
138 net_wm_ping: xproto::Atom,
139 ime_sender: ImeSender,
140 control_flow: Cell<ControlFlow>,
141 exit: Cell<Option<i32>>,
142 root: xproto::Window,
143 ime: Option<RefCell<Ime>>,
144 windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
145 redraw_sender: WakeSender<WindowId>,
146 activation_sender: WakeSender<ActivationToken>,
147 device_events: Cell<DeviceEvents>,
148 _marker: ::std::marker::PhantomData<T>,
149}
150
151pub struct EventLoop<T: 'static> {
152 loop_running: bool,
153 event_loop: Loop<'static, EventLoopState>,
154 waker: calloop::ping::Ping,
155 event_processor: EventProcessor<T>,
156 redraw_receiver: PeekableReceiver<WindowId>,
157 user_receiver: PeekableReceiver<T>,
158 activation_receiver: PeekableReceiver<ActivationToken>,
159 user_sender: Sender<T>,
160
161 /// The current state of the event loop.
162 state: EventLoopState,
163}
164
165type ActivationToken = (WindowId, crate::event_loop::AsyncRequestSerial);
166
167struct EventLoopState {
168 /// The latest readiness state for the x11 file descriptor
169 x11_readiness: Readiness,
170}
171
172pub struct EventLoopProxy<T: 'static> {
173 user_sender: WakeSender<T>,
174}
175
176impl<T: 'static> Clone for EventLoopProxy<T> {
177 fn clone(&self) -> Self {
178 EventLoopProxy {
179 user_sender: self.user_sender.clone(),
180 }
181 }
182}
183
184impl<T: 'static> EventLoop<T> {
185 pub(crate) fn new(xconn: Arc<XConnection>) -> EventLoop<T> {
186 let root = xconn.default_root().root;
187 let atoms = xconn.atoms();
188
189 let wm_delete_window = atoms[WM_DELETE_WINDOW];
190 let net_wm_ping = atoms[_NET_WM_PING];
191
192 let dnd = Dnd::new(Arc::clone(&xconn))
193 .expect("Failed to call XInternAtoms when initializing drag and drop");
194
195 let (ime_sender, ime_receiver) = mpsc::channel();
196 let (ime_event_sender, ime_event_receiver) = mpsc::channel();
197 // Input methods will open successfully without setting the locale, but it won't be
198 // possible to actually commit pre-edit sequences.
199 unsafe {
200 // Remember default locale to restore it if target locale is unsupported
201 // by Xlib
202 let default_locale = setlocale(LC_CTYPE, ptr::null());
203 setlocale(LC_CTYPE, b"\0".as_ptr() as *const _);
204
205 // Check if set locale is supported by Xlib.
206 // If not, calls to some Xlib functions like `XSetLocaleModifiers`
207 // will fail.
208 let locale_supported = (xconn.xlib.XSupportsLocale)() == 1;
209 if !locale_supported {
210 let unsupported_locale = setlocale(LC_CTYPE, ptr::null());
211 warn!(
212 "Unsupported locale \"{}\". Restoring default locale \"{}\".",
213 CStr::from_ptr(unsupported_locale).to_string_lossy(),
214 CStr::from_ptr(default_locale).to_string_lossy()
215 );
216 // Restore default locale
217 setlocale(LC_CTYPE, default_locale);
218 }
219 }
220
221 let ime = Ime::new(Arc::clone(&xconn), ime_event_sender);
222 if let Err(ImeCreationError::OpenFailure(state)) = ime.as_ref() {
223 warn!("Failed to open input method: {state:#?}");
224 } else if let Err(err) = ime.as_ref() {
225 warn!("Failed to set input method destruction callback: {err:?}");
226 }
227
228 let ime = ime.ok().map(RefCell::new);
229
230 let randr_event_offset = xconn
231 .select_xrandr_input(root)
232 .expect("Failed to query XRandR extension");
233
234 let xi2ext = xconn
235 .xcb_connection()
236 .extension_information(xinput::X11_EXTENSION_NAME)
237 .expect("Failed to query XInput extension")
238 .expect("X server missing XInput extension");
239 let xkbext = xconn
240 .xcb_connection()
241 .extension_information(xkb::X11_EXTENSION_NAME)
242 .expect("Failed to query XKB extension")
243 .expect("X server missing XKB extension");
244
245 // Check for XInput2 support.
246 xconn
247 .xcb_connection()
248 .xinput_xi_query_version(2, 3)
249 .expect("Failed to send XInput2 query version request")
250 .reply()
251 .expect("Error while checking for XInput2 query version reply");
252
253 xconn.update_cached_wm_info(root);
254
255 // Create an event loop.
256 let event_loop =
257 Loop::<EventLoopState>::try_new().expect("Failed to initialize the event loop");
258 let handle = event_loop.handle();
259
260 // Create the X11 event dispatcher.
261 let source = X11Source::new(
262 // SAFETY: xcb owns the FD and outlives the source.
263 unsafe { BorrowedFd::borrow_raw(xconn.xcb_connection().as_raw_fd()) },
264 calloop::Interest::READ,
265 calloop::Mode::Level,
266 );
267 handle
268 .insert_source(source, |readiness, _, state| {
269 state.x11_readiness = readiness;
270 Ok(calloop::PostAction::Continue)
271 })
272 .expect("Failed to register the X11 event dispatcher");
273
274 let (waker, waker_source) =
275 calloop::ping::make_ping().expect("Failed to create event loop waker");
276 event_loop
277 .handle()
278 .insert_source(waker_source, move |_, _, _| {
279 // No extra handling is required, we just need to wake-up.
280 })
281 .expect("Failed to register the event loop waker source");
282
283 // Create a channel for handling redraw requests.
284 let (redraw_sender, redraw_channel) = mpsc::channel();
285
286 // Create a channel for sending activation tokens.
287 let (activation_token_sender, activation_token_channel) = mpsc::channel();
288
289 // Create a channel for sending user events.
290 let (user_sender, user_channel) = mpsc::channel();
291
292 let xkb_context =
293 Context::from_x11_xkb(xconn.xcb_connection().get_raw_xcb_connection()).unwrap();
294
295 let mut xmodmap = util::ModifierKeymap::new();
296 xmodmap.reload_from_x_connection(&xconn);
297
298 let window_target = EventLoopWindowTarget {
299 ime,
300 root,
301 control_flow: Cell::new(ControlFlow::default()),
302 exit: Cell::new(None),
303 windows: Default::default(),
304 _marker: ::std::marker::PhantomData,
305 ime_sender,
306 xconn,
307 wm_delete_window,
308 net_wm_ping,
309 redraw_sender: WakeSender {
310 sender: redraw_sender, // not used again so no clone
311 waker: waker.clone(),
312 },
313 activation_sender: WakeSender {
314 sender: activation_token_sender, // not used again so no clone
315 waker: waker.clone(),
316 },
317 device_events: Default::default(),
318 };
319
320 // Set initial device event filter.
321 window_target.update_listen_device_events(true);
322
323 let root_window_target = RootELW {
324 p: super::EventLoopWindowTarget::X(window_target),
325 _marker: PhantomData,
326 };
327
328 let event_processor = EventProcessor {
329 target: root_window_target,
330 dnd,
331 devices: Default::default(),
332 randr_event_offset,
333 ime_receiver,
334 ime_event_receiver,
335 xi2ext,
336 xfiltered_modifiers: VecDeque::with_capacity(MAX_MOD_REPLAY_LEN),
337 xmodmap,
338 xkbext,
339 xkb_context,
340 num_touch: 0,
341 held_key_press: None,
342 first_touch: None,
343 active_window: None,
344 modifiers: Default::default(),
345 is_composing: false,
346 };
347
348 // Register for device hotplug events
349 // (The request buffer is flushed during `init_device`)
350 let xconn = &EventProcessor::window_target(&event_processor.target).xconn;
351
352 xconn
353 .select_xinput_events(
354 root,
355 ALL_DEVICES,
356 x11rb::protocol::xinput::XIEventMask::HIERARCHY,
357 )
358 .expect_then_ignore_error("Failed to register for XInput2 device hotplug events");
359
360 xconn
361 .select_xkb_events(
362 0x100, // Use the "core keyboard device"
363 xkb::EventType::NEW_KEYBOARD_NOTIFY
364 | xkb::EventType::MAP_NOTIFY
365 | xkb::EventType::STATE_NOTIFY,
366 )
367 .unwrap();
368
369 event_processor.init_device(ALL_DEVICES);
370
371 EventLoop {
372 loop_running: false,
373 event_loop,
374 waker,
375 event_processor,
376 redraw_receiver: PeekableReceiver::from_recv(redraw_channel),
377 activation_receiver: PeekableReceiver::from_recv(activation_token_channel),
378 user_receiver: PeekableReceiver::from_recv(user_channel),
379 user_sender,
380 state: EventLoopState {
381 x11_readiness: Readiness::EMPTY,
382 },
383 }
384 }
385
386 pub fn create_proxy(&self) -> EventLoopProxy<T> {
387 EventLoopProxy {
388 user_sender: WakeSender {
389 sender: self.user_sender.clone(),
390 waker: self.waker.clone(),
391 },
392 }
393 }
394
395 pub(crate) fn window_target(&self) -> &RootELW<T> {
396 &self.event_processor.target
397 }
398
399 pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
400 where
401 F: FnMut(Event<T>, &RootELW<T>),
402 {
403 if self.loop_running {
404 return Err(EventLoopError::AlreadyRunning);
405 }
406
407 let exit = loop {
408 match self.pump_events(None, &mut event_handler) {
409 PumpStatus::Exit(0) => {
410 break Ok(());
411 }
412 PumpStatus::Exit(code) => {
413 break Err(EventLoopError::ExitFailure(code));
414 }
415 _ => {
416 continue;
417 }
418 }
419 };
420
421 // Applications aren't allowed to carry windows between separate
422 // `run_on_demand` calls but if they have only just dropped their
423 // windows we need to make sure those last requests are sent to the
424 // X Server.
425 let wt = EventProcessor::window_target(&self.event_processor.target);
426 wt.x_connection().sync_with_server().map_err(|x_err| {
427 EventLoopError::Os(os_error!(OsError::XError(Arc::new(X11Error::Xlib(x_err)))))
428 })?;
429
430 exit
431 }
432
433 pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus
434 where
435 F: FnMut(Event<T>, &RootELW<T>),
436 {
437 if !self.loop_running {
438 self.loop_running = true;
439
440 // run the initial loop iteration
441 self.single_iteration(&mut callback, StartCause::Init);
442 }
443
444 // Consider the possibility that the `StartCause::Init` iteration could
445 // request to Exit.
446 if !self.exiting() {
447 self.poll_events_with_timeout(timeout, &mut callback);
448 }
449 if let Some(code) = self.exit_code() {
450 self.loop_running = false;
451
452 callback(Event::LoopExiting, self.window_target());
453
454 PumpStatus::Exit(code)
455 } else {
456 PumpStatus::Continue
457 }
458 }
459
460 fn has_pending(&mut self) -> bool {
461 self.event_processor.poll()
462 || self.user_receiver.has_incoming()
463 || self.redraw_receiver.has_incoming()
464 }
465
466 pub fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F)
467 where
468 F: FnMut(Event<T>, &RootELW<T>),
469 {
470 let start = Instant::now();
471
472 let has_pending = self.has_pending();
473
474 timeout = if has_pending {
475 // If we already have work to do then we don't want to block on the next poll.
476 Some(Duration::ZERO)
477 } else {
478 let control_flow_timeout = match self.control_flow() {
479 ControlFlow::Wait => None,
480 ControlFlow::Poll => Some(Duration::ZERO),
481 ControlFlow::WaitUntil(wait_deadline) => {
482 Some(wait_deadline.saturating_duration_since(start))
483 }
484 };
485
486 min_timeout(control_flow_timeout, timeout)
487 };
488
489 self.state.x11_readiness = Readiness::EMPTY;
490 if let Err(error) = self
491 .event_loop
492 .dispatch(timeout, &mut self.state)
493 .map_err(std::io::Error::from)
494 {
495 log::error!("Failed to poll for events: {error:?}");
496 let exit_code = error.raw_os_error().unwrap_or(1);
497 self.set_exit_code(exit_code);
498 return;
499 }
500
501 // NB: `StartCause::Init` is handled as a special case and doesn't need
502 // to be considered here
503 let cause = match self.control_flow() {
504 ControlFlow::Poll => StartCause::Poll,
505 ControlFlow::Wait => StartCause::WaitCancelled {
506 start,
507 requested_resume: None,
508 },
509 ControlFlow::WaitUntil(deadline) => {
510 if Instant::now() < deadline {
511 StartCause::WaitCancelled {
512 start,
513 requested_resume: Some(deadline),
514 }
515 } else {
516 StartCause::ResumeTimeReached {
517 start,
518 requested_resume: deadline,
519 }
520 }
521 }
522 };
523
524 // False positive / spurious wake ups could lead to us spamming
525 // redundant iterations of the event loop with no new events to
526 // dispatch.
527 //
528 // If there's no readable event source then we just double check if we
529 // have any pending `_receiver` events and if not we return without
530 // running a loop iteration.
531 // If we don't have any pending `_receiver`
532 if !self.has_pending()
533 && !matches!(
534 &cause,
535 StartCause::ResumeTimeReached { .. } | StartCause::Poll
536 )
537 {
538 return;
539 }
540
541 self.single_iteration(&mut callback, cause);
542 }
543
544 fn single_iteration<F>(&mut self, callback: &mut F, cause: StartCause)
545 where
546 F: FnMut(Event<T>, &RootELW<T>),
547 {
548 callback(Event::NewEvents(cause), &self.event_processor.target);
549
550 // NB: For consistency all platforms must emit a 'resumed' event even though X11
551 // applications don't themselves have a formal suspend/resume lifecycle.
552 if cause == StartCause::Init {
553 callback(Event::Resumed, &self.event_processor.target);
554 }
555
556 // Process all pending events
557 self.drain_events(callback);
558
559 // Empty activation tokens.
560 while let Ok((window_id, serial)) = self.activation_receiver.try_recv() {
561 let token = self
562 .event_processor
563 .with_window(window_id.0 as xproto::Window, |window| {
564 window.generate_activation_token()
565 });
566
567 match token {
568 Some(Ok(token)) => {
569 let event = Event::WindowEvent {
570 window_id: crate::window::WindowId(window_id),
571 event: WindowEvent::ActivationTokenDone {
572 serial,
573 token: crate::window::ActivationToken::_new(token),
574 },
575 };
576 callback(event, &self.event_processor.target)
577 }
578 Some(Err(e)) => {
579 log::error!("Failed to get activation token: {}", e);
580 }
581 None => {}
582 }
583 }
584
585 // Empty the user event buffer
586 {
587 while let Ok(event) = self.user_receiver.try_recv() {
588 callback(Event::UserEvent(event), &self.event_processor.target);
589 }
590 }
591
592 // Empty the redraw requests
593 {
594 let mut windows = HashSet::new();
595
596 while let Ok(window_id) = self.redraw_receiver.try_recv() {
597 windows.insert(window_id);
598 }
599
600 for window_id in windows {
601 let window_id = crate::window::WindowId(window_id);
602 callback(
603 Event::WindowEvent {
604 window_id,
605 event: WindowEvent::RedrawRequested,
606 },
607 &self.event_processor.target,
608 );
609 }
610 }
611
612 // This is always the last event we dispatch before poll again
613 {
614 callback(Event::AboutToWait, &self.event_processor.target);
615 }
616 }
617
618 fn drain_events<F>(&mut self, callback: &mut F)
619 where
620 F: FnMut(Event<T>, &RootELW<T>),
621 {
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
627 .process_event(&mut xev, |window_target, event| {
628 if let Event::WindowEvent {
629 window_id: crate::window::WindowId(wid),
630 event: WindowEvent::RedrawRequested,
631 } = event
632 {
633 let window_target = EventProcessor::window_target(window_target);
634 window_target.redraw_sender.send(wid).unwrap();
635 } else {
636 callback(event, window_target);
637 }
638 });
639 }
640 }
641
642 fn control_flow(&self) -> ControlFlow {
643 let window_target = EventProcessor::window_target(&self.event_processor.target);
644 window_target.control_flow()
645 }
646
647 fn exiting(&self) -> bool {
648 let window_target = EventProcessor::window_target(&self.event_processor.target);
649 window_target.exiting()
650 }
651
652 fn set_exit_code(&self, code: i32) {
653 let window_target = EventProcessor::window_target(&self.event_processor.target);
654 window_target.set_exit_code(code);
655 }
656
657 fn exit_code(&self) -> Option<i32> {
658 let window_target = EventProcessor::window_target(&self.event_processor.target);
659 window_target.exit_code()
660 }
661}
662
663impl<T> AsFd for EventLoop<T> {
664 fn as_fd(&self) -> BorrowedFd<'_> {
665 self.event_loop.as_fd()
666 }
667}
668
669impl<T> AsRawFd for EventLoop<T> {
670 fn as_raw_fd(&self) -> RawFd {
671 self.event_loop.as_raw_fd()
672 }
673}
674
675impl<T> EventLoopWindowTarget<T> {
676 /// Returns the `XConnection` of this events loop.
677 #[inline]
678 pub(crate) fn x_connection(&self) -> &Arc<XConnection> {
679 &self.xconn
680 }
681
682 pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
683 self.xconn.available_monitors().into_iter().flatten()
684 }
685
686 pub fn primary_monitor(&self) -> Option<MonitorHandle> {
687 self.xconn.primary_monitor().ok()
688 }
689
690 pub fn listen_device_events(&self, allowed: DeviceEvents) {
691 self.device_events.set(allowed);
692 }
693
694 /// Update the device event based on window focus.
695 pub fn update_listen_device_events(&self, focus: bool) {
696 let device_events = self.device_events.get() == DeviceEvents::Always
697 || (focus && self.device_events.get() == DeviceEvents::WhenFocused);
698
699 let mut mask = xinput::XIEventMask::from(0u32);
700 if device_events {
701 mask = xinput::XIEventMask::RAW_MOTION
702 | xinput::XIEventMask::RAW_BUTTON_PRESS
703 | xinput::XIEventMask::RAW_BUTTON_RELEASE
704 | xinput::XIEventMask::RAW_KEY_PRESS
705 | xinput::XIEventMask::RAW_KEY_RELEASE;
706 }
707
708 self.xconn
709 .select_xinput_events(self.root, ALL_MASTER_DEVICES, mask)
710 .expect_then_ignore_error("Failed to update device event filter");
711 }
712
713 #[cfg(feature = "rwh_05")]
714 pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
715 let mut display_handle = rwh_05::XlibDisplayHandle::empty();
716 display_handle.display = self.xconn.display as *mut _;
717 display_handle.screen = self.xconn.default_screen_index() as c_int;
718 display_handle.into()
719 }
720
721 #[cfg(feature = "rwh_06")]
722 pub fn raw_display_handle_rwh_06(
723 &self,
724 ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
725 let display_handle = rwh_06::XlibDisplayHandle::new(
726 // SAFETY: display will never be null
727 Some(
728 std::ptr::NonNull::new(self.xconn.display as *mut _)
729 .expect("X11 display should never be null"),
730 ),
731 self.xconn.default_screen_index() as c_int,
732 );
733 Ok(display_handle.into())
734 }
735
736 pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
737 self.control_flow.set(control_flow)
738 }
739
740 pub(crate) fn control_flow(&self) -> ControlFlow {
741 self.control_flow.get()
742 }
743
744 pub(crate) fn exit(&self) {
745 self.exit.set(Some(0))
746 }
747
748 pub(crate) fn clear_exit(&self) {
749 self.exit.set(None)
750 }
751
752 pub(crate) fn exiting(&self) -> bool {
753 self.exit.get().is_some()
754 }
755
756 pub(crate) fn set_exit_code(&self, code: i32) {
757 self.exit.set(Some(code))
758 }
759
760 pub(crate) fn exit_code(&self) -> Option<i32> {
761 self.exit.get()
762 }
763}
764
765impl<T: 'static> EventLoopProxy<T> {
766 pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
767 self.user_sender
768 .send(event)
769 .map_err(|e: EventLoopClosed| EventLoopClosed(e.0))
770 }
771}
772
773struct DeviceInfo<'a> {
774 xconn: &'a XConnection,
775 info: *const ffi::XIDeviceInfo,
776 count: usize,
777}
778
779impl<'a> DeviceInfo<'a> {
780 fn get(xconn: &'a XConnection, device: c_int) -> Option<Self> {
781 unsafe {
782 let mut count: i32 = 0;
783 let info: *mut XIDeviceInfo = (xconn.xinput2.XIQueryDevice)(xconn.display, device, &mut count);
784 xconn.check_errors().ok()?;
785
786 if info.is_null() || count == 0 {
787 None
788 } else {
789 Some(DeviceInfo {
790 xconn,
791 info,
792 count: count as usize,
793 })
794 }
795 }
796 }
797}
798
799impl<'a> Drop for DeviceInfo<'a> {
800 fn drop(&mut self) {
801 assert!(!self.info.is_null());
802 unsafe { (self.xconn.xinput2.XIFreeDeviceInfo)(self.info as *mut _) };
803 }
804}
805
806impl<'a> Deref for DeviceInfo<'a> {
807 type Target = [ffi::XIDeviceInfo];
808 fn deref(&self) -> &Self::Target {
809 unsafe { slice::from_raw_parts(self.info, self.count) }
810 }
811}
812
813#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
814pub struct DeviceId(xinput::DeviceId);
815
816impl DeviceId {
817 #[allow(unused)]
818 pub const unsafe fn dummy() -> Self {
819 DeviceId(0)
820 }
821}
822
823pub(crate) struct Window(Arc<UnownedWindow>);
824
825impl Deref for Window {
826 type Target = UnownedWindow;
827 #[inline]
828 fn deref(&self) -> &UnownedWindow {
829 &self.0
830 }
831}
832
833impl Window {
834 pub(crate) fn new<T>(
835 event_loop: &EventLoopWindowTarget<T>,
836 attribs: WindowAttributes,
837 pl_attribs: PlatformSpecificWindowBuilderAttributes,
838 ) -> Result<Self, RootOsError> {
839 let window: Arc = Arc::new(data:UnownedWindow::new(event_loop, window_attrs:attribs, pl_attribs)?);
840 event_loop
841 .windows
842 .borrow_mut()
843 .insert(k:window.id(), v:Arc::downgrade(&window));
844 Ok(Window(window))
845 }
846}
847
848impl Drop for Window {
849 fn drop(&mut self) {
850 let window: &Window = self.deref();
851 let xconn: &Arc = &window.xconn;
852
853 if let Ok(c: VoidCookie<'_, XCBConnection>) = xconn&XCBConnection
854 .xcb_connection()
855 .destroy_window(window.id().0 as xproto::Window)
856 {
857 c.ignore_error();
858 }
859 }
860}
861
862/// Generic sum error type for X11 errors.
863#[derive(Debug)]
864pub enum X11Error {
865 /// An error from the Xlib library.
866 Xlib(XError),
867
868 /// An error that occurred while trying to connect to the X server.
869 Connect(ConnectError),
870
871 /// An error that occurred over the connection medium.
872 Connection(ConnectionError),
873
874 /// An error that occurred logically on the X11 end.
875 X11(LogicalError),
876
877 /// The XID range has been exhausted.
878 XidsExhausted(IdsExhausted),
879
880 /// Got `null` from an Xlib function without a reason.
881 UnexpectedNull(&'static str),
882
883 /// Got an invalid activation token.
884 InvalidActivationToken(Vec<u8>),
885
886 /// An extension that we rely on is not available.
887 MissingExtension(&'static str),
888
889 /// Could not find a matching X11 visual for this visualid
890 NoSuchVisual(xproto::Visualid),
891
892 /// Unable to parse xsettings.
893 XsettingsParse(xsettings::ParserError),
894
895 /// Failed to get property.
896 GetProperty(util::GetPropertyError),
897}
898
899impl fmt::Display for X11Error {
900 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
901 match self {
902 X11Error::Xlib(e) => write!(f, "Xlib error: {}", e),
903 X11Error::Connect(e) => write!(f, "X11 connection error: {}", e),
904 X11Error::Connection(e) => write!(f, "X11 connection error: {}", e),
905 X11Error::XidsExhausted(e) => write!(f, "XID range exhausted: {}", e),
906 X11Error::GetProperty(e) => write!(f, "Failed to get X property {}", e),
907 X11Error::X11(e) => write!(f, "X11 error: {:?}", e),
908 X11Error::UnexpectedNull(s) => write!(f, "Xlib function returned null: {}", s),
909 X11Error::InvalidActivationToken(s) => write!(
910 f,
911 "Invalid activation token: {}",
912 std::str::from_utf8(s).unwrap_or("<invalid utf8>")
913 ),
914 X11Error::MissingExtension(s) => write!(f, "Missing X11 extension: {}", s),
915 X11Error::NoSuchVisual(visualid) => {
916 write!(
917 f,
918 "Could not find a matching X11 visual for ID `{:x}`",
919 visualid
920 )
921 }
922 X11Error::XsettingsParse(err) => {
923 write!(f, "Failed to parse xsettings: {:?}", err)
924 }
925 }
926 }
927}
928
929impl std::error::Error for X11Error {
930 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
931 match self {
932 X11Error::Xlib(e: &XError) => Some(e),
933 X11Error::Connect(e: &ConnectError) => Some(e),
934 X11Error::Connection(e: &ConnectionError) => Some(e),
935 X11Error::XidsExhausted(e: &IdsExhausted) => Some(e),
936 _ => None,
937 }
938 }
939}
940
941impl From<XError> for X11Error {
942 fn from(e: XError) -> Self {
943 X11Error::Xlib(e)
944 }
945}
946
947impl From<ConnectError> for X11Error {
948 fn from(e: ConnectError) -> Self {
949 X11Error::Connect(e)
950 }
951}
952
953impl From<ConnectionError> for X11Error {
954 fn from(e: ConnectionError) -> Self {
955 X11Error::Connection(e)
956 }
957}
958
959impl From<LogicalError> for X11Error {
960 fn from(e: LogicalError) -> Self {
961 X11Error::X11(e)
962 }
963}
964
965impl From<ReplyError> for X11Error {
966 fn from(value: ReplyError) -> Self {
967 match value {
968 ReplyError::ConnectionError(e: ConnectionError) => e.into(),
969 ReplyError::X11Error(e: X11Error) => e.into(),
970 }
971 }
972}
973
974impl From<ime::ImeContextCreationError> for X11Error {
975 fn from(value: ime::ImeContextCreationError) -> Self {
976 match value {
977 ime::ImeContextCreationError::XError(e: XError) => e.into(),
978 ime::ImeContextCreationError::Null => Self::UnexpectedNull("XOpenIM"),
979 }
980 }
981}
982
983impl From<ReplyOrIdError> for X11Error {
984 fn from(value: ReplyOrIdError) -> Self {
985 match value {
986 ReplyOrIdError::ConnectionError(e: ConnectionError) => e.into(),
987 ReplyOrIdError::X11Error(e: X11Error) => e.into(),
988 ReplyOrIdError::IdsExhausted => Self::XidsExhausted(IdsExhausted),
989 }
990 }
991}
992
993impl From<xsettings::ParserError> for X11Error {
994 fn from(value: xsettings::ParserError) -> Self {
995 Self::XsettingsParse(value)
996 }
997}
998
999impl From<util::GetPropertyError> for X11Error {
1000 fn from(value: util::GetPropertyError) -> Self {
1001 Self::GetProperty(value)
1002 }
1003}
1004
1005/// Type alias for a void cookie.
1006type VoidCookie<'a> = x11rb::cookie::VoidCookie<'a, X11rbConnection>;
1007
1008/// Extension trait for `Result<VoidCookie, E>`.
1009trait CookieResultExt {
1010 /// Unwrap the send error and ignore the result.
1011 fn expect_then_ignore_error(self, msg: &str);
1012}
1013
1014impl<'a, E: fmt::Debug> CookieResultExt for Result<VoidCookie<'a>, E> {
1015 fn expect_then_ignore_error(self, msg: &str) {
1016 self.expect(msg).ignore_error()
1017 }
1018}
1019
1020fn mkwid(w: xproto::Window) -> crate::window::WindowId {
1021 crate::window::WindowId(crate::platform_impl::platform::WindowId(w as _))
1022}
1023fn mkdid(w: xinput::DeviceId) -> crate::event::DeviceId {
1024 crate::event::DeviceId(crate::platform_impl::DeviceId::X(DeviceId(w)))
1025}
1026
1027#[derive(Debug)]
1028pub struct Device {
1029 _name: String,
1030 scroll_axes: Vec<(i32, ScrollAxis)>,
1031 // For master devices, this is the paired device (pointer <-> keyboard).
1032 // For slave devices, this is the master.
1033 attachment: c_int,
1034}
1035
1036#[derive(Debug, Copy, Clone)]
1037struct ScrollAxis {
1038 increment: f64,
1039 orientation: ScrollOrientation,
1040 position: f64,
1041}
1042
1043#[derive(Debug, Copy, Clone)]
1044enum ScrollOrientation {
1045 Vertical,
1046 Horizontal,
1047}
1048
1049impl Device {
1050 fn new(info: &ffi::XIDeviceInfo) -> Self {
1051 let name = unsafe { CStr::from_ptr(info.name).to_string_lossy() };
1052 let mut scroll_axes = Vec::new();
1053
1054 if Device::physical_device(info) {
1055 // Identify scroll axes
1056 for &class_ptr in Device::classes(info) {
1057 let ty = unsafe { (*class_ptr)._type };
1058 if ty == ffi::XIScrollClass {
1059 let info = unsafe { &*(class_ptr as *const ffi::XIScrollClassInfo) };
1060 scroll_axes.push((
1061 info.number,
1062 ScrollAxis {
1063 increment: info.increment,
1064 orientation: match info.scroll_type {
1065 ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal,
1066 ffi::XIScrollTypeVertical => ScrollOrientation::Vertical,
1067 _ => unreachable!(),
1068 },
1069 position: 0.0,
1070 },
1071 ));
1072 }
1073 }
1074 }
1075
1076 let mut device = Device {
1077 _name: name.into_owned(),
1078 scroll_axes,
1079 attachment: info.attachment,
1080 };
1081 device.reset_scroll_position(info);
1082 device
1083 }
1084
1085 fn reset_scroll_position(&mut self, info: &ffi::XIDeviceInfo) {
1086 if Device::physical_device(info) {
1087 for &class_ptr in Device::classes(info) {
1088 let ty = unsafe { (*class_ptr)._type };
1089 if ty == ffi::XIValuatorClass {
1090 let info = unsafe { &*(class_ptr as *const ffi::XIValuatorClassInfo) };
1091 if let Some(&mut (_, ref mut axis)) = self
1092 .scroll_axes
1093 .iter_mut()
1094 .find(|&&mut (axis, _)| axis == info.number)
1095 {
1096 axis.position = info.value;
1097 }
1098 }
1099 }
1100 }
1101 }
1102
1103 #[inline]
1104 fn physical_device(info: &ffi::XIDeviceInfo) -> bool {
1105 info._use == ffi::XISlaveKeyboard
1106 || info._use == ffi::XISlavePointer
1107 || info._use == ffi::XIFloatingSlave
1108 }
1109
1110 #[inline]
1111 fn classes(info: &ffi::XIDeviceInfo) -> &[*const ffi::XIAnyClassInfo] {
1112 unsafe {
1113 slice::from_raw_parts(
1114 info.classes as *const *const ffi::XIAnyClassInfo,
1115 info.num_classes as usize,
1116 )
1117 }
1118 }
1119}
1120
1121/// Convert the raw X11 representation for a 32-bit floating point to a double.
1122#[inline]
1123fn xinput_fp1616_to_float(fp: xinput::Fp1616) -> f64 {
1124 (fp as f64) / ((1 << 16) as f64)
1125}
1126