diff --git a/src/backends/xlib/mod.rs b/src/backends/xlib/mod.rs index 00bb14a..a0f2cdd 100644 --- a/src/backends/xlib/mod.rs +++ b/src/backends/xlib/mod.rs @@ -1,6 +1,6 @@ use log::{debug, error, warn}; use num_traits::Zero; -use std::{ptr::NonNull, rc::Rc}; +use std::{convert::TryFrom, ptr::NonNull, rc::Rc}; use thiserror::Error; @@ -193,7 +193,7 @@ pub mod wmh { pub mod ewmh { use std::{borrow::Borrow, ffi::CString, ops::Index, os::raw::c_long}; - use strum::{EnumCount, EnumIter}; + use strum::{EnumCount, EnumIter, FromRepr}; use x11::xlib::{Atom, XA_ATOM}; use super::{ @@ -201,7 +201,9 @@ pub mod ewmh { Display, }; - #[derive(Debug, PartialEq, Eq, EnumIter, EnumCount, Clone, Copy)] + #[derive( + Debug, PartialEq, Eq, EnumIter, EnumCount, Clone, Copy, FromRepr, + )] pub enum EWMHAtom { NetSupported, NetClientList, @@ -914,8 +916,6 @@ impl XLib { ) == i32::from(Success) }); - debug!("get_atom_property: {} {:?}", success, atom_out); - success.then(|| atom_out).flatten() } diff --git a/src/clients.rs b/src/clients.rs index 1c6d3a8..f581489 100644 --- a/src/clients.rs +++ b/src/clients.rs @@ -4,13 +4,17 @@ use indexmap::IndexMap; use log::error; use num_traits::Zero; +use crate::backends::structs::WindowType; use crate::util::BuildIdentityHasher; use crate::util::{Point, Size}; mod client { use std::hash::{Hash, Hasher}; - use crate::util::{Point, Size}; + use crate::{ + backends::structs::WindowType, + util::{Point, Size}, + }; use x11::xlib::Window; #[derive(Clone, Debug)] @@ -18,7 +22,8 @@ mod client { pub(crate) window: Window, pub(crate) size: Size, pub(crate) position: Point, - pub(crate) transient_for: Option, + pub(crate) parent_window: Option, + pub(crate) window_type: WindowType, pub(crate) fullscreen: bool, } @@ -28,8 +33,9 @@ mod client { window: 0, size: (100, 100).into(), position: (0, 0).into(), - transient_for: None, + parent_window: None, fullscreen: false, + window_type: WindowType::Normal, } } } @@ -49,7 +55,7 @@ mod client { } } - pub fn new_transient( + pub fn new_dialog( window: Window, size: Size, transient: Window, @@ -57,7 +63,7 @@ mod client { Self { window, size, - transient_for: Some(transient), + parent_window: Some(transient), ..Default::default() } } @@ -69,6 +75,24 @@ mod client { } } + pub fn with_window_type(self, window_type: WindowType) -> Self { + Self { + window_type, + ..self + } + } + + pub fn with_parent_window(self, parent_window: Option) -> Self { + Self { + parent_window, + ..self + } + } + + pub fn with_size(self, size: Size) -> Self { + Self { size, ..self } + } + /// toggles the clients fullscreen flag. /// returns `true` if the client is now fullscreen. pub fn toggle_fullscreen(&mut self) -> bool { @@ -90,8 +114,8 @@ mod client { self.fullscreen } - pub fn is_transient(&self) -> bool { - self.transient_for.is_some() + pub fn has_parent_window(&self) -> bool { + self.parent_window.is_some() } } @@ -240,26 +264,41 @@ impl ClientState { pub fn insert(&mut self, mut client: Client) -> Option<&Client> { let key = client.key(); - if client.is_transient() - && self.contains(&client.transient_for.unwrap()) - { - let transient = self.get(&client.transient_for.unwrap()).unwrap(); + match client.window_type { + // idk how to handle docks and desktops, for now they float innit + WindowType::Splash + | WindowType::Dialog + | WindowType::Utility + | WindowType::Menu + | WindowType::Toolbar + | WindowType::Dock + | WindowType::Desktop => { + if let Some(parent) = client + .parent_window + .and_then(|window| self.get(&window).into_option()) + { + client.position = { + ( + parent.position.x + + (parent.size.width - client.size.width) / 2, + parent.position.y + + (parent.size.height - client.size.height) / 2, + ) + .into() + }; + } - client.position = { - ( - transient.position.x - + (transient.size.width - client.size.width) / 2, - transient.position.y - + (transient.size.height - client.size.height) / 2, - ) - .into() - }; + client.size = client.size.clamp( + self.screen_size + - Size::new(self.border_size * 2, self.border_size * 2), + ); - self.floating_clients.insert(key, client); - } else { - self.clients.insert(key, client); - - self.virtual_screens.get_mut_current().insert(&key); + self.floating_clients.insert(key, client); + } + WindowType::Normal => { + self.clients.insert(key, client); + self.virtual_screens.get_mut_current().insert(&key); + } } // adding a client changes the liling layout, rearrange @@ -320,7 +359,15 @@ impl ClientState { } pub fn iter_transient(&self) -> impl Iterator { - self.iter_floating().filter(|&(_, c)| c.is_transient()) + self.iter_floating().filter(|&(_, c)| c.has_parent_window()) + } + + pub fn iter_by_window_type( + &self, + window_type: WindowType, + ) -> impl Iterator { + self.iter_floating() + .filter(move |&(_, c)| c.window_type == window_type) } pub fn iter_visible(&self) -> impl Iterator { @@ -357,7 +404,7 @@ impl ClientState { { match self.get(key) { ClientEntry::Floating(c) => { - if let Some(transient_for) = c.transient_for { + if let Some(transient_for) = c.parent_window { self.is_client_visible(&transient_for) } else { true @@ -519,15 +566,15 @@ impl ClientState { } (None, Some(floating_client)) => { // transient clients cannot be tiled - match floating_client.is_transient() { - true => { - self.floating_clients.insert(key, floating_client); - } - - false => { + // only normal windows can be tiled + match floating_client.window_type { + WindowType::Normal => { self.clients.insert(key, floating_client); self.virtual_screens.get_mut_current().insert(&key); } + _ => { + self.floating_clients.insert(key, floating_client); + } } } _ => { diff --git a/src/state.rs b/src/state.rs index 3e12f82..2fd9fa4 100644 --- a/src/state.rs +++ b/src/state.rs @@ -4,6 +4,7 @@ use log::{error, info}; use x11::xlib::{self, Window}; +use crate::backends::structs::WindowType; use crate::backends::window_event::{ FullscreenEvent, FullscreenState, WindowNameEvent, }; @@ -748,19 +749,16 @@ where } fn new_client(&mut self, window: Window) { - info!("new client: {:?}", window); - let client = if let Some(transient_window) = - self.backend.get_parent_window(window) - { - Client::new_transient( - window, - self.backend - .get_window_size(window) - .unwrap_or((100, 100).into()), - transient_window, - ) - } else { - Client::new_default(window) + let client = match self.backend.get_window_type(window) { + WindowType::Normal => Client::new_default(window), + window_type @ _ => Client::new_default(window) + .with_window_type(window_type) + .with_size( + self.backend + .get_window_size(window) + .unwrap_or((100, 100).into()), + ) + .with_parent_window(self.backend.get_parent_window(window)), }; self.backend.configure_window( @@ -770,6 +768,8 @@ where Some(self.clients.get_border()), ); + info!("new client: {:#?}", client); + self.clients.insert(client).unwrap(); self.arrange_clients();