Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ cc = { version = "1.0.79", optional = true }
[features]
default = ["backend_drm", "backend_gbm", "backend_libinput", "backend_udev", "backend_session_libseat", "backend_x11", "backend_winit", "desktop", "renderer_gl", "renderer_pixman", "renderer_multi", "xwayland", "wayland_frontend", "backend_vulkan"]
backend_winit = ["winit", "backend_egl", "wayland-client", "wayland-cursor", "wayland-egl", "renderer_gl"]
backend_x11 = ["x11rb", "x11rb/dri3", "x11rb/xfixes", "x11rb/present", "x11rb_event_source", "backend_gbm", "backend_drm", "backend_egl"]
backend_x11 = ["x11rb", "x11rb/dri3", "x11rb/xfixes", "x11rb/xinput", "x11rb/present", "x11rb_event_source", "backend_gbm", "backend_drm", "backend_egl"]
backend_drm = ["drm", "drm-ffi"]
backend_gbm = ["gbm", "cc", "pkg-config"]
backend_gbm_has_fd_for_plane = []
Expand Down
27 changes: 18 additions & 9 deletions src/backend/x11/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,28 @@ macro_rules! extensions {

if connection.extension_information(X11_EXTENSION_NAME)?.is_some() {
let version = connection.$extension_fn($req_major, $req_minor)?.reply()?;
let major_version = u32::from(version.major_version);
let minor_version = u32::from(version.minor_version);

#[allow(unused_comparisons)] // Macro comparisons
if version.major_version >= $req_major
|| (version.major_version == $req_major && version.minor_version >= $req_minor)
if major_version >= $req_major
|| (major_version == $req_major && minor_version >= $req_minor)
{
info!(
"Loaded extension {} version {}.{}",
X11_EXTENSION_NAME,
version.major_version,
version.minor_version,
major_version,
minor_version,
);

Some((version.major_version, version.minor_version))
Some((major_version, minor_version))
} else {
if $required {
error!(
"required extension {} version is too low (have {}.{}, expected {}.{})",
X11_EXTENSION_NAME,
version.major_version,
version.minor_version,
major_version,
minor_version,
$req_major,
$req_minor,
);
Expand All @@ -78,8 +80,8 @@ macro_rules! extensions {
name: X11_EXTENSION_NAME,
required_major: $req_major,
required_minor: $req_minor,
available_major: version.major_version,
available_minor: version.minor_version,
available_major: major_version,
available_minor: minor_version,
}.into());
} else {
None
Expand Down Expand Up @@ -133,4 +135,11 @@ extensions! {
minimum: (1, 0),
request: (1, 2),
},

xinput {
xinput_xi_query_version,
required: true,
minimum: (2, 0),
request: (2, 4),
},
}
37 changes: 24 additions & 13 deletions src/backend/x11/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ use x11rb::{
protocol::{
self as x11,
dri3::ConnectionExt as _,
xinput,
xproto::{ColormapAlloc, ConnectionExt, CreateWindowAux, VisualClass, WindowClass, WindowWrapper},
ErrorKind,
},
Expand Down Expand Up @@ -674,7 +675,7 @@ impl X11Inner {
// If X11 is deadlocking somewhere here, make sure you drop your mutex guards.

match event {
x11::Event::FocusIn(focus_in) => {
x11::Event::XinputFocusIn(focus_in) => {
callback(
Focus {
focused: true,
Expand All @@ -684,7 +685,7 @@ impl X11Inner {
);
}

x11::Event::FocusOut(focus_out) => {
x11::Event::XinputFocusOut(focus_out) => {
callback(
Focus {
focused: false,
Expand All @@ -694,7 +695,7 @@ impl X11Inner {
);
}

x11::Event::ButtonPress(button_press) => {
x11::Event::XinputButtonPress(button_press) => {
if let Some(window) = X11Inner::window_ref_from_id(inner, &button_press.event) {
// X11 decided to associate scroll wheel with a button, 4, 5, 6 and 7 for
// up, down, right and left. For scrolling, a press event is emitted and a
Expand Down Expand Up @@ -752,7 +753,7 @@ impl X11Inner {
event: InputEvent::PointerButton {
event: X11MouseInputEvent {
time: button_press.time,
raw: button_press.detail as u32,
raw: button_press.detail,
state: ButtonState::Pressed,
window,
},
Expand All @@ -765,7 +766,7 @@ impl X11Inner {
}
}

x11::Event::ButtonRelease(button_release) => {
x11::Event::XinputButtonRelease(button_release) => {
// Ignore release tick because this event is always sent immediately after the press
// tick for scrolling and the backend will dispatch release event automatically during
// the press event.
Expand All @@ -779,7 +780,7 @@ impl X11Inner {
event: InputEvent::PointerButton {
event: X11MouseInputEvent {
time: button_release.time,
raw: button_release.detail as u32,
raw: button_release.detail,
state: ButtonState::Released,
window,
},
Expand All @@ -791,7 +792,11 @@ impl X11Inner {
}
}

x11::Event::KeyPress(key_press) => {
x11::Event::XinputKeyPress(key_press) => {
if key_press.flags.contains(xinput::KeyEventFlags::KEY_REPEAT) {
return;
}

if let Some(window) = X11Inner::window_ref_from_id(inner, &key_press.event) {
// Do not hold the lock.
let count = { inner.lock().unwrap().key_counter.fetch_add(1, Ordering::SeqCst) + 1 };
Expand All @@ -814,7 +819,7 @@ impl X11Inner {
}
}

x11::Event::KeyRelease(key_release) => {
x11::Event::XinputKeyRelease(key_release) => {
if let Some(window) = X11Inner::window_ref_from_id(inner, &key_release.event) {
let count = {
let key_counter = inner.lock().unwrap().key_counter.clone();
Expand Down Expand Up @@ -845,13 +850,13 @@ impl X11Inner {
}
}

x11::Event::MotionNotify(motion_notify) => {
x11::Event::XinputMotion(motion_notify) => {
if let Some(window) =
X11Inner::window_ref_from_id(inner, &motion_notify.event).and_then(|w| w.upgrade())
{
// Use event_x/y since those are relative the the window receiving events.
let x = motion_notify.event_x as f64;
let y = motion_notify.event_y as f64;
let x = fixed_point_to_float(motion_notify.event_x);
let y = fixed_point_to_float(motion_notify.event_y);

let window_size = { *window.size.lock().unwrap() };

Expand Down Expand Up @@ -907,15 +912,15 @@ impl X11Inner {
}
}

x11::Event::EnterNotify(enter_notify) => {
x11::Event::XinputEnter(enter_notify) => {
if let Some(window) =
X11Inner::window_ref_from_id(inner, &enter_notify.event).and_then(|w| w.upgrade())
{
window.cursor_enter();
}
}

x11::Event::LeaveNotify(leave_notify) => {
x11::Event::XinputLeave(leave_notify) => {
if let Some(window) =
X11Inner::window_ref_from_id(inner, &leave_notify.event).and_then(|w| w.upgrade())
{
Expand Down Expand Up @@ -979,6 +984,12 @@ impl X11Inner {
}
}

fn fixed_point_to_float(value: i32) -> f64 {
let int = value >> 16;
let frac = value & 0xffff;
int as f64 + frac as f64 / u16::MAX as f64
}

fn egl_init(_: &X11Inner) -> Result<(DrmNode, OwnedFd), EGLInitError> {
let display = unsafe { EGLDisplay::new(X11DefaultDisplay)? };
let device = EGLDevice::device_for_display(&display)?;
Expand Down
27 changes: 19 additions & 8 deletions src/backend/x11/window_inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use x11rb::{
protocol::{
present::{self, ConnectionExt as _},
xfixes::ConnectionExt as _,
xinput::{self, ConnectionExt as _},
xproto::{
self as x11, AtomEnum, ConnectionExt, CreateWindowAux, Depth, EventMask, PropMode, Screen,
UnmapNotifyEvent, WindowClass,
Expand Down Expand Up @@ -112,14 +113,6 @@ impl WindowInner {
.event_mask(
EventMask::EXPOSURE // Be told when the window is exposed
| EventMask::STRUCTURE_NOTIFY
| EventMask::KEY_PRESS // Key press and release
| EventMask::KEY_RELEASE
| EventMask::BUTTON_PRESS // Mouse button press and release
| EventMask::BUTTON_RELEASE
| EventMask::POINTER_MOTION // Mouse movement
| EventMask::ENTER_WINDOW // Track whether the cursor enters of leaves the window.
| EventMask::LEAVE_WINDOW
| EventMask::FOCUS_CHANGE
| EventMask::EXPOSURE
| EventMask::NO_EVENT,
)
Expand All @@ -141,6 +134,24 @@ impl WindowInner {
&window_aux,
)?;

connection.xinput_xi_select_events(
window,
&[xinput::EventMask {
deviceid: 1, // AllMasterDevices
mask: vec![
xinput::XIEventMask::KEY_PRESS
| xinput::XIEventMask::KEY_RELEASE
| xinput::XIEventMask::BUTTON_PRESS
| xinput::XIEventMask::BUTTON_RELEASE
| xinput::XIEventMask::MOTION
| xinput::XIEventMask::ENTER
| xinput::XIEventMask::LEAVE
| xinput::XIEventMask::FOCUS_IN
| xinput::XIEventMask::FOCUS_OUT,
],
}],
)?;

// We only ever need one event id since we will only ever have one event context.
let present_event_id = connection.generate_id()?;
connection.present_select_input(
Expand Down