Skip to content

Commit

Permalink
Add support for xinput scrolling via button press events
Browse files Browse the repository at this point in the history
  • Loading branch information
mgsloan committed Oct 1, 2024
1 parent a752bbc commit 4c60cf3
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 51 deletions.
2 changes: 1 addition & 1 deletion crates/gpui/src/platform/linux/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ use crate::{

use super::x11::X11Client;

pub(crate) const SCROLL_LINES: f64 = 3.0;
pub(crate) const SCROLL_LINES: f32 = 3.0;

// Values match the defaults on GTK.
// Taken from https://github.com/GNOME/gtk/blob/main/gtk/gtksettings.c#L320
Expand Down
8 changes: 4 additions & 4 deletions crates/gpui/src/platform/linux/wayland/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1634,10 +1634,10 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
let scroll_delta = state.discrete_scroll_delta.get_or_insert(point(0.0, 0.0));
match axis {
wl_pointer::Axis::VerticalScroll => {
scroll_delta.y += discrete as f32 * axis_modifier * SCROLL_LINES as f32;
scroll_delta.y += discrete as f32 * axis_modifier * SCROLL_LINES;
}
wl_pointer::Axis::HorizontalScroll => {
scroll_delta.x += discrete as f32 * axis_modifier * SCROLL_LINES as f32;
scroll_delta.x += discrete as f32 * axis_modifier * SCROLL_LINES;
}
_ => unreachable!(),
}
Expand All @@ -1662,10 +1662,10 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
let wheel_percent = value120 as f32 / 120.0;
match axis {
wl_pointer::Axis::VerticalScroll => {
scroll_delta.y += wheel_percent * axis_modifier * SCROLL_LINES as f32;
scroll_delta.y += wheel_percent * axis_modifier * SCROLL_LINES;
}
wl_pointer::Axis::HorizontalScroll => {
scroll_delta.x += wheel_percent * axis_modifier * SCROLL_LINES as f32;
scroll_delta.x += wheel_percent * axis_modifier * SCROLL_LINES;
}
_ => unreachable!(),
}
Expand Down
125 changes: 85 additions & 40 deletions crates/gpui/src/platform/linux/x11/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ use crate::{
WindowParams, X11Window,
};

use super::{button_of_key, modifiers_from_state, pressed_button_from_mask};
use super::{
button_or_scroll_from_event_detail, modifiers_from_state, pressed_button_from_mask,
ButtonOrScroll, ScrollDirection,
};
use super::{X11Display, X11WindowStatePtr, XcbAtoms};
use super::{XimCallbackEvent, XimHandler};
use crate::platform::linux::platform::{DOUBLE_CLICK_INTERVAL, SCROLL_LINES};
Expand Down Expand Up @@ -950,35 +953,73 @@ impl X11Client {
window.handle_ime_commit(text);
state = self.0.borrow_mut();
}
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
&& state
.last_mouse_button
.is_some_and(|prev_button| prev_button == button)
&& is_within_click_distance(state.last_location, position)
{
state.current_count += 1;
} else {
state.current_count = 1;
}

state.last_click = Instant::now();
state.last_mouse_button = Some(button);
state.last_location = position;
let current_count = state.current_count;
match button_or_scroll_from_event_detail(event.detail) {
Some(ButtonOrScroll::Button(button)) => {
let click_elapsed = state.last_click.elapsed();
if click_elapsed < DOUBLE_CLICK_INTERVAL
&& state
.last_mouse_button
.is_some_and(|prev_button| prev_button == button)
&& is_within_click_distance(state.last_location, position)
{
state.current_count += 1;
} else {
state.current_count = 1;
}

drop(state);
window.handle_input(PlatformInput::MouseDown(crate::MouseDownEvent {
button,
position,
modifiers,
click_count: current_count,
first_mouse: false,
}));
} else {
log::warn!("Unknown button press: {event:?}");
state.last_click = Instant::now();
state.last_mouse_button = Some(button);
state.last_location = position;
let current_count = state.current_count;

drop(state);
window.handle_input(PlatformInput::MouseDown(crate::MouseDownEvent {
button,
position,
modifiers,
click_count: current_count,
first_mouse: false,
}));
}
Some(ButtonOrScroll::Scroll(direction)) => {
drop(state);
// Emulated scroll button presses are sent simultaneously with smooth scrolling XinputMotion events.
// Since handling those events does the scrolling, they are skipped here.
if !event
.flags
.contains(xinput::PointerEventFlags::POINTER_EMULATED)
{
let delta = match direction {
ScrollDirection::Up => {
if modifiers.shift {
Point::new(SCROLL_LINES, 0.0)
} else {
Point::new(0.0, SCROLL_LINES)
}
}
ScrollDirection::Down => {
if modifiers.shift {
Point::new(-SCROLL_LINES, 0.0)
} else {
Point::new(0.0, -SCROLL_LINES)
}
}
ScrollDirection::Left => Point::new(SCROLL_LINES, 0.0),
ScrollDirection::Right => Point::new(-SCROLL_LINES, 0.0),
};
window.handle_input(PlatformInput::ScrollWheel(
crate::ScrollWheelEvent {
position,
delta: ScrollDelta::Lines(delta),
modifiers,
touch_phase: TouchPhase::default(),
},
));
}
}
None => {
log::error!("Unknown x11 button: {}", event.detail);
}
}
}
Event::XinputButtonRelease(event) => {
Expand All @@ -991,15 +1032,19 @@ impl X11Client {
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.try_into().unwrap()) {
let click_count = state.current_count;
drop(state);
window.handle_input(PlatformInput::MouseUp(crate::MouseUpEvent {
button,
position,
modifiers,
click_count,
}));
match button_or_scroll_from_event_detail(event.detail) {
Some(ButtonOrScroll::Button(button)) => {
let click_count = state.current_count;
drop(state);
window.handle_input(PlatformInput::MouseUp(crate::MouseUpEvent {
button,
position,
modifiers,
click_count,
}));
}
Some(ButtonOrScroll::Scroll(_)) => {}
None => {}
}
}
Event::XinputMotion(event) => {
Expand Down Expand Up @@ -1041,7 +1086,7 @@ impl X11Client {
{
let new_scroll = axisvalues[valuator_idx]
/ fp3232_to_f32(scroll_class.increment)
* SCROLL_LINES as f32;
* SCROLL_LINES;
let old_scroll = self.0.borrow().scroll_x;
self.0.borrow_mut().scroll_x = Some(new_scroll);

Expand All @@ -1062,7 +1107,7 @@ impl X11Client {
// the `increment` is the valuator delta equivalent to one positive unit of scrolling. Here that means SCROLL_LINES lines.
let new_scroll = axisvalues[valuator_idx]
/ fp3232_to_f32(scroll_class.increment)
* SCROLL_LINES as f32;
* SCROLL_LINES;
let old_scroll = self.0.borrow().scroll_y;
self.0.borrow_mut().scroll_y = Some(new_scroll);

Expand Down
28 changes: 22 additions & 6 deletions crates/gpui/src/platform/linux/x11/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,29 @@ use x11rb::protocol::{

use crate::{Modifiers, MouseButton, NavigationDirection};

pub(crate) fn button_of_key(detail: xproto::Button) -> Option<MouseButton> {
pub(crate) enum ButtonOrScroll {
Button(MouseButton),
Scroll(ScrollDirection),
}

pub(crate) enum ScrollDirection {
Up,
Down,
Left,
Right,
}

pub(crate) fn button_or_scroll_from_event_detail(detail: u32) -> Option<ButtonOrScroll> {
Some(match detail {
1 => MouseButton::Left,
2 => MouseButton::Middle,
3 => MouseButton::Right,
8 => MouseButton::Navigate(NavigationDirection::Back),
9 => MouseButton::Navigate(NavigationDirection::Forward),
1 => ButtonOrScroll::Button(MouseButton::Left),
2 => ButtonOrScroll::Button(MouseButton::Middle),
3 => ButtonOrScroll::Button(MouseButton::Right),
4 => ButtonOrScroll::Scroll(ScrollDirection::Up),
5 => ButtonOrScroll::Scroll(ScrollDirection::Down),
6 => ButtonOrScroll::Scroll(ScrollDirection::Left),
7 => ButtonOrScroll::Scroll(ScrollDirection::Right),
8 => ButtonOrScroll::Button(MouseButton::Navigate(NavigationDirection::Back)),
9 => ButtonOrScroll::Button(MouseButton::Navigate(NavigationDirection::Forward)),
_ => return None,
})
}
Expand Down

0 comments on commit 4c60cf3

Please sign in to comment.