srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2025-03-10 16:33:00 +0200
committersrdusr <[email protected]>2025-03-10 16:33:00 +0200
commitd6da5a32c921110cc59684f684751502da0ff0dd (patch)
tree4c26147e0bc6c9428332265828ce6c0eebb43edc /crates/wayland
parentee972222588bfcbdad76a30eee46166891ffc45d (diff)
downloadsrdwm-d6da5a32c921110cc59684f684751502da0ff0dd.tar.gz
srdwm-d6da5a32c921110cc59684f684751502da0ff0dd.zip
Fix border/content-mask sized for a CSD client's whole buffer, margin included
The previous fix for a stale border size (switching effective_frame_of from dwindow.geometry() to raw dwindow.bbox()) traded one bug for another. bbox() is the window's entire committed buffer; geometry() is that buffer intersected with the client's own xdg_surface:: set_window_geometry hint, which excludes any invisible CSD shadow margin the client reserves around its real visible content. The assumption behind the switch - that sync_geometry's unconditional tiled-state bits make every compliant client reserve no such margin, so nothing would be lost - was wrong: confirmed live via temporary diagnostic logging, Chrome reserves a real, correctly-current 10px margin on all four sides regardless of the tiled hint (Firefox, the window that exposed the original staleness bug, does not - the two disagree on this). Raw bbox() therefore handed the border/content mask Chrome's entire buffer, margin included - 20px wider and taller than its real visible chrome on each axis, with no compensating position shift - so the rounded border curve traced a rectangle Chrome's real content never reached, and its true, still-square corner poked straight through the curve instead of being hidden by it. Reported live as a border not lining up with a window's content and a hard block cutting through an otherwise-rounded corner. Fixed by keeping both properties at once: dwindow.geometry().loc as the margin - assumed symmetric (left == right, top == bottom), which holds for every real CSD shadow margin observed here, since it's a fixed design constant that doesn't scale with window size and so has no equivalent staleness window even while the hint's absolute size does - subtracted from the always-fresh bbox(). Current size, correct visible-content bounds, for a client that reserves a margin (Chrome) and one that doesn't (Firefox, whose hint .loc is always (0, 0), where this reduces to plain bbox()) alike.
Diffstat (limited to 'crates/wayland')
-rw-r--r--crates/wayland/src/state/geometry.rs53
1 files changed, 38 insertions, 15 deletions
diff --git a/crates/wayland/src/state/geometry.rs b/crates/wayland/src/state/geometry.rs
index 774eabc..b537412 100644
--- a/crates/wayland/src/state/geometry.rs
+++ b/crates/wayland/src/state/geometry.rs
@@ -84,21 +84,44 @@ impl CompState {
// settling and any reasonable commit-throttle window), until an
// unrelated maximize/restore cycle on the same window happened to
// prompt Firefox into resending a fresh hint and self-correcting.
- // `bbox()` - the real bounding box of the window's current surface
- // tree - updates on every commit unconditionally, independent of
- // whether the client also chose to resend the optional hint, so it
- // has no equivalent staleness window. The one thing this gives up
- // is excluding a CSD client's own invisible drop-shadow margin from
- // the border/content area - but `sync_geometry` already
- // unconditionally tells every window it is tiled on all four sides
- // specifically so a compliant client (GTK4/Firefox concretely, see
- // that function's own doc comment) reserves no such margin at all,
- // so a compliant client loses nothing here. A client that ignores
- // the tiled hint and reserves one anyway ends up with a border a
- // few pixels larger than its real visible chrome - a real but
- // strictly smaller, more cosmetic problem than one stuck at the
- // wrong size and position indefinitely.
- let content = dwindow.bbox();
+ //
+ // A first fix switched outright to `bbox()` - the real bounding
+ // box of the window's current surface tree, which updates on every
+ // commit unconditionally - on the reasoning that `sync_geometry`
+ // already unconditionally tells every window it is tiled on all
+ // four sides specifically so a compliant client reserves no
+ // invisible shadow margin, so nothing would be lost by no longer
+ // excluding one. Wrong: confirmed live via temporary diagnostic
+ // logging, Chrome reserves a real, correctly-current 10px margin on
+ // all four sides regardless of the tiled hint (Firefox, the window
+ // that exposed the original bug, does not - the two disagree on
+ // this, not just on how quickly they resend the hint). Raw `bbox()`
+ // gave the border/content mask Chrome's *entire* buffer, margin
+ // included - 20px wider and taller than its real visible chrome on
+ // each axis, with no compensating position shift - so the rounded
+ // border curve traced a rectangle Chrome's real content never
+ // reached, and its true, still-square corner poked straight through
+ // the curve instead of being hidden by it.
+ //
+ // The fix keeps both properties at once: a margin, `dwindow_
+ // geometry.loc`, assumed symmetric (left == right, top == bottom --
+ // true of every real CSD shadow margin observed here: a fixed
+ // design constant, not something that scales with window size) is
+ // far more durable than the rest of that same hint. A resize
+ // changes a client's real content size; it does not change how
+ // large that client's own shadow is, so the margin has no
+ // equivalent staleness window even while the hint's absolute size
+ // does. Subtracting it from the always-fresh `bbox()` - instead of
+ // trusting the hint's own absolute size (stale-prone) or using
+ // bbox() raw (margin-blind) - gets a content rect that is both
+ // current and correctly excludes the invisible margin, for a
+ // client that reserves one (Chrome) and one that doesn't (Firefox,
+ // where the hint's `.loc` is always `(0, 0)` and this reduces to
+ // plain `bbox()`) alike.
+ let dwindow_geometry = dwindow.geometry();
+ let bbox = dwindow.bbox();
+ let margin = (dwindow_geometry.loc.x.max(0), dwindow_geometry.loc.y.max(0));
+ let content = Rectangle::new(bbox.loc, (bbox.size.w - 2 * margin.0, bbox.size.h - 2 * margin.1).into());
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