atagen

monolith

public
Star0
Watch0

Commit 54559daf11c3

tarball

atagen <boss@atagen.co>2026-10-17 13:39 UTC

3 files changed+57-22
layout: expand and report maximized against the visible tree

A window whose container held only hidden siblings looked like a top-level window but expanded inside that container, which changed nothing on screen. Containers where the window has no visible sibling are now skipped.
Modified file: crates/layout/src/lib.rs+5 additions−2 deletions
@@ -524,7 +524,7 @@ impl Layout {
524524 let Some(o) = self.windows.get(w).and_then(|w| w.output) else {
525525 return false;
526526 };
527- self.outputs[o].tree.maximized(w)
527+ self.outputs[o].tree.maximized(w, self.vis_on(o))
528528 }
529529
530530 pub fn resize(&mut self, axis: Axis, delta: f64) -> bool {
@@ -546,7 +546,10 @@ impl Layout {
546546 ExpandScope::Container => (1, 1),
547547 ExpandScope::All => (0, usize::MAX),
548548 };
549- self.outputs[o].tree.toggle_expand(w, skip, count)
549+ let mut tree = std::mem::take(&mut self.outputs[o].tree);
550+ let expanded = tree.toggle_expand(w, skip, count, self.vis_on(o));
551+ self.outputs[o].tree = tree;
552+ expanded
550553 }
551554
552555 pub fn flip(&mut self, o: OutputId) {
Modified file: crates/layout/src/tests.rs+18 additions
@@ -294,3 +294,21 @@ fn merging_steps_out_of_a_stack_before_joining_another() {
294294 assert_eq!(rect(a).w, AREA.w);
295295 assert!(rect(a).bottom() <= rect(b).y && rect(b).y == rect(c).y);
296296 }
297+
298+/// A window alone on screen in a container of hidden ones expands among the
299+/// windows it is shown beside, not inside the container nobody can see.
300+#[test]
301+fn expand_skips_containers_of_hidden_windows() {
302+ let (a, b, c) = (1, 2, 3);
303+ let mut t: Tree<u32> = Tree::default();
304+ t.insert_row(a);
305+ t.insert_after(b, a);
306+ t.insert_after(c, b);
307+ assert!(t.merge_window(a, Dir::Right, |_| true));
308+ let shown = |w: u32| w != a;
309+ assert!(t.toggle_expand(b, 0, 1, shown));
310+ assert!(t.maximized(b, shown));
311+ let all = t.arrange(AREA, 0.0, shown);
312+ let rect = |w| all.iter().find(|p| p.0 == w).unwrap().1;
313+ assert_eq!(rect(b).w, AREA.w);
314+}
Modified file: crates/layout/src/tree.rs+34 additions−20 deletions
@@ -217,20 +217,31 @@ impl<W: Copy + Eq + Hash> Tree<W> {
217217 }
218218
219219 /// Whether every container above `w` is expanded towards it.
220- pub fn maximized(&self, w: W) -> bool {
220+ pub fn maximized(&self, w: W, vis: impl Fn(W) -> bool) -> bool {
221+ let path = self.shown_path(w, &vis);
222+ !path.is_empty() && path.iter().all(|&(p, c)| self.expanded(p) == Some(c))
223+ }
224+
225+ /// `w`'s ancestry as (container, child) pairs, leaving out containers
226+ /// where the child has no visible sibling. Those look like nothing on
227+ /// screen, so expanding there would do nothing the user could see.
228+ fn shown_path(&self, w: W, vis: &impl Fn(W) -> bool) -> Vec<(NodeId, NodeId)> {
221229 let Some(&leaf) = self.leaves.get(&w) else {
222- return false;
230+ return Vec::new();
223231 };
232+ let mut path = Vec::new();
224233 let mut cur = leaf;
225- let mut any = false;
226234 while let Some(p) = self.nodes[cur].parent {
227- if self.expanded(p) != Some(cur) {
228- return false;
235+ let shared = self
236+ .children(p)
237+ .iter()
238+ .any(|c| c.node != cur && self.visible(c.node, vis));
239+ if shared {
240+ path.push((p, cur));
229241 }
230- any = true;
231242 cur = p;
232243 }
233- any
244+ path
234245 }
235246
236247 /// Transposes the whole tree.
@@ -243,19 +254,22 @@ impl<W: Copy + Eq + Hash> Tree<W> {
243254 }
244255 }
245256
246- /// Toggles expansion for `count` levels of `w`'s ancestry, starting
247- /// `skip` levels up. Level 0 expands the window inside its container.
248- pub fn toggle_expand(&mut self, w: W, skip: usize, count: usize) -> bool {
249- let Some(&leaf) = self.leaves.get(&w) else {
250- return false;
251- };
252- let mut path = Vec::new();
253- let mut cur = leaf;
254- while let Some(p) = self.nodes[cur].parent {
255- path.push((p, cur));
256- cur = p;
257- }
258- let path: Vec<_> = path.into_iter().skip(skip).take(count).collect();
257+ /// Toggles expansion for `count` levels of `w`'s visible ancestry,
258+ /// starting `skip` levels up. Level 0 expands the window inside the
259+ /// nearest container where it has a visible sibling.
260+ pub fn toggle_expand(
261+ &mut self,
262+ w: W,
263+ skip: usize,
264+ count: usize,
265+ vis: impl Fn(W) -> bool,
266+ ) -> bool {
267+ let path: Vec<_> = self
268+ .shown_path(w, &vis)
269+ .into_iter()
270+ .skip(skip)
271+ .take(count)
272+ .collect();
259273 if path.is_empty() {
260274 return false;
261275 }