1#![allow(clippy::wildcard_imports)]
2
3use super::*;
4use crate::models::{Handle, TagId};
5use crate::state::State;
6use crate::{display_action::DisplayAction, models::FocusBehaviour};
7
8impl<H: Handle> State<H> {
9 pub fn handle_window_focus(&mut self, handle: &WindowHandle<H>) {
11 match self.focus_manager.behaviour {
12 FocusBehaviour::Sloppy if self.focus_manager.sloppy_mouse_follows_focus => {
13 let act = DisplayAction::MoveMouseOver(*handle, false);
14 self.actions.push_back(act);
15 }
16 _ => self.focus_window(handle),
17 }
18 }
19
20 pub fn focus_window(&mut self, handle: &WindowHandle<H>) {
22 let Some(window) = self.focus_window_work(handle) else {
23 return;
24 };
25
26 if let Some(workspace_id) = self
28 .workspaces
29 .iter()
30 .find(|ws| ws.is_displaying(&window))
31 .map(|ws| ws.id)
32 {
33 _ = self.focus_workspace_work(workspace_id);
34 }
35
36 if let Some(tag) = window.tag {
38 _ = self.focus_tag_work(tag, true);
39 }
40 }
41
42 pub fn focus_workspace(&mut self, workspace: &Workspace) {
45 if self.focus_workspace_work(workspace.id) {
46 workspace.tag.iter().for_each(|t| {
48 self.focus_tag_work(*t, false);
49
50 if let Some(handle) = self.focus_manager.tags_last_window.get(t).copied() {
51 self.focus_window_work(&handle);
52 } else {
53 self.unfocus_current_window();
54 }
55 });
56 }
57 }
58
59 pub fn focus_tag(&mut self, tag: &TagId) {
62 if !self.focus_tag_work(*tag, false) {
63 return;
64 }
65 let to_focus: Vec<Workspace> = self
67 .workspaces
68 .iter()
69 .filter(|w| w.has_tag(tag))
70 .cloned()
71 .collect();
72 for ws in &to_focus {
73 self.focus_workspace_work(ws.id);
74 }
75 if self.focus_manager.behaviour.is_sloppy() && self.focus_manager.sloppy_mouse_follows_focus
77 {
78 let act = DisplayAction::FocusWindowUnderCursor;
79 self.actions.push_back(act);
80 } else if let Some(handle) = self.focus_manager.tags_last_window.get(tag).copied() {
81 self.focus_window_work(&handle);
82 } else if let Some(ws) = to_focus.first() {
83 let handle = self
84 .windows
85 .iter()
86 .find(|w| ws.is_managed(w))
87 .map(|w| w.handle);
88 if let Some(h) = handle {
89 self.focus_window_work(&h);
90 }
91 }
92
93 if let Some(window) = self.focus_manager.window(&self.windows) {
95 if window.tag != Some(*tag) {
96 self.unfocus_current_window();
97 }
98 }
99 }
100
101 pub fn focus_workspace_with_point(&mut self, x: i32, y: i32) {
103 let Some(focused_id) = self
104 .focus_manager
105 .workspace(&self.workspaces)
106 .map(|ws| ws.id)
107 else {
108 return;
109 };
110
111 if let Some(ws) = self
112 .workspaces
113 .iter()
114 .find(|ws| ws.contains_point(x, y) && ws.id != focused_id)
115 .cloned()
116 {
117 self.focus_workspace(&ws);
118 }
119 }
120
121 pub fn focus_window_with_point(&mut self, x: i32, y: i32) {
123 let handle_found: Option<WindowHandle<H>> = self
124 .windows
125 .iter()
126 .filter(|x| x.can_focus())
127 .find(|w| w.contains_point(x, y))
128 .map(|w| w.handle);
129 match handle_found {
130 Some(found) => self.focus_window(&found),
131 None => self.focus_closest_window(x, y),
133 }
134 }
135
136 pub fn validate_focus_at(&mut self, handle: &WindowHandle<H>) {
138 if let Some(current) = self.focus_manager.window(&self.windows) {
140 if ¤t.handle == handle {
141 return;
142 }
143 }
144 if self
146 .windows
147 .iter()
148 .any(|w| w.can_focus() && &w.handle == handle)
149 {
150 self.focus_window(handle);
151 }
152 }
153
154 fn focus_closest_window(&mut self, x: i32, y: i32) {
157 let Some(ws) = self.workspaces.iter().find(|ws| ws.contains_point(x, y)) else {
158 return;
159 };
160 let mut dists: Vec<(i32, &Window<H>)> = self
161 .windows
162 .iter()
163 .filter(|x| ws.is_managed(x) && x.can_focus())
164 .map(|w| (distance(w, x, y), w))
165 .collect();
166 dists.sort_by(|a, b| (a.0).cmp(&b.0));
167 if let Some(first) = dists.first() {
168 let handle = first.1.handle;
169 self.focus_window(&handle);
170 }
171 }
172
173 fn focus_tag_work(&mut self, tag: TagId, update_workspace: bool) -> bool {
174 if let Some(current_tag) = self.focus_manager.tag(0) {
175 if current_tag == tag {
176 return false;
177 }
178 };
179 self.focus_manager.tag_history.truncate(10);
181 self.focus_manager.tag_history.push_front(tag);
183
184 if update_workspace {
185 if let Some(ws) = self.focus_manager.workspace_mut(&mut self.workspaces) {
186 ws.tag = Some(tag);
187 self.update_static();
188 }
189 }
190
191 let act = DisplayAction::SetCurrentTags(Some(tag));
192 self.actions.push_back(act);
193 true
194 }
195
196 fn focus_window_work(&mut self, handle: &WindowHandle<H>) -> Option<Window<H>> {
197 if self.screens.iter().any(|s| &s.root == handle) {
198 let act = DisplayAction::Unfocus(None, false);
199 self.actions.push_back(act);
200 self.focus_manager.window_history.push_front(None);
201 return None;
202 }
203 let found: &Window<H> = self.windows.iter().find(|w| &w.handle == handle)?;
205 if !found.is_managed() {
207 return None;
208 }
209 let previous = self.focus_manager.window(&self.windows);
210 if let Some(previous) = previous {
212 if &previous.handle == handle {
213 return Some(found.clone());
215 }
216 if let Some(tag_id) = &previous.tag {
217 self.focus_manager
218 .tags_last_window
219 .insert(*tag_id, previous.handle);
220 }
221 }
222
223 self.focus_manager.window_history.truncate(10);
225 self.focus_manager.window_history.push_front(Some(*handle));
227
228 let act = DisplayAction::WindowTakeFocus {
229 window: found.clone(),
230 previous_window: previous.cloned(),
231 };
232 self.actions.push_back(act);
233
234 Some(found.clone())
235 }
236
237 fn focus_workspace_work(&mut self, ws_id: usize) -> bool {
238 if let Some(fws) = self.focus_manager.workspace(&self.workspaces) {
240 if fws.id == ws_id {
241 return false;
242 }
243 }
244 self.focus_manager.workspace_history.truncate(10);
246 if let Some(index) = self.workspaces.iter().position(|x| x.id == ws_id) {
248 self.focus_manager.workspace_history.push_front(index);
249 return true;
250 }
251 false
252 }
253
254 fn unfocus_current_window(&mut self) {
255 if let Some(window) = self.focus_manager.window(&self.windows) {
256 self.actions.push_back(DisplayAction::Unfocus(
257 Some(window.handle),
258 window.floating(),
259 ));
260 self.focus_manager.window_history.push_front(None);
261 if let Some(tag_id) = &window.tag {
262 self.focus_manager
263 .tags_last_window
264 .insert(*tag_id, window.handle);
265 }
266 }
267 }
268}
269
270fn distance<H: Handle>(window: &Window<H>, x: i32, y: i32) -> i32 {
272 let (wx, wy) = window.calculated_xyhw().center();
274 let xs = (wx - x) * (wx - x);
275 let ys = (wy - y) * (wy - y);
276 xs + ys
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282 use crate::{models::MockHandle, Manager};
283
284 #[test]
285 fn focusing_a_workspace_should_make_it_active() {
286 let mut manager = Manager::new_test(vec![]);
287 manager.screen_create_handler(Screen::default());
288 manager.screen_create_handler(Screen::default());
289 let expected = manager.state.workspaces[0].clone();
290 manager.state.focus_workspace(&expected);
291 let actual = manager
292 .state
293 .focus_manager
294 .workspace(&manager.state.workspaces)
295 .unwrap();
296 assert_eq!(&expected, actual);
297 }
298
299 #[test]
300 fn focusing_a_workspace_should_focus_its_last_active_window() {
301 let mut manager = Manager::new_test(vec!["1".to_string(), "2".to_string()]);
302 manager.screen_create_handler(Screen::default());
303 manager.screen_create_handler(Screen::default());
304 manager
305 .state
306 .focus_workspace(&manager.state.workspaces[0].clone());
307 manager.window_created_handler(
308 Window::new(WindowHandle::<MockHandle>(1), None, None),
309 -1,
310 -1,
311 );
312 manager.window_created_handler(
313 Window::new(WindowHandle::<MockHandle>(2), None, None),
314 -1,
315 -1,
316 );
317
318 manager
319 .state
320 .focus_workspace(&manager.state.workspaces[0].clone());
321
322 let expected = manager.state.windows.get(1).map(|w| w.handle);
323 manager.state.focus_window(&expected.unwrap());
324
325 manager
326 .state
327 .focus_workspace(&manager.state.workspaces[1].clone());
328 manager
329 .state
330 .focus_workspace(&manager.state.workspaces[0].clone());
331
332 let actual = manager
333 .state
334 .focus_manager
335 .window(&manager.state.windows)
336 .map(|w| w.handle);
337
338 assert_eq!(expected, actual);
339 }
340
341 #[test]
342 fn focusing_the_same_workspace_shouldnt_add_to_the_history() {
343 let mut manager = Manager::new_test(vec![]);
344 manager.screen_create_handler(Screen::default());
345 manager.screen_create_handler(Screen::default());
346 let ws = manager.state.workspaces[0].clone();
347 manager.state.focus_workspace(&ws);
348 let start_length = manager.state.focus_manager.workspace_history.len();
349 manager.state.focus_workspace(&ws);
350 let end_length = manager.state.focus_manager.workspace_history.len();
351 assert_eq!(start_length, end_length, "expected no new history event");
352 }
353
354 #[test]
355 fn focusing_a_window_should_make_it_active() {
356 let mut manager = Manager::new_test(vec![]);
357 manager.screen_create_handler(Screen::default());
358 manager.window_created_handler(
359 Window::new(WindowHandle::<MockHandle>(1), None, None),
360 -1,
361 -1,
362 );
363 manager.window_created_handler(
364 Window::new(WindowHandle::<MockHandle>(2), None, None),
365 -1,
366 -1,
367 );
368 let expected = manager.state.windows[0].clone();
369 manager.state.focus_window(&expected.handle);
370 let actual = manager
371 .state
372 .focus_manager
373 .window(&manager.state.windows)
374 .unwrap()
375 .handle;
376 assert_eq!(expected.handle, actual);
377 }
378
379 #[test]
380 fn focusing_the_same_window_shouldnt_add_to_the_history() {
381 let mut manager = Manager::new_test(vec![]);
382 manager.screen_create_handler(Screen::default());
383 let window = Window::new(WindowHandle::<MockHandle>(1), None, None);
384 manager.window_created_handler(window.clone(), -1, -1);
385 manager.state.focus_window(&window.handle);
386 let start_length = manager.state.focus_manager.workspace_history.len();
387 manager.window_created_handler(window.clone(), -1, -1);
388 manager.state.focus_window(&window.handle);
389 let end_length = manager.state.focus_manager.workspace_history.len();
390 assert_eq!(start_length, end_length, "expected no new history event");
391 }
392
393 #[test]
394 fn focusing_a_tag_should_make_it_active() {
395 let mut manager = Manager::new_test(vec![]);
396 manager.screen_create_handler(Screen::default());
397 let state = &mut manager.state;
398 let expected: usize = 1;
399 state.focus_tag(&expected);
400 let actual = state.focus_manager.tag(0).unwrap();
401 assert_eq!(actual, expected);
402 }
403
404 #[test]
405 fn focusing_the_same_tag_shouldnt_add_to_the_history() {
406 let mut manager = Manager::new_test(vec![]);
407 manager.screen_create_handler(Screen::default());
408 let state = &mut manager.state;
409 let tag: usize = 1;
410 state.focus_tag(&tag);
411 let start_length = state.focus_manager.tag_history.len();
412 state.focus_tag(&tag);
413 let end_length = state.focus_manager.tag_history.len();
414 assert_eq!(start_length, end_length, "expected no new history event");
415 }
416
417 #[test]
418 fn focusing_a_tag_should_focus_its_workspace() {
419 let mut manager = Manager::new_test(vec!["1".to_string()]);
420 manager.screen_create_handler(Screen::default());
421 manager.screen_create_handler(Screen::default());
422 manager.state.focus_tag(&1);
423 let actual = manager
424 .state
425 .focus_manager
426 .workspace(&manager.state.workspaces)
427 .unwrap();
428 assert_eq!(actual.id, 1);
429 }
430
431 #[test]
432 fn focusing_a_workspace_should_focus_its_tag() {
433 let mut manager = Manager::new_test(vec![]);
434 manager.screen_create_handler(Screen::default());
435 manager.screen_create_handler(Screen::default());
436 manager.screen_create_handler(Screen::default());
437 let ws = manager.state.workspaces[1].clone();
438 manager.state.focus_workspace(&ws);
439 let actual = manager.state.focus_manager.tag(0).unwrap();
440 assert_eq!(2, actual);
441 }
442
443 #[test]
444 fn focusing_a_window_should_focus_its_tag() {
445 let mut manager = Manager::new_test(vec![]);
446 manager.screen_create_handler(Screen::default());
447 manager.screen_create_handler(Screen::default());
448 manager.screen_create_handler(Screen::default());
449 let mut window = Window::new(WindowHandle::<MockHandle>(1), None, None);
450 window.tag(&2);
451 manager.state.windows.push(window.clone());
452 manager.state.focus_window(&window.handle);
453 let actual = manager.state.focus_manager.tag(0).unwrap();
454 assert_eq!(2, actual);
455 }
456
457 #[test]
458 fn focusing_a_window_should_focus_workspace() {
459 let mut manager = Manager::new_test(vec![]);
460 manager.screen_create_handler(Screen::default());
461 manager.screen_create_handler(Screen::default());
462 manager.screen_create_handler(Screen::default());
463 let mut window = Window::new(WindowHandle::<MockHandle>(1), None, None);
464 window.tag(&2);
465 manager.state.windows.push(window.clone());
466 manager.state.focus_window(&window.handle);
467 let actual = manager
468 .state
469 .focus_manager
470 .workspace(&manager.state.workspaces)
471 .unwrap();
472 let expected = &manager.state.workspaces[1];
473 assert_eq!(expected, actual);
474 }
475
476 #[test]
477 fn focusing_an_empty_tag_should_unfocus_any_focused_window() {
478 let mut manager = Manager::new_test(vec![]);
479 manager.screen_create_handler(Screen::default());
480 let mut window = Window::new(WindowHandle::<MockHandle>(1), None, None);
481 window.tag(&1);
482 manager.state.windows.push(window.clone());
483 manager.state.focus_window(&window.handle);
484 manager.state.focus_tag(&2);
485 let focused = manager.state.focus_manager.window(&manager.state.windows);
486 assert!(focused.is_none());
487 }
488}