From 53dc2e7218955231b26574bbc7e47b78f52b0f46 Mon Sep 17 00:00:00 2001 From: drendog Date: Mon, 22 Dec 2025 09:39:10 +0100 Subject: [PATCH] feat: pointer scroll events --- .../wayland/event_handling/app_dispatcher.rs | 27 +++++++++ .../event_handling/event_dispatcher.rs | 28 ++++++++++ .../src/wayland/surfaces/event_context.rs | 56 ++++++++++++++++++- .../src/wayland/surfaces/surface_state.rs | 23 +++++++- 4 files changed, 132 insertions(+), 2 deletions(-) diff --git a/crates/adapters/src/wayland/event_handling/app_dispatcher.rs b/crates/adapters/src/wayland/event_handling/app_dispatcher.rs index a0f8254..a332726 100644 --- a/crates/adapters/src/wayland/event_handling/app_dispatcher.rs +++ b/crates/adapters/src/wayland/event_handling/app_dispatcher.rs @@ -243,6 +243,33 @@ impl Dispatch for AppState { surface.handle_pointer_button(serial, button_state); } } + wl_pointer::Event::AxisSource { axis_source } => { + if let (Some(surface), WEnum::Value(axis_source)) = + (state.active_surface_mut(), axis_source) + { + surface.handle_axis_source(axis_source); + } + } + wl_pointer::Event::Axis { time, axis, value } => { + if let (Some(surface), WEnum::Value(axis)) = (state.active_surface_mut(), axis) { + surface.handle_axis(time, axis, value); + } + } + wl_pointer::Event::AxisDiscrete { axis, discrete } => { + if let (Some(surface), WEnum::Value(axis)) = (state.active_surface_mut(), axis) { + surface.handle_axis_discrete(axis, discrete); + } + } + wl_pointer::Event::AxisStop { time, axis } => { + if let (Some(surface), WEnum::Value(axis)) = (state.active_surface_mut(), axis) { + surface.handle_axis_stop(time, axis); + } + } + wl_pointer::Event::Frame => { + if let Some(surface) = state.active_surface_mut() { + surface.handle_pointer_frame(); + } + } _ => {} } } diff --git a/crates/adapters/src/wayland/event_handling/event_dispatcher.rs b/crates/adapters/src/wayland/event_handling/event_dispatcher.rs index 1685891..a29e57d 100644 --- a/crates/adapters/src/wayland/event_handling/event_dispatcher.rs +++ b/crates/adapters/src/wayland/event_handling/event_dispatcher.rs @@ -138,6 +138,34 @@ impl SurfaceState { self.dispatch_to_active_window(event); } + pub(crate) fn handle_axis_source(&mut self, axis_source: wl_pointer::AxisSource) { + self.set_axis_source(axis_source); + } + + pub(crate) fn handle_axis(&mut self, _time: u32, axis: wl_pointer::Axis, value: f64) { + self.accumulate_axis(axis, value); + } + + pub(crate) fn handle_axis_discrete(&mut self, axis: wl_pointer::Axis, discrete: i32) { + self.accumulate_axis_discrete(axis, discrete); + } + + #[allow(clippy::unused_self)] + pub(crate) fn handle_axis_stop(&mut self, _time: u32, _axis: wl_pointer::Axis) {} + + pub(crate) fn handle_pointer_frame(&mut self) { + let (delta_x, delta_y) = self.take_accumulated_axis(); + + if delta_x.abs() > f32::EPSILON || delta_y.abs() > f32::EPSILON { + let position = self.current_pointer_position(); + self.dispatch_to_active_window(WindowEvent::PointerScrolled { + position, + delta_x, + delta_y, + }); + } + } + pub(crate) fn handle_fractional_scale(&mut self, proxy: &WpFractionalScaleV1, scale: u32) { use crate::wayland::surfaces::display_metrics::DisplayMetrics; let scale_float = DisplayMetrics::scale_factor_from_120ths(scale); diff --git a/crates/adapters/src/wayland/surfaces/event_context.rs b/crates/adapters/src/wayland/surfaces/event_context.rs index 845516e..8e81984 100644 --- a/crates/adapters/src/wayland/surfaces/event_context.rs +++ b/crates/adapters/src/wayland/surfaces/event_context.rs @@ -5,7 +5,11 @@ use slint::platform::{WindowAdapter, WindowEvent}; use slint::{LogicalPosition, PhysicalSize}; use std::cell::Cell; use std::rc::Rc; -use wayland_client::{Proxy, backend::ObjectId, protocol::wl_surface::WlSurface}; +use wayland_client::{ + Proxy, + backend::ObjectId, + protocol::{wl_pointer, wl_surface::WlSurface}, +}; use wayland_protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1; pub struct SharedPointerSerial { @@ -43,6 +47,9 @@ pub struct EventContext { last_pointer_serial: u32, shared_pointer_serial: Option>, active_surface: ActiveWindow, + accumulated_axis_x: f32, + accumulated_axis_y: f32, + axis_source: Option, } impl EventContext { @@ -61,6 +68,9 @@ impl EventContext { last_pointer_serial: 0, shared_pointer_serial: None, active_surface: ActiveWindow::None, + accumulated_axis_x: 0.0, + accumulated_axis_y: 0.0, + axis_source: None, } } @@ -157,6 +167,7 @@ impl EventContext { WindowEvent::PointerMoved { .. } | WindowEvent::PointerPressed { .. } | WindowEvent::PointerReleased { .. } + | WindowEvent::PointerScrolled { .. } ); if let Some(popup_manager) = &self.popup_manager { @@ -188,4 +199,47 @@ impl EventContext { .update_scale_for_fractional_scale_object(fractional_scale_proxy, scale_120ths); } } + + pub fn set_axis_source(&mut self, axis_source: wl_pointer::AxisSource) { + self.axis_source = Some(axis_source); + } + + #[allow(clippy::cast_possible_truncation)] + pub fn accumulate_axis(&mut self, axis: wl_pointer::Axis, value: f64) { + match axis { + wl_pointer::Axis::HorizontalScroll => { + self.accumulated_axis_x += value as f32; + } + wl_pointer::Axis::VerticalScroll => { + self.accumulated_axis_y += value as f32; + } + _ => {} + } + } + + #[allow(clippy::cast_precision_loss)] + pub fn accumulate_axis_discrete(&mut self, axis: wl_pointer::Axis, discrete: i32) { + let delta = discrete as f32 * 60.0; + + match axis { + wl_pointer::Axis::HorizontalScroll => { + self.accumulated_axis_x += delta; + } + wl_pointer::Axis::VerticalScroll => { + self.accumulated_axis_y += delta; + } + _ => {} + } + } + + pub fn take_accumulated_axis(&mut self) -> (f32, f32) { + let delta_x = self.accumulated_axis_x; + let delta_y = self.accumulated_axis_y; + + self.accumulated_axis_x = 0.0; + self.accumulated_axis_y = 0.0; + self.axis_source = None; + + (delta_x, delta_y) + } } diff --git a/crates/adapters/src/wayland/surfaces/surface_state.rs b/crates/adapters/src/wayland/surfaces/surface_state.rs index 0b1251c..ac37901 100644 --- a/crates/adapters/src/wayland/surfaces/surface_state.rs +++ b/crates/adapters/src/wayland/surfaces/surface_state.rs @@ -20,7 +20,10 @@ use slint::{LogicalPosition, PhysicalSize}; use slint::platform::WindowEvent; use slint_interpreter::{ComponentInstance, CompilationResult}; use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1; -use wayland_client::{protocol::wl_surface::WlSurface, Proxy}; +use wayland_client::{ + Proxy, + protocol::{wl_pointer, wl_surface::WlSurface}, +}; use wayland_protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1; pub struct SurfaceState { @@ -272,6 +275,24 @@ impl SurfaceState { self.event_context.borrow().dispatch_to_active_window(event); } + pub fn set_axis_source(&self, axis_source: wl_pointer::AxisSource) { + self.event_context.borrow_mut().set_axis_source(axis_source); + } + + pub fn accumulate_axis(&self, axis: wl_pointer::Axis, value: f64) { + self.event_context.borrow_mut().accumulate_axis(axis, value); + } + + pub fn accumulate_axis_discrete(&self, axis: wl_pointer::Axis, discrete: i32) { + self.event_context + .borrow_mut() + .accumulate_axis_discrete(axis, discrete); + } + + pub fn take_accumulated_axis(&self) -> (f32, f32) { + self.event_context.borrow_mut().take_accumulated_axis() + } + #[allow(clippy::cast_precision_loss)] pub fn update_scale_for_fractional_scale_object( &mut self,