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/wm/core/base_focus_rules.h"
7 #include "ui/aura/client/focus_client.h"
8 #include "ui/aura/window.h"
9 #include "ui/aura/window_event_dispatcher.h"
10 #include "ui/wm/core/window_modality_controller.h"
11 #include "ui/wm/core/window_util.h"
12 #include "ui/wm/public/activation_delegate.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 (wm::GetTransientParent(child
)) {
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(wm::GetTransientParent(child
));
128 if (parent_modal_transient
== child
)
131 return GetActivatableWindow(wm::GetTransientParent(child
));
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
))