diff options
Diffstat (limited to 'sway/commands.c')
-rw-r--r-- | sway/commands.c | 109 |
1 files changed, 45 insertions, 64 deletions
diff --git a/sway/commands.c b/sway/commands.c index fe1e98b5..55eda183 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -42,15 +42,17 @@ struct cmd_results *checkarg(int argc, const char *name, enum expected_args type | |||
42 | } | 42 | } |
43 | 43 | ||
44 | /* Keep alphabetized */ | 44 | /* Keep alphabetized */ |
45 | static struct cmd_handler handlers[] = { | 45 | static const struct cmd_handler handlers[] = { |
46 | { "assign", cmd_assign }, | 46 | { "assign", cmd_assign }, |
47 | { "bar", cmd_bar }, | 47 | { "bar", cmd_bar }, |
48 | { "bindcode", cmd_bindcode }, | 48 | { "bindcode", cmd_bindcode }, |
49 | { "bindgesture", cmd_bindgesture }, | ||
49 | { "bindswitch", cmd_bindswitch }, | 50 | { "bindswitch", cmd_bindswitch }, |
50 | { "bindsym", cmd_bindsym }, | 51 | { "bindsym", cmd_bindsym }, |
51 | { "client.background", cmd_client_noop }, | 52 | { "client.background", cmd_client_noop }, |
52 | { "client.focused", cmd_client_focused }, | 53 | { "client.focused", cmd_client_focused }, |
53 | { "client.focused_inactive", cmd_client_focused_inactive }, | 54 | { "client.focused_inactive", cmd_client_focused_inactive }, |
55 | { "client.focused_tab_title", cmd_client_focused_tab_title }, | ||
54 | { "client.placeholder", cmd_client_noop }, | 56 | { "client.placeholder", cmd_client_noop }, |
55 | { "client.unfocused", cmd_client_unfocused }, | 57 | { "client.unfocused", cmd_client_unfocused }, |
56 | { "client.urgent", cmd_client_urgent }, | 58 | { "client.urgent", cmd_client_urgent }, |
@@ -80,6 +82,7 @@ static struct cmd_handler handlers[] = { | |||
80 | { "no_focus", cmd_no_focus }, | 82 | { "no_focus", cmd_no_focus }, |
81 | { "output", cmd_output }, | 83 | { "output", cmd_output }, |
82 | { "popup_during_fullscreen", cmd_popup_during_fullscreen }, | 84 | { "popup_during_fullscreen", cmd_popup_during_fullscreen }, |
85 | { "primary_selection", cmd_primary_selection }, | ||
83 | { "seat", cmd_seat }, | 86 | { "seat", cmd_seat }, |
84 | { "set", cmd_set }, | 87 | { "set", cmd_set }, |
85 | { "show_marks", cmd_show_marks }, | 88 | { "show_marks", cmd_show_marks }, |
@@ -91,6 +94,7 @@ static struct cmd_handler handlers[] = { | |||
91 | { "titlebar_border_thickness", cmd_titlebar_border_thickness }, | 94 | { "titlebar_border_thickness", cmd_titlebar_border_thickness }, |
92 | { "titlebar_padding", cmd_titlebar_padding }, | 95 | { "titlebar_padding", cmd_titlebar_padding }, |
93 | { "unbindcode", cmd_unbindcode }, | 96 | { "unbindcode", cmd_unbindcode }, |
97 | { "unbindgesture", cmd_unbindgesture }, | ||
94 | { "unbindswitch", cmd_unbindswitch }, | 98 | { "unbindswitch", cmd_unbindswitch }, |
95 | { "unbindsym", cmd_unbindsym }, | 99 | { "unbindsym", cmd_unbindsym }, |
96 | { "workspace", cmd_workspace }, | 100 | { "workspace", cmd_workspace }, |
@@ -98,7 +102,7 @@ static struct cmd_handler handlers[] = { | |||
98 | }; | 102 | }; |
99 | 103 | ||
100 | /* Config-time only commands. Keep alphabetized */ | 104 | /* Config-time only commands. Keep alphabetized */ |
101 | static struct cmd_handler config_handlers[] = { | 105 | static const struct cmd_handler config_handlers[] = { |
102 | { "default_orientation", cmd_default_orientation }, | 106 | { "default_orientation", cmd_default_orientation }, |
103 | { "include", cmd_include }, | 107 | { "include", cmd_include }, |
104 | { "swaybg_command", cmd_swaybg_command }, | 108 | { "swaybg_command", cmd_swaybg_command }, |
@@ -108,7 +112,7 @@ static struct cmd_handler config_handlers[] = { | |||
108 | }; | 112 | }; |
109 | 113 | ||
110 | /* Runtime-only commands. Keep alphabetized */ | 114 | /* Runtime-only commands. Keep alphabetized */ |
111 | static struct cmd_handler command_handlers[] = { | 115 | static const struct cmd_handler command_handlers[] = { |
112 | { "border", cmd_border }, | 116 | { "border", cmd_border }, |
113 | { "create_output", cmd_create_output }, | 117 | { "create_output", cmd_create_output }, |
114 | { "exit", cmd_exit }, | 118 | { "exit", cmd_exit }, |
@@ -144,22 +148,22 @@ static int handler_compare(const void *_a, const void *_b) { | |||
144 | return strcasecmp(a->command, b->command); | 148 | return strcasecmp(a->command, b->command); |
145 | } | 149 | } |
146 | 150 | ||
147 | struct cmd_handler *find_handler(char *line, struct cmd_handler *handlers, | 151 | const struct cmd_handler *find_handler(const char *line, |
148 | size_t handlers_size) { | 152 | const struct cmd_handler *handlers, size_t handlers_size) { |
149 | if (!handlers || !handlers_size) { | 153 | if (!handlers || !handlers_size) { |
150 | return NULL; | 154 | return NULL; |
151 | } | 155 | } |
152 | struct cmd_handler query = { .command = line }; | 156 | const struct cmd_handler query = { .command = line }; |
153 | return bsearch(&query, handlers, | 157 | return bsearch(&query, handlers, |
154 | handlers_size / sizeof(struct cmd_handler), | 158 | handlers_size / sizeof(struct cmd_handler), |
155 | sizeof(struct cmd_handler), handler_compare); | 159 | sizeof(struct cmd_handler), handler_compare); |
156 | } | 160 | } |
157 | 161 | ||
158 | static struct cmd_handler *find_handler_ex(char *line, | 162 | static const struct cmd_handler *find_handler_ex(char *line, |
159 | struct cmd_handler *config_handlers, size_t config_handlers_size, | 163 | const struct cmd_handler *config_handlers, size_t config_handlers_size, |
160 | struct cmd_handler *command_handlers, size_t command_handlers_size, | 164 | const struct cmd_handler *command_handlers, size_t command_handlers_size, |
161 | struct cmd_handler *handlers, size_t handlers_size) { | 165 | const struct cmd_handler *handlers, size_t handlers_size) { |
162 | struct cmd_handler *handler = NULL; | 166 | const struct cmd_handler *handler = NULL; |
163 | if (config->reading) { | 167 | if (config->reading) { |
164 | handler = find_handler(line, config_handlers, config_handlers_size); | 168 | handler = find_handler(line, config_handlers, config_handlers_size); |
165 | } else if (config->active) { | 169 | } else if (config->active) { |
@@ -168,16 +172,17 @@ static struct cmd_handler *find_handler_ex(char *line, | |||
168 | return handler ? handler : find_handler(line, handlers, handlers_size); | 172 | return handler ? handler : find_handler(line, handlers, handlers_size); |
169 | } | 173 | } |
170 | 174 | ||
171 | static struct cmd_handler *find_core_handler(char *line) { | 175 | static const struct cmd_handler *find_core_handler(char *line) { |
172 | return find_handler_ex(line, config_handlers, sizeof(config_handlers), | 176 | return find_handler_ex(line, config_handlers, sizeof(config_handlers), |
173 | command_handlers, sizeof(command_handlers), | 177 | command_handlers, sizeof(command_handlers), |
174 | handlers, sizeof(handlers)); | 178 | handlers, sizeof(handlers)); |
175 | } | 179 | } |
176 | 180 | ||
177 | static void set_config_node(struct sway_node *node) { | 181 | static void set_config_node(struct sway_node *node, bool node_overridden) { |
178 | config->handler_context.node = node; | 182 | config->handler_context.node = node; |
179 | config->handler_context.container = NULL; | 183 | config->handler_context.container = NULL; |
180 | config->handler_context.workspace = NULL; | 184 | config->handler_context.workspace = NULL; |
185 | config->handler_context.node_overridden = node_overridden; | ||
181 | 186 | ||
182 | if (node == NULL) { | 187 | if (node == NULL) { |
183 | return; | 188 | return; |
@@ -186,7 +191,7 @@ static void set_config_node(struct sway_node *node) { | |||
186 | switch (node->type) { | 191 | switch (node->type) { |
187 | case N_CONTAINER: | 192 | case N_CONTAINER: |
188 | config->handler_context.container = node->sway_container; | 193 | config->handler_context.container = node->sway_container; |
189 | config->handler_context.workspace = node->sway_container->workspace; | 194 | config->handler_context.workspace = node->sway_container->pending.workspace; |
190 | break; | 195 | break; |
191 | case N_WORKSPACE: | 196 | case N_WORKSPACE: |
192 | config->handler_context.workspace = node->sway_workspace; | 197 | config->handler_context.workspace = node->sway_workspace; |
@@ -202,6 +207,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, | |||
202 | char *cmd; | 207 | char *cmd; |
203 | char matched_delim = ';'; | 208 | char matched_delim = ';'; |
204 | list_t *containers = NULL; | 209 | list_t *containers = NULL; |
210 | bool using_criteria = false; | ||
205 | 211 | ||
206 | if (seat == NULL) { | 212 | if (seat == NULL) { |
207 | // passing a NULL seat means we just pick the default seat | 213 | // passing a NULL seat means we just pick the default seat |
@@ -225,7 +231,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, | |||
225 | for (; isspace(*head); ++head) {} | 231 | for (; isspace(*head); ++head) {} |
226 | // Extract criteria (valid for this command list only). | 232 | // Extract criteria (valid for this command list only). |
227 | if (matched_delim == ';') { | 233 | if (matched_delim == ';') { |
228 | config->handler_context.using_criteria = false; | 234 | using_criteria = false; |
229 | if (*head == '[') { | 235 | if (*head == '[') { |
230 | char *error = NULL; | 236 | char *error = NULL; |
231 | struct criteria *criteria = criteria_parse(head, &error); | 237 | struct criteria *criteria = criteria_parse(head, &error); |
@@ -239,7 +245,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, | |||
239 | containers = criteria_get_containers(criteria); | 245 | containers = criteria_get_containers(criteria); |
240 | head += strlen(criteria->raw); | 246 | head += strlen(criteria->raw); |
241 | criteria_destroy(criteria); | 247 | criteria_destroy(criteria); |
242 | config->handler_context.using_criteria = true; | 248 | using_criteria = true; |
243 | // Skip leading whitespace | 249 | // Skip leading whitespace |
244 | for (; isspace(*head); ++head) {} | 250 | for (; isspace(*head); ++head) {} |
245 | } | 251 | } |
@@ -265,7 +271,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, | |||
265 | } | 271 | } |
266 | } | 272 | } |
267 | } | 273 | } |
268 | struct cmd_handler *handler = find_core_handler(argv[0]); | 274 | const struct cmd_handler *handler = find_core_handler(argv[0]); |
269 | if (!handler) { | 275 | if (!handler) { |
270 | list_add(res_list, cmd_results_new(CMD_INVALID, | 276 | list_add(res_list, cmd_results_new(CMD_INVALID, |
271 | "Unknown/invalid command '%s'", argv[0])); | 277 | "Unknown/invalid command '%s'", argv[0])); |
@@ -278,11 +284,14 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, | |||
278 | argv[i] = do_var_replacement(argv[i]); | 284 | argv[i] = do_var_replacement(argv[i]); |
279 | } | 285 | } |
280 | 286 | ||
281 | if (!config->handler_context.using_criteria) { | 287 | |
282 | // The container or workspace which this command will run on. | 288 | if (!using_criteria) { |
283 | struct sway_node *node = con ? &con->node : | 289 | if (con) { |
284 | seat_get_focus_inactive(seat, &root->node); | 290 | set_config_node(&con->node, true); |
285 | set_config_node(node); | 291 | } else { |
292 | set_config_node(seat_get_focus_inactive(seat, &root->node), | ||
293 | false); | ||
294 | } | ||
286 | struct cmd_results *res = handler->handle(argc-1, argv+1); | 295 | struct cmd_results *res = handler->handle(argc-1, argv+1); |
287 | list_add(res_list, res); | 296 | list_add(res_list, res); |
288 | if (res->status == CMD_INVALID) { | 297 | if (res->status == CMD_INVALID) { |
@@ -296,7 +305,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, | |||
296 | struct cmd_results *fail_res = NULL; | 305 | struct cmd_results *fail_res = NULL; |
297 | for (int i = 0; i < containers->length; ++i) { | 306 | for (int i = 0; i < containers->length; ++i) { |
298 | struct sway_container *container = containers->items[i]; | 307 | struct sway_container *container = containers->items[i]; |
299 | set_config_node(&container->node); | 308 | set_config_node(&container->node, true); |
300 | struct cmd_results *res = handler->handle(argc-1, argv+1); | 309 | struct cmd_results *res = handler->handle(argc-1, argv+1); |
301 | if (res->status == CMD_SUCCESS) { | 310 | if (res->status == CMD_SUCCESS) { |
302 | free_cmd_results(res); | 311 | free_cmd_results(res); |
@@ -370,12 +379,15 @@ struct cmd_results *config_command(char *exec, char **new_block) { | |||
370 | 379 | ||
371 | // Determine the command handler | 380 | // Determine the command handler |
372 | sway_log(SWAY_INFO, "Config command: %s", exec); | 381 | sway_log(SWAY_INFO, "Config command: %s", exec); |
373 | struct cmd_handler *handler = find_core_handler(argv[0]); | 382 | const struct cmd_handler *handler = find_core_handler(argv[0]); |
374 | if (!handler || !handler->handle) { | 383 | if (!handler || !handler->handle) { |
375 | const char *error = handler | 384 | if (handler) { |
376 | ? "Command '%s' is shimmed, but unimplemented" | 385 | results = cmd_results_new(CMD_INVALID, |
377 | : "Unknown/invalid command '%s'"; | 386 | "Command '%s' is shimmed, but unimplemented", argv[0]); |
378 | results = cmd_results_new(CMD_INVALID, error, argv[0]); | 387 | } else { |
388 | results = cmd_results_new(CMD_INVALID, | ||
389 | "Unknown/invalid command '%s'", argv[0]); | ||
390 | } | ||
379 | goto cleanup; | 391 | goto cleanup; |
380 | } | 392 | } |
381 | 393 | ||
@@ -401,6 +413,7 @@ struct cmd_results *config_command(char *exec, char **new_block) { | |||
401 | && handler->handle != cmd_bindsym | 413 | && handler->handle != cmd_bindsym |
402 | && handler->handle != cmd_bindcode | 414 | && handler->handle != cmd_bindcode |
403 | && handler->handle != cmd_bindswitch | 415 | && handler->handle != cmd_bindswitch |
416 | && handler->handle != cmd_bindgesture | ||
404 | && handler->handle != cmd_set | 417 | && handler->handle != cmd_set |
405 | && handler->handle != cmd_for_window | 418 | && handler->handle != cmd_for_window |
406 | && (*argv[i] == '\"' || *argv[i] == '\'')) { | 419 | && (*argv[i] == '\"' || *argv[i] == '\'')) { |
@@ -418,12 +431,12 @@ cleanup: | |||
418 | } | 431 | } |
419 | 432 | ||
420 | struct cmd_results *config_subcommand(char **argv, int argc, | 433 | struct cmd_results *config_subcommand(char **argv, int argc, |
421 | struct cmd_handler *handlers, size_t handlers_size) { | 434 | const struct cmd_handler *handlers, size_t handlers_size) { |
422 | char *command = join_args(argv, argc); | 435 | char *command = join_args(argv, argc); |
423 | sway_log(SWAY_DEBUG, "Subcommand: %s", command); | 436 | sway_log(SWAY_DEBUG, "Subcommand: %s", command); |
424 | free(command); | 437 | free(command); |
425 | 438 | ||
426 | struct cmd_handler *handler = find_handler(argv[0], handlers, | 439 | const struct cmd_handler *handler = find_handler(argv[0], handlers, |
427 | handlers_size); | 440 | handlers_size); |
428 | if (!handler) { | 441 | if (!handler) { |
429 | return cmd_results_new(CMD_INVALID, | 442 | return cmd_results_new(CMD_INVALID, |
@@ -453,41 +466,13 @@ struct cmd_results *config_commands_command(char *exec) { | |||
453 | goto cleanup; | 466 | goto cleanup; |
454 | } | 467 | } |
455 | 468 | ||
456 | struct cmd_handler *handler = find_handler(cmd, NULL, 0); | 469 | const struct cmd_handler *handler = find_handler(cmd, NULL, 0); |
457 | if (!handler && strcmp(cmd, "*") != 0) { | 470 | if (!handler && strcmp(cmd, "*") != 0) { |
458 | results = cmd_results_new(CMD_INVALID, | 471 | results = cmd_results_new(CMD_INVALID, |
459 | "Unknown/invalid command '%s'", cmd); | 472 | "Unknown/invalid command '%s'", cmd); |
460 | goto cleanup; | 473 | goto cleanup; |
461 | } | 474 | } |
462 | 475 | ||
463 | enum command_context context = 0; | ||
464 | |||
465 | struct { | ||
466 | char *name; | ||
467 | enum command_context context; | ||
468 | } context_names[] = { | ||
469 | { "config", CONTEXT_CONFIG }, | ||
470 | { "binding", CONTEXT_BINDING }, | ||
471 | { "ipc", CONTEXT_IPC }, | ||
472 | { "criteria", CONTEXT_CRITERIA }, | ||
473 | { "all", CONTEXT_ALL }, | ||
474 | }; | ||
475 | |||
476 | for (int i = 1; i < argc; ++i) { | ||
477 | size_t j; | ||
478 | for (j = 0; j < sizeof(context_names) / sizeof(context_names[0]); ++j) { | ||
479 | if (strcmp(context_names[j].name, argv[i]) == 0) { | ||
480 | break; | ||
481 | } | ||
482 | } | ||
483 | if (j == sizeof(context_names) / sizeof(context_names[0])) { | ||
484 | results = cmd_results_new(CMD_INVALID, | ||
485 | "Invalid command context %s", argv[i]); | ||
486 | goto cleanup; | ||
487 | } | ||
488 | context |= context_names[j].context; | ||
489 | } | ||
490 | |||
491 | results = cmd_results_new(CMD_SUCCESS, NULL); | 476 | results = cmd_results_new(CMD_SUCCESS, NULL); |
492 | 477 | ||
493 | cleanup: | 478 | cleanup: |
@@ -504,14 +489,10 @@ struct cmd_results *cmd_results_new(enum cmd_status status, | |||
504 | } | 489 | } |
505 | results->status = status; | 490 | results->status = status; |
506 | if (format) { | 491 | if (format) { |
507 | char *error = malloc(256); | ||
508 | va_list args; | 492 | va_list args; |
509 | va_start(args, format); | 493 | va_start(args, format); |
510 | if (error) { | 494 | results->error = vformat_str(format, args); |
511 | vsnprintf(error, 256, format, args); | ||
512 | } | ||
513 | va_end(args); | 495 | va_end(args); |
514 | results->error = error; | ||
515 | } else { | 496 | } else { |
516 | results->error = NULL; | 497 | results->error = NULL; |
517 | } | 498 | } |