atagen

monolith

public
Star0
Watch0

Commit 8ffa3fa4d4a9

tarball

atagen <boss@atagen.co>2026-10-18 09:38 UTC

2 files changed+21-1
layout: keep the first output a window was evicted from

remove_output overwrote evicted_from on every unplug, so a window moved off one output and then off a second was claimed by the second on replug and never returned to the first. Monitors sleeping together unplug in exactly that order.
Modified file: crates/layout/src/outputs.rs+1 additions−1 deletions
@@ -118,7 +118,7 @@ impl Layout {
118118 if win.scratchpad.is_some() {
119119 continue;
120120 }
121- win.evicted_from = Some(out.name.clone());
121+ win.evicted_from.get_or_insert_with(|| out.name.clone());
122122 if target.is_some() {
123123 self.place(w);
124124 }
Modified file: crates/layout/src/tests.rs+20 additions
@@ -376,3 +376,23 @@ fn moving_past_hidden_windows_does_not_drift() {
376376 assert!((r.y - s.y).abs() < 1e-6 && (r.h - s.h).abs() < 1e-6, "{w}: {r:?} became {s:?}");
377377 }
378378 }
379+
380+/// Monitors sleeping together unplug one after another, so windows already
381+/// moved off the first must still go home to it, not to the second.
382+#[test]
383+fn windows_return_to_where_they_were_first_evicted_from() {
384+ let mut l = Layout::default();
385+ let a = l.add_output("a", AREA);
386+ l.add_output("b", Rect::new(1000.0, 0.0, 800.0, 600.0));
387+ let c = l.add_output("c", Rect::new(1800.0, 0.0, 800.0, 600.0));
388+ let w = l.add_window(Some(a), None, None);
389+ l.remove_output(a);
390+ let b = l.outputs().find(|(_, out)| out.name == "b").unwrap().0;
391+ l.remove_output(b);
392+ assert_eq!(l.window(w).unwrap().output, Some(c));
393+ l.add_output("b", Rect::new(1000.0, 0.0, 800.0, 600.0));
394+ let a = l.add_output("a", AREA);
395+ l.check();
396+ assert_eq!(l.window(w).unwrap().output, Some(a));
397+ assert!(l.output(a).unwrap().tree.contains(w));
398+}