blob: af224fd04ec1f763fbd7a1b367db530843741d10 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_LINUX_PORTAL_H_
#define UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_LINUX_PORTAL_H_
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <vector>
#include "base/functional/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "components/dbus/xdg/request.h"
#include "dbus/bus.h"
#include "ui/shell_dialogs/select_file_dialog_linux.h"
#include "ui/shell_dialogs/shell_dialogs_export.h"
#include "url/gurl.h"
namespace ui {
using OnSelectFileExecutedCallback =
base::OnceCallback<void(std::vector<base::FilePath> paths,
std::string current_filter)>;
using OnSelectFileCanceledCallback = base::OnceCallback<void()>;
// Implementation of SelectFileDialog that has the XDG file chooser portal show
// a platform-dependent file selection dialog. This acts as a modal dialog.
class SHELL_DIALOGS_EXPORT SelectFileDialogLinuxPortal
: public SelectFileDialogLinux {
public:
SelectFileDialogLinuxPortal(Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy);
SelectFileDialogLinuxPortal(const SelectFileDialogLinuxPortal& other) =
delete;
SelectFileDialogLinuxPortal& operator=(
const SelectFileDialogLinuxPortal& other) = delete;
protected:
~SelectFileDialogLinuxPortal() override;
// BaseShellDialog:
void ListenerDestroyed() override;
bool IsRunning(gfx::NativeWindow parent_window) const override;
// SelectFileDialog:
void SelectFileImpl(Type type,
const std::u16string& title,
const base::FilePath& default_path,
const FileTypeInfo* file_types,
int file_type_index,
const base::FilePath::StringType& default_extension,
gfx::NativeWindow owning_window,
const GURL* caller) override;
bool HasMultipleFileTypeChoicesImpl() override;
base::WeakPtr<SelectFileDialogLinuxPortal> GetWeakPtrForTesting() {
return weak_factory_.GetWeakPtr();
}
private:
// Glob-style patterns are indicated by 0, MIME types by 1. Patterns are
// case-sensitive.
using DbusFilterPattern = std::tuple<uint32_t, std::string>;
using DbusFilterPatterns = std::vector<DbusFilterPattern>;
// The first string is a user-visible name for the filter.
using DbusFilter = std::tuple<std::string, DbusFilterPatterns>;
using DbusFilters = std::vector<DbusFilter>;
// A named set of patterns used as a dialog filter.
struct PortalFilter {
PortalFilter();
PortalFilter(const PortalFilter& other);
PortalFilter(PortalFilter&& other);
~PortalFilter();
PortalFilter& operator=(const PortalFilter& other) = default;
PortalFilter& operator=(PortalFilter&& other) = default;
std::string name;
std::vector<std::string> patterns;
};
// A set of PortalFilters, potentially with a default.
struct PortalFilterSet {
PortalFilterSet();
PortalFilterSet(const PortalFilterSet& other);
PortalFilterSet(PortalFilterSet&& other);
~PortalFilterSet();
PortalFilterSet& operator=(const PortalFilterSet& other) = default;
PortalFilterSet& operator=(PortalFilterSet&& other) = default;
std::vector<PortalFilter> filters;
std::optional<PortalFilter> default_filter;
};
PortalFilterSet BuildFilterSet();
void SelectFileImplWithParentHandle(
std::u16string title,
base::FilePath default_path,
PortalFilterSet filter_set,
base::FilePath::StringType default_extension,
std::string parent_handle);
void SelectFileImplOnMainThread(std::u16string title,
base::FilePath default_path,
const bool default_path_exists,
PortalFilterSet filter_set,
base::FilePath::StringType default_extension,
std::string parent_handle);
dbus_xdg::Dictionary BuildOptionsDictionary(
const base::FilePath& default_path,
bool default_path_exists,
const PortalFilterSet& filter_set);
DbusFilter MakeFilterStruct(const PortalFilter& filter);
void MakeFileChooserRequest(const std::string& method,
const std::string& title,
dbus_xdg::Dictionary options,
std::string parent_handle);
void OnFileChooserResponse(
base::expected<dbus_xdg::Dictionary, dbus_xdg::ResponseError> results);
void CompleteOpen(std::vector<base::FilePath> paths,
std::string current_filter);
void CancelOpen();
void DialogCreatedOnInvoker();
void CompleteOpenOnInvoker(std::vector<base::FilePath> paths,
std::string current_filter);
void CancelOpenOnInvoker();
// Removes the DialogInfo parent.
void UnparentOnInvoker();
void OnPortalAvailable(std::u16string title,
base::FilePath default_path,
base::FilePath::StringType default_extension,
std::optional<GURL> caller,
uint32_t version);
// The task runner the SelectFileImpl method was called on.
scoped_refptr<base::SequencedTaskRunner> invoker_task_runner_;
// This should be used by the invoker task runner.
base::WeakPtr<aura::WindowTreeHost> host_;
// The fallback dialog to use if the portal is not available.
scoped_refptr<SelectFileDialog> fallback_dialog_;
std::vector<PortalFilter> filters_;
// The Request representing an in-flight file chooser call, if any.
// We keep this alive until the response arrives or until the dialog
// is destroyed, whichever comes first.
std::unique_ptr<dbus_xdg::Request> file_chooser_request_;
// Event handling on the parent window is disabled while the dialog is active
// to make the dialog modal. This closure should be run when the dialog is
// closed to reenable event handling.
base::OnceClosure reenable_window_event_handling_;
base::WeakPtrFactory<SelectFileDialogLinuxPortal> weak_factory_{this};
};
} // namespace ui
#endif // UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_LINUX_PORTAL_H_