Explorar o código

Dialog: Add filter number, remove NULL termination

Semphris hai 11 meses
pai
achega
8c8ee2174d

+ 13 - 12
include/SDL3/SDL_dialog.h

@@ -78,10 +78,9 @@ typedef struct SDL_DialogFileFilter
  * The filelist argument does not need to be freed; it will automatically be
  * freed when the callback returns.
  *
- * The filter argument is the index of the filter that was selected, or one
- * more than the size of the list (therefore the index of the terminating NULL
- * entry) if no filter was selected, or -1 if the platform or method doesn't
- * support fetching the selected filter.
+ * The filter argument is the index of the filter that was selected, or -1 if
+ * no filter was selected or if the platform or method doesn't support fetching
+ * the selected filter.
  *
  * \param userdata An app-provided pointer, for the callback's use.
  * \param filelist The file(s) chosen by the user.
@@ -135,9 +134,10 @@ typedef void(SDLCALL *SDL_DialogFileCallback)(void *userdata, const char * const
  *                 it will be invoked.
  * \param window The window that the dialog should be modal for. May be NULL.
  *               Not all platforms support this option.
- * \param filters A null-terminated list of SDL_DialogFileFilter's. May be
- *                NULL. Not all platforms support this option, and platforms
- *                that do support it may allow the user to ignore the filters.
+ * \param filters A list of SDL_DialogFileFilter's. May be NULL. Not all
+ *                platforms support this option, and platforms that do support
+ *                it may allow the user to ignore the filters.
+ * \param nfilters The number of filters. Ignored if filters is NULL.
  * \param default_location The default folder or file to start the dialog at.
  *                         May be NULL. Not all platforms support this option.
  * \param allow_many If non-zero, the user will be allowed to select multiple
@@ -150,7 +150,7 @@ typedef void(SDLCALL *SDL_DialogFileCallback)(void *userdata, const char * const
  * \sa SDL_ShowSaveFileDialog
  * \sa SDL_ShowOpenFolderDialog
  */
-extern SDL_DECLSPEC void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, const char *default_location, SDL_bool allow_many);
+extern SDL_DECLSPEC void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location, SDL_bool allow_many);
 
 /**
  * Displays a dialog that lets the user choose a new or existing file on their
@@ -191,9 +191,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback c
  *                 it will be invoked.
  * \param window The window that the dialog should be modal for. May be NULL.
  *               Not all platforms support this option.
- * \param filters A null-terminated list of SDL_DialogFileFilter's. May be
- *                NULL. Not all platforms support this option, and platforms
- *                that do support it may allow the user to ignore the filters.
+ * \param filters A list of SDL_DialogFileFilter's. May be NULL. Not all
+ *                platforms support this option, and platforms that do support
+ *                it may allow the user to ignore the filters.
+ * \param nfilters The number of filters. Ignored if filters is NULL.
  * \param default_location The default folder or file to start the dialog at.
  *                         May be NULL. Not all platforms support this option.
  *
@@ -204,7 +205,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback c
  * \sa SDL_ShowOpenFileDialog
  * \sa SDL_ShowOpenFolderDialog
  */
-extern SDL_DECLSPEC void SDLCALL SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, const char *default_location);
+extern SDL_DECLSPEC void SDLCALL SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location);
 
 /**
  * Displays a dialog that lets the user select a folder on their filesystem.

+ 4 - 9
src/core/android/SDL_android.c

@@ -2910,7 +2910,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeFileDialog)(
 
 SDL_bool Android_JNI_OpenFileDialog(
     SDL_DialogFileCallback callback, void* userdata,
-    const SDL_DialogFileFilter *filters, SDL_bool forwrite, SDL_bool multiple)
+    const SDL_DialogFileFilter *filters, int nfilters, SDL_bool forwrite,
+    SDL_bool multiple)
 {
     if (mAndroidFileDialogData.callback != NULL) {
         SDL_SetError("Only one file dialog can be run at a time.");
@@ -2926,17 +2927,11 @@ SDL_bool Android_JNI_OpenFileDialog(
     /* Setup filters */
     jobjectArray filtersArray = NULL;
     if (filters) {
-        /* Count how many filters */
-        int count = 0;
-        for (const SDL_DialogFileFilter *f = filters; f->name != NULL && f->pattern != NULL; f++) {
-            count++;
-        }
-
         jclass stringClass = (*env)->FindClass(env, "java/lang/String");
-        filtersArray = (*env)->NewObjectArray(env, count, stringClass, NULL);
+        filtersArray = (*env)->NewObjectArray(env, nfilters, stringClass, NULL);
 
         /* Convert to string */
-        for (int i = 0; i < count; i++) {
+        for (int i = 0; i < nfilters; i++) {
             jstring str = (*env)->NewStringUTF(env, filters[i].pattern);
             (*env)->SetObjectArrayElement(env, filtersArray, i, str);
             (*env)->DeleteLocalRef(env, str);

+ 2 - 1
src/core/android/SDL_android.h

@@ -144,7 +144,8 @@ void Android_ActivityMutex_Lock_Running(void);
 
 /* File Dialogs */
 SDL_bool Android_JNI_OpenFileDialog(SDL_DialogFileCallback callback, void* userdata,
-    const SDL_DialogFileFilter *filters, SDL_bool forwrite, SDL_bool multiple);
+    const SDL_DialogFileFilter *filters, int nfilters, SDL_bool forwrite,
+    SDL_bool multiple);
 
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus

+ 21 - 13
src/dialog/SDL_dialog_utils.c

@@ -22,18 +22,24 @@
 
 #include "SDL_dialog_utils.h"
 
-char *convert_filters(const SDL_DialogFileFilter *filters, 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 *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);
 
@@ -41,7 +47,9 @@ char *convert_filters(const SDL_DialogFileFilter *filters, NameTransform ntf,
         return NULL;
     }
 
-    for (const SDL_DialogFileFilter *f = filters; f->name && f->pattern; f++) {
+    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);
@@ -90,9 +98,9 @@ char *convert_filters(const SDL_DialogFileFilter *filters, NameTransform ntf,
 }
 
 char *convert_filter(const 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)
+                     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;
@@ -208,11 +216,11 @@ char *convert_ext_list(const char *list, const char *prefix,
     return converted;
 }
 
-const char *validate_filters(const SDL_DialogFileFilter *filters)
+const char *validate_filters(const SDL_DialogFileFilter *filters, int nfilters)
 {
     if (filters) {
-        for (const SDL_DialogFileFilter *f = filters; f->name && f->pattern; f++) {
-             const char *msg = validate_list(f->pattern);
+        for (int i = 0; i < nfilters; i++) {
+             const char *msg = validate_list(filters[i].pattern);
 
              if (msg) {
                  return msg;

+ 12 - 10
src/dialog/SDL_dialog_utils.h

@@ -32,19 +32,19 @@ typedef char *(NameTransform)(const char * name);
 
 /* Converts all the filters into a single string. */
 /* <prefix>[filter]{<separator>[filter]...}<suffix> */
-char *convert_filters(const SDL_DialogFileFilter *filters, 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 *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. */
 /* <prefix>[filter name]<separator>[filter extension list]<suffix> */
 char *convert_filter(const 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);
+                     const char *prefix, const char *separator,
+                     const char *suffix, const char *ext_prefix,
+                     const char *ext_separator, const char *ext_suffix);
 
 /* Converts the extenstion list of a filter into a single string. */
 /* <prefix>[extension]{<separator>[extension]...}<suffix> */
@@ -53,5 +53,7 @@ char *convert_ext_list(const char *list, const char *prefix,
 
 /* 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);
+const char *validate_filters(const SDL_DialogFileFilter *filters,
+                             int nfilters);
+
 const char *validate_list(const char *list);

+ 4 - 4
src/dialog/android/SDL_androiddialog.c

@@ -22,17 +22,17 @@
 #include "SDL_internal.h"
 #include "../../core/android/SDL_android.h"
 
-void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, const char *default_location, SDL_bool allow_many)
+void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location, SDL_bool allow_many)
 {
-    if (!Android_JNI_OpenFileDialog(callback, userdata, filters, SDL_FALSE, allow_many)) {
+    if (!Android_JNI_OpenFileDialog(callback, userdata, filters, nfilters, SDL_FALSE, allow_many)) {
         /* SDL_SetError is already called when it fails */
         callback(userdata, NULL, -1);
     }
 }
 
-void SDLCALL SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, const char *default_location)
+void SDLCALL SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location)
 {
-    if (!Android_JNI_OpenFileDialog(callback, userdata, filters, SDL_TRUE, SDL_FALSE)) {
+    if (!Android_JNI_OpenFileDialog(callback, userdata, filters, nfilters, SDL_TRUE, SDL_FALSE)) {
         /* SDL_SetError is already called when it fails */
         callback(userdata, NULL, -1);
     }

+ 9 - 11
src/dialog/cocoa/SDL_cocoadialog.m

@@ -31,14 +31,14 @@ typedef enum
     FDT_OPENFOLDER
 } cocoa_FileDialogType;
 
-void show_file_dialog(cocoa_FileDialogType type, SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
+void show_file_dialog(cocoa_FileDialogType type, SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many)
 {
 #if defined(SDL_PLATFORM_TVOS) || defined(SDL_PLATFORM_IOS)
     SDL_SetError("tvOS and iOS don't support path-based file dialogs");
     callback(userdata, NULL, -1);
 #else
     if (filters) {
-        const char *msg = validate_filters(filters);
+        const char *msg = validate_filters(filters, nfilters);
 
         if (msg) {
             SDL_SetError("%s", msg);
@@ -76,13 +76,11 @@ void show_file_dialog(cocoa_FileDialogType type, SDL_DialogFileCallback callback
     };
 
     if (filters) {
-        int n = -1;
-        while (filters[++n].name && filters[n].pattern);
         // 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:n ];
+        NSMutableArray *types = [[NSMutableArray alloc] initWithCapacity:nfilters ];
 
         int has_all_files = 0;
-        for (int i = 0; i < n; i++) {
+        for (int i = 0; i < nfilters; i++) {
             char *pattern = SDL_strdup(filters[i].pattern);
             char *pattern_ptr = pattern;
 
@@ -180,17 +178,17 @@ void show_file_dialog(cocoa_FileDialogType type, SDL_DialogFileCallback callback
 #endif // defined(SDL_PLATFORM_TVOS) || defined(SDL_PLATFORM_IOS)
 }
 
-void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
+void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many)
 {
-    show_file_dialog(FDT_OPEN, callback, userdata, window, filters, default_location, allow_many);
+    show_file_dialog(FDT_OPEN, callback, userdata, window, filters, nfilters, default_location, allow_many);
 }
 
-void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
+void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location)
 {
-    show_file_dialog(FDT_SAVE, callback, userdata, window, filters, default_location, 0);
+    show_file_dialog(FDT_SAVE, callback, userdata, window, filters, nfilters, default_location, 0);
 }
 
 void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many)
 {
-    show_file_dialog(FDT_OPENFOLDER, callback, userdata, window, NULL, default_location, allow_many);
+    show_file_dialog(FDT_OPENFOLDER, callback, userdata, window, NULL, 0, default_location, allow_many);
 }

+ 2 - 2
src/dialog/dummy/SDL_dummydialog.c

@@ -20,13 +20,13 @@
 */
 #include "SDL_internal.h"
 
-void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
+void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many)
 {
   SDL_Unsupported();
   callback(userdata, NULL, -1);
 }
 
-void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
+void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location)
 {
   SDL_Unsupported();
   callback(userdata, NULL, -1);

+ 20 - 20
src/dialog/haiku/SDL_haikudialog.cc

@@ -60,9 +60,10 @@ std::vector<std::string> StringSplit(const std::string& str, const std::string&
 class SDLBRefFilter : public BRefFilter
 {
 public:
-    SDLBRefFilter(const SDL_DialogFileFilter *filters) :
+    SDLBRefFilter(const SDL_DialogFileFilter *filters, int nfilters) :
         BRefFilter(),
-        m_filters(filters)
+        m_filters(filters),
+        m_nfilters(nfilters)
     {
     }
 
@@ -81,14 +82,12 @@ public:
         if (S_ISDIR(info.st_mode))
             return true;
 
-        const auto *filter = m_filters;
-        while (filter->name && filter->pattern) {
-            for (const auto& suffix : StringSplit(filter->pattern, ";")) {
+        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;
                 }
             }
-            filter++;
         }
 
         return false;
@@ -96,6 +95,7 @@ public:
 
 private:
     const SDL_DialogFileFilter * const m_filters;
+    int m_nfilters;
 };
 
 class CallbackLooper : public BLooper
@@ -190,7 +190,7 @@ private:
     SDLBRefFilter *m_filter;
 };
 
-void ShowDialog(bool save, SDL_DialogFileCallback callback, void *userdata, bool many, bool modal, const SDL_DialogFileFilter *filters, bool folder, const char *location)
+void ShowDialog(bool save, SDL_DialogFileCallback callback, void *userdata, bool many, bool modal, const SDL_DialogFileFilter *filters, int nfilters, bool folder, const char *location)
 {
     if (SDL_InitBeApp()) {
         char* err = SDL_strdup(SDL_GetError());
@@ -200,12 +200,14 @@ void ShowDialog(bool save, SDL_DialogFileCallback callback, void *userdata, bool
         return;
     }
 
-    const char *msg = validate_filters(filters);
+    if (filters) {
+        const char *msg = validate_filters(filters, nfilters);
 
-    if (msg) {
-        SDL_SetError("%s", msg);
-        callback(userdata, NULL, -1);
-        return;
+        if (msg) {
+            SDL_SetError("%s", msg);
+            callback(userdata, NULL, -1);
+            return;
+        }
     }
 
     if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) {
@@ -217,7 +219,7 @@ void ShowDialog(bool save, SDL_DialogFileCallback callback, void *userdata, bool
     // 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);
+    SDLBRefFilter *filter = new(std::nothrow) SDLBRefFilter(filters, nfilters);
 
     if (looper == NULL || messenger == NULL || filter == NULL) {
         SDL_free(looper);
@@ -241,19 +243,17 @@ void ShowDialog(bool save, SDL_DialogFileCallback callback, void *userdata, bool
     panel->Show();
 }
 
-void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, const char *default_location, SDL_bool allow_many)
+void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location, SDL_bool allow_many)
 {
-    ShowDialog(false, callback, userdata, allow_many == SDL_TRUE, !!window, filters, false, default_location);
+    ShowDialog(false, callback, userdata, allow_many == SDL_TRUE, !!window, filters, nfilters, false, default_location);
 }
 
-void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, const char *default_location)
+void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location)
 {
-    ShowDialog(true, callback, userdata, false, !!window, filters, false, default_location);
+    ShowDialog(true, callback, userdata, false, !!window, filters, nfilters, false, default_location);
 }
 
 void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const char* default_location, SDL_bool allow_many)
 {
-    // Use a dummy filter to avoid showing files in the dialog
-    SDL_DialogFileFilter filter[] = {{}};
-    ShowDialog(false, callback, userdata, allow_many == SDL_TRUE, !!window, filter, true, default_location);
+    ShowDialog(false, callback, userdata, allow_many == SDL_TRUE, !!window, NULL, 0, true, default_location);
 }

+ 16 - 16
src/dialog/unix/SDL_portaldialog.c

@@ -74,17 +74,17 @@ static void DBus_AppendBoolOption(SDL_DBusContext *dbus, DBusMessageIter *option
     dbus->message_iter_close_container(options, &options_pair);
 }
 
-static void DBus_AppendFilter(SDL_DBusContext *dbus, DBusMessageIter *parent, const SDL_DialogFileFilter *filter)
+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_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);
+    patterns = SDL_strdup(filter.pattern);
     if (!patterns) {
         goto cleanup;
     }
@@ -120,7 +120,7 @@ cleanup:
     dbus->message_iter_close_container(parent, &filter_entry);
 }
 
-static void DBus_AppendFilters(SDL_DBusContext *dbus, DBusMessageIter *options, const SDL_DialogFileFilter *filters)
+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";
@@ -129,8 +129,8 @@ static void DBus_AppendFilters(SDL_DBusContext *dbus, DBusMessageIter *options,
     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 (const SDL_DialogFileFilter *filter = filters; filter && filter->name && filter->pattern; ++filter) {
-        DBus_AppendFilter(dbus, &options_value_array, filter);
+    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);
@@ -269,7 +269,7 @@ not_our_signal:
     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
-static void DBus_OpenDialog(const char *method, const char *method_title, SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many, int open_folders)
+static void DBus_OpenDialog(const char *method, const char *method_title, SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many, int open_folders)
 {
     SDL_DBusContext *dbus = SDL_DBus_GetContext();
     DBusMessage *msg;
@@ -281,7 +281,7 @@ static void DBus_OpenDialog(const char *method, const char *method_title, SDL_Di
     static char *default_parent_window = "";
     SDL_PropertiesID props = SDL_GetWindowProperties(window);
 
-    const char *err_msg = validate_filters(filters);
+    const char *err_msg = validate_filters(filters, nfilters);
 
     if (err_msg) {
         SDL_SetError("%s", err_msg);
@@ -358,7 +358,7 @@ static void DBus_OpenDialog(const char *method, const char *method_title, SDL_Di
         DBus_AppendBoolOption(dbus, &options, "directory", 1);
     }
     if (filters) {
-        DBus_AppendFilters(dbus, &options, filters);
+        DBus_AppendFilters(dbus, &options, filters, nfilters);
     }
     if (default_location) {
         DBus_AppendByteArray(dbus, &options, "current_folder", default_location);
@@ -419,19 +419,19 @@ incorrect_type:
     dbus->message_unref(reply);
 }
 
-void SDL_Portal_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
+void SDL_Portal_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many)
 {
-    DBus_OpenDialog("OpenFile", "Open File", callback, userdata, window, filters, default_location, allow_many, 0);
+    DBus_OpenDialog("OpenFile", "Open File", callback, userdata, window, filters, nfilters, default_location, allow_many, 0);
 }
 
-void SDL_Portal_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
+void SDL_Portal_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location)
 {
-    DBus_OpenDialog("SaveFile", "Save File", callback, userdata, window, filters, default_location, 0, 0);
+    DBus_OpenDialog("SaveFile", "Save File", callback, userdata, window, filters, nfilters, default_location, 0, 0);
 }
 
 void SDL_Portal_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many)
 {
-    DBus_OpenDialog("OpenFile", "Open Folder", callback, userdata, window, NULL, default_location, allow_many, 1);
+    DBus_OpenDialog("OpenFile", "Open Folder", callback, userdata, window, NULL, 0, default_location, allow_many, 1);
 }
 
 int SDL_Portal_detect(void)
@@ -494,13 +494,13 @@ done:
 
 /* Dummy implementation to avoid compilation problems */
 
-void SDL_Portal_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
+void SDL_Portal_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many)
 {
     SDL_Unsupported();
     callback(userdata, NULL, -1);
 }
 
-void SDL_Portal_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
+void SDL_Portal_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location)
 {
     SDL_Unsupported();
     callback(userdata, NULL, -1);

+ 2 - 2
src/dialog/unix/SDL_portaldialog.h

@@ -21,8 +21,8 @@
 
 #include "SDL_internal.h"
 
-void SDL_Portal_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many);
-void SDL_Portal_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location);
+void SDL_Portal_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many);
+void SDL_Portal_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location);
 void SDL_Portal_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many);
 
 /** @returns non-zero if available, zero if unavailable */

+ 6 - 6
src/dialog/unix/SDL_unixdialog.c

@@ -23,8 +23,8 @@
 #include "./SDL_portaldialog.h"
 #include "./SDL_zenitydialog.h"
 
-static void (*detected_open)(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many) = NULL;
-static void (*detected_save)(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location) = NULL;
+static void (*detected_open)(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many) = NULL;
+static void (*detected_save)(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location) = NULL;
 static void (*detected_folder)(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many) = NULL;
 
 static int detect_available_methods(const char *value);
@@ -73,7 +73,7 @@ static int detect_available_methods(const char *value)
     return 0;
 }
 
-void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
+void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many)
 {
     /* Call detect_available_methods() again each time in case the situation changed */
     if (!detected_open && !detect_available_methods(NULL)) {
@@ -82,10 +82,10 @@ void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL
         return;
     }
 
-    detected_open(callback, userdata, window, filters, default_location, allow_many);
+    detected_open(callback, userdata, window, filters, nfilters, default_location, allow_many);
 }
 
-void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
+void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location)
 {
     /* Call detect_available_methods() again each time in case the situation changed */
     if (!detected_save && !detect_available_methods(NULL)) {
@@ -94,7 +94,7 @@ void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL
         return;
     }
 
-    detected_save(callback, userdata, window, filters, default_location);
+    detected_save(callback, userdata, window, filters, nfilters, default_location);
 }
 
 void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many)

+ 10 - 14
src/dialog/unix/SDL_zenitydialog.c

@@ -39,6 +39,7 @@ typedef struct
     void* userdata;
     const char* filename;
     const SDL_DialogFileFilter *filters;
+    int nfilters;
     Uint32 flags;
 } zenityArgs;
 
@@ -110,12 +111,7 @@ static char** generate_args(const zenityArgs* info)
     }
 
     if (info->filters) {
-        const SDL_DialogFileFilter *filter_ptr = info->filters;
-
-        while (filter_ptr->name && filter_ptr->pattern) {
-            argc++;
-            filter_ptr++;
-        }
+        argc += info->nfilters;
     }
 
     argv = SDL_malloc(sizeof(char *) * argc + 1);
@@ -157,10 +153,9 @@ static char** generate_args(const zenityArgs* info)
     }
 
     if (info->filters) {
-        const SDL_DialogFileFilter *filter_ptr = info->filters;
-
-        while (filter_ptr->name && filter_ptr->pattern) {
-            char *filter_str = convert_filter(*filter_ptr, zenity_clean_name,
+        for (int i = 0; i < info->nfilters; i++) {
+            char *filter_str = convert_filter(info->filters[i],
+                                              zenity_clean_name,
                                               "--file-filter=", " | ", "",
                                               "*.", " *.", "");
 
@@ -170,8 +165,6 @@ static char** generate_args(const zenityArgs* info)
 
             argv[nextarg++] = filter_str;
             CHECK_OOM()
-
-            filter_ptr++;
         }
     }
 
@@ -330,7 +323,7 @@ static int run_zenity_thread(void* ptr)
     return 0;
 }
 
-void SDL_Zenity_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
+void SDL_Zenity_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many)
 {
     zenityArgs *args;
     SDL_Thread *thread;
@@ -345,6 +338,7 @@ void SDL_Zenity_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userda
     args->userdata = userdata;
     args->filename = default_location;
     args->filters = filters;
+    args->nfilters = nfilters;
     args->flags = (allow_many == SDL_TRUE) ? ZENITY_MULTIPLE : 0;
 
     thread = SDL_CreateThread(run_zenity_thread, "SDL_ShowOpenFileDialog", (void *) args);
@@ -357,7 +351,7 @@ void SDL_Zenity_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userda
     SDL_DetachThread(thread);
 }
 
-void SDL_Zenity_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
+void SDL_Zenity_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location)
 {
     zenityArgs *args;
     SDL_Thread *thread;
@@ -372,6 +366,7 @@ void SDL_Zenity_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userda
     args->userdata = userdata;
     args->filename = default_location;
     args->filters = filters;
+    args->nfilters = nfilters;
     args->flags = ZENITY_SAVE;
 
     thread = SDL_CreateThread(run_zenity_thread, "SDL_ShowSaveFileDialog", (void *) args);
@@ -399,6 +394,7 @@ void SDL_Zenity_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* user
     args->userdata = userdata;
     args->filename = default_location;
     args->filters = NULL;
+    args->nfilters = 0;
     args->flags = ((allow_many == SDL_TRUE) ? ZENITY_MULTIPLE : 0) | ZENITY_DIRECTORY;
 
     thread = SDL_CreateThread(run_zenity_thread, "SDL_ShowOpenFolderDialog", (void *) args);

+ 2 - 2
src/dialog/unix/SDL_zenitydialog.h

@@ -21,8 +21,8 @@
 
 #include "SDL_internal.h"
 
-void SDL_Zenity_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many);
-void SDL_Zenity_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location);
+void SDL_Zenity_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many);
+void SDL_Zenity_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location);
 void SDL_Zenity_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many);
 
 /** @returns non-zero if available, zero if unavailable */

+ 14 - 18
src/dialog/windows/SDL_windowsdialog.c

@@ -34,6 +34,7 @@ typedef struct
 {
     int is_save;
     const SDL_DialogFileFilter *filters;
+    int nfilters;
     const char* default_file;
     SDL_Window* parent;
     DWORD flags;
@@ -50,18 +51,9 @@ typedef struct
 } winFArgs;
 
 /** Converts dialog.nFilterIndex to SDL-compatible value */
-int getFilterIndex(int as_reported_by_windows, const SDL_DialogFileFilter *filters)
+int getFilterIndex(int as_reported_by_windows)
 {
-    int filter_index = as_reported_by_windows - 1;
-
-    if (filter_index < 0) {
-        filter_index = 0;
-        for (const SDL_DialogFileFilter *filter = filters; filter && filter->name && filter->pattern; filter++) {
-            filter_index++;
-        }
-    }
-
-    return filter_index;
+    return as_reported_by_windows - 1;
 }
 
 /* TODO: The new version of file dialogs */
@@ -70,6 +62,7 @@ void windows_ShowFileDialog(void *ptr)
     winArgs *args = (winArgs *) ptr;
     int is_save = args->is_save;
     const SDL_DialogFileFilter *filters = args->filters;
+    int nfilters = args->nfilters;
     const char* default_file = args->default_file;
     SDL_Window* parent = args->parent;
     DWORD flags = args->flags;
@@ -160,8 +153,9 @@ void windows_ShowFileDialog(void *ptr)
     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, NULL, "", "", "\x01\x01", "",
-                                           "\x01", "\x01", "*.", ";*.", "");
+        char *filterlist = convert_filters(filters, nfilters, NULL, "", "",
+                                           "\x01\x01", "", "\x01", "\x01",
+                                           "*.", ";*.", "");
 
         if (!filterlist) {
             callback(userdata, NULL, -1);
@@ -224,7 +218,7 @@ void windows_ShowFileDialog(void *ptr)
             /* 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, filters));
+            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
@@ -336,7 +330,7 @@ void windows_ShowFileDialog(void *ptr)
                 }
             }
 
-            callback(userdata, (const char * const*) chosen_files_list, getFilterIndex(dialog.nFilterIndex, filters));
+            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]);
@@ -353,7 +347,7 @@ void windows_ShowFileDialog(void *ptr)
                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, filters));
+            callback(userdata, opts, getFilterIndex(dialog.nFilterIndex));
         } else {
             SDL_SetError("Windows error, CommDlgExtendedError: %ld", pCommDlgExtendedError());
             callback(userdata, NULL, -1);
@@ -433,7 +427,7 @@ int windows_folder_dialog_thread(void* ptr)
     return 0;
 }
 
-void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
+void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many)
 {
     winArgs *args;
     SDL_Thread *thread;
@@ -453,6 +447,7 @@ void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL
 
     args->is_save = 0;
     args->filters = filters;
+    args->nfilters = nfilters;
     args->default_file = default_location;
     args->parent = window;
     args->flags = (allow_many == SDL_TRUE) ? OFN_ALLOWMULTISELECT : 0;
@@ -470,7 +465,7 @@ void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL
     SDL_DetachThread(thread);
 }
 
-void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
+void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location)
 {
     winArgs *args;
     SDL_Thread *thread;
@@ -489,6 +484,7 @@ void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL
 
     args->is_save = 1;
     args->filters = filters;
+    args->nfilters = nfilters;
     args->default_file = default_location;
     args->parent = window;
     args->flags = 0;

+ 2 - 2
src/dynapi/SDL_dynapi_procs.h

@@ -810,9 +810,9 @@ SDL_DYNAPI_PROC(void,SDL_SetWindowsMessageHook,(SDL_WindowsMessageHook a, void *
 SDL_DYNAPI_PROC(void,SDL_SetX11EventHook,(SDL_X11EventHook a, void *b),(a,b),)
 SDL_DYNAPI_PROC(int,SDL_ShowCursor,(void),(),return)
 SDL_DYNAPI_PROC(int,SDL_ShowMessageBox,(const SDL_MessageBoxData *a, int *b),(a,b),return)
-SDL_DYNAPI_PROC(void,SDL_ShowOpenFileDialog,(SDL_DialogFileCallback a, void *b, SDL_Window *c, const SDL_DialogFileFilter *d, const char *e, SDL_bool f),(a,b,c,d,e,f),)
+SDL_DYNAPI_PROC(void,SDL_ShowOpenFileDialog,(SDL_DialogFileCallback a, void *b, SDL_Window *c, const SDL_DialogFileFilter *d, int e, const char *f, SDL_bool g),(a,b,c,d,e,f,g),)
 SDL_DYNAPI_PROC(void,SDL_ShowOpenFolderDialog,(SDL_DialogFileCallback a, void *b, SDL_Window *c, const char *d, SDL_bool e),(a,b,c,d,e),)
-SDL_DYNAPI_PROC(void,SDL_ShowSaveFileDialog,(SDL_DialogFileCallback a, void *b, SDL_Window *c, const SDL_DialogFileFilter *d, const char *e),(a,b,c,d,e),)
+SDL_DYNAPI_PROC(void,SDL_ShowSaveFileDialog,(SDL_DialogFileCallback a, void *b, SDL_Window *c, const SDL_DialogFileFilter *d, int e, const char *f),(a,b,c,d,e,f),)
 SDL_DYNAPI_PROC(int,SDL_ShowSimpleMessageBox,(SDL_MessageBoxFlags a, const char *b, const char *c, SDL_Window *d),(a,b,c,d),return)
 SDL_DYNAPI_PROC(int,SDL_ShowWindow,(SDL_Window *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_ShowWindowSystemMenu,(SDL_Window *a, int b, int c),(a,b,c),return)

+ 5 - 5
test/testdialog.c

@@ -15,11 +15,10 @@
 #include <SDL3/SDL_main.h>
 #include <SDL3/SDL_test.h>
 
-const SDL_DialogFileFilter filters[4] = {
+const SDL_DialogFileFilter filters[3] = {
     { "All files", "*" },
     { "JPG images", "jpg;jpeg" },
-    { "PNG images", "png" },
-    { NULL, NULL }
+    { "PNG images", "png" }
 };
 
 static void SDLCALL callback(void* userdata, const char* const* files, int filter) {
@@ -54,6 +53,7 @@ int main(int argc, char *argv[]) {
     const SDL_FRect open_folder_rect = { 370, 50, 220, 140 };
     int i;
     char *initial_path = NULL;
+    const int nfilters = sizeof(filters) / sizeof(*filters);
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, 0);
@@ -114,11 +114,11 @@ int main(int argc, char *argv[]) {
                  * - Nonzero if the user is allowed to choose multiple entries (not for SDL_ShowSaveFileDialog)
                  */
                 if (SDL_PointInRectFloat(&p, &open_file_rect)) {
-                    SDL_ShowOpenFileDialog(callback, NULL, w, filters, initial_path, 1);
+                    SDL_ShowOpenFileDialog(callback, NULL, w, filters, nfilters, initial_path, 1);
                 } else if (SDL_PointInRectFloat(&p, &open_folder_rect)) {
                     SDL_ShowOpenFolderDialog(callback, NULL, w, initial_path, 1);
                 } else if (SDL_PointInRectFloat(&p, &save_file_rect)) {
-                    SDL_ShowSaveFileDialog(callback, NULL, w, filters, initial_path);
+                    SDL_ShowSaveFileDialog(callback, NULL, w, filters, nfilters, initial_path);
                 }
             }
         }