1 #![cfg(any(
2     target_os = "linux",
3     target_os = "dragonfly",
4     target_os = "freebsd",
5     target_os = "netbsd",
6     target_os = "openbsd"
7 ))]
8 
9 mod dnd;
10 mod event_processor;
11 mod events;
12 pub mod ffi;
13 mod ime;
14 mod monitor;
15 pub mod util;
16 mod window;
17 mod xdisplay;
18 
19 pub use self::{
20     monitor::{MonitorHandle, VideoMode},
21     window::UnownedWindow,
22     xdisplay::{XConnection, XError, XNotSupported},
23 };
24 
25 use std::{
26     cell::RefCell,
27     collections::{HashMap, HashSet},
28     ffi::CStr,
29     mem::{self, MaybeUninit},
30     ops::Deref,
31     os::raw::*,
32     ptr,
33     rc::Rc,
34     slice,
35     sync::{mpsc, Arc, Mutex, Weak},
36     time::{Duration, Instant},
37 };
38 
39 use libc::{self, setlocale, LC_CTYPE};
40 
41 use mio::{unix::EventedFd, Events, Poll, PollOpt, Ready, Token};
42 
43 use mio_extras::channel::{channel, Receiver, SendError, Sender};
44 
45 use self::{
46     dnd::{Dnd, DndState},
47     event_processor::EventProcessor,
48     ime::{Ime, ImeCreationError, ImeReceiver, ImeSender},
49     util::modifiers::ModifierKeymap,
50 };
51 use crate::{
52     error::OsError as RootOsError,
53     event::{Event, StartCause},
54     event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
55     platform_impl::{platform::sticky_exit_callback, PlatformSpecificWindowBuilderAttributes},
56     window::WindowAttributes,
57 };
58 
59 const X_TOKEN: Token = Token(0);
60 const USER_TOKEN: Token = Token(1);
61 
62 pub struct EventLoopWindowTarget<T> {
63     xconn: Arc<XConnection>,
64     wm_delete_window: ffi::Atom,
65     net_wm_ping: ffi::Atom,
66     ime_sender: ImeSender,
67     root: ffi::Window,
68     ime: RefCell<Ime>,
69     windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
70     pending_redraws: Arc<Mutex<HashSet<WindowId>>>,
71     _marker: ::std::marker::PhantomData<T>,
72 }
73 
74 pub struct EventLoop<T: 'static> {
75     poll: Poll,
76     event_processor: EventProcessor<T>,
77     user_channel: Receiver<T>,
78     user_sender: Sender<T>,
79     target: Rc<RootELW<T>>,
80 }
81 
82 pub struct EventLoopProxy<T: 'static> {
83     user_sender: Sender<T>,
84 }
85 
86 impl<T: 'static> Clone for EventLoopProxy<T> {
clone(&self) -> Self87     fn clone(&self) -> Self {
88         EventLoopProxy {
89             user_sender: self.user_sender.clone(),
90         }
91     }
92 }
93 
94 impl<T: 'static> EventLoop<T> {
new(xconn: Arc<XConnection>) -> EventLoop<T>95     pub fn new(xconn: Arc<XConnection>) -> EventLoop<T> {
96         let root = unsafe { (xconn.xlib.XDefaultRootWindow)(xconn.display) };
97 
98         let wm_delete_window = unsafe { xconn.get_atom_unchecked(b"WM_DELETE_WINDOW\0") };
99 
100         let net_wm_ping = unsafe { xconn.get_atom_unchecked(b"_NET_WM_PING\0") };
101 
102         let dnd = Dnd::new(Arc::clone(&xconn))
103             .expect("Failed to call XInternAtoms when initializing drag and drop");
104 
105         let (ime_sender, ime_receiver) = mpsc::channel();
106         // Input methods will open successfully without setting the locale, but it won't be
107         // possible to actually commit pre-edit sequences.
108         unsafe {
109             // Remember default locale to restore it if target locale is unsupported
110             // by Xlib
111             let default_locale = setlocale(LC_CTYPE, ptr::null());
112             setlocale(LC_CTYPE, b"\0".as_ptr() as *const _);
113 
114             // Check if set locale is supported by Xlib.
115             // If not, calls to some Xlib functions like `XSetLocaleModifiers`
116             // will fail.
117             let locale_supported = (xconn.xlib.XSupportsLocale)() == 1;
118             if !locale_supported {
119                 let unsupported_locale = setlocale(LC_CTYPE, ptr::null());
120                 warn!(
121                     "Unsupported locale \"{}\". Restoring default locale \"{}\".",
122                     CStr::from_ptr(unsupported_locale).to_string_lossy(),
123                     CStr::from_ptr(default_locale).to_string_lossy()
124                 );
125                 // Restore default locale
126                 setlocale(LC_CTYPE, default_locale);
127             }
128         }
129         let ime = RefCell::new({
130             let result = Ime::new(Arc::clone(&xconn));
131             if let Err(ImeCreationError::OpenFailure(ref state)) = result {
132                 panic!(format!("Failed to open input method: {:#?}", state));
133             }
134             result.expect("Failed to set input method destruction callback")
135         });
136 
137         let randr_event_offset = xconn
138             .select_xrandr_input(root)
139             .expect("Failed to query XRandR extension");
140 
141         let xi2ext = unsafe {
142             let mut ext = XExtension::default();
143 
144             let res = (xconn.xlib.XQueryExtension)(
145                 xconn.display,
146                 b"XInputExtension\0".as_ptr() as *const c_char,
147                 &mut ext.opcode,
148                 &mut ext.first_event_id,
149                 &mut ext.first_error_id,
150             );
151 
152             if res == ffi::False {
153                 panic!("X server missing XInput extension");
154             }
155 
156             ext
157         };
158 
159         unsafe {
160             let mut xinput_major_ver = ffi::XI_2_Major;
161             let mut xinput_minor_ver = ffi::XI_2_Minor;
162             if (xconn.xinput2.XIQueryVersion)(
163                 xconn.display,
164                 &mut xinput_major_ver,
165                 &mut xinput_minor_ver,
166             ) != ffi::Success as libc::c_int
167             {
168                 panic!(
169                     "X server has XInput extension {}.{} but does not support XInput2",
170                     xinput_major_ver, xinput_minor_ver,
171                 );
172             }
173         }
174 
175         xconn.update_cached_wm_info(root);
176 
177         let pending_redraws: Arc<Mutex<HashSet<WindowId>>> = Default::default();
178 
179         let mut mod_keymap = ModifierKeymap::new();
180         mod_keymap.reset_from_x_connection(&xconn);
181 
182         let target = Rc::new(RootELW {
183             p: super::EventLoopWindowTarget::X(EventLoopWindowTarget {
184                 ime,
185                 root,
186                 windows: Default::default(),
187                 _marker: ::std::marker::PhantomData,
188                 ime_sender,
189                 xconn,
190                 wm_delete_window,
191                 net_wm_ping,
192                 pending_redraws: pending_redraws.clone(),
193             }),
194             _marker: ::std::marker::PhantomData,
195         });
196 
197         let poll = Poll::new().unwrap();
198 
199         let (user_sender, user_channel) = channel();
200 
201         poll.register(
202             &EventedFd(&get_xtarget(&target).xconn.x11_fd),
203             X_TOKEN,
204             Ready::readable(),
205             PollOpt::level(),
206         )
207         .unwrap();
208 
209         poll.register(
210             &user_channel,
211             USER_TOKEN,
212             Ready::readable(),
213             PollOpt::level(),
214         )
215         .unwrap();
216 
217         let event_processor = EventProcessor {
218             target: target.clone(),
219             dnd,
220             devices: Default::default(),
221             randr_event_offset,
222             ime_receiver,
223             xi2ext,
224             mod_keymap,
225             device_mod_state: Default::default(),
226             num_touch: 0,
227             first_touch: None,
228             active_window: None,
229         };
230 
231         // Register for device hotplug events
232         // (The request buffer is flushed during `init_device`)
233         get_xtarget(&target)
234             .xconn
235             .select_xinput_events(root, ffi::XIAllDevices, ffi::XI_HierarchyChangedMask)
236             .queue();
237 
238         event_processor.init_device(ffi::XIAllDevices);
239 
240         let result = EventLoop {
241             poll,
242             user_channel,
243             user_sender,
244             event_processor,
245             target,
246         };
247 
248         result
249     }
250 
create_proxy(&self) -> EventLoopProxy<T>251     pub fn create_proxy(&self) -> EventLoopProxy<T> {
252         EventLoopProxy {
253             user_sender: self.user_sender.clone(),
254         }
255     }
256 
window_target(&self) -> &RootELW<T>257     pub(crate) fn window_target(&self) -> &RootELW<T> {
258         &self.target
259     }
260 
run_return<F>(&mut self, mut callback: F) where F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),261     pub fn run_return<F>(&mut self, mut callback: F)
262     where
263         F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
264     {
265         let mut control_flow = ControlFlow::default();
266         let mut events = Events::with_capacity(8);
267         let mut cause = StartCause::Init;
268 
269         loop {
270             sticky_exit_callback(
271                 crate::event::Event::NewEvents(cause),
272                 &self.target,
273                 &mut control_flow,
274                 &mut callback,
275             );
276 
277             // Process all pending events
278             self.drain_events(&mut callback, &mut control_flow);
279 
280             let wt = get_xtarget(&self.target);
281 
282             // Empty the user event buffer
283             {
284                 while let Ok(event) = self.user_channel.try_recv() {
285                     sticky_exit_callback(
286                         crate::event::Event::UserEvent(event),
287                         &self.target,
288                         &mut control_flow,
289                         &mut callback,
290                     );
291                 }
292             }
293             // send MainEventsCleared
294             {
295                 sticky_exit_callback(
296                     crate::event::Event::MainEventsCleared,
297                     &self.target,
298                     &mut control_flow,
299                     &mut callback,
300                 );
301             }
302             // Empty the redraw requests
303             {
304                 // Release the lock to prevent deadlock
305                 let windows: Vec<_> = wt.pending_redraws.lock().unwrap().drain().collect();
306 
307                 for wid in windows {
308                     sticky_exit_callback(
309                         Event::RedrawRequested(crate::window::WindowId(super::WindowId::X(wid))),
310                         &self.target,
311                         &mut control_flow,
312                         &mut callback,
313                     );
314                 }
315             }
316             // send RedrawEventsCleared
317             {
318                 sticky_exit_callback(
319                     crate::event::Event::RedrawEventsCleared,
320                     &self.target,
321                     &mut control_flow,
322                     &mut callback,
323                 );
324             }
325 
326             let start = Instant::now();
327             let (deadline, timeout);
328 
329             match control_flow {
330                 ControlFlow::Exit => break,
331                 ControlFlow::Poll => {
332                     cause = StartCause::Poll;
333                     deadline = None;
334                     timeout = Some(Duration::from_millis(0));
335                 }
336                 ControlFlow::Wait => {
337                     cause = StartCause::WaitCancelled {
338                         start,
339                         requested_resume: None,
340                     };
341                     deadline = None;
342                     timeout = None;
343                 }
344                 ControlFlow::WaitUntil(wait_deadline) => {
345                     cause = StartCause::ResumeTimeReached {
346                         start,
347                         requested_resume: wait_deadline,
348                     };
349                     timeout = if wait_deadline > start {
350                         Some(wait_deadline - start)
351                     } else {
352                         Some(Duration::from_millis(0))
353                     };
354                     deadline = Some(wait_deadline);
355                 }
356             }
357 
358             // If the XConnection already contains buffered events, we don't
359             // need to wait for data on the socket.
360             if !self.event_processor.poll() {
361                 self.poll.poll(&mut events, timeout).unwrap();
362                 events.clear();
363             }
364 
365             let wait_cancelled = deadline.map_or(false, |deadline| Instant::now() < deadline);
366 
367             if wait_cancelled {
368                 cause = StartCause::WaitCancelled {
369                     start,
370                     requested_resume: deadline,
371                 };
372             }
373         }
374 
375         callback(
376             crate::event::Event::LoopDestroyed,
377             &self.target,
378             &mut control_flow,
379         );
380     }
381 
run<F>(mut self, callback: F) -> ! where F: 'static + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),382     pub fn run<F>(mut self, callback: F) -> !
383     where
384         F: 'static + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
385     {
386         self.run_return(callback);
387         ::std::process::exit(0);
388     }
389 
drain_events<F>(&mut self, callback: &mut F, control_flow: &mut ControlFlow) where F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),390     fn drain_events<F>(&mut self, callback: &mut F, control_flow: &mut ControlFlow)
391     where
392         F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
393     {
394         let target = &self.target;
395         let mut xev = MaybeUninit::uninit();
396 
397         let wt = get_xtarget(&self.target);
398 
399         while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
400             let mut xev = unsafe { xev.assume_init() };
401             self.event_processor.process_event(&mut xev, |event| {
402                 sticky_exit_callback(
403                     event,
404                     target,
405                     control_flow,
406                     &mut |event, window_target, control_flow| {
407                         if let Event::RedrawRequested(crate::window::WindowId(
408                             super::WindowId::X(wid),
409                         )) = event
410                         {
411                             wt.pending_redraws.lock().unwrap().insert(wid);
412                         } else {
413                             callback(event, window_target, control_flow);
414                         }
415                     },
416                 );
417             });
418         }
419     }
420 }
421 
get_xtarget<T>(target: &RootELW<T>) -> &EventLoopWindowTarget<T>422 pub(crate) fn get_xtarget<T>(target: &RootELW<T>) -> &EventLoopWindowTarget<T> {
423     match target.p {
424         super::EventLoopWindowTarget::X(ref target) => target,
425         #[cfg(feature = "wayland")]
426         _ => unreachable!(),
427     }
428 }
429 
430 impl<T> EventLoopWindowTarget<T> {
431     /// Returns the `XConnection` of this events loop.
432     #[inline]
x_connection(&self) -> &Arc<XConnection>433     pub fn x_connection(&self) -> &Arc<XConnection> {
434         &self.xconn
435     }
436 }
437 
438 impl<T: 'static> EventLoopProxy<T> {
send_event(&self, event: T) -> Result<(), EventLoopClosed<T>>439     pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
440         self.user_sender.send(event).map_err(|e| {
441             EventLoopClosed(if let SendError::Disconnected(x) = e {
442                 x
443             } else {
444                 unreachable!()
445             })
446         })
447     }
448 }
449 
450 struct DeviceInfo<'a> {
451     xconn: &'a XConnection,
452     info: *const ffi::XIDeviceInfo,
453     count: usize,
454 }
455 
456 impl<'a> DeviceInfo<'a> {
get(xconn: &'a XConnection, device: c_int) -> Option<Self>457     fn get(xconn: &'a XConnection, device: c_int) -> Option<Self> {
458         unsafe {
459             let mut count = 0;
460             let info = (xconn.xinput2.XIQueryDevice)(xconn.display, device, &mut count);
461             xconn.check_errors().ok()?;
462 
463             if info.is_null() || count == 0 {
464                 None
465             } else {
466                 Some(DeviceInfo {
467                     xconn,
468                     info,
469                     count: count as usize,
470                 })
471             }
472         }
473     }
474 }
475 
476 impl<'a> Drop for DeviceInfo<'a> {
drop(&mut self)477     fn drop(&mut self) {
478         assert!(!self.info.is_null());
479         unsafe { (self.xconn.xinput2.XIFreeDeviceInfo)(self.info as *mut _) };
480     }
481 }
482 
483 impl<'a> Deref for DeviceInfo<'a> {
484     type Target = [ffi::XIDeviceInfo];
deref(&self) -> &Self::Target485     fn deref(&self) -> &Self::Target {
486         unsafe { slice::from_raw_parts(self.info, self.count) }
487     }
488 }
489 
490 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
491 pub struct WindowId(ffi::Window);
492 
493 impl WindowId {
dummy() -> Self494     pub unsafe fn dummy() -> Self {
495         WindowId(0)
496     }
497 }
498 
499 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
500 pub struct DeviceId(c_int);
501 
502 impl DeviceId {
dummy() -> Self503     pub unsafe fn dummy() -> Self {
504         DeviceId(0)
505     }
506 }
507 
508 pub struct Window(Arc<UnownedWindow>);
509 
510 impl Deref for Window {
511     type Target = UnownedWindow;
512     #[inline]
deref(&self) -> &UnownedWindow513     fn deref(&self) -> &UnownedWindow {
514         &*self.0
515     }
516 }
517 
518 impl Window {
new<T>( event_loop: &EventLoopWindowTarget<T>, attribs: WindowAttributes, pl_attribs: PlatformSpecificWindowBuilderAttributes, ) -> Result<Self, RootOsError>519     pub fn new<T>(
520         event_loop: &EventLoopWindowTarget<T>,
521         attribs: WindowAttributes,
522         pl_attribs: PlatformSpecificWindowBuilderAttributes,
523     ) -> Result<Self, RootOsError> {
524         let window = Arc::new(UnownedWindow::new(&event_loop, attribs, pl_attribs)?);
525         event_loop
526             .windows
527             .borrow_mut()
528             .insert(window.id(), Arc::downgrade(&window));
529         Ok(Window(window))
530     }
531 }
532 
533 impl Drop for Window {
drop(&mut self)534     fn drop(&mut self) {
535         let window = self.deref();
536         let xconn = &window.xconn;
537         unsafe {
538             (xconn.xlib.XDestroyWindow)(xconn.display, window.id().0);
539             // If the window was somehow already destroyed, we'll get a `BadWindow` error, which we don't care about.
540             let _ = xconn.check_errors();
541         }
542     }
543 }
544 
545 /// XEvents of type GenericEvent store their actual data in an XGenericEventCookie data structure. This is a wrapper to
546 /// extract the cookie from a GenericEvent XEvent and release the cookie data once it has been processed
547 struct GenericEventCookie<'a> {
548     xconn: &'a XConnection,
549     cookie: ffi::XGenericEventCookie,
550 }
551 
552 impl<'a> GenericEventCookie<'a> {
from_event<'b>( xconn: &'b XConnection, event: ffi::XEvent, ) -> Option<GenericEventCookie<'b>>553     fn from_event<'b>(
554         xconn: &'b XConnection,
555         event: ffi::XEvent,
556     ) -> Option<GenericEventCookie<'b>> {
557         unsafe {
558             let mut cookie: ffi::XGenericEventCookie = From::from(event);
559             if (xconn.xlib.XGetEventData)(xconn.display, &mut cookie) == ffi::True {
560                 Some(GenericEventCookie { xconn, cookie })
561             } else {
562                 None
563             }
564         }
565     }
566 }
567 
568 impl<'a> Drop for GenericEventCookie<'a> {
drop(&mut self)569     fn drop(&mut self) {
570         unsafe {
571             (self.xconn.xlib.XFreeEventData)(self.xconn.display, &mut self.cookie);
572         }
573     }
574 }
575 
576 #[derive(Debug, Default, Copy, Clone)]
577 struct XExtension {
578     opcode: c_int,
579     first_event_id: c_int,
580     first_error_id: c_int,
581 }
582 
mkwid(w: ffi::Window) -> crate::window::WindowId583 fn mkwid(w: ffi::Window) -> crate::window::WindowId {
584     crate::window::WindowId(crate::platform_impl::WindowId::X(WindowId(w)))
585 }
mkdid(w: c_int) -> crate::event::DeviceId586 fn mkdid(w: c_int) -> crate::event::DeviceId {
587     crate::event::DeviceId(crate::platform_impl::DeviceId::X(DeviceId(w)))
588 }
589 
590 #[derive(Debug)]
591 struct Device {
592     name: String,
593     scroll_axes: Vec<(i32, ScrollAxis)>,
594     // For master devices, this is the paired device (pointer <-> keyboard).
595     // For slave devices, this is the master.
596     attachment: c_int,
597 }
598 
599 #[derive(Debug, Copy, Clone)]
600 struct ScrollAxis {
601     increment: f64,
602     orientation: ScrollOrientation,
603     position: f64,
604 }
605 
606 #[derive(Debug, Copy, Clone)]
607 enum ScrollOrientation {
608     Vertical,
609     Horizontal,
610 }
611 
612 impl Device {
new<T: 'static>(el: &EventProcessor<T>, info: &ffi::XIDeviceInfo) -> Self613     fn new<T: 'static>(el: &EventProcessor<T>, info: &ffi::XIDeviceInfo) -> Self {
614         let name = unsafe { CStr::from_ptr(info.name).to_string_lossy() };
615         let mut scroll_axes = Vec::new();
616 
617         let wt = get_xtarget(&el.target);
618 
619         if Device::physical_device(info) {
620             // Register for global raw events
621             let mask = ffi::XI_RawMotionMask
622                 | ffi::XI_RawButtonPressMask
623                 | ffi::XI_RawButtonReleaseMask
624                 | ffi::XI_RawKeyPressMask
625                 | ffi::XI_RawKeyReleaseMask;
626             // The request buffer is flushed when we poll for events
627             wt.xconn
628                 .select_xinput_events(wt.root, info.deviceid, mask)
629                 .queue();
630 
631             // Identify scroll axes
632             for class_ptr in Device::classes(info) {
633                 let class = unsafe { &**class_ptr };
634                 match class._type {
635                     ffi::XIScrollClass => {
636                         let info = unsafe {
637                             mem::transmute::<&ffi::XIAnyClassInfo, &ffi::XIScrollClassInfo>(class)
638                         };
639                         scroll_axes.push((
640                             info.number,
641                             ScrollAxis {
642                                 increment: info.increment,
643                                 orientation: match info.scroll_type {
644                                     ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal,
645                                     ffi::XIScrollTypeVertical => ScrollOrientation::Vertical,
646                                     _ => unreachable!(),
647                                 },
648                                 position: 0.0,
649                             },
650                         ));
651                     }
652                     _ => {}
653                 }
654             }
655         }
656 
657         let mut device = Device {
658             name: name.into_owned(),
659             scroll_axes,
660             attachment: info.attachment,
661         };
662         device.reset_scroll_position(info);
663         device
664     }
665 
reset_scroll_position(&mut self, info: &ffi::XIDeviceInfo)666     fn reset_scroll_position(&mut self, info: &ffi::XIDeviceInfo) {
667         if Device::physical_device(info) {
668             for class_ptr in Device::classes(info) {
669                 let class = unsafe { &**class_ptr };
670                 match class._type {
671                     ffi::XIValuatorClass => {
672                         let info = unsafe {
673                             mem::transmute::<&ffi::XIAnyClassInfo, &ffi::XIValuatorClassInfo>(class)
674                         };
675                         if let Some(&mut (_, ref mut axis)) = self
676                             .scroll_axes
677                             .iter_mut()
678                             .find(|&&mut (axis, _)| axis == info.number)
679                         {
680                             axis.position = info.value;
681                         }
682                     }
683                     _ => {}
684                 }
685             }
686         }
687     }
688 
689     #[inline]
physical_device(info: &ffi::XIDeviceInfo) -> bool690     fn physical_device(info: &ffi::XIDeviceInfo) -> bool {
691         info._use == ffi::XISlaveKeyboard
692             || info._use == ffi::XISlavePointer
693             || info._use == ffi::XIFloatingSlave
694     }
695 
696     #[inline]
classes(info: &ffi::XIDeviceInfo) -> &[*const ffi::XIAnyClassInfo]697     fn classes(info: &ffi::XIDeviceInfo) -> &[*const ffi::XIAnyClassInfo] {
698         unsafe {
699             slice::from_raw_parts(
700                 info.classes as *const *const ffi::XIAnyClassInfo,
701                 info.num_classes as usize,
702             )
703         }
704     }
705 }
706