summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs244
1 files changed, 39 insertions, 205 deletions
diff --git a/src/main.rs b/src/main.rs
index 374b403..0232e61 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,24 +1,17 @@
//! A lightweight X11 window manager, inspired by dwm.
+#![deny(clippy::all, clippy::pedantic, clippy::nursery)]
-use atoms::Atoms;
use clients::ClientState;
-use colours::Colours;
-use cursors::Cursors;
-use error::*;
-use keys::KeyboardInfo;
+use conn_info::Connection;
+pub use error::*;
use xcb::{
- x::{
- self, ChangeProperty, ChangeWindowAttributes, CreateWindow, DeleteProperty,
- PropertyNotifyEvent, Window, WindowClass,
- },
- Connection, Event, Extension,
+ x::{self, PropertyNotifyEvent},
+ Connection as RawConnection, Event, Extension,
};
-mod atoms;
mod clients;
-mod colours;
mod config;
-mod cursors;
+mod conn_info;
mod error;
mod focus;
mod keys;
@@ -27,211 +20,62 @@ fn main() -> Result<()> {
cleanup_process_children();
let (conn, screen_num) =
- Connection::connect_with_extensions(None, &[], &[Extension::Xinerama])?;
+ RawConnection::connect_with_extensions(None, &[], &[Extension::Xinerama])?;
- let mut wm = WM::new(&conn, screen_num)?;
+ #[allow(clippy::cast_sign_loss)]
+ let mut wm = WM::new(&conn, screen_num as usize)?;
wm.event_loop()?;
Ok(())
}
-/// The window manager's state
struct WM<'a> {
- /// The open connection to an X server
- conn: &'a Connection,
-
- /// The 'screen' number on the X server
- /// Note this isn't what you think it is on multi-monitor setups
- screen_num: i32,
-
- /// The root window
- root: Window,
-
- /// A window used to prove we're actually EWMH compliant.
- /// See [the EWMH spec](https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html#idm46187912047344)
- check_window: Window,
-
- /// WM client state
+ conn: Connection<'a>,
clients: ClientState,
-
- /// Cached colours,
- colours: Colours,
-
- /// Cached cursors
- cursors: Cursors,
-
- /// Cached atoms
- atoms: Atoms,
-
- /// Cached keyboard layout information
- keyboard_state: KeyboardInfo,
}
-impl WM<'_> {
- /// Prepare the window manager to run on the given connection and screen number.
- /// This will fail if another WM is running.
- fn new(conn: &'_ Connection, screen_num: i32) -> Result<WM<'_>> {
- // Fetch root window
- let setup = conn.get_setup();
- let screen = setup
- .roots()
- .nth(screen_num as usize)
- .ok_or(Error::NoSuchScreen)?;
-
- // Check no other WM is running
- conn.check_request(conn.send_request_checked(&ChangeWindowAttributes {
- window: screen.root(),
- value_list: &[
- x::Cw::BackPixel(screen.white_pixel()),
- x::Cw::EventMask(x::EventMask::SUBSTRUCTURE_REDIRECT),
- ],
- }))
- .map_err(|_| Error::OtherWMRunning)?;
-
- Ok(WM {
- colours: Colours::new_with(conn, screen.default_colormap())?,
- atoms: Atoms::intern_all(conn)?,
- cursors: Cursors::new_with(conn)?,
- keyboard_state: KeyboardInfo::new_with(conn)?,
- clients: Default::default(),
- check_window: conn.generate_id(),
- conn,
- screen_num,
- root: screen.root(),
+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(),
})
}
- /// Set the correct properties on the root window
- fn setup_root(&mut self) -> Result<()> {
- // Check window
- self.conn.send_request(&CreateWindow {
- wid: self.check_window,
- parent: self.root,
- depth: 0,
- x: 0,
- y: 0,
- width: 0,
- height: 0,
- border_width: 0,
- class: WindowClass::InputOutput,
- visual: 0,
- value_list: &[],
- });
-
- self.conn.send_request(&ChangeProperty {
- mode: x::PropMode::Replace,
- window: self.root,
- property: self.atoms.net_wm_check,
- r#type: x::ATOM_WINDOW,
- data: &[self.check_window],
- });
-
- self.conn.send_request(&ChangeProperty {
- mode: x::PropMode::Replace,
- window: self.check_window,
- property: self.atoms.net_wm_check,
- r#type: x::ATOM_WINDOW,
- data: &[self.check_window],
- });
-
- self.conn.send_request(&ChangeProperty {
- mode: x::PropMode::Replace,
- window: self.check_window,
- property: self.atoms.net_wm_name,
- r#type: x::ATOM_STRING,
- data: b"blow",
- });
-
- // Supported flag
- self.conn.send_request(&ChangeProperty {
- mode: x::PropMode::Replace,
- window: self.root,
- property: self.atoms.net_supported,
- r#type: x::ATOM_ATOM,
- data: &[
- self.atoms.net_active_window,
- self.atoms.net_wm_name,
- self.atoms.net_wm_state,
- self.atoms.net_wm_check,
- self.atoms.net_wm_fullscreen,
- self.atoms.net_wm_window_type,
- self.atoms.net_wm_window_type_dialog,
- self.atoms.net_client_list,
- ],
- });
-
- // Cleanup state
- self.conn.send_request(&DeleteProperty {
- window: self.root,
- property: self.atoms.net_client_list,
- });
-
- // Get the right events
- self.conn.send_request(&ChangeWindowAttributes {
- window: self.root,
- value_list: &[
- x::Cw::EventMask(
- x::EventMask::SUBSTRUCTURE_REDIRECT
- | x::EventMask::SUBSTRUCTURE_NOTIFY
- | x::EventMask::BUTTON_PRESS
- | x::EventMask::ENTER_WINDOW
- | x::EventMask::FOCUS_CHANGE
- | x::EventMask::STRUCTURE_NOTIFY
- | x::EventMask::PROPERTY_CHANGE,
- ),
- x::Cw::Cursor(self.cursors.normal()),
- ],
- });
-
- self.grab_keys()?;
-
- self.refocus(usize::MAX, usize::MAX);
- self.conn.flush()?;
-
- Ok(())
- }
-
- fn event_loop(&mut self) -> Result<()> {
- // Perform setup
- self.update_geometry()?;
- self.setup_root()?;
-
+ 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.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)?,
+ 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<()> {
+ fn handle_property_notify(&mut self, e: &PropertyNotifyEvent) -> Result<()> {
match e.atom() {
x::ATOM_WM_HINTS => {
- let Some(p) = self.clients.find_client_pos(e.window()) else {
- return Ok(());
- };
- let focused = p == self.clients.focused();
- self.clients.client_mut(p.0, p.1).and_then(|c| {
- c.sync_properties(self.conn, focused);
- Some(())
- });
+ 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(())
}
@@ -245,15 +89,5 @@ impl WM<'_> {
fn cleanup_process_children() {
// TODO: dont transform children into zombies when they terminate
// TODO: cleanup zombies
-}
-
-impl<'a> std::fmt::Debug for WM<'a> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("WM")
- .field("screen_num", &self.screen_num)
- .field("root", &self.root)
- .field("clients", &self.clients)
- .field("atoms", &self.atoms)
- .finish()
- }
+ todo!()
}