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/base/ime/text_input_focus_manager.h"
14 #include "ui/events/event.h"
15 #include "ui/wm/core/focus_rules.h"
16 #include "ui/wm/core/window_util.h"
17 #include "ui/wm/public/activation_change_observer.h"
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
)
29 aura::Window
* transient_parent
= wm::GetTransientParent(window
);
30 while (transient_parent
) {
31 transient_parent
->parent()->StackChildAtTop(transient_parent
);
32 transient_parent
= wm::GetTransientParent(transient_parent
);
38 ////////////////////////////////////////////////////////////////////////////////
39 // FocusController, public:
41 FocusController::FocusController(FocusRules
* rules
)
42 : active_window_(NULL
),
43 focused_window_(NULL
),
44 updating_focus_(false),
45 updating_activation_(false),
47 observer_manager_(this) {
51 FocusController::~FocusController() {
54 ////////////////////////////////////////////////////////////////////////////////
55 // FocusController, aura::client::ActivationClient implementation:
57 void FocusController::AddObserver(
58 aura::client::ActivationChangeObserver
* observer
) {
59 activation_observers_
.AddObserver(observer
);
62 void FocusController::RemoveObserver(
63 aura::client::ActivationChangeObserver
* observer
) {
64 activation_observers_
.RemoveObserver(observer
);
67 void FocusController::ActivateWindow(aura::Window
* window
) {
71 void FocusController::DeactivateWindow(aura::Window
* window
) {
73 FocusWindow(rules_
->GetNextActivatableWindow(window
));
76 aura::Window
* FocusController::GetActiveWindow() {
77 return active_window_
;
80 aura::Window
* FocusController::GetActivatableWindow(aura::Window
* window
) {
81 return rules_
->GetActivatableWindow(window
);
84 aura::Window
* FocusController::GetToplevelWindow(aura::Window
* window
) {
85 return rules_
->GetToplevelWindow(window
);
88 bool FocusController::CanActivateWindow(aura::Window
* window
) const {
89 return rules_
->CanActivateWindow(window
);
92 ////////////////////////////////////////////////////////////////////////////////
93 // FocusController, aura::client::FocusClient implementation:
95 void FocusController::AddObserver(
96 aura::client::FocusChangeObserver
* observer
) {
97 focus_observers_
.AddObserver(observer
);
100 void FocusController::RemoveObserver(
101 aura::client::FocusChangeObserver
* observer
) {
102 focus_observers_
.RemoveObserver(observer
);
105 void FocusController::FocusWindow(aura::Window
* window
) {
107 (window
->Contains(focused_window_
) || window
->Contains(active_window_
))) {
111 // We should not be messing with the focus if the window has capture, unless
113 if (window
&& (aura::client::GetCaptureWindow(window
) == window
) &&
118 // Focusing a window also activates its containing activatable window. Note
119 // that the rules could redirect activation activation and/or focus.
120 aura::Window
* focusable
= rules_
->GetFocusableWindow(window
);
121 aura::Window
* activatable
=
122 focusable
? rules_
->GetActivatableWindow(focusable
) : NULL
;
124 // We need valid focusable/activatable windows in the event we're not clearing
125 // focus. "Clearing focus" is inferred by whether or not |window| passed to
126 // this function is non-NULL.
127 if (window
&& (!focusable
|| !activatable
))
129 DCHECK((focusable
&& activatable
) || !window
);
131 // Activation change observers may change the focused window. If this happens
132 // we must not adjust the focus below since this will clobber that change.
133 aura::Window
* last_focused_window
= focused_window_
;
134 if (!updating_activation_
)
135 SetActiveWindow(window
, activatable
);
137 // If the window's ActivationChangeObserver shifted focus to a valid window,
138 // we don't want to focus the window we thought would be focused by default.
139 bool activation_changed_focus
= last_focused_window
!= focused_window_
;
140 if (!updating_focus_
&& (!activation_changed_focus
|| !focused_window_
)) {
141 if (active_window_
&& focusable
)
142 DCHECK(active_window_
->Contains(focusable
));
143 SetFocusedWindow(focusable
);
147 void FocusController::ResetFocusWithinActiveWindow(aura::Window
* window
) {
151 if (!active_window_
->Contains(window
))
153 SetFocusedWindow(window
);
156 aura::Window
* FocusController::GetFocusedWindow() {
157 return focused_window_
;
160 ////////////////////////////////////////////////////////////////////////////////
161 // FocusController, ui::EventHandler implementation:
162 void FocusController::OnKeyEvent(ui::KeyEvent
* event
) {
165 void FocusController::OnMouseEvent(ui::MouseEvent
* event
) {
166 if (event
->type() == ui::ET_MOUSE_PRESSED
&& !event
->handled())
167 WindowFocusedFromInputEvent(static_cast<aura::Window
*>(event
->target()));
170 void FocusController::OnScrollEvent(ui::ScrollEvent
* event
) {
173 void FocusController::OnTouchEvent(ui::TouchEvent
* event
) {
176 void FocusController::OnGestureEvent(ui::GestureEvent
* event
) {
177 if (event
->type() == ui::ET_GESTURE_BEGIN
&&
178 event
->details().touch_points() == 1 &&
180 WindowFocusedFromInputEvent(static_cast<aura::Window
*>(event
->target()));
184 ////////////////////////////////////////////////////////////////////////////////
185 // FocusController, aura::WindowObserver implementation:
187 void FocusController::OnWindowVisibilityChanged(aura::Window
* window
,
190 WindowLostFocusFromDispositionChange(window
, window
->parent());
193 void FocusController::OnWindowDestroying(aura::Window
* window
) {
194 WindowLostFocusFromDispositionChange(window
, window
->parent());
197 void FocusController::OnWindowHierarchyChanging(
198 const HierarchyChangeParams
& params
) {
199 if (params
.receiver
== active_window_
&&
200 params
.target
->Contains(params
.receiver
) && (!params
.new_parent
||
201 aura::client::GetFocusClient(params
.new_parent
) !=
202 aura::client::GetFocusClient(params
.receiver
))) {
203 WindowLostFocusFromDispositionChange(params
.receiver
, params
.old_parent
);
207 void FocusController::OnWindowHierarchyChanged(
208 const HierarchyChangeParams
& params
) {
209 if (params
.receiver
== focused_window_
&&
210 params
.target
->Contains(params
.receiver
) && (!params
.new_parent
||
211 aura::client::GetFocusClient(params
.new_parent
) !=
212 aura::client::GetFocusClient(params
.receiver
))) {
213 WindowLostFocusFromDispositionChange(params
.receiver
, params
.old_parent
);
217 ////////////////////////////////////////////////////////////////////////////////
218 // FocusController, private:
220 void FocusController::SetFocusedWindow(aura::Window
* window
) {
221 if (updating_focus_
|| window
== focused_window_
)
223 DCHECK(rules_
->CanFocusWindow(window
));
225 DCHECK_EQ(window
, rules_
->GetFocusableWindow(window
));
227 base::AutoReset
<bool> updating_focus(&updating_focus_
, true);
228 aura::Window
* lost_focus
= focused_window_
;
230 // |window| is going to get the focus, so reset the text input client.
231 // OnWindowFocused() may set a proper text input client if the implementation
232 // supports text input.
233 ui::TextInputFocusManager
* text_input_focus_manager
=
234 ui::TextInputFocusManager::GetInstance();
236 text_input_focus_manager
->FocusTextInputClient(NULL
);
238 // Allow for the window losing focus to be deleted during dispatch. If it is
239 // deleted pass NULL to observers instead of a deleted window.
240 aura::WindowTracker window_tracker
;
242 window_tracker
.Add(lost_focus
);
243 if (focused_window_
&& observer_manager_
.IsObserving(focused_window_
) &&
244 focused_window_
!= active_window_
) {
245 observer_manager_
.Remove(focused_window_
);
247 focused_window_
= window
;
248 if (focused_window_
&& !observer_manager_
.IsObserving(focused_window_
))
249 observer_manager_
.Add(focused_window_
);
251 FOR_EACH_OBSERVER(aura::client::FocusChangeObserver
,
253 OnWindowFocused(focused_window_
,
254 window_tracker
.Contains(lost_focus
) ?
256 if (window_tracker
.Contains(lost_focus
)) {
257 aura::client::FocusChangeObserver
* observer
=
258 aura::client::GetFocusChangeObserver(lost_focus
);
260 observer
->OnWindowFocused(focused_window_
, lost_focus
);
262 aura::client::FocusChangeObserver
* observer
=
263 aura::client::GetFocusChangeObserver(focused_window_
);
265 observer
->OnWindowFocused(
267 window_tracker
.Contains(lost_focus
) ? lost_focus
: NULL
);
270 // Ensure that the text input client is reset when the window loses the focus.
272 text_input_focus_manager
->FocusTextInputClient(NULL
);
275 void FocusController::SetActiveWindow(aura::Window
* requested_window
,
276 aura::Window
* window
) {
277 if (updating_activation_
)
280 if (window
== active_window_
) {
281 if (requested_window
) {
282 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver
,
283 activation_observers_
,
284 OnAttemptToReactivateWindow(requested_window
,
290 DCHECK(rules_
->CanActivateWindow(window
));
292 DCHECK_EQ(window
, rules_
->GetActivatableWindow(window
));
294 base::AutoReset
<bool> updating_activation(&updating_activation_
, true);
295 aura::Window
* lost_activation
= active_window_
;
296 // Allow for the window losing activation to be deleted during dispatch. If
297 // it is deleted pass NULL to observers instead of a deleted window.
298 aura::WindowTracker window_tracker
;
300 window_tracker
.Add(lost_activation
);
301 if (active_window_
&& observer_manager_
.IsObserving(active_window_
) &&
302 focused_window_
!= active_window_
) {
303 observer_manager_
.Remove(active_window_
);
305 active_window_
= window
;
306 if (active_window_
&& !observer_manager_
.IsObserving(active_window_
))
307 observer_manager_
.Add(active_window_
);
308 if (active_window_
) {
309 StackTransientParentsBelowModalWindow(active_window_
);
310 active_window_
->parent()->StackChildAtTop(active_window_
);
313 aura::client::ActivationChangeObserver
* observer
= NULL
;
314 if (window_tracker
.Contains(lost_activation
)) {
315 observer
= aura::client::GetActivationChangeObserver(lost_activation
);
317 observer
->OnWindowActivated(active_window_
, lost_activation
);
319 observer
= aura::client::GetActivationChangeObserver(active_window_
);
321 observer
->OnWindowActivated(
323 window_tracker
.Contains(lost_activation
) ? lost_activation
: NULL
);
325 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver
,
326 activation_observers_
,
327 OnWindowActivated(active_window_
,
328 window_tracker
.Contains(lost_activation
) ?
329 lost_activation
: NULL
));
332 void FocusController::WindowLostFocusFromDispositionChange(
333 aura::Window
* window
,
334 aura::Window
* next
) {
335 // A window's modality state will interfere with focus restoration during its
337 window
->ClearProperty(aura::client::kModalKey
);
338 // TODO(beng): See if this function can be replaced by a call to
340 // Activation adjustments are handled first in the event of a disposition
341 // changed. If an activation change is necessary, focus is reset as part of
342 // that process so there's no point in updating focus independently.
343 if (window
== active_window_
) {
344 aura::Window
* next_activatable
= rules_
->GetNextActivatableWindow(window
);
345 SetActiveWindow(NULL
, next_activatable
);
346 if (!(active_window_
&& active_window_
->Contains(focused_window_
)))
347 SetFocusedWindow(next_activatable
);
348 } else if (window
->Contains(focused_window_
)) {
349 // Active window isn't changing, but focused window might be.
350 SetFocusedWindow(rules_
->GetFocusableWindow(next
));
354 void FocusController::WindowFocusedFromInputEvent(aura::Window
* window
) {
355 // Only focus |window| if it or any of its parents can be focused. Otherwise
356 // FocusWindow() will focus the topmost window, which may not be the
357 // currently focused one.
358 if (rules_
->CanFocusWindow(GetToplevelWindow(window
)))