From 30f41c02aec763d32e62351452da9ef582bc3472 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 6 Mar 2026 13:30:59 -0800 Subject: Move contrib libraries to contrib repo --- contrib/SDL-3.2.8/src/dialog/SDL_dialog.c | 131 ----- contrib/SDL-3.2.8/src/dialog/SDL_dialog.h | 22 - contrib/SDL-3.2.8/src/dialog/SDL_dialog_utils.c | 256 --------- contrib/SDL-3.2.8/src/dialog/SDL_dialog_utils.h | 59 -- .../src/dialog/android/SDL_androiddialog.c | 58 -- .../SDL-3.2.8/src/dialog/cocoa/SDL_cocoadialog.m | 188 ------- .../SDL-3.2.8/src/dialog/dummy/SDL_dummydialog.c | 33 -- .../SDL-3.2.8/src/dialog/haiku/SDL_haikudialog.cc | 293 ---------- .../SDL-3.2.8/src/dialog/unix/SDL_portaldialog.c | 545 ------------------ .../SDL-3.2.8/src/dialog/unix/SDL_portaldialog.h | 27 - contrib/SDL-3.2.8/src/dialog/unix/SDL_unixdialog.c | 81 --- .../SDL-3.2.8/src/dialog/unix/SDL_zenitydialog.c | 366 ------------ .../SDL-3.2.8/src/dialog/unix/SDL_zenitydialog.h | 27 - .../src/dialog/windows/SDL_windowsdialog.c | 611 --------------------- 14 files changed, 2697 deletions(-) delete mode 100644 contrib/SDL-3.2.8/src/dialog/SDL_dialog.c delete mode 100644 contrib/SDL-3.2.8/src/dialog/SDL_dialog.h delete mode 100644 contrib/SDL-3.2.8/src/dialog/SDL_dialog_utils.c delete mode 100644 contrib/SDL-3.2.8/src/dialog/SDL_dialog_utils.h delete mode 100644 contrib/SDL-3.2.8/src/dialog/android/SDL_androiddialog.c delete mode 100644 contrib/SDL-3.2.8/src/dialog/cocoa/SDL_cocoadialog.m delete mode 100644 contrib/SDL-3.2.8/src/dialog/dummy/SDL_dummydialog.c delete mode 100644 contrib/SDL-3.2.8/src/dialog/haiku/SDL_haikudialog.cc delete mode 100644 contrib/SDL-3.2.8/src/dialog/unix/SDL_portaldialog.c delete mode 100644 contrib/SDL-3.2.8/src/dialog/unix/SDL_portaldialog.h delete mode 100644 contrib/SDL-3.2.8/src/dialog/unix/SDL_unixdialog.c delete mode 100644 contrib/SDL-3.2.8/src/dialog/unix/SDL_zenitydialog.c delete mode 100644 contrib/SDL-3.2.8/src/dialog/unix/SDL_zenitydialog.h delete mode 100644 contrib/SDL-3.2.8/src/dialog/windows/SDL_windowsdialog.c (limited to 'contrib/SDL-3.2.8/src/dialog') diff --git a/contrib/SDL-3.2.8/src/dialog/SDL_dialog.c b/contrib/SDL-3.2.8/src/dialog/SDL_dialog.c deleted file mode 100644 index a77e443..0000000 --- a/contrib/SDL-3.2.8/src/dialog/SDL_dialog.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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" - -#include "SDL_dialog.h" -#include "SDL_dialog_utils.h" - -void SDL_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) -{ - if (!callback) { - return; - } -#ifdef SDL_DIALOG_DISABLED - SDL_SetError("SDL not built with dialog support"); - callback(userdata, NULL, -1); -#else - SDL_DialogFileFilter *filters = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, NULL); - int nfilters = (int) SDL_GetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, -1); - - if (filters && nfilters == -1) { - SDL_SetError("Set filter pointers, but didn't set number of filters (SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER)"); - callback(userdata, NULL, -1); - return; - } - - const char *msg = validate_filters(filters, nfilters); - - if (msg) { - SDL_SetError("Invalid dialog file filters: %s", msg); - callback(userdata, NULL, -1); - return; - } - - switch (type) { - case SDL_FILEDIALOG_OPENFILE: - case SDL_FILEDIALOG_SAVEFILE: - case SDL_FILEDIALOG_OPENFOLDER: - SDL_SYS_ShowFileDialogWithProperties(type, callback, userdata, props); - break; - - default: - SDL_SetError("Unsupported file dialog type: %d", (int) type); - callback(userdata, NULL, -1); - break; - }; -#endif -} - -void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location, bool allow_many) -{ -#ifdef SDL_DIALOG_DISABLED - if (!callback) { - return; - } - SDL_SetError("SDL not built with dialog support"); - callback(userdata, NULL, -1); -#else - SDL_PropertiesID props = SDL_CreateProperties(); - - SDL_SetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, (void *) filters); - SDL_SetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, nfilters); - SDL_SetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, window); - SDL_SetStringProperty(props, SDL_PROP_FILE_DIALOG_LOCATION_STRING, default_location); - SDL_SetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, allow_many); - - SDL_ShowFileDialogWithProperties(SDL_FILEDIALOG_OPENFILE, callback, userdata, props); - - SDL_DestroyProperties(props); -#endif -} - -void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location) -{ -#ifdef SDL_DIALOG_DISABLED - if (!callback) { - return; - } - SDL_SetError("SDL not built with dialog support"); - callback(userdata, NULL, -1); -#else - SDL_PropertiesID props = SDL_CreateProperties(); - - SDL_SetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, (void *) filters); - SDL_SetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, nfilters); - SDL_SetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, window); - SDL_SetStringProperty(props, SDL_PROP_FILE_DIALOG_LOCATION_STRING, default_location); - - SDL_ShowFileDialogWithProperties(SDL_FILEDIALOG_SAVEFILE, callback, userdata, props); - - SDL_DestroyProperties(props); -#endif -} - -void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const char *default_location, bool allow_many) -{ -#ifdef SDL_DIALOG_DISABLED - if (!callback) { - return; - } - SDL_SetError("SDL not built with dialog support"); - callback(userdata, NULL, -1); -#else - SDL_PropertiesID props = SDL_CreateProperties(); - - SDL_SetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, window); - SDL_SetStringProperty(props, SDL_PROP_FILE_DIALOG_LOCATION_STRING, default_location); - SDL_SetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, allow_many); - - SDL_ShowFileDialogWithProperties(SDL_FILEDIALOG_OPENFOLDER, callback, userdata, props); - - SDL_DestroyProperties(props); -#endif -} diff --git a/contrib/SDL-3.2.8/src/dialog/SDL_dialog.h b/contrib/SDL-3.2.8/src/dialog/SDL_dialog.h deleted file mode 100644 index beee7dd..0000000 --- a/contrib/SDL-3.2.8/src/dialog/SDL_dialog.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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. -*/ - -void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props); diff --git a/contrib/SDL-3.2.8/src/dialog/SDL_dialog_utils.c b/contrib/SDL-3.2.8/src/dialog/SDL_dialog_utils.c deleted file mode 100644 index 8d2b186..0000000 --- a/contrib/SDL-3.2.8/src/dialog/SDL_dialog_utils.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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" - -#include "SDL_dialog_utils.h" - -char *convert_filters(const SDL_DialogFileFilter *filters, int nfilters, - NameTransform ntf, const char *prefix, - const char *separator, const char *suffix, - const char *filt_prefix, const char *filt_separator, - const char *filt_suffix, const char *ext_prefix, - const char *ext_separator, const char *ext_suffix) -{ - char *combined; - char *new_combined; - char *converted; - const char *terminator; - size_t new_length; - int i; - - if (!filters) { - SDL_SetError("Called convert_filters() with NULL filters (SDL bug)"); - return NULL; - } - - combined = SDL_strdup(prefix); - - if (!combined) { - return NULL; - } - - for (i = 0; i < nfilters; i++) { - const SDL_DialogFileFilter *f = &filters[i]; - - converted = convert_filter(*f, ntf, filt_prefix, filt_separator, - filt_suffix, ext_prefix, ext_separator, - ext_suffix); - - if (!converted) { - SDL_free(combined); - return NULL; - } - - terminator = ((i + 1) < nfilters) ? separator : suffix; - new_length = SDL_strlen(combined) + SDL_strlen(converted) - + SDL_strlen(terminator) + 1; - - new_combined = (char *)SDL_realloc(combined, new_length); - - if (!new_combined) { - SDL_free(converted); - SDL_free(combined); - return NULL; - } - - combined = new_combined; - - SDL_strlcat(combined, converted, new_length); - SDL_strlcat(combined, terminator, new_length); - SDL_free(converted); - } - - new_length = SDL_strlen(combined) + SDL_strlen(suffix) + 1; - - new_combined = (char *)SDL_realloc(combined, new_length); - - if (!new_combined) { - SDL_free(combined); - return NULL; - } - - combined = new_combined; - - SDL_strlcat(combined, suffix, new_length); - - return combined; -} - -char *convert_filter(SDL_DialogFileFilter filter, NameTransform ntf, - const char *prefix, const char *separator, - const char *suffix, const char *ext_prefix, - const char *ext_separator, const char *ext_suffix) -{ - char *converted; - char *name_filtered; - size_t total_length; - char *list; - - list = convert_ext_list(filter.pattern, ext_prefix, ext_separator, - ext_suffix); - - if (!list) { - return NULL; - } - - if (ntf) { - name_filtered = ntf(filter.name); - } else { - // Useless strdup, but easier to read and maintain code this way - name_filtered = SDL_strdup(filter.name); - } - - if (!name_filtered) { - SDL_free(list); - return NULL; - } - - total_length = SDL_strlen(prefix) + SDL_strlen(name_filtered) - + SDL_strlen(separator) + SDL_strlen(list) - + SDL_strlen(suffix) + 1; - - converted = (char *) SDL_malloc(total_length); - - if (!converted) { - SDL_free(list); - SDL_free(name_filtered); - return NULL; - } - - SDL_snprintf(converted, total_length, "%s%s%s%s%s", prefix, name_filtered, - separator, list, suffix); - - SDL_free(list); - SDL_free(name_filtered); - - return converted; -} - -char *convert_ext_list(const char *list, const char *prefix, - const char *separator, const char *suffix) -{ - char *converted; - int semicolons; - size_t total_length; - - semicolons = 0; - - for (const char *c = list; *c; c++) { - semicolons += (*c == ';'); - } - - total_length = - SDL_strlen(list) - semicolons // length of list contents - + semicolons * SDL_strlen(separator) // length of separators - + SDL_strlen(prefix) + SDL_strlen(suffix) // length of prefix/suffix - + 1; // terminating null byte - - converted = (char *) SDL_malloc(total_length); - - if (!converted) { - return NULL; - } - - *converted = '\0'; - - SDL_strlcat(converted, prefix, total_length); - - /* Some platforms may prefer to handle the asterisk manually, but this - function offers to handle it for ease of use. */ - if (SDL_strcmp(list, "*") == 0) { - SDL_strlcat(converted, "*", total_length); - } else { - for (const char *c = list; *c; c++) { - if ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') - || (*c >= '0' && *c <= '9') || *c == '-' || *c == '_' - || *c == '.') { - char str[2]; - str[0] = *c; - str[1] = '\0'; - SDL_strlcat(converted, str, total_length); - } else if (*c == ';') { - if (c == list || c[-1] == ';') { - SDL_SetError("Empty pattern not allowed"); - SDL_free(converted); - return NULL; - } - - SDL_strlcat(converted, separator, total_length); - } else { - SDL_SetError("Invalid character '%c' in pattern (Only [a-zA-Z0-9_.-] allowed, or a single *)", *c); - SDL_free(converted); - return NULL; - } - } - } - - if (list[SDL_strlen(list) - 1] == ';') { - SDL_SetError("Empty pattern not allowed"); - SDL_free(converted); - return NULL; - } - - SDL_strlcat(converted, suffix, total_length); - - return converted; -} - -const char *validate_filters(const SDL_DialogFileFilter *filters, int nfilters) -{ - if (filters) { - for (int i = 0; i < nfilters; i++) { - const char *msg = validate_list(filters[i].pattern); - - if (msg) { - return msg; - } - } - } - - return NULL; -} - -const char *validate_list(const char *list) -{ - if (SDL_strcmp(list, "*") == 0) { - return NULL; - } else { - for (const char *c = list; *c; c++) { - if ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') - || (*c >= '0' && *c <= '9') || *c == '-' || *c == '_' - || *c == '.') { - continue; - } else if (*c == ';') { - if (c == list || c[-1] == ';') { - return "Empty pattern not allowed"; - } - } else { - return "Invalid character in pattern (Only [a-zA-Z0-9_.-] allowed, or a single *)"; - } - } - } - - if (list[SDL_strlen(list) - 1] == ';') { - return "Empty pattern not allowed"; - } - - return NULL; -} diff --git a/contrib/SDL-3.2.8/src/dialog/SDL_dialog_utils.h b/contrib/SDL-3.2.8/src/dialog/SDL_dialog_utils.h deleted file mode 100644 index 1343dd7..0000000 --- a/contrib/SDL-3.2.8/src/dialog/SDL_dialog_utils.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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" - -/* The following are utility functions to help implementations. - They are ordered by scope largeness, decreasing. All implementations - should use them, as they check for invalid filters. Where they are unused, - the validate_* function further down below should be used. */ - -/* Transform the name given in argument into something viable for the engine. - Useful if there are special characters to avoid on certain platforms (such - as "|" with Zenity). */ -typedef char *(NameTransform)(const char * name); - -// Converts all the filters into a single string. -// [filter]{[filter]...} -char *convert_filters(const SDL_DialogFileFilter *filters, int nfilters, - NameTransform ntf, const char *prefix, - const char *separator, const char *suffix, - const char *filt_prefix, const char *filt_separator, - const char *filt_suffix, const char *ext_prefix, - const char *ext_separator, const char *ext_suffix); - -// Converts one filter into a single string. -// [filter name][filter extension list] -char *convert_filter(SDL_DialogFileFilter filter, NameTransform ntf, - const char *prefix, const char *separator, - const char *suffix, const char *ext_prefix, - const char *ext_separator, const char *ext_suffix); - -// Converts the extension list of a filter into a single string. -// [extension]{[extension]...} -char *convert_ext_list(const char *list, const char *prefix, - const char *separator, const char *suffix); - -/* Must be used if convert_* functions aren't used */ -// Returns an error message if there's a problem, NULL otherwise -const char *validate_filters(const SDL_DialogFileFilter *filters, - int nfilters); - -const char *validate_list(const char *list); diff --git a/contrib/SDL-3.2.8/src/dialog/android/SDL_androiddialog.c b/contrib/SDL-3.2.8/src/dialog/android/SDL_androiddialog.c deleted file mode 100644 index 5eaf945..0000000 --- a/contrib/SDL-3.2.8/src/dialog/android/SDL_androiddialog.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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" -#include "../SDL_dialog.h" -#include "../../core/android/SDL_android.h" - -void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) -{ - SDL_DialogFileFilter *filters = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, NULL); - int nfilters = (int) SDL_GetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, 0); - bool allow_many = SDL_GetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, false); - bool is_save; - - if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) { - SDL_SetError("File dialog driver unsupported (don't set SDL_HINT_FILE_DIALOG_DRIVER)"); - callback(userdata, NULL, -1); - return; - } - - switch (type) { - case SDL_FILEDIALOG_OPENFILE: - is_save = false; - break; - - case SDL_FILEDIALOG_SAVEFILE: - is_save = true; - break; - - case SDL_FILEDIALOG_OPENFOLDER: - SDL_Unsupported(); - callback(userdata, NULL, -1); - return; - }; - - if (!Android_JNI_OpenFileDialog(callback, userdata, filters, nfilters, is_save, allow_many)) { - // SDL_SetError is already called when it fails - callback(userdata, NULL, -1); - } -} diff --git a/contrib/SDL-3.2.8/src/dialog/cocoa/SDL_cocoadialog.m b/contrib/SDL-3.2.8/src/dialog/cocoa/SDL_cocoadialog.m deleted file mode 100644 index fb9c5ad..0000000 --- a/contrib/SDL-3.2.8/src/dialog/cocoa/SDL_cocoadialog.m +++ /dev/null @@ -1,188 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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" -#include "../SDL_dialog.h" -#include "../SDL_dialog_utils.h" - -#ifdef SDL_PLATFORM_MACOS - -#import -#import - -void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) -{ - SDL_Window* window = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, NULL); - SDL_DialogFileFilter *filters = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, NULL); - int nfilters = (int) SDL_GetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, 0); - bool allow_many = SDL_GetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, false); - const char* default_location = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_LOCATION_STRING, NULL); - const char* title = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_TITLE_STRING, NULL); - const char* accept = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_ACCEPT_STRING, NULL); - - if (filters) { - const char *msg = validate_filters(filters, nfilters); - - if (msg) { - SDL_SetError("%s", msg); - callback(userdata, NULL, -1); - return; - } - } - - if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) { - SDL_SetError("File dialog driver unsupported (don't set SDL_HINT_FILE_DIALOG_DRIVER)"); - callback(userdata, NULL, -1); - return; - } - - // NSOpenPanel inherits from NSSavePanel - NSSavePanel *dialog; - NSOpenPanel *dialog_as_open; - - switch (type) { - case SDL_FILEDIALOG_SAVEFILE: - dialog = [NSSavePanel savePanel]; - break; - - case SDL_FILEDIALOG_OPENFILE: - dialog_as_open = [NSOpenPanel openPanel]; - [dialog_as_open setAllowsMultipleSelection:((allow_many == true) ? YES : NO)]; - dialog = dialog_as_open; - break; - - case SDL_FILEDIALOG_OPENFOLDER: - dialog_as_open = [NSOpenPanel openPanel]; - [dialog_as_open setCanChooseFiles:NO]; - [dialog_as_open setCanChooseDirectories:YES]; - [dialog_as_open setAllowsMultipleSelection:((allow_many == true) ? YES : NO)]; - dialog = dialog_as_open; - break; - }; - - if (title) { - [dialog setTitle:[NSString stringWithUTF8String:title]]; - } - - if (accept) { - [dialog setPrompt:[NSString stringWithUTF8String:accept]]; - } - - if (filters) { - // On macOS 11.0 and up, this is an array of UTType. Prior to that, it's an array of NSString - NSMutableArray *types = [[NSMutableArray alloc] initWithCapacity:nfilters ]; - - int has_all_files = 0; - for (int i = 0; i < nfilters; i++) { - char *pattern = SDL_strdup(filters[i].pattern); - char *pattern_ptr = pattern; - - if (!pattern_ptr) { - callback(userdata, NULL, -1); - return; - } - - for (char *c = pattern; *c; c++) { - if (*c == ';') { - *c = '\0'; - if(@available(macOS 11.0, *)) { - [types addObject: [UTType typeWithFilenameExtension:[NSString stringWithFormat: @"%s", pattern_ptr]]]; - } else { - [types addObject: [NSString stringWithFormat: @"%s", pattern_ptr]]; - } - pattern_ptr = c + 1; - } else if (*c == '*') { - has_all_files = 1; - } - } - if(@available(macOS 11.0, *)) { - [types addObject: [UTType typeWithFilenameExtension:[NSString stringWithFormat: @"%s", pattern_ptr]]]; - } else { - [types addObject: [NSString stringWithFormat: @"%s", pattern_ptr]]; - } - - SDL_free(pattern); - } - - if (!has_all_files) { - if (@available(macOS 11.0, *)) { - [dialog setAllowedContentTypes:types]; - } else { - [dialog setAllowedFileTypes:types]; - } - } - } - - // Keep behavior consistent with other platforms - [dialog setAllowsOtherFileTypes:YES]; - - if (default_location) { - [dialog setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:default_location]]]; - } - - NSWindow *w = NULL; - - if (window) { - w = (__bridge NSWindow *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL); - } - - if (w) { - // [dialog beginWithCompletionHandler:^(NSInteger result) { - [dialog beginSheetModalForWindow:w completionHandler:^(NSInteger result) { - if (result == NSModalResponseOK) { - if (dialog_as_open) { - NSArray* urls = [dialog_as_open URLs]; - const char *files[[urls count] + 1]; - for (int i = 0; i < [urls count]; i++) { - files[i] = [[[urls objectAtIndex:i] path] UTF8String]; - } - files[[urls count]] = NULL; - callback(userdata, files, -1); - } else { - const char *files[2] = { [[[dialog URL] path] UTF8String], NULL }; - callback(userdata, files, -1); - } - } else if (result == NSModalResponseCancel) { - const char *files[1] = { NULL }; - callback(userdata, files, -1); - } - }]; - } else { - if ([dialog runModal] == NSModalResponseOK) { - if (dialog_as_open) { - NSArray* urls = [dialog_as_open URLs]; - const char *files[[urls count] + 1]; - for (int i = 0; i < [urls count]; i++) { - files[i] = [[[urls objectAtIndex:i] path] UTF8String]; - } - files[[urls count]] = NULL; - callback(userdata, files, -1); - } else { - const char *files[2] = { [[[dialog URL] path] UTF8String], NULL }; - callback(userdata, files, -1); - } - } else { - const char *files[1] = { NULL }; - callback(userdata, files, -1); - } - } -} - -#endif // SDL_PLATFORM_MACOS diff --git a/contrib/SDL-3.2.8/src/dialog/dummy/SDL_dummydialog.c b/contrib/SDL-3.2.8/src/dialog/dummy/SDL_dummydialog.c deleted file mode 100644 index 121a090..0000000 --- a/contrib/SDL-3.2.8/src/dialog/dummy/SDL_dummydialog.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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" - -#include "../SDL_dialog.h" - -#ifdef SDL_DIALOG_DUMMY - -void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) -{ - SDL_Unsupported(); - callback(userdata, NULL, -1); -} - -#endif // SDL_DIALOG_DUMMY diff --git a/contrib/SDL-3.2.8/src/dialog/haiku/SDL_haikudialog.cc b/contrib/SDL-3.2.8/src/dialog/haiku/SDL_haikudialog.cc deleted file mode 100644 index d60e343..0000000 --- a/contrib/SDL-3.2.8/src/dialog/haiku/SDL_haikudialog.cc +++ /dev/null @@ -1,293 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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" -extern "C" { -#include "../SDL_dialog.h" -#include "../SDL_dialog_utils.h" -} -#include "../../core/haiku/SDL_BeApp.h" -#include "../../video/haiku/SDL_BWin.h" - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -bool StringEndsWith(const std::string& str, const std::string& end) -{ - return str.size() >= end.size() && !str.compare(str.size() - end.size(), end.size(), end); -} - -std::vector StringSplit(const std::string& str, const std::string& split) -{ - std::vector result; - std::string s = str; - size_t pos = 0; - - while ((pos = s.find(split)) != std::string::npos) { - result.push_back(s.substr(0, pos)); - s = s.substr(pos + split.size()); - } - - result.push_back(s); - - return result; -} - -class SDLBRefFilter : public BRefFilter -{ -public: - SDLBRefFilter(const SDL_DialogFileFilter *filters, int nfilters) : - BRefFilter(), - m_filters(filters), - m_nfilters(nfilters) - { - } - - virtual bool Filter(const entry_ref *ref, BNode *node, struct stat_beos *stat, const char *mimeType) override - { - BEntry entry(ref); - BPath path; - entry.GetPath(&path); - std::string result = path.Path(); - - if (!m_filters) - return true; - - struct stat info; - node->GetStat(&info); - if (S_ISDIR(info.st_mode)) - return true; - - for (int i = 0; i < m_nfilters; i++) { - for (const auto& suffix : StringSplit(m_filters[i].pattern, ";")) { - if (StringEndsWith(result, std::string(".") + suffix)) { - return true; - } - } - } - - return false; - } - -private: - const SDL_DialogFileFilter * const m_filters; - int m_nfilters; -}; - -class CallbackLooper : public BLooper -{ -public: - CallbackLooper(SDL_DialogFileCallback callback, void *userdata) : - m_callback(callback), - m_userdata(userdata), - m_files(), - m_messenger(), - m_panel(), - m_filter() - { - } - - ~CallbackLooper() - { - delete m_messenger; - delete m_panel; - delete m_filter; - } - - void SetToBeFreed(BMessenger *messenger, BFilePanel *panel, SDLBRefFilter *filter) - { - m_messenger = messenger; - m_panel = panel; - m_filter = filter; - } - - virtual void MessageReceived(BMessage *msg) override - { - entry_ref file; - BPath path; - BEntry entry; - std::string result; - const char *filename; - int32 nFiles = 0; - - switch (msg->what) - { - case B_REFS_RECEIVED: // Open - msg->GetInfo("refs", NULL, &nFiles); - for (int i = 0; i < nFiles; i++) { - msg->FindRef("refs", i, &file); - entry.SetTo(&file); - entry.GetPath(&path); - result = path.Path(); - m_files.push_back(result); - } - break; - - case B_SAVE_REQUESTED: // Save - msg->FindRef("directory", &file); - entry.SetTo(&file); - entry.GetPath(&path); - result = path.Path(); - result += "/"; - msg->FindString("name", &filename); - result += filename; - m_files.push_back(result); - break; - - case B_CANCEL: // Whenever the dialog is closed (Cancel but also after Open and Save) - { - nFiles = m_files.size(); - const char* files[nFiles + 1]; - for (int i = 0; i < nFiles; i++) { - files[i] = m_files[i].c_str(); - } - files[nFiles] = NULL; - m_callback(m_userdata, files, -1); - Quit(); - SDL_QuitBeApp(); - delete this; - } - break; - - default: - BHandler::MessageReceived(msg); - break; - } - } - -private: - SDL_DialogFileCallback m_callback; - void *m_userdata; - std::vector m_files; - - // Only to free stuff later - BMessenger *m_messenger; - BFilePanel *m_panel; - SDLBRefFilter *m_filter; -}; - -void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) -{ - SDL_Window* window = (SDL_Window*) SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, NULL); - SDL_DialogFileFilter* filters = (SDL_DialogFileFilter*) SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, NULL); - int nfilters = (int) SDL_GetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, 0); - bool many = SDL_GetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, false); - const char* location = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_LOCATION_STRING, NULL); - const char* title = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_TITLE_STRING, NULL); - const char* accept = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_ACCEPT_STRING, NULL); - const char* cancel = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_CANCEL_STRING, NULL); - - bool modal = !!window; - - bool save = false; - bool folder = false; - - switch (type) { - case SDL_FILEDIALOG_SAVEFILE: - save = true; - break; - - case SDL_FILEDIALOG_OPENFILE: - break; - - case SDL_FILEDIALOG_OPENFOLDER: - folder = true; - break; - }; - - if (!SDL_InitBeApp()) { - char* err = SDL_strdup(SDL_GetError()); - SDL_SetError("Couldn't init Be app: %s", err); - SDL_free(err); - callback(userdata, NULL, -1); - return; - } - - if (filters) { - const char *msg = validate_filters(filters, nfilters); - - if (msg) { - SDL_SetError("%s", msg); - callback(userdata, NULL, -1); - return; - } - } - - if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) { - SDL_SetError("File dialog driver unsupported"); - callback(userdata, NULL, -1); - return; - } - - // No unique_ptr's because they need to survive the end of the function - CallbackLooper *looper = new(std::nothrow) CallbackLooper(callback, userdata); - BMessenger *messenger = new(std::nothrow) BMessenger(NULL, looper); - SDLBRefFilter *filter = new(std::nothrow) SDLBRefFilter(filters, nfilters); - - if (looper == NULL || messenger == NULL || filter == NULL) { - SDL_free(looper); - SDL_free(messenger); - SDL_free(filter); - SDL_OutOfMemory(); - callback(userdata, NULL, -1); - return; - } - - BEntry entry; - entry_ref entryref; - if (location) { - entry.SetTo(location); - entry.GetRef(&entryref); - } - - BFilePanel *panel = new BFilePanel(save ? B_SAVE_PANEL : B_OPEN_PANEL, messenger, location ? &entryref : NULL, folder ? B_DIRECTORY_NODE : B_FILE_NODE, many, NULL, filter, modal); - - if (title) { - panel->Window()->SetTitle(title); - } - - if (accept) { - panel->SetButtonLabel(B_DEFAULT_BUTTON, accept); - } - - if (cancel) { - panel->SetButtonLabel(B_CANCEL_BUTTON, cancel); - } - - if (window) { - SDL_BWin *bwin = (SDL_BWin *)(window->internal); - panel->Window()->SetLook(B_MODAL_WINDOW_LOOK); - panel->Window()->SetFeel(B_MODAL_SUBSET_WINDOW_FEEL); - panel->Window()->AddToSubset(bwin); - } - - looper->SetToBeFreed(messenger, panel, filter); - looper->Run(); - panel->Show(); -} diff --git a/contrib/SDL-3.2.8/src/dialog/unix/SDL_portaldialog.c b/contrib/SDL-3.2.8/src/dialog/unix/SDL_portaldialog.c deleted file mode 100644 index efecd12..0000000 --- a/contrib/SDL-3.2.8/src/dialog/unix/SDL_portaldialog.c +++ /dev/null @@ -1,545 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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" -#include "../SDL_dialog_utils.h" - -#include "../../core/linux/SDL_dbus.h" - -#ifdef SDL_USE_LIBDBUS - -#include -#include -#include -#include - -#define PORTAL_DESTINATION "org.freedesktop.portal.Desktop" -#define PORTAL_PATH "/org/freedesktop/portal/desktop" -#define PORTAL_INTERFACE "org.freedesktop.portal.FileChooser" - -#define SIGNAL_SENDER "org.freedesktop.portal.Desktop" -#define SIGNAL_INTERFACE "org.freedesktop.portal.Request" -#define SIGNAL_NAME "Response" -#define SIGNAL_FILTER "type='signal', sender='"SIGNAL_SENDER"', interface='"SIGNAL_INTERFACE"', member='"SIGNAL_NAME"', path='" - -#define HANDLE_LEN 10 - -#define WAYLAND_HANDLE_PREFIX "wayland:" -#define X11_HANDLE_PREFIX "x11:" - -typedef struct { - SDL_DialogFileCallback callback; - void *userdata; - const char *path; -} SignalCallback; - -static void DBus_AppendStringOption(SDL_DBusContext *dbus, DBusMessageIter *options, const char *key, const char *value) -{ - DBusMessageIter options_pair, options_value; - - dbus->message_iter_open_container(options, DBUS_TYPE_DICT_ENTRY, NULL, &options_pair); - dbus->message_iter_append_basic(&options_pair, DBUS_TYPE_STRING, &key); - dbus->message_iter_open_container(&options_pair, DBUS_TYPE_VARIANT, "s", &options_value); - dbus->message_iter_append_basic(&options_value, DBUS_TYPE_STRING, &value); - dbus->message_iter_close_container(&options_pair, &options_value); - dbus->message_iter_close_container(options, &options_pair); -} - -static void DBus_AppendBoolOption(SDL_DBusContext *dbus, DBusMessageIter *options, const char *key, int value) -{ - DBusMessageIter options_pair, options_value; - - dbus->message_iter_open_container(options, DBUS_TYPE_DICT_ENTRY, NULL, &options_pair); - dbus->message_iter_append_basic(&options_pair, DBUS_TYPE_STRING, &key); - dbus->message_iter_open_container(&options_pair, DBUS_TYPE_VARIANT, "b", &options_value); - dbus->message_iter_append_basic(&options_value, DBUS_TYPE_BOOLEAN, &value); - dbus->message_iter_close_container(&options_pair, &options_value); - dbus->message_iter_close_container(options, &options_pair); -} - -static void DBus_AppendFilter(SDL_DBusContext *dbus, DBusMessageIter *parent, const SDL_DialogFileFilter filter) -{ - DBusMessageIter filter_entry, filter_array, filter_array_entry; - char *state = NULL, *patterns, *pattern, *glob_pattern; - int zero = 0; - - dbus->message_iter_open_container(parent, DBUS_TYPE_STRUCT, NULL, &filter_entry); - dbus->message_iter_append_basic(&filter_entry, DBUS_TYPE_STRING, &filter.name); - dbus->message_iter_open_container(&filter_entry, DBUS_TYPE_ARRAY, "(us)", &filter_array); - - patterns = SDL_strdup(filter.pattern); - if (!patterns) { - goto cleanup; - } - - pattern = SDL_strtok_r(patterns, ";", &state); - while (pattern) { - size_t max_len = SDL_strlen(pattern) + 3; - - dbus->message_iter_open_container(&filter_array, DBUS_TYPE_STRUCT, NULL, &filter_array_entry); - dbus->message_iter_append_basic(&filter_array_entry, DBUS_TYPE_UINT32, &zero); - - glob_pattern = SDL_calloc(max_len, sizeof(char)); - if (!glob_pattern) { - goto cleanup; - } - glob_pattern[0] = '*'; - /* Special case: The '*' filter doesn't need to be rewritten */ - if (pattern[0] != '*' || pattern[1]) { - glob_pattern[1] = '.'; - SDL_strlcat(glob_pattern + 2, pattern, max_len); - } - dbus->message_iter_append_basic(&filter_array_entry, DBUS_TYPE_STRING, &glob_pattern); - SDL_free(glob_pattern); - - dbus->message_iter_close_container(&filter_array, &filter_array_entry); - pattern = SDL_strtok_r(NULL, ";", &state); - } - -cleanup: - SDL_free(patterns); - - dbus->message_iter_close_container(&filter_entry, &filter_array); - dbus->message_iter_close_container(parent, &filter_entry); -} - -static void DBus_AppendFilters(SDL_DBusContext *dbus, DBusMessageIter *options, const SDL_DialogFileFilter *filters, int nfilters) -{ - DBusMessageIter options_pair, options_value, options_value_array; - static const char *filters_name = "filters"; - - dbus->message_iter_open_container(options, DBUS_TYPE_DICT_ENTRY, NULL, &options_pair); - dbus->message_iter_append_basic(&options_pair, DBUS_TYPE_STRING, &filters_name); - dbus->message_iter_open_container(&options_pair, DBUS_TYPE_VARIANT, "a(sa(us))", &options_value); - dbus->message_iter_open_container(&options_value, DBUS_TYPE_ARRAY, "(sa(us))", &options_value_array); - for (int i = 0; i < nfilters; i++) { - DBus_AppendFilter(dbus, &options_value_array, filters[i]); - } - dbus->message_iter_close_container(&options_value, &options_value_array); - dbus->message_iter_close_container(&options_pair, &options_value); - dbus->message_iter_close_container(options, &options_pair); -} - -static void DBus_AppendByteArray(SDL_DBusContext *dbus, DBusMessageIter *options, const char *key, const char *value) -{ - DBusMessageIter options_pair, options_value, options_array; - - dbus->message_iter_open_container(options, DBUS_TYPE_DICT_ENTRY, NULL, &options_pair); - dbus->message_iter_append_basic(&options_pair, DBUS_TYPE_STRING, &key); - dbus->message_iter_open_container(&options_pair, DBUS_TYPE_VARIANT, "ay", &options_value); - dbus->message_iter_open_container(&options_value, DBUS_TYPE_ARRAY, "y", &options_array); - do { - dbus->message_iter_append_basic(&options_array, DBUS_TYPE_BYTE, value); - } while (*value++); - dbus->message_iter_close_container(&options_value, &options_array); - dbus->message_iter_close_container(&options_pair, &options_value); - dbus->message_iter_close_container(options, &options_pair); -} - -static DBusHandlerResult DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data) -{ - SDL_DBusContext *dbus = SDL_DBus_GetContext(); - SignalCallback *signal_data = (SignalCallback *)data; - - if (dbus->message_is_signal(msg, SIGNAL_INTERFACE, SIGNAL_NAME) && - dbus->message_has_path(msg, signal_data->path)) { - DBusMessageIter signal_iter, result_array, array_entry, value_entry, uri_entry; - uint32_t result; - size_t length = 2, current = 0; - const char **path = NULL; - - dbus->message_iter_init(msg, &signal_iter); - // Check if the parameters are what we expect - if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_UINT32) { - goto not_our_signal; - } - dbus->message_iter_get_basic(&signal_iter, &result); - - if (result == 1 || result == 2) { - // cancelled - const char *result_data[] = { NULL }; - signal_data->callback(signal_data->userdata, result_data, -1); // TODO: Set this to the last selected filter - goto done; - - } else if (result) { - // some error occurred - signal_data->callback(signal_data->userdata, NULL, -1); - goto done; - } - - if (!dbus->message_iter_next(&signal_iter)) { - goto not_our_signal; - } - - if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_ARRAY) { - goto not_our_signal; - } - - dbus->message_iter_recurse(&signal_iter, &result_array); - - while (dbus->message_iter_get_arg_type(&result_array) == DBUS_TYPE_DICT_ENTRY) { - const char *method; - - dbus->message_iter_recurse(&result_array, &array_entry); - if (dbus->message_iter_get_arg_type(&array_entry) != DBUS_TYPE_STRING) { - goto not_our_signal; - } - - dbus->message_iter_get_basic(&array_entry, &method); - if (!SDL_strcmp(method, "uris")) { - // we only care about the selected file paths - break; - } - - if (!dbus->message_iter_next(&result_array)) { - goto not_our_signal; - } - } - - if (!dbus->message_iter_next(&array_entry)) { - goto not_our_signal; - } - - if (dbus->message_iter_get_arg_type(&array_entry) != DBUS_TYPE_VARIANT) { - goto not_our_signal; - } - dbus->message_iter_recurse(&array_entry, &value_entry); - - if (dbus->message_iter_get_arg_type(&value_entry) != DBUS_TYPE_ARRAY) { - goto not_our_signal; - } - dbus->message_iter_recurse(&value_entry, &uri_entry); - - path = SDL_malloc(length * sizeof(const char *)); - if (!path) { - signal_data->callback(signal_data->userdata, NULL, -1); - goto done; - } - - while (dbus->message_iter_get_arg_type(&uri_entry) == DBUS_TYPE_STRING) { - const char *uri = NULL; - - if (current >= length - 1) { - ++length; - const char **newpath = SDL_realloc(path, length * sizeof(const char *)); - if (!newpath) { - signal_data->callback(signal_data->userdata, NULL, -1); - goto done; - } - path = newpath; - } - - dbus->message_iter_get_basic(&uri_entry, &uri); - - // https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.FileChooser.html - // Returned paths will always start with 'file://'; SDL_URIToLocal() truncates it. - char *decoded_uri = SDL_malloc(SDL_strlen(uri) + 1); - if (SDL_URIToLocal(uri, decoded_uri)) { - path[current] = decoded_uri; - } else { - SDL_free(decoded_uri); - SDL_SetError("Portal dialogs: Unsupported protocol: %s", uri); - signal_data->callback(signal_data->userdata, NULL, -1); - goto done; - } - - dbus->message_iter_next(&uri_entry); - ++current; - } - path[current] = NULL; - signal_data->callback(signal_data->userdata, path, -1); // TODO: Fetch the index of the filter that was used -done: - dbus->connection_remove_filter(conn, &DBus_MessageFilter, signal_data); - - if (path) { - for (size_t i = 0; i < current; ++i) { - SDL_free((char *)path[i]); - } - SDL_free(path); - } - SDL_free((void *)signal_data->path); - SDL_free(signal_data); - return DBUS_HANDLER_RESULT_HANDLED; - } - -not_our_signal: - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) -{ - const char *method; - const char *method_title; - - SDL_Window* window = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, NULL); - SDL_DialogFileFilter *filters = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, NULL); - int nfilters = (int) SDL_GetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, 0); - bool allow_many = SDL_GetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, false); - const char* default_location = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_LOCATION_STRING, NULL); - const char* accept = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_ACCEPT_STRING, NULL); - bool open_folders = false; - - switch (type) { - case SDL_FILEDIALOG_OPENFILE: - method = "OpenFile"; - method_title = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_TITLE_STRING, "Open File"); - break; - - case SDL_FILEDIALOG_SAVEFILE: - method = "SaveFile"; - method_title = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_TITLE_STRING, "Save File"); - break; - - case SDL_FILEDIALOG_OPENFOLDER: - method = "OpenFile"; - method_title = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_TITLE_STRING, "Open Folder"); - open_folders = true; - break; - - default: - /* This is already checked in ../SDL_dialog.c; this silences compiler warnings */ - SDL_SetError("Invalid file dialog type: %d", type); - callback(userdata, NULL, -1); - return; - } - - SDL_DBusContext *dbus = SDL_DBus_GetContext(); - DBusMessage *msg; - DBusMessageIter params, options; - const char *signal_id = NULL; - char *handle_str, *filter; - int filter_len; - static uint32_t handle_id = 0; - static char *default_parent_window = ""; - SDL_PropertiesID window_props = SDL_GetWindowProperties(window); - - const char *err_msg = validate_filters(filters, nfilters); - - if (err_msg) { - SDL_SetError("%s", err_msg); - callback(userdata, NULL, -1); - return; - } - - if (dbus == NULL) { - SDL_SetError("Failed to connect to DBus"); - callback(userdata, NULL, -1); - return; - } - - msg = dbus->message_new_method_call(PORTAL_DESTINATION, PORTAL_PATH, PORTAL_INTERFACE, method); - if (msg == NULL) { - SDL_SetError("Failed to send message to portal"); - callback(userdata, NULL, -1); - return; - } - - dbus->message_iter_init_append(msg, ¶ms); - - handle_str = default_parent_window; - if (window_props) { - const char *parent_handle = SDL_GetStringProperty(window_props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_EXPORT_HANDLE_STRING, NULL); - if (parent_handle) { - size_t len = SDL_strlen(parent_handle); - len += sizeof(WAYLAND_HANDLE_PREFIX) + 1; - handle_str = SDL_malloc(len * sizeof(char)); - if (!handle_str) { - callback(userdata, NULL, -1); - return; - } - - SDL_snprintf(handle_str, len, "%s%s", WAYLAND_HANDLE_PREFIX, parent_handle); - } else { - const Uint64 xid = (Uint64)SDL_GetNumberProperty(window_props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); - if (xid) { - const size_t len = sizeof(X11_HANDLE_PREFIX) + 24; // A 64-bit number can be 20 characters max. - handle_str = SDL_malloc(len * sizeof(char)); - if (!handle_str) { - callback(userdata, NULL, -1); - return; - } - - // The portal wants X11 window ID numbers in hex. - SDL_snprintf(handle_str, len, "%s%" SDL_PRIx64, X11_HANDLE_PREFIX, xid); - } - } - } - - dbus->message_iter_append_basic(¶ms, DBUS_TYPE_STRING, &handle_str); - if (handle_str != default_parent_window) { - SDL_free(handle_str); - } - - dbus->message_iter_append_basic(¶ms, DBUS_TYPE_STRING, &method_title); - dbus->message_iter_open_container(¶ms, DBUS_TYPE_ARRAY, "{sv}", &options); - - handle_str = SDL_malloc(sizeof(char) * (HANDLE_LEN + 1)); - if (!handle_str) { - callback(userdata, NULL, -1); - return; - } - SDL_snprintf(handle_str, HANDLE_LEN, "%u", ++handle_id); - DBus_AppendStringOption(dbus, &options, "handle_token", handle_str); - SDL_free(handle_str); - - DBus_AppendBoolOption(dbus, &options, "modal", !!window); - if (allow_many) { - DBus_AppendBoolOption(dbus, &options, "multiple", 1); - } - if (open_folders) { - DBus_AppendBoolOption(dbus, &options, "directory", 1); - } - if (filters) { - DBus_AppendFilters(dbus, &options, filters, nfilters); - } - if (default_location) { - DBus_AppendByteArray(dbus, &options, "current_folder", default_location); - } - if (accept) { - DBus_AppendStringOption(dbus, &options, "accept_label", accept); - } - dbus->message_iter_close_container(¶ms, &options); - - DBusMessage *reply = dbus->connection_send_with_reply_and_block(dbus->session_conn, msg, DBUS_TIMEOUT_INFINITE, NULL); - if (reply) { - DBusMessageIter reply_iter; - dbus->message_iter_init(reply, &reply_iter); - - if (dbus->message_iter_get_arg_type(&reply_iter) == DBUS_TYPE_OBJECT_PATH) { - dbus->message_iter_get_basic(&reply_iter, &signal_id); - } - } - - if (!signal_id) { - SDL_SetError("Invalid response received by DBus"); - callback(userdata, NULL, -1); - goto incorrect_type; - } - - dbus->message_unref(msg); - - filter_len = SDL_strlen(SIGNAL_FILTER) + SDL_strlen(signal_id) + 2; - filter = SDL_malloc(sizeof(char) * filter_len); - if (!filter) { - callback(userdata, NULL, -1); - goto incorrect_type; - } - - SDL_snprintf(filter, filter_len, SIGNAL_FILTER"%s'", signal_id); - dbus->bus_add_match(dbus->session_conn, filter, NULL); - SDL_free(filter); - - SignalCallback *data = SDL_malloc(sizeof(SignalCallback)); - if (!data) { - callback(userdata, NULL, -1); - goto incorrect_type; - } - data->callback = callback; - data->userdata = userdata; - data->path = SDL_strdup(signal_id); - if (!data->path) { - SDL_free(data); - callback(userdata, NULL, -1); - goto incorrect_type; - } - - /* TODO: This should be registered before opening the portal, or the filter will not catch - the message if it is sent before we register the filter. - */ - dbus->connection_add_filter(dbus->session_conn, - &DBus_MessageFilter, data, NULL); - dbus->connection_flush(dbus->session_conn); - -incorrect_type: - dbus->message_unref(reply); -} - -bool SDL_Portal_detect(void) -{ - SDL_DBusContext *dbus = SDL_DBus_GetContext(); - DBusMessage *msg = NULL, *reply = NULL; - char *reply_str = NULL; - DBusMessageIter reply_iter; - static int portal_present = -1; - - // No need for this if the result is cached. - if (portal_present != -1) { - return (portal_present > 0); - } - - portal_present = 0; - - if (!dbus) { - SDL_SetError("%s", "Failed to connect to DBus!"); - return false; - } - - // Use introspection to get the available services. - msg = dbus->message_new_method_call(PORTAL_DESTINATION, PORTAL_PATH, "org.freedesktop.DBus.Introspectable", "Introspect"); - if (!msg) { - goto done; - } - - reply = dbus->connection_send_with_reply_and_block(dbus->session_conn, msg, DBUS_TIMEOUT_USE_DEFAULT, NULL); - dbus->message_unref(msg); - if (!reply) { - goto done; - } - - if (!dbus->message_iter_init(reply, &reply_iter)) { - goto done; - } - - if (dbus->message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_STRING) { - goto done; - } - - /* Introspection gives us a dump of all the services on the destination in XML format, so search the - * giant string for the file chooser protocol. - */ - dbus->message_iter_get_basic(&reply_iter, &reply_str); - if (SDL_strstr(reply_str, PORTAL_INTERFACE)) { - portal_present = 1; // Found it! - } - -done: - if (reply) { - dbus->message_unref(reply); - } - - return (portal_present > 0); -} - -#else - -// Dummy implementation to avoid compilation problems - -void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) -{ - SDL_Unsupported(); - callback(userdata, NULL, -1); -} - -bool SDL_Portal_detect(void) -{ - return false; -} - -#endif // SDL_USE_LIBDBUS diff --git a/contrib/SDL-3.2.8/src/dialog/unix/SDL_portaldialog.h b/contrib/SDL-3.2.8/src/dialog/unix/SDL_portaldialog.h deleted file mode 100644 index 4497287..0000000 --- a/contrib/SDL-3.2.8/src/dialog/unix/SDL_portaldialog.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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" - -void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props); - -/** @returns non-zero if available, zero if unavailable */ -bool SDL_Portal_detect(void); diff --git a/contrib/SDL-3.2.8/src/dialog/unix/SDL_unixdialog.c b/contrib/SDL-3.2.8/src/dialog/unix/SDL_unixdialog.c deleted file mode 100644 index bec2ac9..0000000 --- a/contrib/SDL-3.2.8/src/dialog/unix/SDL_unixdialog.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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" - -#include "../SDL_dialog.h" -#include "./SDL_portaldialog.h" -#include "./SDL_zenitydialog.h" - -static void (*detected_function)(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) = NULL; - -void SDLCALL hint_callback(void *userdata, const char *name, const char *oldValue, const char *newValue); - -static void set_callback(void) -{ - static bool is_set = false; - - if (is_set == false) { - is_set = true; - SDL_AddHintCallback(SDL_HINT_FILE_DIALOG_DRIVER, hint_callback, NULL); - } -} - -// Returns non-zero on success, 0 on failure -static int detect_available_methods(const char *value) -{ - const char *driver = value ? value : SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER); - - set_callback(); - - if (driver == NULL || SDL_strcmp(driver, "portal") == 0) { - if (SDL_Portal_detect()) { - detected_function = SDL_Portal_ShowFileDialogWithProperties; - return 1; - } - } - - if (driver == NULL || SDL_strcmp(driver, "zenity") == 0) { - if (SDL_Zenity_detect()) { - detected_function = SDL_Zenity_ShowFileDialogWithProperties; - return 2; - } - } - - SDL_SetError("File dialog driver unsupported (supported values for SDL_HINT_FILE_DIALOG_DRIVER are 'zenity' and 'portal')"); - return 0; -} - -void SDLCALL hint_callback(void *userdata, const char *name, const char *oldValue, const char *newValue) -{ - detect_available_methods(newValue); -} - -void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) -{ - // Call detect_available_methods() again each time in case the situation changed - if (!detected_function && !detect_available_methods(NULL)) { - // SetError() done by detect_available_methods() - callback(userdata, NULL, -1); - return; - } - - detected_function(type, callback, userdata, props); -} diff --git a/contrib/SDL-3.2.8/src/dialog/unix/SDL_zenitydialog.c b/contrib/SDL-3.2.8/src/dialog/unix/SDL_zenitydialog.c deleted file mode 100644 index 4632c8e..0000000 --- a/contrib/SDL-3.2.8/src/dialog/unix/SDL_zenitydialog.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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" - -#include "../SDL_dialog_utils.h" - -#define X11_HANDLE_MAX_WIDTH 28 -typedef struct -{ - SDL_DialogFileCallback callback; - void *userdata; - void *argv; - - /* Zenity only works with X11 handles apparently */ - char x11_window_handle[X11_HANDLE_MAX_WIDTH]; - /* These are part of argv, but are tracked separately for deallocation purposes */ - int nfilters; - char **filters_slice; - char *filename; - char *title; - char *accept; - char *cancel; -} zenityArgs; - -static char *zenity_clean_name(const char *name) -{ - char *newname = SDL_strdup(name); - - /* Filter out "|", which Zenity considers a special character. Let's hope - there aren't others. TODO: find something better. */ - for (char *c = newname; *c; c++) { - if (*c == '|') { - // Zenity doesn't support escaping with '\' - *c = '/'; - } - } - - return newname; -} - -static bool get_x11_window_handle(SDL_PropertiesID props, char *out) -{ - SDL_Window *window = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, NULL); - if (!window) { - return false; - } - SDL_PropertiesID window_props = SDL_GetWindowProperties(window); - if (!window_props) { - return false; - } - Uint64 handle = (Uint64)SDL_GetNumberProperty(window_props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); - if (!handle) { - return false; - } - if (SDL_snprintf(out, X11_HANDLE_MAX_WIDTH, "0x%" SDL_PRIx64, handle) >= X11_HANDLE_MAX_WIDTH) { - return false; - }; - return true; -} - -/* Exec call format: - * - * zenity --file-selection --separator=\n [--multiple] - * [--directory] [--save --confirm-overwrite] - * [--filename FILENAME] [--modal --attach 0x11w1nd0w] - * [--title TITLE] [--ok-label ACCEPT] - * [--cancel-label CANCEL] - * [--file-filter=Filter Name | *.filt *.fn ...]... - */ -static zenityArgs *create_zenity_args(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) -{ - zenityArgs *args = SDL_calloc(1, sizeof(*args)); - if (!args) { - return NULL; - } - args->callback = callback; - args->userdata = userdata; - args->nfilters = SDL_GetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, 0); - - const char **argv = SDL_malloc( - sizeof(*argv) * (3 /* zenity --file-selection --separator=\n */ - + 1 /* --multiple */ - + 2 /* --directory | --save --confirm-overwrite */ - + 2 /* --filename [file] */ - + 3 /* --modal --attach [handle] */ - + 2 /* --title [title] */ - + 2 /* --ok-label [label] */ - + 2 /* --cancel-label [label] */ - + args->nfilters + 1 /* NULL */)); - if (!argv) { - goto cleanup; - } - args->argv = argv; - - /* Properties can be destroyed as soon as the function returns; copy over what we need. */ -#define COPY_STRING_PROPERTY(dst, prop) \ - { \ - const char *str = SDL_GetStringProperty(props, prop, NULL); \ - if (str) { \ - dst = SDL_strdup(str); \ - if (!dst) { \ - goto cleanup; \ - } \ - } \ - } - - COPY_STRING_PROPERTY(args->filename, SDL_PROP_FILE_DIALOG_LOCATION_STRING); - COPY_STRING_PROPERTY(args->title, SDL_PROP_FILE_DIALOG_TITLE_STRING); - COPY_STRING_PROPERTY(args->accept, SDL_PROP_FILE_DIALOG_ACCEPT_STRING); - COPY_STRING_PROPERTY(args->cancel, SDL_PROP_FILE_DIALOG_CANCEL_STRING); -#undef COPY_STRING_PROPERTY - - // ARGV PASS - int argc = 0; - argv[argc++] = "zenity"; - argv[argc++] = "--file-selection"; - argv[argc++] = "--separator=\n"; - - if (SDL_GetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, false)) { - argv[argc++] = "--multiple"; - } - - switch (type) { - case SDL_FILEDIALOG_OPENFILE: - break; - - case SDL_FILEDIALOG_SAVEFILE: - argv[argc++] = "--save"; - /* Asking before overwriting while saving seems like a sane default */ - argv[argc++] = "--confirm-overwrite"; - break; - - case SDL_FILEDIALOG_OPENFOLDER: - argv[argc++] = "--directory"; - break; - }; - - if (args->filename) { - argv[argc++] = "--filename"; - argv[argc++] = args->filename; - } - - if (get_x11_window_handle(props, args->x11_window_handle)) { - argv[argc++] = "--modal"; - argv[argc++] = "--attach"; - argv[argc++] = args->x11_window_handle; - } - - if (args->title) { - argv[argc++] = "--title"; - argv[argc++] = args->title; - } - - if (args->accept) { - argv[argc++] = "--ok-label"; - argv[argc++] = args->accept; - } - - if (args->cancel) { - argv[argc++] = "--cancel-label"; - argv[argc++] = args->cancel; - } - - const SDL_DialogFileFilter *filters = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, NULL); - if (filters) { - args->filters_slice = (char **)&argv[argc]; - for (int i = 0; i < args->nfilters; i++) { - char *filter_str = convert_filter(filters[i], - zenity_clean_name, - "--file-filter=", " | ", "", - "*.", " *.", ""); - - if (!filter_str) { - while (i--) { - SDL_free(args->filters_slice[i]); - } - goto cleanup; - } - - args->filters_slice[i] = filter_str; - } - argc += args->nfilters; - } - - argv[argc] = NULL; - return args; - -cleanup: - SDL_free(args->filename); - SDL_free(args->title); - SDL_free(args->accept); - SDL_free(args->cancel); - SDL_free(argv); - SDL_free(args); - return NULL; -} - -// TODO: Zenity survives termination of the parent - -static void run_zenity(SDL_DialogFileCallback callback, void *userdata, void *argv) -{ - SDL_Process *process = NULL; - SDL_Environment *env = NULL; - int status = -1; - size_t bytes_read = 0; - char *container = NULL; - size_t narray = 1; - char **array = NULL; - bool result = false; - - env = SDL_CreateEnvironment(true); - if (!env) { - goto done; - } - - /* Recent versions of Zenity have different exit codes, but picks up - different codes from the environment */ - SDL_SetEnvironmentVariable(env, "ZENITY_OK", "0", true); - SDL_SetEnvironmentVariable(env, "ZENITY_CANCEL", "1", true); - SDL_SetEnvironmentVariable(env, "ZENITY_ESC", "1", true); - SDL_SetEnvironmentVariable(env, "ZENITY_EXTRA", "2", true); - SDL_SetEnvironmentVariable(env, "ZENITY_ERROR", "2", true); - SDL_SetEnvironmentVariable(env, "ZENITY_TIMEOUT", "2", true); - - SDL_PropertiesID props = SDL_CreateProperties(); - SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, argv); - SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ENVIRONMENT_POINTER, env); - SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_NULL); - SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); - SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_NUMBER, SDL_PROCESS_STDIO_NULL); - process = SDL_CreateProcessWithProperties(props); - SDL_DestroyProperties(props); - if (!process) { - goto done; - } - - container = SDL_ReadProcess(process, &bytes_read, &status); - if (!container) { - goto done; - } - - array = (char **)SDL_malloc((narray + 1) * sizeof(char *)); - if (!array) { - goto done; - } - array[0] = container; - array[1] = NULL; - - for (int i = 0; i < bytes_read; i++) { - if (container[i] == '\n') { - container[i] = '\0'; - // Reading from a process often leaves a trailing \n, so ignore the last one - if (i < bytes_read - 1) { - array[narray] = container + i + 1; - narray++; - char **new_array = (char **)SDL_realloc(array, (narray + 1) * sizeof(char *)); - if (!new_array) { - goto done; - } - array = new_array; - array[narray] = NULL; - } - } - } - - // 0 = the user chose one or more files, 1 = the user canceled the dialog - if (status == 0 || status == 1) { - callback(userdata, (const char *const *)array, -1); - } else { - SDL_SetError("Could not run zenity: exit code %d", status); - callback(userdata, NULL, -1); - } - - result = true; - -done: - SDL_free(array); - SDL_free(container); - SDL_DestroyEnvironment(env); - SDL_DestroyProcess(process); - - if (!result) { - callback(userdata, NULL, -1); - } -} - -static void free_zenity_args(zenityArgs *args) -{ - if (args->filters_slice) { - for (int i = 0; i < args->nfilters; i++) { - SDL_free(args->filters_slice[i]); - } - } - SDL_free(args->filename); - SDL_free(args->title); - SDL_free(args->accept); - SDL_free(args->cancel); - SDL_free(args->argv); - SDL_free(args); -} - -static int run_zenity_thread(void *ptr) -{ - zenityArgs *args = ptr; - run_zenity(args->callback, args->userdata, args->argv); - free_zenity_args(args); - return 0; -} - -void SDL_Zenity_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) -{ - zenityArgs *args = create_zenity_args(type, callback, userdata, props); - if (!args) { - callback(userdata, NULL, -1); - return; - } - - SDL_Thread *thread = SDL_CreateThread(run_zenity_thread, "SDL_ZenityFileDialog", (void *)args); - - if (!thread) { - free_zenity_args(args); - callback(userdata, NULL, -1); - return; - } - - SDL_DetachThread(thread); -} - -bool SDL_Zenity_detect(void) -{ - const char *args[] = { - "zenity", "--version", NULL - }; - int status = -1; - - SDL_PropertiesID props = SDL_CreateProperties(); - SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, args); - SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_NULL); - SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_NULL); - SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_NUMBER, SDL_PROCESS_STDIO_NULL); - SDL_Process *process = SDL_CreateProcessWithProperties(props); - SDL_DestroyProperties(props); - if (process) { - SDL_WaitProcess(process, true, &status); - SDL_DestroyProcess(process); - } - return (status == 0); -} diff --git a/contrib/SDL-3.2.8/src/dialog/unix/SDL_zenitydialog.h b/contrib/SDL-3.2.8/src/dialog/unix/SDL_zenitydialog.h deleted file mode 100644 index 4cfe892..0000000 --- a/contrib/SDL-3.2.8/src/dialog/unix/SDL_zenitydialog.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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" - -extern void SDL_Zenity_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props); - -/** @returns non-zero if available, zero if unavailable */ -extern bool SDL_Zenity_detect(void); diff --git a/contrib/SDL-3.2.8/src/dialog/windows/SDL_windowsdialog.c b/contrib/SDL-3.2.8/src/dialog/windows/SDL_windowsdialog.c deleted file mode 100644 index 2de224f..0000000 --- a/contrib/SDL-3.2.8/src/dialog/windows/SDL_windowsdialog.c +++ /dev/null @@ -1,611 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - 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" -#include "../SDL_dialog.h" -#include "../SDL_dialog_utils.h" - -#include -#include -#include -#include "../../core/windows/SDL_windows.h" -#include "../../thread/SDL_systhread.h" - -// If this number is too small, selecting too many files will give an error -#define SELECTLIST_SIZE 65536 - -typedef struct -{ - bool is_save; - wchar_t *filters_str; - char *default_file; - SDL_Window *parent; - DWORD flags; - SDL_DialogFileCallback callback; - void *userdata; - char *title; - char *accept; - char *cancel; -} winArgs; - -typedef struct -{ - SDL_Window *parent; - SDL_DialogFileCallback callback; - char *default_folder; - void *userdata; - char *title; - char *accept; - char *cancel; -} winFArgs; - -void freeWinArgs(winArgs *args) -{ - SDL_free(args->default_file); - SDL_free(args->filters_str); - SDL_free(args->title); - SDL_free(args->accept); - SDL_free(args->cancel); - - SDL_free(args); -} - -void freeWinFArgs(winFArgs *args) -{ - SDL_free(args->default_folder); - SDL_free(args->title); - SDL_free(args->accept); - SDL_free(args->cancel); - - SDL_free(args); -} - -/** Converts dialog.nFilterIndex to SDL-compatible value */ -int getFilterIndex(int as_reported_by_windows) -{ - return as_reported_by_windows - 1; -} - -char *clear_filt_names(const char *filt) -{ - char *cleared = SDL_strdup(filt); - - for (char *c = cleared; *c; c++) { - /* 0x01 bytes are used as temporary replacement for the various 0x00 - bytes required by Win32 (one null byte between each filter, two at - the end of the filters). Filter out these bytes from the filter names - to avoid early-ending the filters if someone puts two consecutive - 0x01 bytes in their filter names. */ - if (*c == '\x01') { - *c = ' '; - } - } - - return cleared; -} - -// TODO: The new version of file dialogs -void windows_ShowFileDialog(void *ptr) -{ - winArgs *args = (winArgs *) ptr; - bool is_save = args->is_save; - const char *default_file = args->default_file; - SDL_Window *parent = args->parent; - DWORD flags = args->flags; - SDL_DialogFileCallback callback = args->callback; - void *userdata = args->userdata; - const char *title = args->title; - wchar_t *filter_wchar = args->filters_str; - - /* GetOpenFileName and GetSaveFileName have the same signature - (yes, LPOPENFILENAMEW even for the save dialog) */ - typedef BOOL (WINAPI *pfnGetAnyFileNameW)(LPOPENFILENAMEW); - typedef DWORD (WINAPI *pfnCommDlgExtendedError)(void); - HMODULE lib = LoadLibraryW(L"Comdlg32.dll"); - pfnGetAnyFileNameW pGetAnyFileName = NULL; - pfnCommDlgExtendedError pCommDlgExtendedError = NULL; - - if (lib) { - pGetAnyFileName = (pfnGetAnyFileNameW) GetProcAddress(lib, is_save ? "GetSaveFileNameW" : "GetOpenFileNameW"); - pCommDlgExtendedError = (pfnCommDlgExtendedError) GetProcAddress(lib, "CommDlgExtendedError"); - } else { - SDL_SetError("Couldn't load Comdlg32.dll"); - callback(userdata, NULL, -1); - return; - } - - if (!pGetAnyFileName) { - SDL_SetError("Couldn't load GetOpenFileName/GetSaveFileName from library"); - callback(userdata, NULL, -1); - return; - } - - if (!pCommDlgExtendedError) { - SDL_SetError("Couldn't load CommDlgExtendedError from library"); - callback(userdata, NULL, -1); - return; - } - - HWND window = NULL; - - if (parent) { - window = (HWND) SDL_GetPointerProperty(SDL_GetWindowProperties(parent), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); - } - - wchar_t *filebuffer; // lpstrFile - wchar_t initfolder[MAX_PATH] = L""; // lpstrInitialDir - - /* If SELECTLIST_SIZE is too large, putting filebuffer on the stack might - cause an overflow */ - filebuffer = (wchar_t *) SDL_malloc(SELECTLIST_SIZE * sizeof(wchar_t)); - - // Necessary for the return code below - SDL_memset(filebuffer, 0, SELECTLIST_SIZE * sizeof(wchar_t)); - - if (default_file) { - /* On Windows 10, 11 and possibly others, lpstrFile can be initialized - with a path and the dialog will start at that location, but *only if - the path contains a filename*. If it ends with a folder (directory - separator), it fails with 0x3002 (12290) FNERR_INVALIDFILENAME. For - that specific case, lpstrInitialDir must be used instead, but just - for that case, because lpstrInitialDir doesn't support file names. - - On top of that, lpstrInitialDir hides a special algorithm that - decides which folder to actually use as starting point, which may or - may not be the one provided, or some other unrelated folder. Also, - the algorithm changes between platforms. Assuming the documentation - is correct, the algorithm is there under 'lpstrInitialDir': - - https://learn.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamew - - Finally, lpstrFile does not support forward slashes. lpstrInitialDir - does, though. */ - - char last_c = default_file[SDL_strlen(default_file) - 1]; - - if (last_c == '\\' || last_c == '/') { - MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, default_file, -1, initfolder, MAX_PATH); - } else { - MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, default_file, -1, filebuffer, MAX_PATH); - - for (int i = 0; i < SELECTLIST_SIZE; i++) { - if (filebuffer[i] == L'/') { - filebuffer[i] = L'\\'; - } - } - } - } - - wchar_t *title_w = NULL; - - if (title) { - title_w = WIN_UTF8ToStringW(title); - if (!title_w) { - SDL_free(filebuffer); - callback(userdata, NULL, -1); - return; - } - } - - OPENFILENAMEW dialog; - dialog.lStructSize = sizeof(OPENFILENAME); - dialog.hwndOwner = window; - dialog.hInstance = 0; - dialog.lpstrFilter = filter_wchar; - dialog.lpstrCustomFilter = NULL; - dialog.nMaxCustFilter = 0; - dialog.nFilterIndex = 0; - dialog.lpstrFile = filebuffer; - dialog.nMaxFile = SELECTLIST_SIZE; - dialog.lpstrFileTitle = NULL; - dialog.lpstrInitialDir = *initfolder ? initfolder : NULL; - dialog.lpstrTitle = title_w; - dialog.Flags = flags | OFN_EXPLORER | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; - dialog.nFileOffset = 0; - dialog.nFileExtension = 0; - dialog.lpstrDefExt = NULL; - dialog.lCustData = 0; - dialog.lpfnHook = NULL; - dialog.lpTemplateName = NULL; - // Skipped many mac-exclusive and reserved members - dialog.FlagsEx = 0; - - BOOL result = pGetAnyFileName(&dialog); - - SDL_free(title_w); - - if (result) { - if (!(flags & OFN_ALLOWMULTISELECT)) { - // File is a C string stored in dialog.lpstrFile - char *chosen_file = WIN_StringToUTF8W(dialog.lpstrFile); - const char *opts[2] = { chosen_file, NULL }; - callback(userdata, opts, getFilterIndex(dialog.nFilterIndex)); - SDL_free(chosen_file); - } else { - /* File is either a C string if the user chose a single file, else - it's a series of strings formatted like: - - "C:\\path\\to\\folder\0filename1.ext\0filename2.ext\0\0" - - The code below will only stop on a double NULL in all cases, so - it is important that the rest of the buffer has been zeroed. */ - char chosen_folder[MAX_PATH]; - char chosen_file[MAX_PATH]; - wchar_t *file_ptr = dialog.lpstrFile; - size_t nfiles = 0; - size_t chosen_folder_size; - char **chosen_files_list = (char **) SDL_malloc(sizeof(char *) * (nfiles + 1)); - - if (!chosen_files_list) { - callback(userdata, NULL, -1); - SDL_free(filebuffer); - return; - } - - chosen_files_list[nfiles] = NULL; - - if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_folder, MAX_PATH, NULL, NULL) >= MAX_PATH) { - SDL_SetError("Path too long or invalid character in path"); - SDL_free(chosen_files_list); - callback(userdata, NULL, -1); - SDL_free(filebuffer); - return; - } - - chosen_folder_size = SDL_strlen(chosen_folder); - SDL_strlcpy(chosen_file, chosen_folder, MAX_PATH); - chosen_file[chosen_folder_size] = '\\'; - - file_ptr += SDL_strlen(chosen_folder) + 1; - - while (*file_ptr) { - nfiles++; - char **new_cfl = (char **) SDL_realloc(chosen_files_list, sizeof(char*) * (nfiles + 1)); - - if (!new_cfl) { - for (size_t i = 0; i < nfiles - 1; i++) { - SDL_free(chosen_files_list[i]); - } - - SDL_free(chosen_files_list); - callback(userdata, NULL, -1); - SDL_free(filebuffer); - return; - } - - chosen_files_list = new_cfl; - chosen_files_list[nfiles] = NULL; - - int diff = ((int) chosen_folder_size) + 1; - - if (WideCharToMultiByte(CP_UTF8, 0, file_ptr, -1, chosen_file + diff, MAX_PATH - diff, NULL, NULL) >= MAX_PATH - diff) { - SDL_SetError("Path too long or invalid character in path"); - - for (size_t i = 0; i < nfiles - 1; i++) { - SDL_free(chosen_files_list[i]); - } - - SDL_free(chosen_files_list); - callback(userdata, NULL, -1); - SDL_free(filebuffer); - return; - } - - file_ptr += SDL_strlen(chosen_file) + 1 - diff; - - chosen_files_list[nfiles - 1] = SDL_strdup(chosen_file); - - if (!chosen_files_list[nfiles - 1]) { - for (size_t i = 0; i < nfiles - 1; i++) { - SDL_free(chosen_files_list[i]); - } - - SDL_free(chosen_files_list); - callback(userdata, NULL, -1); - SDL_free(filebuffer); - return; - } - } - - // If the user chose only one file, it's all just one string - if (nfiles == 0) { - nfiles++; - char **new_cfl = (char **) SDL_realloc(chosen_files_list, sizeof(char*) * (nfiles + 1)); - - if (!new_cfl) { - SDL_free(chosen_files_list); - callback(userdata, NULL, -1); - SDL_free(filebuffer); - return; - } - - chosen_files_list = new_cfl; - chosen_files_list[nfiles] = NULL; - chosen_files_list[nfiles - 1] = SDL_strdup(chosen_folder); - - if (!chosen_files_list[nfiles - 1]) { - SDL_free(chosen_files_list); - callback(userdata, NULL, -1); - SDL_free(filebuffer); - return; - } - } - - callback(userdata, (const char * const*) chosen_files_list, getFilterIndex(dialog.nFilterIndex)); - - for (size_t i = 0; i < nfiles; i++) { - SDL_free(chosen_files_list[i]); - } - - SDL_free(chosen_files_list); - } - } else { - DWORD error = pCommDlgExtendedError(); - // Error code 0 means the user clicked the cancel button. - if (error == 0) { - /* Unlike SDL's handling of errors, Windows does reset the error - code to 0 after calling GetOpenFileName if another Windows - function before set a different error code, so it's safe to - check for success. */ - const char *opts[1] = { NULL }; - callback(userdata, opts, getFilterIndex(dialog.nFilterIndex)); - } else { - SDL_SetError("Windows error, CommDlgExtendedError: %ld", pCommDlgExtendedError()); - callback(userdata, NULL, -1); - } - } - - SDL_free(filebuffer); -} - -int windows_file_dialog_thread(void *ptr) -{ - windows_ShowFileDialog(ptr); - freeWinArgs(ptr); - return 0; -} - -int CALLBACK browse_callback_proc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) -{ - switch (uMsg) { - case BFFM_INITIALIZED: - if (lpData) { - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData); - } - break; - case BFFM_SELCHANGED: - break; - case BFFM_VALIDATEFAILED: - break; - default: - break; - } - return 0; -} - -void windows_ShowFolderDialog(void *ptr) -{ - winFArgs *args = (winFArgs *) ptr; - SDL_Window *window = args->parent; - SDL_DialogFileCallback callback = args->callback; - void *userdata = args->userdata; - HWND parent = NULL; - const char *title = args->title; - - if (window) { - parent = (HWND) SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); - } - - wchar_t *title_w = NULL; - - if (title) { - title_w = WIN_UTF8ToStringW(title); - if (!title_w) { - callback(userdata, NULL, -1); - return; - } - } - - wchar_t buffer[MAX_PATH]; - - BROWSEINFOW dialog; - dialog.hwndOwner = parent; - dialog.pidlRoot = NULL; - dialog.pszDisplayName = buffer; - dialog.lpszTitle = title_w; - dialog.ulFlags = BIF_USENEWUI; - dialog.lpfn = browse_callback_proc; - dialog.lParam = (LPARAM)args->default_folder; - dialog.iImage = 0; - - LPITEMIDLIST lpItem = SHBrowseForFolderW(&dialog); - - SDL_free(title_w); - - if (lpItem != NULL) { - SHGetPathFromIDListW(lpItem, buffer); - char *chosen_file = WIN_StringToUTF8W(buffer); - const char *files[2] = { chosen_file, NULL }; - callback(userdata, (const char * const*) files, -1); - SDL_free(chosen_file); - } else { - const char *files[1] = { NULL }; - callback(userdata, (const char * const*) files, -1); - } -} - -int windows_folder_dialog_thread(void *ptr) -{ - windows_ShowFolderDialog(ptr); - freeWinFArgs((winFArgs *)ptr); - return 0; -} - -wchar_t *win_get_filters(const SDL_DialogFileFilter *filters, int nfilters) -{ - wchar_t *filter_wchar = NULL; - - if (filters) { - // '\x01' is used in place of a null byte - // suffix needs two null bytes in case the filter list is empty - char *filterlist = convert_filters(filters, nfilters, clear_filt_names, - "", "", "\x01\x01", "", "\x01", - "\x01", "*.", ";*.", ""); - - if (!filterlist) { - return NULL; - } - - int filter_len = (int)SDL_strlen(filterlist); - - for (char *c = filterlist; *c; c++) { - if (*c == '\x01') { - *c = '\0'; - } - } - - int filter_wlen = MultiByteToWideChar(CP_UTF8, 0, filterlist, filter_len, NULL, 0); - filter_wchar = (wchar_t *)SDL_malloc(filter_wlen * sizeof(wchar_t)); - if (!filter_wchar) { - SDL_free(filterlist); - return NULL; - } - - MultiByteToWideChar(CP_UTF8, 0, filterlist, filter_len, filter_wchar, filter_wlen); - - SDL_free(filterlist); - } - - return filter_wchar; -} - -static void ShowFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location, bool allow_many, bool is_save, const char *title, const char *accept, const char *cancel) -{ - winArgs *args; - SDL_Thread *thread; - wchar_t *filters_str; - - if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) { - SDL_SetError("File dialog driver unsupported"); - callback(userdata, NULL, -1); - return; - } - - args = (winArgs *)SDL_malloc(sizeof(*args)); - if (args == NULL) { - callback(userdata, NULL, -1); - return; - } - - filters_str = win_get_filters(filters, nfilters); - - if (!filters_str && filters) { - callback(userdata, NULL, -1); - SDL_free(args); - return; - } - - args->is_save = is_save; - args->filters_str = filters_str; - args->default_file = default_location ? SDL_strdup(default_location) : NULL; - args->parent = window; - args->flags = allow_many ? OFN_ALLOWMULTISELECT : 0; - args->callback = callback; - args->userdata = userdata; - args->title = title ? SDL_strdup(title) : NULL; - args->accept = accept ? SDL_strdup(accept) : NULL; - args->cancel = cancel ? SDL_strdup(cancel) : NULL; - - thread = SDL_CreateThread(windows_file_dialog_thread, "SDL_Windows_ShowFileDialog", (void *) args); - - if (thread == NULL) { - callback(userdata, NULL, -1); - // The thread won't have run, therefore the data won't have been freed - freeWinArgs(args); - return; - } - - SDL_DetachThread(thread); -} - -void ShowFolderDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const char *default_location, bool allow_many, const char *title, const char *accept, const char *cancel) -{ - winFArgs *args; - SDL_Thread *thread; - - if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) { - SDL_SetError("File dialog driver unsupported"); - callback(userdata, NULL, -1); - return; - } - - args = (winFArgs *)SDL_malloc(sizeof(*args)); - if (args == NULL) { - callback(userdata, NULL, -1); - return; - } - - args->parent = window; - args->callback = callback; - args->default_folder = default_location ? SDL_strdup(default_location) : NULL; - args->userdata = userdata; - args->title = title ? SDL_strdup(title) : NULL; - args->accept = accept ? SDL_strdup(accept) : NULL; - args->cancel = cancel ? SDL_strdup(cancel) : NULL; - - thread = SDL_CreateThread(windows_folder_dialog_thread, "SDL_Windows_ShowFolderDialog", (void *) args); - - if (thread == NULL) { - callback(userdata, NULL, -1); - // The thread won't have run, therefore the data won't have been freed - freeWinFArgs(args); - return; - } - - SDL_DetachThread(thread); -} - -void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) -{ - /* The internal functions will start threads, and the properties may be freed as soon as this function returns. - Save a copy of what we need before invoking the functions and starting the threads. */ - SDL_Window *window = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, NULL); - SDL_DialogFileFilter *filters = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, NULL); - int nfilters = (int) SDL_GetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, 0); - bool allow_many = SDL_GetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, false); - const char *default_location = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_LOCATION_STRING, NULL); - const char *title = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_TITLE_STRING, NULL); - const char *accept = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_ACCEPT_STRING, NULL); - const char *cancel = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_CANCEL_STRING, NULL); - bool is_save = false; - - switch (type) { - case SDL_FILEDIALOG_SAVEFILE: - is_save = true; - SDL_FALLTHROUGH; - case SDL_FILEDIALOG_OPENFILE: - ShowFileDialog(callback, userdata, window, filters, nfilters, default_location, allow_many, is_save, title, accept, cancel); - break; - - case SDL_FILEDIALOG_OPENFOLDER: - ShowFolderDialog(callback, userdata, window, default_location, allow_many, title, accept, cancel); - break; - }; -} -- cgit v1.2.3