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
70
71
72
73
74
75
76
77
78
79
80
81
82
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

//! Pointer → ltk dispatch.
//!
//! Each [`PointerInput`] (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 crate::app::App;
use crate::event_loop::AppData;
use crate::platform::Platform;

use super::event::{ PointerButton, PointerInput, PointerKind };

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, P: Platform> AppData<A, P>
{
	/// The entry point for a mouse or a touchpad. See [`super::event`].
	pub( crate ) fn pointer_input( &mut self, input: &PointerInput )
	{
		self.pointer_focus = input.focus;
		self.report_mouse_button( input );
		match input.kind
		{
			PointerKind::Enter                          => self.on_pointer_enter( input.focus ),
			PointerKind::Leave                          => self.app.on_pointer_hover( input.focus.target(), None ),
			PointerKind::Motion                         => self.on_pointer_motion( input ),
			PointerKind::Press( PointerButton::Left )   => self.on_pointer_left_press( input ),
			PointerKind::Press( PointerButton::Right )  => self.on_pointer_right_click( input ),
			PointerKind::Press( PointerButton::Middle ) => self.on_pointer_middle_press( input ),
			PointerKind::Press( PointerButton::Back )   => self.handle_back( input.focus ),
			PointerKind::Release( PointerButton::Left ) => self.on_pointer_release( input ),
			PointerKind::Axis { horizontal, vertical, source } => self.on_pointer_axis( input, horizontal, vertical, source ),
			_ => {}
		}
	}

	/// Hand a press or release of the left, middle or right button to [`App::on_mouse_button`].
	fn report_mouse_button( &mut self, input: &PointerInput )
	{
		let ( button, pressed ) = match input.kind
		{
			PointerKind::Press( button )   => ( button, true ),
			PointerKind::Release( button ) => ( button, false ),
			_                              => return,
		};
		let Some( button ) = button.mouse_button() else { return };
		let pos = self.surface( input.focus ).to_physical( input.position.0, input.position.1 );
		self.app.on_mouse_button( &crate::app::MouseButtonEvent
		{
			button,
			x:     pos.x,
			y:     pos.y,
			pressed,
			ctrl:  self.ctrl_pressed,
			shift: self.shift_pressed,
			alt:   self.alt_pressed,
		} );
	}
}