From f6a05121ec9cad153423c995e394e8765e001655 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Sun, 9 Nov 2025 12:01:53 -0500
Subject: [PATCH] wayland: Handle dispatch errors when showing a window
If a dispatch event when showing a window returns a failure code, handle the display disconnected condition and break out of the loop, otherwise, it will hang forever.
---
src/video/wayland/SDL_waylandevents.c | 16 ++-------------
src/video/wayland/SDL_waylandvideo.c | 29 ++++++++++++++++++++++++++-
src/video/wayland/SDL_waylandvideo.h | 6 +++---
src/video/wayland/SDL_waylandwindow.c | 18 ++++++++++++++---
4 files changed, 48 insertions(+), 21 deletions(-)
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index b69116a07e603..ee1378dec22e4 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -671,20 +671,8 @@ void Wayland_PumpEvents(SDL_VideoDevice *_this)
}
connection_error:
- if (ret < 0 && !d->display_disconnected) {
- /* Something has failed with the Wayland connection -- for example,
- * the compositor may have shut down and closed its end of the socket,
- * or there is a library-specific error.
- *
- * Try to recover once, then quit.
- */
- if (!Wayland_VideoReconnect(_this)) {
- d->display_disconnected = 1;
- SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Wayland display connection closed by server (fatal)");
-
- // Only send a single quit message, as application shutdown might call SDL_PumpEvents().
- SDL_SendQuit();
- }
+ if (ret < 0) {
+ Wayland_HandleDisplayDisconnected(_this);
}
}
diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index bddf90320c0e9..848e43740a835 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -1681,7 +1681,7 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this)
}
}
-bool Wayland_VideoReconnect(SDL_VideoDevice *_this)
+static bool Wayland_VideoReconnect(SDL_VideoDevice *_this)
{
#if 0 // TODO RECONNECT: Uncomment all when https://invent.kde.org/plasma/kwin/-/wikis/Restarting is completed
SDL_VideoData *data = _this->internal;
@@ -1728,6 +1728,33 @@ bool Wayland_VideoReconnect(SDL_VideoDevice *_this)
#endif // 0
}
+bool Wayland_HandleDisplayDisconnected(SDL_VideoDevice *_this)
+{
+ SDL_VideoData *video_data = _this->internal;
+
+ /* Something has failed with the Wayland connection -- for example,
+ * the compositor may have shut down and closed its end of the socket,
+ * or there is a library-specific error.
+ *
+ * Try to recover once, then quit.
+ */
+ if (video_data->display_disconnected) {
+ return false;
+ }
+
+ if (Wayland_VideoReconnect(_this)) {
+ return true;
+ }
+
+ video_data->display_disconnected = true;
+ SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Wayland display connection closed by server (fatal)");
+
+ // Only send a single quit message, as application shutdown might call SDL_PumpEvents().
+ SDL_SendQuit();
+
+ return false;
+}
+
void Wayland_VideoQuit(SDL_VideoDevice *_this)
{
Wayland_VideoCleanup(_this);
diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
index e2ae097decee1..bab5d51d9235c 100644
--- a/src/video/wayland/SDL_waylandvideo.h
+++ b/src/video/wayland/SDL_waylandvideo.h
@@ -48,9 +48,7 @@ typedef struct
struct SDL_VideoData
{
- bool initializing;
struct wl_display *display;
- int display_disconnected;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_shm *shm;
@@ -99,6 +97,8 @@ struct SDL_VideoData
int output_count;
int output_max;
+ bool initializing;
+ bool display_disconnected;
bool display_externally_owned;
bool scale_to_display_enabled;
};
@@ -140,6 +140,6 @@ struct wl_event_queue *Wayland_DisplayCreateQueue(struct wl_display *display, co
extern bool Wayland_LoadLibdecor(SDL_VideoData *data, bool ignore_xdg);
-extern bool Wayland_VideoReconnect(SDL_VideoDevice *_this);
+extern bool Wayland_HandleDisplayDisconnected(SDL_VideoDevice *_this);
#endif // SDL_waylandvideo_h_
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index 7eb6d104afded..5fddec7221fda 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -2036,8 +2036,16 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
if (data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
if (data->shell_surface.libdecor.frame) {
while (data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
- libdecor_dispatch(c->shell.libdecor, -1);
- WAYLAND_wl_display_dispatch_pending(c->display);
+ if (libdecor_dispatch(c->shell.libdecor, -1) < 0) {
+ if (!Wayland_HandleDisplayDisconnected(_this)) {
+ return;
+ }
+ }
+ if (WAYLAND_wl_display_dispatch_pending(c->display) < 0) {
+ if (!Wayland_HandleDisplayDisconnected(_this)) {
+ return;
+ }
+ }
}
}
} else
@@ -2050,7 +2058,11 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
wl_surface_commit(data->surface);
if (data->shell_surface.xdg.surface) {
while (data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
- WAYLAND_wl_display_dispatch(c->display);
+ if (WAYLAND_wl_display_dispatch(c->display) < 0) {
+ if (!Wayland_HandleDisplayDisconnected(_this)) {
+ return;
+ }
+ }
}
}
} else {