SDL_ShowFileDialogWithProperties with more options

This commit is contained in:
Semphris
2024-10-12 00:30:23 -04:00
committed by Sam Lantinga
parent dc5a2ddfd0
commit a4852f3a10
19 changed files with 608 additions and 297 deletions

View File

@@ -30,6 +30,7 @@ LOCAL_SRC_FILES := \
$(wildcard $(LOCAL_PATH)/src/core/*.c) \
$(wildcard $(LOCAL_PATH)/src/core/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/cpuinfo/*.c) \
$(LOCAL_PATH)/src/dialog/SDL_dialog.c \
$(LOCAL_PATH)/src/dialog/SDL_dialog_utils.c \
$(LOCAL_PATH)/src/dialog/android/SDL_androiddialog.c \
$(wildcard $(LOCAL_PATH)/src/dynapi/*.c) \

View File

@@ -2874,6 +2874,7 @@ endif()
if (SDL_DIALOG)
sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/SDL_dialog_utils.c)
sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/SDL_dialog.c)
if(ANDROID)
sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/android/SDL_androiddialog.c)
set(HAVE_SDL_DIALOG TRUE)

View File

@@ -517,6 +517,7 @@
</ClCompile>
<ClCompile Include="..\..\src\camera\dummy\SDL_camera_dummy.c" />
<ClCompile Include="..\..\src\camera\SDL_camera.c" />
<ClCompile Include="..\..\src\dialog\SDL_dialog.c" />
<ClCompile Include="..\..\src\dialog\SDL_dialog_utils.c" />
<ClCompile Include="..\..\src\filesystem\SDL_filesystem.c" />
<ClCompile Include="..\..\src\filesystem\windows\SDL_sysfsops.c" />

View File

@@ -7,6 +7,9 @@
<ClCompile Include="..\..\src\dialog\SDL_dialog_utils.c">
<Filter>dialog</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dialog\SDL_dialog.c">
<Filter>dialog</Filter>
</ClCompile>
<ClCompile Include="..\..\src\filesystem\SDL_filesystem.c">
<Filter>filesystem</Filter>
</ClCompile>

View File

@@ -412,6 +412,7 @@
<ClCompile Include="..\..\src\camera\dummy\SDL_camera_dummy.c" />
<ClCompile Include="..\..\src\camera\mediafoundation\SDL_camera_mediafoundation.c" />
<ClCompile Include="..\..\src\camera\SDL_camera.c" />
<ClCompile Include="..\..\src\dialog\SDL_dialog.c" />
<ClCompile Include="..\..\src\dialog\SDL_dialog_utils.c" />
<ClCompile Include="..\..\src\filesystem\SDL_filesystem.c" />
<ClCompile Include="..\..\src\filesystem\windows\SDL_sysfsops.c" />

View File

@@ -950,6 +950,9 @@
<ClCompile Include="..\..\src\camera\SDL_camera.c">
<Filter>camera</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dialog\SDL_dialog.c">
<Filter>dialog</Filter>
</ClCompile>
<ClCompile Include="..\..\src\dialog\SDL_dialog_utils.c">
<Filter>dialog</Filter>
</ClCompile>

View File

@@ -30,6 +30,7 @@
#include <SDL3/SDL_stdinc.h>
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_properties.h>
#include <SDL3/SDL_video.h>
#include <SDL3/SDL_begin_code.h>
@@ -55,6 +56,7 @@ extern "C" {
* \sa SDL_ShowOpenFileDialog
* \sa SDL_ShowSaveFileDialog
* \sa SDL_ShowOpenFolderDialog
* \sa SDL_ShowFileDialogWithProperties
*/
typedef struct SDL_DialogFileFilter
{
@@ -93,14 +95,13 @@ typedef struct SDL_DialogFileFilter
* \sa SDL_ShowOpenFileDialog
* \sa SDL_ShowSaveFileDialog
* \sa SDL_ShowOpenFolderDialog
* \sa SDL_ShowFileDialogWithProperties
*/
typedef void (SDLCALL *SDL_DialogFileCallback)(void *userdata, const char * const *filelist, int filter);
/**
* Displays a dialog that lets the user select a file on their filesystem.
*
* This function should only be invoked from the main thread.
*
* This is an asynchronous function; it will return immediately, and the
* result will be passed to the callback.
*
@@ -127,19 +128,25 @@ typedef void (SDLCALL *SDL_DialogFileCallback)(void *userdata, const char * cons
* Not all platforms support this option.
* \param filters a list of filters, may be NULL. Not all platforms support
* this option, and platforms that do support it may allow the
* user to ignore the filters.
* user to ignore the filters. If non-NULL, it must remain valid
* at least until the callback is invoked.
* \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
* entries. Not all platforms support this option.
*
* \threadsafety This function should be called only from the main thread. The
* callback may be invoked from the same thread or from a
* different one, depending on the OS's constraints.
*
* \since This function is available since SDL 3.1.3.
*
* \sa SDL_DialogFileCallback
* \sa SDL_DialogFileFilter
* \sa SDL_ShowSaveFileDialog
* \sa SDL_ShowOpenFolderDialog
* \sa SDL_ShowFileDialogWithProperties
*/
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, bool allow_many);
@@ -147,8 +154,6 @@ extern SDL_DECLSPEC void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback c
* Displays a dialog that lets the user choose a new or existing file on their
* filesystem.
*
* This function should only be invoked from the main thread.
*
* This is an asynchronous function; it will return immediately, and the
* result will be passed to the callback.
*
@@ -174,25 +179,29 @@ extern SDL_DECLSPEC void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback c
* Not all platforms support this option.
* \param filters a list of filters, may be NULL. Not all platforms support
* this option, and platforms that do support it may allow the
* user to ignore the filters.
* user to ignore the filters. If non-NULL, it must remain valid
* at least until the callback is invoked.
* \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.
*
* \threadsafety This function should be called only from the main thread. The
* callback may be invoked from the same thread or from a
* different one, depending on the OS's constraints.
*
* \since This function is available since SDL 3.1.3.
*
* \sa SDL_DialogFileCallback
* \sa SDL_DialogFileFilter
* \sa SDL_ShowOpenFileDialog
* \sa SDL_ShowOpenFolderDialog
* \sa SDL_ShowFileDialogWithProperties
*/
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.
*
* This function should only be invoked from the main thread.
*
* This is an asynchronous function; it will return immediately, and the
* result will be passed to the callback.
*
@@ -222,14 +231,83 @@ extern SDL_DECLSPEC void SDLCALL SDL_ShowSaveFileDialog(SDL_DialogFileCallback c
* \param allow_many if non-zero, the user will be allowed to select multiple
* entries. Not all platforms support this option.
*
* \threadsafety This function should be called only from the main thread. The
* callback may be invoked from the same thread or from a
* different one, depending on the OS's constraints.
*
* \since This function is available since SDL 3.1.3.
*
* \sa SDL_DialogFileCallback
* \sa SDL_ShowOpenFileDialog
* \sa SDL_ShowSaveFileDialog
* \sa SDL_ShowFileDialogWithProperties
*/
extern SDL_DECLSPEC void SDLCALL SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const char *default_location, bool allow_many);
typedef enum SDL_FileDialogType {
SDL_FILEDIALOG_OPENFILE,
SDL_FILEDIALOG_SAVEFILE,
SDL_FILEDIALOG_OPENFOLDER
} SDL_FileDialogType;
#define SDL_PROP_FILE_DIALOG_FILTERS_POINTER "SDL.filedialog.filters"
#define SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER "SDL.filedialog.nfilters"
#define SDL_PROP_FILE_DIALOG_WINDOW_POINTER "SDL.filedialog.window"
#define SDL_PROP_FILE_DIALOG_LOCATION_STRING "SDL.filedialog.location"
#define SDL_PROP_FILE_DIALOG_MANY_BOOLEAN "SDL.filedialog.many"
#define SDL_PROP_FILE_DIALOG_TITLE_STRING "SDL.filedialog.title"
#define SDL_PROP_FILE_DIALOG_ACCEPT_STRING "SDL.filedialog.accept"
#define SDL_PROP_FILE_DIALOG_CANCEL_STRING "SDL.filedialog.cancel"
/**
* Create and launch a file dialog with the specified properties.
*
* These are the supported properties:
*
* - `SDL_PROP_FILE_DIALOG_FILTERS_POINTER`: a pointer to a list of
* SDL_DialogFileFilter's, which will be used as filters for file-based
* selections. Ignored if the dialog is an "Open Folder" dialog. If non-NULL,
* the array of filters must remain valid at least until the callback is
* invoked.
* - `SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER`: the number of filters in the array
* of filters, if it exists.
* - `SDL_PROP_FILE_DIALOG_WINDOW_POINTER`: the window that the dialog should
* be modal for.
* - `SDL_PROP_FILE_DIALOG_LOCATION_STRING`: the default folder or file to
* start the dialog at.
* - `SDL_PROP_FILE_DIALOG_MANY_BOOLEAN`: true to allow the user to select more
* than one entry.
* - `SDL_PROP_FILE_DIALOG_TITLE_STRING`: the title for the dialog.
* - `SDL_PROP_FILE_DIALOG_ACCEPT_STRING`: the label that the accept button
* should have.
* - `SDL_PROP_FILE_DIALOG_CANCEL_STRING`: the label that the cancel button
* should have.
*
* Note that each platform may or may not support any of the properties.
*
* \param type the type of file dialog.
* \param callback a function pointer to be invoked when the user selects a
* file and accepts, or cancels the dialog, or an error
* occurs.
* \param userdata an optional pointer to pass extra data to the callback when
* it will be invoked.
* \param props the properties to use.
*
* \threadsafety This function should be called only from the main thread. The
* callback may be invoked from the same thread or from a
* different one, depending on the OS's constraints.
*
* \since This function is available since SDL 3.2.0.
*
* \sa SDL_FileDialogType
* \sa SDL_DialogFileCallback
* \sa SDL_DialogFileFilter
* \sa SDL_ShowOpenFileDialog
* \sa SDL_ShowSaveFileDialog
* \sa SDL_ShowOpenFolderDialog
*/
extern SDL_DECLSPEC void SDLCALL SDL_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}

103
src/dialog/SDL_dialog.c Normal file
View File

@@ -0,0 +1,103 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#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;
}
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;
};
}
void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location, bool allow_many)
{
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);
}
void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location)
{
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);
}
void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const char *default_location, bool allow_many)
{
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);
}

22
src/dialog/SDL_dialog.h Normal file
View File

@@ -0,0 +1,22 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props);

View File

@@ -20,26 +20,39 @@
*/
#include "SDL_internal.h"
#include "../SDL_dialog.h"
#include "../../core/android/SDL_android.h"
void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location, bool allow_many)
void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props)
{
if (!Android_JNI_OpenFileDialog(callback, userdata, filters, nfilters, false, allow_many)) {
// SDL_SetError is already called when it fails
callback(userdata, NULL, -1);
}
}
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;
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, nfilters, true, false)) {
// SDL_SetError is already called when it fails
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;
}
}
void SDLCALL SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const char *default_location, bool allow_many)
{
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);
}
}

View File

@@ -19,6 +19,7 @@
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
@@ -26,15 +27,16 @@
#import <Cocoa/Cocoa.h>
#import <UniformTypeIdentifiers/UTType.h>
typedef enum
void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props)
{
FDT_SAVE,
FDT_OPEN,
FDT_OPENFOLDER
} cocoa_FileDialogType;
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);
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, bool allow_many)
{
if (filters) {
const char *msg = validate_filters(filters, nfilters);
@@ -46,7 +48,7 @@ void show_file_dialog(cocoa_FileDialogType type, SDL_DialogFileCallback callback
}
if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) {
SDL_SetError("File dialog driver unsupported");
SDL_SetError("File dialog driver unsupported (don't set SDL_HINT_FILE_DIALOG_DRIVER)");
callback(userdata, NULL, -1);
return;
}
@@ -56,15 +58,17 @@ void show_file_dialog(cocoa_FileDialogType type, SDL_DialogFileCallback callback
NSOpenPanel *dialog_as_open;
switch (type) {
case FDT_SAVE:
case SDL_FILEDIALOG_SAVEFILE:
dialog = [NSSavePanel savePanel];
break;
case FDT_OPEN:
case SDL_FILEDIALOG_OPENFILE:
dialog_as_open = [NSOpenPanel openPanel];
[dialog_as_open setAllowsMultipleSelection:((allow_many == true) ? YES : NO)];
dialog = dialog_as_open;
break;
case FDT_OPENFOLDER:
case SDL_FILEDIALOG_OPENFOLDER:
dialog_as_open = [NSOpenPanel openPanel];
[dialog_as_open setCanChooseFiles:NO];
[dialog_as_open setCanChooseDirectories:YES];
@@ -73,6 +77,14 @@ void show_file_dialog(cocoa_FileDialogType type, SDL_DialogFileCallback callback
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 ];
@@ -175,19 +187,4 @@ void show_file_dialog(cocoa_FileDialogType type, SDL_DialogFileCallback callback
}
}
void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, bool 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, int nfilters, const char* default_location)
{
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, bool allow_many)
{
show_file_dialog(FDT_OPENFOLDER, callback, userdata, window, NULL, 0, default_location, allow_many);
}
#endif // SDL_PLATFORM_MACOS

View File

@@ -20,21 +20,11 @@
*/
#include "SDL_internal.h"
#include "../SDL_dialog.h"
#ifdef SDL_DIALOG_DUMMY
void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, bool allow_many)
{
SDL_Unsupported();
callback(userdata, NULL, -1);
}
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);
}
void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, bool allow_many)
void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props)
{
SDL_Unsupported();
callback(userdata, NULL, -1);

View File

@@ -20,9 +20,11 @@
*/
#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 <string>
#include <vector>
@@ -190,8 +192,35 @@ private:
SDLBRefFilter *m_filter;
};
void ShowDialog(bool save, SDL_DialogFileCallback callback, void *userdata, bool many, bool modal, const SDL_DialogFileFilter *filters, int nfilters, bool folder, const char *location)
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);
@@ -238,22 +267,27 @@ void ShowDialog(bool save, SDL_DialogFileCallback callback, void *userdata, bool
}
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();
}
void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location, bool allow_many)
{
ShowDialog(false, callback, userdata, allow_many == true, !!window, filters, nfilters, false, 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, nfilters, false, default_location);
}
void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const char* default_location, bool allow_many)
{
ShowDialog(false, callback, userdata, allow_many == true, !!window, NULL, 0, true, default_location);
}

View File

@@ -275,8 +275,43 @@ 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, int nfilters, const char* default_location, bool allow_many, int open_folders)
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;
@@ -285,7 +320,7 @@ static void DBus_OpenDialog(const char *method, const char *method_title, SDL_Di
int filter_len;
static uint32_t handle_id = 0;
static char *default_parent_window = "";
SDL_PropertiesID props = SDL_GetWindowProperties(window);
SDL_PropertiesID window_props = SDL_GetWindowProperties(window);
const char *err_msg = validate_filters(filters, nfilters);
@@ -311,8 +346,8 @@ static void DBus_OpenDialog(const char *method, const char *method_title, SDL_Di
dbus->message_iter_init_append(msg, &params);
handle_str = default_parent_window;
if (props) {
const char *parent_handle = SDL_GetStringProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_EXPORT_HANDLE_STRING, NULL);
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;
@@ -324,7 +359,7 @@ static void DBus_OpenDialog(const char *method, const char *method_title, SDL_Di
SDL_snprintf(handle_str, len, "%s%s", WAYLAND_HANDLE_PREFIX, parent_handle);
} else {
const Uint64 xid = (Uint64)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
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));
@@ -357,7 +392,7 @@ static void DBus_OpenDialog(const char *method, const char *method_title, SDL_Di
SDL_free(handle_str);
DBus_AppendBoolOption(dbus, &options, "modal", !!window);
if (allow_many == true) {
if (allow_many) {
DBus_AppendBoolOption(dbus, &options, "multiple", 1);
}
if (open_folders) {
@@ -369,6 +404,9 @@ static void DBus_OpenDialog(const char *method, const char *method_title, SDL_Di
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(&params, &options);
DBusMessage *reply = dbus->connection_send_with_reply_and_block(dbus->session_conn, msg, DBUS_TIMEOUT_INFINITE, NULL);
@@ -425,21 +463,6 @@ incorrect_type:
dbus->message_unref(reply);
}
void SDL_Portal_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, bool allow_many)
{
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, int nfilters, const char* default_location)
{
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, bool allow_many)
{
DBus_OpenDialog("OpenFile", "Open Folder", callback, userdata, window, NULL, 0, default_location, allow_many, 1);
}
bool SDL_Portal_detect(void)
{
SDL_DBusContext *dbus = SDL_DBus_GetContext();
@@ -500,19 +523,7 @@ done:
// Dummy implementation to avoid compilation problems
void SDL_Portal_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, 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, int nfilters, const char* default_location)
{
SDL_Unsupported();
callback(userdata, NULL, -1);
}
void SDL_Portal_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, bool allow_many)
void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props)
{
SDL_Unsupported();
callback(userdata, NULL, -1);

View File

@@ -21,9 +21,7 @@
#include "SDL_internal.h"
void SDL_Portal_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, 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, bool allow_many);
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);

View File

@@ -20,19 +20,13 @@
*/
#include "SDL_internal.h"
#include "../SDL_dialog.h"
#include "./SDL_portaldialog.h"
#include "./SDL_zenitydialog.h"
static void (*detected_open)(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, 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, bool allow_many) = NULL;
static void (*detected_function)(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) = NULL;
static int detect_available_methods(const char *value);
void SDLCALL hint_callback(void *userdata, const char *name, const char *oldValue, const char *newValue)
{
detect_available_methods(newValue);
}
void SDLCALL hint_callback(void *userdata, const char *name, const char *oldValue, const char *newValue);
static void set_callback(void)
{
@@ -53,58 +47,35 @@ static int detect_available_methods(const char *value)
if (driver == NULL || SDL_strcmp(driver, "portal") == 0) {
if (SDL_Portal_detect()) {
detected_open = SDL_Portal_ShowOpenFileDialog;
detected_save = SDL_Portal_ShowSaveFileDialog;
detected_folder = SDL_Portal_ShowOpenFolderDialog;
detected_function = SDL_Portal_ShowFileDialogWithProperties;
return 1;
}
}
if (driver == NULL || SDL_strcmp(driver, "zenity") == 0) {
if (SDL_Zenity_detect()) {
detected_open = SDL_Zenity_ShowOpenFileDialog;
detected_save = SDL_Zenity_ShowSaveFileDialog;
detected_folder = SDL_Zenity_ShowOpenFolderDialog;
detected_function = SDL_Zenity_ShowFileDialogWithProperties;
return 2;
}
}
SDL_SetError("File dialog driver unsupported");
SDL_SetError("File dialog driver unsupported (supported values for SDL_HINT_FILE_DIALOG_DRIVER are 'zenity' and 'portal')");
return 0;
}
void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, bool allow_many)
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_open && !detect_available_methods(NULL)) {
if (!detected_function && !detect_available_methods(NULL)) {
// SetError() done by detect_available_methods()
callback(userdata, NULL, -1);
return;
}
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, 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)) {
// SetError() done by detect_available_methods()
callback(userdata, NULL, -1);
return;
}
detected_save(callback, userdata, window, filters, nfilters, default_location);
}
void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, bool allow_many)
{
// Call detect_available_methods() again each time in case the situation changed
if (!detected_folder && !detect_available_methods(NULL)) {
// SetError() done by detect_available_methods()
callback(userdata, NULL, -1);
return;
}
detected_folder(callback, userdata, window, default_location, allow_many);
detected_function(type, callback, userdata, props);
}

View File

@@ -26,13 +26,6 @@
#include <sys/wait.h>
#include <unistd.h>
typedef enum
{
ZENITY_MULTIPLE = 0x1,
ZENITY_DIRECTORY = 0x2,
ZENITY_SAVE = 0x4
} zenityFlags;
typedef struct
{
SDL_DialogFileCallback callback;
@@ -40,7 +33,13 @@ typedef struct
const char* filename;
const SDL_DialogFileFilter *filters;
int nfilters;
Uint32 flags;
bool allow_many;
SDL_FileDialogType type;
/* Zenity only works with X11 handles apparently */
Uint64 x11_window_handle;
const char *title;
const char *accept;
const char *cancel;
} zenityArgs;
#define CLEAR_AND_RETURN() \
@@ -84,7 +83,10 @@ char *zenity_clean_name(const char *name)
/* Exec call format:
*
* /usr/bin/env zenity --file-selection --separator=\n [--multiple]
* [--directory] [--save] [--filename FILENAME]
* [--directory] [--save --confirm-overwrite]
* [--filename FILENAME] [--modal --attach 0x11w1nd0w]
* [--title TITLE] [--ok-label ACCEPT]
* [--cancel-label CANCEL]
* [--file-filter=Filter Name | *.filt *.fn ...]...
*/
static char** generate_args(const zenityArgs* info)
@@ -94,22 +96,43 @@ static char** generate_args(const zenityArgs* info)
char **argv = NULL;
// ARGC PASS
if (info->flags & ZENITY_MULTIPLE) {
if (info->allow_many) {
argc++;
}
if (info->flags & ZENITY_DIRECTORY) {
argc++;
}
switch (info->type) {
case SDL_FILEDIALOG_OPENFILE:
break;
if (info->flags & ZENITY_SAVE) {
case SDL_FILEDIALOG_SAVEFILE:
argc += 2;
break;
case SDL_FILEDIALOG_OPENFOLDER:
argc++;
}
break;
};
if (info->filename) {
argc += 2;
}
if (info->x11_window_handle) {
argc += 3;
}
if (info->title) {
argc += 2;
}
if (info->accept) {
argc += 2;
}
if (info->cancel) {
argc += 2;
}
if (info->filters) {
argc += info->nfilters;
}
@@ -119,6 +142,7 @@ static char** generate_args(const zenityArgs* info)
return NULL;
}
// ARGV PASS
argv[nextarg++] = SDL_strdup("/usr/bin/env");
CHECK_OOM()
argv[nextarg++] = SDL_strdup("zenity");
@@ -128,21 +152,25 @@ static char** generate_args(const zenityArgs* info)
argv[nextarg++] = SDL_strdup("--separator=\n");
CHECK_OOM()
// ARGV PASS
if (info->flags & ZENITY_MULTIPLE) {
if (info->allow_many) {
argv[nextarg++] = SDL_strdup("--multiple");
CHECK_OOM()
}
if (info->flags & ZENITY_DIRECTORY) {
argv[nextarg++] = SDL_strdup("--directory");
CHECK_OOM()
}
switch (info->type) {
case SDL_FILEDIALOG_OPENFILE:
break;
if (info->flags & ZENITY_SAVE) {
case SDL_FILEDIALOG_SAVEFILE:
argv[nextarg++] = SDL_strdup("--save");
CHECK_OOM()
}
/* Asking before overwriting while saving seems like a sane default */
argv[nextarg++] = SDL_strdup("--confirm-overwrite");
break;
case SDL_FILEDIALOG_OPENFOLDER:
argv[nextarg++] = SDL_strdup("--directory");
break;
};
if (info->filename) {
argv[nextarg++] = SDL_strdup("--filename");
@@ -152,6 +180,43 @@ static char** generate_args(const zenityArgs* info)
CHECK_OOM()
}
if (info->x11_window_handle) {
argv[nextarg++] = SDL_strdup("--modal");
CHECK_OOM()
argv[nextarg++] = SDL_strdup("--attach");
CHECK_OOM()
argv[nextarg++] = SDL_malloc(64);
CHECK_OOM()
SDL_snprintf(argv[nextarg - 1], 64, "0x%" SDL_PRIx64, info->x11_window_handle);
}
if (info->title) {
argv[nextarg++] = SDL_strdup("--title");
CHECK_OOM()
argv[nextarg++] = SDL_strdup(info->title);
CHECK_OOM()
}
if (info->accept) {
argv[nextarg++] = SDL_strdup("--ok-label");
CHECK_OOM()
argv[nextarg++] = SDL_strdup(info->accept);
CHECK_OOM()
}
if (info->cancel) {
argv[nextarg++] = SDL_strdup("--cancel-label");
CHECK_OOM()
argv[nextarg++] = SDL_strdup(info->cancel);
CHECK_OOM()
}
if (info->filters) {
for (int i = 0; i < info->nfilters; i++) {
char *filter_str = convert_filter(info->filters[i],
@@ -290,7 +355,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, int nfilters, const char* default_location, bool allow_many)
void SDL_Zenity_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props)
{
zenityArgs *args;
SDL_Thread *thread;
@@ -301,72 +366,31 @@ void SDL_Zenity_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userda
return;
}
/* Properties can be destroyed as soon as the function returns; copy over what we need. */
args->callback = callback;
args->userdata = userdata;
args->filename = default_location;
args->filters = filters;
args->nfilters = nfilters;
args->flags = (allow_many == true) ? ZENITY_MULTIPLE : 0;
args->filename = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_LOCATION_STRING, NULL);
args->filters = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, NULL);
args->nfilters = SDL_GetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, 0);
args->allow_many = SDL_GetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, false);
args->type = type;
args->x11_window_handle = 0;
args->title = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_TITLE_STRING, NULL);
args->accept = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_ACCEPT_STRING, NULL);
args->cancel = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_CANCEL_STRING, NULL);
thread = SDL_CreateThread(run_zenity_thread, "SDL_ShowOpenFileDialog", (void *) args);
if (thread == NULL) {
callback(userdata, NULL, -1);
return;
}
SDL_DetachThread(thread);
}
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;
args = SDL_malloc(sizeof(zenityArgs));
if (args == NULL) {
callback(userdata, NULL, -1);
return;
}
args->callback = callback;
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);
if (thread == NULL) {
callback(userdata, NULL, -1);
return;
}
SDL_DetachThread(thread);
}
void SDL_Zenity_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, bool allow_many)
{
zenityArgs *args;
SDL_Thread *thread;
args = SDL_malloc(sizeof(zenityArgs));
if (args == NULL) {
callback(userdata, NULL, -1);
return;
}
args->callback = callback;
args->userdata = userdata;
args->filename = default_location;
args->filters = NULL;
args->nfilters = 0;
args->flags = ((allow_many == true) ? ZENITY_MULTIPLE : 0) | ZENITY_DIRECTORY;
thread = SDL_CreateThread(run_zenity_thread, "SDL_ShowOpenFolderDialog", (void *) args);
SDL_Window *window = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, NULL);
if (window) {
SDL_PropertiesID window_props = SDL_GetWindowProperties(window);
if (window_props) {
args->x11_window_handle = (Uint64) SDL_GetNumberProperty(window_props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
}
}
thread = SDL_CreateThread(run_zenity_thread, "SDL_ZenityFileDialog", (void *) args);
if (thread == NULL) {
SDL_free(args);
callback(userdata, NULL, -1);
return;
}

View File

@@ -21,9 +21,7 @@
#include "SDL_internal.h"
extern void SDL_Zenity_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, bool allow_many);
extern void SDL_Zenity_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location);
extern void SDL_Zenity_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, bool allow_many);
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);

View File

@@ -19,6 +19,7 @@
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 <windows.h>
@@ -32,7 +33,7 @@
typedef struct
{
int is_save;
bool is_save;
const SDL_DialogFileFilter *filters;
int nfilters;
const char* default_file;
@@ -40,6 +41,9 @@ typedef struct
DWORD flags;
SDL_DialogFileCallback callback;
void* userdata;
const char* title;
const char* accept;
const char* cancel;
} winArgs;
typedef struct
@@ -48,6 +52,9 @@ typedef struct
SDL_DialogFileCallback callback;
const char* default_folder;
void* userdata;
const char* title;
const char* accept;
const char* cancel;
} winFArgs;
/** Converts dialog.nFilterIndex to SDL-compatible value */
@@ -60,7 +67,7 @@ int getFilterIndex(int as_reported_by_windows)
void windows_ShowFileDialog(void *ptr)
{
winArgs *args = (winArgs *) ptr;
int is_save = args->is_save;
bool is_save = args->is_save;
const SDL_DialogFileFilter *filters = args->filters;
int nfilters = args->nfilters;
const char* default_file = args->default_file;
@@ -68,6 +75,7 @@ void windows_ShowFileDialog(void *ptr)
DWORD flags = args->flags;
SDL_DialogFileCallback callback = args->callback;
void* userdata = args->userdata;
const char *title = args->title;
/* GetOpenFileName and GetSaveFileName have the same signature
(yes, LPOPENFILENAMEW even for the save dialog) */
@@ -185,6 +193,34 @@ void windows_ShowFileDialog(void *ptr)
SDL_free(filterlist);
}
wchar_t *title_w = NULL;
if (title) {
int title_len = (int) SDL_strlen(title);
/* If the title is longer than 2GB, it might be exploitable. */
if (title_len < 0) {
title_len = 0;
}
int title_wlen = MultiByteToWideChar(CP_UTF8, 0, title, title_len, NULL, 0);
if (title_wlen < 0) {
title_wlen = 0;
}
title_w = (wchar_t *)SDL_malloc(title_wlen * sizeof(wchar_t));
if (!title_w) {
SDL_free(filter_wchar);
SDL_free(filebuffer);
callback(userdata, NULL, -1);
return;
}
MultiByteToWideChar(CP_UTF8, 0, title, title_len, title_w, title_wlen);
}
OPENFILENAMEW dialog;
dialog.lStructSize = sizeof(OPENFILENAME);
dialog.hwndOwner = window;
@@ -197,7 +233,7 @@ void windows_ShowFileDialog(void *ptr)
dialog.nMaxFile = SELECTLIST_SIZE;
dialog.lpstrFileTitle = NULL;
dialog.lpstrInitialDir = *initfolder ? initfolder : NULL;
dialog.lpstrTitle = NULL;
dialog.lpstrTitle = title_w;
dialog.Flags = flags | OFN_EXPLORER | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
dialog.nFileOffset = 0;
dialog.nFileExtension = 0;
@@ -211,6 +247,7 @@ void windows_ShowFileDialog(void *ptr)
BOOL result = pGetAnyFileName(&dialog);
SDL_free(filter_wchar);
SDL_free(title_w);
if (result) {
if (!(flags & OFN_ALLOWMULTISELECT)) {
@@ -388,25 +425,54 @@ void windows_ShowFolderDialog(void* ptr)
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) {
int title_len = (int) SDL_strlen(title);
/* If the title is longer than 2GB, it might be exploitable. */
if (title_len < 0) {
title_len = 0;
}
int title_wlen = MultiByteToWideChar(CP_UTF8, 0, title, title_len, NULL, 0);
if (title_wlen < 0) {
title_wlen = 0;
}
title_w = (wchar_t *)SDL_malloc(title_wlen * sizeof(wchar_t));
if (!title_w) {
callback(userdata, NULL, -1);
return;
}
MultiByteToWideChar(CP_UTF8, 0, title, title_len, title_w, title_wlen);
}
wchar_t buffer[MAX_PATH];
BROWSEINFOW dialog;
dialog.hwndOwner = parent;
dialog.pidlRoot = NULL;
// Windows docs say this is `LPTSTR` - apparently it's actually `LPWSTR`
dialog.pszDisplayName = buffer;
dialog.lpszTitle = NULL;
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);
@@ -426,45 +492,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, int nfilters, const char* default_location, bool allow_many)
{
winArgs *args;
SDL_Thread *thread;
if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) {
SDL_Log("%s", SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER));
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;
}
args->is_save = 0;
args->filters = filters;
args->nfilters = nfilters;
args->default_file = default_location;
args->parent = window;
args->flags = (allow_many != false) ? OFN_ALLOWMULTISELECT : 0;
args->callback = callback;
args->userdata = userdata;
thread = SDL_CreateThread(windows_file_dialog_thread, "SDL_ShowOpenFileDialog", (void *) args);
if (thread == NULL) {
callback(userdata, NULL, -1);
SDL_free(args);
return;
}
SDL_DetachThread(thread);
}
void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location)
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;
@@ -481,16 +509,19 @@ void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL
return;
}
args->is_save = 1;
args->is_save = is_save;
args->filters = filters;
args->nfilters = nfilters;
args->default_file = default_location;
args->parent = window;
args->flags = 0;
args->flags = allow_many ? OFN_ALLOWMULTISELECT : 0;
args->callback = callback;
args->userdata = userdata;
args->title = title;
args->accept = accept;
args->cancel = cancel;
thread = SDL_CreateThread(windows_file_dialog_thread, "SDL_ShowSaveFileDialog", (void *) args);
thread = SDL_CreateThread(windows_file_dialog_thread, "SDL_Windows_ShowFileDialog", (void *) args);
if (thread == NULL) {
callback(userdata, NULL, -1);
@@ -501,7 +532,7 @@ void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL
SDL_DetachThread(thread);
}
void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, bool allow_many)
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;
@@ -522,8 +553,11 @@ void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, S
args->callback = callback;
args->default_folder = default_location;
args->userdata = userdata;
args->title = title;
args->accept = accept;
args->cancel = cancel;
thread = SDL_CreateThread(windows_folder_dialog_thread, "SDL_ShowOpenFolderDialog", (void *) args);
thread = SDL_CreateThread(windows_folder_dialog_thread, "SDL_Windows_ShowFolderDialog", (void *) args);
if (thread == NULL) {
callback(userdata, NULL, -1);
@@ -533,3 +567,31 @@ void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, S
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;
};
}