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