atagen

monolith

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