Use x11rb for event handling

Signed-off-by: John Nunley <dev@notgull.net>
This commit is contained in:
John Nunley
2023-09-29 20:11:29 -07:00
parent 5c9f1b2e9a
commit 9477514ad5
5 changed files with 710 additions and 782 deletions

View File

@@ -44,7 +44,7 @@ impl From<io::Error> for DndDataParseError {
pub(crate) struct Dnd { pub(crate) struct Dnd {
xconn: Arc<XConnection>, xconn: Arc<XConnection>,
// Populated by XdndEnter event handler // Populated by XdndEnter event handler
pub version: Option<c_long>, pub version: Option<u32>,
pub type_list: Option<Vec<xproto::Atom>>, pub type_list: Option<Vec<xproto::Atom>>,
// Populated by XdndPosition event handler // Populated by XdndPosition event handler
pub source_window: Option<xproto::Window>, pub source_window: Option<xproto::Window>,

View File

@@ -1,27 +1,33 @@
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::HashMap, collections::{HashMap, VecDeque},
os::raw::{c_char, c_int, c_long, c_ulong},
rc::Rc, rc::Rc,
slice,
sync::{mpsc, Arc, Mutex}, sync::{mpsc, Arc, Mutex},
}; };
use x11rb::x11_utils::Serialize; use x11rb::protocol::{
use x11rb::{ xinput, xkb,
protocol::{
xinput,
xproto::{self, ConnectionExt as _}, xproto::{self, ConnectionExt as _},
}, Event as X11Event,
x11_utils::ExtensionInformation,
}; };
use x11rb::{connection::Connection, x11_utils::Serialize};
use super::{ use super::{
atoms::*, ffi, get_xtarget, ime, mkdid, mkwid, util, CookieResultExt, Device, DeviceId, atoms::*, get_xtarget, ime, mkdid, mkwid, util, xinput_fp1616_to_float, xinput_fp3232_to_float,
DeviceInfo, Dnd, DndState, GenericEventCookie, ScrollOrientation, UnownedWindow, WindowId, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState, ScrollOrientation, UnownedWindow,
WindowId,
}; };
use crate::event::InnerSizeWriter; use crate::event::InnerSizeWriter;
use crate::event::{
ElementState::{Pressed, Released},
MouseButton::{Back, Forward, Left, Middle, Other, Right},
MouseScrollDelta::LineDelta,
Touch,
WindowEvent::{
AxisMotion, CursorEntered, CursorLeft, CursorMoved, Focused, MouseInput, MouseWheel,
},
};
use crate::{ use crate::{
dpi::{PhysicalPosition, PhysicalSize}, dpi::{PhysicalPosition, PhysicalSize},
event::{DeviceEvent, ElementState, Event, Ime, RawKeyEvent, TouchPhase, WindowEvent}, event::{DeviceEvent, ElementState, Event, Ime, RawKeyEvent, TouchPhase, WindowEvent},
@@ -34,13 +40,13 @@ use crate::{
const KEYCODE_OFFSET: u8 = 8; const KEYCODE_OFFSET: u8 = 8;
pub(super) struct EventProcessor<T: 'static> { pub(super) struct EventProcessor<T: 'static> {
/// Queue of unprocessed events.
pub(super) event_queue: Rc<RefCell<VecDeque<X11Event>>>,
pub(super) dnd: Dnd, pub(super) dnd: Dnd,
/// Requests from other threads for IME. /// Requests from other threads for IME.
pub(super) ime_requests: mpsc::Receiver<ime::ImeRequest>, pub(super) ime_requests: mpsc::Receiver<ime::ImeRequest>,
pub(super) randr_event_offset: u8,
pub(super) devices: RefCell<HashMap<DeviceId, Device>>, pub(super) devices: RefCell<HashMap<DeviceId, Device>>,
pub(super) xi2ext: ExtensionInformation,
pub(super) xkbext: ExtensionInformation,
pub(super) target: Rc<RootELW<T>>, pub(super) target: Rc<RootELW<T>>,
pub(super) kb_state: KbdState, pub(super) kb_state: KbdState,
// Number of touch events currently in progress // Number of touch events currently in progress
@@ -96,90 +102,57 @@ impl<T: 'static> EventProcessor<T> {
} }
pub(super) fn poll(&self) -> bool { pub(super) fn poll(&self) -> bool {
let wt = get_xtarget(&self.target); // See if we have a cached event.
let result = unsafe { (wt.xconn.xlib.XPending)(wt.xconn.display) }; if !self.event_queue.borrow().is_empty() {
return true;
result != 0
} }
pub(super) unsafe fn poll_one_event(&mut self, event_ptr: *mut ffi::XEvent) -> bool { // If not, try to poll for one,
let wt = get_xtarget(&self.target); match get_xtarget(&self.target)
// This function is used to poll and remove a single event .x_connection()
// from the Xlib event queue in a non-blocking, atomic way. .xcb_connection()
// XCheckIfEvent is non-blocking and removes events from queue. .poll_for_event()
// XNextEvent can't be used because it blocks while holding the .expect("Error while polling for X11 events")
// global Xlib mutex. {
// XPeekEvent does not remove events from the queue. None => false,
unsafe extern "C" fn predicate( Some(event) => {
_display: *mut ffi::Display, self.event_queue.borrow_mut().push_back(event);
_event: *mut ffi::XEvent, true
_arg: *mut c_char, }
) -> c_int { }
// This predicate always returns "true" (1) to accept all events
1
} }
let result = unsafe { pub(super) fn poll_one_event(&mut self) -> Option<X11Event> {
(wt.xconn.xlib.XCheckIfEvent)( if let Some(event) = self.event_queue.borrow_mut().pop_front() {
wt.xconn.display, return Some(event);
event_ptr,
Some(predicate),
std::ptr::null_mut(),
)
};
result != 0
} }
pub(super) fn process_event<F>(&mut self, xev: &mut ffi::XEvent, mut callback: F) get_xtarget(&self.target)
.x_connection()
.xcb_connection()
.poll_for_event()
.expect("Error while polling for X11 events")
}
pub(super) fn process_event<F>(&mut self, event: X11Event, mut callback: F)
where where
F: FnMut(Event<T>), F: FnMut(Event<T>),
{ {
let wt = get_xtarget(&self.target); let wt = get_xtarget(&self.target);
let atoms = wt.x_connection().atoms(); let atoms = wt.x_connection().atoms();
// XFilterEvent tells us when an event has been discarded by the input method.
// Specifically, this involves all of the KeyPress events in compose/pre-edit sequences,
// along with an extra copy of the KeyRelease events. This also prevents backspace and
// arrow keys from being detected twice.
if ffi::True
== unsafe {
(wt.xconn.xlib.XFilterEvent)(xev, {
let xev: &ffi::XAnyEvent = xev.as_ref();
xev.window
})
}
{
return;
}
let event_type = xev.get_type();
match event_type {
ffi::ClientMessage => {
let client_msg: &ffi::XClientMessageEvent = xev.as_ref();
match &event {
X11Event::ClientMessage(client_msg) => {
let window = client_msg.window as xproto::Window; let window = client_msg.window as xproto::Window;
let window_id = mkwid(window); let window_id = mkwid(window);
if client_msg.data.get_long(0) as xproto::Atom == wt.wm_delete_window { let data = client_msg.data.as_data32();
if data[0] == wt.wm_delete_window {
callback(Event::WindowEvent { callback(Event::WindowEvent {
window_id, window_id,
event: WindowEvent::CloseRequested, event: WindowEvent::CloseRequested,
}); });
} else if client_msg.data.get_long(0) as xproto::Atom == wt.net_wm_ping { } else if data[0] == wt.net_wm_ping {
let response_msg: &mut ffi::XClientMessageEvent = xev.as_mut();
let client_msg = xproto::ClientMessageEvent {
response_type: xproto::CLIENT_MESSAGE_EVENT,
format: response_msg.format as _,
sequence: response_msg.serial as _,
window: wt.root,
type_: response_msg.message_type as _,
data: xproto::ClientMessageData::from({
let [a, b, c, d, e]: [c_long; 5] =
response_msg.data.as_longs().try_into().unwrap();
[a as u32, b as u32, c as u32, d as u32, e as u32]
}),
};
wt.xconn wt.xconn
.xcb_connection() .xcb_connection()
.send_event( .send_event(
@@ -190,24 +163,20 @@ impl<T: 'static> EventProcessor<T> {
client_msg.serialize(), client_msg.serialize(),
) )
.expect_then_ignore_error("Failed to send `ClientMessage` event."); .expect_then_ignore_error("Failed to send `ClientMessage` event.");
} else if client_msg.message_type == atoms[XdndEnter] as c_ulong { } else if client_msg.type_ == atoms[XdndEnter] {
let source_window = client_msg.data.get_long(0) as xproto::Window; let source_window = data[0];
let flags = client_msg.data.get_long(1); let flags = data[1];
let version = flags >> 24; let version = flags >> 24;
self.dnd.version = Some(version); self.dnd.version = Some(version);
let has_more_types = flags - (flags & (c_long::max_value() - 1)) == 1; let has_more_types = flags - (flags & (u32::max_value() - 1)) == 1;
if !has_more_types { if !has_more_types {
let type_list = vec![ let type_list = vec![data[2], data[3], data[4]];
client_msg.data.get_long(2) as xproto::Atom,
client_msg.data.get_long(3) as xproto::Atom,
client_msg.data.get_long(4) as xproto::Atom,
];
self.dnd.type_list = Some(type_list); self.dnd.type_list = Some(type_list);
} else if let Ok(more_types) = unsafe { self.dnd.get_type_list(source_window) } } else if let Ok(more_types) = unsafe { self.dnd.get_type_list(source_window) }
{ {
self.dnd.type_list = Some(more_types); self.dnd.type_list = Some(more_types);
} }
} else if client_msg.message_type == atoms[XdndPosition] as c_ulong { } else if client_msg.type_ == atoms[XdndPosition] {
// This event occurs every time the mouse moves while a file's being dragged // This event occurs every time the mouse moves while a file's being dragged
// over our window. We emit HoveredFile in response; while the macOS backend // over our window. We emit HoveredFile in response; while the macOS backend
// does that upon a drag entering, XDND doesn't have access to the actual drop // does that upon a drag entering, XDND doesn't have access to the actual drop
@@ -216,7 +185,7 @@ impl<T: 'static> EventProcessor<T> {
// supply position updates with `HoveredFile` or another event, implementing // supply position updates with `HoveredFile` or another event, implementing
// that here would be trivial. // that here would be trivial.
let source_window = client_msg.data.get_long(0) as xproto::Window; let source_window = data[0];
// Equivalent to `(x << shift) | y` // Equivalent to `(x << shift) | y`
// where `shift = mem::size_of::<c_short>() * 8` // where `shift = mem::size_of::<c_short>() * 8`
@@ -244,7 +213,7 @@ impl<T: 'static> EventProcessor<T> {
unsafe { unsafe {
if self.dnd.result.is_none() { if self.dnd.result.is_none() {
let time = if version >= 1 { let time = if version >= 1 {
client_msg.data.get_long(3) as xproto::Timestamp data[3] as xproto::Timestamp
} else { } else {
// In version 0, time isn't specified // In version 0, time isn't specified
x11rb::CURRENT_TIME x11rb::CURRENT_TIME
@@ -268,7 +237,7 @@ impl<T: 'static> EventProcessor<T> {
} }
self.dnd.reset(); self.dnd.reset();
} }
} else if client_msg.message_type == atoms[XdndDrop] as c_ulong { } else if client_msg.type_ == atoms[XdndDrop] {
let (source_window, state) = if let Some(source_window) = self.dnd.source_window let (source_window, state) = if let Some(source_window) = self.dnd.source_window
{ {
if let Some(Ok(ref path_list)) = self.dnd.result { if let Some(Ok(ref path_list)) = self.dnd.result {
@@ -283,7 +252,7 @@ impl<T: 'static> EventProcessor<T> {
} else { } else {
// `source_window` won't be part of our DND state if we already rejected the drop in our // `source_window` won't be part of our DND state if we already rejected the drop in our
// `XdndPosition` handler. // `XdndPosition` handler.
let source_window = client_msg.data.get_long(0) as xproto::Window; let source_window = data[0];
(source_window, DndState::Rejected) (source_window, DndState::Rejected)
}; };
unsafe { unsafe {
@@ -292,7 +261,7 @@ impl<T: 'static> EventProcessor<T> {
.expect("Failed to send `XdndFinished` message."); .expect("Failed to send `XdndFinished` message.");
} }
self.dnd.reset(); self.dnd.reset();
} else if client_msg.message_type == atoms[XdndLeave] as c_ulong { } else if client_msg.type_ == atoms[XdndLeave] {
self.dnd.reset(); self.dnd.reset();
callback(Event::WindowEvent { callback(Event::WindowEvent {
window_id, window_id,
@@ -301,16 +270,14 @@ impl<T: 'static> EventProcessor<T> {
} }
} }
ffi::SelectionNotify => { X11Event::SelectionNotify(xsel) => {
let xsel: &ffi::XSelectionEvent = xev.as_ref(); let window = xsel.requestor;
let window = xsel.requestor as xproto::Window;
let window_id = mkwid(window); let window_id = mkwid(window);
// Set the timestamp. // Set the timestamp.
wt.xconn.set_timestamp(xsel.time as xproto::Timestamp); wt.xconn.set_timestamp(xsel.time as xproto::Timestamp);
if xsel.property == atoms[XdndSelection] as c_ulong { if xsel.property == atoms[XdndSelection] {
let mut result = None; let mut result = None;
// This is where we receive data from drag and drop // This is where we receive data from drag and drop
@@ -331,9 +298,8 @@ impl<T: 'static> EventProcessor<T> {
} }
} }
ffi::ConfigureNotify => { X11Event::ConfigureNotify(xev) => {
let xev: &ffi::XConfigureEvent = xev.as_ref(); let xwindow = xev.window;
let xwindow = xev.window as xproto::Window;
let window_id = mkwid(xwindow); let window_id = mkwid(xwindow);
if let Some(window) = self.with_window(xwindow, Arc::clone) { if let Some(window) = self.with_window(xwindow, Arc::clone) {
@@ -344,11 +310,11 @@ impl<T: 'static> EventProcessor<T> {
// We don't want to send `Moved` when this is false, since then every `Resized` // We don't want to send `Moved` when this is false, since then every `Resized`
// (whether the window moved or not) is accompanied by an extraneous `Moved` event // (whether the window moved or not) is accompanied by an extraneous `Moved` event
// that has a position relative to the parent window. // that has a position relative to the parent window.
let is_synthetic = xev.send_event == ffi::True; let is_synthetic = xev.response_type & 0x80 == 0;
// These are both in physical space. // These are both in physical space.
let new_inner_size = (xev.width as u32, xev.height as u32); let new_inner_size = (xev.width as u32, xev.height as u32);
let new_inner_position = (xev.x, xev.y); let new_inner_position = (xev.x as i32, xev.y as i32);
let (mut resized, moved) = { let (mut resized, moved) = {
let mut shared_state_lock = window.shared_state_lock(); let mut shared_state_lock = window.shared_state_lock();
@@ -513,9 +479,7 @@ impl<T: 'static> EventProcessor<T> {
} }
} }
ffi::ReparentNotify => { X11Event::ReparentNotify(xev) => {
let xev: &ffi::XReparentEvent = xev.as_ref();
// This is generally a reliable way to detect when the window manager's been // This is generally a reliable way to detect when the window manager's been
// replaced, though this event is only fired by reparenting window managers // replaced, though this event is only fired by reparenting window managers
// (which is almost all of them). Failing to correctly update WM info doesn't // (which is almost all of them). Failing to correctly update WM info doesn't
@@ -527,8 +491,7 @@ impl<T: 'static> EventProcessor<T> {
window.invalidate_cached_frame_extents(); window.invalidate_cached_frame_extents();
}); });
} }
ffi::MapNotify => { X11Event::MapNotify(xev) => {
let xev: &ffi::XMapEvent = xev.as_ref();
let window = xev.window as xproto::Window; let window = xev.window as xproto::Window;
let window_id = mkwid(window); let window_id = mkwid(window);
@@ -545,9 +508,7 @@ impl<T: 'static> EventProcessor<T> {
event: WindowEvent::Focused(focus), event: WindowEvent::Focused(focus),
}); });
} }
ffi::DestroyNotify => { X11Event::DestroyNotify(xev) => {
let xev: &ffi::XDestroyWindowEvent = xev.as_ref();
let window = xev.window as xproto::Window; let window = xev.window as xproto::Window;
let window_id = mkwid(window); let window_id = mkwid(window);
@@ -577,21 +538,18 @@ impl<T: 'static> EventProcessor<T> {
} }
} }
ffi::VisibilityNotify => { X11Event::VisibilityNotify(xev) => {
let xev: &ffi::XVisibilityEvent = xev.as_ref();
let xwindow = xev.window as xproto::Window; let xwindow = xev.window as xproto::Window;
callback(Event::WindowEvent { callback(Event::WindowEvent {
window_id: mkwid(xwindow), window_id: mkwid(xwindow),
event: WindowEvent::Occluded(xev.state == ffi::VisibilityFullyObscured), event: WindowEvent::Occluded(xev.state == xproto::Visibility::FULLY_OBSCURED),
}); });
self.with_window(xwindow, |window| { self.with_window(xwindow, |window| {
window.visibility_notify(); window.visibility_notify();
}); });
} }
ffi::Expose => { X11Event::Expose(xev) => {
let xev: &ffi::XExposeEvent = xev.as_ref();
// Multiple Expose events may be received for subareas of a window. // Multiple Expose events may be received for subareas of a window.
// We issue `RedrawRequested` only for the last event of such a series. // We issue `RedrawRequested` only for the last event of such a series.
if xev.count == 0 { if xev.count == 0 {
@@ -606,9 +564,7 @@ impl<T: 'static> EventProcessor<T> {
} }
// Note that in compose/pre-edit sequences, we'll always receive KeyRelease events // Note that in compose/pre-edit sequences, we'll always receive KeyRelease events
ty @ ffi::KeyPress | ty @ ffi::KeyRelease => { X11Event::KeyPress(xkev) | X11Event::KeyRelease(xkev) => {
let xkev: &mut ffi::XKeyEvent = xev.as_mut();
// Set the timestamp. // Set the timestamp.
wt.xconn.set_timestamp(xkev.time as xproto::Timestamp); wt.xconn.set_timestamp(xkev.time as xproto::Timestamp);
@@ -620,7 +576,7 @@ impl<T: 'static> EventProcessor<T> {
let window_id = mkwid(window); let window_id = mkwid(window);
let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD); let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD);
let keycode = xkev.keycode as _; let keycode = xkev.detail.into();
// Update state to track key repeats and determine whether this key was a repeat. // Update state to track key repeats and determine whether this key was a repeat.
// //
@@ -635,7 +591,7 @@ impl<T: 'static> EventProcessor<T> {
let repeat = if self.kb_state.key_repeats(keycode) { let repeat = if self.kb_state.key_repeats(keycode) {
let is_latest_held = self.held_key_press == Some(keycode); let is_latest_held = self.held_key_press == Some(keycode);
if ty == ffi::KeyPress { if matches!(event, X11Event::KeyPress(_)) {
self.held_key_press = Some(keycode); self.held_key_press = Some(keycode);
is_latest_held is_latest_held
} else { } else {
@@ -651,7 +607,7 @@ impl<T: 'static> EventProcessor<T> {
false false
}; };
let state = if ty == ffi::KeyPress { let state = if matches!(event, X11Event::KeyPress(_)) {
ElementState::Pressed ElementState::Pressed
} else { } else {
ElementState::Released ElementState::Released
@@ -670,49 +626,28 @@ impl<T: 'static> EventProcessor<T> {
} }
} }
ffi::GenericEvent => { X11Event::XinputButtonPress(xev) | X11Event::XinputButtonRelease(xev) => {
let guard = if let Some(e) = GenericEventCookie::from_event(&wt.xconn, *xev) {
e
} else {
return;
};
let xev = &guard.cookie;
if self.xi2ext.major_opcode != xev.extension as u8 {
return;
}
use crate::event::{
ElementState::{Pressed, Released},
MouseButton::{Back, Forward, Left, Middle, Other, Right},
MouseScrollDelta::LineDelta,
Touch,
WindowEvent::{
AxisMotion, CursorEntered, CursorLeft, CursorMoved, Focused, MouseInput,
MouseWheel,
},
};
match xev.evtype {
ffi::XI_ButtonPress | ffi::XI_ButtonRelease => {
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
let window_id = mkwid(xev.event as xproto::Window); let window_id = mkwid(xev.event as xproto::Window);
let device_id = mkdid(xev.deviceid as xinput::DeviceId); let device_id = mkdid(xev.deviceid as xinput::DeviceId);
// Set the timestamp. // Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp); wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
if (xev.flags & ffi::XIPointerEmulated) != 0 { if xev
.flags
.contains(xinput::PointerEventFlags::POINTER_EMULATED)
{
// Deliver multi-touch events instead of emulated mouse events. // Deliver multi-touch events instead of emulated mouse events.
return; return;
} }
let state = if xev.evtype == ffi::XI_ButtonPress { let state = if matches!(event, X11Event::XinputButtonPress(_)) {
Pressed Pressed
} else { } else {
Released Released
}; };
match xev.detail as u32 { match xev.detail {
ffi::Button1 => callback(Event::WindowEvent { 1 => callback(Event::WindowEvent {
window_id, window_id,
event: MouseInput { event: MouseInput {
device_id, device_id,
@@ -720,7 +655,7 @@ impl<T: 'static> EventProcessor<T> {
button: Left, button: Left,
}, },
}), }),
ffi::Button2 => callback(Event::WindowEvent { 2 => callback(Event::WindowEvent {
window_id, window_id,
event: MouseInput { event: MouseInput {
device_id, device_id,
@@ -728,7 +663,7 @@ impl<T: 'static> EventProcessor<T> {
button: Middle, button: Middle,
}, },
}), }),
ffi::Button3 => callback(Event::WindowEvent { 3 => callback(Event::WindowEvent {
window_id, window_id,
event: MouseInput { event: MouseInput {
device_id, device_id,
@@ -741,7 +676,10 @@ impl<T: 'static> EventProcessor<T> {
// In practice, even clicky scroll wheels appear to be reported by evdev (and XInput2 in // In practice, even clicky scroll wheels appear to be reported by evdev (and XInput2 in
// turn) as axis motion, so we don't otherwise special-case these button presses. // turn) as axis motion, so we don't otherwise special-case these button presses.
4..=7 => { 4..=7 => {
if xev.flags & ffi::XIPointerEmulated == 0 { if xev
.flags
.contains(xinput::PointerEventFlags::POINTER_EMULATED)
{
callback(Event::WindowEvent { callback(Event::WindowEvent {
window_id, window_id,
event: MouseWheel { event: MouseWheel {
@@ -786,29 +724,28 @@ impl<T: 'static> EventProcessor<T> {
}), }),
} }
} }
ffi::XI_Motion => { X11Event::XinputMotion(xev) => {
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
// Set the timestamp. // Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp); wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
let device_id = mkdid(xev.deviceid as xinput::DeviceId); let device_id = mkdid(xev.deviceid as xinput::DeviceId);
let window = xev.event as xproto::Window; let window = xev.event as xproto::Window;
let window_id = mkwid(window); let window_id = mkwid(window);
let new_cursor_pos = (xev.event_x, xev.event_y); let new_cursor_pos = (
xinput_fp1616_to_float(xev.event_x),
xinput_fp1616_to_float(xev.event_y),
);
let cursor_moved = self.with_window(window, |window| { let cursor_moved = self.with_window(window, |window| {
let mut shared_state_lock = window.shared_state_lock(); let mut shared_state_lock = window.shared_state_lock();
util::maybe_change(&mut shared_state_lock.cursor_pos, new_cursor_pos) util::maybe_change(&mut shared_state_lock.cursor_pos, new_cursor_pos)
}); });
if cursor_moved == Some(true) { if cursor_moved == Some(true) {
let position = PhysicalPosition::new(xev.event_x, xev.event_y);
callback(Event::WindowEvent { callback(Event::WindowEvent {
window_id, window_id,
event: CursorMoved { event: CursorMoved {
device_id, device_id,
position, position: new_cursor_pos.into(),
}, },
}); });
} else if cursor_moved.is_none() { } else if cursor_moved.is_none() {
@@ -818,24 +755,31 @@ impl<T: 'static> EventProcessor<T> {
// More gymnastics, for self.devices // More gymnastics, for self.devices
let mut events = Vec::new(); let mut events = Vec::new();
{ {
let mask = unsafe {
slice::from_raw_parts(
xev.valuators.mask,
xev.valuators.mask_len as usize,
)
};
let mut devices = self.devices.borrow_mut(); let mut devices = self.devices.borrow_mut();
let physical_device = match devices let physical_device =
.get_mut(&DeviceId(xev.sourceid as xinput::DeviceId)) match devices.get_mut(&DeviceId(xev.sourceid as xinput::DeviceId)) {
{
Some(device) => device, Some(device) => device,
None => return, None => return,
}; };
let mut value = xev.valuators.values; let mask = bytemuck::cast_slice::<u32, u8>(&xev.valuator_mask);
for i in 0..xev.valuators.mask_len * 8 { let mut values = &*xev.axisvalues;
if ffi::XIMaskIsSet(mask, i) {
let x = unsafe { *value }; for i in 0..mask.len() * 8 {
let byte_index = i / 8;
let bit_index = i % 8;
if mask[byte_index] & (1 << bit_index) == 0 {
continue;
}
// This mask is set, get the value.
let x = {
let (value, rest) = values.split_first().unwrap();
values = rest;
xinput_fp3232_to_float(*value)
};
if let Some(&mut (_, ref mut info)) = physical_device if let Some(&mut (_, ref mut info)) = physical_device
.scroll_axes .scroll_axes
.iter_mut() .iter_mut()
@@ -865,12 +809,10 @@ impl<T: 'static> EventProcessor<T> {
event: AxisMotion { event: AxisMotion {
device_id, device_id,
axis: i as u32, axis: i as u32,
value: unsafe { *value }, value: x,
}, },
}); });
} }
value = unsafe { value.offset(1) };
}
} }
} }
for event in events { for event in events {
@@ -878,9 +820,7 @@ impl<T: 'static> EventProcessor<T> {
} }
} }
ffi::XI_Enter => { X11Event::XinputEnter(xev) => {
let xev: &ffi::XIEnterEvent = unsafe { &*(xev.data as *const _) };
// Set the timestamp. // Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp); wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
@@ -888,17 +828,15 @@ impl<T: 'static> EventProcessor<T> {
let window_id = mkwid(window); let window_id = mkwid(window);
let device_id = mkdid(xev.deviceid as xinput::DeviceId); let device_id = mkdid(xev.deviceid as xinput::DeviceId);
if let Some(all_info) = if let Some(all_info) = DeviceInfo::get(&wt.xconn, super::ALL_DEVICES.into()) {
DeviceInfo::get(&wt.xconn, super::ALL_DEVICES.into())
{
let mut devices = self.devices.borrow_mut(); let mut devices = self.devices.borrow_mut();
for device_info in all_info.iter() { for device_info in all_info.iter() {
if device_info.deviceid == xev.sourceid if device_info.deviceid == xev.sourceid as _
// This is needed for resetting to work correctly on i3, and // This is needed for resetting to work correctly on i3, and
// presumably some other WMs. On those, `XI_Enter` doesn't include // presumably some other WMs. On those, `XI_Enter` doesn't include
// the physical device ID, so both `sourceid` and `deviceid` are // the physical device ID, so both `sourceid` and `deviceid` are
// the virtual device. // the virtual device.
|| device_info.attachment == xev.sourceid || device_info.attachment == xev.sourceid as _
{ {
let device_id = DeviceId(device_info.deviceid as _); let device_id = DeviceId(device_info.deviceid as _);
if let Some(device) = devices.get_mut(&device_id) { if let Some(device) = devices.get_mut(&device_id) {
@@ -914,7 +852,10 @@ impl<T: 'static> EventProcessor<T> {
event: CursorEntered { device_id }, event: CursorEntered { device_id },
}); });
let position = PhysicalPosition::new(xev.event_x, xev.event_y); let position = PhysicalPosition::new(
xinput_fp1616_to_float(xev.event_x),
xinput_fp1616_to_float(xev.event_y),
);
callback(Event::WindowEvent { callback(Event::WindowEvent {
window_id, window_id,
@@ -925,8 +866,7 @@ impl<T: 'static> EventProcessor<T> {
}); });
} }
} }
ffi::XI_Leave => { X11Event::XinputLeave(xev) => {
let xev: &ffi::XILeaveEvent = unsafe { &*(xev.data as *const _) };
let window = xev.event as xproto::Window; let window = xev.event as xproto::Window;
// Set the timestamp. // Set the timestamp.
@@ -944,8 +884,7 @@ impl<T: 'static> EventProcessor<T> {
}); });
} }
} }
ffi::XI_FocusIn => { X11Event::XinputFocusIn(xev) => {
let xev: &ffi::XIFocusInEvent = unsafe { &*(xev.data as *const _) };
let window = xev.event as xproto::Window; let window = xev.event as xproto::Window;
// Set the timestamp. // Set the timestamp.
@@ -963,7 +902,10 @@ impl<T: 'static> EventProcessor<T> {
wt.update_listen_device_events(true); wt.update_listen_device_events(true);
let window_id = mkwid(window); let window_id = mkwid(window);
let position = PhysicalPosition::new(xev.event_x, xev.event_y); let position = PhysicalPosition::new(
xinput_fp1616_to_float(xev.event_x),
xinput_fp1616_to_float(xev.event_y),
);
if let Some(window) = self.with_window(window, Arc::clone) { if let Some(window) = self.with_window(window, Arc::clone) {
window.shared_state_lock().has_focus = true; window.shared_state_lock().has_focus = true;
@@ -1010,8 +952,7 @@ impl<T: 'static> EventProcessor<T> {
); );
} }
} }
ffi::XI_FocusOut => { X11Event::XinputFocusOut(xev) => {
let xev: &ffi::XIFocusOutEvent = unsafe { &*(xev.data as *const _) };
let window = xev.event as xproto::Window; let window = xev.event as xproto::Window;
// Set the timestamp. // Set the timestamp.
@@ -1046,9 +987,7 @@ impl<T: 'static> EventProcessor<T> {
callback(Event::WindowEvent { callback(Event::WindowEvent {
window_id, window_id,
event: WindowEvent::ModifiersChanged( event: WindowEvent::ModifiersChanged(ModifiersState::empty().into()),
ModifiersState::empty().into(),
),
}); });
if let Some(window) = self.with_window(window, Arc::clone) { if let Some(window) = self.with_window(window, Arc::clone) {
@@ -1062,28 +1001,30 @@ impl<T: 'static> EventProcessor<T> {
} }
} }
ffi::XI_TouchBegin | ffi::XI_TouchUpdate | ffi::XI_TouchEnd => { X11Event::XinputTouchBegin(xev)
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) }; | X11Event::XinputTouchUpdate(xev)
| X11Event::XinputTouchEnd(xev) => {
// Set the timestamp. // Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp); wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
let window = xev.event as xproto::Window; let window = xev.event as xproto::Window;
let window_id = mkwid(window); let window_id = mkwid(window);
let phase = match xev.evtype { let phase = match event {
ffi::XI_TouchBegin => TouchPhase::Started, X11Event::XinputTouchBegin(_) => TouchPhase::Started,
ffi::XI_TouchUpdate => TouchPhase::Moved, X11Event::XinputTouchUpdate(_) => TouchPhase::Moved,
ffi::XI_TouchEnd => TouchPhase::Ended, X11Event::XinputTouchEnd(_) => TouchPhase::Ended,
_ => unreachable!(), _ => unreachable!(),
}; };
if self.window_exists(window) { if self.window_exists(window) {
let id = xev.detail as u64; let id = xev.detail as u64;
let location = PhysicalPosition::new(xev.event_x, xev.event_y); let location = PhysicalPosition::new(
xinput_fp1616_to_float(xev.event_x),
xinput_fp1616_to_float(xev.event_y),
);
// Mouse cursor position changes when touch events are received. // Mouse cursor position changes when touch events are received.
// Only the first concurrently active touch ID moves the mouse cursor. // Only the first concurrently active touch ID moves the mouse cursor.
if is_first_touch(&mut self.first_touch, &mut self.num_touch, id, phase) if is_first_touch(&mut self.first_touch, &mut self.num_touch, id, phase) {
{
callback(Event::WindowEvent { callback(Event::WindowEvent {
window_id, window_id,
event: WindowEvent::CursorMoved { event: WindowEvent::CursorMoved {
@@ -1106,20 +1047,21 @@ impl<T: 'static> EventProcessor<T> {
} }
} }
ffi::XI_RawButtonPress | ffi::XI_RawButtonRelease => { X11Event::XinputRawButtonPress(xev) | X11Event::XinputRawButtonRelease(xev) => {
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
// Set the timestamp. // Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp); wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
if xev.flags & ffi::XIPointerEmulated == 0 { if xev
.flags
.contains(xinput::PointerEventFlags::POINTER_EMULATED)
{
callback(Event::DeviceEvent { callback(Event::DeviceEvent {
device_id: mkdid(xev.deviceid as xinput::DeviceId), device_id: mkdid(xev.deviceid as xinput::DeviceId),
event: DeviceEvent::Button { event: DeviceEvent::Button {
button: xev.detail as u32, button: xev.detail,
state: match xev.evtype { state: match event {
ffi::XI_RawButtonPress => Pressed, X11Event::XinputRawButtonPress(_) => Pressed,
ffi::XI_RawButtonRelease => Released, X11Event::XinputRawButtonRelease(_) => Released,
_ => unreachable!(), _ => unreachable!(),
}, },
}, },
@@ -1127,26 +1069,33 @@ impl<T: 'static> EventProcessor<T> {
} }
} }
ffi::XI_RawMotion => { X11Event::XinputRawMotion(xev) => {
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
// Set the timestamp. // Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp); wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
let did = mkdid(xev.deviceid as xinput::DeviceId); let did = mkdid(xev.deviceid as xinput::DeviceId);
let mask = unsafe {
slice::from_raw_parts(
xev.valuators.mask,
xev.valuators.mask_len as usize,
)
};
let mut value = xev.raw_values;
let mut mouse_delta = (0.0, 0.0); let mut mouse_delta = (0.0, 0.0);
let mut scroll_delta = (0.0, 0.0); let mut scroll_delta = (0.0, 0.0);
for i in 0..xev.valuators.mask_len * 8 {
if ffi::XIMaskIsSet(mask, i) { let mask = bytemuck::cast_slice::<u32, u8>(&xev.valuator_mask);
let x = unsafe { *value }; let mut values = &*xev.axisvalues;
for i in 0..mask.len() * 8 {
let byte_index = i / 8;
let bit_index = i % 8;
if mask[byte_index] & (1 << bit_index) == 0 {
continue;
}
// This mask is set, get the value.
let x = {
let (value, rest) = values.split_first().unwrap();
values = rest;
xinput_fp3232_to_float(*value)
};
// We assume that every XInput2 device with analog axes is a pointing device emitting // We assume that every XInput2 device with analog axes is a pointing device emitting
// relative coordinates. // relative coordinates.
match i { match i {
@@ -1163,9 +1112,8 @@ impl<T: 'static> EventProcessor<T> {
value: x, value: x,
}, },
}); });
value = unsafe { value.offset(1) };
}
} }
if mouse_delta != (0.0, 0.0) { if mouse_delta != (0.0, 0.0) {
callback(Event::DeviceEvent { callback(Event::DeviceEvent {
device_id: did, device_id: did,
@@ -1181,24 +1129,22 @@ impl<T: 'static> EventProcessor<T> {
}); });
} }
} }
ffi::XI_RawKeyPress | ffi::XI_RawKeyRelease => { X11Event::XinputRawKeyPress(xev) | X11Event::XinputRawKeyRelease(xev) => {
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
// Set the timestamp. // Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp); wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
let state = match xev.evtype { let state = match event {
ffi::XI_RawKeyPress => Pressed, X11Event::XinputRawKeyPress(_) => Pressed,
ffi::XI_RawKeyRelease => Released, X11Event::XinputRawKeyRelease(_) => Released,
_ => unreachable!(), _ => unreachable!(),
}; };
let device_id = mkdid(xev.sourceid as xinput::DeviceId); let device_id = mkdid(xev.sourceid as xinput::DeviceId);
let keycode = xev.detail as u32; let keycode = xev.detail;
if keycode < KEYCODE_OFFSET as u32 { if keycode < KEYCODE_OFFSET as u32 {
return; return;
} }
let physical_key = keymap::raw_keycode_to_physicalkey(keycode); let physical_key = keymap::raw_keycode_to_keycode(keycode);
callback(Event::DeviceEvent { callback(Event::DeviceEvent {
device_id, device_id,
@@ -1209,23 +1155,22 @@ impl<T: 'static> EventProcessor<T> {
}); });
} }
ffi::XI_HierarchyChanged => { X11Event::XinputHierarchy(xev) => {
let xev: &ffi::XIHierarchyEvent = unsafe { &*(xev.data as *const _) };
// Set the timestamp. // Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp); wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
for info in for info in &xev.infos {
unsafe { slice::from_raw_parts(xev.info, xev.num_info as usize) } if info.flags.contains(
{ xinput::HierarchyMask::MASTER_ADDED | xinput::HierarchyMask::MASTER_REMOVED,
if 0 != info.flags & (ffi::XISlaveAdded | ffi::XIMasterAdded) { ) {
self.init_device(info.deviceid as xinput::DeviceId); self.init_device(info.deviceid as xinput::DeviceId);
callback(Event::DeviceEvent { callback(Event::DeviceEvent {
device_id: mkdid(info.deviceid as xinput::DeviceId), device_id: mkdid(info.deviceid as xinput::DeviceId),
event: DeviceEvent::Added, event: DeviceEvent::Added,
}); });
} else if 0 != info.flags & (ffi::XISlaveRemoved | ffi::XIMasterRemoved) } else if info.flags.contains(
{ xinput::HierarchyMask::SLAVE_ADDED | xinput::HierarchyMask::SLAVE_REMOVED,
) {
callback(Event::DeviceEvent { callback(Event::DeviceEvent {
device_id: mkdid(info.deviceid as xinput::DeviceId), device_id: mkdid(info.deviceid as xinput::DeviceId),
event: DeviceEvent::Removed, event: DeviceEvent::Removed,
@@ -1236,50 +1181,31 @@ impl<T: 'static> EventProcessor<T> {
} }
} }
_ => {} X11Event::XkbNewKeyboardNotify(xev) => {
}
}
_ => {
if event_type == self.xkbext.first_event as _ {
let xev = unsafe { &*(xev as *const _ as *const ffi::XkbAnyEvent) };
match xev.xkb_type {
ffi::XkbNewKeyboardNotify => {
let xev = unsafe {
&*(xev as *const _ as *const ffi::XkbNewKeyboardNotifyEvent)
};
// Set the timestamp. // Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp); wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
let keycodes_changed_flag = 0x1; let keycodes_changed = xev.changed.contains(xkb::NKNDetail::KEYCODES);
let geometry_changed_flag = 0x1 << 1; let geometry_changed = xev.changed.contains(xkb::NKNDetail::GEOMETRY);
let keycodes_changed = if xev.device_id as i32 == self.kb_state.core_keyboard_id
util::has_flag(xev.changed, keycodes_changed_flag);
let geometry_changed =
util::has_flag(xev.changed, geometry_changed_flag);
if xev.device == self.kb_state.core_keyboard_id
&& (keycodes_changed || geometry_changed) && (keycodes_changed || geometry_changed)
{ {
unsafe { self.kb_state.init_with_x11_keymap() }; unsafe { self.kb_state.init_with_x11_keymap() };
} }
} }
ffi::XkbStateNotify => { X11Event::XkbStateNotify(xev) => {
let xev =
unsafe { &*(xev as *const _ as *const ffi::XkbStateNotifyEvent) };
// Set the timestamp. // Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp); wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
let prev_mods = self.kb_state.mods_state(); let prev_mods = self.kb_state.mods_state();
self.kb_state.update_modifiers( self.kb_state.update_modifiers(
xev.base_mods, xev.base_mods.into(),
xev.latched_mods, xev.latched_mods.into(),
xev.locked_mods, xev.locked_mods.into(),
xev.base_group as u32, xev.base_group as u32,
xev.latched_group as u32, xev.latched_group as u32,
xev.locked_group as u32, xev.locked_group.into(),
); );
let new_mods = self.kb_state.mods_state(); let new_mods = self.kb_state.mods_state();
if prev_mods != new_mods { if prev_mods != new_mods {
@@ -1293,12 +1219,13 @@ impl<T: 'static> EventProcessor<T> {
} }
} }
} }
_ => {}
} X11Event::RandrNotify(_) => {
}
if event_type == self.randr_event_offset as c_int {
self.process_dpi_change(&mut callback); self.process_dpi_change(&mut callback);
} }
_ => {
// Don't care, lol
} }
} }

View File

@@ -9,8 +9,10 @@ use x11rb::protocol::Event;
use xim::x11rb::{HasConnection, X11rbClient}; use xim::x11rb::{HasConnection, X11rbClient};
use xim::{AttributeName, Client as _, ClientError, ClientHandler, InputStyle, Point}; use xim::{AttributeName, Client as _, ClientError, ClientHandler, InputStyle, Point};
use std::cell::RefCell;
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use std::fmt; use std::fmt;
use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
impl HasConnection for XConnection { impl HasConnection for XConnection {
@@ -78,6 +80,9 @@ pub(super) struct ImeData {
/// Inner IME handler. /// Inner IME handler.
struct ImeHandler { struct ImeHandler {
/// Handle to the event queue.
event_queue: Rc<RefCell<VecDeque<Event>>>,
/// Whether IME is currently disconnected. /// Whether IME is currently disconnected.
disconnected: bool, disconnected: bool,
@@ -139,7 +144,11 @@ enum Style {
impl ImeData { impl ImeData {
/// Creates the IME data for the display. /// Creates the IME data for the display.
pub(super) fn new(conn: &Arc<XConnection>, screen: usize) -> Result<Self, X11Error> { pub(super) fn new(
conn: &Arc<XConnection>,
screen: usize,
event_queue: &Rc<RefCell<VecDeque<Event>>>,
) -> Result<Self, X11Error> {
// IM servers to try, in order: // IM servers to try, in order:
// - None, which defaults to the environment variable `XMODIFIERS` in xim's impl. // - None, which defaults to the environment variable `XMODIFIERS` in xim's impl.
// - "local", which is the default for most IMEs. // - "local", which is the default for most IMEs.
@@ -154,6 +163,7 @@ impl ImeData {
return Ok(Self { return Ok(Self {
client, client,
handler: ImeHandler { handler: ImeHandler {
event_queue: event_queue.clone(),
disconnected: true, disconnected: true,
ime_events: VecDeque::new(), ime_events: VecDeque::new(),
pending_windows: VecDeque::new(), pending_windows: VecDeque::new(),
@@ -429,8 +439,44 @@ impl ImeData {
let mut last_event = self.conn().poll_for_event()?; let mut last_event = self.conn().poll_for_event()?;
loop { loop {
if let Some(last_event) = last_event { if let Some(last_event) = last_event.as_ref() {
if self.filter_event(&last_event)? { if self.filter_event(last_event)? {
return Ok(());
}
}
{
// Check the event queue for events.
let event_queue = self.handler.event_queue.clone();
let mut event_queue = event_queue.borrow_mut();
// Check the event queue for events we can use.
let mut found_event = false;
let mut last_err = None;
event_queue.retain(|event| match self.filter_event(event) {
Ok(false) => {
found_event = true;
true
}
Ok(true) => false,
Err(err) => {
last_err = Some(err);
true
}
});
// Push our own event to the queue.
if let Some(last_event) = last_event.take() {
event_queue.push_back(last_event);
}
// Check for errors.
if let Some(err) = last_err {
return Err(err);
}
// If we found an event, then we're done.
if found_event {
return Ok(()); return Ok(());
} }
} }

View File

@@ -27,8 +27,7 @@ use std::{
cell::{Cell, RefCell}, cell::{Cell, RefCell},
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
ffi::CStr, ffi::CStr,
fmt, fmt, mem,
mem::MaybeUninit,
ops::Deref, ops::Deref,
os::{ os::{
raw::*, raw::*,
@@ -43,15 +42,12 @@ use std::{
use atoms::*; use atoms::*;
use x11rb::x11_utils::X11Error as LogicalError; use x11rb::protocol::{
use x11rb::{
connection::RequestConnection,
protocol::{
xinput::{self, ConnectionExt as _}, xinput::{self, ConnectionExt as _},
xkb, xkb,
xproto::{self, ConnectionExt as _}, xproto::{self, ConnectionExt as _},
},
}; };
use x11rb::x11_utils::X11Error as LogicalError;
use x11rb::{ use x11rb::{
errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError}, errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError},
xcb_ffi::ReplyOrIdError, xcb_ffi::ReplyOrIdError,
@@ -200,12 +196,15 @@ impl<T: 'static> EventLoop<T> {
let wm_delete_window = atoms[WM_DELETE_WINDOW]; let wm_delete_window = atoms[WM_DELETE_WINDOW];
let net_wm_ping = atoms[_NET_WM_PING]; let net_wm_ping = atoms[_NET_WM_PING];
// Create an event queue.
let event_queue = Rc::new(RefCell::new(std::collections::VecDeque::with_capacity(4)));
let dnd = Dnd::new(Arc::clone(&xconn)) let dnd = Dnd::new(Arc::clone(&xconn))
.expect("Failed to call XInternAtoms when initializing drag and drop"); .expect("Failed to call XInternAtoms when initializing drag and drop");
let (ime_sender, ime_receiver) = mpsc::channel(); let (ime_sender, ime_receiver) = mpsc::channel();
let ime = match ime::ImeData::new(&xconn, xconn.default_screen_index()) { let ime = match ime::ImeData::new(&xconn, xconn.default_screen_index(), &event_queue) {
Ok(ime) => Some(ime), Ok(ime) => Some(ime),
Err(e) => { Err(e) => {
log::error!("Failed to open IME: {e}"); log::error!("Failed to open IME: {e}");
@@ -213,21 +212,10 @@ impl<T: 'static> EventLoop<T> {
} }
}; };
let randr_event_offset = xconn xconn
.select_xrandr_input(root) .select_xrandr_input(root)
.expect("Failed to query XRandR extension"); .expect("Failed to query XRandR extension");
let xi2ext = xconn
.xcb_connection()
.extension_information(xinput::X11_EXTENSION_NAME)
.expect("Failed to query XInput extension")
.expect("X server missing XInput extension");
let xkbext = xconn
.xcb_connection()
.extension_information(xkb::X11_EXTENSION_NAME)
.expect("Failed to query XKB extension")
.expect("X server missing XKB extension");
// Check for XInput2 support. // Check for XInput2 support.
xconn xconn
.xcb_connection() .xcb_connection()
@@ -309,13 +297,11 @@ impl<T: 'static> EventLoop<T> {
}); });
let event_processor = EventProcessor { let event_processor = EventProcessor {
event_queue,
target: target.clone(), target: target.clone(),
dnd, dnd,
devices: Default::default(), devices: Default::default(),
randr_event_offset,
ime_requests: ime_receiver, ime_requests: ime_receiver,
xi2ext,
xkbext,
kb_state, kb_state,
num_touch: 0, num_touch: 0,
held_key_press: None, held_key_press: None,
@@ -598,12 +584,10 @@ impl<T: 'static> EventLoop<T> {
F: FnMut(Event<T>, &RootELW<T>), F: FnMut(Event<T>, &RootELW<T>),
{ {
let target = &self.target; let target = &self.target;
let mut xev = MaybeUninit::uninit();
let wt = get_xtarget(&self.target); let wt = get_xtarget(&self.target);
while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } { while let Some(event) = self.event_processor.poll_one_event() {
let mut xev = unsafe { xev.assume_init() }; self.event_processor.process_event(event, |event| {
self.event_processor.process_event(&mut xev, |event| {
if let Event::WindowEvent { if let Event::WindowEvent {
window_id: crate::window::WindowId(wid), window_id: crate::window::WindowId(wid),
event: WindowEvent::RedrawRequested, event: WindowEvent::RedrawRequested,
@@ -983,34 +967,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 _))
} }
@@ -1112,8 +1068,15 @@ impl Device {
} }
} }
/// Convert the raw X11 representation for a 32-bit floating point to a double. /// Convert the raw X11 representation for a 32-bit fixed point to a double.
#[inline] #[inline]
fn xinput_fp1616_to_float(fp: xinput::Fp1616) -> f64 { fn xinput_fp1616_to_float(fp: xinput::Fp1616) -> f64 {
(fp as f64) / ((1 << 16) as f64) (fp as f64) / ((1 << 16) as f64)
} }
/// Conver the raw X11 representation for a 64-bit fixed point number to a double.
#[inline]
fn xinput_fp3232_to_float(fp: xinput::Fp3232) -> f64 {
let xinput::Fp3232 { integral, frac } = fp;
integral as f64 + (frac as f64 / (1u64 << 32) as f64)
}

View File

@@ -17,7 +17,6 @@ pub use self::{cursor::*, geometry::*, hint::*, input::*, window_property::*, wm
use std::{ use std::{
mem::{self, MaybeUninit}, mem::{self, MaybeUninit},
ops::BitAnd,
os::raw::*, os::raw::*,
}; };
@@ -34,13 +33,6 @@ pub fn maybe_change<T: PartialEq>(field: &mut Option<T>, value: T) -> bool {
} }
} }
pub fn has_flag<T>(bitset: T, flag: T) -> bool
where
T: Copy + PartialEq + BitAnd<T, Output = T>,
{
bitset & flag == flag
}
impl XConnection { impl XConnection {
// This is impoartant, so pay attention! // This is impoartant, so pay attention!
// Xlib has an output buffer, and tries to hide the async nature of X from you. // Xlib has an output buffer, and tries to hide the async nature of X from you.