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"
10 #include "base/memory/scoped_ptr.h"
11 #include "ui/aura/client/aura_constants.h"
12 #include "ui/aura/client/window_tree_client.h"
13 #include "ui/aura/test/aura_test_base.h"
14 #include "ui/aura/window.h"
15 #include "ui/aura/window_event_dispatcher.h"
16 #include "ui/compositor/layer.h"
17 #include "ui/wm/core/default_activation_client.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/core/wm_state.h"
22 #include "ui/wm/public/activation_client.h"
26 class ShadowControllerTest
: public aura::test::AuraTestBase
{
28 ShadowControllerTest() {}
29 ~ShadowControllerTest() override
{}
31 void SetUp() override
{
32 wm_state_
.reset(new wm::WMState
);
33 AuraTestBase::SetUp();
34 new wm::DefaultActivationClient(root_window());
35 aura::client::ActivationClient
* activation_client
=
36 aura::client::GetActivationClient(root_window());
37 shadow_controller_
.reset(new ShadowController(activation_client
));
39 void TearDown() override
{
40 shadow_controller_
.reset();
41 AuraTestBase::TearDown();
46 ShadowController
* shadow_controller() { return shadow_controller_
.get(); }
48 void ActivateWindow(aura::Window
* window
) {
50 DCHECK(window
->GetRootWindow());
51 aura::client::GetActivationClient(window
->GetRootWindow())->ActivateWindow(
56 scoped_ptr
<ShadowController
> shadow_controller_
;
57 scoped_ptr
<wm::WMState
> wm_state_
;
59 DISALLOW_COPY_AND_ASSIGN(ShadowControllerTest
);
62 // Tests that various methods in Window update the Shadow object as expected.
63 TEST_F(ShadowControllerTest
, Shadow
) {
64 scoped_ptr
<aura::Window
> window(new aura::Window(NULL
));
65 window
->SetType(ui::wm::WINDOW_TYPE_NORMAL
);
66 window
->Init(aura::WINDOW_LAYER_TEXTURED
);
67 ParentWindow(window
.get());
69 // We should create the shadow before the window is visible (the shadow's
70 // layer won't get drawn yet since it's a child of the window's layer).
71 ShadowController::TestApi
api(shadow_controller());
72 const Shadow
* shadow
= api
.GetShadowForWindow(window
.get());
73 ASSERT_TRUE(shadow
!= NULL
);
74 EXPECT_TRUE(shadow
->layer()->visible());
76 // The shadow should remain visible after window visibility changes.
78 EXPECT_TRUE(shadow
->layer()->visible());
80 EXPECT_TRUE(shadow
->layer()->visible());
82 // If the shadow is disabled, it should be hidden.
83 SetShadowType(window
.get(), SHADOW_TYPE_NONE
);
85 EXPECT_FALSE(shadow
->layer()->visible());
86 SetShadowType(window
.get(), SHADOW_TYPE_RECTANGULAR
);
87 EXPECT_TRUE(shadow
->layer()->visible());
89 // The shadow's layer should be a child of the window's layer.
90 EXPECT_EQ(window
->layer(), shadow
->layer()->parent());
92 window
->parent()->RemoveChild(window
.get());
93 aura::Window
* window_ptr
= window
.get();
95 EXPECT_TRUE(api
.GetShadowForWindow(window_ptr
) == NULL
);
98 // Tests that the window's shadow's bounds are updated correctly.
99 TEST_F(ShadowControllerTest
, ShadowBounds
) {
100 scoped_ptr
<aura::Window
> window(new aura::Window(NULL
));
101 window
->SetType(ui::wm::WINDOW_TYPE_NORMAL
);
102 window
->Init(aura::WINDOW_LAYER_TEXTURED
);
103 ParentWindow(window
.get());
106 const gfx::Rect
kOldBounds(20, 30, 400, 300);
107 window
->SetBounds(kOldBounds
);
109 // When the shadow is first created, it should use the window's size (but
110 // remain at the origin, since it's a child of the window's layer).
111 SetShadowType(window
.get(), SHADOW_TYPE_RECTANGULAR
);
112 ShadowController::TestApi
api(shadow_controller());
113 const Shadow
* shadow
= api
.GetShadowForWindow(window
.get());
114 ASSERT_TRUE(shadow
!= NULL
);
115 EXPECT_EQ(gfx::Rect(kOldBounds
.size()).ToString(),
116 shadow
->content_bounds().ToString());
118 // When we change the window's bounds, the shadow's should be updated too.
119 gfx::Rect
kNewBounds(50, 60, 500, 400);
120 window
->SetBounds(kNewBounds
);
121 EXPECT_EQ(gfx::Rect(kNewBounds
.size()).ToString(),
122 shadow
->content_bounds().ToString());
125 // Tests that activating a window changes the shadow style.
126 TEST_F(ShadowControllerTest
, ShadowStyle
) {
127 ShadowController::TestApi
api(shadow_controller());
129 scoped_ptr
<aura::Window
> window1(new aura::Window(NULL
));
130 window1
->SetType(ui::wm::WINDOW_TYPE_NORMAL
);
131 window1
->Init(aura::WINDOW_LAYER_TEXTURED
);
132 ParentWindow(window1
.get());
133 window1
->SetBounds(gfx::Rect(10, 20, 300, 400));
135 ActivateWindow(window1
.get());
137 // window1 is active, so style should have active appearance.
138 Shadow
* shadow1
= api
.GetShadowForWindow(window1
.get());
139 ASSERT_TRUE(shadow1
!= NULL
);
140 EXPECT_EQ(Shadow::STYLE_ACTIVE
, shadow1
->style());
142 // Create another window and activate it.
143 scoped_ptr
<aura::Window
> window2(new aura::Window(NULL
));
144 window2
->SetType(ui::wm::WINDOW_TYPE_NORMAL
);
145 window2
->Init(aura::WINDOW_LAYER_TEXTURED
);
146 ParentWindow(window2
.get());
147 window2
->SetBounds(gfx::Rect(11, 21, 301, 401));
149 ActivateWindow(window2
.get());
151 // window1 is now inactive, so shadow should go inactive.
152 Shadow
* shadow2
= api
.GetShadowForWindow(window2
.get());
153 ASSERT_TRUE(shadow2
!= NULL
);
154 EXPECT_EQ(Shadow::STYLE_INACTIVE
, shadow1
->style());
155 EXPECT_EQ(Shadow::STYLE_ACTIVE
, shadow2
->style());
158 // Tests that shadow gets updated when the window show state chagnes.
159 TEST_F(ShadowControllerTest
, ShowState
) {
160 ShadowController::TestApi
api(shadow_controller());
162 scoped_ptr
<aura::Window
> window(new aura::Window(NULL
));
163 window
->SetType(ui::wm::WINDOW_TYPE_NORMAL
);
164 window
->Init(aura::WINDOW_LAYER_TEXTURED
);
165 ParentWindow(window
.get());
168 Shadow
* shadow
= api
.GetShadowForWindow(window
.get());
169 ASSERT_TRUE(shadow
!= NULL
);
170 EXPECT_EQ(Shadow::STYLE_INACTIVE
, shadow
->style());
172 window
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MAXIMIZED
);
173 EXPECT_FALSE(shadow
->layer()->visible());
175 window
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_NORMAL
);
176 EXPECT_TRUE(shadow
->layer()->visible());
178 window
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_FULLSCREEN
);
179 EXPECT_FALSE(shadow
->layer()->visible());
182 // Tests that we use smaller shadows for tooltips and menus.
183 TEST_F(ShadowControllerTest
, SmallShadowsForTooltipsAndMenus
) {
184 ShadowController::TestApi
api(shadow_controller());
186 scoped_ptr
<aura::Window
> tooltip_window(new aura::Window(NULL
));
187 tooltip_window
->SetType(ui::wm::WINDOW_TYPE_TOOLTIP
);
188 tooltip_window
->Init(aura::WINDOW_LAYER_TEXTURED
);
189 ParentWindow(tooltip_window
.get());
190 tooltip_window
->SetBounds(gfx::Rect(10, 20, 300, 400));
191 tooltip_window
->Show();
193 Shadow
* tooltip_shadow
= api
.GetShadowForWindow(tooltip_window
.get());
194 ASSERT_TRUE(tooltip_shadow
!= NULL
);
195 EXPECT_EQ(Shadow::STYLE_SMALL
, tooltip_shadow
->style());
197 scoped_ptr
<aura::Window
> menu_window(new aura::Window(NULL
));
198 menu_window
->SetType(ui::wm::WINDOW_TYPE_MENU
);
199 menu_window
->Init(aura::WINDOW_LAYER_TEXTURED
);
200 ParentWindow(menu_window
.get());
201 menu_window
->SetBounds(gfx::Rect(10, 20, 300, 400));
204 Shadow
* menu_shadow
= api
.GetShadowForWindow(tooltip_window
.get());
205 ASSERT_TRUE(menu_shadow
!= NULL
);
206 EXPECT_EQ(Shadow::STYLE_SMALL
, menu_shadow
->style());
209 // http://crbug.com/120210 - transient parents of certain types of transients
210 // should not lose their shadow when they lose activation to the transient.
211 TEST_F(ShadowControllerTest
, TransientParentKeepsActiveShadow
) {
212 ShadowController::TestApi
api(shadow_controller());
214 scoped_ptr
<aura::Window
> window1(new aura::Window(NULL
));
215 window1
->SetType(ui::wm::WINDOW_TYPE_NORMAL
);
216 window1
->Init(aura::WINDOW_LAYER_TEXTURED
);
217 ParentWindow(window1
.get());
218 window1
->SetBounds(gfx::Rect(10, 20, 300, 400));
220 ActivateWindow(window1
.get());
222 // window1 is active, so style should have active appearance.
223 Shadow
* shadow1
= api
.GetShadowForWindow(window1
.get());
224 ASSERT_TRUE(shadow1
!= NULL
);
225 EXPECT_EQ(Shadow::STYLE_ACTIVE
, shadow1
->style());
227 // Create a window that is transient to window1, and that has the 'hide on
228 // deactivate' property set. Upon activation, window1 should still have an
230 scoped_ptr
<aura::Window
> window2(new aura::Window(NULL
));
231 window2
->SetType(ui::wm::WINDOW_TYPE_NORMAL
);
232 window2
->Init(aura::WINDOW_LAYER_TEXTURED
);
233 ParentWindow(window2
.get());
234 window2
->SetBounds(gfx::Rect(11, 21, 301, 401));
235 AddTransientChild(window1
.get(), window2
.get());
236 aura::client::SetHideOnDeactivate(window2
.get(), true);
238 ActivateWindow(window2
.get());
240 // window1 is now inactive, but its shadow should still appear active.
241 EXPECT_EQ(Shadow::STYLE_ACTIVE
, shadow1
->style());