1// Copyright (c) 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/wm/dock/docked_window_resizer.h" 6 7#include "ash/ash_switches.h" 8#include "ash/root_window_controller.h" 9#include "ash/screen_util.h" 10#include "ash/shelf/shelf.h" 11#include "ash/shelf/shelf_layout_manager.h" 12#include "ash/shelf/shelf_model.h" 13#include "ash/shelf/shelf_types.h" 14#include "ash/shelf/shelf_widget.h" 15#include "ash/shell.h" 16#include "ash/shell_window_ids.h" 17#include "ash/test/ash_test_base.h" 18#include "ash/test/cursor_manager_test_api.h" 19#include "ash/test/shell_test_api.h" 20#include "ash/test/test_shelf_delegate.h" 21#include "ash/wm/dock/docked_window_layout_manager.h" 22#include "ash/wm/drag_window_resizer.h" 23#include "ash/wm/panels/panel_layout_manager.h" 24#include "ash/wm/window_state.h" 25#include "ash/wm/window_util.h" 26#include "ash/wm/wm_event.h" 27#include "base/command_line.h" 28#include "ui/aura/client/aura_constants.h" 29#include "ui/aura/client/window_tree_client.h" 30#include "ui/aura/test/test_window_delegate.h" 31#include "ui/aura/window_event_dispatcher.h" 32#include "ui/base/hit_test.h" 33#include "ui/base/ui_base_types.h" 34#include "ui/events/test/event_generator.h" 35#include "ui/views/widget/widget.h" 36#include "ui/wm/core/coordinate_conversion.h" 37#include "ui/wm/core/window_util.h" 38 39namespace ash { 40 41class DockedWindowResizerTest 42 : public test::AshTestBase, 43 public testing::WithParamInterface<ui::wm::WindowType> { 44 public: 45 DockedWindowResizerTest() : model_(NULL), window_type_(GetParam()) {} 46 virtual ~DockedWindowResizerTest() {} 47 48 virtual void SetUp() OVERRIDE { 49 AshTestBase::SetUp(); 50 UpdateDisplay("600x400"); 51 test::ShellTestApi test_api(Shell::GetInstance()); 52 model_ = test_api.shelf_model(); 53 } 54 55 virtual void TearDown() OVERRIDE { 56 AshTestBase::TearDown(); 57 } 58 59 protected: 60 enum DockedEdge { 61 DOCKED_EDGE_NONE, 62 DOCKED_EDGE_LEFT, 63 DOCKED_EDGE_RIGHT, 64 }; 65 66 int ideal_width() const { return DockedWindowLayoutManager::kIdealWidth; } 67 int min_dock_gap() const { return DockedWindowLayoutManager::kMinDockGap; } 68 int max_width() const { return DockedWindowLayoutManager::kMaxDockWidth; } 69 int docked_width(const DockedWindowLayoutManager* layout_manager) const { 70 return layout_manager->docked_width_; 71 } 72 int docked_alignment(const DockedWindowLayoutManager* layout_manager) const { 73 return layout_manager->alignment_; 74 } 75 aura::Window* CreateTestWindow(const gfx::Rect& bounds) { 76 aura::Window* window = CreateTestWindowInShellWithDelegateAndType( 77 &delegate_, 78 window_type_, 79 0, 80 bounds); 81 if (window_type_ == ui::wm::WINDOW_TYPE_PANEL) { 82 test::TestShelfDelegate* shelf_delegate = 83 test::TestShelfDelegate::instance(); 84 shelf_delegate->AddShelfItem(window); 85 PanelLayoutManager* manager = static_cast<PanelLayoutManager*>( 86 Shell::GetContainer(window->GetRootWindow(), 87 kShellWindowId_PanelContainer)->layout_manager()); 88 manager->Relayout(); 89 } 90 return window; 91 } 92 93 aura::Window* CreateModalWindow(const gfx::Rect& bounds) { 94 aura::Window* window = new aura::Window(&delegate_); 95 window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM); 96 window->SetType(ui::wm::WINDOW_TYPE_NORMAL); 97 window->Init(aura::WINDOW_LAYER_TEXTURED); 98 window->Show(); 99 100 if (bounds.IsEmpty()) { 101 ParentWindowInPrimaryRootWindow(window); 102 } else { 103 gfx::Display display = 104 Shell::GetScreen()->GetDisplayMatching(bounds); 105 aura::Window* root = ash::Shell::GetInstance()->display_controller()-> 106 GetRootWindowForDisplayId(display.id()); 107 gfx::Point origin = bounds.origin(); 108 ::wm::ConvertPointFromScreen(root, &origin); 109 window->SetBounds(gfx::Rect(origin, bounds.size())); 110 aura::client::ParentWindowWithContext(window, root, bounds); 111 } 112 return window; 113 } 114 115 static WindowResizer* CreateSomeWindowResizer( 116 aura::Window* window, 117 const gfx::Point& point_in_parent, 118 int window_component) { 119 return CreateWindowResizer( 120 window, 121 point_in_parent, 122 window_component, 123 aura::client::WINDOW_MOVE_SOURCE_MOUSE).release(); 124 } 125 126 void DragStart(aura::Window* window) { 127 DragStartAtOffsetFromWindowOrigin(window, 0, 0); 128 } 129 130 void DragStartAtOffsetFromWindowOrigin(aura::Window* window, 131 int dx, int dy) { 132 initial_location_in_parent_ = 133 window->bounds().origin() + gfx::Vector2d(dx, dy); 134 resizer_.reset(CreateSomeWindowResizer(window, 135 initial_location_in_parent_, 136 HTCAPTION)); 137 ASSERT_TRUE(resizer_.get()); 138 } 139 140 void ResizeStartAtOffsetFromWindowOrigin(aura::Window* window, 141 int dx, int dy, 142 int window_component) { 143 initial_location_in_parent_ = 144 window->bounds().origin() + gfx::Vector2d(dx, dy); 145 resizer_.reset(CreateSomeWindowResizer(window, 146 initial_location_in_parent_, 147 window_component)); 148 ASSERT_TRUE(resizer_.get()); 149 } 150 151 void DragMove(int dx, int dy) { 152 resizer_->Drag(initial_location_in_parent_ + gfx::Vector2d(dx, dy), 0); 153 } 154 155 void DragEnd() { 156 resizer_->CompleteDrag(); 157 resizer_.reset(); 158 } 159 160 void DragRevert() { 161 resizer_->RevertDrag(); 162 resizer_.reset(); 163 } 164 165 // Panels are parented by panel container during drags. 166 // All other windows that are tested here are parented by dock container 167 // during drags. 168 int CorrectContainerIdDuringDrag() { 169 if (window_type_ == ui::wm::WINDOW_TYPE_PANEL) 170 return kShellWindowId_PanelContainer; 171 return kShellWindowId_DockedContainer; 172 } 173 174 // Test dragging the window vertically (to detach if it is a panel) and then 175 // horizontally to the edge with an added offset from the edge of |dx|. 176 void DragRelativeToEdge(DockedEdge edge, 177 aura::Window* window, 178 int dx) { 179 DragVerticallyAndRelativeToEdge( 180 edge, 181 window, 182 dx, 183 window_type_ == ui::wm::WINDOW_TYPE_PANEL ? -100 : 20, 184 25, 185 5); 186 } 187 188 void DragToVerticalPositionAndToEdge(DockedEdge edge, 189 aura::Window* window, 190 int y) { 191 DragToVerticalPositionRelativeToEdge(edge, window, 0, y); 192 } 193 194 void DragToVerticalPositionRelativeToEdge(DockedEdge edge, 195 aura::Window* window, 196 int dx, 197 int y) { 198 gfx::Rect initial_bounds = window->GetBoundsInScreen(); 199 DragVerticallyAndRelativeToEdge(edge, 200 window, 201 dx, y - initial_bounds.y(), 202 25, 5); 203 } 204 205 // Detach if our window is a panel, then drag it vertically by |dy| and 206 // horizontally to the edge with an added offset from the edge of |dx|. 207 void DragVerticallyAndRelativeToEdge(DockedEdge edge, 208 aura::Window* window, 209 int dx, int dy, 210 int grab_x, int grab_y) { 211 gfx::Rect initial_bounds = window->GetBoundsInScreen(); 212 // avoid snap by clicking away from the border 213 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin(window, 214 grab_x, grab_y)); 215 216 gfx::Rect work_area = 217 Shell::GetScreen()->GetDisplayNearestWindow(window).work_area(); 218 gfx::Point initial_location_in_screen = initial_location_in_parent_; 219 ::wm::ConvertPointToScreen(window->parent(), &initial_location_in_screen); 220 // Drag the window left or right to the edge (or almost to it). 221 if (edge == DOCKED_EDGE_LEFT) 222 dx += work_area.x() - initial_location_in_screen.x(); 223 else if (edge == DOCKED_EDGE_RIGHT) 224 dx += work_area.right() - 1 - initial_location_in_screen.x(); 225 DragMove(dx, dy); 226 EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id()); 227 // Release the mouse and the panel should be attached to the dock. 228 DragEnd(); 229 230 // x-coordinate can get adjusted by snapping or sticking. 231 // y-coordinate could be changed by possible automatic layout if docked. 232 if (window->parent()->id() != kShellWindowId_DockedContainer && 233 !wm::GetWindowState(window)->HasRestoreBounds()) { 234 EXPECT_EQ(initial_bounds.y() + dy, window->GetBoundsInScreen().y()); 235 } 236 } 237 238 bool test_panels() const { return window_type_ == ui::wm::WINDOW_TYPE_PANEL; } 239 240 aura::test::TestWindowDelegate* delegate() { 241 return &delegate_; 242 } 243 244 const gfx::Point& initial_location_in_parent() const { 245 return initial_location_in_parent_; 246 } 247 248 private: 249 scoped_ptr<WindowResizer> resizer_; 250 ShelfModel* model_; 251 ui::wm::WindowType window_type_; 252 aura::test::TestWindowDelegate delegate_; 253 254 // Location at start of the drag in |window->parent()|'s coordinates. 255 gfx::Point initial_location_in_parent_; 256 257 DISALLOW_COPY_AND_ASSIGN(DockedWindowResizerTest); 258}; 259 260// Verifies a window can be dragged and attached to the dock. 261TEST_P(DockedWindowResizerTest, AttachRightPrecise) { 262 if (!SupportsHostWindowResize()) 263 return; 264 265 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 266 DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0); 267 268 // The window should be docked at the right edge. 269 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 270 window->GetBoundsInScreen().right()); 271 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 272} 273 274// Verifies a window can be dragged and attached to the dock 275// even if pointer overshoots the screen edge by a few pixels (sticky edge) 276TEST_P(DockedWindowResizerTest, AttachRightOvershoot) { 277 if (!SupportsHostWindowResize()) 278 return; 279 280 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 281 DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), +4); 282 283 // The window should be docked at the right edge. 284 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 285 window->GetBoundsInScreen().right()); 286 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 287} 288 289// Verifies a window can be dragged and then if a pointer is not quite reaching 290// the screen edge the window does not get docked and stays in the desktop. 291TEST_P(DockedWindowResizerTest, AttachRightUndershoot) { 292 if (!SupportsHostWindowResize()) 293 return; 294 295 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 296 // Grabbing at 70px ensures that at least 30% of the window is in screen, 297 // otherwise the window would be adjusted in 298 // WorkspaceLayoutManager::AdjustWindowBoundsWhenAdded. 299 const int kGrabOffsetX = 70; 300 const int kUndershootBy = 1; 301 DragVerticallyAndRelativeToEdge(DOCKED_EDGE_RIGHT, 302 window.get(), 303 -kUndershootBy, test_panels() ? -100 : 20, 304 kGrabOffsetX, 5); 305 306 // The window right should be past the screen edge but not docked. 307 // Initial touch point is 70px to the right which helps to find where the edge 308 // should be. 309 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right() + 310 window->bounds().width() - kGrabOffsetX - kUndershootBy - 1, 311 window->GetBoundsInScreen().right()); 312 EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id()); 313} 314 315// Verifies a window can be dragged and attached to the dock. 316TEST_P(DockedWindowResizerTest, AttachLeftPrecise) { 317 if (!SupportsHostWindowResize()) 318 return; 319 320 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 321 DragRelativeToEdge(DOCKED_EDGE_LEFT, window.get(), 0); 322 323 // The window should be docked at the left edge. 324 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().x(), 325 window->GetBoundsInScreen().x()); 326 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 327} 328 329// Verifies a window can be dragged and attached to the dock 330// even if pointer overshoots the screen edge by a few pixels (sticky edge) 331TEST_P(DockedWindowResizerTest, AttachLeftOvershoot) { 332 if (!SupportsHostWindowResize()) 333 return; 334 335 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 336 DragRelativeToEdge(DOCKED_EDGE_LEFT, window.get(), -4); 337 338 // The window should be docked at the left edge. 339 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().x(), 340 window->GetBoundsInScreen().x()); 341 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 342} 343 344// Verifies a window can be dragged and then if a pointer is not quite reaching 345// the screen edge the window does not get docked and stays in the desktop. 346TEST_P(DockedWindowResizerTest, AttachLeftUndershoot) { 347 if (!SupportsHostWindowResize()) 348 return; 349 350 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 351 gfx::Rect initial_bounds(window->bounds()); 352 DragRelativeToEdge(DOCKED_EDGE_LEFT, window.get(), 1); 353 354 // The window should be crossing the screen edge but not docked. 355 int expected_x = initial_bounds.x() - initial_location_in_parent().x() + 1; 356 EXPECT_EQ(expected_x, window->GetBoundsInScreen().x()); 357 EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id()); 358} 359 360// Dock on the right side, change shelf alignment, check that windows move to 361// the opposite side. 362TEST_P(DockedWindowResizerTest, AttachRightChangeShelf) { 363 if (!SupportsHostWindowResize()) 364 return; 365 366 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 367 DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0); 368 369 // The window should be docked at the right edge. 370 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 371 window->GetBoundsInScreen().right()); 372 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 373 374 // set launcher shelf to be aligned on the right 375 ash::Shell* shell = ash::Shell::GetInstance(); 376 shell->SetShelfAlignment(SHELF_ALIGNMENT_RIGHT, 377 shell->GetPrimaryRootWindow()); 378 // The window should have moved and get attached to the left dock. 379 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().x(), 380 window->GetBoundsInScreen().x()); 381 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 382 383 // set launcher shelf to be aligned on the left 384 shell->SetShelfAlignment(SHELF_ALIGNMENT_LEFT, 385 shell->GetPrimaryRootWindow()); 386 // The window should have moved and get attached to the right edge. 387 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 388 window->GetBoundsInScreen().right()); 389 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 390 391 // set launcher shelf to be aligned at the bottom 392 shell->SetShelfAlignment(SHELF_ALIGNMENT_BOTTOM, 393 shell->GetPrimaryRootWindow()); 394 // The window should stay in the right edge. 395 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 396 window->GetBoundsInScreen().right()); 397 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 398} 399 400// Dock on the right side, try to undock, then drag more to really undock 401TEST_P(DockedWindowResizerTest, AttachTryDetach) { 402 if (!SupportsHostWindowResize()) 403 return; 404 405 scoped_ptr<aura::Window> window(CreateTestWindow( 406 gfx::Rect(0, 0, ideal_width() + 10, 201))); 407 DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0); 408 409 // The window should be docked at the right edge. 410 // Its width should shrink to ideal width. 411 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 412 window->GetBoundsInScreen().right()); 413 EXPECT_EQ(ideal_width(), window->GetBoundsInScreen().width()); 414 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 415 416 // Try to detach by dragging left less than kSnapToDockDistance. 417 // The window should stay docked. 418 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin( 419 window.get(), 10, 0)); 420 DragMove(-4, -10); 421 // Release the mouse and the window should be still attached to the dock. 422 DragEnd(); 423 424 // The window should be still attached to the right edge. 425 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 426 window->GetBoundsInScreen().right()); 427 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 428 429 // Try to detach by dragging left by kSnapToDockDistance or more. 430 // The window should get undocked. 431 const int left_edge = window->bounds().x(); 432 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin( 433 window.get(), 10, 0)); 434 DragMove(-32, -10); 435 // Release the mouse and the window should be no longer attached to the dock. 436 DragEnd(); 437 438 // The window should be floating on the desktop again and moved to the left. 439 EXPECT_EQ(left_edge - 32, window->GetBoundsInScreen().x()); 440 EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id()); 441} 442 443// Dock on the right side, and undock by dragging the right edge of the window 444// header. This test is useful because both the position of the dragged window 445// and the position of the mouse are used in determining whether a window should 446// be undocked. 447TEST_P(DockedWindowResizerTest, AttachTryDetachDragRightEdgeOfHeader) { 448 if (!SupportsHostWindowResize()) 449 return; 450 451 scoped_ptr<aura::Window> window(CreateTestWindow( 452 gfx::Rect(0, 0, ideal_width() + 10, 201))); 453 DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0); 454 455 // The window should be docked at the right edge. 456 // Its width should shrink to ideal width. 457 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 458 window->GetBoundsInScreen().right()); 459 EXPECT_EQ(ideal_width(), window->GetBoundsInScreen().width()); 460 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 461 462 // Try to detach by dragging left less than kSnapToDockDistance. 463 // The window should stay docked. 464 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin( 465 window.get(), ideal_width() - 10, 0)); 466 DragMove(-4, -10); 467 // Release the mouse and the window should be still attached to the dock. 468 DragEnd(); 469 470 // The window should be still attached to the right edge. 471 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 472 window->GetBoundsInScreen().right()); 473 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 474 475 // Try to detach by dragging left by kSnapToDockDistance or more. 476 // The window should get undocked. 477 const int left_edge = window->bounds().x(); 478 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin( 479 window.get(), ideal_width() - 10, 0)); 480 DragMove(-32, -10); 481 // Release the mouse and the window should be no longer attached to the dock. 482 DragEnd(); 483 484 // The window should be floating on the desktop again and moved to the left. 485 EXPECT_EQ(left_edge - 32, window->GetBoundsInScreen().x()); 486 EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id()); 487} 488 489// Minimize a docked window, then restore it and check that it is still docked. 490TEST_P(DockedWindowResizerTest, AttachMinimizeRestore) { 491 if (!SupportsHostWindowResize()) 492 return; 493 494 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 495 DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0); 496 497 // The window should be docked at the right edge. 498 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 499 window->GetBoundsInScreen().right()); 500 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 501 502 wm::WindowState* window_state = wm::GetWindowState(window.get()); 503 // Minimize the window, it should be hidden. 504 window_state->Minimize(); 505 RunAllPendingInMessageLoop(); 506 EXPECT_FALSE(window->IsVisible()); 507 EXPECT_TRUE(window_state->IsMinimized()); 508 // Restore the window; window should be visible. 509 window_state->Restore(); 510 RunAllPendingInMessageLoop(); 511 EXPECT_TRUE(window->IsVisible()); 512 EXPECT_TRUE(window_state->IsNormalStateType()); 513} 514 515// Maximize a docked window and check that it is maximized and no longer docked. 516TEST_P(DockedWindowResizerTest, AttachMaximize) { 517 if (!SupportsHostWindowResize()) 518 return; 519 520 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 521 DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0); 522 523 // The window should be docked at the right edge. 524 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 525 window->GetBoundsInScreen().right()); 526 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 527 528 wm::WindowState* window_state = wm::GetWindowState(window.get()); 529 // Maximize the window, it should get undocked and maximized in a desktop. 530 window_state->Maximize(); 531 RunAllPendingInMessageLoop(); 532 EXPECT_TRUE(window->IsVisible()); 533 EXPECT_TRUE(window_state->IsMaximized()); 534 EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id()); 535} 536 537// Dock two windows, undock one, check that the other one is still docked. 538TEST_P(DockedWindowResizerTest, AttachTwoWindows) { 539 if (!SupportsHostWindowResize()) 540 return; 541 UpdateDisplay("600x600"); 542 543 scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 544 scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 545 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); 546 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 50); 547 548 // Docking second window should not minimize the first. 549 wm::WindowState* window_state1 = wm::GetWindowState(w1.get()); 550 EXPECT_FALSE(window_state1->IsMinimized()); 551 552 // Both windows should be docked at the right edge. 553 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 554 w1->GetBoundsInScreen().right()); 555 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 556 557 EXPECT_EQ(w2->GetRootWindow()->GetBoundsInScreen().right(), 558 w2->GetBoundsInScreen().right()); 559 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id()); 560 561 // Detach by dragging left (should get undocked). 562 const int left_edge = w2->bounds().x(); 563 ASSERT_NO_FATAL_FAILURE(DragStart(w2.get())); 564 // Drag up as well to avoid attaching panels to launcher shelf. 565 DragMove(-32, -100); 566 // Release the mouse and the window should be no longer attached to the edge. 567 DragEnd(); 568 569 // The first window should be still docked. 570 EXPECT_FALSE(window_state1->IsMinimized()); 571 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 572 w1->GetBoundsInScreen().right()); 573 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 574 575 // The window should be floating on the desktop again and moved to the left. 576 EXPECT_EQ(left_edge - 32, w2->GetBoundsInScreen().x()); 577 EXPECT_EQ(kShellWindowId_DefaultContainer, w2->parent()->id()); 578} 579 580// Create two windows, dock one and change shelf to auto-hide. 581TEST_P(DockedWindowResizerTest, AttachOneAutoHideShelf) { 582 if (!SupportsHostWindowResize()) 583 return; 584 585 scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 586 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); 587 588 // w1 should be docked at the right edge. 589 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 590 w1->GetBoundsInScreen().right()); 591 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 592 593 scoped_ptr<aura::Window> w2(CreateTestWindowInShellWithDelegateAndType( 594 NULL, ui::wm::WINDOW_TYPE_NORMAL, 0, gfx::Rect(20, 20, 150, 20))); 595 wm::GetWindowState(w2.get())->Maximize(); 596 EXPECT_EQ(kShellWindowId_DefaultContainer, w2->parent()->id()); 597 EXPECT_TRUE(wm::GetWindowState(w2.get())->IsMaximized()); 598 599 gfx::Rect work_area = 600 Shell::GetScreen()->GetDisplayNearestWindow(w1.get()).work_area(); 601 DockedWindowLayoutManager* manager = 602 static_cast<DockedWindowLayoutManager*>(w1->parent()->layout_manager()); 603 604 // Docked window should be centered vertically in the work area. 605 EXPECT_EQ(work_area.CenterPoint().y(), w1->bounds().CenterPoint().y()); 606 // Docked background should extend to the bottom of work area. 607 EXPECT_EQ(work_area.bottom(), manager->docked_bounds().bottom()); 608 609 // set launcher shelf to be aligned on the right 610 ash::Shell* shell = ash::Shell::GetInstance(); 611 shell->SetShelfAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, 612 shell->GetPrimaryRootWindow()); 613 work_area = 614 Shell::GetScreen()->GetDisplayNearestWindow(w1.get()).work_area(); 615 // Docked window should be centered vertically in the work area. 616 EXPECT_EQ(work_area.CenterPoint().y(), w1->bounds().CenterPoint().y()); 617 // Docked background should extend to the bottom of work area. 618 EXPECT_EQ(work_area.bottom(), manager->docked_bounds().bottom()); 619} 620 621// Dock one window, try to dock another window on the opposite side (should not 622// dock). 623TEST_P(DockedWindowResizerTest, AttachOnTwoSides) { 624 if (!SupportsHostWindowResize()) 625 return; 626 627 scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 628 scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 629 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); 630 gfx::Rect initial_bounds(w2->bounds()); 631 DragToVerticalPositionAndToEdge(DOCKED_EDGE_LEFT, w2.get(), 50); 632 633 // The first window should be docked at the right edge. 634 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 635 w1->GetBoundsInScreen().right()); 636 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 637 638 // The second window should be near the left edge but not snapped. 639 // Normal window will get side-maximized while panels will not. 640 int expected_x = test_panels() ? 641 (initial_bounds.x() - initial_location_in_parent().x()) : 0; 642 EXPECT_EQ(expected_x, w2->GetBoundsInScreen().x()); 643 EXPECT_EQ(kShellWindowId_DefaultContainer, w2->parent()->id()); 644} 645 646// Tests that reverting a drag restores docked state if a window was docked. 647TEST_P(DockedWindowResizerTest, RevertDragRestoresAttachment) { 648 if (!SupportsHostWindowResize()) 649 return; 650 651 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 652 DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0); 653 654 // The window should be docked at the right edge. 655 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 656 window->GetBoundsInScreen().right()); 657 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 658 659 // Drag the window out but revert the drag 660 ASSERT_NO_FATAL_FAILURE(DragStart(window.get())); 661 DragMove(-50, 0); 662 DragRevert(); 663 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 664 665 // Detach window. 666 ASSERT_NO_FATAL_FAILURE(DragStart(window.get())); 667 DragMove(-50, 0); 668 DragEnd(); 669 EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id()); 670} 671 672// Tests that reverting drag restores undocked state if a window was not docked. 673TEST_P(DockedWindowResizerTest, RevertDockedDragRevertsAttachment) { 674 if (!SupportsHostWindowResize()) 675 return; 676 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 677 aura::Window* dock_container = Shell::GetContainer( 678 window->GetRootWindow(), 679 kShellWindowId_DockedContainer); 680 DockedWindowLayoutManager* manager = 681 static_cast<DockedWindowLayoutManager*>(dock_container->layout_manager()); 682 int previous_container_id = window->parent()->id(); 683 // Drag the window out but revert the drag 684 ASSERT_NO_FATAL_FAILURE(DragStart(window.get())); 685 DragMove(-50 - window->bounds().x(), 50 - window->bounds().y()); 686 EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id()); 687 DragRevert(); 688 EXPECT_EQ(previous_container_id, window->parent()->id()); 689 EXPECT_EQ(DOCKED_ALIGNMENT_NONE, docked_alignment(manager)); 690 691 // Drag a window to the left so that it overlaps the screen edge. 692 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin( 693 window.get(), 694 window->bounds().width()/2 + 10, 695 0)); 696 DragMove(-50 - window->bounds().x(), 50 - window->bounds().y()); 697 DragEnd(); 698 // The window now overlaps the left screen edge but is not docked. 699 EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id()); 700 EXPECT_EQ(DOCKED_ALIGNMENT_NONE, docked_alignment(manager)); 701 EXPECT_LT(window->bounds().x(), 0); 702 EXPECT_GT(window->bounds().right(), 0); 703 704 // Drag the window further left and revert the drag. 705 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin( 706 window.get(), 707 window->bounds().width()/2 + 10, 708 0)); 709 DragMove(-10, 10); 710 DragRevert(); 711 // The window should be in default container and not docked. 712 EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id()); 713 // Docked area alignment should be cleared. 714 EXPECT_EQ(DOCKED_ALIGNMENT_NONE, docked_alignment(manager)); 715} 716 717// Move a docked window to the second display 718TEST_P(DockedWindowResizerTest, DragAcrossDisplays) { 719 if (!SupportsMultipleDisplays()) 720 return; 721 722 UpdateDisplay("800x800,800x800"); 723 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 724 EXPECT_EQ(2, static_cast<int>(root_windows.size())); 725 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 726 gfx::Rect initial_bounds = window->GetBoundsInScreen(); 727 EXPECT_EQ(root_windows[0], window->GetRootWindow()); 728 729 DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0); 730 // The window should be docked at the right edge. 731 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 732 window->GetBoundsInScreen().right()); 733 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 734 735 // Try dragging to the right - enough to get it peeking at the other screen 736 // but not enough to land in the other screen. 737 // The window should stay on the left screen. 738 ASSERT_NO_FATAL_FAILURE(DragStart(window.get())); 739 DragMove(100, 0); 740 EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id()); 741 DragEnd(); 742 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 743 window->GetBoundsInScreen().right()); 744 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 745 EXPECT_EQ(root_windows[0], window->GetRootWindow()); 746 747 // Undock and move to the right - enough to get the mouse pointer past the 748 // edge of the screen and into the second screen. The window should now be 749 // in the second screen and not docked. 750 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin( 751 window.get(), 752 window->bounds().width()/2 + 10, 753 0)); 754 DragMove(window->bounds().width()/2 - 5, 0); 755 EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id()); 756 DragEnd(); 757 EXPECT_NE(window->GetRootWindow()->GetBoundsInScreen().right(), 758 window->GetBoundsInScreen().right()); 759 EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id()); 760 EXPECT_EQ(root_windows[1], window->GetRootWindow()); 761 762 // Keep dragging it to the right until its left edge touches the screen edge. 763 // The window should now be in the second screen and not docked. 764 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin( 765 window.get(), 766 window->bounds().width()/2 + 10, 767 0)); 768 DragMove(window->GetRootWindow()->GetBoundsInScreen().x() - 769 window->GetBoundsInScreen().x(), 770 0); 771 EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id()); 772 DragEnd(); 773 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().x(), 774 window->GetBoundsInScreen().x()); 775 EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id()); 776 EXPECT_EQ(root_windows[1], window->GetRootWindow()); 777} 778 779// Dock two windows, undock one. 780// Test the docked windows area size and default container resizing. 781TEST_P(DockedWindowResizerTest, AttachTwoWindowsDetachOne) { 782 if (!SupportsHostWindowResize()) 783 return; 784 UpdateDisplay("600x600"); 785 786 scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 787 scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 201))); 788 // Work area should cover the whole screen. 789 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w2.get()).width(), 790 ScreenUtil::GetDisplayWorkAreaBoundsInParent(w2.get()).width()); 791 792 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); 793 // A window should be docked at the right edge. 794 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 795 w1->GetBoundsInScreen().right()); 796 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 797 DockedWindowLayoutManager* manager = 798 static_cast<DockedWindowLayoutManager*>(w1->parent()->layout_manager()); 799 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 800 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 801 802 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 100); 803 // Both windows should now be docked at the right edge. 804 EXPECT_EQ(w2->GetRootWindow()->GetBoundsInScreen().right(), 805 w2->GetBoundsInScreen().right()); 806 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id()); 807 // Dock width should be set to a wider window. 808 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 809 EXPECT_EQ(std::max(w1->bounds().width(), w2->bounds().width()), 810 docked_width(manager)); 811 812 // Try to detach by dragging left a bit (should not get undocked). 813 // This would normally detach a single docked window but since we have another 814 // window and the mouse pointer does not leave the dock area the window 815 // should stay docked. 816 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin(w2.get(), 60, 0)); 817 // Drag up as well as left to avoid attaching panels to launcher shelf. 818 DragMove(-40, -40); 819 // Release the mouse and the window should be still attached to the edge. 820 DragEnd(); 821 822 // The first window should be still docked. 823 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 824 w1->GetBoundsInScreen().right()); 825 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 826 827 // The second window should be still docked. 828 EXPECT_EQ(w2->GetRootWindow()->GetBoundsInScreen().right(), 829 w2->GetBoundsInScreen().right()); 830 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id()); 831 832 // Detach by dragging left more (should get undocked). 833 const int left_edge = w2->bounds().x(); 834 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin( 835 w2.get(), 836 w2->bounds().width()/2 + 10, 837 0)); 838 // Drag up as well to avoid attaching panels to launcher shelf. 839 const int drag_x = -(w2->bounds().width()/2 + 20); 840 DragMove(drag_x, -100); 841 // Release the mouse and the window should be no longer attached to the edge. 842 DragEnd(); 843 844 // The second window should be floating on the desktop again. 845 EXPECT_EQ(left_edge + drag_x, w2->bounds().x()); 846 EXPECT_EQ(kShellWindowId_DefaultContainer, w2->parent()->id()); 847 // Dock width should be set to remaining single docked window. 848 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 849 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 850 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 851} 852 853// Dock one of the windows. Maximize other testing desktop resizing. 854TEST_P(DockedWindowResizerTest, AttachWindowMaximizeOther) { 855 if (!SupportsHostWindowResize()) 856 return; 857 858 scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 859 scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 201))); 860 // Work area should cover the whole screen. 861 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w2.get()).width(), 862 ScreenUtil::GetDisplayWorkAreaBoundsInParent(w2.get()).width()); 863 864 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); 865 // A window should be docked at the right edge. 866 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 867 w1->GetBoundsInScreen().right()); 868 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 869 DockedWindowLayoutManager* manager = 870 static_cast<DockedWindowLayoutManager*>(w1->parent()->layout_manager()); 871 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 872 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 873 874 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin(w2.get(), 25, 5)); 875 DragMove(w2->GetRootWindow()->bounds().width() 876 -w2->bounds().width() 877 -(w2->bounds().width()/2 + 20) 878 -w2->bounds().x(), 879 50 - w2->bounds().y()); 880 DragEnd(); 881 // The first window should be still docked. 882 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 883 w1->GetBoundsInScreen().right()); 884 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 885 886 // The second window should be floating on the desktop. 887 EXPECT_EQ(w2->GetRootWindow()->GetBoundsInScreen().right() - 888 (w2->bounds().width()/2 + 20), 889 w2->GetBoundsInScreen().right()); 890 EXPECT_EQ(kShellWindowId_DefaultContainer, w2->parent()->id()); 891 // Dock width should be set to remaining single docked window. 892 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 893 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 894 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 895 // Desktop work area should now shrink. 896 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w2.get()).width() - 897 docked_width(manager) - min_dock_gap(), 898 ScreenUtil::GetDisplayWorkAreaBoundsInParent(w2.get()).width()); 899 900 // Maximize the second window - Maximized area should be shrunk. 901 const gfx::Rect restored_bounds = w2->bounds(); 902 wm::WindowState* w2_state = wm::GetWindowState(w2.get()); 903 w2_state->Maximize(); 904 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w2.get()).width() - 905 docked_width(manager) - min_dock_gap(), 906 w2->bounds().width()); 907 908 // Detach the first window (this should require very little drag). 909 ASSERT_NO_FATAL_FAILURE(DragStart(w1.get())); 910 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 911 DragMove(-35, 10); 912 // Alignment is set to "NONE" when drag starts. 913 EXPECT_EQ(DOCKED_ALIGNMENT_NONE, docked_alignment(manager)); 914 // Release the mouse and the window should be no longer attached to the edge. 915 DragEnd(); 916 EXPECT_EQ(DOCKED_ALIGNMENT_NONE, docked_alignment(manager)); 917 // Dock should get shrunk and desktop should get expanded. 918 EXPECT_EQ(kShellWindowId_DefaultContainer, w1->parent()->id()); 919 EXPECT_EQ(kShellWindowId_DefaultContainer, w2->parent()->id()); 920 EXPECT_EQ(DOCKED_ALIGNMENT_NONE, docked_alignment(manager)); 921 EXPECT_EQ(0, docked_width(manager)); 922 // The second window should now get resized and take up the whole screen. 923 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w2.get()).width(), 924 w2->bounds().width()); 925 926 // Dock the first window to the left edge. 927 // Click at an offset from origin to prevent snapping. 928 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin(w1.get(), 10, 0)); 929 // Drag left to get pointer touching the screen edge. 930 DragMove(-w1->bounds().x() - 10, 0); 931 // Alignment set to "NONE" during the drag of the window when none are docked. 932 EXPECT_EQ(DOCKED_ALIGNMENT_NONE, docked_alignment(manager)); 933 // Release the mouse and the window should be now attached to the edge. 934 DragEnd(); 935 // Dock should get expanded and desktop should get shrunk. 936 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 937 EXPECT_EQ(DOCKED_ALIGNMENT_LEFT, docked_alignment(manager)); 938 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 939 // Second window should still be in the desktop. 940 EXPECT_EQ(kShellWindowId_DefaultContainer, w2->parent()->id()); 941 // Maximized window should be shrunk. 942 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w2.get()).width() - 943 docked_width(manager) - min_dock_gap(), 944 w2->bounds().width()); 945 946 // Unmaximize the second window. 947 w2_state->Restore(); 948 // Its bounds should get restored. 949 EXPECT_EQ(restored_bounds, w2->bounds()); 950} 951 952// Dock one window. Test the sticky behavior near screen or desktop edge. 953TEST_P(DockedWindowResizerTest, AttachOneTestSticky) { 954 if (!SupportsHostWindowResize()) 955 return; 956 957 scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 958 scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 201))); 959 // Work area should cover the whole screen. 960 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w2.get()).width(), 961 ScreenUtil::GetDisplayWorkAreaBoundsInParent(w2.get()).width()); 962 963 DragToVerticalPositionAndToEdge(DOCKED_EDGE_LEFT, w1.get(), 20); 964 // A window should be docked at the left edge. 965 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().x(), 966 w1->GetBoundsInScreen().x()); 967 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 968 DockedWindowLayoutManager* manager = 969 static_cast<DockedWindowLayoutManager*>(w1->parent()->layout_manager()); 970 // The first window should be docked. 971 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().x(), 972 w1->GetBoundsInScreen().x()); 973 // Dock width should be set to that of a single docked window. 974 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 975 EXPECT_EQ(DOCKED_ALIGNMENT_LEFT, docked_alignment(manager)); 976 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 977 978 // Position second window in the desktop 20px to the right of the docked w1. 979 DragToVerticalPositionRelativeToEdge(DOCKED_EDGE_LEFT, 980 w2.get(), 981 20 + 25 - 982 min_dock_gap(), 983 50); 984 // The second window should be floating on the desktop. 985 EXPECT_EQ(w2->GetRootWindow()->GetBoundsInScreen().x() + 986 (w1->bounds().right() + 20), 987 w2->GetBoundsInScreen().x()); 988 EXPECT_EQ(kShellWindowId_DefaultContainer, w2->parent()->id()); 989 // Dock width should be set to that of a single docked window. 990 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 991 EXPECT_EQ(DOCKED_ALIGNMENT_LEFT, docked_alignment(manager)); 992 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 993 994 // Drag w2 almost to the dock, the mouse pointer not quite reaching the dock. 995 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin(w2.get(), 10, 0)); 996 DragMove(1 + docked_width(manager) - w2->bounds().x(), 0); 997 // Alignment set to "LEFT" during the drag because dock has a window in it. 998 EXPECT_EQ(DOCKED_ALIGNMENT_LEFT, docked_alignment(manager)); 999 // Release the mouse and the window should not be attached to the edge. 1000 DragEnd(); 1001 // Dock should still have only one window in it. 1002 EXPECT_EQ(DOCKED_ALIGNMENT_LEFT, docked_alignment(manager)); 1003 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1004 // The second window should still be in the desktop. 1005 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1006 EXPECT_EQ(kShellWindowId_DefaultContainer, w2->parent()->id()); 1007 1008 // Drag w2 by a bit more - it should resist the drag (stuck edges) 1009 int start_x = w2->bounds().x(); 1010 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromWindowOrigin(w2.get(), 100, 5)); 1011 DragMove(-2, 0); 1012 // Window should not actually move. 1013 EXPECT_EQ(start_x, w2->bounds().x()); 1014 // Alignment set to "LEFT" during the drag because dock has a window in it. 1015 EXPECT_EQ(DOCKED_ALIGNMENT_LEFT, docked_alignment(manager)); 1016 // Release the mouse and the window should not be attached to the edge. 1017 DragEnd(); 1018 // Window should be still where it was before the last drag started. 1019 EXPECT_EQ(start_x, w2->bounds().x()); 1020 // Dock should still have only one window in it 1021 EXPECT_EQ(DOCKED_ALIGNMENT_LEFT, docked_alignment(manager)); 1022 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1023 // The second window should still be in the desktop 1024 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1025 EXPECT_EQ(kShellWindowId_DefaultContainer, w2->parent()->id()); 1026 1027 // Drag w2 by more than the stuck threshold and drop it into the dock. 1028 ASSERT_NO_FATAL_FAILURE(DragStart(w2.get())); 1029 DragMove(-100, 0); 1030 // Window should actually move. 1031 EXPECT_NE(start_x, w2->bounds().x()); 1032 // Alignment set to "LEFT" during the drag because dock has a window in it. 1033 EXPECT_EQ(DOCKED_ALIGNMENT_LEFT, docked_alignment(manager)); 1034 // Release the mouse and the window should be attached to the edge. 1035 DragEnd(); 1036 // Both windows are docked now. 1037 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1038 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id()); 1039 // Dock should get expanded and desktop should get shrunk. 1040 EXPECT_EQ(DOCKED_ALIGNMENT_LEFT, docked_alignment(manager)); 1041 EXPECT_EQ(std::max(w1->bounds().width(), w2->bounds().width()), 1042 docked_width(manager)); 1043 // Desktop work area should now shrink by dock width. 1044 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w2.get()).width() - 1045 docked_width(manager) - min_dock_gap(), 1046 ScreenUtil::GetDisplayWorkAreaBoundsInParent(w2.get()).width()); 1047} 1048 1049// Dock two windows, resize one. 1050// Test the docked windows area size and remaining desktop resizing. 1051TEST_P(DockedWindowResizerTest, ResizeOneOfTwoWindows) { 1052 if (!SupportsHostWindowResize()) 1053 return; 1054 1055 // Wider display to start since panels are limited to half the display width. 1056 UpdateDisplay("1000x600"); 1057 scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 1058 scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 201))); 1059 // Work area should cover the whole screen. 1060 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w2.get()).width(), 1061 ScreenUtil::GetDisplayWorkAreaBoundsInParent(w2.get()).width()); 1062 1063 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); 1064 // A window should be docked at the right edge. 1065 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 1066 w1->GetBoundsInScreen().right()); 1067 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1068 DockedWindowLayoutManager* manager = 1069 static_cast<DockedWindowLayoutManager*>(w1->parent()->layout_manager()); 1070 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1071 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1072 1073 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 100); 1074 // Both windows should now be docked at the right edge. 1075 EXPECT_EQ(w2->GetRootWindow()->GetBoundsInScreen().right(), 1076 w2->GetBoundsInScreen().right()); 1077 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id()); 1078 // Dock width should be set to a wider window. 1079 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1080 EXPECT_EQ(std::max(w1->bounds().width(), w2->bounds().width()), 1081 docked_width(manager)); 1082 1083 // Resize the first window left by a bit and test that the dock expands. 1084 int previous_width = w1->bounds().width(); 1085 const int kResizeSpan1 = 30; 1086 ASSERT_NO_FATAL_FAILURE(ResizeStartAtOffsetFromWindowOrigin(w1.get(), 1087 0, 20, 1088 HTLEFT)); 1089 DragMove(-kResizeSpan1, 0); 1090 // Alignment set to "RIGHT" during the drag because dock has a window in it. 1091 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1092 // Release the mouse and the window should be attached to the edge. 1093 DragEnd(); 1094 // Dock should still have both windows in it. 1095 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1096 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id()); 1097 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1098 // w1 is now wider than before. The dock should expand and be as wide as w1. 1099 EXPECT_EQ(previous_width + kResizeSpan1, w1->bounds().width()); 1100 // Both windows should get resized since they both don't have min/max size. 1101 EXPECT_EQ(w1->bounds().width(), w2->bounds().width()); 1102 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1103 // Desktop work area should shrink. 1104 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w2.get()).width() - 1105 docked_width(manager) - min_dock_gap(), 1106 ScreenUtil::GetDisplayWorkAreaBoundsInParent(w2.get()).width()); 1107 1108 // Resize the first window left by more than the dock maximum width. 1109 // This should cause the window width to be restricted by maximum dock width. 1110 previous_width = w1->bounds().width(); 1111 const int kResizeSpan2 = 250; 1112 ASSERT_NO_FATAL_FAILURE(ResizeStartAtOffsetFromWindowOrigin(w1.get(), 1113 0, 20, 1114 HTLEFT)); 1115 DragMove(-kResizeSpan2, 0); 1116 // Alignment set to "RIGHT" during the drag because dock has a window in it. 1117 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1118 // Release the mouse and the window should be attached to the edge. 1119 DragEnd(); 1120 // Dock should still have both windows in it. 1121 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1122 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id()); 1123 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1124 // w1 is now as wide as the maximum dock width and the dock should get 1125 // resized to the maximum width. 1126 EXPECT_EQ(max_width(), w1->bounds().width()); 1127 // Both windows should get resized since they both don't have min/max size. 1128 EXPECT_EQ(w1->bounds().width(), w2->bounds().width()); 1129 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1130 // Desktop work area should shrink. 1131 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w2.get()).width() - 1132 docked_width(manager) - min_dock_gap(), 1133 ScreenUtil::GetDisplayWorkAreaBoundsInParent(w2.get()).width()); 1134 1135 // Resize the first window right to get it completely inside the docked area. 1136 previous_width = w1->bounds().width(); 1137 const int kResizeSpan3 = 100; 1138 ASSERT_NO_FATAL_FAILURE(ResizeStartAtOffsetFromWindowOrigin(w1.get(), 1139 0, 20, 1140 HTLEFT)); 1141 DragMove(kResizeSpan3, 0); 1142 // Alignment set to "RIGHT" during the drag because dock has a window in it. 1143 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1144 // Release the mouse and the window should be docked. 1145 DragEnd(); 1146 // Dock should still have both windows in it. 1147 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1148 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id()); 1149 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1150 // w1 should be narrower than before by the length of the drag. 1151 EXPECT_EQ(previous_width - kResizeSpan3, w1->bounds().width()); 1152 // Both windows should get resized since they both don't have min/max size. 1153 EXPECT_EQ(w1->bounds().width(), w2->bounds().width()); 1154 // The dock should be as wide as w1 or w2. 1155 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1156 // Desktop work area should shrink. 1157 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w2.get()).width() - 1158 docked_width(manager) - min_dock_gap(), 1159 ScreenUtil::GetDisplayWorkAreaBoundsInParent(w2.get()).width()); 1160 1161 // Resize the first window left to be overhang again. 1162 previous_width = w1->bounds().width(); 1163 ASSERT_NO_FATAL_FAILURE(ResizeStartAtOffsetFromWindowOrigin(w1.get(), 1164 0, 20, 1165 HTLEFT)); 1166 DragMove(-kResizeSpan3, 0); 1167 DragEnd(); 1168 EXPECT_EQ(previous_width + kResizeSpan3, w1->bounds().width()); 1169 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1170 // Docked area should be as wide as possible (maximum) and same as w1. 1171 EXPECT_EQ(max_width(), docked_width(manager)); 1172 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1173 1174 // Undock the first window. Docked area should shrink to its ideal size. 1175 ASSERT_NO_FATAL_FAILURE(DragStart(w1.get())); 1176 // Drag up as well to avoid attaching panels to launcher shelf. 1177 DragMove(-(400 - 210), -100); 1178 // Alignment set to "RIGHT" since we have another window docked. 1179 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1180 // Release the mouse and the window should be no longer attached to the edge. 1181 DragEnd(); 1182 EXPECT_EQ(kShellWindowId_DefaultContainer, w1->parent()->id()); 1183 // Dock should be as wide as w2 (and same as ideal width). 1184 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1185 EXPECT_EQ(ideal_width(), docked_width(manager)); 1186 EXPECT_EQ(w2->bounds().width(), docked_width(manager)); 1187 // The second window should be still docked. 1188 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id()); 1189 // Desktop work area should be inset. 1190 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w1.get()).width() - 1191 docked_width(manager) - min_dock_gap(), 1192 ScreenUtil::GetDisplayWorkAreaBoundsInParent(w1.get()).width()); 1193} 1194 1195// Dock a window, resize it and test that undocking it preserves the width. 1196TEST_P(DockedWindowResizerTest, ResizingKeepsWidth) { 1197 if (!SupportsHostWindowResize()) 1198 return; 1199 1200 // Wider display to start since panels are limited to half the display width. 1201 UpdateDisplay("1000x600"); 1202 scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 1203 1204 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); 1205 // Window should be docked at the right edge. 1206 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 1207 w1->GetBoundsInScreen().right()); 1208 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1209 DockedWindowLayoutManager* manager = 1210 static_cast<DockedWindowLayoutManager*>(w1->parent()->layout_manager()); 1211 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1212 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1213 1214 // Resize the window left by a bit and test that the dock expands. 1215 int previous_width = w1->bounds().width(); 1216 const int kResizeSpan1 = 30; 1217 ASSERT_NO_FATAL_FAILURE(ResizeStartAtOffsetFromWindowOrigin(w1.get(), 1218 0, 20, 1219 HTLEFT)); 1220 DragMove(-kResizeSpan1, 0); 1221 // Alignment stays "RIGHT" during the drag because the only docked window 1222 // is being resized. 1223 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1224 // Release the mouse and the window should be attached to the edge. 1225 DragEnd(); 1226 // The window should get docked. 1227 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1228 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1229 // w1 is now wider and the dock should expand to be as wide as w1. 1230 EXPECT_EQ(previous_width + kResizeSpan1, w1->bounds().width()); 1231 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1232 1233 // Undock by dragging almost to the left edge. 1234 DragToVerticalPositionRelativeToEdge(DOCKED_EDGE_LEFT, w1.get(), 100, 20); 1235 // Width should be preserved. 1236 EXPECT_EQ(previous_width + kResizeSpan1, w1->bounds().width()); 1237 // Height should be restored to what it was originally. 1238 EXPECT_EQ(201, w1->bounds().height()); 1239 1240 // Dock again. 1241 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); 1242 // Width should be reset to initial ideal width (25px). 1243 EXPECT_EQ(ideal_width(), w1->bounds().width()); 1244 1245 // Undock again by dragging left. 1246 DragToVerticalPositionRelativeToEdge(DOCKED_EDGE_LEFT, w1.get(), 100, 20); 1247 // Width should be reset to what it was last time the window was not docked. 1248 EXPECT_EQ(previous_width + kResizeSpan1, w1->bounds().width()); 1249 // Height should be restored to what it was originally. 1250 EXPECT_EQ(201, w1->bounds().height()); 1251} 1252 1253// Dock a window, resize it and test that it stays docked. 1254TEST_P(DockedWindowResizerTest, ResizingKeepsDockedState) { 1255 if (!SupportsHostWindowResize()) 1256 return; 1257 1258 // Wider display to start since panels are limited to half the display width. 1259 UpdateDisplay("1000x600"); 1260 scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 1261 1262 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); 1263 // Window should be docked at the right edge. 1264 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 1265 w1->GetBoundsInScreen().right()); 1266 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1267 DockedWindowLayoutManager* manager = 1268 static_cast<DockedWindowLayoutManager*>(w1->parent()->layout_manager()); 1269 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1270 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1271 1272 // Resize the window left by a bit and test that the dock expands. 1273 int previous_width = w1->bounds().width(); 1274 const int kResizeSpan1 = 30; 1275 ASSERT_NO_FATAL_FAILURE(ResizeStartAtOffsetFromWindowOrigin( 1276 w1.get(), 0, 20, HTLEFT)); 1277 DragMove(-kResizeSpan1, 0); 1278 // Normally alignment would be reset to "NONE" during the drag when there is 1279 // only a single window docked and it is being dragged. However because that 1280 // window is being resized rather than moved the alignment is not changed. 1281 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1282 // Release the mouse and the window should be attached to the edge. 1283 DragEnd(); 1284 // The window should stay docked. 1285 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1286 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1287 // w1 is now wider and the dock should expand to be as wide as w1. 1288 EXPECT_EQ(previous_width + kResizeSpan1, w1->bounds().width()); 1289 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1290 1291 // Resize the window by dragging its right edge left a bit and test that the 1292 // window stays docked. 1293 previous_width = w1->bounds().width(); 1294 const int kResizeSpan2 = 15; 1295 ASSERT_NO_FATAL_FAILURE(ResizeStartAtOffsetFromWindowOrigin( 1296 w1.get(), w1->bounds().width(), 20, HTRIGHT)); 1297 DragMove(-kResizeSpan2, 0); 1298 // Alignment stays "RIGHT" during the drag because the window is being 1299 // resized rather than dragged. 1300 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1301 // Release the mouse and the window should be attached to the edge. 1302 DragEnd(); 1303 // The window should stay docked. 1304 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1305 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1306 // The dock should stay as wide as w1 is now (a bit less than before). 1307 EXPECT_EQ(previous_width - kResizeSpan2, w1->bounds().width()); 1308 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1309} 1310 1311// Dock two windows, resize one. Test the docked windows area size. 1312TEST_P(DockedWindowResizerTest, ResizeTwoWindows) { 1313 if (!SupportsHostWindowResize()) 1314 return; 1315 1316 // Wider display to start since panels are limited to half the display width. 1317 UpdateDisplay("1000x600"); 1318 scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 1319 scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 201))); 1320 1321 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); 1322 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 100); 1323 // Both windows should now be docked at the right edge. 1324 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1325 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id()); 1326 // Dock width should be set to ideal width. 1327 DockedWindowLayoutManager* manager = 1328 static_cast<DockedWindowLayoutManager*>(w1->parent()->layout_manager()); 1329 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1330 EXPECT_EQ(ideal_width(), docked_width(manager)); 1331 1332 // Resize the first window left by a bit and test that the dock expands. 1333 int previous_width = w1->bounds().width(); 1334 const int kResizeSpan1 = 30; 1335 ASSERT_NO_FATAL_FAILURE(ResizeStartAtOffsetFromWindowOrigin(w1.get(), 1336 0, 20, 1337 HTLEFT)); 1338 DragMove(-kResizeSpan1, 0); 1339 DragEnd(); 1340 // w1 is now wider than before. 1341 EXPECT_EQ(previous_width + kResizeSpan1, w1->bounds().width()); 1342 // Both windows should get resized since they both don't have min/max size. 1343 EXPECT_EQ(w1->bounds().width(), w2->bounds().width()); 1344 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1345 1346 // Resize the second window left by a bit more and test that the dock expands. 1347 previous_width = w2->bounds().width(); 1348 ASSERT_NO_FATAL_FAILURE(ResizeStartAtOffsetFromWindowOrigin(w2.get(), 1349 0, 20, 1350 HTLEFT)); 1351 DragMove(-kResizeSpan1, 0); 1352 DragEnd(); 1353 // w2 should get wider since it was resized by a user. 1354 EXPECT_EQ(previous_width + kResizeSpan1, w2->bounds().width()); 1355 // w1 should stay as wide as w2 since both were flush with the dock edge. 1356 EXPECT_EQ(w2->bounds().width(), w1->bounds().width()); 1357 EXPECT_EQ(w2->bounds().width(), docked_width(manager)); 1358 1359 // Undock w2 and then dock it back. 1360 DragToVerticalPositionRelativeToEdge(DOCKED_EDGE_RIGHT, w2.get(), -400, 100); 1361 EXPECT_EQ(kShellWindowId_DefaultContainer, w2->parent()->id()); 1362 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 100); 1363 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id()); 1364 // w2 should become same width as w1. 1365 EXPECT_EQ(w1->bounds().width(), w2->bounds().width()); 1366 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1367 1368 // Make w1 even wider. 1369 ASSERT_NO_FATAL_FAILURE(ResizeStartAtOffsetFromWindowOrigin(w1.get(), 1370 0, 20, 1371 HTLEFT)); 1372 DragMove(-kResizeSpan1, 0); 1373 DragEnd(); 1374 // Making w1 wider should make both windows wider since w2 no longer remembers 1375 // user width. 1376 EXPECT_EQ(w1->bounds().width(), w2->bounds().width()); 1377 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1378} 1379 1380// Tests that dragging a window down to shelf attaches a panel but does not 1381// attach a regular window. 1382TEST_P(DockedWindowResizerTest, DragToShelf) { 1383 if (!SupportsHostWindowResize()) 1384 return; 1385 1386 scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 1387 // Work area should cover the whole screen. 1388 EXPECT_EQ(ScreenUtil::GetDisplayBoundsInParent(w1.get()).width(), 1389 ScreenUtil::GetDisplayWorkAreaBoundsInParent(w1.get()).width()); 1390 1391 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); 1392 // A window should be docked at the right edge. 1393 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 1394 w1->GetBoundsInScreen().right()); 1395 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1396 DockedWindowLayoutManager* manager = 1397 static_cast<DockedWindowLayoutManager*>(w1->parent()->layout_manager()); 1398 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1399 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1400 1401 // Detach and drag down to shelf. 1402 ASSERT_NO_FATAL_FAILURE(DragStart(w1.get())); 1403 DragMove(-40, 0); 1404 // Alignment is set to "NONE" when drag starts. 1405 EXPECT_EQ(DOCKED_ALIGNMENT_NONE, docked_alignment(manager)); 1406 // Release the mouse and the window should be no longer attached to the edge. 1407 DragEnd(); 1408 EXPECT_EQ(DOCKED_ALIGNMENT_NONE, docked_alignment(manager)); 1409 1410 // Drag down almost to shelf. A panel will snap, a regular window won't. 1411 ShelfWidget* shelf = Shelf::ForPrimaryDisplay()->shelf_widget(); 1412 const int shelf_y = shelf->GetWindowBoundsInScreen().y(); 1413 const int kDistanceFromShelf = 10; 1414 ASSERT_NO_FATAL_FAILURE(DragStart(w1.get())); 1415 DragMove(0, -kDistanceFromShelf + shelf_y - w1->bounds().bottom()); 1416 DragEnd(); 1417 if (test_panels()) { 1418 // The panel should be touching the shelf and attached. 1419 EXPECT_EQ(shelf_y, w1->bounds().bottom()); 1420 EXPECT_TRUE(wm::GetWindowState(w1.get())->panel_attached()); 1421 } else { 1422 // The window should not be touching the shelf. 1423 EXPECT_EQ(shelf_y - kDistanceFromShelf, w1->bounds().bottom()); 1424 } 1425} 1426 1427// Tests that docking and undocking a |window| with a transient child properly 1428// maintains the parent of that transient child to be the same as the |window|. 1429TEST_P(DockedWindowResizerTest, DragWindowWithTransientChild) { 1430 if (!SupportsHostWindowResize()) 1431 return; 1432 1433 // Create a window with a transient child. 1434 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 1435 scoped_ptr<aura::Window> child(CreateTestWindowInShellWithDelegateAndType( 1436 NULL, ui::wm::WINDOW_TYPE_NORMAL, 0, gfx::Rect(20, 20, 150, 20))); 1437 ::wm::AddTransientChild(window.get(), child.get()); 1438 if (window->parent() != child->parent()) 1439 window->parent()->AddChild(child.get()); 1440 EXPECT_EQ(window.get(), ::wm::GetTransientParent(child.get())); 1441 1442 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, window.get(), 20); 1443 1444 // A window should be docked at the right edge. 1445 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 1446 EXPECT_EQ(kShellWindowId_DockedContainer, child->parent()->id()); 1447 1448 // Drag the child - it should move freely and stay where it is dragged. 1449 ASSERT_NO_FATAL_FAILURE(DragStart(child.get())); 1450 DragMove(500, 20); 1451 DragEnd(); 1452 EXPECT_EQ(gfx::Point(20 + 500, 20 + 20).ToString(), 1453 child->GetBoundsInScreen().origin().ToString()); 1454 1455 // Undock the window by dragging left. 1456 ASSERT_NO_FATAL_FAILURE(DragStart(window.get())); 1457 DragMove(-32, -10); 1458 DragEnd(); 1459 1460 // The window should be undocked and the transient child should be reparented. 1461 EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id()); 1462 EXPECT_EQ(kShellWindowId_DefaultContainer, child->parent()->id()); 1463 // The child should not have moved. 1464 EXPECT_EQ(gfx::Point(20 + 500, 20 + 20).ToString(), 1465 child->GetBoundsInScreen().origin().ToString()); 1466} 1467 1468// Tests that reparenting windows during the drag does not affect system modal 1469// windows that are transient children of the dragged windows. 1470TEST_P(DockedWindowResizerTest, DragWindowWithModalTransientChild) { 1471 if (!SupportsHostWindowResize()) 1472 return; 1473 1474 // Create a window. 1475 scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 1476 gfx::Rect bounds(window->bounds()); 1477 1478 // Start dragging the window. 1479 ASSERT_NO_FATAL_FAILURE(DragStart(window.get())); 1480 gfx::Vector2d move_vector(40, test_panels() ? -60 : 60); 1481 DragMove(move_vector.x(), move_vector.y()); 1482 EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id()); 1483 1484 // While still dragging create a modal window and make it a transient child of 1485 // the |window|. 1486 scoped_ptr<aura::Window> child(CreateModalWindow(gfx::Rect(20, 20, 150, 20))); 1487 ::wm::AddTransientChild(window.get(), child.get()); 1488 EXPECT_EQ(window.get(), ::wm::GetTransientParent(child.get())); 1489 EXPECT_EQ(kShellWindowId_SystemModalContainer, child->parent()->id()); 1490 1491 // End the drag, the |window| should have moved (if it is a panel it will 1492 // no longer be attached to the shelf since we dragged it above). 1493 DragEnd(); 1494 bounds.Offset(move_vector); 1495 EXPECT_EQ(bounds.ToString(), window->GetBoundsInScreen().ToString()); 1496 1497 // The original |window| should be in the default container (not docked or 1498 // attached). 1499 EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id()); 1500 // The transient |child| should still be in system modal container. 1501 EXPECT_EQ(kShellWindowId_SystemModalContainer, child->parent()->id()); 1502 // The |child| should not have moved. 1503 EXPECT_EQ(gfx::Point(20, 20).ToString(), 1504 child->GetBoundsInScreen().origin().ToString()); 1505 // The |child| should still be a transient child of |window|. 1506 EXPECT_EQ(window.get(), ::wm::GetTransientParent(child.get())); 1507} 1508 1509// Tests that side snapping a window undocks it, closes the dock and then snaps. 1510TEST_P(DockedWindowResizerTest, SideSnapDocked) { 1511 if (!SupportsHostWindowResize() || test_panels()) 1512 return; 1513 1514 scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201))); 1515 wm::WindowState* window_state = wm::GetWindowState(w1.get()); 1516 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); 1517 // A window should be docked at the right edge. 1518 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 1519 w1->GetBoundsInScreen().right()); 1520 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1521 DockedWindowLayoutManager* manager = 1522 static_cast<DockedWindowLayoutManager*>(w1->parent()->layout_manager()); 1523 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1524 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1525 EXPECT_TRUE(window_state->IsDocked()); 1526 EXPECT_FALSE(window_state->IsSnapped()); 1527 1528 // Side snap at right edge. 1529 const wm::WMEvent snap_right(wm::WM_EVENT_SNAP_RIGHT); 1530 window_state->OnWMEvent(&snap_right); 1531 // The window should be snapped at the right edge and the dock should close. 1532 gfx::Rect work_area(ScreenUtil::GetDisplayWorkAreaBoundsInParent(w1.get())); 1533 EXPECT_EQ(0, docked_width(manager)); 1534 EXPECT_EQ(work_area.height(), w1->bounds().height()); 1535 EXPECT_EQ(work_area.right(), w1->bounds().right()); 1536 EXPECT_EQ(kShellWindowId_DefaultContainer, w1->parent()->id()); 1537 EXPECT_FALSE(window_state->IsDocked()); 1538 EXPECT_TRUE(window_state->IsSnapped()); 1539 1540 // Dock again. 1541 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20); 1542 // A window should be docked at the right edge. 1543 EXPECT_EQ(w1->GetRootWindow()->GetBoundsInScreen().right(), 1544 w1->GetBoundsInScreen().right()); 1545 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id()); 1546 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1547 EXPECT_EQ(w1->bounds().width(), docked_width(manager)); 1548 EXPECT_TRUE(window_state->IsDocked()); 1549 EXPECT_FALSE(window_state->IsSnapped()); 1550 1551 // Side snap at left edge. 1552 const wm::WMEvent snap_left(wm::WM_EVENT_SNAP_LEFT); 1553 window_state->OnWMEvent(&snap_left); 1554 // The window should be snapped at the right edge and the dock should close. 1555 EXPECT_EQ(work_area.ToString(), 1556 ScreenUtil::GetDisplayWorkAreaBoundsInParent(w1.get()).ToString()); 1557 EXPECT_EQ(0, docked_width(manager)); 1558 EXPECT_EQ(work_area.height(), w1->bounds().height()); 1559 EXPECT_EQ(work_area.x(), w1->bounds().x()); 1560 EXPECT_EQ(kShellWindowId_DefaultContainer, w1->parent()->id()); 1561 EXPECT_FALSE(window_state->IsDocked()); 1562 EXPECT_TRUE(window_state->IsSnapped()); 1563} 1564 1565// Tests that a window is undocked if the window is maximized via a keyboard 1566// accelerator during a drag. 1567TEST_P(DockedWindowResizerTest, MaximizedDuringDrag) { 1568 if (!SupportsHostWindowResize() || test_panels()) 1569 return; 1570 1571 scoped_ptr<aura::Window> window(CreateTestWindow( 1572 gfx::Rect(0, 0, ideal_width(), 201))); 1573 wm::WindowState* window_state = wm::GetWindowState(window.get()); 1574 1575 // Dock the window to the right edge. 1576 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, window.get(), 20); 1577 EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(), 1578 window->GetBoundsInScreen().right()); 1579 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id()); 1580 DockedWindowLayoutManager* manager = 1581 static_cast<DockedWindowLayoutManager*>( 1582 window->parent()->layout_manager()); 1583 EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, docked_alignment(manager)); 1584 EXPECT_EQ(window->bounds().width(), docked_width(manager)); 1585 EXPECT_TRUE(window_state->IsDocked()); 1586 1587 // Maximize the window while in a real drag. In particular, 1588 // ToplevelWindowEventHandler::ScopedWindowResizer::OnWindowStateTypeChanged() 1589 // must be called in order for the maximized window's size to be correct. 1590 delegate()->set_window_component(HTCAPTION); 1591 ui::test::EventGenerator& generator = GetEventGenerator(); 1592 generator.MoveMouseTo(window->GetBoundsInScreen().origin()); 1593 generator.PressLeftButton(); 1594 generator.MoveMouseBy(10, 10); 1595 window_state->Maximize(); 1596 generator.ReleaseLeftButton(); 1597 1598 // |window| should get undocked. 1599 EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id()); 1600 EXPECT_EQ(0, docked_width(manager)); 1601 EXPECT_EQ( 1602 ScreenUtil::GetMaximizedWindowBoundsInParent(window.get()).ToString(), 1603 window->bounds().ToString()); 1604 EXPECT_TRUE(window_state->IsMaximized()); 1605} 1606 1607// Tests run twice - on both panels and normal windows 1608INSTANTIATE_TEST_CASE_P(NormalOrPanel, 1609 DockedWindowResizerTest, 1610 testing::Values(ui::wm::WINDOW_TYPE_NORMAL, 1611 ui::wm::WINDOW_TYPE_PANEL)); 1612 1613} // namespace ash 1614