SDL: wayland: Fix toggling fullscreen with fixed-size windows

From c7e29a9e95375a1ae0ced34e2fc2cc40c3055e47 Mon Sep 17 00:00:00 2001
From: Ethan Lee <[EMAIL REDACTED]>
Date: Tue, 6 Apr 2021 18:10:40 -0400
Subject: [PATCH] wayland: Fix toggling fullscreen with fixed-size windows

---
 src/video/wayland/SDL_waylandwindow.c | 152 +++++++++-----------------
 1 file changed, 54 insertions(+), 98 deletions(-)

diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index 5491d2dbf..4550feb06 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -43,12 +43,60 @@ static float get_window_scale_factor(SDL_Window *window) {
       return ((SDL_WindowData*)window->driverdata)->scale_factor;
 }
 
+static void
+CommitMinMaxDimensions(SDL_Window *window)
+{
+    SDL_WindowData *wind = window->driverdata;
+    SDL_VideoData *data = wind->waylandData;
+    int min_width, min_height, max_width, max_height;
+
+    if (window->flags & SDL_WINDOW_FULLSCREEN) {
+        min_width = 0;
+        min_height = 0;
+        max_width = 0;
+        max_height = 0;
+    } else if (window->flags & SDL_WINDOW_RESIZABLE) {
+        min_width = window->min_w;
+        min_height = window->min_h;
+        max_width = window->max_w;
+        max_height = window->max_h;
+    } else {
+        min_width = window->w;
+        min_height = window->h;
+        max_width = window->w;
+        max_height = window->h;
+    }
+
+    if (data->shell.xdg) {
+        xdg_toplevel_set_min_size(wind->shell_surface.xdg.roleobj.toplevel,
+                                  min_width,
+                                  min_height);
+        xdg_toplevel_set_max_size(wind->shell_surface.xdg.roleobj.toplevel,
+                                  max_width,
+                                  max_height);
+    } else if (data->shell.zxdg) {
+        zxdg_toplevel_v6_set_min_size(wind->shell_surface.zxdg.roleobj.toplevel,
+                                      min_width,
+                                      min_height);
+        zxdg_toplevel_v6_set_max_size(wind->shell_surface.zxdg.roleobj.toplevel,
+                                      max_width,
+                                      max_height);
+    }
+
+    wl_surface_commit(wind->surface);
+}
+
 static void
 SetFullscreen(SDL_Window *window, struct wl_output *output)
 {
     SDL_WindowData *wind = window->driverdata;
     SDL_VideoData *viddata = wind->waylandData;
 
+    /* The desktop may try to enforce min/max sizes here, so turn them off for
+     * fullscreen and on (if applicable) for windowed
+     */
+    CommitMinMaxDimensions(window);
+
     if (viddata->shell.xdg) {
         if (output) {
             xdg_toplevel_set_fullscreen(wind->shell_surface.xdg.roleobj.toplevel, output);
@@ -313,7 +361,7 @@ handle_configure_xdg_toplevel(void *data,
         if (*state == XDG_TOPLEVEL_STATE_FULLSCREEN) {
             fullscreen = SDL_TRUE;
         }
-     }
+    }
 
     if (!fullscreen) {
         if (window->flags & SDL_WINDOW_FULLSCREEN) {
@@ -634,40 +682,7 @@ Wayland_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
 void
 Wayland_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
 {
-    int min_width, min_height, max_width, max_height;
-    SDL_VideoData *data = _this->driverdata;
-    SDL_WindowData *wind = window->driverdata;
-
-    if (resizable) {
-        /* FIXME: Is there a better way to get max window size from Wayland? -flibit */
-        const int maxsize = 0x7FFFFFFF;
-        min_width = window->min_w;
-        min_height = window->min_h;
-        max_width = (window->max_w == 0) ? maxsize : window->max_w;
-        max_height = (window->max_h == 0) ? maxsize : window->max_h;
-    } else {
-        min_width = window->w;
-        min_height = window->h;
-        max_width = window->w;
-        max_height = window->h;
-    }
-
-    /* Note that this is also handled by the xdg-shell/wl_shell callbacks! */
-    if (data->shell.xdg) {
-        xdg_toplevel_set_min_size(wind->shell_surface.xdg.roleobj.toplevel,
-                                  min_width,
-                                  min_height);
-        xdg_toplevel_set_max_size(wind->shell_surface.xdg.roleobj.toplevel,
-                                  max_width,
-                                  max_height);
-    } else if (data->shell.zxdg) {
-        zxdg_toplevel_v6_set_min_size(wind->shell_surface.zxdg.roleobj.toplevel,
-                                      min_width,
-                                      min_height);
-        zxdg_toplevel_v6_set_max_size(wind->shell_surface.zxdg.roleobj.toplevel,
-                                      max_width,
-                                      max_height);
-    }
+    CommitMinMaxDimensions(window);
 }
 
 void
@@ -786,28 +801,12 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
         data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface);
         xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data);
         xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname);
-        if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
-            xdg_toplevel_set_min_size(data->shell_surface.xdg.roleobj.toplevel,
-                                      window->w,
-                                      window->h);
-            xdg_toplevel_set_max_size(data->shell_surface.xdg.roleobj.toplevel,
-                                      window->w,
-                                      window->h);
-        }
     } else if (c->shell.zxdg) {
         data->shell_surface.zxdg.surface = zxdg_shell_v6_get_xdg_surface(c->shell.zxdg, data->surface);
         /* !!! FIXME: add popup role */
         data->shell_surface.zxdg.roleobj.toplevel = zxdg_surface_v6_get_toplevel(data->shell_surface.zxdg.surface);
         zxdg_toplevel_v6_add_listener(data->shell_surface.zxdg.roleobj.toplevel, &toplevel_listener_zxdg, data);
         zxdg_toplevel_v6_set_app_id(data->shell_surface.zxdg.roleobj.toplevel, c->classname);
-        if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
-            zxdg_toplevel_v6_set_min_size(data->shell_surface.zxdg.roleobj.toplevel,
-                                          window->w,
-                                          window->h);
-            zxdg_toplevel_v6_set_max_size(data->shell_surface.zxdg.roleobj.toplevel,
-                                          window->w,
-                                          window->h);
-        }
     } else {
         data->shell_surface.wl = wl_shell_get_shell_surface(c->shell.wl, data->surface);
         wl_shell_surface_set_class(data->shell_surface.wl, c->classname);
@@ -885,7 +884,8 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
         Wayland_input_lock_pointer(c->input);
     }
 
-    wl_surface_commit(data->surface);
+    /* This will call wl_surface_commit */
+    CommitMinMaxDimensions(window);
     WAYLAND_wl_display_flush(c->display);
 
     /* we have to wait until the surface gets a "configure" event, or
@@ -954,39 +954,13 @@ Wayland_HandlePendingResize(SDL_Window *window)
 void
 Wayland_SetWindowMinimumSize(_THIS, SDL_Window * window)
 {
-    SDL_VideoData *data = _this->driverdata;
-    SDL_WindowData *wind = window->driverdata;
-
-    if (window->flags & SDL_WINDOW_RESIZABLE) {
-        if (data->shell.xdg) {
-            xdg_toplevel_set_min_size(wind->shell_surface.xdg.roleobj.toplevel,
-                                      window->min_w,
-                                      window->min_h);
-        } else if (data->shell.zxdg) {
-            zxdg_toplevel_v6_set_min_size(wind->shell_surface.zxdg.roleobj.toplevel,
-                                          window->min_w,
-                                          window->min_h);
-        }
-    }
+    CommitMinMaxDimensions(window);
 }
 
 void
 Wayland_SetWindowMaximumSize(_THIS, SDL_Window * window)
 {
-    SDL_VideoData *data = _this->driverdata;
-    SDL_WindowData *wind = window->driverdata;
-
-    if (window->flags & SDL_WINDOW_RESIZABLE) {
-        if (data->shell.xdg) {
-            xdg_toplevel_set_max_size(wind->shell_surface.xdg.roleobj.toplevel,
-                                      window->max_w,
-                                      window->max_h);
-        } else if (data->shell.zxdg) {
-            zxdg_toplevel_v6_set_max_size(wind->shell_surface.zxdg.roleobj.toplevel,
-                                          window->max_w,
-                                          window->max_h);
-        }
-    }
+    CommitMinMaxDimensions(window);
 }
 
 void Wayland_SetWindowSize(_THIS, SDL_Window * window)
@@ -995,24 +969,6 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window)
     SDL_WindowData *wind = window->driverdata;
     struct wl_region *region;
 
-    if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
-        if (data->shell.xdg) {
-            xdg_toplevel_set_min_size(wind->shell_surface.xdg.roleobj.toplevel,
-                                      window->w,
-                                      window->h);
-            xdg_toplevel_set_max_size(wind->shell_surface.xdg.roleobj.toplevel,
-                                      window->w,
-                                      window->h);
-        } else if (data->shell.zxdg) {
-            zxdg_toplevel_v6_set_min_size(wind->shell_surface.zxdg.roleobj.toplevel,
-                                          window->w,
-                                          window->h);
-            zxdg_toplevel_v6_set_max_size(wind->shell_surface.zxdg.roleobj.toplevel,
-                                          window->w,
-                                          window->h);
-        }
-    }
-
     wl_surface_set_buffer_scale(wind->surface, get_window_scale_factor(window));
 
     if (wind->egl_window) {