4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 1 | use crate::{Insets, Layout, Output, OutputId, Rect, TagId, Tree, WindowId, translate}; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 2 | |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 3 | #[derive(Clone, Debug)] |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 4 | pub(crate) struct Parked { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 5 | tree: Tree<WindowId>, |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 6 | viewed: Vec<TagId>, |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 7 | floating: Vec<WindowId>, |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 8 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 9 | |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 10 | impl Layout { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 11 | /// Adds an output. One that was unplugged before gets back its tree, |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 12 | /// views and the windows that had to leave it. |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 13 | pub fn add_output(&mut self, name: &str, area: Rect) -> OutputId { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 14 | let id = self.outputs.insert(Output { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 15 | name: name.into(), |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 16 | area, |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 17 | reserved: Insets::default(), |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 18 | tree: Tree::default(), |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 19 | viewed: Vec::new(), |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 20 | floating: Vec::new(), |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 21 | }); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 22 | if let Some(parked) = self.parked.remove(name) { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 23 | self.restore(id, parked); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 24 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 25 | self.active.get_or_insert(id); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 26 | let detached: Vec<WindowId> = self |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 27 | .windows |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 28 | .iter() |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 29 | .filter(|(_, w)| w.output.is_none()) |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 30 | .map(|(id, _)| id) |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 31 | .collect(); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 32 | for w in detached { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 33 | self.windows[w].output = Some(id); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 34 | self.place(w); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 35 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 36 | id |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 37 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 38 | |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 39 | fn restore(&mut self, id: OutputId, parked: Parked) { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 40 | let name = self.outputs[id].name.clone(); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 41 | let ours = |l: &Self, w: WindowId| { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 42 | l.windows |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 43 | .get(w) |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 44 | .is_some_and(|x| x.evicted_from.as_deref() == Some(&name) && x.scratchpad.is_none()) |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 45 | }; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 46 | let mut tree = parked.tree; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 47 | tree.retain(|w| ours(self, w) && !self.windows[w].floating); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 48 | let floating: Vec<WindowId> = parked |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 49 | .floating |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 50 | .into_iter() |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 51 | .filter(|&w| ours(self, w) && self.windows[w].floating) |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 52 | .collect(); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 53 | for w in tree |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 54 | .windows() |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 55 | .chain(floating.iter().copied()) |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 56 | .collect::<Vec<_>>() |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 57 | { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 58 | self.unplace(w); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 59 | let win = &mut self.windows[w]; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 60 | if let (Some(from), Some(rect)) = (win.output, win.float_rect) { |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 61 | win.float_rect = Some(translate( |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 62 | rect, |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 63 | self.outputs[from].usable(), |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 64 | self.outputs[id].usable(), |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 65 | )); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 66 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 67 | win.output = Some(id); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 68 | win.evicted_from = None; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 69 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 70 | let out = &mut self.outputs[id]; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 71 | out.tree = tree; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 72 | out.floating = floating; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 73 | out.viewed = parked |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 74 | .viewed |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 75 | .into_iter() |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 76 | .filter(|&t| self.tags.contains_key(t)) |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 77 | .collect(); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 78 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 79 | |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 80 | /// Removes an output. Its windows move to an output viewing their tag, |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 81 | /// or the active one, and remember where they came from. |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 82 | pub fn remove_output(&mut self, o: OutputId) { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 83 | let Some(out) = self.outputs.remove(o) else { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 84 | return; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 85 | }; |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 86 | let left_usable = out.usable(); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 87 | self.parked.insert( |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 88 | out.name.clone(), |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 89 | Parked { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 90 | tree: out.tree, |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 91 | viewed: out.viewed, |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 92 | floating: out.floating, |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 93 | }, |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 94 | ); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 95 | if self.active == Some(o) { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 96 | self.active = self.outputs.keys().next(); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 97 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 98 | for sp in &mut self.scratchpads { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 99 | if sp.output == Some(o) { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 100 | sp.output = self.active; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 101 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 102 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 103 | let leaving: Vec<WindowId> = self |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 104 | .windows |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 105 | .iter() |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 106 | .filter(|(_, w)| w.output == Some(o)) |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 107 | .map(|(id, _)| id) |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 108 | .collect(); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 109 | for w in leaving { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 110 | let tag = self.windows[w].tag; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 111 | let target = self |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 112 | .outputs |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 113 | .keys() |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 114 | .find(|&t| self.is_viewed(t, tag)) |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 115 | .or(self.active); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 116 | let win = &mut self.windows[w]; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 117 | if let (Some(t), Some(rect)) = (target, win.float_rect) { |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 118 | win.float_rect = Some(translate(rect, left_usable, self.outputs[t].usable())); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 119 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 120 | win.output = target; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 121 | if win.scratchpad.is_some() { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 122 | continue; |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 123 | } |
8ffa3fa4d4a9 | atagen | 2026-10-18 09:38 UTC | 124 | win.evicted_from.get_or_insert_with(|| out.name.clone()); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 125 | if target.is_some() { |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 126 | self.place(w); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 127 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 128 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 129 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 130 | |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 131 | pub fn set_output_area(&mut self, o: OutputId, area: Rect) { |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 132 | let Some(out) = self.outputs.get_mut(o) else { |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 133 | return; |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 134 | }; |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 135 | let before = out.usable(); |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 136 | out.area = area; |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 137 | self.rescale_floats(o, before); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 138 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 139 | |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 140 | /// Returns whether anything changed. |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 141 | pub fn set_reserved(&mut self, o: OutputId, reserved: Insets) -> bool { |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 142 | let Some(out) = self.outputs.get_mut(o) else { |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 143 | return false; |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 144 | }; |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 145 | if out.reserved == reserved { |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 146 | return false; |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 147 | } |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 148 | let before = out.usable(); |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 149 | out.reserved = reserved; |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 150 | self.rescale_floats(o, before); |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 151 | true |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 152 | } |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 153 | |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 154 | /// Carries floating windows along when the usable area of o changes. |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 155 | fn rescale_floats(&mut self, o: OutputId, before: Rect) { |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 156 | let after = self.outputs[o].usable(); |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 157 | if after == before { |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 158 | return; |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 159 | } |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 160 | for win in self.windows.values_mut().filter(|w| w.output == Some(o)) { |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 161 | if let Some(rect) = win.float_rect { |
4b73e40af1e3 | atagen | 2026-10-19 07:44 UTC | 162 | win.float_rect = Some(translate(rect, before, after)); |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 163 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 164 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 165 | } |
4cbf881c67bd | atagen | 2026-10-17 04:56 UTC | 166 | } |