commit a96a4eb

uint  ·  2026-02-18 06:07:03 +0000 UTC
parent 76db202
add wallpaper protocol with separate screen buffers support

add wallpaper protocol
> swc just uses a buffer, processing is done on client
removed STB
11 files changed,  +197, -71
+7, -0
 1@@ -97,6 +97,7 @@ PROTO_EXTENSIONS= \
 2 	protocol/server-decoration.xml \
 3 	protocol/swc.xml \
 4 	protocol/swc_snap.xml \
 5+	protocol/swc_wallpaper.xml \
 6 	protocol/wayland-drm.xml \
 7 	${WAYLAND_PROTOCOLS_DATADIR}/stable/xdg-shell/xdg-shell.xml \
 8 	${WAYLAND_PROTOCOLS_DATADIR}/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml \
 9@@ -124,6 +125,7 @@ PROTO_GEN_C= \
10 	protocol/server-decoration-protocol.c \
11 	protocol/swc-protocol.c \
12 	protocol/swc_snap-protocol.c \
13+	protocol/swc_wallpaper-protocol.c \
14 	protocol/wayland-drm-protocol.c \
15 	protocol/xdg-decoration-unstable-v1-protocol.c \
16 	protocol/xdg-shell-protocol.c
17@@ -137,6 +139,8 @@ PROTO_GEN_H= \
18 	protocol/swc-client-protocol.h \
19 	protocol/swc_snap-server-protocol.h \
20 	protocol/swc_snap-client-protocol.h \
21+	protocol/swc_wallpaper-server-protocol.h \
22+	protocol/swc_wallpaper-client-protocol.h \
23 	protocol/wayland-drm-server-protocol.h \
24 	protocol/wayland-drm-client-protocol.h \
25 	protocol/xdg-decoration-unstable-v1-server-protocol.h \
26@@ -213,6 +217,7 @@ SWC_SOURCES= \
27 	protocol/server-decoration-protocol.c \
28 	protocol/swc-protocol.c \
29 	protocol/swc_snap-protocol.c \
30+	protocol/swc_wallpaper-protocol.c \
31 	protocol/wayland-drm-protocol.c \
32 	protocol/xdg-decoration-unstable-v1-protocol.c \
33 	protocol/xdg-shell-protocol.c
34@@ -275,11 +280,13 @@ install: build
35 	install -d ${DESTDIR}${BINDIR}
36 	install -d ${DESTDIR}${LIBDIR}
37 	install -d ${DESTDIR}${INCLUDEDIR}
38+	install -d ${DESTDIR}${DATADIR}/swc
39 	install -d ${DESTDIR}${PKGCONFIGDIR}
40 	install -m 4755 launch/swc-launch ${DESTDIR}${BINDIR}/
41 	install -m 644 libswc/libswc.a ${DESTDIR}${LIBDIR}/
42 	install -m 644 libswc/swc.h ${DESTDIR}${INCLUDEDIR}/
43 	install -m 644 ${PROTO_GEN_H} ${DESTDIR}${INCLUDEDIR}/
44+	install -m 644 protocol/swc.xml protocol/swc_snap.xml protocol/swc_wallpaper.xml ${DESTDIR}${DATADIR}/swc/
45 	install -m 644 swc.pc ${DESTDIR}${PKGCONFIGDIR}/
46 
47 clean:
+37, -8
  1@@ -44,6 +44,7 @@
  2 #include "subsurface.h"
  3 #include "util.h"
  4 #include "view.h"
  5+#include "wallpaper.h"
  6 #include "window.h"
  7 
  8 #include <errno.h>
  9@@ -109,6 +110,7 @@ static struct {
 10 
 11 	bool updating;
 12 	struct wl_global *global;
 13+	bool initialized;
 14 
 15 	/* zoom level (1.0 = normal, >1 = zoomed in, <1 = zoomed out) */
 16 	float zoom;
 17@@ -302,7 +304,7 @@ repaint_view(struct target *target, struct compositor_view *view, pixman_region3
 18 }
 19 
 20 static void
 21-renderer_repaint(struct target *target, pixman_region32_t *damage, pixman_region32_t *base_damage, struct wl_list *views)
 22+renderer_repaint(struct target *target, pixman_region32_t *damage, pixman_region32_t *base_damage, struct wl_list *views, struct screen *screen)
 23 {
 24 	struct compositor_view *view;
 25 	const struct swc_rectangle *target_geom = &target->view->geometry;
 26@@ -314,10 +316,12 @@ renderer_repaint(struct target *target, pixman_region32_t *damage, pixman_region
 27 	wld_set_target_surface(swc.drm->renderer, target->surface);
 28 
 29 	if (pixman_region32_not_empty(base_damage)) {
 30+		struct wld_buffer *background = swc_wallpaper_buffer_for_screen(screen);
 31+
 32 		pixman_region32_translate(base_damage, -target->view->geometry.x, -target->view->geometry.y);
 33 		
 34-		if(wallbuf)
 35-			wld_copy_region(swc.drm->renderer, wallbuf, 0, 0, base_damage);
 36+		if (background)
 37+			wld_copy_region(swc.drm->renderer, background, 0, 0, base_damage);
 38 
 39 		else
 40 			wld_fill_region(swc.drm->renderer, bgcolor, base_damage);
 41@@ -508,6 +512,23 @@ schedule_updates(uint32_t screens)
 42 	compositor.scheduled_updates |= screens;
 43 }
 44 
 45+void
 46+compositor_damage_all(void)
 47+{
 48+	struct screen *screen;
 49+
 50+	if (!compositor.initialized)
 51+		return;
 52+
 53+	wl_list_for_each (screen, &swc.screens, link) {
 54+		pixman_region32_union_rect(&compositor.damage, &compositor.damage,
 55+			screen->base.geometry.x, screen->base.geometry.y,
 56+			screen->base.geometry.width, screen->base.geometry.height);
 57+	}
 58+
 59+	schedule_updates(-1);
 60+}
 61+
 62 static void
 63 overlay_damage_region(int32_t x, int32_t y, uint32_t width, uint32_t height, uint32_t border_width)
 64 {
 65@@ -597,6 +618,7 @@ render_zoomed_to_shm(struct screen *screen, float zoom)
 66 	int32_t cx = screen_x + width / 2;
 67 	int32_t cy = screen_y + height / 2;
 68 	struct compositor_view *view;
 69+	struct wld_buffer *background;
 70 
 71 	struct wld_buffer *buffer = wld_create_buffer(swc.shm->context,
 72 		width, height, WLD_FORMAT_XRGB8888, WLD_FLAG_MAP);
 73@@ -610,8 +632,9 @@ render_zoomed_to_shm(struct screen *screen, float zoom)
 74 
 75 	pixman_region32_t full;
 76 	pixman_region32_init_rect(&full, 0, 0, width, height);
 77-	if (wallbuf)
 78-		wld_copy_region(swc.shm->renderer, wallbuf, 0, 0, &full);
 79+	background = swc_wallpaper_buffer_for_screen(screen);
 80+	if (background)
 81+		wld_copy_region(swc.shm->renderer, background, 0, 0, &full);
 82 	else
 83 		wld_fill_region(swc.shm->renderer, bgcolor, &full);
 84 	pixman_region32_fini(&full);
 85@@ -1327,7 +1350,7 @@ update_screen(struct screen *screen)
 86 		pixman_region32_translate(&damage, geom->x, geom->y);
 87 		pixman_region32_init(&base_damage);
 88 		pixman_region32_subtract(&base_damage, &damage, &compositor.opaque);
 89-		renderer_repaint(target, &damage, &base_damage, &compositor.views);
 90+		renderer_repaint(target, &damage, &base_damage, &compositor.views, screen);
 91 		pixman_region32_fini(&damage);
 92 		pixman_region32_fini(&base_damage);
 93 	}
 94@@ -1508,12 +1531,16 @@ compositor_initialize(void)
 95 	for (keysym = XKB_KEY_XF86Switch_VT_1; keysym <= XKB_KEY_XF86Switch_VT_12; ++keysym)
 96 		swc_add_binding(SWC_BINDING_KEY, SWC_MOD_ANY, keysym, &handle_switch_vt, NULL);
 97 
 98+	compositor.initialized = true;
 99+
100 	return true;
101 }
102 
103 void
104 compositor_finalize(void)
105 {
106+	compositor.initialized = false;
107+
108 	if (compositor.zoom_buffer)
109 		wld_buffer_unreference(compositor.zoom_buffer);
110 	pixman_region32_fini(&compositor.damage);
111@@ -1540,6 +1567,7 @@ compositor_render_to_shm(struct screen *screen)
112 	pixman_region32_t region;
113 	pixman_region32_t damage;
114 	uint32_t caps;
115+	struct wld_buffer *background;
116 
117 	/* create shm buf */
118 	buffer = wld_create_buffer(swc.shm->context, width, height,
119@@ -1559,8 +1587,9 @@ compositor_render_to_shm(struct screen *screen)
120 	pixman_region32_init_rect(&damage, screen->base.geometry.x, screen->base.geometry.y, width, height);
121 
122 	/* background */
123-	if (wallbuf)
124-		wld_copy_region(swc.shm->renderer, wallbuf, 0, 0, &region);
125+	background = swc_wallpaper_buffer_for_screen(screen);
126+	if (background)
127+		wld_copy_region(swc.shm->renderer, background, 0, 0, &region);
128 	else
129 		wld_fill_region(swc.shm->renderer, bgcolor, &region);
130 
+1, -0
1@@ -48,6 +48,7 @@ struct swc_compositor {
2 
3 bool compositor_initialize(void);
4 void compositor_finalize(void);
5+void compositor_damage_all(void);
6 
7 struct compositor_view {
8 	struct view base;
+1, -0
1@@ -51,6 +51,7 @@ struct swc {
2 	struct wl_global *shell;
3 	struct wl_global *snap_manager;
4 	struct wl_global *subcompositor;
5+	struct wl_global *wallpaper_manager;
6 	struct wl_global *xdg_decoration_manager;
7 	struct wl_global *xdg_shell;
8 
+2, -0
 1@@ -61,6 +61,7 @@ SWC_SOURCES =                       \
 2     protocol/server-decoration-protocol.c \
 3     protocol/swc-protocol.c         \
 4     protocol/swc_snap-protocol.c    \
 5+    protocol/swc_wallpaper-protocol.c \
 6     protocol/wayland-drm-protocol.c \
 7     protocol/xdg-decoration-unstable-v1-protocol.c \
 8     protocol/xdg-shell-protocol.c
 9@@ -113,6 +114,7 @@ $(call objects,dmabuf): protocol/linux-dmabuf-unstable-v1-server-protocol.h
10 $(call objects,drm drm_buffer): protocol/wayland-drm-server-protocol.h
11 $(call objects,kde_decoration): protocol/server-decoration-server-protocol.h
12 $(call objects,snap): protocol/swc_snap-server-protocol.h
13+$(call objects,wallpaper): protocol/swc_wallpaper-server-protocol.h
14 $(call objects,xdg_decoration): protocol/xdg-decoration-unstable-v1-server-protocol.h
15 $(call objects,xdg_shell): protocol/xdg-shell-server-protocol.h
16 $(call objects,pointer): cursor/cursor_data.h
+12, -2
 1@@ -40,6 +40,7 @@
 2 #include "snap.h"
 3 #include "subcompositor.h"
 4 #include "util.h"
 5+#include "wallpaper.h"
 6 #include "window.h"
 7 #include "xdg_decoration.h"
 8 #include "xdg_shell.h"
 9@@ -222,10 +223,16 @@ swc_initialize(struct wl_display *display, struct wl_event_loop *event_loop, con
10 		goto error14;
11 	}
12 
13+	swc.wallpaper_manager = swc_wallpaper_manager_create(display);
14+	if (!swc.wallpaper_manager) {
15+		ERROR("Could not initialize wallpaper manager\n");
16+		goto error15;
17+	}
18+
19 #ifdef ENABLE_XWAYLAND
20 	if (!xserver_initialize()) {
21 		ERROR("Could not initialize xwayland\n");
22-		goto error15;
23+		goto error16;
24 	}
25 #endif
26 
27@@ -234,9 +241,11 @@ swc_initialize(struct wl_display *display, struct wl_event_loop *event_loop, con
28 	return true;
29 
30 #ifdef ENABLE_XWAYLAND
31+error16:
32+	wl_global_destroy(swc.wallpaper_manager);
33+#endif
34 error15:
35 	wl_global_destroy(swc.snap_manager);
36-#endif
37 error14:
38 	wl_global_destroy(swc.panel_manager);
39 error13:
40@@ -275,6 +284,7 @@ swc_finalize(void)
41 #ifdef ENABLE_XWAYLAND
42 	xserver_finalize();
43 #endif
44+	wl_global_destroy(swc.wallpaper_manager);
45 	wl_global_destroy(swc.snap_manager);
46 	wl_global_destroy(swc.panel_manager);
47 	wl_global_destroy(swc.xdg_decoration_manager);
+10, -7
 1@@ -35,6 +35,7 @@ extern "C" {
 2 struct libinput_device;
 3 struct wl_display;
 4 struct wl_event_loop;
 5+struct wld_buffer;
 6 
 7 /**
 8  * gett the current cursor position
 9@@ -438,19 +439,21 @@ int swc_add_axis_binding(uint32_t modifiers, uint32_t axis, swc_axis_binding_han
10 
11 /* Wallpaper {{{ */
12 
13-extern unsigned char *wallpaper;
14-extern struct wld_buffer *wallbuf;
15-
16 /**
17- * Set wallpaper to image from fs path.
18- * TODO: tiling, maybe diff image for each screen
19+ * Set fallback wallpaper buffer for all screens that dom't have an override.
20  */
21+void swc_wallpaper_set_buffer(struct wld_buffer *buffer);
22 
23-void swc_wallpaper_set(char* path);
24+/**
25+ * Set wallpaper buffer for specified screen id.
26+ *
27+ * Passing NULL clears the override for that screen.
28+ */
29+void swc_wallpaper_set_buffer_for_screen(uint8_t screen_id, struct wld_buffer *buffer);
30 
31 /**
32  * Set wallpaper to a single color
33- * pretty much ignored if wallpaper is set to image
34+ * used when no wallpaper buffer is set
35  * defaults to black
36  */
37 
+93, -54
  1@@ -1,77 +1,116 @@
  2-#include <pixman.h>
  3 #include <wld/wld.h>
  4 
  5-#define STB_IMAGE_IMPLEMENTATION
  6-#define STBI_NO_HDR
  7-#include "../stb/stb_image.h"
  8-
  9-#define STB_IMAGE_RESIZE_IMPLEMENTATION
 10-#include "../stb/stb_image_resize2.h"
 11-
 12 #include "swc.h"
 13-#include "internal.h"
 14-#include "drm.h"
 15-#include "util.h"
 16-#include "shm.h"
 17+#include "compositor.h"
 18 #include "screen.h"
 19+#include "util.h"
 20+#include "wayland_buffer.h"
 21+#include "wallpaper.h"
 22+#include "swc_wallpaper-server-protocol.h"
 23 
 24-unsigned char *wallpaper = NULL;
 25-struct wld_buffer *wallbuf = NULL;
 26+#define MAX_WALLPAPER_SCREENS 32
 27 
 28+static struct wld_buffer *wallbuf = NULL;
 29+static struct wld_buffer *screen_wallbuf[MAX_WALLPAPER_SCREENS];
 30 uint32_t bgcolor = 0xff000000;
 31 
 32+static void
 33+set_buffer_slot(struct wld_buffer **slot, struct wld_buffer *buffer)
 34+{
 35+	if (buffer)
 36+		wld_buffer_reference(buffer);
 37+	if (*slot)
 38+		wld_buffer_unreference(*slot);
 39+
 40+	*slot = buffer;
 41+}
 42+
 43+struct wld_buffer *
 44+swc_wallpaper_buffer_for_screen(struct screen *screen)
 45+{
 46+	if (screen
 47+	 && screen->id < ARRAY_LENGTH(screen_wallbuf)
 48+	 && screen_wallbuf[screen->id])
 49+		return screen_wallbuf[screen->id];
 50+
 51+	return wallbuf;
 52+}
 53+
 54 EXPORT void
 55-swc_wallpaper_set(char* path)
 56+swc_wallpaper_set_buffer(struct wld_buffer *buffer)
 57 {
 58-	int width, height, chan;
 59-	unsigned char *loaded;
 60-	struct screen *screen;
 61-	int target_width = 0, target_height = 0;
 62+	set_buffer_slot(&wallbuf, buffer);
 63+	compositor_damage_all();
 64+}
 65 
 66-	loaded = stbi_load(path, &width, &height, &chan, 4);
 67-	if (!loaded)
 68+EXPORT void
 69+swc_wallpaper_set_buffer_for_screen(uint8_t screen_id, struct wld_buffer *buffer)
 70+{
 71+	if (screen_id >= ARRAY_LENGTH(screen_wallbuf))
 72 		return;
 73 
 74-	/* get screen dimensions */
 75-	wl_list_for_each(screen, &swc.screens, link) {
 76-		target_width = screen->base.geometry.width;
 77-		target_height = screen->base.geometry.height;
 78-		break;
 79-	}
 80+	set_buffer_slot(&screen_wallbuf[screen_id], buffer);
 81+	compositor_damage_all();
 82+}
 83+
 84+EXPORT void
 85+swc_wallpaper_color_set(uint32_t color)
 86+{
 87+	bgcolor = color;
 88+	compositor_damage_all();
 89+}
 90+
 91+static void
 92+set_buffer(struct wl_client *client, struct wl_resource *resource,
 93+           int32_t screen_id, struct wl_resource *buffer_resource)
 94+{
 95+	struct wld_buffer *buffer = NULL;
 96 
 97-	/* If we have a screen and dimensions wrong  scale  */
 98-	if (target_width > 0 && target_height > 0 &&
 99-	    (width != target_width || height != target_height)) {
100-		wallpaper = stbir_resize_uint8_srgb(loaded, width, height, 0,
101-		                                     NULL, target_width, target_height, 0,
102-		                                     STBIR_RGBA);
103-		stbi_image_free(loaded);
104-		width = target_width;
105-		height = target_height;
106-	} else {
107-		wallpaper = loaded;
108+	(void)client;
109+
110+	if (buffer_resource) {
111+		buffer = wayland_buffer_get(buffer_resource);
112+		if (!buffer) {
113+			wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
114+			                       "buffer is not a wl_buffer");
115+			return;
116+		}
117 	}
118 
119-	/* swap color channels to be compatible */
120-	for(int i = 0; i < width * height; i++) {
121-		unsigned char r = wallpaper[i*4];
122-		wallpaper[i*4] = wallpaper[(i*4)+2];
123-		wallpaper[(i*4)+2] = r;
124+	if (screen_id == -1) {
125+		swc_wallpaper_set_buffer(buffer);
126+		return;
127 	}
128 
129-	union wld_object obj;
130-	obj.ptr = (uint32_t*)wallpaper;
131+	if (screen_id < 0 || screen_id >= ARRAY_LENGTH(screen_wallbuf))
132+		return;
133 
134-	wallbuf = wld_import_buffer(swc.shm->context,
135-			WLD_OBJECT_DATA,
136-			obj,
137-			width, height,
138-			WLD_FORMAT_ARGB8888,
139-			width * 4);
140+	swc_wallpaper_set_buffer_for_screen((uint8_t)screen_id, buffer);
141 }
142 
143-EXPORT void
144-swc_wallpaper_color_set(uint32_t color)
145+static const struct swc_wallpaper_interface wallpaper_impl = {
146+	.destroy = destroy_resource,
147+	.set_buffer = set_buffer,
148+};
149+
150+static void
151+bind_wallpaper(struct wl_client *client, void *data, uint32_t version, uint32_t id)
152 {
153-	bgcolor = color;
154+	(void)data;
155+
156+	struct wl_resource *resource;
157+
158+	resource = wl_resource_create(client, &swc_wallpaper_interface, version, id);
159+	if (!resource) {
160+		wl_client_post_no_memory(client);
161+		return;
162+	}
163+
164+	wl_resource_set_implementation(resource, &wallpaper_impl, NULL, NULL);
165+}
166+
167+struct wl_global *
168+swc_wallpaper_manager_create(struct wl_display *display)
169+{
170+	return wl_global_create(display, &swc_wallpaper_interface, 1, NULL, bind_wallpaper);
171 }
+12, -0
 1@@ -0,0 +1,12 @@
 2+#ifndef SWC_WALLPAPER_H
 3+#define SWC_WALLPAPER_H
 4+
 5+struct wl_display;
 6+struct wl_global;
 7+struct wld_buffer;
 8+struct screen;
 9+
10+struct wl_global *swc_wallpaper_manager_create(struct wl_display *display);
11+struct wld_buffer *swc_wallpaper_buffer_for_screen(struct screen *screen);
12+
13+#endif
+3, -0
 1@@ -7,6 +7,7 @@ PROTOCOL_EXTENSIONS =           \
 2     $(dir)/server-decoration.xml\
 3     $(dir)/swc.xml              \
 4     $(dir)/swc_snap.xml         \
 5+    $(dir)/swc_wallpaper.xml    \
 6     $(dir)/wayland-drm.xml      \
 7     $(wayland_protocols)/stable/xdg-shell/xdg-shell.xml \
 8     $(wayland_protocols)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml \
 9@@ -29,5 +30,7 @@ CLEAN_FILES += ${dir}/${proto_base}-protocol.c \
10 
11 install-$(dir): | $(DESTDIR)$(DATADIR)/swc
12 	install -m 644 protocol/swc.xml $(DESTDIR)$(DATADIR)/swc
13+	install -m 644 protocol/swc_snap.xml $(DESTDIR)$(DATADIR)/swc
14+	install -m 644 protocol/swc_wallpaper.xml $(DESTDIR)$(DATADIR)/swc
15 
16 include common.mk
+19, -0
 1@@ -0,0 +1,19 @@
 2+<?xml version="1.0" encoding="UTF-8"?>
 3+<protocol name="swc_wallpaper">
 4+    <interface name="swc_wallpaper" version="1">
 5+        <description summary="set compositor wallpaper">
 6+            Allows clients to set wallpaper buffers.
 7+        </description>
 8+
 9+        <request name="destroy" type="destructor" />
10+
11+        <request name="set_buffer">
12+            <description summary="set or clear wallpaper buffer">
13+                screen_id=-1 targets global fallback wallpaper.
14+                Any other screen_id targets that id.
15+            </description>
16+            <arg name="screen_id" type="int" />
17+            <arg name="buffer" type="object" interface="wl_buffer" allow-null="true" />
18+        </request>
19+    </interface>
20+</protocol>