From d8e32c3e3cdcb48f64d23b08dc9d821663d09bd2 Mon Sep 17 00:00:00 2001 From: apricotbucket28 <71973804+apricotbucket28@users.noreply.github.com> Date: Mon, 18 Mar 2024 18:50:29 -0300 Subject: [PATCH] linux: scrolling improvements (#9103) This PR adjusts scrolling to be a lot faster on Linux and also makes terminal scrolling work. For Wayland, it makes scrolling faster by handling the `AxisValue120` event (which also allows high-resolution scrolling on supported mice) On X11, changed the 1 line per scroll to 3. ### Different solutions I tried replicating Chromium's scrolling behaviour, but it was inconsistent in X11/Wayland and found it too fast on Wayland. Plus, it also didn't match VSCode, since it seems that they do something different. Release Notes: - Made scrolling faster on Linux - Made terminal scroll on Linux --- crates/gpui/src/platform/linux/platform.rs | 2 + .../gpui/src/platform/linux/wayland/client.rs | 64 +++++++++++++++++-- crates/gpui/src/platform/linux/x11/client.rs | 9 +-- crates/terminal/src/terminal.rs | 3 + 4 files changed, 68 insertions(+), 10 deletions(-) diff --git a/crates/gpui/src/platform/linux/platform.rs b/crates/gpui/src/platform/linux/platform.rs index 622504efaf..0f5dc8b18a 100644 --- a/crates/gpui/src/platform/linux/platform.rs +++ b/crates/gpui/src/platform/linux/platform.rs @@ -30,6 +30,8 @@ use crate::{ use super::x11::X11Client; +pub(super) const SCROLL_LINES: f64 = 3.0; + #[derive(Default)] pub(crate) struct Callbacks { open_urls: Option)>>, diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index 23b2c5dc47..7bb3ebb0f8 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -14,7 +14,7 @@ use wayland_backend::protocol::WEnum; use wayland_client::globals::{registry_queue_init, GlobalListContents}; use wayland_client::protocol::wl_callback::WlCallback; use wayland_client::protocol::wl_output; -use wayland_client::protocol::wl_pointer::AxisRelativeDirection; +use wayland_client::protocol::wl_pointer::{AxisRelativeDirection, AxisSource}; use wayland_client::{ delegate_noop, protocol::{ @@ -64,6 +64,7 @@ pub(crate) struct WaylandClientStateInner { repeat: KeyRepeat, modifiers: Modifiers, scroll_direction: f64, + axis_source: AxisSource, mouse_location: Option>, button_pressed: Option, mouse_focused_window: Option>, @@ -97,9 +98,22 @@ pub(crate) struct WaylandClient { qh: Arc>, } -const WL_SEAT_VERSION: u32 = 4; +const WL_SEAT_MIN_VERSION: u32 = 4; const WL_OUTPUT_VERSION: u32 = 2; +fn wl_seat_version(version: u32) -> u32 { + if version >= wl_pointer::EVT_AXIS_VALUE120_SINCE { + wl_pointer::EVT_AXIS_VALUE120_SINCE + } else if version >= WL_SEAT_MIN_VERSION { + WL_SEAT_MIN_VERSION + } else { + panic!( + "wl_seat below required version: {} < {}", + version, WL_SEAT_MIN_VERSION + ); + } +} + impl WaylandClient { pub(crate) fn new(linux_platform_inner: Rc) -> Self { let conn = Connection::connect_to_env().unwrap(); @@ -114,7 +128,7 @@ impl WaylandClient { "wl_seat" => { globals.registry().bind::( global.name, - WL_SEAT_VERSION, + wl_seat_version(global.version), &qh, (), ); @@ -163,6 +177,7 @@ impl WaylandClient { command: false, }, scroll_direction: -1.0, + axis_source: AxisSource::Wheel, mouse_location: None, button_pressed: None, mouse_focused_window: None, @@ -325,10 +340,10 @@ impl Dispatch for WaylandClientStat wl_registry::Event::Global { name, interface, - version: _, + version, } => match &interface[..] { "wl_seat" => { - registry.bind::(name, WL_SEAT_VERSION, qh, ()); + registry.bind::(name, wl_seat_version(version), qh, ()); } "wl_output" => { state.outputs.push(( @@ -914,12 +929,49 @@ impl Dispatch for WaylandClientState { _ => -1.0, } } + wl_pointer::Event::AxisSource { + axis_source: WEnum::Value(axis_source), + } => { + state.axis_source = axis_source; + } + wl_pointer::Event::AxisValue120 { + axis: WEnum::Value(axis), + value120, + } => { + let focused_window = &state.mouse_focused_window; + let mouse_location = &state.mouse_location; + if let (Some(focused_window), Some(mouse_location)) = + (focused_window, mouse_location) + { + let value = value120 as f64 * state.scroll_direction; + focused_window.handle_input(PlatformInput::ScrollWheel(ScrollWheelEvent { + position: *mouse_location, + delta: match axis { + wl_pointer::Axis::VerticalScroll => { + ScrollDelta::Pixels(Point::new(Pixels(0.0), Pixels(value as f32))) + } + wl_pointer::Axis::HorizontalScroll => { + ScrollDelta::Pixels(Point::new(Pixels(value as f32), Pixels(0.0))) + } + _ => unimplemented!(), + }, + modifiers: state.modifiers, + touch_phase: TouchPhase::Moved, + })) + } + } wl_pointer::Event::Axis { time, axis: WEnum::Value(axis), value, .. } => { + if wl_pointer.version() >= wl_pointer::EVT_AXIS_VALUE120_SINCE + && state.axis_source != AxisSource::Continuous + { + return; + } + let focused_window = &state.mouse_focused_window; let mouse_location = &state.mouse_location; if let (Some(focused_window), Some(mouse_location)) = @@ -938,7 +990,7 @@ impl Dispatch for WaylandClientState { _ => unimplemented!(), }, modifiers: state.modifiers, - touch_phase: TouchPhase::Started, + touch_phase: TouchPhase::Moved, })) } } diff --git a/crates/gpui/src/platform/linux/x11/client.rs b/crates/gpui/src/platform/linux/x11/client.rs index 8a20c77490..d3288a3c3e 100644 --- a/crates/gpui/src/platform/linux/x11/client.rs +++ b/crates/gpui/src/platform/linux/x11/client.rs @@ -23,7 +23,7 @@ use crate::{ ScrollDelta, Size, TouchPhase, WindowParams, }; -use super::{X11Display, X11Window, X11WindowState, XcbAtoms}; +use super::{super::SCROLL_LINES, X11Display, X11Window, X11WindowState, XcbAtoms}; use calloop::{ generic::{FdWrapper, Generic}, RegistrationToken, @@ -221,12 +221,13 @@ impl X11Client { })); } else if event.detail >= 4 && event.detail <= 5 { // https://stackoverflow.com/questions/15510472/scrollwheel-event-in-x11 - let delta_x = if event.detail == 4 { 1.0 } else { -1.0 }; + let scroll_direction = if event.detail == 4 { 1.0 } else { -1.0 }; + let scroll_y = SCROLL_LINES * scroll_direction; window.handle_input(PlatformInput::ScrollWheel(crate::ScrollWheelEvent { position, - delta: ScrollDelta::Lines(Point::new(0.0, delta_x)), + delta: ScrollDelta::Lines(Point::new(0.0, scroll_y as f32)), modifiers, - touch_phase: TouchPhase::default(), + touch_phase: TouchPhase::Moved, })); } else { log::warn!("Unknown button press: {event:?}"); diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index e9324191f1..b39c6eb53e 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -70,7 +70,10 @@ actions!( ///Scrolling is unbearably sluggish by default. Alacritty supports a configurable ///Scroll multiplier that is set to 3 by default. This will be removed when I ///Implement scroll bars. +#[cfg(target_os = "macos")] const SCROLL_MULTIPLIER: f32 = 4.; +#[cfg(not(target_os = "macos"))] +const SCROLL_MULTIPLIER: f32 = 1.; const MAX_SEARCH_LINES: usize = 100; const DEBUG_TERMINAL_WIDTH: Pixels = px(500.); const DEBUG_TERMINAL_HEIGHT: Pixels = px(30.);