فهرست منبع

– gdk: Add SDL_GDKGetDefaultUser, SDL_GetPrefPath implementation

Ethan Lee 1 سال پیش
والد
کامیت
24fcb61470

+ 1 - 1
VisualC-GDK/SDL/SDL.vcxproj

@@ -563,7 +563,7 @@
     <ClCompile Include="..\..\src\events\SDL_touch.c" />
     <ClCompile Include="..\..\src\events\SDL_windowevents.c" />
     <ClCompile Include="..\..\src\file\SDL_rwops.c" />
-    <ClCompile Include="..\..\src\filesystem\windows\SDL_sysfilesystem.c" />
+    <ClCompile Include="..\..\src\filesystem\gdk\SDL_sysfilesystem.cpp" />
     <ClCompile Include="..\..\src\haptic\dummy\SDL_syshaptic.c" />
     <ClCompile Include="..\..\src\haptic\SDL_haptic.c" />
     <ClCompile Include="..\..\src\haptic\windows\SDL_dinputhaptic.c" />

+ 3 - 3
VisualC-GDK/SDL/SDL.vcxproj.filters

@@ -31,7 +31,7 @@
     <Filter Include="filesystem">
       <UniqueIdentifier>{377061e4-3856-4f05-b916-0d3b360df0f6}</UniqueIdentifier>
     </Filter>
-    <Filter Include="filesystem\windows">
+    <Filter Include="filesystem\gdk">
       <UniqueIdentifier>{226a6643-1c65-4c7f-92aa-861313d974bb}</UniqueIdentifier>
     </Filter>
     <Filter Include="haptic">
@@ -925,8 +925,8 @@
     <ClCompile Include="..\..\src\file\SDL_rwops.c">
       <Filter>file</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\filesystem\windows\SDL_sysfilesystem.c">
-      <Filter>filesystem\windows</Filter>
+    <ClCompile Include="..\..\src\filesystem\gdk\SDL_sysfilesystem.cpp">
+      <Filter>filesystem\gdk</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\haptic\SDL_haptic.c">
       <Filter>haptic</Filter>

+ 6 - 0
docs/README-gdk.md

@@ -29,6 +29,12 @@ The Windows GDK port supports the full set of Win32 APIs, renderers, controllers
   * Global task queue callbacks are dispatched during `SDL_PumpEvents` (which is also called internally if using `SDL_PollEvent`).
   * You can get the handle of the global task queue through `SDL_GDKGetTaskQueue`, if needed. When done with the queue, be sure to use `XTaskQueueCloseHandle` to decrement the reference count (otherwise it will cause a resource leak).
 
+* Single-player games have some additional features available:
+  * Call `SDL_GDKGetDefaultUser` to get the default XUserHandle pointer.
+  * `SDL_GetPrefPath` still works, but only for single-player titles.
+
+These functions mostly wrap around async APIs, and thus should be treated as synchronous alternatives. Also note that the single-player functions return on any OS errors, so be sure to validate the return values!
+
 * What doesn't work:
   * Compilation with anything other than through the included Visual C++ solution file
 

+ 15 - 1
include/SDL_system.h

@@ -593,7 +593,8 @@ extern DECLSPEC void SDLCALL SDL_OnApplicationDidChangeStatusBarOrientation(void
 
 /* Functions used only by GDK */
 #if defined(__GDK__)
-typedef struct XTaskQueueObject * XTaskQueueHandle;
+typedef struct XTaskQueueObject *XTaskQueueHandle;
+typedef struct XUser *XUserHandle;
 
 /**
  * Gets a reference to the global async task queue handle for GDK,
@@ -610,6 +611,19 @@ typedef struct XTaskQueueObject * XTaskQueueHandle;
  */
 extern DECLSPEC int SDLCALL SDL_GDKGetTaskQueue(XTaskQueueHandle * outTaskQueue);
 
+/**
+ * Gets a reference to the default user handle for GDK.
+ *
+ * This is effectively a synchronous version of XUserAddAsync, which always
+ * prefers the default user and allows a sign-in UI.
+ *
+ * \param outUserHandle a pointer to be filled in with the default user handle.
+ * \returns 0 if success, -1 if any error occurs.
+ *
+ * \since This function is available since SDL 2.28.0.
+ */
+extern DECLSPEC int SDLCALL SDL_GDKGetDefaultUser(XUserHandle * outUserHandle);
+
 #endif
 
 /* Ends C function definitions when using C++ */

+ 21 - 0
src/core/gdk/SDL_gdk.cpp

@@ -218,3 +218,24 @@ SDL_GDKSuspendComplete()
         SetEvent(plmSuspendComplete);
     }
 }
+
+extern "C" DECLSPEC int
+SDL_GDKGetDefaultUser(XUserHandle *outUserHandle)
+{
+    XAsyncBlock block = { 0 };
+    HRESULT result;
+
+    if (FAILED(result = XUserAddAsync(XUserAddOptions::AddDefaultUserAllowingUI, &block))) {
+        return WIN_SetErrorFromHRESULT("XUserAddAsync", result);
+    }
+
+    do {
+        result = XUserAddResult(&block, outUserHandle);
+    } while (result == E_PENDING);
+    if (FAILED(result)) {
+        return WIN_SetErrorFromHRESULT("XUserAddResult", result);
+    }
+
+    return 0;
+}
+

+ 140 - 0
src/filesystem/gdk/SDL_sysfilesystem.cpp

@@ -0,0 +1,140 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifdef SDL_FILESYSTEM_XBOX
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* System dependent filesystem routines                                */
+
+#include "../../core/windows/SDL_windows.h"
+#include "SDL_hints.h"
+#include "SDL_system.h"
+#include "SDL_filesystem.h"
+#include <XGameSaveFiles.h>
+
+char *
+SDL_GetBasePath(void)
+{
+    /* NOTE: This function is a UTF8 version of the Win32 SDL_GetBasePath()!
+     * The GDK actually _recommends_ the 'A' functions over the 'W' functions :o
+     */
+    DWORD buflen = 128;
+    CHAR *path = NULL;
+    DWORD len = 0;
+    int i;
+
+    while (SDL_TRUE) {
+        void *ptr = SDL_realloc(path, buflen * sizeof(CHAR));
+        if (ptr == NULL) {
+            SDL_free(path);
+            SDL_OutOfMemory();
+            return NULL;
+        }
+
+        path = (CHAR *)ptr;
+
+        len = GetModuleFileNameA(NULL, path, buflen);
+        /* if it truncated, then len >= buflen - 1 */
+        /* if there was enough room (or failure), len < buflen - 1 */
+        if (len < buflen - 1) {
+            break;
+        }
+
+        /* buffer too small? Try again. */
+        buflen *= 2;
+    }
+
+    if (len == 0) {
+        SDL_free(path);
+        WIN_SetError("Couldn't locate our .exe");
+        return NULL;
+    }
+
+    for (i = len - 1; i > 0; i--) {
+        if (path[i] == '\\') {
+            break;
+        }
+    }
+
+    SDL_assert(i > 0);  /* Should have been an absolute path. */
+    path[i + 1] = '\0'; /* chop off filename. */
+
+    return path;
+}
+
+char *
+SDL_GetPrefPath(const char *org, const char *app)
+{
+    XUserHandle user = NULL;
+    XAsyncBlock block = { 0 };
+    char *folderPath;
+    HRESULT result;
+    const char *csid = SDL_GetHint("SDL_GDK_SERVICE_CONFIGURATION_ID");
+    
+    if (app == NULL) {
+        SDL_InvalidParamError("app");
+        return NULL;
+    }
+
+    /* This should be set before calling SDL_GetPrefPath! */
+    if (csid == NULL) {
+        SDL_LogWarn(SDL_LOG_CATEGORY_SYSTEM, "Set SDL_GDK_SERVICE_CONFIGURATION_ID before calling SDL_GetPrefPath!");
+        return SDL_strdup("T:\\");
+    }
+
+    if (SDL_GDKGetDefaultUser(&user) < 0) {
+        /* Error already set, just return */
+        return NULL;
+    }
+
+    if (FAILED(result = XGameSaveFilesGetFolderWithUiAsync(user, csid, &block))) {
+        WIN_SetErrorFromHRESULT("XGameSaveFilesGetFolderWithUiAsync", result);
+        return NULL;
+    }
+
+    folderPath = (char*) SDL_malloc(MAX_PATH);
+    do {
+        result = XGameSaveFilesGetFolderWithUiResult(&block, MAX_PATH, folderPath);
+    } while (result == E_PENDING);
+    if (FAILED(result)) {
+        WIN_SetErrorFromHRESULT("XGameSaveFilesGetFolderWithUiResult", result);
+        SDL_free(folderPath);
+        return NULL;
+    }
+
+    /* We aren't using 'app' here because the container rules are a lot more
+     * strict than the NTFS rules, so it will most likely be invalid :(
+     */
+    SDL_strlcat(folderPath, "\\SDLPrefPath\\", MAX_PATH);
+    if (CreateDirectoryA(folderPath, NULL) == FALSE) {
+        if (GetLastError() != ERROR_ALREADY_EXISTS) {
+            WIN_SetError("CreateDirectoryA");
+            SDL_free(folderPath);
+            return NULL;
+        }
+    }
+    return folderPath;
+}
+
+#endif /* SDL_FILESYSTEM_XBOX */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 0 - 16
src/filesystem/windows/SDL_sysfilesystem.c

@@ -170,20 +170,4 @@ char *SDL_GetPrefPath(const char *org, const char *app)
 
 #endif /* SDL_FILESYSTEM_WINDOWS */
 
-#ifdef SDL_FILESYSTEM_XBOX
-#include "SDL_filesystem.h"
-#include "SDL_error.h"
-char *SDL_GetBasePath(void)
-{
-    SDL_Unsupported();
-    return NULL;
-}
-
-char *SDL_GetPrefPath(const char *org, const char *app)
-{
-    SDL_Unsupported();
-    return NULL;
-}
-#endif /* SDL_FILESYSTEM_XBOX */
-
 /* vi: set ts=4 sw=4 expandtab: */