diff options
-rw-r--r-- | include/sway/commands.h | 6 | ||||
-rw-r--r-- | include/swaynag/swaynag.h | 1 | ||||
-rw-r--r-- | sway/commands.c | 68 | ||||
-rw-r--r-- | sway/commands/bind.c | 21 | ||||
-rw-r--r-- | sway/ipc-server.c | 11 | ||||
-rw-r--r-- | sway/main.c | 13 | ||||
-rw-r--r-- | sway/tree/view.c | 9 | ||||
-rw-r--r-- | swaynag/config.c | 10 | ||||
-rw-r--r-- | swaynag/swaynag.1.scd | 9 | ||||
-rw-r--r-- | swaynag/swaynag.c | 7 |
10 files changed, 92 insertions, 63 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h index eb446eae..c3913c79 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h | |||
@@ -56,7 +56,7 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers, | |||
56 | * all matching containers. Otherwise, it'll run on the `con` container. If | 56 | * all matching containers. Otherwise, it'll run on the `con` container. If |
57 | * `con` is NULL then it'll run on the currently focused container. | 57 | * `con` is NULL then it'll run on the currently focused container. |
58 | */ | 58 | */ |
59 | struct cmd_results *execute_command(char *command, struct sway_seat *seat, | 59 | list_t *execute_command(char *command, struct sway_seat *seat, |
60 | struct sway_container *con); | 60 | struct sway_container *con); |
61 | /** | 61 | /** |
62 | * Parse and handles a command during config file loading. | 62 | * Parse and handles a command during config file loading. |
@@ -82,11 +82,11 @@ struct cmd_results *cmd_results_new(enum cmd_status status, const char* input, c | |||
82 | */ | 82 | */ |
83 | void free_cmd_results(struct cmd_results *results); | 83 | void free_cmd_results(struct cmd_results *results); |
84 | /** | 84 | /** |
85 | * Serializes cmd_results to a JSON string. | 85 | * Serializes a list of cmd_results to a JSON string. |
86 | * | 86 | * |
87 | * Free the JSON string later on. | 87 | * Free the JSON string later on. |
88 | */ | 88 | */ |
89 | char *cmd_results_to_json(struct cmd_results *results); | 89 | char *cmd_results_to_json(list_t *res_list); |
90 | 90 | ||
91 | struct cmd_results *add_color(const char *name, | 91 | struct cmd_results *add_color(const char *name, |
92 | char *buffer, const char *color); | 92 | char *buffer, const char *color); |
diff --git a/include/swaynag/swaynag.h b/include/swaynag/swaynag.h index a32d1503..0fd1eb50 100644 --- a/include/swaynag/swaynag.h +++ b/include/swaynag/swaynag.h | |||
@@ -44,6 +44,7 @@ struct swaynag_button { | |||
44 | int y; | 44 | int y; |
45 | int width; | 45 | int width; |
46 | int height; | 46 | int height; |
47 | bool terminal; | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | struct swaynag_details { | 50 | struct swaynag_details { |
diff --git a/sway/commands.c b/sway/commands.c index bffc18f6..1203f63a 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -215,12 +215,9 @@ static void set_config_node(struct sway_node *node) { | |||
215 | } | 215 | } |
216 | } | 216 | } |
217 | 217 | ||
218 | struct cmd_results *execute_command(char *_exec, struct sway_seat *seat, | 218 | list_t *execute_command(char *_exec, struct sway_seat *seat, |
219 | struct sway_container *con) { | 219 | struct sway_container *con) { |
220 | // Even though this function will process multiple commands we will only | 220 | list_t *res_list = create_list(); |
221 | // return the last error, if any (for now). (Since we have access to an | ||
222 | // error string we could e.g. concatenate all errors there.) | ||
223 | struct cmd_results *results = NULL; | ||
224 | char *exec = strdup(_exec); | 221 | char *exec = strdup(_exec); |
225 | char *head = exec; | 222 | char *head = exec; |
226 | char *cmdlist; | 223 | char *cmdlist; |
@@ -254,8 +251,8 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat, | |||
254 | char *error = NULL; | 251 | char *error = NULL; |
255 | struct criteria *criteria = criteria_parse(head, &error); | 252 | struct criteria *criteria = criteria_parse(head, &error); |
256 | if (!criteria) { | 253 | if (!criteria) { |
257 | results = cmd_results_new(CMD_INVALID, head, | 254 | list_add(res_list, cmd_results_new(CMD_INVALID, head, |
258 | "%s", error); | 255 | "%s", error)); |
259 | free(error); | 256 | free(error); |
260 | goto cleanup; | 257 | goto cleanup; |
261 | } | 258 | } |
@@ -291,10 +288,8 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat, | |||
291 | } | 288 | } |
292 | struct cmd_handler *handler = find_handler(argv[0], NULL, 0); | 289 | struct cmd_handler *handler = find_handler(argv[0], NULL, 0); |
293 | if (!handler) { | 290 | if (!handler) { |
294 | if (results) { | 291 | list_add(res_list, cmd_results_new(CMD_INVALID, cmd, |
295 | free_cmd_results(results); | 292 | "Unknown/invalid command")); |
296 | } | ||
297 | results = cmd_results_new(CMD_INVALID, cmd, "Unknown/invalid command"); | ||
298 | free_argv(argc, argv); | 293 | free_argv(argc, argv); |
299 | goto cleanup; | 294 | goto cleanup; |
300 | } | 295 | } |
@@ -308,29 +303,21 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat, | |||
308 | if (!config->handler_context.using_criteria) { | 303 | if (!config->handler_context.using_criteria) { |
309 | set_config_node(node); | 304 | set_config_node(node); |
310 | struct cmd_results *res = handler->handle(argc-1, argv+1); | 305 | struct cmd_results *res = handler->handle(argc-1, argv+1); |
311 | if (res->status != CMD_SUCCESS) { | 306 | list_add(res_list, res); |
307 | if (res->status == CMD_INVALID) { | ||
312 | free_argv(argc, argv); | 308 | free_argv(argc, argv); |
313 | if (results) { | ||
314 | free_cmd_results(results); | ||
315 | } | ||
316 | results = res; | ||
317 | goto cleanup; | 309 | goto cleanup; |
318 | } | 310 | } |
319 | free_cmd_results(res); | ||
320 | } else { | 311 | } else { |
321 | for (int i = 0; i < views->length; ++i) { | 312 | for (int i = 0; i < views->length; ++i) { |
322 | struct sway_view *view = views->items[i]; | 313 | struct sway_view *view = views->items[i]; |
323 | set_config_node(&view->container->node); | 314 | set_config_node(&view->container->node); |
324 | struct cmd_results *res = handler->handle(argc-1, argv+1); | 315 | struct cmd_results *res = handler->handle(argc-1, argv+1); |
325 | if (res->status != CMD_SUCCESS) { | 316 | list_add(res_list, res); |
317 | if (res->status == CMD_INVALID) { | ||
326 | free_argv(argc, argv); | 318 | free_argv(argc, argv); |
327 | if (results) { | ||
328 | free_cmd_results(results); | ||
329 | } | ||
330 | results = res; | ||
331 | goto cleanup; | 319 | goto cleanup; |
332 | } | 320 | } |
333 | free_cmd_results(res); | ||
334 | } | 321 | } |
335 | } | 322 | } |
336 | free_argv(argc, argv); | 323 | free_argv(argc, argv); |
@@ -339,10 +326,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat, | |||
339 | cleanup: | 326 | cleanup: |
340 | free(exec); | 327 | free(exec); |
341 | list_free(views); | 328 | list_free(views); |
342 | if (!results) { | 329 | return res_list; |
343 | results = cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
344 | } | ||
345 | return results; | ||
346 | } | 330 | } |
347 | 331 | ||
348 | // this is like execute_command above, except: | 332 | // this is like execute_command above, except: |
@@ -420,6 +404,7 @@ struct cmd_results *config_command(char *exec) { | |||
420 | // Strip quotes and unescape the string | 404 | // Strip quotes and unescape the string |
421 | for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { | 405 | for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { |
422 | if (handler->handle != cmd_exec && handler->handle != cmd_exec_always | 406 | if (handler->handle != cmd_exec && handler->handle != cmd_exec_always |
407 | && handler->handle != cmd_mode | ||
423 | && handler->handle != cmd_bindsym | 408 | && handler->handle != cmd_bindsym |
424 | && handler->handle != cmd_bindcode | 409 | && handler->handle != cmd_bindcode |
425 | && handler->handle != cmd_set | 410 | && handler->handle != cmd_set |
@@ -574,20 +559,25 @@ void free_cmd_results(struct cmd_results *results) { | |||
574 | free(results); | 559 | free(results); |
575 | } | 560 | } |
576 | 561 | ||
577 | char *cmd_results_to_json(struct cmd_results *results) { | 562 | char *cmd_results_to_json(list_t *res_list) { |
578 | json_object *result_array = json_object_new_array(); | 563 | json_object *result_array = json_object_new_array(); |
579 | json_object *root = json_object_new_object(); | 564 | for (int i = 0; i < res_list->length; ++i) { |
580 | json_object_object_add(root, "success", | 565 | struct cmd_results *results = res_list->items[i]; |
581 | json_object_new_boolean(results->status == CMD_SUCCESS)); | 566 | json_object *root = json_object_new_object(); |
582 | if (results->input) { | 567 | json_object_object_add(root, "success", |
583 | json_object_object_add( | 568 | json_object_new_boolean(results->status == CMD_SUCCESS)); |
584 | root, "input", json_object_new_string(results->input)); | 569 | if (results->error) { |
585 | } | 570 | json_object_object_add(root, "parse_error", |
586 | if (results->error) { | 571 | json_object_new_boolean(results->status == CMD_INVALID)); |
587 | json_object_object_add( | 572 | json_object_object_add( |
588 | root, "error", json_object_new_string(results->error)); | 573 | root, "error", json_object_new_string(results->error)); |
574 | } | ||
575 | if (results->input) { | ||
576 | json_object_object_add( | ||
577 | root, "input", json_object_new_string(results->input)); | ||
578 | } | ||
579 | json_object_array_add(result_array, root); | ||
589 | } | 580 | } |
590 | json_object_array_add(result_array, root); | ||
591 | const char *json = json_object_to_json_string(result_array); | 581 | const char *json = json_object_to_json_string(result_array); |
592 | char *res = strdup(json); | 582 | char *res = strdup(json); |
593 | json_object_put(result_array); | 583 | json_object_put(result_array); |
diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 08acbe7a..34881b0f 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c | |||
@@ -289,13 +289,20 @@ void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) | |||
289 | wlr_log(WLR_DEBUG, "running command for binding: %s", binding->command); | 289 | wlr_log(WLR_DEBUG, "running command for binding: %s", binding->command); |
290 | 290 | ||
291 | config->handler_context.seat = seat; | 291 | config->handler_context.seat = seat; |
292 | struct cmd_results *results = execute_command(binding->command, NULL, NULL); | 292 | list_t *res_list = execute_command(binding->command, NULL, NULL); |
293 | if (results->status == CMD_SUCCESS) { | 293 | bool success = true; |
294 | while (res_list->length) { | ||
295 | struct cmd_results *results = res_list->items[0]; | ||
296 | if (results->status != CMD_SUCCESS) { | ||
297 | wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", | ||
298 | binding->command, results->error); | ||
299 | success = false; | ||
300 | } | ||
301 | free_cmd_results(results); | ||
302 | list_del(res_list, 0); | ||
303 | } | ||
304 | list_free(res_list); | ||
305 | if (success) { | ||
294 | ipc_event_binding(binding); | 306 | ipc_event_binding(binding); |
295 | } else { | ||
296 | wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", | ||
297 | binding->command, results->error); | ||
298 | } | 307 | } |
299 | |||
300 | free_cmd_results(results); | ||
301 | } | 308 | } |
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index aa0f0fad..95433d97 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -597,13 +597,18 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
597 | switch (client->current_command) { | 597 | switch (client->current_command) { |
598 | case IPC_COMMAND: | 598 | case IPC_COMMAND: |
599 | { | 599 | { |
600 | struct cmd_results *results = execute_command(buf, NULL, NULL); | 600 | list_t *res_list = execute_command(buf, NULL, NULL); |
601 | transaction_commit_dirty(); | 601 | transaction_commit_dirty(); |
602 | char *json = cmd_results_to_json(results); | 602 | char *json = cmd_results_to_json(res_list); |
603 | int length = strlen(json); | 603 | int length = strlen(json); |
604 | client_valid = ipc_send_reply(client, json, (uint32_t)length); | 604 | client_valid = ipc_send_reply(client, json, (uint32_t)length); |
605 | free(json); | 605 | free(json); |
606 | free_cmd_results(results); | 606 | while (res_list->length) { |
607 | struct cmd_results *results = res_list->items[0]; | ||
608 | free_cmd_results(results); | ||
609 | list_del(res_list, 0); | ||
610 | } | ||
611 | list_free(res_list); | ||
607 | goto exit_cleanup; | 612 | goto exit_cleanup; |
608 | } | 613 | } |
609 | 614 | ||
diff --git a/sway/main.c b/sway/main.c index a21970e2..a74183fe 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -392,11 +392,16 @@ int main(int argc, char **argv) { | |||
392 | wlr_log(WLR_DEBUG, "Running deferred commands"); | 392 | wlr_log(WLR_DEBUG, "Running deferred commands"); |
393 | while (config->cmd_queue->length) { | 393 | while (config->cmd_queue->length) { |
394 | char *line = config->cmd_queue->items[0]; | 394 | char *line = config->cmd_queue->items[0]; |
395 | struct cmd_results *res = execute_command(line, NULL, NULL); | 395 | list_t *res_list = execute_command(line, NULL, NULL); |
396 | if (res->status != CMD_SUCCESS) { | 396 | while (res_list->length) { |
397 | wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error); | 397 | struct cmd_results *res = res_list->items[0]; |
398 | if (res->status != CMD_SUCCESS) { | ||
399 | wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error); | ||
400 | } | ||
401 | free_cmd_results(res); | ||
402 | list_del(res_list, 0); | ||
398 | } | 403 | } |
399 | free_cmd_results(res); | 404 | list_free(res_list); |
400 | free(line); | 405 | free(line); |
401 | list_del(config->cmd_queue, 0); | 406 | list_del(config->cmd_queue, 0); |
402 | } | 407 | } |
diff --git a/sway/tree/view.c b/sway/tree/view.c index f7af841c..0edefc8e 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -437,9 +437,14 @@ void view_execute_criteria(struct sway_view *view) { | |||
437 | wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", | 437 | wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", |
438 | criteria->raw, view, criteria->cmdlist); | 438 | criteria->raw, view, criteria->cmdlist); |
439 | list_add(view->executed_criteria, criteria); | 439 | list_add(view->executed_criteria, criteria); |
440 | struct cmd_results *res = execute_command( | 440 | list_t *res_list = execute_command( |
441 | criteria->cmdlist, NULL, view->container); | 441 | criteria->cmdlist, NULL, view->container); |
442 | free_cmd_results(res); | 442 | while (res_list->length) { |
443 | struct cmd_results *res = res_list->items[0]; | ||
444 | free_cmd_results(res); | ||
445 | list_del(res_list, 0); | ||
446 | } | ||
447 | list_free(res_list); | ||
443 | } | 448 | } |
444 | list_free(criterias); | 449 | list_free(criterias); |
445 | } | 450 | } |
diff --git a/swaynag/config.c b/swaynag/config.c index 63808ce4..e724aa0c 100644 --- a/swaynag/config.c +++ b/swaynag/config.c | |||
@@ -52,6 +52,7 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag, | |||
52 | 52 | ||
53 | static struct option opts[] = { | 53 | static struct option opts[] = { |
54 | {"button", required_argument, NULL, 'b'}, | 54 | {"button", required_argument, NULL, 'b'}, |
55 | {"button-no-terminal", required_argument, NULL, 'B'}, | ||
55 | {"config", required_argument, NULL, 'c'}, | 56 | {"config", required_argument, NULL, 'c'}, |
56 | {"debug", no_argument, NULL, 'd'}, | 57 | {"debug", no_argument, NULL, 'd'}, |
57 | {"edge", required_argument, NULL, 'e'}, | 58 | {"edge", required_argument, NULL, 'e'}, |
@@ -86,7 +87,10 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag, | |||
86 | "Usage: swaynag [options...]\n" | 87 | "Usage: swaynag [options...]\n" |
87 | "\n" | 88 | "\n" |
88 | " -b, --button <text> <action> Create a button with text that " | 89 | " -b, --button <text> <action> Create a button with text that " |
89 | "executes action when pressed. Multiple buttons can be defined.\n" | 90 | "executes action in a terminal when pressed. Multiple buttons can " |
91 | "be defined.\n" | ||
92 | " -B, --button-no-terminal <text> <action> Like --button, but does" | ||
93 | "not run the action in a terminal.\n" | ||
90 | " -c, --config <path> Path to config file.\n" | 94 | " -c, --config <path> Path to config file.\n" |
91 | " -d, --debug Enable debugging.\n" | 95 | " -d, --debug Enable debugging.\n" |
92 | " -e, --edge top|bottom Set the edge to use.\n" | 96 | " -e, --edge top|bottom Set the edge to use.\n" |
@@ -117,12 +121,13 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag, | |||
117 | 121 | ||
118 | optind = 1; | 122 | optind = 1; |
119 | while (1) { | 123 | while (1) { |
120 | int c = getopt_long(argc, argv, "b:c:de:f:hlL:m:o:s:t:v", opts, NULL); | 124 | int c = getopt_long(argc, argv, "b:B:c:de:f:hlL:m:o:s:t:v", opts, NULL); |
121 | if (c == -1) { | 125 | if (c == -1) { |
122 | break; | 126 | break; |
123 | } | 127 | } |
124 | switch (c) { | 128 | switch (c) { |
125 | case 'b': // Button | 129 | case 'b': // Button |
130 | case 'B': // Button (No Terminal) | ||
126 | if (swaynag) { | 131 | if (swaynag) { |
127 | if (optind >= argc) { | 132 | if (optind >= argc) { |
128 | fprintf(stderr, "Missing action for button %s\n", optarg); | 133 | fprintf(stderr, "Missing action for button %s\n", optarg); |
@@ -133,6 +138,7 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag, | |||
133 | button->text = strdup(optarg); | 138 | button->text = strdup(optarg); |
134 | button->type = SWAYNAG_ACTION_COMMAND; | 139 | button->type = SWAYNAG_ACTION_COMMAND; |
135 | button->action = strdup(argv[optind]); | 140 | button->action = strdup(argv[optind]); |
141 | button->terminal = c == 'b'; | ||
136 | list_add(swaynag->buttons, button); | 142 | list_add(swaynag->buttons, button); |
137 | } | 143 | } |
138 | optind++; | 144 | optind++; |
diff --git a/swaynag/swaynag.1.scd b/swaynag/swaynag.1.scd index bb69e47d..b25568a0 100644 --- a/swaynag/swaynag.1.scd +++ b/swaynag/swaynag.1.scd | |||
@@ -12,7 +12,14 @@ _swaynag_ [options...] | |||
12 | 12 | ||
13 | *-b, --button* <text> <action> | 13 | *-b, --button* <text> <action> |
14 | Create a button with the text _text_ that executes _action_ when pressed. | 14 | Create a button with the text _text_ that executes _action_ when pressed. |
15 | Multiple buttons can be defined by providing the flag multiple times. | 15 | If the environment variable `TERMINAL` is set, _action_ will be run inside |
16 | the terminal. Otherwise, it will fallback to running directly. Multiple | ||
17 | buttons can be defined by providing the flag multiple times. | ||
18 | |||
19 | *-B, --button-no-terminal* <text> <action> | ||
20 | Create a button with the text _text_ that executes _action_ when pressed. | ||
21 | _action_ will be run directly instead of in a terminal. Multiple buttons | ||
22 | can be defined by providing the flag multiple times. | ||
16 | 23 | ||
17 | *-c, --config* <path> | 24 | *-c, --config* <path> |
18 | The config file to use. By default, the following paths are checked: | 25 | The config file to use. By default, the following paths are checked: |
diff --git a/swaynag/swaynag.c b/swaynag/swaynag.c index 74e127b6..a2a0b412 100644 --- a/swaynag/swaynag.c +++ b/swaynag/swaynag.c | |||
@@ -49,14 +49,17 @@ static void swaynag_button_execute(struct swaynag *swaynag, | |||
49 | if (fork() == 0) { | 49 | if (fork() == 0) { |
50 | // Child of the child. Will be reparented to the init process | 50 | // Child of the child. Will be reparented to the init process |
51 | char *terminal = getenv("TERMINAL"); | 51 | char *terminal = getenv("TERMINAL"); |
52 | if (terminal && strlen(terminal)) { | 52 | if (button->terminal && terminal && strlen(terminal)) { |
53 | wlr_log(WLR_DEBUG, "Found $TERMINAL: %s", terminal); | 53 | wlr_log(WLR_DEBUG, "Found $TERMINAL: %s", terminal); |
54 | if (!terminal_execute(terminal, button->action)) { | 54 | if (!terminal_execute(terminal, button->action)) { |
55 | swaynag_destroy(swaynag); | 55 | swaynag_destroy(swaynag); |
56 | exit(EXIT_FAILURE); | 56 | exit(EXIT_FAILURE); |
57 | } | 57 | } |
58 | } else { | 58 | } else { |
59 | wlr_log(WLR_DEBUG, "$TERMINAL not found. Running directly"); | 59 | if (button->terminal) { |
60 | wlr_log(WLR_DEBUG, | ||
61 | "$TERMINAL not found. Running directly"); | ||
62 | } | ||
60 | execl("/bin/sh", "/bin/sh", "-c", button->action, NULL); | 63 | execl("/bin/sh", "/bin/sh", "-c", button->action, NULL); |
61 | } | 64 | } |
62 | } | 65 | } |