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/launcher/launcher.h"
6 #include "ash/root_window_controller.h"
7 #include "ash/screen_ash.h"
8 #include "ash/shelf/shelf_widget.h"
10 #include "ash/test/ash_test_base.h"
11 #include "ash/test/launcher_test_api.h"
12 #include "ash/test/shelf_view_test_api.h"
13 #include "ash/test/shell_test_api.h"
14 #include "ash/test/test_launcher_delegate.h"
15 #include "ash/wm/mru_window_tracker.h"
16 #include "ash/wm/overview/window_selector.h"
17 #include "ash/wm/overview/window_selector_controller.h"
18 #include "ash/wm/window_state.h"
19 #include "ash/wm/window_util.h"
20 #include "base/basictypes.h"
21 #include "base/compiler_specific.h"
22 #include "base/memory/scoped_vector.h"
23 #include "base/run_loop.h"
24 #include "ui/aura/client/activation_delegate.h"
25 #include "ui/aura/client/aura_constants.h"
26 #include "ui/aura/client/cursor_client.h"
27 #include "ui/aura/client/focus_client.h"
28 #include "ui/aura/root_window.h"
29 #include "ui/aura/test/event_generator.h"
30 #include "ui/aura/test/test_window_delegate.h"
31 #include "ui/aura/test/test_windows.h"
32 #include "ui/aura/window.h"
33 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
34 #include "ui/gfx/rect_conversions.h"
35 #include "ui/gfx/transform.h"
42 class NonActivatableActivationDelegate
43 : public aura::client::ActivationDelegate {
45 virtual bool ShouldActivate() const OVERRIDE {
50 bool IsWindowAbove(aura::Window* w1, aura::Window* w2) {
51 aura::Window* parent = w1->parent();
52 DCHECK_EQ(parent, w2->parent());
53 for (aura::Window::Windows::const_iterator iter = parent->children().begin();
54 iter != parent->children().end(); ++iter) {
64 aura::Window* GetWindowByName(aura::Window* container,
65 const std::string& name) {
66 aura::Window* window = NULL;
67 for (aura::Window::Windows::const_iterator iter =
68 container->children().begin(); iter != container->children().end();
70 if ((*iter)->name() == name) {
71 // The name should be unique.
79 // Returns the copy of |window| created for overview. It is found using the
80 // window name which should be the same as the source window's name with a
81 // special suffix, and in the same container as the source window.
82 aura::Window* GetCopyWindow(aura::Window* window) {
83 aura::Window* copy_window = NULL;
84 std::string copy_name = window->name() + " (Copy)";
85 std::vector<aura::Window*> containers(
86 Shell::GetContainersFromAllRootWindows(window->parent()->id(), NULL));
87 for (std::vector<aura::Window*>::iterator iter = containers.begin();
88 iter != containers.end(); ++iter) {
89 aura::Window* found = GetWindowByName(*iter, copy_name);
91 // There should only be one copy window.
101 class WindowSelectorTest : public test::AshTestBase {
103 WindowSelectorTest() {}
104 virtual ~WindowSelectorTest() {}
106 virtual void SetUp() OVERRIDE {
107 test::AshTestBase::SetUp();
108 ASSERT_TRUE(test::TestLauncherDelegate::instance());
110 shelf_view_test_.reset(new test::ShelfViewTestAPI(
111 test::LauncherTestAPI(Launcher::ForPrimaryDisplay()).shelf_view()));
112 shelf_view_test_->SetAnimationDuration(1);
115 aura::Window* CreateWindow(const gfx::Rect& bounds) {
116 return CreateTestWindowInShellWithDelegate(&delegate_, -1, bounds);
119 aura::Window* CreateNonActivatableWindow(const gfx::Rect& bounds) {
120 aura::Window* window = CreateWindow(bounds);
121 aura::client::SetActivationDelegate(window,
122 &non_activatable_activation_delegate_);
123 EXPECT_FALSE(ash::wm::CanActivateWindow(window));
127 aura::Window* CreatePanelWindow(const gfx::Rect& bounds) {
128 aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
129 NULL, aura::client::WINDOW_TYPE_PANEL, 0, bounds);
130 test::TestLauncherDelegate::instance()->AddLauncherItem(window);
131 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
135 bool WindowsOverlapping(aura::Window* window1, aura::Window* window2) {
136 gfx::RectF window1_bounds = GetTransformedTargetBounds(window1);
137 gfx::RectF window2_bounds = GetTransformedTargetBounds(window2);
138 return window1_bounds.Intersects(window2_bounds);
141 void ToggleOverview() {
142 ash::Shell::GetInstance()->window_selector_controller()->ToggleOverview();
145 void Cycle(WindowSelector::Direction direction) {
146 ash::Shell::GetInstance()->window_selector_controller()->
147 HandleCycleWindow(direction);
151 ash::Shell::GetInstance()->window_selector_controller()->window_selector_->
155 void FireOverviewStartTimer() {
156 // Calls the method to start overview mode which is normally called by the
157 // timer. The timer will still fire and call this method triggering the
158 // DCHECK that overview mode was not already started, except that we call
159 // StopCycling before the timer has a chance to fire.
160 ash::Shell::GetInstance()->window_selector_controller()->window_selector_->
164 gfx::Transform GetTransformRelativeTo(gfx::PointF origin,
165 const gfx::Transform& transform) {
167 t.Translate(origin.x(), origin.y());
168 t.PreconcatTransform(transform);
169 t.Translate(-origin.x(), -origin.y());
173 gfx::RectF GetTransformedBounds(aura::Window* window) {
174 gfx::RectF bounds(ash::ScreenAsh::ConvertRectToScreen(
175 window->parent(), window->layer()->bounds()));
176 gfx::Transform transform(GetTransformRelativeTo(bounds.origin(),
177 window->layer()->transform()));
178 transform.TransformRect(&bounds);
182 gfx::RectF GetTransformedTargetBounds(aura::Window* window) {
183 gfx::RectF bounds(ash::ScreenAsh::ConvertRectToScreen(
184 window->parent(), window->layer()->GetTargetBounds()));
185 gfx::Transform transform(GetTransformRelativeTo(bounds.origin(),
186 window->layer()->GetTargetTransform()));
187 transform.TransformRect(&bounds);
191 void ClickWindow(aura::Window* window) {
192 aura::test::EventGenerator event_generator(window->GetRootWindow(), window);
193 gfx::RectF target = GetTransformedBounds(window);
194 event_generator.ClickLeftButton();
198 return ash::Shell::GetInstance()->window_selector_controller()->
202 aura::Window* GetFocusedWindow() {
203 return aura::client::GetFocusClient(
204 Shell::GetPrimaryRootWindow())->GetFocusedWindow();
207 test::ShelfViewTestAPI* shelf_view_test() {
208 return shelf_view_test_.get();
212 aura::test::TestWindowDelegate delegate_;
213 NonActivatableActivationDelegate non_activatable_activation_delegate_;
214 scoped_ptr<test::ShelfViewTestAPI> shelf_view_test_;
216 DISALLOW_COPY_AND_ASSIGN(WindowSelectorTest);
219 // Tests entering overview mode with two windows and selecting one.
220 TEST_F(WindowSelectorTest, Basic) {
221 gfx::Rect bounds(0, 0, 400, 400);
222 aura::Window* root_window = Shell::GetPrimaryRootWindow();
223 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
224 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
225 scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
226 scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds));
227 EXPECT_TRUE(WindowsOverlapping(window1.get(), window2.get()));
228 EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get()));
229 wm::ActivateWindow(window2.get());
230 EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
231 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
232 EXPECT_EQ(window2.get(), GetFocusedWindow());
233 // Hide the cursor before entering overview to test that it will be shown.
234 aura::client::GetCursorClient(root_window)->HideCursor();
236 // In overview mode the windows should no longer overlap and focus should
237 // be removed from the window.
239 EXPECT_EQ(NULL, GetFocusedWindow());
240 EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get()));
241 EXPECT_FALSE(WindowsOverlapping(window1.get(), panel1.get()));
242 // Panels 1 and 2 should still be overlapping being in a single selector
244 EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get()));
246 // The cursor should be visible and locked as a pointer
247 EXPECT_EQ(ui::kCursorPointer,
248 root_window->GetDispatcher()->last_cursor().native_type());
249 EXPECT_TRUE(aura::client::GetCursorClient(root_window)->IsCursorLocked());
250 EXPECT_TRUE(aura::client::GetCursorClient(root_window)->IsCursorVisible());
252 // Clicking window 1 should activate it.
253 ClickWindow(window1.get());
254 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
255 EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
256 EXPECT_EQ(window1.get(), GetFocusedWindow());
258 // Cursor should have been unlocked.
259 EXPECT_FALSE(aura::client::GetCursorClient(root_window)->IsCursorLocked());
262 // Tests that the shelf dimming state is removed while in overview and restored
263 // on exiting overview.
264 TEST_F(WindowSelectorTest, OverviewUndimsShelf) {
265 gfx::Rect bounds(0, 0, 400, 400);
266 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
267 wm::WindowState* window_state = wm::GetWindowState(window1.get());
268 window_state->Maximize();
269 ash::ShelfWidget* shelf = Shell::GetPrimaryRootWindowController()->shelf();
270 EXPECT_TRUE(shelf->GetDimsShelf());
272 EXPECT_FALSE(shelf->GetDimsShelf());
274 EXPECT_TRUE(shelf->GetDimsShelf());
277 // Tests that beginning window selection hides the app list.
278 TEST_F(WindowSelectorTest, SelectingHidesAppList) {
279 gfx::Rect bounds(0, 0, 400, 400);
280 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
281 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
282 Shell::GetInstance()->ToggleAppList(NULL);
283 EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility());
285 EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility());
288 // The app list uses an animation to fade out. If it is toggled on immediately
289 // after being removed the old widget is re-used and it does not gain focus.
290 // When running under normal circumstances this shouldn't be possible, but
291 // it is in a test without letting the message loop run.
292 RunAllPendingInMessageLoop();
294 Shell::GetInstance()->ToggleAppList(NULL);
295 EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility());
296 Cycle(WindowSelector::FORWARD);
297 EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility());
301 // Tests that a minimized window's visibility and layer visibility is correctly
302 // changed when entering overview and restored when leaving overview mode.
303 TEST_F(WindowSelectorTest, MinimizedWindowVisibility) {
304 gfx::Rect bounds(0, 0, 400, 400);
305 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
306 wm::WindowState* window_state = wm::GetWindowState(window1.get());
307 window_state->Minimize();
308 EXPECT_FALSE(window1->IsVisible());
309 EXPECT_FALSE(window1->layer()->GetTargetVisibility());
311 ui::ScopedAnimationDurationScaleMode normal_duration_mode(
312 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
314 EXPECT_TRUE(window1->IsVisible());
315 EXPECT_TRUE(window1->layer()->GetTargetVisibility());
318 ui::ScopedAnimationDurationScaleMode normal_duration_mode(
319 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
321 EXPECT_FALSE(window1->IsVisible());
322 EXPECT_FALSE(window1->layer()->GetTargetVisibility());
326 // Tests that a bounds change during overview is corrected for.
327 TEST_F(WindowSelectorTest, BoundsChangeDuringOverview) {
328 scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 400, 400)));
330 gfx::Rect overview_bounds =
331 ToEnclosingRect(GetTransformedTargetBounds(window.get()));
332 window->SetBounds(gfx::Rect(200, 0, 200, 200));
333 gfx::Rect new_overview_bounds =
334 ToEnclosingRect(GetTransformedTargetBounds(window.get()));
335 EXPECT_EQ(overview_bounds.x(), new_overview_bounds.x());
336 EXPECT_EQ(overview_bounds.y(), new_overview_bounds.y());
337 EXPECT_EQ(overview_bounds.width(), new_overview_bounds.width());
338 EXPECT_EQ(overview_bounds.height(), new_overview_bounds.height());
342 // Tests entering overview mode with three windows and cycling through them.
343 TEST_F(WindowSelectorTest, BasicCycle) {
344 gfx::Rect bounds(0, 0, 400, 400);
345 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
346 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
347 scoped_ptr<aura::Window> window3(CreateWindow(bounds));
348 wm::ActivateWindow(window3.get());
349 wm::ActivateWindow(window2.get());
350 wm::ActivateWindow(window1.get());
351 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
352 EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
353 EXPECT_FALSE(wm::IsActiveWindow(window3.get()));
355 Cycle(WindowSelector::FORWARD);
356 EXPECT_TRUE(IsSelecting());
357 Cycle(WindowSelector::FORWARD);
359 EXPECT_FALSE(IsSelecting());
360 EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
361 EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
362 EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
365 // Tests that cycling through windows preserves the window stacking order.
366 TEST_F(WindowSelectorTest, CyclePreservesStackingOrder) {
367 gfx::Rect bounds(0, 0, 400, 400);
368 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
369 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
370 scoped_ptr<aura::Window> window3(CreateWindow(bounds));
371 wm::ActivateWindow(window3.get());
372 wm::ActivateWindow(window2.get());
373 wm::ActivateWindow(window1.get());
374 // Window order from top to bottom is 1, 2, 3.
375 EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get()));
376 EXPECT_TRUE(IsWindowAbove(window2.get(), window3.get()));
379 Cycle(WindowSelector::FORWARD);
380 EXPECT_TRUE(IsWindowAbove(window2.get(), window1.get()));
381 EXPECT_TRUE(IsWindowAbove(window1.get(), window3.get()));
384 Cycle(WindowSelector::FORWARD);
385 EXPECT_TRUE(IsWindowAbove(window3.get(), window1.get()));
386 EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get()));
389 Cycle(WindowSelector::FORWARD);
390 EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get()));
391 EXPECT_TRUE(IsWindowAbove(window2.get(), window3.get()));
395 // Tests that cycling through windows shows and minimizes windows as they
397 TEST_F(WindowSelectorTest, CyclePreservesMinimization) {
398 gfx::Rect bounds(0, 0, 400, 400);
399 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
400 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
401 wm::ActivateWindow(window2.get());
402 wm::GetWindowState(window2.get())->Minimize();
403 wm::ActivateWindow(window1.get());
404 EXPECT_TRUE(wm::IsWindowMinimized(window2.get()));
407 Cycle(WindowSelector::FORWARD);
408 EXPECT_FALSE(wm::IsWindowMinimized(window2.get()));
411 Cycle(WindowSelector::FORWARD);
412 EXPECT_TRUE(wm::IsWindowMinimized(window2.get()));
415 EXPECT_TRUE(wm::IsWindowMinimized(window2.get()));
418 // Tests beginning cycling while in overview mode.
419 TEST_F(WindowSelectorTest, OverviewTransitionToCycle) {
420 gfx::Rect bounds(0, 0, 400, 400);
421 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
422 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
423 wm::ActivateWindow(window2.get());
424 wm::ActivateWindow(window1.get());
427 Cycle(WindowSelector::FORWARD);
430 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
431 EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
432 EXPECT_EQ(window2.get(), GetFocusedWindow());
435 // Tests cycles between panel and normal windows.
436 TEST_F(WindowSelectorTest, CyclePanels) {
437 gfx::Rect bounds(0, 0, 400, 400);
438 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
439 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
440 scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
441 scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds));
442 wm::ActivateWindow(window2.get());
443 wm::ActivateWindow(window1.get());
444 wm::ActivateWindow(panel2.get());
445 wm::ActivateWindow(panel1.get());
446 EXPECT_TRUE(wm::IsActiveWindow(panel1.get()));
448 // Cycling once should select window1 since the panels are grouped into a
449 // single selectable item.
450 Cycle(WindowSelector::FORWARD);
452 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
454 // Cycling again should select the most recently used panel.
455 Cycle(WindowSelector::FORWARD);
457 EXPECT_TRUE(wm::IsActiveWindow(panel1.get()));
460 // Tests the visibility of panel windows during cycling.
461 TEST_F(WindowSelectorTest, CyclePanelVisibility) {
462 gfx::Rect bounds(0, 0, 400, 400);
463 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
464 scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
465 wm::ActivateWindow(panel1.get());
466 wm::ActivateWindow(window1.get());
468 Cycle(WindowSelector::FORWARD);
469 FireOverviewStartTimer();
470 EXPECT_EQ(1.0f, panel1->layer()->GetTargetOpacity());
474 // Tests cycles between panel and normal windows.
475 TEST_F(WindowSelectorTest, CyclePanelsDestroyed) {
476 gfx::Rect bounds(0, 0, 400, 400);
477 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
478 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
479 scoped_ptr<aura::Window> window3(CreateWindow(bounds));
480 scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
481 scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds));
482 wm::ActivateWindow(window3.get());
483 wm::ActivateWindow(panel2.get());
484 wm::ActivateWindow(panel1.get());
485 wm::ActivateWindow(window2.get());
486 wm::ActivateWindow(window1.get());
487 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
489 // Cycling once highlights window2.
490 Cycle(WindowSelector::FORWARD);
491 // All panels are destroyed.
494 // Cycling again should now select window3.
495 Cycle(WindowSelector::FORWARD);
497 EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
500 // Tests cycles between panel and normal windows.
501 TEST_F(WindowSelectorTest, CycleMruPanelDestroyed) {
502 gfx::Rect bounds(0, 0, 400, 400);
503 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
504 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
505 scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
506 scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds));
507 wm::ActivateWindow(panel2.get());
508 wm::ActivateWindow(panel1.get());
509 wm::ActivateWindow(window2.get());
510 wm::ActivateWindow(window1.get());
511 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
513 // Cycling once highlights window2.
514 Cycle(WindowSelector::FORWARD);
515 // Panel 1 is the next item as the MRU panel, removing it should make panel 2
516 // the next window to be selected.
518 // Cycling again should now select window3.
519 Cycle(WindowSelector::FORWARD);
521 EXPECT_TRUE(wm::IsActiveWindow(panel2.get()));
524 // Tests that a newly created window aborts overview.
525 TEST_F(WindowSelectorTest, NewWindowCancelsOveriew) {
526 gfx::Rect bounds(0, 0, 400, 400);
527 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
528 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
530 EXPECT_TRUE(IsSelecting());
532 // A window being created should exit overview mode.
533 scoped_ptr<aura::Window> window3(CreateWindow(bounds));
534 EXPECT_FALSE(IsSelecting());
537 // Tests that a window activation exits overview mode.
538 TEST_F(WindowSelectorTest, ActivationCancelsOveriew) {
539 gfx::Rect bounds(0, 0, 400, 400);
540 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
541 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
544 EXPECT_TRUE(IsSelecting());
546 // A window being activated should exit overview mode.
548 EXPECT_FALSE(IsSelecting());
550 // window1 should be focused after exiting even though window2 was focused on
551 // entering overview because we exited due to an activation.
552 EXPECT_EQ(window1.get(), GetFocusedWindow());
555 // Verifies that overview mode only begins after a delay when cycling.
556 TEST_F(WindowSelectorTest, CycleOverviewDelay) {
557 gfx::Rect bounds(0, 0, 400, 400);
558 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
559 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
560 EXPECT_TRUE(WindowsOverlapping(window1.get(), window2.get()));
562 // When cycling first starts, the windows will still be overlapping.
563 Cycle(WindowSelector::FORWARD);
564 EXPECT_TRUE(IsSelecting());
565 EXPECT_TRUE(WindowsOverlapping(window1.get(), window2.get()));
567 // Once the overview timer fires, the windows should no longer overlap.
568 FireOverviewStartTimer();
569 EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get()));
573 // Tests that exiting overview mode without selecting a window restores focus
574 // to the previously focused window.
575 TEST_F(WindowSelectorTest, CancelRestoresFocus) {
576 gfx::Rect bounds(0, 0, 400, 400);
577 scoped_ptr<aura::Window> window(CreateWindow(bounds));
578 wm::ActivateWindow(window.get());
579 EXPECT_EQ(window.get(), GetFocusedWindow());
581 // In overview mode, focus should be removed.
583 EXPECT_EQ(NULL, GetFocusedWindow());
585 // If canceling overview mode, focus should be restored.
587 EXPECT_EQ(window.get(), GetFocusedWindow());
590 // Tests that overview mode is exited if the last remaining window is destroyed.
591 TEST_F(WindowSelectorTest, LastWindowDestroyed) {
592 gfx::Rect bounds(0, 0, 400, 400);
593 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
594 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
599 EXPECT_FALSE(IsSelecting());
602 // Tests that entering overview mode restores a window to its original
604 TEST_F(WindowSelectorTest, QuickReentryRestoresInitialTransform) {
605 gfx::Rect bounds(0, 0, 400, 400);
606 scoped_ptr<aura::Window> window(CreateWindow(bounds));
607 gfx::Rect initial_bounds = ToEnclosingRect(
608 GetTransformedBounds(window.get()));
610 // Quickly exit and reenter overview mode. The window should still be
611 // animating when we reenter. We cannot short circuit animations for this but
612 // we also don't have to wait for them to complete.
614 ui::ScopedAnimationDurationScaleMode normal_duration_mode(
615 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
619 EXPECT_NE(initial_bounds, ToEnclosingRect(
620 GetTransformedTargetBounds(window.get())));
622 EXPECT_FALSE(IsSelecting());
623 EXPECT_EQ(initial_bounds, ToEnclosingRect(
624 GetTransformedTargetBounds(window.get())));
627 // Tests that non-activatable windows are hidden when entering overview mode.
628 TEST_F(WindowSelectorTest, NonActivatableWindowsHidden) {
629 gfx::Rect bounds(0, 0, 400, 400);
630 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
631 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
632 scoped_ptr<aura::Window> non_activatable_window(
633 CreateNonActivatableWindow(Shell::GetPrimaryRootWindow()->bounds()));
634 EXPECT_TRUE(non_activatable_window->IsVisible());
636 EXPECT_FALSE(non_activatable_window->IsVisible());
638 EXPECT_TRUE(non_activatable_window->IsVisible());
640 // Test that a window behind the fullscreen non-activatable window can be
642 non_activatable_window->parent()->StackChildAtTop(
643 non_activatable_window.get());
645 ClickWindow(window1.get());
646 EXPECT_FALSE(IsSelecting());
647 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
650 // Tests that windows with modal child windows are transformed with the modal
651 // child even though not activatable themselves.
652 TEST_F(WindowSelectorTest, ModalChild) {
653 gfx::Rect bounds(0, 0, 400, 400);
654 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
655 scoped_ptr<aura::Window> child1(CreateWindow(bounds));
656 child1->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
657 window1->AddTransientChild(child1.get());
658 EXPECT_EQ(window1->parent(), child1->parent());
660 EXPECT_TRUE(window1->IsVisible());
661 EXPECT_TRUE(child1->IsVisible());
662 EXPECT_EQ(ToEnclosingRect(GetTransformedTargetBounds(child1.get())),
663 ToEnclosingRect(GetTransformedTargetBounds(window1.get())));
667 // Tests that clicking a modal window's parent activates the modal window in
669 TEST_F(WindowSelectorTest, ClickModalWindowParent) {
670 scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 180, 180)));
671 scoped_ptr<aura::Window> child1(CreateWindow(gfx::Rect(200, 0, 180, 180)));
672 child1->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
673 window1->AddTransientChild(child1.get());
674 EXPECT_FALSE(WindowsOverlapping(window1.get(), child1.get()));
675 EXPECT_EQ(window1->parent(), child1->parent());
677 // Given that their relative positions are preserved, the windows should still
679 EXPECT_FALSE(WindowsOverlapping(window1.get(), child1.get()));
680 ClickWindow(window1.get());
681 EXPECT_FALSE(IsSelecting());
683 // Clicking on window1 should activate child1.
684 EXPECT_TRUE(wm::IsActiveWindow(child1.get()));
687 // Tests that windows remain on the display they are currently on in overview
689 TEST_F(WindowSelectorTest, MultipleDisplays) {
690 if (!SupportsMultipleDisplays())
693 UpdateDisplay("600x400,600x400");
694 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
695 gfx::Rect bounds1(0, 0, 400, 400);
696 gfx::Rect bounds2(650, 0, 400, 400);
698 scoped_ptr<aura::Window> window1(CreateWindow(bounds1));
699 scoped_ptr<aura::Window> window2(CreateWindow(bounds1));
700 scoped_ptr<aura::Window> window3(CreateWindow(bounds2));
701 scoped_ptr<aura::Window> window4(CreateWindow(bounds2));
702 scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds1));
703 scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds1));
704 scoped_ptr<aura::Window> panel3(CreatePanelWindow(bounds2));
705 scoped_ptr<aura::Window> panel4(CreatePanelWindow(bounds2));
706 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
707 EXPECT_EQ(root_windows[0], window2->GetRootWindow());
708 EXPECT_EQ(root_windows[1], window3->GetRootWindow());
709 EXPECT_EQ(root_windows[1], window4->GetRootWindow());
711 EXPECT_EQ(root_windows[0], panel1->GetRootWindow());
712 EXPECT_EQ(root_windows[0], panel2->GetRootWindow());
713 EXPECT_EQ(root_windows[1], panel3->GetRootWindow());
714 EXPECT_EQ(root_windows[1], panel4->GetRootWindow());
716 // In overview mode, each window remains in the same root window.
718 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
719 EXPECT_EQ(root_windows[0], window2->GetRootWindow());
720 EXPECT_EQ(root_windows[1], window3->GetRootWindow());
721 EXPECT_EQ(root_windows[1], window4->GetRootWindow());
722 EXPECT_EQ(root_windows[0], panel1->GetRootWindow());
723 EXPECT_EQ(root_windows[0], panel2->GetRootWindow());
724 EXPECT_EQ(root_windows[1], panel3->GetRootWindow());
725 EXPECT_EQ(root_windows[1], panel4->GetRootWindow());
727 EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
728 ToEnclosingRect(GetTransformedTargetBounds(window1.get()))));
729 EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
730 ToEnclosingRect(GetTransformedTargetBounds(window2.get()))));
731 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
732 ToEnclosingRect(GetTransformedTargetBounds(window3.get()))));
733 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
734 ToEnclosingRect(GetTransformedTargetBounds(window4.get()))));
736 EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
737 ToEnclosingRect(GetTransformedTargetBounds(panel1.get()))));
738 EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
739 ToEnclosingRect(GetTransformedTargetBounds(panel2.get()))));
740 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
741 ToEnclosingRect(GetTransformedTargetBounds(panel3.get()))));
742 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
743 ToEnclosingRect(GetTransformedTargetBounds(panel4.get()))));
744 EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get()));
745 EXPECT_TRUE(WindowsOverlapping(panel3.get(), panel4.get()));
746 EXPECT_FALSE(WindowsOverlapping(panel1.get(), panel3.get()));
749 // Verifies that the single display overview used during alt tab cycling uses
750 // the display of the initial window by default.
751 TEST_F(WindowSelectorTest, CycleOverviewUsesInitialDisplay) {
752 if (!SupportsMultipleDisplays())
755 UpdateDisplay("400x400,400x400");
756 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
758 scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 100, 100)));
759 scoped_ptr<aura::Window> window2(CreateWindow(gfx::Rect(450, 0, 100, 100)));
760 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
761 EXPECT_EQ(root_windows[1], window2->GetRootWindow());
762 wm::ActivateWindow(window2.get());
763 wm::ActivateWindow(window1.get());
764 EXPECT_EQ(root_windows[0], Shell::GetTargetRootWindow());
766 Cycle(WindowSelector::FORWARD);
767 FireOverviewStartTimer();
769 EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
770 ToEnclosingRect(GetTransformedTargetBounds(window1.get()))));
771 EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
772 ToEnclosingRect(GetTransformedTargetBounds(window2.get()))));
776 // Verifies that the windows being shown on another display are copied.
777 TEST_F(WindowSelectorTest, CycleMultipleDisplaysCopiesWindows) {
778 if (!SupportsMultipleDisplays())
781 UpdateDisplay("400x400,400x400");
782 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
784 gfx::Rect root1_rect(0, 0, 100, 100);
785 gfx::Rect root2_rect(450, 0, 100, 100);
786 scoped_ptr<aura::Window> unmoved1(CreateWindow(root2_rect));
787 scoped_ptr<aura::Window> unmoved2(CreateWindow(root2_rect));
788 scoped_ptr<aura::Window> moved1_trans_parent(CreateWindow(root1_rect));
789 scoped_ptr<aura::Window> moved1(CreateWindow(root1_rect));
790 unmoved1->SetName("unmoved1");
791 unmoved2->SetName("unmoved2");
792 moved1->SetName("moved1");
793 moved1->SetProperty(aura::client::kModalKey,
794 ui::MODAL_TYPE_WINDOW);
795 moved1_trans_parent->AddTransientChild(moved1.get());
796 moved1_trans_parent->SetName("moved1_trans_parent");
798 EXPECT_EQ(root_windows[0], moved1->GetRootWindow());
799 EXPECT_EQ(root_windows[0], moved1_trans_parent->GetRootWindow());
800 EXPECT_EQ(root_windows[1], unmoved1->GetRootWindow());
801 EXPECT_EQ(root_windows[1], unmoved2->GetRootWindow());
802 wm::ActivateWindow(unmoved2.get());
803 wm::ActivateWindow(unmoved1.get());
805 Cycle(WindowSelector::FORWARD);
806 FireOverviewStartTimer();
808 // All windows are moved to second root window.
809 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
810 ToEnclosingRect(GetTransformedTargetBounds(unmoved1.get()))));
811 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
812 ToEnclosingRect(GetTransformedTargetBounds(unmoved2.get()))));
813 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
814 ToEnclosingRect(GetTransformedTargetBounds(moved1.get()))));
815 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
816 ToEnclosingRect(GetTransformedTargetBounds(moved1_trans_parent.get()))));
818 // unmoved1 and unmoved2 were already on the correct display and should not
820 EXPECT_TRUE(!GetCopyWindow(unmoved1.get()));
821 EXPECT_TRUE(!GetCopyWindow(unmoved2.get()));
823 // moved1 and its transient parent moved1_trans_parent should have also been
824 // copied for displaying on root_windows[1].
825 aura::Window* copy1 = GetCopyWindow(moved1.get());
826 aura::Window* copy1_trans_parent = GetCopyWindow(moved1_trans_parent.get());
827 ASSERT_FALSE(!copy1);
828 ASSERT_FALSE(!copy1_trans_parent);
830 // Verify that the bounds and transform of the copy match the original window
831 // but that it is on the other root window.
832 EXPECT_EQ(root_windows[1], copy1->GetRootWindow());
833 EXPECT_EQ(moved1->GetBoundsInScreen(), copy1->GetBoundsInScreen());
834 EXPECT_EQ(moved1->layer()->GetTargetTransform(),
835 copy1->layer()->GetTargetTransform());
838 // After cycling the copy windows should have been destroyed.
839 RunAllPendingInMessageLoop();
840 EXPECT_TRUE(!GetCopyWindow(moved1.get()));
841 EXPECT_TRUE(!GetCopyWindow(moved1_trans_parent.get()));
844 // Tests that beginning to cycle from overview mode moves windows to the
846 TEST_F(WindowSelectorTest, MultipleDisplaysOverviewTransitionToCycle) {
847 if (!SupportsMultipleDisplays())
850 UpdateDisplay("400x400,400x400");
851 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
853 scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 100, 100)));
854 scoped_ptr<aura::Window> window2(CreateWindow(gfx::Rect(450, 0, 100, 100)));
855 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
856 EXPECT_EQ(root_windows[1], window2->GetRootWindow());
857 wm::ActivateWindow(window2.get());
858 wm::ActivateWindow(window1.get());
861 EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
862 ToEnclosingRect(GetTransformedTargetBounds(window1.get()))));
863 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
864 ToEnclosingRect(GetTransformedTargetBounds(window2.get()))));
866 Cycle(WindowSelector::FORWARD);
867 EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
868 ToEnclosingRect(GetTransformedTargetBounds(window1.get()))));
869 EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
870 ToEnclosingRect(GetTransformedTargetBounds(window2.get()))));
874 // Tests that a bounds change during overview is corrected for.
875 TEST_F(WindowSelectorTest, BoundsChangeDuringCycleOnOtherDisplay) {
876 if (!SupportsMultipleDisplays())
879 UpdateDisplay("400x400,400x400");
880 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
882 scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 100, 100)));
883 scoped_ptr<aura::Window> window2(CreateWindow(gfx::Rect(450, 0, 100, 100)));
884 scoped_ptr<aura::Window> window3(CreateWindow(gfx::Rect(450, 0, 100, 100)));
885 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
886 EXPECT_EQ(root_windows[1], window2->GetRootWindow());
887 EXPECT_EQ(root_windows[1], window3->GetRootWindow());
888 wm::ActivateWindow(window1.get());
889 wm::ActivateWindow(window2.get());
890 wm::ActivateWindow(window3.get());
892 Cycle(WindowSelector::FORWARD);
893 FireOverviewStartTimer();
895 gfx::Rect overview_bounds(
896 ToEnclosingRect(GetTransformedTargetBounds(window1.get())));
897 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(overview_bounds));
899 // Change the position and size of window1 (being displayed on the second
900 // root window) and it should remain within the same bounds.
901 window1->SetBounds(gfx::Rect(100, 0, 200, 200));
902 gfx::Rect new_overview_bounds =
903 ToEnclosingRect(GetTransformedTargetBounds(window1.get()));
904 EXPECT_EQ(overview_bounds.x(), new_overview_bounds.x());
905 EXPECT_EQ(overview_bounds.y(), new_overview_bounds.y());
906 EXPECT_EQ(overview_bounds.width(), new_overview_bounds.width());
907 EXPECT_EQ(overview_bounds.height(), new_overview_bounds.height());
911 } // namespace internal