diff options
Diffstat (limited to 'sway/commands')
-rw-r--r-- | sway/commands/gesture.c | 166 | ||||
-rw-r--r-- | sway/commands/mode.c | 3 |
2 files changed, 169 insertions, 0 deletions
diff --git a/sway/commands/gesture.c b/sway/commands/gesture.c new file mode 100644 index 00000000..d4442cc3 --- /dev/null +++ b/sway/commands/gesture.c @@ -0,0 +1,166 @@ +#define _POSIX_C_SOURCE 200809L +#include "sway/config.h" + +#include "gesture.h" +#include "log.h" +#include "stringop.h" +#include "sway/commands.h" + +void free_gesture_binding(struct sway_gesture_binding *binding) { + if (!binding) { + return; + } + free(binding->input); + free(binding->command); + free(binding); +} + +/** + * Returns true if the bindings have the same gesture type, direction, etc + */ +static bool binding_gesture_equal(struct sway_gesture_binding *binding_a, + struct sway_gesture_binding *binding_b) { + if (strcmp(binding_a->input, binding_b->input) != 0) { + return false; + } + + if (!gesture_equal(&binding_a->gesture, &binding_b->gesture)) { + return false; + } + + if ((binding_a->flags & BINDING_EXACT) != + (binding_b->flags & BINDING_EXACT)) { + return false; + } + return true; +} + +/** + * Add gesture binding to config + */ +static struct cmd_results *gesture_binding_add( + struct sway_gesture_binding *binding, + const char *gesturecombo, bool warn) { + list_t *mode_bindings = config->current_mode->gesture_bindings; + // overwrite the binding if it already exists + bool overwritten = false; + for (int i = 0; i < mode_bindings->length; ++i) { + struct sway_gesture_binding *config_binding = mode_bindings->items[i]; + if (binding_gesture_equal(binding, config_binding)) { + sway_log(SWAY_INFO, "Overwriting binding '%s' to `%s` from `%s`", + gesturecombo, binding->command, config_binding->command); + if (warn) { + config_add_swaynag_warning("Overwriting binding" + "'%s' to `%s` from `%s`", + gesturecombo, binding->command, + config_binding->command); + } + free_gesture_binding(config_binding); + mode_bindings->items[i] = binding; + overwritten = true; + } + } + + if (!overwritten) { + list_add(mode_bindings, binding); + sway_log(SWAY_DEBUG, "bindgesture - Bound %s to command `%s`", + gesturecombo, binding->command); + } + + return cmd_results_new(CMD_SUCCESS, NULL); +} + +/** + * Remove gesture binding from config + */ +static struct cmd_results *gesture_binding_remove( + struct sway_gesture_binding *binding, const char *gesturecombo) { + list_t *mode_bindings = config->current_mode->gesture_bindings; + for (int i = 0; i < mode_bindings->length; ++i) { + struct sway_gesture_binding *config_binding = mode_bindings->items[i]; + if (binding_gesture_equal(binding, config_binding)) { + free_gesture_binding(config_binding); + free_gesture_binding(binding); + list_del(mode_bindings, i); + sway_log(SWAY_DEBUG, "unbindgesture - Unbound %s gesture", + gesturecombo); + return cmd_results_new(CMD_SUCCESS, NULL); + } + } + + free_gesture_binding(binding); + return cmd_results_new(CMD_FAILURE, "Could not find gesture binding `%s`", + gesturecombo); +} + +/** + * Parse and execute bindgesture or unbindgesture command. + */ +static struct cmd_results *cmd_bind_or_unbind_gesture(int argc, char **argv, bool unbind) { + int minargs = 2; + char *bindtype = "bindgesture"; + if (unbind) { + minargs--; + bindtype = "unbindgesture"; + } + + struct cmd_results *error = NULL; + if ((error = checkarg(argc, bindtype, EXPECTED_AT_LEAST, minargs))) { + return error; + } + struct sway_gesture_binding *binding = calloc(1, sizeof(struct sway_gesture_binding)); + if (!binding) { + return cmd_results_new(CMD_FAILURE, "Unable to allocate binding"); + } + binding->input = strdup("*"); + + bool warn = true; + + // Handle flags + while (argc > 0) { + if (strcmp("--exact", argv[0]) == 0) { + binding->flags |= BINDING_EXACT; + } else if (strcmp("--no-warn", argv[0]) == 0) { + warn = false; + } else if (strncmp("--input-device=", argv[0], + strlen("--input-device=")) == 0) { + free(binding->input); + binding->input = strdup(argv[0] + strlen("--input-device=")); + } else { + break; + } + argv++; + argc--; + } + + if (argc < minargs) { + free(binding); + return cmd_results_new(CMD_FAILURE, + "Invalid %s command (expected at least %d " + "non-option arguments, got %d)", bindtype, minargs, argc); + } + + char* errmsg = NULL; + if ((errmsg = gesture_parse(argv[0], &binding->gesture))) { + free(binding); + struct cmd_results *final = cmd_results_new(CMD_FAILURE, + "Invalid %s command (%s)", + bindtype, errmsg); + free(errmsg); + return final; + } + + if (unbind) { + return gesture_binding_remove(binding, argv[0]); + } + binding->command = join_args(argv + 1, argc - 1); + return gesture_binding_add(binding, argv[0], warn); +} + +struct cmd_results *cmd_bindgesture(int argc, char **argv) { + return cmd_bind_or_unbind_gesture(argc, argv, false); +} + +struct cmd_results *cmd_unbindgesture(int argc, char **argv) { + return cmd_bind_or_unbind_gesture(argc, argv, true); +} diff --git a/sway/commands/mode.c b/sway/commands/mode.c index e23e4ee4..7263efcb 100644 --- a/sway/commands/mode.c +++ b/sway/commands/mode.c @@ -11,10 +11,12 @@ // Must be in order for the bsearch static const struct cmd_handler mode_handlers[] = { { "bindcode", cmd_bindcode }, + { "bindgesture", cmd_bindgesture }, { "bindswitch", cmd_bindswitch }, { "bindsym", cmd_bindsym }, { "set", cmd_set }, { "unbindcode", cmd_unbindcode }, + { "unbindgesture", cmd_unbindgesture }, { "unbindswitch", cmd_unbindswitch }, { "unbindsym", cmd_unbindsym }, }; @@ -59,6 +61,7 @@ struct cmd_results *cmd_mode(int argc, char **argv) { mode->keycode_bindings = create_list(); mode->mouse_bindings = create_list(); mode->switch_bindings = create_list(); + mode->gesture_bindings = create_list(); mode->pango = pango; list_add(config->modes, mode); } |