From 646b37e7e3aa5931079c6b9e804f420bb43c74d5 Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Mon, 11 May 2026 16:57:00 +0200 Subject: Fix spawn placement under the top bar, add per-window minimum sizes, and clean up maximize Four reports after restarting into today's build, with a screenshot. The screenshot was measured, not eyeballed: top bar y=0..29, a 4px accent border at y=30..33, titlebar from y=34, bottom border at y=1027..1030, and 49px of bare desktop below it. Windows spawning too close to the top bar. A remembered position was validated only by asking whether it landed on some monitor's full_geometry, which includes the strip a top bar reserves, so an app whose remembered y was small reopened with its titlebar under the bar. That is why it was "sometimes": it depended on the stored value, and the live store holds wezterm at y=44 and firefox at y=69 against a 30px bar. Remembered positions are now clamped into the monitor's usable area. Placement not surviving a logout. Window memory does persist, but five of the eleven entries in the live store were saved with a second monitor attached, at x >= 2000. Those points match no current monitor and were discarded outright, falling back to a fresh cascade, so those apps appeared to remember nothing. Such a position is now clamped onto a monitor that exists instead. Per-window minimum sizes. One global floor is wrong in both directions. Three sources now, in increasing precedence: the global floor, the client's own declared minimum (xdg_toplevel.set_min_size or ICCCM hints), and a min_width/min_height window rule overriding both. A rule wins permanently -- the backend refreshes the client's declared minimum on every decoration redraw and must not undo a deliberate override. Maximize, three faults in one report. A maximized window now draws no border: its edges are the screen's edges, and the only place maximize stops short is the bar strip, which is exactly where the measured line was. maximize_geometry_for no longer subtracts a bottom-anchored dock's exclusive zone, so maximize runs to the bottom of the screen and the dock floats over it; top, left and right are still honoured. general.maximize_covers_dock = false restores the old behaviour. With the border gone the window sits flush under the bar instead of with an accent line crowding it. Verified: seven new tests on the real numbers from the live store, and maximize geometry measured live in a nested instance (a window maximized on a split half reports exactly that half's rect). NOT confirmed on screen: the border removal and the dock behaviour - the nested backend has no bar or dock to reserve a zone, and an attempt to check the border produced a failing control, since srd set border_width only affects windows created after it. 515 tests pass, clippy clean. --- docs/DEFAULTS.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'docs/DEFAULTS.md') diff --git a/docs/DEFAULTS.md b/docs/DEFAULTS.md index 3497410..2cc1614 100644 --- a/docs/DEFAULTS.md +++ b/docs/DEFAULTS.md @@ -20,6 +20,7 @@ srd.set("general.gpu", false) -- Default: false - udev srd.set("general.desktop_icons", true) -- Default: true - see "Desktop icons" below srd.set("general.desktop_icons_all_monitors", true) -- Default: true - mirror icons onto every monitor, not just primary srd.set("general.config_reload_on_write", true) -- Default: true - re-read init.lua when it changes on disk +srd.set("general.maximize_covers_dock", true) -- Default: true - maximize runs under a bottom dock, not above it srd.set("general.reserve_top", 0) -- Default: 0 - static space reserved before any bar/dock connects srd.set("general.reserve_bottom", 0) -- Default: 0 - see "Startup space reservation" below srd.set("general.reserve_left", 0) -- Default: 0 @@ -881,3 +882,56 @@ One limit to know: a reload does not re-register key *grabs* with the backend, so a brand new key combination needs a restart before the compositor sees that key at all. An existing combination picks up its new action immediately. + +## Window minimum sizes + +Every window has a minimum size it cannot be resized below. Three sources, +in increasing precedence: + +1. A global floor, used when nothing else applies. +2. The client's own declared minimum - `xdg_toplevel.set_min_size` for a + native Wayland window, the ICCCM size hints for an XWayland one. Read + from the client and refreshed as it changes. +3. A `min_width`/`min_height` window rule, which overrides both. Either may + be given alone; the other axis keeps the global floor. + +```lua +srd.rule({ class = "Alacritty" }, { min_width = 480, min_height = 320 }) +``` + +A rule wins permanently: the client's own declared minimum is never allowed +to overwrite it, so an application that reports a minimum too large for a +small screen can be overridden. The minimum applies to interactive resizing, +to a size restored from window memory, and to any programmatic resize. + +## Maximize + +Maximize targets the monitor's full rectangle minus the space reserved by +top, left and right layer-shell surfaces. A bottom-anchored dock is +deliberately not subtracted, so a maximized window runs to the bottom of the +screen and the dock floats over it - the usual behaviour for an auto-hiding +dock. Set `general.maximize_covers_dock = false` to have maximize stop above +the dock instead. + +A maximized window draws no border. Its edges are the screen's edges, so a +border has nothing to separate it from, and where maximize does stop short +(the strip a top bar reserves) a border would otherwise draw as a hard line +directly against the bar. + +## Where a window opens + +In order: a `geometry` window rule wins outright; otherwise a position and +size remembered for that `app_id` are restored; otherwise smart placement +picks a free grid cell, falling back to a cascade. + +A remembered position is clamped into the target monitor's *usable* area -- +the region left after bars and docks reserve their space. Without that +clamp, an app whose remembered `y` was smaller than the top bar's height +reopened with its titlebar underneath the bar, where it could not be +grabbed. A position remembered on a monitor that is no longer connected is +clamped onto a current monitor rather than discarded, so undocking does not +make an app forget where it lives. + +Dialogs are centred instead, and take neither a remembered position nor a +remembered size - window memory is keyed by `app_id`, which a dialog shares +with the window that spawned it. -- cgit v1.2.3