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 internal::kShellWindowId_OverlayContainer,
20 internal::kShellWindowId_LockSystemModalContainer,
21 internal::kShellWindowId_SettingBubbleContainer,
22 internal::kShellWindowId_LockScreenContainer,
23 internal::kShellWindowId_SystemModalContainer,
24 internal::kShellWindowId_AlwaysOnTopContainer,
25 internal::kShellWindowId_AppListContainer,
26 internal::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 internal::kShellWindowId_DockedContainer,
32 internal::kShellWindowId_PanelContainer,
33 internal::kShellWindowId_ShelfContainer,
34 internal::kShellWindowId_StatusContainer,
35 };
36
BelongsToContainerWithEqualOrGreaterId(const aura::Window * window,int container_id)37 bool BelongsToContainerWithEqualOrGreaterId(const aura::Window* window,
38 int container_id) {
39 for (; window; window = window->parent()) {
40 if (window->id() >= container_id)
41 return true;
42 }
43 return false;
44 }
45
46 } // namespace
47
48 ////////////////////////////////////////////////////////////////////////////////
49 // AshFocusRules, public:
50
AshFocusRules()51 AshFocusRules::AshFocusRules() {
52 }
53
~AshFocusRules()54 AshFocusRules::~AshFocusRules() {
55 }
56
57 ////////////////////////////////////////////////////////////////////////////////
58 // AshFocusRules, views::corewm::FocusRules:
59
SupportsChildActivation(aura::Window * window) const60 bool AshFocusRules::SupportsChildActivation(aura::Window* window) const {
61 if (window->id() == internal::kShellWindowId_DefaultContainer)
62 return true;
63
64 for (size_t i = 0; i < arraysize(kWindowContainerIds); i++) {
65 if (window->id() == kWindowContainerIds[i])
66 return true;
67 }
68 return false;
69 }
70
IsWindowConsideredVisibleForActivation(aura::Window * window) const71 bool AshFocusRules::IsWindowConsideredVisibleForActivation(
72 aura::Window* window) const {
73 if (BaseFocusRules::IsWindowConsideredVisibleForActivation(window))
74 return true;
75
76 // Minimized windows are hidden in their minimized state, but they can always
77 // be activated.
78 if (wm::GetWindowState(window)->IsMinimized())
79 return true;
80
81 return window->TargetVisibility() && (window->parent()->id() ==
82 internal::kShellWindowId_DefaultContainer || window->parent()->id() ==
83 internal::kShellWindowId_LockScreenContainer);
84 }
85
CanActivateWindow(aura::Window * window) const86 bool AshFocusRules::CanActivateWindow(aura::Window* window) const {
87 // Clearing activation is always permissible.
88 if (!window)
89 return true;
90
91 if (!BaseFocusRules::CanActivateWindow(window))
92 return false;
93
94 if (Shell::GetInstance()->IsSystemModalWindowOpen()) {
95 return BelongsToContainerWithEqualOrGreaterId(
96 window, internal::kShellWindowId_SystemModalContainer);
97 }
98
99 return true;
100 }
101
GetNextActivatableWindow(aura::Window * ignore) const102 aura::Window* AshFocusRules::GetNextActivatableWindow(
103 aura::Window* ignore) const {
104 DCHECK(ignore);
105
106 int starting_container_index = 0;
107 // If the container of the window losing focus is in the list, start from that
108 // container.
109 aura::Window* root = ignore->GetRootWindow();
110 if (!root)
111 root = Shell::GetTargetRootWindow();
112 int container_count = static_cast<int>(arraysize(kWindowContainerIds));
113 for (int i = 0; ignore && i < container_count; i++) {
114 aura::Window* container = Shell::GetContainer(root, kWindowContainerIds[i]);
115 if (container && container->Contains(ignore)) {
116 starting_container_index = i;
117 break;
118 }
119 }
120
121 // Look for windows to focus in |ignore|'s container. If none are found, we
122 // look in all the containers in front of |ignore|'s container, then all
123 // behind.
124 aura::Window* window = NULL;
125 for (int i = starting_container_index; !window && i < container_count; i++)
126 window = GetTopmostWindowToActivateForContainerIndex(i, ignore);
127 if (!window && starting_container_index > 0) {
128 for (int i = starting_container_index - 1; !window && i >= 0; i--)
129 window = GetTopmostWindowToActivateForContainerIndex(i, ignore);
130 }
131 return window;
132 }
133
134 ////////////////////////////////////////////////////////////////////////////////
135 // AshFocusRules, private:
136
GetTopmostWindowToActivateForContainerIndex(int index,aura::Window * ignore) const137 aura::Window* AshFocusRules::GetTopmostWindowToActivateForContainerIndex(
138 int index,
139 aura::Window* ignore) const {
140 aura::Window* window = NULL;
141 aura::Window* root = ignore ? ignore->GetRootWindow() : NULL;
142 aura::Window::Windows containers = Shell::GetContainersFromAllRootWindows(
143 kWindowContainerIds[index], root);
144 for (aura::Window::Windows::const_iterator iter = containers.begin();
145 iter != containers.end() && !window; ++iter) {
146 window = GetTopmostWindowToActivateInContainer((*iter), ignore);
147 }
148 return window;
149 }
150
GetTopmostWindowToActivateInContainer(aura::Window * container,aura::Window * ignore) const151 aura::Window* AshFocusRules::GetTopmostWindowToActivateInContainer(
152 aura::Window* container,
153 aura::Window* ignore) const {
154 for (aura::Window::Windows::const_reverse_iterator i =
155 container->children().rbegin();
156 i != container->children().rend();
157 ++i) {
158 WindowState* window_state = GetWindowState(*i);
159 if (*i != ignore &&
160 window_state->CanActivate() &&
161 !window_state->IsMinimized())
162 return *i;
163 }
164 return NULL;
165 }
166
167 } // namespace wm
168 } // namespace ash
169