summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Brian Ashworth <bosrsf04@gmail.com>2018-08-02 21:37:29 -0400
committerLibravatar Brian Ashworth <bosrsf04@gmail.com>2018-08-03 10:37:35 -0400
commita7f7d4a488c8d3b2461122765f9904c8a411a583 (patch)
tree7abee51265a8b9550c62255d0c6649935ee1d6a2
parentShow swaynag on config errors (diff)
downloadsway-a7f7d4a488c8d3b2461122765f9904c8a411a583.tar.gz
sway-a7f7d4a488c8d3b2461122765f9904c8a411a583.tar.zst
sway-a7f7d4a488c8d3b2461122765f9904c8a411a583.zip
Write to swaynag pipe fd directly on config errors
-rw-r--r--include/sway/commands.h1
-rw-r--r--include/sway/config.h14
-rw-r--r--include/sway/swaynag.h33
-rw-r--r--sway/commands.c8
-rw-r--r--sway/commands/include.c15
-rw-r--r--sway/commands/reload.c15
-rw-r--r--sway/commands/swaynag_command.c20
-rw-r--r--sway/config.c104
-rw-r--r--sway/main.c15
-rw-r--r--sway/meson.build2
-rw-r--r--sway/sway.5.scd7
-rw-r--r--sway/swaynag.c103
12 files changed, 227 insertions, 110 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 41858ccc..f83907b2 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -150,6 +150,7 @@ sway_cmd cmd_splitt;
150sway_cmd cmd_splitv; 150sway_cmd cmd_splitv;
151sway_cmd cmd_sticky; 151sway_cmd cmd_sticky;
152sway_cmd cmd_swaybg_command; 152sway_cmd cmd_swaybg_command;
153sway_cmd cmd_swaynag_command;
153sway_cmd cmd_swap; 154sway_cmd cmd_swap;
154sway_cmd cmd_title_format; 155sway_cmd cmd_title_format;
155sway_cmd cmd_unmark; 156sway_cmd cmd_unmark;
diff --git a/include/sway/config.h b/include/sway/config.h
index 4fc3eadb..632aca14 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -7,6 +7,7 @@
7#include <wlr/types/wlr_box.h> 7#include <wlr/types/wlr_box.h>
8#include <xkbcommon/xkbcommon.h> 8#include <xkbcommon/xkbcommon.h>
9#include "list.h" 9#include "list.h"
10#include "swaynag.h"
10#include "tree/layout.h" 11#include "tree/layout.h"
11#include "tree/container.h" 12#include "tree/container.h"
12#include "wlr-layer-shell-unstable-v1-protocol.h" 13#include "wlr-layer-shell-unstable-v1-protocol.h"
@@ -308,7 +309,8 @@ enum focus_wrapping_mode {
308 * The configuration struct. The result of loading a config file. 309 * The configuration struct. The result of loading a config file.
309 */ 310 */
310struct sway_config { 311struct sway_config {
311 pid_t swaynag_pid; 312 char *swaynag_command;
313 struct swaynag_instance swaynag_config_errors;
312 list_t *symbols; 314 list_t *symbols;
313 list_t *modes; 315 list_t *modes;
314 list_t *bars; 316 list_t *bars;
@@ -346,6 +348,7 @@ struct sway_config {
346 bool failed; 348 bool failed;
347 bool reloading; 349 bool reloading;
348 bool reading; 350 bool reading;
351 bool validating;
349 bool auto_back_and_forth; 352 bool auto_back_and_forth;
350 bool show_marks; 353 bool show_marks;
351 354
@@ -404,18 +407,19 @@ struct sway_config {
404 * Loads the main config from the given path. is_active should be true when 407 * Loads the main config from the given path. is_active should be true when
405 * reloading the config. 408 * reloading the config.
406 */ 409 */
407bool load_main_config(const char *path, bool is_active, char **errors); 410bool load_main_config(const char *path, bool is_active, bool validating);
408 411
409/** 412/**
410 * Loads an included config. Can only be used after load_main_config. 413 * Loads an included config. Can only be used after load_main_config.
411 */ 414 */
412bool load_include_configs(const char *path, struct sway_config *config, 415bool load_include_configs(const char *path, struct sway_config *config,
413 char **errors); 416 struct swaynag_instance *swaynag);
414 417
415/** 418/**
416 * Reads the config from the given FILE. 419 * Reads the config from the given FILE.
417 */ 420 */
418bool read_config(FILE *file, struct sway_config *config, char **errors); 421bool read_config(FILE *file, struct sway_config *config,
422 struct swaynag_instance *swaynag);
419 423
420/** 424/**
421 * Free config struct 425 * Free config struct
@@ -424,8 +428,6 @@ void free_config(struct sway_config *config);
424 428
425void free_sway_variable(struct sway_variable *var); 429void free_sway_variable(struct sway_variable *var);
426 430
427void spawn_swaynag_config_errors(struct sway_config *config, char *errors);
428
429/** 431/**
430 * Does variable replacement for a string based on the config's currently loaded variables. 432 * Does variable replacement for a string based on the config's currently loaded variables.
431 */ 433 */
diff --git a/include/sway/swaynag.h b/include/sway/swaynag.h
new file mode 100644
index 00000000..ac0086a1
--- /dev/null
+++ b/include/sway/swaynag.h
@@ -0,0 +1,33 @@
1#ifndef _SWAY_SWAYNAG_H
2#define _SWAY_SWAYNAG_H
3
4struct swaynag_instance {
5 const char *args;
6 pid_t pid;
7 int fd[2];
8 bool detailed;
9};
10
11// Copy all fields of one instance to another
12void swaynag_clone(struct swaynag_instance *dest,
13 struct swaynag_instance *src);
14
15// Spawn swaynag. If swaynag->detailed, then swaynag->fd[1] will left open
16// so it can be written to. Call swaynag_show when done writing. This will
17// be automatically called by swaynag_log if the instance is not spawned and
18// swaynag->detailed is true.
19bool swaynag_spawn(const char *swaynag_command,
20 struct swaynag_instance *swaynag);
21
22// Kill the swaynag instance
23void swaynag_kill(struct swaynag_instance *swaynag);
24
25// Write a log message to swaynag->fd[1]. This will fail when swaynag->detailed
26// is false.
27void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
28 const char *fmt, ...);
29
30// If swaynag->detailed, close swaynag->fd[1] so swaynag displays
31void swaynag_show(struct swaynag_instance *swaynag);
32
33#endif
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[] = {
132static struct cmd_handler config_handlers[] = { 132static 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
6struct 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
160static void config_defaults(struct sway_config *config) { 163static 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
323static bool load_config(const char *path, struct sway_config *config, 337static 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
353bool load_main_config(const char *file, bool is_active, char **errors) { 367bool 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
446static bool load_include_config(const char *path, const char *parent_dir, 469static 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
503bool load_include_configs(const char *path, struct sway_config *config, 526bool 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
582static void log_error(char **errors, const char *fmt, ...) { 605bool 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
601bool 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
741void 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
773char *do_var_replacement(char *str) { 749char *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
62The following commands cannot be used directly in the configuration file. 69The following commands cannot be used directly in the configuration file.
63They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). 70They 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
11void 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
20bool 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
60void swaynag_kill(struct swaynag_instance *swaynag) {
61 if (swaynag->pid > 0) {
62 kill(swaynag->pid, SIGTERM);
63 swaynag->pid = -1;
64 }
65}
66
67void 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
98void swaynag_show(struct swaynag_instance *swaynag) {
99 if (swaynag->detailed && swaynag->pid > 0) {
100 close(swaynag->fd[1]);
101 }
102}
103