From 507bc75ccc340d3a0371027474cd14e0519b48af Mon Sep 17 00:00:00 2001 From: NoOneBtw Date: Thu, 13 May 2021 00:16:14 +0200 Subject: [PATCH] started with Client Manager logic --- src/client_logic.rs | 456 ++++++++++++++++++++++++++++++++++++++++++++ src/clients2.rs | 68 ++++--- src/main.rs | 1 + 3 files changed, 502 insertions(+), 23 deletions(-) create mode 100644 src/client_logic.rs diff --git a/src/client_logic.rs b/src/client_logic.rs new file mode 100644 index 0000000..f1b64bd --- /dev/null +++ b/src/client_logic.rs @@ -0,0 +1,456 @@ +#![allow(dead_code)] + +use crate::clients2::*; +use std::hash::Hash; + +pub struct Size { + width: T, + height: T, +} + +impl Size { + pub fn new(width: T, height: T) -> Self { + Self { width, height } + } + + /// Get a reference to the size's width. + pub fn width(&self) -> &T { + &self.width + } + + /// Get a reference to the size's height. + pub fn height(&self) -> &T { + &self.height + } + + /// Get a mutable reference to the size's width. + pub fn width_mut(&mut self) -> &mut T { + &mut self.width + } + + /// Get a mutable reference to the size's height. + pub fn height_mut(&mut self) -> &mut T { + &mut self.height + } +} + +impl Size +where + T: Copy, +{ + pub fn dimensions(&self) -> (T, T) { + (self.width, self.height) + } +} + +pub struct Workspace +where + T: Eq, +{ + master: Vec, + aux: Vec, +} + +pub struct WorkspaceStore +where + T: Eq, +{ + workspaces: Vec>, + current_indices: Vec, + previous_indices: Option>, +} + +pub struct ClientManager +where + T: Hash + Eq + Copy, +{ + store: ClientStore, + focused: Option, + workspaces: WorkspaceStore, + + // config + gap: i32, + border_size: i32, + master_size: f32, + screen_size: Size, + + // experimental + invalidated: std::collections::HashSet, +} + +impl Default for Workspace +where + T: Eq, +{ + fn default() -> Self { + Self { + master: vec![], + aux: vec![], + } + } +} + +impl Default for WorkspaceStore +where + T: Eq, +{ + fn default() -> Self { + Self { + workspaces: vec![Default::default()], + current_indices: vec![0], + previous_indices: None, + } + } +} + +impl Default for ClientManager +where + T: Hash + Eq + Copy, +{ + fn default() -> Self { + Self { + store: Default::default(), + focused: None, + workspaces: Default::default(), + gap: 0, + border_size: 0, + master_size: 1.0, + screen_size: Size::new(1, 1), + invalidated: Default::default(), + } + } +} + +enum WorkspaceEntry { + Master(T), + Aux(T), + Vacant, +} + +impl Workspace +where + T: Eq, +{ + pub fn contains(&self, key: &T) -> bool { + self.aux.contains(key) || self.master.contains(key) + } + + pub fn is_master(&self, key: &T) -> bool { + self.master.contains(key) + } + + pub fn is_aux(&self, key: &T) -> bool { + self.aux.contains(key) + } + + pub fn push(&mut self, key: T) { + self.aux.push(key); + } + + pub fn remove(&mut self, key: &T) { + self.master.retain(|k| k != key); + self.aux.retain(|k| k != key); + } + + pub fn entry(&self, key: &T) -> Workspace<&T> { + todo!() + } +} + +impl WorkspaceStore +where + T: Eq, +{ + pub fn new(num: usize) -> Self { + let mut workspaces = Vec::with_capacity(num); + workspaces.resize_with(num, Default::default); + + Self { + workspaces, + ..Default::default() + } + } + + pub fn remove(&mut self, key: &T) { + self.iter_mut().for_each(|w| w.remove(key)); + } + + fn len(&self) -> usize { + self.workspaces.len() + } + + fn get_current(&self) -> impl Iterator> { + self.current_indices + .iter() + .map(move |&i| &self.workspaces[i]) + } + + fn get_current_mut(&mut self) -> impl Iterator> { + let current_indices = &self.current_indices; + + self.workspaces + .iter_mut() + .enumerate() + .filter(move |(i, _)| current_indices.contains(i)) + .map(|(_, w)| w) + } + + fn iter_current_master(&self) -> impl Iterator { + let current_indices = &self.current_indices; + + self.workspaces + .iter() + .enumerate() + .filter(move |(i, _)| current_indices.contains(i)) + .map(|(_, w)| w) + .flat_map(|w| w.master.iter()) + } + + fn iter_current_aux(&self) -> impl Iterator { + let current_indices = &self.current_indices; + + self.workspaces + .iter() + .enumerate() + .filter(move |(i, _)| current_indices.contains(i)) + .map(|(_, w)| w) + .flat_map(|w| w.aux.iter()) + } + + fn iter_mut_current_master(&mut self) -> impl Iterator { + let current_indices = &self.current_indices; + + self.workspaces + .iter_mut() + .enumerate() + .filter(move |(i, _)| current_indices.contains(i)) + .map(|(_, w)| w) + .flat_map(|w| w.master.iter_mut()) + } + + fn iter_mut_current_aux(&mut self) -> impl Iterator { + let current_indices = &self.current_indices; + + self.workspaces + .iter_mut() + .enumerate() + .filter(move |(i, _)| current_indices.contains(i)) + .map(|(_, w)| w) + .flat_map(|w| w.aux.iter_mut()) + } + + fn iter(&self) -> impl Iterator> { + self.workspaces.iter() + } + + fn iter_mut(&mut self) -> impl Iterator> { + self.workspaces.iter_mut() + } + + fn select_workspace(&mut self, idx: usize) { + let len = self.len(); + + self.previous_indices = Some(std::mem::replace( + &mut self.current_indices, + vec![idx % len], + )); + } + + fn toggle_additional_workspace(&mut self, idx: usize) { + let idx = idx % self.len(); + + if self.current_indices.contains(&idx) { + self.current_indices.retain(|&i| i != idx); + } else { + self.current_indices.push(idx); + } + } + + fn select_workspaces(&mut self, idx: I) + where + Vec: From, + { + self.previous_indices = + Some(std::mem::replace(&mut self.current_indices, idx.into())); + } + + fn select_previous_workspaces(&mut self) { + if let Some(previous_indices) = &mut self.previous_indices { + std::mem::swap(previous_indices, &mut self.current_indices); + } + } + + /// Rotate n times left + fn rotate_left(&mut self, n: usize) { + let len = self.len(); + + let rotate_index = |i| -> usize { + let a = n % len; + let b = i & len; + + ((b + len) - a) % len + }; + + self.select_workspaces( + self.current_indices + .iter() + .map(rotate_index) + .collect::>(), + ); + } + + /// Rotate n times left + fn rotate_right(&mut self, n: usize) { + let len = self.len(); + + let rotate_index = |i| -> usize { + let a = n % len; + let b = i & len; + + ((b + len) + a) % len + }; + + self.select_workspaces( + self.current_indices + .iter() + .map(rotate_index) + .collect::>(), + ); + } +} + +impl ClientManager +where + T: Hash + Eq + Copy, +{ + pub fn new() -> Self { + Self::default() + } + + pub fn with_gap(self, gap: i32) -> Self { + Self { gap, ..self } + } + + pub fn with_border(self, border_size: i32) -> Self { + Self { + border_size, + ..self + } + } + + pub fn with_screen_size(self, screen_size: Size) -> Self { + Self { + screen_size, + ..self + } + } + + pub fn with_workspaces(self, num: usize) -> Self { + Self { + workspaces: WorkspaceStore::new(num), + ..self + } + } + + pub fn new_client(&mut self, client: Client) { + let entry = self.store.insert(Entry::Tiled(client)); + + match entry { + Entry::Tiled(client) => { + self.workspaces + .get_current_mut() + .next() + .unwrap() + .push(client.window_id()); + self.tile_clients() + } + _ => {} + } + } + + pub fn remove_client(&mut self, key: &T) { + if let Some(id) = self.focused { + if id == *key { + self.focused = None; + } + } + + match self.store.remove(key) { + // if the window was tiled, remove it from all workspaces and retile all clients + Entry::Tiled(_) => { + self.workspaces.remove(key); + self.tile_clients(); + } + _ => {} + }; + } + + pub fn tile_clients(&mut self) { + let gap = self.gap; + let border = self.border_size; + + let (width, height) = { + let dimensions = self.screen_size.dimensions(); + (dimensions.0 - gap * 2, dimensions.1 - gap * 2) + }; + + let len_master = self.workspaces.iter_current_master().count(); + let len_aux = self.workspaces.iter_current_aux().count(); + + let width_master = match len_aux { + 0 => width, + _ => width * (self.master_size / 2.0) as i32, + }; + let width_aux = width - width_master; + + let height_master = match len_master { + 0 | 1 => height, + n => height / n as i32, + }; + let height_aux = match len_aux { + 0 | 1 => height, + n => height / n as i32, + }; + + for (i, id) in self.workspaces.iter_mut_current_master().enumerate() { + let size = ( + width_master - gap * 2 - border * 2, + height_master - gap * 2 - border * 2, + ); + + let position = (gap * 2, height_master * i as i32 + gap * 2); + + if let Some(client) = + Option::<&mut Client>::from(self.store.get_mut(id)) + { + if *client.position() != position || *client.size() != size { + *client.position_mut() = position; + *client.size_mut() = size; + + self.invalidated.insert(*id); + } + } + } + + for (i, id) in self.workspaces.iter_mut_current_aux().enumerate() { + let size = ( + width_aux - gap * 2 - border * 2, + height_aux - gap * 2 - border * 2, + ); + + let position = + (width_master + gap * 2, height_aux * i as i32 + gap * 2); + + if let Some(client) = + Option::<&mut Client>::from(self.store.get_mut(id)) + { + if *client.position() != position || *client.size() != size { + *client.position_mut() = position; + *client.size_mut() = size; + + self.invalidated.insert(*id); + } + } + } + } +} diff --git a/src/clients2.rs b/src/clients2.rs index c69b2f6..a47925b 100644 --- a/src/clients2.rs +++ b/src/clients2.rs @@ -11,7 +11,7 @@ pub struct Client { } #[derive(Debug, PartialEq, Eq)] -enum Entry { +pub enum Entry { Tiled(T), Floating(T), Transient(T), @@ -22,7 +22,7 @@ enum Entry { type ClientSet = indexmap::IndexMap>; //type ClientSet = std::collections::HashMap>; -struct ClientStore +pub struct ClientStore where T: Hash + Eq, { @@ -89,6 +89,26 @@ impl Client { pub fn window_id_ref(&self) -> &T { &self.window_id } + + /// Get a mutable reference to the client's size. + pub fn size_mut(&mut self) -> &mut (i32, i32) { + &mut self.size + } + + /// Get a mutable reference to the client's position. + pub fn position_mut(&mut self) -> &mut (i32, i32) { + &mut self.position + } + + /// Get a reference to the client's size. + pub fn size(&self) -> &(i32, i32) { + &self.size + } + + /// Get a reference to the client's position. + pub fn position(&self) -> &(i32, i32) { + &self.position + } } impl Client @@ -146,40 +166,40 @@ impl From>> for Entry { } impl Entry { - fn unwrap(self) -> T { + pub fn unwrap(self) -> T { Option::::from(self).unwrap() } - fn unwrap_ref(&self) -> &T { + pub fn unwrap_ref(&self) -> &T { Option::<&T>::from(self).unwrap() } - fn unwrap_mut(&mut self) -> &mut T { + pub fn unwrap_mut(&mut self) -> &mut T { Option::<&mut T>::from(self).unwrap() } - fn is_floating(&self) -> bool { + pub fn is_floating(&self) -> bool { match self { Self::Floating(_) => true, _ => false, } } - fn is_tiled(&self) -> bool { + pub fn is_tiled(&self) -> bool { match self { Self::Tiled(_) => true, _ => false, } } - fn is_transient(&self) -> bool { + pub fn is_transient(&self) -> bool { match self { Self::Transient(_) => true, _ => false, } } - fn is_fullscreen(&self) -> bool { + pub fn is_fullscreen(&self) -> bool { match self { Self::Fullscreen(_) => true, _ => false, @@ -205,11 +225,11 @@ impl ClientStore where T: Hash + Eq + Copy, { - fn new() -> Self { + pub fn new() -> Self { Self::default() } - fn insert(&mut self, entry: Entry>) -> Entry<&Client> { + pub fn insert(&mut self, entry: Entry>) -> Entry<&Client> { if let Some(key) = Option::<&Client>::from(&entry).map(|c| c.window_id()) { @@ -235,7 +255,7 @@ where } } - fn remove(&mut self, key: &T) -> Entry> { + pub fn remove(&mut self, key: &T) -> Entry> { if let Some(client) = self.tiled_clients.remove(key) { Entry::Tiled(client) } else if let Some(client) = self.floating_clients.remove(key) { @@ -249,7 +269,7 @@ where } } - fn get(&self, key: &T) -> Entry<&Client> { + pub fn get(&self, key: &T) -> Entry<&Client> { if let Some(client) = self.tiled_clients.get(key) { Entry::Tiled(client) } else if let Some(client) = self.floating_clients.get(key) { @@ -263,7 +283,7 @@ where } } - fn get_mut(&mut self, key: &T) -> Entry<&mut Client> { + pub fn get_mut(&mut self, key: &T) -> Entry<&mut Client> { if let Some(client) = self.tiled_clients.get_mut(key) { Entry::Tiled(client) } else if let Some(client) = self.floating_clients.get_mut(key) { @@ -277,46 +297,48 @@ where } } - fn contains(&self, key: &T) -> bool { + pub fn contains(&self, key: &T) -> bool { self.tiled_clients.contains_key(key) || self.floating_clients.contains_key(key) || self.transient_clients.contains_key(key) || self.fullscreen_clients.contains_key(key) } - fn iter_tiled(&self) -> impl Iterator)> { + pub fn iter_tiled(&self) -> impl Iterator)> { self.tiled_clients.iter() } - fn iter_mut_tiled(&mut self) -> impl Iterator)> { + pub fn iter_mut_tiled( + &mut self, + ) -> impl Iterator)> { self.tiled_clients.iter_mut() } - fn iter_floating(&self) -> impl Iterator)> { + pub fn iter_floating(&self) -> impl Iterator)> { self.floating_clients.iter() } - fn iter_mut_floating( + pub fn iter_mut_floating( &mut self, ) -> impl Iterator)> { self.floating_clients.iter_mut() } - fn iter_transient(&self) -> impl Iterator)> { + pub fn iter_transient(&self) -> impl Iterator)> { self.transient_clients.iter() } - fn iter_mut_transient( + pub fn iter_mut_transient( &mut self, ) -> impl Iterator)> { self.transient_clients.iter_mut() } - fn iter_fullscreen(&self) -> impl Iterator)> { + pub fn iter_fullscreen(&self) -> impl Iterator)> { self.fullscreen_clients.iter() } - fn iter_mut_fullscreen( + pub fn iter_mut_fullscreen( &mut self, ) -> impl Iterator)> { self.fullscreen_clients.iter_mut() diff --git a/src/main.rs b/src/main.rs index 0a391d7..63d27bf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use log4rs::{ }; use state::WMConfig; +mod client_logic; mod clients; mod clients2; mod state;