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
|
//! A lightweight X11 window manager, inspired by dwm.
#![deny(clippy::all, clippy::pedantic, clippy::nursery)]
use clients::ClientState;
use conn_info::Connection;
pub use error::*;
use xcb::{
x::{self, PropertyNotifyEvent},
Connection as RawConnection, Event, Extension,
};
mod clients;
mod config;
mod conn_info;
mod error;
mod focus;
mod keys;
fn main() -> Result<()> {
cleanup_process_children();
let (conn, screen_num) =
RawConnection::connect_with_extensions(None, &[], &[Extension::Xinerama])?;
#[allow(clippy::cast_sign_loss)]
let mut wm = WM::new(&conn, screen_num as usize)?;
wm.event_loop()?;
Ok(())
}
struct WM<'a> {
conn: Connection<'a>,
clients: ClientState,
}
impl<'a> WM<'a> {
pub fn new(conn: &'a RawConnection, screen_num: usize) -> Result<Self> {
Ok(Self {
conn: Connection::new(conn, screen_num)?,
clients: ClientState::default(),
})
}
pub fn event_loop(&mut self) -> Result<()> {
loop {
match self.conn.wait_for_event()? {
// See keys.rs
Event::X(x::Event::KeyPress(e)) => self.handle_key_press(&e),
Event::X(x::Event::MappingNotify(e)) => self.handle_mapping_notify(&e)?,
// See clients/mod.rs
Event::X(x::Event::ConfigureRequest(e)) => self.handle_configure_request(&e)?,
Event::X(x::Event::ConfigureNotify(e)) => self.handle_configure_notify(&e)?,
Event::X(x::Event::DestroyNotify(e)) => self.handle_destroy_notify(&e)?,
Event::X(x::Event::MapRequest(e)) => self.handle_map_request(&e)?,
Event::X(x::Event::UnmapNotify(e)) => self.handle_unmap_notify(&e)?,
// // See focus.rs
Event::X(x::Event::EnterNotify(e)) => self.handle_enter_notify(&e)?,
Event::X(x::Event::FocusIn(e)) => self.handle_focus_in(&e)?,
// // See below
Event::X(x::Event::PropertyNotify(e)) => self.handle_property_notify(&e)?,
_ => {}
};
}
}
/// Handle a property notify event, by doing *todo*
fn handle_property_notify(&mut self, e: &PropertyNotifyEvent) -> Result<()> {
match e.atom() {
x::ATOM_WM_HINTS => {
let focused = self.clients.is_focused(e.window());
if let Some(c) = self.clients.find_client_mut(e.window()) {
c.sync_properties(&self.conn, focused);
self.conn.flush()?;
}
Ok(())
}
_ => Ok(()),
}
}
}
/// Cleanup this process' children and set some flags.
/// This is necessary when used with `startx`
fn cleanup_process_children() {
// TODO: dont transform children into zombies when they terminate
// TODO: cleanup zombies
todo!()
}
|