<NME> pointer.rs
<BEF> use std::sync::{Arc, Mutex};
use wayland_server::{
    protocol::{
        wl_pointer::{Axis, AxisSource, ButtonState, Event, Request, WlPointer},
        wl_surface::WlSurface,
    },
    NewResource, Resource,
};

// TODO: handle pointer surface role

enum GrabStatus {
    None,
        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";

    location: (f64, f64),
    grab: GrabStatus,
    pressed_buttons: Vec<u32>,
}

impl PointerInternal {
    fn new() -> PointerInternal {
        PointerInternal {
            known_pointers: Vec::new(),
            focus: None,
    }
            location: (0.0, 0.0),
            grab: GrabStatus::None,
            pressed_buttons: Vec::new(),
        }
    }

    }
    fn button(&self, seat: &Seat<D>, _data: &mut D, event: &ButtonEvent) {
        for_each_focused_pointers(seat, self, |ptr| {
            ptr.button(event.serial.into(), event.time, event.button, event.state.into());
            if ptr.version() >= 5 {
                ptr.frame();
            }
        })
    }
    fn axis(&self, seat: &Seat<D>, _data: &mut D, details: AxisFrame) {
        for_each_focused_pointers(seat, self, |ptr| {
            // axis
            if details.axis.0 != 0.0 {
                ptr.axis(details.time, WlAxis::HorizontalScroll, details.axis.0);
            }
            if details.axis.1 != 0.0 {
                ptr.axis(details.time, WlAxis::VerticalScroll, details.axis.1);
            }
            if ptr.version() >= 5 {
                // axis source
                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,
                        }
                    } else {
                        source
                    }
                    .into();
                    ptr.axis_source(source);
                }
                // axis discrete
                if details.discrete.0 != 0 {
                    ptr.axis_discrete(WlAxis::HorizontalScroll, details.discrete.0);
                }
                if details.discrete.1 != 0 {
                    ptr.axis_discrete(WlAxis::VerticalScroll, details.discrete.1);
                }
                // stop
                if details.stop.0 {
                    ptr.axis_stop(details.time, WlAxis::HorizontalScroll);
                }
                if details.stop.1 {
                    ptr.axis_stop(details.time, WlAxis::VerticalScroll);
                }
                // frame
                ptr.frame();
            }
        })
    }
}

/// User data for pointer
pub struct PointerUserData<D: SeatHandler> {
    pub(crate) handle: Option<PointerHandle<D>>,
}

impl<D: SeatHandler> fmt::Debug for PointerUserData<D>
where
    <D as SeatHandler>::PointerFocus: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("PointerUserData")
            .field("handle", &self.handle)
            .finish()
    }
}

impl<D> Dispatch<WlPointer, PointerUserData<D>, D> for SeatState<D>
where
    D: Dispatch<WlPointer, PointerUserData<D>>,
    D: SeatHandler,
    <D as SeatHandler>::PointerFocus: WaylandFocus,
    D: 'static,
{
    fn request(
        state: &mut D,
        _client: &wayland_server::Client,
        pointer: &WlPointer,
        request: wl_pointer::Request,
        data: &PointerUserData<D>,
        _dh: &DisplayHandle,
        _data_init: &mut wayland_server::DataInit<'_, D>,
    ) {
        match request {
            Request::SetCursor {
                surface,
                hotspot_x,
                hotspot_y,
                ..
            } => {
                if let Some(ref handle) = data.handle {
                    let seat = {
                        let seat_state = state.seat_state();
                        seat_state
                            .seats
                            .iter()
                            .find(|seat| seat.get_pointer().map(|h| &h == handle).unwrap_or(false))
                            .cloned()
                    };

                    let guard = handle.inner.lock().unwrap();
                    // only allow setting the cursor icon if the current pointer focus
                    // is of the same client
                    let PointerInternal { ref focus, .. } = *guard;
                    if let Some((ref focus, _)) = *focus {
                        if focus.same_client_as(&pointer.id()) {
                            match surface {
                                Some(surface) => {
                                    // tolerate re-using the same surface
                                    if compositor::give_role(&surface, CURSOR_IMAGE_ROLE).is_err()
                                        && compositor::get_role(&surface) != Some(CURSOR_IMAGE_ROLE)
                                    {
                                        pointer.post_error(
                                            wl_pointer::Error::Role,
                                            "Given wl_surface has another role.",
                                        );
                                        return;
                                    }
                                    compositor::with_states(&surface, |states| {
                                        states.data_map.insert_if_missing_threadsafe(|| {
                                            Mutex::new(CursorImageAttributes {
                                                hotspot: (0, 0).into(),
                                            })
                                        });
                                        states
                                            .data_map
                                            .get::<Mutex<CursorImageAttributes>>()
                                            .unwrap()
                                            .lock()
                                            .unwrap()
                                            .hotspot = (hotspot_x, hotspot_y).into();
                                    });

                                    if let Some(seat) = seat {
                                        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)),
        }
    }
}
                }
            });
            self.inner.focus = None;
        }

        // do we enter one ?
}

impl AxisFrame {
    pub fn new(time: u32) -> Self {
        AxisFrame {
            source: None,
    }
}

pub(crate) fn create_pointer_handler() -> PointerHandle {
    PointerHandle {
        inner: Arc::new(Mutex::new(PointerInternal::new())),
    }
}

pub(crate) fn implement_pointer(
    new_pointer: NewResource<WlPointer>,
    handle: Option<&PointerHandle>,
) -> Resource<WlPointer> {
    let destructor = match handle {
        Some(h) => {
            let inner = h.inner.clone();
            Some(move |pointer: Resource<_>| {
                inner
                    .lock()
                    .unwrap()
                    .known_pointers
                    .retain(|p| !p.equals(&pointer))
            })
        }
        None => None,
    };
    new_pointer.implement(
        |request, _pointer| {
            match request {
                Request::SetCursor { .. } => {
                    // TODO
                }
                Request::Release => {
                    // Our destructors already handle it

<MSG> seat: support for curstom cursor images

<DFF> @@ -1,13 +1,31 @@
 use std::sync::{Arc, Mutex};
 use wayland_server::{
     protocol::{
-        wl_pointer::{Axis, AxisSource, ButtonState, Event, Request, WlPointer},
+        wl_pointer::{self, Axis, AxisSource, ButtonState, Event, Request, WlPointer},
         wl_surface::WlSurface,
     },
     NewResource, Resource,
 };
 
-// TODO: handle pointer surface role
+use wayland::compositor::{roles::Role, CompositorToken};
+
+/// The role representing a surface set as the pointer cursor
+#[derive(Default, Copy, Clone)]
+pub struct CursorImageRole {
+    /// Location of the hotspot of the pointer in the surface
+    pub hotspot: (i32, i32),
+}
+
+/// Possible status of a cursor as requested by clients
+#[derive(Clone)]
+pub enum CursorImageStatus {
+    /// The cursor should be hidden
+    Hidden,
+    /// The compositor should draw its cursor
+    Default,
+    /// The cursor should be drawn using this surface as an image
+    Image(Resource<WlSurface>),
+}
 
 enum GrabStatus {
     None,
@@ -22,10 +40,35 @@ struct PointerInternal {
     location: (f64, f64),
     grab: GrabStatus,
     pressed_buttons: Vec<u32>,
+    image_callback: Box<FnMut(CursorImageStatus) + Send>,
 }
 
 impl PointerInternal {
-    fn new() -> PointerInternal {
+    fn new<F, U, R>(token: CompositorToken<U, R>, mut cb: F) -> PointerInternal
+    where
+        U: 'static,
+        R: Role<CursorImageRole> + 'static,
+        F: FnMut(CursorImageStatus) + Send + 'static,
+    {
+        let mut old_status = CursorImageStatus::Default;
+        let wrapper = move |new_status: CursorImageStatus| {
+            if let CursorImageStatus::Image(surface) =
+                ::std::mem::replace(&mut old_status, new_status.clone())
+            {
+                match new_status {
+                    CursorImageStatus::Image(ref new_surface) if new_surface == &surface => {
+                        // don't remove the role, we are just re-binding the same surface
+                    }
+                    _ => {
+                        if surface.is_alive() {
+                            token.remove_role::<CursorImageRole>(&surface).unwrap();
+                        }
+                    }
+                }
+            }
+            cb(new_status)
+        };
+
         PointerInternal {
             known_pointers: Vec::new(),
             focus: None,
@@ -33,6 +76,7 @@ impl PointerInternal {
             location: (0.0, 0.0),
             grab: GrabStatus::None,
             pressed_buttons: Vec::new(),
+            image_callback: Box::new(wrapper) as Box<_>,
         }
     }
 
@@ -297,6 +341,7 @@ impl<'a> PointerInnerHandle<'a> {
                 }
             });
             self.inner.focus = None;
+            (self.inner.image_callback)(CursorImageStatus::Default);
         }
 
         // do we enter one ?
@@ -431,6 +476,7 @@ pub struct AxisFrame {
 }
 
 impl AxisFrame {
+    /// Create a new frame of axis events
     pub fn new(time: u32) -> Self {
         AxisFrame {
             source: None,
@@ -501,34 +547,83 @@ impl AxisFrame {
     }
 }
 
-pub(crate) fn create_pointer_handler() -> PointerHandle {
+pub(crate) fn create_pointer_handler<F, U, R>(token: CompositorToken<U, R>, cb: F) -> PointerHandle
+where
+    R: Role<CursorImageRole> + 'static,
+    U: 'static,
+    F: FnMut(CursorImageStatus) + Send + 'static,
+{
     PointerHandle {
-        inner: Arc::new(Mutex::new(PointerInternal::new())),
+        inner: Arc::new(Mutex::new(PointerInternal::new(token, cb))),
     }
 }
 
-pub(crate) fn implement_pointer(
+pub(crate) fn implement_pointer<U, R>(
     new_pointer: NewResource<WlPointer>,
     handle: Option<&PointerHandle>,
-) -> Resource<WlPointer> {
-    let destructor = match handle {
-        Some(h) => {
-            let inner = h.inner.clone();
-            Some(move |pointer: Resource<_>| {
-                inner
-                    .lock()
-                    .unwrap()
-                    .known_pointers
-                    .retain(|p| !p.equals(&pointer))
-            })
-        }
+    token: CompositorToken<U, R>,
+) -> Resource<WlPointer>
+where
+    R: Role<CursorImageRole> + 'static,
+    U: 'static,
+{
+    let inner = handle.map(|h| h.inner.clone());
+    let destructor = match inner.clone() {
+        Some(inner) => Some(move |pointer: Resource<_>| {
+            inner
+                .lock()
+                .unwrap()
+                .known_pointers
+                .retain(|p| !p.equals(&pointer))
+        }),
         None => None,
     };
     new_pointer.implement(
-        |request, _pointer| {
+        move |request, pointer| {
             match request {
-                Request::SetCursor { .. } => {
-                    // TODO
+                Request::SetCursor {
+                    serial: _,
+                    surface,
+                    hotspot_x,
+                    hotspot_y,
+                } => {
+                    if let Some(ref inner) = inner {
+                        let mut guard = inner.lock().unwrap();
+                        // only allow setting the cursor icon if the current pointer focus
+                        // is of the same client
+                        let PointerInternal {
+                            ref mut image_callback,
+                            ref focus,
+                            ..
+                        } = *guard;
+                        if let Some((ref focus, _)) = *focus {
+                            if focus.same_client_as(&pointer) {
+                                match surface {
+                                    Some(surface) => {
+                                        let role_data = CursorImageRole {
+                                            hotspot: (hotspot_x, hotspot_y),
+                                        };
+                                        // we gracefully tolerate the client to provide a surface that
+                                        // already had the "CursorImage" role, as most clients will
+                                        // always reuse the same surface (and they are right to do so!)
+                                        if token.with_role_data(&surface, |data| *data = role_data).is_err()
+                                            && token.give_role_with(&surface, role_data).is_err()
+                                        {
+                                            pointer.post_error(
+                                                wl_pointer::Error::Role as u32,
+                                                "Given wl_surface has another role.".into(),
+                                            );
+                                            return;
+                                        }
+                                        image_callback(CursorImageStatus::Image(surface));
+                                    }
+                                    None => {
+                                        image_callback(CursorImageStatus::Hidden);
+                                    }
+                                }
+                            }
+                        }
+                    }
                 }
                 Request::Release => {
                     // Our destructors already handle it

seat: support for curstom cursor images