base: Change DCHECK_IS_ON to a macro DCHECK_IS_ON().
[chromium-blink-merge.git] / ui / wm / core / focus_controller.cc
blob722f6c893f9d1e811af21783fcd70a187e96e231
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"
19 namespace wm {
20 namespace {
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;
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);
36 } // namespace
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),
46 rules_(rules),
47 observer_manager_(this) {
48 DCHECK(rules);
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) {
68 FocusWindow(window);
71 void FocusController::DeactivateWindow(aura::Window* window) {
72 if (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) {
106 if (window &&
107 (window->Contains(focused_window_) || window->Contains(active_window_))) {
108 return;
111 // Focusing a window also activates its containing activatable window. Note
112 // that the rules could redirect activation activation and/or focus.
113 aura::Window* focusable = rules_->GetFocusableWindow(window);
114 aura::Window* activatable =
115 focusable ? rules_->GetActivatableWindow(focusable) : NULL;
117 // We need valid focusable/activatable windows in the event we're not clearing
118 // focus. "Clearing focus" is inferred by whether or not |window| passed to
119 // this function is non-NULL.
120 if (window && (!focusable || !activatable))
121 return;
122 DCHECK((focusable && activatable) || !window);
124 // Activation change observers may change the focused window. If this happens
125 // we must not adjust the focus below since this will clobber that change.
126 aura::Window* last_focused_window = focused_window_;
127 if (!updating_activation_)
128 SetActiveWindow(window, activatable);
130 // If the window's ActivationChangeObserver shifted focus to a valid window,
131 // we don't want to focus the window we thought would be focused by default.
132 bool activation_changed_focus = last_focused_window != focused_window_;
133 if (!updating_focus_ && (!activation_changed_focus || !focused_window_)) {
134 if (active_window_ && focusable)
135 DCHECK(active_window_->Contains(focusable));
136 SetFocusedWindow(focusable);
140 void FocusController::ResetFocusWithinActiveWindow(aura::Window* window) {
141 DCHECK(window);
142 if (!active_window_)
143 return;
144 if (!active_window_->Contains(window))
145 return;
146 SetFocusedWindow(window);
149 aura::Window* FocusController::GetFocusedWindow() {
150 return focused_window_;
153 ////////////////////////////////////////////////////////////////////////////////
154 // FocusController, ui::EventHandler implementation:
155 void FocusController::OnKeyEvent(ui::KeyEvent* event) {
158 void FocusController::OnMouseEvent(ui::MouseEvent* event) {
159 if (event->type() == ui::ET_MOUSE_PRESSED && !event->handled())
160 WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
163 void FocusController::OnScrollEvent(ui::ScrollEvent* event) {
166 void FocusController::OnTouchEvent(ui::TouchEvent* event) {
169 void FocusController::OnGestureEvent(ui::GestureEvent* event) {
170 if (event->type() == ui::ET_GESTURE_BEGIN &&
171 event->details().touch_points() == 1 &&
172 !event->handled()) {
173 WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
177 ////////////////////////////////////////////////////////////////////////////////
178 // FocusController, aura::WindowObserver implementation:
180 void FocusController::OnWindowVisibilityChanged(aura::Window* window,
181 bool visible) {
182 if (!visible)
183 WindowLostFocusFromDispositionChange(window, window->parent());
186 void FocusController::OnWindowDestroying(aura::Window* window) {
187 WindowLostFocusFromDispositionChange(window, window->parent());
190 void FocusController::OnWindowHierarchyChanging(
191 const HierarchyChangeParams& params) {
192 if (params.receiver == active_window_ &&
193 params.target->Contains(params.receiver) && (!params.new_parent ||
194 aura::client::GetFocusClient(params.new_parent) !=
195 aura::client::GetFocusClient(params.receiver))) {
196 WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
200 void FocusController::OnWindowHierarchyChanged(
201 const HierarchyChangeParams& params) {
202 if (params.receiver == focused_window_ &&
203 params.target->Contains(params.receiver) && (!params.new_parent ||
204 aura::client::GetFocusClient(params.new_parent) !=
205 aura::client::GetFocusClient(params.receiver))) {
206 WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
210 ////////////////////////////////////////////////////////////////////////////////
211 // FocusController, private:
213 void FocusController::SetFocusedWindow(aura::Window* window) {
214 if (updating_focus_ || window == focused_window_)
215 return;
216 DCHECK(rules_->CanFocusWindow(window));
217 if (window)
218 DCHECK_EQ(window, rules_->GetFocusableWindow(window));
220 base::AutoReset<bool> updating_focus(&updating_focus_, true);
221 aura::Window* lost_focus = focused_window_;
223 // |window| is going to get the focus, so reset the text input client.
224 // OnWindowFocused() may set a proper text input client if the implementation
225 // supports text input.
226 ui::TextInputFocusManager* text_input_focus_manager =
227 ui::TextInputFocusManager::GetInstance();
228 if (window)
229 text_input_focus_manager->FocusTextInputClient(NULL);
231 // Allow for the window losing focus to be deleted during dispatch. If it is
232 // deleted pass NULL to observers instead of a deleted window.
233 aura::WindowTracker window_tracker;
234 if (lost_focus)
235 window_tracker.Add(lost_focus);
236 if (focused_window_ && observer_manager_.IsObserving(focused_window_) &&
237 focused_window_ != active_window_) {
238 observer_manager_.Remove(focused_window_);
240 focused_window_ = window;
241 if (focused_window_ && !observer_manager_.IsObserving(focused_window_))
242 observer_manager_.Add(focused_window_);
244 FOR_EACH_OBSERVER(aura::client::FocusChangeObserver,
245 focus_observers_,
246 OnWindowFocused(focused_window_,
247 window_tracker.Contains(lost_focus) ?
248 lost_focus : NULL));
249 if (window_tracker.Contains(lost_focus)) {
250 aura::client::FocusChangeObserver* observer =
251 aura::client::GetFocusChangeObserver(lost_focus);
252 if (observer)
253 observer->OnWindowFocused(focused_window_, lost_focus);
255 aura::client::FocusChangeObserver* observer =
256 aura::client::GetFocusChangeObserver(focused_window_);
257 if (observer) {
258 observer->OnWindowFocused(
259 focused_window_,
260 window_tracker.Contains(lost_focus) ? lost_focus : NULL);
263 // Ensure that the text input client is reset when the window loses the focus.
264 if (!window)
265 text_input_focus_manager->FocusTextInputClient(NULL);
268 void FocusController::SetActiveWindow(aura::Window* requested_window,
269 aura::Window* window) {
270 if (updating_activation_)
271 return;
273 if (window == active_window_) {
274 if (requested_window) {
275 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
276 activation_observers_,
277 OnAttemptToReactivateWindow(requested_window,
278 active_window_));
280 return;
283 DCHECK(rules_->CanActivateWindow(window));
284 if (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;
292 if (lost_activation)
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);
309 if (observer)
310 observer->OnWindowActivated(active_window_, lost_activation);
312 observer = aura::client::GetActivationChangeObserver(active_window_);
313 if (observer) {
314 observer->OnWindowActivated(
315 active_window_,
316 window_tracker.Contains(lost_activation) ? lost_activation : NULL);
318 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
319 activation_observers_,
320 OnWindowActivated(active_window_,
321 window_tracker.Contains(lost_activation) ?
322 lost_activation : NULL));
325 void FocusController::WindowLostFocusFromDispositionChange(
326 aura::Window* window,
327 aura::Window* next) {
328 // A window's modality state will interfere with focus restoration during its
329 // destruction.
330 window->ClearProperty(aura::client::kModalKey);
331 // TODO(beng): See if this function can be replaced by a call to
332 // FocusWindow().
333 // Activation adjustments are handled first in the event of a disposition
334 // changed. If an activation change is necessary, focus is reset as part of
335 // that process so there's no point in updating focus independently.
336 if (window == active_window_) {
337 aura::Window* next_activatable = rules_->GetNextActivatableWindow(window);
338 SetActiveWindow(NULL, next_activatable);
339 if (!(active_window_ && active_window_->Contains(focused_window_)))
340 SetFocusedWindow(next_activatable);
341 } else if (window->Contains(focused_window_)) {
342 // Active window isn't changing, but focused window might be.
343 SetFocusedWindow(rules_->GetFocusableWindow(next));
347 void FocusController::WindowFocusedFromInputEvent(aura::Window* window) {
348 // Only focus |window| if it or any of its parents can be focused. Otherwise
349 // FocusWindow() will focus the topmost window, which may not be the
350 // currently focused one.
351 if (rules_->CanFocusWindow(GetToplevelWindow(window)))
352 FocusWindow(window);
355 } // namespace wm