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