- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / app_list / win / activation_tracker_win.cc
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
9 namespace {
10
11 static const wchar_t kTrayClassName[] = L"Shell_TrayWnd";
12
13 }  // namespace
14
15 ActivationTrackerWin::ActivationTrackerWin(
16     app_list::AppListView* view,
17     const base::Closure& on_should_dismiss)
18     : view_(view),
19       on_should_dismiss_(on_should_dismiss),
20       regain_next_lost_focus_(false),
21       preserving_focus_for_taskbar_menu_(false) {
22   view_->AddObserver(this);
23 }
24
25 ActivationTrackerWin::~ActivationTrackerWin() {
26   view_->RemoveObserver(this);
27   timer_.Stop();
28 }
29
30 void ActivationTrackerWin::OnActivationChanged(
31     views::Widget* widget, bool active) {
32   const int kFocusCheckIntervalMS = 250;
33   if (active) {
34     timer_.Stop();
35     return;
36   }
37
38   preserving_focus_for_taskbar_menu_ = false;
39   timer_.Start(FROM_HERE,
40                base::TimeDelta::FromMilliseconds(kFocusCheckIntervalMS), this,
41                &ActivationTrackerWin::CheckTaskbarOrViewHasFocus);
42 }
43
44 void ActivationTrackerWin::OnViewHidden() {
45   timer_.Stop();
46 }
47
48 void ActivationTrackerWin::CheckTaskbarOrViewHasFocus() {
49   // Remember if the taskbar had focus without the right mouse button being
50   // down.
51   bool was_preserving_focus = preserving_focus_for_taskbar_menu_;
52   preserving_focus_for_taskbar_menu_ = false;
53
54   // First get the taskbar and jump lists windows (the jump list is the
55   // context menu which the taskbar uses).
56   HWND jump_list_hwnd = FindWindow(L"DV2ControlHost", NULL);
57   HWND taskbar_hwnd = FindWindow(kTrayClassName, NULL);
58
59   // This code is designed to hide the app launcher when it loses focus,
60   // except for the cases necessary to allow the launcher to be pinned or
61   // closed via the taskbar context menu.
62   // First work out if the left or right button is currently down.
63   int swapped = GetSystemMetrics(SM_SWAPBUTTON);
64   int left_button = swapped ? VK_RBUTTON : VK_LBUTTON;
65   bool left_button_down = GetAsyncKeyState(left_button) < 0;
66   int right_button = swapped ? VK_LBUTTON : VK_RBUTTON;
67   bool right_button_down = GetAsyncKeyState(right_button) < 0;
68
69   // Now get the window that currently has focus.
70   HWND focused_hwnd = GetForegroundWindow();
71   if (!focused_hwnd) {
72     // Sometimes the focused window is NULL. This can happen when the focus is
73     // changing due to a mouse button press. If the button is still being
74     // pressed the launcher should not be hidden.
75     if (right_button_down || left_button_down)
76       return;
77
78     // If the focused window is NULL, and the mouse button is not being
79     // pressed, then the launcher no longer has focus.
80     on_should_dismiss_.Run();
81     return;
82   }
83
84   while (focused_hwnd) {
85     // If the focused window is the right click menu (called a jump list) or
86     // the app list, don't hide the launcher.
87     if (focused_hwnd == jump_list_hwnd ||
88         focused_hwnd == view_->GetHWND()) {
89       return;
90     }
91
92     if (focused_hwnd == taskbar_hwnd) {
93       // If the focused window is the taskbar, and the right button is down,
94       // don't hide the launcher as the user might be bringing up the menu.
95       if (right_button_down)
96         return;
97
98       // There is a short period between the right mouse button being down
99       // and the menu gaining focus, where the taskbar has focus and no button
100       // is down. If the taskbar is observed in this state once the launcher
101       // is not dismissed. If it happens twice in a row it is dismissed.
102       if (!was_preserving_focus) {
103         preserving_focus_for_taskbar_menu_ = true;
104         return;
105       }
106
107       break;
108     }
109     focused_hwnd = GetParent(focused_hwnd);
110   }
111
112   if (regain_next_lost_focus_) {
113     regain_next_lost_focus_ = false;
114     view_->GetWidget()->Activate();
115     return;
116   }
117
118   // If we get here, the focused window is not the taskbar, it's context menu,
119   // or the app list.
120   on_should_dismiss_.Run();
121 }