diff options
| author | srdusr <[email protected]> | 2025-08-09 00:57:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2025-08-09 00:57:00 +0200 |
| commit | 61d01bb79c6882c950f45a1176ba1f30fbbd4824 (patch) | |
| tree | eb2a24c7f301f74f987f954b62d768c9cb789fef /crates/wayland/src/input/pointer.rs | |
| parent | 9e811d2f2f1037ba4ec08ab0e05b350e6cf69e66 (diff) | |
| download | srdwm-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.rs | 31 |
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 |