[Android] Implement 3-way sensor fallback for Device Orientation.
[chromium-blink-merge.git] / ui / wm / core / focus_controller.cc
blobe1b644dccc75d72e6dd86b3849956e0d190dfdf5
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"
18 namespace wm {
19 namespace {
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)
26 return;
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);
35 } // namespace
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),
45 rules_(rules),
46 observer_manager_(this) {
47 DCHECK(rules);
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) {
67 FocusWindow(window);
70 void FocusController::DeactivateWindow(aura::Window* window) {
71 if (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,
107 window);
110 void FocusController::ResetFocusWithinActiveWindow(aura::Window* window) {
111 DCHECK(window);
112 if (!active_window_)
113 return;
114 if (!active_window_->Contains(window))
115 return;
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 &&
142 !event->handled()) {
143 WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
147 ////////////////////////////////////////////////////////////////////////////////
148 // FocusController, aura::WindowObserver implementation:
150 void FocusController::OnWindowVisibilityChanged(aura::Window* window,
151 bool visible) {
152 if (!visible)
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
158 // destruction.
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) {
189 if (window &&
190 (window->Contains(focused_window_) || window->Contains(active_window_))) {
191 StackActiveWindow();
192 return;
195 // Focusing a window also activates its containing activatable window. Note
196 // that the rules could redirect activation activation and/or focus.
197 aura::Window* focusable = rules_->GetFocusableWindow(window);
198 aura::Window* activatable =
199 focusable ? rules_->GetActivatableWindow(focusable) : NULL;
201 // We need valid focusable/activatable windows in the event we're not clearing
202 // focus. "Clearing focus" is inferred by whether or not |window| passed to
203 // this function is non-NULL.
204 if (window && (!focusable || !activatable))
205 return;
206 DCHECK((focusable && activatable) || !window);
208 // Activation change observers may change the focused window. If this happens
209 // we must not adjust the focus below since this will clobber that change.
210 aura::Window* last_focused_window = focused_window_;
211 if (!updating_activation_)
212 SetActiveWindow(reason, window, activatable);
214 // If the window's ActivationChangeObserver shifted focus to a valid window,
215 // we don't want to focus the window we thought would be focused by default.
216 bool activation_changed_focus = last_focused_window != focused_window_;
217 if (!updating_focus_ && (!activation_changed_focus || !focused_window_)) {
218 if (active_window_ && focusable)
219 DCHECK(active_window_->Contains(focusable));
220 SetFocusedWindow(focusable);
224 void FocusController::SetFocusedWindow(aura::Window* window) {
225 if (updating_focus_ || window == focused_window_)
226 return;
227 DCHECK(rules_->CanFocusWindow(window));
228 if (window)
229 DCHECK_EQ(window, rules_->GetFocusableWindow(window));
231 base::AutoReset<bool> updating_focus(&updating_focus_, true);
232 aura::Window* lost_focus = focused_window_;
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);
267 void FocusController::SetActiveWindow(
268 aura::client::ActivationChangeObserver::ActivationReason reason,
269 aura::Window* requested_window,
270 aura::Window* window) {
271 if (updating_activation_)
272 return;
274 if (window == active_window_) {
275 if (requested_window) {
276 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
277 activation_observers_,
278 OnAttemptToReactivateWindow(requested_window,
279 active_window_));
281 return;
284 DCHECK(rules_->CanActivateWindow(window));
285 if (window)
286 DCHECK_EQ(window, rules_->GetActivatableWindow(window));
288 base::AutoReset<bool> updating_activation(&updating_activation_, true);
289 aura::Window* lost_activation = active_window_;
290 // Allow for the window losing activation to be deleted during dispatch. If
291 // it is deleted pass NULL to observers instead of a deleted window.
292 aura::WindowTracker window_tracker;
293 if (lost_activation)
294 window_tracker.Add(lost_activation);
295 if (active_window_ && observer_manager_.IsObserving(active_window_) &&
296 focused_window_ != active_window_) {
297 observer_manager_.Remove(active_window_);
299 active_window_ = window;
300 if (active_window_ && !observer_manager_.IsObserving(active_window_))
301 observer_manager_.Add(active_window_);
302 if (active_window_)
303 StackActiveWindow();
305 aura::client::ActivationChangeObserver* observer = NULL;
306 if (window_tracker.Contains(lost_activation)) {
307 observer = aura::client::GetActivationChangeObserver(lost_activation);
308 if (observer)
309 observer->OnWindowActivated(reason, active_window_, lost_activation);
311 observer = aura::client::GetActivationChangeObserver(active_window_);
312 if (observer) {
313 observer->OnWindowActivated(
314 reason, active_window_,
315 window_tracker.Contains(lost_activation) ? lost_activation : NULL);
317 FOR_EACH_OBSERVER(
318 aura::client::ActivationChangeObserver, activation_observers_,
319 OnWindowActivated(
320 reason, active_window_,
321 window_tracker.Contains(lost_activation) ? lost_activation : NULL));
324 void FocusController::StackActiveWindow() {
325 if (active_window_) {
326 StackTransientParentsBelowModalWindow(active_window_);
327 active_window_->parent()->StackChildAtTop(active_window_);
331 void FocusController::WindowLostFocusFromDispositionChange(
332 aura::Window* window,
333 aura::Window* next) {
334 // TODO(beng): See if this function can be replaced by a call to
335 // FocusWindow().
336 // Activation adjustments are handled first in the event of a disposition
337 // changed. If an activation change is necessary, focus is reset as part of
338 // that process so there's no point in updating focus independently.
339 if (window == active_window_) {
340 aura::Window* next_activatable = rules_->GetNextActivatableWindow(window);
341 SetActiveWindow(aura::client::ActivationChangeObserver::ActivationReason::
342 WINDOW_DISPOSITION_CHANGED,
343 NULL, next_activatable);
344 if (!(active_window_ && active_window_->Contains(focused_window_)))
345 SetFocusedWindow(next_activatable);
346 } else if (window->Contains(focused_window_)) {
347 // Active window isn't changing, but focused window might be.
348 SetFocusedWindow(rules_->GetFocusableWindow(next));
352 void FocusController::WindowFocusedFromInputEvent(aura::Window* window) {
353 // Only focus |window| if it or any of its parents can be focused. Otherwise
354 // FocusWindow() will focus the topmost window, which may not be the
355 // currently focused one.
356 if (rules_->CanFocusWindow(GetToplevelWindow(window))) {
357 FocusAndActivateWindow(
358 aura::client::ActivationChangeObserver::ActivationReason::INPUT_EVENT,
359 window);
363 } // namespace wm