OLD | NEW |
| (Empty) |
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/views/corewm/base_focus_rules.h" | |
6 | |
7 #include "ui/aura/client/activation_delegate.h" | |
8 #include "ui/aura/client/focus_client.h" | |
9 #include "ui/aura/window.h" | |
10 #include "ui/aura/window_event_dispatcher.h" | |
11 #include "ui/views/corewm/window_modality_controller.h" | |
12 #include "ui/views/corewm/window_util.h" | |
13 | |
14 namespace views { | |
15 namespace corewm { | |
16 namespace { | |
17 | |
18 aura::Window* GetFocusedWindow(aura::Window* context) { | |
19 aura::client::FocusClient* focus_client = | |
20 aura::client::GetFocusClient(context); | |
21 return focus_client ? focus_client->GetFocusedWindow() : NULL; | |
22 } | |
23 | |
24 } // namespace | |
25 | |
26 //////////////////////////////////////////////////////////////////////////////// | |
27 // BaseFocusRules, protected: | |
28 | |
29 BaseFocusRules::BaseFocusRules() { | |
30 } | |
31 | |
32 BaseFocusRules::~BaseFocusRules() { | |
33 } | |
34 | |
35 bool BaseFocusRules::IsWindowConsideredVisibleForActivation( | |
36 aura::Window* window) const { | |
37 return window->IsVisible(); | |
38 } | |
39 | |
40 //////////////////////////////////////////////////////////////////////////////// | |
41 // BaseFocusRules, FocusRules implementation: | |
42 | |
43 bool BaseFocusRules::IsToplevelWindow(aura::Window* window) const { | |
44 // The window must in a valid hierarchy. | |
45 if (!window->GetRootWindow()) | |
46 return false; | |
47 | |
48 // The window must exist within a container that supports activation. | |
49 // The window cannot be blocked by a modal transient. | |
50 return SupportsChildActivation(window->parent()); | |
51 } | |
52 | |
53 bool BaseFocusRules::CanActivateWindow(aura::Window* window) const { | |
54 // It is possible to activate a NULL window, it is equivalent to clearing | |
55 // activation. | |
56 if (!window) | |
57 return true; | |
58 | |
59 // Only toplevel windows can be activated. | |
60 if (!IsToplevelWindow(window)) | |
61 return false; | |
62 | |
63 // The window must be visible. | |
64 if (!IsWindowConsideredVisibleForActivation(window)) | |
65 return false; | |
66 | |
67 // The window's activation delegate must allow this window to be activated. | |
68 if (aura::client::GetActivationDelegate(window) && | |
69 !aura::client::GetActivationDelegate(window)->ShouldActivate()) { | |
70 return false; | |
71 } | |
72 | |
73 // A window must be focusable to be activatable. We don't call | |
74 // CanFocusWindow() from here because it will call back to us via | |
75 // GetActivatableWindow(). | |
76 if (!window->CanFocus()) | |
77 return false; | |
78 | |
79 // The window cannot be blocked by a modal transient. | |
80 return !GetModalTransient(window); | |
81 } | |
82 | |
83 bool BaseFocusRules::CanFocusWindow(aura::Window* window) const { | |
84 // It is possible to focus a NULL window, it is equivalent to clearing focus. | |
85 if (!window) | |
86 return true; | |
87 | |
88 // The focused window is always inside the active window, so windows that | |
89 // aren't activatable can't contain the focused window. | |
90 aura::Window* activatable = GetActivatableWindow(window); | |
91 if (!activatable || !activatable->Contains(window)) | |
92 return false; | |
93 return window->CanFocus(); | |
94 } | |
95 | |
96 aura::Window* BaseFocusRules::GetToplevelWindow(aura::Window* window) const { | |
97 aura::Window* parent = window->parent(); | |
98 aura::Window* child = window; | |
99 while (parent) { | |
100 if (IsToplevelWindow(child)) | |
101 return child; | |
102 | |
103 parent = parent->parent(); | |
104 child = child->parent(); | |
105 } | |
106 return NULL; | |
107 } | |
108 | |
109 aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) const { | |
110 aura::Window* parent = window->parent(); | |
111 aura::Window* child = window; | |
112 while (parent) { | |
113 if (CanActivateWindow(child)) | |
114 return child; | |
115 | |
116 // CanActivateWindow() above will return false if |child| is blocked by a | |
117 // modal transient. In this case the modal is or contains the activatable | |
118 // window. We recurse because the modal may itself be blocked by a modal | |
119 // transient. | |
120 aura::Window* modal_transient = GetModalTransient(child); | |
121 if (modal_transient) | |
122 return GetActivatableWindow(modal_transient); | |
123 | |
124 if (views::corewm::GetTransientParent(child)) { | |
125 // To avoid infinite recursion, if |child| has a transient parent | |
126 // whose own modal transient is |child| itself, just return |child|. | |
127 aura::Window* parent_modal_transient = | |
128 GetModalTransient(views::corewm::GetTransientParent(child)); | |
129 if (parent_modal_transient == child) | |
130 return child; | |
131 | |
132 return GetActivatableWindow(views::corewm::GetTransientParent(child)); | |
133 } | |
134 | |
135 parent = parent->parent(); | |
136 child = child->parent(); | |
137 } | |
138 return NULL; | |
139 } | |
140 | |
141 aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) const { | |
142 if (CanFocusWindow(window)) | |
143 return window; | |
144 | |
145 // |window| may be in a hierarchy that is non-activatable, in which case we | |
146 // need to cut over to the activatable hierarchy. | |
147 aura::Window* activatable = GetActivatableWindow(window); | |
148 if (!activatable) { | |
149 // There may not be a related activatable hierarchy to cut over to, in which | |
150 // case we try an unrelated one. | |
151 aura::Window* toplevel = GetToplevelWindow(window); | |
152 if (toplevel) | |
153 activatable = GetNextActivatableWindow(toplevel); | |
154 if (!activatable) | |
155 return NULL; | |
156 } | |
157 | |
158 if (!activatable->Contains(window)) { | |
159 // If there's already a child window focused in the activatable hierarchy, | |
160 // just use that (i.e. don't shift focus), otherwise we need to at least cut | |
161 // over to the activatable hierarchy. | |
162 aura::Window* focused = GetFocusedWindow(activatable); | |
163 return activatable->Contains(focused) ? focused : activatable; | |
164 } | |
165 | |
166 while (window && !CanFocusWindow(window)) | |
167 window = window->parent(); | |
168 return window; | |
169 } | |
170 | |
171 aura::Window* BaseFocusRules::GetNextActivatableWindow( | |
172 aura::Window* ignore) const { | |
173 DCHECK(ignore); | |
174 | |
175 // Can be called from the RootWindow's destruction, which has a NULL parent. | |
176 if (!ignore->parent()) | |
177 return NULL; | |
178 | |
179 // In the basic scenarios handled by BasicFocusRules, the pool of activatable | |
180 // windows is limited to the |ignore|'s siblings. | |
181 const aura::Window::Windows& siblings = ignore->parent()->children(); | |
182 DCHECK(!siblings.empty()); | |
183 | |
184 for (aura::Window::Windows::const_reverse_iterator rit = siblings.rbegin(); | |
185 rit != siblings.rend(); | |
186 ++rit) { | |
187 aura::Window* cur = *rit; | |
188 if (cur == ignore) | |
189 continue; | |
190 if (CanActivateWindow(cur)) | |
191 return cur; | |
192 } | |
193 return NULL; | |
194 } | |
195 | |
196 } // namespace corewm | |
197 } // namespace views | |
OLD | NEW |