1 // Copyright 2013 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/workspace_controller.h"
9 #include "ash/ash_switches.h"
10 #include "ash/root_window_controller.h"
11 #include "ash/screen_ash.h"
12 #include "ash/shelf/shelf_layout_manager.h"
13 #include "ash/shelf/shelf_widget.h"
14 #include "ash/shell.h"
15 #include "ash/shell_window_ids.h"
16 #include "ash/system/status_area_widget.h"
17 #include "ash/test/ash_test_base.h"
18 #include "ash/test/shell_test_api.h"
19 #include "ash/wm/window_state.h"
20 #include "ash/wm/window_util.h"
21 #include "base/command_line.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "ui/aura/client/aura_constants.h"
24 #include "ui/aura/root_window.h"
25 #include "ui/aura/test/event_generator.h"
26 #include "ui/aura/test/test_window_delegate.h"
27 #include "ui/aura/test/test_windows.h"
28 #include "ui/aura/window.h"
29 #include "ui/base/hit_test.h"
30 #include "ui/base/ui_base_types.h"
31 #include "ui/compositor/layer.h"
32 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
33 #include "ui/gfx/screen.h"
34 #include "ui/views/corewm/window_animations.h"
35 #include "ui/views/widget/widget.h"
42 // Returns a string containing the names of all the children of |window| (in
43 // order). Each entry is separated by a space.
44 std::string
GetWindowNames(const aura::Window
* window
) {
46 for (size_t i
= 0; i
< window
->children().size(); ++i
) {
49 result
+= window
->children()[i
]->name();
54 // Returns a string containing the names of windows corresponding to each of the
55 // child layers of |window|'s layer. Any layers that don't correspond to a child
56 // Window of |window| are ignored. The result is ordered based on the layer
58 std::string
GetLayerNames(const aura::Window
* window
) {
59 typedef std::map
<const ui::Layer
*, std::string
> LayerToWindowNameMap
;
60 LayerToWindowNameMap window_names
;
61 for (size_t i
= 0; i
< window
->children().size(); ++i
) {
62 window_names
[window
->children()[i
]->layer()] =
63 window
->children()[i
]->name();
67 const std::vector
<ui::Layer
*>& layers(window
->layer()->children());
68 for (size_t i
= 0; i
< layers
.size(); ++i
) {
69 LayerToWindowNameMap::iterator layer_i
=
70 window_names
.find(layers
[i
]);
71 if (layer_i
!= window_names
.end()) {
74 result
+= layer_i
->second
;
80 class WorkspaceControllerTest
: public test::AshTestBase
{
82 WorkspaceControllerTest() {}
83 virtual ~WorkspaceControllerTest() {}
85 aura::Window
* CreateTestWindowUnparented() {
86 aura::Window
* window
= new aura::Window(NULL
);
87 window
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_NORMAL
);
88 window
->SetType(aura::client::WINDOW_TYPE_NORMAL
);
89 window
->Init(ui::LAYER_TEXTURED
);
93 aura::Window
* CreateTestWindow() {
94 aura::Window
* window
= new aura::Window(NULL
);
95 window
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_NORMAL
);
96 window
->SetType(aura::client::WINDOW_TYPE_NORMAL
);
97 window
->Init(ui::LAYER_TEXTURED
);
98 SetDefaultParentByPrimaryRootWindow(window
);
102 aura::Window
* CreateBrowserLikeWindow(const gfx::Rect
& bounds
) {
103 aura::Window
* window
= CreateTestWindow();
104 window
->SetBounds(bounds
);
105 wm::WindowState
* window_state
= wm::GetWindowState(window
);
106 window_state
->SetTrackedByWorkspace(true);
107 window_state
->set_window_position_managed(true);
112 aura::Window
* CreatePopupLikeWindow(const gfx::Rect
& bounds
) {
113 aura::Window
* window
= CreateTestWindowInShellWithBounds(bounds
);
118 aura::Window
* GetDesktop() {
119 return Shell::GetContainer(Shell::GetPrimaryRootWindow(),
120 kShellWindowId_DefaultContainer
);
123 gfx::Rect
GetFullscreenBounds(aura::Window
* window
) {
124 return Shell::GetScreen()->GetDisplayNearestWindow(window
).bounds();
127 ShelfWidget
* shelf_widget() {
128 return Shell::GetPrimaryRootWindowController()->shelf();
131 ShelfLayoutManager
* shelf_layout_manager() {
132 return Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
135 bool GetWindowOverlapsShelf() {
136 return shelf_layout_manager()->window_overlaps_shelf();
140 DISALLOW_COPY_AND_ASSIGN(WorkspaceControllerTest
);
143 // Assertions around adding a normal window.
144 TEST_F(WorkspaceControllerTest
, AddNormalWindowWhenEmpty
) {
145 scoped_ptr
<Window
> w1(CreateTestWindow());
146 w1
->SetBounds(gfx::Rect(0, 0, 250, 251));
148 wm::WindowState
* window_state
= wm::GetWindowState(w1
.get());
150 EXPECT_FALSE(window_state
->HasRestoreBounds());
154 EXPECT_FALSE(window_state
->HasRestoreBounds());
156 ASSERT_TRUE(w1
->layer() != NULL
);
157 EXPECT_TRUE(w1
->layer()->visible());
159 EXPECT_EQ("0,0 250x251", w1
->bounds().ToString());
161 EXPECT_EQ(w1
.get(), GetDesktop()->children()[0]);
164 // Assertions around maximizing/unmaximizing.
165 TEST_F(WorkspaceControllerTest
, SingleMaximizeWindow
) {
166 scoped_ptr
<Window
> w1(CreateTestWindow());
167 w1
->SetBounds(gfx::Rect(0, 0, 250, 251));
170 wm::ActivateWindow(w1
.get());
172 EXPECT_TRUE(wm::IsActiveWindow(w1
.get()));
174 ASSERT_TRUE(w1
->layer() != NULL
);
175 EXPECT_TRUE(w1
->layer()->visible());
177 EXPECT_EQ("0,0 250x251", w1
->bounds().ToString());
179 // Maximize the window.
180 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MAXIMIZED
);
182 EXPECT_TRUE(wm::IsActiveWindow(w1
.get()));
184 EXPECT_EQ(w1
.get(), GetDesktop()->children()[0]);
185 EXPECT_EQ(ScreenAsh::GetMaximizedWindowBoundsInParent(w1
.get()).width(),
186 w1
->bounds().width());
187 EXPECT_EQ(ScreenAsh::GetMaximizedWindowBoundsInParent(w1
.get()).height(),
188 w1
->bounds().height());
190 // Restore the window.
191 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_NORMAL
);
193 EXPECT_EQ(w1
.get(), GetDesktop()->children()[0]);
194 EXPECT_EQ("0,0 250x251", w1
->bounds().ToString());
197 // Assertions around two windows and toggling one to be fullscreen.
198 TEST_F(WorkspaceControllerTest
, FullscreenWithNormalWindow
) {
199 scoped_ptr
<Window
> w1(CreateTestWindow());
200 scoped_ptr
<Window
> w2(CreateTestWindow());
201 w1
->SetBounds(gfx::Rect(0, 0, 250, 251));
204 ASSERT_TRUE(w1
->layer() != NULL
);
205 EXPECT_TRUE(w1
->layer()->visible());
207 w2
->SetBounds(gfx::Rect(0, 0, 50, 51));
208 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_FULLSCREEN
);
210 wm::ActivateWindow(w2
.get());
212 // Both windows should be in the same workspace.
213 EXPECT_EQ(w1
.get(), GetDesktop()->children()[0]);
214 EXPECT_EQ(w2
.get(), GetDesktop()->children()[1]);
217 ScreenAsh::GetMaximizedWindowBoundsInParent(w1
.get()));
218 EXPECT_EQ(work_area
.width(), w2
->bounds().width());
219 EXPECT_EQ(work_area
.height(), w2
->bounds().height());
221 // Restore w2, which should then go back to one workspace.
222 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_NORMAL
);
223 EXPECT_EQ(50, w2
->bounds().width());
224 EXPECT_EQ(51, w2
->bounds().height());
225 EXPECT_TRUE(wm::IsActiveWindow(w2
.get()));
228 // Makes sure requests to change the bounds of a normal window go through.
229 TEST_F(WorkspaceControllerTest
, ChangeBoundsOfNormalWindow
) {
230 scoped_ptr
<Window
> w1(CreateTestWindow());
233 // Setting the bounds should go through since the window is in the normal
235 w1
->SetBounds(gfx::Rect(0, 0, 200, 500));
236 EXPECT_EQ(200, w1
->bounds().width());
237 EXPECT_EQ(500, w1
->bounds().height());
240 // Verifies the bounds is not altered when showing and grid is enabled.
241 TEST_F(WorkspaceControllerTest
, SnapToGrid
) {
242 scoped_ptr
<Window
> w1(CreateTestWindowUnparented());
243 w1
->SetBounds(gfx::Rect(1, 6, 25, 30));
244 SetDefaultParentByPrimaryRootWindow(w1
.get());
245 // We are not aligning this anymore this way. When the window gets shown
246 // the window is expected to be handled differently, but this cannot be
247 // tested with this test. So the result of this test should be that the
248 // bounds are exactly as passed in.
249 EXPECT_EQ("1,6 25x30", w1
->bounds().ToString());
252 // Assertions around a fullscreen window.
253 TEST_F(WorkspaceControllerTest
, SingleFullscreenWindow
) {
254 scoped_ptr
<Window
> w1(CreateTestWindow());
255 w1
->SetBounds(gfx::Rect(0, 0, 250, 251));
256 // Make the window fullscreen.
257 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_FULLSCREEN
);
259 wm::ActivateWindow(w1
.get());
261 EXPECT_EQ(w1
.get(), GetDesktop()->children()[0]);
262 EXPECT_EQ(GetFullscreenBounds(w1
.get()).width(), w1
->bounds().width());
263 EXPECT_EQ(GetFullscreenBounds(w1
.get()).height(), w1
->bounds().height());
265 // Restore the window. Use SHOW_STATE_DEFAULT as that is what we'll end up
266 // with when using views::Widget.
267 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_DEFAULT
);
268 EXPECT_EQ("0,0 250x251", w1
->bounds().ToString());
270 EXPECT_EQ(w1
.get(), GetDesktop()->children()[0]);
271 EXPECT_EQ(250, w1
->bounds().width());
272 EXPECT_EQ(251, w1
->bounds().height());
274 // Back to fullscreen.
275 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_FULLSCREEN
);
276 EXPECT_EQ(w1
.get(), GetDesktop()->children()[0]);
277 EXPECT_EQ(GetFullscreenBounds(w1
.get()).width(), w1
->bounds().width());
278 EXPECT_EQ(GetFullscreenBounds(w1
.get()).height(), w1
->bounds().height());
279 wm::WindowState
* window_state
= wm::GetWindowState(w1
.get());
281 ASSERT_TRUE(window_state
->HasRestoreBounds());
282 EXPECT_EQ("0,0 250x251", window_state
->GetRestoreBoundsInScreen().ToString());
285 // Assertions around minimizing a single window.
286 TEST_F(WorkspaceControllerTest
, MinimizeSingleWindow
) {
287 scoped_ptr
<Window
> w1(CreateTestWindow());
291 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MINIMIZED
);
292 EXPECT_FALSE(w1
->layer()->IsDrawn());
296 EXPECT_TRUE(wm::GetWindowState(w1
.get())->IsNormalShowState());
297 EXPECT_TRUE(w1
->layer()->IsDrawn());
300 // Assertions around minimizing a fullscreen window.
301 TEST_F(WorkspaceControllerTest
, MinimizeFullscreenWindow
) {
302 // Two windows, w1 normal, w2 fullscreen.
303 scoped_ptr
<Window
> w1(CreateTestWindow());
304 scoped_ptr
<Window
> w2(CreateTestWindow());
306 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_FULLSCREEN
);
309 wm::WindowState
* w1_state
= wm::GetWindowState(w1
.get());
310 wm::WindowState
* w2_state
= wm::GetWindowState(w2
.get());
312 w2_state
->Activate();
315 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MINIMIZED
);
316 EXPECT_TRUE(w1
->layer()->IsDrawn());
317 EXPECT_FALSE(w2
->layer()->IsDrawn());
319 // Show the window, which should trigger unminimizing.
321 w2_state
->Activate();
323 EXPECT_TRUE(w2_state
->IsFullscreen());
324 EXPECT_TRUE(w1
->layer()->IsDrawn());
325 EXPECT_TRUE(w2
->layer()->IsDrawn());
327 // Minimize the window, which should hide the window.
328 EXPECT_TRUE(w2_state
->IsActive());
329 w2_state
->Minimize();
330 EXPECT_FALSE(w2_state
->IsActive());
331 EXPECT_FALSE(w2
->layer()->IsDrawn());
332 EXPECT_TRUE(w1_state
->IsActive());
334 // Make the window normal.
335 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_NORMAL
);
336 EXPECT_EQ(w1
.get(), GetDesktop()->children()[0]);
337 EXPECT_EQ(w2
.get(), GetDesktop()->children()[1]);
338 EXPECT_TRUE(w2
->layer()->IsDrawn());
341 // Verifies ShelfLayoutManager's visibility/auto-hide state is correctly
343 TEST_F(WorkspaceControllerTest
, ShelfStateUpdated
) {
344 // Since ShelfLayoutManager queries for mouse location, move the mouse so
345 // it isn't over the shelf.
346 aura::test::EventGenerator
generator(
347 Shell::GetPrimaryRootWindow(), gfx::Point());
348 generator
.MoveMouseTo(0, 0);
350 scoped_ptr
<Window
> w1(CreateTestWindow());
351 const gfx::Rect
w1_bounds(0, 1, 101, 102);
352 ShelfLayoutManager
* shelf
= shelf_layout_manager();
353 shelf
->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
);
354 const gfx::Rect
touches_shelf_bounds(
355 0, shelf
->GetIdealBounds().y() - 10, 101, 102);
356 // Move |w1| to overlap the shelf.
357 w1
->SetBounds(touches_shelf_bounds
);
358 EXPECT_FALSE(GetWindowOverlapsShelf());
360 // A visible ignored window should not trigger the overlap.
361 scoped_ptr
<Window
> w_ignored(CreateTestWindow());
362 w_ignored
->SetBounds(touches_shelf_bounds
);
363 wm::GetWindowState(&(*w_ignored
))->set_ignored_by_shelf(true);
365 EXPECT_FALSE(GetWindowOverlapsShelf());
367 // Make it visible, since visible shelf overlaps should be true.
369 EXPECT_TRUE(GetWindowOverlapsShelf());
371 wm::ActivateWindow(w1
.get());
372 w1
->SetBounds(w1_bounds
);
374 wm::ActivateWindow(w1
.get());
376 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf
->visibility_state());
378 // Maximize the window.
379 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MAXIMIZED
);
380 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf
->visibility_state());
381 EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN
, shelf
->auto_hide_state());
384 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_NORMAL
);
385 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf
->visibility_state());
386 EXPECT_EQ("0,1 101x102", w1
->bounds().ToString());
389 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_FULLSCREEN
);
390 EXPECT_EQ(SHELF_HIDDEN
, shelf
->visibility_state());
393 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_NORMAL
);
394 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf
->visibility_state());
395 EXPECT_EQ("0,1 101x102", w1
->bounds().ToString());
396 EXPECT_FALSE(GetWindowOverlapsShelf());
398 // Move window so it obscures shelf.
399 w1
->SetBounds(touches_shelf_bounds
);
400 EXPECT_TRUE(GetWindowOverlapsShelf());
403 w1
->SetBounds(w1_bounds
);
404 EXPECT_FALSE(GetWindowOverlapsShelf());
407 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MAXIMIZED
);
408 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf
->visibility_state());
409 EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN
, shelf
->auto_hide_state());
412 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MINIMIZED
);
413 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf
->visibility_state());
415 // Since the restore from minimize will restore to the pre-minimize
416 // state (tested elsewhere), we abandon the current size and restore
417 // rect and set them to the window.
418 wm::WindowState
* window_state
= wm::GetWindowState(w1
.get());
420 gfx::Rect restore
= window_state
->GetRestoreBoundsInScreen();
421 EXPECT_EQ("0,0 800x597", w1
->bounds().ToString());
422 EXPECT_EQ("0,1 101x102", restore
.ToString());
423 window_state
->ClearRestoreBounds();
424 w1
->SetBounds(restore
);
427 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_NORMAL
);
428 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf
->visibility_state());
429 EXPECT_EQ("0,1 101x102", w1
->bounds().ToString());
431 // Create another window, maximized.
432 scoped_ptr
<Window
> w2(CreateTestWindow());
433 w2
->SetBounds(gfx::Rect(10, 11, 250, 251));
434 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MAXIMIZED
);
436 wm::ActivateWindow(w2
.get());
437 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf
->visibility_state());
438 EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN
, shelf
->auto_hide_state());
439 EXPECT_EQ("0,1 101x102", w1
->bounds().ToString());
442 wm::ActivateWindow(w1
.get());
443 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf
->visibility_state());
444 EXPECT_EQ("0,1 101x102", w1
->bounds().ToString());
445 EXPECT_EQ(ScreenAsh::GetMaximizedWindowBoundsInParent(
446 w2
->parent()).ToString(),
447 w2
->bounds().ToString());
450 wm::ActivateWindow(w2
.get());
451 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf
->visibility_state());
452 EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN
, shelf
->auto_hide_state());
453 EXPECT_EQ("0,1 101x102", w1
->bounds().ToString());
454 EXPECT_EQ(ScreenAsh::GetMaximizedWindowBoundsInParent(w2
.get()).ToString(),
455 w2
->bounds().ToString());
457 // Turn off auto-hide, switch back to w2 (maximized) and verify overlap.
458 shelf
->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER
);
459 wm::ActivateWindow(w2
.get());
460 EXPECT_FALSE(GetWindowOverlapsShelf());
462 // Move w1 to overlap shelf, it shouldn't change window overlaps shelf since
463 // the window isn't in the visible workspace.
464 w1
->SetBounds(touches_shelf_bounds
);
465 EXPECT_FALSE(GetWindowOverlapsShelf());
467 // Activate w1. Although w1 is visible, the overlap state is still false since
469 wm::ActivateWindow(w1
.get());
470 EXPECT_FALSE(GetWindowOverlapsShelf());
473 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_NORMAL
);
474 EXPECT_TRUE(GetWindowOverlapsShelf());
477 // Verifies going from maximized to minimized sets the right state for painting
478 // the background of the launcher.
479 TEST_F(WorkspaceControllerTest
, MinimizeResetsVisibility
) {
480 scoped_ptr
<Window
> w1(CreateTestWindow());
482 wm::ActivateWindow(w1
.get());
483 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MAXIMIZED
);
484 EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED
, shelf_widget()->GetBackgroundType());
486 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MINIMIZED
);
487 EXPECT_EQ(SHELF_VISIBLE
,
488 shelf_layout_manager()->visibility_state());
489 EXPECT_EQ(SHELF_BACKGROUND_DEFAULT
, shelf_widget()->GetBackgroundType());
492 // Verifies window visibility during various workspace changes.
493 TEST_F(WorkspaceControllerTest
, VisibilityTests
) {
494 scoped_ptr
<Window
> w1(CreateTestWindow());
496 EXPECT_TRUE(w1
->IsVisible());
497 EXPECT_EQ(1.0f
, w1
->layer()->GetCombinedOpacity());
499 // Create another window, activate it and make it fullscreen.
500 scoped_ptr
<Window
> w2(CreateTestWindow());
502 wm::ActivateWindow(w2
.get());
503 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_FULLSCREEN
);
504 EXPECT_TRUE(w2
->IsVisible());
505 EXPECT_EQ(1.0f
, w2
->layer()->GetCombinedOpacity());
506 EXPECT_TRUE(w1
->IsVisible());
508 // Switch to w1. |w1| should be visible on top of |w2|.
509 wm::ActivateWindow(w1
.get());
510 EXPECT_TRUE(w1
->IsVisible());
511 EXPECT_EQ(1.0f
, w1
->layer()->GetCombinedOpacity());
512 EXPECT_TRUE(w2
->IsVisible());
514 // Switch back to |w2|.
515 wm::ActivateWindow(w2
.get());
516 EXPECT_TRUE(w2
->IsVisible());
517 EXPECT_EQ(1.0f
, w2
->layer()->GetCombinedOpacity());
518 EXPECT_TRUE(w1
->IsVisible());
520 // Restore |w2|, both windows should be visible.
521 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_NORMAL
);
522 EXPECT_TRUE(w1
->IsVisible());
523 EXPECT_EQ(1.0f
, w1
->layer()->GetCombinedOpacity());
524 EXPECT_TRUE(w2
->IsVisible());
525 EXPECT_EQ(1.0f
, w2
->layer()->GetCombinedOpacity());
527 // Make |w2| fullscreen again, then close it.
528 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_FULLSCREEN
);
530 EXPECT_FALSE(w2
->IsVisible());
531 EXPECT_EQ(1.0f
, w1
->layer()->GetCombinedOpacity());
532 EXPECT_TRUE(w1
->IsVisible());
534 // Create |w2| and maximize it.
535 w2
.reset(CreateTestWindow());
537 wm::ActivateWindow(w2
.get());
538 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MAXIMIZED
);
539 EXPECT_TRUE(w2
->IsVisible());
540 EXPECT_EQ(1.0f
, w2
->layer()->GetCombinedOpacity());
541 EXPECT_TRUE(w1
->IsVisible());
545 EXPECT_EQ(1.0f
, w1
->layer()->GetCombinedOpacity());
546 EXPECT_TRUE(w1
->IsVisible());
549 // Verifies windows that are offscreen don't move when switching workspaces.
550 TEST_F(WorkspaceControllerTest
, DontMoveOnSwitch
) {
551 aura::test::EventGenerator
generator(
552 Shell::GetPrimaryRootWindow(), gfx::Point());
553 generator
.MoveMouseTo(0, 0);
555 scoped_ptr
<Window
> w1(CreateTestWindow());
556 ShelfLayoutManager
* shelf
= shelf_layout_manager();
557 const gfx::Rect
touches_shelf_bounds(
558 0, shelf
->GetIdealBounds().y() - 10, 101, 102);
559 // Move |w1| to overlap the shelf.
560 w1
->SetBounds(touches_shelf_bounds
);
562 wm::ActivateWindow(w1
.get());
564 // Create another window and maximize it.
565 scoped_ptr
<Window
> w2(CreateTestWindow());
566 w2
->SetBounds(gfx::Rect(10, 11, 250, 251));
567 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MAXIMIZED
);
569 wm::ActivateWindow(w2
.get());
572 wm::ActivateWindow(w1
.get());
573 EXPECT_EQ(touches_shelf_bounds
.ToString(), w1
->bounds().ToString());
576 // Verifies that windows that are completely offscreen move when switching
578 TEST_F(WorkspaceControllerTest
, MoveOnSwitch
) {
579 aura::test::EventGenerator
generator(
580 Shell::GetPrimaryRootWindow(), gfx::Point());
581 generator
.MoveMouseTo(0, 0);
583 scoped_ptr
<Window
> w1(CreateTestWindow());
584 ShelfLayoutManager
* shelf
= shelf_layout_manager();
585 const gfx::Rect
w1_bounds(0, shelf
->GetIdealBounds().y(), 100, 200);
586 // Move |w1| so that the top edge is the same as the top edge of the shelf.
587 w1
->SetBounds(w1_bounds
);
589 wm::ActivateWindow(w1
.get());
590 EXPECT_EQ(w1_bounds
.ToString(), w1
->bounds().ToString());
592 // Create another window and maximize it.
593 scoped_ptr
<Window
> w2(CreateTestWindow());
594 w2
->SetBounds(gfx::Rect(10, 11, 250, 251));
595 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MAXIMIZED
);
597 wm::ActivateWindow(w2
.get());
599 // Increase the size of the WorkAreaInsets. This would make |w1| fall
600 // completely out of the display work area.
602 Shell::GetScreen()->GetPrimaryDisplay().GetWorkAreaInsets();
603 insets
.Set(0, 0, insets
.bottom() + 30, 0);
604 Shell::GetInstance()->SetDisplayWorkAreaInsets(w1
.get(), insets
);
606 // Switch to w1. The window should have moved.
607 wm::ActivateWindow(w1
.get());
608 EXPECT_NE(w1_bounds
.ToString(), w1
->bounds().ToString());
613 // WindowDelegate used by DontCrashOnChangeAndActivate.
614 class DontCrashOnChangeAndActivateDelegate
615 : public aura::test::TestWindowDelegate
{
617 DontCrashOnChangeAndActivateDelegate() : window_(NULL
) {}
619 void set_window(aura::Window
* window
) { window_
= window
; }
621 // WindowDelegate overrides:
622 virtual void OnBoundsChanged(const gfx::Rect
& old_bounds
,
623 const gfx::Rect
& new_bounds
) OVERRIDE
{
625 wm::ActivateWindow(window_
);
631 aura::Window
* window_
;
633 DISALLOW_COPY_AND_ASSIGN(DontCrashOnChangeAndActivateDelegate
);
638 // Exercises possible crash in W2. Here's the sequence:
639 // . minimize a maximized window.
640 // . remove the window (which happens when switching displays).
641 // . add the window back.
642 // . show the window and during the bounds change activate it.
643 TEST_F(WorkspaceControllerTest
, DontCrashOnChangeAndActivate
) {
645 ShelfLayoutManager
* shelf
= shelf_layout_manager();
646 shelf
->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER
);
648 DontCrashOnChangeAndActivateDelegate delegate
;
649 scoped_ptr
<Window
> w1(CreateTestWindowInShellWithDelegate(
650 &delegate
, 1000, gfx::Rect(10, 11, 250, 251)));
653 wm::WindowState
* w1_state
= wm::GetWindowState(w1
.get());
654 w1_state
->Activate();
655 w1_state
->Maximize();
656 w1_state
->Minimize();
658 w1
->parent()->RemoveChild(w1
.get());
660 // Do this so that when we Show() the window a resize occurs and we make the
662 shelf
->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
);
664 SetDefaultParentByPrimaryRootWindow(w1
.get());
665 delegate
.set_window(w1
.get());
669 // Verifies a window with a transient parent not managed by workspace works.
670 TEST_F(WorkspaceControllerTest
, TransientParent
) {
671 // Normal window with no transient parent.
672 scoped_ptr
<Window
> w2(CreateTestWindow());
673 w2
->SetBounds(gfx::Rect(10, 11, 250, 251));
675 wm::ActivateWindow(w2
.get());
677 // Window with a transient parent. We set the transient parent to the root,
678 // which would never happen but is enough to exercise the bug.
679 scoped_ptr
<Window
> w1(CreateTestWindowUnparented());
680 Shell::GetInstance()->GetPrimaryRootWindow()->AddTransientChild(w1
.get());
681 w1
->SetBounds(gfx::Rect(10, 11, 250, 251));
682 SetDefaultParentByPrimaryRootWindow(w1
.get());
684 wm::ActivateWindow(w1
.get());
686 // The window with the transient parent should get added to the same parent as
687 // the normal window.
688 EXPECT_EQ(w2
->parent(), w1
->parent());
691 // Verifies changing TrackedByWorkspace works.
692 TEST_F(WorkspaceControllerTest
, TrackedByWorkspace
) {
693 // Create a fullscreen window.
694 scoped_ptr
<Window
> w1(CreateTestWindow());
696 wm::ActivateWindow(w1
.get());
697 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_FULLSCREEN
);
698 EXPECT_TRUE(wm::IsActiveWindow(w1
.get()));
699 EXPECT_TRUE(w1
->IsVisible());
701 // Create a second fullscreen window and mark it not tracked by workspace
703 scoped_ptr
<Window
> w2(CreateTestWindowUnparented());
704 w2
->SetBounds(gfx::Rect(1, 6, 25, 30));
705 w2
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_FULLSCREEN
);
706 SetDefaultParentByPrimaryRootWindow(w2
.get());
708 wm::GetWindowState(w2
.get())->SetTrackedByWorkspace(false);
709 wm::ActivateWindow(w2
.get());
711 // Activating |w2| should force it to have the same parent as |w1|.
712 EXPECT_EQ(w1
->parent(), w2
->parent());
713 EXPECT_TRUE(wm::IsActiveWindow(w2
.get()));
714 EXPECT_TRUE(w1
->IsVisible());
715 EXPECT_TRUE(w2
->IsVisible());
717 // Because |w2| isn't tracked we should be able to set the bounds of it.
718 gfx::Rect
bounds(w2
->bounds());
720 w2
->SetBounds(bounds
);
721 EXPECT_EQ(bounds
.ToString(), w2
->bounds().ToString());
723 // Transition it to tracked by worskpace. It should end up in the desktop
725 wm::GetWindowState(w2
.get())->SetTrackedByWorkspace(true);
726 EXPECT_TRUE(wm::IsActiveWindow(w2
.get()));
727 EXPECT_TRUE(w1
->IsVisible());
728 EXPECT_TRUE(w2
->IsVisible());
729 EXPECT_EQ(w1
->parent(), w2
->parent());
732 // Test the placement of newly created windows.
733 TEST_F(WorkspaceControllerTest
, BasicAutoPlacingOnCreate
) {
734 if (!SupportsHostWindowResize())
736 UpdateDisplay("1600x1200");
737 // Creating a popup handler here to make sure it does not interfere with the
739 gfx::Rect
source_browser_bounds(16, 32, 640, 320);
740 scoped_ptr
<aura::Window
> browser_window(CreateBrowserLikeWindow(
741 source_browser_bounds
));
743 // Creating a popup to make sure it does not interfere with the positioning.
744 scoped_ptr
<aura::Window
> browser_popup(CreatePopupLikeWindow(
745 gfx::Rect(16, 32, 128, 256)));
747 browser_window
->Show();
748 browser_popup
->Show();
750 { // With a shown window it's size should get returned.
751 scoped_ptr
<aura::Window
> new_browser_window(CreateBrowserLikeWindow(
752 source_browser_bounds
));
753 // The position should be right flush.
754 EXPECT_EQ("960,32 640x320", new_browser_window
->bounds().ToString());
757 { // With the window shown - but more on the right side then on the left
758 // side (and partially out of the screen), it should default to the other
759 // side and inside the screen.
760 gfx::Rect
source_browser_bounds(gfx::Rect(1000, 600, 640, 320));
761 browser_window
->SetBounds(source_browser_bounds
);
763 scoped_ptr
<aura::Window
> new_browser_window(CreateBrowserLikeWindow(
764 source_browser_bounds
));
765 // The position should be left & bottom flush.
766 EXPECT_EQ("0,600 640x320", new_browser_window
->bounds().ToString());
768 // If the other window was already beyond the point to get right flush
769 // it will remain where it is.
770 EXPECT_EQ("1000,600 640x320", browser_window
->bounds().ToString());
773 { // Make sure that popups do not get changed.
774 scoped_ptr
<aura::Window
> new_popup_window(CreatePopupLikeWindow(
775 gfx::Rect(50, 100, 300, 150)));
776 EXPECT_EQ("50,100 300x150", new_popup_window
->bounds().ToString());
779 browser_window
->Hide();
780 { // If a window is there but not shown the default should be centered.
781 scoped_ptr
<aura::Window
> new_browser_window(CreateBrowserLikeWindow(
782 gfx::Rect(50, 100, 300, 150)));
783 EXPECT_EQ("650,100 300x150", new_browser_window
->bounds().ToString());
787 // Test the basic auto placement of one and or two windows in a "simulated
788 // session" of sequential window operations.
789 TEST_F(WorkspaceControllerTest
, BasicAutoPlacingOnShowHide
) {
790 // Test 1: In case there is no manageable window, no window should shift.
792 scoped_ptr
<aura::Window
> window1(CreateTestWindowInShellWithId(0));
793 window1
->SetBounds(gfx::Rect(16, 32, 640, 320));
794 gfx::Rect desktop_area
= window1
->parent()->bounds();
796 scoped_ptr
<aura::Window
> window2(CreateTestWindowInShellWithId(1));
797 // Trigger the auto window placement function by making it visible.
798 // Note that the bounds are getting changed while it is invisible.
800 window2
->SetBounds(gfx::Rect(32, 48, 256, 512));
803 // Check the initial position of the windows is unchanged.
804 EXPECT_EQ("16,32 640x320", window1
->bounds().ToString());
805 EXPECT_EQ("32,48 256x512", window2
->bounds().ToString());
807 // Remove the second window and make sure that the first window
808 // does NOT get centered.
810 EXPECT_EQ("16,32 640x320", window1
->bounds().ToString());
812 wm::WindowState
* window1_state
= wm::GetWindowState(window1
.get());
813 // Test 2: Set up two managed windows and check their auto positioning.
814 window1_state
->set_window_position_managed(true);
816 scoped_ptr
<aura::Window
> window3(CreateTestWindowInShellWithId(2));
817 wm::GetWindowState(window3
.get())->set_window_position_managed(true);
818 // To avoid any auto window manager changes due to SetBounds, the window
819 // gets first hidden and then shown again.
821 window3
->SetBounds(gfx::Rect(32, 48, 256, 512));
823 // |window1| should be flush left and |window3| flush right.
824 EXPECT_EQ("0,32 640x320", window1
->bounds().ToString());
825 EXPECT_EQ(base::IntToString(
826 desktop_area
.width() - window3
->bounds().width()) +
827 ",48 256x512", window3
->bounds().ToString());
829 // After removing |window3|, |window1| should be centered again.
833 (desktop_area
.width() - window1
->bounds().width()) / 2) +
834 ",32 640x320", window1
->bounds().ToString());
836 // Test 3: Set up a manageable and a non manageable window and check
838 scoped_ptr
<aura::Window
> window4(CreateTestWindowInShellWithId(3));
839 // To avoid any auto window manager changes due to SetBounds, the window
840 // gets first hidden and then shown again.
842 window1
->SetBounds(gfx::Rect(16, 32, 640, 320));
843 window4
->SetBounds(gfx::Rect(32, 48, 256, 512));
845 // |window1| should be centered and |window4| untouched.
848 (desktop_area
.width() - window1
->bounds().width()) / 2) +
849 ",32 640x320", window1
->bounds().ToString());
850 EXPECT_EQ("32,48 256x512", window4
->bounds().ToString());
852 // Test4: A single manageable window should get centered.
854 window1_state
->set_bounds_changed_by_user(false);
855 // Trigger the auto window placement function by showing (and hiding) it.
858 // |window1| should be centered.
861 (desktop_area
.width() - window1
->bounds().width()) / 2) +
862 ",32 640x320", window1
->bounds().ToString());
865 // Test the proper usage of user window movement interaction.
866 TEST_F(WorkspaceControllerTest
, TestUserMovedWindowRepositioning
) {
867 scoped_ptr
<aura::Window
> window1(CreateTestWindowInShellWithId(0));
868 window1
->SetBounds(gfx::Rect(16, 32, 640, 320));
869 gfx::Rect desktop_area
= window1
->parent()->bounds();
870 scoped_ptr
<aura::Window
> window2(CreateTestWindowInShellWithId(1));
871 window2
->SetBounds(gfx::Rect(32, 48, 256, 512));
874 wm::WindowState
* window1_state
= wm::GetWindowState(window1
.get());
875 wm::WindowState
* window2_state
= wm::GetWindowState(window2
.get());
877 window1_state
->set_window_position_managed(true);
878 window2_state
->set_window_position_managed(true);
879 EXPECT_FALSE(window1_state
->bounds_changed_by_user());
880 EXPECT_FALSE(window2_state
->bounds_changed_by_user());
882 // Check that the current location gets preserved if the user has
883 // positioned it previously.
884 window1_state
->set_bounds_changed_by_user(true);
886 EXPECT_EQ("16,32 640x320", window1
->bounds().ToString());
887 // Flag should be still set.
888 EXPECT_TRUE(window1_state
->bounds_changed_by_user());
889 EXPECT_FALSE(window2_state
->bounds_changed_by_user());
891 // Turn on the second window and make sure that both windows are now
892 // positionable again (user movement cleared).
895 // |window1| should be flush left and |window2| flush right.
896 EXPECT_EQ("0,32 640x320", window1
->bounds().ToString());
898 base::IntToString(desktop_area
.width() - window2
->bounds().width()) +
899 ",48 256x512", window2
->bounds().ToString());
900 // FLag should now be reset.
901 EXPECT_FALSE(window1_state
->bounds_changed_by_user());
902 EXPECT_FALSE(window2_state
->bounds_changed_by_user());
904 // Going back to one shown window should keep the state.
905 window1_state
->set_bounds_changed_by_user(true);
907 EXPECT_EQ("0,32 640x320", window1
->bounds().ToString());
908 EXPECT_TRUE(window1_state
->bounds_changed_by_user());
911 // Test if the single window will be restored at original position.
912 TEST_F(WorkspaceControllerTest
, TestSingleWindowsRestoredBounds
) {
913 scoped_ptr
<aura::Window
> window1(
914 CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
915 scoped_ptr
<aura::Window
> window2(
916 CreateTestWindowInShellWithBounds(gfx::Rect(110, 110, 100, 100)));
917 scoped_ptr
<aura::Window
> window3(
918 CreateTestWindowInShellWithBounds(gfx::Rect(120, 120, 100, 100)));
922 wm::GetWindowState(window1
.get())->set_window_position_managed(true);
923 wm::GetWindowState(window2
.get())->set_window_position_managed(true);
924 wm::GetWindowState(window3
.get())->set_window_position_managed(true);
927 wm::ActivateWindow(window1
.get());
929 wm::ActivateWindow(window2
.get());
931 wm::ActivateWindow(window3
.get());
932 EXPECT_EQ(0, window1
->bounds().x());
933 EXPECT_EQ(window2
->GetRootWindow()->bounds().right(),
934 window2
->bounds().right());
935 EXPECT_EQ(0, window3
->bounds().x());
938 EXPECT_EQ(window2
->GetRootWindow()->bounds().right(),
939 window2
->bounds().right());
940 EXPECT_EQ(0, window3
->bounds().x());
942 // Being a single window will retore the original location.
944 wm::ActivateWindow(window2
.get());
945 EXPECT_EQ("110,110 100x100", window2
->bounds().ToString());
947 // Showing the 3rd will push the 2nd window left.
949 wm::ActivateWindow(window3
.get());
950 EXPECT_EQ(0, window2
->bounds().x());
951 EXPECT_EQ(window3
->GetRootWindow()->bounds().right(),
952 window3
->bounds().right());
954 // Being a single window will retore the original location.
956 EXPECT_EQ("120,120 100x100", window3
->bounds().ToString());
959 // Test that user placed windows go back to their user placement after the user
960 // closes all other windows.
961 TEST_F(WorkspaceControllerTest
, TestUserHandledWindowRestore
) {
962 scoped_ptr
<aura::Window
> window1(CreateTestWindowInShellWithId(0));
963 gfx::Rect user_pos
= gfx::Rect(16, 42, 640, 320);
964 window1
->SetBounds(user_pos
);
965 wm::WindowState
* window1_state
= wm::GetWindowState(window1
.get());
967 window1_state
->SetPreAutoManageWindowBounds(user_pos
);
968 gfx::Rect desktop_area
= window1
->parent()->bounds();
970 // Create a second window to let the auto manager kick in.
971 scoped_ptr
<aura::Window
> window2(CreateTestWindowInShellWithId(1));
972 window2
->SetBounds(gfx::Rect(32, 48, 256, 512));
975 wm::GetWindowState(window1
.get())->set_window_position_managed(true);
976 wm::GetWindowState(window2
.get())->set_window_position_managed(true);
978 EXPECT_EQ(user_pos
.ToString(), window1
->bounds().ToString());
981 // |window1| should be flush left and |window2| flush right.
982 EXPECT_EQ("0," + base::IntToString(user_pos
.y()) +
983 " 640x320", window1
->bounds().ToString());
985 base::IntToString(desktop_area
.width() - window2
->bounds().width()) +
986 ",48 256x512", window2
->bounds().ToString());
989 // After the other window get hidden the window has to move back to the
990 // previous position and the bounds should still be set and unchanged.
991 EXPECT_EQ(user_pos
.ToString(), window1
->bounds().ToString());
992 ASSERT_TRUE(window1_state
->pre_auto_manage_window_bounds());
993 EXPECT_EQ(user_pos
.ToString(),
994 window1_state
->pre_auto_manage_window_bounds()->ToString());
997 // Test that a window from normal to minimize will repos the remaining.
998 TEST_F(WorkspaceControllerTest
, ToMinimizeRepositionsRemaining
) {
999 scoped_ptr
<aura::Window
> window1(CreateTestWindowInShellWithId(0));
1000 wm::WindowState
* window1_state
= wm::GetWindowState(window1
.get());
1001 window1_state
->set_window_position_managed(true);
1002 window1
->SetBounds(gfx::Rect(16, 32, 640, 320));
1003 gfx::Rect desktop_area
= window1
->parent()->bounds();
1005 scoped_ptr
<aura::Window
> window2(CreateTestWindowInShellWithId(1));
1006 wm::WindowState
* window2_state
= wm::GetWindowState(window2
.get());
1007 window2_state
->set_window_position_managed(true);
1008 window2
->SetBounds(gfx::Rect(32, 48, 256, 512));
1010 window1_state
->Minimize();
1012 // |window2| should be centered now.
1013 EXPECT_TRUE(window2
->IsVisible());
1014 EXPECT_TRUE(window2_state
->IsNormalShowState());
1015 EXPECT_EQ(base::IntToString(
1016 (desktop_area
.width() - window2
->bounds().width()) / 2) +
1017 ",48 256x512", window2
->bounds().ToString());
1019 window1_state
->Restore();
1020 // |window1| should be flush right and |window3| flush left.
1021 EXPECT_EQ(base::IntToString(
1022 desktop_area
.width() - window1
->bounds().width()) +
1023 ",32 640x320", window1
->bounds().ToString());
1024 EXPECT_EQ("0,48 256x512", window2
->bounds().ToString());
1027 // Test that minimizing an initially maximized window will repos the remaining.
1028 TEST_F(WorkspaceControllerTest
, MaxToMinRepositionsRemaining
) {
1029 scoped_ptr
<aura::Window
> window1(CreateTestWindowInShellWithId(0));
1030 wm::WindowState
* window1_state
= wm::GetWindowState(window1
.get());
1031 window1_state
->set_window_position_managed(true);
1032 gfx::Rect desktop_area
= window1
->parent()->bounds();
1034 scoped_ptr
<aura::Window
> window2(CreateTestWindowInShellWithId(1));
1035 wm::WindowState
* window2_state
= wm::GetWindowState(window2
.get());
1036 window2_state
->set_window_position_managed(true);
1037 window2
->SetBounds(gfx::Rect(32, 48, 256, 512));
1039 window1_state
->Maximize();
1040 window1_state
->Minimize();
1042 // |window2| should be centered now.
1043 EXPECT_TRUE(window2
->IsVisible());
1044 EXPECT_TRUE(window2_state
->IsNormalShowState());
1045 EXPECT_EQ(base::IntToString(
1046 (desktop_area
.width() - window2
->bounds().width()) / 2) +
1047 ",48 256x512", window2
->bounds().ToString());
1050 // Test that nomral, maximize, minimizing will repos the remaining.
1051 TEST_F(WorkspaceControllerTest
, NormToMaxToMinRepositionsRemaining
) {
1052 scoped_ptr
<aura::Window
> window1(CreateTestWindowInShellWithId(0));
1053 window1
->SetBounds(gfx::Rect(16, 32, 640, 320));
1054 wm::WindowState
* window1_state
= wm::GetWindowState(window1
.get());
1055 window1_state
->set_window_position_managed(true);
1056 gfx::Rect desktop_area
= window1
->parent()->bounds();
1058 scoped_ptr
<aura::Window
> window2(CreateTestWindowInShellWithId(1));
1059 wm::WindowState
* window2_state
= wm::GetWindowState(window2
.get());
1060 window2_state
->set_window_position_managed(true);
1061 window2
->SetBounds(gfx::Rect(32, 40, 256, 512));
1063 // Trigger the auto window placement function by showing (and hiding) it.
1067 // |window1| should be flush right and |window3| flush left.
1068 EXPECT_EQ(base::IntToString(
1069 desktop_area
.width() - window1
->bounds().width()) +
1070 ",32 640x320", window1
->bounds().ToString());
1071 EXPECT_EQ("0,40 256x512", window2
->bounds().ToString());
1073 window1_state
->Maximize();
1074 window1_state
->Minimize();
1076 // |window2| should be centered now.
1077 EXPECT_TRUE(window2
->IsVisible());
1078 EXPECT_TRUE(window2_state
->IsNormalShowState());
1079 EXPECT_EQ(base::IntToString(
1080 (desktop_area
.width() - window2
->bounds().width()) / 2) +
1081 ",40 256x512", window2
->bounds().ToString());
1084 // Test that nomral, maximize, normal will repos the remaining.
1085 TEST_F(WorkspaceControllerTest
, NormToMaxToNormRepositionsRemaining
) {
1086 scoped_ptr
<aura::Window
> window1(CreateTestWindowInShellWithId(0));
1087 window1
->SetBounds(gfx::Rect(16, 32, 640, 320));
1088 wm::WindowState
* window1_state
= wm::GetWindowState(window1
.get());
1089 window1_state
->set_window_position_managed(true);
1090 gfx::Rect desktop_area
= window1
->parent()->bounds();
1092 scoped_ptr
<aura::Window
> window2(CreateTestWindowInShellWithId(1));
1093 wm::GetWindowState(window2
.get())->set_window_position_managed(true);
1094 window2
->SetBounds(gfx::Rect(32, 40, 256, 512));
1096 // Trigger the auto window placement function by showing (and hiding) it.
1100 // |window1| should be flush right and |window3| flush left.
1101 EXPECT_EQ(base::IntToString(
1102 desktop_area
.width() - window1
->bounds().width()) +
1103 ",32 640x320", window1
->bounds().ToString());
1104 EXPECT_EQ("0,40 256x512", window2
->bounds().ToString());
1106 window1_state
->Maximize();
1107 window1_state
->Restore();
1109 // |window1| should be flush right and |window2| flush left.
1110 EXPECT_EQ(base::IntToString(
1111 desktop_area
.width() - window1
->bounds().width()) +
1112 ",32 640x320", window1
->bounds().ToString());
1113 EXPECT_EQ("0,40 256x512", window2
->bounds().ToString());
1116 // Test that animations are triggered.
1117 TEST_F(WorkspaceControllerTest
, AnimatedNormToMaxToNormRepositionsRemaining
) {
1118 ui::ScopedAnimationDurationScaleMode
normal_duration_mode(
1119 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION
);
1120 scoped_ptr
<aura::Window
> window1(CreateTestWindowInShellWithId(0));
1122 window1
->SetBounds(gfx::Rect(16, 32, 640, 320));
1123 gfx::Rect desktop_area
= window1
->parent()->bounds();
1124 scoped_ptr
<aura::Window
> window2(CreateTestWindowInShellWithId(1));
1126 window2
->SetBounds(gfx::Rect(32, 48, 256, 512));
1128 wm::GetWindowState(window1
.get())->set_window_position_managed(true);
1129 wm::GetWindowState(window2
.get())->set_window_position_managed(true);
1130 // Make sure nothing is animating.
1131 window1
->layer()->GetAnimator()->StopAnimating();
1132 window2
->layer()->GetAnimator()->StopAnimating();
1135 // The second window should now animate.
1136 EXPECT_FALSE(window1
->layer()->GetAnimator()->is_animating());
1137 EXPECT_TRUE(window2
->layer()->GetAnimator()->is_animating());
1138 window2
->layer()->GetAnimator()->StopAnimating();
1141 EXPECT_TRUE(window1
->layer()->GetAnimator()->is_animating());
1142 EXPECT_TRUE(window2
->layer()->GetAnimator()->is_animating());
1144 window1
->layer()->GetAnimator()->StopAnimating();
1145 window2
->layer()->GetAnimator()->StopAnimating();
1146 // |window1| should be flush right and |window2| flush left.
1147 EXPECT_EQ(base::IntToString(
1148 desktop_area
.width() - window1
->bounds().width()) +
1149 ",32 640x320", window1
->bounds().ToString());
1150 EXPECT_EQ("0,48 256x512", window2
->bounds().ToString());
1153 // This tests simulates a browser and an app and verifies the ordering of the
1154 // windows and layers doesn't get out of sync as various operations occur. Its
1155 // really testing code in FocusController, but easier to simulate here. Just as
1156 // with a real browser the browser here has a transient child window
1157 // (corresponds to the status bubble).
1158 TEST_F(WorkspaceControllerTest
, VerifyLayerOrdering
) {
1159 scoped_ptr
<Window
> browser(
1160 aura::test::CreateTestWindowWithDelegate(
1162 aura::client::WINDOW_TYPE_NORMAL
,
1163 gfx::Rect(5, 6, 7, 8),
1165 browser
->SetName("browser");
1166 SetDefaultParentByPrimaryRootWindow(browser
.get());
1168 wm::ActivateWindow(browser
.get());
1170 // |status_bubble| is made a transient child of |browser| and as a result
1171 // owned by |browser|.
1172 aura::test::TestWindowDelegate
* status_bubble_delegate
=
1173 aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate();
1174 status_bubble_delegate
->set_can_focus(false);
1175 Window
* status_bubble
=
1176 aura::test::CreateTestWindowWithDelegate(
1177 status_bubble_delegate
,
1178 aura::client::WINDOW_TYPE_POPUP
,
1179 gfx::Rect(5, 6, 7, 8),
1181 browser
->AddTransientChild(status_bubble
);
1182 SetDefaultParentByPrimaryRootWindow(status_bubble
);
1183 status_bubble
->SetName("status_bubble");
1185 scoped_ptr
<Window
> app(
1186 aura::test::CreateTestWindowWithDelegate(
1188 aura::client::WINDOW_TYPE_NORMAL
,
1189 gfx::Rect(5, 6, 7, 8),
1191 app
->SetName("app");
1192 SetDefaultParentByPrimaryRootWindow(app
.get());
1194 aura::Window
* parent
= browser
->parent();
1197 wm::ActivateWindow(app
.get());
1198 EXPECT_EQ(GetWindowNames(parent
), GetLayerNames(parent
));
1200 // Minimize the app, focus should go the browser.
1201 app
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MINIMIZED
);
1202 EXPECT_TRUE(wm::IsActiveWindow(browser
.get()));
1203 EXPECT_EQ(GetWindowNames(parent
), GetLayerNames(parent
));
1205 // Minimize the browser (neither windows are focused).
1206 browser
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MINIMIZED
);
1207 EXPECT_FALSE(wm::IsActiveWindow(browser
.get()));
1208 EXPECT_FALSE(wm::IsActiveWindow(app
.get()));
1209 EXPECT_EQ(GetWindowNames(parent
), GetLayerNames(parent
));
1211 // Show the browser (which should restore it).
1213 EXPECT_EQ(GetWindowNames(parent
), GetLayerNames(parent
));
1215 // Activate the browser.
1216 ash::wm::ActivateWindow(browser
.get());
1217 EXPECT_TRUE(wm::IsActiveWindow(browser
.get()));
1218 EXPECT_EQ(GetWindowNames(parent
), GetLayerNames(parent
));
1220 // Restore the app. This differs from above code for |browser| as internally
1221 // the app code does this. Restoring this way or using Show() should not make
1223 app
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_NORMAL
);
1224 EXPECT_EQ(GetWindowNames(parent
), GetLayerNames(parent
));
1226 // Activate the app.
1227 ash::wm::ActivateWindow(app
.get());
1228 EXPECT_TRUE(wm::IsActiveWindow(app
.get()));
1229 EXPECT_EQ(GetWindowNames(parent
), GetLayerNames(parent
));
1234 // Used by DragMaximizedNonTrackedWindow to track how many times the window
1235 // hierarchy changes.
1236 class DragMaximizedNonTrackedWindowObserver
1237 : public aura::WindowObserver
{
1239 DragMaximizedNonTrackedWindowObserver() : change_count_(0) {
1242 // Number of times OnWindowHierarchyChanged() has been received.
1243 void clear_change_count() { change_count_
= 0; }
1244 int change_count() const {
1245 return change_count_
;
1248 // aura::WindowObserver overrides:
1249 // Counts number of times a window is reparented. Ignores reparenting into and
1250 // from a docked container which is expected when a tab is dragged.
1251 virtual void OnWindowHierarchyChanged(
1252 const HierarchyChangeParams
& params
) OVERRIDE
{
1253 if ((params
.old_parent
->id() == kShellWindowId_DefaultContainer
&&
1254 params
.new_parent
->id() == kShellWindowId_DockedContainer
) ||
1255 (params
.old_parent
->id() == kShellWindowId_DockedContainer
&&
1256 params
.new_parent
->id() == kShellWindowId_DefaultContainer
)) {
1265 DISALLOW_COPY_AND_ASSIGN(DragMaximizedNonTrackedWindowObserver
);
1270 // Verifies setting tracked by workspace to false and then dragging a fullscreen
1271 // window doesn't result in changing the window hierarchy (which typically
1272 // indicates new workspaces have been created).
1273 TEST_F(WorkspaceControllerTest
, DragFullscreenNonTrackedWindow
) {
1274 aura::test::EventGenerator
generator(
1275 Shell::GetPrimaryRootWindow(), gfx::Point());
1276 generator
.MoveMouseTo(5, 5);
1278 aura::test::TestWindowDelegate delegate
;
1279 delegate
.set_window_component(HTCAPTION
);
1280 scoped_ptr
<Window
> w1(
1281 aura::test::CreateTestWindowWithDelegate(&delegate
,
1282 aura::client::WINDOW_TYPE_NORMAL
,
1283 gfx::Rect(5, 6, 7, 8),
1285 SetDefaultParentByPrimaryRootWindow(w1
.get());
1286 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_FULLSCREEN
);
1288 wm::ActivateWindow(w1
.get());
1289 DragMaximizedNonTrackedWindowObserver observer
;
1290 w1
->parent()->parent()->AddObserver(&observer
);
1291 const gfx::Rect
max_bounds(w1
->bounds());
1293 generator
.PressLeftButton();
1294 generator
.MoveMouseTo(100, 100);
1295 // The bounds shouldn't change (drag should result in nothing happening
1297 EXPECT_EQ(max_bounds
.ToString(), w1
->bounds().ToString());
1299 generator
.ReleaseLeftButton();
1300 EXPECT_EQ(0, observer
.change_count());
1302 // Set tracked to false and repeat, now the window should move.
1303 wm::GetWindowState(w1
.get())->SetTrackedByWorkspace(false);
1304 generator
.MoveMouseTo(5, 5);
1305 generator
.PressLeftButton();
1306 generator
.MoveMouseBy(100, 100);
1307 EXPECT_EQ(gfx::Rect(max_bounds
.x() + 100, max_bounds
.y() + 100,
1308 max_bounds
.width(), max_bounds
.height()).ToString(),
1309 w1
->bounds().ToString());
1311 generator
.ReleaseLeftButton();
1312 wm::GetWindowState(w1
.get())->SetTrackedByWorkspace(true);
1313 // Marking the window tracked again should snap back to origin.
1314 EXPECT_EQ(max_bounds
.ToString(), w1
->bounds().ToString());
1315 EXPECT_EQ(0, observer
.change_count());
1317 w1
->parent()->parent()->RemoveObserver(&observer
);
1320 // Verifies setting tracked by workspace to false and then dragging a maximized
1321 // window can change the bound.
1322 TEST_F(WorkspaceControllerTest
, DragMaximizedNonTrackedWindow
) {
1323 aura::test::EventGenerator
generator(
1324 Shell::GetPrimaryRootWindow(), gfx::Point());
1325 generator
.MoveMouseTo(5, 5);
1327 aura::test::TestWindowDelegate delegate
;
1328 delegate
.set_window_component(HTCAPTION
);
1329 scoped_ptr
<Window
> w1(
1330 aura::test::CreateTestWindowWithDelegate(&delegate
,
1331 aura::client::WINDOW_TYPE_NORMAL
,
1332 gfx::Rect(5, 6, 7, 8),
1334 SetDefaultParentByPrimaryRootWindow(w1
.get());
1335 w1
->SetProperty(aura::client::kShowStateKey
, ui::SHOW_STATE_MAXIMIZED
);
1337 wm::ActivateWindow(w1
.get());
1338 DragMaximizedNonTrackedWindowObserver observer
;
1339 w1
->parent()->parent()->AddObserver(&observer
);
1340 const gfx::Rect
max_bounds(w1
->bounds());
1342 generator
.PressLeftButton();
1343 generator
.MoveMouseTo(100, 100);
1344 // The bounds shouldn't change (drag should result in nothing happening
1346 EXPECT_EQ(max_bounds
.ToString(), w1
->bounds().ToString());
1348 generator
.ReleaseLeftButton();
1349 EXPECT_EQ(0, observer
.change_count());
1351 // Set tracked to false and repeat, now the window should move.
1352 wm::GetWindowState(w1
.get())->SetTrackedByWorkspace(false);
1353 generator
.MoveMouseTo(5, 5);
1354 generator
.PressLeftButton();
1355 generator
.MoveMouseBy(100, 100);
1356 EXPECT_EQ(gfx::Rect(max_bounds
.x() + 100, max_bounds
.y() + 100,
1357 max_bounds
.width(), max_bounds
.height()).ToString(),
1358 w1
->bounds().ToString());
1360 generator
.ReleaseLeftButton();
1361 wm::GetWindowState(w1
.get())->SetTrackedByWorkspace(true);
1362 // Marking the window tracked again should snap back to origin.
1363 EXPECT_EQ(max_bounds
.ToString(), w1
->bounds().ToString());
1364 EXPECT_EQ(0, observer
.change_count());
1366 w1
->parent()->parent()->RemoveObserver(&observer
);
1369 // Verifies that a new maximized window becomes visible after its activation
1370 // is requested, even though it does not become activated because a system
1371 // modal window is active.
1372 TEST_F(WorkspaceControllerTest
, SwitchFromModal
) {
1373 scoped_ptr
<Window
> modal_window(CreateTestWindowUnparented());
1374 modal_window
->SetBounds(gfx::Rect(10, 11, 21, 22));
1375 modal_window
->SetProperty(aura::client::kModalKey
, ui::MODAL_TYPE_SYSTEM
);
1376 SetDefaultParentByPrimaryRootWindow(modal_window
.get());
1377 modal_window
->Show();
1378 wm::ActivateWindow(modal_window
.get());
1380 scoped_ptr
<Window
> maximized_window(CreateTestWindow());
1381 maximized_window
->SetProperty(
1382 aura::client::kShowStateKey
, ui::SHOW_STATE_MAXIMIZED
);
1383 maximized_window
->Show();
1384 wm::ActivateWindow(maximized_window
.get());
1385 EXPECT_TRUE(maximized_window
->IsVisible());
1388 } // namespace internal