cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / win8 / metro_driver / chrome_app_view_ash.cc
blob8686b53c3930d5fbd348e4f5e919d8bd9d523b8c
1 // Copyright (c) 2012 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/metro_driver/stdafx.h"
6 #include "win8/metro_driver/chrome_app_view_ash.h"
8 #include <corewindow.h>
9 #include <shellapi.h>
10 #include <windows.foundation.h>
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/path_service.h"
16 #include "base/threading/thread.h"
17 #include "base/win/metro.h"
18 #include "base/win/win_util.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "ipc/ipc_channel.h"
21 #include "ipc/ipc_channel_proxy.h"
22 #include "ipc/ipc_sender.h"
23 #include "ui/base/gestures/gesture_sequence.h"
24 #include "ui/metro_viewer/metro_viewer_messages.h"
25 #include "win8/metro_driver/file_picker_ash.h"
26 #include "win8/metro_driver/metro_driver.h"
27 #include "win8/metro_driver/winrt_utils.h"
28 #include "win8/viewer/metro_viewer_constants.h"
30 typedef winfoundtn::ITypedEventHandler<
31 winapp::Core::CoreApplicationView*,
32 winapp::Activation::IActivatedEventArgs*> ActivatedHandler;
34 typedef winfoundtn::ITypedEventHandler<
35 winui::Core::CoreWindow*,
36 winui::Core::PointerEventArgs*> PointerEventHandler;
38 typedef winfoundtn::ITypedEventHandler<
39 winui::Core::CoreWindow*,
40 winui::Core::KeyEventArgs*> KeyEventHandler;
42 typedef winfoundtn::ITypedEventHandler<
43 winui::Core::CoreDispatcher*,
44 winui::Core::AcceleratorKeyEventArgs*> AcceleratorKeyEventHandler;
46 typedef winfoundtn::ITypedEventHandler<
47 winui::Core::CoreWindow*,
48 winui::Core::CharacterReceivedEventArgs*> CharEventHandler;
50 typedef winfoundtn::ITypedEventHandler<
51 winui::Core::CoreWindow*,
52 winui::Core::VisibilityChangedEventArgs*> VisibilityChangedHandler;
54 typedef winfoundtn::ITypedEventHandler<
55 winui::Core::CoreWindow*,
56 winui::Core::WindowActivatedEventArgs*> WindowActivatedHandler;
58 typedef winfoundtn::ITypedEventHandler<
59 winui::Core::CoreWindow*,
60 winui::Core::WindowSizeChangedEventArgs*> SizeChangedHandler;
62 // This function is exported by chrome.exe.
63 typedef int (__cdecl *BreakpadExceptionHandler)(EXCEPTION_POINTERS* info);
65 // Global information used across the metro driver.
66 struct Globals {
67 winapp::Activation::ApplicationExecutionState previous_state;
68 winapp::Core::ICoreApplicationExit* app_exit;
69 BreakpadExceptionHandler breakpad_exception_handler;
70 } globals;
72 namespace {
74 // TODO(robertshield): Share this with chrome_app_view.cc
75 void MetroExit() {
76 globals.app_exit->Exit();
79 class ChromeChannelListener : public IPC::Listener {
80 public:
81 ChromeChannelListener(base::MessageLoop* ui_loop, ChromeAppViewAsh* app_view)
82 : ui_proxy_(ui_loop->message_loop_proxy()), app_view_(app_view) {}
84 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
85 IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener, message)
86 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor, OnSetCursor)
87 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileOpen,
88 OnDisplayFileOpenDialog)
89 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileSaveAs,
90 OnDisplayFileSaveAsDialog)
91 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplaySelectFolder,
92 OnDisplayFolderPicker)
93 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPos, OnSetCursorPos)
94 IPC_MESSAGE_UNHANDLED(__debugbreak())
95 IPC_END_MESSAGE_MAP()
96 return true;
99 virtual void OnChannelError() OVERRIDE {
100 DVLOG(1) << "Channel error";
101 MetroExit();
104 private:
105 void OnSetCursor(int64 cursor) {
106 ui_proxy_->PostTask(FROM_HERE,
107 base::Bind(&ChromeAppViewAsh::OnSetCursor,
108 base::Unretained(app_view_),
109 reinterpret_cast<HCURSOR>(cursor)));
112 void OnDisplayFileOpenDialog(const string16& title,
113 const string16& filter,
114 const base::FilePath& default_path,
115 bool allow_multiple_files) {
116 ui_proxy_->PostTask(FROM_HERE,
117 base::Bind(&ChromeAppViewAsh::OnDisplayFileOpenDialog,
118 base::Unretained(app_view_),
119 title,
120 filter,
121 default_path,
122 allow_multiple_files));
125 void OnDisplayFileSaveAsDialog(
126 const MetroViewerHostMsg_SaveAsDialogParams& params) {
127 ui_proxy_->PostTask(
128 FROM_HERE,
129 base::Bind(&ChromeAppViewAsh::OnDisplayFileSaveAsDialog,
130 base::Unretained(app_view_),
131 params));
134 void OnDisplayFolderPicker(const string16& title) {
135 ui_proxy_->PostTask(
136 FROM_HERE,
137 base::Bind(&ChromeAppViewAsh::OnDisplayFolderPicker,
138 base::Unretained(app_view_),
139 title));
142 void OnSetCursorPos(int x, int y) {
143 VLOG(1) << "In IPC OnSetCursorPos: " << x << ", " << y;
144 ui_proxy_->PostTask(
145 FROM_HERE,
146 base::Bind(&ChromeAppViewAsh::OnSetCursorPos,
147 base::Unretained(app_view_),
148 x, y));
152 scoped_refptr<base::MessageLoopProxy> ui_proxy_;
153 ChromeAppViewAsh* app_view_;
156 bool WaitForChromeIPCConnection(const std::string& channel_name) {
157 int ms_elapsed = 0;
158 while (!IPC::Channel::IsNamedServerInitialized(channel_name) &&
159 ms_elapsed < 10000) {
160 ms_elapsed += 500;
161 Sleep(500);
163 return IPC::Channel::IsNamedServerInitialized(channel_name);
166 // This class helps decoding the pointer properties of an event.
167 class PointerInfoHandler {
168 public:
169 PointerInfoHandler() :
170 x_(0),
171 y_(0),
172 wheel_delta_(0),
173 update_kind_(winui::Input::PointerUpdateKind_Other),
174 timestamp_(0),
175 pointer_id_(0) {}
177 HRESULT Init(winui::Core::IPointerEventArgs* args) {
178 HRESULT hr = args->get_CurrentPoint(&pointer_point_);
179 if (FAILED(hr))
180 return hr;
182 winfoundtn::Point point;
183 hr = pointer_point_->get_Position(&point);
184 if (FAILED(hr))
185 return hr;
187 mswr::ComPtr<winui::Input::IPointerPointProperties> properties;
188 hr = pointer_point_->get_Properties(&properties);
189 if (FAILED(hr))
190 return hr;
192 hr = properties->get_PointerUpdateKind(&update_kind_);
193 if (FAILED(hr))
194 return hr;
196 hr = properties->get_MouseWheelDelta(&wheel_delta_);
197 if (FAILED(hr))
198 return hr;
199 x_ = point.X;
200 y_ = point.Y;
201 pointer_point_->get_Timestamp(&timestamp_);
202 pointer_point_->get_PointerId(&pointer_id_);
203 // Map the OS touch event id to a range allowed by the gesture recognizer.
204 if (IsTouch())
205 pointer_id_ %= ui::GestureSequence::kMaxGesturePoints;
206 return S_OK;
209 bool IsType(windevs::Input::PointerDeviceType type) const {
210 mswr::ComPtr<windevs::Input::IPointerDevice> pointer_device;
211 CheckHR(pointer_point_->get_PointerDevice(&pointer_device));
212 windevs::Input::PointerDeviceType device_type;
213 CheckHR(pointer_device->get_PointerDeviceType(&device_type));
214 return (device_type == type);
217 bool IsMouse() const {
218 return IsType(windevs::Input::PointerDeviceType_Mouse);
221 bool IsTouch() const {
222 return IsType(windevs::Input::PointerDeviceType_Touch);
225 int32 wheel_delta() const {
226 return wheel_delta_;
229 ui::EventFlags flags() {
230 switch (update_kind_) {
231 case winui::Input::PointerUpdateKind_LeftButtonPressed:
232 return ui::EF_LEFT_MOUSE_BUTTON;
233 case winui::Input::PointerUpdateKind_LeftButtonReleased:
234 return ui::EF_LEFT_MOUSE_BUTTON;
235 case winui::Input::PointerUpdateKind_RightButtonPressed:
236 return ui::EF_RIGHT_MOUSE_BUTTON;
237 case winui::Input::PointerUpdateKind_RightButtonReleased:
238 return ui::EF_RIGHT_MOUSE_BUTTON;
239 case winui::Input::PointerUpdateKind_MiddleButtonPressed:
240 return ui::EF_MIDDLE_MOUSE_BUTTON;
241 case winui::Input::PointerUpdateKind_MiddleButtonReleased:
242 return ui::EF_MIDDLE_MOUSE_BUTTON;
243 default:
244 return ui::EF_NONE;
248 int x() const { return x_; }
249 int y() const { return y_; }
251 uint32 pointer_id() const {
252 return pointer_id_;
255 uint64 timestamp() const { return timestamp_; }
257 private:
258 int x_;
259 int y_;
260 int wheel_delta_;
261 uint32 pointer_id_;
262 winui::Input::PointerUpdateKind update_kind_;
263 mswr::ComPtr<winui::Input::IPointerPoint> pointer_point_;
264 uint64 timestamp_;
267 void RunMessageLoop(winui::Core::ICoreDispatcher* dispatcher) {
268 // We're entering a nested message loop, let's allow dispatching
269 // tasks while we're in there.
270 base::MessageLoop::current()->SetNestableTasksAllowed(true);
272 // Enter main core message loop. There are several ways to exit it
273 // Nicely:
274 // 1 - User action like ALT-F4.
275 // 2 - Calling ICoreApplicationExit::Exit().
276 // 3- Posting WM_CLOSE to the core window.
277 HRESULT hr = dispatcher->ProcessEvents(
278 winui::Core::CoreProcessEventsOption
279 ::CoreProcessEventsOption_ProcessUntilQuit);
281 // Wind down the thread's chrome message loop.
282 base::MessageLoop::current()->Quit();
285 // Helper to return the state of the shift/control/alt keys.
286 uint32 GetKeyboardEventFlags() {
287 uint32 flags = 0;
288 if (base::win::IsShiftPressed())
289 flags |= ui::EF_SHIFT_DOWN;
290 if (base::win::IsCtrlPressed())
291 flags |= ui::EF_CONTROL_DOWN;
292 if (base::win::IsAltPressed())
293 flags |= ui::EF_ALT_DOWN;
294 return flags;
297 } // namespace
299 ChromeAppViewAsh::ChromeAppViewAsh()
300 : mouse_down_flags_(ui::EF_NONE),
301 ui_channel_(nullptr),
302 core_window_hwnd_(NULL),
303 ui_loop_(base::MessageLoop::TYPE_UI) {
304 DVLOG(1) << __FUNCTION__;
305 globals.previous_state =
306 winapp::Activation::ApplicationExecutionState_NotRunning;
309 ChromeAppViewAsh::~ChromeAppViewAsh() {
310 DVLOG(1) << __FUNCTION__;
313 IFACEMETHODIMP
314 ChromeAppViewAsh::Initialize(winapp::Core::ICoreApplicationView* view) {
315 view_ = view;
316 DVLOG(1) << __FUNCTION__;
317 HRESULT hr = view_->add_Activated(mswr::Callback<ActivatedHandler>(
318 this, &ChromeAppViewAsh::OnActivate).Get(),
319 &activated_token_);
320 CheckHR(hr);
321 return hr;
324 IFACEMETHODIMP
325 ChromeAppViewAsh::SetWindow(winui::Core::ICoreWindow* window) {
326 window_ = window;
327 DVLOG(1) << __FUNCTION__;
329 // Retrieve the native window handle via the interop layer.
330 mswr::ComPtr<ICoreWindowInterop> interop;
331 HRESULT hr = window->QueryInterface(interop.GetAddressOf());
332 CheckHR(hr);
333 hr = interop->get_WindowHandle(&core_window_hwnd_);
334 CheckHR(hr);
336 hr = window_->add_SizeChanged(mswr::Callback<SizeChangedHandler>(
337 this, &ChromeAppViewAsh::OnSizeChanged).Get(),
338 &sizechange_token_);
339 CheckHR(hr);
341 // Register for pointer and keyboard notifications. We forward
342 // them to the browser process via IPC.
343 hr = window_->add_PointerMoved(mswr::Callback<PointerEventHandler>(
344 this, &ChromeAppViewAsh::OnPointerMoved).Get(),
345 &pointermoved_token_);
346 CheckHR(hr);
348 hr = window_->add_PointerPressed(mswr::Callback<PointerEventHandler>(
349 this, &ChromeAppViewAsh::OnPointerPressed).Get(),
350 &pointerpressed_token_);
351 CheckHR(hr);
353 hr = window_->add_PointerReleased(mswr::Callback<PointerEventHandler>(
354 this, &ChromeAppViewAsh::OnPointerReleased).Get(),
355 &pointerreleased_token_);
356 CheckHR(hr);
358 hr = window_->add_KeyDown(mswr::Callback<KeyEventHandler>(
359 this, &ChromeAppViewAsh::OnKeyDown).Get(),
360 &keydown_token_);
361 CheckHR(hr);
363 hr = window_->add_KeyUp(mswr::Callback<KeyEventHandler>(
364 this, &ChromeAppViewAsh::OnKeyUp).Get(),
365 &keyup_token_);
366 CheckHR(hr);
368 mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher;
369 hr = window_->get_Dispatcher(&dispatcher);
370 CheckHR(hr, "Get Dispatcher failed.");
372 mswr::ComPtr<winui::Core::ICoreAcceleratorKeys> accelerator_keys;
373 hr = dispatcher.CopyTo(__uuidof(winui::Core::ICoreAcceleratorKeys),
374 reinterpret_cast<void**>(
375 accelerator_keys.GetAddressOf()));
376 CheckHR(hr, "QI for ICoreAcceleratorKeys failed.");
377 hr = accelerator_keys->add_AcceleratorKeyActivated(
378 mswr::Callback<AcceleratorKeyEventHandler>(
379 this, &ChromeAppViewAsh::OnAcceleratorKeyDown).Get(),
380 &accel_keydown_token_);
381 CheckHR(hr);
383 hr = window_->add_PointerWheelChanged(mswr::Callback<PointerEventHandler>(
384 this, &ChromeAppViewAsh::OnWheel).Get(),
385 &wheel_token_);
386 CheckHR(hr);
388 hr = window_->add_CharacterReceived(mswr::Callback<CharEventHandler>(
389 this, &ChromeAppViewAsh::OnCharacterReceived).Get(),
390 &character_received_token_);
391 CheckHR(hr);
393 hr = window_->add_VisibilityChanged(mswr::Callback<VisibilityChangedHandler>(
394 this, &ChromeAppViewAsh::OnVisibilityChanged).Get(),
395 &visibility_changed_token_);
396 CheckHR(hr);
398 hr = window_->add_Activated(mswr::Callback<WindowActivatedHandler>(
399 this, &ChromeAppViewAsh::OnWindowActivated).Get(),
400 &window_activated_token_);
401 CheckHR(hr);
403 // By initializing the direct 3D swap chain with the corewindow
404 // we can now directly blit to it from the browser process.
405 direct3d_helper_.Initialize(window);
406 DVLOG(1) << "Initialized Direct3D.";
407 return S_OK;
410 IFACEMETHODIMP
411 ChromeAppViewAsh::Load(HSTRING entryPoint) {
412 DVLOG(1) << __FUNCTION__;
413 return S_OK;
416 IFACEMETHODIMP
417 ChromeAppViewAsh::Run() {
418 DVLOG(1) << __FUNCTION__;
419 mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher;
420 HRESULT hr = window_->get_Dispatcher(&dispatcher);
421 CheckHR(hr, "Dispatcher failed.");
423 hr = window_->Activate();
424 if (FAILED(hr)) {
425 DLOG(WARNING) << "activation failed hr=" << hr;
426 return hr;
429 // Create the IPC channel IO thread. It needs to out-live the ChannelProxy.
430 base::Thread io_thread("metro_IO_thread");
431 base::Thread::Options options;
432 options.message_loop_type = base::MessageLoop::TYPE_IO;
433 io_thread.StartWithOptions(options);
435 // Start up Chrome and wait for the desired IPC server connection to exist.
436 WaitForChromeIPCConnection(win8::kMetroViewerIPCChannelName);
438 // In Aura mode we create an IPC channel to the browser, then ask it to
439 // connect to us.
440 ChromeChannelListener ui_channel_listener(&ui_loop_, this);
441 IPC::ChannelProxy ui_channel(win8::kMetroViewerIPCChannelName,
442 IPC::Channel::MODE_NAMED_CLIENT,
443 &ui_channel_listener,
444 io_thread.message_loop_proxy());
445 ui_channel_ = &ui_channel;
447 // Upon receipt of the MetroViewerHostMsg_SetTargetSurface message the
448 // browser will use D3D from the browser process to present to our Window.
449 ui_channel_->Send(new MetroViewerHostMsg_SetTargetSurface(
450 gfx::NativeViewId(core_window_hwnd_)));
451 DVLOG(1) << "ICoreWindow sent " << core_window_hwnd_;
453 // Send an initial size message so that the Ash root window host gets sized
454 // correctly.
455 RECT rect = {0};
456 ::GetWindowRect(core_window_hwnd_, &rect);
457 ui_channel_->Send(
458 new MetroViewerHostMsg_WindowSizeChanged(rect.right - rect.left,
459 rect.bottom - rect.top));
461 // And post the task that'll do the inner Metro message pumping to it.
462 ui_loop_.PostTask(FROM_HERE, base::Bind(&RunMessageLoop, dispatcher.Get()));
463 ui_loop_.Run();
465 DVLOG(0) << "ProcessEvents done, hr=" << hr;
466 return hr;
469 IFACEMETHODIMP
470 ChromeAppViewAsh::Uninitialize() {
471 DVLOG(1) << __FUNCTION__;
472 window_ = nullptr;
473 view_ = nullptr;
474 core_window_hwnd_ = NULL;
475 return S_OK;
478 // static
479 HRESULT ChromeAppViewAsh::Unsnap() {
480 mswr::ComPtr<winui::ViewManagement::IApplicationViewStatics> view_statics;
481 HRESULT hr = winrt_utils::CreateActivationFactory(
482 RuntimeClass_Windows_UI_ViewManagement_ApplicationView,
483 view_statics.GetAddressOf());
484 CheckHR(hr);
486 winui::ViewManagement::ApplicationViewState state =
487 winui::ViewManagement::ApplicationViewState_FullScreenLandscape;
488 hr = view_statics->get_Value(&state);
489 CheckHR(hr);
491 if (state == winui::ViewManagement::ApplicationViewState_Snapped) {
492 boolean success = FALSE;
493 hr = view_statics->TryUnsnap(&success);
495 if (FAILED(hr) || !success) {
496 LOG(ERROR) << "Failed to unsnap. Error 0x" << hr;
497 if (SUCCEEDED(hr))
498 hr = E_UNEXPECTED;
501 return hr;
505 void ChromeAppViewAsh::OnSetCursor(HCURSOR cursor) {
506 ::SetCursor(HCURSOR(cursor));
509 void ChromeAppViewAsh::OnDisplayFileOpenDialog(
510 const string16& title,
511 const string16& filter,
512 const base::FilePath& default_path,
513 bool allow_multiple_files) {
514 DVLOG(1) << __FUNCTION__;
516 // The OpenFilePickerSession instance is deleted when we receive a
517 // callback from the OpenFilePickerSession class about the completion of the
518 // operation.
519 FilePickerSessionBase* file_picker_ =
520 new OpenFilePickerSession(this,
521 title,
522 filter,
523 default_path,
524 allow_multiple_files);
525 file_picker_->Run();
528 void ChromeAppViewAsh::OnDisplayFileSaveAsDialog(
529 const MetroViewerHostMsg_SaveAsDialogParams& params) {
530 DVLOG(1) << __FUNCTION__;
532 // The SaveFilePickerSession instance is deleted when we receive a
533 // callback from the SaveFilePickerSession class about the completion of the
534 // operation.
535 FilePickerSessionBase* file_picker_ =
536 new SaveFilePickerSession(this, params);
537 file_picker_->Run();
540 void ChromeAppViewAsh::OnDisplayFolderPicker(const string16& title) {
541 DVLOG(1) << __FUNCTION__;
542 // The FolderPickerSession instance is deleted when we receive a
543 // callback from the FolderPickerSession class about the completion of the
544 // operation.
545 FilePickerSessionBase* file_picker_ = new FolderPickerSession(this, title);
546 file_picker_->Run();
549 void ChromeAppViewAsh::OnSetCursorPos(int x, int y) {
550 if (ui_channel_) {
551 ::SetCursorPos(x, y);
552 DVLOG(1) << "In UI OnSetCursorPos: " << x << ", " << y;
553 ui_channel_->Send(new MetroViewerHostMsg_SetCursorPosAck());
554 // Generate a fake mouse move which matches the SetCursor coordinates as
555 // the browser expects to receive a mouse move for these coordinates.
556 // It is not clear why we don't receive a real mouse move in response to
557 // the SetCursorPos calll above.
558 ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(x, y, 0));
562 void ChromeAppViewAsh::OnOpenFileCompleted(
563 OpenFilePickerSession* open_file_picker,
564 bool success) {
565 DVLOG(1) << __FUNCTION__;
566 DVLOG(1) << "Success: " << success;
567 if (ui_channel_) {
568 if (open_file_picker->allow_multi_select()) {
569 ui_channel_->Send(new MetroViewerHostMsg_MultiFileOpenDone(
570 success, open_file_picker->filenames()));
571 } else {
572 ui_channel_->Send(new MetroViewerHostMsg_FileOpenDone(
573 success, base::FilePath(open_file_picker->result())));
576 delete open_file_picker;
579 void ChromeAppViewAsh::OnSaveFileCompleted(
580 SaveFilePickerSession* save_file_picker,
581 bool success) {
582 DVLOG(1) << __FUNCTION__;
583 DVLOG(1) << "Success: " << success;
584 if (ui_channel_) {
585 ui_channel_->Send(new MetroViewerHostMsg_FileSaveAsDone(
586 success,
587 base::FilePath(save_file_picker->result()),
588 save_file_picker->filter_index()));
590 delete save_file_picker;
593 void ChromeAppViewAsh::OnFolderPickerCompleted(
594 FolderPickerSession* folder_picker,
595 bool success) {
596 DVLOG(1) << __FUNCTION__;
597 DVLOG(1) << "Success: " << success;
598 if (ui_channel_) {
599 ui_channel_->Send(new MetroViewerHostMsg_SelectFolderDone(
600 success,
601 base::FilePath(folder_picker->result())));
603 delete folder_picker;
606 HRESULT ChromeAppViewAsh::OnActivate(
607 winapp::Core::ICoreApplicationView*,
608 winapp::Activation::IActivatedEventArgs* args) {
609 DVLOG(1) << __FUNCTION__;
610 // Note: If doing more work in this function, you migth need to call
611 // get_PreviousExecutionState() and skip the work if the result is
612 // ApplicationExecutionState_Running and globals.previous_state is too.
613 args->get_PreviousExecutionState(&globals.previous_state);
614 DVLOG(1) << "Previous Execution State: " << globals.previous_state;
616 winapp::Activation::ActivationKind activation_kind;
617 CheckHR(args->get_Kind(&activation_kind));
618 if (activation_kind == winapp::Activation::ActivationKind_Search)
619 HandleSearchRequest(args);
620 else if (activation_kind == winapp::Activation::ActivationKind_Protocol)
621 HandleProtocolRequest(args);
622 // We call ICoreWindow::Activate after the handling for the search/protocol
623 // requests because Chrome can be launched to handle a search request which
624 // in turn launches the chrome browser process in desktop mode via
625 // ShellExecute. If we call ICoreWindow::Activate before this, then
626 // Windows kills the metro chrome process when it calls ShellExecute. Seems
627 // to be a bug.
628 window_->Activate();
629 return S_OK;
632 HRESULT ChromeAppViewAsh::OnPointerMoved(winui::Core::ICoreWindow* sender,
633 winui::Core::IPointerEventArgs* args) {
634 PointerInfoHandler pointer;
635 HRESULT hr = pointer.Init(args);
636 if (FAILED(hr))
637 return hr;
639 if (pointer.IsMouse()) {
640 ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(
641 pointer.x(),
642 pointer.y(),
643 mouse_down_flags_ | GetKeyboardEventFlags()));
644 } else {
645 DCHECK(pointer.IsTouch());
646 ui_channel_->Send(new MetroViewerHostMsg_TouchMoved(pointer.x(),
647 pointer.y(),
648 pointer.timestamp(),
649 pointer.pointer_id()));
651 return S_OK;
654 // NOTE: From experimentation, it seems like Metro only sends a PointerPressed
655 // event for the first button pressed and the last button released in a sequence
656 // of mouse events.
657 // For example, a sequence of LEFT_DOWN, RIGHT_DOWN, LEFT_UP, RIGHT_UP results
658 // only in PointerPressed(LEFT)/PointerReleased(RIGHT) events.
659 HRESULT ChromeAppViewAsh::OnPointerPressed(
660 winui::Core::ICoreWindow* sender,
661 winui::Core::IPointerEventArgs* args) {
662 PointerInfoHandler pointer;
663 HRESULT hr = pointer.Init(args);
664 if (FAILED(hr))
665 return hr;
667 if (pointer.IsMouse()) {
668 mouse_down_flags_ = pointer.flags();
669 ui_channel_->Send(new MetroViewerHostMsg_MouseButton(
670 pointer.x(),
671 pointer.y(),
673 ui::ET_MOUSE_PRESSED,
674 static_cast<ui::EventFlags>(
675 mouse_down_flags_ | GetKeyboardEventFlags())));
676 } else {
677 DCHECK(pointer.IsTouch());
678 ui_channel_->Send(new MetroViewerHostMsg_TouchDown(pointer.x(),
679 pointer.y(),
680 pointer.timestamp(),
681 pointer.pointer_id()));
683 return S_OK;
686 HRESULT ChromeAppViewAsh::OnPointerReleased(
687 winui::Core::ICoreWindow* sender,
688 winui::Core::IPointerEventArgs* args) {
689 PointerInfoHandler pointer;
690 HRESULT hr = pointer.Init(args);
691 if (FAILED(hr))
692 return hr;
694 if (pointer.IsMouse()) {
695 mouse_down_flags_ = ui::EF_NONE;
696 ui_channel_->Send(new MetroViewerHostMsg_MouseButton(
697 pointer.x(),
698 pointer.y(),
700 ui::ET_MOUSE_RELEASED,
701 static_cast<ui::EventFlags>(
702 pointer.flags() | GetKeyboardEventFlags())));
703 } else {
704 DCHECK(pointer.IsTouch());
705 ui_channel_->Send(new MetroViewerHostMsg_TouchUp(pointer.x(),
706 pointer.y(),
707 pointer.timestamp(),
708 pointer.pointer_id()));
710 return S_OK;
713 HRESULT ChromeAppViewAsh::OnWheel(
714 winui::Core::ICoreWindow* sender,
715 winui::Core::IPointerEventArgs* args) {
716 PointerInfoHandler pointer;
717 HRESULT hr = pointer.Init(args);
718 if (FAILED(hr))
719 return hr;
720 DCHECK(pointer.IsMouse());
721 ui_channel_->Send(new MetroViewerHostMsg_MouseButton(pointer.x(), pointer.y(),
722 pointer.wheel_delta(),
723 ui::ET_MOUSEWHEEL,
724 ui::EF_NONE));
725 return S_OK;
728 HRESULT ChromeAppViewAsh::OnKeyDown(
729 winui::Core::ICoreWindow* sender,
730 winui::Core::IKeyEventArgs* args) {
731 winsys::VirtualKey virtual_key;
732 HRESULT hr = args->get_VirtualKey(&virtual_key);
733 if (FAILED(hr))
734 return hr;
735 winui::Core::CorePhysicalKeyStatus status;
736 hr = args->get_KeyStatus(&status);
737 if (FAILED(hr))
738 return hr;
740 ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key,
741 status.RepeatCount,
742 status.ScanCode,
743 GetKeyboardEventFlags()));
744 return S_OK;
747 HRESULT ChromeAppViewAsh::OnKeyUp(
748 winui::Core::ICoreWindow* sender,
749 winui::Core::IKeyEventArgs* args) {
750 winsys::VirtualKey virtual_key;
751 HRESULT hr = args->get_VirtualKey(&virtual_key);
752 if (FAILED(hr))
753 return hr;
754 winui::Core::CorePhysicalKeyStatus status;
755 hr = args->get_KeyStatus(&status);
756 if (FAILED(hr))
757 return hr;
759 ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key,
760 status.RepeatCount,
761 status.ScanCode,
762 GetKeyboardEventFlags()));
763 return S_OK;
766 HRESULT ChromeAppViewAsh::OnAcceleratorKeyDown(
767 winui::Core::ICoreDispatcher* sender,
768 winui::Core::IAcceleratorKeyEventArgs* args) {
769 winsys::VirtualKey virtual_key;
770 HRESULT hr = args->get_VirtualKey(&virtual_key);
771 if (FAILED(hr))
772 return hr;
773 winui::Core::CorePhysicalKeyStatus status;
774 hr = args->get_KeyStatus(&status);
775 if (FAILED(hr))
776 return hr;
778 winui::Core::CoreAcceleratorKeyEventType event_type;
779 hr = args->get_EventType(&event_type);
780 if (FAILED(hr))
781 return hr;
783 uint32 keyboard_flags = GetKeyboardEventFlags();
785 switch (event_type) {
786 case winui::Core::CoreAcceleratorKeyEventType_SystemCharacter:
787 ui_channel_->Send(new MetroViewerHostMsg_Character(virtual_key,
788 status.RepeatCount,
789 status.ScanCode,
790 keyboard_flags));
791 break;
793 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyDown:
794 ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key,
795 status.RepeatCount,
796 status.ScanCode,
797 keyboard_flags));
798 break;
800 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyUp:
801 ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key,
802 status.RepeatCount,
803 status.ScanCode,
804 keyboard_flags));
805 break;
807 default:
808 break;
810 return S_OK;
813 HRESULT ChromeAppViewAsh::OnCharacterReceived(
814 winui::Core::ICoreWindow* sender,
815 winui::Core::ICharacterReceivedEventArgs* args) {
816 unsigned int char_code = 0;
817 HRESULT hr = args->get_KeyCode(&char_code);
818 if (FAILED(hr))
819 return hr;
821 winui::Core::CorePhysicalKeyStatus status;
822 hr = args->get_KeyStatus(&status);
823 if (FAILED(hr))
824 return hr;
826 ui_channel_->Send(new MetroViewerHostMsg_Character(char_code,
827 status.RepeatCount,
828 status.ScanCode,
829 GetKeyboardEventFlags()));
830 return S_OK;
833 HRESULT ChromeAppViewAsh::OnVisibilityChanged(
834 winui::Core::ICoreWindow* sender,
835 winui::Core::IVisibilityChangedEventArgs* args) {
836 boolean visible = false;
837 HRESULT hr = args->get_Visible(&visible);
838 if (FAILED(hr))
839 return hr;
841 ui_channel_->Send(new MetroViewerHostMsg_VisibilityChanged(!!visible));
842 return S_OK;
845 HRESULT ChromeAppViewAsh::OnWindowActivated(
846 winui::Core::ICoreWindow* sender,
847 winui::Core::IWindowActivatedEventArgs* args) {
848 winui::Core::CoreWindowActivationState state;
849 HRESULT hr = args->get_WindowActivationState(&state);
850 if (FAILED(hr))
851 return hr;
852 DVLOG(1) << "Window activation state: " << state;
853 ui_channel_->Send(new MetroViewerHostMsg_WindowActivated(
854 state != winui::Core::CoreWindowActivationState_Deactivated));
855 return S_OK;
858 HRESULT ChromeAppViewAsh::HandleSearchRequest(
859 winapp::Activation::IActivatedEventArgs* args) {
860 mswr::ComPtr<winapp::Activation::ISearchActivatedEventArgs> search_args;
861 CheckHR(args->QueryInterface(
862 winapp::Activation::IID_ISearchActivatedEventArgs, &search_args));
864 if (!ui_channel_) {
865 DVLOG(1) << "Launched to handle search request";
866 base::FilePath chrome_exe_path;
868 if (!PathService::Get(base::FILE_EXE, &chrome_exe_path))
869 return E_FAIL;
871 SHELLEXECUTEINFO sei = { sizeof(sei) };
872 sei.nShow = SW_SHOWNORMAL;
873 sei.lpFile = chrome_exe_path.value().c_str();
874 sei.lpDirectory = L"";
875 sei.lpParameters =
876 L"--silent-launch --viewer-connection=viewer --windows8-search";
877 ::ShellExecuteEx(&sei);
880 mswrw::HString search_string;
881 CheckHR(search_args->get_QueryText(search_string.GetAddressOf()));
882 string16 search_text(MakeStdWString(search_string.Get()));
884 ui_loop_.PostTask(FROM_HERE,
885 base::Bind(&ChromeAppViewAsh::OnSearchRequest,
886 base::Unretained(this),
887 search_text));
888 return S_OK;
891 HRESULT ChromeAppViewAsh::HandleProtocolRequest(
892 winapp::Activation::IActivatedEventArgs* args) {
893 DVLOG(1) << __FUNCTION__;
894 if (!ui_channel_)
895 DVLOG(1) << "Launched to handle url request";
897 mswr::ComPtr<winapp::Activation::IProtocolActivatedEventArgs>
898 protocol_args;
899 CheckHR(args->QueryInterface(
900 winapp::Activation::IID_IProtocolActivatedEventArgs,
901 &protocol_args));
903 mswr::ComPtr<winfoundtn::IUriRuntimeClass> uri;
904 protocol_args->get_Uri(&uri);
905 mswrw::HString url;
906 uri->get_AbsoluteUri(url.GetAddressOf());
907 string16 actual_url(MakeStdWString(url.Get()));
908 DVLOG(1) << "Received url request: " << actual_url;
910 ui_loop_.PostTask(FROM_HERE,
911 base::Bind(&ChromeAppViewAsh::OnNavigateToUrl,
912 base::Unretained(this),
913 actual_url));
914 return S_OK;
917 void ChromeAppViewAsh::OnSearchRequest(const string16& search_string) {
918 DCHECK(ui_channel_);
919 ui_channel_->Send(new MetroViewerHostMsg_SearchRequest(search_string));
922 void ChromeAppViewAsh::OnNavigateToUrl(const string16& url) {
923 DCHECK(ui_channel_);
924 ui_channel_->Send(new MetroViewerHostMsg_OpenURL(url));
927 HRESULT ChromeAppViewAsh::OnSizeChanged(winui::Core::ICoreWindow* sender,
928 winui::Core::IWindowSizeChangedEventArgs* args) {
929 if (!window_) {
930 return S_OK;
933 winfoundtn::Size size;
934 HRESULT hr = args->get_Size(&size);
935 if (FAILED(hr))
936 return hr;
938 uint32 cx = static_cast<uint32>(size.Width);
939 uint32 cy = static_cast<uint32>(size.Height);
941 DVLOG(1) << "Window size changed: width=" << cx << ", height=" << cy;
942 ui_channel_->Send(new MetroViewerHostMsg_WindowSizeChanged(cx, cy));
943 return S_OK;
946 ///////////////////////////////////////////////////////////////////////////////
948 ChromeAppViewFactory::ChromeAppViewFactory(
949 winapp::Core::ICoreApplication* icore_app,
950 LPTHREAD_START_ROUTINE host_main,
951 void* host_context) {
952 mswr::ComPtr<winapp::Core::ICoreApplication> core_app(icore_app);
953 mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit;
954 CheckHR(core_app.As(&app_exit));
955 globals.app_exit = app_exit.Detach();
958 IFACEMETHODIMP
959 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) {
960 *view = mswr::Make<ChromeAppViewAsh>().Detach();
961 return (*view) ? S_OK : E_OUTOFMEMORY;