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 bb8f9a10811797b750b6e384a933dab052e31d7c
parent b22b267112e8231fd55efb87096764514478d5aa
Author: deurzen <m.deurzen@tum.de>
Date:   Sat, 27 Mar 2021 14:36:39 +0100

initial {,Ref}Cell implementation

Diffstat:
MCargo.lock | 4++--
MMakefile | 2+-
Msrc/core/cycle.rs | 230++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/core/model.rs | 773+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/core/workspace.rs | 4++--
Msrc/core/zone.rs | 81+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/winsys/connection.rs | 4++--
Msrc/winsys/xdata/xconnection.rs | 17+++++++++--------
8 files changed, 570 insertions(+), 545 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "anyhow" -version = "1.0.34" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" [[package]] name = "autocfg" diff --git a/Makefile b/Makefile @@ -10,7 +10,7 @@ debug: build ./launch release: - cargo build --release + RUSTFLAGS="--emit=asm" cargo build --release install: install ./target/release/wzrd /usr/local/bin/wzrd diff --git a/src/core/cycle.rs b/src/core/cycle.rs @@ -5,6 +5,8 @@ use crate::identify::Index; use crate::util::BuildIdHasher; use crate::util::Util; +use std::cell::Cell; +use std::cell::RefCell; use std::cmp::Ordering; use std::collections::HashMap; use std::collections::VecDeque; @@ -38,25 +40,68 @@ enum StackAction { } #[derive(Debug, Clone, PartialEq)] +struct HistoryStack { + stack: VecDeque<Ident>, +} + +impl HistoryStack { + fn new() -> Self { + HistoryStack { + stack: VecDeque::with_capacity(30), + } + } + + fn clear(&mut self) { + self.stack.clear(); + } + + fn push_back( + &mut self, + id: Ident, + ) { + self.stack.push_back(id); + } + + fn pop_back(&mut self) -> Option<Ident> { + self.stack.pop_back() + } + + fn remove_id( + &mut self, + id: Ident, + ) { + if let Some(index) = self.stack.iter().rposition(|&i| i == id) { + self.stack.remove(index); + } + } + + fn as_vecdeque(&self) -> VecDeque<Ident> { + self.stack.clone() + } + + fn as_vec(&self) -> Vec<Ident> { + self.stack.iter().cloned().collect::<Vec<Ident>>() + } +} + +#[derive(Debug, Clone, PartialEq)] pub struct Cycle<T> where T: Identify + std::fmt::Debug, { - index: Index, + index: Cell<Index>, elements: VecDeque<T>, indices: HashMap<Ident, Index, BuildIdHasher>, unwindable: bool, - stack: VecDeque<Ident>, + stack: RefCell<HistoryStack>, } impl<T> Cycle<T> where T: Identify + std::fmt::Debug, { - const MAX_STACK_LEN: usize = 0x10; - pub fn new( elements: Vec<T>, unwindable: bool, @@ -68,28 +113,28 @@ where .map(|(i, e)| (e.id(), i)) .collect(), - index: Util::last_index(elements.iter()), + index: Cell::new(Util::last_index(elements.iter())), elements: elements.into(), unwindable, - stack: VecDeque::with_capacity(Self::MAX_STACK_LEN), + stack: RefCell::new(HistoryStack::new()), } } #[inline] fn index(&self) -> Option<Index> { - if self.index < self.elements.len() { - Some(self.index) + if self.index.get() < self.elements.len() { + Some(self.index.get()) } else { None } } pub fn clear(&mut self) { - self.index = 0; + self.index.set(0); self.elements.clear(); self.indices.clear(); - self.stack.clear(); + self.stack.borrow_mut().clear(); } #[inline] @@ -97,8 +142,8 @@ where &self, dir: Direction, ) -> bool { - self.index == Util::last_index(self.elements.iter()) && dir == Direction::Forward - || self.index == 0 && dir == Direction::Backward + self.index.get() == Util::last_index(self.elements.iter()) && dir == Direction::Forward + || self.index.get() == 0 && dir == Direction::Backward } #[inline] @@ -116,7 +161,7 @@ where #[inline] pub fn active_index(&self) -> Index { - self.index + self.index.get() } #[inline] @@ -124,7 +169,7 @@ where &self, dir: Direction, ) -> Index { - self.next_index_from(self.index, dir) + self.next_index_from(self.index.get(), dir) } #[inline] @@ -137,11 +182,11 @@ where } pub fn cycle_active( - &mut self, + &self, dir: Direction, ) -> Option<&T> { self.push_active_to_stack(); - self.index = self.next_index(dir); + self.index.set(self.next_index(dir)); self.active_element() } @@ -150,7 +195,7 @@ where sel: &Selector<T>, ) -> Option<Index> { match sel { - Selector::AtActive => Some(self.index), + Selector::AtActive => Some(self.index.get()), Selector::AtIndex(index) => { if *index < self.len() { return Some(*index); @@ -173,12 +218,12 @@ where #[inline] pub fn active_element(&self) -> Option<&T> { - self.elements.get(self.index) + self.elements.get(self.index.get()) } #[inline] pub fn active_element_mut(&mut self) -> Option<&mut T> { - self.elements.get_mut(self.index) + self.elements.get_mut(self.index.get()) } pub fn rotate( @@ -202,7 +247,7 @@ where &mut self, dir: Direction, ) -> Option<&T> { - match (self.index, self.next_index(dir), dir) { + match (self.index.get(), self.next_index(dir), dir) { (0, _, Direction::Backward) => self.rotate(dir), (_, 0, Direction::Forward) => self.rotate(dir), (active, next, _) => { @@ -230,8 +275,10 @@ where element: T, ) { match insert_pos { - InsertPos::BeforeActive => self.insert(self.index, element), - InsertPos::AfterActive => self.insert_at(&InsertPos::AfterIndex(self.index), element), + InsertPos::BeforeActive => self.insert(self.index.get(), element), + InsertPos::AfterActive => { + self.insert_at(&InsertPos::AfterIndex(self.index.get()), element) + }, InsertPos::BeforeIndex(index) => self.insert(*index, element), InsertPos::Front => self.push_front(element), InsertPos::Back => self.push_back(element), @@ -266,7 +313,7 @@ where self.sync_indices(index, StackAction::Insert); self.indices.insert((&element).id(), index); self.elements.insert(index, element); - self.index = index; + self.index.set(index); } pub fn push_front( @@ -277,7 +324,7 @@ where self.sync_indices(0, StackAction::Insert); self.indices.insert((&element).id(), 0); self.elements.push_front(element); - self.index = 0; + self.index.set(0); } pub fn push_back( @@ -289,7 +336,7 @@ where self.push_active_to_stack(); self.indices.insert((&element).id(), end); self.elements.push_back(element); - self.index = end; + self.index.set(end); } #[inline] @@ -465,14 +512,14 @@ where } pub fn activate_for( - &mut self, + &self, sel: &Selector<T>, ) -> Option<&T> { match sel { Selector::AtActive => self.active_element(), Selector::AtIndex(index) => { self.push_active_to_stack(); - self.index = *index; + self.index.set(*index); self.active_element() }, Selector::AtIdent(id) => { @@ -484,19 +531,19 @@ where }, Selector::First => { self.push_active_to_stack(); - self.index = 0; + self.index.set(0); self.active_element() }, Selector::Last => { self.push_active_to_stack(); - self.index = Util::last_index(self.elements.iter()); + self.index.set(Util::last_index(self.elements.iter())); self.active_element() }, Selector::ForCond(f) => { if let Some((index, _)) = self.by(f) { self.push_active_to_stack(); - self.index = index; - Some(&self.elements[self.index]) + self.index.set(index); + Some(&self.elements[index]) } else { None } @@ -509,7 +556,7 @@ where sel: &Selector<T>, ) -> Option<T> { let (index, element) = match sel { - Selector::AtActive => (self.index, self.elements.remove(self.index)), + Selector::AtActive => (self.index.get(), self.elements.remove(self.index.get())), Selector::AtIndex(index) => (*index, self.elements.remove(*index)), Selector::AtIdent(id) => { if let Some(index) = self.id_to_index(*id) { @@ -592,20 +639,22 @@ where } if action == StackAction::Remove { - match pivot_index.cmp(&self.index) { + match pivot_index.cmp(&self.index.get()) { Ordering::Equal => { if let Some(id) = self.pop_from_stack() { if let Some(index) = self.id_to_index(id) { - self.index = index; + self.index.set(index); return; } } - self.index = Util::last_index(self.elements.iter()); + self.index.set(Util::last_index(self.elements.iter())); }, Ordering::Less => { - if self.index > 0 { - self.index -= 1; + let index = self.index.get(); + + if index > 0 { + self.index.set(index - 1); } }, Ordering::Greater => {}, @@ -656,12 +705,12 @@ where None } - pub fn stack(&self) -> &VecDeque<Ident> { - &self.stack + pub fn stack(&self) -> VecDeque<Ident> { + self.stack.borrow().as_vecdeque() } pub fn stack_after_focus(&self) -> Vec<Ident> { - let mut stack: Vec<Ident> = self.stack.iter().cloned().collect(); + let mut stack: Vec<Ident> = self.stack.borrow().as_vec(); if let Some(index) = self.index() { if let Some(id) = self.index_to_id(index) { @@ -677,7 +726,7 @@ where } fn push_index_to_stack( - &mut self, + &self, index: Option<Index>, ) { if !self.unwindable { @@ -686,14 +735,15 @@ where if let Some(index) = index { if let Some(id) = self.index_to_id(index) { - self.remove_from_stack(id); - self.stack.push_back(id); + let mut stack = self.stack.borrow_mut(); + stack.remove_id(id); + stack.push_back(id); } } } #[inline] - fn push_active_to_stack(&mut self) { + fn push_active_to_stack(&self) { if !self.unwindable { return; } @@ -715,35 +765,25 @@ where } } + #[inline] fn remove_from_stack( - &mut self, + &self, id: Ident, ) { if !self.unwindable { return; } - if let Some(found_index) = self.stack.iter().rposition(|i| *i == id) { - self.stack.remove(found_index); - } + self.stack.borrow_mut().remove_id(id); } #[inline] - fn pop_from_stack(&mut self) -> Option<Ident> { + fn pop_from_stack(&self) -> Option<Ident> { if !self.unwindable { return None; } - self.stack.pop_back() - } - - #[inline] - fn stack_as_vec(&self) -> Vec<Ident> { - if !self.unwindable { - return Vec::new(); - } - - self.stack.iter().cloned().collect() + self.stack.borrow_mut().pop_back() } } @@ -803,11 +843,11 @@ mod tests { fn removing_element_before_focus() { let mut cycle = Cycle::new(vec![0, 10, 20, 30, 40, 50, 60], false); - assert_eq!(cycle.index, 6); + assert_eq!(cycle.index.get(), 6); cycle.remove_for(&Selector::AtIndex(2)); - assert_eq!(cycle.index, 5); + assert_eq!(cycle.index.get(), 5); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), Some(&1)); assert_eq!(cycle.indices.get(&20), None); @@ -818,7 +858,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(2)); - assert_eq!(cycle.index, 4); + assert_eq!(cycle.index.get(), 4); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), Some(&1)); assert_eq!(cycle.indices.get(&20), None); @@ -829,7 +869,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(2)); - assert_eq!(cycle.index, 3); + assert_eq!(cycle.index.get(), 3); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), Some(&1)); assert_eq!(cycle.indices.get(&20), None); @@ -840,7 +880,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(2)); - assert_eq!(cycle.index, 2); + assert_eq!(cycle.index.get(), 2); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), Some(&1)); assert_eq!(cycle.indices.get(&20), None); @@ -851,7 +891,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(2)); - assert_eq!(cycle.index, 1); + assert_eq!(cycle.index.get(), 1); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), Some(&1)); assert_eq!(cycle.indices.get(&20), None); @@ -862,7 +902,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(2)); - assert_eq!(cycle.index, 1); + assert_eq!(cycle.index.get(), 1); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), Some(&1)); assert_eq!(cycle.indices.get(&20), None); @@ -873,7 +913,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(1)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), None); assert_eq!(cycle.indices.get(&20), None); @@ -884,7 +924,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); assert_eq!(cycle.indices.get(&0), None); assert_eq!(cycle.indices.get(&10), None); assert_eq!(cycle.indices.get(&20), None); @@ -898,11 +938,11 @@ mod tests { fn removing_last_element_at_focus() { let mut cycle = Cycle::new(vec![0, 10, 20, 30, 40, 50, 60], false); - assert_eq!(cycle.index, 6); + assert_eq!(cycle.index.get(), 6); cycle.remove_for(&Selector::AtIndex(6)); - assert_eq!(cycle.index, 5); + assert_eq!(cycle.index.get(), 5); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), Some(&1)); assert_eq!(cycle.indices.get(&20), Some(&2)); @@ -913,7 +953,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(6)); - assert_eq!(cycle.index, 5); + assert_eq!(cycle.index.get(), 5); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), Some(&1)); assert_eq!(cycle.indices.get(&20), Some(&2)); @@ -924,7 +964,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(5)); - assert_eq!(cycle.index, 4); + assert_eq!(cycle.index.get(), 4); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), Some(&1)); assert_eq!(cycle.indices.get(&20), Some(&2)); @@ -935,7 +975,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(4)); - assert_eq!(cycle.index, 3); + assert_eq!(cycle.index.get(), 3); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), Some(&1)); assert_eq!(cycle.indices.get(&20), Some(&2)); @@ -946,7 +986,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(3)); - assert_eq!(cycle.index, 2); + assert_eq!(cycle.index.get(), 2); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), Some(&1)); assert_eq!(cycle.indices.get(&20), Some(&2)); @@ -957,7 +997,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(2)); - assert_eq!(cycle.index, 1); + assert_eq!(cycle.index.get(), 1); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), Some(&1)); assert_eq!(cycle.indices.get(&20), None); @@ -968,7 +1008,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(1)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); assert_eq!(cycle.indices.get(&0), Some(&0)); assert_eq!(cycle.indices.get(&10), None); assert_eq!(cycle.indices.get(&20), None); @@ -979,7 +1019,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); assert_eq!(cycle.indices.get(&0), None); assert_eq!(cycle.indices.get(&10), None); assert_eq!(cycle.indices.get(&20), None); @@ -990,7 +1030,7 @@ mod tests { cycle.remove_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); assert_eq!(cycle.indices.get(&0), None); assert_eq!(cycle.indices.get(&10), None); assert_eq!(cycle.indices.get(&20), None); @@ -1004,13 +1044,13 @@ mod tests { fn removing_first_element_at_focus() { let mut cycle = Cycle::new(vec![0, 10, 20, 30, 40, 50, 60], false); - assert_eq!(cycle.index, 6); + assert_eq!(cycle.index.get(), 6); cycle.activate_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); cycle.remove_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 5); + assert_eq!(cycle.index.get(), 5); assert_eq!(cycle.indices.get(&0), None); assert_eq!(cycle.indices.get(&10), Some(&0)); assert_eq!(cycle.indices.get(&20), Some(&1)); @@ -1020,11 +1060,11 @@ mod tests { assert_eq!(cycle.indices.get(&60), Some(&5)); cycle.activate_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); cycle.remove_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 4); + assert_eq!(cycle.index.get(), 4); assert_eq!(cycle.indices.get(&0), None); assert_eq!(cycle.indices.get(&10), None); assert_eq!(cycle.indices.get(&20), Some(&0)); @@ -1034,11 +1074,11 @@ mod tests { assert_eq!(cycle.indices.get(&60), Some(&4)); cycle.activate_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); cycle.remove_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 3); + assert_eq!(cycle.index.get(), 3); assert_eq!(cycle.indices.get(&0), None); assert_eq!(cycle.indices.get(&10), None); assert_eq!(cycle.indices.get(&20), None); @@ -1048,11 +1088,11 @@ mod tests { assert_eq!(cycle.indices.get(&60), Some(&3)); cycle.activate_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); cycle.remove_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 2); + assert_eq!(cycle.index.get(), 2); assert_eq!(cycle.indices.get(&0), None); assert_eq!(cycle.indices.get(&10), None); assert_eq!(cycle.indices.get(&20), None); @@ -1062,11 +1102,11 @@ mod tests { assert_eq!(cycle.indices.get(&60), Some(&2)); cycle.activate_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); cycle.remove_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 1); + assert_eq!(cycle.index.get(), 1); assert_eq!(cycle.indices.get(&0), None); assert_eq!(cycle.indices.get(&10), None); assert_eq!(cycle.indices.get(&20), None); @@ -1076,11 +1116,11 @@ mod tests { assert_eq!(cycle.indices.get(&60), Some(&1)); cycle.activate_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); cycle.remove_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); assert_eq!(cycle.indices.get(&0), None); assert_eq!(cycle.indices.get(&10), None); assert_eq!(cycle.indices.get(&20), None); @@ -1090,11 +1130,11 @@ mod tests { assert_eq!(cycle.indices.get(&60), Some(&0)); cycle.activate_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); cycle.remove_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); assert_eq!(cycle.indices.get(&0), None); assert_eq!(cycle.indices.get(&10), None); assert_eq!(cycle.indices.get(&20), None); @@ -1104,11 +1144,11 @@ mod tests { assert_eq!(cycle.indices.get(&60), None); cycle.activate_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); cycle.remove_for(&Selector::AtIndex(0)); - assert_eq!(cycle.index, 0); + assert_eq!(cycle.index.get(), 0); assert_eq!(cycle.indices.get(&0), None); assert_eq!(cycle.indices.get(&10), None); assert_eq!(cycle.indices.get(&20), None); diff --git a/src/core/model.rs b/src/core/model.rs @@ -13,6 +13,7 @@ use crate::cycle::Selector; use crate::decoration::Decoration; use crate::defaults; use crate::error::StateChangeError; +use crate::identify::Ident; use crate::identify::Index; use crate::jump::JumpCriterium; use crate::layout::Layout; @@ -57,6 +58,8 @@ use winsys::window::Window; use winsys::window::WindowState; use winsys::window::WindowType; +use std::cell::Cell; +use std::cell::RefCell; use std::collections::HashMap; use std::collections::HashSet; @@ -64,23 +67,23 @@ pub struct Model<'model> { conn: &'model mut dyn Connection, zone_manager: ZoneManager, stack_manager: StackManager, - stacking_order: Vec<Window>, + stacking_order: RefCell<Vec<Window>>, pid_map: HashMap<Pid, Window>, client_map: HashMap<Window, Client, BuildIdHasher>, window_map: HashMap<Window, Window, BuildIdHasher>, frame_map: HashMap<Window, Window, BuildIdHasher>, - sticky_clients: HashSet<Window, BuildIdHasher>, - unmanaged_windows: HashSet<Window, BuildIdHasher>, - fullscreen_regions: HashMap<Window, Region, BuildIdHasher>, + sticky_clients: RefCell<HashSet<Window, BuildIdHasher>>, + unmanaged_windows: RefCell<HashSet<Window, BuildIdHasher>>, + fullscreen_regions: RefCell<HashMap<Window, Region, BuildIdHasher>>, partitions: Cycle<Partition>, workspaces: Cycle<Workspace>, move_buffer: Buffer, resize_buffer: Buffer, - prev_partition: Index, - prev_workspace: Index, + prev_partition: Cell<Index>, + prev_workspace: Cell<Index>, running: bool, - focus: Option<Window>, - jumped_from: Option<Window>, + focus: Cell<Option<Window>>, + jumped_from: Cell<Option<Window>>, } impl<'model> Model<'model> { @@ -93,23 +96,23 @@ impl<'model> Model<'model> { Self { zone_manager: ZoneManager::new(), stack_manager: StackManager::new(), - stacking_order: Vec::with_capacity(100), + stacking_order: RefCell::new(Vec::with_capacity(200)), pid_map: HashMap::new(), client_map: HashMap::with_hasher(BuildIdHasher), window_map: HashMap::with_hasher(BuildIdHasher), frame_map: HashMap::with_hasher(BuildIdHasher), - sticky_clients: HashSet::with_hasher(BuildIdHasher), - unmanaged_windows: HashSet::with_hasher(BuildIdHasher), - fullscreen_regions: HashMap::with_hasher(BuildIdHasher), + sticky_clients: RefCell::new(HashSet::with_hasher(BuildIdHasher)), + unmanaged_windows: RefCell::new(HashSet::with_hasher(BuildIdHasher)), + fullscreen_regions: RefCell::new(HashMap::with_hasher(BuildIdHasher)), partitions: Cycle::new(Vec::new(), false), workspaces: Cycle::new(Vec::with_capacity(defaults::WORKSPACE_NAMES.len()), false), move_buffer: Buffer::new(BufferKind::Move, conn.create_handle()), resize_buffer: Buffer::new(BufferKind::Resize, conn.create_handle()), - prev_partition: 0, - prev_workspace: 0, + prev_partition: Cell::new(0), + prev_workspace: Cell::new(0), running: true, - focus: None, - jumped_from: None, + focus: Cell::new(None), + jumped_from: Cell::new(None), conn, }, key_bindings, @@ -123,27 +126,33 @@ impl<'model> Model<'model> { mouse_bindings: &MouseBindings, ) -> Self { info!("initializing window manager"); - model.acquire_partitions(); - for (i, &workspace_name) in defaults::WORKSPACE_NAMES.iter().enumerate() { - let region = model - .partitions - .active_element() - .expect("no screen region found") - .screen() - .placeable_region(); - - let root_id = model.zone_manager.new_zone( - None, - ZoneContent::Layout(Layout::new(), Cycle::new(Vec::new(), true)), - ); + model.acquire_partitions(); + let screen_region = model + .partitions + .active_element() + .expect("no screen region found") + .screen() + .placeable_region(); + + defaults::WORKSPACE_NAMES + .iter() + .enumerate() + .for_each(|(i, &workspace_name)| { + let root_id = model.zone_manager.new_zone( + None, + ZoneContent::Layout(Layout::new(), Cycle::new(Vec::new(), true)), + ); - model - .workspaces - .push_back(Workspace::new(workspace_name, i as u32, root_id)); + model + .workspaces + .push_back(Workspace::new(workspace_name, i as Ident, root_id)); - model.zone_manager.zone_mut(root_id).set_region(region); - } + model + .zone_manager + .zone_mut(root_id) + .set_region(screen_region); + }); model.workspaces.activate_for(&Selector::AtIndex(0)); model.conn.set_current_desktop(0); @@ -292,6 +301,7 @@ impl<'model> Model<'model> { } } + #[inline] fn window( &self, window: Window, @@ -303,6 +313,7 @@ impl<'model> Model<'model> { Some(self.frame_map.get(&window)?.to_owned()) } + #[inline] fn frame( &self, window: Window, @@ -314,6 +325,7 @@ impl<'model> Model<'model> { Some(self.window_map.get(&window)?.to_owned()) } + #[inline] fn client_any( &self, mut window: Window, @@ -325,6 +337,7 @@ impl<'model> Model<'model> { self.client_map.get(&window) } + #[inline] fn client( &self, window: Window, @@ -332,6 +345,7 @@ impl<'model> Model<'model> { self.client_any(window).filter(|client| client.is_managed()) } + #[inline] fn workspace( &self, index: Index, @@ -339,13 +353,6 @@ impl<'model> Model<'model> { self.workspaces.get(index).unwrap() } - fn workspace_mut( - &mut self, - index: Index, - ) -> &mut Workspace { - self.workspaces.get_mut(index).unwrap() - } - fn acquire_partitions(&mut self) { let partitions: Vec<Partition> = self .conn @@ -358,66 +365,57 @@ impl<'model> Model<'model> { }) .collect(); - if partitions == self.partitions.as_vec() { - return; - } - info!("acquired partitions: {:#?}", partitions); self.partitions = Cycle::new(partitions, false); } fn apply_layout( - &mut self, + &self, index: Index, must_apply_stack: bool, ) { - info!("applying layout on workspace {}", index); - if index != self.active_workspace() { return; } + info!("applying layout on workspace {}", index); + let workspace = match self.workspaces.get(index) { Some(workspace) => workspace, None => return, }; - // TODO: zone change - let region = self.active_screen().placeable_region(); - - let placements = - workspace.arrange(&mut self.zone_manager, &self.client_map, region, |client| { - !Self::is_applyable(client) || client.is_iconified() - }); - - let (show, hide): (Vec<&Placement>, Vec<&Placement>) = placements - .iter() - .partition(|&placement| placement.region != PlacementRegion::NoRegion); + let (show, hide): (Vec<Placement>, Vec<Placement>) = workspace + .arrange( + &self.zone_manager, + &self.client_map, + self.active_screen().placeable_region(), + |client| !Self::is_applyable(client) || client.is_iconified(), + ) + .into_iter() + .partition(|placement| placement.region != PlacementRegion::NoRegion); - for placement in show { + show.iter().for_each(|placement| { match placement.kind { PlacementTarget::Client(window) => { - let frame = self.frame(window).unwrap(); - self.update_client_placement(&placement); self.place_client(window, placement.method); - self.map_client(frame); + self.map_client(self.client(window).unwrap()); }, PlacementTarget::Tab(_) => {}, PlacementTarget::Layout => {}, }; - } + }); - for placement in hide { + hide.iter().for_each(|placement| { match placement.kind { PlacementTarget::Client(window) => { - let frame = self.frame(window).unwrap(); - self.unmap_client(frame); + self.unmap_client(self.client(window).unwrap()); }, PlacementTarget::Tab(_) => {}, PlacementTarget::Layout => {}, }; - } + }); if must_apply_stack { self.apply_stack(index); @@ -425,9 +423,13 @@ impl<'model> Model<'model> { } fn apply_stack( - &mut self, + &self, index: Index, ) { + if index != self.active_workspace() { + return; + } + info!("applying stack on workspace {}", index); let workspace = match self.workspaces.get(index) { @@ -438,28 +440,24 @@ impl<'model> Model<'model> { let desktop = self.stack_manager.layer_windows(StackLayer::Desktop); let below = self.stack_manager.layer_windows(StackLayer::Below); let dock = self.stack_manager.layer_windows(StackLayer::Dock); + let above = self.stack_manager.layer_windows(StackLayer::Above); + let notification = self.stack_manager.layer_windows(StackLayer::Notification); - let stack: Vec<Window> = workspace + let stack = workspace .stack_after_focus() .into_iter() .map(|window| self.frame(window).unwrap()) - .collect(); + .collect::<Vec<Window>>(); let (regular, fullscreen): (Vec<Window>, Vec<Window>) = stack.iter().partition(|&&window| { - self.client(window).map_or(false, |client| { - !client.is_fullscreen() || client.is_in_window() - }) - }); - - let (free, regular): (Vec<Window>, Vec<Window>) = - regular.into_iter().partition(|&window| { - self.client(window) - .map_or(true, |client| self.is_free(client)) + let client = self.client(window).unwrap(); + !client.is_fullscreen() || client.is_in_window() }); - let above = self.stack_manager.layer_windows(StackLayer::Above); - let notification = self.stack_manager.layer_windows(StackLayer::Notification); + let (free, regular): (Vec<Window>, Vec<Window>) = regular + .into_iter() + .partition(|&window| self.is_free(self.client(window).unwrap())); let mut windows: Vec<Window> = desktop .into_iter() @@ -473,82 +471,78 @@ impl<'model> Model<'model> { .into_iter() .collect(); - { - // handle above-other relationships - for &window in self.stack_manager.above_other().keys() { - let index = windows.iter().position(|&w| w == window); - - if let Some(index) = index { - windows.remove(index); - } + // handle above-other relationships + self.stack_manager.above_other().keys().for_each(|&window| { + if let Some(index) = windows.iter().position(|&candidate| candidate == window) { + windows.remove(index); } + }); - for (&window, &sibling) in self.stack_manager.above_other() { - let index = windows.iter().position(|&w| w == sibling); - - if let Some(index) = index { + self.stack_manager + .above_other() + .iter() + .for_each(|(&window, &sibling)| { + if let Some(index) = windows.iter().position(|&candidate| candidate == sibling) { if index < windows.len() { windows.insert(index + 1, window); } } - } - } - - { - // handle below-other relationships - for &window in self.stack_manager.below_other().keys() { - let index = windows.iter().position(|&w| w == window); + }); - if let Some(index) = index { - windows.remove(index); - } + // handle below-other relationships + self.stack_manager.below_other().keys().for_each(|&window| { + if let Some(index) = windows.iter().position(|&candidate| candidate == window) { + windows.remove(index); } + }); - for (&window, &sibling) in self.stack_manager.below_other() { - let index = windows.iter().position(|&w| w == sibling); - - if let Some(index) = index { + self.stack_manager + .below_other() + .iter() + .for_each(|(&window, &sibling)| { + if let Some(index) = windows.iter().position(|&candidate| candidate == sibling) { windows.insert(index, window); } - } - } + }); - let mut stack_walk = windows.iter(); + let mut stack_iter = windows.iter(); + let mut prev_window = stack_iter.next().cloned(); let mut order_changed = false; - let mut prev_window = stack_walk.next().cloned(); + let stacking_order = self.stacking_order.borrow(); - for (i, &window) in stack_walk.enumerate() { - order_changed |= self.stacking_order.get(i + 1) != Some(&window); + stack_iter.enumerate().for_each(|(i, &window)| { + order_changed |= stacking_order.get(i + 1) != Some(&window); if order_changed { self.conn.stack_window_above(window, prev_window); } prev_window = Some(window); - } - - self.stacking_order = windows; + }); if !order_changed { return; } - // TODO: keep separate client Vec, open-ended hash iteration not efficient - let mut client_list: Vec<&Client> = self.client_map.values().collect::<Vec<&Client>>(); + drop(stacking_order); + self.stacking_order.replace(windows); + + let mut client_list = self.client_map.values().collect::<Vec<&Client>>(); client_list.sort_by_key(|&a| a.managed_since()); - let client_list: Vec<Window> = client_list + let client_list = client_list .into_iter() .map(|client| client.window()) - .collect(); + .collect::<Vec<Window>>(); + self.conn.update_client_list(&client_list); - let stack_windows: Vec<Window> = stack + let mut client_list_stacking = client_list; + let stack_windows = stack .into_iter() .map(|window| self.window(window).unwrap()) - .collect(); + .collect::<Vec<Window>>(); - let mut client_list_stacking = client_list; client_list_stacking.retain(|&window| !stack_windows.contains(&window)); client_list_stacking = client_list_stacking .iter() @@ -607,7 +601,7 @@ impl<'model> Model<'model> { } self.conn.init_unmanaged(window); - self.unmanaged_windows.insert(window); + self.unmanaged_windows.borrow_mut().insert(window); return; } @@ -781,7 +775,7 @@ impl<'model> Model<'model> { self.conn.set_window_desktop(window, workspace); self.apply_layout(workspace, false); - self.focus(window); + self.focus_window(window); if let Some(ppid) = ppid { if let Some(ppid_window) = self.pid_map.get(&ppid) { @@ -823,53 +817,51 @@ impl<'model> Model<'model> { } fn remanage( - &mut self, - window: Window, + &self, + client: &Client, must_alter_workspace: bool, ) { - if let Some(client) = self.client_any(window) { - if client.is_managed() { - return; - } + if client.is_managed() { + return; + } - info!("remanaging client with window {:#0x}", client.window()); + info!("remanaging client with window {:#0x}", client.window()); - let window = client.window(); - let active_workspace = self.active_workspace(); - let mut workspace = active_workspace; + let window = client.window(); + let active_workspace = self.active_workspace(); + let mut workspace = active_workspace; - if must_alter_workspace { - let leader = client.leader(); + if must_alter_workspace { + let leader = client.leader(); - if let Some(leader) = leader { - if let Some(leader) = self.client(leader) { - workspace = leader.workspace(); - } + if let Some(leader) = leader { + if let Some(leader) = self.client(leader) { + workspace = leader.workspace(); } + } - { - let workspace = self.workspace_mut(workspace); + { + let workspace = self.workspace(workspace); - if !workspace.contains(window) { - workspace.add_client(window, &InsertPos::Back); - } + if !workspace.contains(window) { + workspace.add_client(window, &InsertPos::Back); } - - let client = self.client_any(window).unwrap(); - client.set_workspace(workspace); } let client = self.client_any(window).unwrap(); - client.set_managed(true); + client.set_workspace(workspace); + } + + let client = self.client_any(window).unwrap(); + client.set_managed(true); + let client = self.client_any(window).unwrap(); + if client.is_sticky() { let client = self.client_any(window).unwrap(); - if client.is_sticky() { - let client = self.client_any(window).unwrap(); - client.set_sticky(false); + client.set_sticky(false); - self.stick(window); - self.map_client(window); - } + self.stick(window); + self.map_client(client); } } @@ -891,10 +883,10 @@ impl<'model> Model<'model> { let window = client.window(); let workspace = client.workspace(); - self.unmap_client(window); + self.unmap_client(client); { - let workspace = self.workspace_mut(workspace); + let workspace = self.workspace(workspace); if workspace.contains(window) { workspace.remove_client(window); @@ -917,7 +909,7 @@ impl<'model> Model<'model> { ZoneContent::Layout(Layout::new(), Cycle::new(Vec::new(), true)), ); - let workspace = self.workspace_mut(workspace_index); + let workspace = self.workspace(workspace_index); workspace.add_zone(id, &InsertPos::Back); self.apply_layout(workspace_index, true); } @@ -932,7 +924,7 @@ impl<'model> Model<'model> { .zone_manager .new_zone(Some(cycle), ZoneContent::Tab(Cycle::new(Vec::new(), true))); - let workspace = self.workspace_mut(workspace_index); + let workspace = self.workspace(workspace_index); workspace.add_zone(id, &InsertPos::Back); self.apply_layout(workspace_index, true); } @@ -950,7 +942,7 @@ impl<'model> Model<'model> { self.zone_manager.remove_zone(cycle); - let workspace = self.workspace_mut(workspace_index); + let workspace = self.workspace(workspace_index); workspace.remove_zone(cycle); } @@ -1005,12 +997,15 @@ impl<'model> Model<'model> { self.unstick(window); } - if Some(window) == self.jumped_from { - self.jumped_from = None; + if Some(window) == self.jumped_from.get() { + self.jumped_from.set(None); } - if producer.is_some() { - self.unconsume_client(window); + if let Some(producer) = producer { + let producer = self.client_any(producer); + if let Some(producer) = producer { + self.unconsume_client(producer); + } } if let Some(parent) = parent { @@ -1031,7 +1026,7 @@ impl<'model> Model<'model> { self.window_map.remove(&window); self.client_map.remove(&window); self.pid_map.remove(&window); - self.fullscreen_regions.remove(&window); + self.fullscreen_regions.borrow_mut().remove(&window); self.sync_focus(); } @@ -1087,12 +1082,13 @@ impl<'model> Model<'model> { } fn update_client_placement( - &mut self, + &self, placement: &Placement, ) { match placement.kind { PlacementTarget::Client(window) => { let client = self.client(window).unwrap(); + let region = match placement.region { PlacementRegion::FreeRegion => client.free_region(), PlacementRegion::NewRegion(region) => region, @@ -1106,7 +1102,7 @@ impl<'model> Model<'model> { let id = client.zone(); client.set_region(PlacementClass::Free(region)); - let zone = self.zone_manager.zone_mut(id); + let zone = self.zone_manager.zone(id); zone.set_region(region); zone.set_method(placement.method); }, @@ -1114,7 +1110,7 @@ impl<'model> Model<'model> { let id = client.zone(); client.set_region(PlacementClass::Tile(region)); - let zone = self.zone_manager.zone_mut(id); + let zone = self.zone_manager.zone(id); zone.set_method(placement.method); }, }; @@ -1145,39 +1141,31 @@ impl<'model> Model<'model> { } fn map_client( - &mut self, - window: Window, + &self, + client: &Client, ) { - if let Some(client) = self.client(window) { - if !client.is_mapped() { - let (window, frame) = client.windows(); - - info!("mapping client with window {:#0x}", window); - self.conn.map_window(window); - self.conn.map_window(frame); - self.redraw_client(window); + if !client.is_mapped() { + let (window, frame) = client.windows(); - let client = self.client(window).unwrap(); - client.set_mapped(true); - } + info!("mapping client with window {:#0x}", window); + self.conn.map_window(window); + self.conn.map_window(frame); + self.redraw_client(window); + client.set_mapped(true); } } fn unmap_client( - &mut self, - window: Window, + &self, + client: &Client, ) { - if let Some(client) = self.client(window) { - if client.is_mapped() { - let client = self.client(window).unwrap(); - let (window, frame) = client.windows(); - - info!("unmapping client with window {:#0x}", window); - client.set_mapped(false); - client.expect_unmap(); + if client.is_mapped() { + let (window, frame) = client.windows(); - self.conn.unmap_window(frame); - } + info!("unmapping client with window {:#0x}", window); + self.conn.unmap_window(frame); + client.expect_unmap(); + client.set_mapped(false); } } @@ -1216,7 +1204,7 @@ impl<'model> Model<'model> { consumer.set_producer(producer_window); if consumer_len == 0 { - let producer_workspace = self.workspace_mut(producer_workspace_index); + let producer_workspace = self.workspace(producer_workspace_index); if producer_workspace_index == consumer_workspace_index { producer_workspace.replace_client(producer_window, consumer_window); @@ -1233,70 +1221,59 @@ impl<'model> Model<'model> { } fn unconsume_client( - &mut self, - consumer: Window, + &self, + consumer: &Client, ) { - let consumer_window = consumer; - let consumer = self.client_any(consumer_window); - - if consumer.is_none() { - return; - } - - let consumer = consumer.unwrap(); - let producer_window = consumer.producer(); - let consumer_workspace = consumer.workspace(); - - if producer_window.is_none() { - return; - } - - let producer_window = producer_window.unwrap(); + let (producer, workspace) = match consumer + .producer() + .and_then(|window| self.client_any(window)) + { + Some(producer) => (producer, consumer.workspace()), + None => return, + }; info!( "unconsuming client with window {:#0x} and producer window {:#0x}", - consumer_window, producer_window + consumer.window(), + producer.window() ); - if self.client_map.contains_key(&producer_window) { - let producer = self.client_any(producer_window).unwrap(); - producer.remove_consumer(consumer_window); - let consumer_len = producer.consumer_len(); + producer.remove_consumer(consumer.window()); - if consumer_len == 0 { - producer.set_workspace(consumer_workspace); + if producer.consumer_len() == 0 { + producer.set_workspace(workspace); - if let Some(workspace) = self.workspaces.get_mut(consumer_workspace) { - if workspace.contains(consumer_window) { - workspace.replace_client(consumer_window, producer_window); - } else { - workspace.add_client(producer_window, &InsertPos::Back); - } - } - - self.remanage(producer_window, false); + { + let workspace = self.workspace(workspace); - if consumer_workspace == self.active_workspace() { - self.map_client(producer_window); + if workspace.contains(consumer.window()) { + workspace.replace_client(consumer.window(), producer.window()); + } else { + workspace.add_client(producer.window(), &InsertPos::Back); } + } - self.apply_layout(consumer_workspace, true); + self.remanage(producer, false); + + if workspace == self.active_workspace() { + self.map_client(producer); } + + self.apply_layout(workspace, true); } - let consumer = self.client_any(consumer_window).unwrap(); consumer.unset_producer(); consumer.set_consuming(false); } - pub fn kill_focus(&mut self) { - if let Some(focus) = self.focus { + pub fn kill_focus(&self) { + if let Some(focus) = self.focus.get() { self.kill_client(focus); } } pub fn kill_client( - &mut self, + &self, mut window: Window, ) { if let Some(client) = self.client_any(window) { @@ -1341,7 +1318,7 @@ impl<'model> Model<'model> { .and_then(|ws| ws.cycle_focus(dir, client_map, zone_manager)); if let Some((_, window)) = windows { - self.focus(window); + self.focus_window(window); self.sync_focus(); } } @@ -1350,14 +1327,14 @@ impl<'model> Model<'model> { &mut self, dir: Direction, ) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { let workspace_index = self.active_workspace(); self.workspaces .get_mut(workspace_index) .and_then(|ws| ws.drag_focus(dir)); self.apply_layout(workspace_index, false); - self.focus(focus); + self.focus_window(focus); } } @@ -1366,14 +1343,14 @@ impl<'model> Model<'model> { dir: Direction, ) { let workspace_index = self.active_workspace(); - let workspace = self.workspace_mut(workspace_index); + let workspace = self.workspace(workspace_index); let next_window = workspace.next_client(dir.rev()); workspace.rotate_clients(dir); self.apply_layout(workspace_index, false); if let Some(window) = next_window { - self.focus(window); + self.focus_window(window); } } @@ -1403,7 +1380,7 @@ impl<'model> Model<'model> { } pub fn center_focus(&mut self) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { self.center_client(focus); } } @@ -1426,13 +1403,13 @@ impl<'model> Model<'model> { } pub fn move_focus_to_next_workspace(&mut self) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { self.move_client_to_next_workspace(focus); } } pub fn move_focus_to_prev_workspace(&mut self) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { self.move_client_to_prev_workspace(focus); } } @@ -1441,7 +1418,7 @@ impl<'model> Model<'model> { &mut self, index: Index, ) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { self.move_client_to_workspace(focus, index); } } @@ -1495,18 +1472,19 @@ impl<'model> Model<'model> { ); // add client to requested workspace - let workspace = self.workspace_mut(index); + let workspace = self.workspace(index); workspace.add_client(window, &InsertPos::Back); // remove client from current_index workspace - let workspace = self.workspace_mut(current_index); + let workspace = self.workspace(current_index); workspace.remove_client(window); - self.unmap_client(window); - self.apply_layout(current_index, true); - self.sync_focus(); let client = self.client(window).unwrap(); client.set_workspace(index); + self.unmap_client(client); + + self.apply_layout(current_index, true); + self.sync_focus(); } pub fn toggle_screen_struts(&mut self) { @@ -1531,18 +1509,18 @@ impl<'model> Model<'model> { self.apply_layout(workspace_index, false); } - pub fn toggle_workspace(&mut self) { - self.activate_workspace(self.prev_workspace); + pub fn toggle_workspace(&self) { + self.activate_workspace(self.prev_workspace.get()); } - pub fn activate_next_workspace(&mut self) { + pub fn activate_next_workspace(&self) { let index = self.active_workspace() + 1; let index = index % self.workspaces.len(); self.activate_workspace(index); } - pub fn activate_prev_workspace(&mut self) { + pub fn activate_prev_workspace(&self) { let index = if self.active_workspace() == 0 { self.workspaces.len() - 1 } else { @@ -1553,7 +1531,7 @@ impl<'model> Model<'model> { } pub fn activate_workspace( - &mut self, + &self, index: Index, ) { if index == self.active_workspace() || index >= self.workspaces.len() { @@ -1565,50 +1543,34 @@ impl<'model> Model<'model> { self.stop_moving(); self.stop_resizing(); - self.prev_workspace = self.workspaces.active_index(); - let mut clients_to_map = Vec::with_capacity(20); - let mut windows_to_unmap = Vec::with_capacity(20); + let prev_workspace = self.workspaces.active_index(); + self.prev_workspace.set(prev_workspace); - let workspace_index = self.active_workspace(); - let workspace = self.workspace(workspace_index); - - workspace.on_each_client_mut(&self.client_map, |client| { - if client.is_mapped() && !client.is_sticky() { - windows_to_unmap.push(client.window()); - } - }); - - self.workspaces.activate_for(&Selector::AtIndex(index)); - - let workspace_index = self.active_workspace(); - let workspace = self.workspace(workspace_index); - - workspace.on_each_client_mut(&self.client_map, |client| { - if !client.is_mapped() { - clients_to_map.push(client.window()); - } - }); - - clients_to_map - .into_iter() - .for_each(|window| self.map_client(window)); + self.workspace(index) + .on_each_client(&self.client_map, |client| { + if !client.is_mapped() { + self.map_client(client); + } + }); - windows_to_unmap - .into_iter() - .for_each(|window| self.unmap_client(window)); + self.workspace(prev_workspace) + .on_each_client(&self.client_map, |client| { + if client.is_mapped() && !client.is_sticky() { + self.unmap_client(client); + } + }); - let sticky_windows = self.sticky_clients.iter().copied().collect::<Vec<_>>(); - sticky_windows.into_iter().for_each(|window| { - if let Some(client) = self.client(window) { - client.set_workspace(index); - } + self.sticky_clients.borrow().iter().for_each(|&window| { + self.client(window).unwrap().set_workspace(index); }); - self.apply_layout(self.active_workspace(), true); + self.workspaces.activate_for(&Selector::AtIndex(index)); + self.apply_layout(index, true); self.sync_focus(); self.conn.set_current_desktop(index); } + #[inline] pub fn change_gap_size( &mut self, change: Change<u32>, @@ -1623,6 +1585,7 @@ impl<'model> Model<'model> { Ok(()) } + #[inline] pub fn copy_prev_layout_data(&mut self) -> Result<(), StateChangeError> { let workspace_index = self.active_workspace(); @@ -1634,6 +1597,7 @@ impl<'model> Model<'model> { Ok(()) } + #[inline] pub fn reset_layout_data(&mut self) -> Result<(), StateChangeError> { let workspace_index = self.active_workspace(); @@ -1645,6 +1609,7 @@ impl<'model> Model<'model> { Ok(()) } + #[inline] pub fn reset_gap_size(&mut self) -> Result<(), StateChangeError> { let workspace_index = self.active_workspace(); @@ -1656,6 +1621,7 @@ impl<'model> Model<'model> { Ok(()) } + #[inline] pub fn change_main_count( &mut self, change: Change<u32>, @@ -1670,6 +1636,7 @@ impl<'model> Model<'model> { Ok(()) } + #[inline] pub fn change_main_factor( &mut self, change: Change<f32>, @@ -1684,6 +1651,7 @@ impl<'model> Model<'model> { Ok(()) } + #[inline] pub fn change_margin( &mut self, edge: Edge, @@ -1699,6 +1667,7 @@ impl<'model> Model<'model> { Ok(()) } + #[inline] pub fn reset_margin(&mut self) -> Result<(), StateChangeError> { let workspace_index = self.active_workspace(); @@ -1710,12 +1679,13 @@ impl<'model> Model<'model> { Ok(()) } + #[inline] pub fn set_layout( &mut self, kind: LayoutKind, ) -> Result<(), StateChangeError> { let workspace_index = self.active_workspace(); - let workspace = self.workspace_mut(workspace_index); + let workspace = self.workspace(workspace_index); if let Some(id) = workspace.active_focus_zone() { info!( @@ -1730,9 +1700,10 @@ impl<'model> Model<'model> { Ok(()) } + #[inline] pub fn toggle_layout(&mut self) { let workspace_index = self.active_workspace(); - let workspace = self.workspace_mut(workspace_index); + let workspace = self.workspace(workspace_index); if let Some(id) = workspace.active_focus_zone() { let prev_kind = self.zone_manager.set_prev_kind(id); @@ -1746,8 +1717,9 @@ impl<'model> Model<'model> { } } + #[inline] pub fn toggle_in_window_focus(&mut self) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { if let Some(client) = self.client(focus) { let must_in_window = !client.is_in_window(); client.set_in_window(must_in_window); @@ -1761,8 +1733,9 @@ impl<'model> Model<'model> { } } + #[inline] pub fn toggle_invincible_focus(&mut self) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { if let Some(client) = self.client(focus) { let must_invincible = !client.is_invincible(); client.set_invincible(must_invincible); @@ -1770,8 +1743,9 @@ impl<'model> Model<'model> { } } + #[inline] pub fn toggle_producing_focus(&mut self) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { if let Some(client) = self.client(focus) { let must_producing = !client.is_producing(); client.set_producing(must_producing); @@ -1779,8 +1753,9 @@ impl<'model> Model<'model> { } } + #[inline] pub fn toggle_float_focus(&mut self) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { self.toggle_float_client(focus); } } @@ -1810,104 +1785,104 @@ impl<'model> Model<'model> { } } + #[inline] fn active_partition(&self) -> usize { self.partitions.active_index() } + #[inline] fn active_screen(&self) -> &Screen { self.partitions.active_element().unwrap().screen() } + #[inline] fn active_screen_mut(&mut self) -> &mut Screen { self.partitions.active_element_mut().unwrap().screen_mut() } + #[inline] pub fn active_workspace(&self) -> usize { self.workspaces.active_index() } - fn window_workspace( - &self, - window: Window, - ) -> Option<usize> { - self.client(window).map(|c| c.workspace()) - } - + #[inline] fn focused_client(&self) -> Option<&Client> { self.focus + .get() .or_else(|| self.workspace(self.active_workspace()).focused_client()) .and_then(|id| self.client_map.get(&id)) } - fn focused_client_mut(&mut self) -> Option<&mut Client> { - self.focus - .or_else(|| self.workspace(self.active_workspace()).focused_client()) - .and_then(move |id| self.client_map.get_mut(&id)) + #[inline] + fn focus_window( + &self, + window: Window, + ) { + if let Some(client) = self.client(window) { + self.focus(client); + } } fn focus( - &mut self, - window: Window, + &self, + client: &Client, ) { - if let Some(frame) = self.frame(window) { - if let Some(window) = self.window(window) { - if Some(window) == self.focus { - return; - } + let (window, frame) = client.windows(); - info!("focusing client with window {:#0x}", window); + if Some(window) == self.focus.get() { + return; + } - let active_workspace_index = self.active_workspace(); - let client = self.client(window); + info!("focusing client with window {:#0x}", window); - if !self.is_focusable(window) { - return; - } + let active_workspace_index = self.active_workspace(); + let client = self.client(window); - let client = client.unwrap(); - let client_workspace_index = client.workspace(); - let id = client.zone(); + if !self.is_focusable(window) { + return; + } - if client_workspace_index != active_workspace_index { - self.activate_workspace(client_workspace_index); - } + let client = client.unwrap(); + let client_workspace_index = client.workspace(); + let id = client.zone(); - if let Some(prev_focus) = self.focus { - self.unfocus(prev_focus); - } + if client_workspace_index != active_workspace_index { + self.activate_workspace(client_workspace_index); + } - self.conn.ungrab_buttons(frame); + if let Some(prev_focus) = self.focus.get() { + self.unfocus(prev_focus); + } - if let Some(client) = self.client(window) { - client.set_focused(true); - client.set_urgent(false); - } + self.conn.ungrab_buttons(frame); - self.zone_manager.activate_zone(id); - let cycle = self.zone_manager.nearest_cycle(id); + if let Some(client) = self.client(window) { + client.set_focused(true); + client.set_urgent(false); + } - self.workspaces.get_mut(client_workspace_index).map(|ws| { - ws.activate_zone(cycle); - ws.focus_client(window); - }); + self.zone_manager.activate_zone(id); + let cycle = self.zone_manager.nearest_cycle(id); - if self.zone_manager.is_within_persisent(id) { - self.apply_layout(client_workspace_index, false); - } + let workspace = self.workspace(client_workspace_index); + workspace.activate_zone(cycle); + workspace.focus_client(window); - if self.conn.get_focused_window() != window { - self.conn.focus_window(window); - } + if self.zone_manager.is_within_persisent(id) { + self.apply_layout(client_workspace_index, false); + } - self.focus = Some(window); - self.redraw_client(window); - self.apply_stack(client_workspace_index); - } + if self.conn.get_focused_window() != window { + self.conn.focus_window(window); } + + self.focus.set(Some(window)); + self.redraw_client(window); + self.apply_stack(client_workspace_index); } fn unfocus( - &mut self, + &self, window: Window, ) { if let Some(client) = self.client(window) { @@ -1925,24 +1900,24 @@ impl<'model> Model<'model> { } } - fn sync_focus(&mut self) { + fn sync_focus(&self) { let workspace_index = self.active_workspace(); - let workspace = self.workspace_mut(workspace_index); + let workspace = self.workspace(workspace_index); if !workspace.is_empty() { if let Some(ws_focus) = workspace.focused_client() { - if Some(ws_focus) != self.focus { - self.focus(ws_focus); + if Some(ws_focus) != self.focus.get() { + self.focus_window(ws_focus); } } } else { self.conn.unfocus(); - self.focus = None; + self.focus.set(None); } } pub fn toggle_fullscreen_focus(&mut self) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { self.toggle_fullscreen_client(focus); } } @@ -2055,9 +2030,9 @@ impl<'model> Model<'model> { }, }; - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { if window == focus { - let jumped_from = self.jumped_from; + let jumped_from = self.jumped_from.get(); if jumped_from.is_none() || jumped_from == Some(focus) { return; @@ -2068,11 +2043,11 @@ impl<'model> Model<'model> { } } - self.jumped_from = Some(focus); + self.jumped_from.set(Some(focus)); } info!("jumping to client with window {:#0x}", window); - self.focus(window); + self.focus_window(window); } fn fullscreen( @@ -2087,7 +2062,9 @@ impl<'model> Model<'model> { self.conn .set_window_state(window, WindowState::Fullscreen, true); - self.fullscreen_regions.insert(window, free_region); + self.fullscreen_regions + .borrow_mut() + .insert(window, free_region); let client = self.client(window).unwrap(); client.set_fullscreen(true); @@ -2105,7 +2082,11 @@ impl<'model> Model<'model> { ) { if let Some(client) = self.client(window) { let window = client.window(); - let free_region = self.fullscreen_regions.get(&window).map(|&region| region); + let free_region = self + .fullscreen_regions + .borrow() + .get(&window) + .map(|&region| region); info!("disabling fullscreen for client with window {:#0x}", window); @@ -2125,12 +2106,12 @@ impl<'model> Model<'model> { self.apply_layout(workspace, true); } - self.fullscreen_regions.remove(&window); + self.fullscreen_regions.borrow_mut().remove(&window); } } pub fn toggle_stick_focus(&mut self) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { if let Some(client) = self.client(focus) { if client.is_sticky() { self.unstick(focus); @@ -2142,7 +2123,7 @@ impl<'model> Model<'model> { } fn stick( - &mut self, + &self, window: Window, ) { let client = self.client(window); @@ -2160,9 +2141,9 @@ impl<'model> Model<'model> { client.set_sticky(true); self.conn .set_window_state(window, WindowState::Sticky, true); - self.sticky_clients.insert(window); + self.sticky_clients.borrow_mut().insert(window); - for workspace in self.workspaces.iter_mut() { + for workspace in self.workspaces.iter() { if workspace.number() as Index != workspace_index { workspace.add_client(window, &InsertPos::Back); } @@ -2172,7 +2153,7 @@ impl<'model> Model<'model> { } fn unstick( - &mut self, + &self, window: Window, ) { let client = self.client(window); @@ -2191,9 +2172,9 @@ impl<'model> Model<'model> { self.conn .set_window_state(window, WindowState::Sticky, false); - self.sticky_clients.remove(&window); + self.sticky_clients.borrow_mut().remove(&window); - for workspace in self.workspaces.iter_mut() { + for workspace in self.workspaces.iter() { if workspace.number() as Index != workspace_index { workspace.remove_client(window); workspace.remove_icon(window); @@ -2204,7 +2185,7 @@ impl<'model> Model<'model> { } pub fn iconify_focus(&mut self) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { if let Some(client) = self.client(focus) { if !client.is_iconified() { self.iconify(focus); @@ -2256,11 +2237,11 @@ impl<'model> Model<'model> { info!("iconifying client with window {:#0x}", window); client.set_iconified(true); - self.unmap_client(window); + self.unmap_client(client); self.conn .set_icccm_window_state(window, IcccmWindowState::Iconic); - let workspace = self.workspace_mut(workspace_index); + let workspace = self.workspace(workspace_index); workspace.client_to_icon(window); self.sync_focus(); self.apply_layout(workspace_index, true); @@ -2283,11 +2264,11 @@ impl<'model> Model<'model> { info!("deiconifying client with window {:#0x}", window); client.set_iconified(false); - self.map_client(window); + self.map_client(client); self.conn .set_icccm_window_state(window, IcccmWindowState::Normal); - let workspace = self.workspace_mut(workspace_index); + let workspace = self.workspace(workspace_index); workspace.icon_to_client(window); self.sync_focus(); self.apply_layout(workspace_index, true); @@ -2297,7 +2278,7 @@ impl<'model> Model<'model> { &mut self, edge: Edge, ) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { self.snap_client(focus, edge); } } @@ -2353,7 +2334,7 @@ impl<'model> Model<'model> { edge: Edge, step: i32, ) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { self.nudge_client(focus, edge, step); } } @@ -2463,7 +2444,7 @@ impl<'model> Model<'model> { edge: Edge, step: i32, ) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { self.stretch_client(focus, edge, step); } } @@ -2553,7 +2534,7 @@ impl<'model> Model<'model> { } pub fn start_moving( - &mut self, + &self, window: Window, ) { if !self.move_buffer.is_occupied() && !self.resize_buffer.is_occupied() { @@ -2573,7 +2554,7 @@ impl<'model> Model<'model> { } } - pub fn stop_moving(&mut self) { + pub fn stop_moving(&self) { if self.move_buffer.is_occupied() { self.conn.release_pointer(); self.move_buffer.unset(); @@ -2611,7 +2592,7 @@ impl<'model> Model<'model> { } pub fn start_resizing( - &mut self, + &self, window: Window, ) { if !self.move_buffer.is_occupied() && !self.resize_buffer.is_occupied() { @@ -2628,7 +2609,7 @@ impl<'model> Model<'model> { } } - pub fn stop_resizing(&mut self) { + pub fn stop_resizing(&self) { if self.resize_buffer.is_occupied() { self.conn.release_pointer(); self.resize_buffer.unset(); @@ -2756,9 +2737,9 @@ impl<'model> Model<'model> { if *moves_focus { // TODO: config.focus_follows_mouse - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { if window != focus { - self.focus(window); + self.focus_window(window); } } } @@ -2804,18 +2785,18 @@ impl<'model> Model<'model> { if *moves_focus { // TODO: config.focus_follows_mouse - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { if window != focus { - self.focus(window); + self.focus_window(window); } } } } else { // TODO: config.focus_follows_mouse if event.kind != MouseEventKind::Release { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { if window != focus { - self.focus(window); + self.focus_window(window); } } } @@ -2936,13 +2917,13 @@ impl<'model> Model<'model> { debug!("ENTER for window {:#0x}", window); if let Some(window) = self.window(window) { - if let Some(focus) = self.focus { + if let Some(focus) = self.focus.get() { if focus != window { self.unfocus(focus); } } - self.focus(window); + self.focus_window(window); } } @@ -2971,7 +2952,7 @@ impl<'model> Model<'model> { self.apply_layout(active_workspace, true); } - self.unmanaged_windows.remove(&window); + self.unmanaged_windows.borrow_mut().remove(&window); let client = self.client_any(window); @@ -2989,7 +2970,7 @@ impl<'model> Model<'model> { } if !is_managed { - self.remanage(window, true); + self.remanage(client, true); } let client = self.client_any(window).unwrap(); @@ -3022,7 +3003,7 @@ impl<'model> Model<'model> { ) { debug!("UNMAP for window {:#0x}", window); - if self.unmanaged_windows.contains(&window) { + if self.unmanaged_windows.borrow().contains(&window) { return; } @@ -3127,7 +3108,7 @@ impl<'model> Model<'model> { debug!("FOCUS_REQUEST for window {:#0x}", window); if !on_root { - self.focus(window); + self.focus_window(window); } } diff --git a/src/core/workspace.rs b/src/core/workspace.rs @@ -372,7 +372,7 @@ impl Workspace { pub fn arrange<F>( &self, - zone_manager: &mut ZoneManager, + zone_manager: &ZoneManager, client_map: &HashMap<Window, Client, BuildIdHasher>, screen_region: Region, ignore_filter: F, @@ -381,7 +381,7 @@ impl Workspace { F: Fn(&Client) -> bool, { if !self.clients.borrow().is_empty() { - let zone = zone_manager.zone_mut(self.root_zone); + let zone = zone_manager.zone(self.root_zone); zone.set_region(screen_region); let (to_ignore_ids, to_ignore_clients): (Vec<_>, Vec<_>) = self diff --git a/src/core/zone.rs b/src/core/zone.rs @@ -20,6 +20,7 @@ use crate::placement::PlacementTarget; use winsys::geometry::Region; use winsys::window::Window; +use std::cell::Cell; use std::collections::HashMap; use std::sync::atomic; use std::vec::Vec; @@ -27,9 +28,7 @@ use std::vec::Vec; pub type ZoneId = u32; static INSTANCE_COUNT: atomic::AtomicU32 = atomic::AtomicU32::new(1); -fn next_id() -> ZoneId { - INSTANCE_COUNT.fetch_add(1, atomic::Ordering::Relaxed) as ZoneId -} + #[derive(Debug, PartialEq)] pub enum ZoneContent { Client(Window), @@ -40,30 +39,34 @@ pub enum ZoneContent { #[derive(Debug)] pub struct Zone { id: ZoneId, - parent: Option<ZoneId>, - method: PlacementMethod, + parent: Cell<Option<ZoneId>>, + method: Cell<PlacementMethod>, content: ZoneContent, - region: Region, - decoration: Decoration, - is_visible: bool, + region: Cell<Region>, + decoration: Cell<Decoration>, + is_visible: Cell<bool>, } impl Zone { + fn next_id() -> ZoneId { + INSTANCE_COUNT.fetch_add(1, atomic::Ordering::Relaxed) as ZoneId + } + fn new( parent: Option<ZoneId>, content: ZoneContent, region: Region, ) -> (ZoneId, Self) { - let id = next_id(); + let id = Self::next_id(); (id, Self { id, - parent, - method: PlacementMethod::Free, + parent: Cell::new(parent), + method: Cell::new(PlacementMethod::Free), content, - region, - decoration: Decoration::NO_DECORATION, - is_visible: true, + region: Cell::new(region), + decoration: Cell::new(Decoration::NO_DECORATION), + is_visible: Cell::new(true), }) } @@ -99,17 +102,17 @@ impl Zone { } pub fn set_region( - &mut self, + &self, region: Region, ) { - self.region = region; + self.region.set(region); } pub fn set_method( - &mut self, + &self, method: PlacementMethod, ) { - self.method = method; + self.method.set(method); } pub fn default_data(&self) -> Option<LayoutData> { @@ -148,7 +151,7 @@ impl Zone { } pub fn method(&self) -> PlacementMethod { - self.method + self.method.get() } } @@ -209,14 +212,14 @@ impl ZoneManager { } pub fn activate_zone( - &mut self, + &self, id: ZoneId, ) { if let Some(cycle_id) = self.next_cycle(id) { - let cycle = self.zone_mut(cycle_id); + let cycle = self.zone(cycle_id); match cycle.content { - ZoneContent::Tab(ref mut zones) | ZoneContent::Layout(_, ref mut zones) => { + ZoneContent::Tab(ref zones) | ZoneContent::Layout(_, ref zones) => { zones.activate_for(&Selector::AtIdent(id)); self.activate_zone(cycle_id); }, @@ -337,7 +340,7 @@ impl ZoneManager { &self, id: ZoneId, ) -> Option<ZoneId> { - self.zone_map.get(&id).and_then(|zone| zone.parent) + self.zone_map.get(&id).and_then(|zone| zone.parent.get()) } pub fn cycle_config( @@ -378,7 +381,7 @@ impl ZoneManager { _ => {}, } - if let Some(parent) = zone.parent { + if let Some(parent) = zone.parent.get() { next = parent; } else { panic!("no nearest cycle found"); @@ -455,20 +458,20 @@ impl ZoneManager { } } - return Vec::with_capacity(0); + Vec::with_capacity(0) } /// Arrange a zone and all of its subzones within the region /// of the supplied zone pub fn arrange( - &mut self, + &self, zone: ZoneId, to_ignore: &Vec<ZoneId>, ) -> Vec<Placement> { let cycle = self.nearest_cycle(zone); let zone = self.zone_map.get(&cycle).unwrap(); - let region = zone.region; - let decoration = zone.decoration; + let region = zone.region.get(); + let decoration = zone.decoration.get(); let method = match &zone.content { ZoneContent::Tab(_) => PlacementMethod::Tile, @@ -480,7 +483,7 @@ impl ZoneManager { } fn arrange_subzones( - &mut self, + &self, id: ZoneId, region: Region, decoration: Decoration, @@ -589,7 +592,7 @@ impl ZoneManager { let (region, decoration) = match disposition { Disposition::Unchanged(decoration) => { let zone = self.zone_map.get(&id).unwrap(); - (zone.region, decoration) + (zone.region.get(), decoration) }, Disposition::Changed(region, decoration) => (region, decoration), }; @@ -642,27 +645,27 @@ impl ZoneManager { }; { - let zone = self.zone_map.get_mut(&id).unwrap(); - zone.region = region; - zone.decoration = decoration; - zone.method = method; + let zone = self.zone_map.get(&id).unwrap(); + zone.region.set(region); + zone.decoration.set(decoration); + zone.method.set(method); } zone_changes.into_iter().for_each(|(id, change)| { - let zone = self.zone_map.get_mut(&id).unwrap(); + let zone = self.zone_map.get(&id).unwrap(); match change { ZoneChange::Visible(is_visible) => { - zone.is_visible = is_visible; + zone.is_visible.set(is_visible); }, ZoneChange::Region(region) => { - zone.region = region; + zone.region.set(region); }, ZoneChange::Decoration(decoration) => { - zone.decoration = decoration; + zone.decoration.set(decoration); }, ZoneChange::Method(method) => { - zone.method = method; + zone.method.set(method); }, }; }); diff --git a/src/winsys/connection.rs b/src/winsys/connection.rs @@ -39,10 +39,10 @@ pub trait Connection { pos: Pos, ); fn confine_pointer( - &mut self, + &self, window: Window, ); - fn release_pointer(&mut self); + fn release_pointer(&self); fn is_mapping_request( &self, request: u8, diff --git a/src/winsys/xdata/xconnection.rs b/src/winsys/xdata/xconnection.rs @@ -27,6 +27,7 @@ use crate::window::WindowState; use crate::window::WindowType; use crate::Result; +use std::cell::Cell; use std::collections::HashMap; use std::convert::TryFrom; use std::str::FromStr; @@ -175,7 +176,7 @@ pub struct XConnection<'conn, Conn: connection::Connection> { check_window: Window, background_gc: xproto::Gcontext, database: Option<Database>, - confined_to: Option<Window>, + confined_to: Cell<Option<Window>>, root_event_mask: EventMask, window_event_mask: EventMask, @@ -315,7 +316,7 @@ impl<'conn, Conn: connection::Connection> XConnection<'conn, Conn> { check_window, background_gc, database, - confined_to: None, + confined_to: Cell::new(None), root_event_mask, window_event_mask, @@ -1119,10 +1120,10 @@ impl<'conn, Conn: connection::Connection> Connection for XConnection<'conn, Conn #[inline] fn confine_pointer( - &mut self, + &self, window: Window, ) { - if self.confined_to.is_none() { + if self.confined_to.get().is_none() { if self .conn .grab_pointer( @@ -1145,18 +1146,18 @@ impl<'conn, Conn: connection::Connection> Connection for XConnection<'conn, Conn xproto::GrabMode::ASYNC, )); - self.confined_to = Some(window); + self.confined_to.set(Some(window)); } } } #[inline] - fn release_pointer(&mut self) { - if self.confined_to.is_some() { + fn release_pointer(&self) { + if self.confined_to.get().is_some() { drop(self.conn.ungrab_pointer(x11rb::CURRENT_TIME)); drop(self.conn.ungrab_keyboard(x11rb::CURRENT_TIME)); - self.confined_to = None; + self.confined_to.set(None); } }