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