Home | History | Annotate | Download | only in core
      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 
     19 namespace wm {
     20 namespace {
     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.
     25 void 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 
     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);
     49 }
     50 
     51 FocusController::~FocusController() {
     52 }
     53 
     54 ////////////////////////////////////////////////////////////////////////////////
     55 // FocusController, aura::client::ActivationClient implementation:
     56 
     57 void FocusController::AddObserver(
     58     aura::client::ActivationChangeObserver* observer) {
     59   activation_observers_.AddObserver(observer);
     60 }
     61 
     62 void FocusController::RemoveObserver(
     63     aura::client::ActivationChangeObserver* observer) {
     64   activation_observers_.RemoveObserver(observer);
     65 }
     66 
     67 void FocusController::ActivateWindow(aura::Window* window) {
     68   FocusWindow(window);
     69 }
     70 
     71 void FocusController::DeactivateWindow(aura::Window* window) {
     72   if (window)
     73     FocusWindow(rules_->GetNextActivatableWindow(window));
     74 }
     75 
     76 aura::Window* FocusController::GetActiveWindow() {
     77   return active_window_;
     78 }
     79 
     80 aura::Window* FocusController::GetActivatableWindow(aura::Window* window) {
     81   return rules_->GetActivatableWindow(window);
     82 }
     83 
     84 aura::Window* FocusController::GetToplevelWindow(aura::Window* window) {
     85   return rules_->GetToplevelWindow(window);
     86 }
     87 
     88 bool FocusController::CanActivateWindow(aura::Window* window) const {
     89   return rules_->CanActivateWindow(window);
     90 }
     91 
     92 ////////////////////////////////////////////////////////////////////////////////
     93 // FocusController, aura::client::FocusClient implementation:
     94 
     95 void FocusController::AddObserver(
     96     aura::client::FocusChangeObserver* observer) {
     97   focus_observers_.AddObserver(observer);
     98 }
     99 
    100 void FocusController::RemoveObserver(
    101     aura::client::FocusChangeObserver* observer) {
    102   focus_observers_.RemoveObserver(observer);
    103 }
    104 
    105 void 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 
    147 void 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 
    156 aura::Window* FocusController::GetFocusedWindow() {
    157   return focused_window_;
    158 }
    159 
    160 ////////////////////////////////////////////////////////////////////////////////
    161 // FocusController, ui::EventHandler implementation:
    162 void FocusController::OnKeyEvent(ui::KeyEvent* event) {
    163 }
    164 
    165 void 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 
    170 void FocusController::OnScrollEvent(ui::ScrollEvent* event) {
    171 }
    172 
    173 void FocusController::OnTouchEvent(ui::TouchEvent* event) {
    174 }
    175 
    176 void 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 
    187 void FocusController::OnWindowVisibilityChanged(aura::Window* window,
    188                                                 bool visible) {
    189   if (!visible)
    190     WindowLostFocusFromDispositionChange(window, window->parent());
    191 }
    192 
    193 void FocusController::OnWindowDestroying(aura::Window* window) {
    194   WindowLostFocusFromDispositionChange(window, window->parent());
    195 }
    196 
    197 void 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 
    207 void 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 
    220 void 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 
    275 void 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 
    332 void 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 
    354 void 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