1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

Improve native file dialog parent window selection.

This commit is contained in:
bruvzg
2024-09-30 12:19:48 +03:00
committed by Pāvels Nadtočajevs
parent 134da37497
commit 3e4e6e6c0c
18 changed files with 322 additions and 233 deletions

View File

@@ -979,21 +979,25 @@ Error DisplayServerMacOS::dialog_show(String p_title, String p_description, Vect
return OK;
}
Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
return _file_dialog_with_options_show(p_title, p_current_directory, String(), p_filename, p_show_hidden, p_mode, p_filters, TypedArray<Dictionary>(), p_callback, false);
Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback, WindowID p_window_id) {
return _file_dialog_with_options_show(p_title, p_current_directory, String(), p_filename, p_show_hidden, p_mode, p_filters, TypedArray<Dictionary>(), p_callback, false, p_window_id);
}
Error DisplayServerMacOS::file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) {
return _file_dialog_with_options_show(p_title, p_current_directory, p_root, p_filename, p_show_hidden, p_mode, p_filters, p_options, p_callback, true);
Error DisplayServerMacOS::file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, WindowID p_window_id) {
return _file_dialog_with_options_show(p_title, p_current_directory, p_root, p_filename, p_show_hidden, p_mode, p_filters, p_options, p_callback, true, p_window_id);
}
Error DisplayServerMacOS::_file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb) {
Error DisplayServerMacOS::_file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb, WindowID p_window_id) {
_THREAD_SAFE_METHOD_
ERR_FAIL_INDEX_V(int(p_mode), FILE_DIALOG_MODE_SAVE_MAX, FAILED);
NSString *url = [NSString stringWithUTF8String:p_current_directory.utf8().get_data()];
WindowID prev_focus = last_focused_window;
NSWindow *nswindow = nullptr;
if (windows.has(p_window_id) && !windows[p_window_id].is_popup) {
nswindow = windows[p_window_id].window_object;
}
GodotOpenSaveDelegate *panel_delegate = [[GodotOpenSaveDelegate alloc] init];
if (p_root.length() > 0) {
@@ -1015,98 +1019,102 @@ Error DisplayServerMacOS::_file_dialog_with_options_show(const String &p_title,
[panel setNameFieldStringValue:fileurl];
}
[panel beginSheetModalForWindow:[[NSApplication sharedApplication] mainWindow]
completionHandler:^(NSInteger ret) {
if (ret == NSModalResponseOK) {
// Save bookmark for folder.
if (OS::get_singleton()->is_sandboxed()) {
NSArray *bookmarks = [[NSUserDefaults standardUserDefaults] arrayForKey:@"sec_bookmarks"];
bool skip = false;
for (id bookmark in bookmarks) {
NSError *error = nil;
BOOL isStale = NO;
NSURL *exurl = [NSURL URLByResolvingBookmarkData:bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&error];
if (!error && !isStale && ([[exurl path] compare:[[panel directoryURL] path]] == NSOrderedSame)) {
skip = true;
break;
}
}
if (!skip) {
NSError *error = nil;
NSData *bookmark = [[panel directoryURL] bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:&error];
if (!error) {
NSArray *new_bookmarks = [bookmarks arrayByAddingObject:bookmark];
[[NSUserDefaults standardUserDefaults] setObject:new_bookmarks forKey:@"sec_bookmarks"];
}
}
}
// Callback.
Vector<String> files;
String url;
url.parse_utf8([[[panel URL] path] UTF8String]);
files.push_back(url);
if (callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = true;
Variant v_files = files;
Variant v_index = [panel_delegate getIndex];
Variant v_opt = [panel_delegate getSelection];
Variant ret;
Callable::CallError ce;
const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
void (^completion_handler)(NSInteger ret) = ^(NSInteger ret) {
if (ret == NSModalResponseOK) {
// Save bookmark for folder.
if (OS::get_singleton()->is_sandboxed()) {
NSArray *bookmarks = [[NSUserDefaults standardUserDefaults] arrayForKey:@"sec_bookmarks"];
bool skip = false;
for (id bookmark in bookmarks) {
NSError *error = nil;
BOOL isStale = NO;
NSURL *exurl = [NSURL URLByResolvingBookmarkData:bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&error];
if (!error && !isStale && ([[exurl path] compare:[[panel directoryURL] path]] == NSOrderedSame)) {
skip = true;
break;
}
}
if (!skip) {
NSError *error = nil;
NSData *bookmark = [[panel directoryURL] bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:&error];
if (!error) {
NSArray *new_bookmarks = [bookmarks arrayByAddingObject:bookmark];
[[NSUserDefaults standardUserDefaults] setObject:new_bookmarks forKey:@"sec_bookmarks"];
}
}
}
// Callback.
Vector<String> files;
String url;
url.parse_utf8([[[panel URL] path] UTF8String]);
files.push_back(url);
if (callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = true;
Variant v_files = files;
Variant v_index = [panel_delegate getIndex];
Variant v_opt = [panel_delegate getSelection];
Variant ret;
Callable::CallError ce;
const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
callback.callp(args, 4, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 4, ce)));
}
} else {
Variant v_result = true;
Variant v_files = files;
Variant v_index = [panel_delegate getIndex];
Variant ret;
Callable::CallError ce;
const Variant *args[3] = { &v_result, &v_files, &v_index };
callback.callp(args, 4, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 4, ce)));
}
} else {
Variant v_result = true;
Variant v_files = files;
Variant v_index = [panel_delegate getIndex];
Variant ret;
Callable::CallError ce;
const Variant *args[3] = { &v_result, &v_files, &v_index };
callback.callp(args, 3, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
}
}
}
} else {
if (callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = false;
Variant v_files = Vector<String>();
Variant v_index = [panel_delegate getIndex];
Variant v_opt = [panel_delegate getSelection];
Variant ret;
Callable::CallError ce;
const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
callback.callp(args, 3, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
}
}
}
} else {
if (callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = false;
Variant v_files = Vector<String>();
Variant v_index = [panel_delegate getIndex];
Variant v_opt = [panel_delegate getSelection];
Variant ret;
Callable::CallError ce;
const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
callback.callp(args, 4, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 4, ce)));
}
} else {
Variant v_result = false;
Variant v_files = Vector<String>();
Variant v_index = [panel_delegate getIndex];
Variant ret;
Callable::CallError ce;
const Variant *args[3] = { &v_result, &v_files, &v_index };
callback.callp(args, 4, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 4, ce)));
}
} else {
Variant v_result = false;
Variant v_files = Vector<String>();
Variant v_index = [panel_delegate getIndex];
Variant ret;
Callable::CallError ce;
const Variant *args[3] = { &v_result, &v_files, &v_index };
callback.callp(args, 3, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
}
}
}
}
if (prev_focus != INVALID_WINDOW_ID) {
callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(prev_focus);
}
}];
callback.callp(args, 3, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
}
}
}
}
if (p_window_id != INVALID_WINDOW_ID) {
callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(p_window_id);
}
};
if (nswindow) {
[panel beginSheetModalForWindow:nswindow completionHandler:completion_handler];
} else {
[panel beginWithCompletionHandler:completion_handler];
}
} else {
NSOpenPanel *panel = [NSOpenPanel openPanel];
@@ -1125,104 +1133,108 @@ Error DisplayServerMacOS::_file_dialog_with_options_show(const String &p_title,
}
[panel setAllowsMultipleSelection:(p_mode == FILE_DIALOG_MODE_OPEN_FILES)];
[panel beginSheetModalForWindow:[[NSApplication sharedApplication] mainWindow]
completionHandler:^(NSInteger ret) {
if (ret == NSModalResponseOK) {
// Save bookmark for folder.
NSArray *urls = [(NSOpenPanel *)panel URLs];
if (OS::get_singleton()->is_sandboxed()) {
NSArray *bookmarks = [[NSUserDefaults standardUserDefaults] arrayForKey:@"sec_bookmarks"];
NSMutableArray *new_bookmarks = [bookmarks mutableCopy];
for (NSUInteger i = 0; i != [urls count]; ++i) {
bool skip = false;
for (id bookmark in bookmarks) {
NSError *error = nil;
BOOL isStale = NO;
NSURL *exurl = [NSURL URLByResolvingBookmarkData:bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&error];
if (!error && !isStale && ([[exurl path] compare:[[urls objectAtIndex:i] path]] == NSOrderedSame)) {
skip = true;
break;
}
}
if (!skip) {
NSError *error = nil;
NSData *bookmark = [[urls objectAtIndex:i] bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:&error];
if (!error) {
[new_bookmarks addObject:bookmark];
}
}
}
[[NSUserDefaults standardUserDefaults] setObject:new_bookmarks forKey:@"sec_bookmarks"];
}
// Callback.
Vector<String> files;
for (NSUInteger i = 0; i != [urls count]; ++i) {
String url;
url.parse_utf8([[[urls objectAtIndex:i] path] UTF8String]);
files.push_back(url);
}
if (callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = true;
Variant v_files = files;
Variant v_index = [panel_delegate getIndex];
Variant v_opt = [panel_delegate getSelection];
Variant ret;
Callable::CallError ce;
const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
void (^completion_handler)(NSInteger ret) = ^(NSInteger ret) {
if (ret == NSModalResponseOK) {
// Save bookmark for folder.
NSArray *urls = [(NSOpenPanel *)panel URLs];
if (OS::get_singleton()->is_sandboxed()) {
NSArray *bookmarks = [[NSUserDefaults standardUserDefaults] arrayForKey:@"sec_bookmarks"];
NSMutableArray *new_bookmarks = [bookmarks mutableCopy];
for (NSUInteger i = 0; i != [urls count]; ++i) {
bool skip = false;
for (id bookmark in bookmarks) {
NSError *error = nil;
BOOL isStale = NO;
NSURL *exurl = [NSURL URLByResolvingBookmarkData:bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&error];
if (!error && !isStale && ([[exurl path] compare:[[urls objectAtIndex:i] path]] == NSOrderedSame)) {
skip = true;
break;
}
}
if (!skip) {
NSError *error = nil;
NSData *bookmark = [[urls objectAtIndex:i] bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:&error];
if (!error) {
[new_bookmarks addObject:bookmark];
}
}
}
[[NSUserDefaults standardUserDefaults] setObject:new_bookmarks forKey:@"sec_bookmarks"];
}
// Callback.
Vector<String> files;
for (NSUInteger i = 0; i != [urls count]; ++i) {
String url;
url.parse_utf8([[[urls objectAtIndex:i] path] UTF8String]);
files.push_back(url);
}
if (callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = true;
Variant v_files = files;
Variant v_index = [panel_delegate getIndex];
Variant v_opt = [panel_delegate getSelection];
Variant ret;
Callable::CallError ce;
const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
callback.callp(args, 4, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 4, ce)));
}
} else {
Variant v_result = true;
Variant v_files = files;
Variant v_index = [panel_delegate getIndex];
Variant ret;
Callable::CallError ce;
const Variant *args[3] = { &v_result, &v_files, &v_index };
callback.callp(args, 4, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 4, ce)));
}
} else {
Variant v_result = true;
Variant v_files = files;
Variant v_index = [panel_delegate getIndex];
Variant ret;
Callable::CallError ce;
const Variant *args[3] = { &v_result, &v_files, &v_index };
callback.callp(args, 3, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
}
}
}
} else {
if (callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = false;
Variant v_files = Vector<String>();
Variant v_index = [panel_delegate getIndex];
Variant v_opt = [panel_delegate getSelection];
Variant ret;
Callable::CallError ce;
const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
callback.callp(args, 3, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
}
}
}
} else {
if (callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = false;
Variant v_files = Vector<String>();
Variant v_index = [panel_delegate getIndex];
Variant v_opt = [panel_delegate getSelection];
Variant ret;
Callable::CallError ce;
const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
callback.callp(args, 4, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 4, ce)));
}
} else {
Variant v_result = false;
Variant v_files = Vector<String>();
Variant v_index = [panel_delegate getIndex];
Variant ret;
Callable::CallError ce;
const Variant *args[3] = { &v_result, &v_files, &v_index };
callback.callp(args, 4, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 4, ce)));
}
} else {
Variant v_result = false;
Variant v_files = Vector<String>();
Variant v_index = [panel_delegate getIndex];
Variant ret;
Callable::CallError ce;
const Variant *args[3] = { &v_result, &v_files, &v_index };
callback.callp(args, 3, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
}
}
}
}
if (prev_focus != INVALID_WINDOW_ID) {
callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(prev_focus);
}
}];
callback.callp(args, 3, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
}
}
}
}
if (p_window_id != INVALID_WINDOW_ID) {
callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(p_window_id);
}
};
if (nswindow) {
[panel beginSheetModalForWindow:nswindow completionHandler:completion_handler];
} else {
[panel beginWithCompletionHandler:completion_handler];
}
}
return OK;