SDL: wayland: Refactor for video core changes

From 7def1438c340d779642ba21052ffe263f7a491d9 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Wed, 1 Feb 2023 11:18:03 -0500
Subject: [PATCH] wayland: Refactor for video core changes

Accommodate the new video core changes.

The new video core changes allow for some window geometry calculation refactoring that simplify the system:

- Removal of helper functions
- Eliminate some discrepancies between the libdecor and xdg-toplevel paths
- No need to short-circuit the video core window size event deduplication check
- Exclusive fullscreen windows will always end up on the correct output, even when fullscreen is initiated from the compositor
- Better handling of cases where the desktop is scaled, but does not expose the viewport protocol
- Return the display bounds for the emulated mode if an exclusive fullscreen window has focus
- Fixed cases where changing display properties during runtime wouldn't update the display mode lists
- General cleanup
---
 src/video/wayland/SDL_waylandvideo.c  | 148 +++++-----
 src/video/wayland/SDL_waylandwindow.c | 385 ++++++++++----------------
 src/video/wayland/SDL_waylandwindow.h |   9 +-
 3 files changed, 235 insertions(+), 307 deletions(-)

diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index e1bf8c8a5afe..1575f78270de 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -361,7 +361,7 @@ static const struct zxdg_output_v1_listener xdg_output_listener = {
     xdg_output_handle_description,
 };
 
-static void AddEmulatedModes(SDL_VideoDisplay *dpy, SDL_bool rot_90)
+static void AddEmulatedModes(SDL_DisplayData *dispdata, SDL_bool rot_90)
 {
     struct EmulatedMode
     {
@@ -413,8 +413,9 @@ static void AddEmulatedModes(SDL_VideoDisplay *dpy, SDL_bool rot_90)
 
     int i;
     SDL_DisplayMode mode;
-    const int native_width = dpy->desktop_mode.pixel_w;
-    const int native_height = dpy->desktop_mode.pixel_h;
+    SDL_VideoDisplay *dpy = dispdata->display ? SDL_GetVideoDisplay(dispdata->display) : &dispdata->placeholder;
+    const int native_width = dispdata->pixel_width;
+    const int native_height = dispdata->pixel_height;
 
     for (i = 0; i < SDL_arraysize(mode_list); ++i) {
         SDL_zero(mode);
@@ -423,18 +424,19 @@ static void AddEmulatedModes(SDL_VideoDisplay *dpy, SDL_bool rot_90)
         mode.refresh_rate = dpy->desktop_mode.refresh_rate;
         mode.driverdata = dpy->desktop_mode.driverdata;
 
-        if (rot_90) {
-            mode.pixel_w = mode_list[i].h;
-            mode.pixel_h = mode_list[i].w;
-        } else {
-            mode.pixel_w = mode_list[i].w;
-            mode.pixel_h = mode_list[i].h;
-        }
-
         /* Only add modes that are smaller than the native mode. */
-        if ((mode.pixel_w < native_width && mode.pixel_h < native_height) ||
-            (mode.pixel_w < native_width && mode.pixel_h == native_height) ||
-            (mode.pixel_w == native_width && mode.pixel_h < native_height)) {
+        if ((mode_list[i].w < native_width && mode_list[i].h < native_height) ||
+            (mode_list[i].w < native_width && mode_list[i].h == native_height) ||
+            (mode_list[i].w == native_width && mode_list[i].h < native_height)) {
+
+            if (rot_90) {
+                mode.pixel_w = mode_list[i].h;
+                mode.pixel_h = mode_list[i].w;
+            } else {
+                mode.pixel_w = mode_list[i].w;
+                mode.pixel_h = mode_list[i].h;
+            }
+
             SDL_AddFullscreenDisplayMode(dpy, &mode);
         }
     }
@@ -452,22 +454,6 @@ static void display_handle_geometry(void *data,
 
 {
     SDL_DisplayData *driverdata = (SDL_DisplayData *)data;
-    SDL_VideoDisplay *display;
-    int i;
-
-    if (driverdata->wl_output_done_count) {
-        /* Clear the wl_output ref so Reset doesn't free it */
-        display = SDL_GetVideoDisplay(driverdata->display);
-        for (i = 0; i < display->num_fullscreen_modes; ++i) {
-            display->fullscreen_modes[i].driverdata = NULL;
-        }
-
-        /* Okay, now it's safe to reset */
-        SDL_ResetFullscreenDisplayModes(display);
-
-        /* The display has officially started over. */
-        driverdata->wl_output_done_count = 0;
-    }
 
     /* Apply the change from wl-output only if xdg-output is not supported */
     if (!driverdata->has_logical_position) {
@@ -558,14 +544,29 @@ static void display_handle_done(void *data,
 
     driverdata->wl_output_done_count = SDL_min(driverdata->wl_output_done_count + 1, event_await_count + 1);
 
-    if (driverdata->wl_output_done_count != event_await_count) {
+    if (driverdata->wl_output_done_count < event_await_count) {
         return;
     }
 
+    /* If the display was already created, reset and rebuild the mode list. */
+    if (driverdata->display != 0) {
+        int i;
+        dpy = SDL_GetVideoDisplay(driverdata->display);
+
+        /* Clear the wl_output ref so Reset doesn't free it */
+        for (i = 0; i < dpy->num_fullscreen_modes; ++i) {
+            dpy->fullscreen_modes[i].driverdata = NULL;
+        }
+
+        /* Okay, now it's safe to reset */
+        SDL_ResetFullscreenDisplayModes(dpy);
+    }
+
     /* The native display resolution */
     SDL_zero(native_mode);
     native_mode.format = SDL_PIXELFORMAT_RGB888;
 
+    /* Transform the pixel values, if necessary. */
     if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) {
         native_mode.pixel_w = driverdata->pixel_height;
         native_mode.pixel_h = driverdata->pixel_width;
@@ -577,27 +578,29 @@ static void display_handle_done(void *data,
     native_mode.refresh_rate = ((100 * driverdata->refresh) / 1000) / 100.0f; /* mHz to Hz */
     native_mode.driverdata = driverdata->output;
 
-    /* The scaled desktop mode */
-    SDL_zero(desktop_mode);
-    desktop_mode.format = SDL_PIXELFORMAT_RGB888;
-
-    if (driverdata->has_logical_size) { /* If xdg-output is present, calculate the true scale of the desktop */
+    if (driverdata->has_logical_size) { /* If xdg-output is present... */
         if (video->viewporter) {
+            /* ...and viewports are supported, calculate the true scale of the output. */
             driverdata->scale_factor = (float)native_mode.pixel_w / (float)driverdata->screen_width;
+        } else {
+            /* ...otherwise, the 'native' pixel values are a multiple of the logical screen size. */
+            driverdata->pixel_width = driverdata->screen_width * (int)driverdata->scale_factor;
+            driverdata->pixel_height = driverdata->screen_height * (int)driverdata->scale_factor;
         }
-    } else { /* Scale the desktop coordinates, if xdg-output isn't present */
-        driverdata->screen_width /= driverdata->scale_factor;
-        driverdata->screen_height /= driverdata->scale_factor;
-    }
-
-    /* xdg-output dimensions are already transformed, so no need to rotate. */
-    if (driverdata->has_logical_size || !(driverdata->transform & WL_OUTPUT_TRANSFORM_90)) {
-        desktop_mode.pixel_w = driverdata->pixel_width;
-        desktop_mode.pixel_h = driverdata->pixel_height;
     } else {
-        desktop_mode.pixel_w = driverdata->pixel_height;
-        desktop_mode.pixel_h = driverdata->pixel_width;
+        /* Calculate the screen coordinates from the pixel values, if xdg-output isn't present.
+         * Use the native mode pixel values since they are pre-transformed.
+         */
+        driverdata->screen_width = native_mode.pixel_w / (int)driverdata->scale_factor;
+        driverdata->screen_height = native_mode.pixel_h / (int)driverdata->scale_factor;
     }
+
+    /* The scaled desktop mode */
+    SDL_zero(desktop_mode);
+    desktop_mode.format = SDL_PIXELFORMAT_RGB888;
+
+    desktop_mode.screen_w = driverdata->screen_width;
+    desktop_mode.screen_h = driverdata->screen_height;
     desktop_mode.display_scale = driverdata->scale_factor;
     desktop_mode.refresh_rate = ((100 * driverdata->refresh) / 1000) / 100.0f; /* mHz to Hz */
     desktop_mode.driverdata = driverdata->output;
@@ -609,25 +612,23 @@ static void display_handle_done(void *data,
     }
 
     /* Set the desktop display mode. */
-    SDL_memcpy(&dpy->desktop_mode, &desktop_mode, sizeof(&dpy->desktop_mode));
+    SDL_SetDesktopDisplayMode(dpy, &desktop_mode);
 
-    /* If the desktop is scaled... */
-    if (driverdata->scale_factor > 1.0f) {
-        /* ...expose the native resolution if viewports are available... */
-        if (video->viewporter != NULL) {
-            SDL_AddFullscreenDisplayMode(dpy, &native_mode);
-        } else {
-            /* ...if not, expose some smaller, integer scaled resolutions. */
-            int i;
-            const int base_pixel_w = desktop_mode.pixel_w / (int)desktop_mode.display_scale;
-            const int base_pixel_h = desktop_mode.pixel_h / (int)desktop_mode.display_scale;
-            for (i = 1; i < (int)desktop_mode.display_scale; ++i) {
-                desktop_mode.pixel_w = base_pixel_w * i;
-                desktop_mode.pixel_h = base_pixel_h * i;
-                desktop_mode.display_scale = (float)i;
-
-                SDL_AddFullscreenDisplayMode(dpy, &desktop_mode);
-            }
+    /* ...expose the unscaled, native resolution if the scale is 1.0 or viewports are available... */
+    if (driverdata->scale_factor == 1.0f || video->viewporter != NULL) {
+        SDL_AddFullscreenDisplayMode(dpy, &native_mode);
+    } else {
+        /* ...if not, expose the integer scaled variants of the desktop resolution down to 1. */
+        int i;
+
+        desktop_mode.pixel_w = 0;
+        desktop_mode.pixel_h = 0;
+        desktop_mode.screen_w = driverdata->screen_width;
+        desktop_mode.screen_h = driverdata->screen_height;
+
+        for (i = (int)driverdata->scale_factor; i > 0; --i) {
+            desktop_mode.display_scale = (float)i;
+            SDL_AddFullscreenDisplayMode(dpy, &desktop_mode);
         }
     }
 
@@ -635,7 +636,7 @@ static void display_handle_done(void *data,
     if (video->viewporter && mode_emulation_enabled) {
         const SDL_bool rot_90 = ((driverdata->transform & WL_OUTPUT_TRANSFORM_90) != 0) ||
                                 (driverdata->screen_width < driverdata->screen_height);
-        AddEmulatedModes(dpy, rot_90);
+        AddEmulatedModes(driverdata, rot_90);
     }
 
     /* Calculate the display DPI */
@@ -974,8 +975,19 @@ static int Wayland_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *
     SDL_DisplayData *driverdata = display->driverdata;
     rect->x = driverdata->x;
     rect->y = driverdata->y;
-    rect->w = display->current_mode->screen_w;
-    rect->h = display->current_mode->screen_h;
+
+    /* When an emulated, exclusive fullscreen window has focus, treat the mode dimensions as the display bounds. */
+    if (display->fullscreen_window &&
+        display->fullscreen_window->fullscreen_exclusive &&
+        display->fullscreen_window == SDL_GetFocusWindow() &&
+        display->fullscreen_window->fullscreen_mode.screen_w != 0 &&
+        display->fullscreen_window->fullscreen_mode.screen_h != 0) {
+        rect->w = display->fullscreen_window->fullscreen_mode.screen_w;
+        rect->h = display->fullscreen_window->fullscreen_mode.screen_h;
+    } else {
+        rect->w = display->current_mode->screen_w;
+        rect->h = display->current_mode->screen_h;
+    }
     return 0;
 }
 
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index 6e9297bca543..5519a7975d89 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -53,70 +53,10 @@ SDL_FORCE_INLINE SDL_bool FloatEqual(float a, float b)
     return diff <= largest * SDL_FLT_EPSILON;
 }
 
-static void GetFullScreenDimensions(SDL_Window *window, int *width, int *height, int *drawable_width, int *drawable_height)
-{
-    SDL_WindowData *wind = window->driverdata;
-    SDL_VideoDisplay *disp = SDL_GetVideoDisplayForWindow(window);
-    SDL_DisplayData *output = disp->driverdata;
-
-    int fs_width, fs_height;
-    int buf_width, buf_height;
-    const int output_width = wind->fs_output_width ? wind->fs_output_width : output->screen_width;
-    const int output_height = wind->fs_output_height ? wind->fs_output_height : output->screen_height;
-
-    if (window->fullscreen_exclusive) {
-        /* If a mode was set, use it, otherwise use the native resolution. */
-        const SDL_DisplayMode *mode = SDL_GetWindowFullscreenMode(window);
-        if (!mode) {
-            mode = &disp->desktop_mode;
-        }
-        fs_width = mode->screen_w;
-        fs_height = mode->screen_h;
-        buf_width = mode->pixel_w;
-        buf_height = mode->pixel_h;
-    } else {
-        /*
-         * Fullscreen desktop mandates a desktop sized window, so that's what
-         * applications will get. If the application is DPI aware, it will need
-         * to handle the transformations between the differently sized window
-         * and backbuffer spaces on its own.
-         */
-        fs_width = output_width;
-        fs_height = output_height;
-
-        /* If the application is DPI aware, we can expose the true backbuffer size */
-        if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
-            buf_width = output->pixel_width;
-            buf_height = output->pixel_height;
-        } else {
-            buf_width = fs_width;
-            buf_height = fs_height;
-        }
-    }
-
-    if (width) {
-        *width = fs_width;
-    }
-    if (height) {
-        *height = fs_height;
-    }
-    if (drawable_width) {
-        *drawable_width = buf_width;
-    }
-    if (drawable_height) {
-        *drawable_height = buf_height;
-    }
-}
-
-SDL_FORCE_INLINE SDL_bool FullscreenModeEmulation(SDL_Window *window)
-{
-    return window->fullscreen_exclusive;
-}
-
-SDL_bool SurfaceScaleIsFractional(SDL_Window *window)
+static SDL_bool SurfaceScaleIsFractional(SDL_Window *window)
 {
     SDL_WindowData *data = window->driverdata;
-    const float scale_value = !FullscreenModeEmulation(window) ? data->windowed_scale_factor : window->fullscreen_mode.display_scale;
+    const float scale_value = !(window->fullscreen_exclusive) ? data->windowed_scale_factor : window->fullscreen_mode.display_scale;
     return !FloatEqual(SDL_roundf(scale_value), scale_value);
 }
 
@@ -125,9 +65,8 @@ static SDL_bool WindowNeedsViewport(SDL_Window *window)
     SDL_WindowData *wind = window->driverdata;
     SDL_VideoData *video = wind->waylandData;
     SDL_DisplayData *output = SDL_GetDisplayDriverDataForWindow(window);
-    const int output_width = wind->fs_output_width ? wind->fs_output_width : output->screen_width;
-    const int output_height = wind->fs_output_height ? wind->fs_output_height : output->screen_height;
-    int fs_width, fs_height;
+    const int output_width = wind->requested_window_width ? wind->requested_window_width : output->screen_width;
+    const int output_height = wind->requested_window_height ? wind->requested_window_height : output->screen_height;
 
     /*
      * A viewport is only required when scaling is enabled and:
@@ -137,9 +76,8 @@ static SDL_bool WindowNeedsViewport(SDL_Window *window)
     if (video->viewporter != NULL) {
         if (SurfaceScaleIsFractional(window)) {
             return SDL_TRUE;
-        } else if (FullscreenModeEmulation(window)) {
-            GetFullScreenDimensions(window, &fs_width, &fs_height, NULL, NULL);
-            if (fs_width != output_width || fs_height != output_height) {
+        } else if (window->fullscreen_exclusive) {
+            if (window->fullscreen_mode.screen_w != output_width || window->fullscreen_mode.screen_h != output_height) {
                 return SDL_TRUE;
             }
         }
@@ -154,16 +92,13 @@ static void GetBufferSize(SDL_Window *window, int *width, int *height)
     int buf_width;
     int buf_height;
 
-    if (FullscreenModeEmulation(window)) {
-        GetFullScreenDimensions(window, NULL, NULL, &buf_width, &buf_height);
-    } else if (WindowNeedsViewport(window)) {
-        /* Round fractional backbuffer sizes halfway away from zero. */
-        buf_width = (int)SDL_lroundf((float)window->w * data->windowed_scale_factor);
-        buf_height = (int)SDL_lroundf((float)window->h * data->windowed_scale_factor);
+    if (window->fullscreen_exclusive) {
+        buf_width = window->fullscreen_mode.pixel_w;
+        buf_height = window->fullscreen_mode.pixel_h;
     } else {
-        /* Integer scaled windowed or fullscreen with no viewport */
-        buf_width = window->w * (int)data->windowed_scale_factor;
-        buf_height = window->h * (int)data->windowed_scale_factor;
+        /* Round fractional backbuffer sizes halfway away from zero. */
+        buf_width = (int)SDL_lroundf((float)data->requested_window_width * data->windowed_scale_factor);
+        buf_height = (int)SDL_lroundf((float)data->requested_window_height * data->windowed_scale_factor);
     }
 
     if (width) {
@@ -204,9 +139,9 @@ static void ConfigureWindowGeometry(SDL_Window *window)
     SDL_WindowData *data = window->driverdata;
     SDL_VideoData *viddata = data->waylandData;
     SDL_DisplayData *output = SDL_GetDisplayDriverDataForWindow(window);
-    struct wl_region *region;
     const int old_dw = data->drawable_width;
     const int old_dh = data->drawable_height;
+    int window_width, window_height;
     SDL_bool window_size_changed;
     SDL_bool drawable_size_changed;
 
@@ -221,52 +156,56 @@ static void ConfigureWindowGeometry(SDL_Window *window)
                                      0, 0);
     }
 
-    if (FullscreenModeEmulation(window)) {
-        int fs_width, fs_height;
-        const int output_width = data->fs_output_width ? data->fs_output_width : output->screen_width;
-        const int output_height = data->fs_output_height ? data->fs_output_height : output->screen_height;
+    if (window->fullscreen_exclusive) {
+        /* If the compositor supplied fullscreen dimensions, use them, otherwise fall back to the display dimensions. */
+        const int output_width = data->requested_window_width ? data->requested_window_width : output->screen_width;
+        const int output_height = data->requested_window_height ? data->requested_window_height : output->screen_height;
+        window_width = window->fullscreen_mode.screen_w;
+        window_height = window->fullscreen_mode.screen_h;
 
-        window_size_changed = data->window_width != output_width || data->window_height != output_height;
+        window_size_changed = window_width != window->w || window_height != window->h ||
+            data->wl_window_width != output_width || data->wl_window_height != output_height;
 
         if (window_size_changed || drawable_size_changed) {
-            GetFullScreenDimensions(window, &fs_width, &fs_height, NULL, NULL);
-
             if (WindowNeedsViewport(window)) {
                 /* Set the buffer scale to 1 since a viewport will be used. */
                 wl_surface_set_buffer_scale(data->surface, 1);
                 SetDrawSurfaceViewport(window, data->drawable_width, data->drawable_height,
                                        output_width, output_height);
 
-                data->window_width = output_width;
-                data->window_height = output_height;
-
-                data->pointer_scale_x = (float)fs_width / (float)output_width;
-                data->pointer_scale_y = (float)fs_height / (float)output_height;
+                data->wl_window_width = output_width;
+                data->wl_window_height = output_height;
             } else {
+                /* Always use the mode dimensions for integer scaling. */
+                UnsetDrawSurfaceViewport(window);
                 wl_surface_set_buffer_scale(data->surface, (int32_t)window->fullscreen_mode.display_scale);
 
-                data->window_width = fs_width;
-                data->window_height = fs_height;
-
-                data->pointer_scale_x = 1.0f;
-                data->pointer_scale_y = 1.0f;
+                data->wl_window_width = window->fullscreen_mode.screen_w;
+                data->wl_window_height = window->fullscreen_mode.screen_h;
             }
+
+            data->pointer_scale_x = (float)window_width / (float)data->wl_window_width;
+            data->pointer_scale_y = (float)window_height / (float)data->wl_window_height;
         }
     } else {
-        window_size_changed = data->window_width != window->w || data->window_height != window->h;
+        window_width = data->requested_window_width;
+        window_height = data->requested_window_height;
+
+        window_size_changed = window_width != window->w || window_height != window->h;
 
         if (window_size_changed || drawable_size_changed) {
             if (WindowNeedsViewport(window)) {
                 wl_surface_set_buffer_scale(data->surface, 1);
-                SetDrawSurfaceViewport(window, data->drawable_width, data->drawable_height, window->w, window->h);
+                SetDrawSurfaceViewport(window, data->drawable_width, data->drawable_height,
+                                       window_width, window_height);
             } else {
                 UnsetDrawSurfaceViewport(window);
                 wl_surface_set_buffer_scale(data->surface, (int32_t)data->windowed_scale_factor);
             }
 
             /* Clamp the physical window size to the system minimum required size. */
-            data->window_width = SDL_max(window->w, data->system_min_required_width);
-            data->window_height = SDL_max(window->h, data->system_min_required_height);
+            data->wl_window_width = SDL_max(window_width, data->system_min_required_width);
+            data->wl_window_height = SDL_max(window_height, data->system_min_required_height);
 
             data->pointer_scale_x = 1.0f;
             data->pointer_scale_y = 1.0f;
@@ -278,16 +217,18 @@ static void ConfigureWindowGeometry(SDL_Window *window)
      * need to be recalculated if the output size has changed.
      */
     if (window_size_changed) {
+        struct wl_region *region;
+
         /* libdecor does this internally on frame commits, so it's only needed for xdg surfaces. */
         if (data->shell_surface_type != WAYLAND_SURFACE_LIBDECOR &&
             viddata->shell.xdg && data->shell_surface.xdg.surface != NULL) {
-            xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, data->window_width, data->window_height);
+            xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, data->wl_window_width, data->wl_window_height);
         }
 
         if (!viddata->egl_transparency_enabled) {
             region = wl_compositor_create_region(viddata->compositor);
             wl_region_add(region, 0, 0,
-                          data->window_width, data->window_height);
+                          data->wl_window_width, data->wl_window_height);
             wl_surface_set_opaque_region(data->surface, region);
             wl_region_destroy(region);
         }
@@ -296,6 +237,10 @@ static void ConfigureWindowGeometry(SDL_Window *window)
             Wayland_input_confine_pointer(viddata->input, window);
         }
     }
+
+    /* Unconditionally send the window and drawable size, the video core will deduplicate when required. */
+    SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, window_width, window_height);
+    SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED, data->drawable_width, data->drawable_height);
 }
 
 static void CommitLibdecorFrame(SDL_Window *window)
@@ -304,7 +249,7 @@ static void CommitLibdecorFrame(SDL_Window *window)
     SDL_WindowData *wind = window->driverdata;
 
     if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR && wind->shell_surface.libdecor.frame) {
-        struct libdecor_state *state = libdecor_state_new(wind->window_width, wind->window_height);
+        struct libdecor_state *state = libdecor_state_new(wind->wl_window_width, wind->wl_window_height);
         libdecor_frame_commit(wind->shell_surface.libdecor.frame, state, NULL);
         libdecor_state_free(state);
     }
@@ -326,7 +271,7 @@ static void SetMinMaxDimensions(SDL_Window *window, SDL_bool commit)
         return;
     }
 
-    if (window->fullscreen_exclusive) {
+    if (window->flags & SDL_WINDOW_FULLSCREEN) {
         min_width = 0;
         min_height = 0;
         max_width = 0;
@@ -439,22 +384,23 @@ static void UpdateWindowFullscreen(SDL_Window *window, SDL_bool fullscreen)
     SDL_WindowData *wind = window->driverdata;
 
     if (fullscreen) {
-        if ((window->flags & SDL_WINDOW_FULLSCREEN) == 0) {
+        if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
             wind->is_fullscreen = SDL_TRUE;
+
             wind->in_fullscreen_transition = SDL_TRUE;
             SDL_SetWindowFullscreen(window, SDL_TRUE);
             wind->in_fullscreen_transition = SDL_FALSE;
         }
     } else {
         /* Don't change the fullscreen flags if the window is hidden or being hidden. */
-        if (!window->is_hiding && !(window->flags & SDL_WINDOW_HIDDEN)) {
-            if ((window->flags & SDL_WINDOW_FULLSCREEN) != 0) {
-                wind->is_fullscreen = SDL_FALSE;
-                wind->in_fullscreen_transition = SDL_TRUE;
-                SDL_SetWindowFullscreen(window, SDL_FALSE);
-                wind->in_fullscreen_transition = SDL_FALSE;
-                SetMinMaxDimensions(window, SDL_FALSE);
-            }
+        if ((window->flags & SDL_WINDOW_FULLSCREEN) && !window->is_hiding && !(window->flags & SDL_WINDOW_HIDDEN)) {
+            wind->is_fullscreen = SDL_FALSE;
+
+            wind->in_fullscreen_transition = SDL_TRUE;
+            SDL_SetWindowFullscreen(window, SDL_FALSE);
+            wind->in_fullscreen_transition = SDL_FALSE;
+
+            SetMinMaxDimensions(window, SDL_FALSE);
         }
     }
 }
@@ -474,7 +420,7 @@ static void surface_damage_frame_done(void *data, struct wl_callback *cb, uint32
                                  wind->drawable_width, wind->drawable_height);
     } else {
         wl_surface_damage(wind->surface, 0, 0,
-                          wind->window_width, wind->window_height);
+                          wind->wl_window_width, wind->wl_window_height);
     }
 
     wl_callback_destroy(cb);
@@ -503,14 +449,12 @@ static const struct wl_callback_listener gles_swap_frame_listener = {
     gles_swap_frame_done
 };
 
-static void Wayland_HandleResize(SDL_Window *window, int width, int height);
-
 static void handle_configure_xdg_shell_surface(void *data, struct xdg_surface *xdg, uint32_t serial)
 {
     SDL_WindowData *wind = (SDL_WindowData *)data;
     SDL_Window *window = wind->sdlwindow;
 
-    Wayland_HandleResize(window, window->w, window->h);
+    ConfigureWindowGeometry(window);
     xdg_surface_ack_configure(xdg, serial);
 
     wind->shell_surface.xdg.initial_configure_seen = SDL_TRUE;
@@ -533,6 +477,7 @@ static void handle_configure_xdg_toplevel(void *data,
     SDL_bool fullscreen = SDL_FALSE;
     SDL_bool maximized = SDL_FALSE;
     SDL_bool floating = SDL_TRUE;
+    SDL_bool focused = SDL_FALSE;
     wl_array_for_each (state, states) {
         switch (*state) {
         case XDG_TOPLEVEL_STATE_FULLSCREEN:
@@ -543,6 +488,9 @@ static void handle_configure_xdg_toplevel(void *data,
             maximized = SDL_TRUE;
             floating = SDL_FALSE;
             break;
+        case XDG_TOPLEVEL_STATE_ACTIVATED:
+            focused = SDL_TRUE;
+            break;
         case XDG_TOPLEVEL_STATE_TILED_LEFT:
         case XDG_TOPLEVEL_STATE_TILED_RIGHT:
         case XDG_TOPLEVEL_STATE_TILED_TOP:
@@ -557,18 +505,18 @@ static void handle_configure_xdg_toplevel(void *data,
     UpdateWindowFullscreen(window, fullscreen);
 
     if (!fullscreen) {
-        if ((floating && !wind->was_floating) || width == 0 || height == 0) {
-            /* This usually happens when we're being restored from a
-             * non-floating state, so use the cached floating size here.
-             */
-            width = wind->floating_width;
-            height = wind->floating_height;
-        }
-
         /* xdg_toplevel spec states that this is a suggestion.
-           Ignore if less than or greater than max/min size. */
-
+         * Ignore if less than or greater than max/min size.
+         */
         if ((window->flags & SDL_WINDOW_RESIZABLE)) {
+            if ((floating && !wind->floating) || width == 0 || height == 0) {
+                /* This happens when we're being restored from a
+                 * non-floating state, so use the cached floating size here.
+                 */
+                width = wind->floating_width;
+                height = wind->floating_height;
+            }
+
             if (window->max_w > 0) {
                 width = SDL_min(width, window->max_w);
             }
@@ -586,6 +534,12 @@ static void handle_configure_xdg_toplevel(void *data,
             height = window->windowed.h;
         }
 
+        /* Store current floating dimensions for restoring */
+        if (floating) {
+            wind->floating_width = width;
+            wind->floating_height = height;
+        }
+
         /* Always send a maximized/restore event; if the event is redundant it will
          * automatically be discarded (see src/events/SDL_windowevents.c)
          *
@@ -594,45 +548,25 @@ static void handle_configure_xdg_toplevel(void *data,
         SDL_SendWindowEvent(window,
                             maximized ? SDL_EVENT_WINDOW_MAXIMIZED : SDL_EVENT_WINDOW_RESTORED,
                             0, 0);
-
-        /* Store current floating dimensions for restoring */
-        if (floating) {
-            wind->floating_width = width;
-            wind->floating_height = height;
-        }
-
-        /* Store this now so the xdg_surface configure knows what to resize to */
-        if (window->w != width || window->h != height) {
-            window->w = width;
-            window->h = height;
-            wind->needs_resize_event = SDL_TRUE;
-        }
     } else {
-        /* For fullscreen, foolishly do what the compositor says. If it's wrong,
-         * don't blame us, we were explicitly instructed to do this.
-         *
-         * UPDATE: Nope, sure enough a compositor sends 0,0. This is a known bug:
-         * https://bugs.kde.org/show_bug.cgi?id=444962
-         */
-        if (width && height) {
-            wind->fs_output_width = width;
-            wind->fs_output_height = height;
-        } else {
-            wind->fs_output_width = 0;
-            wind->fs_output_height = 0;
-        }
-
-        if (FullscreenModeEmulation(window)) {
-            GetFullScreenDimensions(window, &width, &height, NULL, NULL);
-        }
-        if (width != 0 && height != 0 && (window->w != width || window->h != height)) {
-            window->w = width;
-            window->h = height;
-            wind->needs_resize_event = SDL_TRUE;
+        /* If an exclusive fullscreen mode was requested, ensure it is placed on the appropriate output. */
+        if (window->fullscreen_exclusive && wind->fullscreen_display != window->fullscreen_mode.displayID) {
+            SDL_VideoDisplay *disp = SDL_GetVideoDisplay(window->fullscreen_mode.displayID);
+            if (disp) {
+                wind->fullscreen_display = disp->id;
+                xdg_toplevel_set_fullscreen(xdg_toplevel, disp->driverdata->output);
+            }
         }
     }
 
-    wind->was_floating = floating;
+    /* Similar to maximized/restore events above, send focus events too! */
+    SDL_Se

(Patch may be truncated, please check the link at the top of this post.)