Просмотр исходного кода

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.
Frank Praznik 4 месяцев назад
Родитель
Сommit
f6a05121ec

+ 2 - 14
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);
     }
 }
 

+ 28 - 1
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);

+ 3 - 3
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_

+ 15 - 3
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 {