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