<NME> pointer.rs
<BEF> use std::sync::{Arc, Mutex};
use wayland_server::{Liveness, Resource};
use wayland_server::protocol::{wl_pointer, wl_surface};

    protocol::{
        wl_pointer::{
            self, Axis as WlAxis, AxisSource as WlAxisSource, ButtonState as WlButtonState, Request,
            WlPointer,
        },
        wl_surface::WlSurface,
    },
    Dispatch, DisplayHandle, Resource,
};

use crate::{
    backend::input::{Axis, AxisSource, ButtonState},
    input::{
        pointer::{
            AxisFrame, ButtonEvent, CursorImageAttributes, CursorImageStatus, MotionEvent, PointerHandle,
            PointerInternal, PointerTarget,
        },
        Seat,
    },
    utils::Serial,
    wayland::compositor,
};

use super::{SeatHandler, SeatState, WaylandFocus};

impl<D: SeatHandler> PointerHandle<D> {
    pub(crate) fn new_pointer(&self, pointer: WlPointer) {
        let mut guard = self.known_pointers.lock().unwrap();
        guard.push(pointer);
    }
}

/// WlSurface role of a cursor image icon
pub const CURSOR_IMAGE_ROLE: &str = "cursor_image";

fn for_each_focused_pointers<D: SeatHandler + 'static>(
    seat: &Seat<D>,
    surface: &WlSurface,
    mut f: impl FnMut(WlPointer),
) {
    if let Some(pointer) = seat.get_pointer() {
        let inner = pointer.known_pointers.lock().unwrap();
        for ptr in &*inner {
            if ptr.id().same_client_as(&surface.id()) {
                f(ptr.clone())
            }
        }
    }
}

#[cfg(feature = "wayland_frontend")]
impl<D> PointerTarget<D> for WlSurface
where
    D: SeatHandler + 'static,
{
    fn enter(&self, seat: &Seat<D>, _data: &mut D, event: &MotionEvent) {
        for_each_focused_pointers(seat, self, |ptr| {
            ptr.enter(event.serial.into(), self, event.location.x, event.location.y);
            if ptr.version() >= 5 {
                ptr.frame();
            }
        })
    }
    fn leave(&self, seat: &Seat<D>, _data: &mut D, serial: Serial, _time: u32) {
        for_each_focused_pointers(seat, self, |ptr| {
            ptr.leave(serial.into(), self);
            if ptr.version() >= 5 {
                ptr.frame();
        if leave {
            guard.with_focused_pointers(|pointer, surface| {
                pointer.leave(serial, surface);
            });
            guard.focus = None;
        }
        })
    }
    fn button(&self, seat: &Seat<D>, _data: &mut D, event: &ButtonEvent) {
        for_each_focused_pointers(seat, self, |ptr| {
                guard.focus = surface.clone();
                guard.with_focused_pointers(|pointer, surface| {
                    pointer.enter(serial, surface, x, y);
                })
            } else {
                // we were on top of a surface and remained on it
                guard.with_focused_pointers(|pointer, _| {
                    pointer.motion(time, x, y);
                })
            }
        }
                if let Some(source) = details.source {
                    // WheelTilt was not supported before version 6
                    // The best we can do is replace it with Wheel
                    let source = if ptr.version() < 6 {
                        match source {
                            AxisSource::WheelTilt => AxisSource::Wheel,
                            other => other,
        let guard = self.inner.lock().unwrap();
        guard.with_focused_pointers(|pointer, _| {
            pointer.button(serial, time, button, state);
        })
    }

    /// 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);
        })
    }

    pub(crate) fn cleanup_old_pointers(&self) {
                }
                // frame
                ptr.frame();
            }
    }
}

pub(crate) fn create_pointer_handler() -> PointerHandle {
    PointerHandle {
        inner: Arc::new(Mutex::new(PointerInternal::new())),
                                        state.cursor_image(&seat, CursorImageStatus::Surface(surface));
                                    }
                                }
                                None => {
                                    if let Some(seat) = seat {
                                        state.cursor_image(&seat, CursorImageStatus::Hidden);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            Request::Release => {
                // Our destructors already handle it
            }
            _ => unreachable!(),
        }
    }

    fn destroyed(_state: &mut D, _: ClientId, object_id: ObjectId, data: &PointerUserData<D>) {
        if let Some(ref handle) = data.handle {
            handle
                .known_pointers
                .lock()
                .unwrap()
                .retain(|p| p.id() != object_id);
        }
    }
}

impl From<Axis> for WlAxis {
    fn from(axis: Axis) -> WlAxis {
        match axis {
            Axis::Horizontal => WlAxis::HorizontalScroll,
            Axis::Vertical => WlAxis::VerticalScroll,
        }
    }
}

#[derive(Debug, thiserror::Error)]
#[error("Unknown Axis {0:?}")]
pub struct UnknownAxis(WlAxis);

impl TryFrom<WlAxis> for Axis {
    type Error = UnknownAxis;
    fn try_from(value: WlAxis) -> Result<Self, Self::Error> {
        match value {
            WlAxis::HorizontalScroll => Ok(Axis::Horizontal),
            WlAxis::VerticalScroll => Ok(Axis::Vertical),
            x => Err(UnknownAxis(x)),
        }
    }
}

impl From<AxisSource> for WlAxisSource {
    fn from(axis: AxisSource) -> WlAxisSource {
        match axis {
            AxisSource::Wheel => WlAxisSource::Wheel,
            AxisSource::Finger => WlAxisSource::Finger,
            AxisSource::Continuous => WlAxisSource::Continuous,
            AxisSource::WheelTilt => WlAxisSource::WheelTilt,
        }
    }
}

impl From<ButtonState> for WlButtonState {
    fn from(state: ButtonState) -> WlButtonState {
        match state {
            ButtonState::Pressed => WlButtonState::Pressed,
            ButtonState::Released => WlButtonState::Released,
        }
    }
}

#[derive(Debug, thiserror::Error)]
#[error("Unknown ButtonState {0:?}")]
pub struct UnknownButtonState(WlButtonState);

impl TryFrom<WlButtonState> for ButtonState {
    type Error = UnknownButtonState;
    fn try_from(value: WlButtonState) -> Result<Self, Self::Error> {
        match value {
            WlButtonState::Pressed => Ok(ButtonState::Pressed),
            WlButtonState::Released => Ok(ButtonState::Released),
            x => Err(UnknownButtonState(x)),
        }
    }
}

<MSG> Merge pull request #83 from Smithay/feature/wl_seat_v5

Upgrade to wl_seat version 5
<DFF> @@ -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,9 @@ impl PointerHandle {
         if leave {
             guard.with_focused_pointers(|pointer, surface| {
                 pointer.leave(serial, surface);
+                if pointer.version() >= 5 {
+                    pointer.frame();
+                }
             });
             guard.focus = None;
         }
@@ -83,11 +86,17 @@ impl PointerHandle {
                 guard.focus = surface.clone();
                 guard.with_focused_pointers(|pointer, surface| {
                     pointer.enter(serial, surface, x, y);
+                    if pointer.version() >= 5 {
+                        pointer.frame();
+                    }
                 })
             } else {
                 // we were on top of a surface and remained on it
                 guard.with_focused_pointers(|pointer, _| {
                     pointer.motion(time, x, y);
+                    if pointer.version() >= 5 {
+                        pointer.frame();
+                    }
                 })
             }
         }
@@ -101,15 +110,20 @@ impl PointerHandle {
         let guard = self.inner.lock().unwrap();
         guard.with_focused_pointers(|pointer, _| {
             pointer.button(serial, time, button, state);
+            if pointer.version() >= 5 {
+                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 +134,87 @@ 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, _| {
+            if pointer.version() >= 5 {
+                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, _| {
+            if pointer.version() >= 5 {
+                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, _| {
+            if pointer.version() >= 5 {
+                pointer.axis_stop(time, axis);
+            }
+        });
+        self
+    }
+
+    /// Finish this event
+    ///
+    /// This will group all axis calls together.
+    /// Note: They are already submitted to the client, obmitting this call just
+    /// leaves room for additional events.
+    pub fn done(&mut self) {
+        self.inner.with_focused_pointers(|pointer, _| {
+            if pointer.version() >= 5 {
+                pointer.frame();
+            }
+        })
+    }
+}
+
 pub(crate) fn create_pointer_handler() -> PointerHandle {
     PointerHandle {
         inner: Arc::new(Mutex::new(PointerInternal::new())),

Merge pull request #83 from Smithay/feature/wl_seat_v5