ltk/event_loop/
repeat.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
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

use calloop::RegistrationToken;
use smithay_client_toolkit::seat::keyboard::KeyEvent;

/// Snapshot of the key whose repeat timer is currently armed.
///
/// Stored on [`super::app_data::AppData::key_repeat`] between press and
/// release of a held-down key. The timer's calloop callback reads this
/// back to re-dispatch the same `KeyEvent` against the same focus, so a
/// held arrow key keeps moving the cursor in the originally-focused text
/// input even if the focus migrates mid-repeat (which it should not —
/// release cancels the timer, and focus changes only happen via Tab /
/// pointer events that arrive after `release_key` is processed).
pub( crate ) struct KeyRepeatState
{
	pub event: KeyEvent,
	pub token: RegistrationToken,
}

/// Snapshot of the button whose press-and-hold repeat timer is
/// currently armed. Mirrors [`KeyRepeatState`] for pointer / touch
/// presses on a [`crate::widget::button::Button`] built with
/// `.repeating( true )`. The timer's callback re-runs the press
/// against the *current* widget tree: it looks the pressed widget
/// up by `flat_idx` on the focus surface, reads its `on_press`
/// fresh, and pushes that into the pending queue. Re-resolving each
/// tick is what makes a stepper button work — the message a stepper
/// builds is `"go to value + step"` computed at view-build time, so
/// replaying the captured message would re-issue the same target
/// after the first fire and the user would see the value freeze
/// after one step. Reading the live `on_press` instead picks up the
/// new target the time picker just rebuilt with the updated value.
///
/// Cancelled on release, pointer leave, gesture cancel, focus loss
/// and long-press promotion. Also self-cancels on the first tick
/// where the widget at `idx` no longer exists or no longer carries
/// an `on_press` message — view restructuring (e.g. tab switch)
/// invalidates the snapshot and we stop rather than firing the
/// wrong widget's message.
pub( crate ) struct ButtonRepeatState
{
	/// calloop registration handle so [`super::app_data::AppData::stop_button_repeat`]
	/// can remove the timer from the event loop without leaking the
	/// source. The surface focus and pressed `flat_idx` live in
	/// the timer's closure capture instead of here — the only
	/// caller that needs to act on them is the closure itself.
	pub token: RegistrationToken,
}