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/focus_controller.h"
7 #include "base/auto_reset.h"
8 #include "ui/aura/client/aura_constants.h"
9 #include "ui/aura/client/capture_client.h"
10 #include "ui/aura/client/focus_change_observer.h"
11 #include "ui/aura/env.h"
12 #include "ui/aura/window_tracker.h"
13 #include "ui/events/event.h"
14 #include "ui/wm/core/focus_rules.h"
15 #include "ui/wm/core/window_util.h"
16 #include "ui/wm/public/activation_change_observer.h"
21 // When a modal window is activated, we bring its entire transient parent chain
22 // to the front. This function must be called before the modal transient is
23 // stacked at the top to ensure correct stacking order.
24 void StackTransientParentsBelowModalWindow(aura::Window
* window
) {
25 if (window
->GetProperty(aura::client::kModalKey
) != ui::MODAL_TYPE_WINDOW
)
28 aura::Window
* transient_parent
= wm::GetTransientParent(window
);
29 while (transient_parent
) {
30 transient_parent
->parent()->StackChildAtTop(transient_parent
);
31 transient_parent
= wm::GetTransientParent(transient_parent
);
37 ////////////////////////////////////////////////////////////////////////////////
38 // FocusController, public:
40 FocusController::FocusController(FocusRules
* rules
)
41 : active_window_(NULL
),
42 focused_window_(NULL
),
43 updating_focus_(false),
44 updating_activation_(false),
46 observer_manager_(this) {
50 FocusController::~FocusController() {
53 ////////////////////////////////////////////////////////////////////////////////
54 // FocusController, aura::client::ActivationClient implementation:
56 void FocusController::AddObserver(
57 aura::client::ActivationChangeObserver
* observer
) {
58 activation_observers_
.AddObserver(observer
);
61 void FocusController::RemoveObserver(
62 aura::client::ActivationChangeObserver
* observer
) {
63 activation_observers_
.RemoveObserver(observer
);
66 void FocusController::ActivateWindow(aura::Window
* window
) {
70 void FocusController::DeactivateWindow(aura::Window
* window
) {
72 FocusWindow(rules_
->GetNextActivatableWindow(window
));
75 aura::Window
* FocusController::GetActiveWindow() {
76 return active_window_
;
79 aura::Window
* FocusController::GetActivatableWindow(aura::Window
* window
) {
80 return rules_
->GetActivatableWindow(window
);
83 aura::Window
* FocusController::GetToplevelWindow(aura::Window
* window
) {
84 return rules_
->GetToplevelWindow(window
);
87 bool FocusController::CanActivateWindow(aura::Window
* window
) const {
88 return rules_
->CanActivateWindow(window
);
91 ////////////////////////////////////////////////////////////////////////////////
92 // FocusController, aura::client::FocusClient implementation:
94 void FocusController::AddObserver(
95 aura::client::FocusChangeObserver
* observer
) {
96 focus_observers_
.AddObserver(observer
);
99 void FocusController::RemoveObserver(
100 aura::client::FocusChangeObserver
* observer
) {
101 focus_observers_
.RemoveObserver(observer
);
104 void FocusController::FocusWindow(aura::Window
* window
) {
105 FocusAndActivateWindow(aura::client::ActivationChangeObserver::
106 ActivationReason::ACTIVATION_CLIENT
,
110 void FocusController::ResetFocusWithinActiveWindow(aura::Window
* window
) {
114 if (!active_window_
->Contains(window
))
116 SetFocusedWindow(window
);
119 aura::Window
* FocusController::GetFocusedWindow() {
120 return focused_window_
;
123 ////////////////////////////////////////////////////////////////////////////////
124 // FocusController, ui::EventHandler implementation:
125 void FocusController::OnKeyEvent(ui::KeyEvent
* event
) {
128 void FocusController::OnMouseEvent(ui::MouseEvent
* event
) {
129 if (event
->type() == ui::ET_MOUSE_PRESSED
&& !event
->handled())
130 WindowFocusedFromInputEvent(static_cast<aura::Window
*>(event
->target()));
133 void FocusController::OnScrollEvent(ui::ScrollEvent
* event
) {
136 void FocusController::OnTouchEvent(ui::TouchEvent
* event
) {
139 void FocusController::OnGestureEvent(ui::GestureEvent
* event
) {
140 if (event
->type() == ui::ET_GESTURE_BEGIN
&&
141 event
->details().touch_points() == 1 &&
143 WindowFocusedFromInputEvent(static_cast<aura::Window
*>(event
->target()));
147 ////////////////////////////////////////////////////////////////////////////////
148 // FocusController, aura::WindowObserver implementation:
150 void FocusController::OnWindowVisibilityChanged(aura::Window
* window
,
153 WindowLostFocusFromDispositionChange(window
, window
->parent());
156 void FocusController::OnWindowDestroying(aura::Window
* window
) {
157 // A window's modality state will interfere with focus restoration during its
159 window
->ClearProperty(aura::client::kModalKey
);
160 WindowLostFocusFromDispositionChange(window
, window
->parent());
163 void FocusController::OnWindowHierarchyChanging(
164 const HierarchyChangeParams
& params
) {
165 if (params
.receiver
== active_window_
&&
166 params
.target
->Contains(params
.receiver
) && (!params
.new_parent
||
167 aura::client::GetFocusClient(params
.new_parent
) !=
168 aura::client::GetFocusClient(params
.receiver
))) {
169 WindowLostFocusFromDispositionChange(params
.receiver
, params
.old_parent
);
173 void FocusController::OnWindowHierarchyChanged(
174 const HierarchyChangeParams
& params
) {
175 if (params
.receiver
== focused_window_
&&
176 params
.target
->Contains(params
.receiver
) && (!params
.new_parent
||
177 aura::client::GetFocusClient(params
.new_parent
) !=
178 aura::client::GetFocusClient(params
.receiver
))) {
179 WindowLostFocusFromDispositionChange(params
.receiver
, params
.old_parent
);
183 ////////////////////////////////////////////////////////////////////////////////
184 // FocusController, private:
186 void FocusController::FocusAndActivateWindow(
187 aura::client::ActivationChangeObserver::ActivationReason reason
,
188 aura::Window
* window
) {
190 (window
->Contains(focused_window_
) || window
->Contains(active_window_
))) {
195 // Focusing a window also activates its containing activatable window. Note
196 // that the rules could redirect activation activation and/or focus.
197 aura::Window
* focusable
= rules_
->GetFocusableWindow(window
);
198 aura::Window
* activatable
=
199 focusable
? rules_
->GetActivatableWindow(focusable
) : NULL
;
201 // We need valid focusable/activatable windows in the event we're not clearing
202 // focus. "Clearing focus" is inferred by whether or not |window| passed to
203 // this function is non-NULL.
204 if (window
&& (!focusable
|| !activatable
))
206 DCHECK((focusable
&& activatable
) || !window
);
208 // Activation change observers may change the focused window. If this happens
209 // we must not adjust the focus below since this will clobber that change.
210 aura::Window
* last_focused_window
= focused_window_
;
211 if (!updating_activation_
)
212 SetActiveWindow(reason
, window
, activatable
);
214 // If the window's ActivationChangeObserver shifted focus to a valid window,
215 // we don't want to focus the window we thought would be focused by default.
216 bool activation_changed_focus
= last_focused_window
!= focused_window_
;
217 if (!updating_focus_
&& (!activation_changed_focus
|| !focused_window_
)) {
218 if (active_window_
&& focusable
)
219 DCHECK(active_window_
->Contains(focusable
));
220 SetFocusedWindow(focusable
);
224 void FocusController::SetFocusedWindow(aura::Window
* window
) {
225 if (updating_focus_
|| window
== focused_window_
)
227 DCHECK(rules_
->CanFocusWindow(window
));
229 DCHECK_EQ(window
, rules_
->GetFocusableWindow(window
));
231 base::AutoReset
<bool> updating_focus(&updating_focus_
, true);
232 aura::Window
* lost_focus
= focused_window_
;
234 // Allow for the window losing focus to be deleted during dispatch. If it is
235 // deleted pass NULL to observers instead of a deleted window.
236 aura::WindowTracker window_tracker
;
238 window_tracker
.Add(lost_focus
);
239 if (focused_window_
&& observer_manager_
.IsObserving(focused_window_
) &&
240 focused_window_
!= active_window_
) {
241 observer_manager_
.Remove(focused_window_
);
243 focused_window_
= window
;
244 if (focused_window_
&& !observer_manager_
.IsObserving(focused_window_
))
245 observer_manager_
.Add(focused_window_
);
247 FOR_EACH_OBSERVER(aura::client::FocusChangeObserver
,
249 OnWindowFocused(focused_window_
,
250 window_tracker
.Contains(lost_focus
) ?
252 if (window_tracker
.Contains(lost_focus
)) {
253 aura::client::FocusChangeObserver
* observer
=
254 aura::client::GetFocusChangeObserver(lost_focus
);
256 observer
->OnWindowFocused(focused_window_
, lost_focus
);
258 aura::client::FocusChangeObserver
* observer
=
259 aura::client::GetFocusChangeObserver(focused_window_
);
261 observer
->OnWindowFocused(
263 window_tracker
.Contains(lost_focus
) ? lost_focus
: NULL
);
267 void FocusController::SetActiveWindow(
268 aura::client::ActivationChangeObserver::ActivationReason reason
,
269 aura::Window
* requested_window
,
270 aura::Window
* window
) {
271 if (updating_activation_
)
274 if (window
== active_window_
) {
275 if (requested_window
) {
276 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver
,
277 activation_observers_
,
278 OnAttemptToReactivateWindow(requested_window
,
284 DCHECK(rules_
->CanActivateWindow(window
));
286 DCHECK_EQ(window
, rules_
->GetActivatableWindow(window
));
288 base::AutoReset
<bool> updating_activation(&updating_activation_
, true);
289 aura::Window
* lost_activation
= active_window_
;
290 // Allow for the window losing activation to be deleted during dispatch. If
291 // it is deleted pass NULL to observers instead of a deleted window.
292 aura::WindowTracker window_tracker
;
294 window_tracker
.Add(lost_activation
);
295 if (active_window_
&& observer_manager_
.IsObserving(active_window_
) &&
296 focused_window_
!= active_window_
) {
297 observer_manager_
.Remove(active_window_
);
299 active_window_
= window
;
300 if (active_window_
&& !observer_manager_
.IsObserving(active_window_
))
301 observer_manager_
.Add(active_window_
);
305 aura::client::ActivationChangeObserver
* observer
= NULL
;
306 if (window_tracker
.Contains(lost_activation
)) {
307 observer
= aura::client::GetActivationChangeObserver(lost_activation
);
309 observer
->OnWindowActivated(reason
, active_window_
, lost_activation
);
311 observer
= aura::client::GetActivationChangeObserver(active_window_
);
313 observer
->OnWindowActivated(
314 reason
, active_window_
,
315 window_tracker
.Contains(lost_activation
) ? lost_activation
: NULL
);
318 aura::client::ActivationChangeObserver
, activation_observers_
,
320 reason
, active_window_
,
321 window_tracker
.Contains(lost_activation
) ? lost_activation
: NULL
));
324 void FocusController::StackActiveWindow() {
325 if (active_window_
) {
326 StackTransientParentsBelowModalWindow(active_window_
);
327 active_window_
->parent()->StackChildAtTop(active_window_
);
331 void FocusController::WindowLostFocusFromDispositionChange(
332 aura::Window
* window
,
333 aura::Window
* next
) {
334 // TODO(beng): See if this function can be replaced by a call to
336 // Activation adjustments are handled first in the event of a disposition
337 // changed. If an activation change is necessary, focus is reset as part of
338 // that process so there's no point in updating focus independently.
339 if (window
== active_window_
) {
340 aura::Window
* next_activatable
= rules_
->GetNextActivatableWindow(window
);
341 SetActiveWindow(aura::client::ActivationChangeObserver::ActivationReason::
342 WINDOW_DISPOSITION_CHANGED
,
343 NULL
, next_activatable
);
344 if (!(active_window_
&& active_window_
->Contains(focused_window_
)))
345 SetFocusedWindow(next_activatable
);
346 } else if (window
->Contains(focused_window_
)) {
347 // Active window isn't changing, but focused window might be.
348 SetFocusedWindow(rules_
->GetFocusableWindow(next
));
352 void FocusController::WindowFocusedFromInputEvent(aura::Window
* window
) {
353 // Only focus |window| if it or any of its parents can be focused. Otherwise
354 // FocusWindow() will focus the topmost window, which may not be the
355 // currently focused one.
356 if (rules_
->CanFocusWindow(GetToplevelWindow(window
))) {
357 FocusAndActivateWindow(
358 aura::client::ActivationChangeObserver::ActivationReason::INPUT_EVENT
,