Skip to content

Fix scroll modifiers getting stuck when TouchPhase::End never arrives - #8636

Open
SulimanAbdulrazzaq wants to merge 1 commit into
emilk:mainfrom
SulimanAbdulrazzaq:fix/wheel-missing-touch-end
Open

SulimanAbdulrazzaq wants to merge 1 commit into
emilk:mainfrom
SulimanAbdulrazzaq:fix/wheel-missing-touch-end

Conversation

@SulimanAbdulrazzaq

Copy link
Copy Markdown
Contributor

winit on Wayland sends TouchPhase::Start for some mouse wheels, but never TouchPhase::End (winit's own comment in its Wayland pointer handler: "the Ended is not guaranteed to be sent for mouse wheels"). Since #7678, WheelState then stays InTouch for good, and in InTouch the modifiers are only ever added to. So after a single ctrl+scroll, every later scroll is a zoom, which is what #8325 bisected to 1b77d70. is_scrolling() also stays true, and with show_tooltips_only_when_still that keeps tooltips from showing.

This ends an InTouch scroll action after 150 ms without scroll events, the same timeout Smoothing already uses. The check runs in after_events, and also when the next wheel event arrives, because an idle app may not run a pass after the timeout has passed. While events keep coming, the modifiers stay latched as #7678 intended.

Tests, in wheel_state.rs:

  • modifiers_should_not_stick_when_touch_phase_end_never_arrives: Start+Move with ctrl, then 1 s later a Move without ctrl. Before the fix it zoomed (left: 0.9753099, right: 1.0).
  • scroll_action_should_end_when_touch_phase_end_never_arrives: is_scrolling() is false after a second without scroll events. Before the fix it stayed true.
  • modifiers_should_stick_until_touch_phase_end: letting go of shift mid-scroll still scrolls horizontally until End (the Improve modifier handling when scrolling #7678 behavior). Passes before and after.

cargo test -p egui --all-features passes (75 unit tests, 186 doc-tests), and so do cargo fmt, ./scripts/lint.py, cargo clippy -p egui --all-features --all-targets -- -D warnings and cargo doc -p egui --document-private-items. The whole-workspace cargo test --all-features on macOS (with the snapshot tests) passes too. I don't have a niri or COSMIC setup, so the tests replay winit's event sequence rather than a real wheel.

winit on Wayland sends `TouchPhase::Start` for some mouse wheels, but
never `TouchPhase::End`. The `WheelState` then stayed `InTouch` forever,
where modifiers only accumulate. After a single ctrl+scroll, every later
scroll was a zoom, and `is_scrolling()` never went back to `false`.

End an `InTouch` scroll action after the same 150 ms without scroll
events that we already use for `Smoothing`. Check this both in
`after_events` and when the next scroll event arrives, since an idle app
may not run a pass after the timeout.
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Preview available at https://egui-pr-preview.github.io/pr/8636-fixwheel-missing-touch-end
Note that it might take a couple seconds for the update to show up after the preview_build workflow has completed.

View snapshot changes at kitdiff

@SulimanAbdulrazzaq
SulimanAbdulrazzaq marked this pull request as ready for review September 25, 2026 15:53
@SulimanAbdulrazzaq

Copy link
Copy Markdown
Contributor Author

@emilk when you have a moment, could you take a look at this one? Everything is green on the current head except the label check.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scrolling breaks when holding CTRL once Control+Scroll prevents scrolling in the future on niri

1 participant