atagen

monolith

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