Revert of Add Masonry to key_silk_cases. (patchset #3 id:40001 of https://codereview...
[chromium-blink-merge.git] / ui / wm / core / focus_controller.cc
blob446e82c269fc4e852491886d1207ecfeaddc93cf
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 // A window's modality state will interfere with focus restoration during its
188 // destruction.
189 window->ClearProperty(aura::client::kModalKey);
190 WindowLostFocusFromDispositionChange(window, window->parent());
193 void FocusController::OnWindowHierarchyChanging(
194 const HierarchyChangeParams& params) {
195 if (params.receiver == active_window_ &&
196 params.target->Contains(params.receiver) && (!params.new_parent ||
197 aura::client::GetFocusClient(params.new_parent) !=
198 aura::client::GetFocusClient(params.receiver))) {
199 WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
203 void FocusController::OnWindowHierarchyChanged(
204 const HierarchyChangeParams& params) {
205 if (params.receiver == focused_window_ &&
206 params.target->Contains(params.receiver) && (!params.new_parent ||
207 aura::client::GetFocusClient(params.new_parent) !=
208 aura::client::GetFocusClient(params.receiver))) {
209 WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
213 ////////////////////////////////////////////////////////////////////////////////
214 // FocusController, private:
216 void FocusController::SetFocusedWindow(aura::Window* window) {
217 if (updating_focus_ || window == focused_window_)
218 return;
219 DCHECK(rules_->CanFocusWindow(window));
220 if (window)
221 DCHECK_EQ(window, rules_->GetFocusableWindow(window));
223 base::AutoReset<bool> updating_focus(&updating_focus_, true);
224 aura::Window* lost_focus = focused_window_;
226 // |window| is going to get the focus, so reset the text input client.
227 // OnWindowFocused() may set a proper text input client if the implementation
228 // supports text input.
229 ui::TextInputFocusManager* text_input_focus_manager =
230 ui::TextInputFocusManager::GetInstance();
231 if (window)
232 text_input_focus_manager->FocusTextInputClient(NULL);
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;
237 if (lost_focus)
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,
248 focus_observers_,
249 OnWindowFocused(focused_window_,
250 window_tracker.Contains(lost_focus) ?
251 lost_focus : NULL));
252 if (window_tracker.Contains(lost_focus)) {
253 aura::client::FocusChangeObserver* observer =
254 aura::client::GetFocusChangeObserver(lost_focus);
255 if (observer)
256 observer->OnWindowFocused(focused_window_, lost_focus);
258 aura::client::FocusChangeObserver* observer =
259 aura::client::GetFocusChangeObserver(focused_window_);
260 if (observer) {
261 observer->OnWindowFocused(
262 focused_window_,
263 window_tracker.Contains(lost_focus) ? lost_focus : NULL);
266 // Ensure that the text input client is reset when the window loses the focus.
267 if (!window)
268 text_input_focus_manager->FocusTextInputClient(NULL);
271 void FocusController::SetActiveWindow(aura::Window* requested_window,
272 aura::Window* window) {
273 if (updating_activation_)
274 return;
276 if (window == active_window_) {
277 if (requested_window) {
278 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
279 activation_observers_,
280 OnAttemptToReactivateWindow(requested_window,
281 active_window_));
283 return;
286 DCHECK(rules_->CanActivateWindow(window));
287 if (window)
288 DCHECK_EQ(window, rules_->GetActivatableWindow(window));
290 base::AutoReset<bool> updating_activation(&updating_activation_, true);
291 aura::Window* lost_activation = active_window_;
292 // Allow for the window losing activation to be deleted during dispatch. If
293 // it is deleted pass NULL to observers instead of a deleted window.
294 aura::WindowTracker window_tracker;
295 if (lost_activation)
296 window_tracker.Add(lost_activation);
297 if (active_window_ && observer_manager_.IsObserving(active_window_) &&
298 focused_window_ != active_window_) {
299 observer_manager_.Remove(active_window_);
301 active_window_ = window;
302 if (active_window_ && !observer_manager_.IsObserving(active_window_))
303 observer_manager_.Add(active_window_);
304 if (active_window_) {
305 StackTransientParentsBelowModalWindow(active_window_);
306 active_window_->parent()->StackChildAtTop(active_window_);
309 aura::client::ActivationChangeObserver* observer = NULL;
310 if (window_tracker.Contains(lost_activation)) {
311 observer = aura::client::GetActivationChangeObserver(lost_activation);
312 if (observer)
313 observer->OnWindowActivated(active_window_, lost_activation);
315 observer = aura::client::GetActivationChangeObserver(active_window_);
316 if (observer) {
317 observer->OnWindowActivated(
318 active_window_,
319 window_tracker.Contains(lost_activation) ? lost_activation : NULL);
321 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
322 activation_observers_,
323 OnWindowActivated(active_window_,
324 window_tracker.Contains(lost_activation) ?
325 lost_activation : NULL));
328 void FocusController::WindowLostFocusFromDispositionChange(
329 aura::Window* window,
330 aura::Window* next) {
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