History

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

apricotbucket28 committed 2 years ago

Commit d8e32c31 parent c0f85814 files · +68 −10Browse files

Unified · Split

4 files
  1. crates/gpui/src/platform/linux/platform.rs +2 −0
  2. crates/gpui/src/platform/linux/wayland/client.rs +58 −6
  3. crates/gpui/src/platform/linux/x11/client.rs +5 −4
  4. crates/terminal/src/terminal.rs +3 −0
crates/gpui/src/platform/linux/platform.rs+2−0
@@ -30,6 +30,8 @@ use crate::{ · 29 unmodified lines
3030
3131 use super::x11::X11Client;
3232
33+pub(super) const SCROLL_LINES: f64 = 3.0;
34+
3335 #[derive(Default)]
3436 pub(crate) struct Callbacks {
3537 open_urls: Option<Box<dyn FnMut(Vec<String>)>>,
crates/gpui/src/platform/linux/wayland/client.rs+58−6
@@ -14,7 +14,7 @@ use wayland_backend::protocol::WEnum; · 13 unmodified lines
1414 use wayland_client::globals::{registry_queue_init, GlobalListContents};
1515 use wayland_client::protocol::wl_callback::WlCallback;
1616 use wayland_client::protocol::wl_output;
17−use wayland_client::protocol::wl_pointer::AxisRelativeDirection;
17+use wayland_client::protocol::wl_pointer::{AxisRelativeDirection, AxisSource};
1818 use wayland_client::{
1919 delegate_noop,
2020 protocol::{
@@ -64,6 +64,7 @@ pub(crate) struct WaylandClientStateInner { · 43 unmodified lines
6464 repeat: KeyRepeat,
6565 modifiers: Modifiers,
6666 scroll_direction: f64,
67+ axis_source: AxisSource,
6768 mouse_location: Option<Point<Pixels>>,
6869 button_pressed: Option<MouseButton>,
6970 mouse_focused_window: Option<Rc<WaylandWindowState>>,
@@ -97,9 +98,22 @@ pub(crate) struct WaylandClient { · 27 unmodified lines
9798 qh: Arc<QueueHandle<WaylandClientState>>,
9899 }
99100
100−const WL_SEAT_VERSION: u32 = 4;
101+const WL_SEAT_MIN_VERSION: u32 = 4;
101102 const WL_OUTPUT_VERSION: u32 = 2;
102103
104+fn wl_seat_version(version: u32) -> u32 {
105+ if version >= wl_pointer::EVT_AXIS_VALUE120_SINCE {
106+ wl_pointer::EVT_AXIS_VALUE120_SINCE
107+ } else if version >= WL_SEAT_MIN_VERSION {
108+ WL_SEAT_MIN_VERSION
109+ } else {
110+ panic!(
111+ "wl_seat below required version: {} < {}",
112+ version, WL_SEAT_MIN_VERSION
113+ );
114+ }
115+}
116+
103117 impl WaylandClient {
104118 pub(crate) fn new(linux_platform_inner: Rc<LinuxPlatformInner>) -> Self {
105119 let conn = Connection::connect_to_env().unwrap();
@@ -114,7 +128,7 @@ impl WaylandClient { · 8 unmodified lines
114128 "wl_seat" => {
115129 globals.registry().bind::<wl_seat::WlSeat, _, _>(
116130 global.name,
117− WL_SEAT_VERSION,
131+ wl_seat_version(global.version),
118132 &qh,
119133 (),
120134 );
@@ -163,6 +177,7 @@ impl WaylandClient { · 42 unmodified lines
163177 command: false,
164178 },
165179 scroll_direction: -1.0,
180+ axis_source: AxisSource::Wheel,
166181 mouse_location: None,
167182 button_pressed: None,
168183 mouse_focused_window: None,
@@ -325,10 +340,10 @@ impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for WaylandClientStat · 156 unmodified lines
325340 wl_registry::Event::Global {
326341 name,
327342 interface,
328− version: _,
343+ version,
329344 } => match &interface[..] {
330345 "wl_seat" => {
331− registry.bind::<wl_seat::WlSeat, _, _>(name, WL_SEAT_VERSION, qh, ());
346+ registry.bind::<wl_seat::WlSeat, _, _>(name, wl_seat_version(version), qh, ());
332347 }
333348 "wl_output" => {
334349 state.outputs.push((
@@ -914,12 +929,49 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientState { · 579 unmodified lines
914929 _ => -1.0,
915930 }
916931 }
932+ wl_pointer::Event::AxisSource {
933+ axis_source: WEnum::Value(axis_source),
934+ } => {
935+ state.axis_source = axis_source;
936+ }
937+ wl_pointer::Event::AxisValue120 {
938+ axis: WEnum::Value(axis),
939+ value120,
940+ } => {
941+ let focused_window = &state.mouse_focused_window;
942+ let mouse_location = &state.mouse_location;
943+ if let (Some(focused_window), Some(mouse_location)) =
944+ (focused_window, mouse_location)
945+ {
946+ let value = value120 as f64 * state.scroll_direction;
947+ focused_window.handle_input(PlatformInput::ScrollWheel(ScrollWheelEvent {
948+ position: *mouse_location,
949+ delta: match axis {
950+ wl_pointer::Axis::VerticalScroll => {
951+ ScrollDelta::Pixels(Point::new(Pixels(0.0), Pixels(value as f32)))
952+ }
953+ wl_pointer::Axis::HorizontalScroll => {
954+ ScrollDelta::Pixels(Point::new(Pixels(value as f32), Pixels(0.0)))
955+ }
956+ _ => unimplemented!(),
957+ },
958+ modifiers: state.modifiers,
959+ touch_phase: TouchPhase::Moved,
960+ }))
961+ }
962+ }
917963 wl_pointer::Event::Axis {
918964 time,
919965 axis: WEnum::Value(axis),
920966 value,
921967 ..
922968 } => {
969+ if wl_pointer.version() >= wl_pointer::EVT_AXIS_VALUE120_SINCE
970+ && state.axis_source != AxisSource::Continuous
971+ {
972+ return;
973+ }
974+
923975 let focused_window = &state.mouse_focused_window;
924976 let mouse_location = &state.mouse_location;
925977 if let (Some(focused_window), Some(mouse_location)) =
@@ -938,7 +990,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientState { · 12 unmodified lines
938990 _ => unimplemented!(),
939991 },
940992 modifiers: state.modifiers,
941− touch_phase: TouchPhase::Started,
993+ touch_phase: TouchPhase::Moved,
942994 }))
943995 }
944996 }
crates/gpui/src/platform/linux/x11/client.rs+5−4
@@ -23,7 +23,7 @@ use crate::{ · 22 unmodified lines
2323 ScrollDelta, Size, TouchPhase, WindowParams,
2424 };
2525
26−use super::{X11Display, X11Window, X11WindowState, XcbAtoms};
26+use super::{super::SCROLL_LINES, X11Display, X11Window, X11WindowState, XcbAtoms};
2727 use calloop::{
2828 generic::{FdWrapper, Generic},
2929 RegistrationToken,
@@ -221,12 +221,13 @@ impl X11Client { · 191 unmodified lines
221221 }));
222222 } else if event.detail >= 4 && event.detail <= 5 {
223223 // https://stackoverflow.com/questions/15510472/scrollwheel-event-in-x11
224− let delta_x = if event.detail == 4 { 1.0 } else { -1.0 };
224+ let scroll_direction = if event.detail == 4 { 1.0 } else { -1.0 };
225+ let scroll_y = SCROLL_LINES * scroll_direction;
225226 window.handle_input(PlatformInput::ScrollWheel(crate::ScrollWheelEvent {
226227 position,
227− delta: ScrollDelta::Lines(Point::new(0.0, delta_x)),
228+ delta: ScrollDelta::Lines(Point::new(0.0, scroll_y as f32)),
228229 modifiers,
229− touch_phase: TouchPhase::default(),
230+ touch_phase: TouchPhase::Moved,
230231 }));
231232 } else {
232233 log::warn!("Unknown button press: {event:?}");
crates/terminal/src/terminal.rs+3−0
@@ -70,7 +70,10 @@ actions!( · 69 unmodified lines
7070 ///Scrolling is unbearably sluggish by default. Alacritty supports a configurable
7171 ///Scroll multiplier that is set to 3 by default. This will be removed when I
7272 ///Implement scroll bars.
73+#[cfg(target_os = "macos")]
7374 const SCROLL_MULTIPLIER: f32 = 4.;
75+#[cfg(not(target_os = "macos"))]
76+const SCROLL_MULTIPLIER: f32 = 1.;
7477 const MAX_SEARCH_LINES: usize = 100;
7578 const DEBUG_TERMINAL_WIDTH: Pixels = px(500.);
7679 const DEBUG_TERMINAL_HEIGHT: Pixels = px(30.);