SDL: wayland: Tag/Check wl_output objects as well, fixes crashes when libdecor is in use

From 03185e748b1db8e9586eaafa42bd92bb1938dcfe Mon Sep 17 00:00:00 2001
From: Ethan Lee <[EMAIL REDACTED]>
Date: Tue, 27 Jul 2021 18:35:00 -0400
Subject: [PATCH] wayland: Tag/Check wl_output objects as well, fixes crashes
 when libdecor is in use

---
 src/video/wayland/SDL_waylandvideo.c  | 34 +++++++++++++++++++++++++++
 src/video/wayland/SDL_waylandvideo.h  |  5 ++++
 src/video/wayland/SDL_waylandwindow.c | 18 +++-----------
 src/video/wayland/SDL_waylandwindow.h |  2 --
 4 files changed, 42 insertions(+), 17 deletions(-)

diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index 7510714ee..0a5cf6e08 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -127,6 +127,39 @@ get_classname()
     return SDL_strdup("SDL_App");
 }
 
+static const char *SDL_WAYLAND_surface_tag = "sdl-window";
+static const char *SDL_WAYLAND_output_tag = "sdl-output";
+
+void SDL_WAYLAND_register_surface(struct wl_surface *surface)
+{
+    if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
+        wl_proxy_set_tag((struct wl_proxy *)surface, &SDL_WAYLAND_surface_tag);
+    }
+}
+
+void SDL_WAYLAND_register_output(struct wl_output *output)
+{
+    if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
+        wl_proxy_set_tag((struct wl_proxy *)output, &SDL_WAYLAND_output_tag);
+    }
+}
+
+SDL_bool SDL_WAYLAND_own_surface(struct wl_surface *surface)
+{
+    if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
+        return wl_proxy_get_tag((struct wl_proxy *) surface) == &SDL_WAYLAND_surface_tag;
+    }
+    return SDL_TRUE; /* For older clients we have to assume this is us... */
+}
+
+SDL_bool SDL_WAYLAND_own_output(struct wl_output *output)
+{
+    if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
+        return wl_proxy_get_tag((struct wl_proxy *) output) == &SDL_WAYLAND_output_tag;
+    }
+    return SDL_TRUE; /* For older clients we have to assume this is us... */
+}
+
 static void
 Wayland_DeleteDevice(SDL_VideoDevice *device)
 {
@@ -392,6 +425,7 @@ Wayland_add_display(SDL_VideoData *d, uint32_t id)
     data->scale_factor = 1.0;
 
     wl_output_add_listener(output, &output_listener, data);
+    SDL_WAYLAND_register_output(output);
 }
 
 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
index 64f4bdac4..f44706f1c 100644
--- a/src/video/wayland/SDL_waylandvideo.h
+++ b/src/video/wayland/SDL_waylandvideo.h
@@ -91,6 +91,11 @@ typedef struct {
     SDL_bool done;
 } SDL_WaylandOutputData;
 
+extern void SDL_WAYLAND_register_surface(struct wl_surface *surface);
+extern void SDL_WAYLAND_register_output(struct wl_output *output);
+extern SDL_bool SDL_WAYLAND_own_surface(struct wl_surface *surface);
+extern SDL_bool SDL_WAYLAND_own_output(struct wl_output *output);
+
 #endif /* SDL_waylandvideo_h_ */
 
 /* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index 81d16076b..daeb55f13 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -42,16 +42,6 @@
 #include <libdecor.h>
 #endif
 
-static const char *SDL_WAYLAND_surface_tag = "sdl-window";
-
-SDL_bool SDL_WAYLAND_own_surface(struct wl_surface *surface)
-{
-    if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
-        return wl_proxy_get_tag((struct wl_proxy *) surface) == &SDL_WAYLAND_surface_tag;
-    }
-    return SDL_TRUE; /* For older clients we have to assume this is us... */
-}
-
 static void
 CommitMinMaxDimensions(SDL_Window *window)
 {
@@ -488,7 +478,7 @@ handle_surface_enter(void *data, struct wl_surface *surface,
     SDL_WindowData *window = data;
     SDL_WaylandOutputData *driverdata = wl_output_get_user_data(output);
 
-    if (!SDL_WAYLAND_own_surface(surface)) {
+    if (!SDL_WAYLAND_own_output(output) || !SDL_WAYLAND_own_surface(surface)) {
         return;
     }
 
@@ -508,7 +498,7 @@ handle_surface_leave(void *data, struct wl_surface *surface,
     int i, send_move_event = 0;
     SDL_WaylandOutputData *driverdata = wl_output_get_user_data(output);
 
-    if (!SDL_WAYLAND_own_surface(surface)) {
+    if (!SDL_WAYLAND_own_output(output) || !SDL_WAYLAND_own_surface(surface)) {
         return;
     }
 
@@ -1138,9 +1128,7 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
         wl_compositor_create_surface(c->compositor);
     wl_surface_add_listener(data->surface, &surface_listener, data);
 
-    if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
-        wl_proxy_set_tag((struct wl_proxy *)data->surface, &SDL_WAYLAND_surface_tag);
-    }
+    SDL_WAYLAND_register_surface(data->surface);
 
     /* Fire a callback when the compositor wants a new frame rendered.
      * Right now this only matters for OpenGL; we use this callback to add a
diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h
index 35774bc73..90405fe20 100644
--- a/src/video/wayland/SDL_waylandwindow.h
+++ b/src/video/wayland/SDL_waylandwindow.h
@@ -114,8 +114,6 @@ Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info);
 extern int Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
 extern int Wayland_FlashWindow(_THIS, SDL_Window * window, SDL_FlashOperation operation);
 
-extern SDL_bool SDL_WAYLAND_own_surface(struct wl_surface *surface);
-
 #endif /* SDL_waylandwindow_h_ */
 
 /* vi: set ts=4 sw=4 expandtab: */