gimp but for windows: a wayland compositor
git clone https://github.com/m-col/wimp
Files | Refs | Readme

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)