From 0e582d0580e1f9dd8fc28fa082fc4718d29b84ef Mon Sep 17 00:00:00 2001 From: Window Maker Date: Thu, 4 Jun 2026 09:36:19 +0200 Subject: [PATCH] render titlebar button icons directly from XPM character data, bypassing XPM parser (which depends on X11) --- src/backend/wayland/wl_framebuf.c | 65 +++++++++++++++++++------------ 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/src/backend/wayland/wl_framebuf.c b/src/backend/wayland/wl_framebuf.c index 87bed74..acc70bb 100644 --- a/src/backend/wayland/wl_framebuf.c +++ b/src/backend/wayland/wl_framebuf.c @@ -727,6 +727,42 @@ wl_frame_paint(struct WFrameWindow *fwin) return 1; } +/* Render XPM character data into an alpha mask RImage. + * Walks the XPM rows directly — only needs the character grid, + * not the XPM color definitions (just "None" detection). */ +static RImage *xpm_to_alpha_mask(char **xpm) +{ + int w = 0, h = 0, ncolors = 0, cpp = 0; + if (sscanf(xpm[0], "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4) + return NULL; + if (w <= 0 || h <= 0 || ncolors < 0 || (cpp != 1 && cpp != 2)) + return NULL; + char none_sym[3] = {0, 0, 0}; + for (int _i = 1; _i <= ncolors; _i++) { + const char *def = xpm[_i]; + if (strstr(def, "None") || strstr(def, "none")) { + none_sym[0] = def[0]; + if (cpp == 2 && def[1] != ' ') none_sym[1] = def[1]; + break; + } + } + RImage *img = RCreateImage(w, h, True); + if (!img) return NULL; + memset(img->data, 0, w * h * 4); + int data_start = 1 + ncolors; + for (int _r = 0; _r < h && (data_start + _r) < 512; _r++) { + const char *row = xpm[data_start + _r]; + int rowlen = strlen(row); + for (int _c = 0; _c < w && _c < rowlen; _c++) { + int is_none = (none_sym[0] && row[_c] == none_sym[0]); + if (cpp == 2 && _c + 1 < rowlen && none_sym[1]) + is_none = is_none && (row[_c + 1] == none_sym[1]); + if (!is_none) + img->data[(_r * w + _c) * 4 + 3] = 0xFF; + } + } + return img; +} void wl_frame_paint_button(WCoreWindow *button, WTexture *texture, @@ -748,30 +784,11 @@ wl_frame_paint_button(WCoreWindow *button, WTexture *texture, if (bw < 3 || bh < 3) return; - /* Build button icon RImages once (avoids XPM parser dependency) */ - if (!wl_state.btn_close_img) { - wl_state.btn_close_img = RCreateImage(10, 10, True); - if (wl_state.btn_close_img) { - unsigned char *d = wl_state.btn_close_img->data; - memset(d, 0, 10 * 10 * 4); - for (int _i = 0; _i < 10; _i++) { - int _j = _i, _k = 9 - _i; - d[(_j * 10 + _i) * 4 + 3] = 0xFF; /* alpha=255 on X diagonals */ - d[(_k * 10 + _i) * 4 + 3] = 0xFF; - } - } - } - if (!wl_state.btn_iconify_img) { - wl_state.btn_iconify_img = RCreateImage(10, 10, True); - if (wl_state.btn_iconify_img) { - unsigned char *d = wl_state.btn_iconify_img->data; - memset(d, 0, 10 * 10 * 4); - for (int _i = 0; _i < 10; _i++) { - d[(8 * 10 + _i) * 4 + 3] = 0xFF; /* alpha=255 on two rows */ - d[(9 * 10 + _i) * 4 + 3] = 0xFF; - } - } - } + /* Build button icon RImages from XPM data arrays directly */ + if (!wl_state.btn_close_img) + wl_state.btn_close_img = xpm_to_alpha_mask(PRED_CLOSE_XPM); + if (!wl_state.btn_iconify_img) + wl_state.btn_iconify_img = xpm_to_alpha_mask(PRED_ICONIFY_XPM); RImage *icon = NULL; if (button == fwin->right_button)