Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / wm / core / base_focus_rules.cc
blobe38aa2e5508dcc9779ea303e54d2d5352e851713
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/wm/core/window_modality_controller.h"
10 #include "ui/wm/core/window_util.h"
11 #include "ui/wm/public/activation_delegate.h"
13 namespace wm {
14 namespace {
16 aura::Window* GetFocusedWindow(aura::Window* context) {
17 aura::client::FocusClient* focus_client =
18 aura::client::GetFocusClient(context);
19 return focus_client ? focus_client->GetFocusedWindow() : NULL;
22 } // namespace
24 ////////////////////////////////////////////////////////////////////////////////
25 // BaseFocusRules, protected:
27 BaseFocusRules::BaseFocusRules() {
30 BaseFocusRules::~BaseFocusRules() {
33 bool BaseFocusRules::IsWindowConsideredVisibleForActivation(
34 aura::Window* window) const {
35 return window->IsVisible();
38 ////////////////////////////////////////////////////////////////////////////////
39 // BaseFocusRules, FocusRules implementation:
41 bool BaseFocusRules::IsToplevelWindow(aura::Window* window) const {
42 // The window must in a valid hierarchy.
43 if (!window->GetRootWindow())
44 return false;
46 // The window must exist within a container that supports activation.
47 // The window cannot be blocked by a modal transient.
48 return SupportsChildActivation(window->parent());
51 bool BaseFocusRules::CanActivateWindow(aura::Window* window) const {
52 // It is possible to activate a NULL window, it is equivalent to clearing
53 // activation.
54 if (!window)
55 return true;
57 // Only toplevel windows can be activated.
58 if (!IsToplevelWindow(window))
59 return false;
61 // The window must be visible.
62 if (!IsWindowConsideredVisibleForActivation(window))
63 return false;
65 // The window's activation delegate must allow this window to be activated.
66 if (aura::client::GetActivationDelegate(window) &&
67 !aura::client::GetActivationDelegate(window)->ShouldActivate()) {
68 return false;
71 // A window must be focusable to be activatable. We don't call
72 // CanFocusWindow() from here because it will call back to us via
73 // GetActivatableWindow().
74 if (!window->CanFocus())
75 return false;
77 // The window cannot be blocked by a modal transient.
78 return !GetModalTransient(window);
81 bool BaseFocusRules::CanFocusWindow(aura::Window* window) const {
82 // It is possible to focus a NULL window, it is equivalent to clearing focus.
83 if (!window)
84 return true;
86 // The focused window is always inside the active window, so windows that
87 // aren't activatable can't contain the focused window.
88 aura::Window* activatable = GetActivatableWindow(window);
89 if (!activatable || !activatable->Contains(window))
90 return false;
91 return window->CanFocus();
94 aura::Window* BaseFocusRules::GetToplevelWindow(aura::Window* window) const {
95 aura::Window* parent = window->parent();
96 aura::Window* child = window;
97 while (parent) {
98 if (IsToplevelWindow(child))
99 return child;
101 parent = parent->parent();
102 child = child->parent();
104 return NULL;
107 aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) const {
108 aura::Window* parent = window->parent();
109 aura::Window* child = window;
110 while (parent) {
111 if (CanActivateWindow(child))
112 return child;
114 // CanActivateWindow() above will return false if |child| is blocked by a
115 // modal transient. In this case the modal is or contains the activatable
116 // window. We recurse because the modal may itself be blocked by a modal
117 // transient.
118 aura::Window* modal_transient = GetModalTransient(child);
119 if (modal_transient)
120 return GetActivatableWindow(modal_transient);
122 if (wm::GetTransientParent(child)) {
123 // To avoid infinite recursion, if |child| has a transient parent
124 // whose own modal transient is |child| itself, just return |child|.
125 aura::Window* parent_modal_transient =
126 GetModalTransient(wm::GetTransientParent(child));
127 if (parent_modal_transient == child)
128 return child;
130 return GetActivatableWindow(wm::GetTransientParent(child));
133 parent = parent->parent();
134 child = child->parent();
136 return NULL;
139 aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) const {
140 if (CanFocusWindow(window))
141 return window;
143 // |window| may be in a hierarchy that is non-activatable, in which case we
144 // need to cut over to the activatable hierarchy.
145 aura::Window* activatable = GetActivatableWindow(window);
146 if (!activatable) {
147 // There may not be a related activatable hierarchy to cut over to, in which
148 // case we try an unrelated one.
149 aura::Window* toplevel = GetToplevelWindow(window);
150 if (toplevel)
151 activatable = GetNextActivatableWindow(toplevel);
152 if (!activatable)
153 return NULL;
156 if (!activatable->Contains(window)) {
157 // If there's already a child window focused in the activatable hierarchy,
158 // just use that (i.e. don't shift focus), otherwise we need to at least cut
159 // over to the activatable hierarchy.
160 aura::Window* focused = GetFocusedWindow(activatable);
161 return activatable->Contains(focused) ? focused : activatable;
164 while (window && !CanFocusWindow(window))
165 window = window->parent();
166 return window;
169 aura::Window* BaseFocusRules::GetNextActivatableWindow(
170 aura::Window* ignore) const {
171 DCHECK(ignore);
173 // Can be called from the RootWindow's destruction, which has a NULL parent.
174 if (!ignore->parent())
175 return NULL;
177 // In the basic scenarios handled by BasicFocusRules, the pool of activatable
178 // windows is limited to the |ignore|'s siblings.
179 const aura::Window::Windows& siblings = ignore->parent()->children();
180 DCHECK(!siblings.empty());
182 for (aura::Window::Windows::const_reverse_iterator rit = siblings.rbegin();
183 rit != siblings.rend();
184 ++rit) {
185 aura::Window* cur = *rit;
186 if (cur == ignore)
187 continue;
188 if (CanActivateWindow(cur))
189 return cur;
191 return NULL;
194 } // namespace wm