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.
5 #include "ash/wm/ash_focus_rules.h"
7 #include "ash/session/session_state_delegate.h"
9 #include "ash/shell_delegate.h"
10 #include "ash/shell_window_ids.h"
11 #include "ash/wm/mru_window_tracker.h"
12 #include "ash/wm/window_state.h"
13 #include "ui/aura/window.h"
19 // These are the list of container ids of containers which may contain windows
20 // that need to be activated in the order that they should be activated.
21 const int kWindowContainerIds
[] = {
22 kShellWindowId_OverlayContainer
,
23 kShellWindowId_LockSystemModalContainer
,
24 kShellWindowId_SettingBubbleContainer
,
25 kShellWindowId_LockScreenContainer
,
26 kShellWindowId_SystemModalContainer
,
27 kShellWindowId_AlwaysOnTopContainer
,
28 kShellWindowId_AppListContainer
,
29 kShellWindowId_DefaultContainer
,
31 // Docked, panel, launcher and status are intentionally checked after other
32 // containers even though these layers are higher. The user expects their
33 // windows to be focused before these elements.
34 kShellWindowId_DockedContainer
,
35 kShellWindowId_PanelContainer
,
36 kShellWindowId_ShelfContainer
,
37 kShellWindowId_StatusContainer
, };
39 bool BelongsToContainerWithEqualOrGreaterId(const aura::Window
* window
,
41 for (; window
; window
= window
->parent()) {
42 if (window
->id() >= container_id
)
50 ////////////////////////////////////////////////////////////////////////////////
51 // AshFocusRules, public:
53 AshFocusRules::AshFocusRules() : is_shutting_down_(false) {
54 ash::Shell::GetInstance()->AddShellObserver(this);
57 AshFocusRules::~AshFocusRules() {
58 ash::Shell::GetInstance()->RemoveShellObserver(this);
61 bool AshFocusRules::IsWindowConsideredActivatable(aura::Window
* window
) const {
62 // Only toplevel windows can be activated.
63 if (!IsToplevelWindow(window
))
66 // The window must be visible.
67 if (!IsWindowConsideredVisibleForActivation(window
))
73 ////////////////////////////////////////////////////////////////////////////////
74 // AshFocusRules, ::wm::FocusRules:
76 bool AshFocusRules::SupportsChildActivation(aura::Window
* window
) const {
77 if (window
->id() == kShellWindowId_DefaultContainer
)
80 for (size_t i
= 0; i
< arraysize(kWindowContainerIds
); i
++) {
81 if (window
->id() == kWindowContainerIds
[i
])
87 bool AshFocusRules::IsWindowConsideredVisibleForActivation(
88 aura::Window
* window
) const {
89 // If the |window| doesn't belong to the current active user and also doesn't
90 // show for the current active user, then it should not be activated.
91 SessionStateDelegate
* delegate
=
92 Shell::GetInstance()->session_state_delegate();
93 if (delegate
->NumberOfLoggedInUsers() > 1) {
94 content::BrowserContext
* active_browser_context
=
95 Shell::GetInstance()->delegate()->GetActiveBrowserContext();
96 content::BrowserContext
* owner_browser_context
=
97 delegate
->GetBrowserContextForWindow(window
);
98 content::BrowserContext
* shown_browser_context
=
99 delegate
->GetUserPresentingBrowserContextForWindow(window
);
101 if (owner_browser_context
&& active_browser_context
&&
102 owner_browser_context
!= active_browser_context
&&
103 shown_browser_context
!= active_browser_context
) {
108 if (BaseFocusRules::IsWindowConsideredVisibleForActivation(window
))
111 // Minimized windows are hidden in their minimized state, but they can always
113 if (wm::GetWindowState(window
)->IsMinimized())
116 return window
->TargetVisibility() &&
117 (window
->parent()->id() == kShellWindowId_DefaultContainer
||
118 window
->parent()->id() == kShellWindowId_LockScreenContainer
);
121 bool AshFocusRules::CanActivateWindow(aura::Window
* window
) const {
122 // Clearing activation is always permissible.
126 if (!BaseFocusRules::CanActivateWindow(window
))
129 if (Shell::GetInstance()->IsSystemModalWindowOpen()) {
130 return BelongsToContainerWithEqualOrGreaterId(
131 window
, kShellWindowId_SystemModalContainer
);
137 aura::Window
* AshFocusRules::GetNextActivatableWindow(
138 aura::Window
* ignore
) const {
139 if (is_shutting_down_
)
144 // Start from the container of the most-recently-used window. If the list of
145 // MRU windows is empty, then start from the container of the window that just
146 // lost focus |ignore|.
147 ash::MruWindowTracker
* mru
= ash::Shell::GetInstance()->mru_window_tracker();
148 std::vector
<aura::Window
*> windows
= mru
->BuildMruWindowList();
149 aura::Window
* starting_window
= windows
.empty() ? ignore
: windows
[0];
151 // Look for windows to focus in |starting_window|'s container. If none are
152 // found, we look in all the containers in front of |starting_window|'s
153 // container, then all behind.
154 int starting_container_index
= 0;
155 aura::Window
* root
= starting_window
->GetRootWindow();
157 root
= Shell::GetTargetRootWindow();
158 int container_count
= static_cast<int>(arraysize(kWindowContainerIds
));
159 for (int i
= 0; i
< container_count
; i
++) {
160 aura::Window
* container
= Shell::GetContainer(root
, kWindowContainerIds
[i
]);
161 if (container
&& container
->Contains(starting_window
)) {
162 starting_container_index
= i
;
167 aura::Window
* window
= nullptr;
168 for (int i
= starting_container_index
; !window
&& i
< container_count
; i
++)
169 window
= GetTopmostWindowToActivateForContainerIndex(i
, ignore
);
170 if (!window
&& starting_container_index
> 0) {
171 for (int i
= starting_container_index
- 1; !window
&& i
>= 0; i
--)
172 window
= GetTopmostWindowToActivateForContainerIndex(i
, ignore
);
177 ////////////////////////////////////////////////////////////////////////////////
178 // AshFocusRules, private:
180 aura::Window
* AshFocusRules::GetTopmostWindowToActivateForContainerIndex(
182 aura::Window
* ignore
) const {
183 aura::Window
* window
= NULL
;
184 aura::Window
* root
= ignore
? ignore
->GetRootWindow() : NULL
;
185 aura::Window::Windows containers
= Shell::GetContainersFromAllRootWindows(
186 kWindowContainerIds
[index
], root
);
187 for (aura::Window::Windows::const_iterator iter
= containers
.begin();
188 iter
!= containers
.end() && !window
; ++iter
) {
189 window
= GetTopmostWindowToActivateInContainer((*iter
), ignore
);
194 aura::Window
* AshFocusRules::GetTopmostWindowToActivateInContainer(
195 aura::Window
* container
,
196 aura::Window
* ignore
) const {
197 for (aura::Window::Windows::const_reverse_iterator i
=
198 container
->children().rbegin();
199 i
!= container
->children().rend();
201 WindowState
* window_state
= GetWindowState(*i
);
203 window_state
->CanActivate() &&
204 !window_state
->IsMinimized())
210 void AshFocusRules::OnAppTerminating() {
211 is_shutting_down_
= true;