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/files/file_path.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/path_service.h" 17 #include "base/threading/thread.h" 18 #include "base/win/metro.h" 19 #include "base/win/win_util.h" 20 #include "chrome/common/chrome_switches.h" 21 #include "ipc/ipc_channel.h" 22 #include "ipc/ipc_channel_proxy.h" 23 #include "ipc/ipc_sender.h" 24 #include "ui/events/gestures/gesture_sequence.h" 25 #include "ui/metro_viewer/metro_viewer_messages.h" 26 #include "win8/metro_driver/file_picker_ash.h" 27 #include "win8/metro_driver/ime/ime_popup_monitor.h" 28 #include "win8/metro_driver/ime/input_source.h" 29 #include "win8/metro_driver/ime/text_service.h" 30 #include "win8/metro_driver/metro_driver.h" 31 #include "win8/metro_driver/winrt_utils.h" 32 #include "win8/viewer/metro_viewer_constants.h" 33 34 typedef winfoundtn::ITypedEventHandler< 35 winapp::Core::CoreApplicationView*, 36 winapp::Activation::IActivatedEventArgs*> ActivatedHandler; 37 38 typedef winfoundtn::ITypedEventHandler< 39 winui::Core::CoreWindow*, 40 winui::Core::PointerEventArgs*> PointerEventHandler; 41 42 typedef winfoundtn::ITypedEventHandler< 43 winui::Core::CoreWindow*, 44 winui::Core::KeyEventArgs*> KeyEventHandler; 45 46 typedef winfoundtn::ITypedEventHandler< 47 winui::Core::CoreDispatcher*, 48 winui::Core::AcceleratorKeyEventArgs*> AcceleratorKeyEventHandler; 49 50 typedef winfoundtn::ITypedEventHandler< 51 winui::Core::CoreWindow*, 52 winui::Core::CharacterReceivedEventArgs*> CharEventHandler; 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 typedef winfoundtn::ITypedEventHandler< 63 winui::Input::EdgeGesture*, 64 winui::Input::EdgeGestureEventArgs*> EdgeEventHandler; 65 66 // This function is exported by chrome.exe. 67 typedef int (__cdecl *BreakpadExceptionHandler)(EXCEPTION_POINTERS* info); 68 69 // Global information used across the metro driver. 70 struct Globals { 71 winapp::Activation::ApplicationExecutionState previous_state; 72 winapp::Core::ICoreApplicationExit* app_exit; 73 BreakpadExceptionHandler breakpad_exception_handler; 74 } globals; 75 76 namespace { 77 78 enum KeyModifier { 79 NONE, 80 SHIFT = 1, 81 CONTROL = 2, 82 ALT = 4 83 }; 84 85 // Helper function to send keystrokes via the SendInput function. 86 // mnemonic_char: The keystroke to be sent. 87 // modifiers: Combination with Alt, Ctrl, Shift, etc. 88 void SendMnemonic( 89 WORD mnemonic_char, KeyModifier modifiers) { 90 INPUT keys[4] = {0}; // Keyboard events 91 int key_count = 0; // Number of generated events 92 93 if (modifiers & SHIFT) { 94 keys[key_count].type = INPUT_KEYBOARD; 95 keys[key_count].ki.wVk = VK_SHIFT; 96 keys[key_count].ki.wScan = MapVirtualKey(VK_SHIFT, 0); 97 key_count++; 98 } 99 100 if (modifiers & CONTROL) { 101 keys[key_count].type = INPUT_KEYBOARD; 102 keys[key_count].ki.wVk = VK_CONTROL; 103 keys[key_count].ki.wScan = MapVirtualKey(VK_CONTROL, 0); 104 key_count++; 105 } 106 107 if (modifiers & ALT) { 108 keys[key_count].type = INPUT_KEYBOARD; 109 keys[key_count].ki.wVk = VK_MENU; 110 keys[key_count].ki.wScan = MapVirtualKey(VK_MENU, 0); 111 key_count++; 112 } 113 114 keys[key_count].type = INPUT_KEYBOARD; 115 keys[key_count].ki.wVk = mnemonic_char; 116 keys[key_count].ki.wScan = MapVirtualKey(mnemonic_char, 0); 117 key_count++; 118 119 bool should_sleep = key_count > 1; 120 121 // Send key downs. 122 for (int i = 0; i < key_count; i++) { 123 SendInput(1, &keys[ i ], sizeof(keys[0])); 124 keys[i].ki.dwFlags |= KEYEVENTF_KEYUP; 125 if (should_sleep) 126 Sleep(10); 127 } 128 129 // Now send key ups in reverse order. 130 for (int i = key_count; i; i--) { 131 SendInput(1, &keys[ i - 1 ], sizeof(keys[0])); 132 if (should_sleep) 133 Sleep(10); 134 } 135 } 136 137 // Helper function to Exit metro chrome cleanly. If we are in the foreground 138 // then we try and exit by sending an Alt+F4 key combination to the core 139 // window which ensures that the chrome application tile does not show up in 140 // the running metro apps list on the top left corner. 141 void MetroExit(HWND core_window) { 142 if ((core_window != NULL) && (core_window == ::GetForegroundWindow())) { 143 DVLOG(1) << "We are in the foreground. Exiting via Alt F4"; 144 SendMnemonic(VK_F4, ALT); 145 } else { 146 globals.app_exit->Exit(); 147 } 148 } 149 150 class ChromeChannelListener : public IPC::Listener { 151 public: 152 ChromeChannelListener(base::MessageLoop* ui_loop, ChromeAppViewAsh* app_view) 153 : ui_proxy_(ui_loop->message_loop_proxy()), 154 app_view_(app_view) {} 155 156 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 157 IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener, message) 158 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktop, 159 OnActivateDesktop) 160 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MetroExit, OnMetroExit) 161 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURLOnDesktop, 162 OnOpenURLOnDesktop) 163 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor, OnSetCursor) 164 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileOpen, 165 OnDisplayFileOpenDialog) 166 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileSaveAs, 167 OnDisplayFileSaveAsDialog) 168 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplaySelectFolder, 169 OnDisplayFolderPicker) 170 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPos, OnSetCursorPos) 171 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCancelComposition, 172 OnImeCancelComposition) 173 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeTextInputClientUpdated, 174 OnImeTextInputClientChanged) 175 IPC_MESSAGE_UNHANDLED(__debugbreak()) 176 IPC_END_MESSAGE_MAP() 177 return true; 178 } 179 180 virtual void OnChannelError() OVERRIDE { 181 DVLOG(1) << "Channel error. Exiting."; 182 MetroExit(app_view_->core_window_hwnd()); 183 // In early Windows 8 versions the code above sometimes fails so we call 184 // it a second time with a NULL window which just calls Exit(). 185 ui_proxy_->PostDelayedTask(FROM_HERE, 186 base::Bind(&MetroExit, HWND(NULL)), 187 base::TimeDelta::FromMilliseconds(100)); 188 } 189 190 private: 191 void OnActivateDesktop(const base::FilePath& shortcut, bool ash_exit) { 192 ui_proxy_->PostTask(FROM_HERE, 193 base::Bind(&ChromeAppViewAsh::OnActivateDesktop, 194 base::Unretained(app_view_), 195 shortcut, ash_exit)); 196 } 197 198 void OnMetroExit() { 199 MetroExit(app_view_->core_window_hwnd()); 200 } 201 202 void OnOpenURLOnDesktop(const base::FilePath& shortcut, 203 const string16& url) { 204 ui_proxy_->PostTask(FROM_HERE, 205 base::Bind(&ChromeAppViewAsh::OnOpenURLOnDesktop, 206 base::Unretained(app_view_), 207 shortcut, url)); 208 } 209 210 void OnSetCursor(int64 cursor) { 211 ui_proxy_->PostTask(FROM_HERE, 212 base::Bind(&ChromeAppViewAsh::OnSetCursor, 213 base::Unretained(app_view_), 214 reinterpret_cast<HCURSOR>(cursor))); 215 } 216 217 void OnDisplayFileOpenDialog(const string16& title, 218 const string16& filter, 219 const base::FilePath& default_path, 220 bool allow_multiple_files) { 221 ui_proxy_->PostTask(FROM_HERE, 222 base::Bind(&ChromeAppViewAsh::OnDisplayFileOpenDialog, 223 base::Unretained(app_view_), 224 title, 225 filter, 226 default_path, 227 allow_multiple_files)); 228 } 229 230 void OnDisplayFileSaveAsDialog( 231 const MetroViewerHostMsg_SaveAsDialogParams& params) { 232 ui_proxy_->PostTask( 233 FROM_HERE, 234 base::Bind(&ChromeAppViewAsh::OnDisplayFileSaveAsDialog, 235 base::Unretained(app_view_), 236 params)); 237 } 238 239 void OnDisplayFolderPicker(const string16& title) { 240 ui_proxy_->PostTask( 241 FROM_HERE, 242 base::Bind(&ChromeAppViewAsh::OnDisplayFolderPicker, 243 base::Unretained(app_view_), 244 title)); 245 } 246 247 void OnSetCursorPos(int x, int y) { 248 VLOG(1) << "In IPC OnSetCursorPos: " << x << ", " << y; 249 ui_proxy_->PostTask( 250 FROM_HERE, 251 base::Bind(&ChromeAppViewAsh::OnSetCursorPos, 252 base::Unretained(app_view_), 253 x, y)); 254 } 255 256 void OnImeCancelComposition() { 257 ui_proxy_->PostTask( 258 FROM_HERE, 259 base::Bind(&ChromeAppViewAsh::OnImeCancelComposition, 260 base::Unretained(app_view_))); 261 } 262 263 void OnImeTextInputClientChanged( 264 const std::vector<int32>& input_scopes, 265 const std::vector<metro_viewer::CharacterBounds>& character_bounds) { 266 ui_proxy_->PostTask( 267 FROM_HERE, 268 base::Bind(&ChromeAppViewAsh::OnImeUpdateTextInputClient, 269 base::Unretained(app_view_), 270 input_scopes, 271 character_bounds)); 272 } 273 274 scoped_refptr<base::MessageLoopProxy> ui_proxy_; 275 ChromeAppViewAsh* app_view_; 276 }; 277 278 bool WaitForChromeIPCConnection(const std::string& channel_name) { 279 int ms_elapsed = 0; 280 while (!IPC::Channel::IsNamedServerInitialized(channel_name) && 281 ms_elapsed < 10000) { 282 ms_elapsed += 500; 283 Sleep(500); 284 } 285 return IPC::Channel::IsNamedServerInitialized(channel_name); 286 } 287 288 // This class helps decoding the pointer properties of an event. 289 class PointerInfoHandler { 290 public: 291 PointerInfoHandler() 292 : x_(0), 293 y_(0), 294 wheel_delta_(0), 295 update_kind_(winui::Input::PointerUpdateKind_Other), 296 timestamp_(0), 297 pointer_id_(0) {} 298 299 HRESULT Init(winui::Core::IPointerEventArgs* args) { 300 HRESULT hr = args->get_CurrentPoint(&pointer_point_); 301 if (FAILED(hr)) 302 return hr; 303 304 winfoundtn::Point point; 305 hr = pointer_point_->get_Position(&point); 306 if (FAILED(hr)) 307 return hr; 308 309 mswr::ComPtr<winui::Input::IPointerPointProperties> properties; 310 hr = pointer_point_->get_Properties(&properties); 311 if (FAILED(hr)) 312 return hr; 313 314 hr = properties->get_PointerUpdateKind(&update_kind_); 315 if (FAILED(hr)) 316 return hr; 317 318 hr = properties->get_MouseWheelDelta(&wheel_delta_); 319 if (FAILED(hr)) 320 return hr; 321 x_ = point.X; 322 y_ = point.Y; 323 pointer_point_->get_Timestamp(×tamp_); 324 pointer_point_->get_PointerId(&pointer_id_); 325 // Map the OS touch event id to a range allowed by the gesture recognizer. 326 if (IsTouch()) 327 pointer_id_ %= ui::GestureSequence::kMaxGesturePoints; 328 return S_OK; 329 } 330 331 bool IsType(windevs::Input::PointerDeviceType type) const { 332 mswr::ComPtr<windevs::Input::IPointerDevice> pointer_device; 333 CheckHR(pointer_point_->get_PointerDevice(&pointer_device)); 334 windevs::Input::PointerDeviceType device_type; 335 CheckHR(pointer_device->get_PointerDeviceType(&device_type)); 336 return (device_type == type); 337 } 338 339 bool IsMouse() const { 340 return IsType(windevs::Input::PointerDeviceType_Mouse); 341 } 342 343 bool IsTouch() const { 344 return IsType(windevs::Input::PointerDeviceType_Touch); 345 } 346 347 int32 wheel_delta() const { 348 return wheel_delta_; 349 } 350 351 ui::EventFlags flags() { 352 switch (update_kind_) { 353 case winui::Input::PointerUpdateKind_LeftButtonPressed: 354 return ui::EF_LEFT_MOUSE_BUTTON; 355 case winui::Input::PointerUpdateKind_LeftButtonReleased: 356 return ui::EF_LEFT_MOUSE_BUTTON; 357 case winui::Input::PointerUpdateKind_RightButtonPressed: 358 return ui::EF_RIGHT_MOUSE_BUTTON; 359 case winui::Input::PointerUpdateKind_RightButtonReleased: 360 return ui::EF_RIGHT_MOUSE_BUTTON; 361 case winui::Input::PointerUpdateKind_MiddleButtonPressed: 362 return ui::EF_MIDDLE_MOUSE_BUTTON; 363 case winui::Input::PointerUpdateKind_MiddleButtonReleased: 364 return ui::EF_MIDDLE_MOUSE_BUTTON; 365 default: 366 return ui::EF_NONE; 367 }; 368 } 369 370 int x() const { return x_; } 371 int y() const { return y_; } 372 373 uint32 pointer_id() const { 374 return pointer_id_; 375 } 376 377 uint64 timestamp() const { return timestamp_; } 378 379 private: 380 int x_; 381 int y_; 382 int wheel_delta_; 383 uint32 pointer_id_; 384 winui::Input::PointerUpdateKind update_kind_; 385 mswr::ComPtr<winui::Input::IPointerPoint> pointer_point_; 386 uint64 timestamp_; 387 }; 388 389 void RunMessageLoop(winui::Core::ICoreDispatcher* dispatcher) { 390 // We're entering a nested message loop, let's allow dispatching 391 // tasks while we're in there. 392 base::MessageLoop::current()->SetNestableTasksAllowed(true); 393 394 // Enter main core message loop. There are several ways to exit it 395 // Nicely: 396 // 1 - User action like ALT-F4. 397 // 2 - Calling ICoreApplicationExit::Exit(). 398 // 3- Posting WM_CLOSE to the core window. 399 HRESULT hr = dispatcher->ProcessEvents( 400 winui::Core::CoreProcessEventsOption 401 ::CoreProcessEventsOption_ProcessUntilQuit); 402 403 // Wind down the thread's chrome message loop. 404 base::MessageLoop::current()->Quit(); 405 } 406 407 // Helper to return the state of the shift/control/alt keys. 408 uint32 GetKeyboardEventFlags() { 409 uint32 flags = 0; 410 if (base::win::IsShiftPressed()) 411 flags |= ui::EF_SHIFT_DOWN; 412 if (base::win::IsCtrlPressed()) 413 flags |= ui::EF_CONTROL_DOWN; 414 if (base::win::IsAltPressed()) 415 flags |= ui::EF_ALT_DOWN; 416 return flags; 417 } 418 419 bool LaunchChromeBrowserProcess(const wchar_t* additional_parameters, 420 winapp::Activation::IActivatedEventArgs* args) { 421 if (args) { 422 DVLOG(1) << __FUNCTION__ << ":" << ::GetCommandLineW(); 423 winapp::Activation::ActivationKind activation_kind; 424 CheckHR(args->get_Kind(&activation_kind)); 425 426 DVLOG(1) << __FUNCTION__ << ", activation_kind=" << activation_kind; 427 428 if (activation_kind == winapp::Activation::ActivationKind_Launch) { 429 mswr::ComPtr<winapp::Activation::ILaunchActivatedEventArgs> launch_args; 430 if (args->QueryInterface( 431 winapp::Activation::IID_ILaunchActivatedEventArgs, 432 &launch_args) == S_OK) { 433 DVLOG(1) << "Activate: ActivationKind_Launch"; 434 mswrw::HString launch_args_str; 435 launch_args->get_Arguments(launch_args_str.GetAddressOf()); 436 string16 actual_launch_args(MakeStdWString(launch_args_str.Get())); 437 if (actual_launch_args == win8::kMetroViewerConnectVerb) { 438 DVLOG(1) << __FUNCTION__ << "Not launching chrome server"; 439 return true; 440 } 441 } 442 } 443 } 444 445 DVLOG(1) << "Launching chrome server"; 446 base::FilePath chrome_exe_path; 447 448 if (!PathService::Get(base::FILE_EXE, &chrome_exe_path)) 449 return false; 450 451 string16 parameters = L"--silent-launch --viewer-connect "; 452 if (additional_parameters) 453 parameters += additional_parameters; 454 455 SHELLEXECUTEINFO sei = { sizeof(sei) }; 456 sei.nShow = SW_SHOWNORMAL; 457 sei.lpFile = chrome_exe_path.value().c_str(); 458 sei.lpDirectory = L""; 459 sei.lpParameters = parameters.c_str(); 460 ::ShellExecuteEx(&sei); 461 return true; 462 } 463 464 } // namespace 465 466 ChromeAppViewAsh::ChromeAppViewAsh() 467 : mouse_down_flags_(ui::EF_NONE), 468 ui_channel_(nullptr), 469 core_window_hwnd_(NULL), 470 ui_loop_(base::MessageLoop::TYPE_UI) { 471 DVLOG(1) << __FUNCTION__; 472 globals.previous_state = 473 winapp::Activation::ApplicationExecutionState_NotRunning; 474 } 475 476 ChromeAppViewAsh::~ChromeAppViewAsh() { 477 DVLOG(1) << __FUNCTION__; 478 } 479 480 IFACEMETHODIMP 481 ChromeAppViewAsh::Initialize(winapp::Core::ICoreApplicationView* view) { 482 view_ = view; 483 DVLOG(1) << __FUNCTION__; 484 HRESULT hr = view_->add_Activated(mswr::Callback<ActivatedHandler>( 485 this, &ChromeAppViewAsh::OnActivate).Get(), 486 &activated_token_); 487 CheckHR(hr); 488 return hr; 489 } 490 491 IFACEMETHODIMP 492 ChromeAppViewAsh::SetWindow(winui::Core::ICoreWindow* window) { 493 window_ = window; 494 DVLOG(1) << __FUNCTION__; 495 496 // Retrieve the native window handle via the interop layer. 497 mswr::ComPtr<ICoreWindowInterop> interop; 498 HRESULT hr = window->QueryInterface(interop.GetAddressOf()); 499 CheckHR(hr); 500 hr = interop->get_WindowHandle(&core_window_hwnd_); 501 CheckHR(hr); 502 503 text_service_ = metro_driver::CreateTextService(this, core_window_hwnd_); 504 505 hr = window_->add_SizeChanged(mswr::Callback<SizeChangedHandler>( 506 this, &ChromeAppViewAsh::OnSizeChanged).Get(), 507 &sizechange_token_); 508 CheckHR(hr); 509 510 // Register for pointer and keyboard notifications. We forward 511 // them to the browser process via IPC. 512 hr = window_->add_PointerMoved(mswr::Callback<PointerEventHandler>( 513 this, &ChromeAppViewAsh::OnPointerMoved).Get(), 514 &pointermoved_token_); 515 CheckHR(hr); 516 517 hr = window_->add_PointerPressed(mswr::Callback<PointerEventHandler>( 518 this, &ChromeAppViewAsh::OnPointerPressed).Get(), 519 &pointerpressed_token_); 520 CheckHR(hr); 521 522 hr = window_->add_PointerReleased(mswr::Callback<PointerEventHandler>( 523 this, &ChromeAppViewAsh::OnPointerReleased).Get(), 524 &pointerreleased_token_); 525 CheckHR(hr); 526 527 hr = window_->add_KeyDown(mswr::Callback<KeyEventHandler>( 528 this, &ChromeAppViewAsh::OnKeyDown).Get(), 529 &keydown_token_); 530 CheckHR(hr); 531 532 hr = window_->add_KeyUp(mswr::Callback<KeyEventHandler>( 533 this, &ChromeAppViewAsh::OnKeyUp).Get(), 534 &keyup_token_); 535 CheckHR(hr); 536 537 mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher; 538 hr = window_->get_Dispatcher(&dispatcher); 539 CheckHR(hr, "Get Dispatcher failed."); 540 541 mswr::ComPtr<winui::Core::ICoreAcceleratorKeys> accelerator_keys; 542 hr = dispatcher.CopyTo(__uuidof(winui::Core::ICoreAcceleratorKeys), 543 reinterpret_cast<void**>( 544 accelerator_keys.GetAddressOf())); 545 CheckHR(hr, "QI for ICoreAcceleratorKeys failed."); 546 hr = accelerator_keys->add_AcceleratorKeyActivated( 547 mswr::Callback<AcceleratorKeyEventHandler>( 548 this, &ChromeAppViewAsh::OnAcceleratorKeyDown).Get(), 549 &accel_keydown_token_); 550 CheckHR(hr); 551 552 hr = window_->add_PointerWheelChanged(mswr::Callback<PointerEventHandler>( 553 this, &ChromeAppViewAsh::OnWheel).Get(), 554 &wheel_token_); 555 CheckHR(hr); 556 557 hr = window_->add_CharacterReceived(mswr::Callback<CharEventHandler>( 558 this, &ChromeAppViewAsh::OnCharacterReceived).Get(), 559 &character_received_token_); 560 CheckHR(hr); 561 562 hr = window_->add_Activated(mswr::Callback<WindowActivatedHandler>( 563 this, &ChromeAppViewAsh::OnWindowActivated).Get(), 564 &window_activated_token_); 565 CheckHR(hr); 566 567 // Register for edge gesture notifications. 568 mswr::ComPtr<winui::Input::IEdgeGestureStatics> edge_gesture_statics; 569 hr = winrt_utils::CreateActivationFactory( 570 RuntimeClass_Windows_UI_Input_EdgeGesture, 571 edge_gesture_statics.GetAddressOf()); 572 CheckHR(hr); 573 574 mswr::ComPtr<winui::Input::IEdgeGesture> edge_gesture; 575 hr = edge_gesture_statics->GetForCurrentView(&edge_gesture); 576 CheckHR(hr); 577 578 hr = edge_gesture->add_Completed(mswr::Callback<EdgeEventHandler>( 579 this, &ChromeAppViewAsh::OnEdgeGestureCompleted).Get(), 580 &edgeevent_token_); 581 CheckHR(hr); 582 583 // By initializing the direct 3D swap chain with the corewindow 584 // we can now directly blit to it from the browser process. 585 direct3d_helper_.Initialize(window); 586 DVLOG(1) << "Initialized Direct3D."; 587 return S_OK; 588 } 589 590 IFACEMETHODIMP 591 ChromeAppViewAsh::Load(HSTRING entryPoint) { 592 DVLOG(1) << __FUNCTION__; 593 return S_OK; 594 } 595 596 IFACEMETHODIMP 597 ChromeAppViewAsh::Run() { 598 DVLOG(1) << __FUNCTION__; 599 mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher; 600 HRESULT hr = window_->get_Dispatcher(&dispatcher); 601 CheckHR(hr, "Dispatcher failed."); 602 603 hr = window_->Activate(); 604 if (FAILED(hr)) { 605 DLOG(WARNING) << "activation failed hr=" << hr; 606 return hr; 607 } 608 609 // Create the IPC channel IO thread. It needs to out-live the ChannelProxy. 610 base::Thread io_thread("metro_IO_thread"); 611 base::Thread::Options options; 612 options.message_loop_type = base::MessageLoop::TYPE_IO; 613 io_thread.StartWithOptions(options); 614 615 // Start up Chrome and wait for the desired IPC server connection to exist. 616 WaitForChromeIPCConnection(win8::kMetroViewerIPCChannelName); 617 618 // In Aura mode we create an IPC channel to the browser, then ask it to 619 // connect to us. 620 ChromeChannelListener ui_channel_listener(&ui_loop_, this); 621 IPC::ChannelProxy ui_channel(win8::kMetroViewerIPCChannelName, 622 IPC::Channel::MODE_NAMED_CLIENT, 623 &ui_channel_listener, 624 io_thread.message_loop_proxy()); 625 ui_channel_ = &ui_channel; 626 627 // Upon receipt of the MetroViewerHostMsg_SetTargetSurface message the 628 // browser will use D3D from the browser process to present to our Window. 629 ui_channel_->Send(new MetroViewerHostMsg_SetTargetSurface( 630 gfx::NativeViewId(core_window_hwnd_))); 631 DVLOG(1) << "ICoreWindow sent " << core_window_hwnd_; 632 633 // Send an initial size message so that the Ash root window host gets sized 634 // correctly. 635 RECT rect = {0}; 636 ::GetWindowRect(core_window_hwnd_, &rect); 637 ui_channel_->Send( 638 new MetroViewerHostMsg_WindowSizeChanged(rect.right - rect.left, 639 rect.bottom - rect.top)); 640 641 input_source_ = metro_driver::InputSource::Create(); 642 if (input_source_) { 643 input_source_->AddObserver(this); 644 // Send an initial input source. 645 OnInputSourceChanged(); 646 } 647 648 // Start receiving IME popup window notifications. 649 metro_driver::AddImePopupObserver(this); 650 651 // And post the task that'll do the inner Metro message pumping to it. 652 ui_loop_.PostTask(FROM_HERE, base::Bind(&RunMessageLoop, dispatcher.Get())); 653 ui_loop_.Run(); 654 655 DVLOG(0) << "ProcessEvents done, hr=" << hr; 656 return hr; 657 } 658 659 IFACEMETHODIMP 660 ChromeAppViewAsh::Uninitialize() { 661 DVLOG(1) << __FUNCTION__; 662 metro_driver::RemoveImePopupObserver(this); 663 input_source_.reset(); 664 text_service_.reset(); 665 window_ = nullptr; 666 view_ = nullptr; 667 core_window_hwnd_ = NULL; 668 return S_OK; 669 } 670 671 // static 672 HRESULT ChromeAppViewAsh::Unsnap() { 673 mswr::ComPtr<winui::ViewManagement::IApplicationViewStatics> view_statics; 674 HRESULT hr = winrt_utils::CreateActivationFactory( 675 RuntimeClass_Windows_UI_ViewManagement_ApplicationView, 676 view_statics.GetAddressOf()); 677 CheckHR(hr); 678 679 winui::ViewManagement::ApplicationViewState state = 680 winui::ViewManagement::ApplicationViewState_FullScreenLandscape; 681 hr = view_statics->get_Value(&state); 682 CheckHR(hr); 683 684 if (state == winui::ViewManagement::ApplicationViewState_Snapped) { 685 boolean success = FALSE; 686 hr = view_statics->TryUnsnap(&success); 687 688 if (FAILED(hr) || !success) { 689 LOG(ERROR) << "Failed to unsnap. Error 0x" << hr; 690 if (SUCCEEDED(hr)) 691 hr = E_UNEXPECTED; 692 } 693 } 694 return hr; 695 } 696 697 void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path, 698 bool ash_exit) { 699 DVLOG(1) << "ChannelAppViewAsh::OnActivateDesktop\n"; 700 701 if (ash_exit) { 702 // As we are the top level window, the exiting is done async so we manage 703 // to execute the entire function including the final Send(). 704 MetroExit(core_window_hwnd()); 705 } 706 707 // We are just executing delegate_execute here without parameters. Assumption 708 // here is that this process will be reused by shell when asking for 709 // IExecuteCommand interface. 710 711 // TODO(shrikant): Consolidate ShellExecuteEx with SEE_MASK_FLAG_LOG_USAGE 712 // and place it metro.h or similar accessible file from all code code paths 713 // using this function. 714 SHELLEXECUTEINFO sei = { sizeof(sei) }; 715 sei.fMask = SEE_MASK_FLAG_LOG_USAGE; 716 sei.nShow = SW_SHOWNORMAL; 717 sei.lpFile = file_path.value().c_str(); 718 sei.lpParameters = NULL; 719 if (!ash_exit) 720 sei.fMask |= SEE_MASK_NOCLOSEPROCESS; 721 ::ShellExecuteExW(&sei); 722 if (!ash_exit) { 723 ::TerminateProcess(sei.hProcess, 0); 724 ::CloseHandle(sei.hProcess); 725 } 726 } 727 728 void ChromeAppViewAsh::OnOpenURLOnDesktop(const base::FilePath& shortcut, 729 const string16& url) { 730 base::FilePath::StringType file = shortcut.value(); 731 SHELLEXECUTEINFO sei = { sizeof(sei) }; 732 sei.fMask = SEE_MASK_FLAG_LOG_USAGE; 733 sei.nShow = SW_SHOWNORMAL; 734 sei.lpFile = file.c_str(); 735 sei.lpDirectory = L""; 736 sei.lpParameters = url.c_str(); 737 BOOL result = ShellExecuteEx(&sei); 738 } 739 740 void ChromeAppViewAsh::OnSetCursor(HCURSOR cursor) { 741 ::SetCursor(HCURSOR(cursor)); 742 } 743 744 void ChromeAppViewAsh::OnDisplayFileOpenDialog( 745 const string16& title, 746 const string16& filter, 747 const base::FilePath& default_path, 748 bool allow_multiple_files) { 749 DVLOG(1) << __FUNCTION__; 750 751 // The OpenFilePickerSession instance is deleted when we receive a 752 // callback from the OpenFilePickerSession class about the completion of the 753 // operation. 754 FilePickerSessionBase* file_picker_ = 755 new OpenFilePickerSession(this, 756 title, 757 filter, 758 default_path, 759 allow_multiple_files); 760 file_picker_->Run(); 761 } 762 763 void ChromeAppViewAsh::OnDisplayFileSaveAsDialog( 764 const MetroViewerHostMsg_SaveAsDialogParams& params) { 765 DVLOG(1) << __FUNCTION__; 766 767 // The SaveFilePickerSession instance is deleted when we receive a 768 // callback from the SaveFilePickerSession class about the completion of the 769 // operation. 770 FilePickerSessionBase* file_picker_ = 771 new SaveFilePickerSession(this, params); 772 file_picker_->Run(); 773 } 774 775 void ChromeAppViewAsh::OnDisplayFolderPicker(const string16& title) { 776 DVLOG(1) << __FUNCTION__; 777 // The FolderPickerSession instance is deleted when we receive a 778 // callback from the FolderPickerSession class about the completion of the 779 // operation. 780 FilePickerSessionBase* file_picker_ = new FolderPickerSession(this, title); 781 file_picker_->Run(); 782 } 783 784 void ChromeAppViewAsh::OnSetCursorPos(int x, int y) { 785 if (ui_channel_) { 786 ::SetCursorPos(x, y); 787 DVLOG(1) << "In UI OnSetCursorPos: " << x << ", " << y; 788 ui_channel_->Send(new MetroViewerHostMsg_SetCursorPosAck()); 789 // Generate a fake mouse move which matches the SetCursor coordinates as 790 // the browser expects to receive a mouse move for these coordinates. 791 // It is not clear why we don't receive a real mouse move in response to 792 // the SetCursorPos calll above. 793 ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(x, y, 0)); 794 } 795 } 796 797 void ChromeAppViewAsh::OnOpenFileCompleted( 798 OpenFilePickerSession* open_file_picker, 799 bool success) { 800 DVLOG(1) << __FUNCTION__; 801 DVLOG(1) << "Success: " << success; 802 if (ui_channel_) { 803 if (open_file_picker->allow_multi_select()) { 804 ui_channel_->Send(new MetroViewerHostMsg_MultiFileOpenDone( 805 success, open_file_picker->filenames())); 806 } else { 807 ui_channel_->Send(new MetroViewerHostMsg_FileOpenDone( 808 success, base::FilePath(open_file_picker->result()))); 809 } 810 } 811 delete open_file_picker; 812 } 813 814 void ChromeAppViewAsh::OnSaveFileCompleted( 815 SaveFilePickerSession* save_file_picker, 816 bool success) { 817 DVLOG(1) << __FUNCTION__; 818 DVLOG(1) << "Success: " << success; 819 if (ui_channel_) { 820 ui_channel_->Send(new MetroViewerHostMsg_FileSaveAsDone( 821 success, 822 base::FilePath(save_file_picker->result()), 823 save_file_picker->filter_index())); 824 } 825 delete save_file_picker; 826 } 827 828 void ChromeAppViewAsh::OnFolderPickerCompleted( 829 FolderPickerSession* folder_picker, 830 bool success) { 831 DVLOG(1) << __FUNCTION__; 832 DVLOG(1) << "Success: " << success; 833 if (ui_channel_) { 834 ui_channel_->Send(new MetroViewerHostMsg_SelectFolderDone( 835 success, 836 base::FilePath(folder_picker->result()))); 837 } 838 delete folder_picker; 839 } 840 841 void ChromeAppViewAsh::OnImeCancelComposition() { 842 if (!text_service_) 843 return; 844 text_service_->CancelComposition(); 845 } 846 847 void ChromeAppViewAsh::OnImeUpdateTextInputClient( 848 const std::vector<int32>& input_scopes, 849 const std::vector<metro_viewer::CharacterBounds>& character_bounds) { 850 if (!text_service_) 851 return; 852 text_service_->OnDocumentChanged(input_scopes, character_bounds); 853 } 854 855 void ChromeAppViewAsh::OnImePopupChanged(ImePopupObserver::EventType event) { 856 if (!ui_channel_) 857 return; 858 switch (event) { 859 case ImePopupObserver::kPopupShown: 860 ui_channel_->Send(new MetroViewerHostMsg_ImeCandidatePopupChanged(true)); 861 return; 862 case ImePopupObserver::kPopupHidden: 863 ui_channel_->Send(new MetroViewerHostMsg_ImeCandidatePopupChanged(false)); 864 return; 865 case ImePopupObserver::kPopupUpdated: 866 // TODO(kochi): Support this event for W3C IME API proposal. 867 // See crbug.com/238585. 868 return; 869 default: 870 NOTREACHED() << "unknown event type: " << event; 871 return; 872 } 873 } 874 875 void ChromeAppViewAsh::OnInputSourceChanged() { 876 if (!input_source_) 877 return; 878 879 LANGID langid = 0; 880 bool is_ime = false; 881 if (!input_source_->GetActiveSource(&langid, &is_ime)) { 882 LOG(ERROR) << "GetActiveSource failed"; 883 return; 884 } 885 ui_channel_->Send(new MetroViewerHostMsg_ImeInputSourceChanged(langid, 886 is_ime)); 887 } 888 889 void ChromeAppViewAsh::OnCompositionChanged( 890 const string16& text, 891 int32 selection_start, 892 int32 selection_end, 893 const std::vector<metro_viewer::UnderlineInfo>& underlines) { 894 ui_channel_->Send(new MetroViewerHostMsg_ImeCompositionChanged( 895 text, selection_start, selection_end, underlines)); 896 } 897 898 void ChromeAppViewAsh::OnTextCommitted(const string16& text) { 899 ui_channel_->Send(new MetroViewerHostMsg_ImeTextCommitted(text)); 900 } 901 902 HRESULT ChromeAppViewAsh::OnActivate( 903 winapp::Core::ICoreApplicationView*, 904 winapp::Activation::IActivatedEventArgs* args) { 905 DVLOG(1) << __FUNCTION__; 906 // Note: If doing more work in this function, you migth need to call 907 // get_PreviousExecutionState() and skip the work if the result is 908 // ApplicationExecutionState_Running and globals.previous_state is too. 909 args->get_PreviousExecutionState(&globals.previous_state); 910 DVLOG(1) << "Previous Execution State: " << globals.previous_state; 911 912 winapp::Activation::ActivationKind activation_kind; 913 CheckHR(args->get_Kind(&activation_kind)); 914 DVLOG(1) << "Activation kind: " << activation_kind; 915 916 if (activation_kind == winapp::Activation::ActivationKind_Search) 917 HandleSearchRequest(args); 918 else if (activation_kind == winapp::Activation::ActivationKind_Protocol) 919 HandleProtocolRequest(args); 920 else 921 LaunchChromeBrowserProcess(NULL, args); 922 // We call ICoreWindow::Activate after the handling for the search/protocol 923 // requests because Chrome can be launched to handle a search request which 924 // in turn launches the chrome browser process in desktop mode via 925 // ShellExecute. If we call ICoreWindow::Activate before this, then 926 // Windows kills the metro chrome process when it calls ShellExecute. Seems 927 // to be a bug. 928 window_->Activate(); 929 return S_OK; 930 } 931 932 HRESULT ChromeAppViewAsh::OnPointerMoved(winui::Core::ICoreWindow* sender, 933 winui::Core::IPointerEventArgs* args) { 934 PointerInfoHandler pointer; 935 HRESULT hr = pointer.Init(args); 936 if (FAILED(hr)) 937 return hr; 938 939 if (pointer.IsMouse()) { 940 ui_channel_->Send(new MetroViewerHostMsg_MouseMoved( 941 pointer.x(), 942 pointer.y(), 943 mouse_down_flags_ | GetKeyboardEventFlags())); 944 } else { 945 DCHECK(pointer.IsTouch()); 946 ui_channel_->Send(new MetroViewerHostMsg_TouchMoved(pointer.x(), 947 pointer.y(), 948 pointer.timestamp(), 949 pointer.pointer_id())); 950 } 951 return S_OK; 952 } 953 954 // NOTE: From experimentation, it seems like Metro only sends a PointerPressed 955 // event for the first button pressed and the last button released in a sequence 956 // of mouse events. 957 // For example, a sequence of LEFT_DOWN, RIGHT_DOWN, LEFT_UP, RIGHT_UP results 958 // only in PointerPressed(LEFT)/PointerReleased(RIGHT) events. 959 HRESULT ChromeAppViewAsh::OnPointerPressed( 960 winui::Core::ICoreWindow* sender, 961 winui::Core::IPointerEventArgs* args) { 962 PointerInfoHandler pointer; 963 HRESULT hr = pointer.Init(args); 964 if (FAILED(hr)) 965 return hr; 966 967 if (pointer.IsMouse()) { 968 // TODO: this is wrong, more than one pointer may be down at a time. 969 mouse_down_flags_ = pointer.flags(); 970 ui_channel_->Send(new MetroViewerHostMsg_MouseButton( 971 pointer.x(), 972 pointer.y(), 973 0, 974 ui::ET_MOUSE_PRESSED, 975 static_cast<ui::EventFlags>( 976 mouse_down_flags_ | GetKeyboardEventFlags()))); 977 } else { 978 DCHECK(pointer.IsTouch()); 979 ui_channel_->Send(new MetroViewerHostMsg_TouchDown(pointer.x(), 980 pointer.y(), 981 pointer.timestamp(), 982 pointer.pointer_id())); 983 } 984 return S_OK; 985 } 986 987 HRESULT ChromeAppViewAsh::OnPointerReleased( 988 winui::Core::ICoreWindow* sender, 989 winui::Core::IPointerEventArgs* args) { 990 PointerInfoHandler pointer; 991 HRESULT hr = pointer.Init(args); 992 if (FAILED(hr)) 993 return hr; 994 995 if (pointer.IsMouse()) { 996 // TODO: this is wrong, more than one pointer may be down at a time. 997 mouse_down_flags_ = ui::EF_NONE; 998 ui_channel_->Send(new MetroViewerHostMsg_MouseButton( 999 pointer.x(), 1000 pointer.y(), 1001 0, 1002 ui::ET_MOUSE_RELEASED, 1003 static_cast<ui::EventFlags>( 1004 pointer.flags() | GetKeyboardEventFlags()))); 1005 } else { 1006 DCHECK(pointer.IsTouch()); 1007 ui_channel_->Send(new MetroViewerHostMsg_TouchUp(pointer.x(), 1008 pointer.y(), 1009 pointer.timestamp(), 1010 pointer.pointer_id())); 1011 } 1012 return S_OK; 1013 } 1014 1015 HRESULT ChromeAppViewAsh::OnWheel( 1016 winui::Core::ICoreWindow* sender, 1017 winui::Core::IPointerEventArgs* args) { 1018 PointerInfoHandler pointer; 1019 HRESULT hr = pointer.Init(args); 1020 if (FAILED(hr)) 1021 return hr; 1022 DCHECK(pointer.IsMouse()); 1023 ui_channel_->Send(new MetroViewerHostMsg_MouseButton(pointer.x(), pointer.y(), 1024 pointer.wheel_delta(), 1025 ui::ET_MOUSEWHEEL, 1026 ui::EF_NONE)); 1027 return S_OK; 1028 } 1029 1030 HRESULT ChromeAppViewAsh::OnKeyDown( 1031 winui::Core::ICoreWindow* sender, 1032 winui::Core::IKeyEventArgs* args) { 1033 winsys::VirtualKey virtual_key; 1034 HRESULT hr = args->get_VirtualKey(&virtual_key); 1035 if (FAILED(hr)) 1036 return hr; 1037 winui::Core::CorePhysicalKeyStatus status; 1038 hr = args->get_KeyStatus(&status); 1039 if (FAILED(hr)) 1040 return hr; 1041 1042 ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key, 1043 status.RepeatCount, 1044 status.ScanCode, 1045 GetKeyboardEventFlags())); 1046 return S_OK; 1047 } 1048 1049 HRESULT ChromeAppViewAsh::OnKeyUp( 1050 winui::Core::ICoreWindow* sender, 1051 winui::Core::IKeyEventArgs* args) { 1052 winsys::VirtualKey virtual_key; 1053 HRESULT hr = args->get_VirtualKey(&virtual_key); 1054 if (FAILED(hr)) 1055 return hr; 1056 winui::Core::CorePhysicalKeyStatus status; 1057 hr = args->get_KeyStatus(&status); 1058 if (FAILED(hr)) 1059 return hr; 1060 1061 ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key, 1062 status.RepeatCount, 1063 status.ScanCode, 1064 GetKeyboardEventFlags())); 1065 return S_OK; 1066 } 1067 1068 HRESULT ChromeAppViewAsh::OnAcceleratorKeyDown( 1069 winui::Core::ICoreDispatcher* sender, 1070 winui::Core::IAcceleratorKeyEventArgs* args) { 1071 winsys::VirtualKey virtual_key; 1072 HRESULT hr = args->get_VirtualKey(&virtual_key); 1073 if (FAILED(hr)) 1074 return hr; 1075 winui::Core::CorePhysicalKeyStatus status; 1076 hr = args->get_KeyStatus(&status); 1077 if (FAILED(hr)) 1078 return hr; 1079 1080 winui::Core::CoreAcceleratorKeyEventType event_type; 1081 hr = args->get_EventType(&event_type); 1082 if (FAILED(hr)) 1083 return hr; 1084 1085 uint32 keyboard_flags = GetKeyboardEventFlags(); 1086 1087 switch (event_type) { 1088 case winui::Core::CoreAcceleratorKeyEventType_SystemCharacter: 1089 ui_channel_->Send(new MetroViewerHostMsg_Character(virtual_key, 1090 status.RepeatCount, 1091 status.ScanCode, 1092 keyboard_flags)); 1093 break; 1094 1095 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyDown: 1096 ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key, 1097 status.RepeatCount, 1098 status.ScanCode, 1099 keyboard_flags)); 1100 break; 1101 1102 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyUp: 1103 ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key, 1104 status.RepeatCount, 1105 status.ScanCode, 1106 keyboard_flags)); 1107 break; 1108 1109 default: 1110 break; 1111 } 1112 return S_OK; 1113 } 1114 1115 HRESULT ChromeAppViewAsh::OnCharacterReceived( 1116 winui::Core::ICoreWindow* sender, 1117 winui::Core::ICharacterReceivedEventArgs* args) { 1118 unsigned int char_code = 0; 1119 HRESULT hr = args->get_KeyCode(&char_code); 1120 if (FAILED(hr)) 1121 return hr; 1122 1123 winui::Core::CorePhysicalKeyStatus status; 1124 hr = args->get_KeyStatus(&status); 1125 if (FAILED(hr)) 1126 return hr; 1127 1128 ui_channel_->Send(new MetroViewerHostMsg_Character(char_code, 1129 status.RepeatCount, 1130 status.ScanCode, 1131 GetKeyboardEventFlags())); 1132 return S_OK; 1133 } 1134 1135 HRESULT ChromeAppViewAsh::OnWindowActivated( 1136 winui::Core::ICoreWindow* sender, 1137 winui::Core::IWindowActivatedEventArgs* args) { 1138 winui::Core::CoreWindowActivationState state; 1139 HRESULT hr = args->get_WindowActivationState(&state); 1140 if (FAILED(hr)) 1141 return hr; 1142 1143 // Treat both full activation (Ash was reopened from the Start Screen or from 1144 // any other Metro entry point in Windows) and pointer activation (user 1145 // clicked back in Ash after using another app on another monitor) the same. 1146 if (state == winui::Core::CoreWindowActivationState_CodeActivated || 1147 state == winui::Core::CoreWindowActivationState_PointerActivated) { 1148 if (text_service_) 1149 text_service_->OnWindowActivated(); 1150 ui_channel_->Send(new MetroViewerHostMsg_WindowActivated()); 1151 } 1152 return S_OK; 1153 } 1154 1155 HRESULT ChromeAppViewAsh::HandleSearchRequest( 1156 winapp::Activation::IActivatedEventArgs* args) { 1157 mswr::ComPtr<winapp::Activation::ISearchActivatedEventArgs> search_args; 1158 CheckHR(args->QueryInterface( 1159 winapp::Activation::IID_ISearchActivatedEventArgs, &search_args)); 1160 1161 if (!ui_channel_) { 1162 DVLOG(1) << "Launched to handle search request"; 1163 LaunchChromeBrowserProcess(L"--windows8-search", args); 1164 } 1165 1166 mswrw::HString search_string; 1167 CheckHR(search_args->get_QueryText(search_string.GetAddressOf())); 1168 string16 search_text(MakeStdWString(search_string.Get())); 1169 1170 ui_loop_.PostTask(FROM_HERE, 1171 base::Bind(&ChromeAppViewAsh::OnSearchRequest, 1172 base::Unretained(this), 1173 search_text)); 1174 return S_OK; 1175 } 1176 1177 HRESULT ChromeAppViewAsh::HandleProtocolRequest( 1178 winapp::Activation::IActivatedEventArgs* args) { 1179 DVLOG(1) << __FUNCTION__; 1180 if (!ui_channel_) 1181 DVLOG(1) << "Launched to handle url request"; 1182 1183 mswr::ComPtr<winapp::Activation::IProtocolActivatedEventArgs> 1184 protocol_args; 1185 CheckHR(args->QueryInterface( 1186 winapp::Activation::IID_IProtocolActivatedEventArgs, 1187 &protocol_args)); 1188 1189 mswr::ComPtr<winfoundtn::IUriRuntimeClass> uri; 1190 protocol_args->get_Uri(&uri); 1191 mswrw::HString url; 1192 uri->get_AbsoluteUri(url.GetAddressOf()); 1193 string16 actual_url(MakeStdWString(url.Get())); 1194 DVLOG(1) << "Received url request: " << actual_url; 1195 1196 ui_loop_.PostTask(FROM_HERE, 1197 base::Bind(&ChromeAppViewAsh::OnNavigateToUrl, 1198 base::Unretained(this), 1199 actual_url)); 1200 return S_OK; 1201 } 1202 1203 HRESULT ChromeAppViewAsh::OnEdgeGestureCompleted( 1204 winui::Input::IEdgeGesture* gesture, 1205 winui::Input::IEdgeGestureEventArgs* args) { 1206 // Swipe from edge gesture (and win+z) is equivalent to pressing F11. 1207 // TODO(cpu): Make this cleaner for m33. 1208 ui_channel_->Send(new MetroViewerHostMsg_KeyDown(VK_F11, 1, 0, 0)); 1209 ::Sleep(15); 1210 ui_channel_->Send(new MetroViewerHostMsg_KeyUp(VK_F11, 1, 0, 0)); 1211 return S_OK; 1212 } 1213 1214 void ChromeAppViewAsh::OnSearchRequest(const string16& search_string) { 1215 DCHECK(ui_channel_); 1216 ui_channel_->Send(new MetroViewerHostMsg_SearchRequest(search_string)); 1217 } 1218 1219 void ChromeAppViewAsh::OnNavigateToUrl(const string16& url) { 1220 DCHECK(ui_channel_); 1221 ui_channel_->Send(new MetroViewerHostMsg_OpenURL(url)); 1222 } 1223 1224 HRESULT ChromeAppViewAsh::OnSizeChanged(winui::Core::ICoreWindow* sender, 1225 winui::Core::IWindowSizeChangedEventArgs* args) { 1226 if (!window_) { 1227 return S_OK; 1228 } 1229 1230 winfoundtn::Size size; 1231 HRESULT hr = args->get_Size(&size); 1232 if (FAILED(hr)) 1233 return hr; 1234 1235 uint32 cx = static_cast<uint32>(size.Width); 1236 uint32 cy = static_cast<uint32>(size.Height); 1237 1238 DVLOG(1) << "Window size changed: width=" << cx << ", height=" << cy; 1239 ui_channel_->Send(new MetroViewerHostMsg_WindowSizeChanged(cx, cy)); 1240 return S_OK; 1241 } 1242 1243 /////////////////////////////////////////////////////////////////////////////// 1244 1245 ChromeAppViewFactory::ChromeAppViewFactory( 1246 winapp::Core::ICoreApplication* icore_app, 1247 LPTHREAD_START_ROUTINE host_main, 1248 void* host_context) { 1249 mswr::ComPtr<winapp::Core::ICoreApplication> core_app(icore_app); 1250 mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit; 1251 CheckHR(core_app.As(&app_exit)); 1252 globals.app_exit = app_exit.Detach(); 1253 } 1254 1255 IFACEMETHODIMP 1256 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) { 1257 *view = mswr::Make<ChromeAppViewAsh>().Detach(); 1258 return (*view) ? S_OK : E_OUTOFMEMORY; 1259 } 1260