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 23using std::make_pair; 24 25namespace views { 26namespace corewm { 27 28namespace { 29 30ShadowType 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 43bool 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. 57Shadow::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). 79class 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 142ShadowController::Impl* ShadowController::Impl::instance_ = NULL; 143 144// static 145ShadowController::Impl* ShadowController::Impl::GetInstance() { 146 if (!instance_) 147 instance_ = new Impl(); 148 return instance_; 149} 150 151void ShadowController::Impl::OnWindowInitialized(aura::Window* window) { 152 observer_manager_.Add(window); 153 SetShadowType(window, GetShadowTypeFromWindow(window)); 154 HandlePossibleShadowVisibilityChange(window); 155} 156 157void 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 166void 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 175void ShadowController::Impl::OnWindowDestroyed(aura::Window* window) { 176 window_shadows_.erase(window); 177 observer_manager_.Remove(window); 178} 179 180void 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 196bool 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 210Shadow* 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 215void 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 225void 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 236ShadowController::Impl::Impl() 237 : observer_manager_(this) { 238 aura::Env::GetInstance()->AddObserver(this); 239} 240 241ShadowController::Impl::~Impl() { 242 DCHECK_EQ(instance_, this); 243 aura::Env::GetInstance()->RemoveObserver(this); 244 instance_ = NULL; 245} 246 247// ShadowController ------------------------------------------------------------ 248 249ShadowController::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 257ShadowController::~ShadowController() { 258 activation_client_->RemoveObserver(this); 259} 260 261void ShadowController::OnWindowActivated(aura::Window* gained_active, 262 aura::Window* lost_active) { 263 impl_->OnWindowActivated(gained_active, lost_active); 264} 265 266// ShadowController::TestApi --------------------------------------------------- 267 268Shadow* ShadowController::TestApi::GetShadowForWindow(aura::Window* window) { 269 return controller_->impl_->GetShadowForWindow(window); 270} 271 272} // namespace corewm 273} // namespace views 274