SDL: wayland: Add support for display connect/disconnect events

From a7a54e64520cff54133f189a3cf4dd1f26395b2c Mon Sep 17 00:00:00 2001
From: Ethan Lee <[EMAIL REDACTED]>
Date: Thu, 18 Nov 2021 00:43:55 -0500
Subject: [PATCH] wayland: Add support for display connect/disconnect events

---
 src/video/wayland/SDL_waylandvideo.c | 38 ++++++++++++++++++++++++++--
 src/video/wayland/SDL_waylandvideo.h |  1 +
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index 01444a01b1..c9d28129b3 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -450,7 +450,7 @@ display_handle_done(void *data,
     if (driverdata->index == -1) {
         /* First time getting display info, create the VideoDisplay */
         driverdata->placeholder.driverdata = driverdata;
-        driverdata->index = SDL_AddVideoDisplay(&driverdata->placeholder, SDL_FALSE);
+        driverdata->index = SDL_AddVideoDisplay(&driverdata->placeholder, SDL_TRUE);
         SDL_free(driverdata->placeholder.name);
         SDL_zero(driverdata->placeholder);
 
@@ -490,6 +490,7 @@ Wayland_add_display(SDL_VideoData *d, uint32_t id)
     data = SDL_malloc(sizeof *data);
     SDL_zerop(data);
     data->output = output;
+    data->registry_id = id;
     data->scale_factor = 1.0;
     data->index = -1;
 
@@ -497,6 +498,35 @@ Wayland_add_display(SDL_VideoData *d, uint32_t id)
     SDL_WAYLAND_register_output(output);
 }
 
+static void
+Wayland_free_display(uint32_t id)
+{
+    int num_displays = SDL_GetNumVideoDisplays();
+    SDL_VideoDisplay *display;
+    SDL_WaylandOutputData *data;
+    int i;
+
+    for (i = 0; i < num_displays; i += 1) {
+        display = SDL_GetDisplay(i);
+        data = (SDL_WaylandOutputData *) display->driverdata;
+        if (data->registry_id == id) {
+            SDL_DelVideoDisplay(i);
+            wl_output_destroy(data->output);
+            SDL_free(data);
+
+            /* Update the index for all remaining displays */
+            num_displays -= 1;
+            for (; i < num_displays; i += 1) {
+                display = SDL_GetDisplay(i);
+                data = (SDL_WaylandOutputData *) display->driverdata;
+                data->index -= 1;
+            }
+
+            return;
+        }
+    }
+}
+
 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
 static void
 windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager,
@@ -593,7 +623,11 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
 }
 
 static void
-display_remove_global(void *data, struct wl_registry *registry, uint32_t id) {}
+display_remove_global(void *data, struct wl_registry *registry, uint32_t id)
+{
+    /* We don't get an interface, just an ID, so assume it's a wl_output :shrug: */
+    Wayland_free_display(id);
+}
 
 static const struct wl_registry_listener registry_listener = {
     display_handle_global,
diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
index 1568122ef0..4e1d8b2eec 100644
--- a/src/video/wayland/SDL_waylandvideo.h
+++ b/src/video/wayland/SDL_waylandvideo.h
@@ -90,6 +90,7 @@ typedef struct {
 
 typedef struct {
     struct wl_output *output;
+    uint32_t registry_id;
     float scale_factor;
     int x, y, width, height, refresh, transform;
     SDL_DisplayOrientation orientation;