Home | History | Annotate | Download | only in wm
      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