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 && window.tag != Some(*tag)
96 {
97 self.unfocus_current_window();
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 && ¤t.handle == handle
141 {
142 return;
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_key(|a| a.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 && current_tag == tag
176 {
177 return false;
178 }
179 self.focus_manager.tag_history.truncate(10);
181 self.focus_manager.tag_history.push_front(tag);
183
184 if update_workspace && let Some(ws) = self.focus_manager.workspace_mut(&mut self.workspaces)
185 {
186 ws.tag = Some(tag);
187 self.update_static();
188 }
189
190 let act = DisplayAction::SetCurrentTags(Some(tag));
191 self.actions.push_back(act);
192 true
193 }
194
195 fn focus_window_work(&mut self, handle: &WindowHandle<H>) -> Option<Window<H>> {
196 if self.screens.iter().any(|s| &s.root == handle) {
197 let act = DisplayAction::Unfocus(None, false);
198 self.actions.push_back(act);
199 self.focus_manager.window_history.push_front(None);
200 return None;
201 }
202 let found: &Window<H> = self.windows.iter().find(|w| &w.handle == handle)?;
204 if !found.is_managed() {
206 return None;
207 }
208 let previous = self.focus_manager.window(&self.windows);
209 if let Some(previous) = previous {
211 if &previous.handle == handle {
212 return Some(found.clone());
214 }
215 if let Some(tag_id) = &previous.tag {
216 self.focus_manager
217 .tags_last_window
218 .insert(*tag_id, previous.handle);
219 }
220 }
221
222 self.focus_manager.window_history.truncate(10);
224 self.focus_manager.window_history.push_front(Some(*handle));
226
227 let act = DisplayAction::WindowTakeFocus {
228 window: found.clone(),
229 previous_window: previous.cloned(),
230 };
231 self.actions.push_back(act);
232
233 Some(found.clone())
234 }
235
236 fn focus_workspace_work(&mut self, ws_id: usize) -> bool {
237 if let Some(fws) = self.focus_manager.workspace(&self.workspaces)
239 && fws.id == ws_id
240 {
241 return false;
242 }
243 self.focus_manager.workspace_history.truncate(10);
245 if let Some(index) = self.workspaces.iter().position(|x| x.id == ws_id) {
247 self.focus_manager.workspace_history.push_front(index);
248 return true;
249 }
250 false
251 }
252
253 fn unfocus_current_window(&mut self) {
254 if let Some(window) = self.focus_manager.window(&self.windows) {
255 self.actions.push_back(DisplayAction::Unfocus(
256 Some(window.handle),
257 window.floating(),
258 ));
259 self.focus_manager.window_history.push_front(None);
260 if let Some(tag_id) = &window.tag {
261 self.focus_manager
262 .tags_last_window
263 .insert(*tag_id, window.handle);
264 }
265 }
266 }
267}
268
269fn distance<H: Handle>(window: &Window<H>, x: i32, y: i32) -> i32 {
271 let (wx, wy) = window.calculated_xyhw().center();
273 let xs = (wx - x) * (wx - x);
274 let ys = (wy - y) * (wy - y);
275 xs + ys
276}
277
278#[cfg(test)]
279mod tests {
280 use super::*;
281 use crate::{Manager, models::MockHandle};
282
283 #[test]
284 fn focusing_a_workspace_should_make_it_active() {
285 let mut manager = Manager::new_test(vec![]);
286 manager.screen_create_handler(Screen::default());
287 manager.screen_create_handler(Screen::default());
288 let expected = manager.state.workspaces[0].clone();
289 manager.state.focus_workspace(&expected);
290 let actual = manager
291 .state
292 .focus_manager
293 .workspace(&manager.state.workspaces)
294 .unwrap();
295 assert_eq!(&expected, actual);
296 }
297
298 #[test]
299 fn focusing_a_workspace_should_focus_its_last_active_window() {
300 let mut manager = Manager::new_test(vec!["1".to_string(), "2".to_string()]);
301 manager.screen_create_handler(Screen::default());
302 manager.screen_create_handler(Screen::default());
303 manager
304 .state
305 .focus_workspace(&manager.state.workspaces[0].clone());
306 manager.window_created_handler(
307 Window::new(WindowHandle::<MockHandle>(1), None, None),
308 -1,
309 -1,
310 );
311 manager.window_created_handler(
312 Window::new(WindowHandle::<MockHandle>(2), None, None),
313 -1,
314 -1,
315 );
316
317 manager
318 .state
319 .focus_workspace(&manager.state.workspaces[0].clone());
320
321 let expected = manager.state.windows.get(1).map(|w| w.handle);
322 manager.state.focus_window(&expected.unwrap());
323
324 manager
325 .state
326 .focus_workspace(&manager.state.workspaces[1].clone());
327 manager
328 .state
329 .focus_workspace(&manager.state.workspaces[0].clone());
330
331 let actual = manager
332 .state
333 .focus_manager
334 .window(&manager.state.windows)
335 .map(|w| w.handle);
336
337 assert_eq!(expected, actual);
338 }
339
340 #[test]
341 fn focusing_the_same_workspace_shouldnt_add_to_the_history() {
342 let mut manager = Manager::new_test(vec![]);
343 manager.screen_create_handler(Screen::default());
344 manager.screen_create_handler(Screen::default());
345 let ws = manager.state.workspaces[0].clone();
346 manager.state.focus_workspace(&ws);
347 let start_length = manager.state.focus_manager.workspace_history.len();
348 manager.state.focus_workspace(&ws);
349 let end_length = manager.state.focus_manager.workspace_history.len();
350 assert_eq!(start_length, end_length, "expected no new history event");
351 }
352
353 #[test]
354 fn focusing_a_window_should_make_it_active() {
355 let mut manager = Manager::new_test(vec![]);
356 manager.screen_create_handler(Screen::default());
357 manager.window_created_handler(
358 Window::new(WindowHandle::<MockHandle>(1), None, None),
359 -1,
360 -1,
361 );
362 manager.window_created_handler(
363 Window::new(WindowHandle::<MockHandle>(2), None, None),
364 -1,
365 -1,
366 );
367 let expected = manager.state.windows[0].clone();
368 manager.state.focus_window(&expected.handle);
369 let actual = manager
370 .state
371 .focus_manager
372 .window(&manager.state.windows)
373 .unwrap()
374 .handle;
375 assert_eq!(expected.handle, actual);
376 }
377
378 #[test]
379 fn focusing_the_same_window_shouldnt_add_to_the_history() {
380 let mut manager = Manager::new_test(vec![]);
381 manager.screen_create_handler(Screen::default());
382 let window = Window::new(WindowHandle::<MockHandle>(1), None, None);
383 manager.window_created_handler(window.clone(), -1, -1);
384 manager.state.focus_window(&window.handle);
385 let start_length = manager.state.focus_manager.workspace_history.len();
386 manager.window_created_handler(window.clone(), -1, -1);
387 manager.state.focus_window(&window.handle);
388 let end_length = manager.state.focus_manager.workspace_history.len();
389 assert_eq!(start_length, end_length, "expected no new history event");
390 }
391
392 #[test]
393 fn focusing_a_tag_should_make_it_active() {
394 let mut manager = Manager::new_test(vec![]);
395 manager.screen_create_handler(Screen::default());
396 let state = &mut manager.state;
397 let expected: usize = 1;
398 state.focus_tag(&expected);
399 let actual = state.focus_manager.tag(0).unwrap();
400 assert_eq!(actual, expected);
401 }
402
403 #[test]
404 fn focusing_the_same_tag_shouldnt_add_to_the_history() {
405 let mut manager = Manager::new_test(vec![]);
406 manager.screen_create_handler(Screen::default());
407 let state = &mut manager.state;
408 let tag: usize = 1;
409 state.focus_tag(&tag);
410 let start_length = state.focus_manager.tag_history.len();
411 state.focus_tag(&tag);
412 let end_length = state.focus_manager.tag_history.len();
413 assert_eq!(start_length, end_length, "expected no new history event");
414 }
415
416 #[test]
417 fn focusing_a_tag_should_focus_its_workspace() {
418 let mut manager = Manager::new_test(vec!["1".to_string()]);
419 manager.screen_create_handler(Screen::default());
420 manager.screen_create_handler(Screen::default());
421 manager.state.focus_tag(&1);
422 let actual = manager
423 .state
424 .focus_manager
425 .workspace(&manager.state.workspaces)
426 .unwrap();
427 assert_eq!(actual.id, 1);
428 }
429
430 #[test]
431 fn focusing_a_workspace_should_focus_its_tag() {
432 let mut manager = Manager::new_test(vec![]);
433 manager.screen_create_handler(Screen::default());
434 manager.screen_create_handler(Screen::default());
435 manager.screen_create_handler(Screen::default());
436 let ws = manager.state.workspaces[1].clone();
437 manager.state.focus_workspace(&ws);
438 let actual = manager.state.focus_manager.tag(0).unwrap();
439 assert_eq!(2, actual);
440 }
441
442 #[test]
443 fn focusing_a_window_should_focus_its_tag() {
444 let mut manager = Manager::new_test(vec![]);
445 manager.screen_create_handler(Screen::default());
446 manager.screen_create_handler(Screen::default());
447 manager.screen_create_handler(Screen::default());
448 let mut window = Window::new(WindowHandle::<MockHandle>(1), None, None);
449 window.tag(&2);
450 manager.state.windows.push(window.clone());
451 manager.state.focus_window(&window.handle);
452 let actual = manager.state.focus_manager.tag(0).unwrap();
453 assert_eq!(2, actual);
454 }
455
456 #[test]
457 fn focusing_a_window_should_focus_workspace() {
458 let mut manager = Manager::new_test(vec![]);
459 manager.screen_create_handler(Screen::default());
460 manager.screen_create_handler(Screen::default());
461 manager.screen_create_handler(Screen::default());
462 let mut window = Window::new(WindowHandle::<MockHandle>(1), None, None);
463 window.tag(&2);
464 manager.state.windows.push(window.clone());
465 manager.state.focus_window(&window.handle);
466 let actual = manager
467 .state
468 .focus_manager
469 .workspace(&manager.state.workspaces)
470 .unwrap();
471 let expected = &manager.state.workspaces[1];
472 assert_eq!(expected, actual);
473 }
474
475 #[test]
476 fn focusing_an_empty_tag_should_unfocus_any_focused_window() {
477 let mut manager = Manager::new_test(vec![]);
478 manager.screen_create_handler(Screen::default());
479 let mut window = Window::new(WindowHandle::<MockHandle>(1), None, None);
480 window.tag(&1);
481 manager.state.windows.push(window.clone());
482 manager.state.focus_window(&window.handle);
483 manager.state.focus_tag(&2);
484 let focused = manager.state.focus_manager.window(&manager.state.windows);
485 assert!(focused.is_none());
486 }
487}