Merge branch 'master' into fix-2416

This commit is contained in:
Ryan Dwyer 2018-08-04 10:15:29 +10:00 committed by GitHub
commit e24fc3df18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 222 additions and 19 deletions

View file

@ -132,6 +132,7 @@ static struct cmd_handler handlers[] = {
static struct cmd_handler config_handlers[] = {
{ "default_orientation", cmd_default_orientation },
{ "swaybg_command", cmd_swaybg_command },
{ "swaynag_command", cmd_swaynag_command },
{ "workspace_layout", cmd_workspace_layout },
};

View file

@ -7,8 +7,10 @@ struct cmd_results *cmd_include(int argc, char **argv) {
return error;
}
if (!load_include_configs(argv[0], config)) {
return cmd_results_new(CMD_INVALID, "include", "Failed to include sub configuration file: %s", argv[0]);
if (!load_include_configs(argv[0], config,
&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);

View file

@ -19,8 +19,9 @@ struct cmd_results *cmd_reload(int argc, char **argv) {
list_add(bar_ids, strdup(bar->id));
}
if (!load_main_config(config->current_config_path, true)) {
return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config.");
if (!load_main_config(config->current_config_path, true, false)) {
return cmd_results_new(CMD_FAILURE, "reload",
"Error(s) reloading config.");
}
ipc_event_workspace(NULL, NULL, "reload");
@ -42,5 +43,6 @@ struct cmd_results *cmd_reload(int argc, char **argv) {
list_free(bar_ids);
arrange_windows(&root_container);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View 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);
}

View file

@ -25,6 +25,7 @@
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/criteria.h"
#include "sway/swaynag.h"
#include "sway/tree/arrange.h"
#include "sway/tree/layout.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));
free(config->swaynag_command);
// TODO: handle all currently unhandled lists as we add implementations
if (config->symbols) {
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) {
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->modes = 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->mouse_warping = true;
config->focus_wrapping = WRAP_YES;
config->validating = false;
config->reloading = false;
config->active = false;
config->failed = false;
@ -319,7 +334,8 @@ static char *get_config_path(void) {
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) {
wlr_log(WLR_ERROR, "Unable to find a config file!");
return false;
@ -338,7 +354,7 @@ static bool load_config(const char *path, struct sway_config *config) {
return false;
}
bool config_load_success = read_config(f, config);
bool config_load_success = read_config(f, config, swaynag);
fclose(f);
if (!config_load_success) {
@ -348,7 +364,7 @@ static bool load_config(const char *path, struct sway_config *config) {
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;
if (file != NULL) {
path = strdup(file);
@ -363,10 +379,17 @@ bool load_main_config(const char *file, bool is_active) {
}
config_defaults(config);
config->validating = validating;
if (is_active) {
wlr_log(WLR_DEBUG, "Performing configuration file reload");
config->reloading = 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();
}
@ -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) {
for (int i = 0; i < config->output_configs->length; i++) {
apply_output_config_to_outputs(config->output_configs->items[i]);
}
config->reloading = false;
if (config->swaynag_config_errors.pid > 0) {
swaynag_show(&config->swaynag_config_errors);
}
}
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,
struct sway_config *config) {
struct sway_config *config, struct swaynag_instance *swaynag) {
// save parent config
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);
int index = config->config_chain->length - 1;
if (!load_config(real_path, config)) {
if (!load_config(real_path, config, swaynag)) {
free(real_path);
config->current_config_path = parent_config;
list_del(config->config_chain, index);
@ -497,7 +524,8 @@ static bool load_include_config(const char *path, const char *parent_dir,
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 *parent_path = strdup(config->current_config_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;
size_t 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);
wordfree(&p);
@ -575,7 +603,8 @@ static char *expand_line(const char *block, const char *line, bool add_brace) {
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;
char *this_config = NULL;
size_t config_size = 0;
@ -665,6 +694,11 @@ bool read_config(FILE *file, struct sway_config *config) {
case CMD_INVALID:
wlr_log(WLR_ERROR, "Error on line %i '%s': %s (%s)", line_number,
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;
break;

View file

@ -22,6 +22,7 @@
#include "sway/debug.h"
#include "sway/desktop/transaction.h"
#include "sway/server.h"
#include "sway/swaynag.h"
#include "sway/tree/layout.h"
#include "sway/ipc-server.h"
#include "ipc-client.h"
@ -416,11 +417,12 @@ int main(int argc, char **argv) {
log_env();
if (validate) {
bool valid = load_main_config(config_path, false);
bool valid = load_main_config(config_path, false, true);
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);
}
@ -430,7 +432,6 @@ int main(int argc, char **argv) {
security_sanity_check();
setenv("WAYLAND_DISPLAY", server.socket, true);
if (!terminate_request) {
if (!server_start_backend(&server)) {
sway_terminate(EXIT_FAILURE);
@ -452,6 +453,10 @@ int main(int argc, char **argv) {
}
transaction_commit_dirty();
if (config->swaynag_config_errors.pid > 0) {
swaynag_show(&config->swaynag_config_errors);
}
if (!terminate_request) {
server_run(&server);
}

View file

@ -9,6 +9,7 @@ sway_sources = files(
'ipc-server.c',
'scratchpad.c',
'security.c',
'swaynag.c',
'desktop/desktop.c',
'desktop/idle_inhibit_v1.c',
@ -78,6 +79,7 @@ sway_sources = files(
'commands/split.c',
'commands/sticky.c',
'commands/swaybg_command.c',
'commands/swaynag_command.c',
'commands/swap.c',
'commands/title_format.c',
'commands/unmark.c',

View file

@ -59,6 +59,13 @@ The following commands may only be used in the configuration file.
Executes custom background _command_. Default is _swaybg_. Refer to
*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.
They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).

94
sway/swaynag.c Normal file
View 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]);
}
}