smithay_client_toolkit/seat/
touch.rs1use std::sync::Mutex;
2
3use wayland_client::protocol::wl_seat::WlSeat;
4
5use wayland_client::protocol::wl_surface::WlSurface;
6use wayland_client::protocol::wl_touch::{Event as TouchEvent, WlTouch};
7use wayland_client::{Connection, Dispatch, QueueHandle};
8
9use crate::seat::SeatState;
10
11#[derive(Debug)]
12pub struct TouchData {
13 seat: WlSeat,
14
15 inner: Mutex<TouchDataInner>,
16}
17
18impl TouchData {
19 pub fn new(seat: WlSeat) -> Self {
21 Self { seat, inner: Default::default() }
22 }
23
24 pub fn seat(&self) -> &WlSeat {
26 &self.seat
27 }
28
29 pub fn latest_down_serial(&self) -> Option<u32> {
31 self.inner.lock().unwrap().latest_down
32 }
33}
34
35#[derive(Debug, Default)]
36pub(crate) struct TouchDataInner {
37 events: Vec<TouchEvent>,
38 active_touch_points: Vec<i32>,
39
40 latest_down: Option<u32>,
42}
43
44#[macro_export]
45macro_rules! delegate_touch {
46 ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
47 $crate::delegate_touch!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; touch: $crate::seat::touch::TouchData);
48 };
49 ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty, touch: [$($td:ty),* $(,)?]) => {
50 $crate::delegate_touch!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; [ $($td),* ]);
51 };
52 (@{$($ty:tt)*}; touch: $td:ty) => {
53 $crate::reexports::client::delegate_dispatch!($($ty)*:
54 [
55 $crate::reexports::client::protocol::wl_touch::WlTouch: $td
56 ] => $crate::seat::SeatState
57 );
58 };
59 (@$ty:tt; [$($td:ty),*] ) => {
60 $(
61 $crate::delegate_touch!(@$ty, touch: $td);
62 )*
63 };
64}
65
66pub trait TouchDataExt: Send + Sync {
67 fn touch_data(&self) -> &TouchData;
68}
69
70impl TouchDataExt for TouchData {
71 fn touch_data(&self) -> &TouchData {
72 self
73 }
74}
75
76pub trait TouchHandler: Sized {
77 #[allow(clippy::too_many_arguments)]
88 fn down(
89 &mut self,
90 conn: &Connection,
91 qh: &QueueHandle<Self>,
92 touch: &WlTouch,
93 serial: u32,
94 time: u32,
95 surface: WlSurface,
96 id: i32,
97 position: (f64, f64),
98 );
99
100 fn up(
102 &mut self,
103 conn: &Connection,
104 qh: &QueueHandle<Self>,
105 touch: &WlTouch,
106 serial: u32,
107 time: u32,
108 id: i32,
109 );
110
111 fn motion(
115 &mut self,
116 conn: &Connection,
117 qh: &QueueHandle<Self>,
118 touch: &WlTouch,
119 time: u32,
120 id: i32,
121 position: (f64, f64),
122 );
123
124 fn shape(
132 &mut self,
133 conn: &Connection,
134 qh: &QueueHandle<Self>,
135 touch: &WlTouch,
136 id: i32,
137 major: f64,
138 minor: f64,
139 );
140
141 fn orientation(
146 &mut self,
147 conn: &Connection,
148 qh: &QueueHandle<Self>,
149 touch: &WlTouch,
150 id: i32,
151 orientation: f64,
152 );
153
154 fn cancel(&mut self, conn: &Connection, qh: &QueueHandle<Self>, touch: &WlTouch);
159}
160
161impl<D, U> Dispatch<WlTouch, U, D> for SeatState
162where
163 D: Dispatch<WlTouch, U> + TouchHandler,
164 U: TouchDataExt,
165{
166 fn event(
167 data: &mut D,
168 touch: &WlTouch,
169 event: TouchEvent,
170 udata: &U,
171 conn: &Connection,
172 qh: &QueueHandle<D>,
173 ) {
174 let udata = udata.touch_data();
175 let mut guard: std::sync::MutexGuard<'_, TouchDataInner> = udata.inner.lock().unwrap();
176
177 let mut save_event = false;
178 let mut process_events = false;
179
180 match &event {
181 TouchEvent::Down { serial, id, .. } => {
183 guard.latest_down = Some(*serial);
184 save_event = true;
185 if let Err(insert_pos) = guard.active_touch_points.binary_search(id) {
186 guard.active_touch_points.insert(insert_pos, *id);
187 }
188 }
189 TouchEvent::Up { id, .. } => {
190 save_event = true;
191 if let Ok(remove_pos) = guard.active_touch_points.binary_search(id) {
192 guard.active_touch_points.remove(remove_pos);
193 }
194
195 if guard.active_touch_points.is_empty() {
200 process_events = true;
201 }
202 }
203 TouchEvent::Motion { .. }
204 | TouchEvent::Shape { .. }
205 | TouchEvent::Orientation { .. } => {
206 save_event = true;
207 }
208 TouchEvent::Frame => {
210 process_events = true;
211 }
212 TouchEvent::Cancel => {
213 guard.events.clear();
214 guard.active_touch_points.clear();
215
216 data.cancel(conn, qh, touch);
217 }
218 _ => unreachable!(),
219 }
220
221 if save_event {
222 guard.events.push(event);
223 }
224
225 if process_events {
226 for event in guard.events.drain(..) {
227 process_framed_event(data, touch, conn, qh, event);
228 }
229 }
230 }
231}
232
233fn process_framed_event<D>(
235 data: &mut D,
236 touch: &WlTouch,
237 conn: &Connection,
238 qh: &QueueHandle<D>,
239 event: TouchEvent,
240) where
241 D: TouchHandler,
242{
243 match event {
244 TouchEvent::Down { serial, time, surface, id, x, y } => {
245 data.down(conn, qh, touch, serial, time, surface, id, (x, y));
246 }
247 TouchEvent::Up { serial, time, id } => {
248 data.up(conn, qh, touch, serial, time, id);
249 }
250 TouchEvent::Motion { time, id, x, y } => {
251 data.motion(conn, qh, touch, time, id, (x, y));
252 }
253 TouchEvent::Shape { id, major, minor } => {
254 data.shape(conn, qh, touch, id, major, minor);
255 }
256 TouchEvent::Orientation { id, orientation } => {
257 data.orientation(conn, qh, touch, id, orientation);
258 }
259 _ => unreachable!(),
261 }
262}