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/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"
18
19namespace wm {
20namespace {
21
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.
25void StackTransientParentsBelowModalWindow(aura::Window* window) {
26  if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_WINDOW)
27    return;
28
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);
33  }
34}
35
36}  // namespace
37
38////////////////////////////////////////////////////////////////////////////////
39// FocusController, public:
40
41FocusController::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);
49}
50
51FocusController::~FocusController() {
52}
53
54////////////////////////////////////////////////////////////////////////////////
55// FocusController, aura::client::ActivationClient implementation:
56
57void FocusController::AddObserver(
58    aura::client::ActivationChangeObserver* observer) {
59  activation_observers_.AddObserver(observer);
60}
61
62void FocusController::RemoveObserver(
63    aura::client::ActivationChangeObserver* observer) {
64  activation_observers_.RemoveObserver(observer);
65}
66
67void FocusController::ActivateWindow(aura::Window* window) {
68  FocusWindow(window);
69}
70
71void FocusController::DeactivateWindow(aura::Window* window) {
72  if (window)
73    FocusWindow(rules_->GetNextActivatableWindow(window));
74}
75
76aura::Window* FocusController::GetActiveWindow() {
77  return active_window_;
78}
79
80aura::Window* FocusController::GetActivatableWindow(aura::Window* window) {
81  return rules_->GetActivatableWindow(window);
82}
83
84aura::Window* FocusController::GetToplevelWindow(aura::Window* window) {
85  return rules_->GetToplevelWindow(window);
86}
87
88bool FocusController::CanActivateWindow(aura::Window* window) const {
89  return rules_->CanActivateWindow(window);
90}
91
92////////////////////////////////////////////////////////////////////////////////
93// FocusController, aura::client::FocusClient implementation:
94
95void FocusController::AddObserver(
96    aura::client::FocusChangeObserver* observer) {
97  focus_observers_.AddObserver(observer);
98}
99
100void FocusController::RemoveObserver(
101    aura::client::FocusChangeObserver* observer) {
102  focus_observers_.RemoveObserver(observer);
103}
104
105void FocusController::FocusWindow(aura::Window* window) {
106  if (window &&
107      (window->Contains(focused_window_) || window->Contains(active_window_))) {
108    return;
109  }
110
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;
116  }
117
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;
123
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);
130
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);
136
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);
144  }
145}
146
147void 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);
154}
155
156aura::Window* FocusController::GetFocusedWindow() {
157  return focused_window_;
158}
159
160////////////////////////////////////////////////////////////////////////////////
161// FocusController, ui::EventHandler implementation:
162void FocusController::OnKeyEvent(ui::KeyEvent* event) {
163}
164
165void FocusController::OnMouseEvent(ui::MouseEvent* event) {
166  if (event->type() == ui::ET_MOUSE_PRESSED && !event->handled())
167    WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
168}
169
170void FocusController::OnScrollEvent(ui::ScrollEvent* event) {
171}
172
173void FocusController::OnTouchEvent(ui::TouchEvent* event) {
174}
175
176void 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()));
181  }
182}
183
184////////////////////////////////////////////////////////////////////////////////
185// FocusController, aura::WindowObserver implementation:
186
187void FocusController::OnWindowVisibilityChanged(aura::Window* window,
188                                                bool visible) {
189  if (!visible)
190    WindowLostFocusFromDispositionChange(window, window->parent());
191}
192
193void FocusController::OnWindowDestroying(aura::Window* window) {
194  WindowLostFocusFromDispositionChange(window, window->parent());
195}
196
197void 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);
204  }
205}
206
207void 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);
214  }
215}
216
217////////////////////////////////////////////////////////////////////////////////
218// FocusController, private:
219
220void 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));
226
227  base::AutoReset<bool> updating_focus(&updating_focus_, true);
228  aura::Window* lost_focus = focused_window_;
229
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);
237
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_);
246  }
247  focused_window_ = window;
248  if (focused_window_ && !observer_manager_.IsObserving(focused_window_))
249    observer_manager_.Add(focused_window_);
250
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);
261  }
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);
268  }
269
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);
273}
274
275void FocusController::SetActiveWindow(aura::Window* requested_window,
276                                      aura::Window* window) {
277  if (updating_activation_)
278    return;
279
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_));
286    }
287    return;
288  }
289
290  DCHECK(rules_->CanActivateWindow(window));
291  if (window)
292    DCHECK_EQ(window, rules_->GetActivatableWindow(window));
293
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_);
304  }
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_);
311  }
312
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);
318  }
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);
324  }
325  FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
326                    activation_observers_,
327                    OnWindowActivated(active_window_,
328                                      window_tracker.Contains(lost_activation) ?
329                                      lost_activation : NULL));
330}
331
332void 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));
351  }
352}
353
354void 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);
360}
361
362}  // namespace wm
363