diff options
Diffstat (limited to 'sway/commands/gesture.c')
-rw-r--r-- | sway/commands/gesture.c | 166 |
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 | |||
9 | void 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 | */ | ||
21 | static 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 | */ | ||
41 | static 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 | */ | ||
76 | static 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 | */ | ||
99 | static 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 | |||
160 | struct cmd_results *cmd_bindgesture(int argc, char **argv) { | ||
161 | return cmd_bind_or_unbind_gesture(argc, argv, false); | ||
162 | } | ||
163 | |||
164 | struct cmd_results *cmd_unbindgesture(int argc, char **argv) { | ||
165 | return cmd_bind_or_unbind_gesture(argc, argv, true); | ||
166 | } | ||