mirror of
https://github.com/rust-windowing/winit.git
synced 2026-09-02 14:50:04 -04:00
Use x11rb for event handling
Signed-off-by: John Nunley <dev@notgull.net>
This commit is contained in:
@@ -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>,
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user