From 7cc8879ab9cda31e7afc899cb7f36829fe7aa23d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 30 Nov 2023 02:43:48 +0100 Subject: [PATCH] Wayland: Use Wayland to wait for libdecor to init Much of libdecor is initialized only after certain events have been received from the compositor and some parts of libdecor 0.1 are unsafe to use until this delayed initialization has completed. Since libdecor does not provide an API to query if or be notified when this has happened, GLFW processed events until its newly created libdecor frame had created its XDG shell objects. This commit switches to using a generic Wayland sync point created just after libdecor (and presumably its plugin) has set up its delayed initialization, instead of relying on the more specific implementation detail mentioned above. It also makes this wait mandatory before the first libdecor frame is created instead of a pre-condition for certain libdecor frame calls, hopefully removing even more dependence on implementation details. (cherry picked from commit 9fdc425931888ea70bc095e53cc006fca8ccb703) --- src/wl_init.c | 32 +++++++++++++++++++++++++++++--- src/wl_platform.h | 2 ++ src/wl_window.c | 10 ++++------ 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/wl_init.c b/src/wl_init.c index 8b4b33e4..bc786677 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -40,6 +40,7 @@ #include #include #include +#include static void wmBaseHandlePing(void* userData, struct xdg_wm_base* wmBase, @@ -177,6 +178,22 @@ static const struct libdecor_interface libdecorInterface = libdecorHandleError }; +static void libdecorReadyCallback(void* userData, + struct wl_callback* callback, + uint32_t time) +{ + _glfw.wl.libdecor.ready = GLFW_TRUE; + + assert(_glfw.wl.libdecor.callback == callback); + wl_callback_destroy(_glfw.wl.libdecor.callback); + _glfw.wl.libdecor.callback = NULL; +} + +static const struct wl_callback_listener libdecorReadyListener = +{ + libdecorReadyCallback +}; + // Create key code translation tables // static void createKeyTables(void) @@ -563,10 +580,17 @@ int _glfwPlatformInit(void) if (_glfw.wl.libdecor.handle) { _glfw.wl.libdecor.context = libdecor_new(_glfw.wl.display, &libdecorInterface); - - // Allow libdecor to receive its globals before proceeding if (_glfw.wl.libdecor.context) - libdecor_dispatch(_glfw.wl.libdecor.context, 1); + { + // Perform an initial dispatch and flush to get the init started + libdecor_dispatch(_glfw.wl.libdecor.context, 0); + + // Create sync point to "know" when libdecor is ready for use + _glfw.wl.libdecor.callback = wl_display_sync(_glfw.wl.display); + wl_callback_add_listener(_glfw.wl.libdecor.callback, + &libdecorReadyListener, + NULL); + } } #ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION @@ -613,6 +637,8 @@ void _glfwPlatformTerminate(void) _glfwTerminateEGL(); _glfwTerminateOSMesa(); + if (_glfw.wl.libdecor.callback) + wl_callback_destroy(_glfw.wl.libdecor.callback); if (_glfw.wl.libdecor.context) libdecor_unref(_glfw.wl.libdecor.context); diff --git a/src/wl_platform.h b/src/wl_platform.h index 4392dced..8affdd16 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -467,6 +467,8 @@ typedef struct _GLFWlibraryWayland struct { void* handle; struct libdecor* context; + struct wl_callback* callback; + GLFWbool ready; PFN_libdecor_new libdecor_new_; PFN_libdecor_unref libdecor_unref_; PFN_libdecor_get_fd libdecor_get_fd_; diff --git a/src/wl_window.c b/src/wl_window.c index d3493d11..a9c71b6e 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -774,6 +774,10 @@ static const struct libdecor_frame_interface libdecorFrameInterface = static GLFWbool createLibdecorFrame(_GLFWwindow* window) { + // Allow libdecor to finish initialization of itself and its plugin + while (!_glfw.wl.libdecor.ready) + _glfwPlatformWaitEvents(); + window->wl.libdecor.frame = libdecor_decorate(_glfw.wl.libdecor.context, window->wl.surface, &libdecorFrameInterface, @@ -812,12 +816,6 @@ static GLFWbool createLibdecorFrame(_GLFWwindow* window) if (window->monitor) { - // HACK: Allow libdecor to finish initialization of itself and its - // plugin so it will create the xdg_toplevel for the frame - // This needs to exist when setting the frame to fullscreen - while (!libdecor_frame_get_xdg_toplevel(window->wl.libdecor.frame)) - _glfwPlatformWaitEvents(); - libdecor_frame_set_fullscreen(window->wl.libdecor.frame, window->monitor->wl.output); setIdleInhibitor(window, GLFW_TRUE);