From 230eefd8d37c87ae71e62ab3f0aaccd338e80342 Mon Sep 17 00:00:00 2001 From: lkn Date: Sun, 7 Jun 2026 16:39:15 +0200 Subject: [PATCH] wl_client_view_unmap: use 1x1 transparent buffer instead of NULL to avoid xdg unmap NULL-buffer unmap triggers a wlroots xdg_surface unmap, which requires a configure/ack cycle before the next buffer attach. This creates a race window where the popup reopen cannot commit its real buffer yet, causing the click to hit the main window instead of the popup. Fix: replace the popup buffer with a 1x1 transparent ARGB buffer instead of attaching NULL. This hides the popup visually (the tiny buffer is invisible) without unmapping the xdg_surface. The surface stays configured and alive, so the next popup open can commit a real buffer immediately without waiting for a configure event. Also: always call resizeMenu() in popUpMenu to ensure the backing buffer is recreated at the correct dimensions after the 1x1 replacement. --- WINGs/wclient_wl.c | 19 +++++++++---------- WINGs/wpopupbutton.c | 6 ++++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/WINGs/wclient_wl.c b/WINGs/wclient_wl.c index 9ad4c4a..d86d7b2 100644 --- a/WINGs/wclient_wl.c +++ b/WINGs/wclient_wl.c @@ -568,17 +568,16 @@ wl_client_view_unmap(WNativeWindow id) { WLClientToplevel *top = wlc_top_find(id); if (!top || !top->surface) return; - /* Attach NULL + commit: the standard Wayland way - * for a client to hide a surface from the compositor. - * The xdg_toplevel object stays alive for remap. */ - /* Attach NULL + commit: the standard Wayland way for a client to - * hide a surface. This triggers a wlroots unmap and the compositor - * will send a new xdg_surface.configure before we can re-attach a - * real buffer. We set configured=0 so wl_client_toplevel_commit_locked - * blocks all buffer attachments until the configure arrives. */ - wl_surface_attach(top->surface, NULL, 0, 0); + /* Replace the popup buffer with a 1x1 transparent pixel instead of + * attaching NULL (which triggers a wlroots xdg unmap + configure + * cycle). A 1x1 invisible buffer keeps the surface alive and + * configured, so the next popup open can commit immediately. */ + if (top->buf) wlclient_destroy_shm_buffer(top->buf); + top->buf = wlclient_create_shm_buffer(top->ctx, 1, 1); + if (!top->buf) return; + wl_surface_attach(top->surface, top->buf->wl_buf, 0, 0); + wl_surface_damage_buffer(top->surface, 0, 0, 1, 1); wl_surface_commit(top->surface); - top->configured = 0; if (top->ctx && top->ctx->display) wl_display_flush(top->ctx->display); } diff --git a/WINGs/wpopupbutton.c b/WINGs/wpopupbutton.c index b15da2a..8e982eb 100644 --- a/WINGs/wpopupbutton.c +++ b/WINGs/wpopupbutton.c @@ -481,8 +481,10 @@ static void popUpMenu(PopUpButton * bPtr) /* Resize before map so the backing has the correct dimensions * before any rendering or commit happens. */ - if (W_VIEW_WIDTH(bPtr->menuView) != W_VIEW_WIDTH(bPtr->view)) - resizeMenu(bPtr); + /* Always resize to ensure the backing matches the current item count + * and pointer position. After a 1x1-buffer unmap, the buffer must be + * recreated at the correct dimensions before wl_redisplay paints. */ + resizeMenu(bPtr); /* Map first — wl_map calls wl_redisplay internally, which fills * the background and dispatches WME_EXPOSE to paint all entries.