Skip to main content

smithay_client_toolkit/seat/
pointer_constraints.rs

1use wayland_client::{
2    globals::GlobalList,
3    protocol::{wl_pointer, wl_region, wl_surface},
4    Connection, Dispatch, QueueHandle,
5};
6use wayland_protocols::wp::pointer_constraints::zv1::client::{
7    zwp_confined_pointer_v1, zwp_locked_pointer_v1, zwp_pointer_constraints_v1,
8};
9
10use crate::{
11    dispatch2::Dispatch2,
12    error::GlobalError,
13    globals::{GlobalData, ProvidesBoundGlobal},
14    registry::GlobalProxy,
15};
16
17#[derive(Debug)]
18pub struct PointerConstraintsState {
19    pointer_constraints: GlobalProxy<zwp_pointer_constraints_v1::ZwpPointerConstraintsV1>,
20}
21
22impl PointerConstraintsState {
23    /// Bind `zwp_pointer_constraints_v1` global, if it exists
24    pub fn bind<D>(globals: &GlobalList, qh: &QueueHandle<D>) -> Self
25    where
26        D: Dispatch<zwp_pointer_constraints_v1::ZwpPointerConstraintsV1, GlobalData> + 'static,
27    {
28        let pointer_constraints = GlobalProxy::from(globals.bind(qh, 1..=1, GlobalData));
29        Self { pointer_constraints }
30    }
31
32    /// Request that the compositor confine the pointer to a region
33    ///
34    /// It is a protocol error to call when a constraint already exists for a pointer on the seat.
35    pub fn confine_pointer<D>(
36        &self,
37        surface: &wl_surface::WlSurface,
38        pointer: &wl_pointer::WlPointer,
39        region: Option<&wl_region::WlRegion>,
40        lifetime: zwp_pointer_constraints_v1::Lifetime,
41        qh: &QueueHandle<D>,
42    ) -> Result<zwp_confined_pointer_v1::ZwpConfinedPointerV1, GlobalError>
43    where
44        D: Dispatch<zwp_confined_pointer_v1::ZwpConfinedPointerV1, PointerConstraintData> + 'static,
45    {
46        let udata = PointerConstraintData { surface: surface.clone(), pointer: pointer.clone() };
47        Ok(self
48            .pointer_constraints
49            .get()?
50            .confine_pointer(surface, pointer, region, lifetime, qh, udata))
51    }
52
53    /// Request that the compositor lock the pointer in place
54    ///
55    /// It is a protocol error to call when a constraint already exists for a pointer on the seat.
56    pub fn lock_pointer<D>(
57        &self,
58        surface: &wl_surface::WlSurface,
59        pointer: &wl_pointer::WlPointer,
60        region: Option<&wl_region::WlRegion>,
61        lifetime: zwp_pointer_constraints_v1::Lifetime,
62        qh: &QueueHandle<D>,
63    ) -> Result<zwp_locked_pointer_v1::ZwpLockedPointerV1, GlobalError>
64    where
65        D: Dispatch<zwp_locked_pointer_v1::ZwpLockedPointerV1, PointerConstraintData> + 'static,
66    {
67        let udata = PointerConstraintData { surface: surface.clone(), pointer: pointer.clone() };
68        Ok(self
69            .pointer_constraints
70            .get()?
71            .lock_pointer(surface, pointer, region, lifetime, qh, udata))
72    }
73}
74
75impl ProvidesBoundGlobal<zwp_pointer_constraints_v1::ZwpPointerConstraintsV1, 1>
76    for PointerConstraintsState
77{
78    fn bound_global(
79        &self,
80    ) -> Result<zwp_pointer_constraints_v1::ZwpPointerConstraintsV1, GlobalError> {
81        self.pointer_constraints.get().cloned()
82    }
83}
84
85pub trait PointerConstraintsHandler: Sized {
86    /// Pointer confinement activated by compositor
87    fn confined(
88        &mut self,
89        conn: &Connection,
90        qh: &QueueHandle<Self>,
91        confined_pointer: &zwp_confined_pointer_v1::ZwpConfinedPointerV1,
92        surface: &wl_surface::WlSurface,
93        pointer: &wl_pointer::WlPointer,
94    );
95
96    /// Pointer confinement deactivated by compositor
97    ///
98    /// For `Oneshot` constraints, it will not be reactivated.
99    fn unconfined(
100        &mut self,
101        conn: &Connection,
102        qh: &QueueHandle<Self>,
103        confined_pointer: &zwp_confined_pointer_v1::ZwpConfinedPointerV1,
104        surface: &wl_surface::WlSurface,
105        pointer: &wl_pointer::WlPointer,
106    );
107
108    /// Pointer lock activated by compositor
109    fn locked(
110        &mut self,
111        conn: &Connection,
112        qh: &QueueHandle<Self>,
113        locked_pointer: &zwp_locked_pointer_v1::ZwpLockedPointerV1,
114        surface: &wl_surface::WlSurface,
115        pointer: &wl_pointer::WlPointer,
116    );
117
118    /// Pointer lock deactivated by compositor
119    ///
120    /// For `Oneshot` constraints, it will not be reactivated.
121    fn unlocked(
122        &mut self,
123        conn: &Connection,
124        qh: &QueueHandle<Self>,
125        locked_pointer: &zwp_locked_pointer_v1::ZwpLockedPointerV1,
126        surface: &wl_surface::WlSurface,
127        pointer: &wl_pointer::WlPointer,
128    );
129}
130
131#[doc(hidden)]
132#[derive(Debug)]
133pub struct PointerConstraintData {
134    surface: wl_surface::WlSurface,
135    pointer: wl_pointer::WlPointer,
136}
137
138impl<D> Dispatch2<zwp_pointer_constraints_v1::ZwpPointerConstraintsV1, D> for GlobalData
139where
140    D: PointerConstraintsHandler,
141{
142    fn event(
143        &self,
144        _data: &mut D,
145        _constraints: &zwp_pointer_constraints_v1::ZwpPointerConstraintsV1,
146        _event: zwp_pointer_constraints_v1::Event,
147        _conn: &Connection,
148        _qh: &QueueHandle<D>,
149    ) {
150        unreachable!()
151    }
152}
153
154impl<D> Dispatch2<zwp_confined_pointer_v1::ZwpConfinedPointerV1, D> for PointerConstraintData
155where
156    D: PointerConstraintsHandler,
157{
158    fn event(
159        &self,
160        data: &mut D,
161        confined_pointer: &zwp_confined_pointer_v1::ZwpConfinedPointerV1,
162        event: zwp_confined_pointer_v1::Event,
163        conn: &Connection,
164        qh: &QueueHandle<D>,
165    ) {
166        match event {
167            zwp_confined_pointer_v1::Event::Confined => {
168                data.confined(conn, qh, confined_pointer, &self.surface, &self.pointer)
169            }
170            zwp_confined_pointer_v1::Event::Unconfined => {
171                data.unconfined(conn, qh, confined_pointer, &self.surface, &self.pointer)
172            }
173            _ => unreachable!(),
174        }
175    }
176}
177
178impl<D> Dispatch2<zwp_locked_pointer_v1::ZwpLockedPointerV1, D> for PointerConstraintData
179where
180    D: PointerConstraintsHandler,
181{
182    fn event(
183        &self,
184        data: &mut D,
185        locked_pointer: &zwp_locked_pointer_v1::ZwpLockedPointerV1,
186        event: zwp_locked_pointer_v1::Event,
187        conn: &Connection,
188        qh: &QueueHandle<D>,
189    ) {
190        match event {
191            zwp_locked_pointer_v1::Event::Locked => {
192                data.locked(conn, qh, locked_pointer, &self.surface, &self.pointer)
193            }
194            zwp_locked_pointer_v1::Event::Unlocked => {
195                data.unlocked(conn, qh, locked_pointer, &self.surface, &self.pointer)
196            }
197            _ => unreachable!(),
198        }
199    }
200}