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::OnWillFocusWindow(aura::Window* window,
     89                                         const ui::Event* event) {
     90   NOTREACHED();
     91   return false;
     92 }
     93 
     94 bool FocusController::CanActivateWindow(aura::Window* window) const {
     95   return rules_->CanActivateWindow(window);
     96 }
     97 
     98 ////////////////////////////////////////////////////////////////////////////////
     99 // FocusController, aura::client::FocusClient implementation:
    100 
    101 void FocusController::AddObserver(
    102     aura::client::FocusChangeObserver* observer) {
    103   focus_observers_.AddObserver(observer);
    104 }
    105 
    106 void FocusController::RemoveObserver(
    107     aura::client::FocusChangeObserver* observer) {
    108   focus_observers_.RemoveObserver(observer);
    109 }
    110 
    111 void FocusController::FocusWindow(aura::Window* window) {
    112   if (window &&
    113       (window->Contains(focused_window_) || window->Contains(active_window_))) {
    114     return;
    115   }
    116 
    117   // We should not be messing with the focus if the window has capture, unless
    118   // no has focus.
    119   if (window && (aura::client::GetCaptureWindow(window) == window) &&
    120       focused_window_) {
    121     return;
    122   }
    123 
    124   // Focusing a window also activates its containing activatable window. Note
    125   // that the rules could redirect activation activation and/or focus.
    126   aura::Window* focusable = rules_->GetFocusableWindow(window);
    127   aura::Window* activatable =
    128       focusable ? rules_->GetActivatableWindow(focusable) : NULL;
    129 
    130   // We need valid focusable/activatable windows in the event we're not clearing
    131   // focus. "Clearing focus" is inferred by whether or not |window| passed to
    132   // this function is non-NULL.
    133   if (window && (!focusable || !activatable))
    134     return;
    135   DCHECK((focusable && activatable) || !window);
    136 
    137   // Activation change observers may change the focused window. If this happens
    138   // we must not adjust the focus below since this will clobber that change.
    139   aura::Window* last_focused_window = focused_window_;
    140   if (!updating_activation_)
    141     SetActiveWindow(window, activatable);
    142 
    143   // If the window's ActivationChangeObserver shifted focus to a valid window,
    144   // we don't want to focus the window we thought would be focused by default.
    145   bool activation_changed_focus = last_focused_window != focused_window_;
    146   if (!updating_focus_ && (!activation_changed_focus || !focused_window_)) {
    147     if (active_window_ && focusable)
    148       DCHECK(active_window_->Contains(focusable));
    149     SetFocusedWindow(focusable);
    150   }
    151 }
    152 
    153 void FocusController::ResetFocusWithinActiveWindow(aura::Window* window) {
    154   DCHECK(window);
    155   if (!active_window_)
    156     return;
    157   if (!active_window_->Contains(window))
    158     return;
    159   SetFocusedWindow(window);
    160 }
    161 
    162 aura::Window* FocusController::GetFocusedWindow() {
    163   return focused_window_;
    164 }
    165 
    166 ////////////////////////////////////////////////////////////////////////////////
    167 // FocusController, ui::EventHandler implementation:
    168 void FocusController::OnKeyEvent(ui::KeyEvent* event) {
    169 }
    170 
    171 void FocusController::OnMouseEvent(ui::MouseEvent* event) {
    172   if (event->type() == ui::ET_MOUSE_PRESSED && !event->handled())
    173     WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
    174 }
    175 
    176 void FocusController::OnScrollEvent(ui::ScrollEvent* event) {
    177 }
    178 
    179 void FocusController::OnTouchEvent(ui::TouchEvent* event) {
    180 }
    181 
    182 void FocusController::OnGestureEvent(ui::GestureEvent* event) {
    183   if (event->type() == ui::ET_GESTURE_BEGIN &&
    184       event->details().touch_points() == 1 &&
    185       !event->handled()) {
    186     WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
    187   }
    188 }
    189 
    190 ////////////////////////////////////////////////////////////////////////////////
    191 // FocusController, aura::WindowObserver implementation:
    192 
    193 void FocusController::OnWindowVisibilityChanged(aura::Window* window,
    194                                                 bool visible) {
    195   if (!visible)
    196     WindowLostFocusFromDispositionChange(window, window->parent());
    197 }
    198 
    199 void FocusController::OnWindowDestroying(aura::Window* window) {
    200   WindowLostFocusFromDispositionChange(window, window->parent());
    201 }
    202 
    203 void FocusController::OnWindowHierarchyChanging(
    204     const HierarchyChangeParams& params) {
    205   if (params.receiver == active_window_ &&
    206       params.target->Contains(params.receiver) && (!params.new_parent ||
    207       aura::client::GetFocusClient(params.new_parent) !=
    208           aura::client::GetFocusClient(params.receiver))) {
    209     WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
    210   }
    211 }
    212 
    213 void FocusController::OnWindowHierarchyChanged(
    214     const HierarchyChangeParams& params) {
    215   if (params.receiver == focused_window_ &&
    216       params.target->Contains(params.receiver) && (!params.new_parent ||
    217       aura::client::GetFocusClient(params.new_parent) !=
    218           aura::client::GetFocusClient(params.receiver))) {
    219     WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
    220   }
    221 }
    222 
    223 ////////////////////////////////////////////////////////////////////////////////
    224 // FocusController, private:
    225 
    226 void FocusController::SetFocusedWindow(aura::Window* window) {
    227   if (updating_focus_ || window == focused_window_)
    228     return;
    229   DCHECK(rules_->CanFocusWindow(window));
    230   if (window)
    231     DCHECK_EQ(window, rules_->GetFocusableWindow(window));
    232 
    233   base::AutoReset<bool> updating_focus(&updating_focus_, true);
    234   aura::Window* lost_focus = focused_window_;
    235 
    236   // |window| is going to get the focus, so reset the text input client.
    237   // OnWindowFocused() may set a proper text input client if the implementation
    238   // supports text input.
    239   ui::TextInputFocusManager* text_input_focus_manager =
    240       ui::TextInputFocusManager::GetInstance();
    241   if (window)
    242     text_input_focus_manager->FocusTextInputClient(NULL);
    243 
    244   // Allow for the window losing focus to be deleted during dispatch. If it is
    245   // deleted pass NULL to observers instead of a deleted window.
    246   aura::WindowTracker window_tracker;
    247   if (lost_focus)
    248     window_tracker.Add(lost_focus);
    249   if (focused_window_ && observer_manager_.IsObserving(focused_window_) &&
    250       focused_window_ != active_window_) {
    251     observer_manager_.Remove(focused_window_);
    252   }
    253   focused_window_ = window;
    254   if (focused_window_ && !observer_manager_.IsObserving(focused_window_))
    255     observer_manager_.Add(focused_window_);
    256 
    257   FOR_EACH_OBSERVER(aura::client::FocusChangeObserver,
    258                     focus_observers_,
    259                     OnWindowFocused(focused_window_,
    260                                     window_tracker.Contains(lost_focus) ?
    261                                     lost_focus : NULL));
    262   if (window_tracker.Contains(lost_focus)) {
    263     aura::client::FocusChangeObserver* observer =
    264         aura::client::GetFocusChangeObserver(lost_focus);
    265     if (observer)
    266       observer->OnWindowFocused(focused_window_, lost_focus);
    267   }
    268   aura::client::FocusChangeObserver* observer =
    269       aura::client::GetFocusChangeObserver(focused_window_);
    270   if (observer) {
    271     observer->OnWindowFocused(
    272         focused_window_,
    273         window_tracker.Contains(lost_focus) ? lost_focus : NULL);
    274   }
    275 
    276   // Ensure that the text input client is reset when the window loses the focus.
    277   if (!window)
    278     text_input_focus_manager->FocusTextInputClient(NULL);
    279 }
    280 
    281 void FocusController::SetActiveWindow(aura::Window* requested_window,
    282                                       aura::Window* window) {
    283   if (updating_activation_)
    284     return;
    285 
    286   if (window == active_window_) {
    287     if (requested_window) {
    288       FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
    289                         activation_observers_,
    290                         OnAttemptToReactivateWindow(requested_window,
    291                                                     active_window_));
    292     }
    293     return;
    294   }
    295 
    296   DCHECK(rules_->CanActivateWindow(window));
    297   if (window)
    298     DCHECK_EQ(window, rules_->GetActivatableWindow(window));
    299 
    300   base::AutoReset<bool> updating_activation(&updating_activation_, true);
    301   aura::Window* lost_activation = active_window_;
    302   // Allow for the window losing activation to be deleted during dispatch. If
    303   // it is deleted pass NULL to observers instead of a deleted window.
    304   aura::WindowTracker window_tracker;
    305   if (lost_activation)
    306     window_tracker.Add(lost_activation);
    307   if (active_window_ && observer_manager_.IsObserving(active_window_) &&
    308       focused_window_ != active_window_) {
    309     observer_manager_.Remove(active_window_);
    310   }
    311   active_window_ = window;
    312   if (active_window_ && !observer_manager_.IsObserving(active_window_))
    313     observer_manager_.Add(active_window_);
    314   if (active_window_) {
    315     StackTransientParentsBelowModalWindow(active_window_);
    316     active_window_->parent()->StackChildAtTop(active_window_);
    317   }
    318 
    319   aura::client::ActivationChangeObserver* observer = NULL;
    320   if (window_tracker.Contains(lost_activation)) {
    321     observer = aura::client::GetActivationChangeObserver(lost_activation);
    322     if (observer)
    323       observer->OnWindowActivated(active_window_, lost_activation);
    324   }
    325   observer = aura::client::GetActivationChangeObserver(active_window_);
    326   if (observer) {
    327     observer->OnWindowActivated(
    328         active_window_,
    329         window_tracker.Contains(lost_activation) ? lost_activation : NULL);
    330   }
    331   FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
    332                     activation_observers_,
    333                     OnWindowActivated(active_window_,
    334                                       window_tracker.Contains(lost_activation) ?
    335                                       lost_activation : NULL));
    336 }
    337 
    338 void FocusController::WindowLostFocusFromDispositionChange(
    339     aura::Window* window,
    340     aura::Window* next) {
    341   // A window's modality state will interfere with focus restoration during its
    342   // destruction.
    343   window->ClearProperty(aura::client::kModalKey);
    344   // TODO(beng): See if this function can be replaced by a call to
    345   //             FocusWindow().
    346   // Activation adjustments are handled first in the event of a disposition
    347   // changed. If an activation change is necessary, focus is reset as part of
    348   // that process so there's no point in updating focus independently.
    349   if (window == active_window_) {
    350     aura::Window* next_activatable = rules_->GetNextActivatableWindow(window);
    351     SetActiveWindow(NULL, next_activatable);
    352     if (!(active_window_ && active_window_->Contains(focused_window_)))
    353       SetFocusedWindow(next_activatable);
    354   } else if (window->Contains(focused_window_)) {
    355     // Active window isn't changing, but focused window might be.
    356     SetFocusedWindow(rules_->GetFocusableWindow(next));
    357   }
    358 }
    359 
    360 void FocusController::WindowFocusedFromInputEvent(aura::Window* window) {
    361   // Only focus |window| if it or any of its parents can be focused. Otherwise
    362   // FocusWindow() will focus the topmost window, which may not be the
    363   // currently focused one.
    364   if (rules_->CanFocusWindow(GetToplevelWindow(window)))
    365     FocusWindow(window);
    366 }
    367 
    368 }  // namespace wm
    369