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 5cd644c6f846c1440efd3dd43822e4dacb440768
parent 2d738c1955333bab37f8fc717ee2711b211ca600
Author: deurzen <m.deurzen@tum.de>
Date:   Wed, 17 Mar 2021 20:18:29 +0100

implements initial zone cycling behavior

Diffstat:
Msrc/core/common.rs | 2++
Msrc/core/main.rs | 10+++++++---
Msrc/core/model.rs | 48++++++++++++++++++++++++++++++++++++++++++------
Msrc/core/workspace.rs | 26+++++++++++++++++++++++---
Msrc/core/zone.rs | 62++++++++++++++++++++++++++++++++++++++++++--------------------
5 files changed, 116 insertions(+), 32 deletions(-)

diff --git a/src/core/common.rs b/src/core/common.rs @@ -33,10 +33,12 @@ pub const FREE_DECORATION: Decoration = Decoration { }), }; +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum StateChangeError { EarlyStop, LimitReached, StateUnchanged, + InvalidCaller, } pub type Color = u32; diff --git a/src/core/main.rs b/src/core/main.rs @@ -183,6 +183,10 @@ fn init_bindings() -> (MouseBindings, KeyBindings) { "1-S-semicolon" => do_internal!(rotate_clients, Direction::Forward), "1-S-comma" => do_internal!(rotate_clients, Direction::Backward), + // zone order modifiers + "1-C-j" => do_internal!(cycle_zones, Direction::Forward), + "1-C-k" => do_internal!(cycle_zones, Direction::Backward), + // active workspace layout setters "1-m" => do_internal!(set_layout, LayoutKind::Monocle), "1-t" => do_internal!(set_layout, LayoutKind::Stack), @@ -293,9 +297,9 @@ fn init_bindings() -> (MouseBindings, KeyBindings) { }), // external spawn commands - "XF86AudioPlay", "1-2-p" => spawn_external!("playerctl play-pause"), - "XF86AudioPrev", "1-2-k" => spawn_external!("playerctl previous"), - "XF86AudioNext", "1-2-j" => spawn_external!("playerctl next"), + "XF86AudioPlay", "1-2-C-p" => spawn_external!("playerctl play-pause"), + "XF86AudioPrev", "1-2-C-k" => spawn_external!("playerctl previous"), + "XF86AudioNext", "1-2-C-j" => spawn_external!("playerctl next"), "1-2-BackSpace" => spawn_external!("playerctl stop"), "XF86AudioMute" => spawn_external!("amixer -D pulse sset Master toggle"), "XF86AudioLowerVolume" => spawn_external!("amixer -D pulse sset Master 5%-"), diff --git a/src/core/model.rs b/src/core/model.rs @@ -137,16 +137,38 @@ impl<'a> Model<'a> { .screen() .placeable_region(); - let id = model.zone_manager.new_zone( + let root_id = model.zone_manager.new_zone( None, 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, id)); + .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(id).set_region(region); + model.zone_manager.zone_mut(root_id).set_region(region); } model.workspaces.activate_for(&Selector::AtIndex(0)); @@ -1306,6 +1328,18 @@ impl<'a> Model<'a> { self.conn.flush(); } + pub fn cycle_zones( + &mut self, + dir: Direction, + ) { + let workspace = self.active_workspace(); + let zone_manager = &self.zone_manager; + + self.workspaces + .get_mut(workspace) + .and_then(|ws| ws.cycle_zones(dir, zone_manager)); + } + pub fn cycle_focus( &mut self, dir: Direction, @@ -1400,7 +1434,7 @@ impl<'a> Model<'a> { client.set_free_region(&active_region); }); - self.set_layout(LayoutKind::Float); + drop(self.set_layout(LayoutKind::Float)); self.apply_layout(workspace_index, false); } @@ -1698,7 +1732,7 @@ impl<'a> Model<'a> { pub fn set_layout( &mut self, kind: LayoutKind, - ) { + ) -> Result<(), StateChangeError> { let workspace_index = self.active_workspace(); let workspace = self.workspace_mut(workspace_index); @@ -1708,9 +1742,11 @@ impl<'a> Model<'a> { kind, workspace_index ); - self.zone_manager.set_kind(id, kind); + self.zone_manager.set_kind(id, kind)?; self.apply_layout(workspace_index, true); } + + Ok(()) } pub fn toggle_layout(&mut self) { diff --git a/src/core/workspace.rs b/src/core/workspace.rs @@ -383,6 +383,27 @@ impl Workspace { } } + pub fn cycle_zones( + &mut self, + dir: Direction, + zone_manager: &ZoneManager, + ) -> Option<(ZoneId, ZoneId)> { + if self.zones.len() < 2 { + return None; + } + + let prev_active = *self.zones.active_element()?; + let mut now_active = *self.zones.cycle_active(dir)?; + + loop { + if zone_manager.is_cycle(now_active) { + return Some((prev_active, now_active)); + } + + now_active = *self.zones.cycle_active(dir)?; + } + } + pub fn cycle_focus( &mut self, dir: Direction, @@ -393,8 +414,8 @@ impl Workspace { return None; } - let window = self.clients.active_element().unwrap(); - let id = client_map.get(window).unwrap().zone(); + let prev_active = *self.clients.active_element()?; + let id = client_map.get(&prev_active).unwrap().zone(); let config = zone_manager.active_layoutconfig(id); if let Some(config) = config { @@ -403,7 +424,6 @@ impl Workspace { } } - let prev_active = *self.clients.active_element()?; let now_active = *self.clients.cycle_active(dir)?; if prev_active != now_active { diff --git a/src/core/zone.rs b/src/core/zone.rs @@ -2,8 +2,10 @@ use crate::common::Decoration; use crate::common::Frame; use crate::common::Ident; 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; @@ -705,13 +707,15 @@ impl Layout { fn set_kind( &mut self, kind: LayoutKind, - ) { + ) -> Result<LayoutKind, StateChangeError> { if kind == self.kind { - return; + return Err(StateChangeError::EarlyStop); } self.prev_kind = self.kind; self.kind = kind; + + Ok(self.prev_kind) } #[inline] @@ -850,26 +854,24 @@ impl Zone { fn set_kind( &mut self, kind: LayoutKind, - ) { + ) -> Result<LayoutKind, StateChangeError> { match self.content { - ZoneContent::Layout(ref mut layout, _) => { - layout.set_kind(kind); - }, - _ => {}, + ZoneContent::Layout(ref mut layout, _) => layout.set_kind(kind), + _ => Err(StateChangeError::InvalidCaller), } } - pub fn prev_kind(&self) -> LayoutKind { + pub fn prev_kind(&self) -> Result<LayoutKind, StateChangeError> { match &self.content { - ZoneContent::Layout(layout, _) => layout.prev_kind, - _ => panic!("attempting to obtain layout kind from non-layout"), + ZoneContent::Layout(layout, _) => Ok(layout.prev_kind), + _ => Err(StateChangeError::InvalidCaller), } } - pub fn kind(&self) -> LayoutKind { + pub fn kind(&self) -> Result<LayoutKind, StateChangeError> { match &self.content { - ZoneContent::Layout(layout, _) => layout.kind, - _ => panic!("attempting to obtain layout kind from non-layout"), + ZoneContent::Layout(layout, _) => Ok(layout.kind), + _ => Err(StateChangeError::InvalidCaller), } } @@ -1004,30 +1006,32 @@ impl ZoneManager { &mut self, id: ZoneId, kind: LayoutKind, - ) { + ) -> Result<LayoutKind, StateChangeError> { let persistent_data_copy = self.persistent_data_copy; let cycle = self.nearest_cycle(id); let cycle = self.zone_mut(cycle); - cycle.set_kind(kind); + let prev_kind = cycle.set_kind(kind)?; if persistent_data_copy { let prev_data = *cycle.prev_data().unwrap(); let data = cycle.data_mut().unwrap(); *data = prev_data; } + + Ok(prev_kind) } pub fn set_prev_kind( &mut self, id: ZoneId, - ) -> LayoutKind { + ) -> Result<LayoutKind, StateChangeError> { let persistent_data_copy = self.persistent_data_copy; let cycle = self.nearest_cycle(id); let cycle = self.zone_mut(cycle); - let prev_kind = cycle.prev_kind(); - cycle.set_kind(prev_kind); + let kind = cycle.prev_kind()?; + let prev_kind = cycle.set_kind(kind)?; if persistent_data_copy { let prev_data = *cycle.prev_data().unwrap(); @@ -1035,7 +1039,7 @@ impl ZoneManager { *data = prev_data; } - prev_kind + Ok(prev_kind) } pub fn active_default_data( @@ -1123,6 +1127,18 @@ impl ZoneManager { zone.config() } + pub fn is_cycle( + &self, + id: ZoneId, + ) -> bool { + let zone = self.zone_map.get(&id).unwrap(); + + match zone.content { + ZoneContent::Tab(_) | ZoneContent::Layout(..) => true, + _ => false, + } + } + pub fn nearest_cycle( &self, id: ZoneId, @@ -1289,7 +1305,13 @@ impl ZoneManager { }); placements.extend( - self.arrange_subzones(id, region, decoration, method, to_ignore), + self.arrange_subzones(id, region, Decoration { + frame: None, + border: Some(Border { + width: 1, + colors: Default::default(), + }), + }, method, to_ignore), ); placements