| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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 "chrome/browser/ui/views/app_list/win/activation_tracker_win.h" | |
| 6 | |
| 7 #include "base/time/time.h" | |
| 8 #include "chrome/browser/ui/app_list/app_list_shower_views.h" | |
| 9 #include "chrome/browser/ui/views/app_list/win/app_list_service_win.h" | |
| 10 #include "ui/app_list/app_list_switches.h" | |
| 11 #include "ui/app_list/views/app_list_view.h" | |
| 12 #include "ui/views/widget/widget.h" | |
| 13 | |
| 14 namespace { | |
| 15 | |
| 16 const wchar_t kJumpListClassName[] = L"DV2ControlHost"; | |
| 17 const wchar_t kTrayClassName[] = L"Shell_TrayWnd"; | |
| 18 const int kFocusCheckIntervalMS = 250; | |
| 19 | |
| 20 } // namespace | |
| 21 | |
| 22 ActivationTrackerWin::ActivationTrackerWin(AppListServiceWin* service) | |
| 23 : service_(service), | |
| 24 taskbar_has_focus_(false) { | |
| 25 service_->shower().app_list()->AddObserver(this); | |
| 26 } | |
| 27 | |
| 28 ActivationTrackerWin::~ActivationTrackerWin() { | |
| 29 DCHECK(service_->shower().app_list()); | |
| 30 service_->shower().app_list()->RemoveObserver(this); | |
| 31 timer_.Stop(); | |
| 32 } | |
| 33 | |
| 34 void ActivationTrackerWin::OnActivationChanged(views::Widget* /*widget*/, | |
| 35 bool active) { | |
| 36 if (active) { | |
| 37 timer_.Stop(); | |
| 38 return; | |
| 39 } | |
| 40 | |
| 41 taskbar_has_focus_ = false; | |
| 42 timer_.Start(FROM_HERE, | |
| 43 base::TimeDelta::FromMilliseconds(kFocusCheckIntervalMS), this, | |
| 44 &ActivationTrackerWin::MaybeDismissAppList); | |
| 45 } | |
| 46 | |
| 47 void ActivationTrackerWin::OnViewHidden() { | |
| 48 timer_.Stop(); | |
| 49 } | |
| 50 | |
| 51 void ActivationTrackerWin::MaybeDismissAppList() { | |
| 52 if (!ShouldDismissAppList()) | |
| 53 return; | |
| 54 | |
| 55 service_->DismissAppList(); | |
| 56 } | |
| 57 | |
| 58 bool ActivationTrackerWin::ShouldDismissAppList() { | |
| 59 // The app launcher should be hidden when it loses focus, except for the cases | |
| 60 // necessary to allow the launcher to be pinned or closed via the taskbar | |
| 61 // context menu. This will return true to dismiss the app launcher unless one | |
| 62 // of the following conditions are met: | |
| 63 // - the switch preventing app list dismissal on blur is active, or | |
| 64 // - the app launcher is focused, or | |
| 65 // - the taskbar's jump list is focused, or | |
| 66 // - the taskbar is focused with the right mouse button pressed. | |
| 67 | |
| 68 if (app_list::switches::ShouldNotDismissOnBlur()) | |
| 69 return false; | |
| 70 | |
| 71 // Remember if the taskbar had focus without the right mouse button being | |
| 72 // down. | |
| 73 bool taskbar_had_focus = taskbar_has_focus_; | |
| 74 taskbar_has_focus_ = false; | |
| 75 | |
| 76 // First get the taskbar and jump lists windows (the jump list is the | |
| 77 // context menu which the taskbar uses). | |
| 78 HWND jump_list_hwnd = FindWindow(kJumpListClassName, NULL); | |
| 79 HWND taskbar_hwnd = FindWindow(kTrayClassName, NULL); | |
| 80 | |
| 81 // First work out if the left or right button is currently down. | |
| 82 int swapped = GetSystemMetrics(SM_SWAPBUTTON); | |
| 83 int left_button = swapped ? VK_RBUTTON : VK_LBUTTON; | |
| 84 bool left_button_down = GetAsyncKeyState(left_button) < 0; | |
| 85 int right_button = swapped ? VK_LBUTTON : VK_RBUTTON; | |
| 86 bool right_button_down = GetAsyncKeyState(right_button) < 0; | |
| 87 | |
| 88 // Now get the window that currently has focus. | |
| 89 HWND focused_hwnd = GetForegroundWindow(); | |
| 90 if (!focused_hwnd) { | |
| 91 // Sometimes the focused window is NULL. This can happen when the focus is | |
| 92 // changing due to a mouse button press. Dismiss the launcher if and only if | |
| 93 // no button is being pressed. | |
| 94 return !right_button_down && !left_button_down; | |
| 95 } | |
| 96 | |
| 97 while (focused_hwnd) { | |
| 98 // If the focused window is the right click menu (called a jump list) or | |
| 99 // the app list, don't hide the launcher. | |
| 100 HWND app_list_hwnd = service_->shower().app_list()->GetHWND(); | |
| 101 if (focused_hwnd == jump_list_hwnd || focused_hwnd == app_list_hwnd) | |
| 102 return false; | |
| 103 | |
| 104 if (focused_hwnd == taskbar_hwnd) { | |
| 105 // If the focused window is the taskbar, and the right button is down, | |
| 106 // don't hide the launcher as the user might be bringing up the menu. | |
| 107 if (right_button_down) | |
| 108 return false; | |
| 109 | |
| 110 // There is a short period between the right mouse button being down | |
| 111 // and the menu gaining focus, where the taskbar has focus and no button | |
| 112 // is down. If the taskbar is observed in this state one time, the | |
| 113 // launcher is not dismissed. If it happens for two consecutive timer | |
| 114 // ticks, it is dismissed. | |
| 115 if (!taskbar_had_focus) { | |
| 116 taskbar_has_focus_ = true; | |
| 117 return false; | |
| 118 } | |
| 119 return true; | |
| 120 } | |
| 121 focused_hwnd = GetParent(focused_hwnd); | |
| 122 } | |
| 123 | |
| 124 // If we get here, the focused window is not the taskbar, its context menu, or | |
| 125 // the app list. | |
| 126 return true; | |
| 127 } | |
| OLD | NEW |