diff options
| author | srdusr <[email protected]> | 2026-04-27 00:18:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2026-04-27 00:18:00 +0200 |
| commit | c4dc99cc3211c4dc1a461f228402be1593b883c9 (patch) | |
| tree | 10a85d60acb863ca98b7e70118dec5cda357efa6 /crates/core/src/window.rs | |
| parent | 436d42da6ef61a5ea20d5102c4baed7bf0993606 (diff) | |
| download | srdwm-c4dc99cc3211c4dc1a461f228402be1593b883c9.tar.gz srdwm-c4dc99cc3211c4dc1a461f228402be1593b883c9.zip | |
Build the eight asks recovered from the previous session's transcript
The punch list was not the whole record. These are the owner's own typed
requests, read back out of the previous session's transcript rather than
guessed at, then each checked against the code before being treated as open.
Three they suspected were already done really were: dialogs already had a
Close-only titlebar, inactive dimming already existed, and the corner resize
hitbox had already been tuned.
Snap layouts on drag, asked for twice. Edge snapping worked but committed
silently on release with nothing shown first, so there was no way to know it
would happen or where. A translucent drop-target preview now follows the
drag, and throwing the pointer at a monitor's top edge drops down the
existing six-cell grid to aim at. The preview calls the same snap_zone that
end_drag does, so the two cannot disagree. Two defects found by screenshot
before landing: moving down onto the flyout closed it, and its labels
overflowed at a fixed cell width - the same "text goes out of view" fault
already fixed once for the context menu.
New File now offers real types, chosen by extension, with the de-duplication
counter placed before the extension so the file stays what it says it is.
Refresh re-reads init.lua and fires a new srd.on("refresh") handler instead
of only re-scanning the icon grid. What refresh means beyond srdwm's own
config stays the config's decision.
general.config_reload_on_write (default on) applies an edited config on save,
via an mtime sweep rather than an inotify watch: no new dependency, same
behaviour on every target, and unaffected by editors that write through a
temp file.
A real bug behind "what happens when our config fails": you lost every
keybinding. do_reload cleared the binding, handler and repeat tables before
re-executing and never restored them, so a syntax error left neither the old
config nor the new one, and the only key still working was the reload combo
nobody thinks to press. The tables are now restored on any failure and
config errors reach notify-send, not just the log.
srd.lock() and a default Mod4+Ctrl+l binding: the built-in lock screen could
not be reached from Lua at all. Native rather than shelling out, because a
lock key that shells out fails silently when the binary is not on PATH.
Default bindings added for srd.window.move and a dynamic/tiling toggle, both
of which existed with no way to reach them, plus srd.layout.get() so the
toggle reads the live workspace rather than the configured default.
Dialogs open centred, and are excluded from remembered geometry in both
directions - that table is keyed by app_id, which a dialog shares with the
window that spawned it, so dialogs inherited an unrelated position and size
and then overwrote it with their own.
theme.decorations.title_bar.button_mode (dynamic by default, or fixed) drops
the Maximize button on a window whose client pinned min == max size, where
pressing it can do nothing. Maximize is removed from the slot list rather
than skipped in place on both the render and hit-test sides, so the remaining
buttons close the gap identically; three tests pin that agreement, which is
what fails silently when it drifts.
Also: the nested backend's screencopy pass now draws both menus, the flyout
and the drag preview. Four investigations in one day started from a
screenshot missing a tier, so that pass carries an explicit list of what it
still omits and the on-screen loop points at it.
512 tests pass, clippy clean.
Diffstat (limited to 'crates/core/src/window.rs')
| -rw-r--r-- | crates/core/src/window.rs | 135 |
1 files changed, 102 insertions, 33 deletions
diff --git a/crates/core/src/window.rs b/crates/core/src/window.rs index a3d48a2..ee9fd23 100644 --- a/crates/core/src/window.rs +++ b/crates/core/src/window.rs @@ -182,6 +182,21 @@ pub struct Window { /// lights - see `hit_test`'s and `decoration::render_titlebar`'s own /// use of this for what actually changes. pub is_dialog: bool, + /// Whether the client says it can actually be resized - `false` when + /// it pinned its minimum and maximum size to the same value (a native + /// `xdg_toplevel`'s `set_min_size`/`set_max_size`, or an XWayland + /// window's ICCCM size hints). Backend-set on every decoration redraw, + /// same as `is_dialog` above, for the same reason: `core` has no + /// protocol of its own to read it from. Defaults to `true`, so a + /// client that never declares limits - the common case - is treated + /// as resizable. + /// + /// Consumed by the `dynamic` titlebar button mode: a window that + /// cannot be resized cannot meaningfully be maximized either, so + /// offering the button is offering a no-op. Every mainstream desktop + /// (GNOME, KDE, Windows) hides or disables it in exactly this case. + /// Asked for as titlebars with "buttons of the program/dynamic". + pub resizable: bool, /// `decorated`'s value from just before entering fullscreen, restored /// on exit - see `WindowManager::toggle_fullscreen`'s doc comment on /// why this can't just hardcode `true` back. @@ -286,6 +301,7 @@ impl Window { restore_geometry: None, decorated: true, is_dialog: false, + resizable: true, restore_decorated: None, floating: false, minimized: false, @@ -503,6 +519,12 @@ impl ResizeEdge { // other" trap every other button-geometry value here already has // to avoid. is_dialog: bool, + // Whether a Maximize button is shown at all - `theme. + // dynamic_buttons && !window.resizable` resolves to `false`. Same + // "must stay in exact agreement with `decoration::render_titlebar`" + // contract as `is_dialog` directly above, and for the same reason: + // the two sides compute button slots independently. + show_maximize: bool, ) -> Option<TitlebarHit> { // Border strips render *outside* `frame` (`decoration:: // border_strips`, `border_width` pixels past each edge) - without @@ -579,10 +601,20 @@ impl ResizeEdge { [TitlebarButton::Close, TitlebarButton::Maximize, TitlebarButton::Minimize] }) }; + // Maximize dropped from the slot list entirely rather than + // left in place and ignored: leaving a hole would put a dead + // gap between the two remaining buttons, and the renderer + // closes the gap, so hit-testing has to close it identically + // or every button after it is offset by one slot. + let order: Vec<TitlebarButton> = if show_maximize { + order.to_vec() + } else { + order.iter().copied().filter(|b| *b != TitlebarButton::Maximize).collect() + }; // A dialog only ever recognizes the first slot, matching // `decoration::render_titlebar` only ever drawing the one // button there too. - let button_count = if is_dialog { 1 } else { 3 }; + let button_count = if is_dialog { 1 } else { order.len() }; if buttons_left { let left = frame.x + BUTTON_CLUSTER_MARGIN as i32; // `x >= left` excludes the dead `BUTTON_CLUSTER_MARGIN` @@ -1000,14 +1032,14 @@ mod tests { // margin is a real dead strip now (see its own doc comment) - a // point only `5` in from the raw edge landed inside it, not on the // button. - let hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - 5, f.y + 5, true, 0, RESIZE_MARGIN, false, None, false); + let hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - 5, f.y + 5, true, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, Some(TitlebarHit::Close)); } #[test] fn maximize_is_left_of_close() { let f = frame(); - let hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - BUTTON_PITCH as i32 - 5, f.y + 5, true, 0, RESIZE_MARGIN, false, None, false); + let hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - BUTTON_PITCH as i32 - 5, f.y + 5, true, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, Some(TitlebarHit::Maximize)); } @@ -1023,12 +1055,12 @@ mod tests { // undecorated windows. let f = frame(); let maximize_spot = f.right() - BUTTON_CLUSTER_MARGIN as i32 - BUTTON_PITCH as i32 - 5; - let hit = ResizeEdge::hit_test(f, maximize_spot, f.y + 5, true, 0, RESIZE_MARGIN, false, None, true); + let hit = ResizeEdge::hit_test(f, maximize_spot, f.y + 5, true, 0, RESIZE_MARGIN, false, None, true, true); assert_ne!(hit, Some(TitlebarHit::Maximize), "a dialog must not have a Maximize hit zone at all"); assert_ne!(hit, Some(TitlebarHit::Minimize), "a dialog must not have a Minimize hit zone at all"); // The one real button (Close) must still be exactly where it always // is - `is_dialog` removes the other two, not shifts this one. - let close_hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - 5, f.y + 5, true, 0, RESIZE_MARGIN, false, None, true); + let close_hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - 5, f.y + 5, true, 0, RESIZE_MARGIN, false, None, true, true); assert_eq!(close_hit, Some(TitlebarHit::Close)); } @@ -1041,7 +1073,7 @@ mod tests { // it get used. let f = frame(); let order = [TitlebarButton::Maximize, TitlebarButton::Minimize, TitlebarButton::Close]; - let hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - 5, f.y + 5, true, 0, RESIZE_MARGIN, false, Some(order), true); + let hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - 5, f.y + 5, true, 0, RESIZE_MARGIN, false, Some(order), true, true); assert_eq!(hit, Some(TitlebarHit::Close)); } @@ -1053,7 +1085,7 @@ mod tests { // not just what gets drawn. let f = frame(); let order = [TitlebarButton::Close, TitlebarButton::Minimize, TitlebarButton::Maximize]; - let hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - BUTTON_PITCH as i32 - 5, f.y + 5, true, 0, RESIZE_MARGIN, false, Some(order), false); + let hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - BUTTON_PITCH as i32 - 5, f.y + 5, true, 0, RESIZE_MARGIN, false, Some(order), false, true); assert_eq!(hit, Some(TitlebarHit::Minimize)); } @@ -1066,8 +1098,8 @@ mod tests { // on. let f = frame(); let order = [TitlebarButton::Maximize, TitlebarButton::Minimize, TitlebarButton::Close]; - let left_hit = ResizeEdge::hit_test(f, f.x + BUTTON_CLUSTER_MARGIN as i32 + 5, f.y + 5, true, 0, RESIZE_MARGIN, true, Some(order), false); - let right_hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - 5, f.y + 5, true, 0, RESIZE_MARGIN, false, Some(order), false); + let left_hit = ResizeEdge::hit_test(f, f.x + BUTTON_CLUSTER_MARGIN as i32 + 5, f.y + 5, true, 0, RESIZE_MARGIN, true, Some(order), false, true); + let right_hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - 5, f.y + 5, true, 0, RESIZE_MARGIN, false, Some(order), false, true); assert_eq!(left_hit, Some(TitlebarHit::Maximize)); assert_eq!(right_hit, Some(TitlebarHit::Maximize)); } @@ -1081,17 +1113,54 @@ mod tests { // of_titlebar_resizes_not_drags` for that zone's own coverage. let f = frame(); let (cx, _) = f.center(); - let hit = ResizeEdge::hit_test(f, cx, f.y + DECORATED_TOP_RESIZE_MARGIN + 5, true, 0, RESIZE_MARGIN, false, None, false); + let hit = ResizeEdge::hit_test(f, cx, f.y + DECORATED_TOP_RESIZE_MARGIN + 5, true, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, Some(TitlebarHit::Drag)); } #[test] fn bottom_right_corner_is_resize() { let f = frame(); - let hit = ResizeEdge::hit_test(f, f.right() - 1, f.bottom() - 1, true, 0, RESIZE_MARGIN, false, None, false); + let hit = ResizeEdge::hit_test(f, f.right() - 1, f.bottom() - 1, true, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, Some(TitlebarHit::Resize(ResizeEdge::BottomRight))); } + #[test] + fn a_non_resizable_window_has_no_maximize_button_to_click() { + // `show_maximize = false` - the dynamic button mode's one rule. + let f = Rect::new(0, 0, 400, 300); + // Buttons on the right, default order Close, Maximize, Minimize. + // Slot 0 is Close either way. + let slot = |i: i32| f.right() - BUTTON_CLUSTER_MARGIN as i32 - BUTTON_PITCH as i32 * i - 1; + let hit = |x: i32, show_max: bool| ResizeEdge::hit_test(f, x, f.y + TITLEBAR_HEIGHT as i32 / 2, true, 0, RESIZE_MARGIN, false, None, false, show_max); + + assert_eq!(hit(slot(1), true), Some(TitlebarHit::Maximize), "resizable: slot 1 is Maximize"); + // With Maximize dropped, Minimize moves up into slot 1 - it must + // not leave a dead gap there. + assert_eq!(hit(slot(1), false), Some(TitlebarHit::Minimize), "non-resizable: Minimize closes the gap"); + assert_eq!(hit(slot(0), false), Some(TitlebarHit::Close), "Close stays put"); + } + + #[test] + fn a_non_resizable_window_still_has_exactly_two_buttons() { + let f = Rect::new(0, 0, 400, 300); + let slot = |i: i32| f.right() - BUTTON_CLUSTER_MARGIN as i32 - BUTTON_PITCH as i32 * i - 1; + let hit = |x: i32| ResizeEdge::hit_test(f, x, f.y + TITLEBAR_HEIGHT as i32 / 2, true, 0, RESIZE_MARGIN, false, None, false, false); + // Slot 2 held Minimize when there were three; with two it is past + // the cluster and must be a drag, not a phantom third button. + assert_eq!(hit(slot(2)), Some(TitlebarHit::Drag), "no third button exists any more"); + } + + #[test] + fn a_dialog_is_close_only_regardless_of_the_dynamic_button_mode() { + let f = Rect::new(0, 0, 400, 300); + let slot = |i: i32| f.right() - BUTTON_CLUSTER_MARGIN as i32 - BUTTON_PITCH as i32 * i - 1; + for show_max in [true, false] { + let hit = |x: i32| ResizeEdge::hit_test(f, x, f.y + TITLEBAR_HEIGHT as i32 / 2, true, 0, RESIZE_MARGIN, false, None, true, show_max); + assert_eq!(hit(slot(0)), Some(TitlebarHit::Close), "show_maximize={show_max}"); + assert_eq!(hit(slot(1)), Some(TitlebarHit::Drag), "a dialog has no second button, show_maximize={show_max}"); + } + } + /// The bug this guards against: an undecorated window's own content in /// its top `TITLEBAR_HEIGHT` band (Firefox's tab strip/URL bar, once /// `decorated = false` actually applies to it) was silently swallowed @@ -1105,7 +1174,7 @@ mod tests { // outside RESIZE_MARGIN, so a real resize edge can't also explain a // `None` here - undecorated, this must not be treated as // decoration (or a resize edge) at all, just plain content. - let hit = ResizeEdge::hit_test(f, cx, f.y + 20, false, 0, RESIZE_MARGIN, false, None, false); + let hit = ResizeEdge::hit_test(f, cx, f.y + 20, false, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, None); } @@ -1113,7 +1182,7 @@ mod tests { fn undecorated_window_still_resizes_from_every_edge_including_top() { let f = frame(); let (cx, _) = f.center(); - let hit = ResizeEdge::hit_test(f, cx, f.y + 1, false, 0, RESIZE_MARGIN, false, None, false); + let hit = ResizeEdge::hit_test(f, cx, f.y + 1, false, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, Some(TitlebarHit::Resize(ResizeEdge::Top))); } @@ -1133,9 +1202,9 @@ mod tests { // resize zone at all, which is no longer true. let f = frame(); let (cx, _) = f.center(); - assert_eq!(ResizeEdge::hit_test(f, cx, f.y + 5, false, 0, RESIZE_MARGIN, false, None, false), None, "5px in: past the narrow undecorated band, must reach the client"); + assert_eq!(ResizeEdge::hit_test(f, cx, f.y + 5, false, 0, RESIZE_MARGIN, false, None, false, true), None, "5px in: past the narrow undecorated band, must reach the client"); assert_eq!( - ResizeEdge::hit_test(f, cx, f.y + DECORATED_TOP_RESIZE_MARGIN + 5, true, 0, RESIZE_MARGIN, false, None, false), + ResizeEdge::hit_test(f, cx, f.y + DECORATED_TOP_RESIZE_MARGIN + 5, true, 0, RESIZE_MARGIN, false, None, false, true), Some(TitlebarHit::Drag), "decorated: past its own (wider) top resize margin, still plain drag" ); @@ -1151,7 +1220,7 @@ mod tests { // within the old, decorated-window-sized corner zone // (`CORNER_MARGIN * RESIZE_MARGIN` = 18px) before this fix. let f = frame(); - let hit = ResizeEdge::hit_test(f, f.right() - 10, f.y + 10, false, 0, RESIZE_MARGIN, false, None, false); + let hit = ResizeEdge::hit_test(f, f.right() - 10, f.y + 10, false, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, None, "past the narrow undecorated corner margin on both axes, must reach the client"); } @@ -1161,7 +1230,7 @@ mod tests { // content near - nothing about `CORNER_MARGIN`'s widening should // survive for an undecorated window at any corner. let f = frame(); - let hit = ResizeEdge::hit_test(f, f.right() - 10, f.bottom() - 10, false, 0, RESIZE_MARGIN, false, None, false); + let hit = ResizeEdge::hit_test(f, f.right() - 10, f.bottom() - 10, false, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, None, "past the narrow undecorated corner margin on both axes, must reach the client"); } @@ -1174,14 +1243,14 @@ mod tests { let f = frame(); let (_, cy) = f.center(); let (cx, _) = f.center(); - assert_eq!(ResizeEdge::hit_test(f, f.right() - 1, cy, false, 0, RESIZE_MARGIN, false, None, false), Some(TitlebarHit::Resize(ResizeEdge::Right))); - assert_eq!(ResizeEdge::hit_test(f, cx, f.bottom() - 1, false, 0, RESIZE_MARGIN, false, None, false), Some(TitlebarHit::Resize(ResizeEdge::Bottom))); + assert_eq!(ResizeEdge::hit_test(f, f.right() - 1, cy, false, 0, RESIZE_MARGIN, false, None, false, true), Some(TitlebarHit::Resize(ResizeEdge::Right))); + assert_eq!(ResizeEdge::hit_test(f, cx, f.bottom() - 1, false, 0, RESIZE_MARGIN, false, None, false, true), Some(TitlebarHit::Resize(ResizeEdge::Bottom))); } #[test] fn outside_frame_is_none() { let f = frame(); - assert_eq!(ResizeEdge::hit_test(f, 0, 0, true, 0, RESIZE_MARGIN, false, None, false), None); + assert_eq!(ResizeEdge::hit_test(f, 0, 0, true, 0, RESIZE_MARGIN, false, None, false, true), None); } #[test] @@ -1196,16 +1265,16 @@ mod tests { let border_width = 2; // One pixel into the border strip, past the left edge. let x = f.x - 1; - assert_eq!(ResizeEdge::hit_test(f, x, cy, true, 0, RESIZE_MARGIN, false, None, false), None, "sanity check: with no border, this point really is outside the window"); + assert_eq!(ResizeEdge::hit_test(f, x, cy, true, 0, RESIZE_MARGIN, false, None, false, true), None, "sanity check: with no border, this point really is outside the window"); assert_eq!( - ResizeEdge::hit_test(f, x, cy, true, border_width, RESIZE_MARGIN, false, None, false), + ResizeEdge::hit_test(f, x, cy, true, border_width, RESIZE_MARGIN, false, None, false, true), Some(TitlebarHit::Resize(ResizeEdge::Left)), "one pixel into the actual drawn border must still register as the left edge" ); // Just past the border entirely (border_width + 1 outside frame) is // still nothing - the fix widens the dead zone's boundary, it // doesn't remove it. - assert_eq!(ResizeEdge::hit_test(f, f.x - border_width as i32 - 1, cy, true, border_width, RESIZE_MARGIN, false, None, false), None); + assert_eq!(ResizeEdge::hit_test(f, f.x - border_width as i32 - 1, cy, true, border_width, RESIZE_MARGIN, false, None, false, true), None); } #[test] @@ -1222,7 +1291,7 @@ mod tests { assert!(corner_reach > RESIZE_MARGIN, "the whole point of this test is that corner reach exceeds a plain edge's"); let x = f.x + corner_reach - 1; let y = f.bottom() - corner_reach + 1; - assert_eq!(ResizeEdge::hit_test(f, x, y, true, 0, RESIZE_MARGIN, false, None, false), Some(TitlebarHit::Resize(ResizeEdge::BottomLeft))); + assert_eq!(ResizeEdge::hit_test(f, x, y, true, 0, RESIZE_MARGIN, false, None, false, true), Some(TitlebarHit::Resize(ResizeEdge::BottomLeft))); } #[test] @@ -1233,7 +1302,7 @@ mod tests { // - must read as a plain bottom edge, not a corner. let x = f.x + corner_reach + 5; let y = f.bottom() - 1; - assert_eq!(ResizeEdge::hit_test(f, x, y, true, 0, RESIZE_MARGIN, false, None, false), Some(TitlebarHit::Resize(ResizeEdge::Bottom))); + assert_eq!(ResizeEdge::hit_test(f, x, y, true, 0, RESIZE_MARGIN, false, None, false, true), Some(TitlebarHit::Resize(ResizeEdge::Bottom))); } #[test] @@ -1244,7 +1313,7 @@ mod tests { // `resize_edge_at` never even ran for a y inside the titlebar. let f = frame(); let corner_reach = CORNER_MARGIN * RESIZE_MARGIN; - let hit = ResizeEdge::hit_test(f, f.x + corner_reach - 1, f.y + corner_reach - 1, true, 0, RESIZE_MARGIN, false, None, false); + let hit = ResizeEdge::hit_test(f, f.x + corner_reach - 1, f.y + corner_reach - 1, true, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, Some(TitlebarHit::Resize(ResizeEdge::TopLeft))); } @@ -1259,7 +1328,7 @@ mod tests { // the raw corner itself now sits in that real dead strip (see its // own doc comment), which correctly falls through to drag/resize, // not Close. - let hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - 1, f.y + 1, true, 0, RESIZE_MARGIN, false, None, false); + let hit = ResizeEdge::hit_test(f, f.right() - BUTTON_CLUSTER_MARGIN as i32 - 1, f.y + 1, true, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, Some(TitlebarHit::Close)); } @@ -1276,7 +1345,7 @@ mod tests { // 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); + let hit = ResizeEdge::hit_test(f, f.right() - 1, f.y + 1, true, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, Some(TitlebarHit::Resize(ResizeEdge::TopRight))); } @@ -1289,7 +1358,7 @@ mod tests { // 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); + let hit = ResizeEdge::hit_test(f, f.right() - 1, f.y + DECORATED_TOP_RESIZE_MARGIN + 5, true, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, Some(TitlebarHit::Drag)); } @@ -1300,7 +1369,7 @@ mod tests { // 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); + let hit = ResizeEdge::hit_test(f, f.x + 1, f.y + 1, true, 0, RESIZE_MARGIN, true, None, false, true); assert_eq!(hit, Some(TitlebarHit::Resize(ResizeEdge::TopLeft))); } @@ -1316,7 +1385,7 @@ mod tests { // boxes, so this is testing the plain top edge specifically. let f = frame(); let x = f.x + f.width as i32 / 2; - let hit = ResizeEdge::hit_test(f, x, f.y + DECORATED_TOP_RESIZE_MARGIN - 1, true, 0, RESIZE_MARGIN, false, None, false); + let hit = ResizeEdge::hit_test(f, x, f.y + DECORATED_TOP_RESIZE_MARGIN - 1, true, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, Some(TitlebarHit::Resize(ResizeEdge::Top))); } @@ -1328,7 +1397,7 @@ mod tests { // silently grown a resize zone everywhere. let f = frame(); let x = f.x + f.width as i32 / 2; - let hit = ResizeEdge::hit_test(f, x, f.y + DECORATED_TOP_RESIZE_MARGIN + 5, true, 0, RESIZE_MARGIN, false, None, false); + let hit = ResizeEdge::hit_test(f, x, f.y + DECORATED_TOP_RESIZE_MARGIN + 5, true, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, Some(TitlebarHit::Drag)); } @@ -1341,7 +1410,7 @@ mod tests { // avoid. Right-aligned close button's box starts at `right - 30`; // well inside it, at the very top row. let f = frame(); - let hit = ResizeEdge::hit_test(f, f.right() - 15, f.y + 1, true, 0, RESIZE_MARGIN, false, None, false); + let hit = ResizeEdge::hit_test(f, f.right() - 15, f.y + 1, true, 0, RESIZE_MARGIN, false, None, false, true); assert_eq!(hit, Some(TitlebarHit::Close)); } |