Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / ash / wm / dock / docked_window_layout_manager_unittest.cc
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_layout_manager.h"
6
7 #include "ash/ash_switches.h"
8 #include "ash/root_window_controller.h"
9 #include "ash/shelf/shelf.h"
10 #include "ash/shelf/shelf_layout_manager.h"
11 #include "ash/shelf/shelf_model.h"
12 #include "ash/shelf/shelf_types.h"
13 #include "ash/shelf/shelf_widget.h"
14 #include "ash/shell.h"
15 #include "ash/shell_window_ids.h"
16 #include "ash/test/ash_test_base.h"
17 #include "ash/test/shelf_test_api.h"
18 #include "ash/test/shelf_view_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/panels/panel_layout_manager.h"
23 #include "ash/wm/window_resizer.h"
24 #include "ash/wm/window_state.h"
25 #include "ash/wm/window_util.h"
26 #include "base/basictypes.h"
27 #include "base/command_line.h"
28 #include "base/strings/string_number_conversions.h"
29 #include "ui/aura/client/aura_constants.h"
30 #include "ui/aura/test/test_window_delegate.h"
31 #include "ui/aura/window.h"
32 #include "ui/aura/window_event_dispatcher.h"
33 #include "ui/base/hit_test.h"
34 #include "ui/gfx/screen.h"
35 #include "ui/views/widget/widget.h"
36 #include "ui/wm/core/coordinate_conversion.h"
37
38 namespace ash {
39
40 class DockedWindowLayoutManagerTest
41     : public test::AshTestBase,
42       public testing::WithParamInterface<ui::wm::WindowType> {
43  public:
44   DockedWindowLayoutManagerTest() : window_type_(GetParam()) {}
45   virtual ~DockedWindowLayoutManagerTest() {}
46
47   virtual void SetUp() OVERRIDE {
48     AshTestBase::SetUp();
49     UpdateDisplay("600x600");
50     ASSERT_TRUE(test::TestShelfDelegate::instance());
51
52     shelf_view_test_.reset(new test::ShelfViewTestAPI(
53         test::ShelfTestAPI(Shelf::ForPrimaryDisplay()).shelf_view()));
54     shelf_view_test_->SetAnimationDuration(1);
55   }
56
57  protected:
58   enum DockedEdge {
59     DOCKED_EDGE_NONE,
60     DOCKED_EDGE_LEFT,
61     DOCKED_EDGE_RIGHT,
62   };
63
64   int min_dock_gap() const { return DockedWindowLayoutManager::kMinDockGap; }
65   int ideal_width() const { return DockedWindowLayoutManager::kIdealWidth; }
66   int docked_width(const DockedWindowLayoutManager* layout_manager) const {
67     return layout_manager->docked_width_;
68   }
69
70   aura::Window* CreateTestWindow(const gfx::Rect& bounds) {
71     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
72         NULL, window_type_, 0, bounds);
73     if (window_type_ == ui::wm::WINDOW_TYPE_PANEL) {
74       test::TestShelfDelegate* shelf_delegate =
75           test::TestShelfDelegate::instance();
76       shelf_delegate->AddShelfItem(window);
77       PanelLayoutManager* manager =
78           static_cast<PanelLayoutManager*>(GetPanelContainer(window)->
79               layout_manager());
80       manager->Relayout();
81     }
82     return window;
83   }
84
85   aura::Window* CreateTestWindowWithDelegate(
86       const gfx::Rect& bounds,
87       aura::test::TestWindowDelegate* delegate) {
88     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
89         delegate, window_type_, 0, bounds);
90     if (window_type_ == ui::wm::WINDOW_TYPE_PANEL) {
91       test::TestShelfDelegate* shelf_delegate =
92           test::TestShelfDelegate::instance();
93       shelf_delegate->AddShelfItem(window);
94       PanelLayoutManager* manager =
95           static_cast<PanelLayoutManager*>(GetPanelContainer(window)->
96               layout_manager());
97       manager->Relayout();
98     }
99     return window;
100   }
101
102   aura::Window* GetPanelContainer(aura::Window* panel) {
103     return Shell::GetContainer(panel->GetRootWindow(),
104                                kShellWindowId_PanelContainer);
105   }
106
107   static WindowResizer* CreateSomeWindowResizer(
108       aura::Window* window,
109       const gfx::Point& point_in_parent,
110       int window_component) {
111     return CreateWindowResizer(
112         window,
113         point_in_parent,
114         window_component,
115         aura::client::WINDOW_MOVE_SOURCE_MOUSE).release();
116   }
117
118   void DragStart(aura::Window* window) {
119     DragStartAtOffsetFromwindowOrigin(window, 0, 0);
120   }
121
122   void DragStartAtOffsetFromwindowOrigin(aura::Window* window,
123                                          int dx, int dy) {
124     initial_location_in_parent_ =
125         window->bounds().origin() + gfx::Vector2d(dx, dy);
126     resizer_.reset(CreateSomeWindowResizer(window,
127                                            initial_location_in_parent_,
128                                            HTCAPTION));
129     ASSERT_TRUE(resizer_.get());
130   }
131
132   void DragMove(int dx, int dy) {
133     resizer_->Drag(initial_location_in_parent_ + gfx::Vector2d(dx, dy), 0);
134   }
135
136   void DragEnd() {
137     resizer_->CompleteDrag();
138     resizer_.reset();
139   }
140
141   void DragRevert() {
142     resizer_->RevertDrag();
143     resizer_.reset();
144   }
145
146   // Panels are parented by panel container during drags.
147   // Docked windows are parented by dock container during drags.
148   // All other windows that we are testing here have default container as a
149   // parent.
150   int CorrectContainerIdDuringDrag() {
151     if (window_type_ == ui::wm::WINDOW_TYPE_PANEL)
152       return kShellWindowId_PanelContainer;
153     return kShellWindowId_DockedContainer;
154   }
155
156   // Test dragging the window vertically (to detach if it is a panel) and then
157   // horizontally to the edge with an added offset from the edge of |dx|.
158   void DragRelativeToEdge(DockedEdge edge, aura::Window* window, int dx) {
159     DragVerticallyAndRelativeToEdge(
160         edge,
161         window,
162         dx,
163         window_type_ == ui::wm::WINDOW_TYPE_PANEL ? -100 : 20);
164   }
165
166   void DragToVerticalPositionAndToEdge(DockedEdge edge,
167                                        aura::Window* window,
168                                        int y) {
169     DragToVerticalPositionRelativeToEdge(edge, window, 0, y);
170   }
171
172   void DragToVerticalPositionRelativeToEdge(DockedEdge edge,
173                                             aura::Window* window,
174                                             int dx,
175                                             int y) {
176     gfx::Rect initial_bounds = window->GetBoundsInScreen();
177     DragVerticallyAndRelativeToEdge(edge, window, dx, y - initial_bounds.y());
178   }
179
180   // Detach if our window is a panel, then drag it vertically by |dy| and
181   // horizontally to the edge with an added offset from the edge of |dx|.
182   void DragVerticallyAndRelativeToEdge(DockedEdge edge,
183                                        aura::Window* window,
184                                        int dx, int dy) {
185     gfx::Rect initial_bounds = window->GetBoundsInScreen();
186     // avoid snap by clicking away from the border
187     ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(window, 25, 5));
188
189     gfx::Rect work_area =
190         Shell::GetScreen()->GetDisplayNearestWindow(window).work_area();
191     gfx::Point initial_location_in_screen = initial_location_in_parent_;
192     ::wm::ConvertPointToScreen(window->parent(), &initial_location_in_screen);
193     // Drag the window left or right to the edge (or almost to it).
194     if (edge == DOCKED_EDGE_LEFT)
195       dx += work_area.x() - initial_location_in_screen.x();
196     else if (edge == DOCKED_EDGE_RIGHT)
197       dx += work_area.right() - 1 - initial_location_in_screen.x();
198     DragMove(dx, dy);
199     EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id());
200     // Release the mouse and the panel should be attached to the dock.
201     DragEnd();
202
203     // x-coordinate can get adjusted by snapping or sticking.
204     // y-coordinate could be changed by possible automatic layout if docked.
205     if (window->parent()->id() != kShellWindowId_DockedContainer &&
206         !wm::GetWindowState(window)->HasRestoreBounds()) {
207       EXPECT_EQ(initial_bounds.y() + dy, window->GetBoundsInScreen().y());
208     }
209   }
210
211  private:
212   scoped_ptr<WindowResizer> resizer_;
213   scoped_ptr<test::ShelfViewTestAPI> shelf_view_test_;
214   ui::wm::WindowType window_type_;
215
216   // Location at start of the drag in |window->parent()|'s coordinates.
217   gfx::Point initial_location_in_parent_;
218
219   DISALLOW_COPY_AND_ASSIGN(DockedWindowLayoutManagerTest);
220 };
221
222 // Tests that a created window is successfully added to the dock
223 // layout manager.
224 TEST_P(DockedWindowLayoutManagerTest, AddOneWindow) {
225   if (!SupportsHostWindowResize())
226     return;
227
228   gfx::Rect bounds(0, 0, 201, 201);
229   scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
230   DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0);
231
232   // The window should be attached and docked at the right edge.
233   // Its width should shrink or grow to ideal width.
234   EXPECT_EQ(window->GetRootWindow()->bounds().right(),
235             window->GetBoundsInScreen().right());
236   EXPECT_EQ(ideal_width(), window->bounds().width());
237   EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id());
238 }
239
240 // Tests that with a window docked on the left the auto-placing logic in
241 // RearrangeVisibleWindowOnShow places windows flush with work area edges.
242 TEST_P(DockedWindowLayoutManagerTest, AutoPlacingLeft) {
243   if (!SupportsHostWindowResize())
244     return;
245
246   gfx::Rect bounds(0, 0, 201, 201);
247   scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
248   DragRelativeToEdge(DOCKED_EDGE_LEFT, window.get(), 0);
249
250   // The window should be attached and snapped to the right side of the screen.
251   EXPECT_EQ(window->GetRootWindow()->bounds().x(),
252             window->GetBoundsInScreen().x());
253   EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id());
254
255   DockedWindowLayoutManager* manager = static_cast<DockedWindowLayoutManager*>(
256       window->parent()->layout_manager());
257
258   // Create two additional windows and test their auto-placement
259   scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1));
260   gfx::Rect desktop_area = window1->parent()->bounds();
261   wm::GetWindowState(window1.get())->set_window_position_managed(true);
262   window1->Hide();
263   window1->SetBounds(gfx::Rect(250, 32, 231, 320));
264   window1->Show();
265   // |window1| should be centered in work area.
266   EXPECT_EQ(base::IntToString(
267       docked_width(manager) + min_dock_gap() +
268       (desktop_area.width() - docked_width(manager) -
269        min_dock_gap() - window1->bounds().width()) / 2) +
270       ",32 231x320", window1->bounds().ToString());
271
272   scoped_ptr<aura::Window> window2(CreateTestWindowInShellWithId(2));
273   wm::GetWindowState(window2.get())->set_window_position_managed(true);
274   // To avoid any auto window manager changes due to SetBounds, the window
275   // gets first hidden and then shown again.
276   window2->Hide();
277   window2->SetBounds(gfx::Rect(250, 48, 150, 300));
278   window2->Show();
279
280   // |window1| should be flush left and |window2| flush right.
281   EXPECT_EQ(
282       base::IntToString(docked_width(manager) + min_dock_gap()) +
283       ",32 231x320", window1->bounds().ToString());
284   EXPECT_EQ(
285       base::IntToString(
286           desktop_area.width() - window2->bounds().width()) +
287       ",48 150x300", window2->bounds().ToString());
288 }
289
290 // Tests that with a window docked on the right the auto-placing logic in
291 // RearrangeVisibleWindowOnShow places windows flush with work area edges.
292 TEST_P(DockedWindowLayoutManagerTest, AutoPlacingRight) {
293   if (!SupportsHostWindowResize())
294     return;
295
296   gfx::Rect bounds(0, 0, 201, 201);
297   scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
298   DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0);
299
300   // The window should be attached and snapped to the right side of the screen.
301   EXPECT_EQ(window->GetRootWindow()->bounds().right(),
302             window->GetBoundsInScreen().right());
303   EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id());
304
305   DockedWindowLayoutManager* manager = static_cast<DockedWindowLayoutManager*>(
306       window->parent()->layout_manager());
307
308   // Create two additional windows and test their auto-placement
309   scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1));
310   gfx::Rect desktop_area = window1->parent()->bounds();
311   wm::GetWindowState(window1.get())->set_window_position_managed(true);
312   window1->Hide();
313   window1->SetBounds(gfx::Rect(16, 32, 231, 320));
314   window1->Show();
315
316   // |window1| should be centered in work area.
317   EXPECT_EQ(base::IntToString(
318       (desktop_area.width() - docked_width(manager) -
319        min_dock_gap() - window1->bounds().width()) / 2) +
320       ",32 231x320", window1->bounds().ToString());
321
322   scoped_ptr<aura::Window> window2(CreateTestWindowInShellWithId(2));
323   wm::GetWindowState(window2.get())->set_window_position_managed(true);
324   // To avoid any auto window manager changes due to SetBounds, the window
325   // gets first hidden and then shown again.
326   window2->Hide();
327   window2->SetBounds(gfx::Rect(32, 48, 256, 512));
328   window2->Show();
329
330   // |window1| should be flush left and |window2| flush right.
331   EXPECT_EQ("0,32 231x320", window1->bounds().ToString());
332   EXPECT_EQ(
333       base::IntToString(
334           desktop_area.width() - window2->bounds().width() -
335           docked_width(manager) - min_dock_gap()) +
336       ",48 256x512", window2->bounds().ToString());
337 }
338
339 // Tests that with a window docked on the right the auto-placing logic in
340 // RearrangeVisibleWindowOnShow places windows flush with work area edges.
341 // Test case for the secondary screen.
342 TEST_P(DockedWindowLayoutManagerTest, AutoPlacingRightSecondScreen) {
343   if (!SupportsMultipleDisplays() || !SupportsHostWindowResize())
344     return;
345
346   // Create a dual screen layout.
347   UpdateDisplay("600x600,600x600");
348
349   gfx::Rect bounds(600, 0, 201, 201);
350   scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
351   // Drag pointer to the right edge of the second screen.
352   DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0);
353
354   // The window should be attached and snapped to the right side of the screen.
355   EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().right(),
356             window->GetBoundsInScreen().right());
357   EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id());
358
359   DockedWindowLayoutManager* manager = static_cast<DockedWindowLayoutManager*>(
360       window->parent()->layout_manager());
361
362   // Create two additional windows and test their auto-placement
363   bounds = gfx::Rect(616, 32, 231, 320);
364   scoped_ptr<aura::Window> window1(
365       CreateTestWindowInShellWithDelegate(NULL, 1, bounds));
366   gfx::Rect desktop_area = window1->parent()->bounds();
367   wm::GetWindowState(window1.get())->set_window_position_managed(true);
368   window1->Hide();
369   window1->Show();
370
371   // |window1| should be centered in work area.
372   EXPECT_EQ(base::IntToString(
373       600 + (desktop_area.width() - docked_width(manager) -
374           min_dock_gap() - window1->bounds().width()) / 2) +
375       ",32 231x320", window1->GetBoundsInScreen().ToString());
376
377   bounds = gfx::Rect(632, 48, 256, 512);
378   scoped_ptr<aura::Window> window2(
379       CreateTestWindowInShellWithDelegate(NULL, 2, bounds));
380   wm::GetWindowState(window2.get())->set_window_position_managed(true);
381   // To avoid any auto window manager changes due to SetBounds, the window
382   // gets first hidden and then shown again.
383   window2->Hide();
384   window2->Show();
385
386   // |window1| should be flush left and |window2| flush right.
387   EXPECT_EQ("600,32 231x320", window1->GetBoundsInScreen().ToString());
388   EXPECT_EQ(
389       base::IntToString(
390           600 + desktop_area.width() - window2->bounds().width() -
391           docked_width(manager) - min_dock_gap()) +
392       ",48 256x512", window2->GetBoundsInScreen().ToString());
393 }
394
395 // Adds two windows and tests that the gaps are evenly distributed.
396 TEST_P(DockedWindowLayoutManagerTest, AddTwoWindows) {
397   if (!SupportsHostWindowResize())
398     return;
399
400   scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
401   scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 202)));
402   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
403   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 300);
404
405   // The windows should be attached and snapped to the right side of the screen.
406   EXPECT_EQ(w1->GetRootWindow()->bounds().right(),
407             w1->GetBoundsInScreen().right());
408   EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id());
409   EXPECT_EQ(w2->GetRootWindow()->bounds().right(),
410             w2->GetBoundsInScreen().right());
411   EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id());
412
413   // Test that the gaps differ at most by a single pixel.
414   gfx::Rect work_area =
415       Shell::GetScreen()->GetDisplayNearestWindow(w1.get()).work_area();
416   int gap1 = w1->GetBoundsInScreen().y();
417   int gap2 = w2->GetBoundsInScreen().y() - w1->GetBoundsInScreen().bottom();
418   int gap3 = work_area.bottom() - w2->GetBoundsInScreen().bottom();
419   EXPECT_EQ(0, gap1);
420   EXPECT_NEAR(gap2, min_dock_gap(), 1);
421   EXPECT_EQ(0, gap3);
422 }
423
424 // Adds two non-overlapping windows and tests layout after a drag.
425 TEST_P(DockedWindowLayoutManagerTest, TwoWindowsDragging) {
426   if (!SupportsHostWindowResize())
427     return;
428
429   scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
430   scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 202)));
431   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
432   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 300);
433
434   // The windows should be attached and snapped to the right side of the screen.
435   EXPECT_EQ(w1->GetRootWindow()->bounds().right(),
436             w1->GetBoundsInScreen().right());
437   EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id());
438   EXPECT_EQ(w2->GetRootWindow()->bounds().right(),
439             w2->GetBoundsInScreen().right());
440   EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id());
441
442   // Drag w2 above w1.
443   ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(w2.get(), 0, 20));
444   DragMove(0, -w2->bounds().height() / 2 - min_dock_gap() - 1);
445   DragEnd();
446
447   // Test the new windows order and that the gaps differ at most by a pixel.
448   gfx::Rect work_area =
449       Shell::GetScreen()->GetDisplayNearestWindow(w1.get()).work_area();
450   int gap1 = w2->GetBoundsInScreen().y() - work_area.y();
451   int gap2 = w1->GetBoundsInScreen().y() - w2->GetBoundsInScreen().bottom();
452   int gap3 = work_area.bottom() - w1->GetBoundsInScreen().bottom();
453   EXPECT_EQ(0, gap1);
454   EXPECT_NEAR(gap2, min_dock_gap(), 1);
455   EXPECT_EQ(0, gap3);
456 }
457
458 // Adds three overlapping windows and tests layout after a drag.
459 TEST_P(DockedWindowLayoutManagerTest, ThreeWindowsDragging) {
460   if (!SupportsHostWindowResize())
461     return;
462   UpdateDisplay("600x1000");
463
464   scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 310)));
465   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
466   scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 310)));
467   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 500);
468   scoped_ptr<aura::Window> w3(CreateTestWindow(gfx::Rect(0, 0, 220, 310)));
469   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w3.get(), 600);
470
471   // All windows should be attached and snapped to the right side of the screen.
472   EXPECT_EQ(w1->GetRootWindow()->bounds().right(),
473             w1->GetBoundsInScreen().right());
474   EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id());
475   EXPECT_EQ(w2->GetRootWindow()->bounds().right(),
476             w2->GetBoundsInScreen().right());
477   EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id());
478   EXPECT_EQ(w3->GetRootWindow()->bounds().right(),
479             w3->GetBoundsInScreen().right());
480   EXPECT_EQ(kShellWindowId_DockedContainer, w3->parent()->id());
481
482   // Test that the top and bottom windows are clamped in work area and
483   // that the gaps between the windows differ at most by a pixel.
484   gfx::Rect work_area =
485       Shell::GetScreen()->GetDisplayNearestWindow(w1.get()).work_area();
486   int gap1 = w1->GetBoundsInScreen().y() - work_area.y();
487   int gap2 = w2->GetBoundsInScreen().y() - w1->GetBoundsInScreen().bottom();
488   int gap3 = w3->GetBoundsInScreen().y() - w2->GetBoundsInScreen().bottom();
489   int gap4 = work_area.bottom() - w3->GetBoundsInScreen().bottom();
490   EXPECT_EQ(0, gap1);
491   EXPECT_NEAR(gap2, min_dock_gap(), 1);
492   EXPECT_NEAR(gap3, min_dock_gap(), 1);
493   EXPECT_EQ(0, gap4);
494
495   // Drag w1 below the point where w1 and w2 would swap places. This point is
496   // half way between the tops of those two windows.
497   // A bit more vertical drag is needed to account for a window bounds changing
498   // to its restore bounds during the drag.
499   ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(w1.get(), 0, 20));
500   DragMove(0, min_dock_gap() + w2->bounds().height() / 2 + 10);
501
502   // During the drag the windows get rearranged and the top and the bottom
503   // should be limited by the work area.
504   EXPECT_EQ(work_area.y(), w2->GetBoundsInScreen().y());
505   EXPECT_GT(w1->GetBoundsInScreen().y(), w2->GetBoundsInScreen().y());
506   EXPECT_EQ(work_area.bottom(), w3->GetBoundsInScreen().bottom());
507   DragEnd();
508
509   // Test the new windows order and that the gaps differ at most by a pixel.
510   gap1 = w2->GetBoundsInScreen().y() - work_area.y();
511   gap2 = w1->GetBoundsInScreen().y() - w2->GetBoundsInScreen().bottom();
512   gap3 = w3->GetBoundsInScreen().y() - w1->GetBoundsInScreen().bottom();
513   gap4 = work_area.bottom() - w3->GetBoundsInScreen().bottom();
514   EXPECT_EQ(0, gap1);
515   EXPECT_NEAR(gap2, min_dock_gap(), 1);
516   EXPECT_NEAR(gap3, min_dock_gap(), 1);
517   EXPECT_EQ(0, gap4);
518 }
519
520 // Adds three windows in bottom display and tests layout after a drag.
521 TEST_P(DockedWindowLayoutManagerTest, ThreeWindowsDraggingSecondScreen) {
522   if (!SupportsMultipleDisplays() || !SupportsHostWindowResize())
523     return;
524
525   // Create two screen vertical layout.
526   UpdateDisplay("600x1000,600x1000");
527   // Layout the secondary display to the bottom of the primary.
528   DisplayLayout layout(DisplayLayout::BOTTOM, 0);
529   ASSERT_GT(Shell::GetScreen()->GetNumDisplays(), 1);
530   Shell::GetInstance()->display_manager()->
531       SetLayoutForCurrentDisplays(layout);
532
533   scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 1000, 201, 310)));
534   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 1000 + 20);
535   scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 1000, 210, 310)));
536   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 1000 + 500);
537   scoped_ptr<aura::Window> w3(CreateTestWindow(gfx::Rect(0, 1000, 220, 310)));
538   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w3.get(), 1000 + 600);
539
540   // All windows should be attached and snapped to the right side of the screen.
541   EXPECT_EQ(w1->GetRootWindow()->bounds().right(),
542             w1->GetBoundsInScreen().right());
543   EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id());
544   EXPECT_EQ(w2->GetRootWindow()->bounds().right(),
545             w2->GetBoundsInScreen().right());
546   EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id());
547   EXPECT_EQ(w3->GetRootWindow()->bounds().right(),
548             w3->GetBoundsInScreen().right());
549   EXPECT_EQ(kShellWindowId_DockedContainer, w3->parent()->id());
550
551   gfx::Rect work_area =
552       Shell::GetScreen()->GetDisplayNearestWindow(w1.get()).work_area();
553   // Test that the top and bottom windows are clamped in work area and
554   // that the overlaps between the windows differ at most by a pixel.
555   int gap1 = w1->GetBoundsInScreen().y() - work_area.y();
556   int gap2 = w2->GetBoundsInScreen().y() - w1->GetBoundsInScreen().bottom();
557   int gap3 = w3->GetBoundsInScreen().y() - w2->GetBoundsInScreen().bottom();
558   int gap4 = work_area.bottom() - w3->GetBoundsInScreen().bottom();
559   EXPECT_EQ(0, gap1);
560   EXPECT_NEAR(gap2, min_dock_gap(), 1);
561   EXPECT_NEAR(gap3, min_dock_gap(), 1);
562   EXPECT_EQ(0, gap4);
563
564   // Drag w1 below the point where w1 and w2 would swap places. This point is
565   // half way between the tops of those two windows.
566   // A bit more vertical drag is needed to account for a window bounds changing
567   // to its restore bounds during the drag.
568   ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(w1.get(), 0, 20));
569   DragMove(0, min_dock_gap() + w2->bounds().height() / 2 + 10);
570
571   // During the drag the windows get rearranged and the top and the bottom
572   // should be limited by the work area.
573   EXPECT_EQ(work_area.y(), w2->GetBoundsInScreen().y());
574   EXPECT_GT(w1->GetBoundsInScreen().y(), w2->GetBoundsInScreen().y());
575   EXPECT_EQ(work_area.bottom(), w3->GetBoundsInScreen().bottom());
576   DragEnd();
577
578   // Test the new windows order and that the overlaps differ at most by a pixel.
579   gap1 = w2->GetBoundsInScreen().y() - work_area.y();
580   gap2 = w1->GetBoundsInScreen().y() - w2->GetBoundsInScreen().bottom();
581   gap3 = w3->GetBoundsInScreen().y() - w1->GetBoundsInScreen().bottom();
582   gap4 = work_area.bottom() - w3->GetBoundsInScreen().bottom();
583   EXPECT_EQ(0, gap1);
584   EXPECT_NEAR(gap2, min_dock_gap(), 1);
585   EXPECT_NEAR(gap3, min_dock_gap(), 1);
586   EXPECT_EQ(0, gap4);
587 }
588
589 // Tests that a second window added to the dock is resized to match.
590 TEST_P(DockedWindowLayoutManagerTest, TwoWindowsWidthNew) {
591   if (!SupportsHostWindowResize())
592     return;
593
594   scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
595   scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 280, 202)));
596   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
597   // The first window should get resized to ideal width.
598   EXPECT_EQ(ideal_width(), w1->bounds().width());
599
600   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 300);
601   // The second window should get resized to the existing dock.
602   EXPECT_EQ(ideal_width(), w2->bounds().width());
603 }
604
605 // Tests that a first non-resizable window added to the dock is not resized.
606 TEST_P(DockedWindowLayoutManagerTest, TwoWindowsWidthNonResizableFirst) {
607   if (!SupportsHostWindowResize())
608     return;
609
610   scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
611   w1->SetProperty(aura::client::kCanResizeKey, false);
612   scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 280, 202)));
613   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
614   // The first window should not get resized.
615   EXPECT_EQ(201, w1->bounds().width());
616
617   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 300);
618   // The second window should get resized to the first window's width.
619   EXPECT_EQ(w1->bounds().width(), w2->bounds().width());
620 }
621
622 // Tests that a second non-resizable window added to the dock is not resized.
623 TEST_P(DockedWindowLayoutManagerTest, TwoWindowsWidthNonResizableSecond) {
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, 280, 202)));
629   w2->SetProperty(aura::client::kCanResizeKey, false);
630   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
631   // The first window should get resized to ideal width.
632   EXPECT_EQ(ideal_width(), w1->bounds().width());
633
634   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 300);
635   // The second window should not get resized.
636   EXPECT_EQ(280, w2->bounds().width());
637
638   // The first window should get resized again - to match the second window.
639   EXPECT_EQ(w1->bounds().width(), w2->bounds().width());
640 }
641
642 // Test that restrictions on minimum and maximum width of windows are honored.
643 TEST_P(DockedWindowLayoutManagerTest, TwoWindowsWidthRestrictions) {
644   if (!SupportsHostWindowResize())
645     return;
646
647   aura::test::TestWindowDelegate delegate1;
648   delegate1.set_maximum_size(gfx::Size(240, 0));
649   scoped_ptr<aura::Window> w1(CreateTestWindowWithDelegate(
650       gfx::Rect(0, 0, 201, 201), &delegate1));
651   aura::test::TestWindowDelegate delegate2;
652   delegate2.set_minimum_size(gfx::Size(260, 0));
653   scoped_ptr<aura::Window> w2(CreateTestWindowWithDelegate(
654       gfx::Rect(0, 0, 280, 202), &delegate2));
655   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
656   // The first window should get resized to its maximum width.
657   EXPECT_EQ(240, w1->bounds().width());
658
659   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 300);
660   // The second window should get resized to its minimum width.
661   EXPECT_EQ(260, w2->bounds().width());
662
663   // The first window should be centered relative to the second.
664   EXPECT_EQ(w1->bounds().CenterPoint().x(), w2->bounds().CenterPoint().x());
665 }
666
667 // Test that restrictions on minimum width of windows are honored.
668 TEST_P(DockedWindowLayoutManagerTest, WidthMoreThanMax) {
669   if (!SupportsHostWindowResize())
670     return;
671
672   aura::test::TestWindowDelegate delegate;
673   delegate.set_minimum_size(gfx::Size(400, 0));
674   scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
675       gfx::Rect(0, 0, 400, 201), &delegate));
676   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, window.get(), 20);
677
678   // Secondary drag ensures that we are testing the minimum size restriction
679   // and not just failure to get past the tiling step in SnapSizer.
680   ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(window.get(),
681                                                             25, 5));
682   DragMove(150,0);
683   DragEnd();
684
685   // The window should not get docked even though it is dragged past the edge.
686   EXPECT_NE(window->GetRootWindow()->bounds().right(),
687             window->GetBoundsInScreen().right());
688   EXPECT_NE(kShellWindowId_DockedContainer, window->parent()->id());
689 }
690
691 // Docks three windows and tests that the very first window gets minimized.
692 TEST_P(DockedWindowLayoutManagerTest, ThreeWindowsMinimize) {
693   if (!SupportsHostWindowResize())
694     return;
695
696   scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
697   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
698   scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 202)));
699   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 200);
700   scoped_ptr<aura::Window> w3(CreateTestWindow(gfx::Rect(0, 0, 220, 204)));
701   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w3.get(), 300);
702
703   // The last two windows should be attached and snapped to the right edge.
704   EXPECT_EQ(w2->GetRootWindow()->bounds().right(),
705             w2->GetBoundsInScreen().right());
706   EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id());
707   EXPECT_EQ(w3->GetRootWindow()->bounds().right(),
708             w3->GetBoundsInScreen().right());
709   EXPECT_EQ(kShellWindowId_DockedContainer, w3->parent()->id());
710
711   // The first window should get minimized but parented by the dock container.
712   EXPECT_TRUE(wm::GetWindowState(w1.get())->IsMinimized());
713   EXPECT_TRUE(wm::GetWindowState(w2.get())->IsNormalStateType());
714   EXPECT_TRUE(wm::GetWindowState(w3.get())->IsNormalStateType());
715   EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id());
716 }
717
718 // Docks up to three windows and tests that they split vertical space.
719 TEST_P(DockedWindowLayoutManagerTest, ThreeWindowsSplitHeightEvenly) {
720   if (!SupportsHostWindowResize())
721     return;
722
723   UpdateDisplay("600x1000");
724   scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
725   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
726   scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 202)));
727   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 200);
728
729   // The two windows should be attached and snapped to the right edge.
730   EXPECT_EQ(w1->GetRootWindow()->bounds().right(),
731             w1->GetBoundsInScreen().right());
732   EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id());
733   EXPECT_EQ(w2->GetRootWindow()->bounds().right(),
734             w2->GetBoundsInScreen().right());
735   EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id());
736
737   // The two windows should be same size vertically and almost 1/2 of work area.
738   gfx::Rect work_area =
739       Shell::GetScreen()->GetDisplayNearestWindow(w1.get()).work_area();
740   EXPECT_NEAR(w1->GetBoundsInScreen().height(),
741               w2->GetBoundsInScreen().height(),
742               1);
743   EXPECT_NEAR(work_area.height() / 2, w1->GetBoundsInScreen().height(),
744               min_dock_gap() * 2);
745
746   // Create and dock the third window.
747   scoped_ptr<aura::Window> w3(CreateTestWindow(gfx::Rect(0, 0, 220, 204)));
748   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w3.get(), 300);
749
750   // All three windows should be docked and snapped to the right edge.
751   EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id());
752   EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id());
753   EXPECT_EQ(kShellWindowId_DockedContainer, w3->parent()->id());
754
755   // All windows should be near same size vertically and about 1/3 of work area.
756   EXPECT_NEAR(w1->GetBoundsInScreen().height(),
757               w2->GetBoundsInScreen().height(),
758               1);
759   EXPECT_NEAR(w2->GetBoundsInScreen().height(),
760               w3->GetBoundsInScreen().height(),
761               1);
762   EXPECT_NEAR(work_area.height() / 3, w1->GetBoundsInScreen().height(),
763               min_dock_gap() * 2);
764 }
765
766 // Docks two windows and tests that restrictions on vertical size are honored.
767 TEST_P(DockedWindowLayoutManagerTest, TwoWindowsHeightRestrictions) {
768   if (!SupportsHostWindowResize())
769     return;
770
771   // The first window is fixed height.
772   aura::test::TestWindowDelegate delegate1;
773   delegate1.set_minimum_size(gfx::Size(0, 300));
774   delegate1.set_maximum_size(gfx::Size(0, 300));
775   scoped_ptr<aura::Window> w1(CreateTestWindowWithDelegate(
776       gfx::Rect(0, 0, 201, 300), &delegate1));
777   // The second window has maximum height.
778   aura::test::TestWindowDelegate delegate2;
779   delegate2.set_maximum_size(gfx::Size(0, 100));
780   scoped_ptr<aura::Window> w2(CreateTestWindowWithDelegate(
781       gfx::Rect(0, 0, 280, 90), &delegate2));
782
783   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
784   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 200);
785
786   // The two windows should be attached and snapped to the right edge.
787   EXPECT_EQ(w1->GetRootWindow()->bounds().right(),
788             w1->GetBoundsInScreen().right());
789   EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id());
790   EXPECT_EQ(w2->GetRootWindow()->bounds().right(),
791             w2->GetBoundsInScreen().right());
792   EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id());
793
794   // The two windows should have their heights restricted.
795   EXPECT_EQ(300, w1->GetBoundsInScreen().height());
796   EXPECT_EQ(100, w2->GetBoundsInScreen().height());
797
798   // w1 should be more than half of the work area height (even with a margin).
799   // w2 should be less than half of the work area height (even with a margin).
800   gfx::Rect work_area =
801       Shell::GetScreen()->GetDisplayNearestWindow(w1.get()).work_area();
802   EXPECT_GT(w1->GetBoundsInScreen().height(), work_area.height() / 2 + 10);
803   EXPECT_LT(w2->GetBoundsInScreen().height(), work_area.height() / 2 - 10);
804 }
805
806 // Tests that a docked window is moved to primary display when secondary display
807 // is disconnected and that it stays docked and properly positioned.
808 TEST_P(DockedWindowLayoutManagerTest, DisplayDisconnectionMovesDocked) {
809   if (!SupportsMultipleDisplays() || !SupportsHostWindowResize())
810     return;
811
812   // Create a dual screen layout.
813   UpdateDisplay("600x700,800x600");
814
815   gfx::Rect bounds(600, 0, 201, 201);
816   scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
817   // Drag pointer to the right edge of the second screen.
818   DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0);
819
820   // Simulate disconnection of the secondary display.
821   UpdateDisplay("600x700");
822
823   // The window should be still docked at the right edge.
824   // Its height should grow to match the new work area.
825   EXPECT_EQ(window->GetRootWindow()->bounds().right(),
826             window->GetBoundsInScreen().right());
827   EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id());
828   EXPECT_EQ(ideal_width(), window->bounds().width());
829   gfx::Rect work_area =
830       Shell::GetScreen()->GetDisplayNearestWindow(window.get()).work_area();
831   EXPECT_EQ(work_area.height(), window->GetBoundsInScreen().height());
832 }
833
834 // Tests run twice - on both panels and normal windows
835 INSTANTIATE_TEST_CASE_P(NormalOrPanel,
836                         DockedWindowLayoutManagerTest,
837                         testing::Values(ui::wm::WINDOW_TYPE_NORMAL,
838                                         ui::wm::WINDOW_TYPE_PANEL));
839
840 }  // namespace ash