Compare commits

..

1 Commits

Author SHA1 Message Date
Shelley Vohr
5c4bc268d0 fix: use Downloads folder as default path for file dialogs
Co-authored-by: Sourav Bera <sbera987654321@gmail.com>
2026-02-25 14:13:20 +01:00
12 changed files with 87 additions and 36 deletions

View File

@@ -21,7 +21,10 @@ The `dialog` module has the following methods:
* `window` [BaseWindow](base-window.md) (optional)
* `options` Object
* `title` string (optional)
* `defaultPath` string (optional)
* `defaultPath` string (optional) - Absolute directory path, absolute file
path, or file name to use by default. If not provided, the dialog will
default to the user's Downloads folder, or their home directory if Downloads
doesn't exist.
* `buttonLabel` string (optional) - Custom label for the confirmation button, when
left empty the default label will be used.
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
@@ -93,7 +96,10 @@ dialog.showOpenDialogSync(mainWindow, {
* `window` [BaseWindow](base-window.md) (optional)
* `options` Object
* `title` string (optional)
* `defaultPath` string (optional)
* `defaultPath` string (optional) - Absolute directory path, absolute file
path, or file name to use by default. If not provided, the dialog will
default to the user's Downloads folder, or their home directory if Downloads
doesn't exist.
* `buttonLabel` string (optional) - Custom label for the confirmation button, when
left empty the default label will be used.
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
@@ -175,7 +181,9 @@ dialog.showOpenDialog(mainWindow, {
* `options` Object
* `title` string (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments.
* `defaultPath` string (optional) - Absolute directory path, absolute file
path, or file name to use by default.
path, or file name to use by default. If not provided, the dialog will
default to the user's Downloads folder, or their home directory if Downloads
doesn't exist.
* `buttonLabel` string (optional) - Custom label for the confirmation button, when
left empty the default label will be used.
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
@@ -206,7 +214,9 @@ The `filters` specifies an array of file types that can be displayed, see
* `options` Object
* `title` string (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments.
* `defaultPath` string (optional) - Absolute directory path, absolute file
path, or file name to use by default.
path, or file name to use by default. If not provided, the dialog will
default to the user's Downloads folder, or their home directory if Downloads
doesn't exist.
* `buttonLabel` string (optional) - Custom label for the confirmation button, when
left empty the default label will be used.
* `filters` [FileFilter[]](structures/file-filter.md) (optional)

View File

@@ -14,6 +14,17 @@ This document uses the following convention to categorize breaking changes:
## Planned Breaking API Changes (42.0)
### Behavior Changed: Dialog methods default to Downloads directory
The `defaultPath` option for the following methods now defaults to the user's Downloads folder (or their home directory if Downloads doesn't exist) when not explicitly provided:
* `dialog.showOpenDialog`
* `dialog.showOpenDialogSync`
* `dialog.showSaveDialog`
* `dialog.showSaveDialogSync`
Previously, these methods used the last-opened directory or an OS-determined default. To preserve the old behavior, explicitly pass `defaultPath` when calling these methods.
### Behavior Changed: Offscreen rendering will use `1.0` as default device scale factor.
Previously, OSR used the primary display's device scale factor for rendering, which made the output frame size vary across users.

View File

@@ -124,7 +124,7 @@ async function main () {
// Get the merge base with the target branch
let mergeBase;
try {
mergeBase = execSync(`git merge-base HEAD origin/${targetBranch}`, {
mergeBase = execSync(`git merge-base ${currentBranch} origin/${targetBranch}`, {
cwd: ELECTRON_DIR,
encoding: 'utf8'
}).trim();

View File

@@ -368,9 +368,6 @@ def upload_io_to_github(release, filename, filepath, version):
for c in iter(lambda: upload_process.stdout.read(1), b""):
sys.stdout.buffer.write(c)
sys.stdout.flush()
upload_process.wait()
if upload_process.returncode != 0:
sys.exit(upload_process.returncode)
if "GITHUB_OUTPUT" in os.environ:
output_path = os.environ["GITHUB_OUTPUT"]

View File

@@ -9,7 +9,6 @@
#include "base/environment.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "content/public/browser/browser_task_traits.h"
@@ -280,8 +279,7 @@ void OnDeploymentCompleted(std::unique_ptr<DeploymentCallbackData> data,
HRESULT error_code;
hr = async_info->get_ErrorCode(&error_code);
if (SUCCEEDED(hr)) {
error +=
" (" + base::NumberToString(static_cast<int>(error_code)) + ")";
error += " (" + std::to_string(static_cast<int>(error_code)) + ")";
}
}
}
@@ -800,10 +798,10 @@ v8::Local<v8::Value> GetPackageInfo() {
ABI::Windows::ApplicationModel::PackageVersion pkg_version;
hr = package_id->get_Version(&pkg_version);
if (SUCCEEDED(hr)) {
std::string version = base::NumberToString(pkg_version.Major) + "." +
base::NumberToString(pkg_version.Minor) + "." +
base::NumberToString(pkg_version.Build) + "." +
base::NumberToString(pkg_version.Revision);
std::string version = std::to_string(pkg_version.Major) + "." +
std::to_string(pkg_version.Minor) + "." +
std::to_string(pkg_version.Build) + "." +
std::to_string(pkg_version.Revision);
result.Set("version", version);
}
}

View File

@@ -23,7 +23,6 @@
#include "base/json/json_reader.h"
#include "base/no_destructor.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/current_thread.h"
#include "base/threading/scoped_blocking_call.h"
@@ -2660,7 +2659,7 @@ void WebContents::RestoreHistory(
thrower.ThrowError(
"Failed to restore navigation history: Invalid navigation entry at "
"index " +
base::NumberToString(index) + ".");
std::to_string(index) + ".");
return;
}

View File

@@ -13,6 +13,7 @@
#include "shell/browser/javascript_environment.h"
#include "shell/browser/native_window_views.h"
#include "shell/browser/ui/file_dialog.h"
#include "shell/common/electron_paths.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "shell/common/gin_helper/dictionary.h"
@@ -81,14 +82,18 @@ class FileChooserDialog : public ui::SelectFileDialog::Listener {
ui::SelectFileDialog::FileTypeInfo file_info =
GetFilterInfo(settings.filters);
ApplySettings(settings);
dialog_->SelectFile(
ui::SelectFileDialog::SELECT_SAVEAS_FILE,
base::UTF8ToUTF16(settings.title), settings.default_path,
&file_info /* file_types */, 0 /* file_type_index */,
base::FilePath::StringType() /* default_extension */,
settings.parent_window ? settings.parent_window->GetNativeWindow()
: nullptr,
nullptr);
base::FilePath default_path = settings.default_path.empty()
? electron::GetDefaultPath()
: settings.default_path;
dialog_->SelectFile(ui::SelectFileDialog::SELECT_SAVEAS_FILE,
base::UTF8ToUTF16(settings.title), default_path,
&file_info /* file_types */, 0 /* file_type_index */,
base::FilePath::StringType() /* default_extension */,
settings.parent_window
? settings.parent_window->GetNativeWindow()
: nullptr,
nullptr);
}
void RunSaveDialog(gin_helper::Promise<gin_helper::Dictionary> promise,
@@ -108,9 +113,13 @@ class FileChooserDialog : public ui::SelectFileDialog::Listener {
ui::SelectFileDialog::FileTypeInfo file_info =
GetFilterInfo(settings.filters);
ApplySettings(settings);
base::FilePath default_path = settings.default_path.empty()
? electron::GetDefaultPath()
: settings.default_path;
dialog_->SelectFile(
GetDialogType(settings.properties), base::UTF8ToUTF16(settings.title),
settings.default_path, &file_info, 0 /* file_type_index */,
default_path, &file_info, 0 /* file_type_index */,
base::FilePath::StringType() /* default_extension */,
settings.parent_window ? settings.parent_window->GetNativeWindow()
: nullptr,

View File

@@ -21,6 +21,7 @@
#include "content/public/browser/browser_thread.h"
#include "electron/mas.h"
#include "shell/browser/native_window.h"
#include "shell/common/electron_paths.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/promise.h"
@@ -186,14 +187,18 @@ void SetupDialog(NSSavePanel* dialog, const DialogSettings& settings) {
[dialog setShowsTagField:settings.shows_tag_field];
base::FilePath default_path = settings.default_path.empty()
? electron::GetDefaultPath()
: settings.default_path;
NSString* default_dir = nil;
NSString* default_filename = nil;
if (!settings.default_path.empty()) {
if (!default_path.empty()) {
electron::ScopedAllowBlockingForElectron allow_blocking;
if (base::DirectoryExists(settings.default_path)) {
default_dir = base::SysUTF8ToNSString(settings.default_path.value());
if (base::DirectoryExists(default_path)) {
default_dir = base::SysUTF8ToNSString(default_path.value());
} else {
if (settings.default_path.IsAbsolute()) {
if (default_path.IsAbsolute()) {
default_dir =
base::SysUTF8ToNSString(settings.default_path.DirName().value());
}

View File

@@ -21,6 +21,7 @@
#include "base/win/registry.h"
#include "shell/browser/native_window_views.h"
#include "shell/browser/ui/win/dialog_thread.h"
#include "shell/common/electron_paths.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/promise.h"
@@ -106,8 +107,12 @@ static HRESULT ShowFileDialog(IFileDialog* dialog,
static void ApplySettings(IFileDialog* dialog, const DialogSettings& settings) {
std::wstring file_part;
if (!IsDirectory(settings.default_path))
file_part = settings.default_path.BaseName().value();
base::FilePath default_path = settings.default_path.empty()
? electron::GetDefaultPath()
: settings.default_path;
if (!IsDirectory(default_path))
file_part = default_path.BaseName().value();
dialog->SetFileName(file_part.c_str());
@@ -149,8 +154,8 @@ static void ApplySettings(IFileDialog* dialog, const DialogSettings& settings) {
}
}
if (settings.default_path.IsAbsolute()) {
SetDefaultFolder(dialog, settings.default_path);
if (default_path.IsAbsolute()) {
SetDefaultFolder(dialog, default_path);
}
}

View File

@@ -114,4 +114,18 @@ void RegisterPathProvider() {
PATH_END);
}
base::FilePath GetDefaultPath() {
base::FilePath path;
ScopedAllowBlockingForElectron allow_blocking;
if (base::PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &path) &&
base::DirectoryExists(path))
return path;
if (base::PathService::Get(base::DIR_HOME, &path))
return path;
return base::FilePath();
}
} // namespace electron

View File

@@ -51,6 +51,10 @@ static_assert(PATH_START < PATH_END, "invalid PATH boundaries");
// Register the path provider with the base::PathService.
void RegisterPathProvider();
// Returns a default directory for file dialogs when no default path is
// provided.
base::FilePath GetDefaultPath();
} // namespace electron
#endif // ELECTRON_SHELL_COMMON_ELECTRON_PATHS_H_

View File

@@ -18,7 +18,6 @@
#include "base/environment.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
@@ -193,7 +192,7 @@ void V8OOMErrorCallback(const char* location, const v8::OOMDetails& details) {
#if !IS_MAS_BUILD()
electron::crash_keys::SetCrashKey("electron.v8-oom.is_heap_oom",
base::NumberToString(details.is_heap_oom));
std::to_string(details.is_heap_oom));
if (location) {
electron::crash_keys::SetCrashKey("electron.v8-oom.location", location);
}