OLD | NEW |
(Empty) | |
| 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.h" |
| 7 |
| 8 #include <algorithm> |
| 9 #include <windows.applicationModel.datatransfer.h> |
| 10 #include <windows.foundation.h> |
| 11 |
| 12 #include "base/bind.h" |
| 13 #include "base/message_loop.h" |
| 14 #include "base/win/metro.h" |
| 15 |
| 16 // This include allows to send WM_SYSCOMMANDs to chrome. |
| 17 #include "chrome/app/chrome_command_ids.h" |
| 18 #include "win8/metro_driver/winrt_utils.h" |
| 19 #include "ui/base/ui_base_switches.h" |
| 20 |
| 21 typedef winfoundtn::ITypedEventHandler< |
| 22 winapp::Core::CoreApplicationView*, |
| 23 winapp::Activation::IActivatedEventArgs*> ActivatedHandler; |
| 24 |
| 25 typedef winfoundtn::ITypedEventHandler< |
| 26 winui::Core::CoreWindow*, |
| 27 winui::Core::WindowSizeChangedEventArgs*> SizeChangedHandler; |
| 28 |
| 29 typedef winfoundtn::ITypedEventHandler< |
| 30 winui::Input::EdgeGesture*, |
| 31 winui::Input::EdgeGestureEventArgs*> EdgeEventHandler; |
| 32 |
| 33 typedef winfoundtn::ITypedEventHandler< |
| 34 winapp::DataTransfer::DataTransferManager*, |
| 35 winapp::DataTransfer::DataRequestedEventArgs*> ShareDataRequestedHandler; |
| 36 |
| 37 typedef winfoundtn::ITypedEventHandler< |
| 38 winui::ViewManagement::InputPane*, |
| 39 winui::ViewManagement::InputPaneVisibilityEventArgs*> |
| 40 InputPaneEventHandler; |
| 41 |
| 42 struct Globals globals; |
| 43 |
| 44 // TODO(ananta) |
| 45 // Remove this once we consolidate metro driver with chrome. |
| 46 const wchar_t kMetroGetCurrentTabInfoMessage[] = |
| 47 L"CHROME_METRO_GET_CURRENT_TAB_INFO"; |
| 48 |
| 49 static const int kFlipWindowsHotKeyId = 0x0000baba; |
| 50 |
| 51 static const int kAnimateWindowTimeoutMs = 200; |
| 52 |
| 53 static const int kCheckOSKDelayMs = 300; |
| 54 |
| 55 const wchar_t kOSKClassName[] = L"IPTip_Main_Window"; |
| 56 |
| 57 static const int kOSKAdjustmentOffset = 20; |
| 58 |
| 59 namespace { |
| 60 |
| 61 void AdjustToFitWindow(HWND hwnd, int flags) { |
| 62 RECT rect = {0}; |
| 63 ::GetWindowRect(globals.core_window, &rect); |
| 64 int cx = rect.right - rect.left; |
| 65 int cy = rect.bottom - rect.top; |
| 66 |
| 67 ::SetWindowPos(hwnd, HWND_TOP, |
| 68 rect.left, rect.top, cx, cy, |
| 69 SWP_NOZORDER | flags); |
| 70 } |
| 71 |
| 72 void AdjustFrameWindowStyleForMetro(HWND hwnd) { |
| 73 DVLOG(1) << __FUNCTION__; |
| 74 // Ajust the frame so the live preview works and the frame buttons dissapear. |
| 75 ::SetWindowLong(hwnd, GWL_STYLE, |
| 76 WS_POPUP | (::GetWindowLong(hwnd, GWL_STYLE) & |
| 77 ~(WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU))); |
| 78 ::SetWindowLong(hwnd, GWL_EXSTYLE, |
| 79 ::GetWindowLong(hwnd, GWL_EXSTYLE) & ~(WS_EX_DLGMODALFRAME | |
| 80 WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); |
| 81 AdjustToFitWindow(hwnd, SWP_FRAMECHANGED | SWP_NOACTIVATE); |
| 82 } |
| 83 |
| 84 void SetFrameWindowInternal(HWND hwnd) { |
| 85 DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd); |
| 86 |
| 87 HWND current_top_frame = |
| 88 !globals.host_windows.empty() ? globals.host_windows.front().first : NULL; |
| 89 if (hwnd != current_top_frame && IsWindow(current_top_frame)) { |
| 90 DVLOG(1) << "Hiding current top window, hwnd=" |
| 91 << LONG_PTR(current_top_frame); |
| 92 ::ShowWindow(current_top_frame, SW_HIDE); |
| 93 } |
| 94 |
| 95 // If chrome opens a url in a foreground tab, it may call SetFrameWindow |
| 96 // again. Ensure that we don't have dups. |
| 97 globals.host_windows.remove_if([hwnd](std::pair<HWND, bool>& item) { |
| 98 return (item.first == hwnd); |
| 99 }); |
| 100 |
| 101 globals.host_windows.push_front(std::make_pair(hwnd, false)); |
| 102 |
| 103 AdjustFrameWindowStyleForMetro(hwnd); |
| 104 } |
| 105 |
| 106 void CloseFrameWindowInternal(HWND hwnd) { |
| 107 DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd); |
| 108 |
| 109 globals.host_windows.remove_if([hwnd](std::pair<HWND, bool>& item) { |
| 110 return (item.first == hwnd); |
| 111 }); |
| 112 |
| 113 if (globals.host_windows.size() > 0) { |
| 114 DVLOG(1) << "Making new top frame window visible:" |
| 115 << reinterpret_cast<int>(globals.host_windows.front().first); |
| 116 AdjustToFitWindow(globals.host_windows.front().first, SWP_SHOWWINDOW); |
| 117 } else { |
| 118 // time to quit |
| 119 DVLOG(1) << "Last host window closed. Calling Exit()."; |
| 120 globals.app_exit->Exit(); |
| 121 } |
| 122 } |
| 123 |
| 124 void FlipFrameWindowsInternal() { |
| 125 DVLOG(1) << __FUNCTION__; |
| 126 // Get the first window in the frame windows queue and push it to the end. |
| 127 // Metroize the next window in the queue. |
| 128 if (globals.host_windows.size() > 1) { |
| 129 std::pair<HWND, bool> current_top_window = globals.host_windows.front(); |
| 130 globals.host_windows.pop_front(); |
| 131 |
| 132 DVLOG(1) << "Making new top frame window visible:" |
| 133 << reinterpret_cast<int>(globals.host_windows.front().first); |
| 134 |
| 135 AdjustToFitWindow(globals.host_windows.front().first, SWP_SHOWWINDOW); |
| 136 |
| 137 DVLOG(1) << "Hiding current top window:" |
| 138 << reinterpret_cast<int>(current_top_window.first); |
| 139 AnimateWindow(current_top_window.first, kAnimateWindowTimeoutMs, |
| 140 AW_HIDE | AW_HOR_POSITIVE | AW_SLIDE); |
| 141 |
| 142 globals.host_windows.push_back(current_top_window); |
| 143 } |
| 144 } |
| 145 |
| 146 } // namespace |
| 147 |
| 148 HRESULT ChromeAppView::TileRequestCreateDone( |
| 149 winfoundtn::IAsyncOperation<bool>* async, |
| 150 AsyncStatus status) { |
| 151 if (status == Completed) { |
| 152 unsigned char result; |
| 153 CheckHR(async->GetResults(&result)); |
| 154 DVLOG(1) << __FUNCTION__ << " result " << static_cast<int>(result); |
| 155 } else { |
| 156 LOG(ERROR) << __FUNCTION__ << " Unexpected async status " << status; |
| 157 } |
| 158 |
| 159 return S_OK; |
| 160 } |
| 161 |
| 162 void ChromeAppView::DisplayNotification( |
| 163 const ToastNotificationHandler::DesktopNotification& notification) { |
| 164 DVLOG(1) << __FUNCTION__; |
| 165 |
| 166 if (IsValidNotification(notification.id)) { |
| 167 NOTREACHED() << "Duplicate notification id passed in."; |
| 168 return; |
| 169 } |
| 170 |
| 171 base::AutoLock lock(notification_lock_); |
| 172 |
| 173 ToastNotificationHandler* notification_handler = |
| 174 new ToastNotificationHandler; |
| 175 |
| 176 notification_map_[notification.id].reset(notification_handler); |
| 177 notification_handler->DisplayNotification(notification); |
| 178 } |
| 179 |
| 180 void ChromeAppView::CancelNotification(const std::string& notification) { |
| 181 DVLOG(1) << __FUNCTION__; |
| 182 |
| 183 base::AutoLock lock(notification_lock_); |
| 184 |
| 185 NotificationMap::iterator index = notification_map_.find(notification); |
| 186 if (index == notification_map_.end()) { |
| 187 NOTREACHED() << "Invalid notification:" << notification.c_str(); |
| 188 return; |
| 189 } |
| 190 |
| 191 scoped_ptr<ToastNotificationHandler> notification_handler( |
| 192 index->second.release()); |
| 193 |
| 194 notification_map_.erase(index); |
| 195 |
| 196 notification_handler->CancelNotification(); |
| 197 } |
| 198 |
| 199 // Returns true if the notification passed in is valid. |
| 200 bool ChromeAppView::IsValidNotification(const std::string& notification) { |
| 201 DVLOG(1) << __FUNCTION__; |
| 202 |
| 203 base::AutoLock lock(notification_lock_); |
| 204 return notification_map_.find(notification) != notification_map_.end(); |
| 205 } |
| 206 |
| 207 void ChromeAppView::ShowDialogBox( |
| 208 const MetroDialogBox::DialogBoxInfo& dialog_box_info) { |
| 209 VLOG(1) << __FUNCTION__; |
| 210 dialog_box_.Show(dialog_box_info); |
| 211 } |
| 212 |
| 213 void ChromeAppView::DismissDialogBox() { |
| 214 VLOG(1) << __FUNCTION__; |
| 215 dialog_box_.Dismiss(); |
| 216 } |
| 217 |
| 218 // static |
| 219 HRESULT ChromeAppView::Unsnap() { |
| 220 mswr::ComPtr<winui::ViewManagement::IApplicationViewStatics> view_statics; |
| 221 HRESULT hr = winrt_utils::CreateActivationFactory( |
| 222 RuntimeClass_Windows_UI_ViewManagement_ApplicationView, |
| 223 view_statics.GetAddressOf()); |
| 224 CheckHR(hr); |
| 225 |
| 226 winui::ViewManagement::ApplicationViewState state = |
| 227 winui::ViewManagement::ApplicationViewState_FullScreenLandscape; |
| 228 hr = view_statics->get_Value(&state); |
| 229 CheckHR(hr); |
| 230 |
| 231 if (state == winui::ViewManagement::ApplicationViewState_Snapped) { |
| 232 boolean success = FALSE; |
| 233 hr = view_statics->TryUnsnap(&success); |
| 234 |
| 235 if (FAILED(hr) || !success) { |
| 236 LOG(ERROR) << "Failed to unsnap. Error 0x" << hr; |
| 237 if (SUCCEEDED(hr)) |
| 238 hr = E_UNEXPECTED; |
| 239 } |
| 240 } |
| 241 return hr; |
| 242 } |
| 243 |
| 244 void ChromeAppView::SetFullscreen(bool fullscreen) { |
| 245 VLOG(1) << __FUNCTION__; |
| 246 |
| 247 if (osk_offset_adjustment_) { |
| 248 VLOG(1) << "Scrolling the window down by: " |
| 249 << osk_offset_adjustment_; |
| 250 |
| 251 ::ScrollWindowEx(globals.host_windows.front().first, |
| 252 0, |
| 253 osk_offset_adjustment_, |
| 254 NULL, |
| 255 NULL, |
| 256 NULL, |
| 257 NULL, |
| 258 SW_INVALIDATE | SW_SCROLLCHILDREN); |
| 259 osk_offset_adjustment_ = 0; |
| 260 } |
| 261 } |
| 262 |
| 263 void UnsnapHelper() { |
| 264 ChromeAppView::Unsnap(); |
| 265 } |
| 266 |
| 267 extern "C" __declspec(dllexport) |
| 268 void MetroUnsnap() { |
| 269 DVLOG(1) << __FUNCTION__; |
| 270 globals.appview_msg_loop->PostTask( |
| 271 FROM_HERE, base::Bind(&UnsnapHelper)); |
| 272 } |
| 273 |
| 274 extern "C" __declspec(dllexport) |
| 275 HWND GetRootWindow() { |
| 276 DVLOG(1) << __FUNCTION__; |
| 277 return globals.core_window; |
| 278 } |
| 279 |
| 280 extern "C" __declspec(dllexport) |
| 281 void SetFrameWindow(HWND hwnd) { |
| 282 DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd); |
| 283 globals.appview_msg_loop->PostTask( |
| 284 FROM_HERE, base::Bind(&SetFrameWindowInternal, hwnd)); |
| 285 } |
| 286 |
| 287 // TODO(ananta) |
| 288 // Handle frame window close by deleting it from the window list and making the |
| 289 // next guy visible. |
| 290 extern "C" __declspec(dllexport) |
| 291 void CloseFrameWindow(HWND hwnd) { |
| 292 DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd); |
| 293 |
| 294 // This is a hack to ensure that the BrowserViewLayout code layout happens |
| 295 // just at the right time to hide the switcher button if it is visible. |
| 296 globals.appview_msg_loop->PostDelayedTask( |
| 297 FROM_HERE, base::Bind(&CloseFrameWindowInternal, hwnd), |
| 298 base::TimeDelta::FromMilliseconds(50)); |
| 299 } |
| 300 |
| 301 // Returns the initial url. This returns a valid url only if we were launched |
| 302 // into metro via a url navigation. |
| 303 extern "C" __declspec(dllexport) |
| 304 const wchar_t* GetInitialUrl() { |
| 305 DVLOG(1) << __FUNCTION__; |
| 306 bool was_initial_activation = globals.is_initial_activation; |
| 307 globals.is_initial_activation = false; |
| 308 if (!was_initial_activation || globals.navigation_url.empty()) |
| 309 return L""; |
| 310 |
| 311 const wchar_t* initial_url = globals.navigation_url.c_str(); |
| 312 DVLOG(1) << initial_url; |
| 313 return initial_url; |
| 314 } |
| 315 |
| 316 // Returns the initial search string. This returns a valid url only if we were |
| 317 // launched into metro via the search charm |
| 318 extern "C" __declspec(dllexport) |
| 319 const wchar_t* GetInitialSearchString() { |
| 320 DVLOG(1) << __FUNCTION__; |
| 321 bool was_initial_activation = globals.is_initial_activation; |
| 322 globals.is_initial_activation = false; |
| 323 if (!was_initial_activation || globals.search_string.empty()) |
| 324 return L""; |
| 325 |
| 326 const wchar_t* initial_search_string = globals.search_string.c_str(); |
| 327 DVLOG(1) << initial_search_string; |
| 328 return initial_search_string; |
| 329 } |
| 330 |
| 331 // Returns the launch type. |
| 332 extern "C" __declspec(dllexport) |
| 333 base::win::MetroLaunchType GetLaunchType( |
| 334 base::win::MetroPreviousExecutionState* previous_state) { |
| 335 if (previous_state) { |
| 336 *previous_state = static_cast<base::win::MetroPreviousExecutionState>( |
| 337 globals.previous_state); |
| 338 } |
| 339 return static_cast<base::win::MetroLaunchType>( |
| 340 globals.initial_activation_kind); |
| 341 } |
| 342 |
| 343 extern "C" __declspec(dllexport) |
| 344 void FlipFrameWindows() { |
| 345 DVLOG(1) << __FUNCTION__; |
| 346 globals.appview_msg_loop->PostTask( |
| 347 FROM_HERE, base::Bind(&FlipFrameWindowsInternal)); |
| 348 } |
| 349 |
| 350 extern "C" __declspec(dllexport) |
| 351 void DisplayNotification(const char* origin_url, const char* icon_url, |
| 352 const wchar_t* title, const wchar_t* body, |
| 353 const wchar_t* display_source, |
| 354 const char* notification_id) { |
| 355 // TODO(ananta) |
| 356 // Needs implementation. |
| 357 DVLOG(1) << __FUNCTION__; |
| 358 |
| 359 ToastNotificationHandler::DesktopNotification notification(origin_url, |
| 360 icon_url, |
| 361 title, |
| 362 body, |
| 363 display_source, |
| 364 notification_id); |
| 365 globals.appview_msg_loop->PostTask( |
| 366 FROM_HERE, base::Bind(&ChromeAppView::DisplayNotification, |
| 367 globals.view, notification)); |
| 368 } |
| 369 |
| 370 extern "C" __declspec(dllexport) |
| 371 bool CancelNotification(const char* notification_id) { |
| 372 // TODO(ananta) |
| 373 // Needs implementation. |
| 374 DVLOG(1) << __FUNCTION__; |
| 375 |
| 376 if (!globals.view->IsValidNotification(notification_id)) { |
| 377 NOTREACHED() << "Invalid notification id :" << notification_id; |
| 378 return false; |
| 379 } |
| 380 |
| 381 globals.appview_msg_loop->PostTask( |
| 382 FROM_HERE, base::Bind(&ChromeAppView::CancelNotification, |
| 383 globals.view, std::string(notification_id))); |
| 384 return true; |
| 385 } |
| 386 |
| 387 // Returns command line switches if any to be used by metro chrome. |
| 388 extern "C" __declspec(dllexport) |
| 389 const wchar_t* GetMetroCommandLineSwitches() { |
| 390 DVLOG(1) << __FUNCTION__; |
| 391 // The metro_command_line_switches field should be filled up once. |
| 392 // ideally in ChromeAppView::Activate. |
| 393 return globals.metro_command_line_switches.c_str(); |
| 394 } |
| 395 |
| 396 // Provides functionality to display a metro style dialog box with two buttons. |
| 397 // Only one dialog box can be displayed at any given time. |
| 398 extern "C" __declspec(dllexport) |
| 399 void ShowDialogBox( |
| 400 const wchar_t* title, |
| 401 const wchar_t* content, |
| 402 const wchar_t* button1_label, |
| 403 const wchar_t* button2_label, |
| 404 base::win::MetroDialogButtonPressedHandler button1_handler, |
| 405 base::win::MetroDialogButtonPressedHandler button2_handler) { |
| 406 VLOG(1) << __FUNCTION__; |
| 407 |
| 408 DCHECK(title); |
| 409 DCHECK(content); |
| 410 DCHECK(button1_label); |
| 411 DCHECK(button2_label); |
| 412 DCHECK(button1_handler); |
| 413 DCHECK(button2_handler); |
| 414 |
| 415 MetroDialogBox::DialogBoxInfo dialog_box_info; |
| 416 dialog_box_info.title = title; |
| 417 dialog_box_info.content = content; |
| 418 dialog_box_info.button1_label = button1_label; |
| 419 dialog_box_info.button2_label = button2_label; |
| 420 dialog_box_info.button1_handler = button1_handler; |
| 421 dialog_box_info.button2_handler = button2_handler; |
| 422 |
| 423 globals.appview_msg_loop->PostTask( |
| 424 FROM_HERE, base::Bind( |
| 425 &ChromeAppView::ShowDialogBox, globals.view, dialog_box_info)); |
| 426 } |
| 427 |
| 428 // Provides functionality to dismiss the previously displayed metro style |
| 429 // dialog box. |
| 430 extern "C" __declspec(dllexport) |
| 431 void DismissDialogBox() { |
| 432 VLOG(1) << __FUNCTION__; |
| 433 |
| 434 globals.appview_msg_loop->PostTask( |
| 435 FROM_HERE, base::Bind( |
| 436 &ChromeAppView::DismissDialogBox, |
| 437 globals.view)); |
| 438 } |
| 439 |
| 440 extern "C" __declspec(dllexport) |
| 441 void SetFullscreen(bool fullscreen) { |
| 442 VLOG(1) << __FUNCTION__; |
| 443 |
| 444 globals.appview_msg_loop->PostTask( |
| 445 FROM_HERE, base::Bind( |
| 446 &ChromeAppView::SetFullscreen, |
| 447 globals.view, fullscreen)); |
| 448 } |
| 449 |
| 450 BOOL CALLBACK CoreWindowFinder(HWND hwnd, LPARAM) { |
| 451 char classname[128]; |
| 452 if (::GetClassNameA(hwnd, classname, ARRAYSIZE(classname))) { |
| 453 if (lstrcmpiA("Windows.UI.Core.CoreWindow", classname) == 0) { |
| 454 globals.core_window = hwnd; |
| 455 return FALSE; |
| 456 } |
| 457 } |
| 458 return TRUE; |
| 459 } |
| 460 |
| 461 template <typename ContainerT> |
| 462 void CloseSecondaryWindows(ContainerT& windows) { |
| 463 DVLOG(1) << "Closing secondary windows", windows.size(); |
| 464 std::for_each(windows.begin(), windows.end(), [](HWND hwnd) { |
| 465 ::PostMessageW(hwnd, WM_CLOSE, 0, 0); |
| 466 }); |
| 467 windows.clear(); |
| 468 } |
| 469 |
| 470 void EndChromeSession() { |
| 471 DVLOG(1) << "Sending chrome WM_ENDSESSION window message."; |
| 472 ::SendMessage(globals.host_windows.front().first, WM_ENDSESSION, FALSE, |
| 473 ENDSESSION_CLOSEAPP); |
| 474 } |
| 475 |
| 476 DWORD WINAPI HostMainThreadProc(void*) { |
| 477 // Test feature - devs have requested the ability to easily add metro-chrome |
| 478 // command line arguments. This is hard since shortcut arguments are ignored, |
| 479 // by Metro, so we instead read them directly from the pinned taskbar |
| 480 // shortcut. This may call Coinitialize and there is tell of badness |
| 481 // occurring if CoInitialize is called on a metro thread. |
| 482 globals.metro_command_line_switches = |
| 483 winrt_utils::ReadArgumentsFromPinnedTaskbarShortcut(); |
| 484 |
| 485 globals.g_core_proc = reinterpret_cast<WNDPROC>( |
| 486 ::SetWindowLong(globals.core_window, GWL_WNDPROC, |
| 487 reinterpret_cast<long>(ChromeAppView::CoreWindowProc))); |
| 488 DWORD exit_code = globals.host_main(globals.host_context); |
| 489 DVLOG(1) << "host thread done, exit_code=" << exit_code; |
| 490 globals.app_exit->Exit(); |
| 491 return exit_code; |
| 492 } |
| 493 |
| 494 ChromeAppView::ChromeAppView() |
| 495 : osk_visible_notification_received_(false), |
| 496 osk_offset_adjustment_(0) { |
| 497 globals.previous_state = |
| 498 winapp::Activation::ApplicationExecutionState_NotRunning; |
| 499 } |
| 500 |
| 501 ChromeAppView::~ChromeAppView() { |
| 502 DVLOG(1) << __FUNCTION__; |
| 503 } |
| 504 |
| 505 IFACEMETHODIMP |
| 506 ChromeAppView::Initialize(winapp::Core::ICoreApplicationView* view) { |
| 507 view_ = view; |
| 508 DVLOG(1) << __FUNCTION__; |
| 509 globals.main_thread_id = ::GetCurrentThreadId(); |
| 510 |
| 511 HRESULT hr = view_->add_Activated(mswr::Callback<ActivatedHandler>( |
| 512 this, &ChromeAppView::OnActivate).Get(), |
| 513 &activated_token_); |
| 514 CheckHR(hr); |
| 515 return hr; |
| 516 } |
| 517 |
| 518 IFACEMETHODIMP |
| 519 ChromeAppView::SetWindow(winui::Core::ICoreWindow* window) { |
| 520 window_ = window; |
| 521 DVLOG(1) << __FUNCTION__; |
| 522 |
| 523 HRESULT hr = url_launch_handler_.Initialize(); |
| 524 CheckHR(hr, "Failed to initialize url launch handler."); |
| 525 |
| 526 // Register for size notifications. |
| 527 hr = window_->add_SizeChanged(mswr::Callback<SizeChangedHandler>( |
| 528 this, &ChromeAppView::OnSizeChanged).Get(), |
| 529 &sizechange_token_); |
| 530 CheckHR(hr); |
| 531 |
| 532 // Register for edge gesture notifications. |
| 533 mswr::ComPtr<winui::Input::IEdgeGestureStatics> edge_gesture_statics; |
| 534 hr = winrt_utils::CreateActivationFactory( |
| 535 RuntimeClass_Windows_UI_Input_EdgeGesture, |
| 536 edge_gesture_statics.GetAddressOf()); |
| 537 CheckHR(hr, "Failed to activate IEdgeGestureStatics."); |
| 538 |
| 539 mswr::ComPtr<winui::Input::IEdgeGesture> edge_gesture; |
| 540 hr = edge_gesture_statics->GetForCurrentView(&edge_gesture); |
| 541 CheckHR(hr); |
| 542 |
| 543 hr = edge_gesture->add_Completed(mswr::Callback<EdgeEventHandler>( |
| 544 this, &ChromeAppView::OnEdgeGestureCompleted).Get(), |
| 545 &edgeevent_token_); |
| 546 CheckHR(hr); |
| 547 |
| 548 // Register for share notifications. |
| 549 mswr::ComPtr<winapp::DataTransfer::IDataTransferManagerStatics> |
| 550 data_mgr_statics; |
| 551 hr = winrt_utils::CreateActivationFactory( |
| 552 RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager, |
| 553 data_mgr_statics.GetAddressOf()); |
| 554 CheckHR(hr, "Failed to activate IDataTransferManagerStatics."); |
| 555 |
| 556 mswr::ComPtr<winapp::DataTransfer::IDataTransferManager> data_transfer_mgr; |
| 557 hr = data_mgr_statics->GetForCurrentView(&data_transfer_mgr); |
| 558 CheckHR(hr, "Failed to get IDataTransferManager for current view."); |
| 559 |
| 560 hr = data_transfer_mgr->add_DataRequested( |
| 561 mswr::Callback<ShareDataRequestedHandler>( |
| 562 this, &ChromeAppView::OnShareDataRequested).Get(), |
| 563 &share_data_requested_token_); |
| 564 CheckHR(hr); |
| 565 |
| 566 // TODO(ananta) |
| 567 // The documented InputPane notifications don't fire on Windows 8 in metro |
| 568 // chrome. Uncomment this once we figure out why they don't fire. |
| 569 // RegisterInputPaneNotifications(); |
| 570 |
| 571 hr = winrt_utils::CreateActivationFactory( |
| 572 RuntimeClass_Windows_UI_ViewManagement_ApplicationView, |
| 573 app_view_.GetAddressOf()); |
| 574 CheckHR(hr); |
| 575 |
| 576 DVLOG(1) << "Created appview instance."; |
| 577 |
| 578 hr = devices_handler_.Initialize(window); |
| 579 // Don't check or return the failure here, we need to let the app |
| 580 // initialization succeed. Even if we won't be able to access devices |
| 581 // we still want to allow the app to start. |
| 582 LOG_IF(ERROR, FAILED(hr)) << "Failed to initialize devices handler."; |
| 583 return S_OK; |
| 584 } |
| 585 |
| 586 IFACEMETHODIMP |
| 587 ChromeAppView::Load(HSTRING entryPoint) { |
| 588 DVLOG(1) << __FUNCTION__; |
| 589 return S_OK; |
| 590 } |
| 591 |
| 592 void RunMessageLoop(winui::Core::ICoreDispatcher* dispatcher) { |
| 593 // We're entering a nested message loop, let's allow dispatching |
| 594 // tasks while we're in there. |
| 595 MessageLoop::current()->SetNestableTasksAllowed(true); |
| 596 |
| 597 // Enter main core message loop. There are several ways to exit it |
| 598 // Nicely: |
| 599 // 1 - User action like ALT-F4. |
| 600 // 2 - Calling ICoreApplicationExit::Exit(). |
| 601 // 3- Posting WM_CLOSE to the core window. |
| 602 HRESULT hr = dispatcher->ProcessEvents( |
| 603 winui::Core::CoreProcessEventsOption |
| 604 ::CoreProcessEventsOption_ProcessUntilQuit); |
| 605 |
| 606 // Wind down the thread's chrome message loop. |
| 607 MessageLoop::current()->Quit(); |
| 608 } |
| 609 |
| 610 void ChromeAppView::CheckForOSKActivation() { |
| 611 // Hack for checking if the OSK was displayed while we are in the foreground. |
| 612 // The input pane notifications which are supposed to fire when the OSK is |
| 613 // shown and hidden don't seem to be firing in Windows 8 metro for us. |
| 614 // The current hack is supposed to workaround that issue till we figure it |
| 615 // out. Logic is to find the OSK window and see if we are the foreground |
| 616 // process. If yes then fire the notification once for when the OSK is shown |
| 617 // and once for when it is hidden. |
| 618 // TODO(ananta) |
| 619 // Take this out when the documented input pane notifcation issues are |
| 620 // addressed. |
| 621 HWND osk = ::FindWindow(kOSKClassName, NULL); |
| 622 if (::IsWindow(osk)) { |
| 623 HWND foreground_window = ::GetForegroundWindow(); |
| 624 if (globals.host_windows.size() > 0 && |
| 625 foreground_window == globals.host_windows.front().first) { |
| 626 RECT osk_rect = {0}; |
| 627 ::GetWindowRect(osk, &osk_rect); |
| 628 |
| 629 if (::IsWindowVisible(osk) && ::IsWindowEnabled(osk)) { |
| 630 if (!globals.view->osk_visible_notification_received()) { |
| 631 DVLOG(1) << "Found KB window while we are in the forground."; |
| 632 HandleInputPaneVisible(osk_rect); |
| 633 } |
| 634 } else if (osk_visible_notification_received()) { |
| 635 DVLOG(1) << "KB window hidden while we are in the foreground."; |
| 636 HandleInputPaneHidden(osk_rect); |
| 637 } |
| 638 } |
| 639 } |
| 640 MessageLoop::current()->PostDelayedTask( |
| 641 FROM_HERE, |
| 642 base::Bind(&ChromeAppView::CheckForOSKActivation, |
| 643 base::Unretained(this)), |
| 644 base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs)); |
| 645 } |
| 646 |
| 647 IFACEMETHODIMP |
| 648 ChromeAppView::Run() { |
| 649 DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(window_.Get()); |
| 650 mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher; |
| 651 HRESULT hr = window_->get_Dispatcher(&dispatcher); |
| 652 CheckHR(hr, "Dispatcher failed."); |
| 653 |
| 654 hr = window_->Activate(); |
| 655 if (SUCCEEDED(hr)) { |
| 656 // TODO(cpu): Draw something here. |
| 657 } else { |
| 658 DVLOG(1) << "Activate failed, hr=" << hr; |
| 659 } |
| 660 |
| 661 // Create a message loop to allow message passing into this thread. |
| 662 MessageLoop msg_loop(MessageLoop::TYPE_UI); |
| 663 |
| 664 // Announce our message loop to the world. |
| 665 globals.appview_msg_loop = msg_loop.message_loop_proxy(); |
| 666 |
| 667 // And post the task that'll do the inner Metro message pumping to it. |
| 668 msg_loop.PostTask(FROM_HERE, base::Bind(&RunMessageLoop, dispatcher.Get())); |
| 669 |
| 670 // Post the recurring task which checks for OSK activation in metro chrome. |
| 671 // Please refer to the comments in the CheckForOSKActivation function for why |
| 672 // this is needed. |
| 673 // TODO(ananta) |
| 674 // Take this out when the documented OSK notifications start working. |
| 675 msg_loop.PostDelayedTask( |
| 676 FROM_HERE, |
| 677 base::Bind(&ChromeAppView::CheckForOSKActivation, |
| 678 base::Unretained(this)), |
| 679 base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs)); |
| 680 |
| 681 msg_loop.Run(); |
| 682 |
| 683 globals.appview_msg_loop = NULL; |
| 684 |
| 685 DVLOG(0) << "ProcessEvents done, hr=" << hr; |
| 686 |
| 687 // We join here with chrome's main thread so that the chrome is not killed |
| 688 // while a critical operation is still in progress. Now, if there are host |
| 689 // windows active it is possible we end up stuck on the wait below therefore |
| 690 // we tell chrome to close its windows. |
| 691 if (!globals.host_windows.empty()) { |
| 692 DVLOG(1) << "Chrome still has windows open!"; |
| 693 EndChromeSession(); |
| 694 } |
| 695 DWORD wr = ::WaitForSingleObject(globals.host_thread, INFINITE); |
| 696 if (wr != WAIT_OBJECT_0) { |
| 697 DVLOG(1) << "Waiting for host thread failed : " << wr; |
| 698 } |
| 699 ::CloseHandle(globals.host_thread); |
| 700 globals.host_thread = NULL; |
| 701 |
| 702 return hr; |
| 703 } |
| 704 |
| 705 IFACEMETHODIMP |
| 706 ChromeAppView::Uninitialize() { |
| 707 DVLOG(1) << __FUNCTION__; |
| 708 window_ = nullptr; |
| 709 view_ = nullptr; |
| 710 base::AutoLock lock(notification_lock_); |
| 711 notification_map_.clear(); |
| 712 return S_OK; |
| 713 } |
| 714 |
| 715 HRESULT ChromeAppView::RegisterInputPaneNotifications() { |
| 716 DVLOG(1) << __FUNCTION__; |
| 717 |
| 718 mswr::ComPtr<winui::ViewManagement::IInputPaneStatics> |
| 719 input_pane_statics; |
| 720 HRESULT hr = winrt_utils::CreateActivationFactory( |
| 721 RuntimeClass_Windows_UI_ViewManagement_InputPane, |
| 722 input_pane_statics.GetAddressOf()); |
| 723 CheckHR(hr); |
| 724 |
| 725 hr = input_pane_statics->GetForCurrentView(&input_pane_); |
| 726 CheckHR(hr); |
| 727 DVLOG(1) << "Got input pane."; |
| 728 |
| 729 hr = input_pane_->add_Showing( |
| 730 mswr::Callback<InputPaneEventHandler>( |
| 731 this, &ChromeAppView::OnInputPaneVisible).Get(), |
| 732 &input_pane_visible_token_); |
| 733 CheckHR(hr); |
| 734 |
| 735 DVLOG(1) << "Added showing event handler for input pane", |
| 736 input_pane_visible_token_.value; |
| 737 |
| 738 hr = input_pane_->add_Hiding( |
| 739 mswr::Callback<InputPaneEventHandler>( |
| 740 this, &ChromeAppView::OnInputPaneHiding).Get(), |
| 741 &input_pane_hiding_token_); |
| 742 CheckHR(hr); |
| 743 |
| 744 DVLOG(1) << "Added hiding event handler for input pane, value=" |
| 745 << input_pane_hiding_token_.value; |
| 746 return hr; |
| 747 } |
| 748 |
| 749 HRESULT ChromeAppView::OnActivate(winapp::Core::ICoreApplicationView*, |
| 750 winapp::Activation::IActivatedEventArgs* args) { |
| 751 DVLOG(1) << __FUNCTION__; |
| 752 |
| 753 args->get_PreviousExecutionState(&globals.previous_state); |
| 754 DVLOG(1) << "Previous Execution State: " << globals.previous_state; |
| 755 |
| 756 window_->Activate(); |
| 757 url_launch_handler_.Activate(args); |
| 758 |
| 759 if (globals.previous_state == |
| 760 winapp::Activation::ApplicationExecutionState_Running && |
| 761 globals.host_thread) { |
| 762 DVLOG(1) << "Already running. Skipping rest of OnActivate."; |
| 763 return S_OK; |
| 764 } |
| 765 |
| 766 do { |
| 767 ::Sleep(10); |
| 768 ::EnumThreadWindows(globals.main_thread_id, &CoreWindowFinder, 0); |
| 769 } while (globals.core_window == NULL); |
| 770 |
| 771 DVLOG(1) << "CoreWindow found: " << std::hex << globals.core_window; |
| 772 |
| 773 if (!globals.host_thread) { |
| 774 globals.host_thread = |
| 775 ::CreateThread(NULL, 0, HostMainThreadProc, NULL, 0, NULL); |
| 776 |
| 777 if (!globals.host_thread) { |
| 778 NOTREACHED() << "thread creation failed."; |
| 779 return E_UNEXPECTED; |
| 780 } |
| 781 } |
| 782 |
| 783 if (RegisterHotKey(globals.core_window, kFlipWindowsHotKeyId, |
| 784 MOD_CONTROL, VK_F12)) { |
| 785 DVLOG(1) << "Registered flip window hotkey."; |
| 786 } else { |
| 787 VPLOG(1) << "Failed to register flip window hotkey."; |
| 788 } |
| 789 HRESULT hr = settings_handler_.Initialize(); |
| 790 CheckHR(hr,"Failed to initialize settings handler."); |
| 791 return hr; |
| 792 } |
| 793 |
| 794 // We subclass the core window for moving the associated chrome window when the |
| 795 // core window is moved around, typically in the snap view operation. The |
| 796 // size changes are handled in the documented size changed event. |
| 797 LRESULT CALLBACK ChromeAppView::CoreWindowProc( |
| 798 HWND window, UINT message, WPARAM wp, LPARAM lp) { |
| 799 |
| 800 static const UINT kBrowserClosingMessage = |
| 801 ::RegisterWindowMessage(L"DefaultBrowserClosing"); |
| 802 |
| 803 if (message == WM_WINDOWPOSCHANGED) { |
| 804 WINDOWPOS* pos = reinterpret_cast<WINDOWPOS*>(lp); |
| 805 if (!(pos->flags & SWP_NOMOVE)) { |
| 806 DVLOG(1) << "WM_WINDOWPOSCHANGED. Moving the chrome window."; |
| 807 globals.view->OnPositionChanged(pos->x, pos->y); |
| 808 } |
| 809 } else if (message == WM_HOTKEY && wp == kFlipWindowsHotKeyId) { |
| 810 FlipFrameWindows(); |
| 811 } else if (message == kBrowserClosingMessage) { |
| 812 DVLOG(1) << "Received DefaultBrowserClosing window message."; |
| 813 // Ensure that the view is uninitialized. The kBrowserClosingMessage |
| 814 // means that the app is going to be terminated, i.e. the proper |
| 815 // uninitialization sequence does not occur. |
| 816 globals.view->Uninitialize(); |
| 817 if (!globals.host_windows.empty()) { |
| 818 EndChromeSession(); |
| 819 } |
| 820 } |
| 821 return CallWindowProc(globals.g_core_proc, window, message, wp, lp); |
| 822 } |
| 823 |
| 824 HRESULT ChromeAppView::OnSizeChanged(winui::Core::ICoreWindow* sender, |
| 825 winui::Core::IWindowSizeChangedEventArgs* args) { |
| 826 if (!globals.host_windows.size()) { |
| 827 return S_OK; |
| 828 } |
| 829 |
| 830 winfoundtn::Size size; |
| 831 args->get_Size(&size); |
| 832 |
| 833 int cx = static_cast<int>(size.Width); |
| 834 int cy = static_cast<int>(size.Height); |
| 835 |
| 836 if (!::SetWindowPos(globals.host_windows.front().first, NULL, 0, 0, cx, cy, |
| 837 SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED)) { |
| 838 DVLOG(1) << "SetWindowPos failed."; |
| 839 } |
| 840 DVLOG(1) << "size changed cx=" << cx; |
| 841 DVLOG(1) << "size changed cy=" << cy; |
| 842 |
| 843 winui::ViewManagement::ApplicationViewState view_state = |
| 844 winui::ViewManagement::ApplicationViewState_FullScreenLandscape; |
| 845 app_view_->get_Value(&view_state); |
| 846 |
| 847 HWND top_level_frame = globals.host_windows.front().first; |
| 848 if (view_state == winui::ViewManagement::ApplicationViewState_Snapped) { |
| 849 DVLOG(1) << "Enabling metro snap mode."; |
| 850 ::PostMessageW(top_level_frame, WM_SYSCOMMAND, IDC_METRO_SNAP_ENABLE, 0); |
| 851 } else { |
| 852 ::PostMessageW(top_level_frame, WM_SYSCOMMAND, IDC_METRO_SNAP_DISABLE, 0); |
| 853 } |
| 854 return S_OK; |
| 855 } |
| 856 |
| 857 HRESULT ChromeAppView::OnPositionChanged(int x, int y) { |
| 858 DVLOG(1) << __FUNCTION__; |
| 859 |
| 860 ::SetWindowPos(globals.host_windows.front().first, NULL, x, y, 0, 0, |
| 861 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOSIZE); |
| 862 return S_OK; |
| 863 } |
| 864 |
| 865 HRESULT ChromeAppView::OnEdgeGestureCompleted( |
| 866 winui::Input::IEdgeGesture* gesture, |
| 867 winui::Input::IEdgeGestureEventArgs* args) { |
| 868 DVLOG(1) << "edge gesture completed."; |
| 869 |
| 870 winui::ViewManagement::ApplicationViewState view_state = |
| 871 winui::ViewManagement::ApplicationViewState_FullScreenLandscape; |
| 872 app_view_->get_Value(&view_state); |
| 873 // We don't want fullscreen chrome unless we are fullscreen metro. |
| 874 if ((view_state == winui::ViewManagement::ApplicationViewState_Filled) || |
| 875 (view_state == winui::ViewManagement::ApplicationViewState_Snapped)) { |
| 876 DVLOG(1) << "No full screen in snapped view state:" << view_state; |
| 877 return S_OK; |
| 878 } |
| 879 |
| 880 // Deactivate anything pending, e.g., the wrench or a context menu. |
| 881 BOOL success = ::ReleaseCapture(); |
| 882 DCHECK(success) << "Couldn't ReleaseCapture() before going full screen"; |
| 883 |
| 884 DVLOG(1) << "Going full screen."; |
| 885 ::PostMessageW(globals.host_windows.front().first, WM_SYSCOMMAND, |
| 886 IDC_FULLSCREEN, 0); |
| 887 return S_OK; |
| 888 } |
| 889 |
| 890 HRESULT ChromeAppView::OnShareDataRequested( |
| 891 winapp::DataTransfer::IDataTransferManager* data_transfer_mgr, |
| 892 winapp::DataTransfer::IDataRequestedEventArgs* event_args) { |
| 893 |
| 894 DVLOG(1) << "Share data requested."; |
| 895 |
| 896 // The current tab info is retrieved from Chrome via a registered window |
| 897 // message. |
| 898 |
| 899 static const UINT get_current_tab_info = |
| 900 RegisterWindowMessage(kMetroGetCurrentTabInfoMessage); |
| 901 |
| 902 static const int kGetTabInfoTimeoutMs = 1000; |
| 903 |
| 904 mswr::ComPtr<winapp::DataTransfer::IDataRequest> data_request; |
| 905 HRESULT hr = event_args->get_Request(&data_request); |
| 906 CheckHR(hr); |
| 907 |
| 908 mswr::ComPtr<winapp::DataTransfer::IDataPackage> data_package; |
| 909 hr = data_request->get_Data(&data_package); |
| 910 CheckHR(hr); |
| 911 |
| 912 base::win::CurrentTabInfo current_tab_info; |
| 913 current_tab_info.title = NULL; |
| 914 current_tab_info.url = NULL; |
| 915 |
| 916 DWORD_PTR result = 0; |
| 917 |
| 918 if (!SendMessageTimeout(globals.host_windows.front().first, |
| 919 get_current_tab_info, |
| 920 reinterpret_cast<WPARAM>(¤t_tab_info), |
| 921 0, |
| 922 SMTO_ABORTIFHUNG, |
| 923 kGetTabInfoTimeoutMs, |
| 924 &result)) { |
| 925 VPLOG(1) << "Failed to retrieve tab info from chrome."; |
| 926 return E_FAIL; |
| 927 } |
| 928 |
| 929 if (!current_tab_info.title || !current_tab_info.url) { |
| 930 DVLOG(1) << "Failed to retrieve tab info from chrome."; |
| 931 return E_FAIL; |
| 932 } |
| 933 |
| 934 string16 current_title(current_tab_info.title); |
| 935 string16 current_url(current_tab_info.url); |
| 936 |
| 937 LocalFree(current_tab_info.title); |
| 938 LocalFree(current_tab_info.url); |
| 939 |
| 940 mswr::ComPtr<winapp::DataTransfer::IDataPackagePropertySet> data_properties; |
| 941 hr = data_package->get_Properties(&data_properties); |
| 942 |
| 943 mswrw::HString title; |
| 944 title.Attach(MakeHString(current_title)); |
| 945 data_properties->put_Title(title.Get()); |
| 946 |
| 947 mswr::ComPtr<winfoundtn::IUriRuntimeClassFactory> uri_factory; |
| 948 hr = winrt_utils::CreateActivationFactory( |
| 949 RuntimeClass_Windows_Foundation_Uri, |
| 950 uri_factory.GetAddressOf()); |
| 951 CheckHR(hr); |
| 952 |
| 953 mswrw::HString url; |
| 954 url.Attach(MakeHString(current_url)); |
| 955 mswr::ComPtr<winfoundtn::IUriRuntimeClass> uri; |
| 956 hr = uri_factory->CreateUri(url.Get(), &uri); |
| 957 CheckHR(hr); |
| 958 |
| 959 hr = data_package->SetUri(uri.Get()); |
| 960 CheckHR(hr); |
| 961 |
| 962 return S_OK; |
| 963 } |
| 964 |
| 965 void ChromeAppView::HandleInputPaneVisible(const RECT& osk_rect) { |
| 966 DCHECK(!osk_visible_notification_received_); |
| 967 |
| 968 DVLOG(1) << __FUNCTION__; |
| 969 DVLOG(1) << "OSK width:" << osk_rect.right - osk_rect.left; |
| 970 DVLOG(1) << "OSK height:" << osk_rect.bottom - osk_rect.top; |
| 971 |
| 972 globals.host_windows.front().second = false; |
| 973 |
| 974 POINT cursor_pos = {0}; |
| 975 GetCursorPos(&cursor_pos); |
| 976 |
| 977 osk_offset_adjustment_ = 0; |
| 978 |
| 979 if (::PtInRect(&osk_rect, cursor_pos)) { |
| 980 DVLOG(1) << "OSK covering focus point."; |
| 981 int osk_height = osk_rect.bottom - osk_rect.top; |
| 982 |
| 983 osk_offset_adjustment_ = osk_height + kOSKAdjustmentOffset; |
| 984 |
| 985 DVLOG(1) << "Scrolling window by offset: " << osk_offset_adjustment_; |
| 986 ::ScrollWindowEx(globals.host_windows.front().first, |
| 987 0, |
| 988 -osk_offset_adjustment_, |
| 989 NULL, |
| 990 NULL, |
| 991 NULL, |
| 992 NULL, |
| 993 SW_INVALIDATE | SW_SCROLLCHILDREN); |
| 994 |
| 995 globals.host_windows.front().second = true; |
| 996 } |
| 997 osk_visible_notification_received_ = true; |
| 998 } |
| 999 |
| 1000 void ChromeAppView::HandleInputPaneHidden(const RECT& osk_rect) { |
| 1001 DCHECK(osk_visible_notification_received_); |
| 1002 DVLOG(1) << __FUNCTION__; |
| 1003 DVLOG(1) << "OSK width:" << osk_rect.right - osk_rect.left; |
| 1004 DVLOG(1) << "OSK height:" << osk_rect.bottom - osk_rect.top; |
| 1005 osk_visible_notification_received_ = false; |
| 1006 if (globals.host_windows.front().second == true) { |
| 1007 |
| 1008 if (osk_offset_adjustment_) { |
| 1009 DVLOG(1) << "Restoring scrolled window offset: " |
| 1010 << osk_offset_adjustment_; |
| 1011 |
| 1012 ::ScrollWindowEx(globals.host_windows.front().first, |
| 1013 0, |
| 1014 osk_offset_adjustment_, |
| 1015 NULL, |
| 1016 NULL, |
| 1017 NULL, |
| 1018 NULL, |
| 1019 SW_INVALIDATE | SW_SCROLLCHILDREN); |
| 1020 } |
| 1021 |
| 1022 globals.host_windows.front().second = false; |
| 1023 } |
| 1024 } |
| 1025 |
| 1026 HRESULT ChromeAppView::OnInputPaneVisible( |
| 1027 winui::ViewManagement::IInputPane* input_pane, |
| 1028 winui::ViewManagement::IInputPaneVisibilityEventArgs* event_args) { |
| 1029 DVLOG(1) << __FUNCTION__; |
| 1030 return S_OK; |
| 1031 } |
| 1032 |
| 1033 HRESULT ChromeAppView::OnInputPaneHiding( |
| 1034 winui::ViewManagement::IInputPane* input_pane, |
| 1035 winui::ViewManagement::IInputPaneVisibilityEventArgs* event_args) { |
| 1036 DVLOG(1) << __FUNCTION__; |
| 1037 return S_OK; |
| 1038 } |
| 1039 |
| 1040 /////////////////////////////////////////////////////////////////////////////// |
| 1041 |
| 1042 ChromeAppViewFactory::ChromeAppViewFactory( |
| 1043 winapp::Core::ICoreApplication* icore_app, |
| 1044 LPTHREAD_START_ROUTINE host_main, |
| 1045 void* host_context) { |
| 1046 globals.host_main = host_main; |
| 1047 globals.host_context = host_context; |
| 1048 mswr::ComPtr<winapp::Core::ICoreApplication> core_app(icore_app); |
| 1049 mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit; |
| 1050 CheckHR(core_app.As(&app_exit)); |
| 1051 globals.app_exit = app_exit.Detach(); |
| 1052 } |
| 1053 |
| 1054 IFACEMETHODIMP |
| 1055 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) { |
| 1056 globals.view = mswr::Make<ChromeAppView>().Detach(); |
| 1057 *view = globals.view; |
| 1058 return (*view) ? S_OK : E_OUTOFMEMORY; |
| 1059 } |
OLD | NEW |