diff options
Diffstat (limited to 'sway')
-rw-r--r-- | sway/commands.c | 8 | ||||
-rw-r--r-- | sway/commands/include.c | 15 | ||||
-rw-r--r-- | sway/commands/reload.c | 15 | ||||
-rw-r--r-- | sway/commands/swaynag_command.c | 20 | ||||
-rw-r--r-- | sway/config.c | 104 | ||||
-rw-r--r-- | sway/main.c | 15 | ||||
-rw-r--r-- | sway/meson.build | 2 | ||||
-rw-r--r-- | sway/sway.5.scd | 7 | ||||
-rw-r--r-- | sway/swaynag.c | 103 |
9 files changed, 185 insertions, 104 deletions
diff --git a/sway/commands.c b/sway/commands.c index 81e9ea42..364c26da 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -132,6 +132,7 @@ static struct cmd_handler handlers[] = { | |||
132 | static struct cmd_handler config_handlers[] = { | 132 | static struct cmd_handler config_handlers[] = { |
133 | { "default_orientation", cmd_default_orientation }, | 133 | { "default_orientation", cmd_default_orientation }, |
134 | { "swaybg_command", cmd_swaybg_command }, | 134 | { "swaybg_command", cmd_swaybg_command }, |
135 | { "swaynag_command", cmd_swaynag_command }, | ||
135 | { "workspace_layout", cmd_workspace_layout }, | 136 | { "workspace_layout", cmd_workspace_layout }, |
136 | }; | 137 | }; |
137 | 138 | ||
@@ -511,14 +512,11 @@ struct cmd_results *cmd_results_new(enum cmd_status status, | |||
511 | results->input = NULL; | 512 | results->input = NULL; |
512 | } | 513 | } |
513 | if (format) { | 514 | if (format) { |
515 | char *error = malloc(256); | ||
514 | va_list args; | 516 | va_list args; |
515 | va_start(args, format); | 517 | va_start(args, format); |
516 | size_t length = vsnprintf(NULL, 0, format, args) + 1; | ||
517 | char *error = malloc(length); | ||
518 | va_end(args); | ||
519 | va_start(args, format); | ||
520 | if (error) { | 518 | if (error) { |
521 | vsnprintf(error, length, format, args); | 519 | vsnprintf(error, 256, format, args); |
522 | } | 520 | } |
523 | va_end(args); | 521 | va_end(args); |
524 | results->error = error; | 522 | results->error = error; |
diff --git a/sway/commands/include.c b/sway/commands/include.c index 72fec7cc..61f383bb 100644 --- a/sway/commands/include.c +++ b/sway/commands/include.c | |||
@@ -7,19 +7,10 @@ struct cmd_results *cmd_include(int argc, char **argv) { | |||
7 | return error; | 7 | return error; |
8 | } | 8 | } |
9 | 9 | ||
10 | char *errors = NULL; | 10 | if (!load_include_configs(argv[0], config, |
11 | if (!load_include_configs(argv[0], config, &errors)) { | 11 | &config->swaynag_config_errors)) { |
12 | struct cmd_results *result = cmd_results_new(CMD_INVALID, "include", | 12 | return cmd_results_new(CMD_INVALID, "include", |
13 | "Failed to include sub configuration file: %s", argv[0]); | 13 | "Failed to include sub configuration file: %s", argv[0]); |
14 | free(errors); | ||
15 | return result; | ||
16 | } | ||
17 | |||
18 | if (errors) { | ||
19 | struct cmd_results *result = cmd_results_new(CMD_INVALID, "include", | ||
20 | "There are errors in the included config\n%s", errors); | ||
21 | free(errors); | ||
22 | return result; | ||
23 | } | 14 | } |
24 | 15 | ||
25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 16 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/reload.c b/sway/commands/reload.c index 9bf671d9..f8ca374d 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c | |||
@@ -1,5 +1,4 @@ | |||
1 | #define _XOPEN_SOURCE 500 | 1 | #define _XOPEN_SOURCE 500 |
2 | #include <signal.h> | ||
3 | #include <string.h> | 2 | #include <string.h> |
4 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
5 | #include "sway/config.h" | 4 | #include "sway/config.h" |
@@ -20,9 +19,7 @@ struct cmd_results *cmd_reload(int argc, char **argv) { | |||
20 | list_add(bar_ids, strdup(bar->id)); | 19 | list_add(bar_ids, strdup(bar->id)); |
21 | } | 20 | } |
22 | 21 | ||
23 | char *errors = NULL; | 22 | if (!load_main_config(config->current_config_path, true, false)) { |
24 | if (!load_main_config(config->current_config_path, true, &errors)) { | ||
25 | free(errors); | ||
26 | return cmd_results_new(CMD_FAILURE, "reload", | 23 | return cmd_results_new(CMD_FAILURE, "reload", |
27 | "Error(s) reloading config."); | 24 | "Error(s) reloading config."); |
28 | } | 25 | } |
@@ -47,15 +44,5 @@ struct cmd_results *cmd_reload(int argc, char **argv) { | |||
47 | 44 | ||
48 | arrange_windows(&root_container); | 45 | arrange_windows(&root_container); |
49 | 46 | ||
50 | if (config->swaynag_pid > 0) { | ||
51 | kill(config->swaynag_pid, SIGTERM); | ||
52 | config->swaynag_pid = -1; | ||
53 | } | ||
54 | |||
55 | if (errors) { | ||
56 | spawn_swaynag_config_errors(config, errors); | ||
57 | free(errors); | ||
58 | } | ||
59 | |||
60 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 47 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
61 | } | 48 | } |
diff --git a/sway/commands/swaynag_command.c b/sway/commands/swaynag_command.c new file mode 100644 index 00000000..c57a80a6 --- /dev/null +++ b/sway/commands/swaynag_command.c | |||
@@ -0,0 +1,20 @@ | |||
1 | #include <string.h> | ||
2 | #include "sway/commands.h" | ||
3 | #include "log.h" | ||
4 | #include "stringop.h" | ||
5 | |||
6 | struct cmd_results *cmd_swaynag_command(int argc, char **argv) { | ||
7 | struct cmd_results *error = NULL; | ||
8 | if ((error = checkarg(argc, "swaynag_command", EXPECTED_AT_LEAST, 1))) { | ||
9 | return error; | ||
10 | } | ||
11 | |||
12 | if (config->swaynag_command) { | ||
13 | free(config->swaynag_command); | ||
14 | } | ||
15 | config->swaynag_command = join_args(argv, argc); | ||
16 | wlr_log(WLR_DEBUG, "Using custom swaynag command: %s", | ||
17 | config->swaynag_command); | ||
18 | |||
19 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
20 | } | ||
diff --git a/sway/config.c b/sway/config.c index bd282541..4464b006 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "sway/commands.h" | 25 | #include "sway/commands.h" |
26 | #include "sway/config.h" | 26 | #include "sway/config.h" |
27 | #include "sway/criteria.h" | 27 | #include "sway/criteria.h" |
28 | #include "sway/swaynag.h" | ||
28 | #include "sway/tree/arrange.h" | 29 | #include "sway/tree/arrange.h" |
29 | #include "sway/tree/layout.h" | 30 | #include "sway/tree/layout.h" |
30 | #include "sway/tree/workspace.h" | 31 | #include "sway/tree/workspace.h" |
@@ -72,6 +73,8 @@ void free_config(struct sway_config *config) { | |||
72 | 73 | ||
73 | memset(&config->handler_context, 0, sizeof(config->handler_context)); | 74 | memset(&config->handler_context, 0, sizeof(config->handler_context)); |
74 | 75 | ||
76 | free(config->swaynag_command); | ||
77 | |||
75 | // TODO: handle all currently unhandled lists as we add implementations | 78 | // TODO: handle all currently unhandled lists as we add implementations |
76 | if (config->symbols) { | 79 | if (config->symbols) { |
77 | for (int i = 0; i < config->symbols->length; ++i) { | 80 | for (int i = 0; i < config->symbols->length; ++i) { |
@@ -158,7 +161,17 @@ static void set_color(float dest[static 4], uint32_t color) { | |||
158 | } | 161 | } |
159 | 162 | ||
160 | static void config_defaults(struct sway_config *config) { | 163 | static void config_defaults(struct sway_config *config) { |
161 | config->swaynag_pid = -1; | 164 | config->swaynag_command = strdup("swaynag"); |
165 | config->swaynag_config_errors = (struct swaynag_instance){ | ||
166 | .args = "--type error " | ||
167 | "--message 'There are errors in your config file' " | ||
168 | "--detailed-message " | ||
169 | "--button 'Exit sway' 'swaymsg exit' " | ||
170 | "--button 'Reload sway' 'swaymsg reload'", | ||
171 | .pid = -1, | ||
172 | .detailed = true, | ||
173 | }; | ||
174 | |||
162 | if (!(config->symbols = create_list())) goto cleanup; | 175 | if (!(config->symbols = create_list())) goto cleanup; |
163 | if (!(config->modes = create_list())) goto cleanup; | 176 | if (!(config->modes = create_list())) goto cleanup; |
164 | if (!(config->bars = create_list())) goto cleanup; | 177 | if (!(config->bars = create_list())) goto cleanup; |
@@ -205,6 +218,7 @@ static void config_defaults(struct sway_config *config) { | |||
205 | config->focus_follows_mouse = true; | 218 | config->focus_follows_mouse = true; |
206 | config->mouse_warping = true; | 219 | config->mouse_warping = true; |
207 | config->focus_wrapping = WRAP_YES; | 220 | config->focus_wrapping = WRAP_YES; |
221 | config->validating = false; | ||
208 | config->reloading = false; | 222 | config->reloading = false; |
209 | config->active = false; | 223 | config->active = false; |
210 | config->failed = false; | 224 | config->failed = false; |
@@ -321,7 +335,7 @@ static char *get_config_path(void) { | |||
321 | } | 335 | } |
322 | 336 | ||
323 | static bool load_config(const char *path, struct sway_config *config, | 337 | static bool load_config(const char *path, struct sway_config *config, |
324 | char **errors) { | 338 | struct swaynag_instance *swaynag) { |
325 | if (path == NULL) { | 339 | if (path == NULL) { |
326 | wlr_log(WLR_ERROR, "Unable to find a config file!"); | 340 | wlr_log(WLR_ERROR, "Unable to find a config file!"); |
327 | return false; | 341 | return false; |
@@ -340,7 +354,7 @@ static bool load_config(const char *path, struct sway_config *config, | |||
340 | return false; | 354 | return false; |
341 | } | 355 | } |
342 | 356 | ||
343 | bool config_load_success = read_config(f, config, errors); | 357 | bool config_load_success = read_config(f, config, swaynag); |
344 | fclose(f); | 358 | fclose(f); |
345 | 359 | ||
346 | if (!config_load_success) { | 360 | if (!config_load_success) { |
@@ -350,7 +364,7 @@ static bool load_config(const char *path, struct sway_config *config, | |||
350 | return true; | 364 | return true; |
351 | } | 365 | } |
352 | 366 | ||
353 | bool load_main_config(const char *file, bool is_active, char **errors) { | 367 | bool load_main_config(const char *file, bool is_active, bool validating) { |
354 | char *path; | 368 | char *path; |
355 | if (file != NULL) { | 369 | if (file != NULL) { |
356 | path = strdup(file); | 370 | path = strdup(file); |
@@ -365,11 +379,16 @@ bool load_main_config(const char *file, bool is_active, char **errors) { | |||
365 | } | 379 | } |
366 | 380 | ||
367 | config_defaults(config); | 381 | config_defaults(config); |
382 | config->validating = validating; | ||
368 | if (is_active) { | 383 | if (is_active) { |
369 | wlr_log(WLR_DEBUG, "Performing configuration file reload"); | 384 | wlr_log(WLR_DEBUG, "Performing configuration file reload"); |
370 | config->swaynag_pid = old_config->swaynag_pid; | ||
371 | config->reloading = true; | 385 | config->reloading = true; |
372 | config->active = true; | 386 | config->active = true; |
387 | |||
388 | swaynag_kill(&old_config->swaynag_config_errors); | ||
389 | swaynag_clone(&config->swaynag_config_errors, | ||
390 | &old_config->swaynag_config_errors); | ||
391 | |||
373 | create_default_output_configs(); | 392 | create_default_output_configs(); |
374 | } | 393 | } |
375 | 394 | ||
@@ -426,13 +445,17 @@ bool load_main_config(const char *file, bool is_active, char **errors) { | |||
426 | } | 445 | } |
427 | */ | 446 | */ |
428 | 447 | ||
429 | success = success && load_config(path, config, errors); | 448 | success = success && load_config(path, config, |
449 | &config->swaynag_config_errors); | ||
430 | 450 | ||
431 | if (is_active) { | 451 | if (is_active) { |
432 | for (int i = 0; i < config->output_configs->length; i++) { | 452 | for (int i = 0; i < config->output_configs->length; i++) { |
433 | apply_output_config_to_outputs(config->output_configs->items[i]); | 453 | apply_output_config_to_outputs(config->output_configs->items[i]); |
434 | } | 454 | } |
435 | config->reloading = false; | 455 | config->reloading = false; |
456 | if (config->swaynag_config_errors.pid > 0) { | ||
457 | swaynag_show(&config->swaynag_config_errors); | ||
458 | } | ||
436 | } | 459 | } |
437 | 460 | ||
438 | if (old_config) { | 461 | if (old_config) { |
@@ -444,7 +467,7 @@ bool load_main_config(const char *file, bool is_active, char **errors) { | |||
444 | } | 467 | } |
445 | 468 | ||
446 | static bool load_include_config(const char *path, const char *parent_dir, | 469 | static bool load_include_config(const char *path, const char *parent_dir, |
447 | struct sway_config *config, char **errors) { | 470 | struct sway_config *config, struct swaynag_instance *swaynag) { |
448 | // save parent config | 471 | // save parent config |
449 | const char *parent_config = config->current_config_path; | 472 | const char *parent_config = config->current_config_path; |
450 | 473 | ||
@@ -488,7 +511,7 @@ static bool load_include_config(const char *path, const char *parent_dir, | |||
488 | list_add(config->config_chain, real_path); | 511 | list_add(config->config_chain, real_path); |
489 | int index = config->config_chain->length - 1; | 512 | int index = config->config_chain->length - 1; |
490 | 513 | ||
491 | if (!load_config(real_path, config, errors)) { | 514 | if (!load_config(real_path, config, swaynag)) { |
492 | free(real_path); | 515 | free(real_path); |
493 | config->current_config_path = parent_config; | 516 | config->current_config_path = parent_config; |
494 | list_del(config->config_chain, index); | 517 | list_del(config->config_chain, index); |
@@ -501,7 +524,7 @@ static bool load_include_config(const char *path, const char *parent_dir, | |||
501 | } | 524 | } |
502 | 525 | ||
503 | bool load_include_configs(const char *path, struct sway_config *config, | 526 | bool load_include_configs(const char *path, struct sway_config *config, |
504 | char **errors) { | 527 | struct swaynag_instance *swaynag) { |
505 | char *wd = getcwd(NULL, 0); | 528 | char *wd = getcwd(NULL, 0); |
506 | char *parent_path = strdup(config->current_config_path); | 529 | char *parent_path = strdup(config->current_config_path); |
507 | const char *parent_dir = dirname(parent_path); | 530 | const char *parent_dir = dirname(parent_path); |
@@ -523,7 +546,7 @@ bool load_include_configs(const char *path, struct sway_config *config, | |||
523 | char **w = p.we_wordv; | 546 | char **w = p.we_wordv; |
524 | size_t i; | 547 | size_t i; |
525 | for (i = 0; i < p.we_wordc; ++i) { | 548 | for (i = 0; i < p.we_wordc; ++i) { |
526 | load_include_config(w[i], parent_dir, config, errors); | 549 | load_include_config(w[i], parent_dir, config, swaynag); |
527 | } | 550 | } |
528 | free(parent_path); | 551 | free(parent_path); |
529 | wordfree(&p); | 552 | wordfree(&p); |
@@ -579,26 +602,8 @@ static char *expand_line(const char *block, const char *line, bool add_brace) { | |||
579 | return expanded; | 602 | return expanded; |
580 | } | 603 | } |
581 | 604 | ||
582 | static void log_error(char **errors, const char *fmt, ...) { | 605 | bool read_config(FILE *file, struct sway_config *config, |
583 | va_list args; | 606 | struct swaynag_instance *swaynag) { |
584 | va_start(args, fmt); | ||
585 | size_t length = vsnprintf(NULL, 0, fmt, args) + 1; | ||
586 | va_end(args); | ||
587 | |||
588 | int offset = *errors ? strlen(*errors) : 0; | ||
589 | char *temp = realloc(*errors, offset + length + 1); | ||
590 | if (!temp) { | ||
591 | wlr_log(WLR_ERROR, "Failed to realloc error log"); | ||
592 | return; | ||
593 | } | ||
594 | *errors = temp; | ||
595 | |||
596 | va_start(args, fmt); | ||
597 | vsnprintf(*errors + offset, length, fmt, args); | ||
598 | va_end(args); | ||
599 | } | ||
600 | |||
601 | bool read_config(FILE *file, struct sway_config *config, char **errors) { | ||
602 | bool reading_main_config = false; | 607 | bool reading_main_config = false; |
603 | char *this_config = NULL; | 608 | char *this_config = NULL; |
604 | size_t config_size = 0; | 609 | size_t config_size = 0; |
@@ -688,8 +693,11 @@ bool read_config(FILE *file, struct sway_config *config, char **errors) { | |||
688 | case CMD_INVALID: | 693 | case CMD_INVALID: |
689 | wlr_log(WLR_ERROR, "Error on line %i '%s': %s (%s)", line_number, | 694 | wlr_log(WLR_ERROR, "Error on line %i '%s': %s (%s)", line_number, |
690 | line, res->error, config->current_config_path); | 695 | line, res->error, config->current_config_path); |
691 | log_error(errors, "Error on line %i (%s) '%s': %s\n", line_number, | 696 | if (!config->validating) { |
692 | config->current_config_path, line, res->error); | 697 | swaynag_log(config->swaynag_command, swaynag, |
698 | "Error on line %i (%s) '%s': %s", line_number, | ||
699 | config->current_config_path, line, res->error); | ||
700 | } | ||
693 | success = false; | 701 | success = false; |
694 | break; | 702 | break; |
695 | 703 | ||
@@ -738,38 +746,6 @@ bool read_config(FILE *file, struct sway_config *config, char **errors) { | |||
738 | return success; | 746 | return success; |
739 | } | 747 | } |
740 | 748 | ||
741 | void spawn_swaynag_config_errors(struct sway_config *config, char *errors) { | ||
742 | char *command = "swaynag " | ||
743 | "--type error " | ||
744 | "--message 'There are errors in your config file' " | ||
745 | "--detailed-message " | ||
746 | "--button 'Exit sway' 'swaymsg exit' " | ||
747 | "--button 'Reload sway' 'swaymsg reload'"; | ||
748 | |||
749 | int fd[2]; | ||
750 | if (pipe(fd) != 0) { | ||
751 | wlr_log(WLR_ERROR, "Failed to create pipe for swaynag"); | ||
752 | return; | ||
753 | } | ||
754 | |||
755 | pid_t pid; | ||
756 | if ((pid = fork()) == 0) { | ||
757 | close(fd[1]); | ||
758 | dup2(fd[0], STDIN_FILENO); | ||
759 | close(fd[0]); | ||
760 | execl("/bin/sh", "/bin/sh", "-c", command, NULL); | ||
761 | _exit(0); | ||
762 | } else if (pid < 0) { | ||
763 | wlr_log(WLR_ERROR, "Failed to create fork for swaynag"); | ||
764 | } | ||
765 | |||
766 | close(fd[0]); | ||
767 | write(fd[1], errors, strlen(errors)); | ||
768 | close(fd[1]); | ||
769 | |||
770 | config->swaynag_pid = pid; | ||
771 | } | ||
772 | |||
773 | char *do_var_replacement(char *str) { | 749 | char *do_var_replacement(char *str) { |
774 | int i; | 750 | int i; |
775 | char *find = str; | 751 | char *find = str; |
diff --git a/sway/main.c b/sway/main.c index de2445a8..c02caf42 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "sway/debug.h" | 22 | #include "sway/debug.h" |
23 | #include "sway/desktop/transaction.h" | 23 | #include "sway/desktop/transaction.h" |
24 | #include "sway/server.h" | 24 | #include "sway/server.h" |
25 | #include "sway/swaynag.h" | ||
25 | #include "sway/tree/layout.h" | 26 | #include "sway/tree/layout.h" |
26 | #include "sway/ipc-server.h" | 27 | #include "sway/ipc-server.h" |
27 | #include "ipc-client.h" | 28 | #include "ipc-client.h" |
@@ -415,14 +416,13 @@ int main(int argc, char **argv) { | |||
415 | ipc_init(&server); | 416 | ipc_init(&server); |
416 | log_env(); | 417 | log_env(); |
417 | 418 | ||
418 | char *errors = NULL; | ||
419 | if (validate) { | 419 | if (validate) { |
420 | bool valid = load_main_config(config_path, false, &errors); | 420 | bool valid = load_main_config(config_path, false, true); |
421 | free(errors); | ||
422 | return valid ? 0 : 1; | 421 | return valid ? 0 : 1; |
423 | } | 422 | } |
424 | 423 | ||
425 | if (!load_main_config(config_path, false, &errors)) { | 424 | setenv("WAYLAND_DISPLAY", server.socket, true); |
425 | if (!load_main_config(config_path, false, false)) { | ||
426 | sway_terminate(EXIT_FAILURE); | 426 | sway_terminate(EXIT_FAILURE); |
427 | } | 427 | } |
428 | 428 | ||
@@ -432,10 +432,8 @@ int main(int argc, char **argv) { | |||
432 | 432 | ||
433 | security_sanity_check(); | 433 | security_sanity_check(); |
434 | 434 | ||
435 | setenv("WAYLAND_DISPLAY", server.socket, true); | ||
436 | if (!terminate_request) { | 435 | if (!terminate_request) { |
437 | if (!server_start_backend(&server)) { | 436 | if (!server_start_backend(&server)) { |
438 | free(errors); | ||
439 | sway_terminate(EXIT_FAILURE); | 437 | sway_terminate(EXIT_FAILURE); |
440 | } | 438 | } |
441 | } | 439 | } |
@@ -455,9 +453,8 @@ int main(int argc, char **argv) { | |||
455 | } | 453 | } |
456 | transaction_commit_dirty(); | 454 | transaction_commit_dirty(); |
457 | 455 | ||
458 | if (errors) { | 456 | if (config->swaynag_config_errors.pid > 0) { |
459 | spawn_swaynag_config_errors(config, errors); | 457 | swaynag_show(&config->swaynag_config_errors); |
460 | free(errors); | ||
461 | } | 458 | } |
462 | 459 | ||
463 | if (!terminate_request) { | 460 | if (!terminate_request) { |
diff --git a/sway/meson.build b/sway/meson.build index a9503c3b..17406f6b 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -9,6 +9,7 @@ sway_sources = files( | |||
9 | 'ipc-server.c', | 9 | 'ipc-server.c', |
10 | 'scratchpad.c', | 10 | 'scratchpad.c', |
11 | 'security.c', | 11 | 'security.c', |
12 | 'swaynag.c', | ||
12 | 13 | ||
13 | 'desktop/desktop.c', | 14 | 'desktop/desktop.c', |
14 | 'desktop/idle_inhibit_v1.c', | 15 | 'desktop/idle_inhibit_v1.c', |
@@ -78,6 +79,7 @@ sway_sources = files( | |||
78 | 'commands/split.c', | 79 | 'commands/split.c', |
79 | 'commands/sticky.c', | 80 | 'commands/sticky.c', |
80 | 'commands/swaybg_command.c', | 81 | 'commands/swaybg_command.c', |
82 | 'commands/swaynag_command.c', | ||
81 | 'commands/swap.c', | 83 | 'commands/swap.c', |
82 | 'commands/title_format.c', | 84 | 'commands/title_format.c', |
83 | 'commands/unmark.c', | 85 | 'commands/unmark.c', |
diff --git a/sway/sway.5.scd b/sway/sway.5.scd index d369d7b6..82df38e3 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd | |||
@@ -59,6 +59,13 @@ The following commands may only be used in the configuration file. | |||
59 | Executes custom background _command_. Default is _swaybg_. Refer to | 59 | Executes custom background _command_. Default is _swaybg_. Refer to |
60 | *output* below for more information. | 60 | *output* below for more information. |
61 | 61 | ||
62 | *swaynag\_command* <command> | ||
63 | Executes custom command for _swaynag_. Default is _swaynag_. Additional | ||
64 | arguments may be appended to the end. This should only be used to either | ||
65 | direct sway to call swaynag from a custom path or to provide additional | ||
66 | arguments. This should be placed at the top of the config for the best | ||
67 | results. | ||
68 | |||
62 | The following commands cannot be used directly in the configuration file. | 69 | The following commands cannot be used directly in the configuration file. |
63 | They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). | 70 | They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). |
64 | 71 | ||
diff --git a/sway/swaynag.c b/sway/swaynag.c new file mode 100644 index 00000000..2dc0cb21 --- /dev/null +++ b/sway/swaynag.c | |||
@@ -0,0 +1,103 @@ | |||
1 | #include <fcntl.h> | ||
2 | #include <signal.h> | ||
3 | #include <stdbool.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <stdio.h> | ||
6 | #include <sys/types.h> | ||
7 | #include <unistd.h> | ||
8 | #include "log.h" | ||
9 | #include "sway/swaynag.h" | ||
10 | |||
11 | void swaynag_clone(struct swaynag_instance *dest, | ||
12 | struct swaynag_instance *src) { | ||
13 | dest->args = src->args; | ||
14 | dest->pid = src->pid; | ||
15 | dest->fd[0] = src->fd[0]; | ||
16 | dest->fd[1] = src->fd[1]; | ||
17 | dest->detailed = src->detailed; | ||
18 | } | ||
19 | |||
20 | bool swaynag_spawn(const char *swaynag_command, | ||
21 | struct swaynag_instance *swaynag) { | ||
22 | if (swaynag->detailed) { | ||
23 | if (pipe(swaynag->fd) != 0) { | ||
24 | wlr_log(WLR_ERROR, "Failed to create pipe for swaynag"); | ||
25 | return false; | ||
26 | } | ||
27 | fcntl(swaynag->fd[1], F_SETFD, FD_CLOEXEC); | ||
28 | } | ||
29 | |||
30 | pid_t pid; | ||
31 | if ((pid = fork()) == 0) { | ||
32 | if (swaynag->detailed) { | ||
33 | close(swaynag->fd[1]); | ||
34 | dup2(swaynag->fd[0], STDIN_FILENO); | ||
35 | close(swaynag->fd[0]); | ||
36 | } | ||
37 | |||
38 | size_t length = strlen(swaynag_command) + strlen(swaynag->args) + 2; | ||
39 | char *cmd = malloc(length); | ||
40 | snprintf(cmd, length, "%s %s", swaynag_command, swaynag->args); | ||
41 | execl("/bin/sh", "/bin/sh", "-c", cmd, NULL); | ||
42 | _exit(0); | ||
43 | } else if (pid < 0) { | ||
44 | wlr_log(WLR_ERROR, "Failed to create fork for swaynag"); | ||
45 | if (swaynag->detailed) { | ||
46 | close(swaynag->fd[0]); | ||
47 | close(swaynag->fd[1]); | ||
48 | } | ||
49 | return false; | ||
50 | } | ||
51 | |||
52 | if (swaynag->detailed) { | ||
53 | close(swaynag->fd[0]); | ||
54 | } | ||
55 | swaynag->pid = pid; | ||
56 | return true; | ||
57 | } | ||
58 | |||
59 | |||
60 | void swaynag_kill(struct swaynag_instance *swaynag) { | ||
61 | if (swaynag->pid > 0) { | ||
62 | kill(swaynag->pid, SIGTERM); | ||
63 | swaynag->pid = -1; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, | ||
68 | const char *fmt, ...) { | ||
69 | if (!swaynag->detailed) { | ||
70 | wlr_log(WLR_ERROR, "Attempting to write to non-detailed swaynag inst"); | ||
71 | return; | ||
72 | } | ||
73 | |||
74 | if (swaynag->pid <= 0 && !swaynag_spawn(swaynag_command, swaynag)) { | ||
75 | return; | ||
76 | } | ||
77 | |||
78 | va_list args; | ||
79 | va_start(args, fmt); | ||
80 | size_t length = vsnprintf(NULL, 0, fmt, args) + 1; | ||
81 | va_end(args); | ||
82 | |||
83 | char *temp = malloc(length + 1); | ||
84 | if (!temp) { | ||
85 | wlr_log(WLR_ERROR, "Failed to allocate buffer for swaynag log entry."); | ||
86 | return; | ||
87 | } | ||
88 | |||
89 | va_start(args, fmt); | ||
90 | vsnprintf(temp, length, fmt, args); | ||
91 | va_end(args); | ||
92 | |||
93 | write(swaynag->fd[1], temp, length); | ||
94 | |||
95 | free(temp); | ||
96 | } | ||
97 | |||
98 | void swaynag_show(struct swaynag_instance *swaynag) { | ||
99 | if (swaynag->detailed && swaynag->pid > 0) { | ||
100 | close(swaynag->fd[1]); | ||
101 | } | ||
102 | } | ||
103 | |||