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.
5 #include "ui/views/corewm/base_focus_rules.h"
7 #include "ui/aura/client/activation_delegate.h"
8 #include "ui/aura/client/focus_client.h"
9 #include "ui/aura/root_window.h"
10 #include "ui/aura/window.h"
11 #include "ui/views/corewm/window_modality_controller.h"
17 aura::Window* GetFocusedWindow(aura::Window* context) {
18 aura::client::FocusClient* focus_client =
19 aura::client::GetFocusClient(context);
20 return focus_client ? focus_client->GetFocusedWindow() : NULL;
25 ////////////////////////////////////////////////////////////////////////////////
26 // BaseFocusRules, protected:
28 BaseFocusRules::BaseFocusRules() {
31 BaseFocusRules::~BaseFocusRules() {
34 bool BaseFocusRules::IsWindowConsideredVisibleForActivation(
35 aura::Window* window) const {
36 return window->IsVisible();
39 ////////////////////////////////////////////////////////////////////////////////
40 // BaseFocusRules, FocusRules implementation:
42 bool BaseFocusRules::IsToplevelWindow(aura::Window* window) const {
43 // The window must in a valid hierarchy.
44 if (!window->GetRootWindow())
47 // The window must exist within a container that supports activation.
48 // The window cannot be blocked by a modal transient.
49 return SupportsChildActivation(window->parent());
52 bool BaseFocusRules::CanActivateWindow(aura::Window* window) const {
53 // It is possible to activate a NULL window, it is equivalent to clearing
58 // Only toplevel windows can be activated.
59 if (!IsToplevelWindow(window))
62 // The window must be visible.
63 if (!IsWindowConsideredVisibleForActivation(window))
66 // The window's activation delegate must allow this window to be activated.
67 if (aura::client::GetActivationDelegate(window) &&
68 !aura::client::GetActivationDelegate(window)->ShouldActivate()) {
72 // A window must be focusable to be activatable. We don't call
73 // CanFocusWindow() from here because it will call back to us via
74 // GetActivatableWindow().
75 if (!window->CanFocus())
78 // The window cannot be blocked by a modal transient.
79 return !GetModalTransient(window);
82 bool BaseFocusRules::CanFocusWindow(aura::Window* window) const {
83 // It is possible to focus a NULL window, it is equivalent to clearing focus.
87 // The focused window is always inside the active window, so windows that
88 // aren't activatable can't contain the focused window.
89 aura::Window* activatable = GetActivatableWindow(window);
90 if (!activatable || !activatable->Contains(window))
92 return window->CanFocus();
95 aura::Window* BaseFocusRules::GetToplevelWindow(aura::Window* window) const {
96 aura::Window* parent = window->parent();
97 aura::Window* child = window;
99 if (IsToplevelWindow(child))
102 parent = parent->parent();
103 child = child->parent();
108 aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) const {
109 aura::Window* parent = window->parent();
110 aura::Window* child = window;
112 if (CanActivateWindow(child))
115 // CanActivateWindow() above will return false if |child| is blocked by a
116 // modal transient. In this case the modal is or contains the activatable
117 // window. We recurse because the modal may itself be blocked by a modal
119 aura::Window* modal_transient = GetModalTransient(child);
121 return GetActivatableWindow(modal_transient);
123 if (child->transient_parent()) {
124 // To avoid infinite recursion, if |child| has a transient parent
125 // whose own modal transient is |child| itself, just return |child|.
126 aura::Window* parent_modal_transient =
127 GetModalTransient(child->transient_parent());
128 if (parent_modal_transient == child)
131 return GetActivatableWindow(child->transient_parent());
134 parent = parent->parent();
135 child = child->parent();
140 aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) const {
141 if (CanFocusWindow(window))
144 // |window| may be in a hierarchy that is non-activatable, in which case we
145 // need to cut over to the activatable hierarchy.
146 aura::Window* activatable = GetActivatableWindow(window);
148 // There may not be a related activatable hierarchy to cut over to, in which
149 // case we try an unrelated one.
150 aura::Window* toplevel = GetToplevelWindow(window);
152 activatable = GetNextActivatableWindow(toplevel);
157 if (!activatable->Contains(window)) {
158 // If there's already a child window focused in the activatable hierarchy,
159 // just use that (i.e. don't shift focus), otherwise we need to at least cut
160 // over to the activatable hierarchy.
161 aura::Window* focused = GetFocusedWindow(activatable);
162 return activatable->Contains(focused) ? focused : activatable;
165 while (window && !CanFocusWindow(window))
166 window = window->parent();
170 aura::Window* BaseFocusRules::GetNextActivatableWindow(
171 aura::Window* ignore) const {
174 // Can be called from the RootWindow's destruction, which has a NULL parent.
175 if (!ignore->parent())
178 // In the basic scenarios handled by BasicFocusRules, the pool of activatable
179 // windows is limited to the |ignore|'s siblings.
180 const aura::Window::Windows& siblings = ignore->parent()->children();
181 DCHECK(!siblings.empty());
183 for (aura::Window::Windows::const_reverse_iterator rit = siblings.rbegin();
184 rit != siblings.rend();
186 aura::Window* cur = *rit;
189 if (CanActivateWindow(cur))
195 } // namespace corewm