commit 0b0298f

shrub  ·  2026-04-28 22:56:01 +0000 UTC
parent 6f1e72f
decor: new parts api for pixel data in decor
4 files changed,  +349, -45
+0, -44
 1@@ -335,26 +335,6 @@ repaint_view(struct target *target, struct compositor_view *view,
 2 
 3 	if ((view->decor.top || view->decor.right || view->decor.bottom ||
 4 	     view->decor.left)) {
 5-		pixman_region32_t decor_region, content_region;
 6-		int32_t x = geom->x - (int32_t)view->decor.left;
 7-		int32_t y = geom->y - (int32_t)view->decor.top;
 8-		uint32_t width = geom->width + view->decor.left + view->decor.right;
 9-		uint32_t height = geom->height + view->decor.top + view->decor.bottom;
10-
11-		pixman_region32_init_rect(&decor_region, x, y, width, height);
12-		pixman_region32_init_rect(&content_region, geom->x, geom->y,
13-		                          geom->width, geom->height);
14-		pixman_region32_subtract(&decor_region, &decor_region, &content_region);
15-		pixman_region32_intersect(&decor_region, &decor_region, damage);
16-		pixman_region32_subtract(&decor_region, &decor_region, &view->clip);
17-		if (pixman_region32_not_empty(&decor_region)) {
18-			pixman_region32_translate(&decor_region, -target_geom->x,
19-			                          -target_geom->y);
20-			wld_fill_region(swc.drm->renderer, view->decor.color,
21-			                &decor_region);
22-		}
23-		pixman_region32_fini(&decor_region);
24-		pixman_region32_fini(&content_region);
25 		decor_repaint(swc.drm->renderer, target_geom, view, damage);
26 	}
27 }
28@@ -1981,31 +1961,7 @@ compositor_render_to_shm(struct screen *screen)
29 
30 		if (view->decor.top || view->decor.right || view->decor.bottom ||
31 		    view->decor.left) {
32-			pixman_region32_t decor_region, content_region;
33-			const struct swc_rectangle *geom = &view->base.geometry;
34 			const struct swc_rectangle *target_geom = &screen->base.geometry;
35-			int32_t x = geom->x - (int32_t)view->decor.left;
36-			int32_t y = geom->y - (int32_t)view->decor.top;
37-			uint32_t decor_width =
38-			    geom->width + view->decor.left + view->decor.right;
39-			uint32_t decor_height =
40-			    geom->height + view->decor.top + view->decor.bottom;
41-
42-			pixman_region32_init_rect(&decor_region, x, y, decor_width,
43-			                          decor_height);
44-			pixman_region32_init_rect(&content_region, geom->x, geom->y,
45-			                          geom->width, geom->height);
46-			pixman_region32_subtract(&decor_region, &decor_region, &content_region);
47-			pixman_region32_intersect(&decor_region, &decor_region, &damage);
48-			pixman_region32_subtract(&decor_region, &decor_region, &view->clip);
49-			if (pixman_region32_not_empty(&decor_region)) {
50-				pixman_region32_translate(&decor_region, -target_geom->x,
51-				                          -target_geom->y);
52-				wld_fill_region(swc.shm->renderer, view->decor.color,
53-				                &decor_region);
54-			}
55-			pixman_region32_fini(&decor_region);
56-			pixman_region32_fini(&content_region);
57 			decor_repaint(swc.shm->renderer, target_geom, view, &damage);
58 		}
59 	}
+8, -0
 1@@ -34,6 +34,12 @@ struct screen;
 2 struct wld_buffer;
 3 struct wld_font;
 4 
 5+struct decor_part_buffer {
 6+	void *data;
 7+	struct wld_buffer *buffer;
 8+	uint32_t width, height, stride;
 9+};
10+
11 struct swc_compositor {
12 	struct pointer_handler *const pointer_handler;
13 	struct {
14@@ -93,6 +99,8 @@ struct compositor_view {
15 		uint32_t color;
16 		uint32_t top, right, bottom, left;
17 		struct swc_decor_text text;
18+		const struct swc_decor_parts *parts_key;
19+		struct decor_part_buffer parts[8];
20 		char *string;
21 		char *font_name;
22 		struct wld_font *font;
+309, -1
  1@@ -1,9 +1,13 @@
  2 #include "decor.h"
  3 
  4 #include "compositor.h"
  5+#include "internal.h"
  6+#include "shm.h"
  7 #include "swc.h"
  8+#include "util.h"
  9 #include "window.h"
 10 
 11+#include <pixman.h>
 12 #include <stdlib.h>
 13 #include <string.h>
 14 #include <wld/wld.h>
 15@@ -12,6 +16,18 @@
 16 
 17 static struct wld_font_context *font_context;
 18 
 19+enum decor_part_index {
 20+	DECOR_PART_TOP_LEFT,
 21+	DECOR_PART_TOP,
 22+	DECOR_PART_TOP_RIGHT,
 23+	DECOR_PART_LEFT,
 24+	DECOR_PART_RIGHT,
 25+	DECOR_PART_BOTTOM_LEFT,
 26+	DECOR_PART_BOTTOM,
 27+	DECOR_PART_BOTTOM_RIGHT,
 28+	DECOR_PART_COUNT,
 29+};
 30+
 31 static uint32_t
 32 decor_title_length(struct wld_font *font, const char *title, uint32_t max_width)
 33 {
 34@@ -80,6 +96,154 @@ streq(const char *a, const char *b)
 35 	return strcmp(a, b) == 0;
 36 }
 37 
 38+static const struct swc_decor_part *
 39+decor_part_at(const struct swc_decor_parts *parts, enum decor_part_index index)
 40+{
 41+	if (!parts) {
 42+		return NULL;
 43+	}
 44+
 45+	switch (index) {
 46+	case DECOR_PART_TOP_LEFT:
 47+		return &parts->top_left;
 48+	case DECOR_PART_TOP:
 49+		return &parts->top;
 50+	case DECOR_PART_TOP_RIGHT:
 51+		return &parts->top_right;
 52+	case DECOR_PART_LEFT:
 53+		return &parts->left;
 54+	case DECOR_PART_RIGHT:
 55+		return &parts->right;
 56+	case DECOR_PART_BOTTOM_LEFT:
 57+		return &parts->bottom_left;
 58+	case DECOR_PART_BOTTOM:
 59+		return &parts->bottom;
 60+	case DECOR_PART_BOTTOM_RIGHT:
 61+		return &parts->bottom_right;
 62+	case DECOR_PART_COUNT:
 63+		break;
 64+	}
 65+
 66+	return NULL;
 67+}
 68+
 69+static void
 70+close_decor_parts(struct compositor_view *view)
 71+{
 72+	for (uint32_t i = 0; i < DECOR_PART_COUNT; ++i) {
 73+		if (view->decor.parts[i].buffer) {
 74+			wld_buffer_unreference(view->decor.parts[i].buffer);
 75+			view->decor.parts[i].buffer = NULL;
 76+		}
 77+		free(view->decor.parts[i].data);
 78+		view->decor.parts[i].data = NULL;
 79+		view->decor.parts[i].width = 0;
 80+		view->decor.parts[i].height = 0;
 81+		view->decor.parts[i].stride = 0;
 82+	}
 83+	view->decor.parts_key = NULL;
 84+}
 85+
 86+static bool
 87+decor_part_is_empty(const struct swc_decor_part *part)
 88+{
 89+	return !part || !part->data || !part->width || !part->height ||
 90+	       !part->stride;
 91+}
 92+
 93+static bool
 94+decor_part_equal(const struct decor_part_buffer *owned,
 95+                 const struct swc_decor_part *part)
 96+{
 97+	size_t size;
 98+
 99+	if (decor_part_is_empty(part)) {
100+		return !owned->data && !owned->buffer && !owned->width && !owned->height &&
101+		       !owned->stride;
102+	}
103+
104+	if (!owned->data || owned->width != part->width ||
105+	    owned->height != part->height || owned->stride != part->stride) {
106+		return false;
107+	}
108+
109+	size = (size_t)part->stride * part->height;
110+	return memcmp(owned->data, part->data, size) == 0;
111+}
112+
113+static bool
114+decor_parts_equal(struct compositor_view *view, const struct swc_decor_parts *parts)
115+{
116+	for (uint32_t i = 0; i < DECOR_PART_COUNT; ++i) {
117+		if (!decor_part_equal(&view->decor.parts[i], decor_part_at(parts, i))) {
118+			return false;
119+		}
120+	}
121+
122+	return true;
123+}
124+
125+static bool
126+copy_decor_part(struct decor_part_buffer *dst, const struct swc_decor_part *src)
127+{
128+	union wld_object object;
129+	size_t size;
130+
131+	if (decor_part_is_empty(src)) {
132+		memset(dst, 0, sizeof(*dst));
133+		return true;
134+	}
135+
136+	size = (size_t)src->stride * src->height;
137+	dst->data = malloc(size);
138+	if (!dst->data) {
139+		return false;
140+	}
141+	memcpy(dst->data, src->data, size);
142+
143+	dst->width = src->width;
144+	dst->height = src->height;
145+	dst->stride = src->stride;
146+	object.ptr = dst->data;
147+	dst->buffer = wld_import_buffer(swc.shm->context, WLD_OBJECT_DATA, object,
148+	                                src->width, src->height,
149+	                                WLD_FORMAT_ARGB8888, src->stride);
150+	if (!dst->buffer) {
151+		free(dst->data);
152+		memset(dst, 0, sizeof(*dst));
153+		return false;
154+	}
155+
156+	return true;
157+}
158+
159+static bool
160+copy_decor_parts(struct compositor_view *view, const struct swc_decor_parts *parts)
161+{
162+	struct decor_part_buffer copied[DECOR_PART_COUNT] = { 0 };
163+	uint32_t i;
164+
165+	for (i = 0; i < DECOR_PART_COUNT; ++i) {
166+		if (!copy_decor_part(&copied[i], decor_part_at(parts, i))) {
167+			goto error;
168+		}
169+	}
170+
171+	close_decor_parts(view);
172+	memcpy(view->decor.parts, copied, sizeof(copied));
173+	view->decor.parts_key = parts;
174+	return true;
175+
176+error:
177+	for (i = 0; i < DECOR_PART_COUNT; ++i) {
178+		if (copied[i].buffer) {
179+			wld_buffer_unreference(copied[i].buffer);
180+		}
181+		free(copied[i].data);
182+	}
183+	return false;
184+}
185+
186 static void
187 close_decor_font(struct compositor_view *view)
188 {
189@@ -98,6 +262,67 @@ close_decor_string(struct compositor_view *view)
190 	view->decor.string = NULL;
191 }
192 
193+static void
194+draw_decor_part(struct wld_renderer *renderer,
195+                const struct swc_rectangle *target_geom,
196+                struct compositor_view *view, pixman_region32_t *damage,
197+                const struct decor_part_buffer *part, int32_t x, int32_t y,
198+                uint32_t width, uint32_t height)
199+{
200+	pixman_region32_t region;
201+	pixman_box32_t *boxes;
202+	int nboxes;
203+
204+	if (!part->buffer || !part->width || !part->height || !width || !height) {
205+		return;
206+	}
207+
208+	pixman_region32_init_rect(&region, x, y, width, height);
209+	pixman_region32_intersect(&region, &region, damage);
210+	pixman_region32_subtract(&region, &region, &view->clip);
211+	boxes = pixman_region32_rectangles(&region, &nboxes);
212+
213+	for (int i = 0; i < nboxes; ++i) {
214+		int32_t rx1 = boxes[i].x1;
215+		int32_t ry1 = boxes[i].y1;
216+		int32_t rx2 = boxes[i].x2;
217+		int32_t ry2 = boxes[i].y2;
218+		int32_t start_y = y + ((ry1 - y) / (int32_t)part->height) * (int32_t)part->height;
219+
220+		if (start_y > ry1) {
221+			start_y -= (int32_t)part->height;
222+		}
223+
224+		for (int32_t tile_y = start_y; tile_y < ry2; tile_y += (int32_t)part->height) {
225+			int32_t start_x =
226+			    x + ((rx1 - x) / (int32_t)part->width) * (int32_t)part->width;
227+
228+			if (start_x > rx1) {
229+				start_x -= (int32_t)part->width;
230+			}
231+
232+			for (int32_t tile_x = start_x; tile_x < rx2;
233+			     tile_x += (int32_t)part->width) {
234+				int32_t clip_x1 = MAX(tile_x, rx1);
235+				int32_t clip_y1 = MAX(tile_y, ry1);
236+				int32_t clip_x2 = MIN(tile_x + (int32_t)part->width, rx2);
237+				int32_t clip_y2 = MIN(tile_y + (int32_t)part->height, ry2);
238+
239+				if (clip_x2 > clip_x1 && clip_y2 > clip_y1) {
240+					wld_copy_rectangle(renderer, part->buffer,
241+					                   clip_x1 - target_geom->x,
242+					                   clip_y1 - target_geom->y,
243+					                   clip_x1 - tile_x, clip_y1 - tile_y,
244+					                   (uint32_t)(clip_x2 - clip_x1),
245+					                   (uint32_t)(clip_y2 - clip_y1));
246+				}
247+			}
248+		}
249+	}
250+
251+	pixman_region32_fini(&region);
252+}
253+
254 bool
255 decor_initialize(void)
256 {
257@@ -118,6 +343,8 @@ void
258 decor_view_initialize(struct compositor_view *view)
259 {
260 	memset(&view->decor.text, 0, sizeof(view->decor.text));
261+	view->decor.parts_key = NULL;
262+	memset(view->decor.parts, 0, sizeof(view->decor.parts));
263 	view->decor.string = NULL;
264 	view->decor.font_name = NULL;
265 	view->decor.font = NULL;
266@@ -126,6 +353,7 @@ decor_view_initialize(struct compositor_view *view)
267 void
268 decor_view_finalize(struct compositor_view *view)
269 {
270+	close_decor_parts(view);
271 	close_decor_string(view);
272 	close_decor_font(view);
273 }
274@@ -139,10 +367,84 @@ decor_repaint(struct wld_renderer *renderer,
275 	const struct swc_decor_text *text = &view->decor.text;
276 	struct wld_font *font = view->decor.font;
277 	const char *title = view->decor.string;
278+	pixman_region32_t decor_region, content_region;
279 	uint32_t title_len, max_width, decor_size;
280 	int32_t x, y, base_x, base_y, advance, available_width;
281 	struct wld_extents extents;
282 	pixman_region32_t title_region;
283+	int32_t outer_x = geom->x - (int32_t)view->decor.left;
284+	int32_t outer_y = geom->y - (int32_t)view->decor.top;
285+	uint32_t outer_width = geom->width + view->decor.left + view->decor.right;
286+	uint32_t outer_height = geom->height + view->decor.top + view->decor.bottom;
287+	uint32_t tl_width = view->decor.parts[DECOR_PART_TOP_LEFT].width;
288+	uint32_t tl_height = view->decor.parts[DECOR_PART_TOP_LEFT].height;
289+	uint32_t tr_width = view->decor.parts[DECOR_PART_TOP_RIGHT].width;
290+	uint32_t tr_height = view->decor.parts[DECOR_PART_TOP_RIGHT].height;
291+	uint32_t bl_width = view->decor.parts[DECOR_PART_BOTTOM_LEFT].width;
292+	uint32_t bl_height = view->decor.parts[DECOR_PART_BOTTOM_LEFT].height;
293+	uint32_t br_width = view->decor.parts[DECOR_PART_BOTTOM_RIGHT].width;
294+	uint32_t br_height = view->decor.parts[DECOR_PART_BOTTOM_RIGHT].height;
295+
296+	if (!view->decor.top && !view->decor.right && !view->decor.bottom &&
297+	    !view->decor.left) {
298+		return;
299+	}
300+
301+	pixman_region32_init_rect(&decor_region, outer_x, outer_y, outer_width,
302+	                          outer_height);
303+	pixman_region32_init_rect(&content_region, geom->x, geom->y, geom->width,
304+	                          geom->height);
305+	pixman_region32_subtract(&decor_region, &decor_region, &content_region);
306+	pixman_region32_intersect(&decor_region, &decor_region, damage);
307+	pixman_region32_subtract(&decor_region, &decor_region, &view->clip);
308+	if (pixman_region32_not_empty(&decor_region)) {
309+		pixman_region32_translate(&decor_region, -target_geom->x, -target_geom->y);
310+		wld_fill_region(renderer, view->decor.color, &decor_region);
311+		pixman_region32_translate(&decor_region, target_geom->x, target_geom->y);
312+	}
313+	pixman_region32_fini(&decor_region);
314+	pixman_region32_fini(&content_region);
315+
316+	draw_decor_part(renderer, target_geom, view, damage,
317+	                &view->decor.parts[DECOR_PART_TOP_LEFT], outer_x, outer_y,
318+	                tl_width, tl_height);
319+	draw_decor_part(renderer, target_geom, view, damage,
320+	                &view->decor.parts[DECOR_PART_TOP_RIGHT],
321+	                outer_x + (int32_t)outer_width - (int32_t)tr_width, outer_y,
322+	                tr_width, tr_height);
323+	draw_decor_part(renderer, target_geom, view, damage,
324+	                &view->decor.parts[DECOR_PART_BOTTOM_LEFT], outer_x,
325+	                outer_y + (int32_t)outer_height - (int32_t)bl_height,
326+	                bl_width, bl_height);
327+	draw_decor_part(renderer, target_geom, view, damage,
328+	                &view->decor.parts[DECOR_PART_BOTTOM_RIGHT],
329+	                outer_x + (int32_t)outer_width - (int32_t)br_width,
330+	                outer_y + (int32_t)outer_height - (int32_t)br_height,
331+	                br_width, br_height);
332+
333+	if (outer_width > tl_width + tr_width) {
334+		draw_decor_part(renderer, target_geom, view, damage,
335+		                &view->decor.parts[DECOR_PART_TOP],
336+		                outer_x + (int32_t)tl_width, outer_y,
337+		                outer_width - tl_width - tr_width, view->decor.top);
338+		draw_decor_part(renderer, target_geom, view, damage,
339+		                &view->decor.parts[DECOR_PART_BOTTOM],
340+		                outer_x + (int32_t)bl_width,
341+		                outer_y + (int32_t)outer_height - (int32_t)view->decor.bottom,
342+		                outer_width - bl_width - br_width, view->decor.bottom);
343+	}
344+
345+	if (outer_height > tl_height + bl_height) {
346+		draw_decor_part(renderer, target_geom, view, damage,
347+		                &view->decor.parts[DECOR_PART_LEFT], outer_x,
348+		                outer_y + (int32_t)tl_height, view->decor.left,
349+		                outer_height - tl_height - bl_height);
350+		draw_decor_part(renderer, target_geom, view, damage,
351+		                &view->decor.parts[DECOR_PART_RIGHT],
352+		                outer_x + (int32_t)outer_width - (int32_t)view->decor.right,
353+		                outer_y + (int32_t)tr_height, view->decor.right,
354+		                outer_height - tr_height - br_height);
355+	}
356 
357 	if (!title || !font || !text->enabled) {
358 		return;
359@@ -295,6 +597,7 @@ decor_view_set(struct compositor_view *view, const struct swc_decor *decor)
360 	struct swc_decor_text text = { 0 };
361 	char *owned_string = NULL;
362 	char *owned_font_name = NULL;
363+	const struct swc_decor_parts *parts = NULL;
364 	uint32_t color = 0, top = 0, right = 0, bottom = 0, left = 0;
365 
366 	if (!decor) {
367@@ -306,6 +609,7 @@ decor_view_set(struct compositor_view *view, const struct swc_decor *decor)
368 	right = decor->right;
369 	bottom = decor->bottom;
370 	left = decor->left;
371+	parts = decor->parts;
372 	text = decor->title;
373 	if (text.enabled) {
374 		font_name = text.font ? text.font : DEFAULT_DECOR_FONT;
375@@ -322,7 +626,8 @@ decor_view_set(struct compositor_view *view, const struct swc_decor *decor)
376 	    view->decor.text.padding == text.padding &&
377 	    view->decor.text.offset_x == text.offset_x &&
378 	    view->decor.text.offset_y == text.offset_y &&
379-	    streq(view->decor.font_name, font_name)) {
380+	    streq(view->decor.font_name, font_name) &&
381+	    decor_parts_equal(view, parts)) {
382 		return;
383 	}
384 
385@@ -346,6 +651,9 @@ apply:
386 	view->decor.text = text;
387 	view->decor.text.string = NULL;
388 	view->decor.text.font = NULL;
389+	if (!copy_decor_parts(view, parts)) {
390+		close_decor_parts(view);
391+	}
392 	close_decor_string(view);
393 	view->decor.string = owned_string;
394 	close_decor_font(view);
+32, -0
 1@@ -441,6 +441,37 @@ struct swc_decor_text {
 2 	const char *font;
 3 };
 4 
 5+/**
 6+ * describes one wm-supplied decor pixel block
 7+ *
 8+ * swc copies the pixel data when swc_window_set_decor() is called, so caller
 9+ * doesnt need to keep it after the call returns
10+ *
11+ * pixel data is expected to be ARGB8888 with the provided stride.
12+ */
13+struct swc_decor_part {
14+	uint32_t width, height;
15+	uint32_t stride;
16+	const void *data;
17+};
18+
19+/**
20+ * describes optional pixel blocks for the outer frame of a decor.
21+ *
22+ * corner parts are drawn once at their matching corner
23+ * edge parts are tiled to fill the remaining edge area between corners.
24+ */
25+struct swc_decor_parts {
26+	struct swc_decor_part top_left;
27+	struct swc_decor_part top;
28+	struct swc_decor_part top_right;
29+	struct swc_decor_part left;
30+	struct swc_decor_part right;
31+	struct swc_decor_part bottom_left;
32+	struct swc_decor_part bottom;
33+	struct swc_decor_part bottom_right;
34+};
35+
36 /**
37  * describe decor around a window's edges.
38  *
39@@ -452,6 +483,7 @@ struct swc_decor_text {
40 struct swc_decor {
41 	uint32_t color;
42 	uint32_t top, right, bottom, left;
43+	const struct swc_decor_parts *parts;
44 	struct swc_decor_text title;
45 };
46