Skip to content

Commit

Permalink
Implement X11 extensions using x11rb instead of Xlib
Browse files Browse the repository at this point in the history
Removes Xlib code by replacing it with the x11rb equivalent,
the commit handles xrandr, xinput, xinput2, and xkb.

Signed-off-by: John Nunley <[email protected]>
  • Loading branch information
notgull authored Aug 29, 2023
1 parent 0c8cf94 commit bb9b629
Show file tree
Hide file tree
Showing 10 changed files with 396 additions and 391 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ wayland-protocols = { version = "0.30.0", features = [ "staging"], optional = tr
calloop = "0.10.5"
rustix = { version = "0.38.4", default-features = false, features = ["std", "system", "thread", "process"] }
x11-dl = { version = "2.18.5", optional = true }
x11rb = { version = "0.12.0", default-features = false, features = ["allow-unsafe-code", "dl-libxcb", "xinput", "xkb"], optional = true }
x11rb = { version = "0.12.0", default-features = false, features = ["allow-unsafe-code", "dl-libxcb", "randr", "resource_manager", "xinput", "xkb"], optional = true }
xkbcommon-dl = "0.4.0"
memmap2 = { version = "0.5.0", optional = true }

Expand Down
3 changes: 2 additions & 1 deletion src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,7 @@ impl<T> EventLoopWindowTarget<T> {
.x_connection()
.available_monitors()
.into_iter()
.flatten()
.map(MonitorHandle::X)
.collect(),
}
Expand All @@ -863,7 +864,7 @@ impl<T> EventLoopWindowTarget<T> {
EventLoopWindowTarget::Wayland(ref evlp) => evlp.primary_monitor(),
#[cfg(x11_platform)]
EventLoopWindowTarget::X(ref evlp) => {
let primary_monitor = MonitorHandle::X(evlp.x_connection().primary_monitor());
let primary_monitor = MonitorHandle::X(evlp.x_connection().primary_monitor().ok()?);
Some(primary_monitor)
}
}
Expand Down
89 changes: 52 additions & 37 deletions src/platform_impl/linux/x11/event_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@ use std::{
sync::{Arc, Mutex},
};

use x11rb::protocol::xproto::{self, ConnectionExt as _};
use x11rb::x11_utils::Serialize;
use x11rb::{
protocol::{
xinput,
xproto::{self, ConnectionExt as _},
},
x11_utils::ExtensionInformation,
};

use super::{
atoms::*, ffi, get_xtarget, mkdid, mkwid, monitor, util, CookieResultExt, Device, DeviceId,
DeviceInfo, Dnd, DndState, GenericEventCookie, ImeReceiver, ScrollOrientation, UnownedWindow,
WindowId, XExtension,
atoms::*, ffi, get_xtarget, mkdid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo,
Dnd, DndState, GenericEventCookie, ImeReceiver, ScrollOrientation, UnownedWindow, WindowId,
};

use crate::{
Expand All @@ -35,10 +40,10 @@ pub(super) struct EventProcessor<T: 'static> {
pub(super) dnd: Dnd,
pub(super) ime_receiver: ImeReceiver,
pub(super) ime_event_receiver: ImeEventReceiver,
pub(super) randr_event_offset: c_int,
pub(super) randr_event_offset: u8,
pub(super) devices: RefCell<HashMap<DeviceId, Device>>,
pub(super) xi2ext: XExtension,
pub(super) xkbext: XExtension,
pub(super) xi2ext: ExtensionInformation,
pub(super) xkbext: ExtensionInformation,
pub(super) target: Rc<RootELW<T>>,
pub(super) kb_state: KbdState,
// Number of touch events currently in progress
Expand All @@ -55,12 +60,12 @@ pub(super) struct EventProcessor<T: 'static> {
}

impl<T: 'static> EventProcessor<T> {
pub(super) fn init_device(&self, device: c_int) {
pub(super) fn init_device(&self, device: xinput::DeviceId) {
let wt = get_xtarget(&self.target);
let mut devices = self.devices.borrow_mut();
if let Some(info) = DeviceInfo::get(&wt.xconn, device) {
if let Some(info) = DeviceInfo::get(&wt.xconn, device as _) {
for info in info.iter() {
devices.insert(DeviceId(info.deviceid), Device::new(info));
devices.insert(DeviceId(info.deviceid as _), Device::new(info));
}
}
}
Expand Down Expand Up @@ -420,7 +425,10 @@ impl<T: 'static> EventProcessor<T> {
let last_scale_factor = shared_state_lock.last_monitor.scale_factor;
let new_scale_factor = {
let window_rect = util::AaRect::new(new_outer_position, new_inner_size);
let monitor = wt.xconn.get_monitor_for_window(Some(window_rect));
let monitor = wt
.xconn
.get_monitor_for_window(Some(window_rect))
.expect("Failed to find monitor for window");

if monitor.is_dummy() {
// Avoid updating monitor using a dummy monitor handle
Expand Down Expand Up @@ -596,7 +604,7 @@ impl<T: 'static> EventProcessor<T> {
};

let window_id = mkwid(window);
let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD.into());
let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD);

let keycode = xkev.keycode as _;

Expand Down Expand Up @@ -672,7 +680,7 @@ impl<T: 'static> EventProcessor<T> {
return;
};
let xev = &guard.cookie;
if self.xi2ext.opcode != xev.extension {
if self.xi2ext.major_opcode != xev.extension as u8 {
return;
}

Expand All @@ -691,7 +699,7 @@ impl<T: 'static> EventProcessor<T> {
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 device_id = mkdid(xev.deviceid);
let device_id = mkdid(xev.deviceid as xinput::DeviceId);

// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
Expand Down Expand Up @@ -787,7 +795,7 @@ impl<T: 'static> EventProcessor<T> {
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);

let device_id = mkdid(xev.deviceid);
let device_id = mkdid(xev.deviceid as xinput::DeviceId);
let window = xev.event as xproto::Window;
let window_id = mkwid(window);
let new_cursor_pos = (xev.event_x, xev.event_y);
Expand Down Expand Up @@ -820,7 +828,9 @@ impl<T: 'static> EventProcessor<T> {
)
};
let mut devices = self.devices.borrow_mut();
let physical_device = match devices.get_mut(&DeviceId(xev.sourceid)) {
let physical_device = match devices
.get_mut(&DeviceId(xev.sourceid as xinput::DeviceId))
{
Some(device) => device,
None => return,
};
Expand All @@ -832,7 +842,7 @@ impl<T: 'static> EventProcessor<T> {
if let Some(&mut (_, ref mut info)) = physical_device
.scroll_axes
.iter_mut()
.find(|&&mut (axis, _)| axis == i)
.find(|&&mut (axis, _)| axis == i as _)
{
let delta = (x - info.position) / info.increment;
info.position = x;
Expand Down Expand Up @@ -879,9 +889,11 @@ impl<T: 'static> EventProcessor<T> {

let window = xev.event as xproto::Window;
let window_id = mkwid(window);
let device_id = mkdid(xev.deviceid);
let device_id = mkdid(xev.deviceid as xinput::DeviceId);

if let Some(all_info) = DeviceInfo::get(&wt.xconn, ffi::XIAllDevices) {
if let Some(all_info) =
DeviceInfo::get(&wt.xconn, super::ALL_DEVICES.into())
{
let mut devices = self.devices.borrow_mut();
for device_info in all_info.iter() {
if device_info.deviceid == xev.sourceid
Expand All @@ -891,7 +903,7 @@ impl<T: 'static> EventProcessor<T> {
// the virtual device.
|| device_info.attachment == xev.sourceid
{
let device_id = DeviceId(device_info.deviceid);
let device_id = DeviceId(device_info.deviceid as _);
if let Some(device) = devices.get_mut(&device_id) {
device.reset_scroll_position(device_info);
}
Expand Down Expand Up @@ -930,7 +942,7 @@ impl<T: 'static> EventProcessor<T> {
callback(Event::WindowEvent {
window_id: mkwid(window),
event: CursorLeft {
device_id: mkdid(xev.deviceid),
device_id: mkdid(xev.deviceid as xinput::DeviceId),
},
});
}
Expand Down Expand Up @@ -978,14 +990,14 @@ impl<T: 'static> EventProcessor<T> {
let pointer_id = self
.devices
.borrow()
.get(&DeviceId(xev.deviceid))
.get(&DeviceId(xev.deviceid as xinput::DeviceId))
.map(|device| device.attachment)
.unwrap_or(2);

callback(Event::WindowEvent {
window_id,
event: CursorMoved {
device_id: mkdid(pointer_id),
device_id: mkdid(pointer_id as _),
position,
},
});
Expand Down Expand Up @@ -1076,7 +1088,7 @@ impl<T: 'static> EventProcessor<T> {
callback(Event::WindowEvent {
window_id,
event: WindowEvent::CursorMoved {
device_id: mkdid(util::VIRTUAL_CORE_POINTER.into()),
device_id: mkdid(util::VIRTUAL_CORE_POINTER),
position: location.cast(),
},
});
Expand All @@ -1085,7 +1097,7 @@ impl<T: 'static> EventProcessor<T> {
callback(Event::WindowEvent {
window_id,
event: WindowEvent::Touch(Touch {
device_id: mkdid(xev.deviceid),
device_id: mkdid(xev.deviceid as xinput::DeviceId),
phase,
location,
force: None, // TODO
Expand All @@ -1103,7 +1115,7 @@ impl<T: 'static> EventProcessor<T> {

if xev.flags & ffi::XIPointerEmulated == 0 {
callback(Event::DeviceEvent {
device_id: mkdid(xev.deviceid),
device_id: mkdid(xev.deviceid as xinput::DeviceId),
event: DeviceEvent::Button {
button: xev.detail as u32,
state: match xev.evtype {
Expand All @@ -1122,7 +1134,7 @@ impl<T: 'static> EventProcessor<T> {
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);

let did = mkdid(xev.deviceid);
let did = mkdid(xev.deviceid as xinput::DeviceId);

let mask = unsafe {
slice::from_raw_parts(
Expand Down Expand Up @@ -1182,7 +1194,7 @@ impl<T: 'static> EventProcessor<T> {
_ => unreachable!(),
};

let device_id = mkdid(xev.sourceid);
let device_id = mkdid(xev.sourceid as xinput::DeviceId);
let keycode = xev.detail as u32;
if keycode < KEYCODE_OFFSET as u32 {
return;
Expand All @@ -1208,19 +1220,19 @@ impl<T: 'static> EventProcessor<T> {
unsafe { slice::from_raw_parts(xev.info, xev.num_info as usize) }
{
if 0 != info.flags & (ffi::XISlaveAdded | ffi::XIMasterAdded) {
self.init_device(info.deviceid);
self.init_device(info.deviceid as xinput::DeviceId);
callback(Event::DeviceEvent {
device_id: mkdid(info.deviceid),
device_id: mkdid(info.deviceid as xinput::DeviceId),
event: DeviceEvent::Added,
});
} else if 0 != info.flags & (ffi::XISlaveRemoved | ffi::XIMasterRemoved)
{
callback(Event::DeviceEvent {
device_id: mkdid(info.deviceid),
device_id: mkdid(info.deviceid as xinput::DeviceId),
event: DeviceEvent::Removed,
});
let mut devices = self.devices.borrow_mut();
devices.remove(&DeviceId(info.deviceid));
devices.remove(&DeviceId(info.deviceid as xinput::DeviceId));
}
}
}
Expand All @@ -1229,7 +1241,7 @@ impl<T: 'static> EventProcessor<T> {
}
}
_ => {
if event_type == self.xkbext.first_event_id {
if event_type == self.xkbext.first_event as _ {
let xev = unsafe { &*(xev as *const _ as *const ffi::XkbAnyEvent) };
match xev.xkb_type {
ffi::XkbNewKeyboardNotify => {
Expand Down Expand Up @@ -1285,11 +1297,14 @@ impl<T: 'static> EventProcessor<T> {
_ => {}
}
}
if event_type == self.randr_event_offset {
if event_type == self.randr_event_offset as c_int {
// In the future, it would be quite easy to emit monitor hotplug events.
let prev_list = monitor::invalidate_cached_monitor_list();
let prev_list = wt.xconn.invalidate_cached_monitor_list();
if let Some(prev_list) = prev_list {
let new_list = wt.xconn.available_monitors();
let new_list = wt
.xconn
.available_monitors()
.expect("Failed to get monitor list");
for new_monitor in new_list {
// Previous list may be empty, in case of disconnecting and
// reconnecting the only one monitor. We still need to emit events in
Expand Down Expand Up @@ -1419,7 +1434,7 @@ impl<T: 'static> EventProcessor<T> {
) where
F: FnMut(Event<T>),
{
let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD.into());
let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD);

// Update modifiers state and emit key events based on which keys are currently pressed.
for keycode in wt
Expand Down
1 change: 0 additions & 1 deletion src/platform_impl/linux/x11/ffi.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use x11_dl::xmd::CARD32;
pub use x11_dl::{
error::OpenError, keysym::*, xcursor::*, xinput::*, xinput2::*, xlib::*, xlib_xcb::*,
xrandr::*, xrender::*,
};

// Isn't defined by x11_dl
Expand Down
Loading

0 comments on commit bb9b629

Please sign in to comment.