diff options
author | tcmal <me@aria.rip> | 2024-06-21 19:13:12 +0100 |
---|---|---|
committer | tcmal <me@aria.rip> | 2024-06-21 19:13:12 +0100 |
commit | 475253b7bcfd03a932c4b7efd969b3d2bf155035 (patch) | |
tree | 44789ce271d14c89cbff777e75f1e9ab6e1a5e64 /src/main.rs | |
parent | c3e98e34ed7d42ef4271339de88f7131e7647442 (diff) |
refactor connection-related stuff out, make things a bit cleaner
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 244 |
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!() } |