mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-28 21:32:39 +00:00
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
This commit is contained in:
parent
c0f8581b29
commit
d8e32c3e3c
4 changed files with 68 additions and 10 deletions
|
@ -30,6 +30,8 @@ use crate::{
|
||||||
|
|
||||||
use super::x11::X11Client;
|
use super::x11::X11Client;
|
||||||
|
|
||||||
|
pub(super) const SCROLL_LINES: f64 = 3.0;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct Callbacks {
|
pub(crate) struct Callbacks {
|
||||||
open_urls: Option<Box<dyn FnMut(Vec<String>)>>,
|
open_urls: Option<Box<dyn FnMut(Vec<String>)>>,
|
||||||
|
|
|
@ -14,7 +14,7 @@ use wayland_backend::protocol::WEnum;
|
||||||
use wayland_client::globals::{registry_queue_init, GlobalListContents};
|
use wayland_client::globals::{registry_queue_init, GlobalListContents};
|
||||||
use wayland_client::protocol::wl_callback::WlCallback;
|
use wayland_client::protocol::wl_callback::WlCallback;
|
||||||
use wayland_client::protocol::wl_output;
|
use wayland_client::protocol::wl_output;
|
||||||
use wayland_client::protocol::wl_pointer::AxisRelativeDirection;
|
use wayland_client::protocol::wl_pointer::{AxisRelativeDirection, AxisSource};
|
||||||
use wayland_client::{
|
use wayland_client::{
|
||||||
delegate_noop,
|
delegate_noop,
|
||||||
protocol::{
|
protocol::{
|
||||||
|
@ -64,6 +64,7 @@ pub(crate) struct WaylandClientStateInner {
|
||||||
repeat: KeyRepeat,
|
repeat: KeyRepeat,
|
||||||
modifiers: Modifiers,
|
modifiers: Modifiers,
|
||||||
scroll_direction: f64,
|
scroll_direction: f64,
|
||||||
|
axis_source: AxisSource,
|
||||||
mouse_location: Option<Point<Pixels>>,
|
mouse_location: Option<Point<Pixels>>,
|
||||||
button_pressed: Option<MouseButton>,
|
button_pressed: Option<MouseButton>,
|
||||||
mouse_focused_window: Option<Rc<WaylandWindowState>>,
|
mouse_focused_window: Option<Rc<WaylandWindowState>>,
|
||||||
|
@ -97,9 +98,22 @@ pub(crate) struct WaylandClient {
|
||||||
qh: Arc<QueueHandle<WaylandClientState>>,
|
qh: Arc<QueueHandle<WaylandClientState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const WL_SEAT_VERSION: u32 = 4;
|
const WL_SEAT_MIN_VERSION: u32 = 4;
|
||||||
const WL_OUTPUT_VERSION: u32 = 2;
|
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 {
|
impl WaylandClient {
|
||||||
pub(crate) fn new(linux_platform_inner: Rc<LinuxPlatformInner>) -> Self {
|
pub(crate) fn new(linux_platform_inner: Rc<LinuxPlatformInner>) -> Self {
|
||||||
let conn = Connection::connect_to_env().unwrap();
|
let conn = Connection::connect_to_env().unwrap();
|
||||||
|
@ -114,7 +128,7 @@ impl WaylandClient {
|
||||||
"wl_seat" => {
|
"wl_seat" => {
|
||||||
globals.registry().bind::<wl_seat::WlSeat, _, _>(
|
globals.registry().bind::<wl_seat::WlSeat, _, _>(
|
||||||
global.name,
|
global.name,
|
||||||
WL_SEAT_VERSION,
|
wl_seat_version(global.version),
|
||||||
&qh,
|
&qh,
|
||||||
(),
|
(),
|
||||||
);
|
);
|
||||||
|
@ -163,6 +177,7 @@ impl WaylandClient {
|
||||||
command: false,
|
command: false,
|
||||||
},
|
},
|
||||||
scroll_direction: -1.0,
|
scroll_direction: -1.0,
|
||||||
|
axis_source: AxisSource::Wheel,
|
||||||
mouse_location: None,
|
mouse_location: None,
|
||||||
button_pressed: None,
|
button_pressed: None,
|
||||||
mouse_focused_window: None,
|
mouse_focused_window: None,
|
||||||
|
@ -325,10 +340,10 @@ impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for WaylandClientStat
|
||||||
wl_registry::Event::Global {
|
wl_registry::Event::Global {
|
||||||
name,
|
name,
|
||||||
interface,
|
interface,
|
||||||
version: _,
|
version,
|
||||||
} => match &interface[..] {
|
} => match &interface[..] {
|
||||||
"wl_seat" => {
|
"wl_seat" => {
|
||||||
registry.bind::<wl_seat::WlSeat, _, _>(name, WL_SEAT_VERSION, qh, ());
|
registry.bind::<wl_seat::WlSeat, _, _>(name, wl_seat_version(version), qh, ());
|
||||||
}
|
}
|
||||||
"wl_output" => {
|
"wl_output" => {
|
||||||
state.outputs.push((
|
state.outputs.push((
|
||||||
|
@ -914,12 +929,49 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientState {
|
||||||
_ => -1.0,
|
_ => -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 {
|
wl_pointer::Event::Axis {
|
||||||
time,
|
time,
|
||||||
axis: WEnum::Value(axis),
|
axis: WEnum::Value(axis),
|
||||||
value,
|
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 focused_window = &state.mouse_focused_window;
|
||||||
let mouse_location = &state.mouse_location;
|
let mouse_location = &state.mouse_location;
|
||||||
if let (Some(focused_window), Some(mouse_location)) =
|
if let (Some(focused_window), Some(mouse_location)) =
|
||||||
|
@ -938,7 +990,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientState {
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
},
|
},
|
||||||
modifiers: state.modifiers,
|
modifiers: state.modifiers,
|
||||||
touch_phase: TouchPhase::Started,
|
touch_phase: TouchPhase::Moved,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ use crate::{
|
||||||
ScrollDelta, Size, TouchPhase, WindowParams,
|
ScrollDelta, Size, TouchPhase, WindowParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{X11Display, X11Window, X11WindowState, XcbAtoms};
|
use super::{super::SCROLL_LINES, X11Display, X11Window, X11WindowState, XcbAtoms};
|
||||||
use calloop::{
|
use calloop::{
|
||||||
generic::{FdWrapper, Generic},
|
generic::{FdWrapper, Generic},
|
||||||
RegistrationToken,
|
RegistrationToken,
|
||||||
|
@ -221,12 +221,13 @@ impl X11Client {
|
||||||
}));
|
}));
|
||||||
} else if event.detail >= 4 && event.detail <= 5 {
|
} else if event.detail >= 4 && event.detail <= 5 {
|
||||||
// https://stackoverflow.com/questions/15510472/scrollwheel-event-in-x11
|
// 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 {
|
window.handle_input(PlatformInput::ScrollWheel(crate::ScrollWheelEvent {
|
||||||
position,
|
position,
|
||||||
delta: ScrollDelta::Lines(Point::new(0.0, delta_x)),
|
delta: ScrollDelta::Lines(Point::new(0.0, scroll_y as f32)),
|
||||||
modifiers,
|
modifiers,
|
||||||
touch_phase: TouchPhase::default(),
|
touch_phase: TouchPhase::Moved,
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Unknown button press: {event:?}");
|
log::warn!("Unknown button press: {event:?}");
|
||||||
|
|
|
@ -70,7 +70,10 @@ actions!(
|
||||||
///Scrolling is unbearably sluggish by default. Alacritty supports a configurable
|
///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
|
///Scroll multiplier that is set to 3 by default. This will be removed when I
|
||||||
///Implement scroll bars.
|
///Implement scroll bars.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
const SCROLL_MULTIPLIER: f32 = 4.;
|
const SCROLL_MULTIPLIER: f32 = 4.;
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
const SCROLL_MULTIPLIER: f32 = 1.;
|
||||||
const MAX_SEARCH_LINES: usize = 100;
|
const MAX_SEARCH_LINES: usize = 100;
|
||||||
const DEBUG_TERMINAL_WIDTH: Pixels = px(500.);
|
const DEBUG_TERMINAL_WIDTH: Pixels = px(500.);
|
||||||
const DEBUG_TERMINAL_HEIGHT: Pixels = px(30.);
|
const DEBUG_TERMINAL_HEIGHT: Pixels = px(30.);
|
||||||
|
|
Loading…
Reference in a new issue