leftwm_core/
event_loop.rs1use crate::models::Handle;
2use crate::{
3 Command, CommandPipe, DisplayEvent, DisplayServer, Manager, Mode, StateSocket, Window,
4};
5use crate::{child_process::Nanny, config::Config};
6use std::path::{Path, PathBuf};
7use std::sync::{Once, atomic::Ordering};
8
9#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, Hash)]
11pub enum Error {
12 #[error("Couldn't create the file: '{}'", .0.display())]
13 CreateFile(PathBuf),
14
15 #[error("Couldn't connect to file: '{}'", .0.display())]
16 ConnectToFile(PathBuf),
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, Hash)]
20enum EventResponse {
21 None,
22 DisplayRefreshNeeded,
23}
24
25impl<H: Handle, C: Config, SERVER: DisplayServer<H>> Manager<H, C, SERVER> {
26 pub async fn start_event_loop(mut self) -> Result<(), Error> {
31 let state_socket = get_state_socket().await?;
32 let command_pipe = get_command_pipe().await?;
33
34 self.call_up_scripts();
35 tracing::info!("LeftWM-core booted!");
36 self.event_loop(state_socket, command_pipe).await
37 }
38
39 async fn event_loop(
40 &mut self,
41 mut state_socket: StateSocket,
42 mut command_pipe: CommandPipe<H>,
43 ) -> Result<(), Error> {
44 let after_first_loop: Once = Once::new();
45 let mut event_buffer: Vec<DisplayEvent<H>> = vec![];
46 while self.should_keep_running(&mut state_socket).await {
47 self.update_manager_state(&mut state_socket).await;
48 self.display_server.flush();
49
50 let response: EventResponse = tokio::select! {
51 () = self.display_server.wait_readable(), if event_buffer.is_empty() => {
52 self.add_events(&mut event_buffer);
53 continue;
54 }
55 () = timeout(100), if (self.state.focus_manager.sloppy_mouse_follows_focus &&
59 self.state.focus_manager.behaviour.is_sloppy() &&
60 event_buffer.is_empty()) => {
61 self.refresh_focus(&mut event_buffer);
62 continue;
63 }
64 Some::<Command<H>>(cmd) = command_pipe.read_command(), if event_buffer.is_empty() => self.execute_command(&cmd),
65 else => self.execute_display_events(&mut event_buffer),
66 };
67
68 match response {
69 EventResponse::None => (),
70 EventResponse::DisplayRefreshNeeded => self.refresh_display(),
71 }
72
73 self.execute_actions(&mut event_buffer);
74
75 after_first_loop.call_once(|| {
78 self.config.load_state(&mut self.state);
79 });
80
81 if self.reap_requested.swap(false, Ordering::SeqCst) {
82 self.children.remove_finished_children();
83 }
84 }
85
86 Ok(())
87 }
88
89 async fn update_manager_state(&self, state_socket: &mut StateSocket) {
90 if self.state.mode == Mode::Normal {
91 state_socket.write_manager_state(&self.state).await.ok();
92 }
93 }
94
95 async fn should_keep_running(&self, state_socket: &mut StateSocket) -> bool {
96 if self.reload_requested {
97 state_socket.shutdown().await;
98 false
99 } else {
100 true
101 }
102 }
103
104 fn execute_display_events(&mut self, event_buffer: &mut Vec<DisplayEvent<H>>) -> EventResponse {
105 let mut display_needs_refresh = false;
106
107 event_buffer.drain(..).for_each(|event: DisplayEvent<H>| {
108 display_needs_refresh = self.display_event_handler(event) || display_needs_refresh;
109 });
110
111 if display_needs_refresh {
112 EventResponse::DisplayRefreshNeeded
113 } else {
114 EventResponse::None
115 }
116 }
117
118 fn refresh_display(&mut self) {
119 self.update_windows();
120
121 match self.state.mode {
122 Mode::ResizingWindow(h) | Mode::MovingWindow(h) => {
124 if let Some(window) = self.state.windows.iter().find(|w| w.handle == h) {
125 self.display_server.update_windows(vec![window]);
126 }
127 }
128 _ => {
129 let windows: Vec<&Window<H>> = self.state.windows.iter().collect();
130 self.display_server.update_windows(windows);
131 }
132 }
133 }
134
135 fn execute_command(&mut self, command: &Command<H>) -> EventResponse {
136 if self.command_handler(command) {
137 EventResponse::DisplayRefreshNeeded
138 } else {
139 EventResponse::None
140 }
141 }
142
143 fn add_events(&mut self, event_buffer: &mut Vec<DisplayEvent<H>>) -> EventResponse {
144 event_buffer.append(&mut self.display_server.get_next_events());
145 EventResponse::None
146 }
147
148 fn refresh_focus(&self, event_buffer: &mut Vec<DisplayEvent<H>>) -> EventResponse {
149 if let Some(verify_event) = self.display_server.generate_verify_focus_event() {
150 event_buffer.push(verify_event);
151 }
152 EventResponse::None
153 }
154
155 fn execute_actions(&mut self, event_buffer: &mut Vec<DisplayEvent<H>>) {
157 while !self.state.actions.is_empty() {
158 if let Some(act) = self.state.actions.pop_front()
159 && let Some(event) = self.display_server.execute_action(act)
160 {
161 event_buffer.push(event);
162 }
163 }
164 }
165
166 fn call_up_scripts(&mut self) {
167 match Nanny::run_global_up_script() {
168 Ok(child) => {
169 self.children.insert(child);
170 }
171 Err(err) => tracing::warn!("Global up script failed: {}", err),
172 }
173 match Nanny::boot_current_theme() {
174 Ok(child) => {
175 self.children.insert(child);
176 }
177 Err(err) => tracing::warn!("Theme loading failed: {}", err),
178 }
179 }
180}
181
182async fn get_state_socket() -> Result<StateSocket, Error> {
183 let socket_filename = Path::new("current_state.sock");
184 let socket_file = place_runtime_file(socket_filename)
185 .map_err(|_| Error::CreateFile(socket_filename.into()))?;
186
187 let mut state_socket = StateSocket::default();
188
189 state_socket
190 .listen(socket_file)
191 .await
192 .map_err(|_| Error::ConnectToFile(socket_filename.into()))?;
193
194 Ok(state_socket)
195}
196
197async fn get_command_pipe<H: Handle>() -> Result<CommandPipe<H>, Error> {
198 let file_name = crate::pipe_name();
199
200 let pipe_file =
201 place_runtime_file(&file_name).map_err(|_| Error::CreateFile(file_name.clone()))?;
202
203 CommandPipe::new(pipe_file)
204 .await
205 .map_err(|_| Error::ConnectToFile(file_name))
206}
207
208fn place_runtime_file<P>(path: P) -> std::io::Result<PathBuf>
209where
210 P: AsRef<Path>,
211{
212 xdg::BaseDirectories::with_prefix("leftwm").place_runtime_file(path)
213}
214
215async fn timeout(mills: u64) {
216 use tokio::time::{Duration, sleep};
217 sleep(Duration::from_millis(mills)).await;
218}