Fix menu rendering: create real frame_bufs for child windows

Child windows (menu content area, titlebar, resizebar) need their own
pixman buffers for painting. Previously frame_create_child returned a
bare synthetic ID with no buffer, so menu_paint_entry found nothing.

Also add parent-child tracking: when a parent frame moves or maps,
all children are repositioned/enabled automatically. Children store
their relative offset and parent ID.
This commit is contained in:
Levi Neely 2026-05-13 16:29:06 +02:00
parent 01bed8bdd3
commit 7921d2def8
1 changed files with 65 additions and 7 deletions

View File

@ -282,7 +282,9 @@ struct wl_frame_buf {
pixman_image_t *image; /* ARGB32 pixel data */
struct wlr_scene_buffer *scene_buf; /* scene graph node */
WNativeWindow id; /* synthetic ID (>= 0x10000000) */
WNativeWindow parent_id; /* parent frame_buf ID (0 = root) */
int x, y; /* position in output coords */
int rel_x, rel_y; /* position relative to parent */
int width, height;
struct wl_list link; /* wl_state.frame_list */
};
@ -3596,12 +3598,51 @@ static WNativeWindow
wl_frame_create_child(WNativeWindow parent_win, WScreen *scr,
int x, int y, int width, int height)
{
(void)parent_win; (void)scr;
(void)x; (void)y; (void)width; (void)height;
/* Child windows (titlebar, buttons, resizebar) are sub-regions of the
* parent frame buffer. Return a synthetic ID so context_save works,
* but no separate buffer is needed — frame_paint renders everything. */
return wl_state.next_synthetic_id++;
(void)scr;
if (width <= 0) width = 1;
if (height <= 0) height = 1;
/* Compute absolute position from parent */
int abs_x = x, abs_y = y;
struct wl_frame_buf *parent = frame_buf_find(parent_win);
if (parent) {
abs_x = parent->x + x;
abs_y = parent->y + y;
}
struct wl_frame_buf *fb = wmalloc(sizeof(*fb));
memset(fb, 0, sizeof(*fb));
fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8,
width, height, NULL, 0);
if (!fb->image) {
wfree(fb);
return WNATIVE_NONE;
}
wlr_buffer_init(&fb->base, &frame_buf_impl, width, height);
fb->id = wl_state.next_synthetic_id++;
fb->parent_id = parent_win;
fb->rel_x = x;
fb->rel_y = y;
fb->x = abs_x;
fb->y = abs_y;
fb->width = width;
fb->height = height;
if (wl_state.scene) {
fb->scene_buf = wlr_scene_buffer_create(&wl_state.scene->tree,
&fb->base);
if (fb->scene_buf) {
wlr_scene_node_set_position(&fb->scene_buf->node, abs_x, abs_y);
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
}
}
wl_list_insert(&wl_state.frame_list, &fb->link);
return fb->id;
}
static void
@ -5294,10 +5335,16 @@ wl_window_map(WNativeWindow win)
wlr_scene_node_set_enabled(&v->scene_node->node, true);
return;
}
/* Frame buffer: enable its scene node. */
/* Frame buffer: enable its scene node and children. */
struct wl_frame_buf *fb = frame_buf_find(win);
if (fb && fb->scene_buf) {
wlr_scene_node_set_enabled(&fb->scene_buf->node, true);
/* Also enable children */
struct wl_frame_buf *child;
wl_list_for_each(child, &wl_state.frame_list, link) {
if (child->parent_id == win && child->scene_buf)
wlr_scene_node_set_enabled(&child->scene_buf->node, true);
}
return;
}
}
@ -5355,6 +5402,17 @@ static void wl_window_move(WNativeWindow win, int x, int y)
fb->x = x; fb->y = y;
if (fb->scene_buf)
wlr_scene_node_set_position(&fb->scene_buf->node, x, y);
/* Move children that track this parent */
struct wl_frame_buf *child;
wl_list_for_each(child, &wl_state.frame_list, link) {
if (child->parent_id == win) {
child->x = x + child->rel_x;
child->y = y + child->rel_y;
if (child->scene_buf)
wlr_scene_node_set_position(&child->scene_buf->node,
child->x, child->y);
}
}
return;
}
}