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 7c99b99a80114faf46f4a93b5c3e6cd1099d8e3f
parent 5cd644c6f846c1440efd3dd43822e4dacb440768
Author: deurzen <m.deurzen@tum.de>
Date:   Fri, 19 Mar 2021 02:40:02 +0100

adds initial zone creation and deletion bindings

Diffstat:
Msrc/core/main.rs | 5+++++
Msrc/core/model.rs | 71++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/core/workspace.rs | 9++++++++-
Msrc/core/zone.rs | 386++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
4 files changed, 313 insertions(+), 158 deletions(-)

diff --git a/src/core/main.rs b/src/core/main.rs @@ -183,6 +183,11 @@ fn init_bindings() -> (MouseBindings, KeyBindings) { "1-S-semicolon" => do_internal!(rotate_clients, Direction::Forward), "1-S-comma" => do_internal!(rotate_clients, Direction::Backward), + // zone creators + "1-C-Return" => do_internal!(create_layout_zone), + "1-C-S-Return" => do_internal!(create_tab_zone), + "1-C-C" => do_internal!(delete_zone), + // zone order modifiers "1-C-j" => do_internal!(cycle_zones, Direction::Forward), "1-C-k" => do_internal!(cycle_zones, Direction::Backward), diff --git a/src/core/model.rs b/src/core/model.rs @@ -142,32 +142,10 @@ impl<'a> Model<'a> { ZoneContent::Layout(Layout::new(), Cycle::new(Vec::new(), true)), ); - let subcycle1_id = model.zone_manager.new_zone( - Some(root_id), - ZoneContent::Tab(Cycle::new(Vec::new(), true)), - ); - - let subcycle2_id = model.zone_manager.new_zone( - Some(root_id), - ZoneContent::Layout(Layout::new(), Cycle::new(Vec::new(), true)), - ); - model .workspaces .push_back(Workspace::new(workspace_name, i as u32, root_id)); - model - .workspaces - .get_mut(i) - .unwrap() - .add_zone(subcycle1_id, &InsertPos::Back); - - model - .workspaces - .get_mut(i) - .unwrap() - .add_zone(subcycle2_id, &InsertPos::Back); - model.zone_manager.zone_mut(root_id).set_region(region); } @@ -358,7 +336,7 @@ impl<'a> Model<'a> { let placements = workspace.arrange(&mut self.zone_manager, &self.client_map, region, |client| { - !Self::is_applyable(client) + !Self::is_applyable(client) || client.is_iconified() }); let (show, hide): (Vec<&Placement>, Vec<&Placement>) = placements @@ -815,7 +793,6 @@ impl<'a> Model<'a> { let current_workspace = self.workspaces.get_mut(workspace).unwrap(); current_workspace.add_client(window, &InsertPos::Back); - current_workspace.add_zone(id, &InsertPos::AfterActive); } if let Some(parent) = parent { @@ -966,6 +943,51 @@ impl<'a> Model<'a> { } } + pub fn create_layout_zone(&mut self) { + let workspace_index = self.active_workspace(); + let workspace = self.workspace(workspace_index); + + let cycle = workspace.active_zone().unwrap(); + let cycle = self.zone_manager.nearest_cycle(cycle); + let id = self.zone_manager.new_zone(Some(cycle), + ZoneContent::Layout(Layout::new(), Cycle::new(Vec::new(), true))); + + let workspace = self.workspace_mut(workspace_index); + workspace.add_zone(id, &InsertPos::Back); + self.apply_layout(workspace_index, true); + } + + pub fn create_tab_zone(&mut self) { + let workspace_index = self.active_workspace(); + let workspace = self.workspace(workspace_index); + + let cycle = workspace.active_zone().unwrap(); + let cycle = self.zone_manager.nearest_cycle(cycle); + let id = self.zone_manager.new_zone(Some(cycle), + ZoneContent::Tab(Cycle::new(Vec::new(), true))); + + let workspace = self.workspace_mut(workspace_index); + workspace.add_zone(id, &InsertPos::Back); + self.apply_layout(workspace_index, true); + } + + pub fn delete_zone(&mut self) { + let workspace_index = self.active_workspace(); + let workspace = self.workspace(workspace_index); + + let cycle = workspace.active_zone().unwrap(); + let cycle = self.zone_manager.nearest_cycle(cycle); + + if cycle == workspace.root_zone() { + return; + } + + self.zone_manager.remove_zone(cycle); + + let workspace = self.workspace_mut(workspace_index); + workspace.remove_zone(cycle); + } + fn is_applyable(client: &Client) -> bool { !client.is_floating() && !client.is_disowned() @@ -1034,7 +1056,6 @@ impl<'a> Model<'a> { self.zone_manager.remove_zone(id); self.workspaces.get_mut(workspace).map(|w| { - w.remove_zone(id); w.remove_client(window); w.remove_icon(window); }); diff --git a/src/core/workspace.rs b/src/core/workspace.rs @@ -345,6 +345,7 @@ impl Workspace { let (to_ignore_ids, to_ignore_clients): (Vec<_>, Vec<_>) = self .clients .iter() + .chain(self.icons.iter()) .map(|window| client_map.get(window).unwrap()) .filter(|&client| ignore_filter(client)) .map(|client| (client.zone(), client)) @@ -361,7 +362,13 @@ impl Workspace { PlacementRegion::NewRegion(screen_region), NO_DECORATION, ) - } else { + } else if client.is_iconified() { + ( + PlacementMethod::Tile, + PlacementRegion::NoRegion, + NO_DECORATION, + ) + }else { ( PlacementMethod::Free, PlacementRegion::FreeRegion, diff --git a/src/core/zone.rs b/src/core/zone.rs @@ -1,3 +1,4 @@ +use crate::common::Border; use crate::common::Decoration; use crate::common::Frame; use crate::common::Ident; @@ -5,7 +6,6 @@ use crate::common::Identify; use crate::common::StateChangeError; use crate::common::FREE_DECORATION; use crate::common::NO_DECORATION; -use crate::common::Border; use crate::cycle::Cycle; use crate::cycle::InsertPos; use crate::cycle::Selector; @@ -155,19 +155,26 @@ impl Default for LayoutData { #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, EnumIter, EnumCount, ToString)] pub enum LayoutKind { /// Free layouts - Float = b'F', - BLFloat = b'L', - SingleFloat = b'Z', - BLSingleFloat = b'Y', + Float = b'f', + BLFloat = b'F', + SingleFloat = b'z', + BLSingleFloat = b'Z', /// Tiled layouts + // Overlapping Center = b';', - Monocle = b'M', - Paper = b'/', - SStack = b'+', - Stack = b'S', - Horz = b'H', - Vert = b'V', + Monocle = b'%', + // Non-overlapping + Paper = b'p', + SPaper = b'P', + Stack = b's', + SStack = b'S', + BStack = b'b', + BSStack = b'B', + Horz = b'h', + SHorz = b'H', + Vert = b'v', + SVert = b'V', } impl LayoutKind { @@ -262,6 +269,27 @@ impl LayoutKind { single: false, wraps: false, }, + LayoutKind::SPaper => LayoutConfig { + method: PlacementMethod::Tile, + decoration: Decoration { + frame: Some(Frame { + extents: Extents { + left: 1, + right: 1, + top: 0, + bottom: 0, + }, + colors: Default::default(), + }), + border: None, + }, + root_only: false, + margin: true, + gap: false, + persistent: true, + single: false, + wraps: false, + }, LayoutKind::Stack => LayoutConfig { method: PlacementMethod::Tile, decoration: Decoration { @@ -304,6 +332,48 @@ impl LayoutKind { single: false, wraps: true, }, + LayoutKind::BStack => LayoutConfig { + method: PlacementMethod::Tile, + decoration: Decoration { + frame: Some(Frame { + extents: Extents { + left: 0, + right: 0, + top: 3, + bottom: 0, + }, + colors: Default::default(), + }), + border: None, + }, + root_only: false, + margin: true, + gap: true, + persistent: false, + single: false, + wraps: true, + }, + LayoutKind::BSStack => LayoutConfig { + method: PlacementMethod::Tile, + decoration: Decoration { + frame: Some(Frame { + extents: Extents { + left: 0, + right: 0, + top: 3, + bottom: 0, + }, + colors: Default::default(), + }), + border: None, + }, + root_only: false, + margin: true, + gap: false, + persistent: false, + single: false, + wraps: true, + }, LayoutKind::Horz => LayoutConfig { method: PlacementMethod::Tile, decoration: Decoration { @@ -325,6 +395,27 @@ impl LayoutKind { single: false, wraps: true, }, + LayoutKind::SHorz => LayoutConfig { + method: PlacementMethod::Tile, + decoration: Decoration { + frame: Some(Frame { + extents: Extents { + left: 0, + right: 0, + top: 3, + bottom: 0, + }, + colors: Default::default(), + }), + border: None, + }, + root_only: false, + margin: true, + gap: false, + persistent: false, + single: false, + wraps: true, + }, LayoutKind::Vert => LayoutConfig { method: PlacementMethod::Tile, decoration: Decoration { @@ -346,6 +437,27 @@ impl LayoutKind { single: false, wraps: true, }, + LayoutKind::SVert => LayoutConfig { + method: PlacementMethod::Tile, + decoration: Decoration { + frame: Some(Frame { + extents: Extents { + left: 0, + right: 0, + top: 3, + bottom: 0, + }, + colors: Default::default(), + }), + border: None, + }, + root_only: false, + margin: true, + gap: false, + persistent: false, + single: false, + wraps: true, + }, #[allow(unreachable_patterns)] _ => unimplemented!("{:?} does not have an associated configuration", self), @@ -365,18 +477,31 @@ impl LayoutKind { }, LayoutKind::Monocle => Default::default(), LayoutKind::Paper => Default::default(), + LayoutKind::SPaper => Default::default(), + LayoutKind::Stack => LayoutData { + main_count: 1u32, + main_factor: 0.50f32, + ..Default::default() + }, LayoutKind::SStack => LayoutData { main_count: 1u32, main_factor: 0.50f32, ..Default::default() }, - LayoutKind::Stack => LayoutData { + LayoutKind::BStack => LayoutData { + main_count: 1u32, + main_factor: 0.50f32, + ..Default::default() + }, + LayoutKind::BSStack => LayoutData { main_count: 1u32, main_factor: 0.50f32, ..Default::default() }, LayoutKind::Horz => Default::default(), + LayoutKind::SHorz => Default::default(), LayoutKind::Vert => Default::default(), + LayoutKind::SVert => Default::default(), #[allow(unreachable_patterns)] _ => unimplemented!("{:?} does not have associated default data", self), @@ -421,7 +546,58 @@ impl LayoutKind { .map(|b| (Disposition::Unchanged(config.decoration), b)) .collect() }, - LayoutKind::Stack => |region, data, active_map| { + LayoutKind::Center => |region, data, active_map| { + let config = &LayoutKind::Center.config(); + let (pos, dim) = region.values(); + + let h_comp = MAX_MAIN_COUNT + 1; + let w_ratio: f32 = data.main_factor / 0.95; + let h_ratio: f32 = (h_comp - data.main_count) as f32 / h_comp as f32; + + active_map + .into_iter() + .map(|_| { + ( + Disposition::Changed( + Region { + pos, + dim, + } + .from_absolute_inner_center(&Dim { + w: (dim.w as f32 * w_ratio) as u32, + h: (dim.h as f32 * h_ratio) as u32, + }), + config.decoration, + ), + true, + ) + }) + .collect() + }, + LayoutKind::Monocle => |region, _, active_map| { + let config = &LayoutKind::Monocle.config(); + let (pos, dim) = region.values(); + + active_map + .into_iter() + .map(|_| { + ( + Disposition::Changed( + Region { + pos, + dim, + }, + config.decoration, + ), + true, + ) + }) + .collect() + }, + LayoutKind::Paper => |region, data, active_map| { + const MIN_W_RATIO: f32 = 0.5; + + let config = &LayoutKind::Paper.config(); let (pos, dim) = region.values(); let n = active_map.len(); @@ -429,44 +605,40 @@ impl LayoutKind { return vec![(Disposition::Changed(*region, NO_DECORATION), true)]; } - let (n_main, n_stack) = Self::stack_split(n, data.main_count); - let h_stack = if n_stack > 0 { dim.h / n_stack } else { 0 }; - let h_main = if n_main > 0 { dim.h / n_main } else { 0 }; + let cw = (dim.w as f32 + * if data.main_factor > MIN_W_RATIO { + data.main_factor + } else { + MIN_W_RATIO + }) as u32; - let div = if data.main_count > 0 { - (dim.w as f32 * data.main_factor) as i32 - } else { - 0 - }; + let w = ((dim.w - cw) as usize / (n - 1)) as i32; + let mut after_active = false; - let config = &LayoutKind::Stack.config(); active_map .into_iter() .enumerate() - .map(|(i, _)| { - let i = i as u32; - - if i < data.main_count { - let w = if n_stack == 0 { dim.w } else { div as u32 }; + .map(|(i, active)| { + if active { + after_active = true; ( Disposition::Changed( - Region::new(pos.x, pos.y + (i * h_main) as i32, w, h_main), + Region::new(pos.x + i as i32 * w, pos.y, cw, dim.h), config.decoration, ), true, ) } else { - let sn = (i - data.main_count) as i32; + let mut x = pos.x + i as i32 * w; + + if after_active { + x += cw as i32 - w; + } ( Disposition::Changed( - Region::new( - pos.x + div, - pos.y + sn * h_stack as i32, - dim.w - div as u32, - h_stack, - ), + Region::new(x, pos.y, w as u32, dim.h), config.decoration, ), true, @@ -475,15 +647,18 @@ impl LayoutKind { }) .collect() }, - LayoutKind::SStack => |region, data, active_map| { + LayoutKind::SPaper => |region, data, active_map| { let mut region = region.clone(); Layout::adjust_for_gap_size(&mut region, data.gap_size, &MIN_ZONE_DIM); + (Self::Paper.func())(&region, data, active_map) + }, + LayoutKind::Stack => |region, data, active_map| { let (pos, dim) = region.values(); let n = active_map.len(); if n == 1 { - return vec![(Disposition::Changed(region, NO_DECORATION), true)]; + return vec![(Disposition::Changed(*region, NO_DECORATION), true)]; } let (n_main, n_stack) = Self::stack_split(n, data.main_count); @@ -532,106 +707,39 @@ impl LayoutKind { }) .collect() }, - LayoutKind::Monocle => |region, _, active_map| { - let config = &LayoutKind::Monocle.config(); - let (pos, dim) = region.values(); + LayoutKind::SStack => |region, data, active_map| { + let mut region = region.clone(); + Layout::adjust_for_gap_size(&mut region, data.gap_size, &MIN_ZONE_DIM); - active_map - .into_iter() - .map(|_| { - ( - Disposition::Changed( - Region { - pos, - dim, - }, - config.decoration, - ), - true, - ) - }) - .collect() + (Self::Stack.func())(&region, data, active_map) }, - LayoutKind::Center => |region, data, active_map| { - let config = &LayoutKind::Center.config(); - let (pos, dim) = region.values(); - - let h_comp = MAX_MAIN_COUNT + 1; - let w_ratio: f32 = data.main_factor / 0.95; - let h_ratio: f32 = (h_comp - data.main_count) as f32 / h_comp as f32; - - active_map - .into_iter() - .map(|_| { - ( - Disposition::Changed( - Region { - pos, - dim, - } - .from_absolute_inner_center(&Dim { - w: (dim.w as f32 * w_ratio) as u32, - h: (dim.h as f32 * h_ratio) as u32, - }), - config.decoration, - ), - true, - ) - }) - .collect() - }, - LayoutKind::Paper => |region, data, active_map| { - const MIN_W_RATIO: f32 = 0.5; - - let config = &LayoutKind::Paper.config(); - let (pos, dim) = region.values(); + LayoutKind::BStack => |region, _data, active_map| { + let (_pos, _dim) = region.values(); let n = active_map.len(); if n == 1 { return vec![(Disposition::Changed(*region, NO_DECORATION), true)]; } - let cw = (dim.w as f32 - * if data.main_factor > MIN_W_RATIO { - data.main_factor - } else { - MIN_W_RATIO - }) as u32; - - let w = ((dim.w - cw) as usize / (n - 1)) as i32; - let mut after_active = false; - - active_map - .into_iter() - .enumerate() - .map(|(i, active)| { - if active { - after_active = true; - - ( - Disposition::Changed( - Region::new(pos.x + i as i32 * w, pos.y, cw, dim.h), - config.decoration, - ), - true, - ) - } else { - let mut x = pos.x + i as i32 * w; - - if after_active { - x += cw as i32 - w; - } + todo!() + }, + LayoutKind::BSStack => |region, data, active_map| { + let mut region = region.clone(); + Layout::adjust_for_gap_size(&mut region, data.gap_size, &MIN_ZONE_DIM); - ( - Disposition::Changed( - Region::new(x, pos.y, w as u32, dim.h), - config.decoration, - ), - true, - ) - } - }) - .collect() + (Self::BStack.func())(&region, data, active_map) + }, + LayoutKind::Horz => |_region, _data, _active_map| { + todo!() + }, + LayoutKind::SHorz => |_region, _data, _active_map| { + todo!() + }, + LayoutKind::Vert => |_region, _data, _active_map| { + todo!() + }, + LayoutKind::SVert => |_region, _data, _active_map| { + todo!() }, #[allow(unreachable_patterns)] @@ -763,6 +871,16 @@ impl Layout { } } +impl Default for Layout { + fn default() -> Self { + Self { + kind: LayoutKind::Stack, + prev_kind: LayoutKind::Stack, + data: HashMap::new(), + } + } +} + trait Apply { fn apply( &self, @@ -1304,15 +1422,19 @@ impl ZoneManager { zone_changes.push((id, ZoneChange::Method(method))); }); - placements.extend( - self.arrange_subzones(id, region, Decoration { + placements.extend(self.arrange_subzones( + id, + region, + Decoration { frame: None, border: Some(Border { width: 1, colors: Default::default(), }), - }, method, to_ignore), - ); + }, + method, + to_ignore, + )); placements },