summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/clients/mod.rs68
-rw-r--r--src/config.rs14
-rw-r--r--src/helpers.rs15
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() {