srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/input/pointer.rs
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2025-08-09 00:57:00 +0200
committersrdusr <[email protected]>2025-08-09 00:57:00 +0200
commit61d01bb79c6882c950f45a1176ba1f30fbbd4824 (patch)
treeeb2a24c7f301f74f987f954b62d768c9cb789fef /crates/wayland/src/input/pointer.rs
parent9e811d2f2f1037ba4ec08ab0e05b350e6cf69e66 (diff)
downloadsrdwm-61d01bb79c6882c950f45a1176ba1f30fbbd4824.tar.gz
srdwm-61d01bb79c6882c950f45a1176ba1f30fbbd4824.zip
Fix interactive-resize border/shadow lag without the OOB risk that sank the first attempt
effective_frame_of now returns the live drag target while a window is being interactively resized (same change as the reverted first attempt), but two things make it safe this time instead of reintroducing the out-of-bounds texture sample that reversion was for: - Every src crop rect built from a window's frame width in udev/render.rs and winit/render.rs (titlebar, top border strip, bottom border strip) is now clamped against DecorationSignature's own recorded width/ border_width - the bitmap's actual last-built size - before reaching MemoryRenderBufferRenderElement::from_buffer, which does not itself validate src against the real texture size. This is a structural floor independent of timing, not a repeat of the previous unsafe approach. - handle_pointer_position now calls redraw_decoration_buffer once per resize motion event (throttled to 60Hz via a new CompState::resize_redraw_at), closing the lag at its source instead of only catching up on the next real client commit. This also fixes the shadow bitmap's identical commit-vs-live-position gap for free, since redraw_decoration_buffer rebuilds all three bitmaps together. Updates the TODO.md entry for this bug with the full before/after.
Diffstat (limited to 'crates/wayland/src/input/pointer.rs')
-rw-r--r--crates/wayland/src/input/pointer.rs31
1 files changed, 31 insertions, 0 deletions
diff --git a/crates/wayland/src/input/pointer.rs b/crates/wayland/src/input/pointer.rs
index 7b3bbce..d4c5678 100644
--- a/crates/wayland/src/input/pointer.rs
+++ b/crates/wayland/src/input/pointer.rs
@@ -16,6 +16,13 @@ use super::keyboard::core_modifiers_from_xkb;
use super::layers::{background_layer_surface_under, layer_surface_under};
use super::{notify_idle_activity, DRAG_MODIFIER};
+/// Minimum gap between `redraw_decoration_buffer` calls fired from an
+/// active resize drag's own pointer-motion events - see `CompState::
+/// resize_redraw_at`'s doc comment. 60Hz: fast enough that the border
+/// visibly tracks the drag, far below the per-motion-event rate a real
+/// mouse or touchpad can produce.
+pub(crate) const RESIZE_REDRAW_INTERVAL: std::time::Duration = std::time::Duration::from_millis(1000 / 60);
+
/// `WindowManager::hit_test`, but substituting each window's currently
/// *animated* rect (if it has one active in `state.window_anims`) for its
/// final `geometry` - see `hit_test_with`'s own doc comment in
@@ -300,6 +307,11 @@ pub(crate) fn handle_pointer_position(state: &mut CompState, pos: Point<f64, Log
let mut wm = state.wm.borrow_mut();
let dragging_or_resizing = wm.is_dragging() || wm.is_resizing();
+ // Captured now, while `wm` is already borrowed, and acted on further
+ // down after `drop(wm)` - `redraw_decoration_buffer` needs `&mut
+ // state` as a whole, which can't happen while `state.wm`'s own
+ // `RefMut` is still alive.
+ let resizing_id = wm.resizing_window();
if wm.is_dragging() {
wm.update_drag(pos.x as i32, pos.y as i32);
} else if wm.is_resizing() {
@@ -338,6 +350,25 @@ pub(crate) fn handle_pointer_position(state: &mut CompState, pos: Point<f64, Log
state.sync_geometry(id);
}
}
+ // Keeps the border/titlebar bitmap tracking an active resize drag's own
+ // live geometry (see `state::geometry::effective_frame_of`'s doc
+ // comment) instead of only catching up once the drag ends - throttled
+ // against `RESIZE_REDRAW_INTERVAL` since motion events can arrive far
+ // faster than a redraw is worth paying for. Reset to `None` on every
+ // tick that isn't resizing this exact window, so a later resize's first
+ // motion event always redraws immediately rather than inheriting a
+ // stale timestamp from a previous drag (or from dragging, which shares
+ // `dragging_or_resizing` above but never touches `resizing_id`).
+ if let Some(id) = resizing_id {
+ let now = std::time::Instant::now();
+ let due = state.resize_redraw_at.is_none_or(|t| now.duration_since(t) >= RESIZE_REDRAW_INTERVAL);
+ if due {
+ state.redraw_decoration_buffer(id);
+ state.resize_redraw_at = Some(now);
+ }
+ } else {
+ state.resize_redraw_at = None;
+ }
}
/// Sets the pointer to a resize-direction shape while hovering (or