winit/platform_impl/linux/x11/
event_processor.rs

1use std::cell::{Cell, RefCell};
2use std::collections::{HashMap, VecDeque};
3use std::os::raw::{c_char, c_int, c_long, c_ulong};
4use std::slice;
5use std::sync::{Arc, Mutex};
6
7use x11_dl::xinput2::{
8    self, XIDeviceEvent, XIEnterEvent, XIFocusInEvent, XIFocusOutEvent, XIHierarchyEvent,
9    XILeaveEvent, XIModifierState, XIRawEvent,
10};
11use x11_dl::xlib::{
12    self, Display as XDisplay, Window as XWindow, XAnyEvent, XClientMessageEvent, XConfigureEvent,
13    XDestroyWindowEvent, XEvent, XExposeEvent, XKeyEvent, XMapEvent, XPropertyEvent,
14    XReparentEvent, XSelectionEvent, XVisibilityEvent, XkbAnyEvent, XkbStateRec,
15};
16use x11rb::protocol::sync::{ConnectionExt, Int64};
17use x11rb::protocol::xinput;
18use x11rb::protocol::xkb::ID as XkbId;
19use x11rb::protocol::xproto::{self, ConnectionExt as _, ModMask};
20use x11rb::x11_utils::{ExtensionInformation, Serialize};
21use xkbcommon_dl::xkb_mod_mask_t;
22
23use crate::dpi::{PhysicalPosition, PhysicalSize};
24use crate::event::{
25    DeviceEvent, ElementState, Event, Ime, MouseButton, MouseScrollDelta, RawKeyEvent,
26    SurfaceSizeWriter, Touch, TouchPhase, WindowEvent,
27};
28use crate::keyboard::ModifiersState;
29use crate::platform_impl::common::xkb::{self, XkbState};
30use crate::platform_impl::platform::common::xkb::Context;
31use crate::platform_impl::platform::x11::ime::{ImeEvent, ImeEventReceiver, ImeRequest};
32use crate::platform_impl::platform::x11::ActiveEventLoop;
33use crate::platform_impl::x11::atoms::*;
34use crate::platform_impl::x11::util::cookie::GenericEventCookie;
35use crate::platform_impl::x11::{
36    mkdid, mkfid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState,
37    ImeReceiver, ScrollOrientation, UnownedWindow, WindowId,
38};
39
40/// The maximum amount of X modifiers to replay.
41pub const MAX_MOD_REPLAY_LEN: usize = 32;
42
43/// The X11 documentation states: "Keycodes lie in the inclusive range `[8, 255]`".
44const KEYCODE_OFFSET: u8 = 8;
45
46pub struct EventProcessor {
47    pub dnd: Dnd,
48    pub ime_receiver: ImeReceiver,
49    pub ime_event_receiver: ImeEventReceiver,
50    pub randr_event_offset: u8,
51    pub devices: RefCell<HashMap<DeviceId, Device>>,
52    pub xi2ext: ExtensionInformation,
53    pub xkbext: ExtensionInformation,
54    pub target: ActiveEventLoop,
55    pub xkb_context: Context,
56    // Number of touch events currently in progress
57    pub num_touch: u32,
58    // This is the last pressed key that is repeatable (if it hasn't been
59    // released).
60    //
61    // Used to detect key repeats.
62    pub held_key_press: Option<u32>,
63    pub first_touch: Option<u32>,
64    // Currently focused window belonging to this process
65    pub active_window: Option<xproto::Window>,
66    /// Latest modifiers we've sent for the user to trigger change in event.
67    pub modifiers: Cell<ModifiersState>,
68    pub xfiltered_modifiers: VecDeque<c_ulong>,
69    pub xmodmap: util::ModifierKeymap,
70    pub is_composing: bool,
71}
72
73impl EventProcessor {
74    pub(crate) fn process_event<F>(&mut self, xev: &mut XEvent, mut callback: F)
75    where
76        F: FnMut(&ActiveEventLoop, Event),
77    {
78        self.process_xevent(xev, &mut callback);
79
80        // Handle IME requests.
81        while let Ok(request) = self.ime_receiver.try_recv() {
82            let ime = match self.target.ime.as_mut() {
83                Some(ime) => ime,
84                None => continue,
85            };
86
87            let ime = ime.get_mut();
88            match request {
89                ImeRequest::Position(window_id, x, y) => {
90                    ime.send_xim_spot(window_id, x, y);
91                },
92                ImeRequest::Allow(window_id, allowed) => {
93                    ime.set_ime_allowed(window_id, allowed);
94                },
95            }
96        }
97
98        // Drain IME events.
99        while let Ok((window, event)) = self.ime_event_receiver.try_recv() {
100            let window_id = mkwid(window as xproto::Window);
101            let event = match event {
102                ImeEvent::Enabled => WindowEvent::Ime(Ime::Enabled),
103                ImeEvent::Start => {
104                    self.is_composing = true;
105                    WindowEvent::Ime(Ime::Preedit("".to_owned(), None))
106                },
107                ImeEvent::Update(text, position) if self.is_composing => {
108                    WindowEvent::Ime(Ime::Preedit(text, Some((position, position))))
109                },
110                ImeEvent::End => {
111                    self.is_composing = false;
112                    // Issue empty preedit on `Done`.
113                    WindowEvent::Ime(Ime::Preedit(String::new(), None))
114                },
115                ImeEvent::Disabled => {
116                    self.is_composing = false;
117                    WindowEvent::Ime(Ime::Disabled)
118                },
119                _ => continue,
120            };
121
122            callback(&self.target, Event::WindowEvent { window_id, event });
123        }
124    }
125
126    /// XFilterEvent tells us when an event has been discarded by the input method.
127    /// Specifically, this involves all of the KeyPress events in compose/pre-edit sequences,
128    /// along with an extra copy of the KeyRelease events. This also prevents backspace and
129    /// arrow keys from being detected twice.
130    fn filter_event(&mut self, xev: &mut XEvent) -> bool {
131        unsafe {
132            (self.target.xconn.xlib.XFilterEvent)(xev, {
133                let xev: &XAnyEvent = xev.as_ref();
134                xev.window
135            }) == xlib::True
136        }
137    }
138
139    fn process_xevent<F>(&mut self, xev: &mut XEvent, mut callback: F)
140    where
141        F: FnMut(&ActiveEventLoop, Event),
142    {
143        let event_type = xev.get_type();
144
145        if self.filter_event(xev) {
146            if event_type == xlib::KeyPress || event_type == xlib::KeyRelease {
147                let xev: &XKeyEvent = xev.as_ref();
148                if self.xmodmap.is_modifier(xev.keycode as u8) {
149                    // Don't grow the buffer past the `MAX_MOD_REPLAY_LEN`. This could happen
150                    // when the modifiers are consumed entirely or serials are altered.
151                    //
152                    // Both cases shouldn't happen in well behaving clients.
153                    if self.xfiltered_modifiers.len() == MAX_MOD_REPLAY_LEN {
154                        self.xfiltered_modifiers.pop_back();
155                    }
156                    self.xfiltered_modifiers.push_front(xev.serial);
157                }
158            }
159            return;
160        }
161
162        match event_type {
163            xlib::ClientMessage => self.client_message(xev.as_ref(), &mut callback),
164            xlib::SelectionNotify => self.selection_notify(xev.as_ref(), &mut callback),
165            xlib::ConfigureNotify => self.configure_notify(xev.as_ref(), &mut callback),
166            xlib::ReparentNotify => self.reparent_notify(xev.as_ref()),
167            xlib::MapNotify => self.map_notify(xev.as_ref(), &mut callback),
168            xlib::DestroyNotify => self.destroy_notify(xev.as_ref(), &mut callback),
169            xlib::PropertyNotify => self.property_notify(xev.as_ref(), &mut callback),
170            xlib::VisibilityNotify => self.visibility_notify(xev.as_ref(), &mut callback),
171            xlib::Expose => self.expose(xev.as_ref(), &mut callback),
172            // Note that in compose/pre-edit sequences, we'll always receive KeyRelease events.
173            ty @ xlib::KeyPress | ty @ xlib::KeyRelease => {
174                let state = if ty == xlib::KeyPress {
175                    ElementState::Pressed
176                } else {
177                    ElementState::Released
178                };
179
180                self.xinput_key_input(xev.as_mut(), state, &mut callback);
181            },
182            xlib::GenericEvent => {
183                let xev: GenericEventCookie =
184                    match GenericEventCookie::from_event(self.target.xconn.clone(), *xev) {
185                        Some(xev) if xev.extension() == self.xi2ext.major_opcode => xev,
186                        _ => return,
187                    };
188
189                let evtype = xev.evtype();
190
191                match evtype {
192                    ty @ xinput2::XI_ButtonPress | ty @ xinput2::XI_ButtonRelease => {
193                        let state = if ty == xinput2::XI_ButtonPress {
194                            ElementState::Pressed
195                        } else {
196                            ElementState::Released
197                        };
198
199                        let xev: &XIDeviceEvent = unsafe { xev.as_event() };
200                        self.update_mods_from_xinput2_event(
201                            &xev.mods,
202                            &xev.group,
203                            false,
204                            &mut callback,
205                        );
206                        self.xinput2_button_input(xev, state, &mut callback);
207                    },
208                    xinput2::XI_Motion => {
209                        let xev: &XIDeviceEvent = unsafe { xev.as_event() };
210                        self.update_mods_from_xinput2_event(
211                            &xev.mods,
212                            &xev.group,
213                            false,
214                            &mut callback,
215                        );
216                        self.xinput2_mouse_motion(xev, &mut callback);
217                    },
218                    xinput2::XI_Enter => {
219                        let xev: &XIEnterEvent = unsafe { xev.as_event() };
220                        self.xinput2_mouse_enter(xev, &mut callback);
221                    },
222                    xinput2::XI_Leave => {
223                        let xev: &XILeaveEvent = unsafe { xev.as_event() };
224                        self.update_mods_from_xinput2_event(
225                            &xev.mods,
226                            &xev.group,
227                            false,
228                            &mut callback,
229                        );
230                        self.xinput2_mouse_left(xev, &mut callback);
231                    },
232                    xinput2::XI_FocusIn => {
233                        let xev: &XIFocusInEvent = unsafe { xev.as_event() };
234                        self.xinput2_focused(xev, &mut callback);
235                    },
236                    xinput2::XI_FocusOut => {
237                        let xev: &XIFocusOutEvent = unsafe { xev.as_event() };
238                        self.xinput2_unfocused(xev, &mut callback);
239                    },
240                    xinput2::XI_TouchBegin | xinput2::XI_TouchUpdate | xinput2::XI_TouchEnd => {
241                        let phase = match evtype {
242                            xinput2::XI_TouchBegin => TouchPhase::Started,
243                            xinput2::XI_TouchUpdate => TouchPhase::Moved,
244                            xinput2::XI_TouchEnd => TouchPhase::Ended,
245                            _ => unreachable!(),
246                        };
247
248                        let xev: &XIDeviceEvent = unsafe { xev.as_event() };
249                        self.xinput2_touch(xev, phase, &mut callback);
250                    },
251                    xinput2::XI_RawButtonPress | xinput2::XI_RawButtonRelease => {
252                        let state = match evtype {
253                            xinput2::XI_RawButtonPress => ElementState::Pressed,
254                            xinput2::XI_RawButtonRelease => ElementState::Released,
255                            _ => unreachable!(),
256                        };
257
258                        let xev: &XIRawEvent = unsafe { xev.as_event() };
259                        self.xinput2_raw_button_input(xev, state, &mut callback);
260                    },
261                    xinput2::XI_RawMotion => {
262                        let xev: &XIRawEvent = unsafe { xev.as_event() };
263                        self.xinput2_raw_mouse_motion(xev, &mut callback);
264                    },
265                    xinput2::XI_RawKeyPress | xinput2::XI_RawKeyRelease => {
266                        let state = match evtype {
267                            xinput2::XI_RawKeyPress => ElementState::Pressed,
268                            xinput2::XI_RawKeyRelease => ElementState::Released,
269                            _ => unreachable!(),
270                        };
271
272                        let xev: &xinput2::XIRawEvent = unsafe { xev.as_event() };
273                        self.xinput2_raw_key_input(xev, state, &mut callback);
274                    },
275
276                    xinput2::XI_HierarchyChanged => {
277                        let xev: &XIHierarchyEvent = unsafe { xev.as_event() };
278                        self.xinput2_hierarchy_changed(xev);
279                    },
280                    _ => {},
281                }
282            },
283            _ => {
284                if event_type == self.xkbext.first_event as _ {
285                    let xev: &XkbAnyEvent = unsafe { &*(xev as *const _ as *const XkbAnyEvent) };
286                    self.xkb_event(xev, &mut callback);
287                }
288                if event_type == self.randr_event_offset as c_int {
289                    self.process_dpi_change(&mut callback);
290                }
291            },
292        }
293    }
294
295    pub fn poll(&self) -> bool {
296        unsafe { (self.target.xconn.xlib.XPending)(self.target.xconn.display) != 0 }
297    }
298
299    pub unsafe fn poll_one_event(&mut self, event_ptr: *mut XEvent) -> bool {
300        // This function is used to poll and remove a single event
301        // from the Xlib event queue in a non-blocking, atomic way.
302        // XCheckIfEvent is non-blocking and removes events from queue.
303        // XNextEvent can't be used because it blocks while holding the
304        // global Xlib mutex.
305        // XPeekEvent does not remove events from the queue.
306        unsafe extern "C" fn predicate(
307            _display: *mut XDisplay,
308            _event: *mut XEvent,
309            _arg: *mut c_char,
310        ) -> c_int {
311            // This predicate always returns "true" (1) to accept all events
312            1
313        }
314
315        unsafe {
316            (self.target.xconn.xlib.XCheckIfEvent)(
317                self.target.xconn.display,
318                event_ptr,
319                Some(predicate),
320                std::ptr::null_mut(),
321            ) != 0
322        }
323    }
324
325    pub fn init_device(&self, device: xinput::DeviceId) {
326        let mut devices = self.devices.borrow_mut();
327        if let Some(info) = DeviceInfo::get(&self.target.xconn, device as _) {
328            for info in info.iter() {
329                devices.insert(DeviceId(info.deviceid as _), Device::new(info));
330            }
331        }
332    }
333
334    pub fn with_window<F, Ret>(&self, window_id: xproto::Window, callback: F) -> Option<Ret>
335    where
336        F: Fn(&Arc<UnownedWindow>) -> Ret,
337    {
338        let mut deleted = false;
339        let window_id = WindowId(window_id as _);
340        let result = self
341            .target
342            .windows
343            .borrow()
344            .get(&window_id)
345            .and_then(|window| {
346                let arc = window.upgrade();
347                deleted = arc.is_none();
348                arc
349            })
350            .map(|window| callback(&window));
351
352        if deleted {
353            // Garbage collection
354            self.target.windows.borrow_mut().remove(&window_id);
355        }
356
357        result
358    }
359
360    fn client_message<F>(&mut self, xev: &XClientMessageEvent, mut callback: F)
361    where
362        F: FnMut(&ActiveEventLoop, Event),
363    {
364        let atoms = self.target.xconn.atoms();
365
366        let window = xev.window as xproto::Window;
367        let window_id = mkwid(window);
368
369        if xev.data.get_long(0) as xproto::Atom == self.target.wm_delete_window {
370            let event = Event::WindowEvent { window_id, event: WindowEvent::CloseRequested };
371            callback(&self.target, event);
372            return;
373        }
374
375        if xev.data.get_long(0) as xproto::Atom == self.target.net_wm_ping {
376            let client_msg = xproto::ClientMessageEvent {
377                response_type: xproto::CLIENT_MESSAGE_EVENT,
378                format: xev.format as _,
379                sequence: xev.serial as _,
380                window: self.target.root,
381                type_: xev.message_type as _,
382                data: xproto::ClientMessageData::from({
383                    let [a, b, c, d, e]: [c_long; 5] = xev.data.as_longs().try_into().unwrap();
384                    [a as u32, b as u32, c as u32, d as u32, e as u32]
385                }),
386            };
387
388            self.target
389                .xconn
390                .xcb_connection()
391                .send_event(
392                    false,
393                    self.target.root,
394                    xproto::EventMask::SUBSTRUCTURE_NOTIFY
395                        | xproto::EventMask::SUBSTRUCTURE_REDIRECT,
396                    client_msg.serialize(),
397                )
398                .expect_then_ignore_error("Failed to send `ClientMessage` event.");
399            return;
400        }
401
402        if xev.data.get_long(0) as xproto::Atom == self.target.net_wm_sync_request {
403            let sync_counter_id = match self
404                .with_window(xev.window as xproto::Window, |window| window.sync_counter_id())
405            {
406                Some(Some(sync_counter_id)) => sync_counter_id.get(),
407                _ => return,
408            };
409
410            #[cfg(target_pointer_width = "32")]
411            let (lo, hi) =
412                (bytemuck::cast::<c_long, u32>(xev.data.get_long(2)), xev.data.get_long(3));
413
414            #[cfg(not(target_pointer_width = "32"))]
415            let (lo, hi) = (
416                (xev.data.get_long(2) & 0xffffffff) as u32,
417                bytemuck::cast::<u32, i32>((xev.data.get_long(3) & 0xffffffff) as u32),
418            );
419
420            self.target
421                .xconn
422                .xcb_connection()
423                .sync_set_counter(sync_counter_id, Int64 { lo, hi })
424                .expect_then_ignore_error("Failed to set XSync counter.");
425
426            return;
427        }
428
429        if xev.message_type == atoms[XdndEnter] as c_ulong {
430            let source_window = xev.data.get_long(0) as xproto::Window;
431            let flags = xev.data.get_long(1);
432            let version = flags >> 24;
433            self.dnd.version = Some(version);
434            let has_more_types = flags - (flags & (c_long::MAX - 1)) == 1;
435            if !has_more_types {
436                let type_list = vec![
437                    xev.data.get_long(2) as xproto::Atom,
438                    xev.data.get_long(3) as xproto::Atom,
439                    xev.data.get_long(4) as xproto::Atom,
440                ];
441                self.dnd.type_list = Some(type_list);
442            } else if let Ok(more_types) = unsafe { self.dnd.get_type_list(source_window) } {
443                self.dnd.type_list = Some(more_types);
444            }
445            return;
446        }
447
448        if xev.message_type == atoms[XdndPosition] as c_ulong {
449            // This event occurs every time the mouse moves while a file's being dragged
450            // over our window. We emit HoveredFile in response; while the macOS backend
451            // does that upon a drag entering, XDND doesn't have access to the actual drop
452            // data until this event. For parity with other platforms, we only emit
453            // `HoveredFile` the first time, though if winit's API is later extended to
454            // supply position updates with `HoveredFile` or another event, implementing
455            // that here would be trivial.
456
457            let source_window = xev.data.get_long(0) as xproto::Window;
458
459            // Equivalent to `(x << shift) | y`
460            // where `shift = mem::size_of::<c_short>() * 8`
461            // Note that coordinates are in "desktop space", not "window space"
462            // (in X11 parlance, they're root window coordinates)
463            // let packed_coordinates = xev.data.get_long(2);
464            // let shift = mem::size_of::<libc::c_short>() * 8;
465            // let x = packed_coordinates >> shift;
466            // let y = packed_coordinates & !(x << shift);
467
468            // By our own state flow, `version` should never be `None` at this point.
469            let version = self.dnd.version.unwrap_or(5);
470
471            // Action is specified in versions 2 and up, though we don't need it anyway.
472            // let action = xev.data.get_long(4);
473
474            let accepted = if let Some(ref type_list) = self.dnd.type_list {
475                type_list.contains(&atoms[TextUriList])
476            } else {
477                false
478            };
479
480            if !accepted {
481                unsafe {
482                    self.dnd
483                        .send_status(window, source_window, DndState::Rejected)
484                        .expect("Failed to send `XdndStatus` message.");
485                }
486                self.dnd.reset();
487                return;
488            }
489
490            self.dnd.source_window = Some(source_window);
491            if self.dnd.result.is_none() {
492                let time = if version >= 1 {
493                    xev.data.get_long(3) as xproto::Timestamp
494                } else {
495                    // In version 0, time isn't specified
496                    x11rb::CURRENT_TIME
497                };
498
499                // Log this timestamp.
500                self.target.xconn.set_timestamp(time);
501
502                // This results in the `SelectionNotify` event below
503                unsafe {
504                    self.dnd.convert_selection(window, time);
505                }
506            }
507
508            unsafe {
509                self.dnd
510                    .send_status(window, source_window, DndState::Accepted)
511                    .expect("Failed to send `XdndStatus` message.");
512            }
513            return;
514        }
515
516        if xev.message_type == atoms[XdndDrop] as c_ulong {
517            let (source_window, state) = if let Some(source_window) = self.dnd.source_window {
518                if let Some(Ok(ref path_list)) = self.dnd.result {
519                    for path in path_list {
520                        let event = Event::WindowEvent {
521                            window_id,
522                            event: WindowEvent::DroppedFile(path.clone()),
523                        };
524                        callback(&self.target, event);
525                    }
526                }
527                (source_window, DndState::Accepted)
528            } else {
529                // `source_window` won't be part of our DND state if we already rejected the drop in
530                // our `XdndPosition` handler.
531                let source_window = xev.data.get_long(0) as xproto::Window;
532                (source_window, DndState::Rejected)
533            };
534
535            unsafe {
536                self.dnd
537                    .send_finished(window, source_window, state)
538                    .expect("Failed to send `XdndFinished` message.");
539            }
540
541            self.dnd.reset();
542            return;
543        }
544
545        if xev.message_type == atoms[XdndLeave] as c_ulong {
546            self.dnd.reset();
547            let event = Event::WindowEvent { window_id, event: WindowEvent::HoveredFileCancelled };
548            callback(&self.target, event);
549        }
550    }
551
552    fn selection_notify<F>(&mut self, xev: &XSelectionEvent, mut callback: F)
553    where
554        F: FnMut(&ActiveEventLoop, Event),
555    {
556        let atoms = self.target.xconn.atoms();
557
558        let window = xev.requestor as xproto::Window;
559        let window_id = mkwid(window);
560
561        // Set the timestamp.
562        self.target.xconn.set_timestamp(xev.time as xproto::Timestamp);
563
564        if xev.property != atoms[XdndSelection] as c_ulong {
565            return;
566        }
567
568        // This is where we receive data from drag and drop
569        self.dnd.result = None;
570        if let Ok(mut data) = unsafe { self.dnd.read_data(window) } {
571            let parse_result = self.dnd.parse_data(&mut data);
572            if let Ok(ref path_list) = parse_result {
573                for path in path_list {
574                    let event = Event::WindowEvent {
575                        window_id,
576                        event: WindowEvent::HoveredFile(path.clone()),
577                    };
578                    callback(&self.target, event);
579                }
580            }
581            self.dnd.result = Some(parse_result);
582        }
583    }
584
585    fn configure_notify<F>(&self, xev: &XConfigureEvent, mut callback: F)
586    where
587        F: FnMut(&ActiveEventLoop, Event),
588    {
589        let xwindow = xev.window as xproto::Window;
590        let window_id = mkwid(xwindow);
591
592        let window = match self.with_window(xwindow, Arc::clone) {
593            Some(window) => window,
594            None => return,
595        };
596
597        // So apparently...
598        // `XSendEvent` (synthetic `ConfigureNotify`) -> position relative to root
599        // `XConfigureNotify` (real `ConfigureNotify`) -> position relative to parent
600        // https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.5
601        // We don't want to send `Moved` when this is false, since then every `SurfaceResized`
602        // (whether the window moved or not) is accompanied by an extraneous `Moved` event
603        // that has a position relative to the parent window.
604        let is_synthetic = xev.send_event == xlib::True;
605
606        // These are both in physical space.
607        let new_surface_size = (xev.width as u32, xev.height as u32);
608        let new_inner_position = (xev.x, xev.y);
609
610        let (mut resized, moved) = {
611            let mut shared_state_lock = window.shared_state_lock();
612
613            let resized = util::maybe_change(&mut shared_state_lock.size, new_surface_size);
614            let moved = if is_synthetic {
615                util::maybe_change(&mut shared_state_lock.inner_position, new_inner_position)
616            } else {
617                // Detect when frame extents change.
618                // Since this isn't synthetic, as per the notes above, this position is relative to
619                // the parent window.
620                let rel_parent = new_inner_position;
621                if util::maybe_change(&mut shared_state_lock.inner_position_rel_parent, rel_parent)
622                {
623                    // This ensures we process the next `Moved`.
624                    shared_state_lock.inner_position = None;
625                    // Extra insurance against stale frame extents.
626                    shared_state_lock.frame_extents = None;
627                }
628                false
629            };
630            (resized, moved)
631        };
632
633        let position = window.shared_state_lock().position;
634
635        let new_outer_position = if let (Some(position), false) = (position, moved) {
636            position
637        } else {
638            let mut shared_state_lock = window.shared_state_lock();
639
640            // We need to convert client area position to window position.
641            let frame_extents =
642                shared_state_lock.frame_extents.as_ref().cloned().unwrap_or_else(|| {
643                    let frame_extents =
644                        self.target.xconn.get_frame_extents_heuristic(xwindow, self.target.root);
645                    shared_state_lock.frame_extents = Some(frame_extents.clone());
646                    frame_extents
647                });
648            let outer =
649                frame_extents.inner_pos_to_outer(new_inner_position.0, new_inner_position.1);
650            shared_state_lock.position = Some(outer);
651
652            // Unlock shared state to prevent deadlock in callback below
653            drop(shared_state_lock);
654
655            if moved {
656                callback(&self.target, Event::WindowEvent {
657                    window_id,
658                    event: WindowEvent::Moved(outer.into()),
659                });
660            }
661            outer
662        };
663
664        if is_synthetic {
665            let mut shared_state_lock = window.shared_state_lock();
666            // If we don't use the existing adjusted value when available, then the user can screw
667            // up the resizing by dragging across monitors *without* dropping the
668            // window.
669            let (width, height) =
670                shared_state_lock.dpi_adjusted.unwrap_or((xev.width as u32, xev.height as u32));
671
672            let last_scale_factor = shared_state_lock.last_monitor.scale_factor;
673            let new_scale_factor = {
674                let window_rect = util::AaRect::new(new_outer_position, new_surface_size);
675                let monitor = self
676                    .target
677                    .xconn
678                    .get_monitor_for_window(Some(window_rect))
679                    .expect("Failed to find monitor for window");
680
681                if monitor.is_dummy() {
682                    // Avoid updating monitor using a dummy monitor handle
683                    last_scale_factor
684                } else {
685                    shared_state_lock.last_monitor = monitor.clone();
686                    monitor.scale_factor
687                }
688            };
689            if last_scale_factor != new_scale_factor {
690                let (new_width, new_height) = window.adjust_for_dpi(
691                    last_scale_factor,
692                    new_scale_factor,
693                    width,
694                    height,
695                    &shared_state_lock,
696                );
697
698                let old_surface_size = PhysicalSize::new(width, height);
699                let new_surface_size = PhysicalSize::new(new_width, new_height);
700
701                // Unlock shared state to prevent deadlock in callback below
702                drop(shared_state_lock);
703
704                let surface_size = Arc::new(Mutex::new(new_surface_size));
705                callback(&self.target, Event::WindowEvent {
706                    window_id,
707                    event: WindowEvent::ScaleFactorChanged {
708                        scale_factor: new_scale_factor,
709                        surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(&surface_size)),
710                    },
711                });
712
713                let new_surface_size = *surface_size.lock().unwrap();
714                drop(surface_size);
715
716                if new_surface_size != old_surface_size {
717                    window.request_surface_size_physical(
718                        new_surface_size.width,
719                        new_surface_size.height,
720                    );
721                    window.shared_state_lock().dpi_adjusted = Some(new_surface_size.into());
722                    // if the DPI factor changed, force a resize event to ensure the logical
723                    // size is computed with the right DPI factor
724                    resized = true;
725                }
726            }
727        }
728
729        // NOTE: Ensure that the lock is dropped before handling the resized and
730        // sending the event back to user.
731        let hittest = {
732            let mut shared_state_lock = window.shared_state_lock();
733            let hittest = shared_state_lock.cursor_hittest;
734
735            // This is a hack to ensure that the DPI adjusted resize is actually
736            // applied on all WMs. KWin doesn't need this, but Xfwm does. The hack
737            // should not be run on other WMs, since tiling WMs constrain the window
738            // size, making the resize fail. This would cause an endless stream of
739            // XResizeWindow requests, making Xorg, the winit client, and the WM
740            // consume 100% of CPU.
741            if let Some(adjusted_size) = shared_state_lock.dpi_adjusted {
742                if new_surface_size == adjusted_size || !util::wm_name_is_one_of(&["Xfwm4"]) {
743                    // When this finally happens, the event will not be synthetic.
744                    shared_state_lock.dpi_adjusted = None;
745                } else {
746                    // Unlock shared state to prevent deadlock in callback below
747                    drop(shared_state_lock);
748                    window.request_surface_size_physical(adjusted_size.0, adjusted_size.1);
749                }
750            }
751
752            hittest
753        };
754
755        // Reload hittest.
756        if hittest.unwrap_or(false) {
757            let _ = window.set_cursor_hittest(true);
758        }
759
760        if resized {
761            callback(&self.target, Event::WindowEvent {
762                window_id,
763                event: WindowEvent::SurfaceResized(new_surface_size.into()),
764            });
765        }
766    }
767
768    /// This is generally a reliable way to detect when the window manager's been
769    /// replaced, though this event is only fired by reparenting window managers
770    /// (which is almost all of them). Failing to correctly update WM info doesn't
771    /// really have much impact, since on the WMs affected (xmonad, dwm, etc.) the only
772    /// effect is that we waste some time trying to query unsupported properties.
773    fn reparent_notify(&self, xev: &XReparentEvent) {
774        self.target.xconn.update_cached_wm_info(self.target.root);
775
776        self.with_window(xev.window as xproto::Window, |window| {
777            window.invalidate_cached_frame_extents();
778        });
779    }
780
781    fn map_notify<F>(&self, xev: &XMapEvent, mut callback: F)
782    where
783        F: FnMut(&ActiveEventLoop, Event),
784    {
785        let window = xev.window as xproto::Window;
786        let window_id = mkwid(window);
787
788        // NOTE: Re-issue the focus state when mapping the window.
789        //
790        // The purpose of it is to deliver initial focused state of the newly created
791        // window, given that we can't rely on `CreateNotify`, due to it being not
792        // sent.
793        let focus = self.with_window(window, |window| window.has_focus()).unwrap_or_default();
794        let event = Event::WindowEvent { window_id, event: WindowEvent::Focused(focus) };
795
796        callback(&self.target, event);
797    }
798
799    fn destroy_notify<F>(&self, xev: &XDestroyWindowEvent, mut callback: F)
800    where
801        F: FnMut(&ActiveEventLoop, Event),
802    {
803        let window = xev.window as xproto::Window;
804        let window_id = mkwid(window);
805
806        // In the event that the window's been destroyed without being dropped first, we
807        // cleanup again here.
808        self.target.windows.borrow_mut().remove(&WindowId(window as _));
809
810        // Since all XIM stuff needs to happen from the same thread, we destroy the input
811        // context here instead of when dropping the window.
812        if let Some(ime) = self.target.ime.as_ref() {
813            ime.borrow_mut()
814                .remove_context(window as XWindow)
815                .expect("Failed to destroy input context");
816        }
817
818        callback(&self.target, Event::WindowEvent { window_id, event: WindowEvent::Destroyed });
819    }
820
821    fn property_notify<F>(&mut self, xev: &XPropertyEvent, mut callback: F)
822    where
823        F: FnMut(&ActiveEventLoop, Event),
824    {
825        let atoms = self.target.x_connection().atoms();
826        let atom = xev.atom as xproto::Atom;
827
828        if atom == xproto::Atom::from(xproto::AtomEnum::RESOURCE_MANAGER)
829            || atom == atoms[_XSETTINGS_SETTINGS]
830        {
831            self.process_dpi_change(&mut callback);
832        }
833    }
834
835    fn visibility_notify<F>(&self, xev: &XVisibilityEvent, mut callback: F)
836    where
837        F: FnMut(&ActiveEventLoop, Event),
838    {
839        let xwindow = xev.window as xproto::Window;
840
841        let event = Event::WindowEvent {
842            window_id: mkwid(xwindow),
843            event: WindowEvent::Occluded(xev.state == xlib::VisibilityFullyObscured),
844        };
845        callback(&self.target, event);
846
847        self.with_window(xwindow, |window| {
848            window.visibility_notify();
849        });
850    }
851
852    fn expose<F>(&self, xev: &XExposeEvent, mut callback: F)
853    where
854        F: FnMut(&ActiveEventLoop, Event),
855    {
856        // Multiple Expose events may be received for subareas of a window.
857        // We issue `RedrawRequested` only for the last event of such a series.
858        if xev.count == 0 {
859            let window = xev.window as xproto::Window;
860            let window_id = mkwid(window);
861
862            let event = Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested };
863
864            callback(&self.target, event);
865        }
866    }
867
868    fn xinput_key_input<F>(&mut self, xev: &mut XKeyEvent, state: ElementState, mut callback: F)
869    where
870        F: FnMut(&ActiveEventLoop, Event),
871    {
872        // Set the timestamp.
873        self.target.xconn.set_timestamp(xev.time as xproto::Timestamp);
874
875        let window = match self.active_window {
876            Some(window) => window,
877            None => return,
878        };
879
880        let window_id = mkwid(window);
881        let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD);
882
883        let keycode = xev.keycode as _;
884
885        // Update state to track key repeats and determine whether this key was a repeat.
886        //
887        // Note, when a key is held before focusing on this window the first
888        // (non-synthetic) event will not be flagged as a repeat (also note that the
889        // synthetic press event that is generated before this when the window gains focus
890        // will also not be flagged as a repeat).
891        //
892        // Only keys that can repeat should change the held_key_press state since a
893        // continuously held repeatable key may continue repeating after the press of a
894        // non-repeatable key.
895        let key_repeats =
896            self.xkb_context.keymap_mut().map(|k| k.key_repeats(keycode)).unwrap_or(false);
897        let repeat = if key_repeats {
898            let is_latest_held = self.held_key_press == Some(keycode);
899
900            if state == ElementState::Pressed {
901                self.held_key_press = Some(keycode);
902                is_latest_held
903            } else {
904                // Check that the released key is the latest repeatable key that has been
905                // pressed, since repeats will continue for the latest key press if a
906                // different previously pressed key is released.
907                if is_latest_held {
908                    self.held_key_press = None;
909                }
910                false
911            }
912        } else {
913            false
914        };
915
916        // NOTE: When the modifier was captured by the XFilterEvents the modifiers for the modifier
917        // itself are out of sync due to XkbState being delivered before XKeyEvent, since it's
918        // being replayed by the XIM, thus we should replay ourselves.
919        let replay = if let Some(position) =
920            self.xfiltered_modifiers.iter().rev().position(|&s| s == xev.serial)
921        {
922            // We don't have to replay modifiers pressed before the current event if some events
923            // were not forwarded to us, since their state is irrelevant.
924            self.xfiltered_modifiers.resize(self.xfiltered_modifiers.len() - 1 - position, 0);
925            true
926        } else {
927            false
928        };
929
930        // Always update the modifiers when we're not replaying.
931        if !replay {
932            self.update_mods_from_core_event(window_id, xev.state as u16, &mut callback);
933        }
934
935        if keycode != 0 && !self.is_composing {
936            // Don't alter the modifiers state from replaying.
937            if replay {
938                self.send_synthic_modifier_from_core(window_id, xev.state as u16, &mut callback);
939            }
940
941            if let Some(mut key_processor) = self.xkb_context.key_context() {
942                let event = key_processor.process_key_event(keycode, state, repeat);
943                let event = Event::WindowEvent {
944                    window_id,
945                    event: WindowEvent::KeyboardInput { device_id, event, is_synthetic: false },
946                };
947                callback(&self.target, event);
948            }
949
950            // Restore the client's modifiers state after replay.
951            if replay {
952                self.send_modifiers(window_id, self.modifiers.get(), true, &mut callback);
953            }
954
955            return;
956        }
957
958        if let Some(ic) =
959            self.target.ime.as_ref().and_then(|ime| ime.borrow().get_context(window as XWindow))
960        {
961            let written = self.target.xconn.lookup_utf8(ic, xev);
962            if !written.is_empty() {
963                let event = Event::WindowEvent {
964                    window_id,
965                    event: WindowEvent::Ime(Ime::Preedit(String::new(), None)),
966                };
967                callback(&self.target, event);
968
969                let event =
970                    Event::WindowEvent { window_id, event: WindowEvent::Ime(Ime::Commit(written)) };
971
972                self.is_composing = false;
973                callback(&self.target, event);
974            }
975        }
976    }
977
978    fn send_synthic_modifier_from_core<F>(
979        &mut self,
980        window_id: crate::window::WindowId,
981        state: u16,
982        mut callback: F,
983    ) where
984        F: FnMut(&ActiveEventLoop, Event),
985    {
986        let keymap = match self.xkb_context.keymap_mut() {
987            Some(keymap) => keymap,
988            None => return,
989        };
990
991        let xcb = self.target.xconn.xcb_connection().get_raw_xcb_connection();
992
993        // Use synthetic state since we're replaying the modifier. The user modifier state
994        // will be restored later.
995        let mut xkb_state = match XkbState::new_x11(xcb, keymap) {
996            Some(xkb_state) => xkb_state,
997            None => return,
998        };
999
1000        let mask = self.xkb_mod_mask_from_core(state);
1001        xkb_state.update_modifiers(mask, 0, 0, 0, 0, Self::core_keyboard_group(state));
1002        let mods: ModifiersState = xkb_state.modifiers().into();
1003
1004        let event =
1005            Event::WindowEvent { window_id, event: WindowEvent::ModifiersChanged(mods.into()) };
1006
1007        callback(&self.target, event);
1008    }
1009
1010    fn xinput2_button_input<F>(&self, event: &XIDeviceEvent, state: ElementState, mut callback: F)
1011    where
1012        F: FnMut(&ActiveEventLoop, Event),
1013    {
1014        let window_id = mkwid(event.event as xproto::Window);
1015        let device_id = mkdid(event.deviceid as xinput::DeviceId);
1016
1017        // Set the timestamp.
1018        self.target.xconn.set_timestamp(event.time as xproto::Timestamp);
1019
1020        // Deliver multi-touch events instead of emulated mouse events.
1021        if (event.flags & xinput2::XIPointerEmulated) != 0 {
1022            return;
1023        }
1024
1025        let event = match event.detail as u32 {
1026            xlib::Button1 => {
1027                WindowEvent::MouseInput { device_id, state, button: MouseButton::Left }
1028            },
1029            xlib::Button2 => {
1030                WindowEvent::MouseInput { device_id, state, button: MouseButton::Middle }
1031            },
1032
1033            xlib::Button3 => {
1034                WindowEvent::MouseInput { device_id, state, button: MouseButton::Right }
1035            },
1036
1037            // Suppress emulated scroll wheel clicks, since we handle the real motion events for
1038            // those. In practice, even clicky scroll wheels appear to be reported by
1039            // evdev (and XInput2 in turn) as axis motion, so we don't otherwise
1040            // special-case these button presses.
1041            4..=7 => WindowEvent::MouseWheel {
1042                device_id,
1043                delta: match event.detail {
1044                    4 => MouseScrollDelta::LineDelta(0.0, 1.0),
1045                    5 => MouseScrollDelta::LineDelta(0.0, -1.0),
1046                    6 => MouseScrollDelta::LineDelta(1.0, 0.0),
1047                    7 => MouseScrollDelta::LineDelta(-1.0, 0.0),
1048                    _ => unreachable!(),
1049                },
1050                phase: TouchPhase::Moved,
1051            },
1052            8 => WindowEvent::MouseInput { device_id, state, button: MouseButton::Back },
1053
1054            9 => WindowEvent::MouseInput { device_id, state, button: MouseButton::Forward },
1055            x => WindowEvent::MouseInput { device_id, state, button: MouseButton::Other(x as u16) },
1056        };
1057
1058        let event = Event::WindowEvent { window_id, event };
1059        callback(&self.target, event);
1060    }
1061
1062    fn xinput2_mouse_motion<F>(&self, event: &XIDeviceEvent, mut callback: F)
1063    where
1064        F: FnMut(&ActiveEventLoop, Event),
1065    {
1066        // Set the timestamp.
1067        self.target.xconn.set_timestamp(event.time as xproto::Timestamp);
1068
1069        let device_id = mkdid(event.deviceid as xinput::DeviceId);
1070        let window = event.event as xproto::Window;
1071        let window_id = mkwid(window);
1072        let new_cursor_pos = (event.event_x, event.event_y);
1073
1074        let cursor_moved = self.with_window(window, |window| {
1075            let mut shared_state_lock = window.shared_state_lock();
1076            util::maybe_change(&mut shared_state_lock.cursor_pos, new_cursor_pos)
1077        });
1078
1079        if cursor_moved == Some(true) {
1080            let position = PhysicalPosition::new(event.event_x, event.event_y);
1081
1082            let event = Event::WindowEvent {
1083                window_id,
1084                event: WindowEvent::CursorMoved { device_id, position },
1085            };
1086            callback(&self.target, event);
1087        } else if cursor_moved.is_none() {
1088            return;
1089        }
1090
1091        // More gymnastics, for self.devices
1092        let mask = unsafe {
1093            slice::from_raw_parts(event.valuators.mask, event.valuators.mask_len as usize)
1094        };
1095        let mut devices = self.devices.borrow_mut();
1096        let physical_device = match devices.get_mut(&DeviceId(event.sourceid as xinput::DeviceId)) {
1097            Some(device) => device,
1098            None => return,
1099        };
1100
1101        let mut events = Vec::new();
1102        let mut value = event.valuators.values;
1103        for i in 0..event.valuators.mask_len * 8 {
1104            if !xinput2::XIMaskIsSet(mask, i) {
1105                continue;
1106            }
1107
1108            let x = unsafe { *value };
1109
1110            if let Some(&mut (_, ref mut info)) =
1111                physical_device.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == i as _)
1112            {
1113                let delta = (x - info.position) / info.increment;
1114                info.position = x;
1115                // X11 vertical scroll coordinates are opposite to winit's
1116                let delta = match info.orientation {
1117                    ScrollOrientation::Horizontal => {
1118                        MouseScrollDelta::LineDelta(-delta as f32, 0.0)
1119                    },
1120                    ScrollOrientation::Vertical => MouseScrollDelta::LineDelta(0.0, -delta as f32),
1121                };
1122
1123                let event = WindowEvent::MouseWheel { device_id, delta, phase: TouchPhase::Moved };
1124                events.push(Event::WindowEvent { window_id, event });
1125            }
1126
1127            value = unsafe { value.offset(1) };
1128        }
1129
1130        for event in events {
1131            callback(&self.target, event);
1132        }
1133    }
1134
1135    fn xinput2_mouse_enter<F>(&self, event: &XIEnterEvent, mut callback: F)
1136    where
1137        F: FnMut(&ActiveEventLoop, Event),
1138    {
1139        // Set the timestamp.
1140        self.target.xconn.set_timestamp(event.time as xproto::Timestamp);
1141
1142        let window = event.event as xproto::Window;
1143        let window_id = mkwid(window);
1144        let device_id = mkdid(event.deviceid as xinput::DeviceId);
1145
1146        if let Some(all_info) = DeviceInfo::get(&self.target.xconn, super::ALL_DEVICES.into()) {
1147            let mut devices = self.devices.borrow_mut();
1148            for device_info in all_info.iter() {
1149                // The second expression is need for resetting to work correctly on i3, and
1150                // presumably some other WMs. On those, `XI_Enter` doesn't include the physical
1151                // device ID, so both `sourceid` and `deviceid` are the virtual device.
1152                if device_info.deviceid == event.sourceid
1153                    || device_info.attachment == event.sourceid
1154                {
1155                    let device_id = DeviceId(device_info.deviceid as _);
1156                    if let Some(device) = devices.get_mut(&device_id) {
1157                        device.reset_scroll_position(device_info);
1158                    }
1159                }
1160            }
1161        }
1162
1163        if self.window_exists(window) {
1164            let position = PhysicalPosition::new(event.event_x, event.event_y);
1165
1166            let event =
1167                Event::WindowEvent { window_id, event: WindowEvent::CursorEntered { device_id } };
1168            callback(&self.target, event);
1169
1170            let event = Event::WindowEvent {
1171                window_id,
1172                event: WindowEvent::CursorMoved { device_id, position },
1173            };
1174            callback(&self.target, event);
1175        }
1176    }
1177
1178    fn xinput2_mouse_left<F>(&self, event: &XILeaveEvent, mut callback: F)
1179    where
1180        F: FnMut(&ActiveEventLoop, Event),
1181    {
1182        let window = event.event as xproto::Window;
1183
1184        // Set the timestamp.
1185        self.target.xconn.set_timestamp(event.time as xproto::Timestamp);
1186
1187        // Leave, FocusIn, and FocusOut can be received by a window that's already
1188        // been destroyed, which the user presumably doesn't want to deal with.
1189        if self.window_exists(window) {
1190            let event = Event::WindowEvent {
1191                window_id: mkwid(window),
1192                event: WindowEvent::CursorLeft {
1193                    device_id: mkdid(event.deviceid as xinput::DeviceId),
1194                },
1195            };
1196            callback(&self.target, event);
1197        }
1198    }
1199
1200    fn xinput2_focused<F>(&mut self, xev: &XIFocusInEvent, mut callback: F)
1201    where
1202        F: FnMut(&ActiveEventLoop, Event),
1203    {
1204        let window = xev.event as xproto::Window;
1205
1206        // Set the timestamp.
1207        self.target.xconn.set_timestamp(xev.time as xproto::Timestamp);
1208
1209        if let Some(ime) = self.target.ime.as_ref() {
1210            ime.borrow_mut().focus(xev.event).expect("Failed to focus input context");
1211        }
1212
1213        if self.active_window == Some(window) {
1214            return;
1215        }
1216
1217        self.active_window = Some(window);
1218
1219        self.target.update_listen_device_events(true);
1220
1221        let window_id = mkwid(window);
1222        let position = PhysicalPosition::new(xev.event_x, xev.event_y);
1223
1224        if let Some(window) = self.with_window(window, Arc::clone) {
1225            window.shared_state_lock().has_focus = true;
1226        }
1227
1228        let event = Event::WindowEvent { window_id, event: WindowEvent::Focused(true) };
1229        callback(&self.target, event);
1230
1231        // Issue key press events for all pressed keys
1232        Self::handle_pressed_keys(
1233            &self.target,
1234            window_id,
1235            ElementState::Pressed,
1236            &mut self.xkb_context,
1237            &mut callback,
1238        );
1239
1240        self.update_mods_from_query(window_id, &mut callback);
1241
1242        // The deviceid for this event is for a keyboard instead of a pointer,
1243        // so we have to do a little extra work.
1244        let pointer_id = self
1245            .devices
1246            .borrow()
1247            .get(&DeviceId(xev.deviceid as xinput::DeviceId))
1248            .map(|device| device.attachment)
1249            .unwrap_or(2);
1250
1251        let event = Event::WindowEvent {
1252            window_id,
1253            event: WindowEvent::CursorMoved { device_id: mkdid(pointer_id as _), position },
1254        };
1255        callback(&self.target, event);
1256    }
1257
1258    fn xinput2_unfocused<F>(&mut self, xev: &XIFocusOutEvent, mut callback: F)
1259    where
1260        F: FnMut(&ActiveEventLoop, Event),
1261    {
1262        let window = xev.event as xproto::Window;
1263
1264        // Set the timestamp.
1265        self.target.xconn.set_timestamp(xev.time as xproto::Timestamp);
1266
1267        if !self.window_exists(window) {
1268            return;
1269        }
1270
1271        if let Some(ime) = self.target.ime.as_ref() {
1272            ime.borrow_mut().unfocus(xev.event).expect("Failed to unfocus input context");
1273        }
1274
1275        if self.active_window.take() == Some(window) {
1276            let window_id = mkwid(window);
1277
1278            self.target.update_listen_device_events(false);
1279
1280            // Clear the modifiers when unfocusing the window.
1281            if let Some(xkb_state) = self.xkb_context.state_mut() {
1282                xkb_state.update_modifiers(0, 0, 0, 0, 0, 0);
1283                let mods = xkb_state.modifiers();
1284                self.send_modifiers(window_id, mods.into(), true, &mut callback);
1285            }
1286
1287            // Issue key release events for all pressed keys
1288            Self::handle_pressed_keys(
1289                &self.target,
1290                window_id,
1291                ElementState::Released,
1292                &mut self.xkb_context,
1293                &mut callback,
1294            );
1295
1296            // Clear this so detecting key repeats is consistently handled when the
1297            // window regains focus.
1298            self.held_key_press = None;
1299
1300            if let Some(window) = self.with_window(window, Arc::clone) {
1301                window.shared_state_lock().has_focus = false;
1302            }
1303
1304            let event = Event::WindowEvent { window_id, event: WindowEvent::Focused(false) };
1305            callback(&self.target, event)
1306        }
1307    }
1308
1309    fn xinput2_touch<F>(&mut self, xev: &XIDeviceEvent, phase: TouchPhase, mut callback: F)
1310    where
1311        F: FnMut(&ActiveEventLoop, Event),
1312    {
1313        // Set the timestamp.
1314        self.target.xconn.set_timestamp(xev.time as xproto::Timestamp);
1315
1316        let window = xev.event as xproto::Window;
1317        if self.window_exists(window) {
1318            let window_id = mkwid(window);
1319            let id = xev.detail as u32;
1320            let location = PhysicalPosition::new(xev.event_x, xev.event_y);
1321
1322            // Mouse cursor position changes when touch events are received.
1323            // Only the first concurrently active touch ID moves the mouse cursor.
1324            if is_first_touch(&mut self.first_touch, &mut self.num_touch, id, phase) {
1325                let event = Event::WindowEvent {
1326                    window_id,
1327                    event: WindowEvent::CursorMoved {
1328                        device_id: mkdid(util::VIRTUAL_CORE_POINTER),
1329                        position: location.cast(),
1330                    },
1331                };
1332                callback(&self.target, event);
1333            }
1334
1335            let event = Event::WindowEvent {
1336                window_id,
1337                event: WindowEvent::Touch(Touch {
1338                    device_id: mkdid(xev.deviceid as xinput::DeviceId),
1339                    phase,
1340                    location,
1341                    force: None, // TODO
1342                    finger_id: mkfid(id),
1343                }),
1344            };
1345            callback(&self.target, event)
1346        }
1347    }
1348
1349    fn xinput2_raw_button_input<F>(&self, xev: &XIRawEvent, state: ElementState, mut callback: F)
1350    where
1351        F: FnMut(&ActiveEventLoop, Event),
1352    {
1353        // Set the timestamp.
1354        self.target.xconn.set_timestamp(xev.time as xproto::Timestamp);
1355
1356        if xev.flags & xinput2::XIPointerEmulated == 0 {
1357            let event = Event::DeviceEvent {
1358                device_id: mkdid(xev.deviceid as xinput::DeviceId),
1359                event: DeviceEvent::Button { state, button: xev.detail as u32 },
1360            };
1361            callback(&self.target, event);
1362        }
1363    }
1364
1365    fn xinput2_raw_mouse_motion<F>(&self, xev: &XIRawEvent, mut callback: F)
1366    where
1367        F: FnMut(&ActiveEventLoop, Event),
1368    {
1369        // Set the timestamp.
1370        self.target.xconn.set_timestamp(xev.time as xproto::Timestamp);
1371
1372        let did = mkdid(xev.deviceid as xinput::DeviceId);
1373
1374        let mask =
1375            unsafe { slice::from_raw_parts(xev.valuators.mask, xev.valuators.mask_len as usize) };
1376        let mut value = xev.raw_values;
1377        let mut mouse_delta = util::Delta::default();
1378        let mut scroll_delta = util::Delta::default();
1379        for i in 0..xev.valuators.mask_len * 8 {
1380            if !xinput2::XIMaskIsSet(mask, i) {
1381                continue;
1382            }
1383            let x = unsafe { value.read_unaligned() };
1384
1385            // We assume that every XInput2 device with analog axes is a pointing device emitting
1386            // relative coordinates.
1387            match i {
1388                0 => mouse_delta.set_x(x),
1389                1 => mouse_delta.set_y(x),
1390                2 => scroll_delta.set_x(x as f32),
1391                3 => scroll_delta.set_y(x as f32),
1392                _ => {},
1393            }
1394
1395            value = unsafe { value.offset(1) };
1396        }
1397
1398        if let Some(mouse_delta) = mouse_delta.consume() {
1399            let event = Event::DeviceEvent {
1400                device_id: did,
1401                event: DeviceEvent::MouseMotion { delta: mouse_delta },
1402            };
1403            callback(&self.target, event);
1404        }
1405
1406        if let Some(scroll_delta) = scroll_delta.consume() {
1407            let event = Event::DeviceEvent {
1408                device_id: did,
1409                event: DeviceEvent::MouseWheel {
1410                    delta: MouseScrollDelta::LineDelta(scroll_delta.0, scroll_delta.1),
1411                },
1412            };
1413            callback(&self.target, event);
1414        }
1415    }
1416
1417    fn xinput2_raw_key_input<F>(&mut self, xev: &XIRawEvent, state: ElementState, mut callback: F)
1418    where
1419        F: FnMut(&ActiveEventLoop, Event),
1420    {
1421        // Set the timestamp.
1422        self.target.xconn.set_timestamp(xev.time as xproto::Timestamp);
1423
1424        let device_id = mkdid(xev.sourceid as xinput::DeviceId);
1425        let keycode = xev.detail as u32;
1426        if keycode < KEYCODE_OFFSET as u32 {
1427            return;
1428        }
1429        let physical_key = xkb::raw_keycode_to_physicalkey(keycode);
1430
1431        callback(&self.target, Event::DeviceEvent {
1432            device_id,
1433            event: DeviceEvent::Key(RawKeyEvent { physical_key, state }),
1434        });
1435    }
1436
1437    fn xinput2_hierarchy_changed(&mut self, xev: &XIHierarchyEvent) {
1438        // Set the timestamp.
1439        self.target.xconn.set_timestamp(xev.time as xproto::Timestamp);
1440        let infos = unsafe { slice::from_raw_parts(xev.info, xev.num_info as usize) };
1441        for info in infos {
1442            if 0 != info.flags & (xinput2::XISlaveAdded | xinput2::XIMasterAdded) {
1443                self.init_device(info.deviceid as xinput::DeviceId);
1444            } else if 0 != info.flags & (xinput2::XISlaveRemoved | xinput2::XIMasterRemoved) {
1445                let mut devices = self.devices.borrow_mut();
1446                devices.remove(&DeviceId(info.deviceid as xinput::DeviceId));
1447            }
1448        }
1449    }
1450
1451    fn xkb_event<F>(&mut self, xev: &XkbAnyEvent, mut callback: F)
1452    where
1453        F: FnMut(&ActiveEventLoop, Event),
1454    {
1455        match xev.xkb_type {
1456            xlib::XkbNewKeyboardNotify => {
1457                let xev = unsafe { &*(xev as *const _ as *const xlib::XkbNewKeyboardNotifyEvent) };
1458
1459                // Set the timestamp.
1460                self.target.xconn.set_timestamp(xev.time as xproto::Timestamp);
1461
1462                let keycodes_changed_flag = 0x1;
1463                let geometry_changed_flag = 0x1 << 1;
1464
1465                let keycodes_changed = util::has_flag(xev.changed, keycodes_changed_flag);
1466                let geometry_changed = util::has_flag(xev.changed, geometry_changed_flag);
1467
1468                if xev.device == self.xkb_context.core_keyboard_id
1469                    && (keycodes_changed || geometry_changed)
1470                {
1471                    let xcb = self.target.xconn.xcb_connection().get_raw_xcb_connection();
1472                    self.xkb_context.set_keymap_from_x11(xcb);
1473                    self.xmodmap.reload_from_x_connection(&self.target.xconn);
1474
1475                    let window_id = match self.active_window.map(super::mkwid) {
1476                        Some(window_id) => window_id,
1477                        None => return,
1478                    };
1479
1480                    if let Some(state) = self.xkb_context.state_mut() {
1481                        let mods = state.modifiers().into();
1482                        self.send_modifiers(window_id, mods, true, &mut callback);
1483                    }
1484                }
1485            },
1486            xlib::XkbMapNotify => {
1487                let xcb = self.target.xconn.xcb_connection().get_raw_xcb_connection();
1488                self.xkb_context.set_keymap_from_x11(xcb);
1489                self.xmodmap.reload_from_x_connection(&self.target.xconn);
1490                let window_id = match self.active_window.map(super::mkwid) {
1491                    Some(window_id) => window_id,
1492                    None => return,
1493                };
1494
1495                if let Some(state) = self.xkb_context.state_mut() {
1496                    let mods = state.modifiers().into();
1497                    self.send_modifiers(window_id, mods, true, &mut callback);
1498                }
1499            },
1500            xlib::XkbStateNotify => {
1501                let xev = unsafe { &*(xev as *const _ as *const xlib::XkbStateNotifyEvent) };
1502
1503                // Set the timestamp.
1504                self.target.xconn.set_timestamp(xev.time as xproto::Timestamp);
1505
1506                if let Some(state) = self.xkb_context.state_mut() {
1507                    state.update_modifiers(
1508                        xev.base_mods,
1509                        xev.latched_mods,
1510                        xev.locked_mods,
1511                        xev.base_group as u32,
1512                        xev.latched_group as u32,
1513                        xev.locked_group as u32,
1514                    );
1515
1516                    let window_id = match self.active_window.map(super::mkwid) {
1517                        Some(window_id) => window_id,
1518                        None => return,
1519                    };
1520
1521                    let mods = state.modifiers().into();
1522                    self.send_modifiers(window_id, mods, true, &mut callback);
1523                }
1524            },
1525            _ => {},
1526        }
1527    }
1528
1529    pub(crate) fn update_mods_from_xinput2_event<F>(
1530        &mut self,
1531        mods: &XIModifierState,
1532        group: &XIModifierState,
1533        force: bool,
1534        mut callback: F,
1535    ) where
1536        F: FnMut(&ActiveEventLoop, Event),
1537    {
1538        if let Some(state) = self.xkb_context.state_mut() {
1539            state.update_modifiers(
1540                mods.base as u32,
1541                mods.latched as u32,
1542                mods.locked as u32,
1543                group.base as u32,
1544                group.latched as u32,
1545                group.locked as u32,
1546            );
1547
1548            // NOTE: we use active window since generally sub windows don't have keyboard input,
1549            // and winit assumes that unfocused window doesn't have modifiers.
1550            let window_id = match self.active_window.map(super::mkwid) {
1551                Some(window_id) => window_id,
1552                None => return,
1553            };
1554
1555            let mods = state.modifiers();
1556            self.send_modifiers(window_id, mods.into(), force, &mut callback);
1557        }
1558    }
1559
1560    fn update_mods_from_query<F>(&mut self, window_id: crate::window::WindowId, mut callback: F)
1561    where
1562        F: FnMut(&ActiveEventLoop, Event),
1563    {
1564        let xkb_state = match self.xkb_context.state_mut() {
1565            Some(xkb_state) => xkb_state,
1566            None => return,
1567        };
1568
1569        unsafe {
1570            let mut state: XkbStateRec = std::mem::zeroed();
1571            if (self.target.xconn.xlib.XkbGetState)(
1572                self.target.xconn.display,
1573                XkbId::USE_CORE_KBD.into(),
1574                &mut state,
1575            ) == xlib::True
1576            {
1577                xkb_state.update_modifiers(
1578                    state.base_mods as u32,
1579                    state.latched_mods as u32,
1580                    state.locked_mods as u32,
1581                    state.base_group as u32,
1582                    state.latched_group as u32,
1583                    state.locked_group as u32,
1584                );
1585            }
1586        }
1587
1588        let mods = xkb_state.modifiers();
1589        self.send_modifiers(window_id, mods.into(), true, &mut callback)
1590    }
1591
1592    pub(crate) fn update_mods_from_core_event<F>(
1593        &mut self,
1594        window_id: crate::window::WindowId,
1595        state: u16,
1596        mut callback: F,
1597    ) where
1598        F: FnMut(&ActiveEventLoop, Event),
1599    {
1600        let xkb_mask = self.xkb_mod_mask_from_core(state);
1601        let xkb_state = match self.xkb_context.state_mut() {
1602            Some(xkb_state) => xkb_state,
1603            None => return,
1604        };
1605
1606        // NOTE: this is inspired by Qt impl.
1607        let mut depressed = xkb_state.depressed_modifiers() & xkb_mask;
1608        let latched = xkb_state.latched_modifiers() & xkb_mask;
1609        let locked = xkb_state.locked_modifiers() & xkb_mask;
1610        // Set modifiers in depressed if they don't appear in any of the final masks.
1611        depressed |= !(depressed | latched | locked) & xkb_mask;
1612
1613        xkb_state.update_modifiers(
1614            depressed,
1615            latched,
1616            locked,
1617            0,
1618            0,
1619            Self::core_keyboard_group(state),
1620        );
1621
1622        let mods = xkb_state.modifiers();
1623        self.send_modifiers(window_id, mods.into(), false, &mut callback);
1624    }
1625
1626    // Bits 13 and 14 report the state keyboard group.
1627    pub fn core_keyboard_group(state: u16) -> u32 {
1628        ((state >> 13) & 3) as u32
1629    }
1630
1631    pub fn xkb_mod_mask_from_core(&mut self, state: u16) -> xkb_mod_mask_t {
1632        let mods_indices = match self.xkb_context.keymap_mut() {
1633            Some(keymap) => keymap.mods_indices(),
1634            None => return 0,
1635        };
1636
1637        // Build the XKB modifiers from the regular state.
1638        let mut depressed = 0u32;
1639        if let Some(shift) = mods_indices.shift.filter(|_| ModMask::SHIFT.intersects(state)) {
1640            depressed |= 1 << shift;
1641        }
1642        if let Some(caps) = mods_indices.caps.filter(|_| ModMask::LOCK.intersects(state)) {
1643            depressed |= 1 << caps;
1644        }
1645        if let Some(ctrl) = mods_indices.ctrl.filter(|_| ModMask::CONTROL.intersects(state)) {
1646            depressed |= 1 << ctrl;
1647        }
1648        if let Some(alt) = mods_indices.alt.filter(|_| ModMask::M1.intersects(state)) {
1649            depressed |= 1 << alt;
1650        }
1651        if let Some(num) = mods_indices.num.filter(|_| ModMask::M2.intersects(state)) {
1652            depressed |= 1 << num;
1653        }
1654        if let Some(mod3) = mods_indices.mod3.filter(|_| ModMask::M3.intersects(state)) {
1655            depressed |= 1 << mod3;
1656        }
1657        if let Some(logo) = mods_indices.logo.filter(|_| ModMask::M4.intersects(state)) {
1658            depressed |= 1 << logo;
1659        }
1660        if let Some(mod5) = mods_indices.mod5.filter(|_| ModMask::M5.intersects(state)) {
1661            depressed |= 1 << mod5;
1662        }
1663
1664        depressed
1665    }
1666
1667    /// Send modifiers for the active window.
1668    ///
1669    /// The event won't be sent when the `modifiers` match the previously `sent` modifiers value,
1670    /// unless `force` is passed. The `force` should be passed when the active window changes.
1671    fn send_modifiers<F: FnMut(&ActiveEventLoop, Event)>(
1672        &self,
1673        window_id: crate::window::WindowId,
1674        modifiers: ModifiersState,
1675        force: bool,
1676        callback: &mut F,
1677    ) {
1678        // NOTE: Always update the modifiers to account for case when they've changed
1679        // and forced was `true`.
1680        if self.modifiers.replace(modifiers) != modifiers || force {
1681            let event = Event::WindowEvent {
1682                window_id,
1683                event: WindowEvent::ModifiersChanged(self.modifiers.get().into()),
1684            };
1685            callback(&self.target, event);
1686        }
1687    }
1688
1689    fn handle_pressed_keys<F>(
1690        target: &ActiveEventLoop,
1691        window_id: crate::window::WindowId,
1692        state: ElementState,
1693        xkb_context: &mut Context,
1694        callback: &mut F,
1695    ) where
1696        F: FnMut(&ActiveEventLoop, Event),
1697    {
1698        let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD);
1699
1700        // Update modifiers state and emit key events based on which keys are currently pressed.
1701        let xcb = target.xconn.xcb_connection().get_raw_xcb_connection();
1702
1703        let keymap = match xkb_context.keymap_mut() {
1704            Some(keymap) => keymap,
1705            None => return,
1706        };
1707
1708        // Send the keys using the synthetic state to not alter the main state.
1709        let mut xkb_state = match XkbState::new_x11(xcb, keymap) {
1710            Some(xkb_state) => xkb_state,
1711            None => return,
1712        };
1713        let mut key_processor = match xkb_context.key_context_with_state(&mut xkb_state) {
1714            Some(key_processor) => key_processor,
1715            None => return,
1716        };
1717
1718        for keycode in target.xconn.query_keymap().into_iter().filter(|k| *k >= KEYCODE_OFFSET) {
1719            let event = key_processor.process_key_event(keycode as u32, state, false);
1720            let event = Event::WindowEvent {
1721                window_id,
1722                event: WindowEvent::KeyboardInput { device_id, event, is_synthetic: true },
1723            };
1724            callback(target, event);
1725        }
1726    }
1727
1728    fn process_dpi_change<F>(&self, callback: &mut F)
1729    where
1730        F: FnMut(&ActiveEventLoop, Event),
1731    {
1732        self.target.xconn.reload_database().expect("failed to reload Xft database");
1733
1734        // In the future, it would be quite easy to emit monitor hotplug events.
1735        let prev_list = {
1736            let prev_list = self.target.xconn.invalidate_cached_monitor_list();
1737            match prev_list {
1738                Some(prev_list) => prev_list,
1739                None => return,
1740            }
1741        };
1742
1743        let new_list = self.target.xconn.available_monitors().expect("Failed to get monitor list");
1744        for new_monitor in new_list {
1745            // Previous list may be empty, in case of disconnecting and
1746            // reconnecting the only one monitor. We still need to emit events in
1747            // this case.
1748            let maybe_prev_scale_factor = prev_list
1749                .iter()
1750                .find(|prev_monitor| prev_monitor.name == new_monitor.name)
1751                .map(|prev_monitor| prev_monitor.scale_factor);
1752            if Some(new_monitor.scale_factor) != maybe_prev_scale_factor {
1753                for window in self.target.windows.borrow().iter().filter_map(|(_, w)| w.upgrade()) {
1754                    window.refresh_dpi_for_monitor(&new_monitor, maybe_prev_scale_factor, |event| {
1755                        callback(&self.target, event);
1756                    })
1757                }
1758            }
1759        }
1760    }
1761
1762    fn window_exists(&self, window_id: xproto::Window) -> bool {
1763        self.with_window(window_id, |_| ()).is_some()
1764    }
1765}
1766
1767fn is_first_touch(first: &mut Option<u32>, num: &mut u32, id: u32, phase: TouchPhase) -> bool {
1768    match phase {
1769        TouchPhase::Started => {
1770            if *num == 0 {
1771                *first = Some(id);
1772            }
1773            *num += 1;
1774        },
1775        TouchPhase::Cancelled | TouchPhase::Ended => {
1776            if *first == Some(id) {
1777                *first = None;
1778            }
1779            *num = num.saturating_sub(1);
1780        },
1781        _ => (),
1782    }
1783
1784    *first == Some(id)
1785}