From c807f386c28738edd330ccb6f81431e9e1b7c5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 20 Jun 2022 00:43:24 +0200 Subject: [PATCH] Wayland: Fix mapping failure on wlroots compositor When showing a window that had already been shown once (and so already had its shell objects), GLFW would attach a new buffer and commit it before waiting for the next configure event. This was a violation of the XDG shell protocol. This was allowed to work as intended on GNOME and KDE without error. However wlroots based compositors would (correctly) emit an error. Unfortunately, I haven't been able to find a way to get both KDE, GNOME and Sway to send the configure event we need in order to map the wl_surface again while keeping our existing shell objects, so with this commit we now create them for each call to glfwShowWindow and destroy them for each call to glfwHideWindow. Fixes #1268 (cherry picked from commit 83a134a92fa8642fe50c6e9b2400044e442d038a) --- README.md | 2 ++ src/wl_window.c | 52 +++++++++++++++++++++++++++++++------------------ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index d83c4b50..6b789908 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,8 @@ information on what to include when reporting a bug. applying the specified ratio - [Wayland] Bugfix: `GLFW_MAXIMIZED` window hint had no effect - [Wayland] Bugfix: `glfwRestoreWindow` had no effect before first show + - [Wayland] Bugfix: Hiding and then showing a window caused program abort on + wlroots compositors (#1268) ## Contact diff --git a/src/wl_window.c b/src/wl_window.c index e54419fb..6d301da8 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -605,6 +605,14 @@ static void xdgSurfaceHandleConfigure(void* userData, resizeWindow(window); _glfwInputWindowSize(window, width, height); + + if (window->wl.visible) + _glfwInputWindowDamage(window); + } + + if (!window->wl.visible) + { + window->wl.visible = GLFW_TRUE; _glfwInputWindowDamage(window); } } @@ -614,7 +622,7 @@ static const struct xdg_surface_listener xdgSurfaceListener = xdgSurfaceHandleConfigure }; -static GLFWbool createXdgSurface(_GLFWwindow* window) +static GLFWbool createShellObjects(_GLFWwindow* window) { window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase, window->wl.surface); @@ -710,6 +718,24 @@ static GLFWbool createXdgSurface(_GLFWwindow* window) return GLFW_TRUE; } +static void destroyShellObjects(_GLFWwindow* window) +{ + destroyFallbackDecorations(window); + + if (window->wl.xdg.decoration) + zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration); + + if (window->wl.xdg.toplevel) + xdg_toplevel_destroy(window->wl.xdg.toplevel); + + if (window->wl.xdg.surface) + xdg_surface_destroy(window->wl.xdg.surface); + + window->wl.xdg.decoration = NULL; + window->wl.xdg.toplevel = NULL; + window->wl.xdg.surface = NULL; +} + static GLFWbool createNativeSurface(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig) @@ -749,10 +775,8 @@ static GLFWbool createNativeSurface(_GLFWwindow* window, if (window->monitor || wndconfig->visible) { - if (!createXdgSurface(window)) + if (!createShellObjects(window)) return GLFW_FALSE; - - window->wl.visible = GLFW_TRUE; } return GLFW_TRUE; @@ -1882,9 +1906,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) if (window->context.destroy) window->context.destroy(window); - destroyFallbackDecorations(window); - if (window->wl.xdg.decoration) - zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration); + destroyShellObjects(window); if (window->wl.decorations.buffer) wl_buffer_destroy(window->wl.decorations.buffer); @@ -1892,12 +1914,6 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) if (window->wl.egl.window) wl_egl_window_destroy(window->wl.egl.window); - if (window->wl.xdg.toplevel) - xdg_toplevel_destroy(window->wl.xdg.toplevel); - - if (window->wl.xdg.surface) - xdg_surface_destroy(window->wl.xdg.surface); - if (window->wl.surface) wl_surface_destroy(window->wl.surface); @@ -2086,15 +2102,11 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window) void _glfwPlatformShowWindow(_GLFWwindow* window) { - if (!window->wl.visible) + if (!window->wl.xdg.toplevel) { // NOTE: The XDG/shell surface is created here so command-line applications // with off-screen windows do not appear in for example the Unity dock - if (!window->wl.xdg.toplevel) - createXdgSurface(window); - - window->wl.visible = GLFW_TRUE; - _glfwInputWindowDamage(window); + createShellObjects(window); } } @@ -2103,6 +2115,8 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) if (window->wl.visible) { window->wl.visible = GLFW_FALSE; + destroyShellObjects(window); + wl_surface_attach(window->wl.surface, NULL, 0, 0); wl_surface_commit(window->wl.surface); }