ltk/input/pointer/
scroll.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
83
84
85
86
87
88
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

use smithay_client_toolkit::seat::pointer::{ PointerEvent, PointerEventKind };
use smithay_client_toolkit::reexports::client::
{
	protocol::{ wl_pointer, wl_pointer::WlPointer },
	Connection, QueueHandle,
};

use crate::app::App;
use crate::event_loop::{ AppData, SurfaceFocus };

impl<A: App> AppData<A>
{
	pub( super ) fn on_pointer_axis(
		&mut self,
		_conn:    &Connection,
		_qh:      &QueueHandle<Self>,
		_pointer: &WlPointer,
		event:    &PointerEvent,
	)
	{
		let focus = self.focus_for_surface( &event.surface )
			.unwrap_or( SurfaceFocus::Main );
		let ( horizontal, vertical, source ) = if let PointerEventKind::Axis { horizontal, vertical, source, .. } = event.kind
		{
			( horizontal, vertical, source )
		} else {
			return;
		};
		let pos = self.surface( focus ).to_physical( event.position.0, event.position.1 );
		let scroll_hit =
		{
			let ss = self.surface( focus );
			ss.scroll_rects.iter()
				.find( |( r, _, _ )| r.contains( pos ) )
				.map( |( _, idx, ax )| ( *idx, *ax ) )
		};
		if let Some( ( scroll_idx, axis ) ) = scroll_hit
		{
			let multiplier = match source
			{
				Some( wl_pointer::AxisSource::Wheel ) => 10.0,
				_                                      => 1.0,
			};
			let step_x = horizontal.absolute as f32 * multiplier;
			let step_y = vertical.absolute   as f32 * multiplier;
			let ss     = self.surface_mut( focus );
			let entry  = ss.scroll_offsets.entry( scroll_idx ).or_insert( ( 0.0, 0.0 ) );
			// Wheels report on a single axis at a time; route to
			// whichever axis the viewport allows. A pure horizontal
			// viewport translates a vertical wheel into horizontal
			// motion (the conventional shift-less wheel-to-strip UX);
			// `Both` keeps each axis independent.
			match axis
			{
				crate::widget::scroll::ScrollAxis::Vertical =>
				{
					entry.1 = ( entry.1 + step_y ).max( 0.0 );
				}
				crate::widget::scroll::ScrollAxis::Horizontal =>
				{
					entry.0 = ( entry.0 + step_x + step_y ).max( 0.0 );
				}
				crate::widget::scroll::ScrollAxis::Both =>
				{
					entry.0 = ( entry.0 + step_x ).max( 0.0 );
					entry.1 = ( entry.1 + step_y ).max( 0.0 );
				}
			}
			ss.request_redraw();
		} else {
			// No LTK scroll viewport under the cursor —
			// surface the raw axis to the app so embedded
			// content (e.g. a WPE view) can handle scrolling
			// itself.
			let multiplier = match source
			{
				Some( wl_pointer::AxisSource::Wheel ) => 10.0,
				_                                      => 1.0,
			};
			let dx = horizontal.absolute as f32 * multiplier;
			let dy = vertical.absolute   as f32 * multiplier;
			self.app.on_pointer_axis( pos.x, pos.y, dx, dy );
		}
	}
}