chore: refresco desde el monorepo (pin tawasuyu.git v0.2.0)
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}