#include "ui/wm/core/base_focus_rules.h"
#include "base/containers/adapters.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/window.h"
#include "ui/wm/core/window_modality_controller.h"
#include "ui/wm/core/window_util.h"
#include "ui/wm/public/activation_delegate.h"
namespace wm {
namespace {
aura::Window* GetFocusedWindow(aura::Window* context) {
aura::client::FocusClient* focus_client =
aura::client::GetFocusClient(context);
return focus_client ? focus_client->GetFocusedWindow() : nullptr;
}
}
BaseFocusRules::BaseFocusRules() = default;
BaseFocusRules::~BaseFocusRules() = default;
bool BaseFocusRules::IsWindowConsideredVisibleForActivation(
const aura::Window* window) const {
return window->IsVisible();
}
bool BaseFocusRules::IsToplevelWindow(const aura::Window* window) const {
if (!window->GetRootWindow())
return false;
return SupportsChildActivation(window->parent());
}
bool BaseFocusRules::CanActivateWindow(const aura::Window* window) const {
if (!window)
return true;
if (window->is_destroying())
return false;
if (!IsToplevelWindow(window))
return false;
if (!IsWindowConsideredVisibleForActivation(window))
return false;
if (GetActivationDelegate(window) &&
!GetActivationDelegate(window)->ShouldActivate()) {
return false;
}
if (!window->CanFocus())
return false;
return !GetModalTransient(window);
}
bool BaseFocusRules::CanFocusWindow(const aura::Window* window,
const ui::Event* event) const {
if (!window)
return true;
const aura::Window* activatable = GetActivatableWindow(window);
if (!activatable || !activatable->Contains(window))
return false;
return window->CanFocus();
}
const aura::Window* BaseFocusRules::GetToplevelWindow(
const aura::Window* window) const {
const aura::Window* parent = window->parent();
const aura::Window* child = window;
while (parent) {
if (IsToplevelWindow(child))
return child;
parent = parent->parent();
child = child->parent();
}
return nullptr;
}
aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) const {
return const_cast<aura::Window*>(
GetActivatableWindow(const_cast<const aura::Window*>(window)));
}
aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) const {
if (CanFocusWindow(window, nullptr))
return window;
aura::Window* activatable = GetActivatableWindow(window);
if (!activatable) {
aura::Window* toplevel = GetToplevelWindow(window);
if (toplevel)
activatable = GetNextActivatableWindow(toplevel);
if (!activatable)
return nullptr;
}
if (!activatable->Contains(window)) {
aura::Window* focused = GetFocusedWindow(activatable);
return activatable->Contains(focused) ? focused : activatable;
}
while (window && !CanFocusWindow(window, nullptr))
window = window->parent();
return window;
}
aura::Window* BaseFocusRules::GetNextActivatableWindow(
aura::Window* ignore) const {
DCHECK(ignore);
if (!ignore->parent())
return nullptr;
const aura::Window::Windows& siblings = ignore->parent()->children();
DCHECK(!siblings.empty());
for (aura::Window* cur : base::Reversed(siblings)) {
if (cur == ignore)
continue;
if (CanActivateWindow(cur))
return cur;
}
return nullptr;
}
const aura::Window* BaseFocusRules::GetActivatableWindow(
const aura::Window* window) const {
const aura::Window* parent = window->parent();
const aura::Window* child = window;
while (parent) {
if (CanActivateWindow(child))
return child;
const aura::Window* modal_transient = GetModalTransient(child);
if (modal_transient)
return GetActivatableWindow(modal_transient);
if (wm::GetTransientParent(child)) {
const aura::Window* parent_modal_transient =
GetModalTransient(wm::GetTransientParent(child));
if (parent_modal_transient == child)
return child;
return GetActivatableWindow(wm::GetTransientParent(child));
}
parent = parent->parent();
child = child->parent();
}
return nullptr;
}
}