2626#ifdef SDL_USE_LIBDBUS
2727
2828#include <errno.h>
29+ #include <libgen.h>
30+ #include <sys/stat.h>
2931#include <sys/types.h>
3032#include <sys/wait.h>
3133#include <unistd.h>
@@ -294,7 +296,12 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
294296 bool allow_many = SDL_GetBooleanProperty (props , SDL_PROP_FILE_DIALOG_MANY_BOOLEAN , false);
295297 const char * default_location = SDL_GetStringProperty (props , SDL_PROP_FILE_DIALOG_LOCATION_STRING , NULL );
296298 const char * accept = SDL_GetStringProperty (props , SDL_PROP_FILE_DIALOG_ACCEPT_STRING , NULL );
299+ char * location_name = NULL ;
300+ char * location_folder = NULL ;
301+ struct stat statbuf ;
297302 bool open_folders = false;
303+ bool save_file_existing = false;
304+ bool save_file_new_named = false;
298305
299306 switch (type ) {
300307 case SDL_FILEDIALOG_OPENFILE :
@@ -305,6 +312,28 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
305312 case SDL_FILEDIALOG_SAVEFILE :
306313 method = "SaveFile" ;
307314 method_title = SDL_GetStringProperty (props , SDL_PROP_FILE_DIALOG_TITLE_STRING , "Save File" );
315+ if (default_location ) {
316+ if (stat (default_location , & statbuf ) == 0 ) {
317+ save_file_existing = S_ISREG (statbuf .st_mode ) || S_ISLNK (statbuf .st_mode );
318+ } else if (errno == ENOENT ) {
319+ char * dirc = SDL_strdup (default_location );
320+ if (dirc ) {
321+ location_folder = SDL_strdup (dirname (dirc ));
322+ SDL_free (dirc );
323+ if (location_folder ) {
324+ save_file_new_named = (stat (location_folder , & statbuf ) == 0 ) && S_ISDIR (statbuf .st_mode );
325+ }
326+ }
327+ }
328+
329+ if (save_file_existing || save_file_new_named ) {
330+ char * basec = SDL_strdup (default_location );
331+ if (basec ) {
332+ location_name = SDL_strdup (basename (basec ));
333+ SDL_free (basec );
334+ }
335+ }
336+ }
308337 break ;
309338
310339 case SDL_FILEDIALOG_OPENFOLDER :
@@ -317,7 +346,7 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
317346 /* This is already checked in ../SDL_dialog.c; this silences compiler warnings */
318347 SDL_SetError ("Invalid file dialog type: %d" , type );
319348 callback (userdata , NULL , -1 );
320- return ;
349+ goto cleanup ;
321350 }
322351
323352 SDL_DBusContext * dbus = SDL_DBus_GetContext ();
@@ -335,20 +364,20 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
335364 if (err_msg ) {
336365 SDL_SetError ("%s" , err_msg );
337366 callback (userdata , NULL , -1 );
338- return ;
367+ goto cleanup ;
339368 }
340369
341370 if (dbus == NULL ) {
342371 SDL_SetError ("Failed to connect to DBus" );
343372 callback (userdata , NULL , -1 );
344- return ;
373+ goto cleanup ;
345374 }
346375
347376 msg = dbus -> message_new_method_call (PORTAL_DESTINATION , PORTAL_PATH , PORTAL_INTERFACE , method );
348377 if (msg == NULL ) {
349378 SDL_SetError ("Failed to send message to portal" );
350379 callback (userdata , NULL , -1 );
351- return ;
380+ goto cleanup ;
352381 }
353382
354383 dbus -> message_iter_init_append (msg , & params );
@@ -362,7 +391,7 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
362391 handle_str = SDL_malloc (len * sizeof (char ));
363392 if (!handle_str ) {
364393 callback (userdata , NULL , -1 );
365- return ;
394+ goto cleanup ;
366395 }
367396
368397 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
373402 handle_str = SDL_malloc (len * sizeof (char ));
374403 if (!handle_str ) {
375404 callback (userdata , NULL , -1 );
376- return ;
405+ goto cleanup ;
377406 }
378407
379408 // The portal wants X11 window ID numbers in hex.
@@ -393,7 +422,7 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
393422 handle_str = SDL_malloc (sizeof (char ) * (HANDLE_LEN + 1 ));
394423 if (!handle_str ) {
395424 callback (userdata , NULL , -1 );
396- return ;
425+ goto cleanup ;
397426 }
398427 SDL_snprintf (handle_str , HANDLE_LEN , "%u" , ++ handle_id );
399428 DBus_AppendStringOption (dbus , & options , "handle_token" , handle_str );
@@ -410,7 +439,20 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
410439 DBus_AppendFilters (dbus , & options , filters , nfilters );
411440 }
412441 if (default_location ) {
413- DBus_AppendByteArray (dbus , & options , "current_folder" , default_location );
442+ if (save_file_existing && location_name ) {
443+ /* Open a save dialog at an existing file */
444+ DBus_AppendByteArray (dbus , & options , "current_file" , default_location );
445+ /* Setting "current_name" should not be necessary however the kde-desktop-portal sets the filename without an extension.
446+ * An alternative would be to match the extension to a filter and set "current_filter".
447+ */
448+ DBus_AppendStringOption (dbus , & options , "current_name" , location_name );
449+ } else if (save_file_new_named && location_folder && location_name ) {
450+ /* Open a save dialog at a location with a suggested name */
451+ DBus_AppendByteArray (dbus , & options , "current_folder" , location_folder );
452+ DBus_AppendStringOption (dbus , & options , "current_name" , location_name );
453+ } else {
454+ DBus_AppendByteArray (dbus , & options , "current_folder" , default_location );
455+ }
414456 }
415457 if (accept ) {
416458 DBus_AppendStringOption (dbus , & options , "accept_label" , accept );
@@ -469,6 +511,10 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
469511
470512incorrect_type :
471513 dbus -> message_unref (reply );
514+
515+ cleanup :
516+ SDL_free (location_name );
517+ SDL_free (location_folder );
472518}
473519
474520bool SDL_Portal_detect (void )
0 commit comments