From dd2e3182116c9b0e07a157adb0ef286a49708fda Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Sat, 6 Aug 2022 12:31:06 -0400 Subject: [PATCH] wayland: Use libdecor visibility toggle for hiding/showing the window The current method of toggling the libdecor window visibility by destroying and recreating the frame results in a race where a use-after-free bug can manifest itself within libdecor when window visibility is toggled quickly. Instead, use the libdecor function for toggling visibility instead of destroying and recreating the frame every time. --- src/video/wayland/SDL_waylandwindow.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index c5b997c7b..a94063d93 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -1228,15 +1228,20 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) /* Create the shell surface and map the toplevel/popup */ #ifdef HAVE_LIBDECOR_H if (WINDOW_IS_LIBDECOR(c, window)) { - data->shell_surface.libdecor.frame = libdecor_decorate(c->shell.libdecor, - data->surface, - &libdecor_frame_interface, - data); - if (data->shell_surface.libdecor.frame == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Failed to create libdecor frame!"); + if (data->shell_surface.libdecor.frame) { + /* If the frame already exists, just set the visibility. */ + libdecor_frame_set_visibility(data->shell_surface.libdecor.frame, true); } else { - libdecor_frame_set_app_id(data->shell_surface.libdecor.frame, c->classname); - libdecor_frame_map(data->shell_surface.libdecor.frame); + data->shell_surface.libdecor.frame = libdecor_decorate(c->shell.libdecor, + data->surface, + &libdecor_frame_interface, + data); + if (data->shell_surface.libdecor.frame == NULL) { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Failed to create libdecor frame!"); + } else { + libdecor_frame_set_app_id(data->shell_surface.libdecor.frame, c->classname); + libdecor_frame_map(data->shell_surface.libdecor.frame); + } } } else #endif @@ -1425,8 +1430,7 @@ void Wayland_HideWindow(_THIS, SDL_Window *window) #ifdef HAVE_LIBDECOR_H if (WINDOW_IS_LIBDECOR(data, window)) { if (wind->shell_surface.libdecor.frame) { - libdecor_frame_unref(wind->shell_surface.libdecor.frame); - wind->shell_surface.libdecor.frame = NULL; + libdecor_frame_set_visibility(wind->shell_surface.libdecor.frame, false); } } else #endif