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
131
132
133
134
use crate::{child_process::Nanny, config::Config};
use crate::{CommandPipe, DisplayServer, Manager, Mode, StateSocket, Window};
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 file_name = CommandPipe::pipe_name();
let pipe_file = place_runtime_file(&file_name)
.unwrap_or_else(|_| panic!("ERROR: couldn't create {}", file_name.display()));
let mut command_pipe = CommandPipe::new(pipe_file)
.await
.unwrap_or_else(|_| panic!("ERROR: couldn't connect to {}", file_name.display()));
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.state).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.is_sloppy() => {
if let Some(verify_event) = self.display_server.generate_verify_focus_event() {
event_buffer.push(verify_event);
}
continue;
}
Some(cmd) = command_pipe.read_command(), if event_buffer.is_empty() => {
needs_update = self.command_handler(&cmd) || needs_update;
}
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::ResizingWindow(h) | Mode::MovingWindow(h) => {
let windows: Vec<&Window> = self
.state
.windows
.iter()
.filter(|w| w.handle == h)
.collect();
self.display_server.update_windows(windows);
}
_ => {
let windows: Vec<&Window> = self.state.windows.iter().collect();
self.display_server.update_windows(windows);
}
}
}
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),
}
self.config.load_state(&mut self.state);
});
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;
}