focus_controller.cc revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
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.
4
5#include "ui/wm/core/focus_controller.h"
6
7#include "base/auto_reset.h"
8#include "ui/aura/client/activation_change_observer.h"
9#include "ui/aura/client/aura_constants.h"
10#include "ui/aura/client/capture_client.h"
11#include "ui/aura/client/focus_change_observer.h"
12#include "ui/aura/env.h"
13#include "ui/aura/window_tracker.h"
14#include "ui/events/event.h"
15#include "ui/wm/core/focus_rules.h"
16#include "ui/wm/core/window_util.h"
17
18namespace wm {
19namespace {
20
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.
24void StackTransientParentsBelowModalWindow(aura::Window* window) {
25  if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_WINDOW)
26    return;
27
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);
32  }
33}
34
35}  // namespace
36
37////////////////////////////////////////////////////////////////////////////////
38// FocusController, public:
39
40FocusController::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);
48}
49
50FocusController::~FocusController() {
51}
52
53////////////////////////////////////////////////////////////////////////////////
54// FocusController, aura::client::ActivationClient implementation:
55
56void FocusController::AddObserver(
57    aura::client::ActivationChangeObserver* observer) {
58  activation_observers_.AddObserver(observer);
59}
60
61void FocusController::RemoveObserver(
62    aura::client::ActivationChangeObserver* observer) {
63  activation_observers_.RemoveObserver(observer);
64}
65
66void FocusController::ActivateWindow(aura::Window* window) {
67  FocusWindow(window);
68}
69
70void FocusController::DeactivateWindow(aura::Window* window) {
71  if (window)
72    FocusWindow(rules_->GetNextActivatableWindow(window));
73}
74
75aura::Window* FocusController::GetActiveWindow() {
76  return active_window_;
77}
78
79aura::Window* FocusController::GetActivatableWindow(aura::Window* window) {
80  return rules_->GetActivatableWindow(window);
81}
82
83aura::Window* FocusController::GetToplevelWindow(aura::Window* window) {
84  return rules_->GetToplevelWindow(window);
85}
86
87bool FocusController::OnWillFocusWindow(aura::Window* window,
88                                        const ui::Event* event) {
89  NOTREACHED();
90  return false;
91}
92
93bool FocusController::CanActivateWindow(aura::Window* window) const {
94  return rules_->CanActivateWindow(window);
95}
96
97////////////////////////////////////////////////////////////////////////////////
98// FocusController, aura::client::FocusClient implementation:
99
100void FocusController::AddObserver(
101    aura::client::FocusChangeObserver* observer) {
102  focus_observers_.AddObserver(observer);
103}
104
105void FocusController::RemoveObserver(
106    aura::client::FocusChangeObserver* observer) {
107  focus_observers_.RemoveObserver(observer);
108}
109
110void FocusController::FocusWindow(aura::Window* window) {
111  if (window &&
112      (window->Contains(focused_window_) || window->Contains(active_window_))) {
113    return;
114  }
115
116  // We should not be messing with the focus if the window has capture, unless
117  // no has focus.
118  if (window && (aura::client::GetCaptureWindow(window) == window) &&
119      focused_window_) {
120    return;
121  }
122
123  // Focusing a window also activates its containing activatable window. Note
124  // that the rules could redirect activation activation and/or focus.
125  aura::Window* focusable = rules_->GetFocusableWindow(window);
126  aura::Window* activatable =
127      focusable ? rules_->GetActivatableWindow(focusable) : NULL;
128
129  // We need valid focusable/activatable windows in the event we're not clearing
130  // focus. "Clearing focus" is inferred by whether or not |window| passed to
131  // this function is non-NULL.
132  if (window && (!focusable || !activatable))
133    return;
134  DCHECK((focusable && activatable) || !window);
135
136  // Activation change observers may change the focused window. If this happens
137  // we must not adjust the focus below since this will clobber that change.
138  aura::Window* last_focused_window = focused_window_;
139  if (!updating_activation_)
140    SetActiveWindow(window, activatable);
141
142  // If the window's ActivationChangeObserver shifted focus to a valid window,
143  // we don't want to focus the window we thought would be focused by default.
144  bool activation_changed_focus = last_focused_window != focused_window_;
145  if (!updating_focus_ && (!activation_changed_focus || !focused_window_)) {
146    if (active_window_ && focusable)
147      DCHECK(active_window_->Contains(focusable));
148    SetFocusedWindow(focusable);
149  }
150}
151
152void FocusController::ResetFocusWithinActiveWindow(aura::Window* window) {
153  DCHECK(window);
154  if (!active_window_)
155    return;
156  if (!active_window_->Contains(window))
157    return;
158  SetFocusedWindow(window);
159}
160
161aura::Window* FocusController::GetFocusedWindow() {
162  return focused_window_;
163}
164
165////////////////////////////////////////////////////////////////////////////////
166// FocusController, ui::EventHandler implementation:
167void FocusController::OnKeyEvent(ui::KeyEvent* event) {
168}
169
170void FocusController::OnMouseEvent(ui::MouseEvent* event) {
171  if (event->type() == ui::ET_MOUSE_PRESSED)
172    WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
173}
174
175void FocusController::OnScrollEvent(ui::ScrollEvent* event) {
176}
177
178void FocusController::OnTouchEvent(ui::TouchEvent* event) {
179}
180
181void FocusController::OnGestureEvent(ui::GestureEvent* event) {
182  if (event->type() == ui::ET_GESTURE_BEGIN &&
183      event->details().touch_points() == 1) {
184    WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
185  }
186}
187
188////////////////////////////////////////////////////////////////////////////////
189// FocusController, aura::WindowObserver implementation:
190
191void FocusController::OnWindowVisibilityChanged(aura::Window* window,
192                                                bool visible) {
193  if (!visible)
194    WindowLostFocusFromDispositionChange(window, window->parent());
195}
196
197void FocusController::OnWindowDestroying(aura::Window* window) {
198  WindowLostFocusFromDispositionChange(window, window->parent());
199}
200
201void FocusController::OnWindowHierarchyChanging(
202    const HierarchyChangeParams& params) {
203  if (params.receiver == active_window_ &&
204      params.target->Contains(params.receiver) && (!params.new_parent ||
205      aura::client::GetFocusClient(params.new_parent) !=
206          aura::client::GetFocusClient(params.receiver))) {
207    WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
208  }
209}
210
211void FocusController::OnWindowHierarchyChanged(
212    const HierarchyChangeParams& params) {
213  if (params.receiver == focused_window_ &&
214      params.target->Contains(params.receiver) && (!params.new_parent ||
215      aura::client::GetFocusClient(params.new_parent) !=
216          aura::client::GetFocusClient(params.receiver))) {
217    WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
218  }
219}
220
221////////////////////////////////////////////////////////////////////////////////
222// FocusController, private:
223
224void 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));
230
231  base::AutoReset<bool> updating_focus(&updating_focus_, true);
232  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_);
241  }
242  focused_window_ = window;
243  if (focused_window_ && !observer_manager_.IsObserving(focused_window_))
244    observer_manager_.Add(focused_window_);
245
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);
256  }
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);
263  }
264}
265
266void FocusController::SetActiveWindow(aura::Window* requested_window,
267                                      aura::Window* window) {
268  if (updating_activation_)
269    return;
270
271  if (window == active_window_) {
272    if (requested_window) {
273      FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
274                        activation_observers_,
275                        OnAttemptToReactivateWindow(requested_window,
276                                                    active_window_));
277    }
278    return;
279  }
280
281  DCHECK(rules_->CanActivateWindow(window));
282  if (window)
283    DCHECK_EQ(window, rules_->GetActivatableWindow(window));
284
285  base::AutoReset<bool> updating_activation(&updating_activation_, true);
286  aura::Window* lost_activation = active_window_;
287  // Allow for the window losing activation to be deleted during dispatch. If
288  // it is deleted pass NULL to observers instead of a deleted window.
289  aura::WindowTracker window_tracker;
290  if (lost_activation)
291    window_tracker.Add(lost_activation);
292  if (active_window_ && observer_manager_.IsObserving(active_window_) &&
293      focused_window_ != active_window_) {
294    observer_manager_.Remove(active_window_);
295  }
296  active_window_ = window;
297  if (active_window_ && !observer_manager_.IsObserving(active_window_))
298    observer_manager_.Add(active_window_);
299  if (active_window_) {
300    StackTransientParentsBelowModalWindow(active_window_);
301    active_window_->parent()->StackChildAtTop(active_window_);
302  }
303
304  aura::client::ActivationChangeObserver* observer = NULL;
305  if (window_tracker.Contains(lost_activation)) {
306    observer = aura::client::GetActivationChangeObserver(lost_activation);
307    if (observer)
308      observer->OnWindowActivated(active_window_, lost_activation);
309  }
310  observer = aura::client::GetActivationChangeObserver(active_window_);
311  if (observer) {
312    observer->OnWindowActivated(
313        active_window_,
314        window_tracker.Contains(lost_activation) ? lost_activation : NULL);
315  }
316  FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
317                    activation_observers_,
318                    OnWindowActivated(active_window_,
319                                      window_tracker.Contains(lost_activation) ?
320                                      lost_activation : NULL));
321}
322
323void FocusController::WindowLostFocusFromDispositionChange(
324    aura::Window* window,
325    aura::Window* next) {
326  // A window's modality state will interfere with focus restoration during its
327  // destruction.
328  window->ClearProperty(aura::client::kModalKey);
329  // TODO(beng): See if this function can be replaced by a call to
330  //             FocusWindow().
331  // Activation adjustments are handled first in the event of a disposition
332  // changed. If an activation change is necessary, focus is reset as part of
333  // that process so there's no point in updating focus independently.
334  if (window == active_window_) {
335    aura::Window* next_activatable = rules_->GetNextActivatableWindow(window);
336    SetActiveWindow(NULL, next_activatable);
337    if (!(active_window_ && active_window_->Contains(focused_window_)))
338      SetFocusedWindow(next_activatable);
339  } else if (window->Contains(focused_window_)) {
340    // Active window isn't changing, but focused window might be.
341    SetFocusedWindow(rules_->GetFocusableWindow(next));
342  }
343}
344
345void FocusController::WindowFocusedFromInputEvent(aura::Window* window) {
346  // Only focus |window| if it or any of its parents can be focused. Otherwise
347  // FocusWindow() will focus the topmost window, which may not be the
348  // currently focused one.
349  if (rules_->CanFocusWindow(GetToplevelWindow(window)))
350    FocusWindow(window);
351}
352
353}  // namespace wm
354