Home | History | Annotate | Download | only in corewm
      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/corewm/shadow_controller.h"
      6 
      7 #include <utility>
      8 
      9 #include "base/command_line.h"
     10 #include "base/logging.h"
     11 #include "base/memory/linked_ptr.h"
     12 #include "base/scoped_observer.h"
     13 #include "ui/aura/client/activation_client.h"
     14 #include "ui/aura/env.h"
     15 #include "ui/aura/env_observer.h"
     16 #include "ui/aura/root_window.h"
     17 #include "ui/aura/window.h"
     18 #include "ui/aura/window_observer.h"
     19 #include "ui/compositor/layer.h"
     20 #include "ui/views/corewm/shadow.h"
     21 #include "ui/views/corewm/shadow_types.h"
     22 
     23 using std::make_pair;
     24 
     25 namespace views {
     26 namespace corewm {
     27 
     28 namespace {
     29 
     30 ShadowType GetShadowTypeFromWindow(aura::Window* window) {
     31   switch (window->type()) {
     32     case aura::client::WINDOW_TYPE_NORMAL:
     33     case aura::client::WINDOW_TYPE_PANEL:
     34     case aura::client::WINDOW_TYPE_MENU:
     35     case aura::client::WINDOW_TYPE_TOOLTIP:
     36       return SHADOW_TYPE_RECTANGULAR;
     37     default:
     38       break;
     39   }
     40   return SHADOW_TYPE_NONE;
     41 }
     42 
     43 bool ShouldUseSmallShadowForWindow(aura::Window* window) {
     44   switch (window->type()) {
     45     case aura::client::WINDOW_TYPE_MENU:
     46     case aura::client::WINDOW_TYPE_TOOLTIP:
     47       return true;
     48     default:
     49       break;
     50   }
     51   return false;
     52 }
     53 
     54 // Returns the shadow style to be applied to |losing_active| when it is losing
     55 // active to |gaining_active|. |gaining_active| may be of a type that hides when
     56 // inactive, and as such we do not want to render |losing_active| as inactive.
     57 Shadow::Style GetShadowStyleForWindowLosingActive(
     58     aura::Window* losing_active,
     59     aura::Window* gaining_active) {
     60   if (gaining_active && aura::client::GetHideOnDeactivate(gaining_active)) {
     61     aura::Window::Windows::const_iterator it =
     62         std::find(losing_active->transient_children().begin(),
     63                   losing_active->transient_children().end(),
     64                   gaining_active);
     65     if (it != losing_active->transient_children().end())
     66       return Shadow::STYLE_ACTIVE;
     67   }
     68   return Shadow::STYLE_INACTIVE;
     69 }
     70 
     71 }  // namespace
     72 
     73 // ShadowController::Impl ------------------------------------------------------
     74 
     75 // Real implementation of the ShadowController. ShadowController observes
     76 // ActivationChangeObserver, which are per ActivationClient, where as there is
     77 // only a single Impl (as it observes all window creation by way of an
     78 // EnvObserver).
     79 class ShadowController::Impl :
     80       public aura::EnvObserver,
     81       public aura::WindowObserver,
     82       public base::RefCounted<Impl> {
     83  public:
     84   // Returns the singleton instance, destroyed when there are no more refs.
     85   static Impl* GetInstance();
     86 
     87   // aura::EnvObserver override:
     88   virtual void OnWindowInitialized(aura::Window* window) OVERRIDE;
     89 
     90   // aura::WindowObserver overrides:
     91   virtual void OnWindowPropertyChanged(
     92       aura::Window* window, const void* key, intptr_t old) OVERRIDE;
     93   virtual void OnWindowBoundsChanged(
     94       aura::Window* window,
     95       const gfx::Rect& old_bounds,
     96       const gfx::Rect& new_bounds) OVERRIDE;
     97   virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
     98 
     99  private:
    100   friend class base::RefCounted<Impl>;
    101   friend class ShadowController;
    102   friend class ShadowController::TestApi;
    103 
    104   typedef std::map<aura::Window*, linked_ptr<Shadow> > WindowShadowMap;
    105 
    106   Impl();
    107   virtual ~Impl();
    108 
    109   // Forwarded from ShadowController.
    110   void OnWindowActivated(aura::Window* gained_active,
    111                          aura::Window* lost_active);
    112 
    113   // Checks if |window| is visible and contains a property requesting a shadow.
    114   bool ShouldShowShadowForWindow(aura::Window* window) const;
    115 
    116   // Returns |window|'s shadow from |window_shadows_|, or NULL if no shadow
    117   // exists.
    118   Shadow* GetShadowForWindow(aura::Window* window);
    119 
    120   // Updates the shadow styles for windows when activation changes.
    121   void HandleWindowActivationChange(aura::Window* gaining_active,
    122                                     aura::Window* losing_active);
    123 
    124   // Shows or hides |window|'s shadow as needed (creating the shadow if
    125   // necessary).
    126   void HandlePossibleShadowVisibilityChange(aura::Window* window);
    127 
    128   // Creates a new shadow for |window| and stores it in |window_shadows_|.  The
    129   // shadow's bounds are initialized and it is added to the window's layer.
    130   void CreateShadowForWindow(aura::Window* window);
    131 
    132   WindowShadowMap window_shadows_;
    133 
    134   ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_;
    135 
    136   static Impl* instance_;
    137 
    138   DISALLOW_COPY_AND_ASSIGN(Impl);
    139 };
    140 
    141 // static
    142 ShadowController::Impl* ShadowController::Impl::instance_ = NULL;
    143 
    144 // static
    145 ShadowController::Impl* ShadowController::Impl::GetInstance() {
    146   if (!instance_)
    147     instance_ = new Impl();
    148   return instance_;
    149 }
    150 
    151 void ShadowController::Impl::OnWindowInitialized(aura::Window* window) {
    152   observer_manager_.Add(window);
    153   SetShadowType(window, GetShadowTypeFromWindow(window));
    154   HandlePossibleShadowVisibilityChange(window);
    155 }
    156 
    157 void ShadowController::Impl::OnWindowPropertyChanged(aura::Window* window,
    158                                                      const void* key,
    159                                                      intptr_t old) {
    160   if (key == kShadowTypeKey) {
    161     HandlePossibleShadowVisibilityChange(window);
    162     return;
    163   }
    164 }
    165 
    166 void ShadowController::Impl::OnWindowBoundsChanged(
    167     aura::Window* window,
    168     const gfx::Rect& old_bounds,
    169     const gfx::Rect& new_bounds) {
    170   Shadow* shadow = GetShadowForWindow(window);
    171   if (shadow)
    172     shadow->SetContentBounds(gfx::Rect(new_bounds.size()));
    173 }
    174 
    175 void ShadowController::Impl::OnWindowDestroyed(aura::Window* window) {
    176   window_shadows_.erase(window);
    177   observer_manager_.Remove(window);
    178 }
    179 
    180 void ShadowController::Impl::OnWindowActivated(aura::Window* gained_active,
    181                                                aura::Window* lost_active) {
    182   if (gained_active) {
    183     Shadow* shadow = GetShadowForWindow(gained_active);
    184     if (shadow && !ShouldUseSmallShadowForWindow(gained_active))
    185       shadow->SetStyle(Shadow::STYLE_ACTIVE);
    186   }
    187   if (lost_active) {
    188     Shadow* shadow = GetShadowForWindow(lost_active);
    189     if (shadow && !ShouldUseSmallShadowForWindow(lost_active)) {
    190       shadow->SetStyle(GetShadowStyleForWindowLosingActive(lost_active,
    191                                                            gained_active));
    192     }
    193   }
    194 }
    195 
    196 bool ShadowController::Impl::ShouldShowShadowForWindow(
    197     aura::Window* window) const {
    198   const ShadowType type = GetShadowType(window);
    199   switch (type) {
    200     case SHADOW_TYPE_NONE:
    201       return false;
    202     case SHADOW_TYPE_RECTANGULAR:
    203       return true;
    204     default:
    205       NOTREACHED() << "Unknown shadow type " << type;
    206       return false;
    207   }
    208 }
    209 
    210 Shadow* ShadowController::Impl::GetShadowForWindow(aura::Window* window) {
    211   WindowShadowMap::const_iterator it = window_shadows_.find(window);
    212   return it != window_shadows_.end() ? it->second.get() : NULL;
    213 }
    214 
    215 void ShadowController::Impl::HandlePossibleShadowVisibilityChange(
    216     aura::Window* window) {
    217   const bool should_show = ShouldShowShadowForWindow(window);
    218   Shadow* shadow = GetShadowForWindow(window);
    219   if (shadow)
    220     shadow->layer()->SetVisible(should_show);
    221   else if (should_show && !shadow)
    222     CreateShadowForWindow(window);
    223 }
    224 
    225 void ShadowController::Impl::CreateShadowForWindow(aura::Window* window) {
    226   linked_ptr<Shadow> shadow(new Shadow());
    227   window_shadows_.insert(make_pair(window, shadow));
    228 
    229   shadow->Init(ShouldUseSmallShadowForWindow(window) ?
    230                Shadow::STYLE_SMALL : Shadow::STYLE_ACTIVE);
    231   shadow->SetContentBounds(gfx::Rect(window->bounds().size()));
    232   shadow->layer()->SetVisible(ShouldShowShadowForWindow(window));
    233   window->layer()->Add(shadow->layer());
    234 }
    235 
    236 ShadowController::Impl::Impl()
    237     : observer_manager_(this) {
    238   aura::Env::GetInstance()->AddObserver(this);
    239 }
    240 
    241 ShadowController::Impl::~Impl() {
    242   DCHECK_EQ(instance_, this);
    243   aura::Env::GetInstance()->RemoveObserver(this);
    244   instance_ = NULL;
    245 }
    246 
    247 // ShadowController ------------------------------------------------------------
    248 
    249 ShadowController::ShadowController(
    250     aura::client::ActivationClient* activation_client)
    251     : activation_client_(activation_client),
    252       impl_(Impl::GetInstance()) {
    253   // Watch for window activation changes.
    254   activation_client_->AddObserver(this);
    255 }
    256 
    257 ShadowController::~ShadowController() {
    258   activation_client_->RemoveObserver(this);
    259 }
    260 
    261 void ShadowController::OnWindowActivated(aura::Window* gained_active,
    262                                          aura::Window* lost_active) {
    263   impl_->OnWindowActivated(gained_active, lost_active);
    264 }
    265 
    266 // ShadowController::TestApi ---------------------------------------------------
    267 
    268 Shadow* ShadowController::TestApi::GetShadowForWindow(aura::Window* window) {
    269   return controller_->impl_->GetShadowForWindow(window);
    270 }
    271 
    272 }  // namespace corewm
    273 }  // namespace views
    274