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::InternalMessageFilter::~InternalMessageFilter() {
51 MetroViewerProcessHost::MetroViewerProcessHost(
52 const scoped_refptr
<base::SingleThreadTaskRunner
>& ipc_task_runner
) {
56 channel_
= IPC::ChannelProxy::Create(kMetroViewerIPCChannelName
,
57 IPC::Channel::MODE_NAMED_SERVER
,
62 MetroViewerProcessHost::~MetroViewerProcessHost() {
68 base::ProcessId viewer_process_id
= GetViewerProcessId();
70 if (message_filter_
.get()) {
71 // Wait for the viewer process to go away.
72 if (viewer_process_id
!= base::kNullProcessId
) {
73 base::Process viewer_process
=
74 base::Process::OpenWithAccess(
76 PROCESS_QUERY_INFORMATION
| SYNCHRONIZE
);
77 if (viewer_process
.IsValid()) {
79 viewer_process
.WaitForExit(&exit_code
);
82 channel_
->RemoveFilter(message_filter_
.get());
87 base::ProcessId
MetroViewerProcessHost::GetViewerProcessId() {
89 return channel_
->GetPeerPID();
90 return base::kNullProcessId
;
93 bool MetroViewerProcessHost::LaunchViewerAndWaitForConnection(
94 const base::string16
& app_user_model_id
) {
95 DCHECK_EQ(base::kNullProcessId
, channel_
->GetPeerPID());
97 channel_connected_event_
.reset(new base::WaitableEvent(false, false));
99 message_filter_
= new InternalMessageFilter(this);
100 channel_
->AddFilter(message_filter_
.get());
102 if (base::win::GetVersion() >= base::win::VERSION_WIN8
) {
103 base::win::ScopedComPtr
<IApplicationActivationManager
> activator
;
104 HRESULT hr
= activator
.CreateInstance(CLSID_ApplicationActivationManager
);
107 // Use the "connect" verb to
108 hr
= activator
->ActivateApplication(
109 app_user_model_id
.c_str(), kMetroViewerConnectVerb
, AO_NONE
, &pid
);
112 LOG_IF(ERROR
, FAILED(hr
)) << "Tried and failed to launch Metro Chrome. "
113 << "hr=" << std::hex
<< hr
;
115 // For Windows 7 we need to launch the viewer ourselves.
116 base::FilePath chrome_path
;
117 if (!PathService::Get(base::DIR_EXE
, &chrome_path
))
119 // TODO(cpu): launch with "-ServerName:DefaultBrowserServer"
120 // note that the viewer might try to launch chrome again.
124 // Having launched the viewer process, now we wait for it to connect.
126 channel_connected_event_
->TimedWait(base::TimeDelta::FromSeconds(
127 kViewerProcessConnectionTimeoutSecs
));
128 channel_connected_event_
.reset();
132 bool MetroViewerProcessHost::Send(IPC::Message
* msg
) {
133 return channel_
->Send(msg
);
136 bool MetroViewerProcessHost::OnMessageReceived(
137 const IPC::Message
& message
) {
138 DCHECK(CalledOnValidThread());
140 IPC_BEGIN_MESSAGE_MAP(MetroViewerProcessHost
, message
)
141 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileSaveAsDone
,
143 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileOpenDone
,
145 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MultiFileOpenDone
,
147 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURL
, OnOpenURL
)
148 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SearchRequest
, OnHandleSearchRequest
)
149 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SelectFolderDone
,
151 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetTargetSurface
, OnSetTargetSurface
)
152 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowSizeChanged
,
154 IPC_MESSAGE_UNHANDLED(handled
= false)
155 IPC_END_MESSAGE_MAP()
156 return handled
? true :
157 aura::RemoteWindowTreeHostWin::Instance()->OnMessageReceived(message
);
161 void MetroViewerProcessHost::HandleActivateDesktop(
162 const base::FilePath
& path
,
166 new MetroViewerHostMsg_ActivateDesktop(path
, ash_exit
));
171 void MetroViewerProcessHost::HandleMetroExit() {
173 instance_
->Send(new MetroViewerHostMsg_MetroExit());
177 void MetroViewerProcessHost::HandleOpenFile(
178 const base::string16
& title
,
179 const base::FilePath
& default_path
,
180 const base::string16
& filter
,
181 const OpenFileCompletion
& on_success
,
182 const FileSelectionCanceled
& on_failure
) {
184 instance_
->HandleOpenFileImpl(title
, default_path
, filter
, on_success
,
190 void MetroViewerProcessHost::HandleOpenMultipleFiles(
191 const base::string16
& title
,
192 const base::FilePath
& default_path
,
193 const base::string16
& filter
,
194 const OpenMultipleFilesCompletion
& on_success
,
195 const FileSelectionCanceled
& on_failure
) {
197 instance_
->HandleOpenMultipleFilesImpl(title
, default_path
, filter
,
198 on_success
, on_failure
);
203 void MetroViewerProcessHost::HandleSaveFile(
204 const base::string16
& title
,
205 const base::FilePath
& default_path
,
206 const base::string16
& filter
,
208 const base::string16
& default_extension
,
209 const SaveFileCompletion
& on_success
,
210 const FileSelectionCanceled
& on_failure
) {
212 instance_
->HandleSaveFileImpl(title
, default_path
, filter
, filter_index
,
213 default_extension
, on_success
, on_failure
);
218 void MetroViewerProcessHost::HandleSelectFolder(
219 const base::string16
& title
,
220 const SelectFolderCompletion
& on_success
,
221 const FileSelectionCanceled
& on_failure
) {
223 instance_
->HandleSelectFolderImpl(title
, on_success
, on_failure
);
226 void MetroViewerProcessHost::HandleOpenFileImpl(
227 const base::string16
& title
,
228 const base::FilePath
& default_path
,
229 const base::string16
& filter
,
230 const OpenFileCompletion
& on_success
,
231 const FileSelectionCanceled
& on_failure
) {
232 // Can only have one of these operations in flight.
233 DCHECK(file_open_completion_callback_
.is_null());
234 DCHECK(failure_callback_
.is_null());
236 file_open_completion_callback_
= on_success
;
237 failure_callback_
= on_failure
;
239 Send(new MetroViewerHostMsg_DisplayFileOpen(title
, filter
, default_path
,
243 void MetroViewerProcessHost::HandleOpenMultipleFilesImpl(
244 const base::string16
& title
,
245 const base::FilePath
& default_path
,
246 const base::string16
& filter
,
247 const OpenMultipleFilesCompletion
& on_success
,
248 const FileSelectionCanceled
& on_failure
) {
249 // Can only have one of these operations in flight.
250 DCHECK(multi_file_open_completion_callback_
.is_null());
251 DCHECK(failure_callback_
.is_null());
252 multi_file_open_completion_callback_
= on_success
;
253 failure_callback_
= on_failure
;
255 Send(new MetroViewerHostMsg_DisplayFileOpen(title
, filter
, default_path
,
259 void MetroViewerProcessHost::HandleSaveFileImpl(
260 const base::string16
& title
,
261 const base::FilePath
& default_path
,
262 const base::string16
& filter
,
264 const base::string16
& default_extension
,
265 const SaveFileCompletion
& on_success
,
266 const FileSelectionCanceled
& on_failure
) {
267 MetroViewerHostMsg_SaveAsDialogParams params
;
268 params
.title
= title
;
269 params
.default_extension
= default_extension
;
270 params
.filter
= filter
;
271 params
.filter_index
= filter_index
;
272 params
.suggested_name
= default_path
;
274 // Can only have one of these operations in flight.
275 DCHECK(file_saveas_completion_callback_
.is_null());
276 DCHECK(failure_callback_
.is_null());
277 file_saveas_completion_callback_
= on_success
;
278 failure_callback_
= on_failure
;
280 Send(new MetroViewerHostMsg_DisplayFileSaveAs(params
));
283 void MetroViewerProcessHost::HandleSelectFolderImpl(
284 const base::string16
& title
,
285 const SelectFolderCompletion
& on_success
,
286 const FileSelectionCanceled
& on_failure
) {
287 // Can only have one of these operations in flight.
288 DCHECK(select_folder_completion_callback_
.is_null());
289 DCHECK(failure_callback_
.is_null());
290 select_folder_completion_callback_
= on_success
;
291 failure_callback_
= on_failure
;
293 Send(new MetroViewerHostMsg_DisplaySelectFolder(title
));
296 void MetroViewerProcessHost::NotifyChannelConnected() {
297 if (channel_connected_event_
)
298 channel_connected_event_
->Signal();
301 void MetroViewerProcessHost::OnFileSaveAsDone(bool success
,
302 const base::FilePath
& filename
,
305 file_saveas_completion_callback_
.Run(filename
, filter_index
, NULL
);
307 failure_callback_
.Run(NULL
);
308 file_saveas_completion_callback_
.Reset();
309 failure_callback_
.Reset();
313 void MetroViewerProcessHost::OnFileOpenDone(bool success
,
314 const base::FilePath
& filename
) {
316 file_open_completion_callback_
.Run(base::FilePath(filename
), 0, NULL
);
318 failure_callback_
.Run(NULL
);
319 file_open_completion_callback_
.Reset();
320 failure_callback_
.Reset();
323 void MetroViewerProcessHost::OnMultiFileOpenDone(
325 const std::vector
<base::FilePath
>& files
) {
327 multi_file_open_completion_callback_
.Run(files
, NULL
);
329 failure_callback_
.Run(NULL
);
330 multi_file_open_completion_callback_
.Reset();
331 failure_callback_
.Reset();
334 void MetroViewerProcessHost::OnSelectFolderDone(
336 const base::FilePath
& folder
) {
338 select_folder_completion_callback_
.Run(base::FilePath(folder
), 0, NULL
);
340 failure_callback_
.Run(NULL
);
341 select_folder_completion_callback_
.Reset();
342 failure_callback_
.Reset();