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_
))) {
194 // Focusing a window also activates its containing activatable window. Note
195 // that the rules could redirect activation activation and/or focus.
196 aura::Window
* focusable
= rules_
->GetFocusableWindow(window
);
197 aura::Window
* activatable
=
198 focusable
? rules_
->GetActivatableWindow(focusable
) : NULL
;
200 // We need valid focusable/activatable windows in the event we're not clearing
201 // focus. "Clearing focus" is inferred by whether or not |window| passed to
202 // this function is non-NULL.
203 if (window
&& (!focusable
|| !activatable
))
205 DCHECK((focusable
&& activatable
) || !window
);
207 // Activation change observers may change the focused window. If this happens
208 // we must not adjust the focus below since this will clobber that change.
209 aura::Window
* last_focused_window
= focused_window_
;
210 if (!updating_activation_
)
211 SetActiveWindow(reason
, window
, activatable
);
213 // If the window's ActivationChangeObserver shifted focus to a valid window,
214 // we don't want to focus the window we thought would be focused by default.
215 bool activation_changed_focus
= last_focused_window
!= focused_window_
;
216 if (!updating_focus_
&& (!activation_changed_focus
|| !focused_window_
)) {
217 if (active_window_
&& focusable
)
218 DCHECK(active_window_
->Contains(focusable
));
219 SetFocusedWindow(focusable
);
223 void FocusController::SetFocusedWindow(aura::Window
* window
) {
224 if (updating_focus_
|| window
== focused_window_
)
226 DCHECK(rules_
->CanFocusWindow(window
));
228 DCHECK_EQ(window
, rules_
->GetFocusableWindow(window
));
230 base::AutoReset
<bool> updating_focus(&updating_focus_
, true);
231 aura::Window
* lost_focus
= focused_window_
;
233 // Allow for the window losing focus to be deleted during dispatch. If it is
234 // deleted pass NULL to observers instead of a deleted window.
235 aura::WindowTracker window_tracker
;
237 window_tracker
.Add(lost_focus
);
238 if (focused_window_
&& observer_manager_
.IsObserving(focused_window_
) &&
239 focused_window_
!= active_window_
) {
240 observer_manager_
.Remove(focused_window_
);
242 focused_window_
= window
;
243 if (focused_window_
&& !observer_manager_
.IsObserving(focused_window_
))
244 observer_manager_
.Add(focused_window_
);
246 FOR_EACH_OBSERVER(aura::client::FocusChangeObserver
,
248 OnWindowFocused(focused_window_
,
249 window_tracker
.Contains(lost_focus
) ?
251 if (window_tracker
.Contains(lost_focus
)) {
252 aura::client::FocusChangeObserver
* observer
=
253 aura::client::GetFocusChangeObserver(lost_focus
);
255 observer
->OnWindowFocused(focused_window_
, lost_focus
);
257 aura::client::FocusChangeObserver
* observer
=
258 aura::client::GetFocusChangeObserver(focused_window_
);
260 observer
->OnWindowFocused(
262 window_tracker
.Contains(lost_focus
) ? lost_focus
: NULL
);
266 void FocusController::SetActiveWindow(
267 aura::client::ActivationChangeObserver::ActivationReason reason
,
268 aura::Window
* requested_window
,
269 aura::Window
* window
) {
270 if (updating_activation_
)
273 if (window
== active_window_
) {
274 if (requested_window
) {
275 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver
,
276 activation_observers_
,
277 OnAttemptToReactivateWindow(requested_window
,
283 DCHECK(rules_
->CanActivateWindow(window
));
285 DCHECK_EQ(window
, rules_
->GetActivatableWindow(window
));
287 base::AutoReset
<bool> updating_activation(&updating_activation_
, true);
288 aura::Window
* lost_activation
= active_window_
;
289 // Allow for the window losing activation to be deleted during dispatch. If
290 // it is deleted pass NULL to observers instead of a deleted window.
291 aura::WindowTracker window_tracker
;
293 window_tracker
.Add(lost_activation
);
294 if (active_window_
&& observer_manager_
.IsObserving(active_window_
) &&
295 focused_window_
!= active_window_
) {
296 observer_manager_
.Remove(active_window_
);
298 active_window_
= window
;
299 if (active_window_
&& !observer_manager_
.IsObserving(active_window_
))
300 observer_manager_
.Add(active_window_
);
301 if (active_window_
) {
302 StackTransientParentsBelowModalWindow(active_window_
);
303 active_window_
->parent()->StackChildAtTop(active_window_
);
306 aura::client::ActivationChangeObserver
* observer
= NULL
;
307 if (window_tracker
.Contains(lost_activation
)) {
308 observer
= aura::client::GetActivationChangeObserver(lost_activation
);
310 observer
->OnWindowActivated(reason
, active_window_
, lost_activation
);
312 observer
= aura::client::GetActivationChangeObserver(active_window_
);
314 observer
->OnWindowActivated(
315 reason
, active_window_
,
316 window_tracker
.Contains(lost_activation
) ? lost_activation
: NULL
);
319 aura::client::ActivationChangeObserver
, activation_observers_
,
321 reason
, active_window_
,
322 window_tracker
.Contains(lost_activation
) ? lost_activation
: NULL
));
325 void FocusController::WindowLostFocusFromDispositionChange(
326 aura::Window
* window
,
327 aura::Window
* next
) {
328 // TODO(beng): See if this function can be replaced by a call to
330 // Activation adjustments are handled first in the event of a disposition
331 // changed. If an activation change is necessary, focus is reset as part of
332 // that process so there's no point in updating focus independently.
333 if (window
== active_window_
) {
334 aura::Window
* next_activatable
= rules_
->GetNextActivatableWindow(window
);
335 SetActiveWindow(aura::client::ActivationChangeObserver::ActivationReason::
336 WINDOW_DISPOSITION_CHANGED
,
337 NULL
, next_activatable
);
338 if (!(active_window_
&& active_window_
->Contains(focused_window_
)))
339 SetFocusedWindow(next_activatable
);
340 } else if (window
->Contains(focused_window_
)) {
341 // Active window isn't changing, but focused window might be.
342 SetFocusedWindow(rules_
->GetFocusableWindow(next
));
346 void FocusController::WindowFocusedFromInputEvent(aura::Window
* window
) {
347 // Only focus |window| if it or any of its parents can be focused. Otherwise
348 // FocusWindow() will focus the topmost window, which may not be the
349 // currently focused one.
350 if (rules_
->CanFocusWindow(GetToplevelWindow(window
))) {
351 FocusAndActivateWindow(
352 aura::client::ActivationChangeObserver::ActivationReason::INPUT_EVENT
,