1 // Copyright 2014 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 "ash/wm/window_state.h"
7 #include "ash/screen_util.h"
9 #include "ash/test/ash_test_base.h"
10 #include "ash/wm/window_state.h"
11 #include "ash/wm/wm_event.h"
12 #include "ui/aura/test/test_window_delegate.h"
13 #include "ui/aura/window.h"
19 class AlwaysMaximizeTestState
: public WindowState::State
{
21 explicit AlwaysMaximizeTestState(WindowStateType initial_state_type
)
22 : state_type_(initial_state_type
) {}
23 virtual ~AlwaysMaximizeTestState() {}
25 // WindowState::State overrides:
26 virtual void OnWMEvent(WindowState
* window_state
,
27 const WMEvent
* event
) OVERRIDE
{
28 // We don't do anything here.
30 virtual WindowStateType
GetType() const OVERRIDE
{
33 virtual void AttachState(
34 WindowState
* window_state
,
35 WindowState::State
* previous_state
) OVERRIDE
{
36 // We always maximize.
37 if (state_type_
!= WINDOW_STATE_TYPE_MAXIMIZED
) {
38 window_state
->Maximize();
39 state_type_
= WINDOW_STATE_TYPE_MAXIMIZED
;
42 virtual void DetachState(WindowState
* window_state
) OVERRIDE
{}
45 WindowStateType state_type_
;
47 DISALLOW_COPY_AND_ASSIGN(AlwaysMaximizeTestState
);
52 typedef test::AshTestBase WindowStateTest
;
54 // Test that a window gets properly snapped to the display's edges in a
55 // multi monitor environment.
56 TEST_F(WindowStateTest
, SnapWindowBasic
) {
57 if (!SupportsMultipleDisplays())
60 UpdateDisplay("0+0-500x400, 0+500-600x400");
61 const gfx::Rect kPrimaryDisplayWorkAreaBounds
=
62 ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
63 const gfx::Rect kSecondaryDisplayWorkAreaBounds
=
64 ScreenUtil::GetSecondaryDisplay().work_area();
66 scoped_ptr
<aura::Window
> window(
67 CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
68 WindowState
* window_state
= GetWindowState(window
.get());
69 const WMEvent
snap_left(WM_EVENT_SNAP_LEFT
);
70 window_state
->OnWMEvent(&snap_left
);
71 gfx::Rect expected
= gfx::Rect(
72 kPrimaryDisplayWorkAreaBounds
.x(),
73 kPrimaryDisplayWorkAreaBounds
.y(),
74 kPrimaryDisplayWorkAreaBounds
.width() / 2,
75 kPrimaryDisplayWorkAreaBounds
.height());
76 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
78 const WMEvent
snap_right(WM_EVENT_SNAP_RIGHT
);
79 window_state
->OnWMEvent(&snap_right
);
80 expected
.set_x(kPrimaryDisplayWorkAreaBounds
.right() - expected
.width());
81 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
83 // Move the window to the secondary display.
84 window
->SetBoundsInScreen(gfx::Rect(600, 0, 100, 100),
85 ScreenUtil::GetSecondaryDisplay());
87 window_state
->OnWMEvent(&snap_right
);
89 kSecondaryDisplayWorkAreaBounds
.x() +
90 kSecondaryDisplayWorkAreaBounds
.width() / 2,
91 kSecondaryDisplayWorkAreaBounds
.y(),
92 kSecondaryDisplayWorkAreaBounds
.width() / 2,
93 kSecondaryDisplayWorkAreaBounds
.height());
94 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
96 window_state
->OnWMEvent(&snap_left
);
97 expected
.set_x(kSecondaryDisplayWorkAreaBounds
.x());
98 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
101 // Test how the minimum and maximum size specified by the aura::WindowDelegate
103 TEST_F(WindowStateTest
, SnapWindowMinimumSize
) {
104 if (!SupportsHostWindowResize())
107 UpdateDisplay("0+0-600x900");
108 const gfx::Rect kWorkAreaBounds
=
109 ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
111 aura::test::TestWindowDelegate delegate
;
112 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithDelegate(
113 &delegate
, -1, gfx::Rect(0, 100, kWorkAreaBounds
.width() - 1, 100)));
115 // It should be possible to snap a window with a minimum size.
116 delegate
.set_minimum_size(gfx::Size(kWorkAreaBounds
.width() - 1, 0));
117 WindowState
* window_state
= GetWindowState(window
.get());
118 EXPECT_TRUE(window_state
->CanSnap());
119 const WMEvent
snap_right(WM_EVENT_SNAP_RIGHT
);
120 window_state
->OnWMEvent(&snap_right
);
121 gfx::Rect expected
= gfx::Rect(kWorkAreaBounds
.x() + 1,
123 kWorkAreaBounds
.width() - 1,
124 kWorkAreaBounds
.height());
125 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
127 // It should not be possible to snap a window with a maximum size.
128 delegate
.set_minimum_size(gfx::Size());
129 delegate
.set_maximum_size(gfx::Size(kWorkAreaBounds
.width() - 1, INT_MAX
));
130 EXPECT_FALSE(window_state
->CanSnap());
133 // Test that the minimum size specified by aura::WindowDelegate gets respected.
134 TEST_F(WindowStateTest
, TestRespectMinimumSize
) {
135 if (!SupportsHostWindowResize())
138 UpdateDisplay("0+0-1024x768");
140 aura::test::TestWindowDelegate delegate
;
141 const gfx::Size
minimum_size(gfx::Size(500, 300));
142 delegate
.set_minimum_size(minimum_size
);
144 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithDelegate(
145 &delegate
, -1, gfx::Rect(0, 100, 100, 100)));
147 // Check that the window has the correct minimum size.
148 EXPECT_EQ(minimum_size
.ToString(), window
->bounds().size().ToString());
150 // Set the size to something bigger - that should work.
151 gfx::Rect
bigger_bounds(700, 500, 700, 500);
152 window
->SetBounds(bigger_bounds
);
153 EXPECT_EQ(bigger_bounds
.ToString(), window
->bounds().ToString());
155 // Set the size to something smaller - that should only resize to the smallest
157 gfx::Rect
smaller_bounds(700, 500, 100, 100);
158 window
->SetBounds(smaller_bounds
);
159 EXPECT_EQ(minimum_size
.ToString(), window
->bounds().size().ToString());
162 // Test that the minimum window size specified by aura::WindowDelegate does not
163 // exceed the screen size.
164 TEST_F(WindowStateTest
, TestIgnoreTooBigMinimumSize
) {
165 if (!SupportsHostWindowResize())
168 UpdateDisplay("0+0-1024x768");
169 const gfx::Size work_area_size
=
170 ash::Shell::GetScreen()->GetPrimaryDisplay().work_area().size();
171 const gfx::Size
illegal_size(1280, 960);
172 const gfx::Rect
illegal_bounds(gfx::Point(0, 0), illegal_size
);
174 aura::test::TestWindowDelegate delegate
;
175 const gfx::Size
minimum_size(illegal_size
);
176 delegate
.set_minimum_size(minimum_size
);
178 // The creation should force the window to respect the screen size.
179 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithDelegate(
180 &delegate
, -1, illegal_bounds
));
181 EXPECT_EQ(work_area_size
.ToString(), window
->bounds().size().ToString());
183 // Trying to set the size to something bigger then the screen size should be
185 window
->SetBounds(illegal_bounds
);
186 EXPECT_EQ(work_area_size
.ToString(), window
->bounds().size().ToString());
188 // Maximizing the window should not allow it to go bigger than that either.
189 WindowState
* window_state
= GetWindowState(window
.get());
190 window_state
->Maximize();
191 EXPECT_EQ(work_area_size
.ToString(), window
->bounds().size().ToString());
194 // Test that setting the bounds of a snapped window keeps its snapped.
195 TEST_F(WindowStateTest
, SnapWindowSetBounds
) {
196 if (!SupportsHostWindowResize())
199 UpdateDisplay("0+0-900x600");
200 const gfx::Rect kWorkAreaBounds
=
201 ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
203 scoped_ptr
<aura::Window
> window(
204 CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
205 WindowState
* window_state
= GetWindowState(window
.get());
206 const WMEvent
snap_left(WM_EVENT_SNAP_LEFT
);
207 window_state
->OnWMEvent(&snap_left
);
208 EXPECT_EQ(WINDOW_STATE_TYPE_LEFT_SNAPPED
, window_state
->GetStateType());
209 gfx::Rect expected
= gfx::Rect(kWorkAreaBounds
.x(),
211 kWorkAreaBounds
.width() / 2,
212 kWorkAreaBounds
.height());
213 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
215 // Snapped windows can have any width.
216 expected
.set_width(500);
217 window
->SetBounds(gfx::Rect(10, 10, 500, 300));
218 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
219 EXPECT_EQ(WINDOW_STATE_TYPE_LEFT_SNAPPED
, window_state
->GetStateType());
222 // Test that snapping left/right preserves the restore bounds.
223 TEST_F(WindowStateTest
, RestoreBounds
) {
224 scoped_ptr
<aura::Window
> window(
225 CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
226 WindowState
* window_state
= GetWindowState(window
.get());
228 EXPECT_TRUE(window_state
->IsNormalStateType());
230 // 1) Start with restored window with restore bounds set.
231 gfx::Rect restore_bounds
= window
->GetBoundsInScreen();
232 restore_bounds
.set_width(restore_bounds
.width() + 1);
233 window_state
->SetRestoreBoundsInScreen(restore_bounds
);
234 const WMEvent
snap_left(WM_EVENT_SNAP_LEFT
);
235 window_state
->OnWMEvent(&snap_left
);
236 const WMEvent
snap_right(WM_EVENT_SNAP_RIGHT
);
237 window_state
->OnWMEvent(&snap_right
);
238 EXPECT_NE(restore_bounds
.ToString(), window
->GetBoundsInScreen().ToString());
239 EXPECT_EQ(restore_bounds
.ToString(),
240 window_state
->GetRestoreBoundsInScreen().ToString());
241 window_state
->Restore();
242 EXPECT_EQ(restore_bounds
.ToString(), window
->GetBoundsInScreen().ToString());
244 // 2) Start with restored bounds set as a result of maximizing the window.
245 window_state
->Maximize();
246 gfx::Rect maximized_bounds
= window
->GetBoundsInScreen();
247 EXPECT_NE(maximized_bounds
.ToString(), restore_bounds
.ToString());
248 EXPECT_EQ(restore_bounds
.ToString(),
249 window_state
->GetRestoreBoundsInScreen().ToString());
251 window_state
->OnWMEvent(&snap_left
);
252 EXPECT_NE(restore_bounds
.ToString(), window
->GetBoundsInScreen().ToString());
253 EXPECT_NE(maximized_bounds
.ToString(),
254 window
->GetBoundsInScreen().ToString());
255 EXPECT_EQ(restore_bounds
.ToString(),
256 window_state
->GetRestoreBoundsInScreen().ToString());
258 window_state
->Restore();
259 EXPECT_EQ(restore_bounds
.ToString(), window
->GetBoundsInScreen().ToString());
262 // Test that maximizing an auto managed window, then snapping it puts the window
263 // at the snapped bounds and not at the auto-managed (centered) bounds.
264 TEST_F(WindowStateTest
, AutoManaged
) {
265 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithId(0));
266 WindowState
* window_state
= GetWindowState(window
.get());
267 window_state
->set_window_position_managed(true);
269 window
->SetBounds(gfx::Rect(100, 100, 100, 100));
272 window_state
->Maximize();
273 const WMEvent
snap_right(WM_EVENT_SNAP_RIGHT
);
274 window_state
->OnWMEvent(&snap_right
);
276 const gfx::Rect kWorkAreaBounds
=
277 ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
278 gfx::Rect
expected_snapped_bounds(
279 kWorkAreaBounds
.x() + kWorkAreaBounds
.width() / 2,
281 kWorkAreaBounds
.width() / 2,
282 kWorkAreaBounds
.height());
283 EXPECT_EQ(expected_snapped_bounds
.ToString(),
284 window
->GetBoundsInScreen().ToString());
286 // The window should still be auto managed despite being right maximized.
287 EXPECT_TRUE(window_state
->window_position_managed());
290 // Test that the replacement of a State object works as expected.
291 TEST_F(WindowStateTest
, SimpleStateSwap
) {
292 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithId(0));
293 WindowState
* window_state
= GetWindowState(window
.get());
294 EXPECT_FALSE(window_state
->IsMaximized());
295 window_state
->SetStateObject(
296 scoped_ptr
<WindowState::State
> (new AlwaysMaximizeTestState(
297 window_state
->GetStateType())));
298 EXPECT_TRUE(window_state
->IsMaximized());
301 // Test that the replacement of a state object, following a restore with the
302 // original one restores the window to its original state.
303 TEST_F(WindowStateTest
, StateSwapRestore
) {
304 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithId(0));
305 WindowState
* window_state
= GetWindowState(window
.get());
306 EXPECT_FALSE(window_state
->IsMaximized());
307 scoped_ptr
<WindowState::State
> old(window_state
->SetStateObject(
308 scoped_ptr
<WindowState::State
> (new AlwaysMaximizeTestState(
309 window_state
->GetStateType()))).Pass());
310 EXPECT_TRUE(window_state
->IsMaximized());
311 window_state
->SetStateObject(old
.Pass());
312 EXPECT_FALSE(window_state
->IsMaximized());
315 // TODO(skuhne): Add more unit test to verify the correctness for the restore