Commit 4b73e40af1e3
tarball4 files changed+85-21
@@ -664,11 +664,11 @@ impl Layout {
664664
if !self.outputs.contains_key(o) || win.output == Some(o) || win.scratchpad.is_some() {665665
return;666666
}667
- let from = win.output.map(|f| self.outputs[f].area);667
+ let from = win.output.map(|f| self.outputs[f].usable());668668
self.unplace(w);669669
let win = &mut self.windows[w];670670
if let (Some(from), Some(rect)) = (from, win.float_rect) {671
- win.float_rect = Some(translate(rect, from, self.outputs[o].area));671
+ win.float_rect = Some(translate(rect, from, self.outputs[o].usable()));672672
}673673
win.output = Some(o);674674
win.evicted_from = None;@@ -948,14 +948,19 @@ pub fn clamp_float(r: Rect, bounds: Rect) -> Rect {
948948
Rect::new(x, y, r.w, r.h)949949
}950950
951
-/// Keeps a rect at the same relative spot when it changes output.951
+/// Keeps a floating rect at the same relative spot and size when the area952
+/// it lives in changes.952953
fn translate(r: Rect, from: Rect, to: Rect) -> Rect {954
+ if to.w <= 0.0 || to.h <= 0.0 {955
+ return r;956
+ }953957
let sx = if from.w > 0.0 { to.w / from.w } else { 1.0 };954958
let sy = if from.h > 0.0 { to.h / from.h } else { 1.0 };955
- Rect::new(959
+ let scaled = Rect::new(956960
to.x + (r.x - from.x) * sx,957961
to.y + (r.y - from.y) * sy,958
- r.w.min(to.w),959
- r.h.min(to.h),960
- )962
+ (r.w * sx).max(MIN_FLOAT_SIZE),963
+ (r.h * sy).max(MIN_FLOAT_SIZE),964
+ );965
+ clamp_float(scaled, to)961966
}@@ -5,7 +5,6 @@ pub(crate) struct Parked {
55
tree: Tree<WindowId>,66
viewed: Vec<TagId>,77
floating: Vec<WindowId>,8
- area: Rect,98
}109
1110
impl Layout {@@ -59,7 +58,11 @@ impl Layout {
5958
self.unplace(w);6059
let win = &mut self.windows[w];6160
if let (Some(from), Some(rect)) = (win.output, win.float_rect) {62
- win.float_rect = Some(translate(rect, self.outputs[from].area, parked.area));61
+ win.float_rect = Some(translate(62
+ rect,63
+ self.outputs[from].usable(),64
+ self.outputs[id].usable(),65
+ ));6366
}6467
win.output = Some(id);6568
win.evicted_from = None;@@ -80,13 +83,13 @@ impl Layout {
8083
let Some(out) = self.outputs.remove(o) else {8184
return;8285
};86
+ let left_usable = out.usable();8387
self.parked.insert(8488
out.name.clone(),8589
Parked {8690
tree: out.tree,8791
viewed: out.viewed,8892
floating: out.floating,89
- area: out.area,9093
},9194
);9295
if self.active == Some(o) {@@ -112,7 +115,7 @@ impl Layout {
112115
.or(self.active);113116
let win = &mut self.windows[w];114117
if let (Some(t), Some(rect)) = (target, win.float_rect) {115
- win.float_rect = Some(translate(rect, out.area, self.outputs[t].area));118
+ win.float_rect = Some(translate(rect, left_usable, self.outputs[t].usable()));116119
}117120
win.output = target;118121
if win.scratchpad.is_some() {@@ -126,19 +129,38 @@ impl Layout {
126129
}127130
128131
pub fn set_output_area(&mut self, o: OutputId, area: Rect) {129
- if let Some(out) = self.outputs.get_mut(o) {130
- out.area = area;131
- }132
+ let Some(out) = self.outputs.get_mut(o) else {133
+ return;134
+ };135
+ let before = out.usable();136
+ out.area = area;137
+ self.rescale_floats(o, before);132138
}133139
134140
/// Returns whether anything changed.135141
pub fn set_reserved(&mut self, o: OutputId, reserved: Insets) -> bool {136
- match self.outputs.get_mut(o) {137
- Some(out) if out.reserved != reserved => {138
- out.reserved = reserved;139
- true142
+ let Some(out) = self.outputs.get_mut(o) else {143
+ return false;144
+ };145
+ if out.reserved == reserved {146
+ return false;147
+ }148
+ let before = out.usable();149
+ out.reserved = reserved;150
+ self.rescale_floats(o, before);151
+ true152
+ }153
+154
+ /// Carries floating windows along when the usable area of o changes.155
+ fn rescale_floats(&mut self, o: OutputId, before: Rect) {156
+ let after = self.outputs[o].usable();157
+ if after == before {158
+ return;159
+ }160
+ for win in self.windows.values_mut().filter(|w| w.output == Some(o)) {161
+ if let Some(rect) = win.float_rect {162
+ win.float_rect = Some(translate(rect, before, after));140163
}141
- _ => false,142164
}143165
}144166
}@@ -47,16 +47,17 @@ impl Layout {
4747
sp.shown = None;4848
return None;4949
}50
- let from = sp.output.map(|f| self.outputs[f].area);50
+ let from = sp.output.map(|f| self.outputs[f].usable());5151
sp.shown = Some(next);5252
sp.output = Some(o);5353
let w = sp.windows[next];5454
self.last_scratchpad = Some(s);5555
let area = self.outputs[o].area;56
+ let usable = self.outputs[o].usable();5657
let win = &mut self.windows[w];5758
if win.output != Some(o) {5859
win.float_rect = match (from, win.float_rect) {59
- (Some(from), Some(r)) => Some(translate(r, from, area)),60
+ (Some(from), Some(r)) => Some(translate(r, from, usable)),6061
_ => Some(centred(area, 0.6)),6162
};6263
win.output = Some(o);@@ -641,3 +641,39 @@ fn oversized_floats_keep_their_top_edge_and_a_strip() {
641641
let fits = clamp_float(Rect::new(900.0, 500.0, 300.0, 200.0), bounds);642642
assert_eq!((fits.x, fits.y), (700.0, 400.0));643643
}644
+645
+#[test]646
+fn floats_follow_their_output_area_and_panels() {647
+ let mut l = Layout::default();648
+ let o = l.add_output("a", AREA);649
+ let w = l.add_window(Some(o), None, Some(Rect::new(500.0, 300.0, 400.0, 300.0)));650
+ l.set_output_area(o, Rect::new(100.0, 50.0, 500.0, 300.0));651
+ let r = l.window(w).unwrap().float_rect.unwrap();652
+ assert_eq!((r.x, r.y, r.w, r.h), (350.0, 200.0, 200.0, 150.0));653
+654
+ l.set_reserved(655
+ o,656
+ Insets {657
+ top: 100.0,658
+ ..Insets::default()659
+ },660
+ );661
+ let r = l.window(w).unwrap().float_rect.unwrap();662
+ let usable = l.output(o).unwrap().usable();663
+ assert!(r.y >= usable.y && r.bottom() <= usable.bottom());664
+}665
+666
+#[test]667
+fn floats_shrink_into_a_smaller_output_they_are_evicted_to() {668
+ let mut l = Layout::default();669
+ let a = l.add_output("a", AREA);670
+ let b = l.add_output("b", Rect::new(1000.0, 0.0, 500.0, 300.0));671
+ let w = l.add_window(Some(a), None, Some(Rect::new(800.0, 400.0, 200.0, 200.0)));672
+ l.remove_output(a);673
+ assert_eq!(l.window(w).unwrap().output, Some(b));674
+ let r = l.window(w).unwrap().float_rect.unwrap();675
+ let usable = l.output(b).unwrap().usable();676
+ assert_eq!((r.w, r.h), (100.0, 100.0));677
+ assert!(r.x >= usable.x && r.right() <= usable.right());678
+ assert!(r.y >= usable.y && r.bottom() <= usable.bottom());679
+}