diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/clients/client.rs | 2 | ||||
-rw-r--r-- | src/clients/hints.rs | 5 | ||||
-rw-r--r-- | src/clients/mod.rs | 11 | ||||
-rw-r--r-- | src/clients/tile.rs | 2 | ||||
-rw-r--r-- | src/config.rs | 7 | ||||
-rw-r--r-- | src/conn_info/atoms.rs | 1 | ||||
-rw-r--r-- | src/conn_info/mod.rs | 7 | ||||
-rw-r--r-- | src/focus.rs | 2 | ||||
-rw-r--r-- | src/keys.rs | 4 | ||||
l--------- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/main.rs | 44 |
11 files changed, 72 insertions, 14 deletions
diff --git a/src/clients/client.rs b/src/clients/client.rs index 3b33b5f..394c319 100644 --- a/src/clients/client.rs +++ b/src/clients/client.rs @@ -133,7 +133,7 @@ impl Client { /// Sync the non-geometry related properties with EWMH hints pub fn sync_properties(&mut self, conn: &Connection<'_>, focused: bool) { - let Some(mut hints) = hints::Xwm::get(conn, self.window) else { + let Some(mut hints) = hints::Ewm::get(conn, self.window) else { return; }; diff --git a/src/clients/hints.rs b/src/clients/hints.rs index dd5bcf7..bd3ef76 100644 --- a/src/clients/hints.rs +++ b/src/clients/hints.rs @@ -5,7 +5,8 @@ use xcb::{ use crate::conn_info::Connection; -pub struct Xwm { +/// EWM Hints set on a window. +pub struct Ewm { flags: u32, input: bool, initial_state: i32, @@ -17,7 +18,7 @@ pub struct Xwm { window_group: u32, } -impl Xwm { +impl Ewm { /// Get the EWM hints for the given window, if they exist and are valid. pub fn get(conn: &Connection<'_>, window: Window) -> Option<Self> { // https://github.com/mirror/libX11/blob/ff8706a5eae25b8bafce300527079f68a201d27f/src/GetHints.c#L106 diff --git a/src/clients/mod.rs b/src/clients/mod.rs index c7df881..ca9ed91 100644 --- a/src/clients/mod.rs +++ b/src/clients/mod.rs @@ -1,3 +1,5 @@ +//! Tracking and managing windows. + use crate::{ config::BORDER_WIDTH, conn_info::Connection, @@ -14,12 +16,19 @@ use xcb::{ BaseEvent, Extension, }; -pub use client::Client; +pub use client::*; +pub use hints::*; pub use monitors::*; +#[doc(hidden)] mod client; + +#[doc(hidden)] mod hints; + +#[doc(hidden)] mod monitors; + mod tile; impl WM<'_> { diff --git a/src/clients/tile.rs b/src/clients/tile.rs index 4a2d4fc..e089c3f 100644 --- a/src/clients/tile.rs +++ b/src/clients/tile.rs @@ -1,3 +1,5 @@ +//! Tiling functions + use std::cmp::min; use crate::conn_info::Connection; diff --git a/src/config.rs b/src/config.rs index e6478b3..246fe12 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,6 @@ +//! User configuration #![allow(clippy::unreadable_literal)] // Colours are more readable this way imo + use std::process::Command; use xcb::x::ModMask; @@ -9,8 +11,13 @@ use crate::{ keys::{Keybind, Keybinds}, }; +/// Width of the border around windows pub const BORDER_WIDTH: u16 = 3; + +/// Default border for windows pub const BORDER_NORMAL: Colour = Colour::from_hex(0x000000); + +/// Border around currently focused window pub const BORDER_FOCUSED: Colour = Colour::from_hex(0xff0000); /// The keybinds to use. diff --git a/src/conn_info/atoms.rs b/src/conn_info/atoms.rs index 9b3a78a..ca715ef 100644 --- a/src/conn_info/atoms.rs +++ b/src/conn_info/atoms.rs @@ -1,4 +1,5 @@ xcb::atoms_struct! { + /// Interned atoms, mostly for window properties #[derive(Copy, Clone, Debug)] pub struct Atoms { pub wm_protocols => b"WM_PROTOCOLS" only_if_exists = false, diff --git a/src/conn_info/mod.rs b/src/conn_info/mod.rs index 183f691..c1d768d 100644 --- a/src/conn_info/mod.rs +++ b/src/conn_info/mod.rs @@ -1,3 +1,5 @@ +//! Global resources and utilities + use std::fmt::Debug; use xcb::{ x::{ @@ -7,9 +9,13 @@ use xcb::{ Connection as RawConnection, Cookie, VoidCookieChecked, }; +#[doc(hidden)] mod atoms; +#[doc(hidden)] mod colours; +#[doc(hidden)] mod cursors; +#[doc(hidden)] mod keys; pub use self::{ @@ -49,6 +55,7 @@ pub struct Connection<'a> { pub keyboard_state: KeyboardInfo, } +/// Helper macro to log a request / cookie when debug_assertions are on macro_rules! debug_req { ($req:ident) => { #[cfg(debug_assertions)] diff --git a/src/focus.rs b/src/focus.rs index 65bf65e..da3b81a 100644 --- a/src/focus.rs +++ b/src/focus.rs @@ -1,3 +1,5 @@ +//! Event handlers for dealing with window focus. + use xcb::x::{EnterNotifyEvent, FocusInEvent, NotifyDetail, NotifyMode}; use crate::WM; diff --git a/src/keys.rs b/src/keys.rs index 3103f41..51d005d 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -1,3 +1,5 @@ +//! Keybind-related code + use crate::{config::KEYBINDS, conn_info::Connection, error::Result, WM}; use xcb::x::{ GrabKey, GrabMode, KeyPressEvent, Mapping, MappingNotifyEvent, ModMask, UngrabKey, GRAB_ANY, @@ -34,7 +36,7 @@ impl WM<'_> { } /// Refresh our keyboard info, and ensure that we get events for bound keys. -fn grab_keys(conn: &mut Connection<'_>) -> Result<()> { +pub fn grab_keys(conn: &mut Connection<'_>) -> Result<()> { // Refresh keyboard state conn.refresh_keyboard_info()?; diff --git a/src/lib.rs b/src/lib.rs new file mode 120000 index 0000000..f61f281 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +src/main.rs
\ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 54d893c..64e9203 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,20 @@ //! A lightweight X11 window manager, inspired by dwm. +//! +//! # Structure +//! +//! The main thing a WM has to do is respond to events: this is done in the [`WM::event_loop`] function, which dispatches to the `handle_*` methods of that struct. +//! +//! [`conn_info`] wraps XCB's [`xcb::Connection`] type and caches common resources such as atoms, colours, cursors, and keyboard layout info. +//! +//! `focus.rs`, [`keys`], and [`clients`] all add some event handlers to [`WM`], but most of the important code is in [`clients`]. +//! +//! [`config`] holds all of the variables that a user might want to change. +//! +//! # XCB +//! +//! Unlike dwm, blow uses XCB rather than Xlib. This means requests are asynchronous by default. +//! In most places, we avoid checking for errors unless we need to see the response to a request. +//! Errors will be caught and logged in the event loop instead. See [`xcb`] documentation for more details. #![deny(clippy::all, clippy::pedantic, clippy::nursery)] use clients::ClientState; @@ -9,12 +25,14 @@ use xcb::{ Connection as RawConnection, Event, Extension, }; -mod clients; -mod config; -mod conn_info; +pub mod clients; +pub mod config; +pub mod conn_info; +#[doc(hidden)] mod error; +#[doc(hidden)] mod focus; -mod keys; +pub mod keys; fn main() -> Result<()> { cleanup_process_children(); @@ -29,12 +47,14 @@ fn main() -> Result<()> { Ok(()) } -struct WM<'a> { +/// All of the state used by the window manager +pub struct WM<'a> { conn: Connection<'a>, clients: ClientState, } impl<'a> WM<'a> { + /// Prepare to start the window manager, using the given connection and scren number. pub fn new(conn: &'a RawConnection, screen_num: usize) -> Result<Self> { let mut this = Self { conn: Connection::new(conn, screen_num)?, @@ -45,6 +65,8 @@ impl<'a> WM<'a> { Ok(this) } + /// Run the main event loop until we encounter a non-recoverable error (usually connection). + /// This will only ever return an error. pub fn event_loop(&mut self) -> Result<()> { loop { match self.conn.wait_for_event() { @@ -68,15 +90,19 @@ impl<'a> WM<'a> { Event::X(x::Event::PropertyNotify(e)) => self.handle_property_notify(&e), _ => {} }, + Err(Error::Xcb(xcb::Error::Protocol(e))) => { + eprintln!("protocol error in event loop: {e:#?}\ncontinuing anyway"); + } Err(e) => { - eprintln!("error in event loop: {e:#?}\ncontinuing anyway"); + eprintln!("unrecoverable error: {e:#?}\nexiting event loop"); + return Err(e); } }; self.conn.flush()?; } } - /// Handle a property notify event, by doing *todo* + /// Update client properties when they change in X11. fn handle_property_notify(&mut self, e: &PropertyNotifyEvent) { if x::ATOM_WM_HINTS == e.atom() { let focused = self.clients.is_focused(e.window()); @@ -88,9 +114,9 @@ impl<'a> WM<'a> { } /// Cleanup this process' children and set some flags. -/// This is necessary when used with `startx` +/// This is necessary when used with `startx`. fn cleanup_process_children() { // TODO: dont transform children into zombies when they terminate // TODO: cleanup zombies - todo!() + // todo!() } |