1 // Copyright (c) 2013 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.
5 #include "win8/viewer/metro_viewer_process_host.h"
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/path_service.h"
14 #include "base/process/process.h"
15 #include "base/strings/string16.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/time/time.h"
18 #include "base/win/scoped_comptr.h"
19 #include "base/win/windows_version.h"
20 #include "ipc/ipc_channel_proxy.h"
21 #include "ipc/ipc_message.h"
22 #include "ipc/ipc_message_macros.h"
23 #include "ui/aura/remote_window_tree_host_win.h"
24 #include "ui/metro_viewer/metro_viewer_messages.h"
25 #include "win8/viewer/metro_viewer_constants.h"
29 const int kViewerProcessConnectionTimeoutSecs
= 60;
36 MetroViewerProcessHost
* MetroViewerProcessHost::instance_
= NULL
;
38 MetroViewerProcessHost::InternalMessageFilter::InternalMessageFilter(
39 MetroViewerProcessHost
* owner
)
43 void MetroViewerProcessHost::InternalMessageFilter::OnChannelConnected(
45 owner_
->NotifyChannelConnected();
48 MetroViewerProcessHost::MetroViewerProcessHost(
49 const scoped_refptr
<base::SingleThreadTaskRunner
>& ipc_task_runner
) {
53 channel_
= IPC::ChannelProxy::Create(kMetroViewerIPCChannelName
,
54 IPC::Channel::MODE_NAMED_SERVER
,
59 MetroViewerProcessHost::~MetroViewerProcessHost() {
65 base::ProcessId viewer_process_id
= GetViewerProcessId();
67 if (message_filter_
.get()) {
68 // Wait for the viewer process to go away.
69 if (viewer_process_id
!= base::kNullProcessId
) {
70 base::Process viewer_process
=
71 base::Process::OpenWithAccess(
73 PROCESS_QUERY_INFORMATION
| SYNCHRONIZE
);
74 if (viewer_process
.IsValid()) {
76 viewer_process
.WaitForExit(&exit_code
);
79 channel_
->RemoveFilter(message_filter_
.get());
84 base::ProcessId
MetroViewerProcessHost::GetViewerProcessId() {
86 return channel_
->GetPeerPID();
87 return base::kNullProcessId
;
90 bool MetroViewerProcessHost::LaunchViewerAndWaitForConnection(
91 const base::string16
& app_user_model_id
) {
92 DCHECK_EQ(base::kNullProcessId
, channel_
->GetPeerPID());
94 channel_connected_event_
.reset(new base::WaitableEvent(false, false));
96 message_filter_
= new InternalMessageFilter(this);
97 channel_
->AddFilter(message_filter_
.get());
99 if (base::win::GetVersion() >= base::win::VERSION_WIN8
) {
100 base::win::ScopedComPtr
<IApplicationActivationManager
> activator
;
101 HRESULT hr
= activator
.CreateInstance(CLSID_ApplicationActivationManager
);
104 // Use the "connect" verb to
105 hr
= activator
->ActivateApplication(
106 app_user_model_id
.c_str(), kMetroViewerConnectVerb
, AO_NONE
, &pid
);
109 LOG_IF(ERROR
, FAILED(hr
)) << "Tried and failed to launch Metro Chrome. "
110 << "hr=" << std::hex
<< hr
;
112 // For Windows 7 we need to launch the viewer ourselves.
113 base::FilePath chrome_path
;
114 if (!PathService::Get(base::DIR_EXE
, &chrome_path
))
116 // TODO(cpu): launch with "-ServerName:DefaultBrowserServer"
117 // note that the viewer might try to launch chrome again.
121 // Having launched the viewer process, now we wait for it to connect.
123 channel_connected_event_
->TimedWait(base::TimeDelta::FromSeconds(
124 kViewerProcessConnectionTimeoutSecs
));
125 channel_connected_event_
.reset();
129 bool MetroViewerProcessHost::Send(IPC::Message
* msg
) {
130 return channel_
->Send(msg
);
133 bool MetroViewerProcessHost::OnMessageReceived(
134 const IPC::Message
& message
) {
135 DCHECK(CalledOnValidThread());
137 IPC_BEGIN_MESSAGE_MAP(MetroViewerProcessHost
, message
)
138 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileSaveAsDone
,
140 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileOpenDone
,
142 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MultiFileOpenDone
,
144 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURL
, OnOpenURL
)
145 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SearchRequest
, OnHandleSearchRequest
)
146 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SelectFolderDone
,
148 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetTargetSurface
, OnSetTargetSurface
)
149 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowSizeChanged
,
151 IPC_MESSAGE_UNHANDLED(handled
= false)
152 IPC_END_MESSAGE_MAP()
153 return handled
? true :
154 aura::RemoteWindowTreeHostWin::Instance()->OnMessageReceived(message
);
158 void MetroViewerProcessHost::HandleActivateDesktop(
159 const base::FilePath
& path
,
163 new MetroViewerHostMsg_ActivateDesktop(path
, ash_exit
));
168 void MetroViewerProcessHost::HandleMetroExit() {
170 instance_
->Send(new MetroViewerHostMsg_MetroExit());
174 void MetroViewerProcessHost::HandleOpenFile(
175 const base::string16
& title
,
176 const base::FilePath
& default_path
,
177 const base::string16
& filter
,
178 const OpenFileCompletion
& on_success
,
179 const FileSelectionCanceled
& on_failure
) {
181 instance_
->HandleOpenFileImpl(title
, default_path
, filter
, on_success
,
187 void MetroViewerProcessHost::HandleOpenMultipleFiles(
188 const base::string16
& title
,
189 const base::FilePath
& default_path
,
190 const base::string16
& filter
,
191 const OpenMultipleFilesCompletion
& on_success
,
192 const FileSelectionCanceled
& on_failure
) {
194 instance_
->HandleOpenMultipleFilesImpl(title
, default_path
, filter
,
195 on_success
, on_failure
);
200 void MetroViewerProcessHost::HandleSaveFile(
201 const base::string16
& title
,
202 const base::FilePath
& default_path
,
203 const base::string16
& filter
,
205 const base::string16
& default_extension
,
206 const SaveFileCompletion
& on_success
,
207 const FileSelectionCanceled
& on_failure
) {
209 instance_
->HandleSaveFileImpl(title
, default_path
, filter
, filter_index
,
210 default_extension
, on_success
, on_failure
);
215 void MetroViewerProcessHost::HandleSelectFolder(
216 const base::string16
& title
,
217 const SelectFolderCompletion
& on_success
,
218 const FileSelectionCanceled
& on_failure
) {
220 instance_
->HandleSelectFolderImpl(title
, on_success
, on_failure
);
223 void MetroViewerProcessHost::HandleOpenFileImpl(
224 const base::string16
& title
,
225 const base::FilePath
& default_path
,
226 const base::string16
& filter
,
227 const OpenFileCompletion
& on_success
,
228 const FileSelectionCanceled
& on_failure
) {
229 // Can only have one of these operations in flight.
230 DCHECK(file_open_completion_callback_
.is_null());
231 DCHECK(failure_callback_
.is_null());
233 file_open_completion_callback_
= on_success
;
234 failure_callback_
= on_failure
;
236 Send(new MetroViewerHostMsg_DisplayFileOpen(title
, filter
, default_path
,
240 void MetroViewerProcessHost::HandleOpenMultipleFilesImpl(
241 const base::string16
& title
,
242 const base::FilePath
& default_path
,
243 const base::string16
& filter
,
244 const OpenMultipleFilesCompletion
& on_success
,
245 const FileSelectionCanceled
& on_failure
) {
246 // Can only have one of these operations in flight.
247 DCHECK(multi_file_open_completion_callback_
.is_null());
248 DCHECK(failure_callback_
.is_null());
249 multi_file_open_completion_callback_
= on_success
;
250 failure_callback_
= on_failure
;
252 Send(new MetroViewerHostMsg_DisplayFileOpen(title
, filter
, default_path
,
256 void MetroViewerProcessHost::HandleSaveFileImpl(
257 const base::string16
& title
,
258 const base::FilePath
& default_path
,
259 const base::string16
& filter
,
261 const base::string16
& default_extension
,
262 const SaveFileCompletion
& on_success
,
263 const FileSelectionCanceled
& on_failure
) {
264 MetroViewerHostMsg_SaveAsDialogParams params
;
265 params
.title
= title
;
266 params
.default_extension
= default_extension
;
267 params
.filter
= filter
;
268 params
.filter_index
= filter_index
;
269 params
.suggested_name
= default_path
;
271 // Can only have one of these operations in flight.
272 DCHECK(file_saveas_completion_callback_
.is_null());
273 DCHECK(failure_callback_
.is_null());
274 file_saveas_completion_callback_
= on_success
;
275 failure_callback_
= on_failure
;
277 Send(new MetroViewerHostMsg_DisplayFileSaveAs(params
));
280 void MetroViewerProcessHost::HandleSelectFolderImpl(
281 const base::string16
& title
,
282 const SelectFolderCompletion
& on_success
,
283 const FileSelectionCanceled
& on_failure
) {
284 // Can only have one of these operations in flight.
285 DCHECK(select_folder_completion_callback_
.is_null());
286 DCHECK(failure_callback_
.is_null());
287 select_folder_completion_callback_
= on_success
;
288 failure_callback_
= on_failure
;
290 Send(new MetroViewerHostMsg_DisplaySelectFolder(title
));
293 void MetroViewerProcessHost::NotifyChannelConnected() {
294 if (channel_connected_event_
)
295 channel_connected_event_
->Signal();
298 void MetroViewerProcessHost::OnFileSaveAsDone(bool success
,
299 const base::FilePath
& filename
,
302 file_saveas_completion_callback_
.Run(filename
, filter_index
, NULL
);
304 failure_callback_
.Run(NULL
);
305 file_saveas_completion_callback_
.Reset();
306 failure_callback_
.Reset();
310 void MetroViewerProcessHost::OnFileOpenDone(bool success
,
311 const base::FilePath
& filename
) {
313 file_open_completion_callback_
.Run(base::FilePath(filename
), 0, NULL
);
315 failure_callback_
.Run(NULL
);
316 file_open_completion_callback_
.Reset();
317 failure_callback_
.Reset();
320 void MetroViewerProcessHost::OnMultiFileOpenDone(
322 const std::vector
<base::FilePath
>& files
) {
324 multi_file_open_completion_callback_
.Run(files
, NULL
);
326 failure_callback_
.Run(NULL
);
327 multi_file_open_completion_callback_
.Reset();
328 failure_callback_
.Reset();
331 void MetroViewerProcessHost::OnSelectFolderDone(
333 const base::FilePath
& folder
) {
335 select_folder_completion_callback_
.Run(base::FilePath(folder
), 0, NULL
);
337 failure_callback_
.Run(NULL
);
338 select_folder_completion_callback_
.Reset();
339 failure_callback_
.Reset();