• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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