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 a0ce39f7bede1ae9ab926667d4dce797c3e8fa01
parent ccbb1679d69a87ee0f104d3909acb3eacd20c970
Author: deurzen <m.deurzen@tum.de>
Date:   Sun, 14 Mar 2021 23:25:25 +0100

implements zone activation

Diffstat:
Msrc/core/client.rs | 4++--
Msrc/core/common.rs | 2+-
Msrc/core/model.rs | 82+++++++++++++++++++++++++++----------------------------------------------------
Msrc/core/workspace.rs | 65++++++++++++++++++++++++++++++++++-------------------------------
Msrc/core/zone.rs | 142++++++++++++++++++++++++++++++++++++-------------------------------------------
5 files changed, 129 insertions(+), 166 deletions(-)

diff --git a/src/core/client.rs b/src/core/client.rs @@ -1,7 +1,7 @@ -use crate::common::Ident; -use crate::common::Identify; use crate::common::Decoration; use crate::common::Frame; +use crate::common::Ident; +use crate::common::Identify; use crate::zone::ZoneId; use winsys::common::Extents; diff --git a/src/core/common.rs b/src/core/common.rs @@ -1,8 +1,8 @@ use winsys::common::Dim; use winsys::common::Extents; +use winsys::common::Padding; use winsys::common::Pos; use winsys::common::Region; -use winsys::common::Padding; use winsys::common::Window; use std::ops::Add; diff --git a/src/core/model.rs b/src/core/model.rs @@ -2,13 +2,13 @@ use crate::binding::KeyBindings; use crate::binding::MouseBindings; use crate::client::Client; use crate::common::Change; +use crate::common::Decoration; use crate::common::Direction; +use crate::common::Frame; use crate::common::Index; 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::common::NO_DECORATION; use crate::consume::get_spawner_pid; use crate::cycle::Cycle; use crate::cycle::InsertPos; @@ -402,7 +402,7 @@ impl<'a> Model<'a> { let (free, regular): (Vec<Window>, Vec<Window>) = regular.iter().partition(|&&window| { self.client(window).map_or(true, |client| { - let id = self.zone_manager.client_id(client.window()); + let id = client.zone(); let zone = self.zone_manager.zone(id); zone.method() == PlacementMethod::Free || client.is_free() @@ -506,24 +506,6 @@ 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, @@ -977,7 +959,7 @@ impl<'a> Model<'a> { client: &Client, ) -> bool { client.is_floating() && (!client.is_fullscreen() || client.is_in_window()) || { - let id = self.zone_manager.client_id(client.window()); + let id = client.zone(); let zone = self.zone_manager.zone(id); zone.method() == PlacementMethod::Free @@ -1008,6 +990,7 @@ impl<'a> Model<'a> { let parent = client.parent(); let producer = client.producer(); let workspace = client.workspace(); + let id = client.zone(); info!("removing client with window {:#0x}", window); @@ -1029,10 +1012,8 @@ impl<'a> Model<'a> { } } - let id = self.zone_manager.client_id(window); self.workspaces.get_mut(workspace).map(|w| { w.remove_zone(id); - w.remove_client(window); w.remove_icon(window); }); @@ -1313,10 +1294,13 @@ impl<'a> Model<'a> { dir: Direction, ) { let workspace = self.active_workspace(); + let client_map = &self.client_map; + let zone_manager = &self.zone_manager; + let windows = self .workspaces .get_mut(workspace) - .and_then(|ws| ws.cycle_focus(dir)); + .and_then(|ws| ws.cycle_focus(dir, client_map, zone_manager)); if let Some((_, window)) = windows { self.focus(window); @@ -1753,7 +1737,6 @@ 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(); @@ -1828,6 +1811,7 @@ impl<'a> Model<'a> { let client = client.unwrap(); let client_workspace_index = client.workspace(); + let id = client.zone(); if client_workspace_index != active_workspace_index { self.activate_workspace(client_workspace_index); @@ -1844,10 +1828,13 @@ impl<'a> Model<'a> { client.set_urgent(false); } - let workspace = self.workspace_mut(client_workspace_index); - workspace.focus_client(window); + self.zone_manager.activate_zone(id); + + self + .workspaces + .get_mut(client_workspace_index) + .and_then(|ws| ws.focus_client(window)); - 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); @@ -1912,9 +1899,6 @@ impl<'a> Model<'a> { ) { if let Some(client) = self.client(window) { 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); @@ -2313,7 +2297,7 @@ impl<'a> Model<'a> { let placement = Placement { method: PlacementMethod::Free, kind: PlacementKind::Client(window), - zone: self.zone_manager.client_id(window), + zone: client.zone(), region: Some(region), decoration: *client.decoration(), }; @@ -2360,7 +2344,7 @@ impl<'a> Model<'a> { let placement = Placement { method: PlacementMethod::Free, kind: PlacementKind::Client(window), - zone: self.zone_manager.client_id(window), + zone: client.zone(), region: Some(region), decoration: *client.decoration(), }; @@ -2423,7 +2407,7 @@ impl<'a> Model<'a> { let placement = Placement { method: PlacementMethod::Free, kind: PlacementKind::Client(window), - zone: self.zone_manager.client_id(window), + zone: client.zone(), region: Some(region), decoration: *client.decoration(), }; @@ -2514,11 +2498,10 @@ impl<'a> Model<'a> { let window = client.window(); let region = region.with_extents(&frame_extents); - let placement = Placement { method: PlacementMethod::Free, kind: PlacementKind::Client(window), - zone: self.zone_manager.client_id(window), + zone: client.zone(), region: Some(region), decoration: *client.decoration(), }; @@ -2574,7 +2557,7 @@ impl<'a> Model<'a> { let placement = Placement { method: PlacementMethod::Free, kind: PlacementKind::Client(window), - zone: self.zone_manager.client_id(window), + zone: client.zone(), region: Some(region), decoration: *client.decoration(), }; @@ -2626,10 +2609,10 @@ impl<'a> Model<'a> { let current_pos = *pos; let previous_region = *client.previous_region(); - let frame_extents = client.frame_extents(); + let decoration = client.decoration(); let (pos, mut dim) = client .free_region() - .without_extents(&frame_extents) + .without_extents(&decoration.extents()) .values(); let top_grip = grip.is_top_grip(); @@ -2659,7 +2642,7 @@ impl<'a> Model<'a> { pos, dim, }) - .with_extents(&frame_extents); + .with_extents(&decoration.extents()); if top_grip { region.pos.y = @@ -2676,21 +2659,12 @@ impl<'a> Model<'a> { } let window = client.window(); - let id = self.zone_manager.client_id(window); - let placement = Placement { method: PlacementMethod::Free, kind: PlacementKind::Client(window), - zone: id, + zone: client.zone(), region: Some(region), - // TODO: zone change: should be proper frame - decoration: Decoration { - border: None, - frame: Some(Frame { - extents: frame_extents, - colors: Default::default(), - }), - }, + decoration: *decoration, }; self.update_client_placement(&placement); @@ -3221,7 +3195,7 @@ impl<'a> Model<'a> { let placement = Placement { method: PlacementMethod::Free, kind: PlacementKind::Client(window), - zone: self.zone_manager.client_id(window), + zone: client.zone(), region: Some(region), decoration: *client.decoration(), }; diff --git a/src/core/workspace.rs b/src/core/workspace.rs @@ -1,12 +1,12 @@ use crate::client::Client; +use crate::common::Border; use crate::common::Change; +use crate::common::Decoration; use crate::common::Direction; +use crate::common::Frame; 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; @@ -340,33 +340,26 @@ impl Workspace { .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.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, + kind: PlacementKind::Client(client.window()), + zone: client.zone(), + region: Some(region), + decoration, + } + })); placements } else { @@ -377,12 +370,22 @@ impl Workspace { pub fn cycle_focus( &mut self, dir: Direction, + client_map: &HashMap<Window, Client>, + zone_manager: &ZoneManager, ) -> Option<(Window, Window)> { if self.clients.len() < 2 { return None; } - // TODO: zone change + let window = self.clients.active_element().unwrap(); + let id = client_map.get(window).unwrap().zone(); + let config = zone_manager.active_layoutconfig(id); + + if let Some(config) = config { + if !config.wraps && self.clients.next_will_wrap(dir) { + return None; + } + } let prev_active = *self.clients.active_element()?; let now_active = *self.clients.cycle_active(dir)?; diff --git a/src/core/zone.rs b/src/core/zone.rs @@ -1,10 +1,13 @@ -use crate::common::Ident; -use crate::common::Identify; +use crate::common::Border; use crate::common::Decoration; use crate::common::Frame; -use crate::common::Border; +use crate::common::Ident; +use crate::common::Identify; +use crate::common::FREE_DECORATION; +use crate::common::NO_DECORATION; use crate::cycle::Cycle; use crate::cycle::InsertPos; +use crate::cycle::Selector; use winsys::common::Dim; use winsys::common::Extents; @@ -158,7 +161,7 @@ impl LayoutKind { match *self { LayoutKind::Float => LayoutConfig { method: PlacementMethod::Free, - decoration: Default::default(), + decoration: FREE_DECORATION, root_only: true, gap: false, persistent: false, @@ -167,7 +170,7 @@ impl LayoutKind { }, LayoutKind::SingleFloat => LayoutConfig { method: PlacementMethod::Free, - decoration: Default::default(), + decoration: FREE_DECORATION, root_only: true, gap: false, persistent: true, @@ -176,10 +179,7 @@ impl LayoutKind { }, LayoutKind::Center => LayoutConfig { method: PlacementMethod::Tile, - decoration: Decoration { - frame: None, - border: None, - }, + decoration: NO_DECORATION, root_only: false, gap: true, persistent: false, @@ -188,10 +188,7 @@ impl LayoutKind { }, LayoutKind::Monocle => LayoutConfig { method: PlacementMethod::Tile, - decoration: Decoration { - frame: None, - border: None, - }, + decoration: NO_DECORATION, root_only: false, gap: true, persistent: false, @@ -349,13 +346,7 @@ impl LayoutKind { let n = active_map.len(); if n == 1 { - return vec![( - Disposition::Changed(*region, Decoration { - border: None, - frame: None, - }), - true, - )]; + return vec![(Disposition::Changed(*region, NO_DECORATION), true)]; } let (n_main, n_stack) = stack_split(n, data.main_count); @@ -461,13 +452,7 @@ impl LayoutKind { let n = active_map.len(); if n == 1 { - return vec![( - Disposition::Changed(*region, Decoration { - border: None, - frame: None, - }), - true, - )]; + return vec![(Disposition::Changed(*region, NO_DECORATION), true)]; } let cw = (dim.w as f32 @@ -666,7 +651,6 @@ pub struct Zone { content: ZoneContent, region: Region, decoration: Decoration, - is_active: bool, is_visible: bool, } @@ -684,11 +668,7 @@ impl Zone { method: PlacementMethod::Free, content, region, - decoration: Decoration { - border: None, - frame: None, - }, - is_active: true, + decoration: NO_DECORATION, is_visible: true, }) } @@ -727,13 +707,6 @@ impl Zone { } } - pub fn set_active( - &mut self, - is_active: bool, - ) { - self.is_active = is_active; - } - pub fn set_region( &mut self, region: Region, @@ -755,7 +728,6 @@ impl Zone { enum ZoneChange { Visible(bool), - Active(bool), Region(Region), Decoration(Decoration), Method(PlacementMethod), @@ -763,14 +735,12 @@ enum ZoneChange { pub struct ZoneManager { zone_map: HashMap<ZoneId, Zone>, - client_zones: HashMap<Window, ZoneId>, } impl ZoneManager { pub fn new() -> Self { Self { zone_map: HashMap::new(), - client_zones: HashMap::new(), } } @@ -780,14 +750,6 @@ impl ZoneManager { content: ZoneContent, ) -> ZoneId { let (id, zone) = Zone::new(parent, content, Region::new(0, 0, 0, 0)); - - match &zone.content { - ZoneContent::Client(window) => { - self.client_zones.insert(*window, id); - }, - _ => {}, - }; - let parent = parent.and_then(|p| self.zone_map.get_mut(&p)); if let Some(parent) = parent { @@ -803,6 +765,33 @@ impl ZoneManager { id } + pub fn activate_zone( + &mut self, + id: ZoneId, + ) { + if let Some(cycle_id) = self.next_cycle(id) { + let cycle = self.zone_mut(cycle_id); + + match cycle.content { + ZoneContent::Tab(ref mut zones) | ZoneContent::Layout(_, ref mut zones) => { + zones.activate_for(&Selector::AtIdent(id)); + self.activate_zone(cycle_id); + } + _ => {} + } + } + } + + pub fn active_layoutconfig( + &self, + id: ZoneId, + ) -> Option<LayoutConfig> { + let cycle = self.nearest_cycle(id); + let cycle = self.zone(cycle); + + cycle.config() + } + pub fn zone_checked( &self, id: ZoneId, @@ -831,25 +820,11 @@ impl ZoneManager { self.zone_map.get_mut(&id).unwrap() } - pub fn remove_zone( - &mut self, - id: ZoneId, - ) { - self.client_zones.remove(&id); - } - - pub fn client_id_checked( + pub fn parent_id( &self, - client: Window, + id: ZoneId, ) -> Option<ZoneId> { - self.client_zones.get(&client).map(|&id| id) - } - - pub fn client_id( - &self, - client: Window, - ) -> ZoneId { - *self.client_zones.get(&client).unwrap() + self.zone_map.get(&id).and_then(|zone| zone.parent) } pub fn cycle_config( @@ -886,14 +861,27 @@ impl ZoneManager { } } - pub fn set_active( - &mut self, + pub fn next_cycle( + &self, id: ZoneId, - active: bool, - ) { - if let Some(zone) = self.zone_map.get_mut(&id) { - zone.is_active = active; + ) -> Option<ZoneId> { + let mut next = self.parent_id(id); + + while next.is_some() { + let next_id = next.unwrap(); + let zone = self.zone_map.get(&next_id).unwrap(); + + match zone.content { + ZoneContent::Tab(_) | ZoneContent::Layout(..) => { + return next; + }, + _ => { + next = self.parent_id(next_id); + }, + } } + + None } fn gather_subzones( @@ -1019,6 +1007,7 @@ impl ZoneManager { } }, ZoneContent::Layout(layout, zones) => { + let active_element = zones.active_element(); let mut subplacements = Vec::new(); let mut placements = vec![Placement { method, @@ -1038,7 +1027,7 @@ impl ZoneManager { &region, zones .iter() - .map(|id| self.zone_map.get(id).unwrap().is_active) + .map(|id| Some(id) == active_element) .collect(), ); @@ -1094,9 +1083,6 @@ impl ZoneManager { ZoneChange::Visible(is_visible) => { zone.is_visible = is_visible; }, - ZoneChange::Active(is_active) => { - zone.is_active = is_active; - }, ZoneChange::Region(region) => { zone.region = region; },