1 use std::{cell::RefCell, collections::HashMap, rc::Rc, slice, sync::Arc};
2 
3 use libc::{c_char, c_int, c_long, c_uint, c_ulong};
4 
5 use parking_lot::MutexGuard;
6 
7 use super::{
8     events, ffi, get_xtarget, mkdid, mkwid, monitor, util, Device, DeviceId, DeviceInfo, Dnd,
9     DndState, GenericEventCookie, ImeReceiver, ScrollOrientation, UnownedWindow, WindowId,
10     XExtension,
11 };
12 
13 use util::modifiers::{ModifierKeyState, ModifierKeymap};
14 
15 use crate::{
16     dpi::{PhysicalPosition, PhysicalSize},
17     event::{
18         DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, TouchPhase, WindowEvent,
19     },
20     event_loop::EventLoopWindowTarget as RootELW,
21 };
22 
23 /// The X11 documentation states: "Keycodes lie in the inclusive range [8,255]".
24 const KEYCODE_OFFSET: u8 = 8;
25 
26 pub(super) struct EventProcessor<T: 'static> {
27     pub(super) dnd: Dnd,
28     pub(super) ime_receiver: ImeReceiver,
29     pub(super) randr_event_offset: c_int,
30     pub(super) devices: RefCell<HashMap<DeviceId, Device>>,
31     pub(super) xi2ext: XExtension,
32     pub(super) target: Rc<RootELW<T>>,
33     pub(super) mod_keymap: ModifierKeymap,
34     pub(super) device_mod_state: ModifierKeyState,
35     // Number of touch events currently in progress
36     pub(super) num_touch: u32,
37     pub(super) first_touch: Option<u64>,
38     // Currently focused window belonging to this process
39     pub(super) active_window: Option<ffi::Window>,
40 }
41 
42 impl<T: 'static> EventProcessor<T> {
init_device(&self, device: c_int)43     pub(super) fn init_device(&self, device: c_int) {
44         let wt = get_xtarget(&self.target);
45         let mut devices = self.devices.borrow_mut();
46         if let Some(info) = DeviceInfo::get(&wt.xconn, device) {
47             for info in info.iter() {
48                 devices.insert(DeviceId(info.deviceid), Device::new(&self, info));
49             }
50         }
51     }
52 
with_window<F, Ret>(&self, window_id: ffi::Window, callback: F) -> Option<Ret> where F: Fn(&Arc<UnownedWindow>) -> Ret,53     fn with_window<F, Ret>(&self, window_id: ffi::Window, callback: F) -> Option<Ret>
54     where
55         F: Fn(&Arc<UnownedWindow>) -> Ret,
56     {
57         let mut deleted = false;
58         let window_id = WindowId(window_id);
59         let wt = get_xtarget(&self.target);
60         let result = wt
61             .windows
62             .borrow()
63             .get(&window_id)
64             .and_then(|window| {
65                 let arc = window.upgrade();
66                 deleted = arc.is_none();
67                 arc
68             })
69             .map(|window| callback(&window));
70         if deleted {
71             // Garbage collection
72             wt.windows.borrow_mut().remove(&window_id);
73         }
74         result
75     }
76 
window_exists(&self, window_id: ffi::Window) -> bool77     fn window_exists(&self, window_id: ffi::Window) -> bool {
78         self.with_window(window_id, |_| ()).is_some()
79     }
80 
poll(&self) -> bool81     pub(super) fn poll(&self) -> bool {
82         let wt = get_xtarget(&self.target);
83         let result = unsafe { (wt.xconn.xlib.XPending)(wt.xconn.display) };
84 
85         result != 0
86     }
87 
poll_one_event(&mut self, event_ptr: *mut ffi::XEvent) -> bool88     pub(super) unsafe fn poll_one_event(&mut self, event_ptr: *mut ffi::XEvent) -> bool {
89         let wt = get_xtarget(&self.target);
90         // This function is used to poll and remove a single event
91         // from the Xlib event queue in a non-blocking, atomic way.
92         // XCheckIfEvent is non-blocking and removes events from queue.
93         // XNextEvent can't be used because it blocks while holding the
94         // global Xlib mutex.
95         // XPeekEvent does not remove events from the queue.
96         unsafe extern "C" fn predicate(
97             _display: *mut ffi::Display,
98             _event: *mut ffi::XEvent,
99             _arg: *mut c_char,
100         ) -> c_int {
101             // This predicate always returns "true" (1) to accept all events
102             1
103         }
104 
105         let result = (wt.xconn.xlib.XCheckIfEvent)(
106             wt.xconn.display,
107             event_ptr,
108             Some(predicate),
109             std::ptr::null_mut(),
110         );
111 
112         result != 0
113     }
114 
process_event<F>(&mut self, xev: &mut ffi::XEvent, mut callback: F) where F: FnMut(Event<'_, T>),115     pub(super) fn process_event<F>(&mut self, xev: &mut ffi::XEvent, mut callback: F)
116     where
117         F: FnMut(Event<'_, T>),
118     {
119         let wt = get_xtarget(&self.target);
120         // XFilterEvent tells us when an event has been discarded by the input method.
121         // Specifically, this involves all of the KeyPress events in compose/pre-edit sequences,
122         // along with an extra copy of the KeyRelease events. This also prevents backspace and
123         // arrow keys from being detected twice.
124         if ffi::True
125             == unsafe {
126                 (wt.xconn.xlib.XFilterEvent)(xev, {
127                     let xev: &ffi::XAnyEvent = xev.as_ref();
128                     xev.window
129                 })
130             }
131         {
132             return;
133         }
134 
135         // We can't call a `&mut self` method because of the above borrow,
136         // so we use this macro for repeated modifier state updates.
137         macro_rules! update_modifiers {
138             ( $state:expr , $modifier:expr ) => {{
139                 match ($state, $modifier) {
140                     (state, modifier) => {
141                         if let Some(modifiers) =
142                             self.device_mod_state.update_state(&state, modifier)
143                         {
144                             if let Some(window_id) = self.active_window {
145                                 callback(Event::WindowEvent {
146                                     window_id: mkwid(window_id),
147                                     event: WindowEvent::ModifiersChanged(modifiers),
148                                 });
149                             }
150                         }
151                     }
152                 }
153             }};
154         }
155 
156         let event_type = xev.get_type();
157         match event_type {
158             ffi::MappingNotify => {
159                 let mapping: &ffi::XMappingEvent = xev.as_ref();
160 
161                 if mapping.request == ffi::MappingModifier
162                     || mapping.request == ffi::MappingKeyboard
163                 {
164                     unsafe {
165                         (wt.xconn.xlib.XRefreshKeyboardMapping)(xev.as_mut());
166                     }
167                     wt.xconn
168                         .check_errors()
169                         .expect("Failed to call XRefreshKeyboardMapping");
170 
171                     self.mod_keymap.reset_from_x_connection(&wt.xconn);
172                     self.device_mod_state.update_keymap(&self.mod_keymap);
173                 }
174             }
175 
176             ffi::ClientMessage => {
177                 let client_msg: &ffi::XClientMessageEvent = xev.as_ref();
178 
179                 let window = client_msg.window;
180                 let window_id = mkwid(window);
181 
182                 if client_msg.data.get_long(0) as ffi::Atom == wt.wm_delete_window {
183                     callback(Event::WindowEvent {
184                         window_id,
185                         event: WindowEvent::CloseRequested,
186                     });
187                 } else if client_msg.data.get_long(0) as ffi::Atom == wt.net_wm_ping {
188                     let response_msg: &mut ffi::XClientMessageEvent = xev.as_mut();
189                     response_msg.window = wt.root;
190                     wt.xconn
191                         .send_event(
192                             wt.root,
193                             Some(ffi::SubstructureNotifyMask | ffi::SubstructureRedirectMask),
194                             *response_msg,
195                         )
196                         .queue();
197                 } else if client_msg.message_type == self.dnd.atoms.enter {
198                     let source_window = client_msg.data.get_long(0) as c_ulong;
199                     let flags = client_msg.data.get_long(1);
200                     let version = flags >> 24;
201                     self.dnd.version = Some(version);
202                     let has_more_types = flags - (flags & (c_long::max_value() - 1)) == 1;
203                     if !has_more_types {
204                         let type_list = vec![
205                             client_msg.data.get_long(2) as c_ulong,
206                             client_msg.data.get_long(3) as c_ulong,
207                             client_msg.data.get_long(4) as c_ulong,
208                         ];
209                         self.dnd.type_list = Some(type_list);
210                     } else if let Ok(more_types) = unsafe { self.dnd.get_type_list(source_window) }
211                     {
212                         self.dnd.type_list = Some(more_types);
213                     }
214                 } else if client_msg.message_type == self.dnd.atoms.position {
215                     // This event occurs every time the mouse moves while a file's being dragged
216                     // over our window. We emit HoveredFile in response; while the macOS backend
217                     // does that upon a drag entering, XDND doesn't have access to the actual drop
218                     // data until this event. For parity with other platforms, we only emit
219                     // `HoveredFile` the first time, though if winit's API is later extended to
220                     // supply position updates with `HoveredFile` or another event, implementing
221                     // that here would be trivial.
222 
223                     let source_window = client_msg.data.get_long(0) as c_ulong;
224 
225                     // Equivalent to `(x << shift) | y`
226                     // where `shift = mem::size_of::<c_short>() * 8`
227                     // Note that coordinates are in "desktop space", not "window space"
228                     // (in X11 parlance, they're root window coordinates)
229                     //let packed_coordinates = client_msg.data.get_long(2);
230                     //let shift = mem::size_of::<libc::c_short>() * 8;
231                     //let x = packed_coordinates >> shift;
232                     //let y = packed_coordinates & !(x << shift);
233 
234                     // By our own state flow, `version` should never be `None` at this point.
235                     let version = self.dnd.version.unwrap_or(5);
236 
237                     // Action is specified in versions 2 and up, though we don't need it anyway.
238                     //let action = client_msg.data.get_long(4);
239 
240                     let accepted = if let Some(ref type_list) = self.dnd.type_list {
241                         type_list.contains(&self.dnd.atoms.uri_list)
242                     } else {
243                         false
244                     };
245 
246                     if accepted {
247                         self.dnd.source_window = Some(source_window);
248                         unsafe {
249                             if self.dnd.result.is_none() {
250                                 let time = if version >= 1 {
251                                     client_msg.data.get_long(3) as c_ulong
252                                 } else {
253                                     // In version 0, time isn't specified
254                                     ffi::CurrentTime
255                                 };
256                                 // This results in the `SelectionNotify` event below
257                                 self.dnd.convert_selection(window, time);
258                             }
259                             self.dnd
260                                 .send_status(window, source_window, DndState::Accepted)
261                                 .expect("Failed to send `XdndStatus` message.");
262                         }
263                     } else {
264                         unsafe {
265                             self.dnd
266                                 .send_status(window, source_window, DndState::Rejected)
267                                 .expect("Failed to send `XdndStatus` message.");
268                         }
269                         self.dnd.reset();
270                     }
271                 } else if client_msg.message_type == self.dnd.atoms.drop {
272                     let (source_window, state) = if let Some(source_window) = self.dnd.source_window
273                     {
274                         if let Some(Ok(ref path_list)) = self.dnd.result {
275                             for path in path_list {
276                                 callback(Event::WindowEvent {
277                                     window_id,
278                                     event: WindowEvent::DroppedFile(path.clone()),
279                                 });
280                             }
281                         }
282                         (source_window, DndState::Accepted)
283                     } else {
284                         // `source_window` won't be part of our DND state if we already rejected the drop in our
285                         // `XdndPosition` handler.
286                         let source_window = client_msg.data.get_long(0) as c_ulong;
287                         (source_window, DndState::Rejected)
288                     };
289                     unsafe {
290                         self.dnd
291                             .send_finished(window, source_window, state)
292                             .expect("Failed to send `XdndFinished` message.");
293                     }
294                     self.dnd.reset();
295                 } else if client_msg.message_type == self.dnd.atoms.leave {
296                     self.dnd.reset();
297                     callback(Event::WindowEvent {
298                         window_id,
299                         event: WindowEvent::HoveredFileCancelled,
300                     });
301                 }
302             }
303 
304             ffi::SelectionNotify => {
305                 let xsel: &ffi::XSelectionEvent = xev.as_ref();
306 
307                 let window = xsel.requestor;
308                 let window_id = mkwid(window);
309 
310                 if xsel.property == self.dnd.atoms.selection {
311                     let mut result = None;
312 
313                     // This is where we receive data from drag and drop
314                     if let Ok(mut data) = unsafe { self.dnd.read_data(window) } {
315                         let parse_result = self.dnd.parse_data(&mut data);
316                         if let Ok(ref path_list) = parse_result {
317                             for path in path_list {
318                                 callback(Event::WindowEvent {
319                                     window_id,
320                                     event: WindowEvent::HoveredFile(path.clone()),
321                                 });
322                             }
323                         }
324                         result = Some(parse_result);
325                     }
326 
327                     self.dnd.result = result;
328                 }
329             }
330 
331             ffi::ConfigureNotify => {
332                 let xev: &ffi::XConfigureEvent = xev.as_ref();
333                 let xwindow = xev.window;
334                 let window_id = mkwid(xwindow);
335 
336                 if let Some(window) = self.with_window(xwindow, Arc::clone) {
337                     // So apparently...
338                     // `XSendEvent` (synthetic `ConfigureNotify`) -> position relative to root
339                     // `XConfigureNotify` (real `ConfigureNotify`) -> position relative to parent
340                     // https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.5
341                     // We don't want to send `Moved` when this is false, since then every `Resized`
342                     // (whether the window moved or not) is accompanied by an extraneous `Moved` event
343                     // that has a position relative to the parent window.
344                     let is_synthetic = xev.send_event == ffi::True;
345 
346                     // These are both in physical space.
347                     let new_inner_size = (xev.width as u32, xev.height as u32);
348                     let new_inner_position = (xev.x as i32, xev.y as i32);
349 
350                     let mut shared_state_lock = window.shared_state.lock();
351 
352                     let (mut resized, moved) = {
353                         let resized =
354                             util::maybe_change(&mut shared_state_lock.size, new_inner_size);
355                         let moved = if is_synthetic {
356                             util::maybe_change(
357                                 &mut shared_state_lock.inner_position,
358                                 new_inner_position,
359                             )
360                         } else {
361                             // Detect when frame extents change.
362                             // Since this isn't synthetic, as per the notes above, this position is relative to the
363                             // parent window.
364                             let rel_parent = new_inner_position;
365                             if util::maybe_change(
366                                 &mut shared_state_lock.inner_position_rel_parent,
367                                 rel_parent,
368                             ) {
369                                 // This ensures we process the next `Moved`.
370                                 shared_state_lock.inner_position = None;
371                                 // Extra insurance against stale frame extents.
372                                 shared_state_lock.frame_extents = None;
373                             }
374                             false
375                         };
376                         (resized, moved)
377                     };
378 
379                     let new_outer_position = if moved || shared_state_lock.position.is_none() {
380                         // We need to convert client area position to window position.
381                         let frame_extents = shared_state_lock
382                             .frame_extents
383                             .as_ref()
384                             .cloned()
385                             .unwrap_or_else(|| {
386                                 let frame_extents =
387                                     wt.xconn.get_frame_extents_heuristic(xwindow, wt.root);
388                                 shared_state_lock.frame_extents = Some(frame_extents.clone());
389                                 frame_extents
390                             });
391                         let outer = frame_extents
392                             .inner_pos_to_outer(new_inner_position.0, new_inner_position.1);
393                         shared_state_lock.position = Some(outer);
394                         if moved {
395                             // Temporarily unlock shared state to prevent deadlock
396                             MutexGuard::unlocked(&mut shared_state_lock, || {
397                                 callback(Event::WindowEvent {
398                                     window_id,
399                                     event: WindowEvent::Moved(outer.into()),
400                                 });
401                             });
402                         }
403                         outer
404                     } else {
405                         shared_state_lock.position.unwrap()
406                     };
407 
408                     if is_synthetic {
409                         // If we don't use the existing adjusted value when available, then the user can screw up the
410                         // resizing by dragging across monitors *without* dropping the window.
411                         let (width, height) = shared_state_lock
412                             .dpi_adjusted
413                             .unwrap_or_else(|| (xev.width as u32, xev.height as u32));
414 
415                         let last_scale_factor = shared_state_lock.last_monitor.scale_factor;
416                         let new_scale_factor = {
417                             let window_rect = util::AaRect::new(new_outer_position, new_inner_size);
418                             let monitor = wt.xconn.get_monitor_for_window(Some(window_rect));
419 
420                             if monitor.is_dummy() {
421                                 // Avoid updating monitor using a dummy monitor handle
422                                 last_scale_factor
423                             } else {
424                                 shared_state_lock.last_monitor = monitor.clone();
425                                 monitor.scale_factor
426                             }
427                         };
428                         if last_scale_factor != new_scale_factor {
429                             let (new_width, new_height) = window.adjust_for_dpi(
430                                 last_scale_factor,
431                                 new_scale_factor,
432                                 width,
433                                 height,
434                                 &shared_state_lock,
435                             );
436 
437                             let old_inner_size = PhysicalSize::new(width, height);
438                             let mut new_inner_size = PhysicalSize::new(new_width, new_height);
439 
440                             // Temporarily unlock shared state to prevent deadlock
441                             MutexGuard::unlocked(&mut shared_state_lock, || {
442                                 callback(Event::WindowEvent {
443                                     window_id,
444                                     event: WindowEvent::ScaleFactorChanged {
445                                         scale_factor: new_scale_factor,
446                                         new_inner_size: &mut new_inner_size,
447                                     },
448                                 });
449                             });
450 
451                             if new_inner_size != old_inner_size {
452                                 window.set_inner_size_physical(
453                                     new_inner_size.width,
454                                     new_inner_size.height,
455                                 );
456                                 shared_state_lock.dpi_adjusted = Some(new_inner_size.into());
457                                 // if the DPI factor changed, force a resize event to ensure the logical
458                                 // size is computed with the right DPI factor
459                                 resized = true;
460                             }
461                         }
462                     }
463 
464                     // This is a hack to ensure that the DPI adjusted resize is actually applied on all WMs. KWin
465                     // doesn't need this, but Xfwm does. The hack should not be run on other WMs, since tiling
466                     // WMs constrain the window size, making the resize fail. This would cause an endless stream of
467                     // XResizeWindow requests, making Xorg, the winit client, and the WM consume 100% of CPU.
468                     if let Some(adjusted_size) = shared_state_lock.dpi_adjusted {
469                         if new_inner_size == adjusted_size || !util::wm_name_is_one_of(&["Xfwm4"]) {
470                             // When this finally happens, the event will not be synthetic.
471                             shared_state_lock.dpi_adjusted = None;
472                         } else {
473                             window.set_inner_size_physical(adjusted_size.0, adjusted_size.1);
474                         }
475                     }
476 
477                     if resized {
478                         // Drop the shared state lock to prevent deadlock
479                         drop(shared_state_lock);
480 
481                         callback(Event::WindowEvent {
482                             window_id,
483                             event: WindowEvent::Resized(new_inner_size.into()),
484                         });
485                     }
486                 }
487             }
488 
489             ffi::ReparentNotify => {
490                 let xev: &ffi::XReparentEvent = xev.as_ref();
491 
492                 // This is generally a reliable way to detect when the window manager's been
493                 // replaced, though this event is only fired by reparenting window managers
494                 // (which is almost all of them). Failing to correctly update WM info doesn't
495                 // really have much impact, since on the WMs affected (xmonad, dwm, etc.) the only
496                 // effect is that we waste some time trying to query unsupported properties.
497                 wt.xconn.update_cached_wm_info(wt.root);
498 
499                 self.with_window(xev.window, |window| {
500                     window.invalidate_cached_frame_extents();
501                 });
502             }
503 
504             ffi::DestroyNotify => {
505                 let xev: &ffi::XDestroyWindowEvent = xev.as_ref();
506 
507                 let window = xev.window;
508                 let window_id = mkwid(window);
509 
510                 // In the event that the window's been destroyed without being dropped first, we
511                 // cleanup again here.
512                 wt.windows.borrow_mut().remove(&WindowId(window));
513 
514                 // Since all XIM stuff needs to happen from the same thread, we destroy the input
515                 // context here instead of when dropping the window.
516                 wt.ime
517                     .borrow_mut()
518                     .remove_context(window)
519                     .expect("Failed to destroy input context");
520 
521                 callback(Event::WindowEvent {
522                     window_id,
523                     event: WindowEvent::Destroyed,
524                 });
525             }
526 
527             ffi::VisibilityNotify => {
528                 let xev: &ffi::XVisibilityEvent = xev.as_ref();
529                 let xwindow = xev.window;
530 
531                 self.with_window(xwindow, |window| window.visibility_notify());
532             }
533 
534             ffi::Expose => {
535                 let xev: &ffi::XExposeEvent = xev.as_ref();
536 
537                 // Multiple Expose events may be received for subareas of a window.
538                 // We issue `RedrawRequested` only for the last event of such a series.
539                 if xev.count == 0 {
540                     let window = xev.window;
541                     let window_id = mkwid(window);
542 
543                     callback(Event::RedrawRequested(window_id));
544                 }
545             }
546 
547             ffi::KeyPress | ffi::KeyRelease => {
548                 use crate::event::ElementState::{Pressed, Released};
549 
550                 // Note that in compose/pre-edit sequences, this will always be Released.
551                 let state = if xev.get_type() == ffi::KeyPress {
552                     Pressed
553                 } else {
554                     Released
555                 };
556 
557                 let xkev: &mut ffi::XKeyEvent = xev.as_mut();
558 
559                 let window = xkev.window;
560                 let window_id = mkwid(window);
561 
562                 // Standard virtual core keyboard ID. XInput2 needs to be used to get a reliable
563                 // value, though this should only be an issue under multiseat configurations.
564                 let device = util::VIRTUAL_CORE_KEYBOARD;
565                 let device_id = mkdid(device);
566                 let keycode = xkev.keycode;
567 
568                 // When a compose sequence or IME pre-edit is finished, it ends in a KeyPress with
569                 // a keycode of 0.
570                 if keycode != 0 {
571                     let scancode = keycode - KEYCODE_OFFSET as u32;
572                     let keysym = wt.xconn.lookup_keysym(xkev);
573                     let virtual_keycode = events::keysym_to_element(keysym as c_uint);
574 
575                     update_modifiers!(
576                         ModifiersState::from_x11_mask(xkev.state),
577                         self.mod_keymap.get_modifier(xkev.keycode as ffi::KeyCode)
578                     );
579 
580                     let modifiers = self.device_mod_state.modifiers();
581 
582                     #[allow(deprecated)]
583                     callback(Event::WindowEvent {
584                         window_id,
585                         event: WindowEvent::KeyboardInput {
586                             device_id,
587                             input: KeyboardInput {
588                                 state,
589                                 scancode,
590                                 virtual_keycode,
591                                 modifiers,
592                             },
593                             is_synthetic: false,
594                         },
595                     });
596                 }
597 
598                 if state == Pressed {
599                     let written = if let Some(ic) = wt.ime.borrow().get_context(window) {
600                         wt.xconn.lookup_utf8(ic, xkev)
601                     } else {
602                         return;
603                     };
604 
605                     for chr in written.chars() {
606                         let event = Event::WindowEvent {
607                             window_id,
608                             event: WindowEvent::ReceivedCharacter(chr),
609                         };
610                         callback(event);
611                     }
612                 }
613             }
614 
615             ffi::GenericEvent => {
616                 let guard = if let Some(e) = GenericEventCookie::from_event(&wt.xconn, *xev) {
617                     e
618                 } else {
619                     return;
620                 };
621                 let xev = &guard.cookie;
622                 if self.xi2ext.opcode != xev.extension {
623                     return;
624                 }
625 
626                 use crate::event::{
627                     ElementState::{Pressed, Released},
628                     MouseButton::{Left, Middle, Other, Right},
629                     MouseScrollDelta::LineDelta,
630                     Touch,
631                     WindowEvent::{
632                         AxisMotion, CursorEntered, CursorLeft, CursorMoved, Focused, MouseInput,
633                         MouseWheel,
634                     },
635                 };
636 
637                 match xev.evtype {
638                     ffi::XI_ButtonPress | ffi::XI_ButtonRelease => {
639                         let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
640                         let window_id = mkwid(xev.event);
641                         let device_id = mkdid(xev.deviceid);
642                         if (xev.flags & ffi::XIPointerEmulated) != 0 {
643                             // Deliver multi-touch events instead of emulated mouse events.
644                             return;
645                         }
646 
647                         let modifiers = ModifiersState::from_x11(&xev.mods);
648                         update_modifiers!(modifiers, None);
649 
650                         let state = if xev.evtype == ffi::XI_ButtonPress {
651                             Pressed
652                         } else {
653                             Released
654                         };
655                         match xev.detail as u32 {
656                             ffi::Button1 => callback(Event::WindowEvent {
657                                 window_id,
658                                 event: MouseInput {
659                                     device_id,
660                                     state,
661                                     button: Left,
662                                     modifiers,
663                                 },
664                             }),
665                             ffi::Button2 => callback(Event::WindowEvent {
666                                 window_id,
667                                 event: MouseInput {
668                                     device_id,
669                                     state,
670                                     button: Middle,
671                                     modifiers,
672                                 },
673                             }),
674                             ffi::Button3 => callback(Event::WindowEvent {
675                                 window_id,
676                                 event: MouseInput {
677                                     device_id,
678                                     state,
679                                     button: Right,
680                                     modifiers,
681                                 },
682                             }),
683 
684                             // Suppress emulated scroll wheel clicks, since we handle the real motion events for those.
685                             // In practice, even clicky scroll wheels appear to be reported by evdev (and XInput2 in
686                             // turn) as axis motion, so we don't otherwise special-case these button presses.
687                             4 | 5 | 6 | 7 => {
688                                 if xev.flags & ffi::XIPointerEmulated == 0 {
689                                     callback(Event::WindowEvent {
690                                         window_id,
691                                         event: MouseWheel {
692                                             device_id,
693                                             delta: match xev.detail {
694                                                 4 => LineDelta(0.0, 1.0),
695                                                 5 => LineDelta(0.0, -1.0),
696                                                 6 => LineDelta(-1.0, 0.0),
697                                                 7 => LineDelta(1.0, 0.0),
698                                                 _ => unreachable!(),
699                                             },
700                                             phase: TouchPhase::Moved,
701                                             modifiers,
702                                         },
703                                     });
704                                 }
705                             }
706 
707                             x => callback(Event::WindowEvent {
708                                 window_id,
709                                 event: MouseInput {
710                                     device_id,
711                                     state,
712                                     button: Other(x as u16),
713                                     modifiers,
714                                 },
715                             }),
716                         }
717                     }
718                     ffi::XI_Motion => {
719                         let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
720                         let device_id = mkdid(xev.deviceid);
721                         let window_id = mkwid(xev.event);
722                         let new_cursor_pos = (xev.event_x, xev.event_y);
723 
724                         let modifiers = ModifiersState::from_x11(&xev.mods);
725                         update_modifiers!(modifiers, None);
726 
727                         let cursor_moved = self.with_window(xev.event, |window| {
728                             let mut shared_state_lock = window.shared_state.lock();
729                             util::maybe_change(&mut shared_state_lock.cursor_pos, new_cursor_pos)
730                         });
731                         if cursor_moved == Some(true) {
732                             let position = PhysicalPosition::new(xev.event_x, xev.event_y);
733 
734                             callback(Event::WindowEvent {
735                                 window_id,
736                                 event: CursorMoved {
737                                     device_id,
738                                     position,
739                                     modifiers,
740                                 },
741                             });
742                         } else if cursor_moved.is_none() {
743                             return;
744                         }
745 
746                         // More gymnastics, for self.devices
747                         let mut events = Vec::new();
748                         {
749                             let mask = unsafe {
750                                 slice::from_raw_parts(
751                                     xev.valuators.mask,
752                                     xev.valuators.mask_len as usize,
753                                 )
754                             };
755                             let mut devices = self.devices.borrow_mut();
756                             let physical_device = match devices.get_mut(&DeviceId(xev.sourceid)) {
757                                 Some(device) => device,
758                                 None => return,
759                             };
760 
761                             let mut value = xev.valuators.values;
762                             for i in 0..xev.valuators.mask_len * 8 {
763                                 if ffi::XIMaskIsSet(mask, i) {
764                                     let x = unsafe { *value };
765                                     if let Some(&mut (_, ref mut info)) = physical_device
766                                         .scroll_axes
767                                         .iter_mut()
768                                         .find(|&&mut (axis, _)| axis == i)
769                                     {
770                                         let delta = (x - info.position) / info.increment;
771                                         info.position = x;
772                                         events.push(Event::WindowEvent {
773                                             window_id,
774                                             event: MouseWheel {
775                                                 device_id,
776                                                 delta: match info.orientation {
777                                                     ScrollOrientation::Horizontal => {
778                                                         LineDelta(delta as f32, 0.0)
779                                                     }
780                                                     // X11 vertical scroll coordinates are opposite to winit's
781                                                     ScrollOrientation::Vertical => {
782                                                         LineDelta(0.0, -delta as f32)
783                                                     }
784                                                 },
785                                                 phase: TouchPhase::Moved,
786                                                 modifiers,
787                                             },
788                                         });
789                                     } else {
790                                         events.push(Event::WindowEvent {
791                                             window_id,
792                                             event: AxisMotion {
793                                                 device_id,
794                                                 axis: i as u32,
795                                                 value: unsafe { *value },
796                                             },
797                                         });
798                                     }
799                                     value = unsafe { value.offset(1) };
800                                 }
801                             }
802                         }
803                         for event in events {
804                             callback(event);
805                         }
806                     }
807 
808                     ffi::XI_Enter => {
809                         let xev: &ffi::XIEnterEvent = unsafe { &*(xev.data as *const _) };
810 
811                         let window_id = mkwid(xev.event);
812                         let device_id = mkdid(xev.deviceid);
813 
814                         if let Some(all_info) = DeviceInfo::get(&wt.xconn, ffi::XIAllDevices) {
815                             let mut devices = self.devices.borrow_mut();
816                             for device_info in all_info.iter() {
817                                 if device_info.deviceid == xev.sourceid
818                                 // This is needed for resetting to work correctly on i3, and
819                                 // presumably some other WMs. On those, `XI_Enter` doesn't include
820                                 // the physical device ID, so both `sourceid` and `deviceid` are
821                                 // the virtual device.
822                                 || device_info.attachment == xev.sourceid
823                                 {
824                                     let device_id = DeviceId(device_info.deviceid);
825                                     if let Some(device) = devices.get_mut(&device_id) {
826                                         device.reset_scroll_position(device_info);
827                                     }
828                                 }
829                             }
830                         }
831 
832                         if self.window_exists(xev.event) {
833                             callback(Event::WindowEvent {
834                                 window_id,
835                                 event: CursorEntered { device_id },
836                             });
837 
838                             let position = PhysicalPosition::new(xev.event_x, xev.event_y);
839 
840                             // The mods field on this event isn't actually populated, so query the
841                             // pointer device. In the future, we can likely remove this round-trip by
842                             // relying on `Xkb` for modifier values.
843                             //
844                             // This needs to only be done after confirming the window still exists,
845                             // since otherwise we risk getting a `BadWindow` error if the window was
846                             // dropped with queued events.
847                             let modifiers = wt
848                                 .xconn
849                                 .query_pointer(xev.event, xev.deviceid)
850                                 .expect("Failed to query pointer device")
851                                 .get_modifier_state();
852 
853                             callback(Event::WindowEvent {
854                                 window_id,
855                                 event: CursorMoved {
856                                     device_id,
857                                     position,
858                                     modifiers,
859                                 },
860                             });
861                         }
862                     }
863                     ffi::XI_Leave => {
864                         let xev: &ffi::XILeaveEvent = unsafe { &*(xev.data as *const _) };
865 
866                         // Leave, FocusIn, and FocusOut can be received by a window that's already
867                         // been destroyed, which the user presumably doesn't want to deal with.
868                         let window_closed = !self.window_exists(xev.event);
869                         if !window_closed {
870                             callback(Event::WindowEvent {
871                                 window_id: mkwid(xev.event),
872                                 event: CursorLeft {
873                                     device_id: mkdid(xev.deviceid),
874                                 },
875                             });
876                         }
877                     }
878                     ffi::XI_FocusIn => {
879                         let xev: &ffi::XIFocusInEvent = unsafe { &*(xev.data as *const _) };
880 
881                         wt.ime
882                             .borrow_mut()
883                             .focus(xev.event)
884                             .expect("Failed to focus input context");
885 
886                         let modifiers = ModifiersState::from_x11(&xev.mods);
887 
888                         self.device_mod_state.update_state(&modifiers, None);
889 
890                         if self.active_window != Some(xev.event) {
891                             self.active_window = Some(xev.event);
892 
893                             let window_id = mkwid(xev.event);
894                             let position = PhysicalPosition::new(xev.event_x, xev.event_y);
895 
896                             callback(Event::WindowEvent {
897                                 window_id,
898                                 event: Focused(true),
899                             });
900 
901                             if !modifiers.is_empty() {
902                                 callback(Event::WindowEvent {
903                                     window_id,
904                                     event: WindowEvent::ModifiersChanged(modifiers),
905                                 });
906                             }
907 
908                             // The deviceid for this event is for a keyboard instead of a pointer,
909                             // so we have to do a little extra work.
910                             let pointer_id = self
911                                 .devices
912                                 .borrow()
913                                 .get(&DeviceId(xev.deviceid))
914                                 .map(|device| device.attachment)
915                                 .unwrap_or(2);
916 
917                             callback(Event::WindowEvent {
918                                 window_id,
919                                 event: CursorMoved {
920                                     device_id: mkdid(pointer_id),
921                                     position,
922                                     modifiers,
923                                 },
924                             });
925 
926                             // Issue key press events for all pressed keys
927                             Self::handle_pressed_keys(
928                                 &wt,
929                                 window_id,
930                                 ElementState::Pressed,
931                                 &self.mod_keymap,
932                                 &mut self.device_mod_state,
933                                 &mut callback,
934                             );
935                         }
936                     }
937                     ffi::XI_FocusOut => {
938                         let xev: &ffi::XIFocusOutEvent = unsafe { &*(xev.data as *const _) };
939                         if !self.window_exists(xev.event) {
940                             return;
941                         }
942                         wt.ime
943                             .borrow_mut()
944                             .unfocus(xev.event)
945                             .expect("Failed to unfocus input context");
946 
947                         if self.active_window.take() == Some(xev.event) {
948                             let window_id = mkwid(xev.event);
949 
950                             // Issue key release events for all pressed keys
951                             Self::handle_pressed_keys(
952                                 &wt,
953                                 window_id,
954                                 ElementState::Released,
955                                 &self.mod_keymap,
956                                 &mut self.device_mod_state,
957                                 &mut callback,
958                             );
959 
960                             callback(Event::WindowEvent {
961                                 window_id,
962                                 event: WindowEvent::ModifiersChanged(ModifiersState::empty()),
963                             });
964 
965                             callback(Event::WindowEvent {
966                                 window_id,
967                                 event: Focused(false),
968                             })
969                         }
970                     }
971 
972                     ffi::XI_TouchBegin | ffi::XI_TouchUpdate | ffi::XI_TouchEnd => {
973                         let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
974                         let window_id = mkwid(xev.event);
975                         let phase = match xev.evtype {
976                             ffi::XI_TouchBegin => TouchPhase::Started,
977                             ffi::XI_TouchUpdate => TouchPhase::Moved,
978                             ffi::XI_TouchEnd => TouchPhase::Ended,
979                             _ => unreachable!(),
980                         };
981                         if self.window_exists(xev.event) {
982                             let id = xev.detail as u64;
983                             let modifiers = self.device_mod_state.modifiers();
984                             let location =
985                                 PhysicalPosition::new(xev.event_x as f64, xev.event_y as f64);
986 
987                             // Mouse cursor position changes when touch events are received.
988                             // Only the first concurrently active touch ID moves the mouse cursor.
989                             if is_first_touch(&mut self.first_touch, &mut self.num_touch, id, phase)
990                             {
991                                 callback(Event::WindowEvent {
992                                     window_id,
993                                     event: WindowEvent::CursorMoved {
994                                         device_id: mkdid(util::VIRTUAL_CORE_POINTER),
995                                         position: location.cast(),
996                                         modifiers,
997                                     },
998                                 });
999                             }
1000 
1001                             callback(Event::WindowEvent {
1002                                 window_id,
1003                                 event: WindowEvent::Touch(Touch {
1004                                     device_id: mkdid(xev.deviceid),
1005                                     phase,
1006                                     location,
1007                                     force: None, // TODO
1008                                     id,
1009                                 }),
1010                             })
1011                         }
1012                     }
1013 
1014                     ffi::XI_RawButtonPress | ffi::XI_RawButtonRelease => {
1015                         let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
1016                         if xev.flags & ffi::XIPointerEmulated == 0 {
1017                             callback(Event::DeviceEvent {
1018                                 device_id: mkdid(xev.deviceid),
1019                                 event: DeviceEvent::Button {
1020                                     button: xev.detail as u32,
1021                                     state: match xev.evtype {
1022                                         ffi::XI_RawButtonPress => Pressed,
1023                                         ffi::XI_RawButtonRelease => Released,
1024                                         _ => unreachable!(),
1025                                     },
1026                                 },
1027                             });
1028                         }
1029                     }
1030 
1031                     ffi::XI_RawMotion => {
1032                         let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
1033                         let did = mkdid(xev.deviceid);
1034 
1035                         let mask = unsafe {
1036                             slice::from_raw_parts(
1037                                 xev.valuators.mask,
1038                                 xev.valuators.mask_len as usize,
1039                             )
1040                         };
1041                         let mut value = xev.raw_values;
1042                         let mut mouse_delta = (0.0, 0.0);
1043                         let mut scroll_delta = (0.0, 0.0);
1044                         for i in 0..xev.valuators.mask_len * 8 {
1045                             if ffi::XIMaskIsSet(mask, i) {
1046                                 let x = unsafe { *value };
1047                                 // We assume that every XInput2 device with analog axes is a pointing device emitting
1048                                 // relative coordinates.
1049                                 match i {
1050                                     0 => mouse_delta.0 = x,
1051                                     1 => mouse_delta.1 = x,
1052                                     2 => scroll_delta.0 = x as f32,
1053                                     3 => scroll_delta.1 = x as f32,
1054                                     _ => {}
1055                                 }
1056                                 callback(Event::DeviceEvent {
1057                                     device_id: did,
1058                                     event: DeviceEvent::Motion {
1059                                         axis: i as u32,
1060                                         value: x,
1061                                     },
1062                                 });
1063                                 value = unsafe { value.offset(1) };
1064                             }
1065                         }
1066                         if mouse_delta != (0.0, 0.0) {
1067                             callback(Event::DeviceEvent {
1068                                 device_id: did,
1069                                 event: DeviceEvent::MouseMotion { delta: mouse_delta },
1070                             });
1071                         }
1072                         if scroll_delta != (0.0, 0.0) {
1073                             callback(Event::DeviceEvent {
1074                                 device_id: did,
1075                                 event: DeviceEvent::MouseWheel {
1076                                     delta: LineDelta(scroll_delta.0, scroll_delta.1),
1077                                 },
1078                             });
1079                         }
1080                     }
1081 
1082                     ffi::XI_RawKeyPress | ffi::XI_RawKeyRelease => {
1083                         let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
1084 
1085                         let state = match xev.evtype {
1086                             ffi::XI_RawKeyPress => Pressed,
1087                             ffi::XI_RawKeyRelease => Released,
1088                             _ => unreachable!(),
1089                         };
1090 
1091                         let device_id = mkdid(xev.sourceid);
1092                         let keycode = xev.detail;
1093                         let scancode = keycode - KEYCODE_OFFSET as i32;
1094                         if scancode < 0 {
1095                             return;
1096                         }
1097                         let keysym = wt.xconn.keycode_to_keysym(keycode as ffi::KeyCode);
1098                         let virtual_keycode = events::keysym_to_element(keysym as c_uint);
1099                         let modifiers = self.device_mod_state.modifiers();
1100 
1101                         #[allow(deprecated)]
1102                         callback(Event::DeviceEvent {
1103                             device_id,
1104                             event: DeviceEvent::Key(KeyboardInput {
1105                                 scancode: scancode as u32,
1106                                 virtual_keycode,
1107                                 state,
1108                                 modifiers,
1109                             }),
1110                         });
1111 
1112                         if let Some(modifier) =
1113                             self.mod_keymap.get_modifier(keycode as ffi::KeyCode)
1114                         {
1115                             self.device_mod_state.key_event(
1116                                 state,
1117                                 keycode as ffi::KeyCode,
1118                                 modifier,
1119                             );
1120 
1121                             let new_modifiers = self.device_mod_state.modifiers();
1122 
1123                             if modifiers != new_modifiers {
1124                                 if let Some(window_id) = self.active_window {
1125                                     callback(Event::WindowEvent {
1126                                         window_id: mkwid(window_id),
1127                                         event: WindowEvent::ModifiersChanged(new_modifiers),
1128                                     });
1129                                 }
1130                             }
1131                         }
1132                     }
1133 
1134                     ffi::XI_HierarchyChanged => {
1135                         let xev: &ffi::XIHierarchyEvent = unsafe { &*(xev.data as *const _) };
1136                         for info in
1137                             unsafe { slice::from_raw_parts(xev.info, xev.num_info as usize) }
1138                         {
1139                             if 0 != info.flags & (ffi::XISlaveAdded | ffi::XIMasterAdded) {
1140                                 self.init_device(info.deviceid);
1141                                 callback(Event::DeviceEvent {
1142                                     device_id: mkdid(info.deviceid),
1143                                     event: DeviceEvent::Added,
1144                                 });
1145                             } else if 0 != info.flags & (ffi::XISlaveRemoved | ffi::XIMasterRemoved)
1146                             {
1147                                 callback(Event::DeviceEvent {
1148                                     device_id: mkdid(info.deviceid),
1149                                     event: DeviceEvent::Removed,
1150                                 });
1151                                 let mut devices = self.devices.borrow_mut();
1152                                 devices.remove(&DeviceId(info.deviceid));
1153                             }
1154                         }
1155                     }
1156 
1157                     _ => {}
1158                 }
1159             }
1160             _ => {
1161                 if event_type == self.randr_event_offset {
1162                     // In the future, it would be quite easy to emit monitor hotplug events.
1163                     let prev_list = monitor::invalidate_cached_monitor_list();
1164                     if let Some(prev_list) = prev_list {
1165                         let new_list = wt.xconn.available_monitors();
1166                         for new_monitor in new_list {
1167                             prev_list
1168                                 .iter()
1169                                 .find(|prev_monitor| prev_monitor.name == new_monitor.name)
1170                                 .map(|prev_monitor| {
1171                                     if new_monitor.scale_factor != prev_monitor.scale_factor {
1172                                         for (window_id, window) in wt.windows.borrow().iter() {
1173                                             if let Some(window) = window.upgrade() {
1174                                                 // Check if the window is on this monitor
1175                                                 let monitor = window.current_monitor();
1176                                                 if monitor.name == new_monitor.name {
1177                                                     let (width, height) =
1178                                                         window.inner_size_physical();
1179                                                     let (new_width, new_height) = window
1180                                                         .adjust_for_dpi(
1181                                                             prev_monitor.scale_factor,
1182                                                             new_monitor.scale_factor,
1183                                                             width,
1184                                                             height,
1185                                                             &*window.shared_state.lock(),
1186                                                         );
1187 
1188                                                     let window_id = crate::window::WindowId(
1189                                                         crate::platform_impl::platform::WindowId::X(
1190                                                             *window_id,
1191                                                         ),
1192                                                     );
1193                                                     let old_inner_size =
1194                                                         PhysicalSize::new(width, height);
1195                                                     let mut new_inner_size =
1196                                                         PhysicalSize::new(new_width, new_height);
1197 
1198                                                     callback(Event::WindowEvent {
1199                                                         window_id,
1200                                                         event: WindowEvent::ScaleFactorChanged {
1201                                                             scale_factor: new_monitor.scale_factor,
1202                                                             new_inner_size: &mut new_inner_size,
1203                                                         },
1204                                                     });
1205 
1206                                                     if new_inner_size != old_inner_size {
1207                                                         let (new_width, new_height) =
1208                                                             new_inner_size.into();
1209                                                         window.set_inner_size_physical(
1210                                                             new_width, new_height,
1211                                                         );
1212                                                     }
1213                                                 }
1214                                             }
1215                                         }
1216                                     }
1217                                 });
1218                         }
1219                     }
1220                 }
1221             }
1222         }
1223 
1224         match self.ime_receiver.try_recv() {
1225             Ok((window_id, x, y)) => {
1226                 wt.ime.borrow_mut().send_xim_spot(window_id, x, y);
1227             }
1228             Err(_) => (),
1229         }
1230     }
1231 
handle_pressed_keys<F>( wt: &super::EventLoopWindowTarget<T>, window_id: crate::window::WindowId, state: ElementState, mod_keymap: &ModifierKeymap, device_mod_state: &mut ModifierKeyState, callback: &mut F, ) where F: FnMut(Event<'_, T>),1232     fn handle_pressed_keys<F>(
1233         wt: &super::EventLoopWindowTarget<T>,
1234         window_id: crate::window::WindowId,
1235         state: ElementState,
1236         mod_keymap: &ModifierKeymap,
1237         device_mod_state: &mut ModifierKeyState,
1238         callback: &mut F,
1239     ) where
1240         F: FnMut(Event<'_, T>),
1241     {
1242         let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD);
1243         let modifiers = device_mod_state.modifiers();
1244 
1245         // Update modifiers state and emit key events based on which keys are currently pressed.
1246         for keycode in wt
1247             .xconn
1248             .query_keymap()
1249             .into_iter()
1250             .filter(|k| *k >= KEYCODE_OFFSET)
1251         {
1252             let scancode = (keycode - KEYCODE_OFFSET) as u32;
1253             let keysym = wt.xconn.keycode_to_keysym(keycode);
1254             let virtual_keycode = events::keysym_to_element(keysym as c_uint);
1255 
1256             if let Some(modifier) = mod_keymap.get_modifier(keycode as ffi::KeyCode) {
1257                 device_mod_state.key_event(
1258                     ElementState::Pressed,
1259                     keycode as ffi::KeyCode,
1260                     modifier,
1261                 );
1262             }
1263 
1264             #[allow(deprecated)]
1265             callback(Event::WindowEvent {
1266                 window_id,
1267                 event: WindowEvent::KeyboardInput {
1268                     device_id,
1269                     input: KeyboardInput {
1270                         scancode,
1271                         state,
1272                         virtual_keycode,
1273                         modifiers,
1274                     },
1275                     is_synthetic: true,
1276                 },
1277             });
1278         }
1279     }
1280 }
1281 
is_first_touch(first: &mut Option<u64>, num: &mut u32, id: u64, phase: TouchPhase) -> bool1282 fn is_first_touch(first: &mut Option<u64>, num: &mut u32, id: u64, phase: TouchPhase) -> bool {
1283     match phase {
1284         TouchPhase::Started => {
1285             if *num == 0 {
1286                 *first = Some(id);
1287             }
1288             *num += 1;
1289         }
1290         TouchPhase::Cancelled | TouchPhase::Ended => {
1291             if *first == Some(id) {
1292                 *first = None;
1293             }
1294             *num = num.saturating_sub(1);
1295         }
1296         _ => (),
1297     }
1298 
1299     *first == Some(id)
1300 }
1301