SDL: wayland: Apply toplevel bounds to windows

From 28389f1c38f4798ddbdb1c83fa288424346321f0 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Fri, 3 Jan 2025 16:16:28 -0500
Subject: [PATCH] wayland: Apply toplevel bounds to windows

Apply the supplied xdg-toplevel bounds to resizable windows during initial mapping. Libdecor functionality will have to be added separately, as the functionality needs to be added to the library first.
---
 src/video/wayland/SDL_waylandwindow.c | 25 ++++++++++++++++---------
 src/video/wayland/SDL_waylandwindow.h |  6 ++++++
 2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index 2755a43db8038..33e15724a54ce 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -833,6 +833,12 @@ static void handle_configure_xdg_toplevel(void *data,
                 if (floating) {
                     width = window->floating.w;
                     height = window->floating.h;
+
+                    // Clamp the window to the toplevel bounds, if any are set.
+                    if (wind->toplevel_bounds.width && wind->toplevel_bounds.height) {
+                        width = SDL_min(wind->toplevel_bounds.width, width);
+                        height = SDL_min(wind->toplevel_bounds.height, height);
+                    }
                 } else {
                     width = window->windowed.w;
                     height = window->windowed.h;
@@ -972,7 +978,9 @@ static void handle_xdg_configure_toplevel_bounds(void *data,
                                                  struct xdg_toplevel *xdg_toplevel,
                                                  int32_t width, int32_t height)
 {
-    // NOP
+    SDL_WindowData *window = (SDL_WindowData *)data;
+    window->toplevel_bounds.width = width;
+    window->toplevel_bounds.height = height;
 }
 
 static void handle_xdg_toplevel_wm_capabilities(void *data,
@@ -1946,6 +1954,13 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
     } else
 #endif
         if (data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP || data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) {
+
+        // Create the window decorations
+        if (data->shell_surface_type != WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP && data->shell_surface.xdg.toplevel.xdg_toplevel && c->decoration_manager) {
+            data->server_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(c->decoration_manager, data->shell_surface.xdg.toplevel.xdg_toplevel);
+            zxdg_toplevel_decoration_v1_add_listener(data->server_decoration, &decoration_listener, window);
+        }
+
         /* Unlike libdecor we need to call this explicitly to prevent a deadlock.
          * libdecor will call this as part of their configure event!
          * -flibit
@@ -1957,14 +1972,6 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
                 WAYLAND_wl_display_dispatch(c->display);
             }
         }
-
-        // Create the window decorations
-        if (data->shell_surface_type != WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP && data->shell_surface.xdg.toplevel.xdg_toplevel && c->decoration_manager) {
-            data->server_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(c->decoration_manager, data->shell_surface.xdg.toplevel.xdg_toplevel);
-            zxdg_toplevel_decoration_v1_add_listener(data->server_decoration,
-                                                     &decoration_listener,
-                                                     window);
-        }
     } else {
         // Nothing to see here, just commit.
         wl_surface_commit(data->surface);
diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h
index d181b21dc6eb9..906c5e448dbe5 100644
--- a/src/video/wayland/SDL_waylandwindow.h
+++ b/src/video/wayland/SDL_waylandwindow.h
@@ -174,6 +174,12 @@ struct SDL_WindowData
         int min_height;
     } system_limits;
 
+    struct
+    {
+        int width;
+        int height;
+    } toplevel_bounds;
+
     SDL_DisplayID last_displayID;
     int fullscreen_deadline_count;
     int maximized_restored_deadline_count;