Roll src/third_party/skia fd0ecf4:d803cda
[chromium-blink-merge.git] / ash / wm / dock / docked_window_layout_manager_unittest.cc
blob0346758a50ba860f7fdddba0c27a716286d7cf87
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.
5 #include "ash/wm/dock/docked_window_layout_manager.h"
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"
38 namespace ash {
40 class DockedWindowLayoutManagerTest
41 : public test::AshTestBase,
42 public testing::WithParamInterface<ui::wm::WindowType> {
43 public:
44 DockedWindowLayoutManagerTest() : window_type_(GetParam()) {}
45 virtual ~DockedWindowLayoutManagerTest() {}
47 void SetUp() override {
48 AshTestBase::SetUp();
49 UpdateDisplay("600x600");
50 ASSERT_TRUE(test::TestShelfDelegate::instance());
52 shelf_view_test_.reset(new test::ShelfViewTestAPI(
53 test::ShelfTestAPI(Shelf::ForPrimaryDisplay()).shelf_view()));
54 shelf_view_test_->SetAnimationDuration(1);
57 protected:
58 enum DockedEdge {
59 DOCKED_EDGE_NONE,
60 DOCKED_EDGE_LEFT,
61 DOCKED_EDGE_RIGHT,
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_;
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();
82 return window;
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();
99 return window;
102 aura::Window* GetPanelContainer(aura::Window* panel) {
103 return Shell::GetContainer(panel->GetRootWindow(),
104 kShellWindowId_PanelContainer);
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();
118 void DragStart(aura::Window* window) {
119 DragStartAtOffsetFromwindowOrigin(window, 0, 0);
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());
132 void DragMove(int dx, int dy) {
133 resizer_->Drag(initial_location_in_parent_ + gfx::Vector2d(dx, dy), 0);
136 void DragEnd() {
137 resizer_->CompleteDrag();
138 resizer_.reset();
141 void DragRevert() {
142 resizer_->RevertDrag();
143 resizer_.reset();
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;
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,
163 window_type_ == ui::wm::WINDOW_TYPE_PANEL ? -100 : 20);
166 void DragToVerticalPositionAndToEdge(DockedEdge edge,
167 aura::Window* window,
168 int y) {
169 DragToVerticalPositionRelativeToEdge(edge, window, 0, y);
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());
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));
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();
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());
211 private:
212 scoped_ptr<WindowResizer> resizer_;
213 scoped_ptr<test::ShelfViewTestAPI> shelf_view_test_;
214 ui::wm::WindowType window_type_;
216 // Location at start of the drag in |window->parent()|'s coordinates.
217 gfx::Point initial_location_in_parent_;
219 DISALLOW_COPY_AND_ASSIGN(DockedWindowLayoutManagerTest);
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;
228 gfx::Rect bounds(0, 0, 201, 201);
229 scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
230 DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0);
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());
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;
246 gfx::Rect bounds(0, 0, 201, 201);
247 scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
248 DragRelativeToEdge(DOCKED_EDGE_LEFT, window.get(), 0);
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());
255 DockedWindowLayoutManager* manager = static_cast<DockedWindowLayoutManager*>(
256 window->parent()->layout_manager());
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());
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();
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());
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;
296 gfx::Rect bounds(0, 0, 201, 201);
297 scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
298 DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0);
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());
305 DockedWindowLayoutManager* manager = static_cast<DockedWindowLayoutManager*>(
306 window->parent()->layout_manager());
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();
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());
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();
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());
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;
346 // Create a dual screen layout.
347 UpdateDisplay("600x600,600x600");
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);
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());
359 DockedWindowLayoutManager* manager = static_cast<DockedWindowLayoutManager*>(
360 window->parent()->layout_manager());
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();
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());
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();
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());
395 // Adds two windows and tests that the gaps are evenly distributed.
396 TEST_P(DockedWindowLayoutManagerTest, AddTwoWindows) {
397 if (!SupportsHostWindowResize())
398 return;
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);
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());
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);
424 // Adds two non-overlapping windows and tests layout after a drag.
425 TEST_P(DockedWindowLayoutManagerTest, TwoWindowsDragging) {
426 if (!SupportsHostWindowResize())
427 return;
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);
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());
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();
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);
458 // Adds three overlapping windows and tests layout after a drag.
459 TEST_P(DockedWindowLayoutManagerTest, ThreeWindowsDragging) {
460 if (!SupportsHostWindowResize())
461 return;
462 UpdateDisplay("600x1000");
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);
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());
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);
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);
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();
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);
520 // Adds three windows in bottom display and tests layout after a drag.
521 TEST_P(DockedWindowLayoutManagerTest, ThreeWindowsDraggingSecondScreen) {
522 if (!SupportsMultipleDisplays() || !SupportsHostWindowResize())
523 return;
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);
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);
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());
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);
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);
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();
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);
589 // Tests that a second window added to the dock is resized to match.
590 TEST_P(DockedWindowLayoutManagerTest, TwoWindowsWidthNew) {
591 if (!SupportsHostWindowResize())
592 return;
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());
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());
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;
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());
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());
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;
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());
634 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 300);
635 // The second window should not get resized.
636 EXPECT_EQ(280, w2->bounds().width());
638 // The first window should get resized again - to match the second window.
639 EXPECT_EQ(w1->bounds().width(), w2->bounds().width());
642 // Test that restrictions on minimum and maximum width of windows are honored.
643 TEST_P(DockedWindowLayoutManagerTest, TwoWindowsWidthRestrictions) {
644 if (!SupportsHostWindowResize())
645 return;
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());
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());
663 // The first window should be centered relative to the second.
664 EXPECT_EQ(w1->bounds().CenterPoint().x(), w2->bounds().CenterPoint().x());
667 // Test that restrictions on minimum width of windows are honored.
668 TEST_P(DockedWindowLayoutManagerTest, WidthMoreThanMax) {
669 if (!SupportsHostWindowResize())
670 return;
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);
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();
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());
691 // Docks three windows and tests that the very first window gets minimized.
692 TEST_P(DockedWindowLayoutManagerTest, ThreeWindowsMinimize) {
693 if (!SupportsHostWindowResize())
694 return;
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);
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());
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(w1.get())->IsDocked());
714 EXPECT_FALSE(wm::GetWindowState(w2.get())->IsMinimized());
715 EXPECT_TRUE(wm::GetWindowState(w2.get())->IsDocked());
716 EXPECT_FALSE(wm::GetWindowState(w3.get())->IsMinimized());
717 EXPECT_TRUE(wm::GetWindowState(w3.get())->IsDocked());
718 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id());
721 // Docks up to three windows and tests that they split vertical space.
722 TEST_P(DockedWindowLayoutManagerTest, ThreeWindowsSplitHeightEvenly) {
723 if (!SupportsHostWindowResize())
724 return;
726 UpdateDisplay("600x1000");
727 scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
728 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
729 scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 202)));
730 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 200);
732 // The two windows should be attached and snapped to the right edge.
733 EXPECT_EQ(w1->GetRootWindow()->bounds().right(),
734 w1->GetBoundsInScreen().right());
735 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id());
736 EXPECT_EQ(w2->GetRootWindow()->bounds().right(),
737 w2->GetBoundsInScreen().right());
738 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id());
740 // The two windows should be same size vertically and almost 1/2 of work area.
741 gfx::Rect work_area =
742 Shell::GetScreen()->GetDisplayNearestWindow(w1.get()).work_area();
743 EXPECT_NEAR(w1->GetBoundsInScreen().height(),
744 w2->GetBoundsInScreen().height(),
746 EXPECT_NEAR(work_area.height() / 2, w1->GetBoundsInScreen().height(),
747 min_dock_gap() * 2);
749 // Create and dock the third window.
750 scoped_ptr<aura::Window> w3(CreateTestWindow(gfx::Rect(0, 0, 220, 204)));
751 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w3.get(), 300);
753 // All three windows should be docked and snapped to the right edge.
754 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id());
755 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id());
756 EXPECT_EQ(kShellWindowId_DockedContainer, w3->parent()->id());
758 // All windows should be near same size vertically and about 1/3 of work area.
759 EXPECT_NEAR(w1->GetBoundsInScreen().height(),
760 w2->GetBoundsInScreen().height(),
762 EXPECT_NEAR(w2->GetBoundsInScreen().height(),
763 w3->GetBoundsInScreen().height(),
765 EXPECT_NEAR(work_area.height() / 3, w1->GetBoundsInScreen().height(),
766 min_dock_gap() * 2);
769 // Docks two windows and tests that restrictions on vertical size are honored.
770 TEST_P(DockedWindowLayoutManagerTest, TwoWindowsHeightRestrictions) {
771 if (!SupportsHostWindowResize())
772 return;
774 // The first window is fixed height.
775 aura::test::TestWindowDelegate delegate1;
776 delegate1.set_minimum_size(gfx::Size(0, 300));
777 delegate1.set_maximum_size(gfx::Size(0, 300));
778 scoped_ptr<aura::Window> w1(CreateTestWindowWithDelegate(
779 gfx::Rect(0, 0, 201, 300), &delegate1));
780 // The second window has maximum height.
781 aura::test::TestWindowDelegate delegate2;
782 delegate2.set_maximum_size(gfx::Size(0, 100));
783 scoped_ptr<aura::Window> w2(CreateTestWindowWithDelegate(
784 gfx::Rect(0, 0, 280, 90), &delegate2));
786 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
787 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 200);
789 // The two windows should be attached and snapped to the right edge.
790 EXPECT_EQ(w1->GetRootWindow()->bounds().right(),
791 w1->GetBoundsInScreen().right());
792 EXPECT_EQ(kShellWindowId_DockedContainer, w1->parent()->id());
793 EXPECT_EQ(w2->GetRootWindow()->bounds().right(),
794 w2->GetBoundsInScreen().right());
795 EXPECT_EQ(kShellWindowId_DockedContainer, w2->parent()->id());
797 // The two windows should have their heights restricted.
798 EXPECT_EQ(300, w1->GetBoundsInScreen().height());
799 EXPECT_EQ(100, w2->GetBoundsInScreen().height());
801 // w1 should be more than half of the work area height (even with a margin).
802 // w2 should be less than half of the work area height (even with a margin).
803 gfx::Rect work_area =
804 Shell::GetScreen()->GetDisplayNearestWindow(w1.get()).work_area();
805 EXPECT_GT(w1->GetBoundsInScreen().height(), work_area.height() / 2 + 10);
806 EXPECT_LT(w2->GetBoundsInScreen().height(), work_area.height() / 2 - 10);
809 // Tests that a docked window is moved to primary display when secondary display
810 // is disconnected and that it stays docked and properly positioned.
811 TEST_P(DockedWindowLayoutManagerTest, DisplayDisconnectionMovesDocked) {
812 if (!SupportsMultipleDisplays() || !SupportsHostWindowResize())
813 return;
815 // Create a dual screen layout.
816 UpdateDisplay("600x700,800x600");
818 gfx::Rect bounds(600, 0, 201, 201);
819 scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
820 // Drag pointer to the right edge of the second screen.
821 DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0);
823 // Simulate disconnection of the secondary display.
824 UpdateDisplay("600x700");
826 // The window should be still docked at the right edge.
827 // Its height should grow to match the new work area.
828 EXPECT_EQ(window->GetRootWindow()->bounds().right(),
829 window->GetBoundsInScreen().right());
830 EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id());
831 EXPECT_EQ(ideal_width(), window->bounds().width());
832 gfx::Rect work_area =
833 Shell::GetScreen()->GetDisplayNearestWindow(window.get()).work_area();
834 EXPECT_EQ(work_area.height(), window->GetBoundsInScreen().height());
837 // Tests run twice - on both panels and normal windows
838 INSTANTIATE_TEST_CASE_P(NormalOrPanel,
839 DockedWindowLayoutManagerTest,
840 testing::Values(ui::wm::WINDOW_TYPE_NORMAL,
841 ui::wm::WINDOW_TYPE_PANEL));
843 } // namespace ash