|
@@ -16,6 +16,9 @@
|
|
|
#include "base/mac/mac_util.h"
|
|
|
#include "base/mac/scoped_cftyperef.h"
|
|
|
#include "base/strings/sys_string_conversions.h"
|
|
|
+#include "base/task/post_task.h"
|
|
|
+#include "content/public/browser/browser_task_traits.h"
|
|
|
+#include "content/public/browser/browser_thread.h"
|
|
|
#include "shell/browser/native_window.h"
|
|
|
#include "shell/common/gin_converters/file_path_converter.h"
|
|
|
|
|
@@ -290,6 +293,27 @@ void ReadDialogPaths(NSOpenPanel* dialog, std::vector<base::FilePath>* paths) {
|
|
|
ReadDialogPathsWithBookmarks(dialog, paths, &ignored_bookmarks);
|
|
|
}
|
|
|
|
|
|
+void ResolvePromiseInNextTick(gin_helper::Promise<v8::Local<v8::Value>> promise,
|
|
|
+ v8::Local<v8::Value> value) {
|
|
|
+ // The completionHandler runs inside a transaction commit, and we should
|
|
|
+ // not do any runModal inside it. However since we can not control what
|
|
|
+ // users will run in the microtask, we have to delay the resolution until
|
|
|
+ // next tick, otherwise crash like this may happen:
|
|
|
+ // https://github.com/electron/electron/issues/26884
|
|
|
+ base::PostTask(
|
|
|
+ FROM_HERE, {content::BrowserThread::UI},
|
|
|
+ base::BindOnce(
|
|
|
+ [](gin_helper::Promise<v8::Local<v8::Value>> promise,
|
|
|
+ v8::Global<v8::Value> global) {
|
|
|
+ v8::Isolate* isolate = promise.isolate();
|
|
|
+ v8::Locker locker(isolate);
|
|
|
+ v8::HandleScope handle_scope(isolate);
|
|
|
+ v8::Local<v8::Value> value = global.Get(isolate);
|
|
|
+ promise.Resolve(value);
|
|
|
+ },
|
|
|
+ std::move(promise), v8::Global<v8::Value>(promise.isolate(), value)));
|
|
|
+}
|
|
|
+
|
|
|
} // namespace
|
|
|
|
|
|
bool ShowOpenDialogSync(const DialogSettings& settings,
|
|
@@ -320,7 +344,6 @@ void OpenDialogCompletion(int chosen,
|
|
|
#if defined(MAS_BUILD)
|
|
|
dict.Set("bookmarks", std::vector<std::string>());
|
|
|
#endif
|
|
|
- promise.Resolve(dict);
|
|
|
} else {
|
|
|
std::vector<base::FilePath> paths;
|
|
|
dict.Set("canceled", false);
|
|
@@ -336,8 +359,9 @@ void OpenDialogCompletion(int chosen,
|
|
|
ReadDialogPaths(dialog, &paths);
|
|
|
dict.Set("filePaths", paths);
|
|
|
#endif
|
|
|
- promise.Resolve(dict);
|
|
|
}
|
|
|
+ ResolvePromiseInNextTick(promise.As<v8::Local<v8::Value>>(),
|
|
|
+ dict.GetHandle());
|
|
|
}
|
|
|
|
|
|
void ShowOpenDialog(const DialogSettings& settings,
|
|
@@ -410,7 +434,8 @@ void SaveDialogCompletion(int chosen,
|
|
|
}
|
|
|
#endif
|
|
|
}
|
|
|
- promise.Resolve(dict);
|
|
|
+ ResolvePromiseInNextTick(promise.As<v8::Local<v8::Value>>(),
|
|
|
+ dict.GetHandle());
|
|
|
}
|
|
|
|
|
|
void ShowSaveDialog(const DialogSettings& settings,
|