diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/clients/mod.rs | 68 | ||||
-rw-r--r-- | src/config.rs | 14 | ||||
-rw-r--r-- | src/helpers.rs | 15 |
3 files changed, 86 insertions, 11 deletions
diff --git a/src/clients/mod.rs b/src/clients/mod.rs index 4ebd634..70ffb00 100644 --- a/src/clients/mod.rs +++ b/src/clients/mod.rs @@ -1,6 +1,6 @@ //! Tracking and managing windows. -use std::cmp::Ordering; +use std::{cmp::Ordering, mem}; use crate::{ buttons, @@ -323,6 +323,72 @@ impl ClientState { self.refocus(conn, new_idx); } + /// Shift the focused client up (increase = false) or down (increase = true) the client list + pub fn shift_focused_client(&mut self, conn: &Connection<'_>, increase: bool) { + // We always want to place it after/before the next/previous one on the focused tag + let Some(target) = self.focused_client else { + return; + }; + let mon_idx = self.client_mon_idx(target); + let tag_focus = self.mons[mon_idx].focused_tag; + let look_through = self + .clients + .iter() + .enumerate() + .filter(|(_, c)| tag_focus.matches(c.tag)) + .filter(|(_, c)| c.tiled()) + .map(|(i, _)| i); + + let new_idx = if increase { + look_through + .cycle() + .skip_while(|i| *i != target) + .nth(1) + .unwrap_or(0) + } else { + look_through + .rev() + .cycle() + .skip_while(|i| *i != target) + .nth(1) + .unwrap_or(0) + }; + + // Need to do split it so that the borrow checker is happy + match new_idx.cmp(&target) { + Ordering::Less => { + let (before, after) = self.clients.split_at_mut(target); + mem::swap(&mut before[new_idx], &mut after[0]); + } + Ordering::Greater => { + let (before, after) = self.clients.split_at_mut(new_idx); + mem::swap(&mut before[target], &mut after[0]); + } + Ordering::Equal => return, + } + + self.focused_client = Some(new_idx); // Doesn't need any actual X operations done + self.rearrange_mon(conn, mon_idx); + } + + /// Shift the focused client to the top of the stack + pub fn shift_focused_to_top(&mut self, conn: &Connection<'_>) { + if self.clients.len() == 1 { + return; // Already at the top + } + + let Some(target) = self.focused_client else { + return; + }; + + // Need to do split it so that the borrow checker is happy + let (before, after) = self.clients.split_at_mut(1); + mem::swap(&mut before[0], &mut after[target - 1]); + + self.focused_client = Some(0); // Doesn't need any actual X operations done + self.rearrange_mon(conn, self.focused_mon_idx()); + } + /// Toggle whether the client with the given position is floating pub fn toggle_floating(&mut self, conn: &Connection<'_>, pos: ClientIdx) { let c = &mut self.clients[pos]; diff --git a/src/config.rs b/src/config.rs index f806df4..723f0e7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -10,7 +10,7 @@ use crate::{ conn_info::Colour, helpers::{ focus_next, focus_prev, kill_client, mouse_move, mouse_resize, set_tag, set_tag_focus, - spawn, toggle_floating, toggle_fullscreen, + shift_down, shift_top, shift_up, spawn, toggle_floating, toggle_fullscreen, }, keys::Keybinds, }; @@ -47,6 +47,9 @@ pub const KEYBINDS: Keybinds = Keybinds(&[ bind!(MAIN_MODIFIER , Print -> &|_| spawn::<_, &str>("sh", ["-c", "screenshot"])), bind!(MAIN_MODIFIER , j -> &focus_next), bind!(MAIN_MODIFIER , k -> &focus_prev), + bind!(MAIN_MODIFIER , f -> &shift_top), + bind!(MAIN_MODIFIER.union(ModMask::SHIFT) , j -> &shift_down), + bind!(MAIN_MODIFIER.union(ModMask::SHIFT) , k -> &shift_up), bind!(MAIN_MODIFIER.union(ModMask::SHIFT) , space -> &toggle_floating), bind!(MAIN_MODIFIER.union(ModMask::SHIFT) , f -> &toggle_fullscreen), bind!(MAIN_MODIFIER.union(ModMask::SHIFT) , q -> &kill_client), @@ -69,23 +72,14 @@ pub const KEYBINDS: Keybinds = Keybinds(&[ bind!(MAIN_MODIFIER.union(ModMask::SHIFT) , _7 -> &|wm| set_tag(wm, 7)), bind!(MAIN_MODIFIER.union(ModMask::SHIFT) , _8 -> &|wm| set_tag(wm, 8)), bind!(MAIN_MODIFIER.union(ModMask::SHIFT) , _9 -> &|wm| set_tag(wm, 9)), - // { MODKEY, XK_j, focusstack, {.i = +1 } }, - // { MODKEY, XK_k, focusstack, {.i = -1 } }, // { MODKEY, XK_i, incnmaster, {.i = +1 } }, // { MODKEY, XK_d, incnmaster, {.i = -1 } }, // { MODKEY, XK_h, setmfact, {.f = -0.05} }, // { MODKEY, XK_l, setmfact, {.f = +0.05} }, - // { MODKEY, XK_Return, zoom, {0} }, - // { MODKEY, XK_Tab, view, {0} }, - // { MODKEY|ShiftMask, XK_c, killclient, {0} }, // { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, // { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, // { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, // { MODKEY, XK_space, setlayout, {0} }, - // { MODKEY, XK_comma, focusmon, {.i = -1 } }, - // { MODKEY, XK_period, focusmon, {.i = +1 } }, - // { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, - // { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, // { MODKEY|ShiftMask, XK_q, quit, {0} }, ]); diff --git a/src/helpers.rs b/src/helpers.rs index 819719b..cd9fd18 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -56,6 +56,21 @@ pub fn focus_prev(wm: &mut WM<'_>) { wm.clients.change_focus(&wm.conn, false); } +/// Shift the currently focused window down the stack +pub fn shift_down(wm: &mut WM<'_>) { + wm.clients.shift_focused_client(&wm.conn, true); +} + +/// Shift the currently focused window up the stack +pub fn shift_up(wm: &mut WM<'_>) { + wm.clients.shift_focused_client(&wm.conn, false); +} + +/// Shift the currently focused window to the top of the stack +pub fn shift_top(wm: &mut WM<'_>) { + wm.clients.shift_focused_to_top(&wm.conn); +} + /// Toggle floating status for the currently focused window pub fn toggle_floating(wm: &mut WM<'_>) { if let Some(pos) = wm.clients.focused_pos() { |