aboutsummaryrefslogtreecommitdiffstats
path: root/sway/commands/bind.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/commands/bind.c')
-rw-r--r--sway/commands/bind.c139
1 files changed, 107 insertions, 32 deletions
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index d9ea37b7..cbabb07b 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -1,9 +1,13 @@
1#ifdef __linux__
2#include <linux/input-event-codes.h>
3#elif __FreeBSD__
4#include <dev/evdev/input-event-codes.h>
5#endif
1#include <xkbcommon/xkbcommon.h> 6#include <xkbcommon/xkbcommon.h>
2#include <xkbcommon/xkbcommon-names.h> 7#include <xkbcommon/xkbcommon-names.h>
3#include <strings.h> 8#include <strings.h>
4#include "sway/commands.h" 9#include "sway/commands.h"
5#include "sway/config.h" 10#include "sway/config.h"
6#include "sway/input_state.h"
7#include "list.h" 11#include "list.h"
8#include "log.h" 12#include "log.h"
9#include "stringop.h" 13#include "stringop.h"
@@ -11,13 +15,67 @@
11 15
12int binding_order = 0; 16int binding_order = 0;
13 17
18void free_sway_binding(struct sway_binding *binding) {
19 if (!binding) {
20 return;
21 }
22
23 if (binding->keys) {
24 free_flat_list(binding->keys);
25 }
26 free(binding->command);
27 free(binding);
28}
29
30/**
31 * Returns true if the bindings have the same key and modifier combinations.
32 * Note that keyboard layout is not considered, so the bindings might actually
33 * not be equivalent on some layouts.
34 */
35bool binding_key_compare(struct sway_binding *binding_a,
36 struct sway_binding *binding_b) {
37 if (binding_a->release != binding_b->release) {
38 return false;
39 }
40
41 if (binding_a->bindcode != binding_b->bindcode) {
42 return false;
43 }
44
45 if (binding_a->modifiers ^ binding_b->modifiers) {
46 return false;
47 }
48
49 if (binding_a->keys->length != binding_b->keys->length) {
50 return false;
51 }
52
53 int keys_len = binding_a->keys->length;
54 for (int i = 0; i < keys_len; ++i) {
55 uint32_t key_a = *(uint32_t*)binding_a->keys->items[i];
56 bool found = false;
57 for (int j = 0; j < keys_len; ++j) {
58 uint32_t key_b = *(uint32_t*)binding_b->keys->items[j];
59 if (key_b == key_a) {
60 found = true;
61 break;
62 }
63 }
64 if (!found) {
65 return false;
66 }
67 }
68
69 return true;
70}
71
14struct cmd_results *cmd_bindsym(int argc, char **argv) { 72struct cmd_results *cmd_bindsym(int argc, char **argv) {
15 struct cmd_results *error = NULL; 73 struct cmd_results *error = NULL;
16 if ((error = checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1))) { 74 if ((error = checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1))) {
17 return error; 75 return error;
18 } 76 }
19 77
20 struct sway_binding *binding = malloc(sizeof(struct sway_binding)); 78 struct sway_binding *binding = calloc(1, sizeof(struct sway_binding));
21 if (!binding) { 79 if (!binding) {
22 return cmd_results_new(CMD_FAILURE, "bindsym", 80 return cmd_results_new(CMD_FAILURE, "bindsym",
23 "Unable to allocate binding"); 81 "Unable to allocate binding");
@@ -58,7 +116,7 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) {
58 // Check for mouse binding 116 // Check for mouse binding
59 if (strncasecmp(split->items[i], "button", strlen("button")) == 0 && 117 if (strncasecmp(split->items[i], "button", strlen("button")) == 0 &&
60 strlen(split->items[i]) == strlen("button0")) { 118 strlen(split->items[i]) == strlen("button0")) {
61 sym = ((char *)split->items[i])[strlen("button")] - '1' + M_LEFT_CLICK; 119 sym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT;
62 } 120 }
63 if (!sym) { 121 if (!sym) {
64 struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym", 122 struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym",
@@ -67,7 +125,7 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) {
67 free_flat_list(split); 125 free_flat_list(split);
68 return ret; 126 return ret;
69 } 127 }
70 xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); 128 xkb_keysym_t *key = calloc(1, sizeof(xkb_keysym_t));
71 if (!key) { 129 if (!key) {
72 free_sway_binding(binding); 130 free_sway_binding(binding);
73 free_flat_list(split); 131 free_flat_list(split);
@@ -78,20 +136,29 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) {
78 list_add(binding->keys, key); 136 list_add(binding->keys, key);
79 } 137 }
80 free_flat_list(split); 138 free_flat_list(split);
139 binding->order = binding_order++;
81 140
82 struct sway_mode *mode = config->current_mode; 141 list_t *mode_bindings = config->current_mode->keysym_bindings;
83 int i = list_seq_find(mode->bindings, sway_binding_cmp_keys, binding); 142
84 if (i > -1) { 143 // overwrite the binding if it already exists
85 sway_log(L_DEBUG, "bindsym - '%s' already exists, overwriting", argv[0]); 144 bool overwritten = false;
86 struct sway_binding *dup = mode->bindings->items[i]; 145 for (int i = 0; i < mode_bindings->length; ++i) {
87 free_sway_binding(dup); 146 struct sway_binding *config_binding = mode_bindings->items[i];
88 list_del(mode->bindings, i); 147 if (binding_key_compare(binding, config_binding)) {
148 wlr_log(L_DEBUG, "overwriting old binding with command '%s'",
149 config_binding->command);
150 free_sway_binding(config_binding);
151 mode_bindings->items[i] = binding;
152 overwritten = true;
153 }
89 } 154 }
90 binding->order = binding_order++;
91 list_add(mode->bindings, binding);
92 list_qsort(mode->bindings, sway_binding_cmp_qsort);
93 155
94 sway_log(L_DEBUG, "bindsym - Bound %s to command %s", argv[0], binding->command); 156 if (!overwritten) {
157 list_add(mode_bindings, binding);
158 }
159
160 wlr_log(L_DEBUG, "bindsym - Bound %s to command %s",
161 argv[0], binding->command);
95 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 162 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
96} 163}
97 164
@@ -101,7 +168,7 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) {
101 return error; 168 return error;
102 } 169 }
103 170
104 struct sway_binding *binding = malloc(sizeof(struct sway_binding)); 171 struct sway_binding *binding = calloc(1, sizeof(struct sway_binding));
105 if (!binding) { 172 if (!binding) {
106 return cmd_results_new(CMD_FAILURE, "bindsym", 173 return cmd_results_new(CMD_FAILURE, "bindsym",
107 "Unable to allocate binding"); 174 "Unable to allocate binding");
@@ -138,33 +205,41 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) {
138 // parse keycode 205 // parse keycode
139 xkb_keycode_t keycode = (int)strtol(split->items[i], NULL, 10); 206 xkb_keycode_t keycode = (int)strtol(split->items[i], NULL, 10);
140 if (!xkb_keycode_is_legal_ext(keycode)) { 207 if (!xkb_keycode_is_legal_ext(keycode)) {
141 error = cmd_results_new(CMD_INVALID, "bindcode", "Invalid keycode '%s'", (char *)split->items[i]); 208 error =
209 cmd_results_new(CMD_INVALID, "bindcode",
210 "Invalid keycode '%s'", (char *)split->items[i]);
142 free_sway_binding(binding); 211 free_sway_binding(binding);
143 list_free(split); 212 list_free(split);
144 return error; 213 return error;
145 } 214 }
146 xkb_keycode_t *key = malloc(sizeof(xkb_keycode_t)); 215 xkb_keycode_t *key = calloc(1, sizeof(xkb_keycode_t));
147 *key = keycode - 8; 216 *key = keycode - 8;
148 list_add(binding->keys, key); 217 list_add(binding->keys, key);
149 } 218 }
150 free_flat_list(split); 219 free_flat_list(split);
151 220
152 struct sway_mode *mode = config->current_mode; 221 binding->order = binding_order++;
153 int i = list_seq_find(mode->bindings, sway_binding_cmp_keys, binding); 222
154 if (i > -1) { 223 list_t *mode_bindings = config->current_mode->keycode_bindings;
155 struct sway_binding *dup = mode->bindings->items[i]; 224
156 if (dup->bindcode) { 225 // overwrite the binding if it already exists
157 sway_log(L_DEBUG, "bindcode - '%s' already exists, overwriting", argv[0]); 226 bool overwritten = false;
158 } else { 227 for (int i = 0; i < mode_bindings->length; ++i) {
159 sway_log(L_DEBUG, "bindcode - '%s' already exists as bindsym, overwriting", argv[0]); 228 struct sway_binding *config_binding = mode_bindings->items[i];
229 if (binding_key_compare(binding, config_binding)) {
230 wlr_log(L_DEBUG, "overwriting old binding with command '%s'",
231 config_binding->command);
232 free_sway_binding(config_binding);
233 mode_bindings->items[i] = binding;
234 overwritten = true;
160 } 235 }
161 free_sway_binding(dup);
162 list_del(mode->bindings, i);
163 } 236 }
164 binding->order = binding_order++;
165 list_add(mode->bindings, binding);
166 list_qsort(mode->bindings, sway_binding_cmp_qsort);
167 237
168 sway_log(L_DEBUG, "bindcode - Bound %s to command %s", argv[0], binding->command); 238 if (!overwritten) {
239 list_add(mode_bindings, binding);
240 }
241
242 wlr_log(L_DEBUG, "bindcode - Bound %s to command %s",
243 argv[0], binding->command);
169 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 244 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
170} 245}