leftwm_core/models/
focus_manager.rs1use crate::config::Config;
2use crate::{models::TagId, models::WindowHandle, Window, Workspace};
3
4use serde::{Deserialize, Serialize};
5use std::collections::{HashMap, VecDeque};
6
7use super::window::Handle;
8use super::MaybeWindowHandle;
9
10#[derive(Default, Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
11pub enum FocusBehaviour {
12 #[default]
13 Sloppy,
14 ClickTo,
15 Driven,
16}
17
18impl FocusBehaviour {
19 pub fn is_sloppy(self) -> bool {
20 self == FocusBehaviour::Sloppy
21 }
22
23 pub fn is_clickto(self) -> bool {
24 self == FocusBehaviour::ClickTo
25 }
26
27 pub fn is_driven(self) -> bool {
28 self == FocusBehaviour::Driven
29 }
30}
31
32#[derive(Default, Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
34pub enum FocusOnActivationBehaviour {
35 DoNothing,
37 #[default]
39 MarkUrgent,
40 SwitchTo,
42}
43
44#[derive(Serialize, Deserialize, Debug, Clone)]
46pub struct FocusManager<H: Handle> {
47 pub workspace_history: VecDeque<usize>,
48 #[serde(bound = "")]
49 pub window_history: VecDeque<MaybeWindowHandle<H>>,
50 pub tag_history: VecDeque<TagId>,
51 #[serde(bound = "")]
52 pub tags_last_window: HashMap<TagId, WindowHandle<H>>,
53 pub last_mouse_position: Option<(i32, i32)>,
54 pub behaviour: FocusBehaviour,
56 pub focus_new_windows: bool,
57 pub sloppy_mouse_follows_focus: bool,
58 pub create_follows_cursor: bool,
59}
60
61impl<H: Handle> FocusManager<H> {
62 pub fn new(config: &impl Config) -> Self {
63 Self {
64 workspace_history: Default::default(),
65 window_history: Default::default(),
66 tag_history: Default::default(),
67 tags_last_window: Default::default(),
68 last_mouse_position: None,
69 behaviour: config.focus_behaviour(),
70 focus_new_windows: config.focus_new_windows(),
71 sloppy_mouse_follows_focus: config.sloppy_mouse_follows_focus(),
72 create_follows_cursor: config.create_follows_cursor(),
73 }
74 }
75
76 #[must_use]
78 pub fn workspace<'a, 'b>(&self, workspaces: &'a [Workspace]) -> Option<&'b Workspace>
79 where
80 'a: 'b,
81 {
82 let index = *self.workspace_history.front()?;
83 workspaces.get(index)
84 }
85
86 pub fn workspace_mut<'a, 'b>(
88 &self,
89 workspaces: &'a mut [Workspace],
90 ) -> Option<&'b mut Workspace>
91 where
92 'a: 'b,
93 {
94 let index = *self.workspace_history.front()?;
95 workspaces.get_mut(index)
96 }
97
98 pub fn tag(&self, offset: usize) -> Option<TagId> {
101 self.tag_history.get(offset).copied()
102 }
103
104 #[must_use]
106 pub fn window<'a, 'b>(&self, windows: &'a [Window<H>]) -> Option<&'b Window<H>>
107 where
108 'a: 'b,
109 {
110 let handle = *self.window_history.front()?;
111 if let Some(handle) = handle {
112 return windows.iter().find(|w| w.handle == handle);
113 }
114 None
115 }
116
117 pub fn window_mut<'a, 'b>(&self, windows: &'a mut [Window<H>]) -> Option<&'b mut Window<H>>
119 where
120 'a: 'b,
121 {
122 let handle = *self.window_history.front()?;
123 if let Some(handle) = handle {
124 return windows.iter_mut().find(|w| w.handle == handle);
125 }
126 None
127 }
128
129 pub fn create_follows_cursor(&self) -> bool {
131 self.create_follows_cursor
132 }
133}