mirror of
				https://github.com/labwc/labwc.git
				synced 2025-11-03 09:01:51 -05:00 
			
		
		
		
	
							parent
							
								
									14a0c83ae0
								
							
						
					
					
						commit
						4a8b50603e
					
				
					 9 changed files with 115 additions and 18 deletions
				
			
		| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								src/action.c
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								src/action.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
		if (current_keybind_action) {
 | 
			
		||||
			wl_list_append(¤t_keybind->actions,
 | 
			
		||||
				¤t_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);
 | 
			
		||||
		if (current_mousebind_action) {
 | 
			
		||||
			wl_list_append(¤t_mousebind->actions,
 | 
			
		||||
				¤t_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(¤t->actions)) {
 | 
			
		||||
			wl_list_remove(¤t->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(¤t->actions)) {
 | 
			
		||||
			wl_list_remove(¤t->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");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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(¤t_item->actions, ¤t_item_action->link);
 | 
			
		||||
		if (current_item_action) {
 | 
			
		||||
			wl_list_append(¤t_item->actions,
 | 
			
		||||
				¤t_item_action->link);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (!current_item_action) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
 | 
			
		||||
			"nodename: '%s' content: '%s'", nodename, content);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue