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