implement solid color rendering for swaybg

master
Zandr Martin 9 years ago
parent 2e4ece65da
commit 98aa59fdda
No known key found for this signature in database
GPG Key ID: AA2BB8EF77F7BBDC

@ -12,6 +12,8 @@ add_library(sway-common STATIC
stringop.c stringop.c
) )
target_link_libraries(sway-common m)
if(Backtrace_FOUND) if(Backtrace_FOUND)
set_target_properties(sway-common set_target_properties(sway-common
PROPERTIES PROPERTIES

@ -97,3 +97,16 @@ pid_t get_parent_pid(pid_t child) {
return -1; 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;
}

@ -5,6 +5,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "list.h" #include "list.h"
#include "util.h"
/** /**
* Colors for a box with background, border and text colors. * Colors for a box with background, border and text colors.
@ -47,11 +48,6 @@ struct config {
} colors; } colors;
}; };
/**
* Parse colors defined as hex string to uint32_t.
*/
uint32_t parse_color(const char *color);
/** /**
* Parse position top|bottom|left|right. * Parse position top|bottom|left|right.
*/ */

@ -81,7 +81,7 @@ struct output_config {
int enabled; int enabled;
int width, height; int width, height;
int x, y; int x, y;
int scale; int scale;
char *background; char *background;
char *background_option; char *background_option;
}; };

@ -44,4 +44,10 @@ int get_modifier_names(const char **names, uint32_t modifier_masks);
*/ */
pid_t get_parent_pid(pid_t pid); 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 #endif

@ -1651,47 +1651,52 @@ static struct cmd_results *cmd_output(int argc, char **argv) {
} else if (strcasecmp(command, "background") == 0 || strcasecmp(command, "bg") == 0) { } else if (strcasecmp(command, "background") == 0 || strcasecmp(command, "bg") == 0) {
wordexp_t p; wordexp_t p;
if (++i >= argc) { 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) { 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); if (strcasecmp(argv[argc - 1], "solid_color") == 0) {
char *mode = argv[argc - 1]; output->background = strdup(argv[argc - 2]);
if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) { output->background_option = strdup("solid_color");
return cmd_results_new(CMD_INVALID, "output", "Invalid syntax (%s)", src); } else {
} char *src = join_args(argv + i, argc - i - 1);
free(src); char *mode = argv[argc - 1];
src = p.we_wordv[0]; if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) {
if (config->reading && *src != '/') { return cmd_results_new(CMD_INVALID, "output", "Invalid syntax (%s)", 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); 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);
} }
} }

@ -308,6 +308,10 @@ The default colors are:
Sets the wallpaper for the given output to the specified file, using the given Sets the wallpaper for the given output to the specified file, using the given
scaling mode (one of "stretch", "fill", "fit", "center", "tile"). scaling mode (one of "stretch", "fill", "fit", "center", "tile").
**output** <name> <background|bg> <color> solid_color::
Sets the background of the given output to the specified color. _color_ should
be specified as an _#rrggbb_ (no alpha) color.
**output** <name> disable:: **output** <name> disable::
Disables the specified output. Disables the specified output.

@ -5,19 +5,6 @@
#include "log.h" #include "log.h"
#include "bar/config.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) { uint32_t parse_position(const char *position) {
if (strcmp("top", position) == 0) { if (strcmp("top", position) == 0) {
return DESKTOP_SHELL_PANEL_POSITION_TOP; return DESKTOP_SHELL_PANEL_POSITION_TOP;

@ -6,6 +6,7 @@
#include "log.h" #include "log.h"
#include "bar/config.h" #include "bar/config.h"
#include "bar/status_line.h" #include "bar/status_line.h"
#include "util.h"
#define I3JSON_MAXDEPTH 4 #define I3JSON_MAXDEPTH 4
#define I3JSON_UNKNOWN 0 #define I3JSON_UNKNOWN 0

@ -1,6 +1,8 @@
#include "wayland-desktop-shell-client-protocol.h" #include "wayland-desktop-shell-client-protocol.h"
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <time.h> #include <time.h>
#include <string.h> #include <string.h>
@ -9,6 +11,7 @@
#include "client/cairo.h" #include "client/cairo.h"
#include "log.h" #include "log.h"
#include "list.h" #include "list.h"
#include "util.h"
list_t *surfaces; list_t *surfaces;
struct registry *registry; struct registry *registry;
@ -32,6 +35,23 @@ void sway_terminate(int exit_code) {
exit(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) { int main(int argc, const char **argv) {
init_log(L_INFO); init_log(L_INFO);
surfaces = create_list(); surfaces = create_list();
@ -57,112 +77,118 @@ int main(int argc, const char **argv) {
window_make_shell(window); window_make_shell(window);
list_add(surfaces, 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 #ifdef WITH_GDK_PIXBUF
GError *err = NULL; GError *err = NULL;
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(argv[2], &err); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(argv[2], &err);
if (!pixbuf) { if (!pixbuf) {
sway_abort("Failed to load background image."); sway_abort("Failed to load background image.");
} }
cairo_surface_t *image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); cairo_surface_t *image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf);
g_object_unref(pixbuf); g_object_unref(pixbuf);
#else #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 #endif //WITH_GDK_PIXBUF
if (!image) { if (!image) {
sway_abort("Failed to read background image."); sway_abort("Failed to read background image.");
} }
double width = cairo_image_surface_get_width(image); double width = cairo_image_surface_get_width(image);
double height = cairo_image_surface_get_height(image); double height = cairo_image_surface_get_height(image);
const char *scaling_mode_str = argv[3]; const char *scaling_mode_str = argv[3];
enum scaling_mode scaling_mode = SCALING_MODE_STRETCH; enum scaling_mode scaling_mode = SCALING_MODE_STRETCH;
if (strcmp(scaling_mode_str, "stretch") == 0) { if (strcmp(scaling_mode_str, "stretch") == 0) {
scaling_mode = SCALING_MODE_STRETCH; scaling_mode = SCALING_MODE_STRETCH;
} else if (strcmp(scaling_mode_str, "fill") == 0) { } else if (strcmp(scaling_mode_str, "fill") == 0) {
scaling_mode = SCALING_MODE_FILL; scaling_mode = SCALING_MODE_FILL;
} else if (strcmp(scaling_mode_str, "fit") == 0) { } else if (strcmp(scaling_mode_str, "fit") == 0) {
scaling_mode = SCALING_MODE_FIT; scaling_mode = SCALING_MODE_FIT;
} else if (strcmp(scaling_mode_str, "center") == 0) { } else if (strcmp(scaling_mode_str, "center") == 0) {
scaling_mode = SCALING_MODE_CENTER; scaling_mode = SCALING_MODE_CENTER;
} else if (strcmp(scaling_mode_str, "tile") == 0) { } else if (strcmp(scaling_mode_str, "tile") == 0) {
scaling_mode = SCALING_MODE_TILE; scaling_mode = SCALING_MODE_TILE;
} else { } else {
sway_abort("Unsupported scaling mode: %s", scaling_mode_str); sway_abort("Unsupported scaling mode: %s", scaling_mode_str);
} }
for (i = 0; i < surfaces->length; ++i) { for (i = 0; i < surfaces->length; ++i) {
struct window *window = surfaces->items[i]; struct window *window = surfaces->items[i];
if (window_prerender(window) && window->cairo) { if (window_prerender(window) && window->cairo) {
switch (scaling_mode) { switch (scaling_mode) {
case SCALING_MODE_STRETCH: case SCALING_MODE_STRETCH:
cairo_scale(window->cairo, cairo_scale(window->cairo,
(double) window->width / width, (double) window->width / width,
(double) window->height / height); (double) window->height / height);
cairo_set_source_surface(window->cairo, image, 0, 0); cairo_set_source_surface(window->cairo, image, 0, 0);
break; break;
case SCALING_MODE_FILL: case SCALING_MODE_FILL:
{ {
double window_ratio = (double) window->width / window->height; double window_ratio = (double) window->width / window->height;
double bg_ratio = width / height; double bg_ratio = width / height;
if (window_ratio > bg_ratio) { if (window_ratio > bg_ratio) {
double scale = (double) window->width / width; double scale = (double) window->width / width;
cairo_scale(window->cairo, scale, scale); cairo_scale(window->cairo, scale, scale);
cairo_set_source_surface(window->cairo, image, cairo_set_source_surface(window->cairo, image,
0, 0,
(double) window->height/2 / scale - height/2); (double) window->height/2 / scale - height/2);
} else { } else {
double scale = (double) window->height / height; double scale = (double) window->height / height;
cairo_scale(window->cairo, scale, scale); cairo_scale(window->cairo, scale, scale);
cairo_set_source_surface(window->cairo, image, cairo_set_source_surface(window->cairo, image,
(double) window->width/2 / scale - width/2, (double) window->width/2 / scale - width/2,
0); 0);
}
break;
} }
break; case SCALING_MODE_FIT:
} {
case SCALING_MODE_FIT: double window_ratio = (double) window->width / window->height;
{ double bg_ratio = width / height;
double window_ratio = (double) window->width / window->height;
double bg_ratio = width / height; if (window_ratio > bg_ratio) {
double scale = (double) window->height / height;
if (window_ratio > bg_ratio) { cairo_scale(window->cairo, scale, scale);
double scale = (double) window->height / height; cairo_set_source_surface(window->cairo, image,
cairo_scale(window->cairo, scale, scale); (double) window->width/2 / scale - width/2,
cairo_set_source_surface(window->cairo, image, 0);
(double) window->width/2 / scale - width/2, } else {
0); double scale = (double) window->width / width;
} else { cairo_scale(window->cairo, scale, scale);
double scale = (double) window->width / width; cairo_set_source_surface(window->cairo, image,
cairo_scale(window->cairo, scale, scale); 0,
(double) window->height/2 / scale - height/2);
}
break;
}
case SCALING_MODE_CENTER:
cairo_set_source_surface(window->cairo, image, cairo_set_source_surface(window->cairo, image,
0, (double) window->width/2 - width/2,
(double) window->height/2 / scale - height/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); while (wl_display_dispatch(registry->display) != -1);

Loading…
Cancel
Save