srdusr
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2025-08-10 14:25:00 +0200
committersrdusr <[email protected]>2025-08-10 14:25:00 +0200
commit7f4740046a004a1ad06aefa5d1d6b1a351571b1a (patch)
tree9a22cd7bf999cd2645e7c10907b161f3c347ebe9
parent61d01bb79c6882c950f45a1176ba1f30fbbd4824 (diff)
downloadsrdwm-7f4740046a004a1ad06aefa5d1d6b1a351571b1a.tar.gz
srdwm-7f4740046a004a1ad06aefa5d1d6b1a351571b1a.zip
Make corner resize reachable at the button corner, and widen it everywhere else
Reported live: "even where decorations are corner i should still be able to corner resize, just its... hitbox... does not get in the way of the close icon" - the titlebar corner holding Close/Maximize/Minimize had no resize target at all, by design (competing with the close button was judged worse than losing that one corner). The BUTTON_CLUSTER_MARGIN strip between the button cluster and the frame's true edge was already dead space no button claims, regardless of button_count - its own top DECORATED_TOP_RESIZE_MARGIN rows now register as the diagonal corner (TopLeft/TopRight) instead of falling through to Top/Drag, without touching the button's own hitbox at all. Also requested: widen the other three corners' own resize zone, since a user reaching for a plain edge-resize instinctively aims for the middle of that edge, not its corner - a bigger corner zone doesn't compete with that instinct the way a bigger RESIZE_MARGIN would compete with ordinary content clicks near an edge. CORNER_MARGIN raised from 3 to 5 (18px to 30px at the default resize_margin). Updated one existing test whose own per-window resize_margin override (30px) now put its plain-edge test point inside the widened corner zone on a window too short for the two to stay apart - taller geometry, same edge point relative to center, no change to what it actually verifies. Added coverage for the new button-corner resize target on both sides, and for the dead strip's own non-corner rows still just dragging as before.
-rw-r--r--crates/core/src/manager/tests.rs14
-rw-r--r--crates/core/src/window.rs76
2 files changed, 86 insertions, 4 deletions
diff --git a/crates/core/src/manager/tests.rs b/crates/core/src/manager/tests.rs
index 9af0181..88699de 100644
--- a/crates/core/src/manager/tests.rs
+++ b/crates/core/src/manager/tests.rs
@@ -432,13 +432,21 @@
wm.set_layout(wm.current_workspace(), "tiling"); // keeps add_window from overriding geometry via SmartPlacement
let id = wm.alloc_window_id();
let mut w = Window::new(id, "a");
- w.geometry = Rect::new(100, 100, 400, 300);
+ // Tall enough that `CORNER_MARGIN * resize_margin`'s own widened
+ // corner zone (150px at this override, see `CORNER_MARGIN`'s own
+ // doc comment on why it's deliberately generous) doesn't reach
+ // anywhere near the plain-edge point tested below - a shorter
+ // window here used to work purely because the corner zone was
+ // narrower, not because this test cared about corners at all.
+ w.geometry = Rect::new(100, 100, 400, 800);
w.resize_margin = Some(30);
wm.add_window(w);
// 15px in from the left edge: well past the WM-wide default (6px),
- // but still inside this window's own wider 30px override.
- let hit = wm.hit_test(115, 250);
+ // but still inside this window's own wider 30px override. Deep in
+ // the window's own vertical middle, well clear of either corner
+ // zone.
+ let hit = wm.hit_test(115, 500);
assert_eq!(hit.map(|(_, h)| h), Some(TitlebarHit::Resize(ResizeEdge::Left)));
}
diff --git a/crates/core/src/window.rs b/crates/core/src/window.rs
index 6e40486..99d8de7 100644
--- a/crates/core/src/window.rs
+++ b/crates/core/src/window.rs
@@ -396,7 +396,19 @@ pub const DECORATED_TOP_RESIZE_MARGIN: i32 = RESIZE_MARGIN;
/// - see `ResizeEdge::resize_edge_at`'s doc comment for why corners need
/// more room than a straight edge at all, not just a proportionally bigger
/// dead-simple hit box.
-pub const CORNER_MARGIN: i32 = 3;
+///
+/// Bumped from `3` (18px at the default `RESIZE_MARGIN`) to `5` (30px):
+/// reported live as still too tight to land reliably, and there's real
+/// room to widen it further than a plain edge ever could be - someone
+/// reaching for a straight edge-resize instinctively aims for the middle
+/// of that edge, not its corner, precisely to *avoid* accidentally
+/// grabbing a corner instead. A bigger corner zone doesn't compete with
+/// that instinct the way a bigger `RESIZE_MARGIN` would compete with
+/// ordinary clicks near an edge (`RESIZE_MARGIN`'s own doc comment).
+/// Applies to every corner `resize_edge_at` and the titlebar's own
+/// non-button corner check use - not the button-side corner, which
+/// stays deliberately narrower than this; see its own hit-test comment.
+pub const CORNER_MARGIN: i32 = 5;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ResizeEdge {
@@ -545,6 +557,22 @@ impl ResizeEdge {
}
}
}
+ // `x < left` is the same dead `BUTTON_CLUSTER_MARGIN` strip
+ // excluded above, now put to use: it's already unclaimed by
+ // any button's own hitbox, by construction, so its own top
+ // `DECORATED_TOP_RESIZE_MARGIN` rows are a safe, if
+ // deliberately narrow, diagonal-resize target right at the
+ // button-side corner - narrower than the non-button
+ // corner's own `corner_zone` above on purpose, since this
+ // one has Close sitting immediately next to it and widening
+ // it any further would start eating into that button's own
+ // hitbox instead of just the dead space next to it.
+ // Reported live: this corner had no resize target at all,
+ // "even where decorations are corner i should still be able
+ // to corner resize."
+ if x < left && y <= frame.y + DECORATED_TOP_RESIZE_MARGIN {
+ return Some(TitlebarHit::Resize(ResizeEdge::TopLeft));
+ }
if y <= frame.y + DECORATED_TOP_RESIZE_MARGIN {
return Some(TitlebarHit::Resize(ResizeEdge::Top));
}
@@ -565,6 +593,11 @@ impl ResizeEdge {
}
}
}
+ // Mirror of the `buttons_left` branch's own identical check
+ // above - see its comment for the full reasoning.
+ if x > right && y <= frame.y + DECORATED_TOP_RESIZE_MARGIN {
+ return Some(TitlebarHit::Resize(ResizeEdge::TopRight));
+ }
if y <= frame.y + DECORATED_TOP_RESIZE_MARGIN {
return Some(TitlebarHit::Resize(ResizeEdge::Top));
}
@@ -1085,6 +1118,47 @@ mod tests {
}
#[test]
+ fn button_side_corner_still_resizes_from_its_own_dead_strip() {
+ // Reported live: "even where decorations are corner i should still
+ // be able to corner resize, just its... hitbox... does not get in
+ // the way of the close icon." The raw corner pixel sits in the
+ // `BUTTON_CLUSTER_MARGIN` dead strip outside Close's own hitbox
+ // (see `decorated_window_top_right_corner_still_closes_not_resizes`
+ // just above), which used to fall through to plain `Top`/`Drag`
+ // with no diagonal target at all. Both axes right at the true
+ // corner - well within the dead strip horizontally (`- 1` from the
+ // frame's own edge, nowhere near where Close's hitbox starts) and
+ // within `DECORATED_TOP_RESIZE_MARGIN` vertically.
+ let f = frame();
+ let hit = ResizeEdge::hit_test(f, f.right() - 1, f.y + 1, true, 0, RESIZE_MARGIN, false, None, false);
+ assert_eq!(hit, Some(TitlebarHit::Resize(ResizeEdge::TopRight)));
+ }
+
+ #[test]
+ fn button_side_corner_below_its_own_resize_row_still_drags() {
+ // The dead strip's own top rows are the new corner-resize target
+ // (`button_side_corner_still_resizes_from_its_own_dead_strip`), but
+ // the rest of that same narrow column, below
+ // `DECORATED_TOP_RESIZE_MARGIN`, is still ordinary titlebar drag --
+ // this only ever claims the true corner, not the whole column
+ // beside Close.
+ let f = frame();
+ let hit = ResizeEdge::hit_test(f, f.right() - 1, f.y + DECORATED_TOP_RESIZE_MARGIN + 5, true, 0, RESIZE_MARGIN, false, None, false);
+ assert_eq!(hit, Some(TitlebarHit::Drag));
+ }
+
+ #[test]
+ fn button_side_corner_still_resizes_from_its_own_dead_strip_when_buttons_are_left() {
+ // Mirror of `button_side_corner_still_resizes_from_its_own_dead_
+ // strip` with `buttons_left: true` - Close now owns the top-left
+ // corner, so the dead strip and its own corner-resize target move
+ // to the frame's left edge instead.
+ let f = frame();
+ let hit = ResizeEdge::hit_test(f, f.x + 1, f.y + 1, true, 0, RESIZE_MARGIN, true, None, false);
+ assert_eq!(hit, Some(TitlebarHit::Resize(ResizeEdge::TopLeft)));
+ }
+
+ #[test]
fn decorated_window_very_top_edge_of_titlebar_resizes_not_drags() {
// The actual regression: reported live as "can't resize tmux's
// window from the top, but can in Firefox" - a decorated window's