From 0cf867d54880525801c24904bf2560cd9899c382 Mon Sep 17 00:00:00 2001 From: lkn Date: Sat, 23 May 2026 14:08:34 +0200 Subject: [PATCH] fix: enable titlebar button scene_bufs for click and visibility Buttons were rendered into the titlebar buffer with their own scene_buf nodes disabled. This made them invisible to wlr_scene_node_at and required a fragile coordinate-based hit-test (frame_buf_button_at). Switch to rendering each button into its own frame_buf image and enabling its scene_buf node. This makes buttons: - Visible as independent scene nodes - Directly hittable by wlr_scene_node_at - Properly clickable via the normal frame_buf_at path Update frame_buf_button_at to use a size threshold (<=30px) instead of the disabled-node check to identify button sub-windows. --- src/backend/wayland/wl_backend.c | 48 +++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 2cdfb25..24be4c4 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -3975,7 +3975,9 @@ frame_buf_button_at(int px, int py) wl_list_for_each(fb, &wl_state.frame_list, link) { if (!fb->parent_id) continue; /* top-level root */ if (!fb->scene_buf) continue; /* no scene node */ - if (fb->scene_buf->node.enabled) continue; /* visible node — titlebar/resizebar */ + /* Buttons are small children of the titlebar with enabled scene_bufs. + * Skip large nodes (titlebars, resizebars) by size threshold. */ + if (fb->width > 30 || fb->height > 30) continue; if (px < fb->x || px >= fb->x + fb->width) continue; if (py < fb->y || py >= fb->y + fb->height) continue; /* Prefer the smallest (most specific) enclosing fb. */ @@ -7584,16 +7586,10 @@ static void wl_frame_paint_button(WCoreWindow *button, WTexture *texture, if (!fwin || !fwin->core) return; - struct wl_frame_buf *frame_fb = frame_buf_find(fwin->core->window); - struct wl_frame_buf *tb_fb = fwin->titlebar ? frame_buf_find(fwin->titlebar->window) : NULL; struct wl_frame_buf *btn_fb = frame_buf_find(button->window); - /* Render into titlebar buffer if available, else frame buffer */ - struct wl_frame_buf *target = (tb_fb && tb_fb->image) ? tb_fb : frame_fb; - if (!target || !target->image || !btn_fb) + if (!btn_fb || !btn_fb->image) return; - int bx = btn_fb->rel_x; - int by = btn_fb->rel_y; int bw = btn_fb->width; int bh = btn_fb->height; @@ -7613,19 +7609,36 @@ static void wl_frame_paint_button(WCoreWindow *button, WTexture *texture, if (!icon) return; + /* Clear button buffer with titlebar background */ + struct wl_frame_buf *tb_fb = fwin->titlebar ? frame_buf_find(fwin->titlebar->window) : NULL; + uint32_t bg_pixel = 0xFF333333; + if (tb_fb && tb_fb->image) { + /* Sample background color from titlebar at button position */ + uint32_t *tb_data = pixman_image_get_data(tb_fb->image); + int tb_stride = pixman_image_get_stride(tb_fb->image) / 4; + int sample_y = btn_fb->rel_y + bh / 2; + int sample_x = btn_fb->rel_x + bw / 2; + if (sample_y >= 0 && sample_y < tb_fb->height && + sample_x >= 0 && sample_x < tb_fb->width) + bg_pixel = tb_data[sample_y * tb_stride + sample_x]; + } + uint32_t *dst = pixman_image_get_data(btn_fb->image); + int dst_stride = pixman_image_get_stride(btn_fb->image) / 4; + for (int y = 0; y < bh; y++) + for (int x = 0; x < bw; x++) + dst[y * dst_stride + x] = bg_pixel; + /* Blit icon centered in button area */ - uint32_t *dst = pixman_image_get_data(target->image); - int dst_stride = pixman_image_get_stride(target->image) / 4; - int ix = bx + (bw - icon->width) / 2 + (pushed ? 1 : 0); - int iy = by + (bh - icon->height) / 2 + (pushed ? 1 : 0); + int ix = (bw - icon->width) / 2 + (pushed ? 1 : 0); + int iy = (bh - icon->height) / 2 + (pushed ? 1 : 0); for (int y = 0; y < icon->height; y++) { int dy = iy + y; - if (dy < 0 || dy >= target->height) continue; + if (dy < 0 || dy >= bh) continue; uint32_t *dst_row = dst + dy * dst_stride; for (int x = 0; x < icon->width; x++) { int dx = ix + x; - if (dx < 0 || dx >= target->width) continue; + if (dx < 0 || dx >= bw) continue; unsigned char r, g, b, a; if (icon->format == RRGBAFormat) { int off = (y * icon->width + x) * 4; @@ -7636,14 +7649,15 @@ static void wl_frame_paint_button(WCoreWindow *button, WTexture *texture, r = icon->data[off]; g = icon->data[off+1]; b = icon->data[off+2]; a = 255; } - if (a == 0) continue; /* transparent */ + if (a == 0) continue; dst_row[dx] = ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b; } } - if (target->scene_buf) - wlr_scene_buffer_set_buffer(target->scene_buf, &target->base); + /* Enable and commit the button's own scene_buf */ + wlr_scene_buffer_set_buffer(btn_fb->scene_buf, &btn_fb->base); + wlr_scene_node_set_enabled(&btn_fb->scene_buf->node, true); } static void wl_noop_netwm_init(WScreen *scr) { (void)scr; }