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