filesystem: SDL_GetUserFolder() now follows the SDL_GetStringRule.

It also now caches at the higher level, so the platform-specific bits don't
change their interface much.

Reference Issue #10229.
This commit is contained in:
Ryan C. Gordon 2024-07-15 20:03:15 -04:00
parent d40b89dff6
commit 2321726ff1
19 changed files with 48 additions and 31 deletions

View file

@ -204,12 +204,13 @@ typedef enum SDL_Folder
SDL_FOLDER_TEMPLATES, SDL_FOLDER_TEMPLATES,
/** Video files that can be played using a standard video player (mp4, /** Video files that can be played using a standard video player (mp4,
webm...). */ webm...). */
SDL_FOLDER_VIDEOS SDL_FOLDER_VIDEOS,
/** total number of types in this enum, not a folder type by itself. */
SDL_FOLDER_TOTAL
} SDL_Folder; } SDL_Folder;
/** /**
* Finds the most suitable user folder for the specified purpose, and returns * Finds the most suitable user folder for a specific purpose.
* its path in OS-specific notation.
* *
* Many OSes provide certain standard folders for certain purposes, such as * Many OSes provide certain standard folders for certain purposes, such as
* storing pictures, music or videos for a certain user. This function gives * storing pictures, music or videos for a certain user. This function gives
@ -220,14 +221,10 @@ typedef enum SDL_Folder
* data for the application to manage, see SDL_GetBasePath() and * data for the application to manage, see SDL_GetBasePath() and
* SDL_GetPrefPath(). * SDL_GetPrefPath().
* *
* Note that the function is expensive, and should be called once at the
* beginning of the execution and kept for as long as needed.
*
* The returned path is guaranteed to end with a path separator ('\\' on * The returned path is guaranteed to end with a path separator ('\\' on
* Windows, '/' on most other platforms). * Windows, '/' on most other platforms).
* *
* The returned value is owned by the caller and should be freed with * The returned string follows the SDL_GetStringRule.
* SDL_free().
* *
* If NULL is returned, the error may be obtained with SDL_GetError(). * If NULL is returned, the error may be obtained with SDL_GetError().
* *
@ -236,10 +233,8 @@ typedef enum SDL_Folder
* folder, or NULL if an error happened. * folder, or NULL if an error happened.
* *
* \since This function is available since SDL 3.0.0. * \since This function is available since SDL 3.0.0.
*
* \sa SDL_Folder
*/ */
extern SDL_DECLSPEC char *SDLCALL SDL_GetUserFolder(SDL_Folder folder); extern SDL_DECLSPEC const char *SDLCALL SDL_GetUserFolder(SDL_Folder folder);
/* Abstract filesystem interface */ /* Abstract filesystem interface */

View file

@ -228,8 +228,9 @@ Sint32 JNI_OnLoad(void *vm, void *reserved)
} }
#endif #endif
// !!! FIXME: this probably belongs in src/filesystem/gdk
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) #if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
char *SDL_GetUserFolder(SDL_Folder folder) const char *SDL_GetUserFolder(SDL_Folder folder)
{ {
(void)folder; (void)folder;
SDL_Unsupported(); SDL_Unsupported();

View file

@ -502,7 +502,7 @@ SDL_DYNAPI_PROC(const char*,SDL_GetTouchDeviceName,(SDL_TouchID a),(a),return)
SDL_DYNAPI_PROC(SDL_TouchDeviceType,SDL_GetTouchDeviceType,(SDL_TouchID a),(a),return) SDL_DYNAPI_PROC(SDL_TouchDeviceType,SDL_GetTouchDeviceType,(SDL_TouchID a),(a),return)
SDL_DYNAPI_PROC(SDL_TouchID*,SDL_GetTouchDevices,(int *a),(a),return) SDL_DYNAPI_PROC(SDL_TouchID*,SDL_GetTouchDevices,(int *a),(a),return)
SDL_DYNAPI_PROC(SDL_Finger**,SDL_GetTouchFingers,(SDL_TouchID a, int *b),(a,b),return) SDL_DYNAPI_PROC(SDL_Finger**,SDL_GetTouchFingers,(SDL_TouchID a, int *b),(a,b),return)
SDL_DYNAPI_PROC(char*,SDL_GetUserFolder,(SDL_Folder a),(a),return) SDL_DYNAPI_PROC(const char*,SDL_GetUserFolder,(SDL_Folder a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GetVersion,(void),(),return) SDL_DYNAPI_PROC(int,SDL_GetVersion,(void),(),return)
SDL_DYNAPI_PROC(const char*,SDL_GetVideoDriver,(int a),(a),return) SDL_DYNAPI_PROC(const char*,SDL_GetVideoDriver,(int a),(a),return)
SDL_DYNAPI_PROC(SDL_WinRT_DeviceFamily,SDL_GetWinRTDeviceFamily,(void),(),return) SDL_DYNAPI_PROC(SDL_WinRT_DeviceFamily,SDL_GetWinRTDeviceFamily,(void),(),return)

View file

@ -411,14 +411,38 @@ const char *SDL_GetBasePath(void)
return CachedBasePath; return CachedBasePath;
} }
static char *CachedUserFolders[SDL_FOLDER_TOTAL];
const char *SDL_GetUserFolder(SDL_Folder folder)
{
const int idx = (int) folder;
if ((idx < 0) || (idx >= SDL_arraysize(CachedUserFolders))) {
SDL_InvalidParamError("folder");
return NULL;
}
if (!CachedUserFolders[idx]) {
CachedUserFolders[idx] = SDL_SYS_GetUserFolder(folder);
}
return CachedUserFolders[idx];
}
void SDL_InitFilesystem(void) void SDL_InitFilesystem(void)
{ {
CachedBasePath = NULL; // just in case. CachedBasePath = NULL; // just in case.
SDL_zeroa(CachedUserFolders);
} }
void SDL_QuitFilesystem(void) void SDL_QuitFilesystem(void)
{ {
SDL_free(CachedBasePath); SDL_free(CachedBasePath);
CachedBasePath = NULL; CachedBasePath = NULL;
for (int i = 0; i < SDL_arraysize(CachedUserFolders); i++) {
SDL_free(CachedUserFolders[i]);
CachedUserFolders[i] = NULL;
}
} }

View file

@ -24,6 +24,7 @@
// return a string that we can SDL_free(). It will be cached at the higher level. // return a string that we can SDL_free(). It will be cached at the higher level.
extern char *SDL_SYS_GetBasePath(void); extern char *SDL_SYS_GetBasePath(void);
extern char *SDL_SYS_GetUserFolder(SDL_Folder folder);
int SDL_SYS_EnumerateDirectory(const char *path, const char *dirname, SDL_EnumerateDirectoryCallback cb, void *userdata); int SDL_SYS_EnumerateDirectory(const char *path, const char *dirname, SDL_EnumerateDirectoryCallback cb, void *userdata);
int SDL_SYS_RemovePath(const char *path); int SDL_SYS_RemovePath(const char *path);

View file

@ -49,7 +49,7 @@ char *SDL_GetPrefPath(const char *org, const char *app)
return NULL; return NULL;
} }
char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{ {
/* TODO: see https://developer.android.com/reference/android/os/Environment#lfields /* TODO: see https://developer.android.com/reference/android/os/Environment#lfields
and https://stackoverflow.com/questions/39332085/get-path-to-pictures-directory */ and https://stackoverflow.com/questions/39332085/get-path-to-pictures-directory */

View file

@ -126,7 +126,7 @@ char *SDL_GetPrefPath(const char *org, const char *app)
} }
} }
char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{ {
@autoreleasepool { @autoreleasepool {
#ifdef SDL_PLATFORM_TVOS #ifdef SDL_PLATFORM_TVOS

View file

@ -37,7 +37,7 @@ char *SDL_GetPrefPath(const char *org, const char *app)
return NULL; return NULL;
} }
char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{ {
SDL_Unsupported(); SDL_Unsupported();
return NULL; return NULL;

View file

@ -81,7 +81,7 @@ char *SDL_GetPrefPath(const char *org, const char *app)
return retval; return retval;
} }
char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{ {
const char *home = NULL; const char *home = NULL;

View file

@ -97,7 +97,7 @@ char *SDL_GetPrefPath(const char *org, const char *app)
return retval; return retval;
} }
char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{ {
const char *home = NULL; const char *home = NULL;
char *retval; char *retval;

View file

@ -60,7 +60,7 @@ char *SDL_GetPrefPath(const char *org, const char *app)
} }
/* TODO */ /* TODO */
char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{ {
SDL_Unsupported(); SDL_Unsupported();
return NULL; return NULL;

View file

@ -108,7 +108,7 @@ char *SDL_GetPrefPath(const char *org, const char *app)
} }
/* TODO */ /* TODO */
char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{ {
SDL_Unsupported(); SDL_Unsupported();
return NULL; return NULL;

View file

@ -78,7 +78,7 @@ char *SDL_GetPrefPath(const char *org, const char *app)
} }
/* TODO */ /* TODO */
char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{ {
SDL_Unsupported(); SDL_Unsupported();
return NULL; return NULL;

View file

@ -197,7 +197,7 @@ char *SDL_GetPrefPath(const char *org, const char *app)
} }
/* TODO */ /* TODO */
char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{ {
SDL_Unsupported(); SDL_Unsupported();
return NULL; return NULL;

View file

@ -510,7 +510,7 @@ static char *xdg_user_dir_lookup (const char *type)
return NULL; return NULL;
} }
char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{ {
const char *param = NULL; const char *param = NULL;
char *retval; char *retval;

View file

@ -81,7 +81,7 @@ char *SDL_GetPrefPath(const char *org, const char *app)
} }
/* TODO */ /* TODO */
char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{ {
SDL_Unsupported(); SDL_Unsupported();
return NULL; return NULL;

View file

@ -174,7 +174,7 @@ char *SDL_GetPrefPath(const char *org, const char *app)
return retval; return retval;
} }
char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{ {
typedef HRESULT (WINAPI *pfnSHGetKnownFolderPath)(REFGUID /* REFKNOWNFOLDERID */, DWORD, HANDLE, PWSTR*); typedef HRESULT (WINAPI *pfnSHGetKnownFolderPath)(REFGUID /* REFKNOWNFOLDERID */, DWORD, HANDLE, PWSTR*);
HMODULE lib = LoadLibrary(L"Shell32.dll"); HMODULE lib = LoadLibrary(L"Shell32.dll");

View file

@ -227,7 +227,7 @@ extern "C" char *SDL_GetPrefPath(const char *org, const char *app)
return retval; return retval;
} }
char *SDL_GetUserFolder(SDL_Folder folder) char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{ {
wstring wpath; wstring wpath;

View file

@ -52,7 +52,7 @@ int main(int argc, char *argv[]) {
const SDL_FRect save_file_rect = { 50, 290, 220, 140 }; const SDL_FRect save_file_rect = { 50, 290, 220, 140 };
const SDL_FRect open_folder_rect = { 370, 50, 220, 140 }; const SDL_FRect open_folder_rect = { 370, 50, 220, 140 };
int i; int i;
char *initial_path = NULL; const char *initial_path = NULL;
const int nfilters = sizeof(filters) / sizeof(*filters); const int nfilters = sizeof(filters) / sizeof(*filters);
/* Initialize test framework */ /* Initialize test framework */
@ -147,10 +147,6 @@ int main(int argc, char *argv[]) {
SDL_RenderPresent(r); SDL_RenderPresent(r);
} }
if (initial_path) {
SDL_free(initial_path);
}
SDLTest_CleanupTextDrawing(); SDLTest_CleanupTextDrawing();
SDL_DestroyRenderer(r); SDL_DestroyRenderer(r);
SDL_DestroyWindow(w); SDL_DestroyWindow(w);