aboutsummaryrefslogtreecommitdiff
path: root/sway/commands
diff options
context:
space:
mode:
Diffstat (limited to 'sway/commands')
-rw-r--r--sway/commands/gesture.c166
-rw-r--r--sway/commands/mode.c3
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);
}