Add Profile::IsChild and IsLegacySupervised
[chromium-blink-merge.git] / ui / wm / core / focus_controller.cc
blob66c6deb65fc3f31477c174a7417da1fe15af3a53
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 // We should not be messing with the focus if the window has capture, unless
112 // no has focus.
113 if (window && (aura::client::GetCaptureWindow(window) == window) &&
114 focused_window_) {
115 return;
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))
128 return;
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) {
148 DCHECK(window);
149 if (!active_window_)
150 return;
151 if (!active_window_->Contains(window))
152 return;
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 &&
179 !event->handled()) {
180 WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
184 ////////////////////////////////////////////////////////////////////////////////
185 // FocusController, aura::WindowObserver implementation:
187 void FocusController::OnWindowVisibilityChanged(aura::Window* window,
188 bool visible) {
189 if (!visible)
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_)
222 return;
223 DCHECK(rules_->CanFocusWindow(window));
224 if (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();
235 if (window)
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;
241 if (lost_focus)
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,
252 focus_observers_,
253 OnWindowFocused(focused_window_,
254 window_tracker.Contains(lost_focus) ?
255 lost_focus : NULL));
256 if (window_tracker.Contains(lost_focus)) {
257 aura::client::FocusChangeObserver* observer =
258 aura::client::GetFocusChangeObserver(lost_focus);
259 if (observer)
260 observer->OnWindowFocused(focused_window_, lost_focus);
262 aura::client::FocusChangeObserver* observer =
263 aura::client::GetFocusChangeObserver(focused_window_);
264 if (observer) {
265 observer->OnWindowFocused(
266 focused_window_,
267 window_tracker.Contains(lost_focus) ? lost_focus : NULL);
270 // Ensure that the text input client is reset when the window loses the focus.
271 if (!window)
272 text_input_focus_manager->FocusTextInputClient(NULL);
275 void FocusController::SetActiveWindow(aura::Window* requested_window,
276 aura::Window* window) {
277 if (updating_activation_)
278 return;
280 if (window == active_window_) {
281 if (requested_window) {
282 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
283 activation_observers_,
284 OnAttemptToReactivateWindow(requested_window,
285 active_window_));
287 return;
290 DCHECK(rules_->CanActivateWindow(window));
291 if (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;
299 if (lost_activation)
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);
316 if (observer)
317 observer->OnWindowActivated(active_window_, lost_activation);
319 observer = aura::client::GetActivationChangeObserver(active_window_);
320 if (observer) {
321 observer->OnWindowActivated(
322 active_window_,
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
336 // destruction.
337 window->ClearProperty(aura::client::kModalKey);
338 // TODO(beng): See if this function can be replaced by a call to
339 // FocusWindow().
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)))
359 FocusWindow(window);
362 } // namespace wm