From 134e727b25a73b59b7ee80c6f621d45270d2b38c Mon Sep 17 00:00:00 2001 From: NoOneBtw Date: Tue, 4 May 2021 18:52:08 +0200 Subject: [PATCH] fixed some bugs related to floating window stacking --- rustfmt.toml | 3 +- src/clients.rs | 189 ++++++++++++++++++++++++++----------------------- src/main.rs | 2 +- src/state.rs | 71 ++++++++++--------- src/xlib.rs | 4 +- xinitrc | 2 +- 6 files changed, 142 insertions(+), 129 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index 385cc57..fa14856 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,2 @@ -imports_granularity = "Crate" -wrap_comments = true +#wrap_comments = true max_width = 80 \ No newline at end of file diff --git a/src/clients.rs b/src/clients.rs index 274b98f..8a14056 100644 --- a/src/clients.rs +++ b/src/clients.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] -use std::collections::HashMap; use std::num::NonZeroI32; +use std::{collections::HashMap, ops::Rem, usize}; use log::{error, info}; @@ -113,31 +113,6 @@ mod client { self.to_owned() } } - - /* - impl Borrow for Client { - fn borrow(&self) -> &Window { - &self.window - } - } - - impl ClientKey for Rc { - fn key(&self) -> u64 { - self.window - } - } - impl<'a> Borrow for Client { - fn borrow(&self) -> &(dyn ClientKey + 'a) { - self - } - } - - impl<'a> Borrow for Rc { - fn borrow(&self) -> &(dyn ClientKey + 'a) { - self - } - } - */ } pub use client::*; @@ -218,56 +193,15 @@ pub enum ClientEntry { Vacant, } -impl Into> for ClientEntry { - fn into(self) -> Option { - match self { - Self::Vacant => None, - Self::Tiled(client) | Self::Floating(client) => Some(client), - } - } -} - -impl ClientEntry { - pub fn into_option(self) -> Option { - self.into() - } - - pub fn unwrap(self) -> T { - self.into_option().unwrap() - } - - pub fn is_vacant(&self) -> bool { - match self { - ClientEntry::Vacant => true, - _ => false, - } - } - - pub fn is_floating(&self) -> bool { - match self { - ClientEntry::Floating(_) => true, - _ => false, - } - } - - pub fn is_tiled(&self) -> bool { - match self { - ClientEntry::Tiled(_) => true, - _ => false, - } - } - - pub fn is_occupied(&self) -> bool { - !self.is_vacant() - } -} - #[derive(Debug, Clone)] pub struct ClientState { pub(self) clients: Clients, pub(self) floating_clients: Clients, focused: Option, pub(self) virtual_screens: VecDeque, + + gap: i32, + screen_size: (i32, i32), } #[derive(Debug, Clone)] @@ -286,6 +220,8 @@ impl Default for ClientState { floating_clients: Default::default(), focused: None, virtual_screens: vss, + gap: 0, + screen_size: (1, 1), } } } @@ -295,13 +231,24 @@ impl ClientState { Self::default() } - pub fn with_virtualscreens(num: usize) -> Self { + pub fn with_gap(self, gap: i32) -> Self { + Self { gap, ..self } + } + + pub fn with_screen_size(self, screen_size: (i32, i32)) -> Self { + Self { + screen_size, + ..self + } + } + + pub fn with_virtualscreens(self, num: usize) -> Self { let mut vss = VecDeque::::new(); vss.resize_with(num, Default::default); Self { virtual_screens: vss, - ..Default::default() + ..self } } @@ -333,6 +280,9 @@ impl ClientState { self.focus_client(&key); + // adding a client changes the liling layout, rearrange + self.arrange_virtual_screen(); + // TODO: eventually make this function return a `ClientEntry` instead of an `Option`. self.get(&key).into_option() } @@ -351,6 +301,9 @@ impl ClientState { self.clients.remove(&key.key()); self.floating_clients.remove(&key.key()); + + // removing a client changes the liling layout, rearrange + self.arrange_virtual_screen(); } pub fn contains(&self, key: &K) -> bool @@ -460,12 +413,18 @@ impl ClientState { } } - pub fn rotate_right(&mut self) { - self.virtual_screens.rotate_right(1); + pub fn rotate_right(&mut self, n: Option) { + self.virtual_screens + .rotate_right(n.unwrap_or(1).rem(self.virtual_screens.len())); + + self.arrange_virtual_screen(); } - pub fn rotate_left(&mut self) { - self.virtual_screens.rotate_left(1); + pub fn rotate_left(&mut self, n: Option) { + self.virtual_screens + .rotate_left(n.unwrap_or(1).rem(self.virtual_screens.len())); + + self.arrange_virtual_screen(); } /** @@ -508,6 +467,7 @@ impl ClientState { true => { self.floating_clients.insert(key, floating_client); } + false => { self.clients.insert(key, floating_client); if let Some(vs) = self.virtual_screens.front_mut() { @@ -520,14 +480,22 @@ impl ClientState { error!("wtf? Client was present in tiled and floating list.") } }; + + // we added or removed a client from the tiling so the layout changed, rearrange + self.arrange_virtual_screen(); } fn remove_from_virtual_screens(&mut self, key: &K) where K: ClientKey, { - if let Some(vs) = self.get_mut_virtualscreen_for_client(key) { - vs.remove(key); + if self.contains(key) { + if let Some(vs) = self.get_mut_virtualscreen_for_client(key) { + vs.remove(key); + + // we removed a client so the layout changed, rearrange + self.arrange_virtual_screen(); + } } } @@ -578,7 +546,9 @@ impl ClientState { if focused == key.key() { (ClientEntry::Vacant, ClientEntry::Vacant) } else { - // focus the new client and return reference to it and the previously focused client. + // focus the new client and return reference to it + // and the previously focused client. + self.focused = Some(key.key()); (self.get(key), self.get(&focused)) } @@ -599,7 +569,8 @@ impl ClientState { } /** - sets `self.focused` to `None` and returns a reference to the previously focused Client if any. + sets `self.focused` to `None` and returns a reference to + the previously focused Client if any. */ pub fn unfocus(&mut self) -> ClientEntry<&Client> { match self.focused { @@ -627,6 +598,8 @@ impl ClientState { { if let Some(vs) = self.get_mut_virtualscreen_for_client(key) { vs.switch_stack_for_client(key); + + self.arrange_virtual_screen(); } } @@ -635,13 +608,9 @@ impl ClientState { screen width and screen height. Optionally adds a gap between windows `gap.unwrap_or(0)` pixels wide. */ - pub fn arrange_virtual_screen( - &mut self, - width: i32, - height: i32, - gap: Option, - ) { - let gap = gap.unwrap_or(0); + pub fn arrange_virtual_screen(&mut self) { + let gap = self.gap; + let (width, height) = self.screen_size; // should be fine to unwrap since we will always have at least 1 virtual screen if let Some(vs) = self.virtual_screens.front_mut() { @@ -692,7 +661,7 @@ impl ClientState { } } - info!("{:#?}", self); + //info!("{:#?}", self); } // Should have xlib send those changes back to the x server after this function @@ -777,3 +746,47 @@ impl VirtualScreen { } } } + +impl Into> for ClientEntry { + fn into(self) -> Option { + match self { + Self::Vacant => None, + Self::Tiled(client) | Self::Floating(client) => Some(client), + } + } +} + +impl ClientEntry { + pub fn into_option(self) -> Option { + self.into() + } + + pub fn unwrap(self) -> T { + self.into_option().unwrap() + } + + pub fn is_vacant(&self) -> bool { + match self { + ClientEntry::Vacant => true, + _ => false, + } + } + + pub fn is_floating(&self) -> bool { + match self { + ClientEntry::Floating(_) => true, + _ => false, + } + } + + pub fn is_tiled(&self) -> bool { + match self { + ClientEntry::Tiled(_) => true, + _ => false, + } + } + + pub fn is_occupied(&self) -> bool { + !self.is_vacant() + } +} diff --git a/src/main.rs b/src/main.rs index 2a56f87..bb9b3da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,7 +45,7 @@ fn main() { log_prologue(); - state::WindowManager::new(WMConfig::default()).init().run(); + state::WindowManager::new(WMConfig::default()).run(); } fn log_prologue() { diff --git a/src/state.rs b/src/state.rs index 7175903..24194ca 100644 --- a/src/state.rs +++ b/src/state.rs @@ -13,7 +13,7 @@ use xlib::{ }; use crate::{ - clients::{Client, ClientKey, ClientState}, + clients::{Client, ClientEntry, ClientKey, ClientState}, xlib::KeyOrButton, xlib::XLib, }; @@ -40,8 +40,8 @@ pub struct WindowManager { #[derive(Debug, Clone, Copy)] pub enum Direction { - Left, - Right, + Left(Option), + Right(Option), } enum MoveResizeInfo { @@ -70,10 +70,13 @@ struct KeyBinding { impl WindowManager { pub fn new(config: WMConfig) -> Self { - let clients = - ClientState::with_virtualscreens(config.num_virtualscreens); let xlib = XLib::new(); + let clients = ClientState::new() + .with_virtualscreens(config.num_virtualscreens) + .with_gap(config.gap.unwrap_or(1)) + .with_screen_size(xlib.dimensions()); + Self { clients, move_resize_window: MoveResizeInfo::None, @@ -82,9 +85,10 @@ impl WindowManager { last_rotation: None, config, } + .init() } - pub fn init(mut self) -> Self { + fn init(mut self) -> Self { self.xlib.add_global_keybind(KeyOrButton::button( 1, self.config.mod_key, @@ -152,12 +156,12 @@ impl WindowManager { self.add_keybind(KeyBinding::new( self.xlib.make_key("Left", self.config.mod_key), - |wm, _| wm.rotate_virtual_screen(Direction::Left), + |wm, _| wm.rotate_virtual_screen(Direction::Left(None)), )); self.add_keybind(KeyBinding::new( self.xlib.make_key("Right", self.config.mod_key), - |wm, _| wm.rotate_virtual_screen(Direction::Right), + |wm, _| wm.rotate_virtual_screen(Direction::Right(None)), )); self.add_keybind(KeyBinding::new( @@ -177,12 +181,12 @@ impl WindowManager { self.add_keybind(KeyBinding::new( self.xlib.make_key("J", self.config.mod_key | ShiftMask), - |wm, _| wm.rotate_virtual_screen(Direction::Left), + |wm, _| wm.rotate_virtual_screen(Direction::Left(None)), )); self.add_keybind(KeyBinding::new( self.xlib.make_key("K", self.config.mod_key | ShiftMask), - |wm, _| wm.rotate_virtual_screen(Direction::Right), + |wm, _| wm.rotate_virtual_screen(Direction::Right(None)), )); self.xlib.init(); @@ -262,8 +266,8 @@ impl WindowManager { self.last_rotation = Some(dir); match dir { - Direction::Left => self.clients.rotate_left(), - Direction::Right => self.clients.rotate_right(), + Direction::Left(n) => self.clients.rotate_left(n), + Direction::Right(n) => self.clients.rotate_right(n), } self.arrange_clients(); @@ -273,7 +277,7 @@ impl WindowManager { self.clients.iter_visible().next().map(|(k, _)| k).cloned(); if let Some(key) = to_focus { - self.focus_client(&key); + self.focus_client(&key, false); } } @@ -286,7 +290,7 @@ impl WindowManager { .cloned(); if let Some(k) = k { - self.focus_client(&k); + self.focus_client(&k, false); } } @@ -299,7 +303,7 @@ impl WindowManager { .cloned(); if let Some(k) = k { - self.focus_client(&k); + self.focus_client(&k, false); } } @@ -320,10 +324,6 @@ impl WindowManager { } fn arrange_clients(&mut self) { - let (width, height) = self.xlib.dimensions(); - self.clients - .arrange_virtual_screen(width, height, self.config.gap); - self.clients .iter_visible() .for_each(|(_, c)| self.xlib.move_resize_client(c)); @@ -333,7 +333,7 @@ impl WindowManager { self.raise_floating_clients(); } - fn focus_client(&mut self, key: &K) + fn focus_client(&mut self, key: &K, try_raise: bool) where K: ClientKey, { @@ -343,12 +343,19 @@ impl WindowManager { self.xlib.unfocus_client(old); } - if let Some(new) = new.into_option() { - self.xlib.focus_client(new); - self.xlib.raise_client(new); - } + match new { + ClientEntry::Floating(new) => { + self.xlib.focus_client(new); - self.raise_floating_clients(); + if try_raise { + self.xlib.raise_client(new); + } + } + ClientEntry::Tiled(new) => { + self.xlib.focus_client(new); + } + _ => {} + } } fn new_client(&mut self, window: Window) { @@ -368,7 +375,7 @@ impl WindowManager { self.clients.insert(client).unwrap(); self.xlib.map_window(window); - self.focus_client(&window); + self.focus_client(&window, true); self.arrange_clients(); } @@ -377,15 +384,12 @@ impl WindowManager { let event: &XMapRequestEvent = event.as_ref(); if !self.clients.contains(&event.window) { - info!("MapRequest: new client: {:?}", event.window); - self.new_client(event.window); } } fn unmap_notify(&mut self, event: &XEvent) { let event: &XUnmapEvent = event.as_ref(); - info!("unmap_notify: {:?}", event.window); self.clients.remove(&event.window); @@ -394,7 +398,6 @@ impl WindowManager { fn destroy_notify(&mut self, event: &XEvent) { let event: &XDestroyWindowEvent = event.as_ref(); - info!("destroy_notify: {:?}", event.window); self.clients.remove(&event.window); @@ -413,7 +416,7 @@ impl WindowManager { fn enter_notify(&mut self, event: &XEvent) { let event: &XCrossingEvent = event.as_ref(); - self.focus_client(&event.window); + self.focus_client(&event.window, false); } /// ensure event.subwindow refers to a valid client. @@ -514,7 +517,7 @@ impl WindowManager { } fn button_press(&mut self, event: &XButtonPressedEvent) { - self.focus_client(&event.subwindow); + self.focus_client(&event.subwindow, true); match event.button { 1 | 3 => match self.move_resize_window { @@ -587,8 +590,8 @@ impl std::ops::Not for Direction { fn not(self) -> Self::Output { match self { - Direction::Left => Direction::Right, - Direction::Right => Direction::Left, + Direction::Left(n) => Direction::Right(n), + Direction::Right(n) => Direction::Left(n), } } } diff --git a/src/xlib.rs b/src/xlib.rs index d374c6c..131170b 100644 --- a/src/xlib.rs +++ b/src/xlib.rs @@ -216,12 +216,10 @@ impl XLib { } self.send_event(client, self.atoms.take_focus); - - self.raise_client(client); } pub fn unfocus_client(&self, client: &Client) { - info!("unfocusing client: {:?}", client); + //info!("unfocusing client: {:?}", client); unsafe { xlib::XSetInputFocus( self.dpy(), diff --git a/xinitrc b/xinitrc index 2ddca22..d002ad4 100644 --- a/xinitrc +++ b/xinitrc @@ -4,4 +4,4 @@ /usr/bin/xsetroot -solid darkslategrey /usr/bin/feh --bg-fill "/mnt/storage/rust/wm/starship.jpg" export RUST_BACKTRACE=1 -exec /mnt/storage/rust/wm/target/debug/wm >& /home/user/.local/portlights.log +exec /mnt/storage/rust/wm/target/release/wm >& /home/user/.local/portlights.log