1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use wayland_client::{
    globals::GlobalList, protocol::wl_pointer, Connection, Dispatch, QueueHandle,
};
use wayland_protocols::wp::relative_pointer::zv1::client::{
    zwp_relative_pointer_manager_v1, zwp_relative_pointer_v1,
};

use crate::{error::GlobalError, globals::GlobalData, registry::GlobalProxy};

#[derive(Debug)]
pub struct RelativePointerState {
    relative_pointer_manager:
        GlobalProxy<zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1>,
}

impl RelativePointerState {
    /// Bind `zwp_relative_pointer_manager_v1` global, if it exists
    pub fn bind<D>(globals: &GlobalList, qh: &QueueHandle<D>) -> Self
    where
        D: Dispatch<zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1, GlobalData>
            + 'static,
    {
        let relative_pointer_manager = GlobalProxy::from(globals.bind(qh, 1..=1, GlobalData));
        Self { relative_pointer_manager }
    }

    pub fn get_relative_pointer<D>(
        &self,
        pointer: &wl_pointer::WlPointer,
        qh: &QueueHandle<D>,
    ) -> Result<zwp_relative_pointer_v1::ZwpRelativePointerV1, GlobalError>
    where
        D: Dispatch<zwp_relative_pointer_v1::ZwpRelativePointerV1, RelativePointerData> + 'static,
    {
        let udata = RelativePointerData { wl_pointer: pointer.clone() };
        Ok(self.relative_pointer_manager.get()?.get_relative_pointer(pointer, qh, udata))
    }
}

#[derive(Debug)]
pub struct RelativeMotionEvent {
    /// (x, y) motion vector
    pub delta: (f64, f64),
    /// Unaccelerated (x, y) motion vector
    pub delta_unaccel: (f64, f64),
    /// Timestamp in microseconds
    pub utime: u64,
}

pub trait RelativePointerHandler: Sized {
    fn relative_pointer_motion(
        &mut self,
        conn: &Connection,
        qh: &QueueHandle<Self>,
        relative_pointer: &zwp_relative_pointer_v1::ZwpRelativePointerV1,
        pointer: &wl_pointer::WlPointer,
        event: RelativeMotionEvent,
    );
}

#[doc(hidden)]
#[derive(Debug)]
pub struct RelativePointerData {
    wl_pointer: wl_pointer::WlPointer,
}

impl<D> Dispatch<zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1, GlobalData, D>
    for RelativePointerState
where
    D: Dispatch<zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1, GlobalData>
        + RelativePointerHandler,
{
    fn event(
        _data: &mut D,
        _manager: &zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
        _event: zwp_relative_pointer_manager_v1::Event,
        _: &GlobalData,
        _conn: &Connection,
        _qh: &QueueHandle<D>,
    ) {
        unreachable!()
    }
}

impl<D> Dispatch<zwp_relative_pointer_v1::ZwpRelativePointerV1, RelativePointerData, D>
    for RelativePointerState
where
    D: Dispatch<zwp_relative_pointer_v1::ZwpRelativePointerV1, RelativePointerData>
        + RelativePointerHandler,
{
    fn event(
        data: &mut D,
        relative_pointer: &zwp_relative_pointer_v1::ZwpRelativePointerV1,
        event: zwp_relative_pointer_v1::Event,
        udata: &RelativePointerData,
        conn: &Connection,
        qh: &QueueHandle<D>,
    ) {
        match event {
            zwp_relative_pointer_v1::Event::RelativeMotion {
                utime_hi,
                utime_lo,
                dx,
                dy,
                dx_unaccel,
                dy_unaccel,
            } => {
                data.relative_pointer_motion(
                    conn,
                    qh,
                    relative_pointer,
                    &udata.wl_pointer,
                    RelativeMotionEvent {
                        utime: ((utime_hi as u64) << 32) | (utime_lo as u64),
                        delta: (dx, dy),
                        delta_unaccel: (dx_unaccel, dy_unaccel),
                    },
                );
            }
            _ => unreachable!(),
        }
    }
}

#[macro_export]
macro_rules! delegate_relative_pointer {
    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
        $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::protocols::wp::relative_pointer::zv1::client::zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1: $crate::globals::GlobalData
        ] => $crate::seat::relative_pointer::RelativePointerState);
        $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::protocols::wp::relative_pointer::zv1::client::zwp_relative_pointer_v1::ZwpRelativePointerV1: $crate::seat::relative_pointer::RelativePointerData
        ] => $crate::seat::relative_pointer::RelativePointerState);
    };
}