Home | History | Annotate | Download | only in dock
      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/coordinate_conversion.h"
     22 #include "ash/wm/dock/docked_window_layout_manager.h"
     23 #include "ash/wm/drag_window_resizer.h"
     24 #include "ash/wm/panels/panel_layout_manager.h"
     25 #include "ash/wm/window_state.h"
     26 #include "ash/wm/window_util.h"
     27 #include "ash/wm/wm_event.h"
     28 #include "base/command_line.h"
     29 #include "ui/aura/client/aura_constants.h"
     30 #include "ui/aura/client/window_tree_client.h"
     31 #include "ui/aura/test/event_generator.h"
     32 #include "ui/aura/test/test_window_delegate.h"
     33 #include "ui/aura/window_event_dispatcher.h"
     34 #include "ui/base/hit_test.h"
     35 #include "ui/base/ui_base_types.h"
     36 #include "ui/views/widget/widget.h"
     37 #include "ui/wm/core/window_util.h"
     38 
     39 namespace ash {
     40 
     41 class 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.
    261 TEST_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)
    276 TEST_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.
    291 TEST_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.
    316 TEST_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)
    331 TEST_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.
    346 TEST_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.
    362 TEST_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
    401 TEST_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.
    447 TEST_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.
    490 TEST_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.
    516 TEST_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.
    538 TEST_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.
    581 TEST_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).
    623 TEST_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.
    647 TEST_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.
    673 TEST_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
    718 TEST_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.
    781 TEST_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.
    854 TEST_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.
    953 TEST_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.
   1051 TEST_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.
   1196 TEST_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.
   1254 TEST_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.
   1312 TEST_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.
   1382 TEST_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|.
   1429 TEST_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.
   1470 TEST_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.
   1510 TEST_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.
   1567 TEST_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   aura::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
   1608 INSTANTIATE_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