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) {