aboutsummaryrefslogtreecommitdiffstats
path: root/sway/commands.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/commands.c')
-rw-r--r--sway/commands.c109
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 */
45static struct cmd_handler handlers[] = { 45static 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 */
101static struct cmd_handler config_handlers[] = { 105static 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 */
111static struct cmd_handler command_handlers[] = { 115static 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
147struct cmd_handler *find_handler(char *line, struct cmd_handler *handlers, 151const 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
158static struct cmd_handler *find_handler_ex(char *line, 162static 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
171static struct cmd_handler *find_core_handler(char *line) { 175static 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
177static void set_config_node(struct sway_node *node) { 181static 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
420struct cmd_results *config_subcommand(char **argv, int argc, 433struct 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
493cleanup: 478cleanup:
@@ -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 }