blob: c83f06df0757faaeec3f5057a3d5032a38db7c0d [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/wm/ash_focus_rules.h"
#include "ash/aura/wm_window_aura.h"
#include "ash/common/wm/container_finder.h"
#include "ash/common/wm/focus_rules.h"
#include "ash/common/wm/mru_window_tracker.h"
#include "ash/common/wm/window_state.h"
#include "ash/common/wm_shell.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "ash/wm/window_state_aura.h"
#include "ui/aura/window.h"
namespace ash {
namespace wm {
namespace {
bool BelongsToContainerWithEqualOrGreaterId(const aura::Window* window,
int container_id) {
for (; window; window = window->parent()) {
if (window->id() >= container_id)
return true;
}
return false;
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// AshFocusRules, public:
AshFocusRules::AshFocusRules() {}
AshFocusRules::~AshFocusRules() {}
bool AshFocusRules::IsWindowConsideredActivatable(aura::Window* window) const {
return ash::IsWindowConsideredActivatable(WmWindowAura::Get(window));
}
////////////////////////////////////////////////////////////////////////////////
// AshFocusRules, ::wm::FocusRules:
bool AshFocusRules::IsToplevelWindow(aura::Window* window) const {
return ash::IsToplevelWindow(WmWindowAura::Get(window));
}
bool AshFocusRules::SupportsChildActivation(aura::Window* window) const {
return ash::IsActivatableShellWindowId(window->id());
}
bool AshFocusRules::IsWindowConsideredVisibleForActivation(
aura::Window* window) const {
return ash::IsWindowConsideredVisibleForActivation(WmWindowAura::Get(window));
}
bool AshFocusRules::CanActivateWindow(aura::Window* window) const {
// Clearing activation is always permissible.
if (!window)
return true;
if (!BaseFocusRules::CanActivateWindow(window))
return false;
if (WmShell::Get()->IsSystemModalWindowOpen()) {
return BelongsToContainerWithEqualOrGreaterId(
window, kShellWindowId_SystemModalContainer);
}
return true;
}
aura::Window* AshFocusRules::GetNextActivatableWindow(
aura::Window* ignore) const {
DCHECK(ignore);
// Start from the container of the most-recently-used window. If the list of
// MRU windows is empty, then start from the container of the window that just
// lost focus |ignore|.
MruWindowTracker* mru = WmShell::Get()->mru_window_tracker();
std::vector<WmWindow*> windows = mru->BuildMruWindowList();
aura::Window* starting_window =
windows.empty() ? ignore : WmWindowAura::GetAuraWindow(windows[0]);
// Look for windows to focus in |starting_window|'s container. If none are
// found, we look in all the containers in front of |starting_window|'s
// container, then all behind.
int starting_container_index = 0;
aura::Window* root = starting_window->GetRootWindow();
if (!root)
root = Shell::GetTargetRootWindow();
int container_count = static_cast<int>(kNumActivatableShellWindowIds);
for (int i = 0; i < container_count; i++) {
aura::Window* container =
Shell::GetContainer(root, kActivatableShellWindowIds[i]);
if (container && container->Contains(starting_window)) {
starting_container_index = i;
break;
}
}
aura::Window* window = nullptr;
for (int i = starting_container_index; !window && i < container_count; i++)
window = GetTopmostWindowToActivateForContainerIndex(i, ignore);
if (!window && starting_container_index > 0) {
for (int i = starting_container_index - 1; !window && i >= 0; i--)
window = GetTopmostWindowToActivateForContainerIndex(i, ignore);
}
return window;
}
////////////////////////////////////////////////////////////////////////////////
// AshFocusRules, private:
aura::Window* AshFocusRules::GetTopmostWindowToActivateForContainerIndex(
int index,
aura::Window* ignore) const {
aura::Window* window = nullptr;
aura::Window* root = ignore ? ignore->GetRootWindow() : nullptr;
WmWindow::Windows containers = GetContainersFromAllRootWindows(
kActivatableShellWindowIds[index], WmWindowAura::Get(root));
for (WmWindow* container : containers) {
window = GetTopmostWindowToActivateInContainer(
WmWindowAura::GetAuraWindow(container), ignore);
if (window)
return window;
}
return window;
}
aura::Window* AshFocusRules::GetTopmostWindowToActivateInContainer(
aura::Window* container,
aura::Window* ignore) const {
for (aura::Window::Windows::const_reverse_iterator i =
container->children().rbegin();
i != container->children().rend(); ++i) {
WindowState* window_state = GetWindowState(*i);
if (*i != ignore && window_state->CanActivate() &&
!window_state->IsMinimized())
return *i;
}
return NULL;
}
} // namespace wm
} // namespace ash