From 38a0009e03ce0060fc9a9f4eecde116a82bd6a49 Mon Sep 17 00:00:00 2001 From: lkn Date: Sun, 7 Jun 2026 14:51:30 +0200 Subject: [PATCH] wl_unmap: send NULL buffer to WINGs client toplevel surfaces on unmap When a WINGs client popup is unmapped (popDownMenu), the scene node is disabled via W_ViewSceneNodeSetEnabledFn. But for WINGs client toplevels (which have their own wl_surface + xdg_toplevel via libwayland-client), the surface still holds its last committed buffer. Disabling the scene node is not enough - the compositor still sees the surface as mapped. Fix: add wl_client_toplevel_unmap which attaches NULL to the wl_surface and commits, properly unmapping it from the compositor. Wire through W_WLClientUnmapFn function pointer in wview_wl.c, called from wl_unmap for topLevel views. --- WINGs/wclient_wl.c | 13 +++++++++++++ WINGs/wview_wl.c | 7 +++++++ src/backend/wayland/wl_backend.c | 3 +++ 3 files changed, 23 insertions(+) diff --git a/WINGs/wclient_wl.c b/WINGs/wclient_wl.c index 260e0ac..e8bd387 100644 --- a/WINGs/wclient_wl.c +++ b/WINGs/wclient_wl.c @@ -552,6 +552,19 @@ wl_client_toplevel_destroy(struct W_View *view) wl_client_view_destroy_backing((unsigned long)view->window); } +void +wl_client_toplevel_unmap(WNativeWindow id) +{ + WLClientToplevel *top = wlc_top_find(id); + if (!top || !top->surface) return; + /* Attach NULL to unmap the surface from the compositor. */ + wl_surface_attach(top->surface, NULL, 0, 0); + wl_surface_commit(top->surface); + if (top->ctx && top->ctx->display) + wl_display_flush(top->ctx->display); + top->mapped = 0; +} + void W_WLClientSetMinMaxSize(W_View *view) { diff --git a/WINGs/wview_wl.c b/WINGs/wview_wl.c index 5bd87ac..843f93b 100644 --- a/WINGs/wview_wl.c +++ b/WINGs/wview_wl.c @@ -18,6 +18,7 @@ static unsigned int wl_view_next_id = WL_VIEW_ID_BASE; void (*W_ViewCommitBackingFn)(unsigned long id) = NULL; void (*W_ViewDestroyBackingFn)(unsigned long id) = NULL; void (*W_ViewSceneNodeSetEnabledFn)(unsigned long id, int enabled) = NULL; +void (*W_WLClientUnmapFn)(unsigned long id) = NULL; /* Callback for wclient_wl.c to trigger a full redisplay after resize */ static void wl_redisplay(void *vctx, W_View *view); @@ -211,6 +212,12 @@ static void wl_unmap(void *vctx, W_View *view) /* Disable the scene buffer so the view disappears from screen. */ if (W_ViewSceneNodeSetEnabledFn) W_ViewSceneNodeSetEnabledFn((unsigned long)view->window, 0); + /* For WINGs client toplevels (popup menus), send a NULL buffer + * to the wl_surface so the compositor fully unmaps the surface. + * Scene-node disable alone is insufficient because the surface + * still holds its last committed buffer. */ + if (view->flags.topLevel && W_WLClientUnmapFn) + W_WLClientUnmapFn((unsigned long)view->window); if (view->parent && view->parent->flags.mapped) wl_redisplay(vctx, view->parent); } diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index f23a6ea..f686587 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -471,6 +471,9 @@ wl_display_open(const char *name) extern void wl_pointer_ungrab(unsigned long); W_WLPointerGrabFn = wl_pointer_grab; W_WLPointerUngrabFn = wl_pointer_ungrab; + extern void (*W_WLClientUnmapFn)(unsigned long); + extern void wl_client_toplevel_unmap(WNativeWindow); + W_WLClientUnmapFn = wl_client_toplevel_unmap; extern void (*W_ClipboardStoreFn)(const char *text, int len); extern char *(*W_ClipboardFetchFn)(int *len_out);