From 5290bb036c206e117ff8d8e627f9b28acf1671e4 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Mon, 30 Jun 2025 11:40:20 -0400
Subject: [PATCH] wayland: Ensure that the xdg_surface is always configured
after creation
The spec states that xdg_surface must have seen an initial configure event before attaching a buffer, however, this was only being done when initially showing the window, and not after show->hide->show cycle.
Always wait for the initial configure event when (re)creating an xdg_surface as part of the show window sequence.
(cherry picked from commit ecdc6f2adbe20d46ae6e2b7cf05c95ed9bdd369e)
---
src/video/wayland/SDL_waylandwindow.c | 54 ++++++++++++---------------
src/video/wayland/SDL_waylandwindow.h | 2 -
2 files changed, 23 insertions(+), 33 deletions(-)
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index 1fea144e17032..e43584e150d59 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -181,7 +181,7 @@ static void SetMinMaxDimensions(SDL_Window *window)
#ifdef HAVE_LIBDECOR_H
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
- if (!wind->shell_surface.libdecor.initial_configure_seen || !wind->shell_surface.libdecor.frame) {
+ if (!wind->shell_surface.libdecor.frame) {
return; // Can't do anything yet, wait for ShowWindow
}
/* No need to change these values if the window is non-resizable,
@@ -198,7 +198,7 @@ static void SetMinMaxDimensions(SDL_Window *window)
} else
#endif
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) {
- if (wind->shell_surface.xdg.toplevel.xdg_toplevel == NULL) {
+ if (!wind->shell_surface.xdg.toplevel.xdg_toplevel) {
return; // Can't do anything yet, wait for ShowWindow
}
xdg_toplevel_set_min_size(wind->shell_surface.xdg.toplevel.xdg_toplevel,
@@ -753,7 +753,9 @@ static void handle_configure_xdg_shell_surface(void *data, struct xdg_surface *x
xdg_surface_ack_configure(xdg, serial);
}
- wind->shell_surface.xdg.initial_configure_seen = true;
+ if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
+ wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME;
+ }
}
static const struct xdg_surface_listener shell_surface_listener_xdg = {
@@ -970,10 +972,6 @@ static void handle_configure_xdg_toplevel(void *data,
wind->active = active;
window->tiled = tiled;
wind->resizing = resizing;
-
- if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
- wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME;
- }
}
static void handle_close_xdg_toplevel(void *data, struct xdg_toplevel *xdg_toplevel)
@@ -1122,9 +1120,7 @@ static void handle_configure_zxdg_decoration(void *data,
WAYLAND_wl_display_roundtrip(internal->waylandData->display);
Wayland_HideWindow(device, window);
- SDL_zero(internal->shell_surface);
internal->shell_surface_type = WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR;
-
Wayland_ShowWindow(device, window);
}
}
@@ -1406,11 +1402,8 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
libdecor_state_free(state);
}
- if (!wind->shell_surface.libdecor.initial_configure_seen) {
- LibdecorGetMinContentSize(frame, &wind->system_limits.min_width, &wind->system_limits.min_height);
- wind->shell_surface.libdecor.initial_configure_seen = true;
- }
if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
+ LibdecorGetMinContentSize(frame, &wind->system_limits.min_width, &wind->system_limits.min_height);
wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME;
}
@@ -1819,12 +1812,10 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
}
}
- /* The window was hidden, but the sync point hasn't yet been reached.
- * Pump events to avoid a possible protocol violation.
- */
- if (data->show_hide_sync_required) {
+ // Always roundtrip to ensure there are no pending buffer attachments.
+ do {
WAYLAND_wl_display_roundtrip(c->display);
- }
+ } while (data->show_hide_sync_required);
data->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE;
@@ -1984,7 +1975,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
#ifdef HAVE_LIBDECOR_H
if (data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
if (data->shell_surface.libdecor.frame) {
- while (!data->shell_surface.libdecor.initial_configure_seen) {
+ while (data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
WAYLAND_wl_display_flush(c->display);
WAYLAND_wl_display_dispatch(c->display);
}
@@ -1998,7 +1989,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
*/
wl_surface_commit(data->surface);
if (data->shell_surface.xdg.surface) {
- while (!data->shell_surface.xdg.initial_configure_seen) {
+ while (data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
WAYLAND_wl_display_flush(c->display);
WAYLAND_wl_display_dispatch(c->display);
}
@@ -2158,26 +2149,27 @@ void Wayland_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
if (wind->shell_surface.libdecor.frame) {
libdecor_frame_unref(wind->shell_surface.libdecor.frame);
- wind->shell_surface.libdecor.frame = NULL;
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER, NULL);
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, NULL);
}
} else
#endif
+ {
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP) {
- Wayland_ReleasePopup(_this, window);
- } else if (wind->shell_surface.xdg.toplevel.xdg_toplevel) {
- xdg_toplevel_destroy(wind->shell_surface.xdg.toplevel.xdg_toplevel);
- wind->shell_surface.xdg.toplevel.xdg_toplevel = NULL;
- SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, NULL);
- }
- if (wind->shell_surface.xdg.surface) {
- xdg_surface_destroy(wind->shell_surface.xdg.surface);
- wind->shell_surface.xdg.surface = NULL;
- SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER, NULL);
+ Wayland_ReleasePopup(_this, window);
+ } else if (wind->shell_surface.xdg.toplevel.xdg_toplevel) {
+ xdg_toplevel_destroy(wind->shell_surface.xdg.toplevel.xdg_toplevel);
+ SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, NULL);
+ }
+
+ if (wind->shell_surface.xdg.surface) {
+ xdg_surface_destroy(wind->shell_surface.xdg.surface);
+ SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER, NULL);
+ }
}
+ SDL_zero(wind->shell_surface);
wind->show_hide_sync_required = true;
struct wl_callback *cb = wl_display_sync(_this->internal->display);
wl_callback_add_listener(cb, &show_hide_sync_listener, (void*)((uintptr_t)window->id));
diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h
index ee27f337b8805..1afec8892f0e7 100644
--- a/src/video/wayland/SDL_waylandwindow.h
+++ b/src/video/wayland/SDL_waylandwindow.h
@@ -48,7 +48,6 @@ struct SDL_WindowData
struct
{
struct libdecor_frame *frame;
- bool initial_configure_seen;
} libdecor;
#endif
struct
@@ -66,7 +65,6 @@ struct SDL_WindowData
struct xdg_positioner *xdg_positioner;
} popup;
};
- bool initial_configure_seen;
} xdg;
} shell_surface;
enum