From ac093dc65142803601838d32dd85ed993892c7f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 28 Sep 2022 22:52:54 +0200 Subject: [PATCH] wayland/xdg-shell: Send xdg_popup.popup_done when position invalid A client may provide a positioner that places the window outside of its parent. This isn't allowed, according to spec, so we hide the window and log a warning. This, however, leads these affected clients with an incorrect view of what is mapped or not, meaning it becomes harder to recover. Fix this by sending xdg_popup.done when we hide the popup due to an invalid position. Don't error out the client, let the bug slide, as that's a less jarring experience for existing applications that reproduce this than being disconnected, which practically feels like a crash. Related: https://gitlab.gnome.org/GNOME/mutter/-/issues/2408 Part-of: --- src/wayland/meta-wayland-xdg-shell.c | 39 +++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c index 5ae8408c7..485aa01f5 100644 --- a/src/wayland/meta-wayland-xdg-shell.c +++ b/src/wayland/meta-wayland-xdg-shell.c @@ -184,6 +184,12 @@ surface_from_xdg_toplevel_resource (struct wl_resource *resource) return surface_from_xdg_surface_resource (resource); } +static MetaWaylandXdgPopup * +meta_wayland_xdg_popup_from_surface (MetaWaylandSurface *surface) +{ + return META_WAYLAND_XDG_POPUP (surface->role); +} + static void meta_wayland_xdg_surface_reset (MetaWaylandXdgSurface *xdg_surface) { @@ -1131,6 +1137,37 @@ finish_popup_setup (MetaWaylandXdgPopup *xdg_popup) } } +static void +dismiss_invalid_popup (MetaWaylandXdgPopup *xdg_popup) +{ + if (xdg_popup->popup) + { + while (TRUE) + { + MetaWaylandSurface *top_popup_surface; + MetaWaylandXdgPopup *top_xdg_popup; + + top_popup_surface = + meta_wayland_popup_get_top_popup (xdg_popup->popup); + if (!top_popup_surface) + break; + + top_xdg_popup = meta_wayland_xdg_popup_from_surface (top_popup_surface); + + xdg_popup_send_popup_done (top_xdg_popup->resource); + meta_wayland_popup_destroy (top_xdg_popup->popup); + + if (top_xdg_popup == xdg_popup) + break; + } + } + else + { + xdg_popup_send_popup_done (xdg_popup->resource); + meta_wayland_xdg_popup_unmap (xdg_popup); + } +} + static void meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role, MetaWaylandSurfaceState *pending) @@ -1211,7 +1248,7 @@ meta_wayland_xdg_popup_post_apply_state (MetaWaylandSurfaceRole *surface_role, { g_warning ("Buggy client caused popup to be placed outside of " "parent window"); - dismiss_popup (xdg_popup); + dismiss_invalid_popup (xdg_popup); } }