window_selector_unittest.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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. 4 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" 9#include "ash/shell.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" 36 37namespace ash { 38namespace internal { 39 40namespace { 41 42class NonActivatableActivationDelegate 43 : public aura::client::ActivationDelegate { 44 public: 45 virtual bool ShouldActivate() const OVERRIDE { 46 return false; 47 } 48}; 49 50bool 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) { 55 if (*iter == w1) 56 return false; 57 if (*iter == w2) 58 return true; 59 } 60 NOTREACHED(); 61 return false; 62} 63 64aura::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(); 69 ++iter) { 70 if ((*iter)->name() == name) { 71 // The name should be unique. 72 DCHECK(!window); 73 window = *iter; 74 } 75 } 76 return window; 77} 78 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. 82aura::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); 90 if (found) { 91 // There should only be one copy window. 92 DCHECK(!copy_window); 93 copy_window = found; 94 } 95 } 96 return copy_window; 97} 98 99} // namespace 100 101class WindowSelectorTest : public test::AshTestBase { 102 public: 103 WindowSelectorTest() {} 104 virtual ~WindowSelectorTest() {} 105 106 virtual void SetUp() OVERRIDE { 107 test::AshTestBase::SetUp(); 108 ASSERT_TRUE(test::TestLauncherDelegate::instance()); 109 110 shelf_view_test_.reset(new test::ShelfViewTestAPI( 111 test::LauncherTestAPI(Launcher::ForPrimaryDisplay()).shelf_view())); 112 shelf_view_test_->SetAnimationDuration(1); 113 } 114 115 aura::Window* CreateWindow(const gfx::Rect& bounds) { 116 return CreateTestWindowInShellWithDelegate(&delegate_, -1, bounds); 117 } 118 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)); 124 return window; 125 } 126 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(); 132 return window; 133 } 134 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); 139 } 140 141 void ToggleOverview() { 142 ash::Shell::GetInstance()->window_selector_controller()->ToggleOverview(); 143 } 144 145 void Cycle(WindowSelector::Direction direction) { 146 ash::Shell::GetInstance()->window_selector_controller()-> 147 HandleCycleWindow(direction); 148 } 149 150 void StopCycling() { 151 ash::Shell::GetInstance()->window_selector_controller()->window_selector_-> 152 SelectWindow(); 153 } 154 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_-> 161 StartOverview(); 162 } 163 164 gfx::Transform GetTransformRelativeTo(gfx::PointF origin, 165 const gfx::Transform& transform) { 166 gfx::Transform t; 167 t.Translate(origin.x(), origin.y()); 168 t.PreconcatTransform(transform); 169 t.Translate(-origin.x(), -origin.y()); 170 return t; 171 } 172 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); 179 return bounds; 180 } 181 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); 188 return bounds; 189 } 190 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(); 195 } 196 197 bool IsSelecting() { 198 return ash::Shell::GetInstance()->window_selector_controller()-> 199 IsSelecting(); 200 } 201 202 aura::Window* GetFocusedWindow() { 203 return aura::client::GetFocusClient( 204 Shell::GetPrimaryRootWindow())->GetFocusedWindow(); 205 } 206 207 test::ShelfViewTestAPI* shelf_view_test() { 208 return shelf_view_test_.get(); 209 } 210 211 private: 212 aura::test::TestWindowDelegate delegate_; 213 NonActivatableActivationDelegate non_activatable_activation_delegate_; 214 scoped_ptr<test::ShelfViewTestAPI> shelf_view_test_; 215 216 DISALLOW_COPY_AND_ASSIGN(WindowSelectorTest); 217}; 218 219// Tests entering overview mode with two windows and selecting one. 220TEST_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(); 235 236 // In overview mode the windows should no longer overlap and focus should 237 // be removed from the window. 238 ToggleOverview(); 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 243 // item. 244 EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get())); 245 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()); 251 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()); 257 258 // Cursor should have been unlocked. 259 EXPECT_FALSE(aura::client::GetCursorClient(root_window)->IsCursorLocked()); 260} 261 262// Tests that the shelf dimming state is removed while in overview and restored 263// on exiting overview. 264TEST_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()); 271 ToggleOverview(); 272 EXPECT_FALSE(shelf->GetDimsShelf()); 273 ToggleOverview(); 274 EXPECT_TRUE(shelf->GetDimsShelf()); 275} 276 277// Tests that beginning window selection hides the app list. 278TEST_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()); 284 ToggleOverview(); 285 EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility()); 286 ToggleOverview(); 287 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(); 293 294 Shell::GetInstance()->ToggleAppList(NULL); 295 EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility()); 296 Cycle(WindowSelector::FORWARD); 297 EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility()); 298 StopCycling(); 299} 300 301// Tests that a minimized window's visibility and layer visibility is correctly 302// changed when entering overview and restored when leaving overview mode. 303TEST_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()); 310 { 311 ui::ScopedAnimationDurationScaleMode normal_duration_mode( 312 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); 313 ToggleOverview(); 314 EXPECT_TRUE(window1->IsVisible()); 315 EXPECT_TRUE(window1->layer()->GetTargetVisibility()); 316 } 317 { 318 ui::ScopedAnimationDurationScaleMode normal_duration_mode( 319 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); 320 ToggleOverview(); 321 EXPECT_FALSE(window1->IsVisible()); 322 EXPECT_FALSE(window1->layer()->GetTargetVisibility()); 323 } 324} 325 326// Tests that a bounds change during overview is corrected for. 327TEST_F(WindowSelectorTest, BoundsChangeDuringOverview) { 328 scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 400, 400))); 329 ToggleOverview(); 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()); 339 ToggleOverview(); 340} 341 342// Tests entering overview mode with three windows and cycling through them. 343TEST_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())); 354 355 Cycle(WindowSelector::FORWARD); 356 EXPECT_TRUE(IsSelecting()); 357 Cycle(WindowSelector::FORWARD); 358 StopCycling(); 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())); 363} 364 365// Tests that cycling through windows preserves the window stacking order. 366TEST_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())); 377 378 // On window 2. 379 Cycle(WindowSelector::FORWARD); 380 EXPECT_TRUE(IsWindowAbove(window2.get(), window1.get())); 381 EXPECT_TRUE(IsWindowAbove(window1.get(), window3.get())); 382 383 // On window 3. 384 Cycle(WindowSelector::FORWARD); 385 EXPECT_TRUE(IsWindowAbove(window3.get(), window1.get())); 386 EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get())); 387 388 // Back on window 1. 389 Cycle(WindowSelector::FORWARD); 390 EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get())); 391 EXPECT_TRUE(IsWindowAbove(window2.get(), window3.get())); 392 StopCycling(); 393} 394 395// Tests that cycling through windows shows and minimizes windows as they 396// are passed. 397TEST_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())); 405 406 // On window 2. 407 Cycle(WindowSelector::FORWARD); 408 EXPECT_FALSE(wm::IsWindowMinimized(window2.get())); 409 410 // Back on window 1. 411 Cycle(WindowSelector::FORWARD); 412 EXPECT_TRUE(wm::IsWindowMinimized(window2.get())); 413 414 StopCycling(); 415 EXPECT_TRUE(wm::IsWindowMinimized(window2.get())); 416} 417 418// Tests beginning cycling while in overview mode. 419TEST_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()); 425 426 ToggleOverview(); 427 Cycle(WindowSelector::FORWARD); 428 StopCycling(); 429 430 EXPECT_TRUE(wm::IsActiveWindow(window2.get())); 431 EXPECT_FALSE(wm::IsActiveWindow(window1.get())); 432 EXPECT_EQ(window2.get(), GetFocusedWindow()); 433} 434 435// Tests cycles between panel and normal windows. 436TEST_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())); 447 448 // Cycling once should select window1 since the panels are grouped into a 449 // single selectable item. 450 Cycle(WindowSelector::FORWARD); 451 StopCycling(); 452 EXPECT_TRUE(wm::IsActiveWindow(window1.get())); 453 454 // Cycling again should select the most recently used panel. 455 Cycle(WindowSelector::FORWARD); 456 StopCycling(); 457 EXPECT_TRUE(wm::IsActiveWindow(panel1.get())); 458} 459 460// Tests the visibility of panel windows during cycling. 461TEST_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()); 467 468 Cycle(WindowSelector::FORWARD); 469 FireOverviewStartTimer(); 470 EXPECT_EQ(1.0f, panel1->layer()->GetTargetOpacity()); 471 StopCycling(); 472} 473 474// Tests cycles between panel and normal windows. 475TEST_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())); 488 489 // Cycling once highlights window2. 490 Cycle(WindowSelector::FORWARD); 491 // All panels are destroyed. 492 panel1.reset(); 493 panel2.reset(); 494 // Cycling again should now select window3. 495 Cycle(WindowSelector::FORWARD); 496 StopCycling(); 497 EXPECT_TRUE(wm::IsActiveWindow(window3.get())); 498} 499 500// Tests cycles between panel and normal windows. 501TEST_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())); 512 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. 517 panel1.reset(); 518 // Cycling again should now select window3. 519 Cycle(WindowSelector::FORWARD); 520 StopCycling(); 521 EXPECT_TRUE(wm::IsActiveWindow(panel2.get())); 522} 523 524// Tests that a newly created window aborts overview. 525TEST_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)); 529 ToggleOverview(); 530 EXPECT_TRUE(IsSelecting()); 531 532 // A window being created should exit overview mode. 533 scoped_ptr<aura::Window> window3(CreateWindow(bounds)); 534 EXPECT_FALSE(IsSelecting()); 535} 536 537// Tests that a window activation exits overview mode. 538TEST_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)); 542 window2->Focus(); 543 ToggleOverview(); 544 EXPECT_TRUE(IsSelecting()); 545 546 // A window being activated should exit overview mode. 547 window1->Focus(); 548 EXPECT_FALSE(IsSelecting()); 549 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()); 553} 554 555// Verifies that overview mode only begins after a delay when cycling. 556TEST_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())); 561 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())); 566 567 // Once the overview timer fires, the windows should no longer overlap. 568 FireOverviewStartTimer(); 569 EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get())); 570 StopCycling(); 571} 572 573// Tests that exiting overview mode without selecting a window restores focus 574// to the previously focused window. 575TEST_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()); 580 581 // In overview mode, focus should be removed. 582 ToggleOverview(); 583 EXPECT_EQ(NULL, GetFocusedWindow()); 584 585 // If canceling overview mode, focus should be restored. 586 ToggleOverview(); 587 EXPECT_EQ(window.get(), GetFocusedWindow()); 588} 589 590// Tests that overview mode is exited if the last remaining window is destroyed. 591TEST_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)); 595 ToggleOverview(); 596 597 window1.reset(); 598 window2.reset(); 599 EXPECT_FALSE(IsSelecting()); 600} 601 602// Tests that entering overview mode restores a window to its original 603// target location. 604TEST_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())); 609 ToggleOverview(); 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. 613 { 614 ui::ScopedAnimationDurationScaleMode normal_duration_mode( 615 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); 616 ToggleOverview(); 617 ToggleOverview(); 618 } 619 EXPECT_NE(initial_bounds, ToEnclosingRect( 620 GetTransformedTargetBounds(window.get()))); 621 ToggleOverview(); 622 EXPECT_FALSE(IsSelecting()); 623 EXPECT_EQ(initial_bounds, ToEnclosingRect( 624 GetTransformedTargetBounds(window.get()))); 625} 626 627// Tests that non-activatable windows are hidden when entering overview mode. 628TEST_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()); 635 ToggleOverview(); 636 EXPECT_FALSE(non_activatable_window->IsVisible()); 637 ToggleOverview(); 638 EXPECT_TRUE(non_activatable_window->IsVisible()); 639 640 // Test that a window behind the fullscreen non-activatable window can be 641 // clicked. 642 non_activatable_window->parent()->StackChildAtTop( 643 non_activatable_window.get()); 644 ToggleOverview(); 645 ClickWindow(window1.get()); 646 EXPECT_FALSE(IsSelecting()); 647 EXPECT_TRUE(wm::IsActiveWindow(window1.get())); 648} 649 650// Tests that windows with modal child windows are transformed with the modal 651// child even though not activatable themselves. 652TEST_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()); 659 ToggleOverview(); 660 EXPECT_TRUE(window1->IsVisible()); 661 EXPECT_TRUE(child1->IsVisible()); 662 EXPECT_EQ(ToEnclosingRect(GetTransformedTargetBounds(child1.get())), 663 ToEnclosingRect(GetTransformedTargetBounds(window1.get()))); 664 ToggleOverview(); 665} 666 667// Tests that clicking a modal window's parent activates the modal window in 668// overview. 669TEST_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()); 676 ToggleOverview(); 677 // Given that their relative positions are preserved, the windows should still 678 // not overlap. 679 EXPECT_FALSE(WindowsOverlapping(window1.get(), child1.get())); 680 ClickWindow(window1.get()); 681 EXPECT_FALSE(IsSelecting()); 682 683 // Clicking on window1 should activate child1. 684 EXPECT_TRUE(wm::IsActiveWindow(child1.get())); 685} 686 687// Tests that windows remain on the display they are currently on in overview 688// mode. 689TEST_F(WindowSelectorTest, MultipleDisplays) { 690 if (!SupportsMultipleDisplays()) 691 return; 692 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); 697 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()); 710 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()); 715 716 // In overview mode, each window remains in the same root window. 717 ToggleOverview(); 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()); 726 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())))); 735 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())); 747} 748 749// Verifies that the single display overview used during alt tab cycling uses 750// the display of the initial window by default. 751TEST_F(WindowSelectorTest, CycleOverviewUsesInitialDisplay) { 752 if (!SupportsMultipleDisplays()) 753 return; 754 755 UpdateDisplay("400x400,400x400"); 756 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); 757 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()); 765 766 Cycle(WindowSelector::FORWARD); 767 FireOverviewStartTimer(); 768 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())))); 773 StopCycling(); 774} 775 776// Verifies that the windows being shown on another display are copied. 777TEST_F(WindowSelectorTest, CycleMultipleDisplaysCopiesWindows) { 778 if (!SupportsMultipleDisplays()) 779 return; 780 781 UpdateDisplay("400x400,400x400"); 782 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); 783 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"); 797 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()); 804 805 Cycle(WindowSelector::FORWARD); 806 FireOverviewStartTimer(); 807 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())))); 817 818 // unmoved1 and unmoved2 were already on the correct display and should not 819 // have been copied. 820 EXPECT_TRUE(!GetCopyWindow(unmoved1.get())); 821 EXPECT_TRUE(!GetCopyWindow(unmoved2.get())); 822 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); 829 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()); 836 StopCycling(); 837 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())); 842} 843 844// Tests that beginning to cycle from overview mode moves windows to the 845// active display. 846TEST_F(WindowSelectorTest, MultipleDisplaysOverviewTransitionToCycle) { 847 if (!SupportsMultipleDisplays()) 848 return; 849 850 UpdateDisplay("400x400,400x400"); 851 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); 852 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()); 859 860 ToggleOverview(); 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())))); 865 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())))); 871 StopCycling(); 872} 873 874// Tests that a bounds change during overview is corrected for. 875TEST_F(WindowSelectorTest, BoundsChangeDuringCycleOnOtherDisplay) { 876 if (!SupportsMultipleDisplays()) 877 return; 878 879 UpdateDisplay("400x400,400x400"); 880 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); 881 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()); 891 892 Cycle(WindowSelector::FORWARD); 893 FireOverviewStartTimer(); 894 895 gfx::Rect overview_bounds( 896 ToEnclosingRect(GetTransformedTargetBounds(window1.get()))); 897 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(overview_bounds)); 898 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()); 908 StopCycling(); 909} 910 911} // namespace internal 912} // namespace ash 913