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. 4 5 #include "win8/metro_driver/stdafx.h" 6 #include "win8/metro_driver/chrome_app_view_ash.h" 7 8 #include <corewindow.h> 9 #include <shellapi.h> 10 #include <windows.foundation.h> 11 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" 29 30 typedef winfoundtn::ITypedEventHandler< 31 winapp::Core::CoreApplicationView*, 32 winapp::Activation::IActivatedEventArgs*> ActivatedHandler; 33 34 typedef winfoundtn::ITypedEventHandler< 35 winui::Core::CoreWindow*, 36 winui::Core::PointerEventArgs*> PointerEventHandler; 37 38 typedef winfoundtn::ITypedEventHandler< 39 winui::Core::CoreWindow*, 40 winui::Core::KeyEventArgs*> KeyEventHandler; 41 42 typedef winfoundtn::ITypedEventHandler< 43 winui::Core::CoreDispatcher*, 44 winui::Core::AcceleratorKeyEventArgs*> AcceleratorKeyEventHandler; 45 46 typedef winfoundtn::ITypedEventHandler< 47 winui::Core::CoreWindow*, 48 winui::Core::CharacterReceivedEventArgs*> CharEventHandler; 49 50 typedef winfoundtn::ITypedEventHandler< 51 winui::Core::CoreWindow*, 52 winui::Core::VisibilityChangedEventArgs*> VisibilityChangedHandler; 53 54 typedef winfoundtn::ITypedEventHandler< 55 winui::Core::CoreWindow*, 56 winui::Core::WindowActivatedEventArgs*> WindowActivatedHandler; 57 58 typedef winfoundtn::ITypedEventHandler< 59 winui::Core::CoreWindow*, 60 winui::Core::WindowSizeChangedEventArgs*> SizeChangedHandler; 61 62 // This function is exported by chrome.exe. 63 typedef int (__cdecl *BreakpadExceptionHandler)(EXCEPTION_POINTERS* info); 64 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; 71 72 namespace { 73 74 // TODO(robertshield): Share this with chrome_app_view.cc 75 void MetroExit() { 76 globals.app_exit->Exit(); 77 } 78 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) {} 83 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; 97 } 98 99 virtual void OnChannelError() OVERRIDE { 100 DVLOG(1) << "Channel error"; 101 MetroExit(); 102 } 103 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))); 110 } 111 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)); 123 } 124 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)); 132 } 133 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)); 140 } 141 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)); 149 } 150 151 152 scoped_refptr<base::MessageLoopProxy> ui_proxy_; 153 ChromeAppViewAsh* app_view_; 154 }; 155 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); 162 } 163 return IPC::Channel::IsNamedServerInitialized(channel_name); 164 } 165 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) {} 176 177 HRESULT Init(winui::Core::IPointerEventArgs* args) { 178 HRESULT hr = args->get_CurrentPoint(&pointer_point_); 179 if (FAILED(hr)) 180 return hr; 181 182 winfoundtn::Point point; 183 hr = pointer_point_->get_Position(&point); 184 if (FAILED(hr)) 185 return hr; 186 187 mswr::ComPtr<winui::Input::IPointerPointProperties> properties; 188 hr = pointer_point_->get_Properties(&properties); 189 if (FAILED(hr)) 190 return hr; 191 192 hr = properties->get_PointerUpdateKind(&update_kind_); 193 if (FAILED(hr)) 194 return hr; 195 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(×tamp_); 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; 207 } 208 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); 215 } 216 217 bool IsMouse() const { 218 return IsType(windevs::Input::PointerDeviceType_Mouse); 219 } 220 221 bool IsTouch() const { 222 return IsType(windevs::Input::PointerDeviceType_Touch); 223 } 224 225 int32 wheel_delta() const { 226 return wheel_delta_; 227 } 228 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; 245 }; 246 } 247 248 int x() const { return x_; } 249 int y() const { return y_; } 250 251 uint32 pointer_id() const { 252 return pointer_id_; 253 } 254 255 uint64 timestamp() const { return timestamp_; } 256 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_; 265 }; 266 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); 271 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); 280 281 // Wind down the thread's chrome message loop. 282 base::MessageLoop::current()->Quit(); 283 } 284 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; 295 } 296 297 } // namespace 298 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; 307 } 308 309 ChromeAppViewAsh::~ChromeAppViewAsh() { 310 DVLOG(1) << __FUNCTION__; 311 } 312 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; 322 } 323 324 IFACEMETHODIMP 325 ChromeAppViewAsh::SetWindow(winui::Core::ICoreWindow* window) { 326 window_ = window; 327 DVLOG(1) << __FUNCTION__; 328 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); 335 336 hr = window_->add_SizeChanged(mswr::Callback<SizeChangedHandler>( 337 this, &ChromeAppViewAsh::OnSizeChanged).Get(), 338 &sizechange_token_); 339 CheckHR(hr); 340 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); 347 348 hr = window_->add_PointerPressed(mswr::Callback<PointerEventHandler>( 349 this, &ChromeAppViewAsh::OnPointerPressed).Get(), 350 &pointerpressed_token_); 351 CheckHR(hr); 352 353 hr = window_->add_PointerReleased(mswr::Callback<PointerEventHandler>( 354 this, &ChromeAppViewAsh::OnPointerReleased).Get(), 355 &pointerreleased_token_); 356 CheckHR(hr); 357 358 hr = window_->add_KeyDown(mswr::Callback<KeyEventHandler>( 359 this, &ChromeAppViewAsh::OnKeyDown).Get(), 360 &keydown_token_); 361 CheckHR(hr); 362 363 hr = window_->add_KeyUp(mswr::Callback<KeyEventHandler>( 364 this, &ChromeAppViewAsh::OnKeyUp).Get(), 365 &keyup_token_); 366 CheckHR(hr); 367 368 mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher; 369 hr = window_->get_Dispatcher(&dispatcher); 370 CheckHR(hr, "Get Dispatcher failed."); 371 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); 382 383 hr = window_->add_PointerWheelChanged(mswr::Callback<PointerEventHandler>( 384 this, &ChromeAppViewAsh::OnWheel).Get(), 385 &wheel_token_); 386 CheckHR(hr); 387 388 hr = window_->add_CharacterReceived(mswr::Callback<CharEventHandler>( 389 this, &ChromeAppViewAsh::OnCharacterReceived).Get(), 390 &character_received_token_); 391 CheckHR(hr); 392 393 hr = window_->add_VisibilityChanged(mswr::Callback<VisibilityChangedHandler>( 394 this, &ChromeAppViewAsh::OnVisibilityChanged).Get(), 395 &visibility_changed_token_); 396 CheckHR(hr); 397 398 hr = window_->add_Activated(mswr::Callback<WindowActivatedHandler>( 399 this, &ChromeAppViewAsh::OnWindowActivated).Get(), 400 &window_activated_token_); 401 CheckHR(hr); 402 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; 408 } 409 410 IFACEMETHODIMP 411 ChromeAppViewAsh::Load(HSTRING entryPoint) { 412 DVLOG(1) << __FUNCTION__; 413 return S_OK; 414 } 415 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."); 422 423 hr = window_->Activate(); 424 if (FAILED(hr)) { 425 DLOG(WARNING) << "activation failed hr=" << hr; 426 return hr; 427 } 428 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); 434 435 // Start up Chrome and wait for the desired IPC server connection to exist. 436 WaitForChromeIPCConnection(win8::kMetroViewerIPCChannelName); 437 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; 446 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_; 452 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)); 460 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(); 464 465 DVLOG(0) << "ProcessEvents done, hr=" << hr; 466 return hr; 467 } 468 469 IFACEMETHODIMP 470 ChromeAppViewAsh::Uninitialize() { 471 DVLOG(1) << __FUNCTION__; 472 window_ = nullptr; 473 view_ = nullptr; 474 core_window_hwnd_ = NULL; 475 return S_OK; 476 } 477 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); 485 486 winui::ViewManagement::ApplicationViewState state = 487 winui::ViewManagement::ApplicationViewState_FullScreenLandscape; 488 hr = view_statics->get_Value(&state); 489 CheckHR(hr); 490 491 if (state == winui::ViewManagement::ApplicationViewState_Snapped) { 492 boolean success = FALSE; 493 hr = view_statics->TryUnsnap(&success); 494 495 if (FAILED(hr) || !success) { 496 LOG(ERROR) << "Failed to unsnap. Error 0x" << hr; 497 if (SUCCEEDED(hr)) 498 hr = E_UNEXPECTED; 499 } 500 } 501 return hr; 502 } 503 504 505 void ChromeAppViewAsh::OnSetCursor(HCURSOR cursor) { 506 ::SetCursor(HCURSOR(cursor)); 507 } 508 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__; 515 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(); 526 } 527 528 void ChromeAppViewAsh::OnDisplayFileSaveAsDialog( 529 const MetroViewerHostMsg_SaveAsDialogParams& params) { 530 DVLOG(1) << __FUNCTION__; 531 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(); 538 } 539 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(); 547 } 548 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)); 559 } 560 } 561 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()))); 574 } 575 } 576 delete open_file_picker; 577 } 578 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())); 589 } 590 delete save_file_picker; 591 } 592 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()))); 602 } 603 delete folder_picker; 604 } 605 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; 615 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; 630 } 631 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; 638 639 if (pointer.IsMouse()) { 640 ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(pointer.x(), 641 pointer.y(), 642 mouse_down_flags_)); 643 } else { 644 DCHECK(pointer.IsTouch()); 645 ui_channel_->Send(new MetroViewerHostMsg_TouchMoved(pointer.x(), 646 pointer.y(), 647 pointer.timestamp(), 648 pointer.pointer_id())); 649 } 650 return S_OK; 651 } 652 653 // NOTE: From experimentation, it seems like Metro only sends a PointerPressed 654 // event for the first button pressed and the last button released in a sequence 655 // of mouse events. 656 // For example, a sequence of LEFT_DOWN, RIGHT_DOWN, LEFT_UP, RIGHT_UP results 657 // only in PointerPressed(LEFT)/PointerReleased(RIGHT) events. 658 HRESULT ChromeAppViewAsh::OnPointerPressed( 659 winui::Core::ICoreWindow* sender, 660 winui::Core::IPointerEventArgs* args) { 661 PointerInfoHandler pointer; 662 HRESULT hr = pointer.Init(args); 663 if (FAILED(hr)) 664 return hr; 665 666 if (pointer.IsMouse()) { 667 mouse_down_flags_ = pointer.flags(); 668 ui_channel_->Send(new MetroViewerHostMsg_MouseButton(pointer.x(), 669 pointer.y(), 670 0, 671 ui::ET_MOUSE_PRESSED, 672 mouse_down_flags_)); 673 } else { 674 DCHECK(pointer.IsTouch()); 675 ui_channel_->Send(new MetroViewerHostMsg_TouchDown(pointer.x(), 676 pointer.y(), 677 pointer.timestamp(), 678 pointer.pointer_id())); 679 } 680 return S_OK; 681 } 682 683 HRESULT ChromeAppViewAsh::OnPointerReleased( 684 winui::Core::ICoreWindow* sender, 685 winui::Core::IPointerEventArgs* args) { 686 PointerInfoHandler pointer; 687 HRESULT hr = pointer.Init(args); 688 if (FAILED(hr)) 689 return hr; 690 691 if (pointer.IsMouse()) { 692 mouse_down_flags_ = ui::EF_NONE; 693 ui_channel_->Send(new MetroViewerHostMsg_MouseButton(pointer.x(), 694 pointer.y(), 695 0, 696 ui::ET_MOUSE_RELEASED, 697 pointer.flags())); 698 } else { 699 DCHECK(pointer.IsTouch()); 700 ui_channel_->Send(new MetroViewerHostMsg_TouchUp(pointer.x(), 701 pointer.y(), 702 pointer.timestamp(), 703 pointer.pointer_id())); 704 } 705 return S_OK; 706 } 707 708 HRESULT ChromeAppViewAsh::OnWheel( 709 winui::Core::ICoreWindow* sender, 710 winui::Core::IPointerEventArgs* args) { 711 PointerInfoHandler pointer; 712 HRESULT hr = pointer.Init(args); 713 if (FAILED(hr)) 714 return hr; 715 DCHECK(pointer.IsMouse()); 716 ui_channel_->Send(new MetroViewerHostMsg_MouseButton(pointer.x(), pointer.y(), 717 pointer.wheel_delta(), 718 ui::ET_MOUSEWHEEL, 719 ui::EF_NONE)); 720 return S_OK; 721 } 722 723 HRESULT ChromeAppViewAsh::OnKeyDown( 724 winui::Core::ICoreWindow* sender, 725 winui::Core::IKeyEventArgs* args) { 726 winsys::VirtualKey virtual_key; 727 HRESULT hr = args->get_VirtualKey(&virtual_key); 728 if (FAILED(hr)) 729 return hr; 730 winui::Core::CorePhysicalKeyStatus status; 731 hr = args->get_KeyStatus(&status); 732 if (FAILED(hr)) 733 return hr; 734 735 ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key, 736 status.RepeatCount, 737 status.ScanCode, 738 GetKeyboardEventFlags())); 739 return S_OK; 740 } 741 742 HRESULT ChromeAppViewAsh::OnKeyUp( 743 winui::Core::ICoreWindow* sender, 744 winui::Core::IKeyEventArgs* args) { 745 winsys::VirtualKey virtual_key; 746 HRESULT hr = args->get_VirtualKey(&virtual_key); 747 if (FAILED(hr)) 748 return hr; 749 winui::Core::CorePhysicalKeyStatus status; 750 hr = args->get_KeyStatus(&status); 751 if (FAILED(hr)) 752 return hr; 753 754 ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key, 755 status.RepeatCount, 756 status.ScanCode, 757 GetKeyboardEventFlags())); 758 return S_OK; 759 } 760 761 HRESULT ChromeAppViewAsh::OnAcceleratorKeyDown( 762 winui::Core::ICoreDispatcher* sender, 763 winui::Core::IAcceleratorKeyEventArgs* args) { 764 winsys::VirtualKey virtual_key; 765 HRESULT hr = args->get_VirtualKey(&virtual_key); 766 if (FAILED(hr)) 767 return hr; 768 winui::Core::CorePhysicalKeyStatus status; 769 hr = args->get_KeyStatus(&status); 770 if (FAILED(hr)) 771 return hr; 772 773 winui::Core::CoreAcceleratorKeyEventType event_type; 774 hr = args->get_EventType(&event_type); 775 if (FAILED(hr)) 776 return hr; 777 778 uint32 keyboard_flags = GetKeyboardEventFlags(); 779 780 switch (event_type) { 781 case winui::Core::CoreAcceleratorKeyEventType_SystemCharacter: 782 ui_channel_->Send(new MetroViewerHostMsg_Character(virtual_key, 783 status.RepeatCount, 784 status.ScanCode, 785 keyboard_flags)); 786 break; 787 788 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyDown: 789 ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key, 790 status.RepeatCount, 791 status.ScanCode, 792 keyboard_flags)); 793 break; 794 795 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyUp: 796 ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key, 797 status.RepeatCount, 798 status.ScanCode, 799 keyboard_flags)); 800 break; 801 802 default: 803 break; 804 } 805 return S_OK; 806 } 807 808 HRESULT ChromeAppViewAsh::OnCharacterReceived( 809 winui::Core::ICoreWindow* sender, 810 winui::Core::ICharacterReceivedEventArgs* args) { 811 unsigned int char_code = 0; 812 HRESULT hr = args->get_KeyCode(&char_code); 813 if (FAILED(hr)) 814 return hr; 815 816 winui::Core::CorePhysicalKeyStatus status; 817 hr = args->get_KeyStatus(&status); 818 if (FAILED(hr)) 819 return hr; 820 821 ui_channel_->Send(new MetroViewerHostMsg_Character(char_code, 822 status.RepeatCount, 823 status.ScanCode, 824 GetKeyboardEventFlags())); 825 return S_OK; 826 } 827 828 HRESULT ChromeAppViewAsh::OnVisibilityChanged( 829 winui::Core::ICoreWindow* sender, 830 winui::Core::IVisibilityChangedEventArgs* args) { 831 boolean visible = false; 832 HRESULT hr = args->get_Visible(&visible); 833 if (FAILED(hr)) 834 return hr; 835 836 ui_channel_->Send(new MetroViewerHostMsg_VisibilityChanged(!!visible)); 837 return S_OK; 838 } 839 840 HRESULT ChromeAppViewAsh::OnWindowActivated( 841 winui::Core::ICoreWindow* sender, 842 winui::Core::IWindowActivatedEventArgs* args) { 843 winui::Core::CoreWindowActivationState state; 844 HRESULT hr = args->get_WindowActivationState(&state); 845 if (FAILED(hr)) 846 return hr; 847 DVLOG(1) << "Window activation state: " << state; 848 ui_channel_->Send(new MetroViewerHostMsg_WindowActivated( 849 state != winui::Core::CoreWindowActivationState_Deactivated)); 850 return S_OK; 851 } 852 853 HRESULT ChromeAppViewAsh::HandleSearchRequest( 854 winapp::Activation::IActivatedEventArgs* args) { 855 mswr::ComPtr<winapp::Activation::ISearchActivatedEventArgs> search_args; 856 CheckHR(args->QueryInterface( 857 winapp::Activation::IID_ISearchActivatedEventArgs, &search_args)); 858 859 if (!ui_channel_) { 860 DVLOG(1) << "Launched to handle search request"; 861 base::FilePath chrome_exe_path; 862 863 if (!PathService::Get(base::FILE_EXE, &chrome_exe_path)) 864 return E_FAIL; 865 866 SHELLEXECUTEINFO sei = { sizeof(sei) }; 867 sei.nShow = SW_SHOWNORMAL; 868 sei.lpFile = chrome_exe_path.value().c_str(); 869 sei.lpDirectory = L""; 870 sei.lpParameters = 871 L"--silent-launch --viewer-connection=viewer --windows8-search"; 872 ::ShellExecuteEx(&sei); 873 } 874 875 mswrw::HString search_string; 876 CheckHR(search_args->get_QueryText(search_string.GetAddressOf())); 877 string16 search_text(MakeStdWString(search_string.Get())); 878 879 ui_loop_.PostTask(FROM_HERE, 880 base::Bind(&ChromeAppViewAsh::OnSearchRequest, 881 base::Unretained(this), 882 search_text)); 883 return S_OK; 884 } 885 886 HRESULT ChromeAppViewAsh::HandleProtocolRequest( 887 winapp::Activation::IActivatedEventArgs* args) { 888 DVLOG(1) << __FUNCTION__; 889 if (!ui_channel_) 890 DVLOG(1) << "Launched to handle url request"; 891 892 mswr::ComPtr<winapp::Activation::IProtocolActivatedEventArgs> 893 protocol_args; 894 CheckHR(args->QueryInterface( 895 winapp::Activation::IID_IProtocolActivatedEventArgs, 896 &protocol_args)); 897 898 mswr::ComPtr<winfoundtn::IUriRuntimeClass> uri; 899 protocol_args->get_Uri(&uri); 900 mswrw::HString url; 901 uri->get_AbsoluteUri(url.GetAddressOf()); 902 string16 actual_url(MakeStdWString(url.Get())); 903 DVLOG(1) << "Received url request: " << actual_url; 904 905 ui_loop_.PostTask(FROM_HERE, 906 base::Bind(&ChromeAppViewAsh::OnNavigateToUrl, 907 base::Unretained(this), 908 actual_url)); 909 return S_OK; 910 } 911 912 void ChromeAppViewAsh::OnSearchRequest(const string16& search_string) { 913 DCHECK(ui_channel_); 914 ui_channel_->Send(new MetroViewerHostMsg_SearchRequest(search_string)); 915 } 916 917 void ChromeAppViewAsh::OnNavigateToUrl(const string16& url) { 918 DCHECK(ui_channel_); 919 ui_channel_->Send(new MetroViewerHostMsg_OpenURL(url)); 920 } 921 922 HRESULT ChromeAppViewAsh::OnSizeChanged(winui::Core::ICoreWindow* sender, 923 winui::Core::IWindowSizeChangedEventArgs* args) { 924 if (!window_) { 925 return S_OK; 926 } 927 928 winfoundtn::Size size; 929 HRESULT hr = args->get_Size(&size); 930 if (FAILED(hr)) 931 return hr; 932 933 uint32 cx = static_cast<uint32>(size.Width); 934 uint32 cy = static_cast<uint32>(size.Height); 935 936 DVLOG(1) << "Window size changed: width=" << cx << ", height=" << cy; 937 ui_channel_->Send(new MetroViewerHostMsg_WindowSizeChanged(cx, cy)); 938 return S_OK; 939 } 940 941 /////////////////////////////////////////////////////////////////////////////// 942 943 ChromeAppViewFactory::ChromeAppViewFactory( 944 winapp::Core::ICoreApplication* icore_app, 945 LPTHREAD_START_ROUTINE host_main, 946 void* host_context) { 947 mswr::ComPtr<winapp::Core::ICoreApplication> core_app(icore_app); 948 mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit; 949 CheckHR(core_app.As(&app_exit)); 950 globals.app_exit = app_exit.Detach(); 951 } 952 953 IFACEMETHODIMP 954 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) { 955 *view = mswr::Make<ChromeAppViewAsh>().Detach(); 956 return (*view) ? S_OK : E_OUTOFMEMORY; 957 } 958