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.
5 #include "ui/wm/core/shadow_controller.h"
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/aura_constants.h"
14 #include "ui/aura/env.h"
15 #include "ui/aura/env_observer.h"
16 #include "ui/aura/window.h"
17 #include "ui/aura/window_observer.h"
18 #include "ui/base/ui_base_types.h"
19 #include "ui/compositor/layer.h"
20 #include "ui/wm/core/shadow.h"
21 #include "ui/wm/core/shadow_types.h"
22 #include "ui/wm/core/window_util.h"
23 #include "ui/wm/public/activation_client.h"
31 ShadowType
GetShadowTypeFromWindow(aura::Window
* window
) {
32 switch (window
->type()) {
33 case ui::wm::WINDOW_TYPE_NORMAL
:
34 case ui::wm::WINDOW_TYPE_PANEL
:
35 case ui::wm::WINDOW_TYPE_MENU
:
36 case ui::wm::WINDOW_TYPE_TOOLTIP
:
37 return SHADOW_TYPE_RECTANGULAR
;
41 return SHADOW_TYPE_NONE
;
44 bool ShouldUseSmallShadowForWindow(aura::Window
* window
) {
45 switch (window
->type()) {
46 case ui::wm::WINDOW_TYPE_MENU
:
47 case ui::wm::WINDOW_TYPE_TOOLTIP
:
55 bool IsShadowAlwaysActive(aura::Window
* window
) {
56 return GetShadowType(window
) == SHADOW_TYPE_RECTANGULAR_ALWAYS_ACTIVE
;
59 Shadow::Style
GetShadowStyleForWindow(aura::Window
* window
) {
60 return ShouldUseSmallShadowForWindow(window
) ? Shadow::STYLE_SMALL
:
61 ((IsActiveWindow(window
) || IsShadowAlwaysActive(window
)) ?
62 Shadow::STYLE_ACTIVE
: Shadow::STYLE_INACTIVE
);
65 // Returns the shadow style to be applied to |losing_active| when it is losing
66 // active to |gaining_active|. |gaining_active| may be of a type that hides when
67 // inactive, and as such we do not want to render |losing_active| as inactive.
68 Shadow::Style
GetShadowStyleForWindowLosingActive(
69 aura::Window
* losing_active
,
70 aura::Window
* gaining_active
) {
71 if (IsShadowAlwaysActive(losing_active
))
72 return Shadow::STYLE_ACTIVE
;
74 if (gaining_active
&& aura::client::GetHideOnDeactivate(gaining_active
)) {
75 aura::Window::Windows::const_iterator it
=
76 std::find(GetTransientChildren(losing_active
).begin(),
77 GetTransientChildren(losing_active
).end(),
79 if (it
!= GetTransientChildren(losing_active
).end())
80 return Shadow::STYLE_ACTIVE
;
82 return Shadow::STYLE_INACTIVE
;
87 // ShadowController::Impl ------------------------------------------------------
89 // Real implementation of the ShadowController. ShadowController observes
90 // ActivationChangeObserver, which are per ActivationClient, where as there is
91 // only a single Impl (as it observes all window creation by way of an
93 class ShadowController::Impl
:
94 public aura::EnvObserver
,
95 public aura::WindowObserver
,
96 public base::RefCounted
<Impl
> {
98 // Returns the singleton instance, destroyed when there are no more refs.
99 static Impl
* GetInstance();
101 // aura::EnvObserver override:
102 void OnWindowInitialized(aura::Window
* window
) override
;
104 // aura::WindowObserver overrides:
105 void OnWindowPropertyChanged(aura::Window
* window
,
107 intptr_t old
) override
;
108 void OnWindowBoundsChanged(aura::Window
* window
,
109 const gfx::Rect
& old_bounds
,
110 const gfx::Rect
& new_bounds
) override
;
111 void OnWindowDestroyed(aura::Window
* window
) override
;
114 friend class base::RefCounted
<Impl
>;
115 friend class ShadowController
;
116 friend class ShadowController::TestApi
;
118 typedef std::map
<aura::Window
*, linked_ptr
<Shadow
> > WindowShadowMap
;
123 // Forwarded from ShadowController.
124 void OnWindowActivated(aura::Window
* gained_active
,
125 aura::Window
* lost_active
);
127 // Checks if |window| is visible and contains a property requesting a shadow.
128 bool ShouldShowShadowForWindow(aura::Window
* window
) const;
130 // Returns |window|'s shadow from |window_shadows_|, or NULL if no shadow
132 Shadow
* GetShadowForWindow(aura::Window
* window
);
134 // Updates the shadow styles for windows when activation changes.
135 void HandleWindowActivationChange(aura::Window
* gaining_active
,
136 aura::Window
* losing_active
);
138 // Shows or hides |window|'s shadow as needed (creating the shadow if
140 void HandlePossibleShadowVisibilityChange(aura::Window
* window
);
142 // Creates a new shadow for |window| and stores it in |window_shadows_|. The
143 // shadow's bounds are initialized and it is added to the window's layer.
144 void CreateShadowForWindow(aura::Window
* window
);
146 WindowShadowMap window_shadows_
;
148 ScopedObserver
<aura::Window
, aura::WindowObserver
> observer_manager_
;
150 static Impl
* instance_
;
152 DISALLOW_COPY_AND_ASSIGN(Impl
);
156 ShadowController::Impl
* ShadowController::Impl::instance_
= NULL
;
159 ShadowController::Impl
* ShadowController::Impl::GetInstance() {
161 instance_
= new Impl();
165 void ShadowController::Impl::OnWindowInitialized(aura::Window
* window
) {
166 observer_manager_
.Add(window
);
167 SetShadowType(window
, GetShadowTypeFromWindow(window
));
168 HandlePossibleShadowVisibilityChange(window
);
171 void ShadowController::Impl::OnWindowPropertyChanged(aura::Window
* window
,
174 if (key
== kShadowTypeKey
|| key
== aura::client::kShowStateKey
) {
175 HandlePossibleShadowVisibilityChange(window
);
180 void ShadowController::Impl::OnWindowBoundsChanged(
181 aura::Window
* window
,
182 const gfx::Rect
& old_bounds
,
183 const gfx::Rect
& new_bounds
) {
184 Shadow
* shadow
= GetShadowForWindow(window
);
186 shadow
->SetContentBounds(gfx::Rect(new_bounds
.size()));
189 void ShadowController::Impl::OnWindowDestroyed(aura::Window
* window
) {
190 window_shadows_
.erase(window
);
191 observer_manager_
.Remove(window
);
194 void ShadowController::Impl::OnWindowActivated(aura::Window
* gained_active
,
195 aura::Window
* lost_active
) {
197 Shadow
* shadow
= GetShadowForWindow(gained_active
);
198 if (shadow
&& !ShouldUseSmallShadowForWindow(gained_active
))
199 shadow
->SetStyle(Shadow::STYLE_ACTIVE
);
202 Shadow
* shadow
= GetShadowForWindow(lost_active
);
203 if (shadow
&& !ShouldUseSmallShadowForWindow(lost_active
)) {
204 shadow
->SetStyle(GetShadowStyleForWindowLosingActive(lost_active
,
210 bool ShadowController::Impl::ShouldShowShadowForWindow(
211 aura::Window
* window
) const {
212 ui::WindowShowState show_state
=
213 window
->GetProperty(aura::client::kShowStateKey
);
214 if (show_state
== ui::SHOW_STATE_FULLSCREEN
||
215 show_state
== ui::SHOW_STATE_MAXIMIZED
) {
216 return SHADOW_TYPE_NONE
;
219 const ShadowType type
= GetShadowType(window
);
221 case SHADOW_TYPE_NONE
:
223 case SHADOW_TYPE_RECTANGULAR
:
224 case SHADOW_TYPE_RECTANGULAR_ALWAYS_ACTIVE
:
227 NOTREACHED() << "Unknown shadow type " << type
;
232 Shadow
* ShadowController::Impl::GetShadowForWindow(aura::Window
* window
) {
233 WindowShadowMap::const_iterator it
= window_shadows_
.find(window
);
234 return it
!= window_shadows_
.end() ? it
->second
.get() : NULL
;
237 void ShadowController::Impl::HandlePossibleShadowVisibilityChange(
238 aura::Window
* window
) {
239 const bool should_show
= ShouldShowShadowForWindow(window
);
240 Shadow
* shadow
= GetShadowForWindow(window
);
242 shadow
->SetStyle(GetShadowStyleForWindow(window
));
243 shadow
->layer()->SetVisible(should_show
);
244 } else if (should_show
&& !shadow
) {
245 CreateShadowForWindow(window
);
249 void ShadowController::Impl::CreateShadowForWindow(aura::Window
* window
) {
250 linked_ptr
<Shadow
> shadow(new Shadow());
251 window_shadows_
.insert(make_pair(window
, shadow
));
252 shadow
->Init(GetShadowStyleForWindow(window
));
253 shadow
->SetContentBounds(gfx::Rect(window
->bounds().size()));
254 shadow
->layer()->SetVisible(ShouldShowShadowForWindow(window
));
255 window
->layer()->Add(shadow
->layer());
258 ShadowController::Impl::Impl()
259 : observer_manager_(this) {
260 aura::Env::GetInstance()->AddObserver(this);
263 ShadowController::Impl::~Impl() {
264 DCHECK_EQ(instance_
, this);
265 aura::Env::GetInstance()->RemoveObserver(this);
269 // ShadowController ------------------------------------------------------------
271 ShadowController::ShadowController(
272 aura::client::ActivationClient
* activation_client
)
273 : activation_client_(activation_client
),
274 impl_(Impl::GetInstance()) {
275 // Watch for window activation changes.
276 activation_client_
->AddObserver(this);
279 ShadowController::~ShadowController() {
280 activation_client_
->RemoveObserver(this);
283 void ShadowController::OnWindowActivated(aura::Window
* gained_active
,
284 aura::Window
* lost_active
) {
285 impl_
->OnWindowActivated(gained_active
, lost_active
);
288 // ShadowController::TestApi ---------------------------------------------------
290 Shadow
* ShadowController::TestApi::GetShadowForWindow(aura::Window
* window
) {
291 return controller_
->impl_
->GetShadowForWindow(window
);