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
3 // found in the LICENSE file.
4
5 #include "ash/wm/ash_focus_rules.h"
6
7 #include "ash/shell.h"
8 #include "ash/shell_window_ids.h"
9 #include "ash/wm/window_state.h"
10 #include "ui/aura/window.h"
11
12 namespace ash {
13 namespace wm {
14 namespace {
15
16 // These are the list of container ids of containers which may contain windows
17 // that need to be activated in the order that they should be activated.
18 const int kWindowContainerIds[] = {
19 kShellWindowId_OverlayContainer,
20 kShellWindowId_LockSystemModalContainer,
21 kShellWindowId_SettingBubbleContainer,
22 kShellWindowId_LockScreenContainer,
23 kShellWindowId_SystemModalContainer,
24 kShellWindowId_AlwaysOnTopContainer,
25 kShellWindowId_AppListContainer,
26 kShellWindowId_DefaultContainer,
27
28 // Docked, panel, launcher and status are intentionally checked after other
29 // containers even though these layers are higher. The user expects their
30 // windows to be focused before these elements.
31 kShellWindowId_DockedContainer,
32 kShellWindowId_PanelContainer,
33 kShellWindowId_ShelfContainer,
34 kShellWindowId_StatusContainer, };
35
BelongsToContainerWithEqualOrGreaterId(const aura::Window * window,int container_id)36 bool BelongsToContainerWithEqualOrGreaterId(const aura::Window* window,
37 int container_id) {
38 for (; window; window = window->parent()) {
39 if (window->id() >= container_id)
40 return true;
41 }
42 return false;
43 }
44
45 } // namespace
46
47 ////////////////////////////////////////////////////////////////////////////////
48 // AshFocusRules, public:
49
AshFocusRules()50 AshFocusRules::AshFocusRules() {
51 }
52
~AshFocusRules()53 AshFocusRules::~AshFocusRules() {
54 }
55
56 ////////////////////////////////////////////////////////////////////////////////
57 // AshFocusRules, ::wm::FocusRules:
58
SupportsChildActivation(aura::Window * window) const59 bool AshFocusRules::SupportsChildActivation(aura::Window* window) const {
60 if (window->id() == kShellWindowId_DefaultContainer)
61 return true;
62
63 for (size_t i = 0; i < arraysize(kWindowContainerIds); i++) {
64 if (window->id() == kWindowContainerIds[i])
65 return true;
66 }
67 return false;
68 }
69
IsWindowConsideredVisibleForActivation(aura::Window * window) const70 bool AshFocusRules::IsWindowConsideredVisibleForActivation(
71 aura::Window* window) const {
72 if (BaseFocusRules::IsWindowConsideredVisibleForActivation(window))
73 return true;
74
75 // Minimized windows are hidden in their minimized state, but they can always
76 // be activated.
77 if (wm::GetWindowState(window)->IsMinimized())
78 return true;
79
80 return window->TargetVisibility() &&
81 (window->parent()->id() == kShellWindowId_DefaultContainer ||
82 window->parent()->id() == kShellWindowId_LockScreenContainer);
83 }
84
CanActivateWindow(aura::Window * window) const85 bool AshFocusRules::CanActivateWindow(aura::Window* window) const {
86 // Clearing activation is always permissible.
87 if (!window)
88 return true;
89
90 if (!BaseFocusRules::CanActivateWindow(window))
91 return false;
92
93 if (Shell::GetInstance()->IsSystemModalWindowOpen()) {
94 return BelongsToContainerWithEqualOrGreaterId(
95 window, kShellWindowId_SystemModalContainer);
96 }
97
98 return true;
99 }
100
GetNextActivatableWindow(aura::Window * ignore) const101 aura::Window* AshFocusRules::GetNextActivatableWindow(
102 aura::Window* ignore) const {
103 DCHECK(ignore);
104
105 int starting_container_index = 0;
106 // If the container of the window losing focus is in the list, start from that
107 // container.
108 aura::Window* root = ignore->GetRootWindow();
109 if (!root)
110 root = Shell::GetTargetRootWindow();
111 int container_count = static_cast<int>(arraysize(kWindowContainerIds));
112 for (int i = 0; ignore && i < container_count; i++) {
113 aura::Window* container = Shell::GetContainer(root, kWindowContainerIds[i]);
114 if (container && container->Contains(ignore)) {
115 starting_container_index = i;
116 break;
117 }
118 }
119
120 // Look for windows to focus in |ignore|'s container. If none are found, we
121 // look in all the containers in front of |ignore|'s container, then all
122 // behind.
123 aura::Window* window = NULL;
124 for (int i = starting_container_index; !window && i < container_count; i++)
125 window = GetTopmostWindowToActivateForContainerIndex(i, ignore);
126 if (!window && starting_container_index > 0) {
127 for (int i = starting_container_index - 1; !window && i >= 0; i--)
128 window = GetTopmostWindowToActivateForContainerIndex(i, ignore);
129 }
130 return window;
131 }
132
133 ////////////////////////////////////////////////////////////////////////////////
134 // AshFocusRules, private:
135
GetTopmostWindowToActivateForContainerIndex(int index,aura::Window * ignore) const136 aura::Window* AshFocusRules::GetTopmostWindowToActivateForContainerIndex(
137 int index,
138 aura::Window* ignore) const {
139 aura::Window* window = NULL;
140 aura::Window* root = ignore ? ignore->GetRootWindow() : NULL;
141 aura::Window::Windows containers = Shell::GetContainersFromAllRootWindows(
142 kWindowContainerIds[index], root);
143 for (aura::Window::Windows::const_iterator iter = containers.begin();
144 iter != containers.end() && !window; ++iter) {
145 window = GetTopmostWindowToActivateInContainer((*iter), ignore);
146 }
147 return window;
148 }
149
GetTopmostWindowToActivateInContainer(aura::Window * container,aura::Window * ignore) const150 aura::Window* AshFocusRules::GetTopmostWindowToActivateInContainer(
151 aura::Window* container,
152 aura::Window* ignore) const {
153 for (aura::Window::Windows::const_reverse_iterator i =
154 container->children().rbegin();
155 i != container->children().rend();
156 ++i) {
157 WindowState* window_state = GetWindowState(*i);
158 if (*i != ignore &&
159 window_state->CanActivate() &&
160 !window_state->IsMinimized())
161 return *i;
162 }
163 return NULL;
164 }
165
166 } // namespace wm
167 } // namespace ash
168