summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbhinav Prasai <abhinav.prsai@gmail.com>2025-08-29 13:22:39 +0100
committerAbhinav Prasai <abhinav.prsai@gmail.com>2025-08-29 13:22:39 +0100
commit495d9dca7d549c6ab2b3d6173a42f0bcd21feb29 (patch)
treedcc19dcd95c44bea5347391769ddd203d8de4bb4
parent6962146b747e449e7281b6c6acda0a32fb1ff453 (diff)
allow custom layouts + other changes vvv
* remove config.h * improve modifier mask cleaning * use keycode instead of sym when dealing with bindings * put <linux/limits.h> into ifdef __linux__
-rw-r--r--src/config.h79
-rw-r--r--src/defs.h1
-rw-r--r--src/parser.c12
-rw-r--r--src/sxwm.c114
4 files changed, 74 insertions, 132 deletions
diff --git a/src/config.h b/src/config.h
deleted file mode 100644
index e257da3..0000000
--- a/src/config.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* See LICENSE for more information on use */
-#include <X11/Xlib.h>
-#include <X11/keysym.h>
-#include "defs.h"
-
-CMD(terminal, "st");
-CMD(browser, "firefox");
-
-const Binding binds[] = {
- {Mod4Mask | ShiftMask, XK_e, {.fn = quit}, TYPE_FUNC},
- {Mod4Mask | ShiftMask, XK_q, {.fn = close_focused}, TYPE_FUNC},
-
- {Mod4Mask, XK_j, {.fn = focus_next}, TYPE_FUNC},
- {Mod4Mask, XK_k, {.fn = focus_prev}, TYPE_FUNC},
-
- {Mod4Mask, XK_comma, {.fn = focus_prev_mon}, TYPE_FUNC},
- {Mod4Mask, XK_period, {.fn = focus_next_mon}, TYPE_FUNC},
- {Mod4Mask | ShiftMask, XK_comma, {.fn = move_prev_mon}, TYPE_FUNC},
- {Mod4Mask | ShiftMask, XK_period, {.fn = move_next_mon}, TYPE_FUNC},
-
- {Mod4Mask | ShiftMask, XK_j, {.fn = move_master_next}, TYPE_FUNC},
- {Mod4Mask | ShiftMask, XK_k, {.fn = move_master_prev}, TYPE_FUNC},
-
- {Mod4Mask, XK_l, {.fn = resize_master_add}, TYPE_FUNC},
- {Mod4Mask, XK_h, {.fn = resize_master_sub}, TYPE_FUNC},
-
- {Mod4Mask | ControlMask, XK_l, {.fn = resize_stack_add}, TYPE_FUNC},
- {Mod4Mask | ControlMask, XK_h, {.fn = resize_stack_sub}, TYPE_FUNC},
-
- {Mod4Mask, XK_equal, {.fn = inc_gaps}, TYPE_FUNC},
- {Mod4Mask, XK_minus, {.fn = dec_gaps}, TYPE_FUNC},
-
- {Mod4Mask, XK_space, {.fn = toggle_floating}, TYPE_FUNC},
- {Mod4Mask | ShiftMask, XK_space, {.fn = toggle_floating_global}, TYPE_FUNC},
- {Mod4Mask | ShiftMask, XK_f, {.fn = toggle_fullscreen}, TYPE_FUNC},
-
- {Mod4Mask, XK_Return, {.cmd = terminal}, TYPE_CMD},
- {Mod4Mask, XK_b, {.cmd = browser}, TYPE_CMD},
- {Mod4Mask, XK_p, {.cmd = (const char *[]){"dmenu_run", NULL}}, TYPE_CMD},
-
- {Mod4Mask, XK_r, {.fn = reload_config}, TYPE_FUNC},
-
- {Mod4Mask | Mod1Mask, XK_1, {.sp = 0}, TYPE_SP_CREATE},
- {Mod4Mask | Mod1Mask, XK_2, {.sp = 1}, TYPE_SP_CREATE},
- {Mod4Mask | Mod1Mask, XK_3, {.sp = 2}, TYPE_SP_CREATE},
- {Mod4Mask | Mod1Mask, XK_4, {.sp = 3}, TYPE_SP_CREATE},
- {Mod4Mask | Mod1Mask, XK_5, {.sp = 4}, TYPE_SP_CREATE},
-
- {Mod4Mask | ControlMask, XK_1, {.sp = 0}, TYPE_SP_TOGGLE},
- {Mod4Mask | ControlMask, XK_2, {.sp = 1}, TYPE_SP_TOGGLE},
- {Mod4Mask | ControlMask, XK_3, {.sp = 2}, TYPE_SP_TOGGLE},
- {Mod4Mask | ControlMask, XK_4, {.sp = 3}, TYPE_SP_TOGGLE},
- {Mod4Mask | ControlMask, XK_5, {.sp = 4}, TYPE_SP_TOGGLE},
-
- {Mod4Mask | Mod1Mask | ShiftMask, XK_1, {.sp = 0}, TYPE_SP_REMOVE},
- {Mod4Mask | Mod1Mask | ShiftMask, XK_2, {.sp = 1}, TYPE_SP_REMOVE},
- {Mod4Mask | Mod1Mask | ShiftMask, XK_3, {.sp = 2}, TYPE_SP_REMOVE},
- {Mod4Mask | Mod1Mask | ShiftMask, XK_4, {.sp = 3}, TYPE_SP_REMOVE},
- {Mod4Mask | Mod1Mask | ShiftMask, XK_5, {.sp = 4}, TYPE_SP_REMOVE},
-
- {Mod4Mask, XK_1, {.ws = 0}, TYPE_WS_CHANGE},
- {Mod4Mask | ShiftMask, XK_1, {.ws = 0}, TYPE_WS_MOVE},
- {Mod4Mask, XK_2, {.ws = 1}, TYPE_WS_CHANGE},
- {Mod4Mask | ShiftMask, XK_2, {.ws = 1}, TYPE_WS_MOVE},
- {Mod4Mask, XK_3, {.ws = 2}, TYPE_WS_CHANGE},
- {Mod4Mask | ShiftMask, XK_3, {.ws = 2}, TYPE_WS_MOVE},
- {Mod4Mask, XK_4, {.ws = 3}, TYPE_WS_CHANGE},
- {Mod4Mask | ShiftMask, XK_4, {.ws = 3}, TYPE_WS_MOVE},
- {Mod4Mask, XK_5, {.ws = 4}, TYPE_WS_CHANGE},
- {Mod4Mask | ShiftMask, XK_5, {.ws = 4}, TYPE_WS_MOVE},
- {Mod4Mask, XK_6, {.ws = 5}, TYPE_WS_CHANGE},
- {Mod4Mask | ShiftMask, XK_6, {.ws = 5}, TYPE_WS_MOVE},
- {Mod4Mask, XK_7, {.ws = 6}, TYPE_WS_CHANGE},
- {Mod4Mask | ShiftMask, XK_7, {.ws = 6}, TYPE_WS_MOVE},
- {Mod4Mask, XK_8, {.ws = 7}, TYPE_WS_CHANGE},
- {Mod4Mask | ShiftMask, XK_8, {.ws = 7}, TYPE_WS_MOVE},
- {Mod4Mask, XK_9, {.ws = 8}, TYPE_WS_CHANGE},
- {Mod4Mask | ShiftMask, XK_9, {.ws = 8}, TYPE_WS_MOVE},
-};
diff --git a/src/defs.h b/src/defs.h
index e263789..27d16fd 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -66,6 +66,7 @@ typedef union {
typedef struct {
int mods;
KeySym keysym;
+ KeyCode keycode;
Action action;
int type;
} Binding;
diff --git a/src/parser.c b/src/parser.c
index 2fc4709..6bfaeeb 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1,16 +1,20 @@
#define _POSIX_C_SOURCE 200809L
#include <ctype.h>
-#include <linux/limits.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#ifdef __linux__
-#include <wordexp.h>
-#endif
+
#include <X11/keysym.h>
#include <X11/XF86keysym.h>
#include <X11/Xlib.h>
+
+#ifdef __linux__
+#include <wordexp.h>
+#include <linux/limits.h>
+#endif
+
#include "parser.h"
#include "defs.h"
diff --git a/src/sxwm.c b/src/sxwm.c
index 819c660..6ed33c0 100644
--- a/src/sxwm.c
+++ b/src/sxwm.c
@@ -65,6 +65,7 @@ void hdl_config_req(XEvent *xev);
void hdl_dummy(XEvent *xev);
void hdl_destroy_ntf(XEvent *xev);
void hdl_keypress(XEvent *xev);
+void hdl_mapping_ntf(XEvent *xev);
void hdl_map_req(XEvent *xev);
void hdl_motion(XEvent *xev);
void hdl_root_property(XEvent *xev);
@@ -109,6 +110,7 @@ void toggle_scratchpad(int n);
void unswallow_window(Client *c);
void update_borders(void);
void update_client_desktop_properties(void);
+void update_modifier_masks(void);
void update_mons(void);
void update_net_client_list(void);
void update_struts(void);
@@ -118,7 +120,6 @@ Bool window_should_float(Window w);
Bool window_should_start_fullscreen(Window w);
int xerr(Display *d, XErrorEvent *ee);
void xev_case(XEvent *xev);
-#include "config.h"
Atom _NET_ACTIVE_WINDOW;
Atom _NET_CURRENT_DESKTOP;
@@ -132,6 +133,7 @@ Atom _NET_WM_STRUT_PARTIAL;
Atom _NET_SUPPORTING_WM_CHECK;
Atom _NET_WM_NAME;
Atom UTF8_STRING;
+
Atom _NET_WM_DESKTOP;
Atom _NET_CLIENT_LIST;
Atom _NET_FRAME_EXTENTS;
@@ -158,7 +160,6 @@ Cursor cursor_resize;
Client *workspaces[NUM_WORKSPACES] = {NULL};
Config default_config;
Config user_config;
-int current_ws = 0;
DragMode drag_mode = DRAG_NONE;
Client *drag_client = NULL;
Client *swap_target = NULL;
@@ -172,14 +173,18 @@ Scratchpad scratchpads[MAX_SCRATCHPADS];
int scratchpad_count = 0;
int current_scratchpad = 0;
int n_mons = 0;
+int current_ws = 0;
int current_mon = 0;
Bool global_floating = False;
Bool in_ws_switch = False;
Bool backup_binds = False;
Bool running = False;
Bool next_should_float = False;
-
long last_motion_time = 0;
+
+Mask numlock_mask = 0;
+Mask mode_switch_mask = 0;
+
int scr_width;
int scr_height;
int open_windows = 0;
@@ -418,7 +423,7 @@ void change_workspace(int ws)
int clean_mask(int mask)
{
- return mask & ~(LockMask | Mod2Mask | Mod3Mask);
+ return mask & ~(LockMask | numlock_mask | mode_switch_mask);
}
void close_focused(void)
@@ -713,29 +718,29 @@ void grab_button(Mask button, Mask mod, Window w, Bool owner_events, Mask masks)
void grab_keys(void)
{
- const int guards[] = {
- 0, LockMask, Mod2Mask, LockMask | Mod2Mask, Mod5Mask, LockMask |
- Mod5Mask, Mod2Mask | Mod5Mask, LockMask | Mod2Mask | Mod5Mask
+ Mask guards[] = {
+ 0, LockMask, numlock_mask, LockMask | numlock_mask, mode_switch_mask,
+ LockMask | mode_switch_mask, numlock_mask | mode_switch_mask,
+ LockMask | numlock_mask | mode_switch_mask
};
XUngrabKey(dpy, AnyKey, AnyModifier, root);
for (int i = 0; i < user_config.n_binds; i++) {
- Binding *b = &user_config.binds[i];
+ Binding *bind = &user_config.binds[i];
- if ((b->type == TYPE_WS_CHANGE && b->mods != user_config.modkey) ||
- (b->type == TYPE_WS_MOVE && b->mods != (user_config.modkey | ShiftMask))) {
+ if ((bind->type == TYPE_WS_CHANGE && bind->mods != user_config.modkey) ||
+ (bind->type == TYPE_WS_MOVE && bind->mods != (user_config.modkey | ShiftMask))) {
continue;
}
- KeyCode key_code = XKeysymToKeycode(dpy, b->keysym);
- if (!key_code) {
+ bind->keycode = XKeysymToKeycode(dpy, bind->keysym);
+ if (!bind->keycode) {
continue;
}
- size_t guards_len = sizeof(guards) / sizeof(*guards);
- for (size_t guard = 0; guard < guards_len; guard++) {
- XGrabKey(dpy, key_code, b->mods | guards[guard],
- root, True, GrabModeAsync, GrabModeAsync);
+ for (size_t guard = 0; guard < sizeof(guards)/sizeof(guards[0]); guard++) {
+ XGrabKey(dpy, bind->keycode, bind->mods | guards[guard],
+ root, True, GrabModeAsync, GrabModeAsync);
}
}
}
@@ -984,50 +989,33 @@ void hdl_destroy_ntf(XEvent *xev)
void hdl_keypress(XEvent *xev)
{
- KeySym keysym = XkbKeycodeToKeysym(dpy, xev->xkey.keycode, 0, 0);
+ KeyCode code = xev->xkey.keycode;
int mods = clean_mask(xev->xkey.state);
for (int i = 0; i < user_config.n_binds; i++) {
Binding *bind = &user_config.binds[i];
- if (bind->keysym == keysym && clean_mask(bind->mods) == mods) {
+ if (bind->keycode == code && clean_mask(bind->mods) == mods) {
switch (bind->type) {
- case TYPE_CMD:
- spawn(bind->action.cmd);
- break;
-
- case TYPE_FUNC:
- if (bind->action.fn) {
- bind->action.fn();
- }
- break;
-
- case TYPE_WS_CHANGE:
- change_workspace(bind->action.ws);
- update_net_client_list();
- break;
-
- case TYPE_WS_MOVE:
- move_to_workspace(bind->action.ws);
- update_net_client_list();
- break;
-
- case TYPE_SP_REMOVE:
- remove_scratchpad(bind->action.sp);
- break;
-
- case TYPE_SP_TOGGLE:
- toggle_scratchpad(bind->action.sp);
- break;
-
- case TYPE_SP_CREATE:
- set_win_scratchpad(bind->action.sp);
- break;
+ case TYPE_CMD: spawn(bind->action.cmd); break;
+ case TYPE_FUNC: if (bind->action.fn) bind->action.fn(); break;
+ case TYPE_WS_CHANGE: change_workspace(bind->action.ws); update_net_client_list(); break;
+ case TYPE_WS_MOVE: move_to_workspace(bind->action.ws); update_net_client_list(); break;
+ case TYPE_SP_REMOVE: remove_scratchpad(bind->action.sp); break;
+ case TYPE_SP_TOGGLE: toggle_scratchpad(bind->action.sp); break;
+ case TYPE_SP_CREATE: set_win_scratchpad(bind->action.sp); break;
}
return;
}
}
}
+void hdl_mapping_ntf(XEvent *xev)
+{
+ XRefreshKeyboardMapping(&xev->xmapping);
+ update_modifier_masks();
+ grab_keys();
+}
+
void hdl_map_req(XEvent *xev)
{
Window w = xev->xmaprequest.window;
@@ -1440,6 +1428,7 @@ void init_defaults(void)
default_config.warp_cursor = True;
default_config.new_win_master = False;
+ /*
if (backup_binds) {
for (unsigned long i = 0; i < LENGTH(binds); i++) {
default_config.binds[i].mods = binds[i].mods;
@@ -1449,6 +1438,7 @@ void init_defaults(void)
default_config.n_binds++;
}
}
+ */
user_config = default_config;
}
@@ -2004,6 +1994,7 @@ void setup(void)
fprintf(stderr, "sxwmrc: error parsing config file\n");
init_defaults();
}
+ update_modifier_masks();
grab_keys();
startup_exec();
@@ -2041,6 +2032,7 @@ void setup(void)
evtable[ConfigureRequest] = hdl_config_req;
evtable[DestroyNotify] = hdl_destroy_ntf;
evtable[KeyPress] = hdl_keypress;
+ evtable[MappingNotify] = hdl_mapping_ntf;
evtable[MapRequest] = hdl_map_req;
evtable[MotionNotify] = hdl_motion;
evtable[PropertyNotify] = hdl_root_property;
@@ -2777,6 +2769,30 @@ void update_client_desktop_properties(void)
}
}
+void update_modifier_masks(void)
+{
+ XModifierKeymap *mod_mapping = XGetModifierMapping(dpy);
+ KeyCode num = XKeysymToKeycode(dpy, XK_Num_Lock);
+ KeyCode mode = XKeysymToKeycode(dpy, XK_Mode_switch);
+ numlock_mask = 0;
+ mode_switch_mask = 0;
+
+ int n_masks = 8;
+ for (int i = 0; i < n_masks; i++) {
+ for (int j = 0; j < mod_mapping->max_keypermod; j++) {
+ /* keycode at mod[i][j] */
+ KeyCode keycode = mod_mapping->modifiermap[i * mod_mapping->max_keypermod + j];
+ if (keycode == num) {
+ numlock_mask = (1 << i); /* which mod bit == NumLock key */
+ }
+ if (keycode == mode) {
+ mode_switch_mask = (1 << i); /* which mod bit == Mode_switch key */
+ }
+ }
+ }
+ XFreeModifiermap(mod_mapping);
+}
+
void update_mons(void)
{
XineramaScreenInfo *info;