| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "win8/metro_driver/stdafx.h" | 5 #include "win8/metro_driver/stdafx.h" |
| 6 #include "win8/metro_driver/chrome_app_view.h" | 6 #include "win8/metro_driver/chrome_app_view.h" |
| 7 | 7 |
| 8 #include <algorithm> | 8 #include <algorithm> |
| 9 #include <windows.applicationModel.datatransfer.h> | 9 #include <windows.applicationModel.datatransfer.h> |
| 10 #include <windows.foundation.h> | 10 #include <windows.foundation.h> |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 static const int kFlipWindowsHotKeyId = 0x0000baba; | 49 static const int kFlipWindowsHotKeyId = 0x0000baba; |
| 50 | 50 |
| 51 static const int kAnimateWindowTimeoutMs = 200; | 51 static const int kAnimateWindowTimeoutMs = 200; |
| 52 | 52 |
| 53 static const int kCheckOSKDelayMs = 300; | 53 static const int kCheckOSKDelayMs = 300; |
| 54 | 54 |
| 55 const wchar_t kOSKClassName[] = L"IPTip_Main_Window"; | 55 const wchar_t kOSKClassName[] = L"IPTip_Main_Window"; |
| 56 | 56 |
| 57 static const int kOSKAdjustmentOffset = 20; | 57 static const int kOSKAdjustmentOffset = 20; |
| 58 | 58 |
| 59 const wchar_t kChromeSubclassWindowProp[] = L"MetroChromeWindowProc"; |
| 60 |
| 59 namespace { | 61 namespace { |
| 60 | 62 |
| 63 enum Modifier { |
| 64 NONE, |
| 65 SHIFT = 1, |
| 66 CONTROL = 2, |
| 67 ALT = 4 |
| 68 }; |
| 69 |
| 70 // Helper function to send keystrokes via the SendInput function. |
| 71 // Params: |
| 72 // mnemonic_char: The keystroke to be sent. |
| 73 // modifiers: Combination with Alt, Ctrl, Shift, etc. |
| 74 // extended: whether this is an extended key. |
| 75 // unicode: whether this is a unicode key. |
| 76 void SendMnemonic(WORD mnemonic_char, Modifier modifiers, bool extended, |
| 77 bool unicode) { |
| 78 INPUT keys[4] = {0}; // Keyboard events |
| 79 int key_count = 0; // Number of generated events |
| 80 |
| 81 if (modifiers & SHIFT) { |
| 82 keys[key_count].type = INPUT_KEYBOARD; |
| 83 keys[key_count].ki.wVk = VK_SHIFT; |
| 84 keys[key_count].ki.wScan = MapVirtualKey(VK_SHIFT, 0); |
| 85 key_count++; |
| 86 } |
| 87 |
| 88 if (modifiers & CONTROL) { |
| 89 keys[key_count].type = INPUT_KEYBOARD; |
| 90 keys[key_count].ki.wVk = VK_CONTROL; |
| 91 keys[key_count].ki.wScan = MapVirtualKey(VK_CONTROL, 0); |
| 92 key_count++; |
| 93 } |
| 94 |
| 95 if (modifiers & ALT) { |
| 96 keys[key_count].type = INPUT_KEYBOARD; |
| 97 keys[key_count].ki.wVk = VK_MENU; |
| 98 keys[key_count].ki.wScan = MapVirtualKey(VK_MENU, 0); |
| 99 key_count++; |
| 100 } |
| 101 |
| 102 keys[key_count].type = INPUT_KEYBOARD; |
| 103 keys[key_count].ki.wVk = mnemonic_char; |
| 104 keys[key_count].ki.wScan = MapVirtualKey(mnemonic_char, 0); |
| 105 |
| 106 if (extended) |
| 107 keys[key_count].ki.dwFlags |= KEYEVENTF_EXTENDEDKEY; |
| 108 if (unicode) |
| 109 keys[key_count].ki.dwFlags |= KEYEVENTF_UNICODE; |
| 110 key_count++; |
| 111 |
| 112 bool should_sleep = key_count > 1; |
| 113 |
| 114 // Send key downs |
| 115 for (int i = 0; i < key_count; i++) { |
| 116 SendInput(1, &keys[ i ], sizeof(keys[0])); |
| 117 keys[i].ki.dwFlags |= KEYEVENTF_KEYUP; |
| 118 if (should_sleep) { |
| 119 Sleep(10); |
| 120 } |
| 121 } |
| 122 |
| 123 // Now send key ups in reverse order |
| 124 for (int i = key_count; i; i--) { |
| 125 SendInput(1, &keys[ i - 1 ], sizeof(keys[0])); |
| 126 if (should_sleep) { |
| 127 Sleep(10); |
| 128 } |
| 129 } |
| 130 } |
| 131 |
| 132 void MetroExit() { |
| 133 if (globals.core_window == ::GetForegroundWindow()) { |
| 134 DVLOG(1) << "We are in the foreground. Exiting via Alt F4"; |
| 135 SendMnemonic(VK_F4, ALT, false, false); |
| 136 DWORD core_window_process_id = 0; |
| 137 DWORD core_window_thread_id = GetWindowThreadProcessId( |
| 138 globals.core_window, &core_window_process_id); |
| 139 if (core_window_thread_id != ::GetCurrentThreadId()) { |
| 140 // Sleep to give time to the core window thread to get this message. |
| 141 Sleep(100); |
| 142 } |
| 143 } else { |
| 144 DVLOG(1) << "We are not in the foreground. Exiting normally"; |
| 145 globals.app_exit->Exit(); |
| 146 globals.core_window = NULL; |
| 147 } |
| 148 } |
| 149 |
| 61 void AdjustToFitWindow(HWND hwnd, int flags) { | 150 void AdjustToFitWindow(HWND hwnd, int flags) { |
| 62 RECT rect = {0}; | 151 RECT rect = {0}; |
| 63 ::GetWindowRect(globals.core_window, &rect); | 152 ::GetWindowRect(globals.core_window, &rect); |
| 64 int cx = rect.right - rect.left; | 153 int cx = rect.right - rect.left; |
| 65 int cy = rect.bottom - rect.top; | 154 int cy = rect.bottom - rect.top; |
| 66 | 155 |
| 67 ::SetWindowPos(hwnd, HWND_TOP, | 156 ::SetWindowPos(hwnd, HWND_TOP, |
| 68 rect.left, rect.top, cx, cy, | 157 rect.left, rect.top, cx, cy, |
| 69 SWP_NOZORDER | flags); | 158 SWP_NOZORDER | flags); |
| 70 } | 159 } |
| 71 | 160 |
| 161 LRESULT CALLBACK ChromeWindowProc(HWND window, |
| 162 UINT message, |
| 163 WPARAM wp, |
| 164 LPARAM lp) { |
| 165 if (message == WM_SETCURSOR) { |
| 166 // Override the WM_SETCURSOR message to avoid showing the resize cursor |
| 167 // as the mouse moves to the edge of the screen. |
| 168 switch (LOWORD(lp)) { |
| 169 case HTBOTTOM: |
| 170 case HTBOTTOMLEFT: |
| 171 case HTBOTTOMRIGHT: |
| 172 case HTLEFT: |
| 173 case HTRIGHT: |
| 174 case HTTOP: |
| 175 case HTTOPLEFT: |
| 176 case HTTOPRIGHT: |
| 177 lp = MAKELPARAM(HTCLIENT, HIWORD(lp)); |
| 178 break; |
| 179 default: |
| 180 break; |
| 181 } |
| 182 } |
| 183 |
| 184 WNDPROC old_proc = reinterpret_cast<WNDPROC>( |
| 185 ::GetProp(window, kChromeSubclassWindowProp)); |
| 186 DCHECK(old_proc); |
| 187 return CallWindowProc(old_proc, window, message, wp, lp); |
| 188 } |
| 189 |
| 72 void AdjustFrameWindowStyleForMetro(HWND hwnd) { | 190 void AdjustFrameWindowStyleForMetro(HWND hwnd) { |
| 73 DVLOG(1) << __FUNCTION__; | 191 DVLOG(1) << __FUNCTION__; |
| 74 // Ajust the frame so the live preview works and the frame buttons dissapear. | 192 // Ajust the frame so the live preview works and the frame buttons dissapear. |
| 75 ::SetWindowLong(hwnd, GWL_STYLE, | 193 ::SetWindowLong(hwnd, GWL_STYLE, |
| 76 WS_POPUP | (::GetWindowLong(hwnd, GWL_STYLE) & | 194 WS_POPUP | (::GetWindowLong(hwnd, GWL_STYLE) & |
| 77 ~(WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU))); | 195 ~(WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU))); |
| 78 ::SetWindowLong(hwnd, GWL_EXSTYLE, | 196 ::SetWindowLong(hwnd, GWL_EXSTYLE, |
| 79 ::GetWindowLong(hwnd, GWL_EXSTYLE) & ~(WS_EX_DLGMODALFRAME | | 197 ::GetWindowLong(hwnd, GWL_EXSTYLE) & ~(WS_EX_DLGMODALFRAME | |
| 80 WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); | 198 WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); |
| 199 |
| 200 // Subclass the wndproc of the frame window, if it's not already there. |
| 201 if (::GetProp(hwnd, kChromeSubclassWindowProp) == NULL) { |
| 202 WNDPROC old_chrome_proc = reinterpret_cast<WNDPROC>( |
| 203 ::SetWindowLong(hwnd, GWL_WNDPROC, |
| 204 reinterpret_cast<long>(ChromeWindowProc))); |
| 205 ::SetProp(hwnd, kChromeSubclassWindowProp, old_chrome_proc); |
| 206 } |
| 81 AdjustToFitWindow(hwnd, SWP_FRAMECHANGED | SWP_NOACTIVATE); | 207 AdjustToFitWindow(hwnd, SWP_FRAMECHANGED | SWP_NOACTIVATE); |
| 82 } | 208 } |
| 83 | 209 |
| 84 void SetFrameWindowInternal(HWND hwnd) { | 210 void SetFrameWindowInternal(HWND hwnd) { |
| 85 DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd); | 211 DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd); |
| 86 | 212 |
| 87 HWND current_top_frame = | 213 HWND current_top_frame = |
| 88 !globals.host_windows.empty() ? globals.host_windows.front().first : NULL; | 214 !globals.host_windows.empty() ? globals.host_windows.front().first : NULL; |
| 89 if (hwnd != current_top_frame && IsWindow(current_top_frame)) { | 215 if (hwnd != current_top_frame && IsWindow(current_top_frame)) { |
| 90 DVLOG(1) << "Hiding current top window, hwnd=" | 216 DVLOG(1) << "Hiding current top window, hwnd=" |
| (...skipping 19 matching lines...) Expand all Loading... |
| 110 return (item.first == hwnd); | 236 return (item.first == hwnd); |
| 111 }); | 237 }); |
| 112 | 238 |
| 113 if (globals.host_windows.size() > 0) { | 239 if (globals.host_windows.size() > 0) { |
| 114 DVLOG(1) << "Making new top frame window visible:" | 240 DVLOG(1) << "Making new top frame window visible:" |
| 115 << reinterpret_cast<int>(globals.host_windows.front().first); | 241 << reinterpret_cast<int>(globals.host_windows.front().first); |
| 116 AdjustToFitWindow(globals.host_windows.front().first, SWP_SHOWWINDOW); | 242 AdjustToFitWindow(globals.host_windows.front().first, SWP_SHOWWINDOW); |
| 117 } else { | 243 } else { |
| 118 // time to quit | 244 // time to quit |
| 119 DVLOG(1) << "Last host window closed. Calling Exit()."; | 245 DVLOG(1) << "Last host window closed. Calling Exit()."; |
| 120 globals.app_exit->Exit(); | 246 MetroExit(); |
| 121 } | 247 } |
| 122 } | 248 } |
| 123 | 249 |
| 124 void FlipFrameWindowsInternal() { | 250 void FlipFrameWindowsInternal() { |
| 125 DVLOG(1) << __FUNCTION__; | 251 DVLOG(1) << __FUNCTION__; |
| 126 // Get the first window in the frame windows queue and push it to the end. | 252 // Get the first window in the frame windows queue and push it to the end. |
| 127 // Metroize the next window in the queue. | 253 // Metroize the next window in the queue. |
| 128 if (globals.host_windows.size() > 1) { | 254 if (globals.host_windows.size() > 1) { |
| 129 std::pair<HWND, bool> current_top_window = globals.host_windows.front(); | 255 std::pair<HWND, bool> current_top_window = globals.host_windows.front(); |
| 130 globals.host_windows.pop_front(); | 256 globals.host_windows.pop_front(); |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 // by Metro, so we instead read them directly from the pinned taskbar | 605 // by Metro, so we instead read them directly from the pinned taskbar |
| 480 // shortcut. This may call Coinitialize and there is tell of badness | 606 // shortcut. This may call Coinitialize and there is tell of badness |
| 481 // occurring if CoInitialize is called on a metro thread. | 607 // occurring if CoInitialize is called on a metro thread. |
| 482 globals.metro_command_line_switches = | 608 globals.metro_command_line_switches = |
| 483 winrt_utils::ReadArgumentsFromPinnedTaskbarShortcut(); | 609 winrt_utils::ReadArgumentsFromPinnedTaskbarShortcut(); |
| 484 | 610 |
| 485 globals.g_core_proc = reinterpret_cast<WNDPROC>( | 611 globals.g_core_proc = reinterpret_cast<WNDPROC>( |
| 486 ::SetWindowLong(globals.core_window, GWL_WNDPROC, | 612 ::SetWindowLong(globals.core_window, GWL_WNDPROC, |
| 487 reinterpret_cast<long>(ChromeAppView::CoreWindowProc))); | 613 reinterpret_cast<long>(ChromeAppView::CoreWindowProc))); |
| 488 DWORD exit_code = globals.host_main(globals.host_context); | 614 DWORD exit_code = globals.host_main(globals.host_context); |
| 615 |
| 489 DVLOG(1) << "host thread done, exit_code=" << exit_code; | 616 DVLOG(1) << "host thread done, exit_code=" << exit_code; |
| 490 globals.app_exit->Exit(); | 617 MetroExit(); |
| 491 return exit_code; | 618 return exit_code; |
| 492 } | 619 } |
| 493 | 620 |
| 494 ChromeAppView::ChromeAppView() | 621 ChromeAppView::ChromeAppView() |
| 495 : osk_visible_notification_received_(false), | 622 : osk_visible_notification_received_(false), |
| 496 osk_offset_adjustment_(0) { | 623 osk_offset_adjustment_(0) { |
| 497 globals.previous_state = | 624 globals.previous_state = |
| 498 winapp::Activation::ApplicationExecutionState_NotRunning; | 625 winapp::Activation::ApplicationExecutionState_NotRunning; |
| 499 } | 626 } |
| 500 | 627 |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 // windows active it is possible we end up stuck on the wait below therefore | 816 // windows active it is possible we end up stuck on the wait below therefore |
| 690 // we tell chrome to close its windows. | 817 // we tell chrome to close its windows. |
| 691 if (!globals.host_windows.empty()) { | 818 if (!globals.host_windows.empty()) { |
| 692 DVLOG(1) << "Chrome still has windows open!"; | 819 DVLOG(1) << "Chrome still has windows open!"; |
| 693 EndChromeSession(); | 820 EndChromeSession(); |
| 694 } | 821 } |
| 695 DWORD wr = ::WaitForSingleObject(globals.host_thread, INFINITE); | 822 DWORD wr = ::WaitForSingleObject(globals.host_thread, INFINITE); |
| 696 if (wr != WAIT_OBJECT_0) { | 823 if (wr != WAIT_OBJECT_0) { |
| 697 DVLOG(1) << "Waiting for host thread failed : " << wr; | 824 DVLOG(1) << "Waiting for host thread failed : " << wr; |
| 698 } | 825 } |
| 826 |
| 827 DVLOG(1) << "Host thread exited"; |
| 828 |
| 699 ::CloseHandle(globals.host_thread); | 829 ::CloseHandle(globals.host_thread); |
| 700 globals.host_thread = NULL; | 830 globals.host_thread = NULL; |
| 701 | |
| 702 return hr; | 831 return hr; |
| 703 } | 832 } |
| 704 | 833 |
| 705 IFACEMETHODIMP | 834 IFACEMETHODIMP |
| 706 ChromeAppView::Uninitialize() { | 835 ChromeAppView::Uninitialize() { |
| 707 DVLOG(1) << __FUNCTION__; | 836 DVLOG(1) << __FUNCTION__; |
| 708 window_ = nullptr; | 837 window_ = nullptr; |
| 709 view_ = nullptr; | 838 view_ = nullptr; |
| 710 base::AutoLock lock(notification_lock_); | 839 base::AutoLock lock(notification_lock_); |
| 711 notification_map_.clear(); | 840 notification_map_.clear(); |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1050 CheckHR(core_app.As(&app_exit)); | 1179 CheckHR(core_app.As(&app_exit)); |
| 1051 globals.app_exit = app_exit.Detach(); | 1180 globals.app_exit = app_exit.Detach(); |
| 1052 } | 1181 } |
| 1053 | 1182 |
| 1054 IFACEMETHODIMP | 1183 IFACEMETHODIMP |
| 1055 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) { | 1184 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) { |
| 1056 globals.view = mswr::Make<ChromeAppView>().Detach(); | 1185 globals.view = mswr::Make<ChromeAppView>().Detach(); |
| 1057 *view = globals.view; | 1186 *view = globals.view; |
| 1058 return (*view) ? S_OK : E_OUTOFMEMORY; | 1187 return (*view) ? S_OK : E_OUTOFMEMORY; |
| 1059 } | 1188 } |
| OLD | NEW |