summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-15 22:04:05 +0000
committercpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-15 22:04:05 +0000
commit87e031aec0fa50cd1c465ad60c34084abcd1ce80 (patch)
tree856c6b3adae7aab4f6314a7a3a9b505ca00a164b
parent85c797aa71429a7781b442a4de19f3b2379be7d6 (diff)
downloadchromium_src-87e031aec0fa50cd1c465ad60c34084abcd1ce80.zip
chromium_src-87e031aec0fa50cd1c465ad60c34084abcd1ce80.tar.gz
chromium_src-87e031aec0fa50cd1c465ad60c34084abcd1ce80.tar.bz2
Merge 234113 "Exit metro mode without leaving a ghost"
> Exit metro mode without leaving a ghost > > This basically brings the code we have for m28 chrome that > uses alt-f4 trick to kill the metro viewer without leaving > the strange thumbnail window in the desktop left corner. > > BUG=315919 > TEST=see bug > > Review URL: https://codereview.chromium.org/67633002 TBR=cpu@chromium.org Review URL: https://codereview.chromium.org/74003007 git-svn-id: svn://svn.chromium.org/chrome/branches/1700/src@235447 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--win8/metro_driver/chrome_app_view_ash.cc87
-rw-r--r--win8/metro_driver/chrome_app_view_ash.h2
2 files changed, 84 insertions, 5 deletions
diff --git a/win8/metro_driver/chrome_app_view_ash.cc b/win8/metro_driver/chrome_app_view_ash.cc
index 7dd7d39..718c8bf 100644
--- a/win8/metro_driver/chrome_app_view_ash.cc
+++ b/win8/metro_driver/chrome_app_view_ash.cc
@@ -68,9 +68,76 @@ struct Globals {
namespace {
-// TODO(robertshield): Share this with chrome_app_view.cc
-void MetroExit() {
- globals.app_exit->Exit();
+enum KeyModifier {
+ NONE,
+ SHIFT = 1,
+ CONTROL = 2,
+ ALT = 4
+};
+
+// Helper function to send keystrokes via the SendInput function.
+// mnemonic_char: The keystroke to be sent.
+// modifiers: Combination with Alt, Ctrl, Shift, etc.
+void SendMnemonic(
+ WORD mnemonic_char, KeyModifier modifiers) {
+ INPUT keys[4] = {0}; // Keyboard events
+ int key_count = 0; // Number of generated events
+
+ if (modifiers & SHIFT) {
+ keys[key_count].type = INPUT_KEYBOARD;
+ keys[key_count].ki.wVk = VK_SHIFT;
+ keys[key_count].ki.wScan = MapVirtualKey(VK_SHIFT, 0);
+ key_count++;
+ }
+
+ if (modifiers & CONTROL) {
+ keys[key_count].type = INPUT_KEYBOARD;
+ keys[key_count].ki.wVk = VK_CONTROL;
+ keys[key_count].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
+ key_count++;
+ }
+
+ if (modifiers & ALT) {
+ keys[key_count].type = INPUT_KEYBOARD;
+ keys[key_count].ki.wVk = VK_MENU;
+ keys[key_count].ki.wScan = MapVirtualKey(VK_MENU, 0);
+ key_count++;
+ }
+
+ keys[key_count].type = INPUT_KEYBOARD;
+ keys[key_count].ki.wVk = mnemonic_char;
+ keys[key_count].ki.wScan = MapVirtualKey(mnemonic_char, 0);
+ key_count++;
+
+ bool should_sleep = key_count > 1;
+
+ // Send key downs.
+ for (int i = 0; i < key_count; i++) {
+ SendInput(1, &keys[ i ], sizeof(keys[0]));
+ keys[i].ki.dwFlags |= KEYEVENTF_KEYUP;
+ if (should_sleep)
+ Sleep(10);
+ }
+
+ // Now send key ups in reverse order.
+ for (int i = key_count; i; i--) {
+ SendInput(1, &keys[ i - 1 ], sizeof(keys[0]));
+ if (should_sleep)
+ Sleep(10);
+ }
+}
+
+// Helper function to Exit metro chrome cleanly. If we are in the foreground
+// then we try and exit by sending an Alt+F4 key combination to the core
+// window which ensures that the chrome application tile does not show up in
+// the running metro apps list on the top left corner.
+void MetroExit(HWND core_window) {
+ if ((core_window != NULL) && (core_window == ::GetForegroundWindow())) {
+ DVLOG(1) << "We are in the foreground. Exiting via Alt F4";
+ SendMnemonic(VK_F4, ALT);
+ } else {
+ globals.app_exit->Exit();
+ }
}
class ChromeChannelListener : public IPC::Listener {
@@ -99,8 +166,13 @@ class ChromeChannelListener : public IPC::Listener {
}
virtual void OnChannelError() OVERRIDE {
- DVLOG(1) << "Channel error";
- MetroExit();
+ DVLOG(1) << "Channel error. Exiting.";
+ MetroExit(app_view_->core_window_hwnd());
+ // In early Windows 8 versions the code above sometimes fails so we call
+ // it a second time with a NULL window which just calls Exit().
+ ui_proxy_->PostDelayedTask(FROM_HERE,
+ base::Bind(&MetroExit, HWND(NULL)),
+ base::TimeDelta::FromMilliseconds(100));
}
private:
@@ -535,6 +607,11 @@ HRESULT ChromeAppViewAsh::Unsnap() {
void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path) {
DLOG(INFO) << "ChannelAppViewAsh::OnActivateDesktop\n";
+
+ // As we are the top level window, the exiting is done async so we manage
+ // to execute the entire function including the final Send().
+ MetroExit(core_window_hwnd());
+
// We are just executing delegate_execute here without parameters. Assumption
// here is that this process will be reused by shell when asking for
// IExecuteCommand interface.
diff --git a/win8/metro_driver/chrome_app_view_ash.h b/win8/metro_driver/chrome_app_view_ash.h
index b301b3a..a393365 100644
--- a/win8/metro_driver/chrome_app_view_ash.h
+++ b/win8/metro_driver/chrome_app_view_ash.h
@@ -82,6 +82,8 @@ class ChromeAppViewAsh
void OnFolderPickerCompleted(FolderPickerSession* folder_picker,
bool success);
+ HWND core_window_hwnd() const { return core_window_hwnd_; }
+
private:
HRESULT OnActivate(winapp::Core::ICoreApplicationView* view,
winapp::Activation::IActivatedEventArgs* args);