diff options
Diffstat (limited to 'src/clients.rs')
-rw-r--r-- | src/clients.rs | 142 |
1 files changed, 77 insertions, 65 deletions
diff --git a/src/clients.rs b/src/clients.rs index 75ed38a..f04fc36 100644 --- a/src/clients.rs +++ b/src/clients.rs @@ -1,5 +1,6 @@ use std::cmp::min; +use crate::{config::BORDER_WIDTH, error::*, WM}; use xcb::{ x::{ ChangeWindowAttributes, ConfigWindow, ConfigureNotifyEvent, ConfigureRequestEvent, @@ -11,11 +12,8 @@ use xcb::{ BaseEvent, Connection, Extension, Xid, }; -use crate::{error::*, WM}; -const BORDER_WIDTH: u16 = 3; - impl WM<'_> { - /// Update the client state's recorded monitors and monitor sizes + /// Update the client recorded monitors and monitor sizes /// Returns true if any values changed, meaning windows should be re-tiled. pub(crate) fn update_geometry(&mut self) -> Result<bool> { let mut dirty = false; @@ -75,7 +73,7 @@ impl WM<'_> { Ok(()) } - /// Handle a configure request, by checking it's valid and performing it if so + /// Perform configure requests if we're happy with them, or they're for an unmanaged window. pub(crate) fn handle_configure_request(&mut self, e: ConfigureRequestEvent) -> Result<()> { if let Some(c) = self.clients.find_client_mut(e.window()) { // TODO: Allow changing some properties: @@ -102,7 +100,7 @@ impl WM<'_> { Ok(()) } - /// Handle a destroyed window, removing it from the client list and rearranging. + /// Removing destroyed windows from the client list and rearrange. pub(crate) fn handle_destroy_notify(&mut self, e: DestroyNotifyEvent) -> Result<()> { if self.clients.remove_client(e.window()).is_some() { self.clients.rearrange(self.conn); @@ -112,7 +110,7 @@ impl WM<'_> { Ok(()) } - /// Map a window on request, starting to manage it if needed. + /// Map a window, starting to manage it if needed. pub(crate) fn handle_map_request(&mut self, e: MapRequestEvent) -> Result<()> { // Ignore already managed windows if self.clients.find_client_mut(e.window()).is_some() { @@ -124,6 +122,7 @@ impl WM<'_> { .send_request(&GetWindowAttributes { window: e.window() }), )?; if attrs.override_redirect() { + // Something special, don't manage it just let it do its thing. return Ok(()); } @@ -135,7 +134,7 @@ impl WM<'_> { Ok(()) } - /// Handle a window being unmapped by updating its client state, or stop managing it. + /// When a window is unmapped, either stop managing it or update its state. pub(crate) fn handle_unmap_notify(&mut self, e: UnmapNotifyEvent) -> Result<()> { if self.clients.find_client_mut(e.window()).is_some() { if e.is_from_send_event() { @@ -143,7 +142,7 @@ impl WM<'_> { } else { self.clients.remove_client(e.window()); self.clients.rearrange(self.conn); - // TODO: 'disown' the window - unmange(c, 0) + // TODO: 'disown' the window - unmanage(c, 0) } } @@ -198,7 +197,7 @@ impl WM<'_> { // TODO: updatewmhints // XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); - c.select_input( + c.set_event_mask( conn, EventMask::ENTER_WINDOW | EventMask::FOCUS_CHANGE @@ -220,32 +219,17 @@ impl WM<'_> { pub struct ClientState { /// The current arranging function. /// This function is expected to ensure that all clients are the correct size, reconfigure them if needed, and map/unmap as needed. + /// The connection will be flushed after it is called. arrange: &'static dyn Fn(&mut MonitorInfo, &Connection), + + /// A client list for each monitor. mons: Vec<MonitorInfo>, + /// Co-ordinates to the currently focused window. focused: (usize, usize), } -impl Default for ClientState { - fn default() -> Self { - Self { - arrange: &tile, - focused: (0, 0), - mons: vec![], - } - } -} - -impl std::fmt::Debug for ClientState { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ClientState") - .field("focused", &self.focused) - .field("mons", &self.mons) - .finish() - } -} - -/// Info stored for a single monitor +/// Info stored for each monitor #[derive(Debug)] pub struct MonitorInfo { /// Clients attached to that monitor @@ -256,35 +240,22 @@ pub struct MonitorInfo { } impl MonitorInfo { - fn clients_tiled_mut(&mut self) -> impl Iterator<Item = &mut Client> { + /// Iterate over all tiled clients, returning a mutable reference to each. + pub fn clients_tiled_mut(&mut self) -> impl Iterator<Item = &mut Client> { // TODO: tag filtering, floating self.clients.iter_mut() } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct MonitorGeometry { - pub x_org: i16, - pub y_org: i16, - pub width: u16, - pub height: u16, -} - -impl From<ScreenInfo> for MonitorGeometry { - fn from(value: ScreenInfo) -> Self { - Self { - x_org: value.x_org, - y_org: value.y_org, - width: value.width, - height: value.height, - } +impl ClientState { + /// Get the amount of monitors this state is currently aware of + pub fn monitor_count(&self) -> usize { + self.mons.len() } -} -impl ClientState { - /// Set the new amount of screens, moving clients away if necessary + /// Set the new amount of screens, without unmanaging any clients. pub fn truncate_screens(&mut self, new_size: usize) { - // hack: double borrow stuff + // hack: working around double borrow stuff let mut moved_clients = vec![]; for old in self.mons.drain(new_size - self.mons.len()..self.mons.len()) { moved_clients.extend(old.clients.into_iter()); @@ -292,7 +263,7 @@ impl ClientState { self.mons[0].clients.extend(moved_clients); } - /// Set the info for the given screen, resizing the monitor list if necessary. + /// Set the given screen's geometry, resizing the monitor list if necessary. /// Returns true if the new info is different from the old one. pub fn set_monitor_geometry(&mut self, i: usize, info: MonitorGeometry) -> bool { while i >= self.mons.len() { @@ -304,26 +275,20 @@ impl ClientState { dirty } - /// Get the amount of monitors this state is currently aware of - pub fn monitor_count(&self) -> usize { - self.mons.len() - } - /// Find the [`Client`] corresponding to the given window pub fn find_client_mut(&mut self, window: Window) -> Option<&mut Client> { - self.mons - .iter_mut() - .flat_map(|mi| mi.clients.iter_mut()) - .find(|c| c.window == window) + let (mon, i) = self.find_client_pos(window)?; + Some(&mut self.mons[mon].clients[i]) } /// Find the position of the client with the given window, returning (monitor, index) - pub(crate) fn find_client_pos(&mut self, window: Window) -> Option<(usize, usize)> { + pub fn find_client_pos(&mut self, window: Window) -> Option<(usize, usize)> { for (pos_mon, mon) in self.mons.iter_mut().enumerate() { if let Some(pos) = mon.clients.iter().position(|c| c.window == window) { return Some((pos_mon, pos)); } } + None } @@ -384,6 +349,7 @@ impl ClientState { (self.arrange)(&mut self.mons[mon], conn); } + /// Get the currently focused monitor fn focused_mon(&self) -> usize { self.focused.0 } @@ -404,6 +370,7 @@ pub struct Client { } impl Client { + /// Send a configure configure notify event with the current geometry. /// This function does not check for success, so conn.flush() should be called after. fn configure_notify(&self, conn: &Connection) { conn.send_request(&SendEvent { @@ -425,6 +392,7 @@ impl Client { } /// Set this client's geometry, also updating the X11 window if needed. + /// This function does not check for success, so conn.flush() should be called after. fn set_geom( &mut self, conn: &Connection, @@ -458,8 +426,8 @@ impl Client { }); } - /// Set the border of the X11 window to the given value. - /// This sends a request but doesn't wait for the response. + /// Set the border colour of the X11 window to the given value (see `crate::colours::Colours`) + /// This function does not check for success, so conn.flush() should be called after. pub fn set_border(&self, conn: &Connection, colour: u32) { conn.send_request(&ChangeWindowAttributes { window: self.window(), @@ -468,6 +436,7 @@ impl Client { } /// Ensure this client is currently mapped / visible + /// This function does not check for success, so conn.flush() should be called after. pub fn ensure_mapped(&mut self, conn: &Connection) { if !self.mapped { conn.send_request(&MapWindow { @@ -478,6 +447,7 @@ impl Client { } /// Ensure this client is currently unmapped / invisible + /// This function does not check for success, so conn.flush() should be called after. pub fn ensure_unmapped(&mut self, conn: &Connection) { if self.mapped { conn.send_request(&UnmapWindow { @@ -492,7 +462,9 @@ impl Client { self.window } - fn select_input(&self, conn: &Connection, event_mask: EventMask) { + /// Set the event mask for this window + /// This function does not check for success, so conn.flush() should be called after. + fn set_event_mask(&self, conn: &Connection, event_mask: EventMask) { conn.send_request(&ChangeWindowAttributes { window: self.window(), value_list: &[Cw::EventMask(event_mask)], @@ -514,6 +486,7 @@ impl Default for MonitorInfo { } } +/// A simple tiling function fn tile(mon: &mut MonitorInfo, conn: &Connection) { if mon.clients.is_empty() { return; @@ -569,3 +542,42 @@ fn tile(mon: &mut MonitorInfo, conn: &Connection) { c.ensure_mapped(conn); } } + +impl Default for ClientState { + fn default() -> Self { + Self { + arrange: &tile, + focused: (0, 0), + mons: vec![], + } + } +} + +impl std::fmt::Debug for ClientState { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ClientState") + .field("focused", &self.focused) + .field("mons", &self.mons) + .finish() + } +} + +/// Info on the monitor's geometry. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MonitorGeometry { + pub x_org: i16, + pub y_org: i16, + pub width: u16, + pub height: u16, +} + +impl From<ScreenInfo> for MonitorGeometry { + fn from(value: ScreenInfo) -> Self { + Self { + x_org: value.x_org, + y_org: value.y_org, + width: value.width, + height: value.height, + } + } +} |