Skip to content

Commit

Permalink
Replace all X11 mouse events with XI2 equivalents (#11235)
Browse files Browse the repository at this point in the history
This PR replaces all pointer events on X11 with their XI2 equivalents,
which fixes problems with scroll events not being reported when a mouse
button is down. Additionally it closes #11206 by resetting the tracked
global scroll valulator position with `None` on a leave event to prevent
a large scroll delta if scrolling is done outside the window. Lastly, it
resolves the bad window issue kvark was having.

Release Notes:

- Fixed X11 Scroll snapping (#11206 ).

---------

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
  • Loading branch information
someone13574 and mikayla-maki committed May 6, 2024
1 parent 5486c3d commit 9a60c0a
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 60 deletions.
55 changes: 22 additions & 33 deletions crates/gpui/src/platform/linux/x11/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use super::{
super::{open_uri_internal, SCROLL_LINES},
X11Display, X11WindowStatePtr, XcbAtoms,
};
use super::{button_of_key, modifiers_from_state};
use super::{button_from_mask, button_of_key, modifiers_from_state};
use crate::platform::linux::is_within_click_distance;
use crate::platform::linux::platform::DOUBLE_CLICK_INTERVAL;

Expand Down Expand Up @@ -390,16 +390,16 @@ impl X11Client {
drop(state);
window.handle_input(PlatformInput::KeyUp(crate::KeyUpEvent { keystroke }));
}
Event::ButtonPress(event) => {
Event::XinputButtonPress(event) => {
let window = self.get_window(event.event)?;
let mut state = self.0.borrow_mut();

let modifiers = modifiers_from_state(event.state);
let modifiers = modifiers_from_xinput_info(event.mods);
let position = point(
px(event.event_x as f32 / state.scale_factor),
px(event.event_y as f32 / state.scale_factor),
px(event.event_x as f32 / u16::MAX as f32 / state.scale_factor),
px(event.event_y as f32 / u16::MAX as f32 / state.scale_factor),
);
if let Some(button) = button_of_key(event.detail) {
if let Some(button) = button_of_key(event.detail.try_into().unwrap()) {
let click_elapsed = state.last_click.elapsed();

if click_elapsed < DOUBLE_CLICK_INTERVAL
Expand All @@ -426,15 +426,15 @@ impl X11Client {
log::warn!("Unknown button press: {event:?}");
}
}
Event::ButtonRelease(event) => {
Event::XinputButtonRelease(event) => {
let window = self.get_window(event.event)?;
let state = self.0.borrow();
let modifiers = modifiers_from_state(event.state);
let modifiers = modifiers_from_xinput_info(event.mods);
let position = point(
px(event.event_x as f32 / state.scale_factor),
px(event.event_y as f32 / state.scale_factor),
px(event.event_x as f32 / u16::MAX as f32 / state.scale_factor),
px(event.event_y as f32 / u16::MAX as f32 / state.scale_factor),
);
if let Some(button) = button_of_key(event.detail) {
if let Some(button) = button_of_key(event.detail.try_into().unwrap()) {
let click_count = state.current_count;
drop(state);
window.handle_input(PlatformInput::MouseUp(crate::MouseUpEvent {
Expand All @@ -448,6 +448,7 @@ impl X11Client {
Event::XinputMotion(event) => {
let window = self.get_window(event.event)?;
let state = self.0.borrow();
let pressed_button = button_from_mask(event.button_mask[0]);
let position = point(
px(event.event_x as f32 / u16::MAX as f32 / state.scale_factor),
px(event.event_y as f32 / u16::MAX as f32 / state.scale_factor),
Expand All @@ -464,7 +465,7 @@ impl X11Client {
if event.valuator_mask[0] & 3 != 0 {
window.handle_input(PlatformInput::MouseMove(crate::MouseMoveEvent {
position,
pressed_button: None,
pressed_button,
modifiers,
}));
}
Expand Down Expand Up @@ -524,32 +525,20 @@ impl X11Client {
valuator_idx += 1;
}
}
Event::MotionNotify(event) => {
let window = self.get_window(event.event)?;
let state = self.0.borrow();
let pressed_button = super::button_from_state(event.state);
let position = point(
px(event.event_x as f32 / state.scale_factor),
px(event.event_y as f32 / state.scale_factor),
);
let modifiers = modifiers_from_state(event.state);
drop(state);
window.handle_input(PlatformInput::MouseMove(crate::MouseMoveEvent {
pressed_button,
position,
modifiers,
}));
}
Event::LeaveNotify(event) => {
Event::XinputLeave(event) => {
self.0.borrow_mut().scroll_x = None; // Set last scroll to `None` so that a large delta isn't created if scrolling is done outside the window (the valuator is global)
self.0.borrow_mut().scroll_y = None;

let window = self.get_window(event.event)?;
let state = self.0.borrow();
let pressed_button = super::button_from_state(event.state);
let pressed_button = button_from_mask(event.buttons[0]);
let position = point(
px(event.event_x as f32 / state.scale_factor),
px(event.event_y as f32 / state.scale_factor),
px(event.event_x as f32 / u16::MAX as f32 / state.scale_factor),
px(event.event_y as f32 / u16::MAX as f32 / state.scale_factor),
);
let modifiers = modifiers_from_state(event.state);
let modifiers = modifiers_from_xinput_info(event.mods);
drop(state);

window.handle_input(PlatformInput::MouseExited(crate::MouseExitEvent {
pressed_button,
position,
Expand Down
8 changes: 4 additions & 4 deletions crates/gpui/src/platform/linux/x11/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ pub(crate) fn modifiers_from_xinput_info(modifier_info: xinput::ModifierInfo) ->
}
}

pub(crate) fn button_from_state(state: xproto::KeyButMask) -> Option<MouseButton> {
Some(if state.contains(xproto::KeyButMask::BUTTON1) {
pub(crate) fn button_from_mask(button_mask: u32) -> Option<MouseButton> {
Some(if button_mask & 2 == 2 {
MouseButton::Left
} else if state.contains(xproto::KeyButMask::BUTTON2) {
} else if button_mask & 4 == 4 {
MouseButton::Middle
} else if state.contains(xproto::KeyButMask::BUTTON3) {
} else if button_mask & 8 == 8 {
MouseButton::Right
} else {
return None;
Expand Down
42 changes: 19 additions & 23 deletions crates/gpui/src/platform/linux/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ use x11rb::{
connection::{Connection as _, RequestConnection as _},
protocol::{
render::{self, ConnectionExt as _},
xinput,
xproto::{self, ConnectionExt as _},
xinput::{self, ConnectionExt as _},
xproto::{self, ConnectionExt as _, CreateWindowAux},
},
resource_manager::Database,
wrapper::ConnectionExt,
wrapper::ConnectionExt as _,
xcb_ffi::XCBConnection,
};

Expand Down Expand Up @@ -262,14 +262,7 @@ impl X11WindowState {
| xproto::EventMask::LEAVE_WINDOW
| xproto::EventMask::FOCUS_CHANGE
| xproto::EventMask::KEY_PRESS
| xproto::EventMask::KEY_RELEASE
| xproto::EventMask::BUTTON_PRESS
| xproto::EventMask::BUTTON_RELEASE
| xproto::EventMask::POINTER_MOTION
| xproto::EventMask::BUTTON1_MOTION
| xproto::EventMask::BUTTON2_MOTION
| xproto::EventMask::BUTTON3_MOTION
| xproto::EventMask::BUTTON_MOTION,
| xproto::EventMask::KEY_RELEASE,
);

xcb_connection
Expand All @@ -290,18 +283,6 @@ impl X11WindowState {
.check()
.unwrap();

xinput::ConnectionExt::xinput_xi_select_events(
&xcb_connection,
x_window,
&[xinput::EventMask {
deviceid: 1,
mask: vec![xinput::XIEventMask::MOTION],
}],
)
.unwrap()
.check()
.unwrap();

if let Some(titlebar) = params.titlebar {
if let Some(title) = titlebar.title {
xcb_connection
Expand All @@ -326,6 +307,21 @@ impl X11WindowState {
)
.unwrap();

xcb_connection
.xinput_xi_select_events(
x_window,
&[xinput::EventMask {
deviceid: 1,
mask: vec![
xinput::XIEventMask::MOTION
| xinput::XIEventMask::BUTTON_PRESS
| xinput::XIEventMask::BUTTON_RELEASE
| xinput::XIEventMask::LEAVE,
],
}],
)
.unwrap();

xcb_connection.map_window(x_window).unwrap();
xcb_connection.flush().unwrap();

Expand Down

0 comments on commit 9a60c0a

Please sign in to comment.