aboutsummaryrefslogtreecommitdiffstats
path: root/sway/commands/gesture.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/commands/gesture.c')
-rw-r--r--sway/commands/gesture.c166
1 files changed, 166 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 @@
1#define _POSIX_C_SOURCE 200809L
2#include "sway/config.h"
3
4#include "gesture.h"
5#include "log.h"
6#include "stringop.h"
7#include "sway/commands.h"
8
9void free_gesture_binding(struct sway_gesture_binding *binding) {
10 if (!binding) {
11 return;
12 }
13 free(binding->input);
14 free(binding->command);
15 free(binding);
16}
17
18/**
19 * Returns true if the bindings have the same gesture type, direction, etc
20 */
21static bool binding_gesture_equal(struct sway_gesture_binding *binding_a,
22 struct sway_gesture_binding *binding_b) {
23 if (strcmp(binding_a->input, binding_b->input) != 0) {
24 return false;
25 }
26
27 if (!gesture_equal(&binding_a->gesture, &binding_b->gesture)) {
28 return false;
29 }
30
31 if ((binding_a->flags & BINDING_EXACT) !=
32 (binding_b->flags & BINDING_EXACT)) {
33 return false;
34 }
35 return true;
36}
37
38/**
39 * Add gesture binding to config
40 */
41static struct cmd_results *gesture_binding_add(
42 struct sway_gesture_binding *binding,
43 const char *gesturecombo, bool warn) {
44 list_t *mode_bindings = config->current_mode->gesture_bindings;
45 // overwrite the binding if it already exists
46 bool overwritten = false;
47 for (int i = 0; i < mode_bindings->length; ++i) {
48 struct sway_gesture_binding *config_binding = mode_bindings->items[i];
49 if (binding_gesture_equal(binding, config_binding)) {
50 sway_log(SWAY_INFO, "Overwriting binding '%s' to `%s` from `%s`",
51 gesturecombo, binding->command, config_binding->command);
52 if (warn) {
53 config_add_swaynag_warning("Overwriting binding"
54 "'%s' to `%s` from `%s`",
55 gesturecombo, binding->command,
56 config_binding->command);
57 }
58 free_gesture_binding(config_binding);
59 mode_bindings->items[i] = binding;
60 overwritten = true;
61 }
62 }
63
64 if (!overwritten) {
65 list_add(mode_bindings, binding);
66 sway_log(SWAY_DEBUG, "bindgesture - Bound %s to command `%s`",
67 gesturecombo, binding->command);
68 }
69
70 return cmd_results_new(CMD_SUCCESS, NULL);
71}
72
73/**
74 * Remove gesture binding from config
75 */
76static struct cmd_results *gesture_binding_remove(
77 struct sway_gesture_binding *binding, const char *gesturecombo) {
78 list_t *mode_bindings = config->current_mode->gesture_bindings;
79 for (int i = 0; i < mode_bindings->length; ++i) {
80 struct sway_gesture_binding *config_binding = mode_bindings->items[i];
81 if (binding_gesture_equal(binding, config_binding)) {
82 free_gesture_binding(config_binding);
83 free_gesture_binding(binding);
84 list_del(mode_bindings, i);
85 sway_log(SWAY_DEBUG, "unbindgesture - Unbound %s gesture",
86 gesturecombo);
87 return cmd_results_new(CMD_SUCCESS, NULL);
88 }
89 }
90
91 free_gesture_binding(binding);
92 return cmd_results_new(CMD_FAILURE, "Could not find gesture binding `%s`",
93 gesturecombo);
94}
95
96/**
97 * Parse and execute bindgesture or unbindgesture command.
98 */
99static struct cmd_results *cmd_bind_or_unbind_gesture(int argc, char **argv, bool unbind) {
100 int minargs = 2;
101 char *bindtype = "bindgesture";
102 if (unbind) {
103 minargs--;
104 bindtype = "unbindgesture";
105 }
106
107 struct cmd_results *error = NULL;
108 if ((error = checkarg(argc, bindtype, EXPECTED_AT_LEAST, minargs))) {
109 return error;
110 }
111 struct sway_gesture_binding *binding = calloc(1, sizeof(struct sway_gesture_binding));
112 if (!binding) {
113 return cmd_results_new(CMD_FAILURE, "Unable to allocate binding");
114 }
115 binding->input = strdup("*");
116
117 bool warn = true;
118
119 // Handle flags
120 while (argc > 0) {
121 if (strcmp("--exact", argv[0]) == 0) {
122 binding->flags |= BINDING_EXACT;
123 } else if (strcmp("--no-warn", argv[0]) == 0) {
124 warn = false;
125 } else if (strncmp("--input-device=", argv[0],
126 strlen("--input-device=")) == 0) {
127 free(binding->input);
128 binding->input = strdup(argv[0] + strlen("--input-device="));
129 } else {
130 break;
131 }
132 argv++;
133 argc--;
134 }
135
136 if (argc < minargs) {
137 free(binding);
138 return cmd_results_new(CMD_FAILURE,
139 "Invalid %s command (expected at least %d "
140 "non-option arguments, got %d)", bindtype, minargs, argc);
141 }
142
143 char* errmsg = NULL;
144 if ((errmsg = gesture_parse(argv[0], &binding->gesture))) {
145 free(binding);
146 struct cmd_results *final = cmd_results_new(CMD_FAILURE,
147 "Invalid %s command (%s)",
148 bindtype, errmsg);
149 free(errmsg);
150 return final;
151 }
152
153 if (unbind) {
154 return gesture_binding_remove(binding, argv[0]);
155 }
156 binding->command = join_args(argv + 1, argc - 1);
157 return gesture_binding_add(binding, argv[0], warn);
158}
159
160struct cmd_results *cmd_bindgesture(int argc, char **argv) {
161 return cmd_bind_or_unbind_gesture(argc, argv, false);
162}
163
164struct cmd_results *cmd_unbindgesture(int argc, char **argv) {
165 return cmd_bind_or_unbind_gesture(argc, argv, true);
166}