1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use crate::{child_process::Nanny, config::Config, models::FocusBehaviour};
use crate::{CommandPipe, DisplayServer, Manager, Mode, StateSocket, Window, Workspace};
use std::path::{Path, PathBuf};
use std::sync::{atomic::Ordering, Once};
impl<C: Config, SERVER: DisplayServer> Manager<C, SERVER> {
pub async fn event_loop(mut self) {
let socket_file = place_runtime_file("current_state.sock")
.expect("ERROR: couldn't create current_state.sock");
let mut state_socket = StateSocket::default();
state_socket
.listen(socket_file)
.await
.expect("ERROR: couldn't connect to current_state.sock");
let pipe_file =
place_runtime_file("commands.pipe").expect("ERROR: couldn't create commands.pipe");
let mut command_pipe = CommandPipe::new(pipe_file)
.await
.expect("ERROR: couldn't connect to commands.pipe");
let after_first_loop: Once = Once::new();
let mut event_buffer = vec![];
loop {
if self.state.mode == Mode::Normal {
state_socket.write_manager_state(&self).await.ok();
}
self.display_server.flush();
let mut needs_update = false;
tokio::select! {
_ = self.display_server.wait_readable(), if event_buffer.is_empty() => {
event_buffer.append(&mut self.display_server.get_next_events());
continue;
}
_ = timeout(100), if event_buffer.is_empty() && self.state.focus_manager.behaviour == FocusBehaviour::Sloppy => {
let mut focus_event = self.display_server.verify_focused_window();
event_buffer.append(&mut focus_event);
continue;
}
Some(cmd) = command_pipe.read_command(), if event_buffer.is_empty() => {
needs_update = self.command_handler(&cmd) || needs_update;
self.display_server.update_theme_settings(&self.state.config);
}
else => {
event_buffer.drain(..).for_each(|event| needs_update = self.display_event_handler(event) || needs_update);
}
}
if needs_update {
self.update_windows();
match self.state.mode {
Mode::Normal => {
let windows: Vec<&Window> = self.state.windows.iter().collect();
let focused = self.focused_window();
self.display_server.update_windows(windows, focused, &self);
let workspaces: Vec<&Workspace> = self.state.workspaces.iter().collect();
let focused = self.focused_workspace();
self.display_server.update_workspaces(workspaces, focused);
}
Mode::ResizingWindow(h) | Mode::MovingWindow(h) => {
let focused = self.focused_window();
let windows: Vec<&Window> = (&self.state.windows)
.iter()
.filter(|w| w.handle == h)
.collect();
self.display_server.update_windows(windows, focused, &self);
}
}
}
while !self.state.actions.is_empty() {
if let Some(act) = self.state.actions.pop_front() {
if let Some(event) = self.display_server.execute_action(act) {
event_buffer.push(event);
}
}
}
after_first_loop.call_once(|| {
match Nanny::run_global_up_script() {
Ok(child) => {
child.map(|child| self.children.insert(child));
}
Err(err) => log::error!("Global up script faild: {}", err),
}
match Nanny::boot_current_theme() {
Ok(child) => {
child.map(|child| self.children.insert(child));
}
Err(err) => log::error!("Theme loading failed: {}", err),
}
C::load_state(&mut self);
});
if self.reap_requested.swap(false, Ordering::SeqCst) {
self.children.reap();
}
if self.reload_requested {
state_socket.shutdown().await;
break;
}
}
}
}
fn place_runtime_file<P>(path: P) -> std::io::Result<PathBuf>
where
P: AsRef<Path>,
{
xdg::BaseDirectories::with_prefix("leftwm")?.place_runtime_file(path)
}
async fn timeout(mills: u64) {
use tokio::time::{sleep, Duration};
sleep(Duration::from_millis(mills)).await;
}