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(®ion, x, y, width, height);
209+ pixman_region32_intersect(®ion, ®ion, damage);
210+ pixman_region32_subtract(®ion, ®ion, &view->clip);
211+ boxes = pixman_region32_rectangles(®ion, &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(®ion);
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