]> git.mdlowis.com Git - proto/labwc.git/commitdiff
src/config/rcxml.c: allow clearing key/mouse bindings
authorConsolatis <35009135+Consolatis@users.noreply.github.com>
Sun, 29 Jan 2023 03:06:46 +0000 (04:06 +0100)
committerConsolatis <35009135+Consolatis@users.noreply.github.com>
Fri, 3 Feb 2023 02:30:10 +0000 (03:30 +0100)
Fixes #567

docs/rc.xml
include/config/keybind.h
include/config/mousebind.h
src/action.c
src/config/keybind.c
src/config/mousebind.c
src/config/rcxml.c
src/keyboard.c
src/menu/menu.c

index fe95e2f7b7c2a93436be2ac37946951ee8085219..3bf2d116516b3accf70a559aec65114afe2f7cd9 100644 (file)
     <keybind key="W-Return">
       <action name="Execute" command="foot" />
     </keybind>
+    <!--
+      Remove a previously defined keybind
+      A shorter alternative is <keybind key="W-F4" />
+    -->
+    <keybind key="W-F4">
+      <action name="None" />
+    </keybind>
   </keyboard>
 
   <mouse>
index b11914eda60d8dc4e4bc79ed6406d16a9778c392..e6c2f3247bc45b580e9a3ba69f7980f05a1bd9f2 100644 (file)
@@ -28,4 +28,6 @@ struct keybind *keybind_create(const char *keybind);
  */
 uint32_t parse_modifier(const char *symname);
 
+bool keybind_the_same(struct keybind *a, struct keybind *b);
+
 #endif /* __LABWC_KEYBIND_H */
index f7dec7de4723da12a4acf7cd70f1a9b1daee56b8..b6335bdfcb81d22b7b3a95766eb0a9c82ad8a43f 100644 (file)
@@ -48,5 +48,6 @@ enum mouse_event mousebind_event_from_str(const char *str);
 uint32_t mousebind_button_from_str(const char *str, uint32_t *modifiers);
 enum direction mousebind_direction_from_str(const char *str, uint32_t *modifiers);
 struct mousebind *mousebind_create(const char *context);
+bool mousebind_the_same(struct mousebind *a, struct mousebind *b);
 
 #endif /* __LABWC_MOUSEBIND_H */
index 09992ef15de7cc73078f3fc741fd6bcb8c3930ba..5668a62890c10a940a84434104fddc8064c1195f 100644 (file)
@@ -157,8 +157,14 @@ action_create(const char *action_name)
                wlr_log(WLR_ERROR, "action name not specified");
                return NULL;
        }
+
+       enum action_type action_type = action_type_from_str(action_name);
+       if (action_type == ACTION_TYPE_NONE) {
+               return NULL;
+       }
+
        struct action *action = znew(*action);
-       action->type = action_type_from_str(action_name);
+       action->type = action_type;
        wl_list_init(&action->args);
        return action;
 }
@@ -445,8 +451,6 @@ actions_run(struct view *activator, struct server *server,
                                wlr_log(WLR_ERROR, "Invalid SnapToRegion id: '%s'", region_name);
                        }
                        break;
-               case ACTION_TYPE_NONE:
-                       break;
                case ACTION_TYPE_INVALID:
                        wlr_log(WLR_ERROR, "Not executing unknown action");
                        break;
index 858e02073ecd73daa593cd3c3d1d7bb08afabc3d..5700c54cfa378c70be256d76b0afe47b5ba3a0ff 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 #define _POSIX_C_SOURCE 200809L
+#include <assert.h>
 #include <glib.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -26,13 +27,28 @@ parse_modifier(const char *symname)
        }
 }
 
+bool
+keybind_the_same(struct keybind *a, struct keybind *b)
+{
+       assert(a && b);
+       if (a->modifiers != b->modifiers || a->keysyms_len != b->keysyms_len) {
+               return false;
+       }
+       for (size_t i = 0; i < a->keysyms_len; i++) {
+               if (a->keysyms[i] != b->keysyms[i]) {
+                       return false;
+               }
+       }
+       return true;
+}
+
 struct keybind *
 keybind_create(const char *keybind)
 {
        struct keybind *k = znew(*k);
        xkb_keysym_t keysyms[MAX_KEYSYMS];
        gchar **symnames = g_strsplit(keybind, "-", -1);
-       for (int i = 0; symnames[i]; i++) {
+       for (size_t i = 0; symnames[i]; i++) {
                char *symname = symnames[i];
                uint32_t modifier = parse_modifier(symname);
                if (modifier != 0) {
index 4c37ad5f8cbceb81ac14c37a21ba1cc18d68c4c2..c578c46b1acf215b5a8bd5625df19fa93c19118a 100644 (file)
@@ -137,6 +137,17 @@ context_from_str(const char *str)
        return LAB_SSD_NONE;
 }
 
+bool
+mousebind_the_same(struct mousebind *a, struct mousebind *b)
+{
+       assert(a && b);
+       return a->context == b->context
+               && a->button == b->button
+               && a->direction == b->direction
+               && a->mouse_event == b->mouse_event
+               && a->modifiers == b->modifiers;
+}
+
 struct mousebind *
 mousebind_create(const char *context)
 {
index cbb0ca8396e63ca515dfe8460b8b4b15b27fbabb..dd33750efa03537a0f8bbc0af4b82b3b3d155b42 100644 (file)
@@ -111,8 +111,10 @@ fill_keybind(char *nodename, char *content)
                        "nodename: '%s' content: '%s'", nodename, content);
        } else if (!strcmp(nodename, "name.action")) {
                current_keybind_action = action_create(content);
-               wl_list_append(&current_keybind->actions,
-                       &current_keybind_action->link);
+               if (current_keybind_action) {
+                       wl_list_append(&current_keybind->actions,
+                               &current_keybind_action->link);
+               }
        } else if (!current_keybind_action) {
                wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
                        "nodename: '%s' content: '%s'", nodename, content);
@@ -164,8 +166,10 @@ fill_mousebind(char *nodename, char *content)
                        mousebind_event_from_str(content);
        } else if (!strcmp(nodename, "name.action")) {
                current_mousebind_action = action_create(content);
-               wl_list_append(&current_mousebind->actions,
-                       &current_mousebind_action->link);
+               if (current_mousebind_action) {
+                       wl_list_append(&current_mousebind->actions,
+                               &current_mousebind_action->link);
+               }
        } else if (!current_mousebind_action) {
                wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
                        "nodename: '%s' content: '%s'", nodename, content);
@@ -683,20 +687,17 @@ load_default_mouse_bindings(void)
 }
 
 static void
-merge_mouse_bindings(void)
+deduplicate_mouse_bindings(void)
 {
        uint32_t replaced = 0;
+       uint32_t cleared = 0;
        struct mousebind *current, *tmp, *existing;
        wl_list_for_each_safe(existing, tmp, &rc.mousebinds, link) {
                wl_list_for_each_reverse(current, &rc.mousebinds, link) {
                        if (existing == current) {
                                break;
                        }
-                       if (existing->context == current->context
-                                       && existing->button == current->button
-                                       && existing->direction == current->direction
-                                       && existing->mouse_event == current->mouse_event
-                                       && existing->modifiers == current->modifiers) {
+                       if (mousebind_the_same(existing, current)) {
                                wl_list_remove(&existing->link);
                                action_list_free(&existing->actions);
                                free(existing);
@@ -705,9 +706,54 @@ merge_mouse_bindings(void)
                        }
                }
        }
+       wl_list_for_each_safe(current, tmp, &rc.mousebinds, link) {
+               if (wl_list_empty(&current->actions)) {
+                       wl_list_remove(&current->link);
+                       free(current);
+                       cleared++;
+               }
+       }
        if (replaced) {
                wlr_log(WLR_DEBUG, "Replaced %u mousebinds", replaced);
        }
+       if (cleared) {
+               wlr_log(WLR_DEBUG, "Cleared %u mousebinds", cleared);
+       }
+}
+
+static void
+deduplicate_key_bindings(void)
+{
+       uint32_t replaced = 0;
+       uint32_t cleared = 0;
+       struct keybind *current, *tmp, *existing;
+       wl_list_for_each_safe(existing, tmp, &rc.keybinds, link) {
+               wl_list_for_each_reverse(current, &rc.keybinds, link) {
+                       if (existing == current) {
+                               break;
+                       }
+                       if (keybind_the_same(existing, current)) {
+                               wl_list_remove(&existing->link);
+                               action_list_free(&existing->actions);
+                               free(existing);
+                               replaced++;
+                               break;
+                       }
+               }
+       }
+       wl_list_for_each_safe(current, tmp, &rc.keybinds, link) {
+               if (wl_list_empty(&current->actions)) {
+                       wl_list_remove(&current->link);
+                       free(current);
+                       cleared++;
+               }
+       }
+       if (replaced) {
+               wlr_log(WLR_DEBUG, "Replaced %u keybinds", replaced);
+       }
+       if (cleared) {
+               wlr_log(WLR_DEBUG, "Cleared %u keybinds", cleared);
+       }
 }
 
 static void
@@ -723,8 +769,15 @@ post_processing(void)
                load_default_mouse_bindings();
        }
 
-       /* Replace all earlier mousebindings by later ones */
-       merge_mouse_bindings();
+       /*
+        * Replace all earlier bindings by later ones
+        * and clear the ones with an empty action list.
+        *
+        * This is required so users are able to remove
+        * a default binding by using the "None" action.
+        */
+       deduplicate_key_bindings();
+       deduplicate_mouse_bindings();
 
        if (!rc.font_activewindow.name) {
                rc.font_activewindow.name = xstrdup("sans");
index 1749aaf3ef8836280ea341e1c4df584810ef465f..894ae639860027891b9385d721d361f29f21755a 100644 (file)
@@ -81,7 +81,7 @@ static bool
 handle_keybinding(struct server *server, uint32_t modifiers, xkb_keysym_t sym)
 {
        struct keybind *keybind;
-       wl_list_for_each_reverse(keybind, &rc.keybinds, link) {
+       wl_list_for_each(keybind, &rc.keybinds, link) {
                if (modifiers ^ keybind->modifiers) {
                        continue;
                }
index cd463429ecc30f52044e7cf884dadf3ba2b5140a..ecbeb50b3775891020e1964e43c3a5c7f0193860 100644 (file)
@@ -279,7 +279,10 @@ fill_item(char *nodename, char *content)
                 */
        } else if (!strcmp(nodename, "name.action")) {
                current_item_action = action_create(content);
-               wl_list_append(&current_item->actions, &current_item_action->link);
+               if (current_item_action) {
+                       wl_list_append(&current_item->actions,
+                               &current_item_action->link);
+               }
        } else if (!current_item_action) {
                wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
                        "nodename: '%s' content: '%s'", nodename, content);