wzrd

An ICCCM & EWMH compliant X11 reparenting, dynamic window manager, written in Rust
git clone git://git.deurzen.net/wzrd
Log | Files | Refs | LICENSE

commit ccbb1679d69a87ee0f104d3909acb3eacd20c970
parent bd2f9c3d2825ef05d2dac567e1c5b9f2cd74a4c9
Author: deurzen <m.deurzen@tum.de>
Date:   Sun, 14 Mar 2021 11:22:33 +0100

updates zone arrangement handling

Diffstat:
Msrc/core/client.rs | 29+++++++++++++++++++++++++----
Msrc/core/common.rs | 148++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/core/model.rs | 166+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/core/workspace.rs | 87++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/core/zone.rs | 231++++++++++++++++++++++++++++++++++++-------------------------------------------
5 files changed, 409 insertions(+), 252 deletions(-)

diff --git a/src/core/client.rs b/src/core/client.rs @@ -1,8 +1,9 @@ use crate::common::Ident; use crate::common::Identify; -use crate::common::NO_EXTENTS; -use crate::zone::Decoration; -use crate::zone::Frame; +use crate::common::Decoration; +use crate::common::Frame; +use crate::zone::ZoneId; + use winsys::common::Extents; use winsys::common::Hex32; use winsys::common::Pid; @@ -15,6 +16,7 @@ use winsys::common::WindowType; use std::time::SystemTime; pub struct Client { + zone: ZoneId, window: Window, frame: Window, name: String, @@ -74,6 +76,7 @@ impl Client { ppid: Option<Pid>, ) -> Self { Self { + zone: 0, window, frame, name, @@ -117,6 +120,19 @@ impl Client { } #[inline] + pub fn zone(&self) -> ZoneId { + self.zone + } + + #[inline] + pub fn set_zone( + &mut self, + zone: ZoneId, + ) { + self.zone = zone; + } + + #[inline] pub fn windows(&self) -> (Window, Window) { (self.window, self.frame) } @@ -299,7 +315,12 @@ impl Client { #[inline] pub fn frame_extents(&self) -> Extents { - NO_EXTENTS + self.decoration + Extents { + left: 0, + right: 0, + top: 0, + bottom: 0, + } + self.decoration } #[inline] diff --git a/src/core/common.rs b/src/core/common.rs @@ -2,9 +2,10 @@ use winsys::common::Dim; use winsys::common::Extents; use winsys::common::Pos; use winsys::common::Region; +use winsys::common::Padding; use winsys::common::Window; -pub type Color = u32; +use std::ops::Add; #[macro_export] macro_rules! WM_NAME ( @@ -15,22 +16,145 @@ pub const MIN_WINDOW_DIM: Dim = Dim { w: 75, h: 50, }; -pub const BORDER_SIZE: u32 = 3; -pub const FREE_EXTENTS: Extents = Extents { - left: 3, - right: 1, - top: 1, - bottom: 1, +pub const NO_DECORATION: Decoration = Decoration { + border: None, + frame: None, }; -pub const NO_EXTENTS: Extents = Extents { - left: 0, - right: 0, - top: 0, - bottom: 0, +pub const FREE_DECORATION: Decoration = Decoration { + border: None, + frame: Some(Frame { + extents: Extents { + left: 3, + right: 1, + top: 1, + bottom: 1, + }, + colors: ColorScheme::DEFAULT, + }), }; +pub type Color = u32; + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct ColorScheme { + pub regular: Color, + pub focused: Color, + pub urgent: Color, + pub rdisowned: Color, + pub fdisowned: Color, + pub rsticky: Color, + pub fsticky: Color, +} + +impl ColorScheme { + const DEFAULT: Self = Self { + regular: 0x333333, + focused: 0xe78a53, + urgent: 0xfbcb97, + rdisowned: 0x999999, + fdisowned: 0xc1c1c1, + rsticky: 0x444444, + fsticky: 0x5f8787, + }; +} + +impl Default for ColorScheme { + fn default() -> Self { + Self::DEFAULT + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct Border { + pub width: u32, + pub colors: ColorScheme, +} + +impl Add<Border> for Padding { + type Output = Self; + + fn add( + self, + border: Border, + ) -> Self::Output { + Self::Output { + left: self.left + 1, + right: self.right + 1, + top: self.top + 1, + bottom: self.bottom + 1, + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct Frame { + pub extents: Extents, + pub colors: ColorScheme, +} + +impl Add<Frame> for Padding { + type Output = Self; + + fn add( + self, + frame: Frame, + ) -> Self::Output { + Self::Output { + left: self.left + frame.extents.left, + right: self.right + frame.extents.right, + top: self.top + frame.extents.top, + bottom: self.bottom + frame.extents.bottom, + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct Decoration { + pub border: Option<Border>, + pub frame: Option<Frame>, +} + +impl Default for Decoration { + fn default() -> Self { + Self { + border: None, + frame: None, + } + } +} + +impl Decoration { + pub fn extents(&self) -> Extents { + Extents { + left: 0, + right: 0, + top: 0, + bottom: 0, + } + *self + } +} + +impl Add<Decoration> for Padding { + type Output = Self; + + fn add( + mut self, + decoration: Decoration, + ) -> Self::Output { + if let Some(border) = decoration.border { + self = self + border; + } + + if let Some(frame) = decoration.frame { + self = self + frame; + } + + self + } +} + pub type Ident = u32; pub type Index = usize; diff --git a/src/core/model.rs b/src/core/model.rs @@ -4,8 +4,11 @@ use crate::client::Client; use crate::common::Change; use crate::common::Direction; use crate::common::Index; -use crate::common::FREE_EXTENTS; +use crate::common::FREE_DECORATION; +use crate::common::NO_DECORATION; use crate::common::MIN_WINDOW_DIM; +use crate::common::Decoration; +use crate::common::Frame; use crate::consume::get_spawner_pid; use crate::cycle::Cycle; use crate::cycle::InsertPos; @@ -19,13 +22,12 @@ use crate::stack::StackManager; use crate::workspace::Buffer; use crate::workspace::BufferKind; use crate::workspace::Workspace; -use crate::zone::Decoration; -use crate::zone::Frame; use crate::zone::Layout; use crate::zone::LayoutKind; use crate::zone::Placement; use crate::zone::PlacementKind; use crate::zone::PlacementMethod; +use crate::zone::Zone; use crate::zone::ZoneContent; use crate::zone::ZoneId; use crate::zone::ZoneManager; @@ -331,7 +333,10 @@ impl<'a> Model<'a> { // TODO: zone change let region = self.active_screen().placeable_region(); - let placements = workspace.arrange(&mut self.zone_manager, &self.client_map, region); + let placements = + workspace.arrange(&mut self.zone_manager, &self.client_map, region, |client| { + !Self::is_applyable(client) + }); let (show, hide): (Vec<&Placement>, Vec<&Placement>) = placements .iter() @@ -480,22 +485,18 @@ impl<'a> Model<'a> { } let mut client_list: Vec<&Client> = self.client_map.values().collect::<Vec<&Client>>(); - client_list.sort_by_key(|&a| a.managed_since()); let client_list: Vec<Window> = client_list.iter().map(|client| client.window()).collect(); - self.conn.update_client_list(&client_list); - let mut client_list_stacking = client_list; - let stack_windows: Vec<Window> = stack .iter() .map(|&window| self.window(window).unwrap()) .collect(); + let mut client_list_stacking = client_list; client_list_stacking.retain(|&window| !stack_windows.contains(&window)); - client_list_stacking = client_list_stacking .iter() .chain(stack_windows.iter()) @@ -505,6 +506,24 @@ impl<'a> Model<'a> { self.conn.update_client_list_stacking(&client_list_stacking); } + fn zone( + &self, + window: Window, + ) -> Option<&Zone> { + self.zone_manager + .client_id_checked(window) + .and_then(|id| self.zone_manager.zone_checked(id)) + } + + fn zone_mut( + &mut self, + window: Window, + ) -> Option<&mut Zone> { + self.zone_manager + .client_id_checked(window) + .and_then(move |id| self.zone_manager.zone_checked_mut(id)) + } + fn window( &self, window: Window, @@ -682,11 +701,11 @@ impl<'a> Model<'a> { geometry = if size_hints.is_some() { geometry .with_size_hints(&size_hints) - .with_extents(&FREE_EXTENTS) + .with_extents(&FREE_DECORATION.extents()) } else { geometry .with_minimum_dim(&MIN_WINDOW_DIM) - .with_extents(&FREE_EXTENTS) + .with_extents(&FREE_DECORATION.extents()) }; let parent = self.conn.get_icccm_window_transient_for(window); @@ -769,9 +788,10 @@ impl<'a> Model<'a> { client.set_context(context); client.set_workspace(workspace); + let extents = FREE_DECORATION.extents(); self.conn.reparent_window(window, frame, Pos { - x: FREE_EXTENTS.left as i32, - y: FREE_EXTENTS.top as i32, + x: extents.left as i32, + y: extents.top as i32, }); self.conn @@ -786,6 +806,8 @@ impl<'a> Model<'a> { .zone_manager .new_zone(parent_zone, ZoneContent::Client(window)); + client.set_zone(id); + let current_workspace = self.workspaces.get_mut(workspace).unwrap(); current_workspace.add_client(window, &InsertPos::Back); current_workspace.add_zone(id, &InsertPos::AfterActive); @@ -943,41 +965,32 @@ impl<'a> Model<'a> { } } - fn is_applyable( - client: &Client, - // TODO: zone change - // method: PlacementMethod, - ) -> bool { - // TODO: zone change - // method == PlacementMethod::Free - !client.is_floating() && !client.is_disowned() && client.is_managed() + fn is_applyable(client: &Client) -> bool { + !client.is_floating() + && !client.is_disowned() + && client.is_managed() + && (!client.is_fullscreen() || client.is_in_window()) } fn is_free( &self, client: &Client, ) -> bool { - (!client.is_fullscreen() || client.is_in_window()) - && (client.is_floating() || client.is_disowned() || !client.is_managed()) - // TODO: zone change - // || self - // .workspaces - // .get(client.workspace()) - // .unwrap() - // .layout_config() - // .method - // == PlacementMethod::Free) + client.is_floating() && (!client.is_fullscreen() || client.is_in_window()) || { + let id = self.zone_manager.client_id(client.window()); + let zone = self.zone_manager.zone(id); + + zone.method() == PlacementMethod::Free + } } fn is_focusable( &self, window: Window, ) -> bool { - if let Some(client) = self.client(window) { + self.client(window).map_or(false, |client| { !client.is_disowned() && !client.is_iconified() - } else { - false - } + }) } fn remove_window( @@ -1115,7 +1128,6 @@ impl<'a> Model<'a> { self.conn.place_window(window, inner_region); - // TODO: zone change self.conn.place_window(frame, match method { PlacementMethod::Free => &client.free_region(), PlacementMethod::Tile => &client.tile_region(), @@ -1387,9 +1399,7 @@ impl<'a> Model<'a> { client.set_free_region(&active_region); }); - let workspace = self.workspace_mut(workspace_index); - // TODO: zone change - // workspace.set_layout(LayoutKind::Float); + self.set_layout(LayoutKind::Float); self.apply_layout(workspace_index, false); } @@ -1659,7 +1669,6 @@ impl<'a> Model<'a> { pub fn set_layout( &mut self, - // TODO: zone change kind: LayoutKind, ) { let workspace_index = self.active_workspace(); @@ -1669,35 +1678,45 @@ impl<'a> Model<'a> { let cycle = self.zone_manager.nearest_cycle(id); let cycle = self.zone_manager.zone_mut(cycle); + info!( + "activating layout {:?} on workspace {}", + kind, workspace_index + ); + cycle.set_kind(kind); + self.apply_layout(workspace_index, true); } - - info!( - "activating layout {:?} on workspace {}", - kind, workspace_index - ); - - self.apply_layout(workspace_index, true); } pub fn toggle_layout(&mut self) { let workspace_index = self.active_workspace(); let workspace = self.workspace_mut(workspace_index); - workspace.toggle_layout(); - self.apply_layout(workspace_index, true); + if let Some(id) = workspace.active_zone() { + let cycle = self.zone_manager.nearest_cycle(id); + let cycle = self.zone_manager.zone_mut(cycle); + let prev_kind = cycle.get_prev_kind(); + + info!( + "activating layout {:?} on workspace {}", + prev_kind, workspace_index + ); + + cycle.set_kind(prev_kind); + self.apply_layout(workspace_index, true); + } } pub fn toggle_in_window_focus(&mut self) { if let Some(focus) = self.focus { if let Some(client) = self.client_mut(focus) { - let is_in_window = client.is_in_window(); - client.set_in_window(!is_in_window); + let must_in_window = !client.is_in_window(); + client.set_in_window(must_in_window); - if is_in_window { - self.fullscreen(focus); - } else { + if must_in_window { self.unfullscreen(focus); + } else { + self.fullscreen(focus); } } } @@ -1706,8 +1725,8 @@ impl<'a> Model<'a> { pub fn toggle_invincible_focus(&mut self) { if let Some(focus) = self.focus { if let Some(client) = self.client_mut(focus) { - let is_invincible = client.is_invincible(); - client.set_invincible(!is_invincible); + let must_invincible = !client.is_invincible(); + client.set_invincible(must_invincible); } } } @@ -1715,8 +1734,8 @@ impl<'a> Model<'a> { pub fn toggle_producing_focus(&mut self) { if let Some(focus) = self.focus { if let Some(client) = self.client_mut(focus) { - let is_producing = client.is_producing(); - client.set_producing(!is_producing); + let must_producing = !client.is_producing(); + client.set_producing(must_producing); } } } @@ -1734,6 +1753,7 @@ impl<'a> Model<'a> { if let Some(client) = self.client(window) { let active_workspace_index = client.workspace(); let workspace_index = client.workspace(); + let id = self.zone_manager.client_id(client.window()); let client = self.client_mut(window).unwrap(); let must_float = !client.is_floating(); @@ -1827,10 +1847,12 @@ impl<'a> Model<'a> { let workspace = self.workspace_mut(client_workspace_index); workspace.focus_client(window); - // TODO: zone change - // if workspace.layout_config().persistent { - // self.apply_layout(client_workspace_index, false); - // } + let id = self.zone_manager.client_id(window); + if let Some(config) = self.zone_manager.cycle_config(id) { + if config.persistent { + self.apply_layout(client_workspace_index, false); + } + } if self.conn.get_focused_window() != window { self.conn.focus_window(window); @@ -1889,10 +1911,15 @@ impl<'a> Model<'a> { window: Window, ) { if let Some(client) = self.client(window) { - if client.is_fullscreen() { - self.unfullscreen(window); - } else { + let must_fullscreen = !client.is_fullscreen(); + let id = self.zone_manager.client_id(client.window()); + + let must_float = client.is_floating() || client.is_disowned(); + + if must_fullscreen { self.fullscreen(window); + } else { + self.unfullscreen(window); } } } @@ -3363,14 +3390,9 @@ impl<'a> Model<'a> { client.frame_extents() } else { if self.conn.must_manage_window(window) { - FREE_EXTENTS + FREE_DECORATION.extents() } else { - Extents { - left: 0, - right: 0, - top: 0, - bottom: 0, - } + NO_DECORATION.extents() } }, ); diff --git a/src/core/workspace.rs b/src/core/workspace.rs @@ -4,10 +4,15 @@ use crate::common::Direction; use crate::common::Ident; use crate::common::Identify; use crate::common::Index; +use crate::common::Decoration; +use crate::common::Frame; +use crate::common::Border; +use crate::common::FREE_DECORATION; +use crate::common::NO_DECORATION; use crate::cycle::Cycle; use crate::cycle::InsertPos; use crate::cycle::Selector; -use crate::zone::Decoration; +use crate::zone::LayoutKind; use crate::zone::Placement; use crate::zone::PlacementKind; use crate::zone::PlacementMethod; @@ -312,34 +317,56 @@ impl Workspace { self.clients.remove_for(&Selector::AtActive) } - pub fn arrange( + pub fn arrange<F>( &self, zone_manager: &mut ZoneManager, client_map: &HashMap<Window, Client>, screen_region: Region, - ) -> Vec<Placement> { + filter: F, + ) -> Vec<Placement> + where + F: Fn(&Client) -> bool, + { if !self.clients.is_empty() { let zone = zone_manager.zone_mut(self.root_zone); zone.set_region(screen_region); - let mut placements = zone_manager.arrange(self.root_zone); - - self.clients.iter().for_each(|&window| { - let client = client_map.get(&window).unwrap(); - - if client.is_fullscreen() { - placements.push(Placement { - method: PlacementMethod::Tile, - kind: PlacementKind::Client(window), - zone: zone_manager.client_id(window), - region: Some(screen_region), - decoration: Decoration { - border: None, - frame: None, - }, - }); - } - }); + let (to_ignore_ids, to_ignore_clients): (Vec<_>, Vec<_>) = self + .clients + .iter() + .map(|window| client_map.get(window).unwrap()) + .filter(|&client| filter(client)) + .map(|client| (client.zone(), client)) + .unzip(); + + let mut placements = zone_manager.arrange(self.root_zone, &to_ignore_ids); + placements.extend(to_ignore_clients + .iter() + .map(|&client| { + let (method, region, decoration) = + if client.is_fullscreen() && !client.is_in_window() { + ( + PlacementMethod::Tile, + screen_region, + NO_DECORATION, + ) + } else { + ( + PlacementMethod::Free, + *client.free_region(), + FREE_DECORATION, + ) + }; + + Placement { + method: method, + kind: PlacementKind::Client(client.window()), + zone: client.zone(), + region: Some(region), + decoration: decoration, + } + }) + ); placements } else { @@ -347,24 +374,6 @@ impl Workspace { } } - pub fn set_layout( - &mut self, - // kind: LayoutKind, - ) { - // TODO: zone change - } - - pub fn toggle_layout(&mut self) { - // TODO: zone change - } - - pub fn cycle_layout( - &mut self, - dir: Direction, - ) { - // TODO: zone change - } - pub fn cycle_focus( &mut self, dir: Direction, diff --git a/src/core/zone.rs b/src/core/zone.rs @@ -1,5 +1,8 @@ use crate::common::Ident; use crate::common::Identify; +use crate::common::Decoration; +use crate::common::Frame; +use crate::common::Border; use crate::cycle::Cycle; use crate::cycle::InsertPos; @@ -16,13 +19,11 @@ use strum_macros::EnumIter; use strum_macros::ToString; use std::collections::HashMap; -use std::ops::Add; use std::string::ToString; use std::sync::atomic; use std::vec::Vec; pub type ZoneId = u32; -type Color = u32; const MAX_MAIN_COUNT: u32 = 15; const MAX_GAP_SIZE: u32 = 300; @@ -39,109 +40,6 @@ fn next_id() -> ZoneId { } #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct ColorScheme { - pub regular: Color, - pub focused: Color, - pub urgent: Color, - pub rdisowned: Color, - pub fdisowned: Color, - pub rsticky: Color, - pub fsticky: Color, -} - -impl Default for ColorScheme { - fn default() -> Self { - Self { - regular: 0x333333, - focused: 0xe78a53, - urgent: 0xfbcb97, - rdisowned: 0x999999, - fdisowned: 0xc1c1c1, - rsticky: 0x444444, - fsticky: 0x5f8787, - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct Border { - pub width: u32, - pub colors: ColorScheme, -} - -impl Add<Border> for Padding { - type Output = Self; - - fn add( - self, - border: Border, - ) -> Self::Output { - Self::Output { - left: self.left + 1, - right: self.right + 1, - top: self.top + 1, - bottom: self.bottom + 1, - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct Frame { - pub extents: Extents, - pub colors: ColorScheme, -} - -impl Add<Frame> for Padding { - type Output = Self; - - fn add( - self, - frame: Frame, - ) -> Self::Output { - Self::Output { - left: self.left + frame.extents.left, - right: self.right + frame.extents.right, - top: self.top + frame.extents.top, - bottom: self.bottom + frame.extents.bottom, - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct Decoration { - pub border: Option<Border>, - pub frame: Option<Frame>, -} - -impl Default for Decoration { - fn default() -> Self { - Self { - border: None, - frame: None, - } - } -} - -impl Add<Decoration> for Padding { - type Output = Self; - - fn add( - mut self, - decoration: Decoration, - ) -> Self::Output { - if let Some(border) = decoration.border { - self = self + border; - } - - if let Some(frame) = decoration.frame { - self = self + frame; - } - - self - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] enum Disposition { Unchanged, Changed(Region, Decoration), @@ -437,7 +335,6 @@ impl LayoutKind { fn func(&self) -> LayoutFn { match *self { - // TODO LayoutKind::Float => { |_, _, active_map| vec![(Disposition::Unchanged, true); active_map.len()] }, @@ -624,14 +521,14 @@ impl LayoutKind { #[non_exhaustive] #[derive(Debug, PartialEq, Clone, Copy)] -struct LayoutConfig { - method: PlacementMethod, - decoration: Decoration, - root_only: bool, - gap: bool, - persistent: bool, - single: bool, - wraps: bool, +pub struct LayoutConfig { + pub method: PlacementMethod, + pub decoration: Decoration, + pub root_only: bool, + pub gap: bool, + pub persistent: bool, + pub single: bool, + pub wraps: bool, } impl Default for LayoutConfig { @@ -778,8 +675,6 @@ impl Zone { parent: Option<ZoneId>, content: ZoneContent, region: Region, - is_active: bool, - is_visible: bool, ) -> (ZoneId, Self) { let id = next_id(); @@ -793,23 +688,52 @@ impl Zone { border: None, frame: None, }, - is_active, - is_visible, + is_active: true, + is_visible: true, }) } + pub fn set_content( + &mut self, + content: ZoneContent, + ) { + self.content = content; + } + pub fn set_kind( &mut self, kind: LayoutKind, ) { match self.content { ZoneContent::Layout(ref mut layout, _) => { + layout.prev_kind = layout.kind; layout.kind = kind; }, _ => {}, } } + pub fn get_prev_kind(&self) -> LayoutKind { + match &self.content { + ZoneContent::Layout(layout, _) => layout.prev_kind, + _ => panic!("attempting to obtain layout kind from non-layout"), + } + } + + pub fn get_kind(&self) -> LayoutKind { + match &self.content { + ZoneContent::Layout(layout, _) => layout.kind, + _ => panic!("attempting to obtain layout kind from non-layout"), + } + } + + pub fn set_active( + &mut self, + is_active: bool, + ) { + self.is_active = is_active; + } + pub fn set_region( &mut self, region: Region, @@ -817,6 +741,13 @@ impl Zone { self.region = region; } + pub fn config(&self) -> Option<LayoutConfig> { + match self.content { + ZoneContent::Layout(ref layout, _) => Some(layout.kind.config()), + _ => None, + } + } + pub fn method(&self) -> PlacementMethod { self.method } @@ -848,11 +779,14 @@ impl ZoneManager { parent: Option<ZoneId>, content: ZoneContent, ) -> ZoneId { - let (id, zone) = Zone::new(parent, content, Region::new(0, 0, 0, 0), true, true); + let (id, zone) = Zone::new(parent, content, Region::new(0, 0, 0, 0)); - if let ZoneContent::Client(window) = &zone.content { - self.client_zones.insert(*window, id); - } + match &zone.content { + ZoneContent::Client(window) => { + self.client_zones.insert(*window, id); + }, + _ => {}, + }; let parent = parent.and_then(|p| self.zone_map.get_mut(&p)); @@ -869,6 +803,13 @@ impl ZoneManager { id } + pub fn zone_checked( + &self, + id: ZoneId, + ) -> Option<&Zone> { + self.zone_map.get(&id) + } + pub fn zone( &self, id: ZoneId, @@ -876,6 +817,13 @@ impl ZoneManager { self.zone_map.get(&id).unwrap() } + pub fn zone_checked_mut( + &mut self, + id: ZoneId, + ) -> Option<&mut Zone> { + self.zone_map.get_mut(&id) + } + pub fn zone_mut( &mut self, id: ZoneId, @@ -890,6 +838,13 @@ impl ZoneManager { self.client_zones.remove(&id); } + pub fn client_id_checked( + &self, + client: Window, + ) -> Option<ZoneId> { + self.client_zones.get(&client).map(|&id| id) + } + pub fn client_id( &self, client: Window, @@ -897,6 +852,16 @@ impl ZoneManager { *self.client_zones.get(&client).unwrap() } + pub fn cycle_config( + &self, + id: ZoneId, + ) -> Option<LayoutConfig> { + let cycle = self.nearest_cycle(id); + let zone = self.zone(cycle); + + zone.config() + } + pub fn nearest_cycle( &self, id: ZoneId, @@ -965,6 +930,7 @@ impl ZoneManager { pub fn arrange( &mut self, zone: ZoneId, + to_ignore: &Vec<ZoneId>, ) -> Vec<Placement> { let cycle = self.nearest_cycle(zone); let zone = self.zone_map.get(&cycle).unwrap(); @@ -977,7 +943,7 @@ impl ZoneManager { _ => panic!("attempting to derive method from non-cycle"), }; - self.arrange_subzones(cycle, region, decoration, method) + self.arrange_subzones(cycle, region, decoration, method, to_ignore) } fn arrange_subzones( @@ -986,6 +952,7 @@ impl ZoneManager { region: Region, decoration: Decoration, method: PlacementMethod, + to_ignore: &Vec<ZoneId>, ) -> Vec<Placement> { let id = zone; let zone = self.zone_map.get(&id).unwrap(); @@ -1044,7 +1011,9 @@ impl ZoneManager { zone_changes.push((id, ZoneChange::Method(method))); }); - placements.extend(self.arrange_subzones(id, region, decoration, method)); + placements.extend( + self.arrange_subzones(id, region, decoration, method, to_ignore), + ); placements }, } @@ -1059,6 +1028,12 @@ impl ZoneManager { decoration, }]; + let zones: Vec<ZoneId> = zones + .iter() + .filter(|&id| !to_ignore.contains(id)) + .map(|&id| id) + .collect(); + let (method, application) = layout.apply( &region, zones @@ -1097,7 +1072,13 @@ impl ZoneManager { ); subplacements.iter().for_each(|(id, region, decoration)| { - placements.extend(self.arrange_subzones(*id, *region, *decoration, method)); + placements.extend(self.arrange_subzones( + *id, + *region, + *decoration, + method, + to_ignore, + )); }); placements