26
26
#ifdef SDL_USE_LIBDBUS
27
27
28
28
#include <errno.h>
29
+ #include <libgen.h>
30
+ #include <sys/stat.h>
29
31
#include <sys/types.h>
30
32
#include <sys/wait.h>
31
33
#include <unistd.h>
@@ -294,7 +296,12 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
294
296
bool allow_many = SDL_GetBooleanProperty (props , SDL_PROP_FILE_DIALOG_MANY_BOOLEAN , false);
295
297
const char * default_location = SDL_GetStringProperty (props , SDL_PROP_FILE_DIALOG_LOCATION_STRING , NULL );
296
298
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 ;
297
302
bool open_folders = false;
303
+ bool save_file_existing = false;
304
+ bool save_file_new_named = false;
298
305
299
306
switch (type ) {
300
307
case SDL_FILEDIALOG_OPENFILE :
@@ -305,6 +312,28 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
305
312
case SDL_FILEDIALOG_SAVEFILE :
306
313
method = "SaveFile" ;
307
314
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 );
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
+ }
308
337
break ;
309
338
310
339
case SDL_FILEDIALOG_OPENFOLDER :
@@ -317,7 +346,7 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
317
346
/* This is already checked in ../SDL_dialog.c; this silences compiler warnings */
318
347
SDL_SetError ("Invalid file dialog type: %d" , type );
319
348
callback (userdata , NULL , -1 );
320
- return ;
349
+ goto cleanup ;
321
350
}
322
351
323
352
SDL_DBusContext * dbus = SDL_DBus_GetContext ();
@@ -335,20 +364,20 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
335
364
if (err_msg ) {
336
365
SDL_SetError ("%s" , err_msg );
337
366
callback (userdata , NULL , -1 );
338
- return ;
367
+ goto cleanup ;
339
368
}
340
369
341
370
if (dbus == NULL ) {
342
371
SDL_SetError ("Failed to connect to DBus" );
343
372
callback (userdata , NULL , -1 );
344
- return ;
373
+ goto cleanup ;
345
374
}
346
375
347
376
msg = dbus -> message_new_method_call (PORTAL_DESTINATION , PORTAL_PATH , PORTAL_INTERFACE , method );
348
377
if (msg == NULL ) {
349
378
SDL_SetError ("Failed to send message to portal" );
350
379
callback (userdata , NULL , -1 );
351
- return ;
380
+ goto cleanup ;
352
381
}
353
382
354
383
dbus -> message_iter_init_append (msg , & params );
@@ -362,7 +391,7 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
362
391
handle_str = SDL_malloc (len * sizeof (char ));
363
392
if (!handle_str ) {
364
393
callback (userdata , NULL , -1 );
365
- return ;
394
+ goto cleanup ;
366
395
}
367
396
368
397
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
373
402
handle_str = SDL_malloc (len * sizeof (char ));
374
403
if (!handle_str ) {
375
404
callback (userdata , NULL , -1 );
376
- return ;
405
+ goto cleanup ;
377
406
}
378
407
379
408
// The portal wants X11 window ID numbers in hex.
@@ -393,7 +422,7 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
393
422
handle_str = SDL_malloc (sizeof (char ) * (HANDLE_LEN + 1 ));
394
423
if (!handle_str ) {
395
424
callback (userdata , NULL , -1 );
396
- return ;
425
+ goto cleanup ;
397
426
}
398
427
SDL_snprintf (handle_str , HANDLE_LEN , "%u" , ++ handle_id );
399
428
DBus_AppendStringOption (dbus , & options , "handle_token" , handle_str );
@@ -410,7 +439,20 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
410
439
DBus_AppendFilters (dbus , & options , filters , nfilters );
411
440
}
412
441
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
+ }
414
456
}
415
457
if (accept ) {
416
458
DBus_AppendStringOption (dbus , & options , "accept_label" , accept );
@@ -469,6 +511,10 @@ void SDL_Portal_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_Dialog
469
511
470
512
incorrect_type :
471
513
dbus -> message_unref (reply );
514
+
515
+ cleanup :
516
+ SDL_free (location_name );
517
+ SDL_free (location_folder );
472
518
}
473
519
474
520
bool SDL_Portal_detect (void )
0 commit comments