diff options
| author | srdusr <[email protected]> | 2025-10-03 22:59:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2025-10-03 22:59:00 +0200 |
| commit | 4eb36873d4ca4b0faf0e54dbeab8f5f6450dd704 (patch) | |
| tree | 657c89f7398f98b0305b9cd69889c232608f3027 /crates/wayland/src/udev/render.rs | |
| parent | d7031dd060ec12e6de334518aa75122c65794047 (diff) | |
| download | srdwm-4eb36873d4ca4b0faf0e54dbeab8f5f6450dd704.tar.gz srdwm-4eb36873d4ca4b0faf0e54dbeab8f5f6450dd704.zip | |
Make the secondary-cursor sprite opt-in and expire stale entries
Live report: a second cursor appeared uninvited and unusably (frozen,
uncontrollable) on screen. Multi-cursor Phase 1 rendered one sprite per
physical libinput pointer device that had ever reported a position, with
no way to turn it off and no expiry - so a phantom device (a real mouse's
side-button/scroll cluster enumerating as its own HID path is a common
case) that reports once and never moves again left a frozen ghost sprite
with nothing to control or dismiss it.
Adds general.multi_cursor (default false, live-settable via
`srd set multi_cursor <bool>`) and keys secondary_cursors to
(Point, Instant) so both the recording side (udev/session.rs) and the
render side (udev/render.rs) drop any entry older than
SECONDARY_CURSOR_TIMEOUT (1.5s). The "agent controls a window without
interrupting the user" use case this report also raised was never gated
on this flag - that's Multi-cursor Phase 2's pinned virtual-pointer
delivery, which never shows a visible cursor at all.
Diffstat (limited to 'crates/wayland/src/udev/render.rs')
| -rw-r--r-- | crates/wayland/src/udev/render.rs | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/crates/wayland/src/udev/render.rs b/crates/wayland/src/udev/render.rs index 4bfe04d..dc84a2e 100644 --- a/crates/wayland/src/udev/render.rs +++ b/crates/wayland/src/udev/render.rs @@ -321,13 +321,28 @@ impl CompState { // (`cursor_status`/`cursor_buffers`) rather than each // device getting its own - a real visual distinction // between devices is a later-phase refinement, not needed - // to prove multiple live positions render at all. - let active_device = udev.secondary_cursors.iter().find(|&(_, &p)| p == pointer_pos).map(|(d, _)| d.clone()); - for (device, &pos) in &udev.secondary_cursors { - if Some(device) == active_device.as_ref() { - continue; + // to prove multiple live positions render at all. Gated + // on `general.multi_cursor` (off by default) and on each + // entry's own recency: a device that reported a position + // once and then never moved again - the real, reported + // live bug - stops rendering after `SECONDARY_CURSOR_ + // TIMEOUT` instead of sitting frozen on screen forever. + if self.wm.borrow().multi_cursor_enabled { + let now = std::time::Instant::now(); + let active_device = udev + .secondary_cursors + .iter() + .find(|&(_, &(p, _))| p == pointer_pos) + .map(|(d, _)| d.clone()); + for (device, &(pos, seen)) in &udev.secondary_cursors { + if Some(device) == active_device.as_ref() { + continue; + } + if now.duration_since(seen) >= super::SECONDARY_CURSOR_TIMEOUT { + continue; + } + custom_elements.extend(crate::cursor::render_elements(&cursor_status, &cursor_buffers, &mut udev.renderer, pos, origin, hsize)); } - custom_elements.extend(crate::cursor::render_elements(&cursor_status, &cursor_buffers, &mut udev.renderer, pos, origin, hsize)); } // Night light/reading mode - a translucent full-output // overlay, pushed right after the cursor so it colours |