10
10
#include " base/environment.h"
11
11
#include " base/files/file_util.h"
12
12
#include " base/nix/xdg_util.h"
13
+ #include " base/no_destructor.h"
13
14
#include " base/process/kill.h"
14
15
#include " base/process/launch.h"
16
+ #include " chrome/browser/chrome_notification_types.h"
15
17
#include " chrome/browser/ui/gtk/gtk_util.h"
18
+ #include " components/dbus/thread_linux/dbus_thread_linux.h"
19
+ #include " content/public/browser/browser_thread.h"
20
+ #include " content/public/browser/notification_observer.h"
21
+ #include " content/public/browser/notification_registrar.h"
22
+ #include " content/public/browser/notification_service.h"
23
+ #include " dbus/bus.h"
24
+ #include " dbus/message.h"
25
+ #include " dbus/object_proxy.h"
16
26
#include " url/gurl.h"
17
27
18
28
#define ELECTRON_TRASH " ELECTRON_TRASH"
@@ -73,6 +83,87 @@ bool XDGEmail(const std::string& email, const bool wait_for_exit) {
73
83
platform_util::OpenCallback ());
74
84
}
75
85
86
+ const char kFreedesktopFileManagerName [] = " org.freedesktop.FileManager1" ;
87
+ const char kFreedesktopFileManagerPath [] = " /org/freedesktop/FileManager1" ;
88
+
89
+ const char kMethodShowItems [] = " ShowItems" ;
90
+
91
+ class ShowItemHelper : public content ::NotificationObserver {
92
+ public:
93
+ static ShowItemHelper& GetInstance () {
94
+ static base::NoDestructor<ShowItemHelper> instance;
95
+ return *instance;
96
+ }
97
+
98
+ ShowItemHelper () {
99
+ registrar_.Add (this , chrome::NOTIFICATION_APP_TERMINATING,
100
+ content::NotificationService::AllSources ());
101
+ }
102
+
103
+ ShowItemHelper (const ShowItemHelper&) = delete ;
104
+ ShowItemHelper& operator =(const ShowItemHelper&) = delete ;
105
+
106
+ void Observe (int type,
107
+ const content::NotificationSource& source,
108
+ const content::NotificationDetails& details) override {
109
+ DCHECK_CURRENTLY_ON (content::BrowserThread::UI);
110
+ DCHECK_EQ (chrome::NOTIFICATION_APP_TERMINATING, type);
111
+ // The browser process is about to exit. Clean up while we still can.
112
+ if (bus_)
113
+ bus_->ShutdownOnDBusThreadAndBlock ();
114
+ bus_.reset ();
115
+ filemanager_proxy_ = nullptr ;
116
+ }
117
+
118
+ void ShowItemInFolder (const base::FilePath& full_path) {
119
+ if (!bus_) {
120
+ // Sets up the D-Bus connection.
121
+ dbus::Bus::Options bus_options;
122
+ bus_options.bus_type = dbus::Bus::SESSION;
123
+ bus_options.connection_type = dbus::Bus::PRIVATE;
124
+ bus_options.dbus_task_runner = dbus_thread_linux::GetTaskRunner ();
125
+ bus_ = base::MakeRefCounted<dbus::Bus>(bus_options);
126
+ }
127
+
128
+ if (!filemanager_proxy_) {
129
+ filemanager_proxy_ =
130
+ bus_->GetObjectProxy (kFreedesktopFileManagerName ,
131
+ dbus::ObjectPath (kFreedesktopFileManagerPath ));
132
+ }
133
+
134
+ dbus::MethodCall show_items_call (kFreedesktopFileManagerName ,
135
+ kMethodShowItems );
136
+ dbus::MessageWriter writer (&show_items_call);
137
+
138
+ writer.AppendArrayOfStrings (
139
+ {" file://" + full_path.value ()}); // List of file(s) to highlight.
140
+ writer.AppendString ({}); // startup-id
141
+
142
+ filemanager_proxy_->CallMethod (
143
+ &show_items_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
144
+ base::BindOnce (&ShowItemHelper::ShowItemInFolderResponse,
145
+ weak_ptr_factory_.GetWeakPtr (), full_path));
146
+ }
147
+
148
+ private:
149
+ void ShowItemInFolderResponse (const base::FilePath& full_path,
150
+ dbus::Response* response) {
151
+ if (response)
152
+ return ;
153
+
154
+ LOG (ERROR) << " Error calling " << kMethodShowItems ;
155
+ // If the FileManager1 call fails, at least open the parent folder.
156
+ platform_util::OpenPath (full_path.DirName (), platform_util::OpenCallback ());
157
+ }
158
+
159
+ content::NotificationRegistrar registrar_;
160
+
161
+ scoped_refptr<dbus::Bus> bus_;
162
+ dbus::ObjectProxy* filemanager_proxy_ = nullptr ;
163
+
164
+ base::WeakPtrFactory<ShowItemHelper> weak_ptr_factory_{this };
165
+ };
166
+
76
167
} // namespace
77
168
78
169
namespace platform_util {
@@ -82,7 +173,7 @@ void ShowItemInFolder(const base::FilePath& full_path) {
82
173
if (!base::DirectoryExists (dir))
83
174
return ;
84
175
85
- XDGOpen (dir. value (), false , platform_util::OpenCallback () );
176
+ ShowItemHelper::GetInstance (). ShowItemInFolder (full_path );
86
177
}
87
178
88
179
void OpenPath (const base::FilePath& full_path, OpenCallback callback) {
0 commit comments