tawasuyu

tawasuyu/mirada

Sovereign tiling Wayland compositor + window manager in Rust, on Llimphi.

Rust 50Markdown 30TOML 211282 Definiciones

⎇ main vendor/smithay/src/input/touch/mod.rs Rust · 693 líneas · 24.2 KB Historia Quién tocó qué crudo

chore: refresco desde el monorepo (pin tawasuyu.git v0.2.0) a91da3fea · Sergio ·

1//! Touch-related types for smithay's input abstraction
2
3use std::collections::HashMap;
4use std::fmt;
5use std::sync::{Arc, Mutex};
6
7use tracing::{info_span, instrument};
8#[cfg(feature = "wayland_frontend")]
9use wayland_server::Weak;
10
11use crate::backend::input::TouchSlot;
12use crate::utils::{IsAlive, Logical, Point, Serial, SerialCounter};
13
14pub use grab::{DefaultGrab, GrabStartData, TouchDownGrab, TouchGrab};
15
16use super::{GrabStatus, Seat, SeatHandler};
17
18mod grab;
19
20/// An handle to a touch handler
21///
22/// It can be cloned and all clones manipulate the same internal state.
23///
24/// This handle gives you access to an interface to send touch events to your
25/// clients.
26///
27/// When sending events using this handle, they will be intercepted by a touch
28/// grab if any is active. See the [`TouchGrab`] trait for details.
29pub struct TouchHandle<D: SeatHandler> {
30    pub(crate) inner: Arc<Mutex<TouchInternal<D>>>,
31    #[cfg(feature = "wayland_frontend")]
32    pub(crate) known_instances:
33        Arc<Mutex<Vec<(Weak<wayland_server::protocol::wl_touch::WlTouch>, Option<Serial>)>>>,
34    pub(crate) span: tracing::Span,
35}
36
37#[cfg(not(feature = "wayland_frontend"))]
38impl<D: SeatHandler> fmt::Debug for TouchHandle<D> {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        f.debug_struct("TouchHandle").field("inner", &self.inner).finish()
41    }
42}
43
44#[cfg(feature = "wayland_frontend")]
45impl<D: SeatHandler> fmt::Debug for TouchHandle<D> {
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        f.debug_struct("TouchHandle")
48            .field("inner", &self.inner)
49            .field("known_instances", &self.known_instances)
50            .finish()
51    }
52}
53
54impl<D: SeatHandler> Clone for TouchHandle<D> {
55    #[inline]
56    fn clone(&self) -> Self {
57        Self {
58            inner: self.inner.clone(),
59            #[cfg(feature = "wayland_frontend")]
60            known_instances: self.known_instances.clone(),
61            span: self.span.clone(),
62        }
63    }
64}
65
66impl<D: SeatHandler> std::hash::Hash for TouchHandle<D> {
67    #[inline]
68    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
69        Arc::as_ptr(&self.inner).hash(state)
70    }
71}
72
73impl<D: SeatHandler> std::cmp::PartialEq for TouchHandle<D> {
74    #[inline]
75    fn eq(&self, other: &Self) -> bool {
76        Arc::ptr_eq(&self.inner, &other.inner)
77    }
78}
79
80impl<D: SeatHandler> std::cmp::Eq for TouchHandle<D> {}
81
82pub(crate) struct TouchInternal<D: SeatHandler> {
83    focus: HashMap<TouchSlot, TouchSlotState<D>>,
84    seq_counter: SerialCounter,
85    default_grab: Box<dyn Fn() -> Box<dyn TouchGrab<D>> + Send + 'static>,
86    grab: GrabStatus<dyn TouchGrab<D>>,
87}
88
89struct TouchSlotState<D: SeatHandler> {
90    focus: Option<(<D as SeatHandler>::TouchFocus, Point<f64, Logical>)>,
91    frame_pending: Option<<D as SeatHandler>::TouchFocus>,
92    pending: Serial,
93    current: Option<Serial>,
94}
95
96impl<D: SeatHandler> fmt::Debug for TouchSlotState<D> {
97    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98        f.debug_struct("TouchSlotState")
99            .field("focus", &self.focus)
100            .field("frame_pending", &self.frame_pending)
101            .field("pending", &self.pending)
102            .field("current", &self.current)
103            .finish()
104    }
105}
106
107// image_callback does not implement debug, so we have to impl Debug manually
108impl<D: SeatHandler> fmt::Debug for TouchInternal<D> {
109    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110        f.debug_struct("TouchInternal")
111            .field("focus", &self.focus)
112            .field("grab", &self.grab)
113            .finish()
114    }
115}
116
117/// Pointer motion event
118#[derive(Debug, Clone)]
119pub struct DownEvent {
120    /// Slot of this event
121    pub slot: TouchSlot,
122    /// Location of the touch in compositor space
123    pub location: Point<f64, Logical>,
124    /// Serial of the event
125    pub serial: Serial,
126    /// Timestamp of the event, with millisecond granularity
127    pub time: u32,
128}
129
130/// Pointer motion event
131#[derive(Debug, Clone)]
132pub struct UpEvent {
133    /// Slot of this event
134    pub slot: TouchSlot,
135    /// Serial of the event
136    pub serial: Serial,
137    /// Timestamp of the event, with millisecond granularity
138    pub time: u32,
139}
140
141/// Pointer motion event
142#[derive(Debug, Clone)]
143pub struct MotionEvent {
144    /// Slot of this event
145    pub slot: TouchSlot,
146    /// Location of the touch in compositor space
147    pub location: Point<f64, Logical>,
148    /// Timestamp of the event, with millisecond granularity
149    pub time: u32,
150}
151
152/// Pointer motion event
153#[derive(Debug, Clone, Copy)]
154pub struct ShapeEvent {
155    /// Slot of this event
156    pub slot: TouchSlot,
157    /// Length of the major axis in surface-local coordinates
158    pub major: f64,
159    /// Length of the minor axis in surface-local coordinates
160    pub minor: f64,
161}
162
163/// Pointer motion event
164#[derive(Debug, Clone, Copy)]
165pub struct OrientationEvent {
166    /// Slot of this event
167    pub slot: TouchSlot,
168    /// Angle between major axis and positive surface y-axis in degrees
169    pub orientation: f64,
170}
171
172/// Trait representing object that can receive touch interactions
173pub trait TouchTarget<D>: IsAlive + PartialEq + Clone + fmt::Debug + Send
174where
175    D: SeatHandler,
176{
177    /// A new touch point has appeared on the target.
178    ///
179    /// This touch point is assigned a unique ID. Future events from this touch point reference this ID.
180    /// The ID ceases to be valid after a touch up event and may be reused in the future.
181    fn down(&self, seat: &Seat<D>, data: &mut D, event: &DownEvent, seq: Serial);
182
183    /// The touch point has disappeared.
184    ///
185    /// No further events will be sent for this touch point and the touch point's ID
186    /// is released and may be reused in a future touch down event.
187    fn up(&self, seat: &Seat<D>, data: &mut D, event: &UpEvent, seq: Serial);
188
189    /// A touch point has changed coordinates.
190    fn motion(&self, seat: &Seat<D>, data: &mut D, event: &MotionEvent, seq: Serial);
191
192    /// Indicates the end of a set of events that logically belong together.
193    fn frame(&self, seat: &Seat<D>, data: &mut D, seq: Serial);
194
195    /// Touch session cancelled.
196    ///
197    /// Touch cancellation applies to all touch points currently active on this target.
198    /// The client is responsible for finalizing the touch points, future touch points on
199    /// this target may reuse the touch point ID.
200    fn cancel(&self, seat: &Seat<D>, data: &mut D, seq: Serial);
201
202    /// Sent when a touch point has changed its shape.
203    ///
204    /// A touch point shape is approximated by an ellipse through the major and minor axis length.
205    /// The major axis length describes the longer diameter of the ellipse, while the minor axis
206    /// length describes the shorter diameter. Major and minor are orthogonal and both are specified
207    /// in surface-local coordinates. The center of the ellipse is always at the touch point location
208    /// as reported by [`TouchTarget::down`] or [`TouchTarget::motion`].
209    fn shape(&self, seat: &Seat<D>, data: &mut D, event: &ShapeEvent, seq: Serial);
210
211    /// Sent when a touch point has changed its orientation.
212    ///
213    /// The orientation describes the clockwise angle of a touch point's major axis to the positive surface
214    /// y-axis and is normalized to the -180 to +180 degree range. The granularity of orientation depends
215    /// on the touch device, some devices only support binary rotation values between 0 and 90 degrees.
216    fn orientation(&self, seat: &Seat<D>, data: &mut D, event: &OrientationEvent, seq: Serial);
217}
218
219impl<D: SeatHandler + 'static> TouchHandle<D> {
220    pub(crate) fn new<F>(default_grab: F) -> TouchHandle<D>
221    where
222        F: Fn() -> Box<dyn TouchGrab<D>> + Send + 'static,
223    {
224        TouchHandle {
225            inner: Arc::new(Mutex::new(TouchInternal::new(default_grab))),
226            #[cfg(feature = "wayland_frontend")]
227            known_instances: Arc::new(Mutex::new(Vec::new())),
228            span: info_span!("input_touch"),
229        }
230    }
231
232    /// Change the current grab on this touch to the provided grab
233    ///
234    /// Overwrites any current grab.
235    #[instrument(level = "debug", parent = &self.span, skip(self, data, grab))]
236    pub fn set_grab<G: TouchGrab<D> + 'static>(&self, data: &mut D, grab: G, serial: Serial) {
237        let seat = self.get_seat(data);
238        self.inner.lock().unwrap().set_grab(data, &seat, serial, grab);
239    }
240
241    /// Remove any current grab on this touch, resetting it to the default behavior
242    #[instrument(level = "debug", parent = &self.span, skip(self, data))]
243    pub fn unset_grab(&self, data: &mut D) {
244        let seat = self.get_seat(data);
245        self.inner.lock().unwrap().unset_grab(data, &seat);
246    }
247
248    /// Check if this touch is currently grabbed with this serial
249    pub fn has_grab(&self, serial: Serial) -> bool {
250        let guard = self.inner.lock().unwrap();
251        match guard.grab {
252            GrabStatus::Active(s, _) => s == serial,
253            _ => false,
254        }
255    }
256
257    /// Check if this touch is currently being grabbed
258    pub fn is_grabbed(&self) -> bool {
259        let guard = self.inner.lock().unwrap();
260        !matches!(guard.grab, GrabStatus::None)
261    }
262
263    /// Returns the start data for the grab, if any.
264    pub fn grab_start_data(&self) -> Option<GrabStartData<D>> {
265        let guard = self.inner.lock().unwrap();
266        match &guard.grab {
267            GrabStatus::Active(_, g) => Some(g.start_data().clone()),
268            _ => None,
269        }
270    }
271
272    /// Calls `f` with the active grab, if any.
273    pub fn with_grab<T>(&self, f: impl FnOnce(Serial, &dyn TouchGrab<D>) -> T) -> Option<T> {
274        let guard = self.inner.lock().unwrap();
275        if let GrabStatus::Active(s, g) = &guard.grab {
276            Some(f(*s, &**g))
277        } else {
278            None
279        }
280    }
281
282    /// Notify that a new touch point appeared
283    ///
284    /// You provide the location of the touch, in the form of:
285    ///
286    /// - The coordinates of the touch in the global compositor space
287    /// - The surface on top of which the touch point is, and the coordinates of its
288    ///   origin in the global compositor space (or `None` of the touch is not
289    ///   on top of a client surface).
290    pub fn down(
291        &self,
292        data: &mut D,
293        focus: Option<(<D as SeatHandler>::TouchFocus, Point<f64, Logical>)>,
294        event: &DownEvent,
295    ) {
296        let mut inner = self.inner.lock().unwrap();
297        let seat = self.get_seat(data);
298        let seq = inner.seq_counter.next_serial();
299        inner.with_grab(data, &seat, |data, handle, grab| {
300            grab.down(data, handle, focus, event, seq);
301        });
302    }
303
304    /// Notify that a touch point disappeared
305    pub fn up(&self, data: &mut D, event: &UpEvent) {
306        let mut inner = self.inner.lock().unwrap();
307        let seat = self.get_seat(data);
308        let seq = inner.seq_counter.next_serial();
309        inner.with_grab(data, &seat, |data, handle, grab| {
310            grab.up(data, handle, event, seq);
311        });
312    }
313
314    /// Notify that a touch point has changed coordinates.
315    ///
316    /// You provide the location of the touch, in the form of:
317    ///
318    /// - The coordinates of the touch in the global compositor space
319    /// - The surface on top of which the touch point is, and the coordinates of its
320    ///   origin in the global compositor space (or `None` of the touch is not
321    ///   on top of a client surface).
322    ///
323    /// **Note** that this will **not** update the focus of the touch point, the focus
324    /// is only set on [`TouchHandle::down`]. The focus provided to this function
325    /// can be used to find DnD targets during touch motion.
326    pub fn motion(
327        &self,
328        data: &mut D,
329        focus: Option<(<D as SeatHandler>::TouchFocus, Point<f64, Logical>)>,
330        event: &MotionEvent,
331    ) {
332        let mut inner = self.inner.lock().unwrap();
333        let seat = self.get_seat(data);
334        let seq = inner.seq_counter.next_serial();
335        inner.with_grab(data, &seat, |data, handle, grab| {
336            grab.motion(data, handle, focus, event, seq);
337        });
338    }
339
340    /// Notify about the end of a set of events that logically belong together.
341    ///
342    /// This needs to be called after one or move calls to [`TouchHandle::down`] or [`TouchHandle::motion`]
343    pub fn frame(&self, data: &mut D) {
344        let mut inner = self.inner.lock().unwrap();
345        let seat = self.get_seat(data);
346        let seq = inner.seq_counter.next_serial();
347        inner.with_grab(data, &seat, |data, handle, grab| {
348            grab.frame(data, handle, seq);
349        });
350    }
351
352    /// Notify that the touch session has been cancelled.
353    ///
354    /// Use in case you decide the touch stream is a global gesture.
355    /// This will remove all current focus targets, and no further events will be sent
356    /// until a new touch point appears.
357    pub fn cancel(&self, data: &mut D) {
358        let mut inner = self.inner.lock().unwrap();
359        let seat = self.get_seat(data);
360        let seq = inner.seq_counter.next_serial();
361        inner.with_grab(data, &seat, |data, handle, grab| {
362            grab.cancel(data, handle, seq);
363        });
364    }
365
366    /// Notify that a touch point has changed its shape.
367    pub fn shape(&self, data: &mut D, event: &ShapeEvent) {
368        let mut inner = self.inner.lock().unwrap();
369        let seat = self.get_seat(data);
370        let seq = inner.seq_counter.next_serial();
371        inner.with_grab(data, &seat, |data, handle, grab| {
372            grab.shape(data, handle, event, seq);
373        });
374    }
375
376    /// Notify that a touch point has changed its orientation.
377    pub fn orientation(&self, data: &mut D, event: &OrientationEvent) {
378        let mut inner = self.inner.lock().unwrap();
379        let seat = self.get_seat(data);
380        let seq = inner.seq_counter.next_serial();
381        inner.with_grab(data, &seat, |data, handle, grab| {
382            grab.orientation(data, handle, event, seq);
383        });
384    }
385
386    fn get_seat(&self, data: &mut D) -> Seat<D> {
387        let seat_state = data.seat_state();
388        seat_state
389            .seats
390            .iter()
391            .find(|seat| seat.get_touch().map(|h| &h == self).unwrap_or(false))
392            .cloned()
393            .unwrap()
394    }
395}
396
397/// This inner handle is accessed from inside a pointer grab logic, and directly
398/// sends event to the client
399pub struct TouchInnerHandle<'a, D: SeatHandler> {
400    inner: &'a mut TouchInternal<D>,
401    seat: &'a Seat<D>,
402}
403
404impl<D: SeatHandler> fmt::Debug for TouchInnerHandle<'_, D> {
405    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406        f.debug_struct("TouchInnerHandle")
407            .field("inner", &self.inner)
408            .field("seat", &self.seat.arc.name)
409            .finish()
410    }
411}
412
413impl<D: SeatHandler + 'static> TouchInnerHandle<'_, D> {
414    /// Change the current grab on this pointer to the provided grab
415    ///
416    /// Overwrites any current grab.
417    pub fn set_grab<G: TouchGrab<D> + 'static>(
418        &mut self,
419        handler: &mut dyn TouchGrab<D>,
420        data: &mut D,
421        serial: Serial,
422        grab: G,
423    ) {
424        handler.unset(data);
425        self.inner.set_grab(data, self.seat, serial, grab);
426    }
427
428    /// Remove any current grab on this pointer, resetting it to the default behavior
429    ///
430    /// This will also restore the focus of the underlying pointer if restore_focus
431    /// is [`true`]
432    pub fn unset_grab(&mut self, handler: &mut dyn TouchGrab<D>, data: &mut D) {
433        handler.unset(data);
434        self.inner.unset_grab(data, self.seat);
435    }
436
437    /// Notify that a new touch point appeared
438    ///
439    /// You provide the location of the touch, in the form of:
440    ///
441    /// - The coordinates of the touch in the global compositor space
442    /// - The surface on top of which the touch point is, and the coordinates of its
443    ///   origin in the global compositor space (or `None` of the touch is not
444    ///   on top of a client surface).
445    pub fn down(
446        &mut self,
447        data: &mut D,
448        focus: Option<(<D as SeatHandler>::TouchFocus, Point<f64, Logical>)>,
449        event: &DownEvent,
450        seq: Serial,
451    ) {
452        self.inner.down(data, self.seat, focus, event, seq)
453    }
454
455    /// Notify that a touch point disappeared
456    pub fn up(&mut self, data: &mut D, event: &UpEvent, seq: Serial) {
457        self.inner.up(data, self.seat, event, seq)
458    }
459
460    /// Notify that a touch point has changed coordinates.
461    ///
462    /// You provide the location of the touch, in the form of:
463    ///
464    /// - The coordinates of the touch in the global compositor space
465    /// - The surface on top of which the touch point is, and the coordinates of its
466    ///   origin in the global compositor space (or `None` of the touch is not
467    ///   on top of a client surface).
468    ///
469    /// **Note** that this will **not** update the focus of the touch point, the focus
470    /// is only set on [`TouchHandle::down`]. The focus provided to this function
471    /// can be used to find DnD targets during touch motion.
472    pub fn motion(
473        &mut self,
474        data: &mut D,
475        focus: Option<(<D as SeatHandler>::TouchFocus, Point<f64, Logical>)>,
476        event: &MotionEvent,
477        seq: Serial,
478    ) {
479        self.inner.motion(data, self.seat, focus, event, seq)
480    }
481
482    /// Notify about the end of a set of events that logically belong together.
483    ///
484    /// This needs to be called after one or move calls to [`TouchHandle::down`] or [`TouchHandle::motion`]
485    pub fn frame(&mut self, data: &mut D, seq: Serial) {
486        self.inner.frame(data, self.seat, seq)
487    }
488
489    /// Notify that a touch point has changed its shape.
490    pub fn shape(&mut self, data: &mut D, event: &ShapeEvent, seq: Serial) {
491        self.inner.shape(data, self.seat, event, seq)
492    }
493
494    /// Notify that a touch point has changed its orientation.
495    pub fn orientation(&mut self, data: &mut D, event: &OrientationEvent, seq: Serial) {
496        self.inner.orientation(data, self.seat, event, seq)
497    }
498
499    /// Notify that the touch session has been cancelled.
500    ///
501    /// Use in case you decide the touch stream is a global gesture.
502    /// This will remove all current focus targets, and no further events will be sent
503    /// until a new touch point appears.
504    pub fn cancel(&mut self, data: &mut D, seq: Serial) {
505        self.inner.cancel(data, self.seat, seq)
506    }
507}
508
509impl<D: SeatHandler + 'static> TouchInternal<D> {
510    fn new<F>(default_grab: F) -> Self
511    where
512        F: Fn() -> Box<dyn TouchGrab<D>> + Send + 'static,
513    {
514        Self {
515            focus: Default::default(),
516            seq_counter: SerialCounter::new(),
517            default_grab: Box::new(default_grab),
518            grab: GrabStatus::None,
519        }
520    }
521
522    fn set_grab<G: TouchGrab<D> + 'static>(
523        &mut self,
524        data: &mut D,
525        _seat: &Seat<D>,
526        serial: Serial,
527        grab: G,
528    ) {
529        if let GrabStatus::Active(_, handler) = &mut self.grab {
530            handler.unset(data);
531        }
532        self.grab = GrabStatus::Active(serial, Box::new(grab));
533    }
534
535    fn unset_grab(&mut self, data: &mut D, _seat: &Seat<D>) {
536        if let GrabStatus::Active(_, handler) = &mut self.grab {
537            handler.unset(data);
538        }
539        self.grab = GrabStatus::None;
540    }
541
542    fn down(
543        &mut self,
544        data: &mut D,
545        seat: &Seat<D>,
546        focus: Option<(<D as SeatHandler>::TouchFocus, Point<f64, Logical>)>,
547        event: &DownEvent,
548        seq: Serial,
549    ) {
550        self.focus
551            .entry(event.slot)
552            .and_modify(|state| {
553                state.pending = seq;
554                state.frame_pending = None;
555                state.focus.clone_from(&focus);
556            })
557            .or_insert_with(|| TouchSlotState {
558                focus,
559                frame_pending: None,
560                pending: seq,
561                current: None,
562            });
563        let state = self.focus.get(&event.slot).unwrap();
564        if let Some((focus, loc)) = state.focus.as_ref() {
565            let mut new_event = event.clone();
566            new_event.location -= *loc;
567            focus.down(seat, data, &new_event, seq);
568        }
569    }
570
571    fn up(&mut self, data: &mut D, seat: &Seat<D>, event: &UpEvent, seq: Serial) {
572        let Some(state) = self.focus.get_mut(&event.slot) else {
573            return;
574        };
575        state.pending = seq;
576        if let Some((focus, _)) = state.focus.take() {
577            focus.up(seat, data, event, seq);
578
579            // Keep the focus around to be able to send a frame event after up, but move
580            // it out of the current focus to prevent sending other events.
581            state.frame_pending = Some(focus);
582        }
583    }
584
585    fn motion(
586        &mut self,
587        data: &mut D,
588        seat: &Seat<D>,
589        _focus: Option<(<D as SeatHandler>::TouchFocus, Point<f64, Logical>)>,
590        event: &MotionEvent,
591        seq: Serial,
592    ) {
593        let Some(state) = self.focus.get_mut(&event.slot) else {
594            return;
595        };
596        state.pending = seq;
597        if let Some((focus, loc)) = state.focus.as_ref() {
598            let mut new_event = event.clone();
599            new_event.location -= *loc;
600            focus.motion(seat, data, &new_event, seq);
601        }
602    }
603
604    fn frame(&mut self, data: &mut D, seat: &Seat<D>, seq: Serial) {
605        for state in self.focus.values_mut() {
606            if state.current.map(|c| c >= state.pending).unwrap_or(false) {
607                continue;
608            }
609            state.current = Some(seq);
610
611            // Send the frame event for any stored focus in the up handler
612            if let Some(focus) = state.frame_pending.take() {
613                focus.frame(seat, data, seq);
614            }
615
616            if let Some((focus, _)) = state.focus.as_ref() {
617                focus.frame(seat, data, seq);
618            }
619        }
620    }
621
622    fn cancel(&mut self, data: &mut D, seat: &Seat<D>, seq: Serial) {
623        for state in self.focus.values_mut() {
624            if state.current.map(|c| c >= state.pending).unwrap_or(false) {
625                continue;
626            }
627            state.current = Some(seq);
628            if let Some((focus, _)) = state.focus.take() {
629                focus.cancel(seat, data, seq);
630            }
631        }
632    }
633
634    fn shape(&mut self, data: &mut D, seat: &Seat<D>, event: &ShapeEvent, seq: Serial) {
635        let Some(state) = self.focus.get_mut(&event.slot) else {
636            return;
637        };
638        state.pending = seq;
639        if let Some((focus, _)) = state.focus.as_ref() {
640            focus.shape(seat, data, event, seq);
641        }
642    }
643
644    fn orientation(&mut self, data: &mut D, seat: &Seat<D>, event: &OrientationEvent, seq: Serial) {
645        let Some(state) = self.focus.get_mut(&event.slot) else {
646            return;
647        };
648        state.pending = seq;
649        if let Some((focus, _)) = state.focus.as_ref() {
650            focus.orientation(seat, data, event, seq);
651        }
652    }
653
654    fn with_grab<F>(&mut self, data: &mut D, seat: &Seat<D>, f: F)
655    where
656        F: FnOnce(&mut D, &mut TouchInnerHandle<'_, D>, &mut dyn TouchGrab<D>),
657    {
658        let mut grab = std::mem::replace(&mut self.grab, GrabStatus::Borrowed);
659        match grab {
660            GrabStatus::Borrowed => panic!("Accessed a touch grab from within a touch grab access."),
661            GrabStatus::Active(_, ref mut handler) => {
662                // If this grab is associated with a surface that is no longer alive, discard it
663                if let Some((ref focus, _)) = handler.start_data().focus {
664                    if !focus.alive() {
665                        handler.unset(data);
666                        self.grab = GrabStatus::None;
667                        let mut default_grab = (self.default_grab)();
668                        f(
669                            data,
670                            &mut TouchInnerHandle { inner: self, seat },
671                            &mut *default_grab,
672                        );
673                        return;
674                    }
675                }
676                f(data, &mut TouchInnerHandle { inner: self, seat }, &mut **handler);
677            }
678            GrabStatus::None => {
679                let mut default_grab = (self.default_grab)();
680                f(
681                    data,
682                    &mut TouchInnerHandle { inner: self, seat },
683                    &mut *default_grab,
684                );
685            }
686        }
687
688        if let GrabStatus::Borrowed = self.grab {
689            // the grab has not been ended nor replaced, put it back in place
690            self.grab = grab;
691        }
692    }
693}