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.
This commit is contained in:
lkn 2026-05-23 14:08:34 +02:00
parent 9ed1c19d6b
commit 0cf867d548
1 changed files with 31 additions and 17 deletions

View File

@ -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; }