summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-06-26 21:52:09 +0100
committertcmal <me@aria.rip>2024-06-26 21:52:09 +0100
commitadcf670ba60c4489b14d4b9dd03a0f7799cf8fb7 (patch)
treef99dbd4a0d3504278ed16f7cd5753f2a5402675c
parent6785d154460921cc3b774376a676a226402d8270 (diff)
start adding some more keybinds
-rw-r--r--src/clients/mod.rs24
-rw-r--r--src/config.rs54
-rw-r--r--src/helpers.rs46
-rw-r--r--src/keys.rs4
-rw-r--r--src/main.rs1
5 files changed, 118 insertions, 11 deletions
diff --git a/src/clients/mod.rs b/src/clients/mod.rs
index ca9ed91..823a501 100644
--- a/src/clients/mod.rs
+++ b/src/clients/mod.rs
@@ -290,6 +290,30 @@ impl ClientState {
}
}
+ /// Go to the next or previous window in the current monitor, looping around if needed
+ pub fn change_focus(&mut self, conn: &Connection<'_>, increase: bool) {
+ if self.focused.0 >= self.mons.len() {
+ return;
+ }
+
+ let mon = self.focused.0;
+ if self.mons[mon].clients.is_empty() {
+ return;
+ }
+
+ self.refocus(
+ conn,
+ mon,
+ if increase {
+ (self.focused.1 + 1) % self.mons[mon].clients.len()
+ } else if self.focused.1 > 0 {
+ self.focused.1 - 1
+ } else {
+ self.mons[mon].clients.len() - 1
+ },
+ );
+ }
+
/// Get the amount of monitors this state is currently aware of
pub fn monitor_count(&self) -> usize {
self.mons.len()
diff --git a/src/config.rs b/src/config.rs
index 246fe12..3c2b309 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -7,7 +7,9 @@ use xcb::x::ModMask;
use xkeysym::Keysym;
use crate::{
+ bind,
conn_info::Colour,
+ helpers::*,
keys::{Keybind, Keybinds},
};
@@ -20,14 +22,46 @@ pub const BORDER_NORMAL: Colour = Colour::from_hex(0x000000);
/// Border around currently focused window
pub const BORDER_FOCUSED: Colour = Colour::from_hex(0xff0000);
+/// The main modifier used for keybinds.
+pub const MAIN_MODIFIER: ModMask = ModMask::CONTROL;
+
+/// Command for application menu / launcher.
+pub const MENU_COMMAND: &str = "dmenu_run";
+
/// The keybinds to use.
-pub const KEYBINDS: Keybinds = Keybinds(&[Keybind {
- modifiers: ModMask::CONTROL,
- key: Keysym::t,
- action: &|_| {
- // TODO: disown this process, probably using another way to spawn commands
- if let Err(e) = Command::new("xterm").spawn() {
- dbg!(e);
- }
- },
-}]);
+pub const KEYBINDS: Keybinds = Keybinds(&[
+ bind!(MAIN_MODIFIER , Return -> &|_| spawn::<_, &str>("xterm", [])),
+ bind!(MAIN_MODIFIER , p -> &|_| spawn::<_, &str>(MENU_COMMAND, [])),
+ bind!(MAIN_MODIFIER , j -> &focus_next),
+ bind!(MAIN_MODIFIER , k -> &focus_prev),
+ // { 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|ShiftMask, XK_space, togglefloating, {0} },
+ // { MODKEY, XK_0, view, {.ui = ~0 } },
+ // { MODKEY|ShiftMask, XK_0, tag, {.ui = ~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 } },
+ // TAGKEYS( XK_1, 0)
+ // TAGKEYS( XK_2, 1)
+ // TAGKEYS( XK_3, 2)
+ // TAGKEYS( XK_4, 3)
+ // TAGKEYS( XK_5, 4)
+ // TAGKEYS( XK_6, 5)
+ // TAGKEYS( XK_7, 6)
+ // TAGKEYS( XK_8, 7)
+ // TAGKEYS( XK_9, 8)
+ // { MODKEY|ShiftMask, XK_q, quit, {0} },
+]);
diff --git a/src/helpers.rs b/src/helpers.rs
new file mode 100644
index 0000000..ffd11d7
--- /dev/null
+++ b/src/helpers.rs
@@ -0,0 +1,46 @@
+//! Helpers for writing configuration
+
+use crate::WM;
+use std::{ffi::OsStr, process::Command};
+
+/// Syntax sugar for creating [`Keybind`]s. This is helpful for writing [`crate::config::KEYBINDS`]
+///
+/// ```rust
+/// /// Control + Shift + t prints "It Works!"
+/// bind!(ModMask::CONTROL | ModMask::SHIFT + t -> &|_| {println!("It Works!")})
+/// ```
+#[macro_export]
+macro_rules! bind {
+ ($mod:expr , $key:ident -> $action:expr) => {
+ Keybind {
+ modifiers: $mod,
+ key: Keysym::$key,
+ action: $action,
+ }
+ };
+}
+
+/// Execute the given command with arguments, disowning the process.
+pub fn spawn<I, S>(cmd: &str, args: I)
+where
+ I: IntoIterator<Item = S>,
+ S: AsRef<OsStr>,
+{
+ let c = match Command::new(cmd).args(args).spawn() {
+ Ok(c) => c,
+ Err(e) => {
+ eprintln!("error spawning {cmd}: {e:#?}");
+ return;
+ }
+ };
+}
+
+/// Move focus to the next window on the stack
+pub fn focus_next(wm: &mut WM<'_>) {
+ wm.clients.change_focus(&wm.conn, true);
+}
+
+/// Move focus to the next window on the stack
+pub fn focus_prev(wm: &mut WM<'_>) {
+ wm.clients.change_focus(&wm.conn, false);
+}
diff --git a/src/keys.rs b/src/keys.rs
index cf76982..aa84da6 100644
--- a/src/keys.rs
+++ b/src/keys.rs
@@ -1,6 +1,6 @@
//! Keybind-related code
-use crate::{config::KEYBINDS, conn_info::Connection, error::Result, WM};
+use crate::{config::KEYBINDS, conn_info::Connection, debug, error::Result, WM};
use xcb::x::{
GrabKey, GrabMode, KeyPressEvent, Mapping, MappingNotifyEvent, ModMask, UngrabKey, GRAB_ANY,
};
@@ -95,10 +95,12 @@ impl Keybinds {
/// Attempt to run the action for the matching keybind, if it exists.
pub fn dispatch(&self, wm: &mut WM<'_>, key: Keysym, modifiers: ModMask) {
+ debug!("received {key:?}");
if let Some(bind) = self
.binds()
.find(|b| b.key == key && modifiers.contains(b.modifiers))
{
+ debug!("found action");
(bind.action)(wm);
}
}
diff --git a/src/main.rs b/src/main.rs
index 3de3df9..abefd93 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -40,6 +40,7 @@ pub mod conn_info;
mod error;
#[doc(hidden)]
mod focus;
+pub mod helpers;
pub mod keys;
pub mod log;