Morph the selector widget to a constant padding on the window shapes in overview.
[chromium-blink-merge.git] / ash / wm / workspace_controller_unittest.cc
blobecb8248acc44bab4fd923fd5893d2af94ee6de1a
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"
7 #include <map>
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"
37 using aura::Window;
39 namespace ash {
40 namespace internal {
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) {
45 std::string result;
46 for (size_t i = 0; i < window->children().size(); ++i) {
47 if (i != 0)
48 result += " ";
49 result += window->children()[i]->name();
51 return result;
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
57 // ordering.
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();
66 std::string result;
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()) {
72 if (!result.empty())
73 result += " ";
74 result += layer_i->second;
77 return result;
80 class WorkspaceControllerTest : public test::AshTestBase {
81 public:
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);
90 return window;
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);
99 return 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);
108 window->Show();
109 return window;
112 aura::Window* CreatePopupLikeWindow(const gfx::Rect& bounds) {
113 aura::Window* window = CreateTestWindowInShellWithBounds(bounds);
114 window->Show();
115 return window;
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();
139 private:
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());
152 w1->Show();
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));
169 w1->Show();
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));
202 w1->Show();
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);
209 w2->Show();
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]);
216 gfx::Rect work_area(
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());
231 w1->Show();
233 // Setting the bounds should go through since the window is in the normal
234 // workspace.
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);
258 w1->Show();
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());
289 w1->Show();
291 w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
292 EXPECT_FALSE(w1->layer()->IsDrawn());
294 // Show the window.
295 w1->Show();
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());
305 w1->Show();
306 w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
307 w2->Show();
309 wm::WindowState* w1_state = wm::GetWindowState(w1.get());
310 wm::WindowState* w2_state = wm::GetWindowState(w2.get());
312 w2_state->Activate();
314 // Minimize w2.
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.
320 w2->Show();
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
342 // updated.
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);
364 w_ignored->Show();
365 EXPECT_FALSE(GetWindowOverlapsShelf());
367 // Make it visible, since visible shelf overlaps should be true.
368 w1->Show();
369 EXPECT_TRUE(GetWindowOverlapsShelf());
371 wm::ActivateWindow(w1.get());
372 w1->SetBounds(w1_bounds);
373 w1->Show();
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());
383 // Restore.
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());
388 // Fullscreen.
389 w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
390 EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state());
392 // Normal.
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());
402 // Move it back.
403 w1->SetBounds(w1_bounds);
404 EXPECT_FALSE(GetWindowOverlapsShelf());
406 // Maximize again.
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());
411 // Minimize.
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);
426 // 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);
435 w2->Show();
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());
441 // Switch to w1.
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());
449 // Switch to w2.
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
468 // w2 is maximized.
469 wm::ActivateWindow(w1.get());
470 EXPECT_FALSE(GetWindowOverlapsShelf());
472 // Restore w2.
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());
481 w1->Show();
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());
495 w1->Show();
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());
501 w2->Show();
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);
529 w2->Hide();
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());
536 w2->Show();
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());
543 // Close |w2|.
544 w2.reset();
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);
561 w1->Show();
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);
568 w2->Show();
569 wm::ActivateWindow(w2.get());
571 // Switch to w1.
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
577 // workspaces.
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);
588 w1->Show();
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);
596 w2->Show();
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.
601 gfx::Insets insets =
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());
611 namespace {
613 // WindowDelegate used by DontCrashOnChangeAndActivate.
614 class DontCrashOnChangeAndActivateDelegate
615 : public aura::test::TestWindowDelegate {
616 public:
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 {
624 if (window_) {
625 wm::ActivateWindow(window_);
626 window_ = NULL;
630 private:
631 aura::Window* window_;
633 DISALLOW_COPY_AND_ASSIGN(DontCrashOnChangeAndActivateDelegate);
636 } // namespace
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) {
644 // Force the shelf
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)));
652 w1->Show();
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
661 // window active.
662 shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
664 SetDefaultParentByPrimaryRootWindow(w1.get());
665 delegate.set_window(w1.get());
666 w1->Show();
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));
674 w2->Show();
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());
683 w1->Show();
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());
695 w1->Show();
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
702 // manager.
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());
707 w2->Show();
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());
719 bounds.Offset(4, 5);
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
724 // workspace.
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())
735 return;
736 UpdateDisplay("1600x1200");
737 // Creating a popup handler here to make sure it does not interfere with the
738 // existing windows.
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.
799 window2->Hide();
800 window2->SetBounds(gfx::Rect(32, 48, 256, 512));
801 window2->Show();
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.
809 window2.reset();
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.
820 window3->Hide();
821 window3->SetBounds(gfx::Rect(32, 48, 256, 512));
822 window3->Show();
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.
830 window3.reset();
831 EXPECT_EQ(
832 base::IntToString(
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
837 // positioning.
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.
841 window1->Hide();
842 window1->SetBounds(gfx::Rect(16, 32, 640, 320));
843 window4->SetBounds(gfx::Rect(32, 48, 256, 512));
844 window1->Show();
845 // |window1| should be centered and |window4| untouched.
846 EXPECT_EQ(
847 base::IntToString(
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.
853 window4.reset();
854 window1_state->set_bounds_changed_by_user(false);
855 // Trigger the auto window placement function by showing (and hiding) it.
856 window1->Hide();
857 window1->Show();
858 // |window1| should be centered.
859 EXPECT_EQ(
860 base::IntToString(
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));
872 window1->Hide();
873 window2->Hide();
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);
885 window1->Show();
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).
893 window2->Show();
895 // |window1| should be flush left and |window2| flush right.
896 EXPECT_EQ("0,32 640x320", window1->bounds().ToString());
897 EXPECT_EQ(
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);
906 window2->Hide();
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)));
919 window1->Hide();
920 window2->Hide();
921 window3->Hide();
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);
926 window1->Show();
927 wm::ActivateWindow(window1.get());
928 window2->Show();
929 wm::ActivateWindow(window2.get());
930 window3->Show();
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());
937 window1->Hide();
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.
943 window3->Hide();
944 wm::ActivateWindow(window2.get());
945 EXPECT_EQ("110,110 100x100", window2->bounds().ToString());
947 // Showing the 3rd will push the 2nd window left.
948 window3->Show();
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.
955 window2->Hide();
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));
973 window1->Hide();
974 window2->Hide();
975 wm::GetWindowState(window1.get())->set_window_position_managed(true);
976 wm::GetWindowState(window2.get())->set_window_position_managed(true);
977 window1->Show();
978 EXPECT_EQ(user_pos.ToString(), window1->bounds().ToString());
979 window2->Show();
981 // |window1| should be flush left and |window2| flush right.
982 EXPECT_EQ("0," + base::IntToString(user_pos.y()) +
983 " 640x320", window1->bounds().ToString());
984 EXPECT_EQ(
985 base::IntToString(desktop_area.width() - window2->bounds().width()) +
986 ",48 256x512", window2->bounds().ToString());
987 window2->Hide();
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.
1064 window1->Hide();
1065 window1->Show();
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.
1097 window1->Hide();
1098 window1->Show();
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));
1121 window1->Hide();
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));
1125 window2->Hide();
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();
1133 window2->Show();
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();
1140 window1->Show();
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(
1161 NULL,
1162 aura::client::WINDOW_TYPE_NORMAL,
1163 gfx::Rect(5, 6, 7, 8),
1164 NULL));
1165 browser->SetName("browser");
1166 SetDefaultParentByPrimaryRootWindow(browser.get());
1167 browser->Show();
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),
1180 NULL);
1181 browser->AddTransientChild(status_bubble);
1182 SetDefaultParentByPrimaryRootWindow(status_bubble);
1183 status_bubble->SetName("status_bubble");
1185 scoped_ptr<Window> app(
1186 aura::test::CreateTestWindowWithDelegate(
1187 NULL,
1188 aura::client::WINDOW_TYPE_NORMAL,
1189 gfx::Rect(5, 6, 7, 8),
1190 NULL));
1191 app->SetName("app");
1192 SetDefaultParentByPrimaryRootWindow(app.get());
1194 aura::Window* parent = browser->parent();
1196 app->Show();
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).
1212 browser->Show();
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
1222 // a difference.
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));
1232 namespace {
1234 // Used by DragMaximizedNonTrackedWindow to track how many times the window
1235 // hierarchy changes.
1236 class DragMaximizedNonTrackedWindowObserver
1237 : public aura::WindowObserver {
1238 public:
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)) {
1257 return;
1259 change_count_++;
1262 private:
1263 int change_count_;
1265 DISALLOW_COPY_AND_ASSIGN(DragMaximizedNonTrackedWindowObserver);
1268 } // namespace
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),
1284 NULL));
1285 SetDefaultParentByPrimaryRootWindow(w1.get());
1286 w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
1287 w1->Show();
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
1296 // now.
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),
1333 NULL));
1334 SetDefaultParentByPrimaryRootWindow(w1.get());
1335 w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
1336 w1->Show();
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
1345 // now.
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
1389 } // namespace ash