Home | History | Annotate | Download | only in desktop_aura
      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/views/widget/desktop_aura/desktop_activation_client.h"
      6 
      7 #include "base/auto_reset.h"
      8 #include "base/compiler_specific.h"
      9 #include "ui/aura/client/activation_delegate.h"
     10 #include "ui/aura/client/activation_change_observer.h"
     11 #include "ui/aura/client/focus_client.h"
     12 #include "ui/aura/root_window.h"
     13 #include "ui/aura/window.h"
     14 
     15 namespace views {
     16 
     17 namespace {
     18 
     19 aura::Window* FindFocusableWindowFor(aura::Window* window) {
     20   while (window && !window->CanFocus())
     21     window = window->parent();
     22   return window;
     23 }
     24 
     25 }  // namespace
     26 
     27 DesktopActivationClient::DesktopActivationClient(aura::RootWindow* root_window)
     28     : root_window_(root_window),
     29       current_active_(NULL),
     30       updating_activation_(false),
     31       observer_manager_(this) {
     32   aura::client::GetFocusClient(root_window_)->AddObserver(this);
     33   aura::client::SetActivationClient(root_window_, this);
     34   root_window->AddPreTargetHandler(this);
     35 }
     36 
     37 DesktopActivationClient::~DesktopActivationClient() {
     38   root_window_->RemovePreTargetHandler(this);
     39   aura::client::GetFocusClient(root_window_)->RemoveObserver(this);
     40   aura::client::SetActivationClient(root_window_, NULL);
     41 }
     42 
     43 void DesktopActivationClient::AddObserver(
     44     aura::client::ActivationChangeObserver* observer) {
     45   observers_.AddObserver(observer);
     46 }
     47 
     48 void DesktopActivationClient::RemoveObserver(
     49     aura::client::ActivationChangeObserver* observer) {
     50   observers_.RemoveObserver(observer);
     51 }
     52 
     53 void DesktopActivationClient::ActivateWindow(aura::Window* window) {
     54   // Prevent recursion when called from focus.
     55   if (updating_activation_)
     56     return;
     57 
     58   base::AutoReset<bool> in_activate_window(&updating_activation_, true);
     59   // Nothing may actually have changed.
     60   if (current_active_ == window)
     61     return;
     62   // The stacking client may impose rules on what window configurations can be
     63   // activated or deactivated.
     64   if (window && !CanActivateWindow(window))
     65     return;
     66   // Switch internal focus before we change the activation. Will probably cause
     67   // recursion.
     68   if (window &&
     69       !window->Contains(aura::client::GetFocusClient(window)->
     70           GetFocusedWindow())) {
     71     aura::client::GetFocusClient(window)->FocusWindow(window);
     72   }
     73 
     74   aura::Window* old_active = current_active_;
     75   current_active_ = window;
     76   if (window && !observer_manager_.IsObserving(window))
     77     observer_manager_.Add(window);
     78 
     79   FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
     80                     observers_,
     81                     OnWindowActivated(window, old_active));
     82   aura::client::ActivationChangeObserver* observer =
     83       aura::client::GetActivationChangeObserver(old_active);
     84   if (observer)
     85     observer->OnWindowActivated(window, old_active);
     86   observer = aura::client::GetActivationChangeObserver(window);
     87   if (observer)
     88     observer->OnWindowActivated(window, old_active);
     89 }
     90 
     91 void DesktopActivationClient::DeactivateWindow(aura::Window* window) {
     92   if (window == current_active_)
     93     current_active_ = NULL;
     94 }
     95 
     96 aura::Window* DesktopActivationClient::GetActiveWindow() {
     97   return current_active_;
     98 }
     99 
    100 aura::Window* DesktopActivationClient::GetActivatableWindow(
    101     aura::Window* window) {
    102   aura::Window* parent = window->parent();
    103   aura::Window* child = window;
    104   while (parent) {
    105     if (CanActivateWindow(child))
    106       return child;
    107     // If |child| isn't activatable, but has transient parent, trace
    108     // that path instead.
    109     if (child->transient_parent())
    110       return GetActivatableWindow(child->transient_parent());
    111     parent = parent->parent();
    112     child = child->parent();
    113   }
    114   return NULL;
    115 }
    116 
    117 aura::Window* DesktopActivationClient::GetToplevelWindow(aura::Window* window) {
    118   aura::Window* parent = window->parent();
    119   aura::Window* child = window;
    120   aura::Window* root = child->GetRootWindow();
    121   while (parent) {
    122     if (parent == root)
    123       return child;
    124     parent = parent->parent();
    125     child = child->parent();
    126   }
    127   return NULL;
    128 }
    129 
    130 bool DesktopActivationClient::OnWillFocusWindow(aura::Window* window,
    131                                                 const ui::Event* event) {
    132   return CanActivateWindow(GetActivatableWindow(window));
    133 }
    134 
    135 void DesktopActivationClient::OnWindowDestroying(aura::Window* window) {
    136   if (current_active_ == window) {
    137     current_active_ = NULL;
    138     FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
    139                       observers_,
    140                       OnWindowActivated(NULL, window));
    141 
    142     // ash::ActivationController will also activate the next window here; we
    143     // don't do this because that's the desktop environment's job.
    144   }
    145   observer_manager_.Remove(window);
    146 }
    147 
    148 void DesktopActivationClient::OnWindowFocused(aura::Window* gained_focus,
    149                                               aura::Window* lost_focus) {
    150   if (gained_focus)
    151     ActivateWindow(GetActivatableWindow(gained_focus));
    152 }
    153 
    154 bool DesktopActivationClient::CanActivateWindow(aura::Window* window) const {
    155   return window &&
    156       window->IsVisible() &&
    157       (!aura::client::GetActivationDelegate(window) ||
    158        aura::client::GetActivationDelegate(window)->ShouldActivate());
    159 }
    160 
    161 void DesktopActivationClient::OnKeyEvent(ui::KeyEvent* event) {
    162 }
    163 
    164 void DesktopActivationClient::OnMouseEvent(ui::MouseEvent* event) {
    165   if (event->type() == ui::ET_MOUSE_PRESSED)
    166     FocusWindowWithEvent(event);
    167 }
    168 
    169 void DesktopActivationClient::OnScrollEvent(ui::ScrollEvent* event) {
    170 }
    171 
    172 void DesktopActivationClient::OnTouchEvent(ui::TouchEvent* event) {
    173 }
    174 
    175 void DesktopActivationClient::OnGestureEvent(ui::GestureEvent* event) {
    176   if (event->type() == ui::ET_GESTURE_BEGIN &&
    177       event->details().touch_points() == 1) {
    178     FocusWindowWithEvent(event);
    179   }
    180 }
    181 
    182 void DesktopActivationClient::FocusWindowWithEvent(const ui::Event* event) {
    183   aura::Window* window = static_cast<aura::Window*>(event->target());
    184   if (GetActiveWindow() != window) {
    185     aura::client::GetFocusClient(window)->FocusWindow(
    186         FindFocusableWindowFor(window));
    187   }
    188 }
    189 
    190 }  // namespace views
    191