From fd6e972bbf85043224b1626fdd4c4ace3c588846 Mon Sep 17 00:00:00 2001 From: Window Maker Date: Sat, 30 May 2026 11:17:10 +0200 Subject: [PATCH] =?UTF-8?q?wl=5Fbackend:=20fix=20W=5FViewSceneNodeSetEnabl?= =?UTF-8?q?edFn=20never=20wired=20=E2=80=94=20gview=20scene=20buffer=20sta?= =?UTF-8?q?yed=20on=20after=20unmap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- WINGs/wview_wl.c | 22 +++++ ...set_enabled(unsigned long id, int enabled) | 0 src/backend/wayland/wl_backend.c | 89 ++++++++++++++++++- 3 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 l_view_scene_node_set_enabled(unsigned long id, int enabled) diff --git a/WINGs/wview_wl.c b/WINGs/wview_wl.c index a99df7b..0b65190 100644 --- a/WINGs/wview_wl.c +++ b/WINGs/wview_wl.c @@ -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; } diff --git a/l_view_scene_node_set_enabled(unsigned long id, int enabled) b/l_view_scene_node_set_enabled(unsigned long id, int enabled) new file mode 100644 index 0000000..e69de29 diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 376292d..de335fd 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -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) {