ltk/input/pointer/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
//! Wayland pointer → ltk dispatch.
//!
//! Each `wl_pointer` event (motion / press / release / axis) translates
//! into a call on the surface's [`GestureState`](super::gesture::GestureState)
//! plus the follow-up side-effects that can only live at the
//! [`AppData`] level (pending-message push, surface redraw, dirty-cache
//! invalidation, window move). The pointer handler adds three things
//! touch does not have:
//!
//! * **Hover tracking** — motion updates `SurfaceState::hovered_idx`
//! before delegating the motion to the gesture machine, since the
//! hovered widget drives visual state independent of whether a press
//! is active.
//! * **Title-bar interaction** — a press inside the client-side title
//! bar either closes the window (close button hit) or initiates a
//! compositor-driven window move. Neither path goes through the
//! gesture machine.
//! * **Wheel / axis scroll** — routed directly into the per-viewport
//! `scroll_offsets` map; axis events do not have a press/release
//! lifecycle so they bypass the state machine entirely.
use smithay_client_toolkit::seat::pointer::{ PointerEvent, PointerEventKind, PointerHandler };
use smithay_client_toolkit::reexports::client::
{
protocol::wl_pointer::WlPointer,
Connection, QueueHandle,
};
use crate::app::App;
use crate::event_loop::{ AppData, SurfaceFocus };
pub( crate ) mod enter;
pub( crate ) mod motion;
pub( crate ) mod press;
pub( crate ) mod release;
pub( crate ) mod scroll;
pub( crate ) mod helpers;
impl<A: App> PointerHandler for AppData<A>
{
fn pointer_frame(
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
pointer: &WlPointer,
events: &[PointerEvent],
)
{
for event in events
{
let focus = self.focus_for_surface( &event.surface )
.unwrap_or( SurfaceFocus::Main );
self.pointer_focus = focus;
match event.kind
{
PointerEventKind::Enter { .. } => self.on_pointer_enter( conn, qh, pointer, event ),
PointerEventKind::Motion { .. } => self.on_pointer_motion( conn, qh, pointer, event ),
PointerEventKind::Press { button: 0x110, .. } => self.on_pointer_left_press( conn, qh, pointer, event ),
PointerEventKind::Press { button: 0x111, .. } => self.on_pointer_right_click( conn, qh, pointer, event ),
PointerEventKind::Release { button: 0x110, .. } => self.on_pointer_release( conn, qh, pointer, event ),
PointerEventKind::Axis { .. } => self.on_pointer_axis( conn, qh, pointer, event ),
_ => {}
}
}
}
}