SDL: x11: Don't force position windows with an undefined position

From d0ae0936811a49289d7ac0be49058ff9e897156b Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Wed, 22 Jan 2025 19:18:56 -0500
Subject: [PATCH] x11: Don't force position windows with an undefined position

An undefined position means that the window manager can handle placement, so SDL shouldn't override that by forcing a position when showing a window.

Allows for removing a fair bit of now-unnecessary code as well.
---
 src/video/x11/SDL_x11events.c | 46 +++++++++--------------------------
 src/video/x11/SDL_x11window.c | 30 +++++++----------------
 src/video/x11/SDL_x11window.h |  7 +++++-
 3 files changed, 26 insertions(+), 57 deletions(-)

diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c
index 0ced1b68d3074..aebed3ef0710c 100644
--- a/src/video/x11/SDL_x11events.c
+++ b/src/video/x11/SDL_x11events.c
@@ -1424,7 +1424,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
 
         if (xevent->xconfigure.x != data->last_xconfigure.x ||
             xevent->xconfigure.y != data->last_xconfigure.y) {
-            if (!data->disable_size_position_events) {
+            if (!data->size_move_event_flags) {
                 SDL_Window *w;
                 int x = xevent->xconfigure.x;
                 int y = xevent->xconfigure.y;
@@ -1448,7 +1448,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
 
         if (xevent->xconfigure.width != data->last_xconfigure.width ||
             xevent->xconfigure.height != data->last_xconfigure.height) {
-            if (!data->disable_size_position_events) {
+            if (!data->size_move_event_flags) {
                 data->pending_operation &= ~X11_PENDING_OP_RESIZE;
                 SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESIZED,
                                     xevent->xconfigure.width,
@@ -1799,7 +1799,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
                          * shut off to avoid bogus window sizes and positions, and
                          * note that the old borders were non-zero for restoration.
                          */
-                        data->disable_size_position_events = true;
+                        data->size_move_event_flags |= X11_SIZE_MOVE_EVENTS_WAIT_FOR_BORDERS;
                         data->previous_borders_nonzero = true;
                     } else if (!(flags & SDL_WINDOW_FULLSCREEN) &&
                                data->previous_borders_nonzero &&
@@ -1809,10 +1809,10 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
                          * off size events until the borders come back to avoid bogus
                          * window sizes and positions.
                          */
-                        data->disable_size_position_events = true;
+                        data->size_move_event_flags |= X11_SIZE_MOVE_EVENTS_WAIT_FOR_BORDERS;
                         data->previous_borders_nonzero = false;
                     } else {
-                        data->disable_size_position_events = false;
+                        data->size_move_event_flags = 0;
                         data->previous_borders_nonzero = false;
 
                         if (!(data->window->flags & SDL_WINDOW_FULLSCREEN) && data->toggle_borders) {
@@ -1845,7 +1845,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
                             data->pending_operation |= X11_PENDING_OP_MOVE;
                             data->expected.x = data->window->pending.x - data->border_left;
                             data->expected.y = data->window->pending.y - data->border_top;
-                            X11_XMoveWindow(display, data->xwindow, data->window->pending.x - data->border_left, data->window->pending.y - data->border_top);
+                            X11_XMoveWindow(display, data->xwindow, data->expected.x, data->expected.y);
                         }
                         if (data->pending_size) {
                             data->pending_size = false;
@@ -1875,37 +1875,13 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
                right approach, but it seems to work. */
             X11_UpdateKeymap(_this, true);
         } else if (xevent->xproperty.atom == videodata->atoms._NET_FRAME_EXTENTS) {
-            if (data->disable_size_position_events) {
-                /* Re-enable size events if they were turned off waiting for the borders to come back
-                 * when leaving fullscreen.
-                 */
-                data->disable_size_position_events = false;
+            /* Events are disabled when leaving fullscreen until the borders appear to avoid
+             * incorrect size/position events.
+             */
+            if (data->size_move_event_flags) {
+                data->size_move_event_flags &= ~X11_SIZE_MOVE_EVENTS_WAIT_FOR_BORDERS;
                 X11_GetBorderValues(data);
-                if (data->border_top != 0 || data->border_left != 0 || data->border_right != 0 || data->border_bottom != 0) {
-                    // Adjust if the window size/position changed to accommodate the borders.
-                    data->pending_operation |= X11_PENDING_OP_MOVE | X11_PENDING_OP_RESIZE;
-
-                    if (data->pending_position) {
-                        data->pending_position = false;
-                        data->expected.x = data->window->pending.x - data->border_left;
-                        data->expected.y = data->window->pending.y - data->border_top;
-
-                    } else {
-                        data->expected.x = data->window->windowed.x - data->border_left;
-                        data->expected.y = data->window->windowed.y - data->border_top;
-                    }
 
-                    if (data->pending_size) {
-                        data->pending_size = false;
-                        data->expected.w = data->window->pending.w;
-                        data->expected.h = data->window->pending.h;
-                    } else {
-                        data->expected.w = data->window->windowed.w;
-                        data->expected.h = data->window->windowed.h;
-                    }
-                    X11_XMoveWindow(display, data->xwindow, data->expected.x, data->expected.y - data->border_top);
-                    X11_XResizeWindow(display, data->xwindow, data->expected.w, data->expected.h);
-                }
             }
             if (!(data->window->flags & SDL_WINDOW_FULLSCREEN) && data->toggle_borders) {
                 data->toggle_borders = false;
diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c
index 0ecabec6752dc..c3c125eafeb20 100644
--- a/src/video/x11/SDL_x11window.c
+++ b/src/video/x11/SDL_x11window.c
@@ -1440,9 +1440,6 @@ void X11_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
         X11_UpdateWindowPosition(window, false);
     }
 
-    const int target_x = window->last_position_pending ? window->pending.x : window->x;
-    const int target_y = window->last_position_pending ? window->pending.y : window->y;
-
     /* Whether XMapRaised focuses the window is based on the window type and it is
      * wm specific. There isn't much we can do here */
     (void)bActivate;
@@ -1475,33 +1472,24 @@ void X11_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
         X11_GetBorderValues(data);
     }
 
-    /* Some window managers can send garbage coordinates while mapping the window, and need the position sent again
-     * after mapping or the window may not be positioned properly.
-     *
-     * Don't emit size and position events during the initial configure events, they will be sent afterwards, when the
-     * final coordinates are available to avoid sending garbage values.
+    // Apply the pending position, if any, after the window is mapped.
+    data->pending_position = window->last_position_pending;
+
+    /* Some window managers can send garbage coordinates while mapping the window, so don't emit size and position
+     * events during the initial configure events.
      */
-    data->disable_size_position_events = true;
+    data->size_move_event_flags = X11_SIZE_MOVE_EVENTS_DISABLE;
     X11_XSync(display, False);
     X11_PumpEvents(_this);
+    data->size_move_event_flags = 0;
 
     // If a configure event was received (type is non-zero), send the final window size and coordinates.
     if (data->last_xconfigure.type) {
-        int x = data->last_xconfigure.x;
-        int y = data->last_xconfigure.y;
-        SDL_GlobalToRelativeForWindow(data->window, x, y, &x, &y);
-
-        // If the borders appeared, this happened automatically in the event system, otherwise, set the position now.
-        if (data->disable_size_position_events && (target_x != x || target_y != y)) {
-            data->pending_operation = X11_PENDING_OP_MOVE;
-            X11_XMoveWindow(display, data->xwindow, target_x, target_y);
-        }
-
+        int x, y;
+        SDL_GlobalToRelativeForWindow(data->window, data->last_xconfigure.x, data->last_xconfigure.y, &x, &y);
         SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, data->last_xconfigure.width, data->last_xconfigure.height);
         SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, x, y);
     }
-
-    data->disable_size_position_events = false;
 }
 
 void X11_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h
index 16936033596f2..f1a73ab592480 100644
--- a/src/video/x11/SDL_x11window.h
+++ b/src/video/x11/SDL_x11window.h
@@ -103,10 +103,15 @@ struct SDL_WindowData
         X11_PENDING_OP_RESIZE = 0x20
     } pending_operation;
 
+    enum
+    {
+        X11_SIZE_MOVE_EVENTS_DISABLE = 0x01, // Events are completely disabled.
+        X11_SIZE_MOVE_EVENTS_WAIT_FOR_BORDERS = 0x02, // Events are disabled until a _NET_FRAME_EXTENTS event arrives.
+    } size_move_event_flags;
+
     bool pending_size;
     bool pending_position;
     bool window_was_maximized;
-    bool disable_size_position_events;
     bool previous_borders_nonzero;
     bool toggle_borders;
     bool fullscreen_borders_forced_on;