diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 475274b..18455c2 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -7908,11 +7908,19 @@ wl_client_reparent(WNativeWindow client, WNativeWindow new_parent, int x, int y) void wl_view_commit_backing_impl(unsigned long id) { struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)id); + WNativeWindow saved_parent_id = 0; + int saved_rel_x = 0, saved_rel_y = 0; /* If the view was resized, the old frame_buf's image is stale. */ if (fb) { extern void *W_GetViewBacking(unsigned long id); void *current = W_GetViewBacking((unsigned long)id); if (current != (void *)fb->image) { + /* Save parent relation before destroying — the new frame_buf + * must be positioned within the same parent tree so dialog + * content reparented via wl_client_reparent stays visible. */ + saved_parent_id = fb->parent_id; + saved_rel_x = fb->rel_x; + saved_rel_y = fb->rel_y; wlr_scene_node_destroy(&fb->scene_buf->node); wl_list_remove(&fb->link); wlr_buffer_drop(&fb->base); @@ -7921,37 +7929,51 @@ void wl_view_commit_backing_impl(unsigned long id) } } if (!fb) { - /* Auto-create a frame_buf for WINGs toplevel views that were - * not explicitly reparented (e.g. switch panel, menus). - * Without a frame_buf/scene_buffer the view content is painted - * into its pixman backing but never appears on screen. */ extern W_View *W_GetViewForWindow(unsigned long id); extern void *W_GetViewBacking(unsigned long id); W_View *view = W_GetViewForWindow((unsigned long)id); if (view && view->flags.topLevel) { fb = wmalloc(sizeof(*fb)); memset(fb, 0, sizeof(*fb)); - fb->id = id; - fb->x = view->pos.x; - fb->y = view->pos.y; - fb->width = view->size.width; - fb->height = view->size.height; - fb->image = (pixman_image_t *)W_GetViewBacking(id); + fb->id = id; + fb->parent_id = saved_parent_id; + fb->rel_x = saved_rel_x; + fb->rel_y = saved_rel_y; + fb->x = view->pos.x; + fb->y = view->pos.y; + fb->width = view->size.width; + fb->height = view->size.height; + fb->image = (pixman_image_t *)W_GetViewBacking(id); if (fb->image) { pixman_image_ref(fb->image); wlr_buffer_init(&fb->base, &frame_buf_impl, pixman_image_get_width(fb->image), pixman_image_get_height(fb->image)); if (wl_state.scene) { - struct wlr_scene_tree *parent = - wl_state.level_trees[WL_LAYER_FLOATING] + struct wlr_scene_tree *parent = NULL; + /* Re-parent under the saved parent's tree so + * dialogs reparented via wl_client_reparent stay + * correctly positioned within their frame. */ + if (saved_parent_id) { + struct wl_frame_buf *pfb = + frame_buf_find(saved_parent_id); + if (pfb && pfb->tree) + parent = pfb->tree; + } + if (!parent) + parent = wl_state.level_trees[WL_LAYER_FLOATING] ? wl_state.level_trees[WL_LAYER_FLOATING] : &wl_state.scene->tree; fb->scene_buf = wlr_scene_buffer_create(parent, &fb->base); if (fb->scene_buf) { fb_attach_scene_buf_listener(fb); - wlr_scene_node_set_position(&fb->scene_buf->node, - fb->x, fb->y); + /* Position relative to parent's tree or absolute */ + if (parent != &wl_state.scene->tree && saved_parent_id) + wlr_scene_node_set_position(&fb->scene_buf->node, + saved_rel_x, saved_rel_y); + else + wlr_scene_node_set_position(&fb->scene_buf->node, + fb->x, fb->y); wlr_scene_node_set_enabled(&fb->scene_buf->node, false); } }