wl_backend: fix W_ViewSceneNodeSetEnabledFn never wired — gview scene buffer stayed on after unmap
The blue position indicator (gview — geometry view with blue-gray background, white coordinate text) was visible during window move, but never disappeared when the move ended. Root cause: W_ViewSceneNodeSetEnabledFn was declared in wview_wl.c and called by wl_unmap() to disable the view's scene buffer node, but wl_backend.c never wired it up — the pointer was NULL. Also: add auto-create of frame_buf for WINGs toplevel views not explicitly reparented (switch panel, menus, gview), sync position from WINGs view on commit, auto-realize children in wl_map/wl_map_subviews, and guard scene node enablement against unmapped views.
This commit is contained in:
parent
2797e1dcfc
commit
fd6e972bbf
|
|
@ -17,6 +17,7 @@ static unsigned int wl_view_next_id = WL_VIEW_ID_BASE;
|
|||
/* Callback set by WM backend to commit frame_buf after paint */
|
||||
void (*W_ViewCommitBackingFn)(unsigned long id) = NULL;
|
||||
void (*W_ViewDestroyBackingFn)(unsigned long id) = NULL;
|
||||
void (*W_ViewSceneNodeSetEnabledFn)(unsigned long id, int enabled) = NULL;
|
||||
|
||||
/* Callback for wclient_wl.c to trigger a full redisplay after resize */
|
||||
static void wl_redisplay(void *vctx, W_View *view);
|
||||
|
|
@ -207,6 +208,9 @@ static void wl_unmap(void *vctx, W_View *view)
|
|||
{
|
||||
(void)vctx;
|
||||
view->flags.mapped = 0;
|
||||
/* Disable the scene buffer so the view disappears from screen. */
|
||||
if (W_ViewSceneNodeSetEnabledFn)
|
||||
W_ViewSceneNodeSetEnabledFn((unsigned long)view->window, 0);
|
||||
if (view->parent && view->parent->flags.mapped)
|
||||
wl_redisplay(vctx, view->parent);
|
||||
}
|
||||
|
|
@ -290,6 +294,17 @@ static void wl_map(void *vctx, W_View *view)
|
|||
view->flags.mapped = 1;
|
||||
if (!view->flags.realized)
|
||||
return;
|
||||
/* Auto-realize children recursively before redisplay.
|
||||
* W_RealizeView recurses into the full subtree, so calling it
|
||||
* on each direct child handles arbitrary nesting depth. */
|
||||
{
|
||||
W_View *child = view->childrenList;
|
||||
while (child) {
|
||||
if (!child->flags.realized)
|
||||
W_RealizeView(child);
|
||||
child = child->nextSister;
|
||||
}
|
||||
}
|
||||
if (view->flags.topLevel) {
|
||||
wl_redisplay(vctx, view);
|
||||
return;
|
||||
|
|
@ -312,6 +327,13 @@ static void wl_map_subviews(void *vctx, W_View *view)
|
|||
{
|
||||
W_View *child = view->childrenList;
|
||||
while (child) {
|
||||
if (!child->flags.realized) {
|
||||
/* Auto-realize children that were created after their
|
||||
* parent was already realized. This is needed for e.g.
|
||||
* switch panel icon frames added via addIconForWindow
|
||||
* after WMRealizeWidget(panel->win). */
|
||||
W_RealizeView(child);
|
||||
}
|
||||
if (child->flags.realized) {
|
||||
child->flags.mapped = 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2720,6 +2720,10 @@ wl_display_open(const char *name)
|
|||
extern void (*W_ViewDestroyBackingFn)(unsigned long id);
|
||||
W_ViewDestroyBackingFn = wl_view_destroy_backing_impl;
|
||||
|
||||
extern void (*W_ViewSceneNodeSetEnabledFn)(unsigned long id, int enabled);
|
||||
extern void wl_view_scene_node_set_enabled(unsigned long id, int enabled);
|
||||
W_ViewSceneNodeSetEnabledFn = wl_view_scene_node_set_enabled;
|
||||
|
||||
extern void (*W_ClipboardStoreFn)(const char *text, int len);
|
||||
extern char *(*W_ClipboardFetchFn)(int *len_out);
|
||||
W_ClipboardStoreFn = wl_clipboard_store_to_seat;
|
||||
|
|
@ -7815,12 +7819,91 @@ 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);
|
||||
/* 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) {
|
||||
wlr_scene_node_destroy(&fb->scene_buf->node);
|
||||
wl_list_remove(&fb->link);
|
||||
wlr_buffer_drop(&fb->base);
|
||||
wfree(fb);
|
||||
fb = NULL;
|
||||
}
|
||||
}
|
||||
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);
|
||||
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]
|
||||
? 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);
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
|
||||
}
|
||||
}
|
||||
wl_list_insert(&wl_state.frame_list, &fb->link);
|
||||
} else {
|
||||
wfree(fb);
|
||||
fb = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fb && fb->scene_buf) {
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
/* Enable the node — it has content now */
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, true);
|
||||
/* Sync position from the WINGs view — it may have moved since
|
||||
* the frame_buf was created (e.g. switch panel is positioned
|
||||
* after widget creation via WMMoveWidget). */
|
||||
extern W_View *W_GetViewForWindow(unsigned long id);
|
||||
W_View *v = W_GetViewForWindow((unsigned long)id);
|
||||
if (v) {
|
||||
if (fb->x != v->pos.x || fb->y != v->pos.y) {
|
||||
fb->x = v->pos.x;
|
||||
fb->y = v->pos.y;
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node,
|
||||
fb->x, fb->y);
|
||||
}
|
||||
}
|
||||
/* Only enable the scene node if the view is still mapped.
|
||||
* If the view was unmapped (e.g. move ended), wl_unmap disables
|
||||
* it via W_ViewSceneNodeSetEnabledFn — don't re-enable here. */
|
||||
if (!v || v->flags.mapped) {
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
wl_view_scene_node_set_enabled(unsigned long id, int enabled)
|
||||
{
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)id);
|
||||
if (fb && fb->scene_buf)
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, !!enabled);
|
||||
}
|
||||
|
||||
|
||||
void wl_view_destroy_backing_impl(unsigned long id)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue