srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland
diff options
context:
space:
mode:
Diffstat (limited to 'crates/wayland')
-rw-r--r--crates/wayland/src/udev/mod.rs22
-rw-r--r--crates/wayland/src/udev/platform.rs1
-rw-r--r--crates/wayland/src/udev/render.rs18
3 files changed, 41 insertions, 0 deletions
diff --git a/crates/wayland/src/udev/mod.rs b/crates/wayland/src/udev/mod.rs
index b0a2639..22df0e1 100644
--- a/crates/wayland/src/udev/mod.rs
+++ b/crates/wayland/src/udev/mod.rs
@@ -278,6 +278,28 @@ pub(crate) struct UdevState {
/// `None` before the first frame, same reasoning as `last_rendered_
/// workspace` above (renders fully regardless).
pub(crate) last_rendered_layout: Option<u64>,
+ /// Index into `heads` of whichever head the pointer was actually drawn
+ /// on last frame (`None` before the first frame, or if it was on none
+ /// of them). Compared each frame in `render_udev_frame`, same pattern
+ /// as `last_rendered_workspace`/`last_rendered_layout` above, so that
+ /// when the pointer crosses from one monitor to another the head it
+ /// just *left* gets its own `ages` forced back to `[0, 0]` too.
+ ///
+ /// Needed because neither of those two other resets notices this
+ /// transition at all: no window moved, and the workspace didn't
+ /// change, so both stay silent while the cursor sprite simply drops
+ /// out of that head's `custom_elements` list from one frame to the
+ /// next. That leaves the departing head's vacated cursor-sized region
+ /// resting entirely on `OutputDamageTracker`'s own element diffing --
+ /// already documented, for the same "an element disappeared" shape of
+ /// bug on a window vacating part of the screen, as not reliable on its
+ /// own (see `layout_signature`'s own doc comment above `render_udev_
+ /// frame`). Reported live as an intermittent cursor "ghost" briefly
+ /// left behind right after moving the pointer between monitors --
+ /// intermittent because it depends on whatever else that head's own
+ /// diffing already had queued that frame, exactly like the window
+ /// case did.
+ pub(crate) last_cursor_head: Option<usize>,
/// Set only when `SRDWM_GPU=1` and `gpu::probe` succeeds on this
/// hardware - see that function's own doc comment for exactly what
/// it does and does not do yet. `None` (the default, every session
diff --git a/crates/wayland/src/udev/platform.rs b/crates/wayland/src/udev/platform.rs
index b09bd4b..bf82b32 100644
--- a/crates/wayland/src/udev/platform.rs
+++ b/crates/wayland/src/udev/platform.rs
@@ -170,6 +170,7 @@ impl UdevPlatform {
disabled_connectors: std::collections::HashSet::new(),
last_rendered_workspace: None,
last_rendered_layout: None,
+ last_cursor_head: None,
gpu: gpu_context,
};
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: