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
30 30
31use super::x11::X11Client;31use super::x11::X11Client;
32 32
33pub(super) const SCROLL_LINES: f64 = 3.0;
34
33#[derive(Default)]35#[derive(Default)]
34pub(crate) struct Callbacks {36pub(crate) struct Callbacks {
35 open_urls: Option<Box<dyn FnMut(Vec<String>)>>,37 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
14use wayland_client::globals::{registry_queue_init, GlobalListContents};14use wayland_client::globals::{registry_queue_init, GlobalListContents};
15use wayland_client::protocol::wl_callback::WlCallback;15use wayland_client::protocol::wl_callback::WlCallback;
16use wayland_client::protocol::wl_output;16use wayland_client::protocol::wl_output;
17use wayland_client::protocol::wl_pointer::AxisRelativeDirection;17use wayland_client::protocol::wl_pointer::{AxisRelativeDirection, AxisSource};
18use wayland_client::{18use wayland_client::{
19 delegate_noop,19 delegate_noop,
20 protocol::{20 protocol::{
@@ -64,6 +64,7 @@ pub(crate) struct WaylandClientStateInner { · 43 unmodified lines
64 repeat: KeyRepeat,64 repeat: KeyRepeat,
65 modifiers: Modifiers,65 modifiers: Modifiers,
66 scroll_direction: f64,66 scroll_direction: f64,
67 axis_source: AxisSource,
67 mouse_location: Option<Point<Pixels>>,68 mouse_location: Option<Point<Pixels>>,
68 button_pressed: Option<MouseButton>,69 button_pressed: Option<MouseButton>,
69 mouse_focused_window: Option<Rc<WaylandWindowState>>,70 mouse_focused_window: Option<Rc<WaylandWindowState>>,
@@ -97,9 +98,22 @@ pub(crate) struct WaylandClient { · 27 unmodified lines
97 qh: Arc<QueueHandle<WaylandClientState>>,98 qh: Arc<QueueHandle<WaylandClientState>>,
98}99}
99 100
100const WL_SEAT_VERSION: u32 = 4;101const WL_SEAT_MIN_VERSION: u32 = 4;
101const WL_OUTPUT_VERSION: u32 = 2;102const WL_OUTPUT_VERSION: u32 = 2;
102 103
104fn 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
103impl WaylandClient {117impl WaylandClient {
104 pub(crate) fn new(linux_platform_inner: Rc<LinuxPlatformInner>) -> Self {118 pub(crate) fn new(linux_platform_inner: Rc<LinuxPlatformInner>) -> Self {
105 let conn = Connection::connect_to_env().unwrap();119 let conn = Connection::connect_to_env().unwrap();
@@ -114,7 +128,7 @@ impl WaylandClient { · 8 unmodified lines
114 "wl_seat" => {128 "wl_seat" => {
115 globals.registry().bind::<wl_seat::WlSeat, _, _>(129 globals.registry().bind::<wl_seat::WlSeat, _, _>(
116 global.name,130 global.name,
117 WL_SEAT_VERSION,131 wl_seat_version(global.version),
118 &qh,132 &qh,
119 (),133 (),
120 );134 );
@@ -163,6 +177,7 @@ impl WaylandClient { · 42 unmodified lines
163 command: false,177 command: false,
164 },178 },
165 scroll_direction: -1.0,179 scroll_direction: -1.0,
180 axis_source: AxisSource::Wheel,
166 mouse_location: None,181 mouse_location: None,
167 button_pressed: None,182 button_pressed: None,
168 mouse_focused_window: None,183 mouse_focused_window: None,
@@ -325,10 +340,10 @@ impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for WaylandClientStat · 156 unmodified lines
325 wl_registry::Event::Global {340 wl_registry::Event::Global {
326 name,341 name,
327 interface,342 interface,
328 version: _,343 version,
329 } => match &interface[..] {344 } => match &interface[..] {
330 "wl_seat" => {345 "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, ());
332 }347 }
333 "wl_output" => {348 "wl_output" => {
334 state.outputs.push((349 state.outputs.push((
@@ -914,12 +929,49 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientState { · 579 unmodified lines
914 _ => -1.0,929 _ => -1.0,
915 }930 }
916 }931 }
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 }
917 wl_pointer::Event::Axis {963 wl_pointer::Event::Axis {
918 time,964 time,
919 axis: WEnum::Value(axis),965 axis: WEnum::Value(axis),
920 value,966 value,
921 ..967 ..
922 } => {968 } => {
969 if wl_pointer.version() >= wl_pointer::EVT_AXIS_VALUE120_SINCE
970 && state.axis_source != AxisSource::Continuous
971 {
972 return;
973 }
974
923 let focused_window = &state.mouse_focused_window;975 let focused_window = &state.mouse_focused_window;
924 let mouse_location = &state.mouse_location;976 let mouse_location = &state.mouse_location;
925 if let (Some(focused_window), Some(mouse_location)) =977 if let (Some(focused_window), Some(mouse_location)) =
@@ -938,7 +990,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientState { · 12 unmodified lines
938 _ => unimplemented!(),990 _ => unimplemented!(),
939 },991 },
940 modifiers: state.modifiers,992 modifiers: state.modifiers,
941 touch_phase: TouchPhase::Started,993 touch_phase: TouchPhase::Moved,
942 }))994 }))
943 }995 }
944 }996 }
crates/gpui/src/platform/linux/x11/client.rs+5−4
@@ -23,7 +23,7 @@ use crate::{ · 22 unmodified lines
23 ScrollDelta, Size, TouchPhase, WindowParams,23 ScrollDelta, Size, TouchPhase, WindowParams,
24};24};
25 25
26use super::{X11Display, X11Window, X11WindowState, XcbAtoms};26use super::{super::SCROLL_LINES, X11Display, X11Window, X11WindowState, XcbAtoms};
27use calloop::{27use calloop::{
28 generic::{FdWrapper, Generic},28 generic::{FdWrapper, Generic},
29 RegistrationToken,29 RegistrationToken,
@@ -221,12 +221,13 @@ impl X11Client { · 191 unmodified lines
221 }));221 }));
222 } else if event.detail >= 4 && event.detail <= 5 {222 } else if event.detail >= 4 && event.detail <= 5 {
223 // https://stackoverflow.com/questions/15510472/scrollwheel-event-in-x11223 // 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;
225 window.handle_input(PlatformInput::ScrollWheel(crate::ScrollWheelEvent {226 window.handle_input(PlatformInput::ScrollWheel(crate::ScrollWheelEvent {
226 position,227 position,
227 delta: ScrollDelta::Lines(Point::new(0.0, delta_x)),228 delta: ScrollDelta::Lines(Point::new(0.0, scroll_y as f32)),
228 modifiers,229 modifiers,
229 touch_phase: TouchPhase::default(),230 touch_phase: TouchPhase::Moved,
230 }));231 }));
231 } else {232 } else {
232 log::warn!("Unknown button press: {event:?}");233 log::warn!("Unknown button press: {event:?}");
crates/terminal/src/terminal.rs+3−0
@@ -70,7 +70,10 @@ actions!( · 69 unmodified lines
70///Scrolling is unbearably sluggish by default. Alacritty supports a configurable70///Scrolling is unbearably sluggish by default. Alacritty supports a configurable
71///Scroll multiplier that is set to 3 by default. This will be removed when I71///Scroll multiplier that is set to 3 by default. This will be removed when I
72///Implement scroll bars.72///Implement scroll bars.
73#[cfg(target_os = "macos")]
73const SCROLL_MULTIPLIER: f32 = 4.;74const SCROLL_MULTIPLIER: f32 = 4.;
75#[cfg(not(target_os = "macos"))]
76const SCROLL_MULTIPLIER: f32 = 1.;
74const MAX_SEARCH_LINES: usize = 100;77const MAX_SEARCH_LINES: usize = 100;
75const DEBUG_TERMINAL_WIDTH: Pixels = px(500.);78const DEBUG_TERMINAL_WIDTH: Pixels = px(500.);
76const DEBUG_TERMINAL_HEIGHT: Pixels = px(30.);79const DEBUG_TERMINAL_HEIGHT: Pixels = px(30.);