select_file_dialog_linux_portal.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_LINUX_PORTAL_H_
  5. #define UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_LINUX_PORTAL_H_
  6. #include "base/memory/raw_ptr.h"
  7. #include "base/memory/ref_counted.h"
  8. #include "base/memory/scoped_refptr.h"
  9. #include "base/synchronization/atomic_flag.h"
  10. #include "base/task/sequenced_task_runner.h"
  11. #include "dbus/bus.h"
  12. #include "dbus/message.h"
  13. #include "dbus/object_proxy.h"
  14. #include "ui/shell_dialogs/select_file_dialog_linux.h"
  15. namespace ui {
  16. // Implementation of SelectFileDialog that has the XDG file chooser portal show
  17. // a platform-dependent file selection dialog. This acts as a modal dialog.
  18. class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
  19. public:
  20. SelectFileDialogLinuxPortal(Listener* listener,
  21. std::unique_ptr<ui::SelectFilePolicy> policy);
  22. SelectFileDialogLinuxPortal(const SelectFileDialogLinuxPortal& other) =
  23. delete;
  24. SelectFileDialogLinuxPortal& operator=(
  25. const SelectFileDialogLinuxPortal& other) = delete;
  26. // Starts running a test to check for the presence of the file chooser portal
  27. // on the D-Bus task runner. This should only be called once, preferably
  28. // around program start.
  29. static void StartAvailabilityTestInBackground();
  30. // Checks if the file chooser portal is available. Blocks if the availability
  31. // test from above has not yet completed (which should generally not happen).
  32. static bool IsPortalAvailable();
  33. // Destroys the connection to the bus.
  34. static void DestroyPortalConnection();
  35. protected:
  36. ~SelectFileDialogLinuxPortal() override;
  37. // BaseShellDialog implementation:
  38. bool IsRunning(gfx::NativeWindow parent_window) const override;
  39. // SelectFileDialog implementation.
  40. // |params| is user data we pass back via the Listener interface.
  41. void SelectFileImpl(Type type,
  42. const std::u16string& title,
  43. const base::FilePath& default_path,
  44. const FileTypeInfo* file_types,
  45. int file_type_index,
  46. const base::FilePath::StringType& default_extension,
  47. gfx::NativeWindow owning_window,
  48. void* params) override;
  49. bool HasMultipleFileTypeChoicesImpl() override;
  50. private:
  51. // A named set of patterns used as a dialog filter.
  52. struct PortalFilter {
  53. PortalFilter();
  54. PortalFilter(const PortalFilter& other);
  55. PortalFilter(PortalFilter&& other);
  56. ~PortalFilter();
  57. PortalFilter& operator=(const PortalFilter& other) = default;
  58. PortalFilter& operator=(PortalFilter&& other) = default;
  59. std::string name;
  60. std::vector<std::string> patterns;
  61. };
  62. // A set of PortalFilters, potentially with a default.
  63. struct PortalFilterSet {
  64. PortalFilterSet();
  65. PortalFilterSet(const PortalFilterSet& other);
  66. PortalFilterSet(PortalFilterSet&& other);
  67. ~PortalFilterSet();
  68. PortalFilterSet& operator=(const PortalFilterSet& other) = default;
  69. PortalFilterSet& operator=(PortalFilterSet&& other) = default;
  70. std::vector<PortalFilter> filters;
  71. absl::optional<PortalFilter> default_filter;
  72. };
  73. // A wrapper over some shared contextual information that needs to be passed
  74. // around between various handler functions. This is ref-counted due to some
  75. // of the locations its used in having slightly unclear or error-prone
  76. // lifetimes.
  77. struct DialogInfo : base::RefCountedThreadSafe<DialogInfo> {
  78. DialogInfo();
  79. // The response object handle that the portal will send a signal to upon the
  80. // dialog's completion.
  81. raw_ptr<dbus::ObjectProxy, DanglingUntriaged> response_handle = nullptr;
  82. absl::optional<gfx::AcceleratedWidget> parent;
  83. Type type;
  84. // The task runner the SelectFileImpl method was called on.
  85. scoped_refptr<base::SequencedTaskRunner> main_task_runner;
  86. // The untyped params to pass to the listener.
  87. raw_ptr<void> listener_params = nullptr;
  88. private:
  89. friend class base::RefCountedThreadSafe<DialogInfo>;
  90. ~DialogInfo();
  91. };
  92. static scoped_refptr<dbus::Bus>* AcquireBusStorageOnBusThread();
  93. static dbus::Bus* AcquireBusOnBusThread();
  94. static void DestroyBusOnBusThread();
  95. static void CheckPortalAvailabilityOnBusThread();
  96. static bool IsPortalRunningOnBusThread(dbus::ObjectProxy* dbus_proxy);
  97. static bool IsPortalActivatableOnBusThread(dbus::ObjectProxy* dbus_proxy);
  98. // Returns a flag, written by the D-Bus thread and read by the UI thread,
  99. // indicating whether or not the availability test has completed.
  100. static base::AtomicFlag* GetAvailabilityTestCompletionFlag();
  101. PortalFilterSet BuildFilterSet();
  102. void SelectFileImplWithParentHandle(
  103. scoped_refptr<DialogInfo> info,
  104. std::u16string title,
  105. base::FilePath default_path,
  106. PortalFilterSet filter_set,
  107. base::FilePath::StringType default_extension,
  108. std::string parent_handle);
  109. void SelectFileImplOnBusThread(scoped_refptr<DialogInfo> info,
  110. std::u16string title,
  111. base::FilePath default_path,
  112. PortalFilterSet filter_set,
  113. base::FilePath::StringType default_extension,
  114. std::string parent_handle);
  115. void AppendOptions(dbus::MessageWriter* writer,
  116. Type type,
  117. const std::string& response_handle_token,
  118. const base::FilePath& default_path,
  119. const PortalFilterSet& filter_set);
  120. void AppendFiltersOption(dbus::MessageWriter* writer,
  121. const std::vector<PortalFilter>& filters);
  122. void AppendFilterStruct(dbus::MessageWriter* writer,
  123. const PortalFilter& filter);
  124. // Sets up listeners for the response handle's signals.
  125. void ConnectToHandle(scoped_refptr<DialogInfo> info);
  126. // Completes an open call, notifying the listener with the given paths, and
  127. // marks the dialog as closed.
  128. void CompleteOpen(scoped_refptr<DialogInfo> info,
  129. std::vector<base::FilePath> paths,
  130. std::string current_filter);
  131. // Completes an open call, notifying the listener with a cancellation, and
  132. // marks the dialog as closed.
  133. void CancelOpen(scoped_refptr<DialogInfo> info);
  134. void CompleteOpenOnMainThread(scoped_refptr<DialogInfo> info,
  135. std::vector<base::FilePath> paths,
  136. std::string current_filter);
  137. void CancelOpenOnMainThread(scoped_refptr<DialogInfo> info);
  138. // Removes the DialogInfo parent. Must be called on the UI task runner.
  139. void UnparentOnMainThread(DialogInfo* info);
  140. void OnCallResponse(dbus::Bus* bus,
  141. scoped_refptr<DialogInfo> info,
  142. dbus::Response* response,
  143. dbus::ErrorResponse* error_response);
  144. void OnResponseSignalConnected(scoped_refptr<DialogInfo> info,
  145. const std::string& interface,
  146. const std::string& signal,
  147. bool connected);
  148. void OnResponseSignalEmitted(scoped_refptr<DialogInfo> info,
  149. dbus::Signal* signal);
  150. bool CheckResponseCode(dbus::MessageReader* reader);
  151. bool ReadResponseResults(dbus::MessageReader* reader,
  152. std::vector<std::string>* uris,
  153. std::string* current_filter);
  154. std::vector<base::FilePath> ConvertUrisToPaths(
  155. const std::vector<std::string>& uris);
  156. std::set<gfx::AcceleratedWidget> parents_;
  157. // Written by the D-Bus thread and read by the UI thread.
  158. static bool is_portal_available_;
  159. // Used by the D-Bus thread to generate unique handle tokens.
  160. static int handle_token_counter_;
  161. std::vector<PortalFilter> filters_;
  162. };
  163. } // namespace ui
  164. #endif // UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_LINUX_PORTAL_H_