diff --git a/include/sway/config.h b/include/sway/config.h index 632aca143..c2eaea1bc 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -151,6 +151,7 @@ struct output_config { char *background; char *background_option; + char *background_fallback; enum config_dpms dpms_state; }; diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c index 4ed56c2ac..e45b571e8 100644 --- a/sway/commands/output/background.c +++ b/sway/commands/output/background.c @@ -6,6 +6,7 @@ #include #include "sway/commands.h" #include "sway/config.h" +#include "sway/swaynag.h" #include "log.h" #include "stringop.h" @@ -36,6 +37,7 @@ struct cmd_results *output_cmd_background(int argc, char **argv) { output->background = calloc(1, strlen(argv[0]) + 3); snprintf(output->background, strlen(argv[0]) + 3, "\"%s\"", argv[0]); output->background_option = strdup("solid_color"); + output->background_fallback = NULL; argc -= 2; argv += 2; } else { bool valid = false; @@ -104,16 +106,35 @@ struct cmd_results *output_cmd_background(int argc, char **argv) { free(conf); } - if (access(src, F_OK) == -1) { - struct cmd_results *cmd_res = cmd_results_new(CMD_FAILURE, "output", - "Unable to access background file '%s': %s", src, strerror(errno)); + bool can_access = access(src, F_OK) != -1; + if (!can_access) { + wlr_log(WLR_ERROR, "Unable to access background file '%s': %s", + src, strerror(errno)); + if (!config->validating) { + swaynag_log(config->swaynag_command, + &config->swaynag_config_errors, + "Unable to access background file '%s'", src); + } free(src); - return cmd_res; + } else { + output->background = src; + output->background_option = strdup(mode); } - - output->background = src; - output->background_option = strdup(mode); argc -= j + 1; argv += j + 1; + + output->background_fallback = NULL; + if (argc && *argv[0] == '#') { + output->background_fallback = calloc(1, strlen(argv[0]) + 3); + snprintf(output->background_fallback, strlen(argv[0]) + 3, + "\"%s\"", argv[0]); + argc--; argv++; + + if (!can_access) { + output->background = output->background_fallback; + output->background_option = strdup("solid_color"); + output->background_fallback = NULL; + } + } } config->handler_context.leftovers.argc = argc; diff --git a/sway/config/output.c b/sway/config/output.c index 504c48c66..1d8cb3efa 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -77,6 +77,10 @@ void merge_output_config(struct output_config *dst, struct output_config *src) { free(dst->background_option); dst->background_option = strdup(src->background_option); } + if (src->background_fallback) { + free(dst->background_fallback); + dst->background_fallback = strdup(src->background_fallback); + } if (src->dpms_state != 0) { dst->dpms_state = src->dpms_state; } @@ -226,17 +230,19 @@ void apply_output_config(struct output_config *oc, struct sway_container *output wlr_log(WLR_DEBUG, "Setting background for output %d to %s", output_i, oc->background); - size_t len = snprintf(NULL, 0, "%s %d %s %s", + size_t len = snprintf(NULL, 0, "%s %d %s %s %s", config->swaybg_command ? config->swaybg_command : "swaybg", - output_i, oc->background, oc->background_option); + output_i, oc->background, oc->background_option, + oc->background_fallback ? oc->background_fallback : ""); char *command = malloc(len + 1); if (!command) { wlr_log(WLR_DEBUG, "Unable to allocate swaybg command"); return; } - snprintf(command, len + 1, "%s %d %s %s", + snprintf(command, len + 1, "%s %d %s %s %s", config->swaybg_command ? config->swaybg_command : "swaybg", - output_i, oc->background, oc->background_option); + output_i, oc->background, oc->background_option, + oc->background_fallback ? oc->background_fallback : ""); wlr_log(WLR_DEBUG, "-> %s", command); char *const cmd[] = { "sh", "-c", command, NULL }; diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 73a01152e..31ab281ba 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -489,9 +489,13 @@ The default colors are: setting an integral scale factor and adjusting the font size of your applications to taste. -*output* background|bg +*output* background|bg [] Sets the wallpaper for the given output to the specified file, using the - given scaling mode (one of "stretch", "fill", "fit", "center", "tile"). + given scaling mode (one of "stretch", "fill", "fit", "center", "tile"). If + the specified file cannot be accessed or if the image does fill the entire + output, a fallback color may be provided to cover the rest of the output. + __fallback\_color__ should be specified as _#RRGGBB_. Alpha is not + supported. **output** background|bg solid\_color Sets the background of the given output to the specified color. _color_ diff --git a/swaybg/main.c b/swaybg/main.c index f8e7e7efe..5b0d04587 100644 --- a/swaybg/main.c +++ b/swaybg/main.c @@ -17,6 +17,7 @@ struct swaybg_args { int output_idx; const char *path; enum background_mode mode; + const char *fallback; }; struct swaybg_context { @@ -76,6 +77,10 @@ static void render_frame(struct swaybg_state *state) { cairo_set_source_u32(cairo, state->context.color); cairo_paint(cairo); } else { + if (state->args->fallback && state->context.color) { + cairo_set_source_u32(cairo, state->context.color); + cairo_paint(cairo); + } render_background_image(cairo, state->context.image, state->args->mode, buffer_width, buffer_height); } @@ -91,6 +96,9 @@ static bool prepare_context(struct swaybg_state *state) { state->context.color = parse_color(state->args->path); return is_valid_color(state->args->path); } + if (state->args->fallback && is_valid_color(state->args->fallback)) { + state->context.color = parse_color(state->args->fallback); + } if (!(state->context.image = load_background_image(state->args->path))) { return false; } @@ -190,7 +198,7 @@ int main(int argc, const char **argv) { state.args = &args; wlr_log_init(WLR_DEBUG, NULL); - if (argc != 4) { + if (argc < 4 || argc > 5) { wlr_log(WLR_ERROR, "Do not run this program manually. " "See man 5 sway and look for output options."); return 1; @@ -202,6 +210,9 @@ int main(int argc, const char **argv) { if (args.mode == BACKGROUND_MODE_INVALID) { return 1; } + + args.fallback = argc == 5 ? argv[4] : NULL; + if (!prepare_context(&state)) { return 1; }