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