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 |