srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/state
diff options
context:
space:
mode:
Diffstat (limited to 'crates/wayland/src/state')
-rw-r--r--crates/wayland/src/state/geometry.rs54
1 files changed, 48 insertions, 6 deletions
diff --git a/crates/wayland/src/state/geometry.rs b/crates/wayland/src/state/geometry.rs
index b8f610e..5cbece9 100644
--- a/crates/wayland/src/state/geometry.rs
+++ b/crates/wayland/src/state/geometry.rs
@@ -85,6 +85,28 @@ impl CompState {
// branch existing is what keeps that gap small in practice
// rather than a full commit-cycle wide.
if wm.borrow().resizing_window() == Some(id) {
+ // Reinstated once more, but no longer as the *live drag
+ // target*. Returning that made the decoration race ahead of
+ // the content it frames: the titlebar and border tracked the
+ // pointer while the client's actual pixels were still whatever
+ // it last committed, so the two visibly disagreed for the whole
+ // drag - reported as the titlebar not resizing at the same
+ // time as the window, and as the resize feeling cheap.
+ //
+ // Now it returns the committed size, anchored to whichever edge
+ // the drag is holding still, which is exactly the rect the
+ // content actually occupies (`sync_geometry` positions it the
+ // same way). Decoration and content therefore move as one, one
+ // commit behind the pointer rather than out of step with each
+ // other. Every other compositor makes this same trade: a frame
+ // glued to its content and slightly behind the cursor reads as
+ // solid, one that leads its own content reads as broken.
+ //
+ // Falling back to the live target when there is no usable
+ // committed size yet keeps the pre-first-commit case working.
+ if let Some(rect) = Self::committed_frame(wm, id_to_window, id, geom) {
+ return rect;
+ }
return geom;
}
// Same reasoning as the active-resize branch just above, for a gap
@@ -117,8 +139,24 @@ impl CompState {
}) {
return geom;
}
- let Some(w) = wm.borrow().window(id).cloned() else { return geom };
- let Some(dwindow) = id_to_window.get(&id) else { return geom };
+ match Self::committed_frame(wm, id_to_window, id, geom) {
+ Some(rect) => rect,
+ None => geom,
+ }
+ }
+
+ /// `geom` with its size replaced by what the client actually committed,
+ /// and - during a resize from a left or top edge - its origin moved so
+ /// the opposite edge stays put. `None` when there is nothing committed
+ /// to correct against.
+ fn committed_frame(
+ wm: &Rc<RefCell<WindowManager>>,
+ id_to_window: &HashMap<WindowId, DWindow>,
+ id: WindowId,
+ geom: srdwm_core::Rect,
+ ) -> Option<srdwm_core::Rect> {
+ let w = wm.borrow().window(id).cloned()?;
+ let dwindow = id_to_window.get(&id)?;
// `dwindow.geometry()` - `xdg_surface::set_window_geometry` - is,
// per smithay's own implementation, that cached hint *intersected*
// with `bbox()`, falling back to `bbox()` only if the client never
@@ -180,9 +218,9 @@ impl CompState {
if content.size.w <= 0 || content.size.h <= 0 {
// No real committed content yet - racing the first commit
// right after creation, most likely. Nothing to correct
- // against, so fall back to the requested rect rather than
- // collapsing every dimension down to (near) zero.
- return geom;
+ // against, so let the caller fall back to the requested rect
+ // rather than collapsing every dimension down to (near) zero.
+ return None;
}
// `content` (`bbox()`) is in the same *logical* points as
// `xdg_surface::set_window_geometry` would have been, same as
@@ -203,7 +241,11 @@ impl CompState {
let scale = wm.borrow().monitors().iter().find(|m| m.id == w.monitor).map(|m| m.scale).unwrap_or(1.0);
let content_physical = ((content.size.w as f64 * scale).round() as i32, (content.size.h as f64 * scale).round() as i32);
let band = if w.decorated { TITLEBAR_HEIGHT as i32 } else { 0 };
- srdwm_core::Rect { x: geom.x, y: geom.y, width: content_physical.0.max(0) as u32, height: (band + content_physical.1.max(0)) as u32 }
+ // Anchored so a left/top drag holds its opposite edge - the same
+ // correction `sync_geometry` applies when positioning the content
+ // itself, so the two agree by construction rather than by luck.
+ let (x, y) = Self::anchor_resizing_origin(wm, id, geom, content.size, scale);
+ Some(srdwm_core::Rect { x, y, width: content_physical.0.max(0) as u32, height: (band + content_physical.1.max(0)) as u32 })
}
/// The rect a window's border, shadow, occlusion test, and resize-