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/client/aura_constants.h"
13 #include "ui/aura/test/test_window_delegate.h"
14 #include "ui/aura/window.h"
20 class AlwaysMaximizeTestState
: public WindowState::State
{
22 explicit AlwaysMaximizeTestState(WindowStateType initial_state_type
)
23 : state_type_(initial_state_type
) {}
24 ~AlwaysMaximizeTestState() override
{}
26 // WindowState::State overrides:
27 void OnWMEvent(WindowState
* window_state
, const WMEvent
* event
) override
{
28 // We don't do anything here.
30 WindowStateType
GetType() const override
{ return state_type_
; }
31 void AttachState(WindowState
* window_state
,
32 WindowState::State
* previous_state
) override
{
33 // We always maximize.
34 if (state_type_
!= WINDOW_STATE_TYPE_MAXIMIZED
) {
35 window_state
->Maximize();
36 state_type_
= WINDOW_STATE_TYPE_MAXIMIZED
;
39 void DetachState(WindowState
* window_state
) override
{}
42 WindowStateType state_type_
;
44 DISALLOW_COPY_AND_ASSIGN(AlwaysMaximizeTestState
);
49 typedef test::AshTestBase WindowStateTest
;
51 // Test that a window gets properly snapped to the display's edges in a
52 // multi monitor environment.
53 TEST_F(WindowStateTest
, SnapWindowBasic
) {
54 if (!SupportsMultipleDisplays())
57 UpdateDisplay("0+0-500x400, 0+500-600x400");
58 const gfx::Rect kPrimaryDisplayWorkAreaBounds
=
59 ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
60 const gfx::Rect kSecondaryDisplayWorkAreaBounds
=
61 ScreenUtil::GetSecondaryDisplay().work_area();
63 scoped_ptr
<aura::Window
> window(
64 CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
65 WindowState
* window_state
= GetWindowState(window
.get());
66 const WMEvent
snap_left(WM_EVENT_SNAP_LEFT
);
67 window_state
->OnWMEvent(&snap_left
);
68 gfx::Rect expected
= gfx::Rect(
69 kPrimaryDisplayWorkAreaBounds
.x(),
70 kPrimaryDisplayWorkAreaBounds
.y(),
71 kPrimaryDisplayWorkAreaBounds
.width() / 2,
72 kPrimaryDisplayWorkAreaBounds
.height());
73 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
75 const WMEvent
snap_right(WM_EVENT_SNAP_RIGHT
);
76 window_state
->OnWMEvent(&snap_right
);
77 expected
.set_x(kPrimaryDisplayWorkAreaBounds
.right() - expected
.width());
78 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
80 // Move the window to the secondary display.
81 window
->SetBoundsInScreen(gfx::Rect(600, 0, 100, 100),
82 ScreenUtil::GetSecondaryDisplay());
84 window_state
->OnWMEvent(&snap_right
);
86 kSecondaryDisplayWorkAreaBounds
.x() +
87 kSecondaryDisplayWorkAreaBounds
.width() / 2,
88 kSecondaryDisplayWorkAreaBounds
.y(),
89 kSecondaryDisplayWorkAreaBounds
.width() / 2,
90 kSecondaryDisplayWorkAreaBounds
.height());
91 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
93 window_state
->OnWMEvent(&snap_left
);
94 expected
.set_x(kSecondaryDisplayWorkAreaBounds
.x());
95 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
98 // Test how the minimum and maximum size specified by the aura::WindowDelegate
100 TEST_F(WindowStateTest
, SnapWindowMinimumSize
) {
101 if (!SupportsHostWindowResize())
104 UpdateDisplay("0+0-600x900");
105 const gfx::Rect kWorkAreaBounds
=
106 ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
108 aura::test::TestWindowDelegate delegate
;
109 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithDelegate(
110 &delegate
, -1, gfx::Rect(0, 100, kWorkAreaBounds
.width() - 1, 100)));
112 // It should be possible to snap a window with a minimum size.
113 delegate
.set_minimum_size(gfx::Size(kWorkAreaBounds
.width() - 1, 0));
114 WindowState
* window_state
= GetWindowState(window
.get());
115 EXPECT_TRUE(window_state
->CanSnap());
116 const WMEvent
snap_right(WM_EVENT_SNAP_RIGHT
);
117 window_state
->OnWMEvent(&snap_right
);
118 gfx::Rect expected
= gfx::Rect(kWorkAreaBounds
.x() + 1,
120 kWorkAreaBounds
.width() - 1,
121 kWorkAreaBounds
.height());
122 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
124 // It should not be possible to snap a window with a maximum size, or if it
125 // cannot be maximized.
126 delegate
.set_maximum_size(gfx::Size(kWorkAreaBounds
.width() - 1, 0));
127 EXPECT_FALSE(window_state
->CanSnap());
128 delegate
.set_maximum_size(gfx::Size(0, kWorkAreaBounds
.height() - 1));
129 EXPECT_FALSE(window_state
->CanSnap());
130 delegate
.set_maximum_size(gfx::Size());
131 window
->SetProperty(aura::client::kCanMaximizeKey
, false);
132 EXPECT_FALSE(window_state
->CanSnap());
135 // Test that the minimum size specified by aura::WindowDelegate gets respected.
136 TEST_F(WindowStateTest
, TestRespectMinimumSize
) {
137 if (!SupportsHostWindowResize())
140 UpdateDisplay("0+0-1024x768");
142 aura::test::TestWindowDelegate delegate
;
143 const gfx::Size
minimum_size(gfx::Size(500, 300));
144 delegate
.set_minimum_size(minimum_size
);
146 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithDelegate(
147 &delegate
, -1, gfx::Rect(0, 100, 100, 100)));
149 // Check that the window has the correct minimum size.
150 EXPECT_EQ(minimum_size
.ToString(), window
->bounds().size().ToString());
152 // Set the size to something bigger - that should work.
153 gfx::Rect
bigger_bounds(700, 500, 700, 500);
154 window
->SetBounds(bigger_bounds
);
155 EXPECT_EQ(bigger_bounds
.ToString(), window
->bounds().ToString());
157 // Set the size to something smaller - that should only resize to the smallest
159 gfx::Rect
smaller_bounds(700, 500, 100, 100);
160 window
->SetBounds(smaller_bounds
);
161 EXPECT_EQ(minimum_size
.ToString(), window
->bounds().size().ToString());
164 // Test that the minimum window size specified by aura::WindowDelegate does not
165 // exceed the screen size.
166 TEST_F(WindowStateTest
, TestIgnoreTooBigMinimumSize
) {
167 if (!SupportsHostWindowResize())
170 UpdateDisplay("0+0-1024x768");
171 const gfx::Size work_area_size
=
172 ash::Shell::GetScreen()->GetPrimaryDisplay().work_area().size();
173 const gfx::Size
illegal_size(1280, 960);
174 const gfx::Rect
illegal_bounds(gfx::Point(0, 0), illegal_size
);
176 aura::test::TestWindowDelegate delegate
;
177 const gfx::Size
minimum_size(illegal_size
);
178 delegate
.set_minimum_size(minimum_size
);
180 // The creation should force the window to respect the screen size.
181 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithDelegate(
182 &delegate
, -1, illegal_bounds
));
183 EXPECT_EQ(work_area_size
.ToString(), window
->bounds().size().ToString());
185 // Trying to set the size to something bigger then the screen size should be
187 window
->SetBounds(illegal_bounds
);
188 EXPECT_EQ(work_area_size
.ToString(), window
->bounds().size().ToString());
190 // Maximizing the window should not allow it to go bigger than that either.
191 WindowState
* window_state
= GetWindowState(window
.get());
192 window_state
->Maximize();
193 EXPECT_EQ(work_area_size
.ToString(), window
->bounds().size().ToString());
196 // Test that setting the bounds of a snapped window keeps its snapped.
197 TEST_F(WindowStateTest
, SnapWindowSetBounds
) {
198 if (!SupportsHostWindowResize())
201 UpdateDisplay("0+0-900x600");
202 const gfx::Rect kWorkAreaBounds
=
203 ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
205 scoped_ptr
<aura::Window
> window(
206 CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
207 WindowState
* window_state
= GetWindowState(window
.get());
208 const WMEvent
snap_left(WM_EVENT_SNAP_LEFT
);
209 window_state
->OnWMEvent(&snap_left
);
210 EXPECT_EQ(WINDOW_STATE_TYPE_LEFT_SNAPPED
, window_state
->GetStateType());
211 gfx::Rect expected
= gfx::Rect(kWorkAreaBounds
.x(),
213 kWorkAreaBounds
.width() / 2,
214 kWorkAreaBounds
.height());
215 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
217 // Snapped windows can have any width.
218 expected
.set_width(500);
219 window
->SetBounds(gfx::Rect(10, 10, 500, 300));
220 EXPECT_EQ(expected
.ToString(), window
->GetBoundsInScreen().ToString());
221 EXPECT_EQ(WINDOW_STATE_TYPE_LEFT_SNAPPED
, window_state
->GetStateType());
224 // Test that snapping left/right preserves the restore bounds.
225 TEST_F(WindowStateTest
, RestoreBounds
) {
226 scoped_ptr
<aura::Window
> window(
227 CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
228 WindowState
* window_state
= GetWindowState(window
.get());
230 EXPECT_TRUE(window_state
->IsNormalStateType());
232 // 1) Start with restored window with restore bounds set.
233 gfx::Rect restore_bounds
= window
->GetBoundsInScreen();
234 restore_bounds
.set_width(restore_bounds
.width() + 1);
235 window_state
->SetRestoreBoundsInScreen(restore_bounds
);
236 const WMEvent
snap_left(WM_EVENT_SNAP_LEFT
);
237 window_state
->OnWMEvent(&snap_left
);
238 const WMEvent
snap_right(WM_EVENT_SNAP_RIGHT
);
239 window_state
->OnWMEvent(&snap_right
);
240 EXPECT_NE(restore_bounds
.ToString(), window
->GetBoundsInScreen().ToString());
241 EXPECT_EQ(restore_bounds
.ToString(),
242 window_state
->GetRestoreBoundsInScreen().ToString());
243 window_state
->Restore();
244 EXPECT_EQ(restore_bounds
.ToString(), window
->GetBoundsInScreen().ToString());
246 // 2) Start with restored bounds set as a result of maximizing the window.
247 window_state
->Maximize();
248 gfx::Rect maximized_bounds
= window
->GetBoundsInScreen();
249 EXPECT_NE(maximized_bounds
.ToString(), restore_bounds
.ToString());
250 EXPECT_EQ(restore_bounds
.ToString(),
251 window_state
->GetRestoreBoundsInScreen().ToString());
253 window_state
->OnWMEvent(&snap_left
);
254 EXPECT_NE(restore_bounds
.ToString(), window
->GetBoundsInScreen().ToString());
255 EXPECT_NE(maximized_bounds
.ToString(),
256 window
->GetBoundsInScreen().ToString());
257 EXPECT_EQ(restore_bounds
.ToString(),
258 window_state
->GetRestoreBoundsInScreen().ToString());
260 window_state
->Restore();
261 EXPECT_EQ(restore_bounds
.ToString(), window
->GetBoundsInScreen().ToString());
264 // Test that maximizing an auto managed window, then snapping it puts the window
265 // at the snapped bounds and not at the auto-managed (centered) bounds.
266 TEST_F(WindowStateTest
, AutoManaged
) {
267 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithId(0));
268 WindowState
* window_state
= GetWindowState(window
.get());
269 window_state
->set_window_position_managed(true);
271 window
->SetBounds(gfx::Rect(100, 100, 100, 100));
274 window_state
->Maximize();
275 const WMEvent
snap_right(WM_EVENT_SNAP_RIGHT
);
276 window_state
->OnWMEvent(&snap_right
);
278 const gfx::Rect kWorkAreaBounds
=
279 ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
280 gfx::Rect
expected_snapped_bounds(
281 kWorkAreaBounds
.x() + kWorkAreaBounds
.width() / 2,
283 kWorkAreaBounds
.width() / 2,
284 kWorkAreaBounds
.height());
285 EXPECT_EQ(expected_snapped_bounds
.ToString(),
286 window
->GetBoundsInScreen().ToString());
288 // The window should still be auto managed despite being right maximized.
289 EXPECT_TRUE(window_state
->window_position_managed());
292 // Test that the replacement of a State object works as expected.
293 TEST_F(WindowStateTest
, SimpleStateSwap
) {
294 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithId(0));
295 WindowState
* window_state
= GetWindowState(window
.get());
296 EXPECT_FALSE(window_state
->IsMaximized());
297 window_state
->SetStateObject(
298 scoped_ptr
<WindowState::State
> (new AlwaysMaximizeTestState(
299 window_state
->GetStateType())));
300 EXPECT_TRUE(window_state
->IsMaximized());
303 // Test that the replacement of a state object, following a restore with the
304 // original one restores the window to its original state.
305 TEST_F(WindowStateTest
, StateSwapRestore
) {
306 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithId(0));
307 WindowState
* window_state
= GetWindowState(window
.get());
308 EXPECT_FALSE(window_state
->IsMaximized());
309 scoped_ptr
<WindowState::State
> old(window_state
->SetStateObject(
310 scoped_ptr
<WindowState::State
> (new AlwaysMaximizeTestState(
311 window_state
->GetStateType()))).Pass());
312 EXPECT_TRUE(window_state
->IsMaximized());
313 window_state
->SetStateObject(old
.Pass());
314 EXPECT_FALSE(window_state
->IsMaximized());
317 // Tests that a window that had same bounds as the work area shrinks after the
318 // window is maximized and then restored.
319 TEST_F(WindowStateTest
, RestoredWindowBoundsShrink
) {
320 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithId(0));
321 WindowState
* window_state
= GetWindowState(window
.get());
322 EXPECT_FALSE(window_state
->IsMaximized());
323 gfx::Rect work_area
=
324 ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
326 window
->SetBounds(work_area
);
327 window_state
->Maximize();
328 EXPECT_TRUE(window_state
->IsMaximized());
329 EXPECT_EQ(work_area
.ToString(), window
->bounds().ToString());
331 window_state
->Restore();
332 EXPECT_FALSE(window_state
->IsMaximized());
333 EXPECT_NE(work_area
.ToString(), window
->bounds().ToString());
334 EXPECT_TRUE(work_area
.Contains(window
->bounds()));
337 // TODO(skuhne): Add more unit test to verify the correctness for the restore