From e924e8efc0b6058e612122f6731a5d1ec6fa9ef9 Mon Sep 17 00:00:00 2001 From: NoOneBtw Date: Mon, 10 May 2021 21:28:41 +0200 Subject: [PATCH] added screenshot keybinds, fixed focus behaviour --- src/clients.rs | 70 +++++++++++++++++------- src/main.rs | 1 + src/state.rs | 146 +++++++++++++++++++++++++++++-------------------- src/xlib.rs | 46 ++++++++++++++-- 4 files changed, 182 insertions(+), 81 deletions(-) diff --git a/src/clients.rs b/src/clients.rs index 02c45d0..cd65dc1 100644 --- a/src/clients.rs +++ b/src/clients.rs @@ -155,6 +155,7 @@ struct VirtualScreen { struct VirtualScreenStore { screens: Vec, current_idx: usize, + last_idx: Option, } impl Default for ClientState { @@ -274,6 +275,14 @@ impl ClientState { self.floating_clients.iter() } + pub fn iter_floating_visible( + &self, + ) -> impl Iterator { + self.floating_clients + .iter() + .filter(move |&(k, _)| self.is_client_visible(k)) + } + fn iter_all_clients(&self) -> impl Iterator { self.floating_clients.iter().chain(self.clients.iter()) } @@ -292,18 +301,6 @@ impl ClientState { .filter(move |&(k, _)| self.is_client_visible(k)) } - #[allow(dead_code)] - pub fn iter_visible_ordered( - &self, - ) -> impl Iterator { - self.iter_master_stack() - .chain( - self.iter_floating() - .filter(move |&(k, _)| self.is_client_visible(k)), - ) - .chain(self.iter_aux_stack()) - } - #[allow(dead_code)] pub fn iter_current_screen(&self) -> impl Iterator { self.clients.iter().filter(move |&(k, _)| { @@ -380,6 +377,12 @@ impl ClientState { } } + pub fn go_to_nth_virtualscreen(&mut self, n: usize) { + self.virtual_screens.go_to_nth(n); + + self.arrange_virtual_screen(); + } + pub fn rotate_right(&mut self, n: usize) { self.virtual_screens .rotate_right(n.rem(self.virtual_screens.len())); @@ -394,6 +397,12 @@ impl ClientState { self.arrange_virtual_screen(); } + pub fn rotate_back(&mut self) { + self.virtual_screens.go_back(); + + self.arrange_virtual_screen(); + } + /** Sets a tiled client to floating and returns true, does nothing for a floating client and returns false. If this function returns `true` you have to call `arrange_clients` after. @@ -785,6 +794,7 @@ impl VirtualScreenStore { Self { screens, current_idx: 0, + last_idx: None, } } @@ -808,20 +818,42 @@ impl VirtualScreenStore { self.screens.iter_mut() } - fn rotate_left(&mut self, n: usize) { - let l = self.screens.len(); - let a = n % l; - let b = self.current_idx % l; - - self.current_idx = ((b + l) + a) % l; + fn go_back(&mut self) -> usize { + self.last_idx + .and_then(|n| Some(self.go_to_nth(n))) + .unwrap_or(self.current_idx) } - fn rotate_right(&mut self, n: usize) { + fn rotate_left(&mut self, n: usize) -> usize { + self.last_idx = Some(self.current_idx); + let l = self.screens.len(); let a = n % l; let b = self.current_idx % l; self.current_idx = ((b + l) - a) % l; + + self.current_idx + } + + fn rotate_right(&mut self, n: usize) -> usize { + self.last_idx = Some(self.current_idx); + + let l = self.screens.len(); + let a = n % l; + let b = self.current_idx % l; + + self.current_idx = ((b + l) + a) % l; + + self.current_idx + } + + fn go_to_nth(&mut self, n: usize) -> usize { + self.last_idx = Some(self.current_idx); + + self.current_idx = n % self.screens.len(); + + self.current_idx } } diff --git a/src/main.rs b/src/main.rs index 424de3c..0a391d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ use log4rs::{ use state::WMConfig; mod clients; +mod clients2; mod state; mod util; mod xlib; diff --git a/src/state.rs b/src/state.rs index d6f6332..04c49ee 100644 --- a/src/state.rs +++ b/src/state.rs @@ -34,7 +34,6 @@ pub struct WindowManager { keybinds: Vec, xlib: XLib, - last_rotation: Option, config: WMConfig, } @@ -85,7 +84,6 @@ impl WindowManager { move_resize_window: MoveResizeInfo::None, keybinds: Vec::new(), xlib, - last_rotation: None, config, } .init() @@ -131,11 +129,34 @@ impl WindowManager { }, )); + self.add_keybind(KeyBinding::new( + self.xlib.make_key("Print", 0), + |wm, _| wm.spawn("screenshot.sh", &[]), + )); + + self.add_keybind(KeyBinding::new( + self.xlib.make_key("Print", ShiftMask), + |wm, _| wm.spawn("screenshot.sh", &["-edit"]), + )); + self.add_keybind(KeyBinding::new( self.xlib.make_key("M", self.config.mod_key), Self::handle_switch_stack, )); + self.add_keybind(KeyBinding::new( + self.xlib.make_key("F", self.config.mod_key), + |wm, _| { + wm.clients + .get_focused() + .into_option() + .map(|c| c.key()) + .and_then(|k| Some(wm.clients.toggle_floating(&k))); + + wm.arrange_clients(); + }, + )); + self.add_keybind(KeyBinding::new( self.xlib.make_key("Q", self.config.mod_key), Self::kill_client, @@ -146,11 +167,6 @@ impl WindowManager { |wm, _| wm.quit(), )); - self.add_keybind(KeyBinding::new( - self.xlib.make_key("T", self.config.mod_key), - |wm, _| wm.spawn("alacritty", &[]), - )); - self.add_keybind(KeyBinding::new( self.xlib .make_key("Return", self.config.mod_key | ShiftMask), @@ -216,6 +232,10 @@ impl WindowManager { wm.rotate_virtual_screen(Direction::East(N)); } + fn goto_nth(wm: &mut WindowManager, _: &XKeyEvent) { + wm.go_to_nth_virtual_screen(N) + } + // Old keybinds self.add_keybind(KeyBinding::new( @@ -243,66 +263,66 @@ impl WindowManager { |wm, _| wm.rotate_virtual_screen_back(), )); - // Mod + (Shift) + Num + // Mod + Num - // Press Mod + `1` to move `1` virtual screen to the right + // Press Mod + `1` to move go to the `1`th virtual screen self.add_keybind(KeyBinding::new( self.xlib.make_key("1", self.config.mod_key), - rotate_east::<1>, + goto_nth::<1>, )); - // Press Mod + Shift + `1` to move `1` virtual screen to the left - self.add_keybind(KeyBinding::new( - self.xlib.make_key("1", self.config.mod_key | ShiftMask), - rotate_west::<1>, - )); - - // Press Mod + `2` to move `2` virtual screen to the right + // Press Mod + `2` to move go to the `2`th virtual screen self.add_keybind(KeyBinding::new( self.xlib.make_key("2", self.config.mod_key), - rotate_east::<2>, + goto_nth::<2>, )); - // Press Mod + Shift + `2` to move `2` virtual screen to the left - self.add_keybind(KeyBinding::new( - self.xlib.make_key("2", self.config.mod_key | ShiftMask), - rotate_west::<2>, - )); - - // Press Mod + `3` to move `3` virtual screen to the right + // Press Mod + `3` to move go to the `3`th virtual screen self.add_keybind(KeyBinding::new( self.xlib.make_key("3", self.config.mod_key), - rotate_east::<3>, + goto_nth::<3>, )); - // Press Mod + Shift + `3` to move `3` virtual screen to the left - self.add_keybind(KeyBinding::new( - self.xlib.make_key("3", self.config.mod_key | ShiftMask), - rotate_west::<3>, - )); - - // Press Mod + `4` to move `4` virtual screen to the right + // Press Mod + `4` to move go to the `4`th virtual screen self.add_keybind(KeyBinding::new( self.xlib.make_key("4", self.config.mod_key), - rotate_east::<4>, + goto_nth::<4>, )); - // Press Mod + Shift + `4` to move `4` virtual screen to the left - self.add_keybind(KeyBinding::new( - self.xlib.make_key("4", self.config.mod_key | ShiftMask), - rotate_west::<4>, - )); - - // Press Mod + `5` to move `5` virtual screen to the right + // Press Mod + `5` to move go to the `5`th virtual screen self.add_keybind(KeyBinding::new( self.xlib.make_key("5", self.config.mod_key), - rotate_east::<5>, + goto_nth::<5>, )); - // Press Mod + Shift + `5` to move `5` virtual screen to the left + // Press Mod + `6` to move go to the `6`th virtual screen self.add_keybind(KeyBinding::new( - self.xlib.make_key("5", self.config.mod_key | ShiftMask), - rotate_west::<5>, + self.xlib.make_key("6", self.config.mod_key), + goto_nth::<6>, + )); + + // Press Mod + `7` to move go to the `7`th virtual screen + self.add_keybind(KeyBinding::new( + self.xlib.make_key("7", self.config.mod_key), + goto_nth::<7>, + )); + + // Press Mod + `8` to move go to the `8`th virtual screen + self.add_keybind(KeyBinding::new( + self.xlib.make_key("8", self.config.mod_key), + goto_nth::<8>, + )); + + // Press Mod + `9` to move go to the `9`th virtual screen + self.add_keybind(KeyBinding::new( + self.xlib.make_key("9", self.config.mod_key), + goto_nth::<9>, + )); + + // Press Mod + `0` to move go to the `0`th virtual screen + self.add_keybind(KeyBinding::new( + self.xlib.make_key("0", self.config.mod_key), + goto_nth::<10>, )); } @@ -365,16 +385,19 @@ impl WindowManager { } fn rotate_virtual_screen_back(&mut self) { - if let Some(dir) = self.last_rotation { - self.rotate_virtual_screen(!dir); - } + self.clients.rotate_back(); + + self.arrange_clients(); + } + + fn go_to_nth_virtual_screen(&mut self, n: usize) { + self.clients.go_to_nth_virtualscreen(n - 1); + self.arrange_clients(); } fn rotate_virtual_screen(&mut self, dir: Direction) { info!("rotateing VS: {:?}", dir); - self.last_rotation = Some(dir); - match dir { Direction::West(n) => self.clients.rotate_left(n), Direction::East(n) => self.clients.rotate_right(n), @@ -382,7 +405,6 @@ impl WindowManager { } self.arrange_clients(); - self.focus_any(); } fn focus_any(&mut self) { @@ -400,7 +422,8 @@ impl WindowManager { let k = self .clients - .iter_master_stack() + .iter_floating_visible() + .chain(self.clients.iter_master_stack()) .map(|(k, _)| k) // get the first client on the stack thats not already focused .filter(|&&k| focused.map(|f| f != k).unwrap_or(true)) @@ -417,7 +440,8 @@ impl WindowManager { let k = self .clients - .iter_aux_stack() + .iter_floating_visible() + .chain(self.clients.iter_aux_stack()) .map(|(k, _)| k) // get the first client on the stack thats not already focused .filter(|&&k| focused.map(|f| f != k).unwrap_or(true)) @@ -498,15 +522,21 @@ impl WindowManager { } fn arrange_clients(&mut self) { - self.clients - .iter_visible() - .for_each(|(_, c)| self.xlib.move_resize_client(c)); + self.clients.iter_visible().for_each(|(_, c)| { + self.xlib.move_resize_client(c); + //self.xlib.expose_client(c); + }); self.hide_hidden_clients(); self.raise_floating_clients(); - if self.clients.get_focused().is_vacant() { + // if no visible client is focused, focus any. + if !self + .clients + .iter_visible() + .any(|(k, _)| self.clients.is_focused(k)) + { self.focus_any(); } } @@ -760,7 +790,7 @@ impl KeyBinding { impl Default for WMConfig { fn default() -> Self { Self { - num_virtualscreens: 5, + num_virtualscreens: 10, mod_key: Mod4Mask, gap: Some(2), } diff --git a/src/xlib.rs b/src/xlib.rs index d7633fc..a5c8f6f 100644 --- a/src/xlib.rs +++ b/src/xlib.rs @@ -11,7 +11,7 @@ use x11::xlib::{ Window, XCloseDisplay, XConfigureRequestEvent, XDefaultScreen, XEvent, XGetTransientForHint, XGrabPointer, XInternAtom, XKillClient, XMapWindow, XOpenDisplay, XRaiseWindow, XRootWindow, XSetErrorHandler, XSync, - XUngrabButton, XUngrabKey, XUngrabPointer, XWarpPointer, + XUngrabButton, XUngrabKey, XUngrabPointer, XWarpPointer, XWindowAttributes, }; use xlib::GrabModeAsync; @@ -234,7 +234,7 @@ impl XLib { ); } - self.send_event(client, self.atoms.take_focus); + self.send_protocol(client, self.atoms.take_focus); } pub fn unfocus_client(&self, client: &Client) { @@ -391,6 +391,24 @@ impl XLib { } } + fn get_window_attributes( + &self, + window: Window, + ) -> Option { + let mut wa = unsafe { + std::mem::MaybeUninit::::zeroed() + .assume_init() + }; + + if unsafe { + xlib::XGetWindowAttributes(self.dpy(), window, &mut wa) != 0 + } { + Some(wa) + } else { + None + } + } + pub fn get_transient_for_window(&self, window: Window) -> Option { let mut transient_for: Window = 0; @@ -403,6 +421,26 @@ impl XLib { } } + pub fn expose_client(&self, client: &Client) { + self.expose_window(client.window); + } + + fn expose_window(&self, window: Window) { + if let Some(wa) = self.get_window_attributes(window) { + unsafe { + xlib::XClearArea( + self.dpy(), + window, + 0, + 0, + wa.width as u32, + wa.height as u32, + 1, + ); + } + } + } + pub fn configure_window(&self, event: &XConfigureRequestEvent) { let mut wc = xlib::XWindowChanges { x: event.x, @@ -496,7 +534,7 @@ impl XLib { } pub fn kill_client(&self, client: &Client) { - if !self.send_event(client, self.atoms.delete_window) { + if !self.send_protocol(client, self.atoms.delete_window) { unsafe { XKillClient(self.dpy(), client.window); } @@ -565,7 +603,7 @@ impl XLib { return false; } - fn send_event(&self, client: &Client, proto: xlib::Atom) -> bool { + fn send_protocol(&self, client: &Client, proto: xlib::Atom) -> bool { if self.check_for_protocol(client, proto) { let mut data = xlib::ClientMessageData::default(); data.set_long(0, proto as i64);