From adcf670ba60c4489b14d4b9dd03a0f7799cf8fb7 Mon Sep 17 00:00:00 2001 From: tcmal Date: Wed, 26 Jun 2024 21:52:09 +0100 Subject: start adding some more keybinds --- src/clients/mod.rs | 24 ++++++++++++++++++++++++ src/config.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++---------- src/helpers.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/keys.rs | 4 +++- src/main.rs | 1 + 5 files changed, 118 insertions(+), 11 deletions(-) create mode 100644 src/helpers.rs 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(cmd: &str, args: I) +where + I: IntoIterator, + S: AsRef, +{ + 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; -- cgit v1.2.3