Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(803)

Side by Side Diff: win8/metro_driver/chrome_app_view_ash.cc

Issue 67633002: Exit metro mode without leaving a ghost (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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_ash.h" 6 #include "win8/metro_driver/chrome_app_view_ash.h"
7 7
8 #include <corewindow.h> 8 #include <corewindow.h>
9 #include <shellapi.h> 9 #include <shellapi.h>
10 #include <windows.foundation.h> 10 #include <windows.foundation.h>
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 61
62 // Global information used across the metro driver. 62 // Global information used across the metro driver.
63 struct Globals { 63 struct Globals {
64 winapp::Activation::ApplicationExecutionState previous_state; 64 winapp::Activation::ApplicationExecutionState previous_state;
65 winapp::Core::ICoreApplicationExit* app_exit; 65 winapp::Core::ICoreApplicationExit* app_exit;
66 BreakpadExceptionHandler breakpad_exception_handler; 66 BreakpadExceptionHandler breakpad_exception_handler;
67 } globals; 67 } globals;
68 68
69 namespace { 69 namespace {
70 70
71 // TODO(robertshield): Share this with chrome_app_view.cc 71 enum KeyModifier {
72 void MetroExit() { 72 NONE,
73 globals.app_exit->Exit(); 73 SHIFT = 1,
74 CONTROL = 2,
75 ALT = 4
76 };
77
78 // Helper function to send keystrokes via the SendInput function.
79 // mnemonic_char: The keystroke to be sent.
80 // modifiers: Combination with Alt, Ctrl, Shift, etc.
81 void SendMnemonic(
82 WORD mnemonic_char, KeyModifier modifiers) {
83 INPUT keys[4] = {0}; // Keyboard events
84 int key_count = 0; // Number of generated events
85
86 if (modifiers & SHIFT) {
87 keys[key_count].type = INPUT_KEYBOARD;
88 keys[key_count].ki.wVk = VK_SHIFT;
89 keys[key_count].ki.wScan = MapVirtualKey(VK_SHIFT, 0);
90 key_count++;
91 }
92
93 if (modifiers & CONTROL) {
94 keys[key_count].type = INPUT_KEYBOARD;
95 keys[key_count].ki.wVk = VK_CONTROL;
96 keys[key_count].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
97 key_count++;
98 }
99
100 if (modifiers & ALT) {
101 keys[key_count].type = INPUT_KEYBOARD;
102 keys[key_count].ki.wVk = VK_MENU;
103 keys[key_count].ki.wScan = MapVirtualKey(VK_MENU, 0);
104 key_count++;
105 }
106
107 keys[key_count].type = INPUT_KEYBOARD;
108 keys[key_count].ki.wVk = mnemonic_char;
109 keys[key_count].ki.wScan = MapVirtualKey(mnemonic_char, 0);
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 // Now send key ups in reverse order.
123 for (int i = key_count; i; i--) {
124 SendInput(1, &keys[ i - 1 ], sizeof(keys[0]));
125 if (should_sleep)
126 Sleep(10);
127 }
128 }
129
130 // Helper function to Exit metro chrome cleanly. If we are in the foreground
131 // then we try and exit by sending an Alt+F4 key combination to the core
132 // window which ensures that the chrome application tile does not show up in
133 // the running metro apps list on the top left corner.
134 void MetroExit(HWND core_window) {
135 if ((core_window != NULL) && (core_window == ::GetForegroundWindow())) {
136 DVLOG(1) << "We are in the foreground. Exiting via Alt F4";
137 SendMnemonic(VK_F4, ALT);
138 } else {
139 globals.app_exit->Exit();
140 }
74 } 141 }
75 142
76 class ChromeChannelListener : public IPC::Listener { 143 class ChromeChannelListener : public IPC::Listener {
77 public: 144 public:
78 ChromeChannelListener(base::MessageLoop* ui_loop, ChromeAppViewAsh* app_view) 145 ChromeChannelListener(base::MessageLoop* ui_loop, ChromeAppViewAsh* app_view)
79 : ui_proxy_(ui_loop->message_loop_proxy()), 146 : ui_proxy_(ui_loop->message_loop_proxy()),
80 app_view_(app_view) {} 147 app_view_(app_view) {}
81 148
82 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 149 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
83 IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener, message) 150 IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener, message)
84 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktop, 151 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktop,
85 OnActivateDesktop) 152 OnActivateDesktop)
86 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURLOnDesktop, 153 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURLOnDesktop,
87 OnOpenURLOnDesktop) 154 OnOpenURLOnDesktop)
88 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor, OnSetCursor) 155 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor, OnSetCursor)
89 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileOpen, 156 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileOpen,
90 OnDisplayFileOpenDialog) 157 OnDisplayFileOpenDialog)
91 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileSaveAs, 158 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileSaveAs,
92 OnDisplayFileSaveAsDialog) 159 OnDisplayFileSaveAsDialog)
93 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplaySelectFolder, 160 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplaySelectFolder,
94 OnDisplayFolderPicker) 161 OnDisplayFolderPicker)
95 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPos, OnSetCursorPos) 162 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPos, OnSetCursorPos)
96 IPC_MESSAGE_UNHANDLED(__debugbreak()) 163 IPC_MESSAGE_UNHANDLED(__debugbreak())
97 IPC_END_MESSAGE_MAP() 164 IPC_END_MESSAGE_MAP()
98 return true; 165 return true;
99 } 166 }
100 167
101 virtual void OnChannelError() OVERRIDE { 168 virtual void OnChannelError() OVERRIDE {
102 DVLOG(1) << "Channel error"; 169 DVLOG(1) << "Channel error. Exiting.";
103 MetroExit(); 170 MetroExit(app_view_->core_window());
171 // In early Windows 8 versions the code above sometimes fails so we call
172 // it a second time with a NULL window which just calls Exit().
173 ui_proxy_->PostDelayedTask(FROM_HERE,
174 base::Bind(&MetroExit, HWND(NULL)),
175 base::TimeDelta::FromMilliseconds(100));
104 } 176 }
105 177
106 private: 178 private:
107 void OnActivateDesktop(const base::FilePath& shortcut) { 179 void OnActivateDesktop(const base::FilePath& shortcut) {
108 ui_proxy_->PostTask(FROM_HERE, 180 ui_proxy_->PostTask(FROM_HERE,
109 base::Bind(&ChromeAppViewAsh::OnActivateDesktop, 181 base::Bind(&ChromeAppViewAsh::OnActivateDesktop,
110 base::Unretained(app_view_), 182 base::Unretained(app_view_),
111 shortcut)); 183 shortcut));
112 } 184 }
113 185
(...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 LOG(ERROR) << "Failed to unsnap. Error 0x" << hr; 626 LOG(ERROR) << "Failed to unsnap. Error 0x" << hr;
555 if (SUCCEEDED(hr)) 627 if (SUCCEEDED(hr))
556 hr = E_UNEXPECTED; 628 hr = E_UNEXPECTED;
557 } 629 }
558 } 630 }
559 return hr; 631 return hr;
560 } 632 }
561 633
562 void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path) { 634 void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path) {
563 DLOG(INFO) << "ChannelAppViewAsh::OnActivateDesktop\n"; 635 DLOG(INFO) << "ChannelAppViewAsh::OnActivateDesktop\n";
636
637 // As we are the top level window, the exiting is done async so we manage
638 // to execute the entire function including the final Send().
639 MetroExit(core_window());
640
564 // We are just executing delegate_execute here without parameters. Assumption 641 // We are just executing delegate_execute here without parameters. Assumption
565 // here is that this process will be reused by shell when asking for 642 // here is that this process will be reused by shell when asking for
566 // IExecuteCommand interface. 643 // IExecuteCommand interface.
567 644
568 // TODO(shrikant): Consolidate ShellExecuteEx with SEE_MASK_FLAG_LOG_USAGE 645 // TODO(shrikant): Consolidate ShellExecuteEx with SEE_MASK_FLAG_LOG_USAGE
569 // and place it metro.h or similar accessible file from all code code paths 646 // and place it metro.h or similar accessible file from all code code paths
570 // using this function. 647 // using this function.
571 SHELLEXECUTEINFO sei = { sizeof(sei) }; 648 SHELLEXECUTEINFO sei = { sizeof(sei) };
572 sei.fMask = SEE_MASK_FLAG_LOG_USAGE; 649 sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
573 sei.nShow = SW_SHOWNORMAL; 650 sei.nShow = SW_SHOWNORMAL;
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after
1028 mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit; 1105 mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit;
1029 CheckHR(core_app.As(&app_exit)); 1106 CheckHR(core_app.As(&app_exit));
1030 globals.app_exit = app_exit.Detach(); 1107 globals.app_exit = app_exit.Detach();
1031 } 1108 }
1032 1109
1033 IFACEMETHODIMP 1110 IFACEMETHODIMP
1034 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) { 1111 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) {
1035 *view = mswr::Make<ChromeAppViewAsh>().Detach(); 1112 *view = mswr::Make<ChromeAppViewAsh>().Detach();
1036 return (*view) ? S_OK : E_OUTOFMEMORY; 1113 return (*view) ? S_OK : E_OUTOFMEMORY;
1037 } 1114 }
OLDNEW
« win8/metro_driver/chrome_app_view_ash.h ('K') | « win8/metro_driver/chrome_app_view_ash.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698