Merge pull request #735 from Consolatis/feature/clear_action

Allow clearing key/mouse bindings
This commit is contained in:
Johan Malm 2023-02-04 18:59:38 +00:00 committed by GitHub
commit f829a78918
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 115 additions and 18 deletions

View file

@ -23,6 +23,13 @@
<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>

View 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 */

View 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 */

View 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;

View 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) {

View 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)
{

View 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");

View 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;
}

View 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);