diff options
| author | srdusr <[email protected]> | 2025-10-07 22:20:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2025-10-07 22:20:00 +0200 |
| commit | 9f07715b469a481849ee35ffa33d6dab34356c7d (patch) | |
| tree | 7080f57115b9ea3ccab43e458c34aa2acec74501 /crates/wayland/src/udev/render.rs | |
| parent | 4eb36873d4ca4b0faf0e54dbeab8f5f6450dd704 (diff) | |
| download | srdwm-9f07715b469a481849ee35ffa33d6dab34356c7d.tar.gz srdwm-9f07715b469a481849ee35ffa33d6dab34356c7d.zip | |
Fix intermittent cursor ghosting when crossing between monitors
Live report: the real cursor sometimes leaves a brief ghost behind right
after moving between monitors. The bare-metal render loop already forces
a full repaint (ages = [0, 0]) on a workspace switch or any window move/
resize/open/close/restack, both added earlier for the same underlying gap:
the damage tracker's own element diffing doesn't always catch a vacated
region on its own. Neither reset noticed the pointer leaving one monitor
for another - no window moved, no workspace changed - so that head's own
vacated cursor-sized region was left entirely to the tracker's diffing,
intermittently.
Adds UdevState::last_cursor_head, compared each frame the same way the
other two resets are; only the head the pointer just left gets forced back
to ages = [0, 0] (the newly-entered head draws a genuinely new element
there and diffs correctly on its own).
Diffstat (limited to 'crates/wayland/src/udev/render.rs')
| -rw-r--r-- | crates/wayland/src/udev/render.rs | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/crates/wayland/src/udev/render.rs b/crates/wayland/src/udev/render.rs index dc84a2e..f850a19 100644 --- a/crates/wayland/src/udev/render.rs +++ b/crates/wayland/src/udev/render.rs @@ -167,6 +167,24 @@ impl CompState { head.ages = [0, 0]; } } + // See `UdevState::last_cursor_head`'s own doc comment: neither reset + // above notices the pointer crossing from one monitor to another, + // so that head's own vacated cursor-sized region was left entirely + // to `OutputDamageTracker`'s own diffing - reported live as an + // intermittent cursor "ghost" briefly left behind on the monitor + // just departed. Only the head being *left* needs the forced + // repaint; the one being entered draws a genuinely new element + // there this frame regardless, which diffs correctly on its own. + let current_cursor_head = udev.heads.iter().position(|h| { + let local = (udev.pointer_pos.x as i32 - h.location.x, udev.pointer_pos.y as i32 - h.location.y); + local.0 >= 0 && local.1 >= 0 && local.0 < h.size.0 && local.1 < h.size.1 + }); + if !locked && udev.last_cursor_head != current_cursor_head { + if let Some(old) = udev.last_cursor_head.and_then(|i| udev.heads.get_mut(i)) { + old.ages = [0, 0]; + } + udev.last_cursor_head = current_cursor_head; + } // A head whose page-flip event never arrives (kernel-dropped, or a // DRM event this driver never sends for reasons this backend has no // visibility into) would otherwise sit in `flip_pending` forever: |