| 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 | |