SDL: Added SDL_CreateWindowWithPosition()

From 2aa2fa5449d490159850ba46f9eefbd341edad44 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 31 Mar 2023 17:07:38 -0700
Subject: [PATCH] Added SDL_CreateWindowWithPosition()

It turns out there's a race condition on X11 where the window could be placed by the window manager while being placed by the application, so we need to have the initial position available at window creation.
---
 build-scripts/SDL_migration.cocci |  9 +++-
 docs/README-migration.md          |  9 +---
 include/SDL3/SDL_video.h          | 71 ++++++++++++++++++++++++++++++-
 src/dynapi/SDL_dynapi.sym         |  1 +
 src/dynapi/SDL_dynapi_overrides.h |  1 +
 src/dynapi/SDL_dynapi_procs.h     |  1 +
 src/test/SDL_test_common.c        |  5 +--
 src/video/SDL_video.c             |  5 +++
 test/testautomation_video.c       |  6 +--
 9 files changed, 88 insertions(+), 20 deletions(-)

diff --git a/build-scripts/SDL_migration.cocci b/build-scripts/SDL_migration.cocci
index 2fa9e20b5210..9bb8d8ba49ea 100644
--- a/build-scripts/SDL_migration.cocci
+++ b/build-scripts/SDL_migration.cocci
@@ -2519,16 +2519,21 @@ SDL_Event *e1;
 + e1->gsensor
 @@
 expression e1, e2, e3, e4;
-constant c1, c2;
 @@
-- SDL_CreateWindow(e1, c1, c2, e2, e3, e4)
+- SDL_CreateWindow(e1, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, e2, e3, e4)
 + SDL_CreateWindow(e1, e2, e3, e4)
 @@
+expression e1, e2, e3, e4, e5, e6;
+@@
+- SDL_CreateWindow(e1, e2, e3, e4, e5, e6)
++ SDL_CreateWindowWithPosition(e1, e2, e3, e4, e5, e6)
+@@
 expression e1, e2, e3, e4;
 constant c1, c2;
 @@
 - SDL_CreateShapedWindow(e1, c1, c2, e2, e3, e4)
 + SDL_CreateShapedWindow(e1, e2, e3, e4)
+@@
 typedef SDL_atomic_t, SDL_AtomicInt;
 @@
 - SDL_atomic_t
diff --git a/docs/README-migration.md b/docs/README-migration.md
index a2b68fe03860..07824f1a0aa8 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -1036,14 +1036,7 @@ Rather than iterating over displays using display index, there is a new function
 }

-SDL_CreateWindow() has been simplified and no longer takes a window position. You can set a position for your window during window creation by creating it hidden and setting the position before showing it:
-```c
-{

  • SDL_Window *window = SDL_CreateWindow(“Test”, 640, 480, SDL_WINDOW_HIDDEN);
  • SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
  • SDL_ShowWindow(window);
    -}
    -```
    +SDL_CreateWindow() has been simplified and no longer takes a window position. You can use SDL_CreateWindowWithPosition() if you need to set the window position when creating it.

The SDL_WINDOWPOS_UNDEFINED_DISPLAY() and SDL_WINDOWPOS_CENTERED_DISPLAY() macros take a display ID instead of display index. The display ID 0 has a special meaning in this case, and is used to indicate the primary display.

diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h
index f8132ad28f73…98dc9663876b 100644
— a/include/SDL3/SDL_video.h
+++ b/include/SDL3/SDL_video.h
@@ -92,6 +92,7 @@ typedef enum
*

  • \sa SDL_CreateWindow()
  • \sa SDL_CreateWindowFrom()
    • \sa SDL_CreateWindowWithPosition()
    • \sa SDL_DestroyWindow()
    • \sa SDL_FlashWindow()
    • \sa SDL_GetWindowData()
      @@ -602,7 +603,7 @@ extern DECLSPEC void *SDLCALL SDL_GetWindowICCProfile(SDL_Window *window, size_t
      extern DECLSPEC Uint32 SDLCALL SDL_GetWindowPixelFormat(SDL_Window *window);

/**

    • Create a window with the specified position, dimensions, and flags.
    • Create a window with the specified dimensions and flags.
    • flags may be any of the following OR’d together:

@@ -661,10 +662,78 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetWindowPixelFormat(SDL_Window *window);
*

  • \sa SDL_CreatePopupWindow
  • \sa SDL_CreateWindowFrom
    • \sa SDL_CreateWindowWithPosition
    • \sa SDL_DestroyWindow
      */
      extern DECLSPEC SDL_Window *SDLCALL SDL_CreateWindow(const char *title, int w, int h, Uint32 flags);

+/**

    • Create a window with the specified position, dimensions, and flags.
    • flags may be any of the following OR’d together:
      • SDL_WINDOW_FULLSCREEN: fullscreen window at desktop resolution
      • SDL_WINDOW_OPENGL: window usable with an OpenGL context
      • SDL_WINDOW_VULKAN: window usable with a Vulkan instance
      • SDL_WINDOW_METAL: window usable with a Metal instance
      • SDL_WINDOW_HIDDEN: window is not visible
      • SDL_WINDOW_BORDERLESS: no window decoration
      • SDL_WINDOW_RESIZABLE: window can be resized
      • SDL_WINDOW_MINIMIZED: window is minimized
      • SDL_WINDOW_MAXIMIZED: window is maximized
      • SDL_WINDOW_MOUSE_GRABBED: window has grabbed mouse focus
    • The SDL_Window is implicitly shown if SDL_WINDOW_HIDDEN is not set.
    • On Apple’s macOS, you must set the NSHighResolutionCapable Info.plist
    • property to YES, otherwise you will not receive a High-DPI OpenGL canvas.
    • The window size in pixels may differ from its size in screen coordinates if
    • the window is on a high density display (one with an OS scaling factor).
    • Use SDL_GetWindowSize() to query the client area’s size in screen
    • coordinates, and SDL_GetWindowSizeInPixels() or SDL_GetRenderOutputSize()
    • to query the drawable size in pixels. Note that the drawable size can vary
    • after the window is created and should be queried again if you get an
    • SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED event.
    • If the window is set fullscreen, the width and height parameters w and
    • h will not be used. However, invalid size parameters (e.g. too large) may
    • still fail. Window size is actually limited to 16384 x 16384 for all
    • platforms at window creation.
    • If the window is created with any of the SDL_WINDOW_OPENGL or
    • SDL_WINDOW_VULKAN flags, then the corresponding LoadLibrary function
    • (SDL_GL_LoadLibrary or SDL_Vulkan_LoadLibrary) is called and the
    • corresponding UnloadLibrary function is called by SDL_DestroyWindow().
    • If SDL_WINDOW_VULKAN is specified and there isn’t a working Vulkan driver,
    • SDL_CreateWindow() will fail because SDL_Vulkan_LoadLibrary() will fail.
    • If SDL_WINDOW_METAL is specified on an OS that does not support Metal,
    • SDL_CreateWindow() will fail.
    • On non-Apple devices, SDL requires you to either not link to the Vulkan
    • loader or link to a dynamic library version. This limitation may be removed
    • in a future version of SDL.
    • \param title the title of the window, in UTF-8 encoding
    • \param x the x position of the window, or SDL_WINDOWPOS_CENTERED
    • \param y the y position of the window, or SDL_WINDOWPOS_CENTERED
    • \param w the width of the window, in screen coordinates
    • \param h the height of the window, in screen coordinates
    • \param flags 0, or one or more SDL_WindowFlags OR’d together
    • \returns the window that was created or NULL on failure; call
    •      SDL_GetError() for more information.
      
    • \since This function is available since SDL 3.0.0.
    • \sa SDL_CreatePopupWindow
    • \sa SDL_CreateWindow
    • \sa SDL_CreateWindowFrom
    • \sa SDL_DestroyWindow
  • */
    +extern DECLSPEC SDL_Window *SDLCALL SDL_CreateWindowWithPosition(const char *title, int x, int y, int w, int h, Uint32 flags);

/**

  • Create a child popup window of the specified parent window.

diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 0592fa3a8d78…ab7ad80510ca 100644
— a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -841,6 +841,7 @@ SDL3_0.0.0 {
SDL_GetSystemTheme;
SDL_CreatePopupWindow;
SDL_GetWindowParent;

  • SDL_CreateWindowWithPosition;

    extra symbols go here (don’t modify this line)

local: *;
};
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 1c7d5be751a9…55d74be9adbb 100644
— a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -867,3 +867,4 @@
#define SDL_GetSystemTheme SDL_GetSystemTheme_REAL
#define SDL_CreatePopupWindow SDL_CreatePopupWindow_REAL
#define SDL_GetWindowParent SDL_GetWindowParent_REAL
+#define SDL_CreateWindowWithPosition SDL_CreateWindowWithPosition_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index f8542e613391…5f5beeecde16 100644
— a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -912,3 +912,4 @@ SDL_DYNAPI_PROC(int,SDL_GetRenderWindowSize,(SDL_Renderer *a, int *b, int c),(a
SDL_DYNAPI_PROC(SDL_SystemTheme,SDL_GetSystemTheme,(void),(),return)
SDL_DYNAPI_PROC(SDL_Window
,SDL_CreatePopupWindow,(SDL_Window a, int b, int c, int d, int e, Uint32 f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(SDL_Window
,SDL_GetWindowParent,(SDL_Window a),(a),return)
+SDL_DYNAPI_PROC(SDL_Window
,SDL_CreateWindowWithPosition,(const char *a, int b, int c, int d, int e, Uint32 f),(a,b,c,d,e,f),return)
diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c
index 45339dd18f8d…806c5fb041d8 100644
— a/src/test/SDL_test_common.c
+++ b/src/test/SDL_test_common.c
@@ -1312,15 +1312,12 @@ SDLTest_CommonInit(SDLTest_CommonState *state)
} else {
SDL_strlcpy(title, state->window_title, SDL_arraysize(title));
}

  •        state->windows[i] = SDL_CreateWindow(title, r.w, r.h, state->window_flags);
    
  •        state->windows[i] = SDL_CreateWindowWithPosition(title, r.x, r.y, r.w, r.h, state->window_flags);
           if (!state->windows[i]) {
               SDL_Log("Couldn't create window: %s\n",
                       SDL_GetError());
               return SDL_FALSE;
           }
    
  •        if (r.x != SDL_WINDOWPOS_UNDEFINED || r.y != SDL_WINDOWPOS_UNDEFINED) {
    
  •            SDL_SetWindowPosition(state->windows[i], r.x, r.y);
    
  •        }
           if (state->window_minW || state->window_minH) {
               SDL_SetWindowMinimumSize(state->windows[i], state->window_minW, state->window_minH);
           }
    

diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 795def749784…aaf99ab18a0b 100644
— a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -1948,6 +1948,11 @@ SDL_Window *SDL_CreateWindow(const char *title, int w, int h, Uint32 flags)
return SDL_CreateWindowInternal(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w , h, NULL, flags);
}

+SDL_Window *SDL_CreateWindowWithPosition(const char *title, int x, int y, int w, int h, Uint32 flags)
+{

  • return SDL_CreateWindowInternal(title, x, y, w , h, NULL, flags);
    +}

SDL_Window *SDL_CreatePopupWindow(SDL_Window *parent, int offset_x, int offset_y, int w, int h, Uint32 flags)
{
if (!(_this->quirk_flags & VIDEO_DEVICE_QUIRK_HAS_POPUP_WINDOW_SUPPORT)) {
diff --git a/test/testautomation_video.c b/test/testautomation_video.c
index b8fd98f5f4d4…a878ef7eae5e 100644
— a/test/testautomation_video.c
+++ b/test/testautomation_video.c
@@ -1672,14 +1672,10 @@ static int video_setWindowCenteredOnDisplay(void *arg)
expectedX = (expectedDisplayRect.x + ((expectedDisplayRect.w - w) / 2));
expectedY = (expectedDisplayRect.y + ((expectedDisplayRect.h - h) / 2));

  •            window = SDL_CreateWindow(title, w, h, SDL_WINDOW_HIDDEN);
    
  •            window = SDL_CreateWindowWithPosition(title, x, y, w, h, 0);
               SDLTest_AssertPass("Call to SDL_CreateWindow('Title',%d,%d,%d,%d,SHOWN)", x, y, w, h);
               SDLTest_AssertCheck(window != NULL, "Validate that returned window struct is not NULL");
    
  •            /* Set the desired position */
    
  •            SDL_SetWindowPosition(window, x, y);
    
  •            SDL_ShowWindow(window);
    
  •            /* Check the window is centered on the requested display */
               currentDisplay = SDL_GetDisplayForWindow(window);
               SDL_GetWindowSize(window, &currentW, &currentH);