Commit 9d1128e3c227
tarball3 files changed+116-60
@@ -427,12 +427,14 @@ impl Layout {
427427
let split = anchor428428
.filter(|_| self.autotile)429429
.and_then(|a| self.split_axis(o, a));430
- let tree = &mut self.outputs[o].tree;430
+ let mut tree = std::mem::take(&mut self.outputs[o].tree);431
+ let vis = self.vis_on(o);431432
match (anchor, split) {432
- (Some(a), Some(axis)) => tree.insert_split(w, a, axis),433
- (Some(a), None) => tree.insert_after(w, a),434
- (None, _) => tree.insert_row(w),433
+ (Some(a), Some(axis)) => tree.insert_split(w, a, axis, vis),434
+ (Some(a), None) => tree.insert_after(w, a, vis),435
+ (None, _) => tree.insert_row(w, vis),435436
}437
+ self.outputs[o].tree = tree;436438
}437439
438440
/// The axis a window opening beside `anchor` should split it along, the@@ -456,8 +458,10 @@ impl Layout {
456458
let Some(o) = self.windows[w].output else {457459
return;458460
};461
+ let mut tree = std::mem::take(&mut self.outputs[o].tree);462
+ tree.remove(w, self.vis_on(o));459463
let out = &mut self.outputs[o];460
- out.tree.remove(w);464
+ out.tree = tree;461465
out.floating.retain(|&f| f != w);462466
}463467
@@ -240,11 +240,11 @@ proptest! {
240240
fn hidden_windows_keep_their_slots() {241241
let (a, b, c, d, e) = (1, 2, 3, 4, 5);242242
let mut t: Tree<u32> = Tree::default();243
- t.insert_row(a);244
- t.insert_after(d, a);245
- t.insert_after(b, d);246
- t.insert_row(c);247
- t.insert_after(e, c);243
+ t.insert_row(a, |_| true);244
+ t.insert_after(d, a, |_| true);245
+ t.insert_after(b, d, |_| true);246
+ t.insert_row(c, |_| true);247
+ t.insert_after(e, c, |_| true);248248
t.check();249249
let hidden = |w: u32| w != d && w != e;250250
let all = |_| true;@@ -270,11 +270,11 @@ fn hidden_windows_keep_their_slots() {
270270
fn moving_toward_a_hidden_lane_joins_it() {271271
let (a, b, c, d, e) = (1, 2, 3, 4, 5);272272
let mut t: Tree<u32> = Tree::default();273
- t.insert_row(a);274
- t.insert_after(b, a);275
- t.insert_after(c, b);276
- t.insert_row(d);277
- t.insert_after(e, c);273
+ t.insert_row(a, |_| true);274
+ t.insert_after(b, a, |_| true);275
+ t.insert_after(c, b, |_| true);276
+ t.insert_row(d, |_| true);277
+ t.insert_after(e, c, |_| true);278278
let tag_two = |w: u32| w != a && w != d;279279
assert!(t.move_window(e, Dir::Down, tag_two));280280
t.check();@@ -290,9 +290,9 @@ fn merging_steps_out_of_a_stack_before_joining_another() {
290290
let (a, b, c) = (1, 2, 3);291291
let stacked = || {292292
let mut t: Tree<u32> = Tree::default();293
- t.insert_row(a);294
- t.insert_after(b, a);295
- t.insert_after(c, b);293
+ t.insert_row(a, |_| true);294
+ t.insert_after(b, a, |_| true);295
+ t.insert_after(c, b, |_| true);296296
assert!(t.merge_window(b, Dir::Left, |_| true));297297
t298298
};@@ -325,9 +325,9 @@ fn extended_windows_move_their_group() {
325325
let (a, b, c) = (1, 2, 3);326326
let all = |_| true;327327
let mut t: Tree<u32> = Tree::default();328
- t.insert_row(a);329
- t.insert_after(b, a);330
- t.insert_after(c, b);328
+ t.insert_row(a, |_| true);329
+ t.insert_after(b, a, |_| true);330
+ t.insert_after(c, b, |_| true);331331
assert!(t.merge_window(b, Dir::Left, all));332332
assert!(t.toggle_expand(b, 0, 1, all));333333
let rects = |t: &Tree<u32>| {@@ -355,10 +355,10 @@ fn retagging_an_extended_window_leaves_hidden_members() {
355355
let (a, b, c, d) = (1, 2, 3, 4);356356
let shown = |w| w != d;357357
let mut t: Tree<u32> = Tree::default();358
- t.insert_row(a);359
- t.insert_after(b, a);360
- t.insert_after(c, b);361
- t.insert_after(d, c);358
+ t.insert_row(a, |_| true);359
+ t.insert_after(b, a, |_| true);360
+ t.insert_after(c, b, |_| true);361
+ t.insert_after(d, c, |_| true);362362
assert!(t.toggle_expand(b, 0, 1, shown));363363
let mut group = t.group_windows(b, shown);364364
group.sort();@@ -372,9 +372,9 @@ fn retagging_an_extended_window_leaves_hidden_members() {
372372
fn expand_skips_containers_of_hidden_windows() {373373
let (a, b, c) = (1, 2, 3);374374
let mut t: Tree<u32> = Tree::default();375
- t.insert_row(a);376
- t.insert_after(b, a);377
- t.insert_after(c, b);375
+ t.insert_row(a, |_| true);376
+ t.insert_after(b, a, |_| true);377
+ t.insert_after(c, b, |_| true);378378
assert!(t.merge_window(a, Dir::Right, |_| true));379379
let shown = |w: u32| w != a;380380
assert!(t.toggle_expand(b, 0, 1, shown));@@ -390,9 +390,9 @@ fn stacking_in_and_out_does_not_drift() {
390390
for out in [Dir::Up, Dir::Down, Dir::Right] {391391
let (a, b, c) = (1, 2, 3);392392
let mut t: Tree<u32> = Tree::default();393
- t.insert_row(a);394
- t.insert_after(b, a);395
- t.insert_after(c, b);393
+ t.insert_row(a, |_| true);394
+ t.insert_after(b, a, |_| true);395
+ t.insert_after(c, b, |_| true);396396
assert!(t.merge_window(c, Dir::Left, |_| true));397397
assert!(t.merge_window(c, out, |_| true));398398
let once = t.arrange(AREA, 0.0, |_| true);@@ -411,10 +411,10 @@ fn stacking_in_and_out_does_not_drift() {
411411
fn moving_past_hidden_windows_does_not_drift() {412412
let (a, b, h, h2) = (1, 2, 3, 4);413413
let mut t: Tree<u32> = Tree::default();414
- t.insert_row(h);415
- t.insert_row(a);416
- t.insert_after(h2, a);417
- t.insert_after(b, h2);414
+ t.insert_row(h, |_| true);415
+ t.insert_row(a, |_| true);416
+ t.insert_after(h2, a, |_| true);417
+ t.insert_after(b, h2, |_| true);418418
let vis = |w: u32| w != h && w != h2;419419
let mut once = None;420420
for _ in 0..4 {@@ -459,9 +459,9 @@ fn windows_return_to_where_they_were_first_evicted_from() {
459459
fn moving_toward_a_stack_showing_one_window_swaps() {460460
let (a, b, h) = (1, 2, 3);461461
let mut t: Tree<u32> = Tree::default();462
- t.insert_row(a);463
- t.insert_after(b, a);464
- t.insert_after(h, b);462
+ t.insert_row(a, |_| true);463
+ t.insert_after(b, a, |_| true);464
+ t.insert_after(h, b, |_| true);465465
assert!(t.merge_window(h, Dir::Left, |_| true));466466
let vis = |w: u32| w != h;467467
assert!(t.move_window(a, Dir::Right, vis));@@ -483,12 +483,12 @@ fn moves_are_seen_or_undone() {
483483
for _ in 0..2000 {484484
let seq = proptest::strategy::ValueTree::current(&ops.new_tree(&mut runner).unwrap());485485
let mut t: Tree<u32> = Tree::default();486
- t.insert_row(0);486
+ t.insert_row(0, |_| true);487487
let mut n = 1;488488
for &(w, d, kind, hide) in &seq {489489
let vis = |x: u32| hide & (1 << x) == 0;490490
if kind == 0 && n < 5 {491
- t.insert_after(n, u32::from(w) % n);491
+ t.insert_after(n, u32::from(w) % n, |_| true);492492
n += 1;493493
continue;494494
}@@ -569,14 +569,14 @@ fn rect_of(t: &Tree<u32>, w: u32, vis: impl Fn(u32) -> bool) -> Rect {
569569
fn splitting_a_lone_window_shares_its_space() {570570
let (a, b, c) = (1, 2, 3);571571
let mut t: Tree<u32> = Tree::default();572
- t.insert_row(a);573
- t.insert_split(b, a, Axis::Horizontal);572
+ t.insert_row(a, |_| true);573
+ t.insert_split(b, a, Axis::Horizontal, |_| true);574574
t.check();575575
let (ra, rb) = (rect_of(&t, a, |_| true), rect_of(&t, b, |_| true));576576
assert_eq!((ra.w, rb.w, ra.h), (AREA.w / 2.0, AREA.w / 2.0, AREA.h));577577
assert!(ra.x < rb.x);578578
579
- t.insert_split(c, b, Axis::Vertical);579
+ t.insert_split(c, b, Axis::Vertical, |_| true);580580
t.check();581581
let (rb, rc) = (rect_of(&t, b, |_| true), rect_of(&t, c, |_| true));582582
assert_eq!(@@ -591,11 +591,11 @@ fn splitting_a_lone_window_shares_its_space() {
591591
fn splitting_along_the_parents_axis_appends_a_sibling() {592592
let (a, b, c, d) = (1, 2, 3, 4);593593
let mut t: Tree<u32> = Tree::default();594
- t.insert_row(a);595
- t.insert_split(b, a, Axis::Horizontal);596
- t.insert_split(c, b, Axis::Vertical);594
+ t.insert_row(a, |_| true);595
+ t.insert_split(b, a, Axis::Horizontal, |_| true);596
+ t.insert_split(c, b, Axis::Vertical, |_| true);597597
let before = rect_of(&t, a, |_| true);598
- t.insert_split(d, a, Axis::Horizontal);598
+ t.insert_split(d, a, Axis::Horizontal, |_| true);599599
t.check();600600
let all = |_| true;601601
let (ra, rd, rb) = (@@ -612,19 +612,19 @@ fn splitting_along_the_parents_axis_appends_a_sibling() {
612612
fn splitting_beside_hidden_windows_leaves_their_slots_alone() {613613
let (a, b, c, d) = (1, 2, 3, 4);614614
let mut t: Tree<u32> = Tree::default();615
- t.insert_row(a);616
- t.insert_after(b, a);617
- t.insert_after(c, a);615
+ t.insert_row(a, |_| true);616
+ t.insert_after(b, a, |_| true);617
+ t.insert_after(c, a, |_| true);618618
let tag_one = |w: u32| w == a || w == d;619619
assert_eq!(rect_of(&t, a, tag_one).h, AREA.h);620620
621
- t.insert_split(d, a, Axis::Vertical);621
+ t.insert_split(d, a, Axis::Vertical, |_| true);622622
t.check();623623
let (ra, rd) = (rect_of(&t, a, tag_one), rect_of(&t, d, tag_one));624624
assert_eq!((ra.h, rd.h, ra.w), (AREA.h / 2.0, AREA.h / 2.0, AREA.w));625625
assert!(ra.y < rd.y);626626
627
- t.insert_split(d + 1, a, Axis::Horizontal);627
+ t.insert_split(d + 1, a, Axis::Horizontal, |_| true);628628
t.check();629629
let shown = |w: u32| w == a || w == d + 1;630630
let (ra, re) = (rect_of(&t, a, shown), rect_of(&t, d + 1, shown));@@ -633,6 +633,30 @@ fn splitting_beside_hidden_windows_leaves_their_slots_alone() {
633633
assert_eq!(t.windows().count(), 5, "hidden windows stay in the tree");634634
}635635
636
+/// Windows opened and closed beside a hidden one used to leave it a larger637
+/// share each time, doubling it per split.638
+#[test]639
+fn hidden_shares_survive_windows_coming_and_going() {640
+ let (a, h, n) = (1, 2, 3);641
+ let mut t: Tree<u32> = Tree::default();642
+ t.insert_row(a, |_| true);643
+ t.insert_after(h, a, |_| true);644
+ let vis = |w: u32| w != h;645
+ let before = rect_of(&t, h, |_| true);646
+ for _ in 0..3 {647
+ t.insert_split(n, a, Axis::Horizontal, vis);648
+ t.remove(n, vis);649
+ t.insert_after(n, a, vis);650
+ t.remove(n, vis);651
+ }652
+ t.check();653
+ let after = rect_of(&t, h, |_| true);654
+ assert!(655
+ (after.w - before.w).abs() < 1e-6,656
+ "{before:?} became {after:?}"657
+ );658
+}659
+636660
#[test]637661
fn autotile_dwindles_by_the_anchors_shape() {638662
let mut l = Layout {@@ -118,9 +118,9 @@ impl<W: Copy + Eq + Hash> Tree<W> {
118118
119119
/// Inserts `w` as the next sibling of `anchor`, or as a new row if120120
/// `anchor` is not in the tree.121
- pub fn insert_after(&mut self, w: W, anchor: W) {121
+ pub fn insert_after(&mut self, w: W, anchor: W, vis: impl Fn(W) -> bool) {122122
let Some(&a) = self.leaves.get(&anchor) else {123
- return self.insert_row(w);123
+ return self.insert_row(w, vis);124124
};125125
match self.position(a) {126126
Some((p, i)) if Some(p) == self.root && self.axis(p) == Some(self.stack) => {@@ -135,6 +135,7 @@ impl<W: Copy + Eq + Hash> Tree<W> {
135135
Some((p, i)) => {136136
let n = self.new_leaf(w, self.size(p));137137
self.attach(p, i + 1, n);138
+ self.rescale_hidden(n, true, &vis);138139
self.reveal(n, true);139140
}140141
None => {@@ -149,9 +150,9 @@ impl<W: Copy + Eq + Hash> Tree<W> {
149150
150151
/// Inserts `w` after `anchor` by splitting `anchor` along `axis`. They151152
/// share the space `anchor` had, and its siblings keep theirs.152
- pub fn insert_split(&mut self, w: W, anchor: W, axis: Axis) {153
+ pub fn insert_split(&mut self, w: W, anchor: W, axis: Axis, vis: impl Fn(W) -> bool) {153154
let Some(&a) = self.leaves.get(&anchor) else {154
- return self.insert_row(w);155
+ return self.insert_row(w, vis);155156
};156157
let size = self.size(a);157158
let n = self.new_leaf(w, size);@@ -184,8 +185,32 @@ impl<W: Copy + Eq + Hash> Tree<W> {
184185
}185186
}186187
188
+ /// Scales the hidden siblings of a visible `n` arriving in or leaving its189
+ /// container by as much as the visible ones grow or shrink together, so190
+ /// the share they come back to does not drift as windows come and go.191
+ fn rescale_hidden(&mut self, n: NodeId, arriving: bool, vis: &impl Fn(W) -> bool) {192
+ let (Some((p, _)), true) = (self.position(n), self.visible(n, vis)) else {193
+ return;194
+ };195
+ let axis = self.axis(p).expect("parents are containers");196
+ let (shown, hidden): (Vec<NodeId>, Vec<NodeId>) = self197
+ .children(p)198
+ .iter()199
+ .filter(|&&c| c != n)200
+ .partition(|&&c| self.visible(c, vis));201
+ let rest: f64 = shown.iter().map(|&c| self.extent(c, axis, vis)).sum();202
+ if rest <= 0.0 {203
+ return;204
+ }205
+ let with = rest + self.extent(n, axis, vis);206
+ let by = if arriving { with / rest } else { rest / with };207
+ for c in hidden {208
+ self.scale(c, axis, by);209
+ }210
+ }211
+187212
/// Appends `w` as a row of its own along the stacking axis.188
- pub fn insert_row(&mut self, w: W) {213
+ pub fn insert_row(&mut self, w: W, vis: impl Fn(W) -> bool) {189214
let size = self.root.map_or([1.0; 2], |r| self.size(r));190215
let n = self.new_leaf(w, size);191216
match self.root {@@ -193,6 +218,7 @@ impl<W: Copy + Eq + Hash> Tree<W> {
193218
Some(r) if self.axis(r) == Some(self.stack) => {194219
let end = self.children(r).len();195220
self.attach(r, end, n);221
+ self.rescale_hidden(n, true, &vis);196222
}197223
Some(r) => {198224
let c = self.new_container(self.stack);@@ -204,10 +230,12 @@ impl<W: Copy + Eq + Hash> Tree<W> {
204230
self.reveal(n, true);205231
}206232
207
- pub fn remove(&mut self, w: W) -> bool {208
- let Some(n) = self.leaves.remove(&w) else {233
+ pub fn remove(&mut self, w: W, vis: impl Fn(W) -> bool) -> bool {234
+ let Some(&n) = self.leaves.get(&w) else {209235
return false;210236
};237
+ self.rescale_hidden(n, false, &vis);238
+ self.leaves.remove(&w);211239
self.detach(n);212240
self.nodes.remove(n);213241
true@@ -216,7 +244,7 @@ impl<W: Copy + Eq + Hash> Tree<W> {
216244
pub fn retain(&mut self, mut keep: impl FnMut(W) -> bool) {217245
let gone: Vec<W> = self.windows().filter(|&w| !keep(w)).collect();218246
for w in gone {219
- self.remove(w);247
+ self.remove(w, |_| false);220248
}221249
}