diff --git a/src/input/mod.rs b/src/input/mod.rs index ab21346f08a8..3eb66da73716 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -126,12 +126,15 @@ use std::{ use tracing::{info_span, instrument}; -use self::pointer::{CursorImageStatus, PointerHandle, PointerTarget}; use self::touch::TouchTarget; use self::{ keyboard::{Error as KeyboardError, KeyboardHandle, KeyboardTarget, LedState}, touch::TouchHandle, }; +use self::{ + pointer::{CursorImageStatus, PointerHandle, PointerTarget}, + touch::TouchGrab, +}; use crate::utils::user_data::UserDataMap; pub mod keyboard; @@ -592,8 +595,23 @@ impl Seat { /// let touch_handle = seat.add_touch(); /// ``` pub fn add_touch(&mut self) -> TouchHandle { + Self::add_touch_with_default_grab(self, || Box::new(touch::DefaultGrab)) + } + + /// Adds the touch capability to this seat and allows the use of a custom default [`TouchGrab`] + /// + /// The default grab is used in case no other grab is currently active. When using [`Seat::add_touch`] + /// it will use [`touch::DefaultGrab`] which will install [`touch::TouchDownGrab`] on the first touch point. + /// [`touch::TouchDownGrab`] makes sure all further touch points will use the same target until all touch + /// points are released again. + /// + /// See [`Seat::add_touch`] for more information + pub fn add_touch_with_default_grab(&mut self, defaut_grab: F) -> TouchHandle + where + F: Fn() -> Box> + Send + 'static, + { let mut inner = self.arc.inner.lock().unwrap(); - let touch = TouchHandle::new(); + let touch = TouchHandle::new(defaut_grab); if inner.touch.is_some() { // If there's already a tocuh device, remove it notify the clients about the change. inner.touch = None; diff --git a/src/input/touch/grab.rs b/src/input/touch/grab.rs index a73c5e4c53b9..bf0c81140934 100644 --- a/src/input/touch/grab.rs +++ b/src/input/touch/grab.rs @@ -144,8 +144,9 @@ impl fmt::Debug for GrabStatus { } } -// The default grab, the behavior when no particular grab is in progress -pub(super) struct DefaultGrab; +/// The default grab, the behavior when no particular grab is in progress +#[derive(Debug)] +pub struct DefaultGrab; impl TouchGrab for DefaultGrab { fn down( @@ -160,7 +161,7 @@ impl TouchGrab for DefaultGrab { handle.set_grab( data, event.serial, - ClickGrab { + TouchDownGrab { start_data: GrabStartData { focus, slot: event.slot, @@ -199,17 +200,28 @@ impl TouchGrab for DefaultGrab { } } -// A click grab, basic grab started when an user clicks a surface -// to maintain it focused until the user releases the click. -// -// In case the user maintains several simultaneous clicks, release -// the grab once all are released. -struct ClickGrab { - start_data: GrabStartData, - touch_points: usize, +/// A touch down grab, basic grab started when an user touches a surface +/// to maintain it focused until the user releases the touch. +/// +/// In case the user maintains several simultaneous touch points, release +/// the grab once all are released. +pub struct TouchDownGrab { + /// Start date for this grab + pub start_data: GrabStartData, + /// Currently active touch points + pub touch_points: usize, +} + +impl fmt::Debug for TouchDownGrab { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TouchDownGrab") + .field("start_data", &self.start_data) + .field("touch_points", &self.touch_points) + .finish() + } } -impl TouchGrab for ClickGrab { +impl TouchGrab for TouchDownGrab { fn down( &mut self, data: &mut D, diff --git a/src/input/touch/mod.rs b/src/input/touch/mod.rs index f57d89d6203b..21b4e92c19a2 100644 --- a/src/input/touch/mod.rs +++ b/src/input/touch/mod.rs @@ -9,8 +9,8 @@ use tracing::{info_span, instrument}; use crate::backend::input::TouchSlot; use crate::utils::{IsAlive, Logical, Point, Serial, SerialCounter}; -use self::grab::{DefaultGrab, GrabStatus}; -pub use grab::{GrabStartData, TouchGrab}; +use self::grab::GrabStatus; +pub use grab::{DefaultGrab, GrabStartData, TouchDownGrab, TouchGrab}; use super::{Seat, SeatHandler}; @@ -78,6 +78,7 @@ impl std::cmp::Eq for TouchHandle {} pub(crate) struct TouchInternal { focus: HashMap>, seq_counter: SerialCounter, + default_grab: Box Box> + Send + 'static>, grab: GrabStatus, } @@ -210,9 +211,12 @@ where } impl TouchHandle { - pub(crate) fn new() -> TouchHandle { + pub(crate) fn new(default_grab: F) -> TouchHandle + where + F: Fn() -> Box> + Send + 'static, + { TouchHandle { - inner: Arc::new(Mutex::new(TouchInternal::new())), + inner: Arc::new(Mutex::new(TouchInternal::new(default_grab))), #[cfg(feature = "wayland_frontend")] known_instances: Arc::new(Mutex::new(Vec::new())), span: info_span!("input_touch"), @@ -449,10 +453,14 @@ impl<'a, D: SeatHandler + 'static> TouchInnerHandle<'a, D> { } impl TouchInternal { - fn new() -> Self { + fn new(default_grab: F) -> Self + where + F: Fn() -> Box> + Send + 'static, + { Self { focus: Default::default(), seq_counter: SerialCounter::new(), + default_grab: Box::new(default_grab), grab: GrabStatus::None, } } @@ -563,14 +571,16 @@ impl TouchInternal { if let Some((ref focus, _)) = handler.start_data().focus { if !focus.alive() { self.grab = GrabStatus::None; - f(&mut TouchInnerHandle { inner: self, seat }, &mut DefaultGrab); + let mut default_grab = (self.default_grab)(); + f(&mut TouchInnerHandle { inner: self, seat }, &mut *default_grab); return; } } f(&mut TouchInnerHandle { inner: self, seat }, &mut **handler); } GrabStatus::None => { - f(&mut TouchInnerHandle { inner: self, seat }, &mut DefaultGrab); + let mut default_grab = (self.default_grab)(); + f(&mut TouchInnerHandle { inner: self, seat }, &mut *default_grab); } }