mirror of
https://github.com/swaywm/sway.git
synced 2024-12-29 16:36:26 +01:00
9ea99a5d36
render_background_image alters the scale that cairo uses. Depending on the image mode, resolution, and image size, this may cause the surface to be rendered increasingly smaller. By calling cairo_save and cairo_restore, any changes to the cairo settings by the function are not kept as a side effect. The surface that swaybg uses is also now cleared before rendering a frame. This is needed to avoid artifacts on resolution or scale changes with certain combinations of image modes, resolutions, and image sizes. This was also part of the increasingly smaller background visual since it made it so it was not obvious the region being rendered to was smaller and caused an increasing number of smaller images to be appear for each hotplug.
121 lines
3.7 KiB
C
121 lines
3.7 KiB
C
#include <assert.h>
|
|
#include <stdbool.h>
|
|
#include <wlr/util/log.h>
|
|
#include "background-image.h"
|
|
#include "cairo.h"
|
|
|
|
enum background_mode parse_background_mode(const char *mode) {
|
|
if (strcmp(mode, "stretch") == 0) {
|
|
return BACKGROUND_MODE_STRETCH;
|
|
} else if (strcmp(mode, "fill") == 0) {
|
|
return BACKGROUND_MODE_FILL;
|
|
} else if (strcmp(mode, "fit") == 0) {
|
|
return BACKGROUND_MODE_FIT;
|
|
} else if (strcmp(mode, "center") == 0) {
|
|
return BACKGROUND_MODE_CENTER;
|
|
} else if (strcmp(mode, "tile") == 0) {
|
|
return BACKGROUND_MODE_TILE;
|
|
} else if (strcmp(mode, "solid_color") == 0) {
|
|
return BACKGROUND_MODE_SOLID_COLOR;
|
|
}
|
|
wlr_log(WLR_ERROR, "Unsupported background mode: %s", mode);
|
|
return BACKGROUND_MODE_INVALID;
|
|
}
|
|
|
|
cairo_surface_t *load_background_image(const char *path) {
|
|
cairo_surface_t *image;
|
|
#ifdef HAVE_GDK_PIXBUF
|
|
GError *err = NULL;
|
|
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &err);
|
|
if (!pixbuf) {
|
|
wlr_log(WLR_ERROR, "Failed to load background image (%s).",
|
|
err->message);
|
|
return false;
|
|
}
|
|
image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf);
|
|
g_object_unref(pixbuf);
|
|
#else
|
|
image = cairo_image_surface_create_from_png(path);
|
|
#endif //HAVE_GDK_PIXBUF
|
|
if (!image) {
|
|
wlr_log(WLR_ERROR, "Failed to read background image.");
|
|
return NULL;
|
|
}
|
|
if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) {
|
|
wlr_log(WLR_ERROR, "Failed to read background image: %s."
|
|
#ifndef HAVE_GDK_PIXBUF
|
|
"\nSway was compiled without gdk_pixbuf support, so only"
|
|
"\nPNG images can be loaded. This is the likely cause."
|
|
#endif //HAVE_GDK_PIXBUF
|
|
, cairo_status_to_string(cairo_surface_status(image)));
|
|
return NULL;
|
|
}
|
|
return image;
|
|
}
|
|
|
|
void render_background_image(cairo_t *cairo, cairo_surface_t *image,
|
|
enum background_mode mode, int buffer_width, int buffer_height) {
|
|
double width = cairo_image_surface_get_width(image);
|
|
double height = cairo_image_surface_get_height(image);
|
|
|
|
cairo_save(cairo);
|
|
switch (mode) {
|
|
case BACKGROUND_MODE_STRETCH:
|
|
cairo_scale(cairo,
|
|
(double)buffer_width / width,
|
|
(double)buffer_height / height);
|
|
cairo_set_source_surface(cairo, image, 0, 0);
|
|
break;
|
|
case BACKGROUND_MODE_FILL: {
|
|
double window_ratio = (double)buffer_width / buffer_height;
|
|
double bg_ratio = width / height;
|
|
|
|
if (window_ratio > bg_ratio) {
|
|
double scale = (double)buffer_width / width;
|
|
cairo_scale(cairo, scale, scale);
|
|
cairo_set_source_surface(cairo, image,
|
|
0, (double)buffer_height / 2 / scale - height / 2);
|
|
} else {
|
|
double scale = (double)buffer_height / height;
|
|
cairo_scale(cairo, scale, scale);
|
|
cairo_set_source_surface(cairo, image,
|
|
(double)buffer_width / 2 / scale - width / 2, 0);
|
|
}
|
|
break;
|
|
}
|
|
case BACKGROUND_MODE_FIT: {
|
|
double window_ratio = (double)buffer_width / buffer_height;
|
|
double bg_ratio = width / height;
|
|
|
|
if (window_ratio > bg_ratio) {
|
|
double scale = (double)buffer_height / height;
|
|
cairo_scale(cairo, scale, scale);
|
|
cairo_set_source_surface(cairo, image,
|
|
(double)buffer_width / 2 / scale - width / 2, 0);
|
|
} else {
|
|
double scale = (double)buffer_width / width;
|
|
cairo_scale(cairo, scale, scale);
|
|
cairo_set_source_surface(cairo, image,
|
|
0, (double)buffer_height / 2 / scale - height / 2);
|
|
}
|
|
break;
|
|
}
|
|
case BACKGROUND_MODE_CENTER:
|
|
cairo_set_source_surface(cairo, image,
|
|
(double)buffer_width / 2 - width / 2,
|
|
(double)buffer_height / 2 - height / 2);
|
|
break;
|
|
case BACKGROUND_MODE_TILE: {
|
|
cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image);
|
|
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
|
|
cairo_set_source(cairo, pattern);
|
|
break;
|
|
}
|
|
case BACKGROUND_MODE_SOLID_COLOR:
|
|
case BACKGROUND_MODE_INVALID:
|
|
assert(0);
|
|
break;
|
|
}
|
|
cairo_paint(cairo);
|
|
cairo_restore(cairo);
|
|
}
|