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 ),
				_ => {}
			}
		}
	}
}