1 | //! Touch handling. |
2 | |
3 | use tracing::warn; |
4 | |
5 | use sctk::reexports::client::protocol::wl_seat::WlSeat; |
6 | use sctk::reexports::client::protocol::wl_surface::WlSurface; |
7 | use sctk::reexports::client::protocol::wl_touch::WlTouch; |
8 | use sctk::reexports::client::{Connection, Proxy, QueueHandle}; |
9 | |
10 | use sctk::seat::touch::{TouchData, TouchHandler}; |
11 | |
12 | use crate::dpi::LogicalPosition; |
13 | use crate::event::{Touch, TouchPhase, WindowEvent}; |
14 | |
15 | use crate::platform_impl::wayland::state::WinitState; |
16 | use crate::platform_impl::wayland::{self, DeviceId}; |
17 | |
18 | impl TouchHandler for WinitState { |
19 | fn down( |
20 | &mut self, |
21 | _: &Connection, |
22 | _: &QueueHandle<Self>, |
23 | touch: &WlTouch, |
24 | _: u32, |
25 | _: u32, |
26 | surface: WlSurface, |
27 | id: i32, |
28 | position: (f64, f64), |
29 | ) { |
30 | let window_id = wayland::make_wid(&surface); |
31 | let scale_factor = match self.windows.get_mut().get(&window_id) { |
32 | Some(window) => window.lock().unwrap().scale_factor(), |
33 | None => return, |
34 | }; |
35 | |
36 | let seat_state = match self.seats.get_mut(&touch.seat().id()) { |
37 | Some(seat_state) => seat_state, |
38 | None => { |
39 | warn!("Received wl_touch::down without seat" ); |
40 | return; |
41 | }, |
42 | }; |
43 | |
44 | // Update the state of the point. |
45 | let location = LogicalPosition::<f64>::from(position); |
46 | seat_state.touch_map.insert(id, TouchPoint { surface, location }); |
47 | |
48 | self.events_sink.push_window_event( |
49 | WindowEvent::Touch(Touch { |
50 | device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland( |
51 | DeviceId, |
52 | )), |
53 | phase: TouchPhase::Started, |
54 | location: location.to_physical(scale_factor), |
55 | force: None, |
56 | id: id as u64, |
57 | }), |
58 | window_id, |
59 | ); |
60 | } |
61 | |
62 | fn up( |
63 | &mut self, |
64 | _: &Connection, |
65 | _: &QueueHandle<Self>, |
66 | touch: &WlTouch, |
67 | _: u32, |
68 | _: u32, |
69 | id: i32, |
70 | ) { |
71 | let seat_state = match self.seats.get_mut(&touch.seat().id()) { |
72 | Some(seat_state) => seat_state, |
73 | None => { |
74 | warn!("Received wl_touch::up without seat" ); |
75 | return; |
76 | }, |
77 | }; |
78 | |
79 | // Remove the touch point. |
80 | let touch_point = match seat_state.touch_map.remove(&id) { |
81 | Some(touch_point) => touch_point, |
82 | None => return, |
83 | }; |
84 | |
85 | let window_id = wayland::make_wid(&touch_point.surface); |
86 | let scale_factor = match self.windows.get_mut().get(&window_id) { |
87 | Some(window) => window.lock().unwrap().scale_factor(), |
88 | None => return, |
89 | }; |
90 | |
91 | self.events_sink.push_window_event( |
92 | WindowEvent::Touch(Touch { |
93 | device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland( |
94 | DeviceId, |
95 | )), |
96 | phase: TouchPhase::Ended, |
97 | location: touch_point.location.to_physical(scale_factor), |
98 | force: None, |
99 | id: id as u64, |
100 | }), |
101 | window_id, |
102 | ); |
103 | } |
104 | |
105 | fn motion( |
106 | &mut self, |
107 | _: &Connection, |
108 | _: &QueueHandle<Self>, |
109 | touch: &WlTouch, |
110 | _: u32, |
111 | id: i32, |
112 | position: (f64, f64), |
113 | ) { |
114 | let seat_state = match self.seats.get_mut(&touch.seat().id()) { |
115 | Some(seat_state) => seat_state, |
116 | None => { |
117 | warn!("Received wl_touch::motion without seat" ); |
118 | return; |
119 | }, |
120 | }; |
121 | |
122 | // Remove the touch point. |
123 | let touch_point = match seat_state.touch_map.get_mut(&id) { |
124 | Some(touch_point) => touch_point, |
125 | None => return, |
126 | }; |
127 | |
128 | let window_id = wayland::make_wid(&touch_point.surface); |
129 | let scale_factor = match self.windows.get_mut().get(&window_id) { |
130 | Some(window) => window.lock().unwrap().scale_factor(), |
131 | None => return, |
132 | }; |
133 | |
134 | touch_point.location = LogicalPosition::<f64>::from(position); |
135 | |
136 | self.events_sink.push_window_event( |
137 | WindowEvent::Touch(Touch { |
138 | device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland( |
139 | DeviceId, |
140 | )), |
141 | phase: TouchPhase::Moved, |
142 | location: touch_point.location.to_physical(scale_factor), |
143 | force: None, |
144 | id: id as u64, |
145 | }), |
146 | window_id, |
147 | ); |
148 | } |
149 | |
150 | fn cancel(&mut self, _: &Connection, _: &QueueHandle<Self>, touch: &WlTouch) { |
151 | let seat_state = match self.seats.get_mut(&touch.seat().id()) { |
152 | Some(seat_state) => seat_state, |
153 | None => { |
154 | warn!("Received wl_touch::cancel without seat" ); |
155 | return; |
156 | }, |
157 | }; |
158 | |
159 | for (id, touch_point) in seat_state.touch_map.drain() { |
160 | let window_id = wayland::make_wid(&touch_point.surface); |
161 | let scale_factor = match self.windows.get_mut().get(&window_id) { |
162 | Some(window) => window.lock().unwrap().scale_factor(), |
163 | None => return, |
164 | }; |
165 | |
166 | let location = touch_point.location.to_physical(scale_factor); |
167 | |
168 | self.events_sink.push_window_event( |
169 | WindowEvent::Touch(Touch { |
170 | device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland( |
171 | DeviceId, |
172 | )), |
173 | phase: TouchPhase::Cancelled, |
174 | location, |
175 | force: None, |
176 | id: id as u64, |
177 | }), |
178 | window_id, |
179 | ); |
180 | } |
181 | } |
182 | |
183 | fn shape( |
184 | &mut self, |
185 | _: &Connection, |
186 | _: &QueueHandle<Self>, |
187 | _: &WlTouch, |
188 | _: i32, |
189 | _: f64, |
190 | _: f64, |
191 | ) { |
192 | // Blank. |
193 | } |
194 | |
195 | fn orientation(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &WlTouch, _: i32, _: f64) { |
196 | // Blank. |
197 | } |
198 | } |
199 | |
200 | /// The state of the touch point. |
201 | #[derive (Debug)] |
202 | pub struct TouchPoint { |
203 | /// The surface on which the point is present. |
204 | pub surface: WlSurface, |
205 | |
206 | /// The location of the point on the surface. |
207 | pub location: LogicalPosition<f64>, |
208 | } |
209 | |
210 | pub trait TouchDataExt { |
211 | fn seat(&self) -> &WlSeat; |
212 | } |
213 | |
214 | impl TouchDataExt for WlTouch { |
215 | fn seat(&self) -> &WlSeat { |
216 | self.data::<TouchData>().expect("failed to get touch data." ).seat() |
217 | } |
218 | } |
219 | |
220 | sctk::delegate_touch!(WinitState); |
221 | |