12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/wm/ash_focus_rules.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/shell.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/shell_window_ids.h"
968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ash/wm/window_state.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/aura/window.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace ash {
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace wm {
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// These are the list of container ids of containers which may contain windows
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// that need to be activated in the order that they should be activated.
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kWindowContainerIds[] = {
19c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    kShellWindowId_OverlayContainer,
20c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    kShellWindowId_LockSystemModalContainer,
21c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    kShellWindowId_SettingBubbleContainer,
22c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    kShellWindowId_LockScreenContainer,
23c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    kShellWindowId_SystemModalContainer,
24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    kShellWindowId_AlwaysOnTopContainer,
25c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    kShellWindowId_AppListContainer,
26c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    kShellWindowId_DefaultContainer,
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Docked, panel, launcher and status are intentionally checked after other
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // containers even though these layers are higher. The user expects their
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // windows to be focused before these elements.
31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    kShellWindowId_DockedContainer,
32c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    kShellWindowId_PanelContainer,
33c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    kShellWindowId_ShelfContainer,
34c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    kShellWindowId_StatusContainer, };
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BelongsToContainerWithEqualOrGreaterId(const aura::Window* window,
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            int container_id) {
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (; window; window = window->parent()) {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (window->id() >= container_id)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// AshFocusRules, public:
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AshFocusRules::AshFocusRules() {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AshFocusRules::~AshFocusRules() {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// AshFocusRules, ::wm::FocusRules:
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AshFocusRules::SupportsChildActivation(aura::Window* window) const {
60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (window->id() == kShellWindowId_DefaultContainer)
612385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    return true;
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < arraysize(kWindowContainerIds); i++) {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (window->id() == kWindowContainerIds[i])
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AshFocusRules::IsWindowConsideredVisibleForActivation(
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    aura::Window* window) const {
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (BaseFocusRules::IsWindowConsideredVisibleForActivation(window))
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Minimized windows are hidden in their minimized state, but they can always
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // be activated.
7768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (wm::GetWindowState(window)->IsMinimized())
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
80c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return window->TargetVisibility() &&
81c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch         (window->parent()->id() == kShellWindowId_DefaultContainer ||
82c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          window->parent()->id() == kShellWindowId_LockScreenContainer);
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AshFocusRules::CanActivateWindow(aura::Window* window) const {
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Clearing activation is always permissible.
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!window)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!BaseFocusRules::CanActivateWindow(window))
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (Shell::GetInstance()->IsSystemModalWindowOpen()) {
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return BelongsToContainerWithEqualOrGreaterId(
95c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        window, kShellWindowId_SystemModalContainer);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)aura::Window* AshFocusRules::GetNextActivatableWindow(
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    aura::Window* ignore) const {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ignore);
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int starting_container_index = 0;
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the container of the window losing focus is in the list, start from that
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // container.
1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  aura::Window* root = ignore->GetRootWindow();
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!root)
110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    root = Shell::GetTargetRootWindow();
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int container_count = static_cast<int>(arraysize(kWindowContainerIds));
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; ignore && i < container_count; i++) {
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    aura::Window* container = Shell::GetContainer(root, kWindowContainerIds[i]);
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (container && container->Contains(ignore)) {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      starting_container_index = i;
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Look for windows to focus in |ignore|'s container. If none are found, we
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // look in all the containers in front of |ignore|'s container, then all
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // behind.
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  aura::Window* window = NULL;
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = starting_container_index; !window && i < container_count; i++)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    window = GetTopmostWindowToActivateForContainerIndex(i, ignore);
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!window && starting_container_index > 0) {
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = starting_container_index - 1; !window && i >= 0; i--)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      window = GetTopmostWindowToActivateForContainerIndex(i, ignore);
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return window;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// AshFocusRules, private:
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)aura::Window* AshFocusRules::GetTopmostWindowToActivateForContainerIndex(
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int index,
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    aura::Window* ignore) const {
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  aura::Window* window = NULL;
1401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  aura::Window* root = ignore ? ignore->GetRootWindow() : NULL;
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  aura::Window::Windows containers = Shell::GetContainersFromAllRootWindows(
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kWindowContainerIds[index], root);
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (aura::Window::Windows::const_iterator iter = containers.begin();
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        iter != containers.end() && !window; ++iter) {
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    window = GetTopmostWindowToActivateInContainer((*iter), ignore);
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return window;
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)aura::Window* AshFocusRules::GetTopmostWindowToActivateInContainer(
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    aura::Window* container,
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    aura::Window* ignore) const {
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (aura::Window::Windows::const_reverse_iterator i =
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           container->children().rbegin();
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       i != container->children().rend();
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       ++i) {
15768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    WindowState* window_state = GetWindowState(*i);
15868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (*i != ignore &&
15968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        window_state->CanActivate() &&
16068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        !window_state->IsMinimized())
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return *i;
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NULL;
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace wm
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace ash
168