Fixed bug 4689 - SDL fails to detect compositor shutdown on Wayland -- program keeps running

M Stoeckl

To reproduce:

1. Run any SDL-based program with a Wayland compositor, orphaning it so that it doesn't have an immediate parent process. (For example, from a terminal, running `supertux2 & disown`.) The program should use the wayland backend, i.e. by setting environment variable SDL_VIDEODRIVER=wayland.
2. Kill the compositor process.

Results:

- The SDL program will keep running.

Expected results:

- The SDL program should close. (What close should mean here, I'm not sure - is injecting an SDL_Quit the appropriate action when a video driver disconnects?)

Build data:

2019-06-22, hg tip (12901:5cbf6472a916), Linux, can reproduce with sway, weston, and other Wayland oompositors.
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index f9397fd..2f842e1 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -178,15 +178,23 @@
 Wayland_PumpEvents(_THIS)
 {
     SDL_VideoData *d = _this->driverdata;
+    int err;
 
     WAYLAND_wl_display_flush(d->display);
 
     if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) {
-        WAYLAND_wl_display_dispatch(d->display);
+        err = WAYLAND_wl_display_dispatch(d->display);
+    } else {
+        err = WAYLAND_wl_display_dispatch_pending(d->display);
     }
-    else
-    {
-        WAYLAND_wl_display_dispatch_pending(d->display);
+    if (err == -1 && !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. No recovery is possible. */
+        d->display_disconnected = 1;
+        /* Only send a single quit message, as application shutdown might call
+         * SDL_PumpEvents */
+        SDL_SendQuit();
     }
 }
 
diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index b128bb8..c858606 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -412,10 +412,9 @@
 int
 Wayland_VideoInit(_THIS)
 {
-    SDL_VideoData *data = SDL_malloc(sizeof *data);
+    SDL_VideoData *data = SDL_calloc(1, sizeof(*data));
     if (data == NULL)
         return SDL_OutOfMemory();
-    memset(data, 0, sizeof *data);
 
     _this->driverdata = data;
 
diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
index b6499d0..127c8c0 100644
--- a/src/video/wayland/SDL_waylandvideo.h
+++ b/src/video/wayland/SDL_waylandvideo.h
@@ -48,6 +48,7 @@
 
 typedef struct {
     struct wl_display *display;
+    int display_disconnected;
     struct wl_registry *registry;
     struct wl_compositor *compositor;
     struct wl_shm *shm;