• 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/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"
13 
14 namespace wm {
15 namespace {
16 
GetFocusedWindow(aura::Window * context)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;
21 }
22 
23 }  // namespace
24 
25 ////////////////////////////////////////////////////////////////////////////////
26 // BaseFocusRules, protected:
27 
BaseFocusRules()28 BaseFocusRules::BaseFocusRules() {
29 }
30 
~BaseFocusRules()31 BaseFocusRules::~BaseFocusRules() {
32 }
33 
IsWindowConsideredVisibleForActivation(aura::Window * window) const34 bool BaseFocusRules::IsWindowConsideredVisibleForActivation(
35     aura::Window* window) const {
36   return window->IsVisible();
37 }
38 
39 ////////////////////////////////////////////////////////////////////////////////
40 // BaseFocusRules, FocusRules implementation:
41 
IsToplevelWindow(aura::Window * window) const42 bool BaseFocusRules::IsToplevelWindow(aura::Window* window) const {
43   // The window must in a valid hierarchy.
44   if (!window->GetRootWindow())
45     return false;
46 
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());
50 }
51 
CanActivateWindow(aura::Window * window) const52 bool BaseFocusRules::CanActivateWindow(aura::Window* window) const {
53   // It is possible to activate a NULL window, it is equivalent to clearing
54   // activation.
55   if (!window)
56     return true;
57 
58   // Only toplevel windows can be activated.
59   if (!IsToplevelWindow(window))
60     return false;
61 
62   // The window must be visible.
63   if (!IsWindowConsideredVisibleForActivation(window))
64     return false;
65 
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()) {
69     return false;
70   }
71 
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())
76     return false;
77 
78   // The window cannot be blocked by a modal transient.
79   return !GetModalTransient(window);
80 }
81 
CanFocusWindow(aura::Window * window) const82 bool BaseFocusRules::CanFocusWindow(aura::Window* window) const {
83   // It is possible to focus a NULL window, it is equivalent to clearing focus.
84   if (!window)
85     return true;
86 
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))
91     return false;
92   return window->CanFocus();
93 }
94 
GetToplevelWindow(aura::Window * window) const95 aura::Window* BaseFocusRules::GetToplevelWindow(aura::Window* window) const {
96   aura::Window* parent = window->parent();
97   aura::Window* child = window;
98   while (parent) {
99     if (IsToplevelWindow(child))
100       return child;
101 
102     parent = parent->parent();
103     child = child->parent();
104   }
105   return NULL;
106 }
107 
GetActivatableWindow(aura::Window * window) const108 aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) const {
109   aura::Window* parent = window->parent();
110   aura::Window* child = window;
111   while (parent) {
112     if (CanActivateWindow(child))
113       return child;
114 
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
118     // transient.
119     aura::Window* modal_transient = GetModalTransient(child);
120     if (modal_transient)
121       return GetActivatableWindow(modal_transient);
122 
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)
129         return child;
130 
131       return GetActivatableWindow(wm::GetTransientParent(child));
132     }
133 
134     parent = parent->parent();
135     child = child->parent();
136   }
137   return NULL;
138 }
139 
GetFocusableWindow(aura::Window * window) const140 aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) const {
141   if (CanFocusWindow(window))
142     return window;
143 
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);
147   if (!activatable) {
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);
151     if (toplevel)
152       activatable = GetNextActivatableWindow(toplevel);
153     if (!activatable)
154       return NULL;
155   }
156 
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;
163   }
164 
165   while (window && !CanFocusWindow(window))
166     window = window->parent();
167   return window;
168 }
169 
GetNextActivatableWindow(aura::Window * ignore) const170 aura::Window* BaseFocusRules::GetNextActivatableWindow(
171     aura::Window* ignore) const {
172   DCHECK(ignore);
173 
174   // Can be called from the RootWindow's destruction, which has a NULL parent.
175   if (!ignore->parent())
176     return NULL;
177 
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());
182 
183   for (aura::Window::Windows::const_reverse_iterator rit = siblings.rbegin();
184        rit != siblings.rend();
185        ++rit) {
186     aura::Window* cur = *rit;
187     if (cur == ignore)
188       continue;
189     if (CanActivateWindow(cur))
190       return cur;
191   }
192   return NULL;
193 }
194 
195 }  // namespace wm
196