parent
3d4c53459a
commit
22e932b5ab
5 changed files with 84 additions and 53 deletions
|
|
@ -11,6 +11,7 @@ Unreleased` header.
|
||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- On X11, fix use after free during xinput2 handling.
|
||||||
- On X11, filter close to zero values in mouse device events
|
- On X11, filter close to zero values in mouse device events
|
||||||
- Move `dpi` types to its own crate, and re-export it from the root crate.
|
- Move `dpi` types to its own crate, and re-export it from the root crate.
|
||||||
- Implement `Sync` for `EventLoopProxy<T: Send>`.
|
- Implement `Sync` for `EventLoopProxy<T: Send>`.
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,10 @@ use crate::platform_impl::platform::common::xkb::Context;
|
||||||
use crate::platform_impl::platform::x11::ime::{ImeEvent, ImeEventReceiver, ImeRequest};
|
use crate::platform_impl::platform::x11::ime::{ImeEvent, ImeEventReceiver, ImeRequest};
|
||||||
use crate::platform_impl::platform::x11::ActiveEventLoop;
|
use crate::platform_impl::platform::x11::ActiveEventLoop;
|
||||||
use crate::platform_impl::platform::ActiveEventLoop as PlatformActiveEventLoop;
|
use crate::platform_impl::platform::ActiveEventLoop as PlatformActiveEventLoop;
|
||||||
|
use crate::platform_impl::x11::util::cookie::GenericEventCookie;
|
||||||
use crate::platform_impl::x11::{
|
use crate::platform_impl::x11::{
|
||||||
atoms::*, mkdid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState,
|
atoms::*, mkdid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState,
|
||||||
GenericEventCookie, ImeReceiver, ScrollOrientation, UnownedWindow, WindowId,
|
ImeReceiver, ScrollOrientation, UnownedWindow, WindowId,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The maximum amount of X modifiers to replay.
|
/// The maximum amount of X modifiers to replay.
|
||||||
|
|
@ -184,14 +185,15 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
xlib::GenericEvent => {
|
xlib::GenericEvent => {
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
let xev = match GenericEventCookie::from_event(&wt.xconn, *xev) {
|
let xev: GenericEventCookie =
|
||||||
Some(xev) if xev.cookie.extension as u8 == self.xi2ext.major_opcode => {
|
match GenericEventCookie::from_event(wt.xconn.clone(), *xev) {
|
||||||
xev.cookie
|
Some(xev) if xev.extension() == self.xi2ext.major_opcode => xev,
|
||||||
}
|
_ => return,
|
||||||
_ => return,
|
};
|
||||||
};
|
|
||||||
|
|
||||||
match xev.evtype {
|
let evtype = xev.evtype();
|
||||||
|
|
||||||
|
match evtype {
|
||||||
ty @ xinput2::XI_ButtonPress | ty @ xinput2::XI_ButtonRelease => {
|
ty @ xinput2::XI_ButtonPress | ty @ xinput2::XI_ButtonRelease => {
|
||||||
let state = if ty == xinput2::XI_ButtonPress {
|
let state = if ty == xinput2::XI_ButtonPress {
|
||||||
ElementState::Pressed
|
ElementState::Pressed
|
||||||
|
|
@ -199,7 +201,7 @@ impl EventProcessor {
|
||||||
ElementState::Released
|
ElementState::Released
|
||||||
};
|
};
|
||||||
|
|
||||||
let xev: &XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &XIDeviceEvent = unsafe { xev.as_event() };
|
||||||
self.update_mods_from_xinput2_event(
|
self.update_mods_from_xinput2_event(
|
||||||
&xev.mods,
|
&xev.mods,
|
||||||
&xev.group,
|
&xev.group,
|
||||||
|
|
@ -209,7 +211,7 @@ impl EventProcessor {
|
||||||
self.xinput2_button_input(xev, state, &mut callback);
|
self.xinput2_button_input(xev, state, &mut callback);
|
||||||
}
|
}
|
||||||
xinput2::XI_Motion => {
|
xinput2::XI_Motion => {
|
||||||
let xev: &XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &XIDeviceEvent = unsafe { xev.as_event() };
|
||||||
self.update_mods_from_xinput2_event(
|
self.update_mods_from_xinput2_event(
|
||||||
&xev.mods,
|
&xev.mods,
|
||||||
&xev.group,
|
&xev.group,
|
||||||
|
|
@ -219,11 +221,11 @@ impl EventProcessor {
|
||||||
self.xinput2_mouse_motion(xev, &mut callback);
|
self.xinput2_mouse_motion(xev, &mut callback);
|
||||||
}
|
}
|
||||||
xinput2::XI_Enter => {
|
xinput2::XI_Enter => {
|
||||||
let xev: &XIEnterEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &XIEnterEvent = unsafe { xev.as_event() };
|
||||||
self.xinput2_mouse_enter(xev, &mut callback);
|
self.xinput2_mouse_enter(xev, &mut callback);
|
||||||
}
|
}
|
||||||
xinput2::XI_Leave => {
|
xinput2::XI_Leave => {
|
||||||
let xev: &XILeaveEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &XILeaveEvent = unsafe { xev.as_event() };
|
||||||
self.update_mods_from_xinput2_event(
|
self.update_mods_from_xinput2_event(
|
||||||
&xev.mods,
|
&xev.mods,
|
||||||
&xev.group,
|
&xev.group,
|
||||||
|
|
@ -233,51 +235,51 @@ impl EventProcessor {
|
||||||
self.xinput2_mouse_left(xev, &mut callback);
|
self.xinput2_mouse_left(xev, &mut callback);
|
||||||
}
|
}
|
||||||
xinput2::XI_FocusIn => {
|
xinput2::XI_FocusIn => {
|
||||||
let xev: &XIFocusInEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &XIFocusInEvent = unsafe { xev.as_event() };
|
||||||
self.xinput2_focused(xev, &mut callback);
|
self.xinput2_focused(xev, &mut callback);
|
||||||
}
|
}
|
||||||
xinput2::XI_FocusOut => {
|
xinput2::XI_FocusOut => {
|
||||||
let xev: &XIFocusOutEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &XIFocusOutEvent = unsafe { xev.as_event() };
|
||||||
self.xinput2_unfocused(xev, &mut callback);
|
self.xinput2_unfocused(xev, &mut callback);
|
||||||
}
|
}
|
||||||
xinput2::XI_TouchBegin | xinput2::XI_TouchUpdate | xinput2::XI_TouchEnd => {
|
xinput2::XI_TouchBegin | xinput2::XI_TouchUpdate | xinput2::XI_TouchEnd => {
|
||||||
let phase = match xev.evtype {
|
let phase = match evtype {
|
||||||
xinput2::XI_TouchBegin => TouchPhase::Started,
|
xinput2::XI_TouchBegin => TouchPhase::Started,
|
||||||
xinput2::XI_TouchUpdate => TouchPhase::Moved,
|
xinput2::XI_TouchUpdate => TouchPhase::Moved,
|
||||||
xinput2::XI_TouchEnd => TouchPhase::Ended,
|
xinput2::XI_TouchEnd => TouchPhase::Ended,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let xev: &XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &XIDeviceEvent = unsafe { xev.as_event() };
|
||||||
self.xinput2_touch(xev, phase, &mut callback);
|
self.xinput2_touch(xev, phase, &mut callback);
|
||||||
}
|
}
|
||||||
xinput2::XI_RawButtonPress | xinput2::XI_RawButtonRelease => {
|
xinput2::XI_RawButtonPress | xinput2::XI_RawButtonRelease => {
|
||||||
let state = match xev.evtype {
|
let state = match evtype {
|
||||||
xinput2::XI_RawButtonPress => ElementState::Pressed,
|
xinput2::XI_RawButtonPress => ElementState::Pressed,
|
||||||
xinput2::XI_RawButtonRelease => ElementState::Released,
|
xinput2::XI_RawButtonRelease => ElementState::Released,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let xev: &XIRawEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &XIRawEvent = unsafe { xev.as_event() };
|
||||||
self.xinput2_raw_button_input(xev, state, &mut callback);
|
self.xinput2_raw_button_input(xev, state, &mut callback);
|
||||||
}
|
}
|
||||||
xinput2::XI_RawMotion => {
|
xinput2::XI_RawMotion => {
|
||||||
let xev: &XIRawEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &XIRawEvent = unsafe { xev.as_event() };
|
||||||
self.xinput2_raw_mouse_motion(xev, &mut callback);
|
self.xinput2_raw_mouse_motion(xev, &mut callback);
|
||||||
}
|
}
|
||||||
xinput2::XI_RawKeyPress | xinput2::XI_RawKeyRelease => {
|
xinput2::XI_RawKeyPress | xinput2::XI_RawKeyRelease => {
|
||||||
let state = match xev.evtype {
|
let state = match evtype {
|
||||||
xinput2::XI_RawKeyPress => ElementState::Pressed,
|
xinput2::XI_RawKeyPress => ElementState::Pressed,
|
||||||
xinput2::XI_RawKeyRelease => ElementState::Released,
|
xinput2::XI_RawKeyRelease => ElementState::Released,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let xev: &xinput2::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &xinput2::XIRawEvent = unsafe { xev.as_event() };
|
||||||
self.xinput2_raw_key_input(xev, state, &mut callback);
|
self.xinput2_raw_key_input(xev, state, &mut callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
xinput2::XI_HierarchyChanged => {
|
xinput2::XI_HierarchyChanged => {
|
||||||
let xev: &XIHierarchyEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &XIHierarchyEvent = unsafe { xev.as_event() };
|
||||||
self.xinput2_hierarchy_changed(xev, &mut callback);
|
self.xinput2_hierarchy_changed(xev, &mut callback);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,9 @@ const ALL_DEVICES: u16 = 0;
|
||||||
const ALL_MASTER_DEVICES: u16 = 1;
|
const ALL_MASTER_DEVICES: u16 = 1;
|
||||||
const ICONIC_STATE: u32 = 3;
|
const ICONIC_STATE: u32 = 3;
|
||||||
|
|
||||||
|
/// The underlying x11rb connection that we are using.
|
||||||
|
type X11rbConnection = x11rb::xcb_ffi::XCBConnection;
|
||||||
|
|
||||||
type X11Source = Generic<BorrowedFd<'static>>;
|
type X11Source = Generic<BorrowedFd<'static>>;
|
||||||
|
|
||||||
struct WakeSender<T> {
|
struct WakeSender<T> {
|
||||||
|
|
@ -985,9 +988,6 @@ impl From<xsettings::ParserError> for X11Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The underlying x11rb connection that we are using.
|
|
||||||
type X11rbConnection = x11rb::xcb_ffi::XCBConnection;
|
|
||||||
|
|
||||||
/// Type alias for a void cookie.
|
/// Type alias for a void cookie.
|
||||||
type VoidCookie<'a> = x11rb::cookie::VoidCookie<'a, X11rbConnection>;
|
type VoidCookie<'a> = x11rb::cookie::VoidCookie<'a, X11rbConnection>;
|
||||||
|
|
||||||
|
|
@ -1003,34 +1003,6 @@ impl<'a, E: fmt::Debug> CookieResultExt for Result<VoidCookie<'a>, E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// XEvents of type GenericEvent store their actual data in an XGenericEventCookie data structure. This is a wrapper to
|
|
||||||
/// extract the cookie from a GenericEvent XEvent and release the cookie data once it has been processed
|
|
||||||
struct GenericEventCookie<'a> {
|
|
||||||
xconn: &'a XConnection,
|
|
||||||
cookie: ffi::XGenericEventCookie,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> GenericEventCookie<'a> {
|
|
||||||
fn from_event(xconn: &XConnection, event: ffi::XEvent) -> Option<GenericEventCookie<'_>> {
|
|
||||||
unsafe {
|
|
||||||
let mut cookie: ffi::XGenericEventCookie = From::from(event);
|
|
||||||
if (xconn.xlib.XGetEventData)(xconn.display, &mut cookie) == ffi::True {
|
|
||||||
Some(GenericEventCookie { xconn, cookie })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Drop for GenericEventCookie<'a> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
(self.xconn.xlib.XFreeEventData)(self.xconn.display, &mut self.cookie);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mkwid(w: xproto::Window) -> crate::window::WindowId {
|
fn mkwid(w: xproto::Window) -> crate::window::WindowId {
|
||||||
crate::window::WindowId(crate::platform_impl::platform::WindowId(w as _))
|
crate::window::WindowId(crate::platform_impl::platform::WindowId(w as _))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
55
src/platform_impl/linux/x11/util/cookie.rs
Normal file
55
src/platform_impl/linux/x11/util/cookie.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
use std::ffi::c_int;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use x11_dl::xlib::{self, XEvent, XGenericEventCookie};
|
||||||
|
|
||||||
|
use crate::platform_impl::x11::XConnection;
|
||||||
|
|
||||||
|
/// XEvents of type GenericEvent store their actual data in an XGenericEventCookie data structure.
|
||||||
|
/// This is a wrapper to extract the cookie from a GenericEvent XEvent and release the cookie data
|
||||||
|
/// once it has been processed
|
||||||
|
pub struct GenericEventCookie {
|
||||||
|
cookie: XGenericEventCookie,
|
||||||
|
xconn: Arc<XConnection>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenericEventCookie {
|
||||||
|
pub fn from_event(xconn: Arc<XConnection>, event: XEvent) -> Option<GenericEventCookie> {
|
||||||
|
unsafe {
|
||||||
|
let mut cookie: XGenericEventCookie = From::from(event);
|
||||||
|
if (xconn.xlib.XGetEventData)(xconn.display, &mut cookie) == xlib::True {
|
||||||
|
Some(GenericEventCookie { cookie, xconn })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn extension(&self) -> u8 {
|
||||||
|
self.cookie.extension as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn evtype(&self) -> c_int {
|
||||||
|
self.cookie.evtype
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Borrow inner event data as `&T`.
|
||||||
|
///
|
||||||
|
/// ## SAFETY
|
||||||
|
///
|
||||||
|
/// The caller must ensure that the event has the `T` inside of it.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn as_event<T>(&self) -> &T {
|
||||||
|
unsafe { &*(self.cookie.data as *const _) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for GenericEventCookie {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
(self.xconn.xlib.XFreeEventData)(self.xconn.display, &mut self.cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
mod client_msg;
|
mod client_msg;
|
||||||
|
pub mod cookie;
|
||||||
mod cursor;
|
mod cursor;
|
||||||
mod geometry;
|
mod geometry;
|
||||||
mod hint;
|
mod hint;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue