refactor Client to better reflect different window types

This commit is contained in:
Janis 2022-05-08 01:11:04 +02:00 committed by Gitea
parent 449b4cccd8
commit bae880c5e1
3 changed files with 98 additions and 51 deletions

View file

@ -1,6 +1,6 @@
use log::{debug, error, warn}; use log::{debug, error, warn};
use num_traits::Zero; use num_traits::Zero;
use std::{ptr::NonNull, rc::Rc}; use std::{convert::TryFrom, ptr::NonNull, rc::Rc};
use thiserror::Error; use thiserror::Error;
@ -193,7 +193,7 @@ pub mod wmh {
pub mod ewmh { pub mod ewmh {
use std::{borrow::Borrow, ffi::CString, ops::Index, os::raw::c_long}; 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 x11::xlib::{Atom, XA_ATOM};
use super::{ use super::{
@ -201,7 +201,9 @@ pub mod ewmh {
Display, Display,
}; };
#[derive(Debug, PartialEq, Eq, EnumIter, EnumCount, Clone, Copy)] #[derive(
Debug, PartialEq, Eq, EnumIter, EnumCount, Clone, Copy, FromRepr,
)]
pub enum EWMHAtom { pub enum EWMHAtom {
NetSupported, NetSupported,
NetClientList, NetClientList,
@ -914,8 +916,6 @@ impl XLib {
) == i32::from(Success) ) == i32::from(Success)
}); });
debug!("get_atom_property: {} {:?}", success, atom_out);
success.then(|| atom_out).flatten() success.then(|| atom_out).flatten()
} }

View file

@ -4,13 +4,17 @@ use indexmap::IndexMap;
use log::error; use log::error;
use num_traits::Zero; use num_traits::Zero;
use crate::backends::structs::WindowType;
use crate::util::BuildIdentityHasher; use crate::util::BuildIdentityHasher;
use crate::util::{Point, Size}; use crate::util::{Point, Size};
mod client { mod client {
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use crate::util::{Point, Size}; use crate::{
backends::structs::WindowType,
util::{Point, Size},
};
use x11::xlib::Window; use x11::xlib::Window;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -18,7 +22,8 @@ mod client {
pub(crate) window: Window, pub(crate) window: Window,
pub(crate) size: Size<i32>, pub(crate) size: Size<i32>,
pub(crate) position: Point<i32>, pub(crate) position: Point<i32>,
pub(crate) transient_for: Option<Window>, pub(crate) parent_window: Option<Window>,
pub(crate) window_type: WindowType,
pub(crate) fullscreen: bool, pub(crate) fullscreen: bool,
} }
@ -28,8 +33,9 @@ mod client {
window: 0, window: 0,
size: (100, 100).into(), size: (100, 100).into(),
position: (0, 0).into(), position: (0, 0).into(),
transient_for: None, parent_window: None,
fullscreen: false, fullscreen: false,
window_type: WindowType::Normal,
} }
} }
} }
@ -49,7 +55,7 @@ mod client {
} }
} }
pub fn new_transient( pub fn new_dialog(
window: Window, window: Window,
size: Size<i32>, size: Size<i32>,
transient: Window, transient: Window,
@ -57,7 +63,7 @@ mod client {
Self { Self {
window, window,
size, size,
transient_for: Some(transient), parent_window: Some(transient),
..Default::default() ..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<Window>) -> Self {
Self {
parent_window,
..self
}
}
pub fn with_size(self, size: Size<i32>) -> Self {
Self { size, ..self }
}
/// toggles the clients fullscreen flag. /// toggles the clients fullscreen flag.
/// returns `true` if the client is now fullscreen. /// returns `true` if the client is now fullscreen.
pub fn toggle_fullscreen(&mut self) -> bool { pub fn toggle_fullscreen(&mut self) -> bool {
@ -90,8 +114,8 @@ mod client {
self.fullscreen self.fullscreen
} }
pub fn is_transient(&self) -> bool { pub fn has_parent_window(&self) -> bool {
self.transient_for.is_some() self.parent_window.is_some()
} }
} }
@ -240,27 +264,42 @@ impl ClientState {
pub fn insert(&mut self, mut client: Client) -> Option<&Client> { pub fn insert(&mut self, mut client: Client) -> Option<&Client> {
let key = client.key(); let key = client.key();
if client.is_transient() match client.window_type {
&& self.contains(&client.transient_for.unwrap()) // 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())
{ {
let transient = self.get(&client.transient_for.unwrap()).unwrap();
client.position = { client.position = {
( (
transient.position.x parent.position.x
+ (transient.size.width - client.size.width) / 2, + (parent.size.width - client.size.width) / 2,
transient.position.y parent.position.y
+ (transient.size.height - client.size.height) / 2, + (parent.size.height - client.size.height) / 2,
) )
.into() .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); self.floating_clients.insert(key, client);
} else { }
WindowType::Normal => {
self.clients.insert(key, client); self.clients.insert(key, client);
self.virtual_screens.get_mut_current().insert(&key); self.virtual_screens.get_mut_current().insert(&key);
} }
}
// adding a client changes the liling layout, rearrange // adding a client changes the liling layout, rearrange
self.arrange_virtual_screen(); self.arrange_virtual_screen();
@ -320,7 +359,15 @@ impl ClientState {
} }
pub fn iter_transient(&self) -> impl Iterator<Item = (&u64, &Client)> { pub fn iter_transient(&self) -> impl Iterator<Item = (&u64, &Client)> {
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<Item = (&u64, &Client)> {
self.iter_floating()
.filter(move |&(_, c)| c.window_type == window_type)
} }
pub fn iter_visible(&self) -> impl Iterator<Item = (&u64, &Client)> { pub fn iter_visible(&self) -> impl Iterator<Item = (&u64, &Client)> {
@ -357,7 +404,7 @@ impl ClientState {
{ {
match self.get(key) { match self.get(key) {
ClientEntry::Floating(c) => { 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) self.is_client_visible(&transient_for)
} else { } else {
true true
@ -519,15 +566,15 @@ impl ClientState {
} }
(None, Some(floating_client)) => { (None, Some(floating_client)) => {
// transient clients cannot be tiled // transient clients cannot be tiled
match floating_client.is_transient() { // only normal windows can be tiled
true => { match floating_client.window_type {
self.floating_clients.insert(key, floating_client); WindowType::Normal => {
}
false => {
self.clients.insert(key, floating_client); self.clients.insert(key, floating_client);
self.virtual_screens.get_mut_current().insert(&key); self.virtual_screens.get_mut_current().insert(&key);
} }
_ => {
self.floating_clients.insert(key, floating_client);
}
} }
} }
_ => { _ => {

View file

@ -4,6 +4,7 @@ use log::{error, info};
use x11::xlib::{self, Window}; use x11::xlib::{self, Window};
use crate::backends::structs::WindowType;
use crate::backends::window_event::{ use crate::backends::window_event::{
FullscreenEvent, FullscreenState, WindowNameEvent, FullscreenEvent, FullscreenState, WindowNameEvent,
}; };
@ -748,19 +749,16 @@ where
} }
fn new_client(&mut self, window: Window) { fn new_client(&mut self, window: Window) {
info!("new client: {:?}", window); let client = match self.backend.get_window_type(window) {
let client = if let Some(transient_window) = WindowType::Normal => Client::new_default(window),
self.backend.get_parent_window(window) window_type @ _ => Client::new_default(window)
{ .with_window_type(window_type)
Client::new_transient( .with_size(
window,
self.backend self.backend
.get_window_size(window) .get_window_size(window)
.unwrap_or((100, 100).into()), .unwrap_or((100, 100).into()),
transient_window,
) )
} else { .with_parent_window(self.backend.get_parent_window(window)),
Client::new_default(window)
}; };
self.backend.configure_window( self.backend.configure_window(
@ -770,6 +768,8 @@ where
Some(self.clients.get_border()), Some(self.clients.get_border()),
); );
info!("new client: {:#?}", client);
self.clients.insert(client).unwrap(); self.clients.insert(client).unwrap();
self.arrange_clients(); self.arrange_clients();