mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-05-31 14:29:14 +08:00
dialog: Fix save file chooser with xdg portal
This correctly sets the xdg portal fields for targeting a specific new filename or existing file. "current_name" sets the dialogs placeholder name. "current_file" targets an existing file. "current_folder" for when the target is a folder.
This commit is contained in:
committed by
Sam Lantinga
parent
1af7dfb0a7
commit
c79a18d0fa
@@ -26,6 +26,8 @@
|
|||||||
#ifdef SDL_USE_LIBDBUS
|
#ifdef SDL_USE_LIBDBUS
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -294,7 +296,12 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
|
|||||||
bool allow_many = SDL_GetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, false);
|
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 *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);
|
const char *accept = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_ACCEPT_STRING, NULL);
|
||||||
|
char *location_name = NULL;
|
||||||
|
char *location_folder = NULL;
|
||||||
|
struct stat statbuf;
|
||||||
bool open_folders = false;
|
bool open_folders = false;
|
||||||
|
bool save_file_existing = false;
|
||||||
|
bool save_file_new_named = false;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SDL_FILEDIALOG_OPENFILE:
|
case SDL_FILEDIALOG_OPENFILE:
|
||||||
@@ -305,6 +312,28 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
|
|||||||
case SDL_FILEDIALOG_SAVEFILE:
|
case SDL_FILEDIALOG_SAVEFILE:
|
||||||
method = "SaveFile";
|
method = "SaveFile";
|
||||||
method_title = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_TITLE_STRING, "Save File");
|
method_title = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_TITLE_STRING, "Save File");
|
||||||
|
if (default_location) {
|
||||||
|
if (stat(default_location, &statbuf) == 0) {
|
||||||
|
save_file_existing = S_ISREG(statbuf.st_mode);
|
||||||
|
} else if (errno == ENOENT) {
|
||||||
|
char *dirc = SDL_strdup(default_location);
|
||||||
|
if (dirc) {
|
||||||
|
location_folder = SDL_strdup(dirname(dirc));
|
||||||
|
SDL_free(dirc);
|
||||||
|
if (location_folder) {
|
||||||
|
save_file_new_named = (stat(location_folder, &statbuf) == 0) && S_ISDIR(statbuf.st_mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (save_file_existing || save_file_new_named) {
|
||||||
|
char *basec = SDL_strdup(default_location);
|
||||||
|
if (basec) {
|
||||||
|
location_name = SDL_strdup(basename(basec));
|
||||||
|
SDL_free(basec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_FILEDIALOG_OPENFOLDER:
|
case SDL_FILEDIALOG_OPENFOLDER:
|
||||||
@@ -317,7 +346,7 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
|
|||||||
/* This is already checked in ../SDL_dialog.c; this silences compiler warnings */
|
/* This is already checked in ../SDL_dialog.c; this silences compiler warnings */
|
||||||
SDL_SetError("Invalid file dialog type: %d", type);
|
SDL_SetError("Invalid file dialog type: %d", type);
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
return;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||||
@@ -335,20 +364,20 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
|
|||||||
if (err_msg) {
|
if (err_msg) {
|
||||||
SDL_SetError("%s", err_msg);
|
SDL_SetError("%s", err_msg);
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
return;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dbus == NULL) {
|
if (dbus == NULL) {
|
||||||
SDL_SetError("Failed to connect to DBus");
|
SDL_SetError("Failed to connect to DBus");
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
return;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = dbus->message_new_method_call(PORTAL_DESTINATION, PORTAL_PATH, PORTAL_INTERFACE, method);
|
msg = dbus->message_new_method_call(PORTAL_DESTINATION, PORTAL_PATH, PORTAL_INTERFACE, method);
|
||||||
if (msg == NULL) {
|
if (msg == NULL) {
|
||||||
SDL_SetError("Failed to send message to portal");
|
SDL_SetError("Failed to send message to portal");
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
return;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbus->message_iter_init_append(msg, ¶ms);
|
dbus->message_iter_init_append(msg, ¶ms);
|
||||||
@@ -362,7 +391,7 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
|
|||||||
handle_str = SDL_malloc(len * sizeof(char));
|
handle_str = SDL_malloc(len * sizeof(char));
|
||||||
if (!handle_str) {
|
if (!handle_str) {
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
return;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_snprintf(handle_str, len, "%s%s", WAYLAND_HANDLE_PREFIX, parent_handle);
|
SDL_snprintf(handle_str, len, "%s%s", WAYLAND_HANDLE_PREFIX, parent_handle);
|
||||||
@@ -373,7 +402,7 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
|
|||||||
handle_str = SDL_malloc(len * sizeof(char));
|
handle_str = SDL_malloc(len * sizeof(char));
|
||||||
if (!handle_str) {
|
if (!handle_str) {
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
return;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The portal wants X11 window ID numbers in hex.
|
// The portal wants X11 window ID numbers in hex.
|
||||||
@@ -393,7 +422,7 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
|
|||||||
handle_str = SDL_malloc(sizeof(char) * (HANDLE_LEN + 1));
|
handle_str = SDL_malloc(sizeof(char) * (HANDLE_LEN + 1));
|
||||||
if (!handle_str) {
|
if (!handle_str) {
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
return;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
SDL_snprintf(handle_str, HANDLE_LEN, "%u", ++handle_id);
|
SDL_snprintf(handle_str, HANDLE_LEN, "%u", ++handle_id);
|
||||||
DBus_AppendStringOption(dbus, &options, "handle_token", handle_str);
|
DBus_AppendStringOption(dbus, &options, "handle_token", handle_str);
|
||||||
@@ -410,7 +439,20 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
|
|||||||
DBus_AppendFilters(dbus, &options, filters, nfilters);
|
DBus_AppendFilters(dbus, &options, filters, nfilters);
|
||||||
}
|
}
|
||||||
if (default_location) {
|
if (default_location) {
|
||||||
DBus_AppendByteArray(dbus, &options, "current_folder", default_location);
|
if (save_file_existing && location_name) {
|
||||||
|
/* Open a save dialog at an existing file */
|
||||||
|
DBus_AppendByteArray(dbus, &options, "current_file", default_location);
|
||||||
|
/* Setting "current_name" should not be necessary however the kde-desktop-portal sets the filename without an extension.
|
||||||
|
* An alternative would be to match the extension to a filter and set "current_filter".
|
||||||
|
*/
|
||||||
|
DBus_AppendStringOption(dbus, &options, "current_name", location_name);
|
||||||
|
} else if (save_file_new_named && location_folder && location_name) {
|
||||||
|
/* Open a save dialog at a location with a suggested name */
|
||||||
|
DBus_AppendByteArray(dbus, &options, "current_folder", location_folder);
|
||||||
|
DBus_AppendStringOption(dbus, &options, "current_name", location_name);
|
||||||
|
} else {
|
||||||
|
DBus_AppendByteArray(dbus, &options, "current_folder", default_location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (accept) {
|
if (accept) {
|
||||||
DBus_AppendStringOption(dbus, &options, "accept_label", accept);
|
DBus_AppendStringOption(dbus, &options, "accept_label", accept);
|
||||||
@@ -469,6 +511,10 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
|
|||||||
|
|
||||||
incorrect_type:
|
incorrect_type:
|
||||||
dbus->message_unref(reply);
|
dbus->message_unref(reply);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
SDL_free(location_name);
|
||||||
|
SDL_free(location_folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDL_Portal_detect(void)
|
bool SDL_Portal_detect(void)
|
||||||
|
|||||||
+38
-1
@@ -12,6 +12,7 @@
|
|||||||
/* Sample program: Create open and save dialogs. */
|
/* Sample program: Create open and save dialogs. */
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3/SDL_iostream.h>
|
||||||
#include <SDL3/SDL_main.h>
|
#include <SDL3/SDL_main.h>
|
||||||
#include <SDL3/SDL_test.h>
|
#include <SDL3/SDL_test.h>
|
||||||
|
|
||||||
@@ -23,6 +24,8 @@ const SDL_DialogFileFilter filters[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void SDLCALL callback(void *userdata, const char * const *files, int filter) {
|
static void SDLCALL callback(void *userdata, const char * const *files, int filter) {
|
||||||
|
char **saved_path = userdata;
|
||||||
|
|
||||||
if (files) {
|
if (files) {
|
||||||
const char* filter_name = "(filter fetching unsupported)";
|
const char* filter_name = "(filter fetching unsupported)";
|
||||||
|
|
||||||
@@ -36,6 +39,13 @@ static void SDLCALL callback(void *userdata, const char * const *files, int filt
|
|||||||
|
|
||||||
SDL_Log("Filter used: '%s'", filter_name);
|
SDL_Log("Filter used: '%s'", filter_name);
|
||||||
|
|
||||||
|
if (*files && saved_path) {
|
||||||
|
*saved_path = SDL_strdup(*files);
|
||||||
|
/* Create the file */
|
||||||
|
SDL_IOStream *stream = SDL_IOFromFile(*saved_path, "w");
|
||||||
|
SDL_CloseIO(stream);
|
||||||
|
}
|
||||||
|
|
||||||
while (*files) {
|
while (*files) {
|
||||||
SDL_Log("'%s'", *files);
|
SDL_Log("'%s'", *files);
|
||||||
files++;
|
files++;
|
||||||
@@ -45,6 +55,23 @@ static void SDLCALL callback(void *userdata, const char * const *files, int filt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *concat_strings(const char *a, const char *b)
|
||||||
|
{
|
||||||
|
char *out = NULL;
|
||||||
|
|
||||||
|
if (a != NULL && b != NULL) {
|
||||||
|
const size_t out_size = SDL_strlen(a) + SDL_strlen(b) + 1;
|
||||||
|
out = (char *)SDL_malloc(out_size);
|
||||||
|
if (out) {
|
||||||
|
*out = '\0';
|
||||||
|
SDL_strlcat(out, a, out_size);
|
||||||
|
SDL_strlcat(out, b, out_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
SDL_Window *w;
|
SDL_Window *w;
|
||||||
@@ -54,7 +81,9 @@ int main(int argc, char *argv[])
|
|||||||
const SDL_FRect save_file_rect = { 50, 290, 220, 140 };
|
const SDL_FRect save_file_rect = { 50, 290, 220, 140 };
|
||||||
const SDL_FRect open_folder_rect = { 370, 50, 220, 140 };
|
const SDL_FRect open_folder_rect = { 370, 50, 220, 140 };
|
||||||
int i;
|
int i;
|
||||||
|
const char *default_filename = "Untitled.index";
|
||||||
const char *initial_path = NULL;
|
const char *initial_path = NULL;
|
||||||
|
char *last_saved_path = NULL;
|
||||||
|
|
||||||
/* Initialize test framework */
|
/* Initialize test framework */
|
||||||
state = SDLTest_CommonCreateState(argv, 0);
|
state = SDLTest_CommonCreateState(argv, 0);
|
||||||
@@ -116,7 +145,14 @@ int main(int argc, char *argv[])
|
|||||||
} else if (SDL_PointInRectFloat(&p, &open_folder_rect)) {
|
} else if (SDL_PointInRectFloat(&p, &open_folder_rect)) {
|
||||||
SDL_ShowOpenFolderDialog(callback, NULL, w, initial_path, 1);
|
SDL_ShowOpenFolderDialog(callback, NULL, w, initial_path, 1);
|
||||||
} else if (SDL_PointInRectFloat(&p, &save_file_rect)) {
|
} else if (SDL_PointInRectFloat(&p, &save_file_rect)) {
|
||||||
SDL_ShowSaveFileDialog(callback, NULL, w, filters, SDL_arraysize(filters), initial_path);
|
char *save_path = NULL;
|
||||||
|
if (last_saved_path) {
|
||||||
|
save_path = SDL_strdup(last_saved_path);
|
||||||
|
} else {
|
||||||
|
save_path = concat_strings(initial_path, default_filename);
|
||||||
|
}
|
||||||
|
SDL_ShowSaveFileDialog(callback, &last_saved_path, w, filters, SDL_arraysize(filters), save_path ? save_path : default_filename);
|
||||||
|
SDL_free(save_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,6 +181,7 @@ int main(int argc, char *argv[])
|
|||||||
SDL_RenderPresent(r);
|
SDL_RenderPresent(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_free(last_saved_path);
|
||||||
SDLTest_CleanupTextDrawing();
|
SDLTest_CleanupTextDrawing();
|
||||||
SDL_DestroyRenderer(r);
|
SDL_DestroyRenderer(r);
|
||||||
SDL_DestroyWindow(w);
|
SDL_DestroyWindow(w);
|
||||||
|
|||||||
Reference in New Issue
Block a user