mirror of
https://codeberg.org/dwl/dwl-patches.git
synced 2025-09-06 11:14:51 +00:00
riverctl patch: add keybind modes
This commit is contained in:
parent
c7b78634a0
commit
0caf84ae8e
@ -7,13 +7,26 @@ Most of this patch is stored in river-control.h, It contains a list of functions
|
||||
|
||||
This patches main intended use case is to have a startup script that calls dwlctl a bunch to add all the binds/rules you want, without the need of restarting dwl if you make any changes to the list of binds/rules.
|
||||
|
||||
This patch also adds keybind modes which allow switching between a diffrent sets of keybinds on the fly.
|
||||
Also you can set a keybind mode as oneshot(meaning as soon as a keybind is activated the mode is switch) by using...
|
||||
`dwlctl oneshot-mode _layout_you_want_to_make_oneshot_here_ _layout_you_want_to_switch_to_after_keybind_pressed_`
|
||||
Just make sure to set a mode as oneshot after creating a bind under it otherwise it won't work.
|
||||
|
||||
|
||||
### dwlctl syntax example
|
||||
```
|
||||
dwlctl clear-binds
|
||||
|
||||
dwlctl bind super,shift Return spawn kitty tmux
|
||||
dwlctl bind normal super,shift Return spawn kitty tmux
|
||||
|
||||
dwlctl bind supershift q killclient
|
||||
dwlctl bind normal supershift q killclient
|
||||
|
||||
dwlctl bind normal super l enter-mode layoutpick
|
||||
|
||||
dwlctl bind layoutpick none t layout 0
|
||||
dwlctl bind layoutpick none f layout 1
|
||||
dwlctl bind layoutpick none m layout 2
|
||||
dwlctl oneshot-mode layoutpick normal
|
||||
|
||||
dwlctl clear-rules
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
From de574aa854d6da09a886f946b557d349c04e749d Mon Sep 17 00:00:00 2001
|
||||
From da6c19ca2bf476426ee598072a12b6d6e1679c54 Mon Sep 17 00:00:00 2001
|
||||
From: Zuki Air <zukirust@gmail.com>
|
||||
Date: Sun, 27 Jul 2025 11:30:32 +0100
|
||||
Subject: [PATCH] river-ctl patch
|
||||
@ -12,11 +12,11 @@ fix bug
|
||||
.gitignore | 1 +
|
||||
Makefile | 22 +-
|
||||
config.def.h | 36 +-
|
||||
dwl.c | 20 +-
|
||||
dwl.c | 47 +-
|
||||
dwlctl.c | 132 +++++
|
||||
protocols/river-control-unstable-v1.xml | 85 +++
|
||||
river-control.h | 669 ++++++++++++++++++++++++
|
||||
7 files changed, 949 insertions(+), 16 deletions(-)
|
||||
river-control.h | 753 ++++++++++++++++++++++++
|
||||
7 files changed, 1054 insertions(+), 22 deletions(-)
|
||||
create mode 100644 dwlctl.c
|
||||
create mode 100644 protocols/river-control-unstable-v1.xml
|
||||
create mode 100644 river-control.h
|
||||
@ -148,7 +148,7 @@ index 95c2afa..72afbd6 100644
|
||||
CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6),
|
||||
CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 12f441e..cf89d9a 100644
|
||||
index 12f441e..2cbb1b0 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -145,7 +145,7 @@ typedef struct {
|
||||
@ -187,20 +187,54 @@ index 12f441e..cf89d9a 100644
|
||||
if ((!r->title || strstr(title, r->title))
|
||||
&& (!r->id || strstr(appid, r->id))) {
|
||||
c->isfloating = r->isfloating;
|
||||
@@ -1613,8 +1618,10 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
|
||||
@@ -1605,6 +1610,16 @@ inputdevice(struct wl_listener *listener, void *data)
|
||||
wlr_seat_set_capabilities(seat, caps);
|
||||
}
|
||||
|
||||
+inline bool
|
||||
+keybinding_key(uint32_t mods, xkb_keysym_t sym,const Key *k) {
|
||||
+ if (CLEANMASK(mods) == CLEANMASK(k->mod)
|
||||
+ && sym == k->keysym && k->func) {
|
||||
+ k->func(&k->arg);
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
int
|
||||
keybinding(uint32_t mods, xkb_keysym_t sym)
|
||||
{
|
||||
@@ -1613,14 +1628,21 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
|
||||
* processing keys, rather than passing them on to the client for its own
|
||||
* processing.
|
||||
*/
|
||||
- const Key *k;
|
||||
- for (k = keys; k < END(keys); k++) {
|
||||
- if (CLEANMASK(mods) == CLEANMASK(k->mod)
|
||||
- && sym == k->keysym && k->func) {
|
||||
- k->func(&k->arg);
|
||||
- return 1;
|
||||
- }
|
||||
- }
|
||||
+ const Key_linked *kl;
|
||||
+ const Key *k;
|
||||
+ wl_list_for_each(kl,&keys_list,link) {
|
||||
+
|
||||
+ wl_list_for_each(kl,&active_mode->linked_keys,link) {
|
||||
+ k = kl->key;
|
||||
if (CLEANMASK(mods) == CLEANMASK(k->mod)
|
||||
&& sym == k->keysym && k->func) {
|
||||
k->func(&k->arg);
|
||||
@@ -2645,6 +2652,9 @@ setup(void)
|
||||
+ if (keybinding_key(mods,sym,k) == true) {
|
||||
+ if (active_mode->oneshot_mode != NULL) {
|
||||
+ active_mode = active_mode->oneshot_mode;
|
||||
+ }
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
+ for (k = keys_always; k < END(keys_always); k++) {
|
||||
+ if (keybinding_key(mods,sym,k) == true) {return 1;}
|
||||
+ }
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2645,6 +2667,9 @@ setup(void)
|
||||
wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);
|
||||
wl_signal_add(&output_mgr->events.test, &output_mgr_test);
|
||||
|
||||
@ -210,7 +244,7 @@ index 12f441e..cf89d9a 100644
|
||||
/* Make sure XWayland clients don't connect to the parent X server,
|
||||
* e.g when running in the x11 backend or the wayland backend and the
|
||||
* compositor has Xwayland support */
|
||||
@@ -3187,6 +3197,8 @@ main(int argc, char *argv[])
|
||||
@@ -3187,6 +3212,8 @@ main(int argc, char *argv[])
|
||||
{
|
||||
char *startup_cmd = NULL;
|
||||
int c;
|
||||
@ -450,23 +484,25 @@ index 0000000..aa5fc4d
|
||||
+</protocol>
|
||||
diff --git a/river-control.h b/river-control.h
|
||||
new file mode 100644
|
||||
index 0000000..b8c7a8e
|
||||
index 0000000..ad76520
|
||||
--- /dev/null
|
||||
+++ b/river-control.h
|
||||
@@ -0,0 +1,669 @@
|
||||
@@ -0,0 +1,753 @@
|
||||
+#include "river-control-unstable-v1-private-protocol.c"
|
||||
+#include "river-control-unstable-v1-protocol.h"
|
||||
+#ifdef KEYS_USED
|
||||
+void default_binds(void);
|
||||
+void default_binds(struct wl_list*);
|
||||
+#endif
|
||||
+void enter_mode(const Arg*);
|
||||
+void create_mode_user(const Arg*);
|
||||
+void oneshot_mode(const Arg*);
|
||||
+void clear_rules(const Arg*);
|
||||
+void clear_binds(const Arg*);
|
||||
+void setborderpx(const Arg*);
|
||||
+// TODO add dynamic rules then its fully complete!
|
||||
+struct wl_list arg_str_store;
|
||||
+struct wl_list rule_str_store;
|
||||
+struct wl_list rules_list;
|
||||
+struct wl_list keys_list;
|
||||
+struct wl_list modes_list;
|
||||
+typedef struct {
|
||||
+ Key *key;
|
||||
+ struct wl_list link;
|
||||
@ -480,6 +516,15 @@ index 0000000..b8c7a8e
|
||||
+ bool no_remove;
|
||||
+ struct Str_link *str_link;
|
||||
+} Rule_linked;
|
||||
+typedef struct Mode Mode;
|
||||
+struct Mode {
|
||||
+ struct wl_list link;
|
||||
+ struct wl_list linked_keys;
|
||||
+ struct Mode *oneshot_mode;
|
||||
+ char* name;
|
||||
+};
|
||||
+Mode *active_mode;
|
||||
+Mode *normal_mode;
|
||||
+struct Keysym_str_pair {
|
||||
+ xkb_keysym_t keysym;
|
||||
+ const char * keysym_str;
|
||||
@ -508,10 +553,9 @@ index 0000000..b8c7a8e
|
||||
+struct Func_str_type_pair Func_str_type_pair_list[] = {
|
||||
+ { clear_binds, FUNC_STR_ARG_TYPE_NONE, "clear-binds" },
|
||||
+ { clear_rules, FUNC_STR_ARG_TYPE_NONE, "clear-rules" },
|
||||
+ STR(togglefakefullscreen,FUNC_STR_ARG_TYPE_NONE),
|
||||
+ STR(togglegaps,FUNC_STR_ARG_TYPE_NONE),
|
||||
+ STR(pushup,FUNC_STR_ARG_TYPE_NONE),
|
||||
+ STR(pushdown,FUNC_STR_ARG_TYPE_NONE),
|
||||
+ { enter_mode, FUNC_STR_ARG_TYPE_STRING_ARRAY, "enter-mode"},
|
||||
+ { oneshot_mode, FUNC_STR_ARG_TYPE_STRING_ARRAY, "oneshot-mode"},
|
||||
+ { create_mode_user, FUNC_STR_ARG_TYPE_STRING_ARRAY, "create-mode"},
|
||||
+ STR(setborderpx,FUNC_STR_ARG_TYPE_UINT),
|
||||
+ STR(setlayout,FUNC_STR_ARG_TYPE_LAYOUT),
|
||||
+ STR(spawn,FUNC_STR_ARG_TYPE_STRING_ARRAY),
|
||||
@ -593,6 +637,7 @@ index 0000000..b8c7a8e
|
||||
+ Func_str_arg_type key_arg_type;
|
||||
+ Rule_match_type_next rule_match_type;
|
||||
+ Rule_type rule_type;
|
||||
+ Mode *key_mode;
|
||||
+ bool rule_valid;
|
||||
+ bool error;
|
||||
+ const char* error_msg;
|
||||
@ -656,7 +701,6 @@ index 0000000..b8c7a8e
|
||||
+ return str_link;
|
||||
+}
|
||||
+struct Str_link* add_arg_str_store(const char* string) {
|
||||
+// char** add_arg_str_store(const char* string) {
|
||||
+ struct Str_link *str_link = calloc(1,sizeof(struct Str_link));
|
||||
+ int i;
|
||||
+ int string_len = strlen(string) + 1;
|
||||
@ -710,31 +754,77 @@ index 0000000..b8c7a8e
|
||||
+ free(rl);
|
||||
+ }
|
||||
+ }
|
||||
+ clear_str_store(&rule_str_store);
|
||||
+}
|
||||
+void setup_binds(void) {
|
||||
+ Key *k;
|
||||
+ Key_linked *kl;
|
||||
+ if (keys_list.next == NULL) {
|
||||
+ wl_list_init(&keys_list);
|
||||
+ }
|
||||
+ for (k = keys_always; k < END(keys_always); k++) {
|
||||
+ kl = calloc(1,sizeof(Key_linked));
|
||||
+ if (kl != NULL) {
|
||||
+ kl->key = k;
|
||||
+ kl->no_free_key = true;
|
||||
+ kl->no_remove = true;
|
||||
+ wl_list_insert(&keys_list,&kl->link);
|
||||
+Mode* create_mode(const char *name) {
|
||||
+ Mode *mode = calloc(1,sizeof(Mode));
|
||||
+ if (mode == NULL) {return NULL;}
|
||||
+ wl_list_init(&mode->linked_keys);
|
||||
+ wl_list_insert(&modes_list, &mode->link);
|
||||
+ if (name != NULL) {
|
||||
+ int string_len = strlen(name) + 1;
|
||||
+ mode->name = malloc(sizeof(char) * string_len);
|
||||
+ if (mode->name == NULL) {
|
||||
+ free(mode);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ }
|
||||
+#ifdef KEYS_USED
|
||||
+ default_binds();
|
||||
+#endif
|
||||
+ memcpy(mode->name,name,string_len);
|
||||
+ }
|
||||
+ return mode;
|
||||
+}
|
||||
+Mode* get_mode(char* mode_name) {
|
||||
+ Mode *mode;
|
||||
+ wl_list_for_each(mode,&modes_list,link) {
|
||||
+ if (strcmp(mode_name,mode->name) == 0) {
|
||||
+ return mode;
|
||||
+ }
|
||||
+ }
|
||||
+ return NULL;
|
||||
+}
|
||||
+void oneshot_mode(const Arg *arg) {
|
||||
+ char * oneshot_mode_name = *(char **)arg->v;
|
||||
+ char * return_mode_name = *((char **)arg->v+1);
|
||||
+ if (oneshot_mode_name != NULL && return_mode_name != NULL) {
|
||||
+ Mode *oneshot_mode = get_mode(oneshot_mode_name);
|
||||
+ if (oneshot_mode_name != NULL) {
|
||||
+ oneshot_mode->oneshot_mode = get_mode(return_mode_name);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+void create_mode_user(const Arg *arg) {
|
||||
+ char * mode_name = *(char **)arg->v;
|
||||
+ if (mode_name != NULL) {
|
||||
+ Mode *mode_exists = get_mode(mode_name);
|
||||
+ if (mode_exists == NULL) {
|
||||
+ create_mode(mode_name);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+void enter_mode(const Arg *arg) {
|
||||
+ char * mode_name = *(char **)arg->v;
|
||||
+ Mode *mode = get_mode(mode_name);
|
||||
+ if (mode != NULL) {
|
||||
+ active_mode = mode;
|
||||
+ }
|
||||
+}
|
||||
+char * zriver_default_mode_name = "normal";
|
||||
+void setup_binds(void) {
|
||||
+ if (modes_list.next == NULL) {
|
||||
+ Mode *normal;
|
||||
+ wl_list_init(&modes_list);
|
||||
+ normal = create_mode(NULL);
|
||||
+ if (normal == NULL) { die("out of memory!"); }
|
||||
+ normal->name = zriver_default_mode_name;
|
||||
+ normal_mode = normal;
|
||||
+ active_mode = normal;
|
||||
+ default_binds(&normal->linked_keys);
|
||||
+ }
|
||||
+ if (arg_str_store.next == NULL) {
|
||||
+ wl_list_init(&arg_str_store);
|
||||
+ }
|
||||
+}
|
||||
+#ifdef KEYS_USED
|
||||
+void default_binds(void) {
|
||||
+void default_binds(struct wl_list *keys_list) {
|
||||
+ Key *k;
|
||||
+ Key_linked *kl;
|
||||
+ for (k = keys; k < END(keys); k++) {
|
||||
@ -742,23 +832,33 @@ index 0000000..b8c7a8e
|
||||
+ if (kl != NULL) {
|
||||
+ kl->key = k;
|
||||
+ kl->no_free_key = true;
|
||||
+ wl_list_insert(&keys_list,&kl->link);
|
||||
+ wl_list_insert(keys_list,&kl->link);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+#endif
|
||||
+void clear_binds(const Arg* arg) {
|
||||
+ Key_linked *kl,*tmp_kl;
|
||||
+ Mode *mode,*tmp_mode;
|
||||
+ active_mode = normal_mode;
|
||||
+
|
||||
+ wl_list_for_each_safe(kl,tmp_kl,&keys_list,link) {
|
||||
+ if (kl->no_remove == false) {
|
||||
+ wl_list_remove(&kl->link);
|
||||
+ if (kl->no_free_key == false) {
|
||||
+ free(kl->key);
|
||||
+ wl_list_for_each_safe(mode,tmp_mode,&modes_list,link) {
|
||||
+ wl_list_for_each_safe(kl,tmp_kl,&mode->linked_keys,link) {
|
||||
+ if (kl->no_remove == false) {
|
||||
+ wl_list_remove(&kl->link);
|
||||
+ if (kl->no_free_key == false) {
|
||||
+ free(kl->key);
|
||||
+ }
|
||||
+ free(kl);
|
||||
+ }
|
||||
+ free(kl);
|
||||
+ }
|
||||
+ if (normal_mode != mode) {
|
||||
+ wl_list_remove(&mode->link);
|
||||
+ free(mode->name);
|
||||
+ free(mode);
|
||||
+ }
|
||||
+ }
|
||||
+ clear_str_store(&arg_str_store);
|
||||
+}
|
||||
+
|
||||
+void zriver_control_add_argument(struct wl_client *client,
|
||||
@ -781,7 +881,6 @@ index 0000000..b8c7a8e
|
||||
+ args->str_link = add_rule_str_store();
|
||||
+ args->p.rl->rule->monitor = -1;
|
||||
+ } else {
|
||||
+ // free(args->p.rl);
|
||||
+ args->error = true;
|
||||
+ args->error_msg = zriver_error_alloc;
|
||||
+ }
|
||||
@ -790,7 +889,6 @@ index 0000000..b8c7a8e
|
||||
+ args->error_msg = zriver_error_alloc;
|
||||
+ }
|
||||
+ } else if (strcmp("map",argument) == 0 || strcmp("bind",argument) == 0) {
|
||||
+ // printf("add bind!\n");
|
||||
+ args->type = ZRIVER_ARG_TYPE_KEY;
|
||||
+ args->p.kl = calloc(1,sizeof(Key_linked));
|
||||
+ if (args->p.kl != NULL) {
|
||||
@ -895,7 +993,7 @@ index 0000000..b8c7a8e
|
||||
+ append_str_store((char**)args->p.fa->arg.v,argument,args->argc-1);
|
||||
+ }
|
||||
+ } else if (args->type == ZRIVER_ARG_TYPE_KEY) {
|
||||
+ if (args->argc == 1) {
|
||||
+ if (args->argc == 2) {
|
||||
+ for (ms = Mod_str_pair_list; ms < END(Mod_str_pair_list); ms++) {
|
||||
+ if (strstr(argument,ms->mod_str)) {
|
||||
+ if (args->p.kl->key->mod != 0) {
|
||||
@ -903,11 +1001,33 @@ index 0000000..b8c7a8e
|
||||
+ } else {
|
||||
+ args->p.kl->key->mod = ms->mod;
|
||||
+ }
|
||||
+ // printf("mod %s %i after %i detected\n",ms->mod_str,ms->mod,args->p.kl->key->mod);
|
||||
+ // printf("mod %i\n",WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT);
|
||||
+ }
|
||||
+ }
|
||||
+ } else if (args->argc == 2) {
|
||||
+ } else if (args->argc == 1) {
|
||||
+ int arg_len = strlen(argument) + 1;
|
||||
+ if (arg_len > 1) {
|
||||
+ bool found_mode = false;
|
||||
+ Mode *mode;
|
||||
+ wl_list_for_each(mode,&modes_list,link) {
|
||||
+ printf("mode name: %s, argument %s \n",mode->name,argument);
|
||||
+ if (strcmp(argument,mode->name) == 0) {
|
||||
+ found_mode = true;
|
||||
+ args->key_mode = mode;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (found_mode == false) {
|
||||
+ args->key_mode = create_mode(argument);
|
||||
+ if (args->key_mode == NULL) {
|
||||
+ args->error = true;
|
||||
+ args->error_msg = zriver_error_alloc;
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ args->error = true;
|
||||
+ args->error_msg = zriver_error_too_few_args;
|
||||
+ }
|
||||
+ } else if (args->argc == 3) {
|
||||
+ if (strcmp(argument,"none") == 0 ) {
|
||||
+ args->p.kl->key->keysym = XKB_KEY_NoSymbol;
|
||||
+ } else {
|
||||
@ -917,7 +1037,7 @@ index 0000000..b8c7a8e
|
||||
+ args->error_msg = zriver_error_invalid_keysym;
|
||||
+ }
|
||||
+ }
|
||||
+ } else if (args->argc == 3) {
|
||||
+ } else if (args->argc == 4) {
|
||||
+ for (fst = Func_str_type_pair_list; fst < END(Func_str_type_pair_list); fst++) {
|
||||
+ if (strcmp(argument,fst->func_str) == 0) {
|
||||
+ args->p.kl->key->func = fst->func;
|
||||
@ -925,11 +1045,11 @@ index 0000000..b8c7a8e
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ } else if (args->argc == 4) {
|
||||
+ } else if (args->argc == 5) {
|
||||
+ arg_filter = true;
|
||||
+ arg = &args->p.kl->key->arg;
|
||||
+ } else if (args->argc > 4 && args->argc < STR_LINK_ARRAY_SIZE && args->key_arg_type == FUNC_STR_ARG_TYPE_STRING_ARRAY && args->p.kl->key->arg.v != NULL) {
|
||||
+ append_str_store((char**)args->p.kl->key->arg.v,argument,args->argc-4);
|
||||
+ } else if (args->argc > 5 && args->argc < STR_LINK_ARRAY_SIZE && args->key_arg_type == FUNC_STR_ARG_TYPE_STRING_ARRAY && args->p.kl->key->arg.v != NULL) {
|
||||
+ append_str_store((char**)args->p.kl->key->arg.v,argument,args->argc-5);
|
||||
+ }
|
||||
+ }
|
||||
+ if (arg_filter == true && arg != NULL) {
|
||||
@ -937,7 +1057,6 @@ index 0000000..b8c7a8e
|
||||
+ case(FUNC_STR_ARG_TYPE_NONE):
|
||||
+ break;
|
||||
+ case(FUNC_STR_ARG_TYPE_UINT):
|
||||
+ // TODO make overflow check
|
||||
+ arg->i = strtol(argument,NULL,10);
|
||||
+ if (arg->i >= 0) {
|
||||
+ arg->ui = arg->i;
|
||||
@ -959,7 +1078,6 @@ index 0000000..b8c7a8e
|
||||
+ } else {
|
||||
+ arg->v = args->str_link->string;
|
||||
+ }
|
||||
+ // printf("string arg %s \n",*(char**)arg->v);
|
||||
+
|
||||
+ break;
|
||||
+ case(FUNC_STR_ARG_TYPE_WLR_DIRECTION):
|
||||
@ -1033,7 +1151,7 @@ index 0000000..b8c7a8e
|
||||
+ } else if (args->error == false) {
|
||||
+ if (args->type == ZRIVER_ARG_TYPE_KEY) {
|
||||
+ if (args->p.kl->key != NULL && args->p.kl->key->func != NULL) {
|
||||
+ wl_list_insert(&keys_list,&args->p.kl->link);
|
||||
+ wl_list_insert(&args->key_mode->linked_keys,&args->p.kl->link);
|
||||
+ zriver_command_callback_v1_send_success(callback_interface,"bind success!");
|
||||
+ } else {
|
||||
+ if (args->str_link != NULL) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user