winit/platform_impl/linux/wayland/seat/touch/
mod.rs

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