fixed some bugs related to floating window stacking
This commit is contained in:
		
							parent
							
								
									95d7740119
								
							
						
					
					
						commit
						134e727b25
					
				|  | @ -1,3 +1,2 @@ | |||
| imports_granularity = "Crate" | ||||
| wrap_comments = true | ||||
| #wrap_comments = true | ||||
| max_width = 80 | ||||
							
								
								
									
										185
									
								
								src/clients.rs
									
									
									
									
									
								
							
							
						
						
									
										185
									
								
								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<Window> for Client { | ||||
|     fn borrow(&self) -> &Window { | ||||
|     &self.window | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     impl ClientKey for Rc<Client> { | ||||
|     fn key(&self) -> u64 { | ||||
|     self.window | ||||
|     } | ||||
|     } | ||||
|     impl<'a> Borrow<dyn ClientKey + 'a> for Client { | ||||
|     fn borrow(&self) -> &(dyn ClientKey + 'a) { | ||||
|         self | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     impl<'a> Borrow<dyn ClientKey + 'a> for Rc<Client> { | ||||
|     fn borrow(&self) -> &(dyn ClientKey + 'a) { | ||||
|         self | ||||
|     } | ||||
|     } | ||||
|     */ | ||||
| } | ||||
| 
 | ||||
| pub use client::*; | ||||
|  | @ -218,56 +193,15 @@ pub enum ClientEntry<T> { | |||
|     Vacant, | ||||
| } | ||||
| 
 | ||||
| impl<T> Into<Option<T>> for ClientEntry<T> { | ||||
|     fn into(self) -> Option<T> { | ||||
|         match self { | ||||
|             Self::Vacant => None, | ||||
|             Self::Tiled(client) | Self::Floating(client) => Some(client), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T> ClientEntry<T> { | ||||
|     pub fn into_option(self) -> Option<T> { | ||||
|         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<ClientRef>, | ||||
|     pub(self) virtual_screens: VecDeque<VirtualScreen>, | ||||
| 
 | ||||
|     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::<VirtualScreen>::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<K>(&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<usize>) { | ||||
|         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<usize>) { | ||||
|         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<K>(&mut self, key: &K) | ||||
|     where | ||||
|         K: ClientKey, | ||||
|     { | ||||
|         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<i32>, | ||||
|     ) { | ||||
|         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<T> Into<Option<T>> for ClientEntry<T> { | ||||
|     fn into(self) -> Option<T> { | ||||
|         match self { | ||||
|             Self::Vacant => None, | ||||
|             Self::Tiled(client) | Self::Floating(client) => Some(client), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T> ClientEntry<T> { | ||||
|     pub fn into_option(self) -> Option<T> { | ||||
|         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() | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ fn main() { | |||
| 
 | ||||
|     log_prologue(); | ||||
| 
 | ||||
|     state::WindowManager::new(WMConfig::default()).init().run(); | ||||
|     state::WindowManager::new(WMConfig::default()).run(); | ||||
| } | ||||
| 
 | ||||
| fn log_prologue() { | ||||
|  |  | |||
							
								
								
									
										67
									
								
								src/state.rs
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								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<usize>), | ||||
|     Right(Option<usize>), | ||||
| } | ||||
| 
 | ||||
| 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<K>(&mut self, key: &K) | ||||
|     fn focus_client<K>(&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() { | ||||
|         match new { | ||||
|             ClientEntry::Floating(new) => { | ||||
|                 self.xlib.focus_client(new); | ||||
| 
 | ||||
|                 if try_raise { | ||||
|                     self.xlib.raise_client(new); | ||||
|                 } | ||||
| 
 | ||||
|         self.raise_floating_clients(); | ||||
|             } | ||||
|             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), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -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(), | ||||
|  |  | |||
							
								
								
									
										2
									
								
								xinitrc
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								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 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue