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 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 50 AshFocusRules::AshFocusRules() { 51 } 52 53 AshFocusRules::~AshFocusRules() { 54 } 55 56 //////////////////////////////////////////////////////////////////////////////// 57 // AshFocusRules, ::wm::FocusRules: 58 59 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 70 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 85 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 101 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 136 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 150 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