fix: revert required portal version for file chooser dialogs (#44681)

* feat: add support for configuring xdg portal version at runtime

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* doc: update command-line-switches.md

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* doc: update command-line-switches.md

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

Co-authored-by: Robo <hop2deep@gmail.com>

* doc: required portal version for defaultPath support

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

Co-authored-by: Robo <hop2deep@gmail.com>

* doc: update more occurrances

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* fix: remove warning from save dialogs

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* doc: update command-line-switches.md

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

Co-authored-by: Robo <hop2deep@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
This commit is contained in:
trop[bot] 2024-11-15 11:30:06 -05:00 committed by GitHub
parent 900400e442
commit 2ee65f9c10
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 170 additions and 10 deletions

View file

@ -241,6 +241,13 @@ Force using discrete GPU when there are multiple GPUs available.
Force using integrated GPU when there are multiple GPUs available.
### --xdg-portal-required-version=`version`
Sets the minimum required version of XDG portal implementation to `version`
in order to use the portal backend for file dialogs on linux. File dialogs
will fallback to using gtk or kde depending on the desktop environment when
the required version is unavailable. Current default is set to `3`.
## Node.js Flags
Electron supports some of the [CLI flags][node-cli] supported by Node.js.

View file

@ -78,6 +78,11 @@ dialog.showOpenDialogSync(mainWindow, {
})
```
**Note:** On Linux `defaultPath` is not supported when using portal file chooser
dialogs unless the portal backend is version 4 or higher. You can use `--xdg-portal-required-version`
[command-line switch](./command-line-switches.md#--xdg-portal-required-versionversion)
to force gtk or kde dialogs.
### `dialog.showOpenDialog([window, ]options)`
* `window` [BaseWindow](base-window.md) (optional)
@ -150,6 +155,11 @@ dialog.showOpenDialog(mainWindow, {
})
```
**Note:** On Linux `defaultPath` is not supported when using portal file chooser
dialogs unless the portal backend is version 4 or higher. You can use `--xdg-portal-required-version`
[command-line switch](./command-line-switches.md#--xdg-portal-required-versionversion)
to force gtk or kde dialogs.
### `dialog.showSaveDialogSync([window, ]options)`
* `window` [BaseWindow](base-window.md) (optional)

View file

@ -199,21 +199,68 @@ index 64a79ebe2e2d21d5a6b4a98042d1cdb7b6edad52..16f2ae01a8d33e6341ed52638e963c34
&SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse, this,
parent));
diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.cc b/ui/shell_dialogs/select_file_dialog_linux_portal.cc
index 143f5fe1028e154192767599a1e68b45301a894d..d612e1614a313db0dcf7dc592fd6fa74c89e70e1 100644
index 143f5fe1028e154192767599a1e68b45301a894d..132e670dc3ccd9a0f904a8869e516f4556fbf0af 100644
--- a/ui/shell_dialogs/select_file_dialog_linux_portal.cc
+++ b/ui/shell_dialogs/select_file_dialog_linux_portal.cc
@@ -40,7 +40,9 @@ namespace {
@@ -11,6 +11,7 @@
#include <string_view>
+#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/no_destructor.h"
@@ -40,6 +41,8 @@ namespace {
constexpr char kXdgPortalService[] = "org.freedesktop.portal.Desktop";
constexpr char kXdgPortalObject[] = "/org/freedesktop/portal/desktop";
-constexpr int kXdgPortalRequiredVersion = 3;
+// Version 4 includes support for current_folder option to the OpenFile method via
+// https://github.com/flatpak/xdg-desktop-portal/commit/71165a5.
+constexpr int kXdgPortalRequiredVersion = 4;
constexpr int kXdgPortalRequiredVersion = 3;
constexpr char kXdgPortalRequestInterfaceName[] =
"org.freedesktop.portal.Request";
@@ -214,6 +216,8 @@ void SelectFileDialogLinuxPortal::SelectFileImpl(
@@ -66,6 +69,8 @@ constexpr int kFileChooserFilterKindGlob = 0;
constexpr char kFileUriPrefix[] = "file://";
+const char kXdgPortalRequiredVersionFlag[] = "xdg-portal-required-version";
+
struct FileChooserProperties : dbus::PropertySet {
dbus::Property<uint32_t> version;
@@ -171,10 +176,18 @@ void SelectFileDialogLinuxPortal::StartAvailabilityTestInBackground() {
if (GetAvailabilityTestCompletionFlag()->IsSet())
return;
+ auto* cmd = base::CommandLine::ForCurrentProcess();
+ unsigned int xdg_portal_required_version;
+ if (!base::StringToUint(cmd->GetSwitchValueASCII(kXdgPortalRequiredVersionFlag),
+ &xdg_portal_required_version)) {
+ xdg_portal_required_version = kXdgPortalRequiredVersion;
+ }
+
dbus_thread_linux::GetTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(
- &SelectFileDialogLinuxPortal::CheckPortalAvailabilityOnBusThread));
+ &SelectFileDialogLinuxPortal::CheckPortalAvailabilityOnBusThread,
+ xdg_portal_required_version));
}
// static
@@ -185,6 +198,11 @@ bool SelectFileDialogLinuxPortal::IsPortalAvailable() {
return is_portal_available_;
}
+// static
+int SelectFileDialogLinuxPortal::GetPortalVersion() {
+ return available_portal_version_;
+}
+
// static
void SelectFileDialogLinuxPortal::DestroyPortalConnection() {
dbus_thread_linux::GetTaskRunner()->PostTask(
@@ -214,6 +232,8 @@ void SelectFileDialogLinuxPortal::SelectFileImpl(
weak_factory_.GetWeakPtr()));
info_->type = type;
info_->main_task_runner = base::SequencedTaskRunner::GetCurrentDefault();
@ -222,7 +269,50 @@ index 143f5fe1028e154192767599a1e68b45301a894d..d612e1614a313db0dcf7dc592fd6fa74
if (owning_window) {
if (auto* root = owning_window->GetRootWindow()) {
@@ -471,7 +475,9 @@ void SelectFileDialogLinuxPortal::DialogInfo::AppendOptions(
@@ -260,7 +280,8 @@ bool SelectFileDialogLinuxPortal::HasMultipleFileTypeChoicesImpl() {
}
// static
-void SelectFileDialogLinuxPortal::CheckPortalAvailabilityOnBusThread() {
+void SelectFileDialogLinuxPortal::CheckPortalAvailabilityOnBusThread(
+ unsigned int xdg_portal_required_version) {
DCHECK(dbus_thread_linux::GetTaskRunner()->RunsTasksInCurrentSequence());
base::AtomicFlag* availability_test_complete =
GetAvailabilityTestCompletionFlag();
@@ -274,6 +295,7 @@ void SelectFileDialogLinuxPortal::CheckPortalAvailabilityOnBusThread() {
base::BindOnce(
[](scoped_refptr<dbus::Bus> bus,
base::AtomicFlag* availability_test_complete,
+ unsigned int xdg_portal_required_version,
std::optional<bool> name_has_owner) {
if (name_has_owner.value_or(false)) {
// The portal service has an owner, proceed to check the version.
@@ -285,15 +307,22 @@ void SelectFileDialogLinuxPortal::CheckPortalAvailabilityOnBusThread() {
if (!properties.GetAndBlock(&properties.version)) {
LOG(ERROR) << "Failed to read portal version property";
} else if (properties.version.value() >=
- kXdgPortalRequiredVersion) {
+ xdg_portal_required_version) {
is_portal_available_ = true;
+ available_portal_version_ = properties.version.value();
+ } else {
+ VLOG(1) << "File chooser portal available version: "
+ << properties.version.value();
+ available_portal_version_ = properties.version.value();
}
}
+ VLOG(1) << "File chooser portal expected version: "
+ << xdg_portal_required_version;
VLOG(1) << "File chooser portal available: "
<< (is_portal_available_ ? "yes" : "no");
availability_test_complete->Set();
},
- bus, availability_test_complete));
+ bus, availability_test_complete, xdg_portal_required_version));
}
// static
@@ -471,7 +500,9 @@ void SelectFileDialogLinuxPortal::DialogInfo::AppendOptions(
response_handle_token);
if (type == SelectFileDialog::Type::SELECT_UPLOAD_FOLDER) {
@ -233,7 +323,7 @@ index 143f5fe1028e154192767599a1e68b45301a894d..d612e1614a313db0dcf7dc592fd6fa74
l10n_util::GetStringUTF8(
IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON));
}
@@ -480,6 +486,8 @@ void SelectFileDialogLinuxPortal::DialogInfo::AppendOptions(
@@ -480,6 +511,8 @@ void SelectFileDialogLinuxPortal::DialogInfo::AppendOptions(
type == SelectFileDialog::Type::SELECT_UPLOAD_FOLDER ||
type == SelectFileDialog::Type::SELECT_EXISTING_FOLDER) {
AppendBoolOption(&options_writer, kFileChooserOptionDirectory, true);
@ -242,11 +332,29 @@ index 143f5fe1028e154192767599a1e68b45301a894d..d612e1614a313db0dcf7dc592fd6fa74
} else if (type == SelectFileDialog::Type::SELECT_OPEN_MULTI_FILE) {
AppendBoolOption(&options_writer, kFileChooserOptionMultiple, true);
}
@@ -820,6 +853,7 @@ SelectFileDialogLinuxPortal::DialogInfo::DialogInfo(
SelectFileDialogLinuxPortal::DialogInfo::~DialogInfo() = default;
bool SelectFileDialogLinuxPortal::is_portal_available_ = false;
+unsigned int SelectFileDialogLinuxPortal::available_portal_version_ = 0;
int SelectFileDialogLinuxPortal::handle_token_counter_ = 0;
} // namespace ui
diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.h b/ui/shell_dialogs/select_file_dialog_linux_portal.h
index d57a52b3ccbd3bd6d390615351ea2ad1e475b157..433f34ac6779611623241cd977dd1214e97fece7 100644
index d57a52b3ccbd3bd6d390615351ea2ad1e475b157..6a2800add2428ffd91286748f886d6c42510ba31 100644
--- a/ui/shell_dialogs/select_file_dialog_linux_portal.h
+++ b/ui/shell_dialogs/select_file_dialog_linux_portal.h
@@ -120,6 +120,8 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
@@ -47,6 +47,9 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
// availability test has not yet completed.
static bool IsPortalAvailable();
+ // Get version of portal if available.
+ static int GetPortalVersion();
+
// Destroys the connection to the bus.
static void DestroyPortalConnection();
@@ -120,6 +123,8 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
Type type;
// The task runner the SelectFileImpl method was called on.
scoped_refptr<base::SequencedTaskRunner> main_task_runner;
@ -255,3 +363,23 @@ index d57a52b3ccbd3bd6d390615351ea2ad1e475b157..433f34ac6779611623241cd977dd1214
private:
friend class base::RefCountedThreadSafe<DialogInfo>;
@@ -176,7 +181,8 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
};
// D-Bus configuration and initialization.
- static void CheckPortalAvailabilityOnBusThread();
+ static void CheckPortalAvailabilityOnBusThread(
+ unsigned int xdg_portal_required_version);
// Returns a flag, written by the D-Bus thread and read by the UI thread,
// indicating whether or not the availability test has completed.
@@ -208,6 +214,9 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
// Written by the D-Bus thread and read by the UI thread.
static bool is_portal_available_;
+ // Written by the D-Bus thread and read by the UI thread.
+ static unsigned int available_portal_version_;
+
// Used by the D-Bus thread to generate unique handle tokens.
static int handle_token_counter_;

View file

@ -18,6 +18,7 @@
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/promise.h"
#include "ui/shell_dialogs/select_file_dialog.h"
#include "ui/shell_dialogs/select_file_dialog_linux_portal.h"
#include "ui/shell_dialogs/select_file_policy.h"
#include "ui/shell_dialogs/selected_file_info.h"
@ -58,6 +59,18 @@ ui::SelectFileDialog::FileTypeInfo GetFilterInfo(const Filters& filters) {
return file_type_info;
}
void LogIfNeededAboutUnsupportedPortalFeature(const DialogSettings& settings) {
if (!settings.default_path.empty() &&
ui::SelectFileDialogLinuxPortal::IsPortalAvailable() &&
ui::SelectFileDialogLinuxPortal::GetPortalVersion() < 4) {
LOG(INFO) << "Available portal version "
<< ui::SelectFileDialogLinuxPortal::GetPortalVersion()
<< " does not support defaultPath option, try the non-portal"
<< " file chooser dialogs by launching with"
<< " --xdg-portal-required-version";
}
}
class FileChooserDialog : public ui::SelectFileDialog::Listener {
public:
enum class DialogType { OPEN, SAVE };
@ -200,6 +213,7 @@ class FileChooserDialog : public ui::SelectFileDialog::Listener {
bool ShowOpenDialogSync(const DialogSettings& settings,
std::vector<base::FilePath>* paths) {
LogIfNeededAboutUnsupportedPortalFeature(settings);
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
auto cb = base::BindOnce(
[](base::RepeatingClosure cb, std::vector<base::FilePath>* file_paths,
@ -217,6 +231,7 @@ bool ShowOpenDialogSync(const DialogSettings& settings,
void ShowOpenDialog(const DialogSettings& settings,
gin_helper::Promise<gin_helper::Dictionary> promise) {
LogIfNeededAboutUnsupportedPortalFeature(settings);
FileChooserDialog* dialog = new FileChooserDialog();
dialog->RunOpenDialog(std::move(promise), settings);
}