fix: xdg portal version detection for file dialogs on linux (#46922)
* chore: use dbus thread for portal version detection Co-authored-by: deepak1556 <hop2deep@gmail.com> * Update shell/browser/ui/file_dialog_linux_portal.cc Co-authored-by: Robo <hop2deep@gmail.com> Co-authored-by: Charles Kerr <charles@charleskerr.com> --------- Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: deepak1556 <hop2deep@gmail.com> Co-authored-by: Charles Kerr <charles@charleskerr.com>
This commit is contained in:
parent
0810fe54d4
commit
01994637e8
5 changed files with 172 additions and 86 deletions
121
shell/browser/ui/file_dialog_linux_portal.cc
Normal file
121
shell/browser/ui/file_dialog_linux_portal.cc
Normal file
|
@ -0,0 +1,121 @@
|
|||
// Copyright (c) 2025 Microsoft, GmbH.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/ui/file_dialog.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/synchronization/atomic_flag.h"
|
||||
#include "components/dbus/thread_linux/dbus_thread_linux.h"
|
||||
#include "components/dbus/utils/check_for_service_and_start.h"
|
||||
#include "dbus/bus.h"
|
||||
#include "dbus/object_path.h"
|
||||
#include "dbus/object_proxy.h"
|
||||
#include "dbus/property.h"
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr char kXdgPortalService[] = "org.freedesktop.portal.Desktop";
|
||||
constexpr char kXdgPortalObject[] = "/org/freedesktop/portal/desktop";
|
||||
constexpr char kFileChooserInterfaceName[] =
|
||||
"org.freedesktop.portal.FileChooser";
|
||||
|
||||
// Version 4 includes support for current_folder option to the OpenFile method
|
||||
// via https://github.com/flatpak/xdg-desktop-portal/commit/71165a5.
|
||||
uint32_t g_required_portal_version = 3;
|
||||
uint32_t g_available_portal_version = 0;
|
||||
constexpr char kXdgPortalRequiredVersionFlag[] = "xdg-portal-required-version";
|
||||
|
||||
bool g_portal_available = false;
|
||||
|
||||
struct FileChooserProperties : dbus::PropertySet {
|
||||
dbus::Property<uint32_t> version;
|
||||
|
||||
explicit FileChooserProperties(dbus::ObjectProxy* object_proxy)
|
||||
: dbus::PropertySet(object_proxy, kFileChooserInterfaceName, {}) {
|
||||
RegisterProperty("version", &version);
|
||||
}
|
||||
|
||||
~FileChooserProperties() override = default;
|
||||
};
|
||||
|
||||
base::AtomicFlag* GetAvailabilityTestCompletionFlag() {
|
||||
static base::NoDestructor<base::AtomicFlag> flag;
|
||||
return flag.get();
|
||||
}
|
||||
|
||||
void CheckPortalAvailabilityOnBusThread() {
|
||||
auto* flag = GetAvailabilityTestCompletionFlag();
|
||||
if (flag->IsSet())
|
||||
return;
|
||||
|
||||
dbus::Bus::Options options;
|
||||
options.bus_type = dbus::Bus::SESSION;
|
||||
options.connection_type = dbus::Bus::PRIVATE;
|
||||
options.dbus_task_runner = dbus_thread_linux::GetTaskRunner();
|
||||
scoped_refptr<dbus::Bus> bus = base::MakeRefCounted<dbus::Bus>(options);
|
||||
dbus_utils::CheckForServiceAndStart(
|
||||
bus, kXdgPortalService,
|
||||
base::BindOnce(
|
||||
[](scoped_refptr<dbus::Bus> bus, base::AtomicFlag* flag,
|
||||
std::optional<bool> name_has_owner) {
|
||||
if (name_has_owner.value_or(false)) {
|
||||
//
|
||||
dbus::ObjectPath portal_path(kXdgPortalObject);
|
||||
dbus::ObjectProxy* portal =
|
||||
bus->GetObjectProxy(kXdgPortalService, portal_path);
|
||||
FileChooserProperties properties(portal);
|
||||
if (!properties.GetAndBlock(&properties.version)) {
|
||||
LOG(ERROR) << "Failed to read portal version property";
|
||||
} else if (properties.version.value() >=
|
||||
g_required_portal_version) {
|
||||
g_portal_available = true;
|
||||
g_available_portal_version = properties.version.value();
|
||||
}
|
||||
}
|
||||
VLOG(1) << "File chooser portal available: "
|
||||
<< (g_portal_available ? "yes" : "no");
|
||||
flag->Set();
|
||||
bus->ShutdownAndBlock();
|
||||
},
|
||||
std::move(bus), flag));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void StartPortalAvailabilityTestInBackground() {
|
||||
if (GetAvailabilityTestCompletionFlag()->IsSet())
|
||||
return;
|
||||
|
||||
const auto* cmd = base::CommandLine::ForCurrentProcess();
|
||||
if (!base::StringToUint(
|
||||
cmd->GetSwitchValueASCII(kXdgPortalRequiredVersionFlag),
|
||||
&g_required_portal_version)) {
|
||||
VLOG(1) << "Unable to parse --xdg-portal-required-version";
|
||||
}
|
||||
|
||||
dbus_thread_linux::GetTaskRunner()->PostTask(
|
||||
FROM_HERE, base::BindOnce(&CheckPortalAvailabilityOnBusThread));
|
||||
}
|
||||
|
||||
bool IsPortalAvailable() {
|
||||
if (!GetAvailabilityTestCompletionFlag()->IsSet())
|
||||
LOG(WARNING) << "Portal availability checked before test was complete";
|
||||
|
||||
return g_portal_available;
|
||||
}
|
||||
|
||||
uint32_t GetPortalVersion() {
|
||||
return g_available_portal_version;
|
||||
}
|
||||
|
||||
} // namespace file_dialog
|
Loading…
Add table
Add a link
Reference in a new issue