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/focus_controller.h" | |
6 | |
7 #include "base/auto_reset.h" | |
8 #include "ui/aura/client/activation_change_observer.h" | |
9 #include "ui/aura/client/aura_constants.h" | |
10 #include "ui/aura/client/capture_client.h" | |
11 #include "ui/aura/client/focus_change_observer.h" | |
12 #include "ui/aura/env.h" | |
13 #include "ui/aura/window_tracker.h" | |
14 #include "ui/events/event.h" | |
15 #include "ui/views/corewm/focus_rules.h" | |
16 #include "ui/views/corewm/window_util.h" | |
17 | |
18 namespace views { | |
19 namespace corewm { | |
20 namespace { | |
21 | |
22 // When a modal window is activated, we bring its entire transient parent chain | |
23 // to the front. This function must be called before the modal transient is | |
24 // stacked at the top to ensure correct stacking order. | |
25 void StackTransientParentsBelowModalWindow(aura::Window* window) { | |
26 if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_WINDOW) | |
27 return; | |
28 | |
29 aura::Window* transient_parent = views::corewm::GetTransientParent(window); | |
30 while (transient_parent) { | |
31 transient_parent->parent()->StackChildAtTop(transient_parent); | |
32 transient_parent = views::corewm::GetTransientParent(transient_parent); | |
33 } | |
34 } | |
35 | |
36 // Stack's |window|'s layer above |relative_to|'s layer. | |
37 void StackWindowLayerAbove(aura::Window* window, aura::Window* relative_to) { | |
38 // Stack |window| above the last transient child of |relative_to| that shares | |
39 // the same parent. | |
40 const aura::Window::Windows& window_transients( | |
41 GetTransientChildren(relative_to)); | |
42 for (aura::Window::Windows::const_iterator i = window_transients.begin(); | |
43 i != window_transients.end(); ++i) { | |
44 aura::Window* transient = *i; | |
45 if (transient->parent() == relative_to->parent()) | |
46 relative_to = transient; | |
47 } | |
48 if (window != relative_to) { | |
49 window->layer()->parent()->StackAbove(window->layer(), | |
50 relative_to->layer()); | |
51 } | |
52 } | |
53 | |
54 } // namespace | |
55 | |
56 //////////////////////////////////////////////////////////////////////////////// | |
57 // FocusController, public: | |
58 | |
59 FocusController::FocusController(FocusRules* rules) | |
60 : active_window_(NULL), | |
61 focused_window_(NULL), | |
62 updating_focus_(false), | |
63 updating_activation_(false), | |
64 rules_(rules), | |
65 observer_manager_(this) { | |
66 DCHECK(rules); | |
67 } | |
68 | |
69 FocusController::~FocusController() { | |
70 } | |
71 | |
72 //////////////////////////////////////////////////////////////////////////////// | |
73 // FocusController, aura::client::ActivationClient implementation: | |
74 | |
75 void FocusController::AddObserver( | |
76 aura::client::ActivationChangeObserver* observer) { | |
77 activation_observers_.AddObserver(observer); | |
78 } | |
79 | |
80 void FocusController::RemoveObserver( | |
81 aura::client::ActivationChangeObserver* observer) { | |
82 activation_observers_.RemoveObserver(observer); | |
83 } | |
84 | |
85 void FocusController::ActivateWindow(aura::Window* window) { | |
86 FocusWindow(window); | |
87 } | |
88 | |
89 void FocusController::DeactivateWindow(aura::Window* window) { | |
90 if (window) | |
91 FocusWindow(rules_->GetNextActivatableWindow(window)); | |
92 } | |
93 | |
94 aura::Window* FocusController::GetActiveWindow() { | |
95 return active_window_; | |
96 } | |
97 | |
98 aura::Window* FocusController::GetActivatableWindow(aura::Window* window) { | |
99 return rules_->GetActivatableWindow(window); | |
100 } | |
101 | |
102 aura::Window* FocusController::GetToplevelWindow(aura::Window* window) { | |
103 return rules_->GetToplevelWindow(window); | |
104 } | |
105 | |
106 bool FocusController::OnWillFocusWindow(aura::Window* window, | |
107 const ui::Event* event) { | |
108 NOTREACHED(); | |
109 return false; | |
110 } | |
111 | |
112 bool FocusController::CanActivateWindow(aura::Window* window) const { | |
113 return rules_->CanActivateWindow(window); | |
114 } | |
115 | |
116 //////////////////////////////////////////////////////////////////////////////// | |
117 // FocusController, aura::client::FocusClient implementation: | |
118 | |
119 void FocusController::AddObserver( | |
120 aura::client::FocusChangeObserver* observer) { | |
121 focus_observers_.AddObserver(observer); | |
122 } | |
123 | |
124 void FocusController::RemoveObserver( | |
125 aura::client::FocusChangeObserver* observer) { | |
126 focus_observers_.RemoveObserver(observer); | |
127 } | |
128 | |
129 void FocusController::FocusWindow(aura::Window* window) { | |
130 if (window && | |
131 (window->Contains(focused_window_) || window->Contains(active_window_))) { | |
132 return; | |
133 } | |
134 | |
135 // We should not be messing with the focus if the window has capture, unless | |
136 // no has focus. | |
137 if (window && (aura::client::GetCaptureWindow(window) == window) && | |
138 focused_window_) { | |
139 return; | |
140 } | |
141 | |
142 // Focusing a window also activates its containing activatable window. Note | |
143 // that the rules could redirect activation activation and/or focus. | |
144 aura::Window* focusable = rules_->GetFocusableWindow(window); | |
145 aura::Window* activatable = | |
146 focusable ? rules_->GetActivatableWindow(focusable) : NULL; | |
147 | |
148 // We need valid focusable/activatable windows in the event we're not clearing | |
149 // focus. "Clearing focus" is inferred by whether or not |window| passed to | |
150 // this function is non-NULL. | |
151 if (window && (!focusable || !activatable)) | |
152 return; | |
153 DCHECK((focusable && activatable) || !window); | |
154 | |
155 // Activation change observers may change the focused window. If this happens | |
156 // we must not adjust the focus below since this will clobber that change. | |
157 aura::Window* last_focused_window = focused_window_; | |
158 if (!updating_activation_) | |
159 SetActiveWindow(window, activatable); | |
160 | |
161 // If the window's ActivationChangeObserver shifted focus to a valid window, | |
162 // we don't want to focus the window we thought would be focused by default. | |
163 bool activation_changed_focus = last_focused_window != focused_window_; | |
164 if (!updating_focus_ && (!activation_changed_focus || !focused_window_)) { | |
165 if (active_window_ && focusable) | |
166 DCHECK(active_window_->Contains(focusable)); | |
167 SetFocusedWindow(focusable); | |
168 } | |
169 } | |
170 | |
171 void FocusController::ResetFocusWithinActiveWindow(aura::Window* window) { | |
172 DCHECK(window); | |
173 if (!active_window_) | |
174 return; | |
175 if (!active_window_->Contains(window)) | |
176 return; | |
177 SetFocusedWindow(window); | |
178 } | |
179 | |
180 aura::Window* FocusController::GetFocusedWindow() { | |
181 return focused_window_; | |
182 } | |
183 | |
184 //////////////////////////////////////////////////////////////////////////////// | |
185 // FocusController, ui::EventHandler implementation: | |
186 void FocusController::OnKeyEvent(ui::KeyEvent* event) { | |
187 } | |
188 | |
189 void FocusController::OnMouseEvent(ui::MouseEvent* event) { | |
190 if (event->type() == ui::ET_MOUSE_PRESSED) | |
191 WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target())); | |
192 } | |
193 | |
194 void FocusController::OnScrollEvent(ui::ScrollEvent* event) { | |
195 } | |
196 | |
197 void FocusController::OnTouchEvent(ui::TouchEvent* event) { | |
198 } | |
199 | |
200 void FocusController::OnGestureEvent(ui::GestureEvent* event) { | |
201 if (event->type() == ui::ET_GESTURE_BEGIN && | |
202 event->details().touch_points() == 1) { | |
203 WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target())); | |
204 } | |
205 } | |
206 | |
207 //////////////////////////////////////////////////////////////////////////////// | |
208 // FocusController, aura::WindowObserver implementation: | |
209 | |
210 void FocusController::OnWindowVisibilityChanged(aura::Window* window, | |
211 bool visible) { | |
212 if (!visible) { | |
213 WindowLostFocusFromDispositionChange(window, window->parent()); | |
214 // Despite the focus change, we need to keep the window being hidden | |
215 // stacked above the new window so it stays open on top as it animates away. | |
216 aura::Window* next_window = GetActiveWindow(); | |
217 if (next_window && next_window->parent() == window->parent()) | |
218 StackWindowLayerAbove(window, next_window); | |
219 } | |
220 } | |
221 | |
222 void FocusController::OnWindowDestroying(aura::Window* window) { | |
223 WindowLostFocusFromDispositionChange(window, window->parent()); | |
224 } | |
225 | |
226 void FocusController::OnWindowHierarchyChanging( | |
227 const HierarchyChangeParams& params) { | |
228 if (params.receiver == active_window_ && | |
229 params.target->Contains(params.receiver) && (!params.new_parent || | |
230 aura::client::GetFocusClient(params.new_parent) != | |
231 aura::client::GetFocusClient(params.receiver))) { | |
232 WindowLostFocusFromDispositionChange(params.receiver, params.old_parent); | |
233 } | |
234 } | |
235 | |
236 void FocusController::OnWindowHierarchyChanged( | |
237 const HierarchyChangeParams& params) { | |
238 if (params.receiver == focused_window_ && | |
239 params.target->Contains(params.receiver) && (!params.new_parent || | |
240 aura::client::GetFocusClient(params.new_parent) != | |
241 aura::client::GetFocusClient(params.receiver))) { | |
242 WindowLostFocusFromDispositionChange(params.receiver, params.old_parent); | |
243 } | |
244 } | |
245 | |
246 //////////////////////////////////////////////////////////////////////////////// | |
247 // FocusController, private: | |
248 | |
249 void FocusController::SetFocusedWindow(aura::Window* window) { | |
250 if (updating_focus_ || window == focused_window_) | |
251 return; | |
252 DCHECK(rules_->CanFocusWindow(window)); | |
253 if (window) | |
254 DCHECK_EQ(window, rules_->GetFocusableWindow(window)); | |
255 | |
256 base::AutoReset<bool> updating_focus(&updating_focus_, true); | |
257 aura::Window* lost_focus = focused_window_; | |
258 // Allow for the window losing focus to be deleted during dispatch. If it is | |
259 // deleted pass NULL to observers instead of a deleted window. | |
260 aura::WindowTracker window_tracker; | |
261 if (lost_focus) | |
262 window_tracker.Add(lost_focus); | |
263 if (focused_window_ && observer_manager_.IsObserving(focused_window_) && | |
264 focused_window_ != active_window_) { | |
265 observer_manager_.Remove(focused_window_); | |
266 } | |
267 focused_window_ = window; | |
268 if (focused_window_ && !observer_manager_.IsObserving(focused_window_)) | |
269 observer_manager_.Add(focused_window_); | |
270 | |
271 FOR_EACH_OBSERVER(aura::client::FocusChangeObserver, | |
272 focus_observers_, | |
273 OnWindowFocused(focused_window_, | |
274 window_tracker.Contains(lost_focus) ? | |
275 lost_focus : NULL)); | |
276 if (window_tracker.Contains(lost_focus)) { | |
277 aura::client::FocusChangeObserver* observer = | |
278 aura::client::GetFocusChangeObserver(lost_focus); | |
279 if (observer) | |
280 observer->OnWindowFocused(focused_window_, lost_focus); | |
281 } | |
282 aura::client::FocusChangeObserver* observer = | |
283 aura::client::GetFocusChangeObserver(focused_window_); | |
284 if (observer) { | |
285 observer->OnWindowFocused( | |
286 focused_window_, | |
287 window_tracker.Contains(lost_focus) ? lost_focus : NULL); | |
288 } | |
289 } | |
290 | |
291 void FocusController::SetActiveWindow(aura::Window* requested_window, | |
292 aura::Window* window) { | |
293 if (updating_activation_) | |
294 return; | |
295 | |
296 if (window == active_window_) { | |
297 if (requested_window) { | |
298 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver, | |
299 activation_observers_, | |
300 OnAttemptToReactivateWindow(requested_window, | |
301 active_window_)); | |
302 } | |
303 return; | |
304 } | |
305 | |
306 DCHECK(rules_->CanActivateWindow(window)); | |
307 if (window) | |
308 DCHECK_EQ(window, rules_->GetActivatableWindow(window)); | |
309 | |
310 base::AutoReset<bool> updating_activation(&updating_activation_, true); | |
311 aura::Window* lost_activation = active_window_; | |
312 // Allow for the window losing activation to be deleted during dispatch. If | |
313 // it is deleted pass NULL to observers instead of a deleted window. | |
314 aura::WindowTracker window_tracker; | |
315 if (lost_activation) | |
316 window_tracker.Add(lost_activation); | |
317 if (active_window_ && observer_manager_.IsObserving(active_window_) && | |
318 focused_window_ != active_window_) { | |
319 observer_manager_.Remove(active_window_); | |
320 } | |
321 active_window_ = window; | |
322 if (active_window_ && !observer_manager_.IsObserving(active_window_)) | |
323 observer_manager_.Add(active_window_); | |
324 if (active_window_) { | |
325 StackTransientParentsBelowModalWindow(active_window_); | |
326 active_window_->parent()->StackChildAtTop(active_window_); | |
327 } | |
328 | |
329 aura::client::ActivationChangeObserver* observer = NULL; | |
330 if (window_tracker.Contains(lost_activation)) { | |
331 observer = aura::client::GetActivationChangeObserver(lost_activation); | |
332 if (observer) | |
333 observer->OnWindowActivated(active_window_, lost_activation); | |
334 } | |
335 observer = aura::client::GetActivationChangeObserver(active_window_); | |
336 if (observer) { | |
337 observer->OnWindowActivated( | |
338 active_window_, | |
339 window_tracker.Contains(lost_activation) ? lost_activation : NULL); | |
340 } | |
341 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver, | |
342 activation_observers_, | |
343 OnWindowActivated(active_window_, | |
344 window_tracker.Contains(lost_activation) ? | |
345 lost_activation : NULL)); | |
346 } | |
347 | |
348 void FocusController::WindowLostFocusFromDispositionChange( | |
349 aura::Window* window, | |
350 aura::Window* next) { | |
351 // A window's modality state will interfere with focus restoration during its | |
352 // destruction. | |
353 window->ClearProperty(aura::client::kModalKey); | |
354 // TODO(beng): See if this function can be replaced by a call to | |
355 // FocusWindow(). | |
356 // Activation adjustments are handled first in the event of a disposition | |
357 // changed. If an activation change is necessary, focus is reset as part of | |
358 // that process so there's no point in updating focus independently. | |
359 if (window == active_window_) { | |
360 aura::Window* next_activatable = rules_->GetNextActivatableWindow(window); | |
361 SetActiveWindow(NULL, next_activatable); | |
362 if (!(active_window_ && active_window_->Contains(focused_window_))) | |
363 SetFocusedWindow(next_activatable); | |
364 } else if (window->Contains(focused_window_)) { | |
365 // Active window isn't changing, but focused window might be. | |
366 SetFocusedWindow(rules_->GetFocusableWindow(next)); | |
367 } | |
368 } | |
369 | |
370 void FocusController::WindowFocusedFromInputEvent(aura::Window* window) { | |
371 // Only focus |window| if it or any of its parents can be focused. Otherwise | |
372 // FocusWindow() will focus the topmost window, which may not be the | |
373 // currently focused one. | |
374 if (rules_->CanFocusWindow(GetToplevelWindow(window))) | |
375 FocusWindow(window); | |
376 } | |
377 | |
378 } // namespace corewm | |
379 } // namespace views | |
OLD | NEW |