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/process/process_handle.h"
16 #include "base/strings/string16.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "base/time/time.h"
19 #include "base/win/scoped_comptr.h"
20 #include "base/win/windows_version.h"
21 #include "ipc/ipc_channel_proxy.h"
22 #include "ipc/ipc_message.h"
23 #include "ipc/ipc_message_macros.h"
24 #include "ui/aura/remote_window_tree_host_win.h"
25 #include "ui/metro_viewer/metro_viewer_messages.h"
26 #include "win8/viewer/metro_viewer_constants.h"
30 const int kViewerProcessConnectionTimeoutSecs
= 60;
37 MetroViewerProcessHost
* MetroViewerProcessHost::instance_
= NULL
;
39 MetroViewerProcessHost::InternalMessageFilter::InternalMessageFilter(
40 MetroViewerProcessHost
* owner
)
44 void MetroViewerProcessHost::InternalMessageFilter::OnChannelConnected(
46 owner_
->NotifyChannelConnected();
49 MetroViewerProcessHost::MetroViewerProcessHost(
50 base::SingleThreadTaskRunner
* ipc_task_runner
) {
54 channel_
= IPC::ChannelProxy::Create(kMetroViewerIPCChannelName
,
55 IPC::Channel::MODE_NAMED_SERVER
,
60 MetroViewerProcessHost::~MetroViewerProcessHost() {
66 base::ProcessId viewer_process_id
= GetViewerProcessId();
68 if (message_filter_
) {
69 // Wait for the viewer process to go away.
70 if (viewer_process_id
!= base::kNullProcessId
) {
71 base::ProcessHandle viewer_process
= NULL
;
72 base::OpenProcessHandleWithAccess(
74 PROCESS_QUERY_INFORMATION
| SYNCHRONIZE
,
77 ::WaitForSingleObject(viewer_process
, INFINITE
);
78 ::CloseHandle(viewer_process
);
81 channel_
->RemoveFilter(message_filter_
);
86 base::ProcessId
MetroViewerProcessHost::GetViewerProcessId() {
88 return channel_
->GetPeerPID();
89 return base::kNullProcessId
;
92 bool MetroViewerProcessHost::LaunchViewerAndWaitForConnection(
93 const base::string16
& app_user_model_id
) {
94 DCHECK_EQ(base::kNullProcessId
, channel_
->GetPeerPID());
96 channel_connected_event_
.reset(new base::WaitableEvent(false, false));
98 message_filter_
= new InternalMessageFilter(this);
99 channel_
->AddFilter(message_filter_
);
101 if (base::win::GetVersion() >= base::win::VERSION_WIN8
) {
102 base::win::ScopedComPtr
<IApplicationActivationManager
> activator
;
103 HRESULT hr
= activator
.CreateInstance(CLSID_ApplicationActivationManager
);
106 // Use the "connect" verb to
107 hr
= activator
->ActivateApplication(
108 app_user_model_id
.c_str(), kMetroViewerConnectVerb
, AO_NONE
, &pid
);
111 LOG_IF(ERROR
, FAILED(hr
)) << "Tried and failed to launch Metro Chrome. "
112 << "hr=" << std::hex
<< hr
;
114 // For Windows 7 we need to launch the viewer ourselves.
115 base::FilePath chrome_path
;
116 if (!PathService::Get(base::DIR_EXE
, &chrome_path
))
118 // TODO(cpu): launch with "-ServerName:DefaultBrowserServer"
119 // note that the viewer might try to launch chrome again.
123 // Having launched the viewer process, now we wait for it to connect.
125 channel_connected_event_
->TimedWait(base::TimeDelta::FromSeconds(
126 kViewerProcessConnectionTimeoutSecs
));
127 channel_connected_event_
.reset();
131 bool MetroViewerProcessHost::Send(IPC::Message
* msg
) {
132 return channel_
->Send(msg
);
135 bool MetroViewerProcessHost::OnMessageReceived(
136 const IPC::Message
& message
) {
137 DCHECK(CalledOnValidThread());
139 IPC_BEGIN_MESSAGE_MAP(MetroViewerProcessHost
, message
)
140 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileSaveAsDone
,
142 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileOpenDone
,
144 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MultiFileOpenDone
,
146 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURL
, OnOpenURL
)
147 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SearchRequest
, OnHandleSearchRequest
)
148 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SelectFolderDone
,
150 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetTargetSurface
, OnSetTargetSurface
)
151 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowSizeChanged
,
153 IPC_MESSAGE_UNHANDLED(handled
= false)
154 IPC_END_MESSAGE_MAP()
155 return handled
? true :
156 aura::RemoteWindowTreeHostWin::Instance()->OnMessageReceived(message
);
160 void MetroViewerProcessHost::HandleActivateDesktop(
161 const base::FilePath
& path
,
165 new MetroViewerHostMsg_ActivateDesktop(path
, ash_exit
));
170 void MetroViewerProcessHost::HandleMetroExit() {
172 instance_
->Send(new MetroViewerHostMsg_MetroExit());
176 void MetroViewerProcessHost::HandleOpenFile(
177 const base::string16
& title
,
178 const base::FilePath
& default_path
,
179 const base::string16
& filter
,
180 const OpenFileCompletion
& on_success
,
181 const FileSelectionCanceled
& on_failure
) {
183 instance_
->HandleOpenFileImpl(title
, default_path
, filter
, on_success
,
189 void MetroViewerProcessHost::HandleOpenMultipleFiles(
190 const base::string16
& title
,
191 const base::FilePath
& default_path
,
192 const base::string16
& filter
,
193 const OpenMultipleFilesCompletion
& on_success
,
194 const FileSelectionCanceled
& on_failure
) {
196 instance_
->HandleOpenMultipleFilesImpl(title
, default_path
, filter
,
197 on_success
, on_failure
);
202 void MetroViewerProcessHost::HandleSaveFile(
203 const base::string16
& title
,
204 const base::FilePath
& default_path
,
205 const base::string16
& filter
,
207 const base::string16
& default_extension
,
208 const SaveFileCompletion
& on_success
,
209 const FileSelectionCanceled
& on_failure
) {
211 instance_
->HandleSaveFileImpl(title
, default_path
, filter
, filter_index
,
212 default_extension
, on_success
, on_failure
);
217 void MetroViewerProcessHost::HandleSelectFolder(
218 const base::string16
& title
,
219 const SelectFolderCompletion
& on_success
,
220 const FileSelectionCanceled
& on_failure
) {
222 instance_
->HandleSelectFolderImpl(title
, on_success
, on_failure
);
225 void MetroViewerProcessHost::HandleOpenFileImpl(
226 const base::string16
& title
,
227 const base::FilePath
& default_path
,
228 const base::string16
& filter
,
229 const OpenFileCompletion
& on_success
,
230 const FileSelectionCanceled
& on_failure
) {
231 // Can only have one of these operations in flight.
232 DCHECK(file_open_completion_callback_
.is_null());
233 DCHECK(failure_callback_
.is_null());
235 file_open_completion_callback_
= on_success
;
236 failure_callback_
= on_failure
;
238 Send(new MetroViewerHostMsg_DisplayFileOpen(title
, filter
, default_path
,
242 void MetroViewerProcessHost::HandleOpenMultipleFilesImpl(
243 const base::string16
& title
,
244 const base::FilePath
& default_path
,
245 const base::string16
& filter
,
246 const OpenMultipleFilesCompletion
& on_success
,
247 const FileSelectionCanceled
& on_failure
) {
248 // Can only have one of these operations in flight.
249 DCHECK(multi_file_open_completion_callback_
.is_null());
250 DCHECK(failure_callback_
.is_null());
251 multi_file_open_completion_callback_
= on_success
;
252 failure_callback_
= on_failure
;
254 Send(new MetroViewerHostMsg_DisplayFileOpen(title
, filter
, default_path
,
258 void MetroViewerProcessHost::HandleSaveFileImpl(
259 const base::string16
& title
,
260 const base::FilePath
& default_path
,
261 const base::string16
& filter
,
263 const base::string16
& default_extension
,
264 const SaveFileCompletion
& on_success
,
265 const FileSelectionCanceled
& on_failure
) {
266 MetroViewerHostMsg_SaveAsDialogParams params
;
267 params
.title
= title
;
268 params
.default_extension
= default_extension
;
269 params
.filter
= filter
;
270 params
.filter_index
= filter_index
;
271 params
.suggested_name
= default_path
;
273 // Can only have one of these operations in flight.
274 DCHECK(file_saveas_completion_callback_
.is_null());
275 DCHECK(failure_callback_
.is_null());
276 file_saveas_completion_callback_
= on_success
;
277 failure_callback_
= on_failure
;
279 Send(new MetroViewerHostMsg_DisplayFileSaveAs(params
));
282 void MetroViewerProcessHost::HandleSelectFolderImpl(
283 const base::string16
& title
,
284 const SelectFolderCompletion
& on_success
,
285 const FileSelectionCanceled
& on_failure
) {
286 // Can only have one of these operations in flight.
287 DCHECK(select_folder_completion_callback_
.is_null());
288 DCHECK(failure_callback_
.is_null());
289 select_folder_completion_callback_
= on_success
;
290 failure_callback_
= on_failure
;
292 Send(new MetroViewerHostMsg_DisplaySelectFolder(title
));
295 void MetroViewerProcessHost::NotifyChannelConnected() {
296 if (channel_connected_event_
)
297 channel_connected_event_
->Signal();
300 void MetroViewerProcessHost::OnFileSaveAsDone(bool success
,
301 const base::FilePath
& filename
,
304 file_saveas_completion_callback_
.Run(filename
, filter_index
, NULL
);
306 failure_callback_
.Run(NULL
);
307 file_saveas_completion_callback_
.Reset();
308 failure_callback_
.Reset();
312 void MetroViewerProcessHost::OnFileOpenDone(bool success
,
313 const base::FilePath
& filename
) {
315 file_open_completion_callback_
.Run(base::FilePath(filename
), 0, NULL
);
317 failure_callback_
.Run(NULL
);
318 file_open_completion_callback_
.Reset();
319 failure_callback_
.Reset();
322 void MetroViewerProcessHost::OnMultiFileOpenDone(
324 const std::vector
<base::FilePath
>& files
) {
326 multi_file_open_completion_callback_
.Run(files
, NULL
);
328 failure_callback_
.Run(NULL
);
329 multi_file_open_completion_callback_
.Reset();
330 failure_callback_
.Reset();
333 void MetroViewerProcessHost::OnSelectFolderDone(
335 const base::FilePath
& folder
) {
337 select_folder_completion_callback_
.Run(base::FilePath(folder
), 0, NULL
);
339 failure_callback_
.Run(NULL
);
340 select_folder_completion_callback_
.Reset();
341 failure_callback_
.Reset();