diff --git a/examples/udev.rs b/examples/udev.rs index d51e28f..64c9255 100644 --- a/examples/udev.rs +++ b/examples/udev.rs @@ -193,7 +193,24 @@ impl InputHandler for LibinputInputHandler { input::Axis::Vertical => wayland_server::protocol::wl_pointer::Axis::VerticalScroll, input::Axis::Horizontal => wayland_server::protocol::wl_pointer::Axis::HorizontalScroll, }; - self.pointer.axis(axis, evt.amount(), evt.time()); + let source = match evt.source() { + input::AxisSource::Continuous | input::AxisSource::Finger => wayland_server::protocol::wl_pointer::AxisSource::Continuous, + input::AxisSource::Wheel | input::AxisSource::WheelTilt => wayland_server::protocol::wl_pointer::AxisSource::Wheel, + }; + let amount = match evt.source() { + input::AxisSource::Continuous | input::AxisSource::Finger => evt.amount(), + input::AxisSource::Wheel | input::AxisSource::WheelTilt => evt.amount() * 3.0, // amount represents steps in that case, + }; + + { + let mut event = self.pointer.axis(); + event.source(source) + .value(axis, amount, evt.time()); + if let input::AxisSource::Wheel = evt.source() { + event.discrete(axis, evt.amount() as i32); + } + // drop and submit the axis event + } } fn on_touch_down( &mut self, _evlh: &mut EventLoopHandle, _: &input::Seat, _: event::touch::TouchDownEvent diff --git a/examples/winit.rs b/examples/winit.rs index e27af60..1ad24b7 100644 --- a/examples/winit.rs +++ b/examples/winit.rs @@ -112,7 +112,26 @@ impl InputHandler for WinitInputHandler { input::Axis::Vertical => wayland_server::protocol::wl_pointer::Axis::VerticalScroll, input::Axis::Horizontal => wayland_server::protocol::wl_pointer::Axis::HorizontalScroll, }; - self.pointer.axis(axis, evt.amount(), evt.time()); + let source = match evt.source() { + input::AxisSource::Continuous => wayland_server::protocol::wl_pointer::AxisSource::Continuous, + input::AxisSource::Wheel => wayland_server::protocol::wl_pointer::AxisSource::Wheel, + _ => unreachable!(), //winit does not have more specific sources + }; + let amount = match evt.source() { + input::AxisSource::Continuous => evt.amount(), + input::AxisSource::Wheel => evt.amount() * 3.0, // amount represents steps in that case, + _ => unreachable!(), //winit does not have more specific sources + }; + + { + let mut event = self.pointer.axis(); + event.source(source) + .value(axis, amount, evt.time()); + if let input::AxisSource::Wheel = evt.source() { + event.discrete(axis, evt.amount() as i32); + } + // drop and submit the axis event + } } fn on_touch_down( &mut self, _evlh: &mut EventLoopHandle, _: &input::Seat, _: winit::WinitTouchStartedEvent diff --git a/src/wayland/seat/mod.rs b/src/wayland/seat/mod.rs index 5fc6b2e..5b484a9 100644 --- a/src/wayland/seat/mod.rs +++ b/src/wayland/seat/mod.rs @@ -102,8 +102,7 @@ impl Seat { known_seats: Vec::new(), }; let token = evlh.state().insert(seat); - // TODO: support version 5 (axis) - let global = evlh.register_global(4, seat_global_bind, token.clone()); + let global = evlh.register_global(5, seat_global_bind, token.clone()); (token, global) } diff --git a/src/wayland/seat/pointer.rs b/src/wayland/seat/pointer.rs index 7fa87a6..5fde17a 100644 --- a/src/wayland/seat/pointer.rs +++ b/src/wayland/seat/pointer.rs @@ -1,4 +1,4 @@ -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, MutexGuard}; use wayland_server::{Liveness, Resource}; use wayland_server::protocol::{wl_pointer, wl_surface}; @@ -73,6 +73,7 @@ impl PointerHandle { if leave { guard.with_focused_pointers(|pointer, surface| { pointer.leave(serial, surface); + pointer.frame(); }); guard.focus = None; } @@ -83,11 +84,13 @@ impl PointerHandle { guard.focus = surface.clone(); guard.with_focused_pointers(|pointer, surface| { pointer.enter(serial, surface, x, y); + pointer.frame(); }) } else { // we were on top of a surface and remained on it guard.with_focused_pointers(|pointer, _| { pointer.motion(time, x, y); + pointer.frame(); }) } } @@ -101,15 +104,18 @@ impl PointerHandle { let guard = self.inner.lock().unwrap(); guard.with_focused_pointers(|pointer, _| { pointer.button(serial, time, button, state); + pointer.frame(); }) } - /// send axis events - pub fn axis(&self, axis: wl_pointer::Axis, value: f64, time: u32) { - let guard = self.inner.lock().unwrap(); - guard.with_focused_pointers(|pointer, _| { - pointer.axis(time, axis, value); - }) + /// Start an axis frame + /// + /// A single frame will group multiple scroll events as if they happended in the same instance. + /// Dropping the returned `PointerAxisHandle` will group the events together. + pub fn axis<'a>(&'a self) -> PointerAxisHandle<'a> { + PointerAxisHandle { + inner: self.inner.lock().unwrap(), + } } pub(crate) fn cleanup_old_pointers(&self) { @@ -120,6 +126,76 @@ impl PointerHandle { } } +/// A frame of pointer axis events. +/// +/// Can be used with the builder pattern, e.g.: +/// ```ignore +/// pointer.axis() +/// .source(AxisSource::Wheel) +/// .discrete(Axis::Vertical, 6) +/// .value(Axis::Vertical, 30, time) +/// .stop(Axis::Vertical); +/// ``` +pub struct PointerAxisHandle<'a> { + inner: MutexGuard<'a, PointerInternal> +} + +impl<'a> PointerAxisHandle<'a> { + /// Specify the source of the axis events + /// + /// This event is optional, if no source is known, you can ignore this call. + /// Only one source event is allowed per frame. + /// + /// Using the `AxisSource::Finger` requires a stop event to be send, + /// when the user lifts off the finger (not necessarily in the same frame). + pub fn source(&mut self, source: wl_pointer::AxisSource) -> &mut Self { + self.inner.with_focused_pointers(|pointer, _| { + pointer.axis_source(source); + }); + self + } + + /// Specify discrete scrolling steps additionally to the computed value. + /// + /// This event is optional and gives the client additional information about + /// the nature of the axis event. E.g. a scroll wheel might issue separate steps, + /// while a touchpad may never issue this event as it has no steps. + pub fn discrete(&mut self, axis: wl_pointer::Axis, steps: i32) -> &mut Self { + self.inner.with_focused_pointers(|pointer, _| { + pointer.axis_discrete(axis, steps); + }); + self + } + + /// The actual scroll value. This event is the only required one, but can also + /// be send multiple times. The values off one frame will be accumulated by the client. + pub fn value(&mut self, axis: wl_pointer::Axis, value: f64, time: u32) -> &mut Self { + self.inner.with_focused_pointers(|pointer, _| { + pointer.axis(time, axis, value); + }); + self + } + + /// Notification of stop of scrolling on an axis. + /// + /// This event is required for sources of the `AxisSource::Finger` type + /// and otherwise optional. + pub fn stop(&mut self, axis: wl_pointer::Axis, time: u32) -> &mut Self { + self.inner.with_focused_pointers(|pointer, _| { + pointer.axis_stop(time, axis); + }); + self + } +} + +impl<'a> Drop for PointerAxisHandle<'a> { + fn drop(&mut self) { + self.inner.with_focused_pointers(|pointer, _| { + pointer.frame(); + }) + } +} + pub(crate) fn create_pointer_handler() -> PointerHandle { PointerHandle { inner: Arc::new(Mutex::new(PointerInternal::new())),