mirror of
				https://github.com/swaywm/sway.git
				synced 2025-11-03 09:01:43 -05:00 
			
		
		
		
	Merge pull request #2400 from RedSoxFan/swaynag-config-errors
Show swaynag on config errors
This commit is contained in:
		
						commit
						38675eba7b
					
				
					 12 changed files with 222 additions and 19 deletions
				
			
		| 
						 | 
					@ -150,6 +150,7 @@ sway_cmd cmd_splitt;
 | 
				
			||||||
sway_cmd cmd_splitv;
 | 
					sway_cmd cmd_splitv;
 | 
				
			||||||
sway_cmd cmd_sticky;
 | 
					sway_cmd cmd_sticky;
 | 
				
			||||||
sway_cmd cmd_swaybg_command;
 | 
					sway_cmd cmd_swaybg_command;
 | 
				
			||||||
 | 
					sway_cmd cmd_swaynag_command;
 | 
				
			||||||
sway_cmd cmd_swap;
 | 
					sway_cmd cmd_swap;
 | 
				
			||||||
sway_cmd cmd_title_format;
 | 
					sway_cmd cmd_title_format;
 | 
				
			||||||
sway_cmd cmd_unmark;
 | 
					sway_cmd cmd_unmark;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
#include <wlr/types/wlr_box.h>
 | 
					#include <wlr/types/wlr_box.h>
 | 
				
			||||||
#include <xkbcommon/xkbcommon.h>
 | 
					#include <xkbcommon/xkbcommon.h>
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
 | 
					#include "swaynag.h"
 | 
				
			||||||
#include "tree/layout.h"
 | 
					#include "tree/layout.h"
 | 
				
			||||||
#include "tree/container.h"
 | 
					#include "tree/container.h"
 | 
				
			||||||
#include "wlr-layer-shell-unstable-v1-protocol.h"
 | 
					#include "wlr-layer-shell-unstable-v1-protocol.h"
 | 
				
			||||||
| 
						 | 
					@ -308,6 +309,8 @@ enum focus_wrapping_mode {
 | 
				
			||||||
 * The configuration struct. The result of loading a config file.
 | 
					 * The configuration struct. The result of loading a config file.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sway_config {
 | 
					struct sway_config {
 | 
				
			||||||
 | 
						char *swaynag_command;
 | 
				
			||||||
 | 
						struct swaynag_instance swaynag_config_errors;
 | 
				
			||||||
	list_t *symbols;
 | 
						list_t *symbols;
 | 
				
			||||||
	list_t *modes;
 | 
						list_t *modes;
 | 
				
			||||||
	list_t *bars;
 | 
						list_t *bars;
 | 
				
			||||||
| 
						 | 
					@ -345,6 +348,7 @@ struct sway_config {
 | 
				
			||||||
	bool failed;
 | 
						bool failed;
 | 
				
			||||||
	bool reloading;
 | 
						bool reloading;
 | 
				
			||||||
	bool reading;
 | 
						bool reading;
 | 
				
			||||||
 | 
						bool validating;
 | 
				
			||||||
	bool auto_back_and_forth;
 | 
						bool auto_back_and_forth;
 | 
				
			||||||
	bool show_marks;
 | 
						bool show_marks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -403,17 +407,19 @@ struct sway_config {
 | 
				
			||||||
 * Loads the main config from the given path. is_active should be true when
 | 
					 * Loads the main config from the given path. is_active should be true when
 | 
				
			||||||
 * reloading the config.
 | 
					 * reloading the config.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool load_main_config(const char *path, bool is_active);
 | 
					bool load_main_config(const char *path, bool is_active, bool validating);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Loads an included config. Can only be used after load_main_config.
 | 
					 * Loads an included config. Can only be used after load_main_config.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool load_include_configs(const char *path, struct sway_config *config);
 | 
					bool load_include_configs(const char *path, struct sway_config *config,
 | 
				
			||||||
 | 
							struct swaynag_instance *swaynag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Reads the config from the given FILE.
 | 
					 * Reads the config from the given FILE.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool read_config(FILE *file, struct sway_config *config);
 | 
					bool read_config(FILE *file, struct sway_config *config,
 | 
				
			||||||
 | 
							struct swaynag_instance *swaynag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Free config struct
 | 
					 * Free config struct
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										29
									
								
								include/sway/swaynag.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								include/sway/swaynag.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					#ifndef _SWAY_SWAYNAG_H
 | 
				
			||||||
 | 
					#define _SWAY_SWAYNAG_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct swaynag_instance {
 | 
				
			||||||
 | 
						const char *args;
 | 
				
			||||||
 | 
						pid_t pid;
 | 
				
			||||||
 | 
						int fd[2];
 | 
				
			||||||
 | 
						bool detailed;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Spawn swaynag. If swaynag->detailed, then swaynag->fd[1] will left open
 | 
				
			||||||
 | 
					// so it can be written to. Call swaynag_show when done writing. This will
 | 
				
			||||||
 | 
					// be automatically called by swaynag_log if the instance is not spawned and
 | 
				
			||||||
 | 
					// swaynag->detailed is true.
 | 
				
			||||||
 | 
					bool swaynag_spawn(const char *swaynag_command,
 | 
				
			||||||
 | 
							struct swaynag_instance *swaynag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Kill the swaynag instance
 | 
				
			||||||
 | 
					void swaynag_kill(struct swaynag_instance *swaynag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Write a log message to swaynag->fd[1]. This will fail when swaynag->detailed
 | 
				
			||||||
 | 
					// is false.
 | 
				
			||||||
 | 
					void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
 | 
				
			||||||
 | 
							const char *fmt, ...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// If swaynag->detailed, close swaynag->fd[1] so swaynag displays
 | 
				
			||||||
 | 
					void swaynag_show(struct swaynag_instance *swaynag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -132,6 +132,7 @@ static struct cmd_handler handlers[] = {
 | 
				
			||||||
static struct cmd_handler config_handlers[] = {
 | 
					static struct cmd_handler config_handlers[] = {
 | 
				
			||||||
	{ "default_orientation", cmd_default_orientation },
 | 
						{ "default_orientation", cmd_default_orientation },
 | 
				
			||||||
	{ "swaybg_command", cmd_swaybg_command },
 | 
						{ "swaybg_command", cmd_swaybg_command },
 | 
				
			||||||
 | 
						{ "swaynag_command", cmd_swaynag_command },
 | 
				
			||||||
	{ "workspace_layout", cmd_workspace_layout },
 | 
						{ "workspace_layout", cmd_workspace_layout },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,8 +7,10 @@ struct cmd_results *cmd_include(int argc, char **argv) {
 | 
				
			||||||
		return error;
 | 
							return error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!load_include_configs(argv[0], config)) {
 | 
						if (!load_include_configs(argv[0], config,
 | 
				
			||||||
		return cmd_results_new(CMD_INVALID, "include", "Failed to include sub configuration file: %s", argv[0]);
 | 
									&config->swaynag_config_errors)) {
 | 
				
			||||||
 | 
							return cmd_results_new(CMD_INVALID, "include",
 | 
				
			||||||
 | 
									"Failed to include sub configuration file: %s", argv[0]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,8 +19,9 @@ struct cmd_results *cmd_reload(int argc, char **argv) {
 | 
				
			||||||
		list_add(bar_ids, strdup(bar->id));
 | 
							list_add(bar_ids, strdup(bar->id));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!load_main_config(config->current_config_path, true)) {
 | 
						if (!load_main_config(config->current_config_path, true, false)) {
 | 
				
			||||||
		return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config.");
 | 
							return cmd_results_new(CMD_FAILURE, "reload",
 | 
				
			||||||
 | 
									"Error(s) reloading config.");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ipc_event_workspace(NULL, NULL, "reload");
 | 
						ipc_event_workspace(NULL, NULL, "reload");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,5 +43,6 @@ struct cmd_results *cmd_reload(int argc, char **argv) {
 | 
				
			||||||
	list_free(bar_ids);
 | 
						list_free(bar_ids);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	arrange_windows(&root_container);
 | 
						arrange_windows(&root_container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										20
									
								
								sway/commands/swaynag_command.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								sway/commands/swaynag_command.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include "sway/commands.h"
 | 
				
			||||||
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					#include "stringop.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cmd_results *cmd_swaynag_command(int argc, char **argv) {
 | 
				
			||||||
 | 
						struct cmd_results *error = NULL;
 | 
				
			||||||
 | 
						if ((error = checkarg(argc, "swaynag_command", EXPECTED_AT_LEAST, 1))) {
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->swaynag_command) {
 | 
				
			||||||
 | 
							free(config->swaynag_command);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						config->swaynag_command = join_args(argv, argc);
 | 
				
			||||||
 | 
						wlr_log(WLR_DEBUG, "Using custom swaynag command: %s",
 | 
				
			||||||
 | 
								config->swaynag_command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@
 | 
				
			||||||
#include "sway/commands.h"
 | 
					#include "sway/commands.h"
 | 
				
			||||||
#include "sway/config.h"
 | 
					#include "sway/config.h"
 | 
				
			||||||
#include "sway/criteria.h"
 | 
					#include "sway/criteria.h"
 | 
				
			||||||
 | 
					#include "sway/swaynag.h"
 | 
				
			||||||
#include "sway/tree/arrange.h"
 | 
					#include "sway/tree/arrange.h"
 | 
				
			||||||
#include "sway/tree/layout.h"
 | 
					#include "sway/tree/layout.h"
 | 
				
			||||||
#include "sway/tree/workspace.h"
 | 
					#include "sway/tree/workspace.h"
 | 
				
			||||||
| 
						 | 
					@ -72,6 +73,8 @@ void free_config(struct sway_config *config) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&config->handler_context, 0, sizeof(config->handler_context));
 | 
						memset(&config->handler_context, 0, sizeof(config->handler_context));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(config->swaynag_command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO: handle all currently unhandled lists as we add implementations
 | 
						// TODO: handle all currently unhandled lists as we add implementations
 | 
				
			||||||
	if (config->symbols) {
 | 
						if (config->symbols) {
 | 
				
			||||||
		for (int i = 0; i < config->symbols->length; ++i) {
 | 
							for (int i = 0; i < config->symbols->length; ++i) {
 | 
				
			||||||
| 
						 | 
					@ -158,6 +161,17 @@ static void set_color(float dest[static 4], uint32_t color) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void config_defaults(struct sway_config *config) {
 | 
					static void config_defaults(struct sway_config *config) {
 | 
				
			||||||
 | 
						config->swaynag_command = strdup("swaynag");
 | 
				
			||||||
 | 
						config->swaynag_config_errors = (struct swaynag_instance){
 | 
				
			||||||
 | 
							.args = "--type error "
 | 
				
			||||||
 | 
								"--message 'There are errors in your config file' "
 | 
				
			||||||
 | 
								"--detailed-message "
 | 
				
			||||||
 | 
								"--button 'Exit sway' 'swaymsg exit' "
 | 
				
			||||||
 | 
								"--button 'Reload sway' 'swaymsg reload'",
 | 
				
			||||||
 | 
							.pid = -1,
 | 
				
			||||||
 | 
							.detailed = true,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(config->symbols = create_list())) goto cleanup;
 | 
						if (!(config->symbols = create_list())) goto cleanup;
 | 
				
			||||||
	if (!(config->modes = create_list())) goto cleanup;
 | 
						if (!(config->modes = create_list())) goto cleanup;
 | 
				
			||||||
	if (!(config->bars = create_list())) goto cleanup;
 | 
						if (!(config->bars = create_list())) goto cleanup;
 | 
				
			||||||
| 
						 | 
					@ -204,6 +218,7 @@ static void config_defaults(struct sway_config *config) {
 | 
				
			||||||
	config->focus_follows_mouse = true;
 | 
						config->focus_follows_mouse = true;
 | 
				
			||||||
	config->mouse_warping = true;
 | 
						config->mouse_warping = true;
 | 
				
			||||||
	config->focus_wrapping = WRAP_YES;
 | 
						config->focus_wrapping = WRAP_YES;
 | 
				
			||||||
 | 
						config->validating = false;
 | 
				
			||||||
	config->reloading = false;
 | 
						config->reloading = false;
 | 
				
			||||||
	config->active = false;
 | 
						config->active = false;
 | 
				
			||||||
	config->failed = false;
 | 
						config->failed = false;
 | 
				
			||||||
| 
						 | 
					@ -319,7 +334,8 @@ static char *get_config_path(void) {
 | 
				
			||||||
	return NULL; // Not reached
 | 
						return NULL; // Not reached
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool load_config(const char *path, struct sway_config *config) {
 | 
					static bool load_config(const char *path, struct sway_config *config,
 | 
				
			||||||
 | 
							struct swaynag_instance *swaynag) {
 | 
				
			||||||
	if (path == NULL) {
 | 
						if (path == NULL) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "Unable to find a config file!");
 | 
							wlr_log(WLR_ERROR, "Unable to find a config file!");
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
| 
						 | 
					@ -338,7 +354,7 @@ static bool load_config(const char *path, struct sway_config *config) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool config_load_success = read_config(f, config);
 | 
						bool config_load_success = read_config(f, config, swaynag);
 | 
				
			||||||
	fclose(f);
 | 
						fclose(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!config_load_success) {
 | 
						if (!config_load_success) {
 | 
				
			||||||
| 
						 | 
					@ -348,7 +364,7 @@ static bool load_config(const char *path, struct sway_config *config) {
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool load_main_config(const char *file, bool is_active) {
 | 
					bool load_main_config(const char *file, bool is_active, bool validating) {
 | 
				
			||||||
	char *path;
 | 
						char *path;
 | 
				
			||||||
	if (file != NULL) {
 | 
						if (file != NULL) {
 | 
				
			||||||
		path = strdup(file);
 | 
							path = strdup(file);
 | 
				
			||||||
| 
						 | 
					@ -363,10 +379,17 @@ bool load_main_config(const char *file, bool is_active) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config_defaults(config);
 | 
						config_defaults(config);
 | 
				
			||||||
 | 
						config->validating = validating;
 | 
				
			||||||
	if (is_active) {
 | 
						if (is_active) {
 | 
				
			||||||
		wlr_log(WLR_DEBUG, "Performing configuration file reload");
 | 
							wlr_log(WLR_DEBUG, "Performing configuration file reload");
 | 
				
			||||||
		config->reloading = true;
 | 
							config->reloading = true;
 | 
				
			||||||
		config->active = true;
 | 
							config->active = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							swaynag_kill(&old_config->swaynag_config_errors);
 | 
				
			||||||
 | 
							memcpy(&config->swaynag_config_errors,
 | 
				
			||||||
 | 
									&old_config->swaynag_config_errors,
 | 
				
			||||||
 | 
									sizeof(struct swaynag_instance));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		create_default_output_configs();
 | 
							create_default_output_configs();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -423,13 +446,17 @@ bool load_main_config(const char *file, bool is_active) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	*/
 | 
						*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	success = success && load_config(path, config);
 | 
						success = success && load_config(path, config,
 | 
				
			||||||
 | 
								&config->swaynag_config_errors);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (is_active) {
 | 
						if (is_active) {
 | 
				
			||||||
		for (int i = 0; i < config->output_configs->length; i++) {
 | 
							for (int i = 0; i < config->output_configs->length; i++) {
 | 
				
			||||||
			apply_output_config_to_outputs(config->output_configs->items[i]);
 | 
								apply_output_config_to_outputs(config->output_configs->items[i]);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		config->reloading = false;
 | 
							config->reloading = false;
 | 
				
			||||||
 | 
							if (config->swaynag_config_errors.pid > 0) {
 | 
				
			||||||
 | 
								swaynag_show(&config->swaynag_config_errors);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (old_config) {
 | 
						if (old_config) {
 | 
				
			||||||
| 
						 | 
					@ -441,7 +468,7 @@ bool load_main_config(const char *file, bool is_active) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool load_include_config(const char *path, const char *parent_dir,
 | 
					static bool load_include_config(const char *path, const char *parent_dir,
 | 
				
			||||||
		struct sway_config *config) {
 | 
							struct sway_config *config, struct swaynag_instance *swaynag) {
 | 
				
			||||||
	// save parent config
 | 
						// save parent config
 | 
				
			||||||
	const char *parent_config = config->current_config_path;
 | 
						const char *parent_config = config->current_config_path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -485,7 +512,7 @@ static bool load_include_config(const char *path, const char *parent_dir,
 | 
				
			||||||
	list_add(config->config_chain, real_path);
 | 
						list_add(config->config_chain, real_path);
 | 
				
			||||||
	int index = config->config_chain->length - 1;
 | 
						int index = config->config_chain->length - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!load_config(real_path, config)) {
 | 
						if (!load_config(real_path, config, swaynag)) {
 | 
				
			||||||
		free(real_path);
 | 
							free(real_path);
 | 
				
			||||||
		config->current_config_path = parent_config;
 | 
							config->current_config_path = parent_config;
 | 
				
			||||||
		list_del(config->config_chain, index);
 | 
							list_del(config->config_chain, index);
 | 
				
			||||||
| 
						 | 
					@ -497,7 +524,8 @@ static bool load_include_config(const char *path, const char *parent_dir,
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool load_include_configs(const char *path, struct sway_config *config) {
 | 
					bool load_include_configs(const char *path, struct sway_config *config,
 | 
				
			||||||
 | 
							struct swaynag_instance *swaynag) {
 | 
				
			||||||
	char *wd = getcwd(NULL, 0);
 | 
						char *wd = getcwd(NULL, 0);
 | 
				
			||||||
	char *parent_path = strdup(config->current_config_path);
 | 
						char *parent_path = strdup(config->current_config_path);
 | 
				
			||||||
	const char *parent_dir = dirname(parent_path);
 | 
						const char *parent_dir = dirname(parent_path);
 | 
				
			||||||
| 
						 | 
					@ -519,7 +547,7 @@ bool load_include_configs(const char *path, struct sway_config *config) {
 | 
				
			||||||
	char **w = p.we_wordv;
 | 
						char **w = p.we_wordv;
 | 
				
			||||||
	size_t i;
 | 
						size_t i;
 | 
				
			||||||
	for (i = 0; i < p.we_wordc; ++i) {
 | 
						for (i = 0; i < p.we_wordc; ++i) {
 | 
				
			||||||
		load_include_config(w[i], parent_dir, config);
 | 
							load_include_config(w[i], parent_dir, config, swaynag);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	free(parent_path);
 | 
						free(parent_path);
 | 
				
			||||||
	wordfree(&p);
 | 
						wordfree(&p);
 | 
				
			||||||
| 
						 | 
					@ -575,7 +603,8 @@ static char *expand_line(const char *block, const char *line, bool add_brace) {
 | 
				
			||||||
	return expanded;
 | 
						return expanded;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool read_config(FILE *file, struct sway_config *config) {
 | 
					bool read_config(FILE *file, struct sway_config *config,
 | 
				
			||||||
 | 
							struct swaynag_instance *swaynag) {
 | 
				
			||||||
	bool reading_main_config = false;
 | 
						bool reading_main_config = false;
 | 
				
			||||||
	char *this_config = NULL;
 | 
						char *this_config = NULL;
 | 
				
			||||||
	size_t config_size = 0;
 | 
						size_t config_size = 0;
 | 
				
			||||||
| 
						 | 
					@ -665,6 +694,11 @@ bool read_config(FILE *file, struct sway_config *config) {
 | 
				
			||||||
		case CMD_INVALID:
 | 
							case CMD_INVALID:
 | 
				
			||||||
			wlr_log(WLR_ERROR, "Error on line %i '%s': %s (%s)", line_number,
 | 
								wlr_log(WLR_ERROR, "Error on line %i '%s': %s (%s)", line_number,
 | 
				
			||||||
				line, res->error, config->current_config_path);
 | 
									line, res->error, config->current_config_path);
 | 
				
			||||||
 | 
								if (!config->validating) {
 | 
				
			||||||
 | 
									swaynag_log(config->swaynag_command, swaynag,
 | 
				
			||||||
 | 
										"Error on line %i (%s) '%s': %s", line_number,
 | 
				
			||||||
 | 
										config->current_config_path, line, res->error);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			success = false;
 | 
								success = false;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								sway/main.c
									
										
									
									
									
								
							
							
						
						
									
										11
									
								
								sway/main.c
									
										
									
									
									
								
							| 
						 | 
					@ -22,6 +22,7 @@
 | 
				
			||||||
#include "sway/debug.h"
 | 
					#include "sway/debug.h"
 | 
				
			||||||
#include "sway/desktop/transaction.h"
 | 
					#include "sway/desktop/transaction.h"
 | 
				
			||||||
#include "sway/server.h"
 | 
					#include "sway/server.h"
 | 
				
			||||||
 | 
					#include "sway/swaynag.h"
 | 
				
			||||||
#include "sway/tree/layout.h"
 | 
					#include "sway/tree/layout.h"
 | 
				
			||||||
#include "sway/ipc-server.h"
 | 
					#include "sway/ipc-server.h"
 | 
				
			||||||
#include "ipc-client.h"
 | 
					#include "ipc-client.h"
 | 
				
			||||||
| 
						 | 
					@ -416,11 +417,12 @@ int main(int argc, char **argv) {
 | 
				
			||||||
	log_env();
 | 
						log_env();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (validate) {
 | 
						if (validate) {
 | 
				
			||||||
		bool valid = load_main_config(config_path, false);
 | 
							bool valid = load_main_config(config_path, false, true);
 | 
				
			||||||
		return valid ? 0 : 1;
 | 
							return valid ? 0 : 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!load_main_config(config_path, false)) {
 | 
						setenv("WAYLAND_DISPLAY", server.socket, true);
 | 
				
			||||||
 | 
						if (!load_main_config(config_path, false, false)) {
 | 
				
			||||||
		sway_terminate(EXIT_FAILURE);
 | 
							sway_terminate(EXIT_FAILURE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -430,7 +432,6 @@ int main(int argc, char **argv) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	security_sanity_check();
 | 
						security_sanity_check();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setenv("WAYLAND_DISPLAY", server.socket, true);
 | 
					 | 
				
			||||||
	if (!terminate_request) {
 | 
						if (!terminate_request) {
 | 
				
			||||||
		if (!server_start_backend(&server)) {
 | 
							if (!server_start_backend(&server)) {
 | 
				
			||||||
			sway_terminate(EXIT_FAILURE);
 | 
								sway_terminate(EXIT_FAILURE);
 | 
				
			||||||
| 
						 | 
					@ -452,6 +453,10 @@ int main(int argc, char **argv) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	transaction_commit_dirty();
 | 
						transaction_commit_dirty();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (config->swaynag_config_errors.pid > 0) {
 | 
				
			||||||
 | 
							swaynag_show(&config->swaynag_config_errors);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!terminate_request) {
 | 
						if (!terminate_request) {
 | 
				
			||||||
		server_run(&server);
 | 
							server_run(&server);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@ sway_sources = files(
 | 
				
			||||||
	'ipc-server.c',
 | 
						'ipc-server.c',
 | 
				
			||||||
	'scratchpad.c',
 | 
						'scratchpad.c',
 | 
				
			||||||
	'security.c',
 | 
						'security.c',
 | 
				
			||||||
 | 
						'swaynag.c',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	'desktop/desktop.c',
 | 
						'desktop/desktop.c',
 | 
				
			||||||
	'desktop/idle_inhibit_v1.c',
 | 
						'desktop/idle_inhibit_v1.c',
 | 
				
			||||||
| 
						 | 
					@ -78,6 +79,7 @@ sway_sources = files(
 | 
				
			||||||
	'commands/split.c',
 | 
						'commands/split.c',
 | 
				
			||||||
	'commands/sticky.c',
 | 
						'commands/sticky.c',
 | 
				
			||||||
	'commands/swaybg_command.c',
 | 
						'commands/swaybg_command.c',
 | 
				
			||||||
 | 
						'commands/swaynag_command.c',
 | 
				
			||||||
	'commands/swap.c',
 | 
						'commands/swap.c',
 | 
				
			||||||
	'commands/title_format.c',
 | 
						'commands/title_format.c',
 | 
				
			||||||
	'commands/unmark.c',
 | 
						'commands/unmark.c',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,6 +59,13 @@ The following commands may only be used in the configuration file.
 | 
				
			||||||
	Executes custom background _command_. Default is _swaybg_. Refer to
 | 
						Executes custom background _command_. Default is _swaybg_. Refer to
 | 
				
			||||||
	*output* below for more information.
 | 
						*output* below for more information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*swaynag\_command* <command>
 | 
				
			||||||
 | 
						Executes custom command for _swaynag_. Default is _swaynag_. Additional
 | 
				
			||||||
 | 
						arguments may be appended to the end. This should only be used to either
 | 
				
			||||||
 | 
						direct sway to call swaynag from a custom path or to provide additional
 | 
				
			||||||
 | 
						arguments. This should be placed at the top of the config for the best
 | 
				
			||||||
 | 
						results.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The following commands cannot be used directly in the configuration file.
 | 
					The following commands cannot be used directly in the configuration file.
 | 
				
			||||||
They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
 | 
					They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										94
									
								
								sway/swaynag.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								sway/swaynag.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,94 @@
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					#include "sway/swaynag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool swaynag_spawn(const char *swaynag_command,
 | 
				
			||||||
 | 
							struct swaynag_instance *swaynag) {
 | 
				
			||||||
 | 
						if (swaynag->detailed) {
 | 
				
			||||||
 | 
							if (pipe(swaynag->fd) != 0) {
 | 
				
			||||||
 | 
								wlr_log(WLR_ERROR, "Failed to create pipe for swaynag");
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							fcntl(swaynag->fd[1], F_SETFD, FD_CLOEXEC);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pid_t pid;
 | 
				
			||||||
 | 
						if ((pid = fork()) == 0) {
 | 
				
			||||||
 | 
							if (swaynag->detailed) {
 | 
				
			||||||
 | 
								close(swaynag->fd[1]);
 | 
				
			||||||
 | 
								dup2(swaynag->fd[0], STDIN_FILENO);
 | 
				
			||||||
 | 
								close(swaynag->fd[0]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							size_t length = strlen(swaynag_command) + strlen(swaynag->args) + 2;
 | 
				
			||||||
 | 
							char *cmd = malloc(length);
 | 
				
			||||||
 | 
							snprintf(cmd, length, "%s %s", swaynag_command, swaynag->args);
 | 
				
			||||||
 | 
							execl("/bin/sh", "/bin/sh", "-c", cmd, NULL);
 | 
				
			||||||
 | 
							_exit(0);
 | 
				
			||||||
 | 
						} else if (pid < 0) {
 | 
				
			||||||
 | 
							wlr_log(WLR_ERROR, "Failed to create fork for swaynag");
 | 
				
			||||||
 | 
							if (swaynag->detailed) {
 | 
				
			||||||
 | 
								close(swaynag->fd[0]);
 | 
				
			||||||
 | 
								close(swaynag->fd[1]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (swaynag->detailed) {
 | 
				
			||||||
 | 
							close(swaynag->fd[0]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						swaynag->pid = pid;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void swaynag_kill(struct swaynag_instance *swaynag) {
 | 
				
			||||||
 | 
						if (swaynag->pid > 0) {
 | 
				
			||||||
 | 
							kill(swaynag->pid, SIGTERM);
 | 
				
			||||||
 | 
							swaynag->pid = -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
 | 
				
			||||||
 | 
							const char *fmt, ...) {
 | 
				
			||||||
 | 
						if (!swaynag->detailed) {
 | 
				
			||||||
 | 
							wlr_log(WLR_ERROR, "Attempting to write to non-detailed swaynag inst");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (swaynag->pid <= 0 && !swaynag_spawn(swaynag_command, swaynag)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va_list args;
 | 
				
			||||||
 | 
						va_start(args, fmt);
 | 
				
			||||||
 | 
						size_t length = vsnprintf(NULL, 0, fmt, args) + 1;
 | 
				
			||||||
 | 
						va_end(args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char *temp = malloc(length + 1);
 | 
				
			||||||
 | 
						if (!temp) {
 | 
				
			||||||
 | 
							wlr_log(WLR_ERROR, "Failed to allocate buffer for swaynag log entry.");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va_start(args, fmt);
 | 
				
			||||||
 | 
						vsnprintf(temp, length, fmt, args);
 | 
				
			||||||
 | 
						va_end(args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						write(swaynag->fd[1], temp, length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(temp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void swaynag_show(struct swaynag_instance *swaynag) {
 | 
				
			||||||
 | 
						if (swaynag->detailed && swaynag->pid > 0) {
 | 
				
			||||||
 | 
							close(swaynag->fd[1]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue