• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "ui/wm/core/base_focus_rules.h"
6 
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"
12 
13 namespace wm {
14 namespace {
15 
GetFocusedWindow(aura::Window * context)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;
20 }
21 
22 }  // namespace
23 
24 ////////////////////////////////////////////////////////////////////////////////
25 // BaseFocusRules, protected:
26 
BaseFocusRules()27 BaseFocusRules::BaseFocusRules() {
28 }
29 
~BaseFocusRules()30 BaseFocusRules::~BaseFocusRules() {
31 }
32 
IsWindowConsideredVisibleForActivation(aura::Window * window) const33 bool BaseFocusRules::IsWindowConsideredVisibleForActivation(
34     aura::Window* window) const {
35   return window->IsVisible();
36 }
37 
38 ////////////////////////////////////////////////////////////////////////////////
39 // BaseFocusRules, FocusRules implementation:
40 
IsToplevelWindow(aura::Window * window) const41 bool BaseFocusRules::IsToplevelWindow(aura::Window* window) const {
42   // The window must in a valid hierarchy.
43   if (!window->GetRootWindow())
44     return false;
45 
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());
49 }
50 
CanActivateWindow(aura::Window * window) const51 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;
56 
57   // Only toplevel windows can be activated.
58   if (!IsToplevelWindow(window))
59     return false;
60 
61   // The window must be visible.
62   if (!IsWindowConsideredVisibleForActivation(window))
63     return false;
64 
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;
69   }
70 
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;
76 
77   // The window cannot be blocked by a modal transient.
78   return !GetModalTransient(window);
79 }
80 
CanFocusWindow(aura::Window * window) const81 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;
85 
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();
92 }
93 
GetToplevelWindow(aura::Window * window) const94 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;
100 
101     parent = parent->parent();
102     child = child->parent();
103   }
104   return NULL;
105 }
106 
GetActivatableWindow(aura::Window * window) const107 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;
113 
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);
121 
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;
129 
130       return GetActivatableWindow(wm::GetTransientParent(child));
131     }
132 
133     parent = parent->parent();
134     child = child->parent();
135   }
136   return NULL;
137 }
138 
GetFocusableWindow(aura::Window * window) const139 aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) const {
140   if (CanFocusWindow(window))
141     return window;
142 
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;
154   }
155 
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;
162   }
163 
164   while (window && !CanFocusWindow(window))
165     window = window->parent();
166   return window;
167 }
168 
GetNextActivatableWindow(aura::Window * ignore) const169 aura::Window* BaseFocusRules::GetNextActivatableWindow(
170     aura::Window* ignore) const {
171   DCHECK(ignore);
172 
173   // Can be called from the RootWindow's destruction, which has a NULL parent.
174   if (!ignore->parent())
175     return NULL;
176 
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());
181 
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;
190   }
191   return NULL;
192 }
193 
194 }  // namespace wm
195