diff options
| author | srdusr <[email protected]> | 2025-02-13 01:14:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2025-02-13 01:14:00 +0200 |
| commit | ed0b8ecf6c08d920ffd1b52c9dc6a24a436ce977 (patch) | |
| tree | 0841a1a8d13a5f36a89f611dde27e6cb9db31c5b /crates/wayland/src/state | |
| parent | b1d69a552cdcc7370c4befd42ef2111c8b367c46 (diff) | |
| download | srdwm-ed0b8ecf6c08d920ffd1b52c9dc6a24a436ce977.tar.gz srdwm-ed0b8ecf6c08d920ffd1b52c9dc6a24a436ce977.zip | |
Implement the Wayland implicit pointer grab
Every pointer motion event re-ran the same popup/layer/content hit-test
from scratch and delivered focus to whatever it found right now - there
was no notion of "a button is held, keep delivering to the surface that
received the press" at all, which is standard, expected Wayland
compositor behavior (every real compositor does this; it's how dragging,
text selection, and scrollbar-thumb dragging all stay coherent even when
the pointer briefly leaves the widget's bounds mid-gesture).
Without it, a real human's hand drifting even slightly outside the
pressed surface mid-drag - trivially easy during a fast, non-perfectly-
straight mouse motion - sent that client an unrequested `leave` event in
the middle of its own gesture. GTK's drag recognizers (a GtkHeaderBar's
move-the-window gesture, concretely) treat a mid-gesture leave as "this
isn't coherent, abort," which reads as "dragging this window by its
title bar does nothing at all" - live-reproduced this work on Nemo,
and consistent with move_request never having fired once all session
despite real attempts.
pointer_button_grab captures the (surface, origin) resolved on a button
press once the held-button count goes from 0 to 1, and every event under
the grab - motion or button, this press's or a later one overlapping
it - is delivered there instead of wherever a fresh hit-test lands,
until every held button is back up.
Diffstat (limited to 'crates/wayland/src/state')
| -rw-r--r-- | crates/wayland/src/state/mod.rs | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/crates/wayland/src/state/mod.rs b/crates/wayland/src/state/mod.rs index 5643ebc..084e407 100644 --- a/crates/wayland/src/state/mod.rs +++ b/crates/wayland/src/state/mod.rs @@ -475,6 +475,35 @@ pub(crate) struct CompState { /// event this session's earlier per-motion diagnostic-logging /// regression already proved is worth being careful around) needs one. pub(crate) last_idle_notify: Option<Instant>, + /// The Wayland-standard "implicit grab": once a pointer button goes + /// down over a surface, every subsequent motion/button event - no + /// matter where the pointer physically ends up - has to keep being + /// delivered to that *same* surface until every held button is + /// released, not whatever a fresh hit-test happens to land on next. + /// Nothing implemented this before: every motion event re-ran the same + /// popup/layer/content hit-test from scratch and called `pointer. + /// motion()` with whatever it found *right now*, so the moment a real + /// human's hand drifted even slightly outside the pressed surface's own + /// bounds mid-gesture (trivially easy during a fast drag - a mouse + /// does not move in a perfectly straight line), that client received an + /// unrequested `leave` in the middle of its own gesture. GTK's drag + /// recognizers (a `GtkHeaderBar`'s move-the-window gesture, concretely) + /// treat a mid-gesture `leave` as "this isn't coherent, abort" - which + /// reads as "dragging this window's title bar does nothing at all," + /// live-reproduced this session. `(surface, origin)` is captured once, + /// from the same resolution `refresh_pointer_focus` already computes, + /// the instant the held-button count goes from 0 to 1; `origin` is + /// reused for every event under the grab so surface-local coordinates + /// keep updating correctly even though the target surface no longer + /// does. + pub(crate) pointer_button_grab: Option<(WlSurface, Point<f64, Logical>)>, + /// How many pointer buttons are currently held - what actually decides + /// when [`Self::pointer_button_grab`] starts (0 -> 1) and ends (only + /// once every button, not just one of several held at once, comes back + /// up), matching the real Wayland implicit-grab rule instead of the + /// single-button assumption that would break as soon as a drag and a + /// second accidental button overlapped. + pub(crate) pointer_buttons_held: u32, /// Windows currently mid-tween - see `WindowAnim` and `sync_geometry`'s /// `anim_from` handling. Driven forward once per frame by /// `tick_animations`, called from both backends' poll loops. |