Commit 007fd523267378b2d6afeda885ba959be180c852 Parent: f87ba5e2a6c5dabfc839335181d94294408e2be7 Author: mcol <mcol@posteo.net> Date: 2020-11-10 23:27:35 +0000 Committer: mcol <mcol@posteo.net> Committed: 2020-11-10 23:27:35 +0000 Allow setting of image as wallpaper, tile wallpaper, and pan it
src/types.h Modified
@@ -1,10 +1,12 @@ #ifndef DESKWM_TYPES_H #define DESKWM_TYPES_H +#include <cairo/cairo.h> #include <stdlib.h> #include <unistd.h> #include <wlr/backend.h> #include <wlr/render/wlr_renderer.h> +#include <wlr/render/wlr_texture.h> #include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_output_layout.h> @@ -71,11 +73,18 @@ struct wl_listener key_listener; }; +struct wallpaper { + struct wlr_texture *texture; + int width, height; +}; + struct desk { struct wl_list link; struct server *server; struct wl_list views; float background[4]; + struct wallpaper *wallpaper; + double panned_x, panned_y; int index; };
src/output.c Modified
@@ -54,6 +54,7 @@ void on_frame(struct wl_listener *listener, void *data) { struct output *output = wl_container_of(listener, output, frame_listener); struct wlr_renderer *renderer = output->server->renderer; + struct desk *desk = output->server->current_desk; struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -65,11 +66,21 @@ int width, height; wlr_output_effective_resolution(output->wlr_output, &width, &height); wlr_renderer_begin(renderer, width, height); - - wlr_renderer_clear(renderer, output->server->current_desk->background); + wlr_renderer_clear(renderer, desk->background); + struct wallpaper *wallpaper = desk->wallpaper; + if (wallpaper != NULL) { + int wh = wallpaper->height; + int ww = wallpaper->width; + for (int x = ((int)desk->panned_x % ww) - ww; x < width; x += ww) { + for (int y = ((int)desk->panned_y % wh) - wh; y < height; y += wh) { + wlr_render_texture(renderer, wallpaper->texture, + output->wlr_output->transform_matrix, x, y, 1.0f); + } + } + } struct view *view; - wl_list_for_each_reverse(view, &output->server->current_desk->views, link) { + wl_list_for_each_reverse(view, &desk->views, link) { struct render_data rdata = { .output = output->wlr_output, .view = view,
src/input.c Modified
@@ -132,6 +132,8 @@ view->x += dx; view->y += dy; } + server->current_desk->panned_x += dx; + server->current_desk->panned_y += dy; break; case CURSOR_MOVE:
src/desk.c Modified
@@ -13,6 +13,7 @@ desk->server = server; wl_list_init(&desk->views); assign_colour("#5D479D", desk->background); + desk->wallpaper = NULL; desk->index = num_desks; num_desks++; }
src/config.c Modified
@@ -1,7 +1,9 @@ +#include <cairo/cairo.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <wordexp.h> +#include <wlr/render/wlr_texture.h> #include <unistd.h> #include "config.h" @@ -10,26 +12,73 @@ void assign_colour(char *hex, float dest[4]) { - switch (strlen(hex)) { - case 6: - case 8: - break; - case 7: - case 9: - if (hex[0] == '#') { - hex++; - break; - } - default: - return; + if (strlen(hex) != 7 || hex[0] != '#') { + wlr_log(WLR_INFO, "Invalid colour: %s. Should be in the form #rrggbb.", hex); + return; } + hex++; char c[2]; for (int i = 0; i < 3; i++) { strncpy(c, &hex[i * 2], 2); dest[i] = (float)strtol(c, NULL, 16) / 255; } - dest[4] = 1; + dest[3] = 1; +} + + +static void load_wallpaper( + struct server *server, struct desk *desk, char *path +) { + cairo_surface_t *image = cairo_image_surface_create_from_png(path); + + if (!image) + goto fail; + if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) + goto fail; + + struct wallpaper *wallpaper = calloc(1, sizeof(struct wallpaper)); + wallpaper->width = cairo_image_surface_get_width(image); + wallpaper->height = cairo_image_surface_get_height(image); + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, wallpaper->width); + + // we copy the image to a second surface to ensure the pixel format is + // compatible with wlr_texture_from_pixels + cairo_surface_t *canvas = cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, wallpaper->width, wallpaper->height); + cairo_t *cr = cairo_create(canvas); + cairo_set_source_surface(cr, image, 0, 0); + cairo_paint(cr); + + wallpaper->texture = wlr_texture_from_pixels( + server->renderer, WL_SHM_FORMAT_ARGB8888, stride, wallpaper->width, + wallpaper->height, cairo_image_surface_get_data(canvas) + ); + desk->wallpaper = wallpaper; + cairo_destroy(cr); + cairo_surface_destroy(image); + cairo_surface_destroy(canvas); + return; + +fail: + wlr_log(WLR_INFO, "Could not load image: %s", path); +} + + +static void set_wallpaper(struct server *server, char *wallpaper) { + struct desk *desk = wl_container_of(server->desks.prev, desk, link); + + // wallpaper is a colour + if (strlen(wallpaper) == 7 && wallpaper[0] == '#') { + assign_colour(wallpaper, desk->background); + return; + } + + // wallpaper is a path to an image + wordexp_t p; + wordexp(wallpaper, &p, WRDE_NOCMD | WRDE_UNDEF); + load_wallpaper(server, desk, p.we_wordv[0]); + wordfree(&p); } @@ -54,7 +103,7 @@ wordexp_t p; wordexp(config, &p, WRDE_NOCMD | WRDE_UNDEF); - if(access(p.we_wordv[0], R_OK) == -1) { + if (access(p.we_wordv[0], R_OK) == -1) { wlr_log(WLR_INFO, "%s not accessible. Using defaults.", p.we_wordv[0]); wordfree(&p); return; @@ -72,8 +121,7 @@ add_desk(server); } else if (!strcasecmp(s, "background")) { if ((s = strtok(NULL, " \t\n\r"))) { - struct desk *desk = wl_container_of(server->desks.prev, desk, link); - assign_colour(s, desk->background); + set_wallpaper(server, s); } } else if (!strcasecmp(s, "modifier")) { }
Makefile Modified
@@ -4,7 +4,8 @@ CFLAGS += -g -I. -DWLR_USE_UNSTABLE -Wall -Wextra -pedantic LDFLAGS += $(shell pkg-config --cflags --libs wlroots) \ $(shell pkg-config --cflags --libs wayland-server) \ - $(shell pkg-config --cflags --libs xkbcommon) + $(shell pkg-config --cflags --libs xkbcommon) \ + $(shell pkg-config --cflags --libs cairo) ${OUT}: xdg-shell-protocol.h xdg-shell-protocol.c ${OBJECTS} @$(CC) -o ${OUT} $(OBJECTS) $(LDFLAGS)