Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / wm / core / focus_controller.cc
blobd062903216a0a763eaeb13e465187f1892ef6149
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 return;
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))
204 return;
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_)
225 return;
226 DCHECK(rules_->CanFocusWindow(window));
227 if (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;
236 if (lost_focus)
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,
247 focus_observers_,
248 OnWindowFocused(focused_window_,
249 window_tracker.Contains(lost_focus) ?
250 lost_focus : NULL));
251 if (window_tracker.Contains(lost_focus)) {
252 aura::client::FocusChangeObserver* observer =
253 aura::client::GetFocusChangeObserver(lost_focus);
254 if (observer)
255 observer->OnWindowFocused(focused_window_, lost_focus);
257 aura::client::FocusChangeObserver* observer =
258 aura::client::GetFocusChangeObserver(focused_window_);
259 if (observer) {
260 observer->OnWindowFocused(
261 focused_window_,
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_)
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(reason, active_window_, lost_activation);
312 observer = aura::client::GetActivationChangeObserver(active_window_);
313 if (observer) {
314 observer->OnWindowActivated(
315 reason, active_window_,
316 window_tracker.Contains(lost_activation) ? lost_activation : NULL);
318 FOR_EACH_OBSERVER(
319 aura::client::ActivationChangeObserver, activation_observers_,
320 OnWindowActivated(
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
329 // FocusWindow().
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,
353 window);
357 } // namespace wm