1#[cfg(test)]
2use leftwm_layouts::layouts::Layouts;
3
4use crate::config::Config;
5use crate::display_servers::DisplayServer;
6use crate::state::State;
7use crate::utils::child_process::Children;
8use std::sync::{Arc, atomic::AtomicBool};
9
10use super::Handle;
11
12#[derive(Debug)]
14pub struct Manager<H: Handle, C, SERVER> {
15 pub state: State<H>,
16 pub config: C,
17
18 pub(crate) children: Children,
19 pub(crate) reap_requested: Arc<AtomicBool>,
20 pub(crate) reload_requested: bool,
21 pub display_server: SERVER,
22}
23
24impl<H: Handle, C, SERVER> Manager<H, C, SERVER>
25where
26 C: Config,
27 SERVER: DisplayServer<H>,
28{
29 pub fn new(config: C) -> Self {
30 Self {
31 display_server: SERVER::new(&config),
32 state: State::new(&config),
33 config,
34 children: Default::default(),
35 reap_requested: Default::default(),
36 reload_requested: false,
37 }
38 }
39}
40
41impl<H: Handle, C, SERVER> Manager<H, C, SERVER> {
42 pub fn register_child_hook(&self) {
43 crate::child_process::register_child_hook(self.reap_requested.clone());
44 }
45
46 pub fn hard_reload(&mut self) {
48 self.reload_requested = true;
49 }
50}
51
52impl<H: Handle, C: Config, SERVER: DisplayServer<H>> Manager<H, C, SERVER> {
53 pub fn load_theme_config(&mut self) -> bool {
55 let focused = self
56 .state
57 .focus_manager
58 .window_history
59 .front()
60 .and_then(|o| *o);
61 self.display_server
62 .reload_config(&self.config, focused, &self.state.windows);
63 self.state.load_theme_config(&self.config);
64 true
65 }
66}
67
68#[cfg(test)]
69impl
70 Manager<
71 crate::models::window::MockHandle,
72 crate::config::tests::TestConfig,
73 crate::display_servers::MockDisplayServer<crate::models::window::MockHandle>,
74 >
75{
76 pub fn new_with_screens(
77 config: crate::config::tests::TestConfig,
78 screens: &[super::Screen<crate::models::window::MockHandle>],
79 ) -> Self {
80 let mut events = vec![];
87 if let Some(workspaces) = config.workspaces() {
88 for (i, wsc) in workspaces.iter().enumerate() {
89 let mut screen = super::Screen::from(wsc);
90 screen.root =
91 crate::models::WindowHandle(crate::models::window::MockHandle::default());
92 match screens.iter().find(|s| s.output == wsc.output) {
94 Some(output_match) => {
95 if wsc.relative.unwrap_or(false) {
96 screen.bbox.add(output_match.bbox);
97 }
98 screen.id = Some(i + 1);
99 }
100 None => continue,
101 }
102
103 events.push(screen);
105 }
106
107 let auto_derive_workspaces: bool = config.auto_derive_workspaces() || events.is_empty();
108 let mut next_id = workspaces.len() + 1;
109
110 if auto_derive_workspaces {
112 screens
113 .iter()
114 .filter(|screen| !workspaces.iter().any(|wsc| wsc.output == screen.output))
115 .for_each(|screen| {
116 let mut s = screen.clone();
117 s.id = Some(next_id);
118 next_id += 1;
119 events.push(s);
120 });
121 }
122 }
123
124 let mut manager = Self::new(config);
126
127 for screen in events {
129 manager.screen_create_handler(screen);
130 }
131
132 manager
133 }
134
135 pub fn new_test(tags: Vec<String>) -> Self {
136 use crate::config::tests::TestConfig;
137 let defs = Layouts::default().layouts;
138 let names = defs.iter().map(|def| def.name.clone()).collect();
139 Self::new(TestConfig {
140 tags,
141 layouts: names,
142 layout_definitions: defs,
143 ..TestConfig::default()
144 })
145 }
146
147 pub fn new_test_with_border(tags: Vec<String>, border_width: i32) -> Self {
148 use crate::config::tests::TestConfig;
149 let defs = Layouts::default().layouts;
150 let names = defs.iter().map(|def| def.name.clone()).collect();
151 Self::new(TestConfig {
152 tags,
153 layouts: names,
154 layout_definitions: defs,
155 border_width,
156 single_window_border: false,
157 ..TestConfig::default()
158 })
159 }
160}
161
162#[cfg(test)]
163mod pr_1301_issue {
164 use leftwm_layouts::layouts::Layouts;
170
171 use crate::{
172 Manager,
173 config::tests::TestConfig,
174 display_servers::MockDisplayServer,
175 layouts,
176 models::{BBox, MockHandle, Screen},
177 };
178
179 fn test_config() -> TestConfig {
180 TestConfig {
181 layouts: vec![
182 layouts::FIBONACCI.to_string(),
183 "Grid".to_string(),
184 layouts::MONOCLE.to_string(),
185 ],
186 layout_definitions: Layouts::default().layouts,
187 workspaces: Some(vec![
188 crate::config::Workspace {
189 output: "DP-3".to_string(),
190 y: 0,
191 x: 0,
192 height: 1080,
193 width: 1920,
194 default_layout: Some(layouts::MONOCLE.to_string()),
195 ..Default::default()
196 },
197 crate::config::Workspace {
198 output: "DP-4".to_string(),
199 y: 1080,
200 x: 0,
201 height: 1080,
202 width: 1920,
203 default_layout: Some("Grid".to_string()),
204 ..Default::default()
205 },
206 ]),
207 ..Default::default()
208 }
209 }
210
211 #[test]
212 fn default_layout_with_correct_screen() {
217 let mut manager: Manager<MockHandle, TestConfig, MockDisplayServer<MockHandle>> =
218 Manager::new_with_screens(
219 test_config(),
220 &[
221 Screen::new(
222 BBox {
223 x: 0,
224 y: 0,
225 width: 1920,
226 height: 1080,
227 },
228 "DP-3".to_string(),
229 ),
230 Screen::new(
231 BBox {
232 x: 0,
233 y: 1080,
234 width: 1920,
235 height: 1080,
236 },
237 "DP-4".to_string(),
238 ),
239 ],
240 );
241
242 assert_eq!(2, manager.state.workspaces.len());
243 assert_eq!(
244 layouts::MONOCLE,
245 &manager.state.layout_manager.layout(1, 1).name
246 );
247 assert_eq!("Grid", &manager.state.layout_manager.layout(2, 1).name);
248 }
249
250 #[test]
251 fn default_layout_with_incorrect_screen() {
255 let mut manager: Manager<MockHandle, TestConfig, MockDisplayServer<MockHandle>> =
256 Manager::new_with_screens(
257 test_config(),
258 &[Screen::new(
259 BBox {
260 x: 0,
261 y: 0,
262 width: 1920,
263 height: 1080,
264 },
265 "eDP-1".to_string(),
267 )],
268 );
269
270 assert_eq!(1, manager.state.workspaces.len());
272 assert_eq!(3, manager.state.workspaces[0].id);
274 assert_eq!(
276 layouts::FIBONACCI,
277 &manager.state.layout_manager.layout(3, 1).name
278 );
279 }
280
281 #[test]
282 fn default_layout_with_one_configured_screen() {
284 let mut manager: Manager<MockHandle, TestConfig, MockDisplayServer<MockHandle>> =
285 Manager::new_with_screens(
286 test_config(),
287 &[
288 Screen::new(
289 BBox {
290 x: 0,
291 y: 0,
292 width: 1920,
293 height: 1080,
294 },
295 "DP-3".to_string(),
296 ),
297 Screen::new(
298 BBox {
299 x: 0,
300 y: 1080,
301 width: 1920,
302 height: 1080,
303 },
304 "eDP-1".to_string(),
305 ),
306 ],
307 );
308
309 assert_eq!(2, manager.state.workspaces.len());
311 assert_eq!(
313 layouts::MONOCLE,
314 &manager.state.layout_manager.layout(1, 1).name
315 );
316 assert_eq!(1, manager.state.workspaces[0].id);
318 assert_eq!(
320 layouts::FIBONACCI,
321 &manager.state.layout_manager.layout(3, 1).name
322 );
323 assert_eq!(3, manager.state.workspaces[1].id);
325 }
326}