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