use xcb::{ x::{ ConfigureNotifyEvent, ConfigureRequestEvent, DestroyNotifyEvent, MapRequestEvent, UnmapNotifyEvent, }, xinerama::{self, ScreenInfo}, Extension, }; use crate::{error::*, WM}; impl WM<'_> { /// Update the client state's recorded monitors and monitor sizes pub(crate) fn update_geometry(&mut self) -> Result<()> { if self .conn .active_extensions() .any(|e| e == Extension::Xinerama) { let reply = self .conn .wait_for_reply(self.conn.send_request(&xinerama::QueryScreens {}))?; // Monitor removed, move its clients away if reply.screen_info().len() > self.clients.monitor_count() { self.clients.truncate_screens(reply.screen_info().len()); } // Update screen info & add new client lists if needed for (i, monitor) in reply.screen_info().iter().enumerate() { self.clients.set_screen_info(i, *monitor); } } else { // Only one screen if self.clients.monitor_count() > 1 { self.clients.truncate_screens(1); } // TODO: it looks like this won't actually update when the screen size changes? let setup = self.conn.get_setup(); let screen = setup .roots() .nth(self.screen_num as usize) .ok_or(Error::NoSuchScreen)?; self.clients.set_screen_info( 0, ScreenInfo { x_org: 0, y_org: 0, width: screen.width_in_pixels(), height: screen.height_in_pixels(), }, ); } Ok(()) } pub(crate) fn handle_configure_request(&mut self, _e: ConfigureRequestEvent) -> Result<()> { todo!() } pub(crate) fn handle_configure_notify(&mut self, _e: ConfigureNotifyEvent) -> Result<()> { todo!() } pub(crate) fn handle_destroy_notify(&mut self, _e: DestroyNotifyEvent) -> Result<()> { todo!() } pub(crate) fn handle_map_request(&mut self, _e: MapRequestEvent) -> Result<()> { todo!() } pub(crate) fn handle_unmap_notify(&mut self, _e: UnmapNotifyEvent) -> Result<()> { todo!() } } /// Holds state related to the window manager's clients /// This contains a list of clients per monitor, alongside info on that monitor's screen size. #[derive(Debug, Default)] pub struct ClientState(Vec); /// Info stored for a single monitor #[derive(Debug)] pub struct MonitorInfo { /// Clients attached to that monitor clients: Vec, /// The monitor's geometry screen_info: ScreenInfo, } /// Information about a single client / window #[derive(Debug)] pub struct Client { // TODO } impl ClientState { /// Set the new amount of screens, moving clients away if necessary pub fn truncate_screens(&mut self, new_size: usize) { // hack: double borrow stuff let mut moved_clients = vec![]; for old in self.0.drain(new_size - self.0.len()..self.0.len()) { moved_clients.extend(old.clients.into_iter()); } self.0[0].clients.extend(moved_clients); } /// Set the info for the given screen, resizing the monitor list if necessary. pub fn set_screen_info(&mut self, i: usize, info: ScreenInfo) { while i >= self.0.len() { self.0.push(MonitorInfo::default()) } self.0[i].screen_info = info; } /// Get the amount of monitors this state is currently aware of pub fn monitor_count(&self) -> usize { self.0.len() } } impl Default for MonitorInfo { fn default() -> Self { Self { clients: vec![], screen_info: ScreenInfo { x_org: 0, y_org: 0, width: 0, height: 0, }, } } }