1 // Copyright (c) 2012 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/wm/panels/panel_layout_manager.h" 6 7 #include "ash/ash_switches.h" 8 #include "ash/launcher/launcher.h" 9 #include "ash/root_window_controller.h" 10 #include "ash/screen_ash.h" 11 #include "ash/shelf/shelf_button.h" 12 #include "ash/shelf/shelf_layout_manager.h" 13 #include "ash/shelf/shelf_model.h" 14 #include "ash/shelf/shelf_types.h" 15 #include "ash/shelf/shelf_util.h" 16 #include "ash/shelf/shelf_view.h" 17 #include "ash/shelf/shelf_widget.h" 18 #include "ash/shell.h" 19 #include "ash/shell_window_ids.h" 20 #include "ash/test/ash_test_base.h" 21 #include "ash/test/launcher_test_api.h" 22 #include "ash/test/shelf_view_test_api.h" 23 #include "ash/test/shell_test_api.h" 24 #include "ash/test/test_shelf_delegate.h" 25 #include "ash/wm/mru_window_tracker.h" 26 #include "ash/wm/window_util.h" 27 #include "base/basictypes.h" 28 #include "base/command_line.h" 29 #include "base/compiler_specific.h" 30 #include "base/i18n/rtl.h" 31 #include "base/run_loop.h" 32 #include "ui/aura/client/aura_constants.h" 33 #include "ui/aura/root_window.h" 34 #include "ui/aura/test/event_generator.h" 35 #include "ui/aura/test/test_windows.h" 36 #include "ui/aura/window.h" 37 #include "ui/base/l10n/l10n_util.h" 38 #include "ui/views/corewm/corewm_switches.h" 39 #include "ui/views/widget/widget.h" 40 41 namespace ash { 42 namespace internal { 43 44 using aura::test::WindowIsAbove; 45 46 class PanelLayoutManagerTest : public test::AshTestBase { 47 public: 48 PanelLayoutManagerTest() {} 49 virtual ~PanelLayoutManagerTest() {} 50 51 virtual void SetUp() OVERRIDE { 52 test::AshTestBase::SetUp(); 53 ASSERT_TRUE(test::TestShelfDelegate::instance()); 54 55 shelf_view_test_.reset(new test::ShelfViewTestAPI( 56 GetShelfView(Launcher::ForPrimaryDisplay()))); 57 shelf_view_test_->SetAnimationDuration(1); 58 } 59 60 aura::Window* CreateNormalWindow(const gfx::Rect& bounds) { 61 return CreateTestWindowInShellWithBounds(bounds); 62 } 63 64 aura::Window* CreatePanelWindow(const gfx::Rect& bounds) { 65 aura::Window* window = CreateTestWindowInShellWithDelegateAndType( 66 NULL, 67 aura::client::WINDOW_TYPE_PANEL, 68 0, 69 bounds); 70 test::TestShelfDelegate* shelf_delegate = 71 test::TestShelfDelegate::instance(); 72 shelf_delegate->AddLauncherItem(window); 73 PanelLayoutManager* manager = static_cast<PanelLayoutManager*>( 74 GetPanelContainer(window)->layout_manager()); 75 manager->Relayout(); 76 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 77 return window; 78 } 79 80 aura::Window* GetPanelContainer(aura::Window* panel) { 81 return Shell::GetContainer(panel->GetRootWindow(), 82 internal::kShellWindowId_PanelContainer); 83 } 84 85 views::Widget* GetCalloutWidgetForPanel(aura::Window* panel) { 86 PanelLayoutManager* manager = 87 static_cast<PanelLayoutManager*>(GetPanelContainer(panel)-> 88 layout_manager()); 89 DCHECK(manager); 90 PanelLayoutManager::PanelList::iterator found = std::find( 91 manager->panel_windows_.begin(), manager->panel_windows_.end(), 92 panel); 93 DCHECK(found != manager->panel_windows_.end()); 94 DCHECK(found->callout_widget); 95 return reinterpret_cast<views::Widget*>(found->callout_widget); 96 } 97 98 void PanelInScreen(aura::Window* panel) { 99 gfx::Rect panel_bounds = panel->GetBoundsInRootWindow(); 100 gfx::Point root_point = gfx::Point(panel_bounds.x(), panel_bounds.y()); 101 gfx::Display display = ScreenAsh::FindDisplayContainingPoint(root_point); 102 103 gfx::Rect panel_bounds_in_screen = panel->GetBoundsInScreen(); 104 gfx::Point screen_bottom_right = gfx::Point( 105 panel_bounds_in_screen.right(), 106 panel_bounds_in_screen.bottom()); 107 gfx::Rect display_bounds = display.bounds(); 108 EXPECT_TRUE(screen_bottom_right.x() < display_bounds.width() && 109 screen_bottom_right.y() < display_bounds.height()); 110 } 111 112 void PanelsNotOverlapping(aura::Window* panel1, aura::Window* panel2) { 113 // Waits until all shelf view animations are done. 114 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 115 gfx::Rect window1_bounds = panel1->GetBoundsInRootWindow(); 116 gfx::Rect window2_bounds = panel2->GetBoundsInRootWindow(); 117 118 EXPECT_FALSE(window1_bounds.Intersects(window2_bounds)); 119 } 120 121 // TODO(dcheng): This should be const, but GetScreenBoundsOfItemIconForWindow 122 // takes a non-const Window. We can probably fix that. 123 void IsPanelAboveLauncherIcon(aura::Window* panel) { 124 // Waits until all shelf view animations are done. 125 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 126 127 Launcher* launcher = 128 RootWindowController::ForLauncher(panel)->shelf()->launcher(); 129 gfx::Rect icon_bounds = launcher->GetScreenBoundsOfItemIconForWindow(panel); 130 ASSERT_FALSE(icon_bounds.width() == 0 && icon_bounds.height() == 0); 131 132 gfx::Rect window_bounds = panel->GetBoundsInScreen(); 133 ASSERT_LT(icon_bounds.width(), window_bounds.width()); 134 ASSERT_LT(icon_bounds.height(), window_bounds.height()); 135 gfx::Rect launcher_bounds = launcher->shelf_widget()-> 136 GetWindowBoundsInScreen(); 137 ShelfAlignment alignment = GetAlignment(panel->GetRootWindow()); 138 139 if (IsHorizontal(alignment)) { 140 // The horizontal bounds of the panel window should contain the bounds of 141 // the launcher icon. 142 EXPECT_LE(window_bounds.x(), icon_bounds.x()); 143 EXPECT_GE(window_bounds.right(), icon_bounds.right()); 144 } else { 145 // The vertical bounds of the panel window should contain the bounds of 146 // the launcher icon. 147 EXPECT_LE(window_bounds.y(), icon_bounds.y()); 148 EXPECT_GE(window_bounds.bottom(), icon_bounds.bottom()); 149 } 150 151 switch (alignment) { 152 case SHELF_ALIGNMENT_BOTTOM: 153 EXPECT_EQ(launcher_bounds.y(), window_bounds.bottom()); 154 break; 155 case SHELF_ALIGNMENT_LEFT: 156 EXPECT_EQ(launcher_bounds.right(), window_bounds.x()); 157 break; 158 case SHELF_ALIGNMENT_RIGHT: 159 EXPECT_EQ(launcher_bounds.x(), window_bounds.right()); 160 break; 161 case SHELF_ALIGNMENT_TOP: 162 EXPECT_EQ(launcher_bounds.bottom(), window_bounds.y()); 163 break; 164 } 165 } 166 167 void IsCalloutAboveLauncherIcon(aura::Window* panel) { 168 // Flush the message loop, since callout updates use a delayed task. 169 base::RunLoop().RunUntilIdle(); 170 views::Widget* widget = GetCalloutWidgetForPanel(panel); 171 172 Launcher* launcher = 173 RootWindowController::ForLauncher(panel)->shelf()->launcher(); 174 gfx::Rect icon_bounds = launcher->GetScreenBoundsOfItemIconForWindow(panel); 175 ASSERT_FALSE(icon_bounds.IsEmpty()); 176 177 gfx::Rect panel_bounds = panel->GetBoundsInScreen(); 178 gfx::Rect callout_bounds = widget->GetWindowBoundsInScreen(); 179 ASSERT_FALSE(icon_bounds.IsEmpty()); 180 181 EXPECT_TRUE(widget->IsVisible()); 182 183 ShelfAlignment alignment = GetAlignment(panel->GetRootWindow()); 184 switch (alignment) { 185 case SHELF_ALIGNMENT_BOTTOM: 186 EXPECT_EQ(panel_bounds.bottom(), callout_bounds.y()); 187 break; 188 case SHELF_ALIGNMENT_LEFT: 189 EXPECT_EQ(panel_bounds.x(), callout_bounds.right()); 190 break; 191 case SHELF_ALIGNMENT_RIGHT: 192 EXPECT_EQ(panel_bounds.right(), callout_bounds.x()); 193 break; 194 case SHELF_ALIGNMENT_TOP: 195 EXPECT_EQ(panel_bounds.y(), callout_bounds.bottom()); 196 break; 197 } 198 199 if (IsHorizontal(alignment)) { 200 EXPECT_NEAR(icon_bounds.CenterPoint().x(), 201 widget->GetWindowBoundsInScreen().CenterPoint().x(), 202 1); 203 } else { 204 EXPECT_NEAR(icon_bounds.CenterPoint().y(), 205 widget->GetWindowBoundsInScreen().CenterPoint().y(), 206 1); 207 } 208 } 209 210 bool IsPanelCalloutVisible(aura::Window* panel) { 211 views::Widget* widget = GetCalloutWidgetForPanel(panel); 212 return widget->IsVisible(); 213 } 214 215 test::ShelfViewTestAPI* shelf_view_test() { 216 return shelf_view_test_.get(); 217 } 218 219 // Clicks the launcher items on |shelf_view| that is 220 /// associated with given |window|. 221 void ClickLauncherItemForWindow(ShelfView* shelf_view, 222 aura::Window* window) { 223 test::ShelfViewTestAPI test_api(shelf_view); 224 test_api.SetAnimationDuration(1); 225 test_api.RunMessageLoopUntilAnimationsDone(); 226 ShelfModel* model = test::ShellTestApi(Shell::GetInstance()).shelf_model(); 227 int index = model->ItemIndexByID(GetLauncherIDForWindow(window)); 228 gfx::Rect bounds = test_api.GetButton(index)->GetBoundsInScreen(); 229 230 aura::test::EventGenerator& event_generator = GetEventGenerator(); 231 event_generator.MoveMouseTo(bounds.CenterPoint()); 232 event_generator.ClickLeftButton(); 233 234 test_api.RunMessageLoopUntilAnimationsDone(); 235 } 236 237 void SetAlignment(aura::Window* root_window, ShelfAlignment alignment) { 238 ash::Shell* shell = ash::Shell::GetInstance(); 239 shell->SetShelfAlignment(alignment, root_window); 240 } 241 242 ShelfAlignment GetAlignment(aura::Window* root_window) { 243 ash::Shell* shell = ash::Shell::GetInstance(); 244 return shell->GetShelfAlignment(root_window); 245 } 246 247 void SetShelfAutoHideBehavior(aura::Window* window, 248 ShelfAutoHideBehavior behavior) { 249 internal::ShelfLayoutManager* shelf = 250 RootWindowController::ForWindow(window)->shelf()-> 251 shelf_layout_manager(); 252 shelf->SetAutoHideBehavior(behavior); 253 ShelfView* shelf_view = GetShelfView(Launcher::ForWindow(window)); 254 test::ShelfViewTestAPI test_api(shelf_view); 255 test_api.RunMessageLoopUntilAnimationsDone(); 256 } 257 258 void SetShelfVisibilityState(aura::Window* window, 259 ShelfVisibilityState visibility_state) { 260 internal::ShelfLayoutManager* shelf = 261 RootWindowController::ForWindow(window)->shelf()-> 262 shelf_layout_manager(); 263 shelf->SetState(visibility_state); 264 } 265 266 internal::ShelfView* GetShelfView(Launcher* launcher) { 267 return test::LauncherTestAPI(launcher).shelf_view(); 268 } 269 270 private: 271 scoped_ptr<test::ShelfViewTestAPI> shelf_view_test_; 272 273 bool IsHorizontal(ShelfAlignment alignment) { 274 return alignment == SHELF_ALIGNMENT_BOTTOM || 275 alignment == SHELF_ALIGNMENT_TOP; 276 } 277 278 DISALLOW_COPY_AND_ASSIGN(PanelLayoutManagerTest); 279 }; 280 281 class PanelLayoutManagerTextDirectionTest 282 : public PanelLayoutManagerTest, 283 public testing::WithParamInterface<bool> { 284 public: 285 PanelLayoutManagerTextDirectionTest() : is_rtl_(GetParam()) {} 286 virtual ~PanelLayoutManagerTextDirectionTest() {} 287 288 virtual void SetUp() OVERRIDE { 289 original_locale = l10n_util::GetApplicationLocale(std::string()); 290 if (is_rtl_) 291 base::i18n::SetICUDefaultLocale("he"); 292 PanelLayoutManagerTest::SetUp(); 293 ASSERT_EQ(is_rtl_, base::i18n::IsRTL()); 294 } 295 296 virtual void TearDown() OVERRIDE { 297 if (is_rtl_) 298 base::i18n::SetICUDefaultLocale(original_locale); 299 PanelLayoutManagerTest::TearDown(); 300 } 301 302 private: 303 bool is_rtl_; 304 std::string original_locale; 305 306 DISALLOW_COPY_AND_ASSIGN(PanelLayoutManagerTextDirectionTest); 307 }; 308 309 // Tests that a created panel window is above the launcher icon in LTR and RTL. 310 TEST_P(PanelLayoutManagerTextDirectionTest, AddOnePanel) { 311 gfx::Rect bounds(0, 0, 201, 201); 312 scoped_ptr<aura::Window> window(CreatePanelWindow(bounds)); 313 EXPECT_EQ(GetPanelContainer(window.get()), window->parent()); 314 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(window.get())); 315 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(window.get())); 316 } 317 318 // Tests that a created panel window is successfully aligned over a hidden 319 // launcher icon. 320 TEST_F(PanelLayoutManagerTest, PanelAlignsToHiddenLauncherIcon) { 321 gfx::Rect bounds(0, 0, 201, 201); 322 SetShelfAutoHideBehavior(Shell::GetPrimaryRootWindow(), 323 SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); 324 scoped_ptr<aura::Window> normal_window(CreateNormalWindow(bounds)); 325 scoped_ptr<aura::Window> window(CreatePanelWindow(bounds)); 326 EXPECT_EQ(GetPanelContainer(window.get()), window->parent()); 327 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(window.get())); 328 } 329 330 TEST_F(PanelLayoutManagerTest, PanelAlignsToHiddenLauncherIconSecondDisplay) { 331 if (!SupportsMultipleDisplays()) 332 return; 333 334 // Keep the displays wide so that launchers have enough 335 // space for launcher buttons. 336 UpdateDisplay("400x400,600x400"); 337 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 338 339 scoped_ptr<aura::Window> normal_window( 340 CreateNormalWindow(gfx::Rect(450, 0, 100, 100))); 341 scoped_ptr<aura::Window> panel(CreatePanelWindow(gfx::Rect(400, 0, 50, 50))); 342 EXPECT_EQ(root_windows[1], panel->GetRootWindow()); 343 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(panel.get())); 344 gfx::Rect shelf_visible_position = panel->GetBoundsInScreen(); 345 346 SetShelfAutoHideBehavior(root_windows[1], 347 SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); 348 // Expect the panel X position to remain the same after the shelf is hidden 349 // but the Y to move down. 350 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(panel.get())); 351 EXPECT_EQ(shelf_visible_position.x(), panel->GetBoundsInScreen().x()); 352 EXPECT_GT(panel->GetBoundsInScreen().y(), shelf_visible_position.y()); 353 } 354 355 // Tests interactions between multiple panels 356 TEST_F(PanelLayoutManagerTest, MultiplePanelsAreAboveIcons) { 357 gfx::Rect odd_bounds(0, 0, 201, 201); 358 gfx::Rect even_bounds(0, 0, 200, 200); 359 360 scoped_ptr<aura::Window> w1(CreatePanelWindow(odd_bounds)); 361 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get())); 362 363 scoped_ptr<aura::Window> w2(CreatePanelWindow(even_bounds)); 364 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get())); 365 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get())); 366 367 scoped_ptr<aura::Window> w3(CreatePanelWindow(odd_bounds)); 368 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get())); 369 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get())); 370 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get())); 371 } 372 373 TEST_F(PanelLayoutManagerTest, MultiplePanelStacking) { 374 gfx::Rect bounds(0, 0, 201, 201); 375 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 376 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 377 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 378 379 // Default stacking order. 380 EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get())); 381 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 382 383 // Changing the active window should update the stacking order. 384 wm::ActivateWindow(w1.get()); 385 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 386 EXPECT_TRUE(WindowIsAbove(w1.get(), w2.get())); 387 EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get())); 388 389 wm::ActivateWindow(w2.get()); 390 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 391 EXPECT_TRUE(WindowIsAbove(w1.get(), w3.get())); 392 EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get())); 393 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 394 395 wm::ActivateWindow(w3.get()); 396 EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get())); 397 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 398 } 399 400 TEST_F(PanelLayoutManagerTest, MultiplePanelStackingVertical) { 401 // set launcher shelf to be aligned on the right 402 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_RIGHT); 403 404 // Size panels in such a way that ordering them by X coordinate would cause 405 // stacking order to be incorrect. Test that stacking order is based on Y. 406 scoped_ptr<aura::Window> w1(CreatePanelWindow(gfx::Rect(0, 0, 210, 201))); 407 scoped_ptr<aura::Window> w2(CreatePanelWindow(gfx::Rect(0, 0, 220, 201))); 408 scoped_ptr<aura::Window> w3(CreatePanelWindow(gfx::Rect(0, 0, 200, 201))); 409 410 // Default stacking order. 411 EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get())); 412 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 413 414 // Changing the active window should update the stacking order. 415 wm::ActivateWindow(w1.get()); 416 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 417 EXPECT_TRUE(WindowIsAbove(w1.get(), w2.get())); 418 EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get())); 419 420 wm::ActivateWindow(w2.get()); 421 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 422 EXPECT_TRUE(WindowIsAbove(w1.get(), w3.get())); 423 EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get())); 424 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 425 426 wm::ActivateWindow(w3.get()); 427 EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get())); 428 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 429 } 430 431 TEST_F(PanelLayoutManagerTest, MultiplePanelCallout) { 432 gfx::Rect bounds(0, 0, 200, 200); 433 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 434 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 435 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 436 scoped_ptr<aura::Window> w4(CreateNormalWindow(gfx::Rect())); 437 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 438 EXPECT_TRUE(IsPanelCalloutVisible(w1.get())); 439 EXPECT_TRUE(IsPanelCalloutVisible(w2.get())); 440 EXPECT_TRUE(IsPanelCalloutVisible(w3.get())); 441 wm::ActivateWindow(w1.get()); 442 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w1.get())); 443 wm::ActivateWindow(w2.get()); 444 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w2.get())); 445 wm::ActivateWindow(w3.get()); 446 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w3.get())); 447 wm::ActivateWindow(w4.get()); 448 wm::ActivateWindow(w3.get()); 449 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w3.get())); 450 w3.reset(); 451 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w2.get())); 452 } 453 454 // Tests removing panels. 455 TEST_F(PanelLayoutManagerTest, RemoveLeftPanel) { 456 gfx::Rect bounds(0, 0, 201, 201); 457 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 458 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 459 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 460 461 // At this point, windows should be stacked with 1 < 2 < 3 462 wm::ActivateWindow(w1.get()); 463 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 464 // Now, windows should be stacked 1 > 2 > 3 465 w1.reset(); 466 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get())); 467 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get())); 468 EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get())); 469 } 470 471 TEST_F(PanelLayoutManagerTest, RemoveMiddlePanel) { 472 gfx::Rect bounds(0, 0, 201, 201); 473 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 474 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 475 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 476 477 // At this point, windows should be stacked with 1 < 2 < 3 478 wm::ActivateWindow(w2.get()); 479 // Windows should be stacked 1 < 2 > 3 480 w2.reset(); 481 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get())); 482 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get())); 483 EXPECT_TRUE(WindowIsAbove(w3.get(), w1.get())); 484 } 485 486 TEST_F(PanelLayoutManagerTest, RemoveRightPanel) { 487 gfx::Rect bounds(0, 0, 201, 201); 488 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 489 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 490 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 491 492 // At this point, windows should be stacked with 1 < 2 < 3 493 wm::ActivateWindow(w3.get()); 494 // Order shouldn't change. 495 w3.reset(); 496 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get())); 497 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get())); 498 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 499 } 500 501 TEST_F(PanelLayoutManagerTest, RemoveNonActivePanel) { 502 gfx::Rect bounds(0, 0, 201, 201); 503 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 504 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 505 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 506 507 // At this point, windows should be stacked with 1 < 2 < 3 508 wm::ActivateWindow(w2.get()); 509 // Windows should be stacked 1 < 2 > 3 510 w1.reset(); 511 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get())); 512 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get())); 513 EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get())); 514 } 515 516 TEST_F(PanelLayoutManagerTest, SplitView) { 517 gfx::Rect bounds(0, 0, 90, 201); 518 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 519 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 520 521 EXPECT_NO_FATAL_FAILURE(PanelsNotOverlapping(w1.get(), w2.get())); 522 } 523 524 #if defined(OS_WIN) 525 // RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962 526 #define MAYBE_SplitViewOverlapWhenLarge DISABLED_SplitViewOverlapWhenLarge 527 #else 528 #define MAYBE_SplitViewOverlapWhenLarge SplitViewOverlapWhenLarge 529 #endif 530 531 TEST_F(PanelLayoutManagerTest, MAYBE_SplitViewOverlapWhenLarge) { 532 gfx::Rect bounds(0, 0, 600, 201); 533 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 534 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 535 536 EXPECT_NO_FATAL_FAILURE(PanelInScreen(w1.get())); 537 EXPECT_NO_FATAL_FAILURE(PanelInScreen(w2.get())); 538 } 539 540 TEST_F(PanelLayoutManagerTest, FanWindows) { 541 gfx::Rect bounds(0, 0, 201, 201); 542 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 543 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 544 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 545 546 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 547 int window_x1 = w1->GetBoundsInRootWindow().CenterPoint().x(); 548 int window_x2 = w2->GetBoundsInRootWindow().CenterPoint().x(); 549 int window_x3 = w3->GetBoundsInRootWindow().CenterPoint().x(); 550 Launcher* launcher = Launcher::ForPrimaryDisplay(); 551 int icon_x1 = launcher->GetScreenBoundsOfItemIconForWindow(w1.get()).x(); 552 int icon_x2 = launcher->GetScreenBoundsOfItemIconForWindow(w2.get()).x(); 553 EXPECT_EQ(window_x2 - window_x1, window_x3 - window_x2); 554 int spacing = window_x2 - window_x1; 555 EXPECT_GT(spacing, icon_x2 - icon_x1); 556 } 557 558 TEST_F(PanelLayoutManagerTest, FanLargeWindow) { 559 gfx::Rect small_bounds(0, 0, 201, 201); 560 gfx::Rect large_bounds(0, 0, 501, 201); 561 scoped_ptr<aura::Window> w1(CreatePanelWindow(small_bounds)); 562 scoped_ptr<aura::Window> w2(CreatePanelWindow(large_bounds)); 563 scoped_ptr<aura::Window> w3(CreatePanelWindow(small_bounds)); 564 565 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 566 int window_x1 = w1->GetBoundsInRootWindow().CenterPoint().x(); 567 int window_x2 = w2->GetBoundsInRootWindow().CenterPoint().x(); 568 int window_x3 = w3->GetBoundsInRootWindow().CenterPoint().x(); 569 // The distances may not be equidistant with a large panel but the panels 570 // should be in the correct order with respect to their midpoints. 571 EXPECT_GT(window_x2, window_x1); 572 EXPECT_GT(window_x3, window_x2); 573 } 574 575 TEST_F(PanelLayoutManagerTest, MinimizeRestorePanel) { 576 gfx::Rect bounds(0, 0, 201, 201); 577 scoped_ptr<aura::Window> window(CreatePanelWindow(bounds)); 578 // Activate the window, ensure callout is visible. 579 wm::ActivateWindow(window.get()); 580 RunAllPendingInMessageLoop(); 581 EXPECT_TRUE(IsPanelCalloutVisible(window.get())); 582 // Minimize the panel, callout should be hidden. 583 window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); 584 RunAllPendingInMessageLoop(); 585 EXPECT_FALSE(IsPanelCalloutVisible(window.get())); 586 // Restore the pantel; panel should not be activated by default but callout 587 // should be visible. 588 window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); 589 RunAllPendingInMessageLoop(); 590 EXPECT_TRUE(IsPanelCalloutVisible(window.get())); 591 // Activate the window, ensure callout is visible. 592 wm::ActivateWindow(window.get()); 593 RunAllPendingInMessageLoop(); 594 EXPECT_TRUE(IsPanelCalloutVisible(window.get())); 595 } 596 597 TEST_F(PanelLayoutManagerTest, PanelMoveBetweenMultipleDisplays) { 598 if (!SupportsMultipleDisplays()) 599 return; 600 601 // Keep the displays wide so that launchers have enough 602 // space for launcher buttons. 603 UpdateDisplay("600x400,600x400"); 604 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 605 606 scoped_ptr<aura::Window> p1_d1(CreatePanelWindow(gfx::Rect(0, 0, 50, 50))); 607 scoped_ptr<aura::Window> p2_d1(CreatePanelWindow(gfx::Rect(0, 0, 50, 50))); 608 scoped_ptr<aura::Window> p1_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50))); 609 scoped_ptr<aura::Window> p2_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50))); 610 611 ShelfView* shelf_view_1st = GetShelfView(Launcher::ForPrimaryDisplay()); 612 ShelfView* shelf_view_2nd = 613 GetShelfView(Launcher::ForWindow(root_windows[1])); 614 615 EXPECT_EQ(root_windows[0], p1_d1->GetRootWindow()); 616 EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow()); 617 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 618 EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow()); 619 620 EXPECT_EQ(internal::kShellWindowId_PanelContainer, p1_d1->parent()->id()); 621 EXPECT_EQ(internal::kShellWindowId_PanelContainer, p2_d1->parent()->id()); 622 EXPECT_EQ(internal::kShellWindowId_PanelContainer, p1_d2->parent()->id()); 623 EXPECT_EQ(internal::kShellWindowId_PanelContainer, p2_d2->parent()->id()); 624 625 // Test a panel on 1st display. 626 // Clicking on the same display has no effect. 627 ClickLauncherItemForWindow(shelf_view_1st, p1_d1.get()); 628 EXPECT_EQ(root_windows[0], p1_d1->GetRootWindow()); 629 EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow()); 630 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 631 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 632 EXPECT_FALSE(root_windows[1]->GetBoundsInScreen().Contains( 633 p1_d1->GetBoundsInScreen())); 634 635 // Test if clicking on another display moves the panel to 636 // that display. 637 ClickLauncherItemForWindow(shelf_view_2nd, p1_d1.get()); 638 EXPECT_EQ(root_windows[1], p1_d1->GetRootWindow()); 639 EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow()); 640 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 641 EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow()); 642 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains( 643 p1_d1->GetBoundsInScreen())); 644 645 // Test a panel on 2nd display. 646 // Clicking on the same display has no effect. 647 ClickLauncherItemForWindow(shelf_view_2nd, p1_d2.get()); 648 EXPECT_EQ(root_windows[1], p1_d1->GetRootWindow()); 649 EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow()); 650 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 651 EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow()); 652 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains( 653 p1_d2->GetBoundsInScreen())); 654 655 // Test if clicking on another display moves the panel to 656 // that display. 657 ClickLauncherItemForWindow(shelf_view_1st, p1_d2.get()); 658 EXPECT_EQ(root_windows[1], p1_d1->GetRootWindow()); 659 EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow()); 660 EXPECT_EQ(root_windows[0], p1_d2->GetRootWindow()); 661 EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow()); 662 EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains( 663 p1_d2->GetBoundsInScreen())); 664 665 // Test if clicking on a previously moved window moves the 666 // panel back to the original display. 667 ClickLauncherItemForWindow(shelf_view_1st, p1_d1.get()); 668 EXPECT_EQ(root_windows[0], p1_d1->GetRootWindow()); 669 EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow()); 670 EXPECT_EQ(root_windows[0], p1_d2->GetRootWindow()); 671 EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow()); 672 EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains( 673 p1_d1->GetBoundsInScreen())); 674 } 675 676 TEST_F(PanelLayoutManagerTest, PanelAttachPositionMultipleDisplays) { 677 if (!SupportsMultipleDisplays()) 678 return; 679 680 // Keep the displays wide so that launchers have enough space for launcher 681 // buttons. Use differently sized displays so the launcher is in a different 682 // position on second display. 683 UpdateDisplay("600x400,600x600"); 684 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 685 686 scoped_ptr<aura::Window> p1_d1(CreatePanelWindow(gfx::Rect(0, 0, 50, 50))); 687 scoped_ptr<aura::Window> p1_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50))); 688 689 EXPECT_EQ(root_windows[0], p1_d1->GetRootWindow()); 690 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 691 692 IsPanelAboveLauncherIcon(p1_d1.get()); 693 IsCalloutAboveLauncherIcon(p1_d1.get()); 694 IsPanelAboveLauncherIcon(p1_d2.get()); 695 IsCalloutAboveLauncherIcon(p1_d2.get()); 696 } 697 698 TEST_F(PanelLayoutManagerTest, PanelAlignmentSecondDisplay) { 699 if (!SupportsMultipleDisplays()) 700 return; 701 702 UpdateDisplay("600x400,600x400"); 703 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 704 705 scoped_ptr<aura::Window> p1_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50))); 706 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 707 708 IsPanelAboveLauncherIcon(p1_d2.get()); 709 IsCalloutAboveLauncherIcon(p1_d2.get()); 710 711 SetAlignment(root_windows[1], SHELF_ALIGNMENT_RIGHT); 712 IsPanelAboveLauncherIcon(p1_d2.get()); 713 IsCalloutAboveLauncherIcon(p1_d2.get()); 714 SetAlignment(root_windows[1], SHELF_ALIGNMENT_LEFT); 715 IsPanelAboveLauncherIcon(p1_d2.get()); 716 IsCalloutAboveLauncherIcon(p1_d2.get()); 717 SetAlignment(root_windows[1], SHELF_ALIGNMENT_TOP); 718 IsPanelAboveLauncherIcon(p1_d2.get()); 719 IsCalloutAboveLauncherIcon(p1_d2.get()); 720 } 721 722 TEST_F(PanelLayoutManagerTest, AlignmentLeft) { 723 gfx::Rect bounds(0, 0, 201, 201); 724 scoped_ptr<aura::Window> w(CreatePanelWindow(bounds)); 725 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_LEFT); 726 IsPanelAboveLauncherIcon(w.get()); 727 IsCalloutAboveLauncherIcon(w.get()); 728 } 729 730 TEST_F(PanelLayoutManagerTest, AlignmentRight) { 731 gfx::Rect bounds(0, 0, 201, 201); 732 scoped_ptr<aura::Window> w(CreatePanelWindow(bounds)); 733 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_RIGHT); 734 IsPanelAboveLauncherIcon(w.get()); 735 IsCalloutAboveLauncherIcon(w.get()); 736 } 737 738 TEST_F(PanelLayoutManagerTest, AlignmentTop) { 739 gfx::Rect bounds(0, 0, 201, 201); 740 scoped_ptr<aura::Window> w(CreatePanelWindow(bounds)); 741 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_TOP); 742 IsPanelAboveLauncherIcon(w.get()); 743 IsCalloutAboveLauncherIcon(w.get()); 744 } 745 746 // Tests that panels will hide and restore their state with the shelf visibility 747 // state. This ensures that entering full-screen mode will hide your panels 748 // until you leave it. 749 TEST_F(PanelLayoutManagerTest, PanelsHideAndRestoreWithShelf) { 750 gfx::Rect bounds(0, 0, 201, 201); 751 752 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 753 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 754 scoped_ptr<aura::Window> w3; 755 // Minimize w2. 756 w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); 757 RunAllPendingInMessageLoop(); 758 EXPECT_TRUE(w1->IsVisible()); 759 EXPECT_FALSE(w2->IsVisible()); 760 761 SetShelfVisibilityState(Shell::GetPrimaryRootWindow(), SHELF_HIDDEN); 762 RunAllPendingInMessageLoop(); 763 764 // w3 is created while in full-screen mode, should only become visible when 765 // we exit fullscreen mode. 766 w3.reset(CreatePanelWindow(bounds)); 767 768 EXPECT_FALSE(w1->IsVisible()); 769 EXPECT_FALSE(w2->IsVisible()); 770 EXPECT_FALSE(w3->IsVisible()); 771 772 // While in full-screen mode, the panel windows should still be in the 773 // switchable window list - http://crbug.com/313919. 774 MruWindowTracker::WindowList switchable_window_list = 775 Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList(); 776 EXPECT_EQ(3u, switchable_window_list.size()); 777 EXPECT_NE(switchable_window_list.end(), 778 std::find(switchable_window_list.begin(), switchable_window_list.end(), 779 w1.get())); 780 EXPECT_NE(switchable_window_list.end(), 781 std::find(switchable_window_list.begin(), switchable_window_list.end(), 782 w2.get())); 783 EXPECT_NE(switchable_window_list.end(), 784 std::find(switchable_window_list.begin(), switchable_window_list.end(), 785 w3.get())); 786 787 SetShelfVisibilityState(Shell::GetPrimaryRootWindow(), SHELF_VISIBLE); 788 RunAllPendingInMessageLoop(); 789 790 // Windows should be restored to their prior state. 791 EXPECT_TRUE(w1->IsVisible()); 792 EXPECT_FALSE(w2->IsVisible()); 793 EXPECT_TRUE(w3->IsVisible()); 794 } 795 796 INSTANTIATE_TEST_CASE_P(LtrRtl, PanelLayoutManagerTextDirectionTest, 797 testing::Bool()); 798 799 } // namespace internal 800 } // namespace ash 801