aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2018-03-27 15:36:56 -0400
committerDrew DeVault <sir@cmpwn.com>2018-03-28 14:25:19 -0400
commitf018d30fe4e9e35e602d54fbb7edcdfb0443e9ca (patch)
treeb246399ca881f82bfe0bd776dffdd9cf47fd838f
parent632bb948b7ffbb08a6e965dabf88347afd0a1fa8 (diff)
Implement image backgrounds
-rw-r--r--swaybg/main.c114
1 files changed, 112 insertions, 2 deletions
diff --git a/swaybg/main.c b/swaybg/main.c
index 4473869b..29cce251 100644
--- a/swaybg/main.c
+++ b/swaybg/main.c
@@ -26,8 +26,14 @@ struct swaybg_args {
enum scaling_mode mode;
};
+struct swaybg_context {
+ uint32_t color;
+ cairo_surface_t *image;
+};
+
struct swaybg_state {
const struct swaybg_args *args;
+ struct swaybg_context context;
struct wl_display *display;
struct wl_compositor *compositor;
@@ -62,6 +68,71 @@ bool is_valid_color(const char *color) {
return true;
}
+static void render_image(struct swaybg_state *state) {
+ cairo_t *cairo = state->current_buffer->cairo;
+ cairo_surface_t *image = state->context.image;
+ double width = cairo_image_surface_get_width(image);
+ double height = cairo_image_surface_get_height(image);
+ int wwidth = state->width;
+ int wheight = state->height;
+
+ switch (state->args->mode) {
+ case SCALING_MODE_STRETCH:
+ cairo_scale(cairo, (double)wwidth / width, (double)wheight / height);
+ cairo_set_source_surface(cairo, image, 0, 0);
+ break;
+ case SCALING_MODE_FILL: {
+ double window_ratio = (double)wwidth / wheight;
+ double bg_ratio = width / height;
+
+ if (window_ratio > bg_ratio) {
+ double scale = (double)wwidth / width;
+ cairo_scale(cairo, scale, scale);
+ cairo_set_source_surface(cairo, image,
+ 0, (double)wheight / 2 / scale - height / 2);
+ } else {
+ double scale = (double)wheight / height;
+ cairo_scale(cairo, scale, scale);
+ cairo_set_source_surface(cairo, image,
+ (double)wwidth / 2 / scale - width / 2, 0);
+ }
+ break;
+ }
+ case SCALING_MODE_FIT: {
+ double window_ratio = (double)wwidth / wheight;
+ double bg_ratio = width / height;
+
+ if (window_ratio > bg_ratio) {
+ double scale = (double)wheight / height;
+ cairo_scale(cairo, scale, scale);
+ cairo_set_source_surface(cairo, image,
+ (double)wwidth / 2 / scale - width / 2, 0);
+ } else {
+ double scale = (double)wwidth / width;
+ cairo_scale(cairo, scale, scale);
+ cairo_set_source_surface(cairo, image,
+ 0, (double)wheight / 2 / scale - height / 2);
+ }
+ break;
+ }
+ case SCALING_MODE_CENTER:
+ cairo_set_source_surface(cairo, image,
+ (double)wwidth / 2 - width / 2,
+ (double)wheight / 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(cairo, pattern);
+ break;
+ }
+ case SCALING_MODE_SOLID_COLOR:
+ // Should never happen
+ break;
+ }
+ cairo_paint(cairo);
+}
+
static void render_frame(struct swaybg_state *state) {
if (!state->run_display) {
return;
@@ -73,11 +144,11 @@ static void render_frame(struct swaybg_state *state) {
switch (state->args->mode) {
case SCALING_MODE_SOLID_COLOR:
- cairo_set_source_u32(cairo, parse_color(state->args->path));
+ cairo_set_source_u32(cairo, state->context.color);
cairo_paint(cairo);
break;
default:
- exit(1);
+ render_image(state);
break;
}
@@ -86,6 +157,41 @@ static void render_frame(struct swaybg_state *state) {
wl_surface_commit(state->surface);
}
+static bool prepare_context(struct swaybg_state *state) {
+ if (state->args->mode == SCALING_MODE_SOLID_COLOR) {
+ state->context.color = parse_color(state->args->path);
+ return is_valid_color(state->args->path);
+ }
+#ifdef WITH_GDK_PIXBUF
+ GError *err = NULL;
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(state->args->path, &err);
+ if (!pixbuf) {
+ wlr_log(L_ERROR, "Failed to load background image.");
+ return false;
+ }
+ state->context.image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf);
+ g_object_unref(pixbuf);
+#else
+ state->context.image = cairo_image_surface_create_from_png(
+ state->args->path);
+#endif //WITH_GDK_PIXBUF
+ if (!state->context.image) {
+ wlr_log(L_ERROR, "Failed to read background image.");
+ return false;
+ }
+ if (cairo_surface_status(state->context.image) != CAIRO_STATUS_SUCCESS) {
+ wlr_log(L_ERROR, "Failed to read background image: %s."
+#ifndef WITH_GDK_PIXBUF
+ "\nSway was compiled without gdk_pixbuf support, so only"
+ "\nPNG images can be loaded. This is the likely cause."
+#endif //WITH_GDK_PIXBUF
+ , cairo_status_to_string(
+ cairo_surface_status(state->context.image)));
+ return false;
+ }
+ return true;
+}
+
static void layer_surface_configure(void *data,
struct zwlr_layer_surface_v1 *surface,
uint32_t serial, uint32_t width, uint32_t height) {
@@ -217,6 +323,10 @@ int main(int argc, const char **argv) {
wl_surface_commit(state.surface);
wl_display_roundtrip(state.display);
+ if (!prepare_context(&state)) {
+ return 1;
+ }
+
state.run_display = true;
render_frame(&state);
while (wl_display_dispatch(state.display) != -1 && state.run_display) {