summaryrefslogtreecommitdiffstats
path: root/sway
diff options
context:
space:
mode:
authorLibravatar Brian Ashworth <bosrsf04@gmail.com>2018-05-30 13:20:02 -0400
committerLibravatar Brian Ashworth <bosrsf04@gmail.com>2018-06-02 08:07:44 -0400
commit7c810dc344c28d1876c5ee158cb0806289d0f813 (patch)
treedbe756bceca42ea6f9a6cf5e5771037417bb64c3 /sway
parentMerge pull request #2080 from frsfnrrg/keyboard-remodeling (diff)
downloadsway-7c810dc344c28d1876c5ee158cb0806289d0f813.tar.gz
sway-7c810dc344c28d1876c5ee158cb0806289d0f813.tar.zst
sway-7c810dc344c28d1876c5ee158cb0806289d0f813.zip
Make command block implementation generic
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c153
-rw-r--r--sway/commands/bar.c118
-rw-r--r--sway/commands/bar/colors.c26
-rw-r--r--sway/commands/bar/id.c3
-rw-r--r--sway/commands/input.c103
-rw-r--r--sway/commands/mode.c28
-rw-r--r--sway/commands/seat.c61
-rw-r--r--sway/config.c156
-rw-r--r--sway/input/keyboard.c1
-rw-r--r--sway/ipc-server.c1
10 files changed, 265 insertions, 385 deletions
diff --git a/sway/commands.c b/sway/commands.c
index e9762bef..825fda8f 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -16,11 +16,6 @@
16#include "stringop.h" 16#include "stringop.h"
17#include "log.h" 17#include "log.h"
18 18
19struct cmd_handler {
20 char *command;
21 sway_cmd *handle;
22};
23
24// Returns error object, or NULL if check succeeds. 19// Returns error object, or NULL if check succeeds.
25struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) { 20struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) {
26 struct cmd_results *error = NULL; 21 struct cmd_results *error = NULL;
@@ -122,47 +117,6 @@ static struct cmd_handler handlers[] = {
122 { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth }, 117 { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth },
123}; 118};
124 119
125static struct cmd_handler bar_handlers[] = {
126 { "activate_button", bar_cmd_activate_button },
127 { "binding_mode_indicator", bar_cmd_binding_mode_indicator },
128 { "bindsym", bar_cmd_bindsym },
129 { "colors", bar_cmd_colors },
130 { "context_button", bar_cmd_context_button },
131 { "font", bar_cmd_font },
132 { "height", bar_cmd_height },
133 { "hidden_state", bar_cmd_hidden_state },
134 { "icon_theme", bar_cmd_icon_theme },
135 { "id", bar_cmd_id },
136 { "mode", bar_cmd_mode },
137 { "modifier", bar_cmd_modifier },
138 { "output", bar_cmd_output },
139 { "pango_markup", bar_cmd_pango_markup },
140 { "position", bar_cmd_position },
141 { "secondary_button", bar_cmd_secondary_button },
142 { "separator_symbol", bar_cmd_separator_symbol },
143 { "status_command", bar_cmd_status_command },
144 { "strip_workspace_numbers", bar_cmd_strip_workspace_numbers },
145 { "swaybar_command", bar_cmd_swaybar_command },
146 { "tray_output", bar_cmd_tray_output },
147 { "tray_padding", bar_cmd_tray_padding },
148 { "workspace_buttons", bar_cmd_workspace_buttons },
149 { "wrap_scroll", bar_cmd_wrap_scroll },
150};
151
152static struct cmd_handler bar_colors_handlers[] = {
153 { "active_workspace", bar_colors_cmd_active_workspace },
154 { "background", bar_colors_cmd_background },
155 { "binding_mode", bar_colors_cmd_binding_mode },
156 { "focused_background", bar_colors_cmd_focused_background },
157 { "focused_separator", bar_colors_cmd_focused_separator },
158 { "focused_statusline", bar_colors_cmd_focused_statusline },
159 { "focused_workspace", bar_colors_cmd_focused_workspace },
160 { "inactive_workspace", bar_colors_cmd_inactive_workspace },
161 { "separator", bar_colors_cmd_separator },
162 { "statusline", bar_colors_cmd_statusline },
163 { "urgent_workspace", bar_colors_cmd_urgent_workspace },
164};
165
166/* Config-time only commands. Keep alphabetized */ 120/* Config-time only commands. Keep alphabetized */
167static struct cmd_handler config_handlers[] = { 121static struct cmd_handler config_handlers[] = {
168 { "default_orientation", cmd_default_orientation }, 122 { "default_orientation", cmd_default_orientation },
@@ -202,62 +156,14 @@ static int handler_compare(const void *_a, const void *_b) {
202 return strcasecmp(a->command, b->command); 156 return strcasecmp(a->command, b->command);
203} 157}
204 158
205// must be in order for the bsearch 159struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers,
206static struct cmd_handler input_handlers[] = { 160 int handlers_size) {
207 { "accel_profile", input_cmd_accel_profile },
208 { "click_method", input_cmd_click_method },
209 { "drag_lock", input_cmd_drag_lock },
210 { "dwt", input_cmd_dwt },
211 { "events", input_cmd_events },
212 { "left_handed", input_cmd_left_handed },
213 { "map_from_region", input_cmd_map_from_region },
214 { "map_to_output", input_cmd_map_to_output },
215 { "middle_emulation", input_cmd_middle_emulation },
216 { "natural_scroll", input_cmd_natural_scroll },
217 { "pointer_accel", input_cmd_pointer_accel },
218 { "repeat_delay", input_cmd_repeat_delay },
219 { "repeat_rate", input_cmd_repeat_rate },
220 { "scroll_method", input_cmd_scroll_method },
221 { "tap", input_cmd_tap },
222 { "xkb_layout", input_cmd_xkb_layout },
223 { "xkb_model", input_cmd_xkb_model },
224 { "xkb_options", input_cmd_xkb_options },
225 { "xkb_rules", input_cmd_xkb_rules },
226 { "xkb_variant", input_cmd_xkb_variant },
227};
228
229// must be in order for the bsearch
230static struct cmd_handler seat_handlers[] = {
231 { "attach", seat_cmd_attach },
232 { "cursor", seat_cmd_cursor },
233 { "fallback", seat_cmd_fallback },
234};
235
236static struct cmd_handler *find_handler(char *line, enum cmd_status block) {
237 struct cmd_handler d = { .command=line }; 161 struct cmd_handler d = { .command=line };
238 struct cmd_handler *res = NULL; 162 struct cmd_handler *res = NULL;
239 wlr_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_SEAT); 163 wlr_log(L_DEBUG, "find_handler(%s)", line);
240 164
241 bool config_loading = config->reading || !config->active; 165 bool config_loading = config->reading || !config->active;
242 166
243 if (block == CMD_BLOCK_BAR) {
244 return bsearch(&d, bar_handlers,
245 sizeof(bar_handlers) / sizeof(struct cmd_handler),
246 sizeof(struct cmd_handler), handler_compare);
247 } else if (block == CMD_BLOCK_BAR_COLORS) {
248 return bsearch(&d, bar_colors_handlers,
249 sizeof(bar_colors_handlers) / sizeof(struct cmd_handler),
250 sizeof(struct cmd_handler), handler_compare);
251 } else if (block == CMD_BLOCK_INPUT) {
252 return bsearch(&d, input_handlers,
253 sizeof(input_handlers) / sizeof(struct cmd_handler),
254 sizeof(struct cmd_handler), handler_compare);
255 } else if (block == CMD_BLOCK_SEAT) {
256 return bsearch(&d, seat_handlers,
257 sizeof(seat_handlers) / sizeof(struct cmd_handler),
258 sizeof(struct cmd_handler), handler_compare);
259 }
260
261 if (!config_loading) { 167 if (!config_loading) {
262 res = bsearch(&d, command_handlers, 168 res = bsearch(&d, command_handlers,
263 sizeof(command_handlers) / sizeof(struct cmd_handler), 169 sizeof(command_handlers) / sizeof(struct cmd_handler),
@@ -278,8 +184,13 @@ static struct cmd_handler *find_handler(char *line, enum cmd_status block) {
278 } 184 }
279 } 185 }
280 186
281 res = bsearch(&d, handlers, 187 if (!cmd_handlers) {
282 sizeof(handlers) / sizeof(struct cmd_handler), 188 cmd_handlers = handlers;
189 handlers_size = sizeof(handlers);
190 }
191
192 res = bsearch(&d, cmd_handlers,
193 handlers_size / sizeof(struct cmd_handler),
283 sizeof(struct cmd_handler), handler_compare); 194 sizeof(struct cmd_handler), handler_compare);
284 195
285 return res; 196 return res;
@@ -349,7 +260,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
349 } 260 }
350 } 261 }
351 } 262 }
352 struct cmd_handler *handler = find_handler(argv[0], CMD_BLOCK_END); 263 struct cmd_handler *handler = find_handler(argv[0], NULL, 0);
353 if (!handler) { 264 if (!handler) {
354 if (results) { 265 if (results) {
355 free_cmd_results(results); 266 free_cmd_results(results);
@@ -413,7 +324,7 @@ cleanup:
413// be chained together) 324// be chained together)
414// 4) execute_command handles all state internally while config_command has 325// 4) execute_command handles all state internally while config_command has
415// some state handled outside (notably the block mode, in read_config) 326// some state handled outside (notably the block mode, in read_config)
416struct cmd_results *config_command(char *exec, enum cmd_status block) { 327struct cmd_results *config_command(char *exec) {
417 struct cmd_results *results = NULL; 328 struct cmd_results *results = NULL;
418 int argc; 329 int argc;
419 char **argv = split_args(exec, &argc); 330 char **argv = split_args(exec, &argc);
@@ -422,13 +333,21 @@ struct cmd_results *config_command(char *exec, enum cmd_status block) {
422 goto cleanup; 333 goto cleanup;
423 } 334 }
424 335
425 wlr_log(L_INFO, "handling config command '%s'", exec); 336 // Start block
337 if (argc > 1 && strcmp(argv[argc - 1], "{") == 0) {
338 char *block = join_args(argv, argc - 1);
339 results = cmd_results_new(CMD_BLOCK, block, NULL);
340 free(block);
341 goto cleanup;
342 }
343
426 // Endblock 344 // Endblock
427 if (**argv == '}') { 345 if (strcmp(argv[argc - 1], "}") == 0) {
428 results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); 346 results = cmd_results_new(CMD_BLOCK_END, NULL, NULL);
429 goto cleanup; 347 goto cleanup;
430 } 348 }
431 struct cmd_handler *handler = find_handler(argv[0], block); 349 wlr_log(L_INFO, "handling config command '%s'", exec);
350 struct cmd_handler *handler = find_handler(argv[0], NULL, 0);
432 if (!handler) { 351 if (!handler) {
433 char *input = argv[0] ? argv[0] : "(empty)"; 352 char *input = argv[0] ? argv[0] : "(empty)";
434 results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); 353 results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
@@ -457,6 +376,30 @@ cleanup:
457 return results; 376 return results;
458} 377}
459 378
379struct cmd_results *subcommand(char **argv, int argc,
380 struct cmd_handler *handlers, int handlers_size) {
381 char *command = join_args(argv, argc);
382 wlr_log(L_DEBUG, "Subcommand: %s", command);
383 free(command);
384
385 struct cmd_handler *handler = find_handler(argv[0], handlers,
386 handlers_size);
387 if (!handler) {
388 char *input = argv[0] ? argv[0] : "(empty)";
389 return cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
390 }
391 // Strip quotes for first argument.
392 // TODO This part needs to be handled much better
393 if (argc > 1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
394 strip_quotes(argv[1]);
395 }
396 if (handler->handle) {
397 return handler->handle(argc - 1, argv + 1);
398 }
399 return cmd_results_new(CMD_INVALID, argv[0],
400 "This command is shimmed, but unimplemented");
401}
402
460struct cmd_results *config_commands_command(char *exec) { 403struct cmd_results *config_commands_command(char *exec) {
461 struct cmd_results *results = NULL; 404 struct cmd_results *results = NULL;
462 int argc; 405 int argc;
@@ -474,7 +417,7 @@ struct cmd_results *config_commands_command(char *exec) {
474 goto cleanup; 417 goto cleanup;
475 } 418 }
476 419
477 struct cmd_handler *handler = find_handler(cmd, CMD_BLOCK_END); 420 struct cmd_handler *handler = find_handler(cmd, NULL, 0);
478 if (!handler && strcmp(cmd, "*") != 0) { 421 if (!handler && strcmp(cmd, "*") != 0) {
479 char *input = cmd ? cmd : "(empty)"; 422 char *input = cmd ? cmd : "(empty)";
480 results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); 423 results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
diff --git a/sway/commands/bar.c b/sway/commands/bar.c
index ff111163..358b3893 100644
--- a/sway/commands/bar.c
+++ b/sway/commands/bar.c
@@ -1,3 +1,4 @@
1#define _XOPEN_SOURCE 500
1#include <string.h> 2#include <string.h>
2#include <strings.h> 3#include <strings.h>
3#include <wlr/util/log.h> 4#include <wlr/util/log.h>
@@ -5,53 +6,110 @@
5#include "sway/config.h" 6#include "sway/config.h"
6#include "util.h" 7#include "util.h"
7 8
9// Must be in alphabetical order for bsearch
10static struct cmd_handler bar_handlers[] = {
11 { "activate_button", bar_cmd_activate_button },
12 { "binding_mode_indicator", bar_cmd_binding_mode_indicator },
13 { "bindsym", bar_cmd_bindsym },
14 { "colors", bar_cmd_colors },
15 { "context_button", bar_cmd_context_button },
16 { "font", bar_cmd_font },
17 { "height", bar_cmd_height },
18 { "hidden_state", bar_cmd_hidden_state },
19 { "icon_theme", bar_cmd_icon_theme },
20 { "id", bar_cmd_id },
21 { "mode", bar_cmd_mode },
22 { "modifier", bar_cmd_modifier },
23 { "output", bar_cmd_output },
24 { "pango_markup", bar_cmd_pango_markup },
25 { "position", bar_cmd_position },
26 { "secondary_button", bar_cmd_secondary_button },
27 { "separator_symbol", bar_cmd_separator_symbol },
28 { "status_command", bar_cmd_status_command },
29 { "strip_workspace_numbers", bar_cmd_strip_workspace_numbers },
30 { "swaybar_command", bar_cmd_swaybar_command },
31 { "tray_output", bar_cmd_tray_output },
32 { "tray_padding", bar_cmd_tray_padding },
33 { "workspace_buttons", bar_cmd_workspace_buttons },
34 { "wrap_scroll", bar_cmd_wrap_scroll },
35};
36
37// Must be in alphabetical order for bsearch
38static struct cmd_handler bar_config_handlers[] = {
39 { "hidden_state", bar_cmd_hidden_state },
40 { "mode", bar_cmd_mode }
41};
42
8struct cmd_results *cmd_bar(int argc, char **argv) { 43struct cmd_results *cmd_bar(int argc, char **argv) {
9 struct cmd_results *error = NULL; 44 struct cmd_results *error = NULL;
10 if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 1))) { 45 if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 1))) {
11 return error; 46 return error;
12 } 47 }
13 48
14 if (config->reading && strcmp("{", argv[0]) != 0) { 49 if (!config->reading) {
15 return cmd_results_new(CMD_INVALID, "bar", 50 if (!find_handler(argv[0], bar_config_handlers,
16 "Expected '{' at start of bar config definition."); 51 sizeof(bar_config_handlers))) {
52 return cmd_results_new(CMD_FAILURE, "bar",
53 "Can only be used in config file.");
54 }
55 return subcommand(argv, argc, bar_config_handlers,
56 sizeof(bar_config_handlers));
17 } 57 }
18 58
19 if (!config->reading) { 59 if (argc > 1) {
20 if (argc > 1) { 60 struct bar_config *bar = NULL;
21 if (strcasecmp("mode", argv[0]) == 0) { 61 if (!find_handler(argv[0], bar_handlers, sizeof(bar_handlers))
22 return bar_cmd_mode(argc-1, argv + 1); 62 && find_handler(argv[1], bar_handlers, sizeof(bar_handlers))) {
63 for (int i = 0; i < config->bars->length; ++i) {
64 struct bar_config *item = config->bars->items[i];
65 if (strcmp(item->id, argv[0]) == 0) {
66 wlr_log(L_DEBUG, "Selecting bar: %s", argv[0]);
67 bar = item;
68 break;
69 }
23 } 70 }
71 if (!bar) {
72 wlr_log(L_DEBUG, "Creating bar: %s", argv[0]);
73 bar = default_bar_config();
74 if (!bar) {
75 return cmd_results_new(CMD_FAILURE, "bar",
76 "Unable to allocate bar state");
77 }
24 78
25 if (strcasecmp("hidden_state", argv[0]) == 0) { 79 bar->id = strdup(argv[0]);
26 return bar_cmd_hidden_state(argc-1, argv + 1);
27 } 80 }
81 config->current_bar = bar;
82 ++argv; --argc;
28 } 83 }
29 return cmd_results_new(CMD_FAILURE, "bar", "Can only be used in config file.");
30 } 84 }
31 85
32 // Create new bar with default values 86 if (!config->current_bar) {
33 struct bar_config *bar = default_bar_config(); 87 // Create new bar with default values
34 if (!bar) { 88 struct bar_config *bar = default_bar_config();
35 return cmd_results_new(CMD_FAILURE, "bar", "Unable to allocate bar state"); 89 if (!bar) {
36 } 90 return cmd_results_new(CMD_FAILURE, "bar",
91 "Unable to allocate bar state");
92 }
37 93
38 // set bar id 94 // set bar id
39 for (int i = 0; i < config->bars->length; ++i) { 95 for (int i = 0; i < config->bars->length; ++i) {
40 if (bar == config->bars->items[i]) { 96 if (bar == config->bars->items[i]) {
41 const int len = 5 + numlen(i); // "bar-" + i + \0 97 const int len = 5 + numlen(i); // "bar-" + i + \0
42 bar->id = malloc(len * sizeof(char)); 98 bar->id = malloc(len * sizeof(char));
43 if (bar->id) { 99 if (bar->id) {
44 snprintf(bar->id, len, "bar-%d", i); 100 snprintf(bar->id, len, "bar-%d", i);
45 } else { 101 } else {
46 return cmd_results_new(CMD_FAILURE, 102 return cmd_results_new(CMD_FAILURE,
47 "bar", "Unable to allocate bar ID"); 103 "bar", "Unable to allocate bar ID");
104 }
105 break;
48 } 106 }
49 break;
50 } 107 }
108
109 // Set current bar
110 config->current_bar = bar;
111 wlr_log(L_DEBUG, "Creating bar %s", bar->id);
51 } 112 }
52 113
53 // Set current bar 114 return subcommand(argv, argc, bar_handlers, sizeof(bar_handlers));
54 config->current_bar = bar;
55 wlr_log(L_DEBUG, "Configuring bar %s", bar->id);
56 return cmd_results_new(CMD_BLOCK_BAR, NULL, NULL);
57} 115}
diff --git a/sway/commands/bar/colors.c b/sway/commands/bar/colors.c
index 17ba9b7c..6d3c09b8 100644
--- a/sway/commands/bar/colors.c
+++ b/sway/commands/bar/colors.c
@@ -1,6 +1,21 @@
1#include <string.h> 1#include <string.h>
2#include "sway/commands.h" 2#include "sway/commands.h"
3 3
4// Must be in alphabetical order for bsearch
5static struct cmd_handler bar_colors_handlers[] = {
6 { "active_workspace", bar_colors_cmd_active_workspace },
7 { "background", bar_colors_cmd_background },
8 { "binding_mode", bar_colors_cmd_binding_mode },
9 { "focused_background", bar_colors_cmd_focused_background },
10 { "focused_separator", bar_colors_cmd_focused_separator },
11 { "focused_statusline", bar_colors_cmd_focused_statusline },
12 { "focused_workspace", bar_colors_cmd_focused_workspace },
13 { "inactive_workspace", bar_colors_cmd_inactive_workspace },
14 { "separator", bar_colors_cmd_separator },
15 { "statusline", bar_colors_cmd_statusline },
16 { "urgent_workspace", bar_colors_cmd_urgent_workspace },
17};
18
4static struct cmd_results *parse_single_color(char **color, 19static struct cmd_results *parse_single_color(char **color,
5 const char *cmd_name, int argc, char **argv) { 20 const char *cmd_name, int argc, char **argv) {
6 struct cmd_results *error = NULL; 21 struct cmd_results *error = NULL;
@@ -37,15 +52,8 @@ static struct cmd_results *parse_three_colors(char ***colors,
37} 52}
38 53
39struct cmd_results *bar_cmd_colors(int argc, char **argv) { 54struct cmd_results *bar_cmd_colors(int argc, char **argv) {
40 struct cmd_results *error = NULL; 55 return subcommand(argv, argc, bar_colors_handlers,
41 if ((error = checkarg(argc, "colors", EXPECTED_EQUAL_TO, 1))) { 56 sizeof(bar_colors_handlers));
42 return error;
43 }
44 if (strcmp("{", argv[0]) != 0) {
45 return cmd_results_new(CMD_INVALID, "colors",
46 "Expected '{' at the start of colors config definition.");
47 }
48 return cmd_results_new(CMD_BLOCK_BAR_COLORS, NULL, NULL);
49} 57}
50 58
51struct cmd_results *bar_colors_cmd_active_workspace(int argc, char **argv) { 59struct cmd_results *bar_colors_cmd_active_workspace(int argc, char **argv) {
diff --git a/sway/commands/bar/id.c b/sway/commands/bar/id.c
index c1e56f03..6ce86fef 100644
--- a/sway/commands/bar/id.c
+++ b/sway/commands/bar/id.c
@@ -11,6 +11,9 @@ struct cmd_results *bar_cmd_id(int argc, char **argv) {
11 11
12 const char *name = argv[0]; 12 const char *name = argv[0];
13 const char *oldname = config->current_bar->id; 13 const char *oldname = config->current_bar->id;
14 if (strcmp(name, oldname) == 0) {
15 return cmd_results_new(CMD_SUCCESS, NULL, NULL); // NOP
16 }
14 // check if id is used by a previously defined bar 17 // check if id is used by a previously defined bar
15 for (int i = 0; i < config->bars->length; ++i) { 18 for (int i = 0; i < config->bars->length; ++i) {
16 struct bar_config *find = config->bars->items[i]; 19 struct bar_config *find = config->bars->items[i];
diff --git a/sway/commands/input.c b/sway/commands/input.c
index eeb4ee75..972160e2 100644
--- a/sway/commands/input.c
+++ b/sway/commands/input.c
@@ -3,85 +3,50 @@
3#include "sway/commands.h" 3#include "sway/commands.h"
4#include "sway/input/input-manager.h" 4#include "sway/input/input-manager.h"
5#include "log.h" 5#include "log.h"
6#include "stringop.h"
7
8// must be in order for the bsearch
9static struct cmd_handler input_handlers[] = {
10 { "accel_profile", input_cmd_accel_profile },
11 { "click_method", input_cmd_click_method },
12 { "drag_lock", input_cmd_drag_lock },
13 { "dwt", input_cmd_dwt },
14 { "events", input_cmd_events },
15 { "left_handed", input_cmd_left_handed },
16 { "map_from_region", input_cmd_map_from_region },
17 { "map_to_output", input_cmd_map_to_output },
18 { "middle_emulation", input_cmd_middle_emulation },
19 { "natural_scroll", input_cmd_natural_scroll },
20 { "pointer_accel", input_cmd_pointer_accel },
21 { "repeat_delay", input_cmd_repeat_delay },
22 { "repeat_rate", input_cmd_repeat_rate },
23 { "scroll_method", input_cmd_scroll_method },
24 { "tap", input_cmd_tap },
25 { "xkb_layout", input_cmd_xkb_layout },
26 { "xkb_model", input_cmd_xkb_model },
27 { "xkb_options", input_cmd_xkb_options },
28 { "xkb_rules", input_cmd_xkb_rules },
29 { "xkb_variant", input_cmd_xkb_variant },
30};
6 31
7struct cmd_results *cmd_input(int argc, char **argv) { 32struct cmd_results *cmd_input(int argc, char **argv) {
8 struct cmd_results *error = NULL; 33 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) { 34 if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 1))) {
10 return error; 35 return error;
11 } 36 }
12 37
13 if (config->reading && strcmp("{", argv[1]) == 0) { 38 wlr_log(L_DEBUG, "entering input block: %s", argv[0]);
14 free_input_config(config->handler_context.input_config);
15 config->handler_context.input_config = new_input_config(argv[0]);
16 if (!config->handler_context.input_config) {
17 return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
18 }
19 wlr_log(L_DEBUG, "entering input block: %s", argv[0]);
20 return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL);
21 }
22
23 if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 3))) {
24 return error;
25 }
26 39
27 bool has_context = (config->handler_context.input_config != NULL); 40 config->handler_context.input_config = new_input_config(argv[0]);
28 if (!has_context) { 41 if (!config->handler_context.input_config) {
29 // caller did not give a context so create one just for this command 42 return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
30 config->handler_context.input_config = new_input_config(argv[0]);
31 if (!config->handler_context.input_config) {
32 return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
33 }
34 } 43 }
35 44
36 int argc_new = argc-2; 45 struct cmd_results *res = subcommand(argv + 1, argc - 1, input_handlers,
37 char **argv_new = argv+2; 46 sizeof(input_handlers));
38 47
39 struct cmd_results *res; 48 free_input_config(config->handler_context.input_config);
40 if (strcasecmp("accel_profile", argv[1]) == 0) { 49 config->handler_context.input_config = NULL;
41 res = input_cmd_accel_profile(argc_new, argv_new);
42 } else if (strcasecmp("click_method", argv[1]) == 0) {
43 res = input_cmd_click_method(argc_new, argv_new);
44 } else if (strcasecmp("drag_lock", argv[1]) == 0) {
45 res = input_cmd_drag_lock(argc_new, argv_new);
46 } else if (strcasecmp("dwt", argv[1]) == 0) {
47 res = input_cmd_dwt(argc_new, argv_new);
48 } else if (strcasecmp("events", argv[1]) == 0) {
49 res = input_cmd_events(argc_new, argv_new);
50 } else if (strcasecmp("left_handed", argv[1]) == 0) {
51 res = input_cmd_left_handed(argc_new, argv_new);
52 } else if (strcasecmp("middle_emulation", argv[1]) == 0) {
53 res = input_cmd_middle_emulation(argc_new, argv_new);
54 } else if (strcasecmp("natural_scroll", argv[1]) == 0) {
55 res = input_cmd_natural_scroll(argc_new, argv_new);
56 } else if (strcasecmp("pointer_accel", argv[1]) == 0) {
57 res = input_cmd_pointer_accel(argc_new, argv_new);
58 } else if (strcasecmp("repeat_delay", argv[1]) == 0) {
59 res = input_cmd_repeat_delay(argc_new, argv_new);
60 } else if (strcasecmp("repeat_rate", argv[1]) == 0) {
61 res = input_cmd_repeat_rate(argc_new, argv_new);
62 } else if (strcasecmp("scroll_method", argv[1]) == 0) {
63 res = input_cmd_scroll_method(argc_new, argv_new);
64 } else if (strcasecmp("tap", argv[1]) == 0) {
65 res = input_cmd_tap(argc_new, argv_new);
66 } else if (strcasecmp("xkb_layout", argv[1]) == 0) {
67 res = input_cmd_xkb_layout(argc_new, argv_new);
68 } else if (strcasecmp("xkb_model", argv[1]) == 0) {
69 res = input_cmd_xkb_model(argc_new, argv_new);
70 } else if (strcasecmp("xkb_options", argv[1]) == 0) {
71 res = input_cmd_xkb_options(argc_new, argv_new);
72 } else if (strcasecmp("xkb_rules", argv[1]) == 0) {
73 res = input_cmd_xkb_rules(argc_new, argv_new);
74 } else if (strcasecmp("xkb_variant", argv[1]) == 0) {
75 res = input_cmd_xkb_variant(argc_new, argv_new);
76 } else {
77 res = cmd_results_new(CMD_INVALID, "input <device>", "Unknown command %s", argv[1]);
78 }
79
80 if (!has_context) {
81 // clean up the context we created earlier
82 free_input_config(config->handler_context.input_config);
83 config->handler_context.input_config = NULL;
84 }
85 50
86 return res; 51 return res;
87} 52}
diff --git a/sway/commands/mode.c b/sway/commands/mode.c
index c30a8bac..31d0f251 100644
--- a/sway/commands/mode.c
+++ b/sway/commands/mode.c
@@ -7,6 +7,13 @@
7#include "sway/ipc-server.h" 7#include "sway/ipc-server.h"
8#include "list.h" 8#include "list.h"
9#include "log.h" 9#include "log.h"
10#include "stringop.h"
11
12// Must be in order for the bsearch
13static struct cmd_handler mode_handlers[] = {
14 { "bindcode", cmd_bindcode },
15 { "bindsym", cmd_bindsym }
16};
10 17
11struct cmd_results *cmd_mode(int argc, char **argv) { 18struct cmd_results *cmd_mode(int argc, char **argv) {
12 struct cmd_results *error = NULL; 19 struct cmd_results *error = NULL;
@@ -14,12 +21,12 @@ struct cmd_results *cmd_mode(int argc, char **argv) {
14 return error; 21 return error;
15 } 22 }
16 23
17 const char *mode_name = argv[0]; 24 if (argc > 1 && !config->reading) {
18 bool new_mode = (argc == 2 && strcmp(argv[1], "{") == 0);
19 if (new_mode && !config->reading) {
20 return cmd_results_new(CMD_FAILURE, 25 return cmd_results_new(CMD_FAILURE,
21 "mode", "Can only be used in config file."); 26 "mode", "Can only be used in config file.");
22 } 27 }
28
29 const char *mode_name = argv[0];
23 struct sway_mode *mode = NULL; 30 struct sway_mode *mode = NULL;
24 // Find mode 31 // Find mode
25 for (int i = 0; i < config->modes->length; ++i) { 32 for (int i = 0; i < config->modes->length; ++i) {
@@ -30,7 +37,7 @@ struct cmd_results *cmd_mode(int argc, char **argv) {
30 } 37 }
31 } 38 }
32 // Create mode if it doesn't exist 39 // Create mode if it doesn't exist
33 if (!mode && new_mode) { 40 if (!mode && argc > 1) {
34 mode = calloc(1, sizeof(struct sway_mode)); 41 mode = calloc(1, sizeof(struct sway_mode));
35 if (!mode) { 42 if (!mode) {
36 return cmd_results_new(CMD_FAILURE, 43 return cmd_results_new(CMD_FAILURE,
@@ -46,14 +53,21 @@ struct cmd_results *cmd_mode(int argc, char **argv) {
46 "mode", "Unknown mode `%s'", mode_name); 53 "mode", "Unknown mode `%s'", mode_name);
47 return error; 54 return error;
48 } 55 }
49 if ((config->reading && new_mode) || (!config->reading && !new_mode)) { 56 if ((config->reading && argc > 1) || (!config->reading && argc == 1)) {
50 wlr_log(L_DEBUG, "Switching to mode `%s'",mode->name); 57 wlr_log(L_DEBUG, "Switching to mode `%s'",mode->name);
51 } 58 }
52 // Set current mode 59 // Set current mode
53 config->current_mode = mode; 60 config->current_mode = mode;
54 if (!new_mode) { 61 if (argc == 1) {
55 // trigger IPC mode event 62 // trigger IPC mode event
56 ipc_event_mode(config->current_mode->name); 63 ipc_event_mode(config->current_mode->name);
64 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
57 } 65 }
58 return cmd_results_new(new_mode ? CMD_BLOCK_MODE : CMD_SUCCESS, NULL, NULL); 66
67 // Create binding
68 struct cmd_results *result = subcommand(argv + 1, argc - 1, mode_handlers,
69 sizeof(mode_handlers));
70 config->current_mode = config->modes->items[0];
71
72 return result;
59} 73}
diff --git a/sway/commands/seat.c b/sway/commands/seat.c
index 5916015f..6080bf64 100644
--- a/sway/commands/seat.c
+++ b/sway/commands/seat.c
@@ -3,59 +3,32 @@
3#include "sway/commands.h" 3#include "sway/commands.h"
4#include "sway/input/input-manager.h" 4#include "sway/input/input-manager.h"
5#include "log.h" 5#include "log.h"
6#include "stringop.h"
7
8// must be in order for the bsearch
9static struct cmd_handler seat_handlers[] = {
10 { "attach", seat_cmd_attach },
11 { "cursor", seat_cmd_cursor },
12 { "fallback", seat_cmd_fallback },
13};
6 14
7struct cmd_results *cmd_seat(int argc, char **argv) { 15struct cmd_results *cmd_seat(int argc, char **argv) {
8 struct cmd_results *error = NULL; 16 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "seat", EXPECTED_AT_LEAST, 2))) { 17 if ((error = checkarg(argc, "seat", EXPECTED_AT_LEAST, 1))) {
10 return error; 18 return error;
11 } 19 }
12 20
13 if (config->reading && strcmp("{", argv[1]) == 0) { 21 config->handler_context.seat_config = new_seat_config(argv[0]);
14 free_seat_config(config->handler_context.seat_config); 22 if (!config->handler_context.seat_config) {
15 config->handler_context.seat_config = new_seat_config(argv[0]); 23 return cmd_results_new(CMD_FAILURE, NULL,
16 if (!config->handler_context.seat_config) { 24 "Couldn't allocate config");
17 return cmd_results_new(CMD_FAILURE, NULL,
18 "Couldn't allocate config");
19 }
20 wlr_log(L_DEBUG, "entering seat block: %s", argv[0]);
21 return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL);
22 } 25 }
23 26
24 if ((error = checkarg(argc, "seat", EXPECTED_AT_LEAST, 3))) { 27 struct cmd_results *res = subcommand(argv + 1, argc - 1, seat_handlers,
25 return error; 28 sizeof(seat_handlers));
26 }
27
28 bool has_context = (config->handler_context.seat_config != NULL);
29 if (!has_context) {
30 config->handler_context.seat_config = new_seat_config(argv[0]);
31 if (!config->handler_context.seat_config) {
32 return cmd_results_new(CMD_FAILURE, NULL,
33 "Couldn't allocate config");
34 }
35 }
36 29
37 int argc_new = argc-2; 30 free_seat_config(config->handler_context.seat_config);
38 char **argv_new = argv+2; 31 config->handler_context.seat_config = NULL;
39
40 struct cmd_results *res;
41 if (strcasecmp("attach", argv[1]) == 0) {
42 res = seat_cmd_attach(argc_new, argv_new);
43 } else if (strcasecmp("cursor", argv[1]) == 0) {
44 res = seat_cmd_cursor(argc_new, argv_new);
45 } else if (strcasecmp("fallback", argv[1]) == 0) {
46 res = seat_cmd_fallback(argc_new, argv_new);
47 } else {
48 res =
49 cmd_results_new(CMD_INVALID,
50 "seat <name>", "Unknown command %s",
51 argv[1]);
52 }
53
54 if (!has_context) {
55 // clean up the context we created earlier
56 free_seat_config(config->handler_context.seat_config);
57 config->handler_context.seat_config = NULL;
58 }
59 32
60 return res; 33 return res;
61} 34}
diff --git a/sway/config.c b/sway/config.c
index 27308066..26e6f3e3 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -59,12 +59,12 @@ static void free_mode(struct sway_mode *mode) {
59} 59}
60 60
61void free_config(struct sway_config *config) { 61void free_config(struct sway_config *config) {
62 config_clear_handler_context(config);
63
64 if (!config) { 62 if (!config) {
65 return; 63 return;
66 } 64 }
67 65
66 memset(&config->handler_context, 0, sizeof(config->handler_context));
67
68 // TODO: handle all currently unhandled lists as we add implementations 68 // TODO: handle all currently unhandled lists as we add implementations
69 if (config->symbols) { 69 if (config->symbols) {
70 for (int i = 0; i < config->symbols->length; ++i) { 70 for (int i = 0; i < config->symbols->length; ++i) {
@@ -107,7 +107,6 @@ void free_config(struct sway_config *config) {
107 list_free(config->command_policies); 107 list_free(config->command_policies);
108 list_free(config->feature_policies); 108 list_free(config->feature_policies);
109 list_free(config->ipc_policies); 109 list_free(config->ipc_policies);
110 free(config->current_bar);
111 free(config->floating_scroll_up_cmd); 110 free(config->floating_scroll_up_cmd);
112 free(config->floating_scroll_down_cmd); 111 free(config->floating_scroll_down_cmd);
113 free(config->floating_scroll_left_cmd); 112 free(config->floating_scroll_left_cmd);
@@ -514,37 +513,41 @@ bool load_include_configs(const char *path, struct sway_config *config) {
514 return true; 513 return true;
515} 514}
516 515
517void config_clear_handler_context(struct sway_config *config) {
518 free_input_config(config->handler_context.input_config);
519 free_seat_config(config->handler_context.seat_config);
520
521 memset(&config->handler_context, 0, sizeof(config->handler_context));
522}
523
524bool read_config(FILE *file, struct sway_config *config) { 516bool read_config(FILE *file, struct sway_config *config) {
525 bool success = true; 517 bool success = true;
526 enum cmd_status block = CMD_BLOCK_END;
527
528 int line_number = 0; 518 int line_number = 0;
529 char *line; 519 char *line;
520 list_t *stack = create_list();
530 while (!feof(file)) { 521 while (!feof(file)) {
522 char *block = stack->length ? stack->items[0] : NULL;
531 line = read_line(file); 523 line = read_line(file);
532 if (!line) { 524 if (!line) {
533 continue; 525 continue;
534 } 526 }
535 line_number++; 527 line_number++;
528 wlr_log(L_DEBUG, "Read line %d: %s", line_number, line);
536 line = strip_whitespace(line); 529 line = strip_whitespace(line);
537 if (line[0] == '#') { 530 if (line[0] == '#') {
538 free(line); 531 free(line);
539 continue; 532 continue;
540 } 533 }
534 if (strlen(line) == 0) {
535 free(line);
536 continue;
537 }
538 char *full = calloc(strlen(block ? block : "") + strlen(line) + 2, 1);
539 strcat(full, block ? block : "");
540 strcat(full, block ? " " : "");
541 strcat(full, line);
542 wlr_log(L_DEBUG, "Expanded line: %s", full);
541 struct cmd_results *res; 543 struct cmd_results *res;
542 if (block == CMD_BLOCK_COMMANDS) { 544 if (block && strcmp(block, "<commands>") == 0) {
543 // Special case 545 // Special case
544 res = config_commands_command(line); 546 res = config_commands_command(full);
545 } else { 547 } else {
546 res = config_command(line, block); 548 res = config_command(full);
547 } 549 }
550 free(full);
548 switch(res->status) { 551 switch(res->status) {
549 case CMD_FAILURE: 552 case CMD_FAILURE:
550 case CMD_INVALID: 553 case CMD_INVALID:
@@ -558,126 +561,41 @@ bool read_config(FILE *file, struct sway_config *config) {
558 list_add(config->cmd_queue, strdup(line)); 561 list_add(config->cmd_queue, strdup(line));
559 break; 562 break;
560 563
561 case CMD_BLOCK_MODE:
562 if (block == CMD_BLOCK_END) {
563 block = CMD_BLOCK_MODE;
564 } else {
565 wlr_log(L_ERROR, "Invalid block '%s'", line);
566 }
567 break;
568
569 case CMD_BLOCK_INPUT:
570 if (block == CMD_BLOCK_END) {
571 block = CMD_BLOCK_INPUT;
572 } else {
573 wlr_log(L_ERROR, "Invalid block '%s'", line);
574 }
575 break;
576
577 case CMD_BLOCK_SEAT:
578 if (block == CMD_BLOCK_END) {
579 block = CMD_BLOCK_SEAT;
580 } else {
581 wlr_log(L_ERROR, "Invalid block '%s'", line);
582 }
583 break;
584
585 case CMD_BLOCK_BAR:
586 if (block == CMD_BLOCK_END) {
587 block = CMD_BLOCK_BAR;
588 } else {
589 wlr_log(L_ERROR, "Invalid block '%s'", line);
590 }
591 break;
592
593 case CMD_BLOCK_BAR_COLORS:
594 if (block == CMD_BLOCK_BAR) {
595 block = CMD_BLOCK_BAR_COLORS;
596 } else {
597 wlr_log(L_ERROR, "Invalid block '%s'", line);
598 }
599 break;
600
601 case CMD_BLOCK_COMMANDS: 564 case CMD_BLOCK_COMMANDS:
602 if (block == CMD_BLOCK_END) { 565 wlr_log(L_DEBUG, "Entering commands block");
603 block = CMD_BLOCK_COMMANDS; 566 list_insert(stack, 0, "<commands>");
604 } else {
605 wlr_log(L_ERROR, "Invalid block '%s'", line);
606 }
607 break;
608
609 case CMD_BLOCK_IPC:
610 if (block == CMD_BLOCK_END) {
611 block = CMD_BLOCK_IPC;
612 } else {
613 wlr_log(L_ERROR, "Invalid block '%s'", line);
614 }
615 break; 567 break;
616 568
617 case CMD_BLOCK_IPC_EVENTS: 569 case CMD_BLOCK:
618 if (block == CMD_BLOCK_IPC) { 570 wlr_log(L_DEBUG, "Entering block '%s'", res->input);
619 block = CMD_BLOCK_IPC_EVENTS; 571 list_insert(stack, 0, strdup(res->input));
620 } else { 572 if (strcmp(res->input, "bar") == 0) {
621 wlr_log(L_ERROR, "Invalid block '%s'", line); 573 config->current_bar = NULL;
622 } 574 }
623 break; 575 break;
624 576
625 case CMD_BLOCK_END: 577 case CMD_BLOCK_END:
626 switch(block) { 578 if (!block) {
627 case CMD_BLOCK_MODE: 579 wlr_log(L_DEBUG, "Unmatched '}' on line %i", line_number);
628 wlr_log(L_DEBUG, "End of mode block"); 580 success = false;
629 config->current_mode = config->modes->items[0];
630 block = CMD_BLOCK_END;
631 break;
632
633 case CMD_BLOCK_INPUT:
634 wlr_log(L_DEBUG, "End of input block");
635 block = CMD_BLOCK_END;
636 break;
637
638 case CMD_BLOCK_SEAT:
639 wlr_log(L_DEBUG, "End of seat block");
640 block = CMD_BLOCK_END;
641 break; 581 break;
582 }
583 wlr_log(L_DEBUG, "Exiting block '%s'", block);
584 list_del(stack, 0);
585 free(block);
642 586
643 case CMD_BLOCK_BAR: 587 if (strcmp(block, "bar") == 0) {
644 wlr_log(L_DEBUG, "End of bar block");
645 config->current_bar = NULL; 588 config->current_bar = NULL;
646 block = CMD_BLOCK_END;
647 break;
648
649 case CMD_BLOCK_BAR_COLORS:
650 wlr_log(L_DEBUG, "End of bar colors block");
651 block = CMD_BLOCK_BAR;
652 break;
653
654 case CMD_BLOCK_COMMANDS:
655 wlr_log(L_DEBUG, "End of commands block");
656 block = CMD_BLOCK_END;
657 break;
658
659 case CMD_BLOCK_IPC:
660 wlr_log(L_DEBUG, "End of IPC block");
661 block = CMD_BLOCK_END;
662 break;
663
664 case CMD_BLOCK_IPC_EVENTS:
665 wlr_log(L_DEBUG, "End of IPC events block");
666 block = CMD_BLOCK_IPC;
667 break;
668
669 case CMD_BLOCK_END:
670 wlr_log(L_ERROR, "Unmatched }");
671 break;
672
673 default:;
674 } 589 }
675 config_clear_handler_context(config); 590 memset(&config->handler_context, 0,
591 sizeof(config->handler_context));
676 default:; 592 default:;
677 } 593 }
678 free(line); 594 free(line);
679 free_cmd_results(res); 595 free_cmd_results(res);
680 } 596 }
597 list_foreach(stack, free);
598 list_free(stack);
681 599
682 return success; 600 return success;
683} 601}
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index 420cefa6..d90655f2 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -98,7 +98,6 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard,
98 struct sway_binding *binding) { 98 struct sway_binding *binding) {
99 wlr_log(L_DEBUG, "running command for binding: %s", 99 wlr_log(L_DEBUG, "running command for binding: %s",
100 binding->command); 100 binding->command);
101 config_clear_handler_context(config);
102 config->handler_context.seat = keyboard->seat_device->sway_seat; 101 config->handler_context.seat = keyboard->seat_device->sway_seat;
103 struct cmd_results *results = execute_command(binding->command, NULL); 102 struct cmd_results *results = execute_command(binding->command, NULL);
104 if (results->status != CMD_SUCCESS) { 103 if (results->status != CMD_SUCCESS) {
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 15ed6f80..8d9ab06a 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -469,7 +469,6 @@ void ipc_client_handle_command(struct ipc_client *client) {
469 switch (client->current_command) { 469 switch (client->current_command) {
470 case IPC_COMMAND: 470 case IPC_COMMAND:
471 { 471 {
472 config_clear_handler_context(config);
473 struct cmd_results *results = execute_command(buf, NULL); 472 struct cmd_results *results = execute_command(buf, NULL);
474 const char *json = cmd_results_to_json(results); 473 const char *json = cmd_results_to_json(results);
475 char reply[256]; 474 char reply[256];