https://bugs.kde.org/show_bug.cgi?id=478321

[email protected] changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |[email protected]

--- Comment #5 from [email protected] ---
I can reproduce this reliably on a fast 4-finger swipe (touchpad, Plasma
5.27.12 / libinput, Wayland), and traced down what I believe is the actual root
cause.

**Mechanism**

GlobalShortcutsManager wires BOTH SwipeGesture::triggered and
SwipeGesture::cancelled to the same QAction::trigger(), via
Qt::QueuedConnection (globalshortcuts.cpp).

Meanwhile, GestureRecognizer::updateSwipeGesture() (gestures.cpp) eliminates
the "wrong direction" sibling gesture candidate on the very first update of a
swipe, not after some threshold of travel. On a fast swipe, by the time that
queued cancelled signal actually runs (it's delayed behind the current libinput
event batch), the direct progress() callback has already pushed
VirtualDesktopManager's accumulated offset past the switch threshold from the
OTHER (still-active) gesture.

So you get:
1. The real gesture's progress callback commits a desktop switch (correct).
2. The eliminated sibling gesture's queued `cancelled` fires late, and because
`cancelled` is ALSO wired to the switch action, it commits a second, spurious
switch.

This explains why the bug caps at exactly one extra switch per fast swipe
(never more) - there's only one eliminated sibling to produce one stray queued
signal.

**Why "just treat cancelled as a no-op" doesn't work**

I first assumed the fix was to stop `cancelled` from ever triggering a switch.
That's wrong: `VirtualDesktopManager`'s `endSwipeGesture()` legitimately
commits a switch via the `cancelled` path too, for any swipe that ends between
roughly 25-99% of the travel threshold. Removing that would break normal
partial swipes.

**Fix that actually works, tested locally**

Add a way to ask "is a swipe still structurally active right now":
- `GestureRecognizer::hasActiveSwipeGesture()` - trivial,
`!m_activeSwipeGestures.isEmpty()`.
- `GlobalShortcutsManager::isSwipeGestureInProgress()` - exposes that through
the shortcuts manager.

Then, at the top of
`VirtualDesktopManager::gestureReleasedX()`/`gestureReleasedY()`, return early
(skip the queued release) if a swipe gesture is still in progress. A queued
release firing while another swipe is still structurally active is exactly the
late-sibling-cancellation case above; a genuine end-of-gesture release (whether
via `triggered` or `cancelled`) only ever fires once nothing else is active, so
this doesn't affect normal swipes at all.

I've built and tested this on 5.27.12 (backported from master's
`VirtualDesktopManager`/`GestureRecognizer`/`GlobalShortcutsManager`), and it's
fixed the double-switch for me across repeated fast-swipe testing with no
regressions on normal partial swipes. Happy to clean this up into a proper MR
against master if that's useful - let me know.

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to