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
This commit is contained in:
Camilla Löwy 2022-06-20 00:43:24 +02:00
parent eb9c3bee71
commit 83a134a92f
2 changed files with 35 additions and 19 deletions

View File

@ -359,6 +359,8 @@ information on what to include when reporting a bug.
applying the specified ratio applying the specified ratio
- [Wayland] Bugfix: `GLFW_MAXIMIZED` window hint had no effect - [Wayland] Bugfix: `GLFW_MAXIMIZED` window hint had no effect
- [Wayland] Bugfix: `glfwRestoreWindow` had no effect before first show - [Wayland] Bugfix: `glfwRestoreWindow` had no effect before first show
- [Wayland] Bugfix: Hiding and then showing a window caused program abort on
wlroots compositors (#1268)
- [POSIX] Removed use of deprecated function `gettimeofday` - [POSIX] Removed use of deprecated function `gettimeofday`
- [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled - [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled
- [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072) - [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072)

View File

@ -562,6 +562,14 @@ static void xdgSurfaceHandleConfigure(void* userData,
resizeWindow(window); resizeWindow(window);
_glfwInputWindowSize(window, width, height); _glfwInputWindowSize(window, width, height);
if (window->wl.visible)
_glfwInputWindowDamage(window);
}
if (!window->wl.visible)
{
window->wl.visible = GLFW_TRUE;
_glfwInputWindowDamage(window); _glfwInputWindowDamage(window);
} }
} }
@ -571,7 +579,7 @@ static const struct xdg_surface_listener xdgSurfaceListener =
xdgSurfaceHandleConfigure 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.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase,
window->wl.surface); window->wl.surface);
@ -667,6 +675,24 @@ static GLFWbool createXdgSurface(_GLFWwindow* window)
return GLFW_TRUE; 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, static GLFWbool createNativeSurface(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig, const _GLFWwndconfig* wndconfig,
const _GLFWfbconfig* fbconfig) const _GLFWfbconfig* fbconfig)
@ -706,10 +732,8 @@ static GLFWbool createNativeSurface(_GLFWwindow* window,
if (window->monitor || wndconfig->visible) if (window->monitor || wndconfig->visible)
{ {
if (!createXdgSurface(window)) if (!createShellObjects(window))
return GLFW_FALSE; return GLFW_FALSE;
window->wl.visible = GLFW_TRUE;
} }
return GLFW_TRUE; return GLFW_TRUE;
@ -1818,9 +1842,7 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window)
if (window->context.destroy) if (window->context.destroy)
window->context.destroy(window); window->context.destroy(window);
destroyFallbackDecorations(window); destroyShellObjects(window);
if (window->wl.xdg.decoration)
zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration);
if (window->wl.decorations.buffer) if (window->wl.decorations.buffer)
wl_buffer_destroy(window->wl.decorations.buffer); wl_buffer_destroy(window->wl.decorations.buffer);
@ -1828,12 +1850,6 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window)
if (window->wl.egl.window) if (window->wl.egl.window)
wl_egl_window_destroy(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) if (window->wl.surface)
wl_surface_destroy(window->wl.surface); wl_surface_destroy(window->wl.surface);
@ -2021,15 +2037,11 @@ void _glfwMaximizeWindowWayland(_GLFWwindow* window)
void _glfwShowWindowWayland(_GLFWwindow* window) void _glfwShowWindowWayland(_GLFWwindow* window)
{ {
if (!window->wl.visible) if (!window->wl.xdg.toplevel)
{ {
// NOTE: The XDG surface and role are created here so command-line applications // NOTE: The XDG surface and role are created here so command-line applications
// with off-screen windows do not appear in for example the Unity dock // with off-screen windows do not appear in for example the Unity dock
if (!window->wl.xdg.toplevel) createShellObjects(window);
createXdgSurface(window);
window->wl.visible = GLFW_TRUE;
_glfwInputWindowDamage(window);
} }
} }
@ -2038,6 +2050,8 @@ void _glfwHideWindowWayland(_GLFWwindow* window)
if (window->wl.visible) if (window->wl.visible)
{ {
window->wl.visible = GLFW_FALSE; window->wl.visible = GLFW_FALSE;
destroyShellObjects(window);
wl_surface_attach(window->wl.surface, NULL, 0, 0); wl_surface_attach(window->wl.surface, NULL, 0, 0);
wl_surface_commit(window->wl.surface); wl_surface_commit(window->wl.surface);
} }