ltk: opt-in raw touch stream for apps that consume input themselves
Add App::claims_raw_touch(), an opt-in hook that routes the primary finger through the raw on_touch_down/move/up callbacks instead of the built-in single-slot gesture machine. Until now the primary finger was consumed entirely by the widget gesture machine (taps, swipes, presses) and never reached the app, which made it impossible to drive a self-contained input consumer like an embedded WebView or a game canvas from a touchscreen: the widget tree saw the taps, the embedded content never did. With the hook active every finger surfaces verbatim through the raw stream, widget gestures never arm, and per-finger positions are cached in SurfaceState::touch_slots for all slots so wl_touch.up (which carries no coordinates) can still report a release point. The touch module doc and the on_touch_down docs are updated to describe the new contract; the default remains unchanged for every existing app. Pin the transitive dependency ignore to 0.4.23: rust-i18n pulls it via globwalk, 0.4.24+ requires a rustc newer than Debian's 1.85, and its manifest does not declare that MSRV, so a fresh resolution breaks the build on stable.
This commit is contained in:
@@ -43,6 +43,9 @@ rustybuzz = "0.14"
|
||||
image = { version = "=0.25.9", default-features = false, features = ["png", "jpeg", "webp"] }
|
||||
resvg = "0.44"
|
||||
rust-i18n = "3"
|
||||
# Transitive dep of rust-i18n (globwalk → ignore); 0.4.24+ needs a rustc
|
||||
# newer than Debian's 1.85, and its manifest does not declare that MSRV.
|
||||
ignore = "=0.4.23"
|
||||
wayland-protocols = { version = "0.32", features = ["client", "unstable", "staging"] }
|
||||
wayland-egl = "0.32"
|
||||
khronos-egl = { version = "6", features = ["dynamic"] }
|
||||
|
||||
12
src/app.rs
12
src/app.rs
@@ -602,6 +602,10 @@ pub trait App: 'static
|
||||
/// built-in single-slot machine cannot model. `(x, y)` are in
|
||||
/// physical pixels, matching the coordinate space of
|
||||
/// [`Self::on_pointer_move`].
|
||||
///
|
||||
/// When [`Self::claims_raw_touch`] returns `true` the primary
|
||||
/// finger arrives here as well, instead of driving the gesture
|
||||
/// machine.
|
||||
fn on_touch_down( &mut self, _id: i64, _x: f32, _y: f32 ) {}
|
||||
/// See [`Self::on_touch_down`].
|
||||
fn on_touch_move( &mut self, _id: i64, _x: f32, _y: f32 ) {}
|
||||
@@ -609,6 +613,14 @@ pub trait App: 'static
|
||||
/// position of the finger (`wl_touch.up` does not carry one).
|
||||
fn on_touch_up( &mut self, _id: i64, _x: f32, _y: f32 ) {}
|
||||
|
||||
/// Return `true` to receive the *primary* finger through the raw
|
||||
/// [`Self::on_touch_down`] / move / up stream as well, bypassing
|
||||
/// the built-in single-slot gesture machine entirely — widget
|
||||
/// presses, taps and swipes stop working on touch. For apps whose
|
||||
/// surface is one self-contained input consumer (an embedded
|
||||
/// WebView, a game canvas) that needs every finger verbatim.
|
||||
fn claims_raw_touch( &self ) -> bool { false }
|
||||
|
||||
/// Pointer of a cross-application drag-and-drop entered or moved
|
||||
/// inside the main surface. `(x, y)` is in logical pixels.
|
||||
fn on_drop_motion( &mut self, _x: f32, _y: f32 ) {}
|
||||
|
||||
@@ -26,6 +26,13 @@
|
||||
//! per touch id, so an auxiliary slot that landed on an overlay
|
||||
//! keeps reporting through that overlay's `App` callback even if
|
||||
//! the finger drifts over the main surface.
|
||||
//!
|
||||
//! Apps that return `true` from [`App::claims_raw_touch`] opt out of
|
||||
//! the primary-slot gesture machine entirely: every finger, primary
|
||||
//! included, surfaces through the raw `on_touch_*` stream, and
|
||||
//! widget presses, taps and swipes never fire. Positions are cached
|
||||
//! in `SurfaceState::touch_slots` for all fingers in that mode so
|
||||
//! `up` can report a release point.
|
||||
|
||||
use smithay_client_toolkit::seat::touch::TouchHandler;
|
||||
use smithay_client_toolkit::reexports::client::
|
||||
@@ -58,6 +65,16 @@ impl<A: App> TouchHandler for AppData<A>
|
||||
let pos = self.surface( focus ).to_physical( position.0, position.1 );
|
||||
self.pointer_pos = pos;
|
||||
|
||||
// Raw-touch apps take every finger verbatim; the gesture
|
||||
// machine never arms. Slots are tracked so `up` (which carries
|
||||
// no position in wl_touch) can report the release point.
|
||||
if self.app.claims_raw_touch()
|
||||
{
|
||||
self.surface_mut( focus ).touch_slots.insert( id, pos );
|
||||
self.app.on_touch_down( id as i64, pos.x, pos.y );
|
||||
return;
|
||||
}
|
||||
|
||||
// Compositor re-grab after the origin surface died mid-drag: this
|
||||
// slot is already our primary and the drag state was migrated here,
|
||||
// so treat the redundant `down` as a continuation, not a restart.
|
||||
@@ -178,6 +195,16 @@ impl<A: App> TouchHandler for AppData<A>
|
||||
)
|
||||
{
|
||||
let focus = self.touch_focus.remove( &id ).unwrap_or( SurfaceFocus::Main );
|
||||
if self.app.claims_raw_touch()
|
||||
{
|
||||
let pos =
|
||||
{
|
||||
let ss = self.surface_mut( focus );
|
||||
ss.touch_slots.remove( &id ).unwrap_or( self.pointer_pos )
|
||||
};
|
||||
self.app.on_touch_up( id as i64, pos.x, pos.y );
|
||||
return;
|
||||
}
|
||||
// Auxiliary release: not the primary slot → recover the last
|
||||
// recorded position for the up callback (Wayland's `wl_touch.up`
|
||||
// does not carry one) and bail before reaching the gesture
|
||||
@@ -227,6 +254,17 @@ impl<A: App> TouchHandler for AppData<A>
|
||||
let focus = *self.touch_focus.get( &id ).unwrap_or( &SurfaceFocus::Main );
|
||||
let pp = self.surface( focus ).to_physical( position.0, position.1 );
|
||||
|
||||
if self.app.claims_raw_touch()
|
||||
{
|
||||
self.pointer_pos = pp;
|
||||
{
|
||||
let ss = self.surface_mut( focus );
|
||||
ss.touch_slots.insert( id, pp );
|
||||
}
|
||||
self.app.on_touch_move( id as i64, pp.x, pp.y );
|
||||
return;
|
||||
}
|
||||
|
||||
let is_primary =
|
||||
{
|
||||
let ss = self.surface( focus );
|
||||
@@ -296,7 +334,8 @@ impl<A: App> TouchHandler for AppData<A>
|
||||
impl<A: App> AppData<A>
|
||||
{
|
||||
/// Drop every in-flight touch gesture across all surfaces, notifying
|
||||
/// the app of any auxiliary slots that were still down. Shared by the
|
||||
/// the app of any slot still down that it was tracking raw (auxiliary
|
||||
/// fingers, or every finger under `claims_raw_touch`). Shared by the
|
||||
/// `wl_touch.cancel` handler and the touch-capability add / remove path
|
||||
/// (suspend / resume on devices that power the touchscreen down): a
|
||||
/// yanked capability never delivers the pending `up` / `cancel`, so
|
||||
|
||||
Reference in New Issue
Block a user