From a8991f65602abc5ecee740c443c58fa96ecd15e1 Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:55:00 +0200 Subject: Fix window memory never saving on close, and split-screen icon/primary bugs Screenshotted the just-split display on request rather than guessing -- it showed why windows never seem to remember placement/size, plus two real split-screen bugs. Window memory (WindowManager::remembered_geometry) was correctly wired on the read side, but the only writes came from end_drag/end_resize in dragresize.rs - a real drag or resize. A window the user opens, looks at, and closes without ever touching its edges had nothing recorded, so reopening it always fell back to a fresh cascade placement, for what is probably most ordinary window lifecycles. remove_window now also snapshots geometry (same app_id-non-empty gate the drag/resize sites use), persisted at both of its wayland-side call sites the same way the drag/resize-release site already does. desktop_icon_origins mirrored the full icon set onto every Monitor entry when general.desktop_icons_all_monitors is on - which, after a srd.monitor.split, is one entry per split part of the same physical screen, not one per real monitor. Extracted into a separately-tested icon_origins_for that collapses split parts of the same connector back to one origin, keeping a genuinely separate monitor's own origin intact. Found while fixing that: every split part also reported primary: true (computed from the connector's name, which doesn't vary per part) -- fixed by gating on part == 0 too. --- crates/core/src/manager/tests.rs | 29 +++++++++++++++++++++++++++++ crates/core/src/manager/windows.rs | 25 ++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) (limited to 'crates/core/src/manager') diff --git a/crates/core/src/manager/tests.rs b/crates/core/src/manager/tests.rs index c82d3dd..3d628a8 100644 --- a/crates/core/src/manager/tests.rs +++ b/crates/core/src/manager/tests.rs @@ -362,6 +362,35 @@ assert_eq!((placed.x, placed.y), (dragged_to.x, dragged_to.y), "the second alacritty window must open where the first was dragged to"); } + #[test] + fn closing_a_window_remembers_its_geometry_even_if_it_was_never_dragged_or_resized() { + // Real report: "windows don't remember their placement/size" -- + // true for any window the user never manually touched, since only + // `end_drag`/`end_resize` used to write `remembered_geometry` at + // all. A window that was simply placed by SmartPlacement, looked + // at, and closed had nothing recorded, so reopening it always fell + // back to a fresh placement - indistinguishable from the memory + // feature not existing at all for that (extremely common) case. + let mut wm = wm_with_monitor(); + wm.set_layout(wm.current_workspace(), "tiling"); + let a = wm.alloc_window_id(); + let mut w = Window::new(a, "a"); + w.app_id = "alacritty".into(); + w.geometry = Rect::new(321, 111, 444, 222); + wm.add_window(w); + // Never dragged, never resized - closed exactly as SmartPlacement + // left it. + wm.remove_window(a); + + let b = wm.alloc_window_id(); + let mut w2 = Window::new(b, "b"); + w2.app_id = "alacritty".into(); + w2.geometry = Rect::new(0, 0, 800, 600); + wm.add_window(w2); + let placed = wm.window(b).unwrap().geometry; + assert_eq!((placed.x, placed.y, placed.width, placed.height), (321, 111, 444, 222), "the next alacritty window must open where/how large the first one was when it closed"); + } + #[test] fn a_remembered_position_on_a_monitor_that_no_longer_exists_falls_back_to_placement() { let mut wm = wm_with_monitor(); diff --git a/crates/core/src/manager/windows.rs b/crates/core/src/manager/windows.rs index 5468796..40b4c17 100644 --- a/crates/core/src/manager/windows.rs +++ b/crates/core/src/manager/windows.rs @@ -261,7 +261,30 @@ impl WindowManager { if self.focused == Some(id) { self.focused = self.order.last().copied(); } - self.windows.remove(&id) + let window = self.windows.remove(&id); + // Remembers wherever this app's window actually ended up, not just + // wherever a manual drag/resize left it (`dragresize.rs`'s own + // `end_drag`/`end_resize` sites) - without this, an app the user + // never dragged or resized had nothing recorded at all, so closing + // and reopening it always fell back to a fresh cascade placement + // regardless of where it had actually been sitting. Reported live + // as "windows don't remember their placement", indistinguishable + // from a broken feature even though the underlying store and its + // read side (`WindowManager::add_window`'s own `remembered_ + // geometry` lookup) were already both correct - this was the one + // write path that never fired for an app the user just opens, + // looks at, and closes. Same `app_id`-non-empty gate as the + // drag/resize sites, and the same reasoning for not also gating on + // `floating`: a tiled window's geometry is layout-computed and + // simply never consulted again on the read side once `layout_name + // == "tiling"`, so remembering it anyway is harmless, not wasted + // work worth a special case. + if let Some(w) = &window { + if !w.app_id.is_empty() { + self.remembered_geometry.insert(w.app_id.clone(), (w.geometry.x, w.geometry.y, w.geometry.width, w.geometry.height)); + } + } + window } pub fn window(&self, id: WindowId) -> Option<&Window> { -- cgit v1.2.3