@@ -4,6 +4,7 @@ use smithay::{
44 KeyState , KeyboardKeyEvent ,
55 PointerAxisEvent , PointerButtonEvent , PointerMotionEvent ,
66 PointerMotionAbsoluteEvent ,
7+ TouchDownEvent , TouchMotionEvent , TouchUpEvent , TouchCancelEvent , TouchEvent ,
78 } ,
89 desktop:: WindowSurfaceType ,
910 input:: {
@@ -13,6 +14,7 @@ use smithay::{
1314 GrabStartData as PointerGrabStartData ,
1415 MotionEvent , PointerGrab , PointerInnerHandle , RelativeMotionEvent ,
1516 } ,
17+ touch:: { DownEvent as TouchDownData , MotionEvent as TouchMotionData , UpEvent as TouchUpData } ,
1618 } ,
1719 reexports:: wayland_server:: protocol:: wl_surface:: WlSurface ,
1820 utils:: { Logical , Point , Rectangle , Size , SERIAL_COUNTER } ,
@@ -32,6 +34,19 @@ pub fn handle_input<B: InputBackend>(state: &mut BlueState, event: InputEvent<B>
3234 }
3335 InputEvent :: PointerButton { event } => handle_pointer_button ( state, & event) ,
3436 InputEvent :: PointerAxis { event } => handle_pointer_axis ( state, & event) ,
37+ // Touch — was entirely absent before (fell into the wildcard
38+ // below and was silently dropped, along with the seat never
39+ // advertising the `touch` capability at all — see
40+ // `render/mod.rs`'s `add_touch()` calls, added alongside this).
41+ InputEvent :: TouchDown { event } => handle_touch_down ( state, & event) ,
42+ InputEvent :: TouchMotion { event } => handle_touch_motion ( state, & event) ,
43+ InputEvent :: TouchUp { event } => handle_touch_up ( state, & event) ,
44+ InputEvent :: TouchCancel { event } => handle_touch_cancel ( state, & event) ,
45+ InputEvent :: TouchFrame { .. } => {
46+ if let Some ( touch) = state. seat . get_touch ( ) {
47+ touch. frame ( state) ;
48+ }
49+ }
3550 _ => { }
3651 }
3752}
@@ -731,6 +746,120 @@ pub fn start_resize_grab(
731746 ) ;
732747}
733748
749+ // ── Touch ────────────────────────────────────────────────────────────────
750+ //
751+ // New — this seat previously never advertised the `touch` capability at
752+ // all (see `render/mod.rs`'s `add_touch()` calls, added alongside this),
753+ // so every `InputEvent::Touch*` variant fell into `handle_input`'s
754+ // wildcard and was silently dropped, regardless of what hardware sent
755+ // them (a touchscreen, or the winit backend's own touch emulation when
756+ // nested inside a host compositor that has one).
757+ //
758+ // Written without a compiler available to verify the exact smithay
759+ // touch API surface at this pinned rev against (same caveat this file's
760+ // pointer/keyboard code doesn't need anymore having presumably been
761+ // fixed against real compile errors already, but genuinely applies here
762+ // since touch is new) — structured to mirror the pointer handlers
763+ // directly above as closely as the wl_touch protocol's actual semantics
764+ // allow, which is the one thing I'm confident about regardless of exact
765+ // method signatures: unlike wl_pointer, focus for a given touch point
766+ // is resolved *once*, at touch-down, from the touch point's position at
767+ // that moment — motion/up for that same touch id then keep going to
768+ // whatever surface was under it at down, even if the finger slides off
769+ // that surface's bounds entirely (real wl_touch protocol behavior, not
770+ // specific to this compositor).
771+
772+ /// Resolves which surface (if any) is under a global point — the same
773+ /// hit-testing `update_pointer_focus` above already does for the
774+ /// pointer, factored out so touch-down can reuse it without duplicating
775+ /// the `space.element_under` + `surface_under` dance.
776+ fn surface_under_point ( state : & BlueState , pos : Point < f64 , Logical > ) -> Option < ( WlSurface , Point < f64 , Logical > ) > {
777+ state
778+ . space
779+ . element_under ( pos)
780+ . and_then ( |( win, win_loc) | {
781+ let rel = pos - win_loc. to_f64 ( ) ;
782+ win. surface_under ( rel, WindowSurfaceType :: ALL )
783+ . map ( |( s, sp) | ( s, ( win_loc + sp) . to_f64 ( ) ) )
784+ } )
785+ }
786+
787+ /// Touch is inherently absolute (a touchscreen's coordinate space maps
788+ /// directly onto the output, same reasoning as
789+ /// `PointerMotionAbsoluteEvent::position_transformed` above) — this
790+ /// mirrors `handle_pointer_motion_abs`'s own output-size lookup exactly
791+ /// rather than introducing a second way to get it.
792+ fn output_size_for_touch ( state : & BlueState ) -> Size < i32 , Logical > {
793+ state
794+ . space
795+ . outputs ( )
796+ . next ( )
797+ . and_then ( |o| state. space . output_geometry ( o) )
798+ . map ( |g| g. size )
799+ . unwrap_or ( Size :: from ( ( 1920 , 1080 ) ) )
800+ }
801+
802+ fn handle_touch_down < B : InputBackend , E : TouchDownEvent < B > > ( state : & mut BlueState , event : & E ) {
803+ let Some ( touch) = state. seat . get_touch ( ) else { return } ;
804+ let serial = SERIAL_COUNTER . next_serial ( ) ;
805+ let size = output_size_for_touch ( state) ;
806+ let position = event. position_transformed ( size) ;
807+ let focus = surface_under_point ( state, position) ;
808+
809+ touch. down (
810+ state,
811+ focus,
812+ & TouchDownData {
813+ slot : event. slot ( ) ,
814+ location : position,
815+ serial,
816+ time : event. time_msec ( ) ,
817+ } ,
818+ ) ;
819+ }
820+
821+ fn handle_touch_motion < B : InputBackend , E : TouchMotionEvent < B > > ( state : & mut BlueState , event : & E ) {
822+ let Some ( touch) = state. seat . get_touch ( ) else { return } ;
823+ let size = output_size_for_touch ( state) ;
824+ let position = event. position_transformed ( size) ;
825+ // Per wl_touch semantics (see this section's own header note): focus
826+ // for this slot was already fixed at touch-down and isn't
827+ // re-resolved here — passed as `None` on the theory that smithay's
828+ // `TouchHandle::motion` looks up the slot's already-established
829+ // focus internally (mirroring how `PointerHandle::motion` is the
830+ // one that takes an explicit focus, but touch's per-slot routing is
831+ // a different enough model that it may not need it passed again).
832+ // Flagged clearly since this is the least-confident guess in this
833+ // whole section.
834+ touch. motion (
835+ state,
836+ None ,
837+ & TouchMotionData {
838+ slot : event. slot ( ) ,
839+ location : position,
840+ time : event. time_msec ( ) ,
841+ } ,
842+ ) ;
843+ }
844+
845+ fn handle_touch_up < B : InputBackend , E : TouchUpEvent < B > > ( state : & mut BlueState , event : & E ) {
846+ let Some ( touch) = state. seat . get_touch ( ) else { return } ;
847+ let serial = SERIAL_COUNTER . next_serial ( ) ;
848+ touch. up (
849+ state,
850+ & TouchUpData {
851+ slot : event. slot ( ) ,
852+ serial,
853+ time : event. time_msec ( ) ,
854+ } ,
855+ ) ;
856+ }
857+
858+ fn handle_touch_cancel < B : InputBackend , E : TouchCancelEvent < B > > ( state : & mut BlueState , _event : & E ) {
859+ let Some ( touch) = state. seat . get_touch ( ) else { return } ;
860+ touch. cancel ( state) ;
861+ }
862+
734863#[ cfg( test) ]
735864mod resize_edges_tests {
736865 use super :: ResizeEdges ;
0 commit comments