From 98aa59fdda5fcc9a589e93f7c6ef40d3eaee3972 Mon Sep 17 00:00:00 2001 From: Zandr Martin Date: Sat, 30 Jul 2016 18:50:13 -0500 Subject: [PATCH] implement solid color rendering for swaybg --- common/CMakeLists.txt | 2 + common/util.c | 13 +++ include/bar/config.h | 6 +- include/config.h | 2 +- include/util.h | 6 ++ sway/commands.c | 75 ++++++++------- sway/sway.5.txt | 4 + swaybar/config.c | 13 --- swaybar/status_line.c | 1 + swaybg/main.c | 216 +++++++++++++++++++++++------------------- 10 files changed, 189 insertions(+), 149 deletions(-) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 9c2c0a99..3d6e0fb9 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -12,6 +12,8 @@ add_library(sway-common STATIC stringop.c ) +target_link_libraries(sway-common m) + if(Backtrace_FOUND) set_target_properties(sway-common PROPERTIES diff --git a/common/util.c b/common/util.c index 31a75a9b..86120769 100644 --- a/common/util.c +++ b/common/util.c @@ -97,3 +97,16 @@ pid_t get_parent_pid(pid_t child) { return -1; } + +uint32_t parse_color(const char *color) { + int len = strlen(color); + if (color[0] != '#' || (len != 7 && len != 9)) { + sway_log(L_DEBUG, "Invalid color %s, defaulting to color 0xFFFFFFFF", color); + return 0xFFFFFFFF; + } + uint32_t res = (uint32_t)strtol(color + 1, NULL, 16); + if (strlen(color) == 7) { + res = (res << 8) | 0xFF; + } + return res; +} diff --git a/include/bar/config.h b/include/bar/config.h index c957caa7..934116ca 100644 --- a/include/bar/config.h +++ b/include/bar/config.h @@ -5,6 +5,7 @@ #include #include "list.h" +#include "util.h" /** * Colors for a box with background, border and text colors. @@ -47,11 +48,6 @@ struct config { } colors; }; -/** - * Parse colors defined as hex string to uint32_t. - */ -uint32_t parse_color(const char *color); - /** * Parse position top|bottom|left|right. */ diff --git a/include/config.h b/include/config.h index 5e1c123e..56deaf01 100644 --- a/include/config.h +++ b/include/config.h @@ -81,7 +81,7 @@ struct output_config { int enabled; int width, height; int x, y; - int scale; + int scale; char *background; char *background_option; }; diff --git a/include/util.h b/include/util.h index 6f21bff0..e33a08f7 100644 --- a/include/util.h +++ b/include/util.h @@ -44,4 +44,10 @@ int get_modifier_names(const char **names, uint32_t modifier_masks); */ pid_t get_parent_pid(pid_t pid); +/** + * Given a string that represents an RGB(A) color, return a uint32_t + * version of the color. + */ +uint32_t parse_color(const char *color); + #endif diff --git a/sway/commands.c b/sway/commands.c index 053b5792..7247a407 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -1651,47 +1651,52 @@ static struct cmd_results *cmd_output(int argc, char **argv) { } else if (strcasecmp(command, "background") == 0 || strcasecmp(command, "bg") == 0) { wordexp_t p; if (++i >= argc) { - return cmd_results_new(CMD_INVALID, "output", "Missing background file."); + return cmd_results_new(CMD_INVALID, "output", "Missing background file or color specification."); } if (i + 1 >= argc) { - return cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode."); + return cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode or `solid_color`."); } - char *src = join_args(argv + i, argc - i - 1); - char *mode = argv[argc - 1]; - if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) { - return cmd_results_new(CMD_INVALID, "output", "Invalid syntax (%s)", src); - } - free(src); - src = p.we_wordv[0]; - if (config->reading && *src != '/') { - char *conf = strdup(config->current_config); - char *conf_path = dirname(conf); - src = malloc(strlen(conf_path) + strlen(src) + 2); - sprintf(src, "%s/%s", conf_path, p.we_wordv[0]); - free(conf); - } - if (access(src, F_OK) == -1) { - return cmd_results_new(CMD_INVALID, "output", "Background file unreadable (%s)", src); - } - for (char *m = mode; *m; ++m) *m = tolower(*m); - // Check mode - bool valid = false; - size_t j; - for (j = 0; j < sizeof(bg_options) / sizeof(char *); ++j) { - if (strcasecmp(mode, bg_options[j]) == 0) { - valid = true; - break; + if (strcasecmp(argv[argc - 1], "solid_color") == 0) { + output->background = strdup(argv[argc - 2]); + output->background_option = strdup("solid_color"); + } else { + char *src = join_args(argv + i, argc - i - 1); + char *mode = argv[argc - 1]; + if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) { + return cmd_results_new(CMD_INVALID, "output", "Invalid syntax (%s)", src); } - } - if (!valid) { - return cmd_results_new(CMD_INVALID, "output", "Invalid background scaling mode."); - } - output->background = strdup(src); - output->background_option = strdup(mode); - if (src != p.we_wordv[0]) { free(src); + src = p.we_wordv[0]; + if (config->reading && *src != '/') { + char *conf = strdup(config->current_config); + char *conf_path = dirname(conf); + src = malloc(strlen(conf_path) + strlen(src) + 2); + sprintf(src, "%s/%s", conf_path, p.we_wordv[0]); + free(conf); + } + if (access(src, F_OK) == -1) { + return cmd_results_new(CMD_INVALID, "output", "Background file unreadable (%s)", src); + } + for (char *m = mode; *m; ++m) *m = tolower(*m); + // Check mode + bool valid = false; + size_t j; + for (j = 0; j < sizeof(bg_options) / sizeof(char *); ++j) { + if (strcasecmp(mode, bg_options[j]) == 0) { + valid = true; + break; + } + } + if (!valid) { + return cmd_results_new(CMD_INVALID, "output", "Invalid background scaling mode."); + } + output->background = strdup(src); + output->background_option = strdup(mode); + if (src != p.we_wordv[0]) { + free(src); + } + wordfree(&p); } - wordfree(&p); } } diff --git a/sway/sway.5.txt b/sway/sway.5.txt index 446995d5..787253a0 100644 --- a/sway/sway.5.txt +++ b/sway/sway.5.txt @@ -308,6 +308,10 @@ The default colors are: Sets the wallpaper for the given output to the specified file, using the given scaling mode (one of "stretch", "fill", "fit", "center", "tile"). +**output** solid_color:: + Sets the background of the given output to the specified color. _color_ should + be specified as an _#rrggbb_ (no alpha) color. + **output** disable:: Disables the specified output. diff --git a/swaybar/config.c b/swaybar/config.c index f3a3e716..b5dca668 100644 --- a/swaybar/config.c +++ b/swaybar/config.c @@ -5,19 +5,6 @@ #include "log.h" #include "bar/config.h" -uint32_t parse_color(const char *color) { - if (color[0] != '#') { - sway_log(L_DEBUG, "Invalid color %s, defaulting to color 0xFFFFFFFF", color); - return 0xFFFFFFFF; - } - char *end; - uint32_t res = (uint32_t)strtol(color + 1, &end, 16); - if (strlen(color) == 7) { - res = (res << 8) | 0xFF; - } - return res; -} - uint32_t parse_position(const char *position) { if (strcmp("top", position) == 0) { return DESKTOP_SHELL_PANEL_POSITION_TOP; diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 49a8363a..33a8908f 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -6,6 +6,7 @@ #include "log.h" #include "bar/config.h" #include "bar/status_line.h" +#include "util.h" #define I3JSON_MAXDEPTH 4 #define I3JSON_UNKNOWN 0 diff --git a/swaybg/main.c b/swaybg/main.c index 4e0cc4b3..b23b8027 100644 --- a/swaybg/main.c +++ b/swaybg/main.c @@ -1,6 +1,8 @@ #include "wayland-desktop-shell-client-protocol.h" +#include #include #include +#include #include #include #include @@ -9,6 +11,7 @@ #include "client/cairo.h" #include "log.h" #include "list.h" +#include "util.h" list_t *surfaces; struct registry *registry; @@ -32,6 +35,23 @@ void sway_terminate(int exit_code) { exit(exit_code); } +bool is_valid_color(const char *color) { + int len = strlen(color); + if (len != 7 || color[0] != '#') { + sway_log(L_ERROR, "%s is not a valid color for swaybg. Color should be specified as #rrggbb (no alpha).", color); + return false; + } + + int i; + for (i = 1; i < len; ++i) { + if (!isxdigit(color[i])) { + return false; + } + } + + return true; +} + int main(int argc, const char **argv) { init_log(L_INFO); surfaces = create_list(); @@ -57,112 +77,118 @@ int main(int argc, const char **argv) { window_make_shell(window); list_add(surfaces, window); + if (strcmp(argv[3], "solid_color") == 0 && is_valid_color(argv[2])) { + cairo_set_source_u32(window->cairo, parse_color(argv[2])); + cairo_paint(window->cairo); + window_render(window); + } else { #ifdef WITH_GDK_PIXBUF - GError *err = NULL; - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(argv[2], &err); - if (!pixbuf) { - sway_abort("Failed to load background image."); - } - cairo_surface_t *image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); - g_object_unref(pixbuf); + GError *err = NULL; + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(argv[2], &err); + if (!pixbuf) { + sway_abort("Failed to load background image."); + } + cairo_surface_t *image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); + g_object_unref(pixbuf); #else - cairo_surface_t *image = cairo_image_surface_create_from_png(argv[2]); + cairo_surface_t *image = cairo_image_surface_create_from_png(argv[2]); #endif //WITH_GDK_PIXBUF - if (!image) { - sway_abort("Failed to read background image."); - } - double width = cairo_image_surface_get_width(image); - double height = cairo_image_surface_get_height(image); - - const char *scaling_mode_str = argv[3]; - enum scaling_mode scaling_mode = SCALING_MODE_STRETCH; - if (strcmp(scaling_mode_str, "stretch") == 0) { - scaling_mode = SCALING_MODE_STRETCH; - } else if (strcmp(scaling_mode_str, "fill") == 0) { - scaling_mode = SCALING_MODE_FILL; - } else if (strcmp(scaling_mode_str, "fit") == 0) { - scaling_mode = SCALING_MODE_FIT; - } else if (strcmp(scaling_mode_str, "center") == 0) { - scaling_mode = SCALING_MODE_CENTER; - } else if (strcmp(scaling_mode_str, "tile") == 0) { - scaling_mode = SCALING_MODE_TILE; - } else { - sway_abort("Unsupported scaling mode: %s", scaling_mode_str); - } + if (!image) { + sway_abort("Failed to read background image."); + } + double width = cairo_image_surface_get_width(image); + double height = cairo_image_surface_get_height(image); + + const char *scaling_mode_str = argv[3]; + enum scaling_mode scaling_mode = SCALING_MODE_STRETCH; + if (strcmp(scaling_mode_str, "stretch") == 0) { + scaling_mode = SCALING_MODE_STRETCH; + } else if (strcmp(scaling_mode_str, "fill") == 0) { + scaling_mode = SCALING_MODE_FILL; + } else if (strcmp(scaling_mode_str, "fit") == 0) { + scaling_mode = SCALING_MODE_FIT; + } else if (strcmp(scaling_mode_str, "center") == 0) { + scaling_mode = SCALING_MODE_CENTER; + } else if (strcmp(scaling_mode_str, "tile") == 0) { + scaling_mode = SCALING_MODE_TILE; + } else { + sway_abort("Unsupported scaling mode: %s", scaling_mode_str); + } - for (i = 0; i < surfaces->length; ++i) { - struct window *window = surfaces->items[i]; - if (window_prerender(window) && window->cairo) { - switch (scaling_mode) { - case SCALING_MODE_STRETCH: - cairo_scale(window->cairo, - (double) window->width / width, - (double) window->height / height); - cairo_set_source_surface(window->cairo, image, 0, 0); - break; - case SCALING_MODE_FILL: - { - double window_ratio = (double) window->width / window->height; - double bg_ratio = width / height; - - if (window_ratio > bg_ratio) { - double scale = (double) window->width / width; - cairo_scale(window->cairo, scale, scale); - cairo_set_source_surface(window->cairo, image, - 0, - (double) window->height/2 / scale - height/2); - } else { - double scale = (double) window->height / height; - cairo_scale(window->cairo, scale, scale); - cairo_set_source_surface(window->cairo, image, - (double) window->width/2 / scale - width/2, - 0); + for (i = 0; i < surfaces->length; ++i) { + struct window *window = surfaces->items[i]; + if (window_prerender(window) && window->cairo) { + switch (scaling_mode) { + case SCALING_MODE_STRETCH: + cairo_scale(window->cairo, + (double) window->width / width, + (double) window->height / height); + cairo_set_source_surface(window->cairo, image, 0, 0); + break; + case SCALING_MODE_FILL: + { + double window_ratio = (double) window->width / window->height; + double bg_ratio = width / height; + + if (window_ratio > bg_ratio) { + double scale = (double) window->width / width; + cairo_scale(window->cairo, scale, scale); + cairo_set_source_surface(window->cairo, image, + 0, + (double) window->height/2 / scale - height/2); + } else { + double scale = (double) window->height / height; + cairo_scale(window->cairo, scale, scale); + cairo_set_source_surface(window->cairo, image, + (double) window->width/2 / scale - width/2, + 0); + } + break; } - break; - } - case SCALING_MODE_FIT: - { - double window_ratio = (double) window->width / window->height; - double bg_ratio = width / height; - - if (window_ratio > bg_ratio) { - double scale = (double) window->height / height; - cairo_scale(window->cairo, scale, scale); - cairo_set_source_surface(window->cairo, image, - (double) window->width/2 / scale - width/2, - 0); - } else { - double scale = (double) window->width / width; - cairo_scale(window->cairo, scale, scale); + case SCALING_MODE_FIT: + { + double window_ratio = (double) window->width / window->height; + double bg_ratio = width / height; + + if (window_ratio > bg_ratio) { + double scale = (double) window->height / height; + cairo_scale(window->cairo, scale, scale); + cairo_set_source_surface(window->cairo, image, + (double) window->width/2 / scale - width/2, + 0); + } else { + double scale = (double) window->width / width; + cairo_scale(window->cairo, scale, scale); + cairo_set_source_surface(window->cairo, image, + 0, + (double) window->height/2 / scale - height/2); + } + break; + } + case SCALING_MODE_CENTER: cairo_set_source_surface(window->cairo, image, - 0, - (double) window->height/2 / scale - height/2); + (double) window->width/2 - width/2, + (double) window->height/2 - height/2); + break; + case SCALING_MODE_TILE: + { + cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image); + cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); + cairo_set_source(window->cairo, pattern); + break; + } + default: + sway_abort("Scaling mode '%s' not implemented yet!", scaling_mode_str); } - break; - } - case SCALING_MODE_CENTER: - cairo_set_source_surface(window->cairo, image, - (double) window->width/2 - width/2, - (double) window->height/2 - height/2); - break; - case SCALING_MODE_TILE: - { - cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image); - cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); - cairo_set_source(window->cairo, pattern); - break; - } - default: - sway_abort("Scaling mode '%s' not implemented yet!", scaling_mode_str); - } - cairo_paint(window->cairo); + cairo_paint(window->cairo); - window_render(window); + window_render(window); + } } - } - cairo_surface_destroy(image); + cairo_surface_destroy(image); + } while (wl_display_dispatch(registry->display) != -1);