wl_unmap: recycle WINGs client wl_surface on popup close to eliminate stale pixels
The stale popup content visible under the main window after close comes from the wl_redisplay composite of the popup into the parent backing (rootView). Even though rootView is not committed to any wl_surface, the popup surface itself retains its last committed buffer. Disabling the scene node is insufficient for completely eliminating visual artifacts. Fix: add wl_client_toplevel_recycle which destroys the xdg_toplevel, xdg_surface, wl_surface, and SHM buffer but preserves the WLClientToplevel struct and its WINGs window ID mapping. On unmap (wl_unmap), call recycle for topLevel popups. On remap (wl_map), call wl_client_toplevel_remap which recreates all Wayland protocol objects from scratch, triggering a fresh configure cycle. This ensures no stale buffer or state persists between open/close cycles.
This commit is contained in:
parent
60efe4db78
commit
118a7c30a9
|
|
@ -560,6 +560,91 @@ wl_client_toplevel_destroy(struct W_View *view)
|
|||
wl_client_view_destroy_backing((unsigned long)view->window);
|
||||
}
|
||||
|
||||
void
|
||||
wl_client_toplevel_recycle(WNativeWindow id)
|
||||
{
|
||||
WLClientToplevel *top = wlc_top_find(id);
|
||||
if (!top) return;
|
||||
/* Destroy the Wayland protocol objects but keep the
|
||||
* WLClientToplevel struct and its view->window mapping,
|
||||
* so the surface can be recreated cleanly on remap. */
|
||||
if (top->wmaker_popup) {
|
||||
wmaker_popup_v1_destroy(top->wmaker_popup);
|
||||
top->wmaker_popup = NULL;
|
||||
}
|
||||
if (top->xdg_toplevel) {
|
||||
xdg_toplevel_destroy(top->xdg_toplevel);
|
||||
top->xdg_toplevel = NULL;
|
||||
}
|
||||
if (top->xdg_surface) {
|
||||
xdg_surface_destroy(top->xdg_surface);
|
||||
top->xdg_surface = NULL;
|
||||
}
|
||||
if (top->surface) {
|
||||
wl_surface_destroy(top->surface);
|
||||
top->surface = NULL;
|
||||
}
|
||||
if (top->buf) {
|
||||
wlclient_destroy_shm_buffer(top->buf);
|
||||
top->buf = NULL;
|
||||
}
|
||||
top->configured = 0;
|
||||
top->mapped = 0;
|
||||
top->want_close = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_client_toplevel_remap_locked(WLClientToplevel *top)
|
||||
{
|
||||
if (!top || top->surface) return; /* already mapped */
|
||||
WLClientCtx *ctx = top->ctx;
|
||||
if (!ctx || !ctx->compositor || !ctx->wm_base) return;
|
||||
|
||||
top->buf = wlclient_create_shm_buffer(ctx,
|
||||
top->pending_w, top->pending_h);
|
||||
if (!top->buf) return;
|
||||
|
||||
top->surface = wl_compositor_create_surface(ctx->compositor);
|
||||
if (!top->surface) return;
|
||||
|
||||
top->xdg_surface = xdg_wm_base_get_xdg_surface(
|
||||
ctx->wm_base, top->surface);
|
||||
if (!top->xdg_surface) return;
|
||||
xdg_surface_add_listener(top->xdg_surface,
|
||||
&xdg_surface_listener, top);
|
||||
|
||||
top->xdg_toplevel = xdg_surface_get_toplevel(
|
||||
top->xdg_surface);
|
||||
if (!top->xdg_toplevel) return;
|
||||
xdg_toplevel_add_listener(top->xdg_toplevel,
|
||||
&xdg_toplevel_listener, top);
|
||||
|
||||
if (top->view->flags.popup) {
|
||||
xdg_toplevel_set_app_id(top->xdg_toplevel, "wings-popup");
|
||||
xdg_toplevel_set_title(top->xdg_toplevel, "");
|
||||
if (ctx->wmaker_popup_mgr) {
|
||||
top->wmaker_popup =
|
||||
wmaker_popup_manager_v1_get_popup(
|
||||
ctx->wmaker_popup_mgr,
|
||||
top->xdg_toplevel);
|
||||
if (top->wmaker_popup && ctx->main_toplevel)
|
||||
wmaker_popup_v1_set_parent(
|
||||
top->wmaker_popup,
|
||||
ctx->main_toplevel);
|
||||
}
|
||||
}
|
||||
|
||||
wl_surface_commit(top->surface);
|
||||
W_SetViewBacking(top->view->window, top->buf->image);
|
||||
}
|
||||
|
||||
void
|
||||
wl_client_toplevel_remap(WNativeWindow id)
|
||||
{
|
||||
WLClientToplevel *top = wlc_top_find(id);
|
||||
wl_client_toplevel_remap_locked(top);
|
||||
}
|
||||
|
||||
void
|
||||
W_WLClientSetMinMaxSize(W_View *view)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ 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;
|
||||
/* Optional hook: destroy wl_surface + xdg_toplevel on popup unmap
|
||||
* so the compositor has no stale state. Set by the WM backend. */
|
||||
void (*W_WLClientToplevelRecycleFn)(unsigned long id) = NULL;
|
||||
void (*W_WLClientToplevelRemapFn)(unsigned long id) = NULL;
|
||||
void (*W_ViewDestroyBackingFn)(unsigned long id) = NULL;
|
||||
void (*W_ViewSceneNodeSetEnabledFn)(unsigned long id, int enabled) = NULL;
|
||||
|
||||
|
|
@ -211,6 +215,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);
|
||||
/* Destroy the WINGs client wl_surface + xdg_toplevel on unmap so
|
||||
* the compositor has no stale state for this surface. The recycle
|
||||
* function preserves the WLClientToplevel struct and ID mapping
|
||||
* so the surface can be recreated on the next map. */
|
||||
if (view->flags.topLevel && view->flags.popup && W_WLClientToplevelRecycleFn)
|
||||
W_WLClientToplevelRecycleFn((unsigned long)view->window);
|
||||
if (view->parent && view->parent->flags.mapped)
|
||||
wl_redisplay(vctx, view->parent);
|
||||
}
|
||||
|
|
@ -305,7 +315,10 @@ static void wl_map(void *vctx, W_View *view)
|
|||
child = child->nextSister;
|
||||
}
|
||||
}
|
||||
/* Re-enable scene node after unmap so the surface becomes visible again. */
|
||||
/* Re-enable scene node after unmap so the surface becomes visible again.
|
||||
* For recycled popups, recreate the wl_surface + xdg_toplevel first. */
|
||||
if (view->flags.topLevel && view->flags.popup && W_WLClientToplevelRemapFn)
|
||||
W_WLClientToplevelRemapFn((unsigned long)view->window);
|
||||
if (W_ViewSceneNodeSetEnabledFn)
|
||||
W_ViewSceneNodeSetEnabledFn((unsigned long)view->window, 1);
|
||||
|
||||
|
|
|
|||
|
|
@ -470,6 +470,12 @@ wl_display_open(const char *name)
|
|||
unsigned int, int, int, unsigned long);
|
||||
extern void wl_pointer_ungrab(unsigned long);
|
||||
W_WLPointerGrabFn = wl_pointer_grab;
|
||||
extern void (*W_WLClientToplevelRecycleFn)(unsigned long);
|
||||
extern void wl_client_toplevel_recycle(WNativeWindow);
|
||||
W_WLClientToplevelRecycleFn = wl_client_toplevel_recycle;
|
||||
extern void (*W_WLClientToplevelRemapFn)(unsigned long);
|
||||
extern void wl_client_toplevel_remap(WNativeWindow);
|
||||
W_WLClientToplevelRemapFn = wl_client_toplevel_remap;
|
||||
W_WLPointerUngrabFn = wl_pointer_ungrab;
|
||||
|
||||
extern void (*W_ClipboardStoreFn)(const char *text, int len);
|
||||
|
|
|
|||
Loading…
Reference in New Issue