atagen

monolith

public
Star0
Watch0

Commit 00c7b3db8a3f

tarball

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

2 files changed+32-3
layout: swap with a stack that shows only one window

move_window entered any sibling container, so a stack whose other members sat on hidden tags swallowed the moving window although it looked like a lone window to swap with. It now enters only containers showing two or more windows.
Modified file: crates/layout/src/tests.rs+22 additions−2 deletions
@@ -362,7 +362,7 @@ fn moving_past_hidden_windows_does_not_drift() {
362362 t.insert_after(h2, a);
363363 t.insert_after(b, h2);
364364 let vis = |w: u32| w != h && w != h2;
365- let once = t.arrange(AREA, 0.0, |_| true);
365+ let mut once = None;
366366 for _ in 0..4 {
367367 for d in [Dir::Up, Dir::Up, Dir::Down] {
368368 t.move_window(b, d, vis);
@@ -374,8 +374,9 @@ fn moving_past_hidden_windows_does_not_drift() {
374374 );
375375 }
376376 t.check();
377+ let all = t.arrange(AREA, 0.0, |_| true);
378+ assert_eq!(*once.get_or_insert_with(|| all.clone()), all);
377379 }
378- assert_eq!(t.arrange(AREA, 0.0, |_| true), once);
379380 }
380381
381382 /// Monitors sleeping together unplug one after another, so windows already
@@ -397,3 +398,22 @@ fn windows_return_to_where_they_were_first_evicted_from() {
397398 assert_eq!(l.window(w).unwrap().output, Some(a));
398399 assert!(l.output(a).unwrap().tree.contains(w));
399400 }
401+
402+/// A stack showing one window looks like a lone window, so moving toward it
403+/// swaps places instead of joining a stack the user cannot see.
404+#[test]
405+fn moving_toward_a_stack_showing_one_window_swaps() {
406+ let (a, b, h) = (1, 2, 3);
407+ let mut t: Tree<u32> = Tree::default();
408+ t.insert_row(a);
409+ t.insert_after(b, a);
410+ t.insert_after(h, b);
411+ assert!(t.merge_window(h, Dir::Left, |_| true));
412+ let vis = |w: u32| w != h;
413+ assert!(t.move_window(a, Dir::Right, vis));
414+ t.check();
415+ let shown = t.arrange(AREA, 0.0, vis);
416+ let rect = |w| shown.iter().find(|p| p.0 == w).unwrap().1;
417+ assert!(rect(b).x < rect(a).x);
418+ assert_eq!(rect(a).h, AREA.h);
419+}
Modified file: crates/layout/src/tree.rs+10 additions−1 deletions
@@ -487,7 +487,7 @@ impl<W: Copy + Eq + Hash> Tree<W> {
487487 }
488488 if let Some(j) = self.next_shown(p, i, dir, vis) {
489489 let sib = self.children(p)[j];
490- if enter && self.axis(sib).is_some() {
490+ if enter && self.shown_windows(sib, vis) > 1 {
491491 self.join_lane(n, p, j);
492492 } else {
493493 let children = self.children_mut(p);
@@ -724,6 +724,15 @@ impl<W: Copy + Eq + Hash> Tree<W> {
724724 }
725725 }
726726
727+ fn shown_windows(&self, n: NodeId, vis: &impl Fn(W) -> bool) -> usize {
728+ match &self.nodes[n].kind {
729+ Kind::Leaf(w, _) => usize::from(vis(*w)),
730+ Kind::Container { children, .. } => {
731+ children.iter().map(|&c| self.shown_windows(c, vis)).sum()
732+ }
733+ }
734+ }
735+
727736 #[cfg(test)]
728737 pub(crate) fn check(&self) {
729738 let reachable = match self.root {