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"
40 class DockedWindowLayoutManagerTest
41 : public test::AshTestBase
,
42 public testing::WithParamInterface
<ui::wm::WindowType
> {
44 DockedWindowLayoutManagerTest() : window_type_(GetParam()) {}
45 virtual ~DockedWindowLayoutManagerTest() {}
47 void SetUp() override
{
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);
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
)->
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
)->
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(
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
,
124 initial_location_in_parent_
=
125 window
->bounds().origin() + gfx::Vector2d(dx
, dy
);
126 resizer_
.reset(CreateSomeWindowResizer(window
,
127 initial_location_in_parent_
,
129 ASSERT_TRUE(resizer_
.get());
132 void DragMove(int dx
, int dy
) {
133 resizer_
->Drag(initial_location_in_parent_
+ gfx::Vector2d(dx
, dy
), 0);
137 resizer_
->CompleteDrag();
142 resizer_
->RevertDrag();
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
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(
163 window_type_
== ui::wm::WINDOW_TYPE_PANEL
? -100 : 20);
166 void DragToVerticalPositionAndToEdge(DockedEdge edge
,
167 aura::Window
* window
,
169 DragToVerticalPositionRelativeToEdge(edge
, window
, 0, y
);
172 void DragToVerticalPositionRelativeToEdge(DockedEdge edge
,
173 aura::Window
* window
,
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
,
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();
199 EXPECT_EQ(CorrectContainerIdDuringDrag(), window
->parent()->id());
200 // Release the mouse and the panel should be attached to the dock.
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());
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
224 TEST_P(DockedWindowLayoutManagerTest
, AddOneWindow
) {
225 if (!SupportsHostWindowResize())
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 a docked window's bounds cannot be changed programmatically.
241 TEST_P(DockedWindowLayoutManagerTest
, DockedWindowBoundsDontChange
) {
242 if (!SupportsHostWindowResize())
245 gfx::Rect
bounds(0, 0, 201, 201);
246 scoped_ptr
<aura::Window
> window(CreateTestWindow(bounds
));
247 DragRelativeToEdge(DOCKED_EDGE_RIGHT
, window
.get(), 0);
249 // The window should be attached and docked at the right edge.
250 EXPECT_EQ(kShellWindowId_DockedContainer
, window
->parent()->id());
252 bounds
= window
->GetBoundsInScreen();
253 window
->SetBounds(gfx::Rect(210, 210, 210, 210));
254 EXPECT_EQ(bounds
.ToString(), window
->GetBoundsInScreen().ToString());
257 // Tests that with a window docked on the left the auto-placing logic in
258 // RearrangeVisibleWindowOnShow places windows flush with work area edges.
259 TEST_P(DockedWindowLayoutManagerTest
, AutoPlacingLeft
) {
260 if (!SupportsHostWindowResize())
263 gfx::Rect
bounds(0, 0, 201, 201);
264 scoped_ptr
<aura::Window
> window(CreateTestWindow(bounds
));
265 DragRelativeToEdge(DOCKED_EDGE_LEFT
, window
.get(), 0);
267 // The window should be attached and snapped to the right side of the screen.
268 EXPECT_EQ(window
->GetRootWindow()->bounds().x(),
269 window
->GetBoundsInScreen().x());
270 EXPECT_EQ(kShellWindowId_DockedContainer
, window
->parent()->id());
272 DockedWindowLayoutManager
* manager
= static_cast<DockedWindowLayoutManager
*>(
273 window
->parent()->layout_manager());
275 // Create two additional windows and test their auto-placement
276 scoped_ptr
<aura::Window
> window1(CreateTestWindowInShellWithId(1));
277 gfx::Rect desktop_area
= window1
->parent()->bounds();
278 wm::GetWindowState(window1
.get())->set_window_position_managed(true);
280 window1
->SetBounds(gfx::Rect(250, 32, 231, 320));
282 // |window1| should be centered in work area.
283 EXPECT_EQ(base::IntToString(
284 docked_width(manager
) + min_dock_gap() +
285 (desktop_area
.width() - docked_width(manager
) -
286 min_dock_gap() - window1
->bounds().width()) / 2) +
287 ",32 231x320", window1
->bounds().ToString());
289 scoped_ptr
<aura::Window
> window2(CreateTestWindowInShellWithId(2));
290 wm::GetWindowState(window2
.get())->set_window_position_managed(true);
291 // To avoid any auto window manager changes due to SetBounds, the window
292 // gets first hidden and then shown again.
294 window2
->SetBounds(gfx::Rect(250, 48, 150, 300));
297 // |window1| should be flush left and |window2| flush right.
299 base::IntToString(docked_width(manager
) + min_dock_gap()) +
300 ",32 231x320", window1
->bounds().ToString());
303 desktop_area
.width() - window2
->bounds().width()) +
304 ",48 150x300", window2
->bounds().ToString());
307 // Tests that with a window docked on the right the auto-placing logic in
308 // RearrangeVisibleWindowOnShow places windows flush with work area edges.
309 TEST_P(DockedWindowLayoutManagerTest
, AutoPlacingRight
) {
310 if (!SupportsHostWindowResize())
313 gfx::Rect
bounds(0, 0, 201, 201);
314 scoped_ptr
<aura::Window
> window(CreateTestWindow(bounds
));
315 DragRelativeToEdge(DOCKED_EDGE_RIGHT
, window
.get(), 0);
317 // The window should be attached and snapped to the right side of the screen.
318 EXPECT_EQ(window
->GetRootWindow()->bounds().right(),
319 window
->GetBoundsInScreen().right());
320 EXPECT_EQ(kShellWindowId_DockedContainer
, window
->parent()->id());
322 DockedWindowLayoutManager
* manager
= static_cast<DockedWindowLayoutManager
*>(
323 window
->parent()->layout_manager());
325 // Create two additional windows and test their auto-placement
326 scoped_ptr
<aura::Window
> window1(CreateTestWindowInShellWithId(1));
327 gfx::Rect desktop_area
= window1
->parent()->bounds();
328 wm::GetWindowState(window1
.get())->set_window_position_managed(true);
330 window1
->SetBounds(gfx::Rect(16, 32, 231, 320));
333 // |window1| should be centered in work area.
334 EXPECT_EQ(base::IntToString(
335 (desktop_area
.width() - docked_width(manager
) -
336 min_dock_gap() - window1
->bounds().width()) / 2) +
337 ",32 231x320", window1
->bounds().ToString());
339 scoped_ptr
<aura::Window
> window2(CreateTestWindowInShellWithId(2));
340 wm::GetWindowState(window2
.get())->set_window_position_managed(true);
341 // To avoid any auto window manager changes due to SetBounds, the window
342 // gets first hidden and then shown again.
344 window2
->SetBounds(gfx::Rect(32, 48, 256, 512));
347 // |window1| should be flush left and |window2| flush right.
348 EXPECT_EQ("0,32 231x320", window1
->bounds().ToString());
351 desktop_area
.width() - window2
->bounds().width() -
352 docked_width(manager
) - min_dock_gap()) +
353 ",48 256x512", window2
->bounds().ToString());
356 // Tests that with a window docked on the right the auto-placing logic in
357 // RearrangeVisibleWindowOnShow places windows flush with work area edges.
358 // Test case for the secondary screen.
359 TEST_P(DockedWindowLayoutManagerTest
, AutoPlacingRightSecondScreen
) {
360 if (!SupportsMultipleDisplays() || !SupportsHostWindowResize())
363 // Create a dual screen layout.
364 UpdateDisplay("600x600,600x600");
366 gfx::Rect
bounds(600, 0, 201, 201);
367 scoped_ptr
<aura::Window
> window(CreateTestWindow(bounds
));
368 // Drag pointer to the right edge of the second screen.
369 DragRelativeToEdge(DOCKED_EDGE_RIGHT
, window
.get(), 0);
371 // The window should be attached and snapped to the right side of the screen.
372 EXPECT_EQ(window
->GetRootWindow()->GetBoundsInScreen().right(),
373 window
->GetBoundsInScreen().right());
374 EXPECT_EQ(kShellWindowId_DockedContainer
, window
->parent()->id());
376 DockedWindowLayoutManager
* manager
= static_cast<DockedWindowLayoutManager
*>(
377 window
->parent()->layout_manager());
379 // Create two additional windows and test their auto-placement
380 bounds
= gfx::Rect(616, 32, 231, 320);
381 scoped_ptr
<aura::Window
> window1(
382 CreateTestWindowInShellWithDelegate(NULL
, 1, bounds
));
383 gfx::Rect desktop_area
= window1
->parent()->bounds();
384 wm::GetWindowState(window1
.get())->set_window_position_managed(true);
388 // |window1| should be centered in work area.
389 EXPECT_EQ(base::IntToString(
390 600 + (desktop_area
.width() - docked_width(manager
) -
391 min_dock_gap() - window1
->bounds().width()) / 2) +
392 ",32 231x320", window1
->GetBoundsInScreen().ToString());
394 bounds
= gfx::Rect(632, 48, 256, 512);
395 scoped_ptr
<aura::Window
> window2(
396 CreateTestWindowInShellWithDelegate(NULL
, 2, bounds
));
397 wm::GetWindowState(window2
.get())->set_window_position_managed(true);
398 // To avoid any auto window manager changes due to SetBounds, the window
399 // gets first hidden and then shown again.
403 // |window1| should be flush left and |window2| flush right.
404 EXPECT_EQ("600,32 231x320", window1
->GetBoundsInScreen().ToString());
407 600 + desktop_area
.width() - window2
->bounds().width() -
408 docked_width(manager
) - min_dock_gap()) +
409 ",48 256x512", window2
->GetBoundsInScreen().ToString());
412 // Adds two windows and tests that the gaps are evenly distributed.
413 TEST_P(DockedWindowLayoutManagerTest
, AddTwoWindows
) {
414 if (!SupportsHostWindowResize())
417 scoped_ptr
<aura::Window
> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
418 scoped_ptr
<aura::Window
> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 202)));
419 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w1
.get(), 20);
420 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w2
.get(), 300);
422 // The windows should be attached and snapped to the right side of the screen.
423 EXPECT_EQ(w1
->GetRootWindow()->bounds().right(),
424 w1
->GetBoundsInScreen().right());
425 EXPECT_EQ(kShellWindowId_DockedContainer
, w1
->parent()->id());
426 EXPECT_EQ(w2
->GetRootWindow()->bounds().right(),
427 w2
->GetBoundsInScreen().right());
428 EXPECT_EQ(kShellWindowId_DockedContainer
, w2
->parent()->id());
430 // Test that the gaps differ at most by a single pixel.
431 gfx::Rect work_area
=
432 Shell::GetScreen()->GetDisplayNearestWindow(w1
.get()).work_area();
433 int gap1
= w1
->GetBoundsInScreen().y();
434 int gap2
= w2
->GetBoundsInScreen().y() - w1
->GetBoundsInScreen().bottom();
435 int gap3
= work_area
.bottom() - w2
->GetBoundsInScreen().bottom();
437 EXPECT_NEAR(gap2
, min_dock_gap(), 1);
441 // Adds two non-overlapping windows and tests layout after a drag.
442 TEST_P(DockedWindowLayoutManagerTest
, TwoWindowsDragging
) {
443 if (!SupportsHostWindowResize())
446 scoped_ptr
<aura::Window
> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
447 scoped_ptr
<aura::Window
> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 202)));
448 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w1
.get(), 20);
449 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w2
.get(), 300);
451 // The windows should be attached and snapped to the right side of the screen.
452 EXPECT_EQ(w1
->GetRootWindow()->bounds().right(),
453 w1
->GetBoundsInScreen().right());
454 EXPECT_EQ(kShellWindowId_DockedContainer
, w1
->parent()->id());
455 EXPECT_EQ(w2
->GetRootWindow()->bounds().right(),
456 w2
->GetBoundsInScreen().right());
457 EXPECT_EQ(kShellWindowId_DockedContainer
, w2
->parent()->id());
460 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(w2
.get(), 0, 20));
461 DragMove(0, -w2
->bounds().height() / 2 - min_dock_gap() - 1);
464 // Test the new windows order and that the gaps differ at most by a pixel.
465 gfx::Rect work_area
=
466 Shell::GetScreen()->GetDisplayNearestWindow(w1
.get()).work_area();
467 int gap1
= w2
->GetBoundsInScreen().y() - work_area
.y();
468 int gap2
= w1
->GetBoundsInScreen().y() - w2
->GetBoundsInScreen().bottom();
469 int gap3
= work_area
.bottom() - w1
->GetBoundsInScreen().bottom();
471 EXPECT_NEAR(gap2
, min_dock_gap(), 1);
475 // Adds three overlapping windows and tests layout after a drag.
476 TEST_P(DockedWindowLayoutManagerTest
, ThreeWindowsDragging
) {
477 if (!SupportsHostWindowResize())
479 UpdateDisplay("600x1000");
481 scoped_ptr
<aura::Window
> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 310)));
482 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w1
.get(), 20);
483 scoped_ptr
<aura::Window
> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 310)));
484 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w2
.get(), 500);
485 scoped_ptr
<aura::Window
> w3(CreateTestWindow(gfx::Rect(0, 0, 220, 310)));
486 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w3
.get(), 600);
488 // All windows should be attached and snapped to the right side of the screen.
489 EXPECT_EQ(w1
->GetRootWindow()->bounds().right(),
490 w1
->GetBoundsInScreen().right());
491 EXPECT_EQ(kShellWindowId_DockedContainer
, w1
->parent()->id());
492 EXPECT_EQ(w2
->GetRootWindow()->bounds().right(),
493 w2
->GetBoundsInScreen().right());
494 EXPECT_EQ(kShellWindowId_DockedContainer
, w2
->parent()->id());
495 EXPECT_EQ(w3
->GetRootWindow()->bounds().right(),
496 w3
->GetBoundsInScreen().right());
497 EXPECT_EQ(kShellWindowId_DockedContainer
, w3
->parent()->id());
499 // Test that the top and bottom windows are clamped in work area and
500 // that the gaps between the windows differ at most by a pixel.
501 gfx::Rect work_area
=
502 Shell::GetScreen()->GetDisplayNearestWindow(w1
.get()).work_area();
503 int gap1
= w1
->GetBoundsInScreen().y() - work_area
.y();
504 int gap2
= w2
->GetBoundsInScreen().y() - w1
->GetBoundsInScreen().bottom();
505 int gap3
= w3
->GetBoundsInScreen().y() - w2
->GetBoundsInScreen().bottom();
506 int gap4
= work_area
.bottom() - w3
->GetBoundsInScreen().bottom();
508 EXPECT_NEAR(gap2
, min_dock_gap(), 1);
509 EXPECT_NEAR(gap3
, min_dock_gap(), 1);
512 // Drag w1 below the point where w1 and w2 would swap places. This point is
513 // half way between the tops of those two windows.
514 // A bit more vertical drag is needed to account for a window bounds changing
515 // to its restore bounds during the drag.
516 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(w1
.get(), 0, 20));
517 DragMove(0, min_dock_gap() + w2
->bounds().height() / 2 + 10);
519 // During the drag the windows get rearranged and the top and the bottom
520 // should be limited by the work area.
521 EXPECT_EQ(work_area
.y(), w2
->GetBoundsInScreen().y());
522 EXPECT_GT(w1
->GetBoundsInScreen().y(), w2
->GetBoundsInScreen().y());
523 EXPECT_EQ(work_area
.bottom(), w3
->GetBoundsInScreen().bottom());
526 // Test the new windows order and that the gaps differ at most by a pixel.
527 gap1
= w2
->GetBoundsInScreen().y() - work_area
.y();
528 gap2
= w1
->GetBoundsInScreen().y() - w2
->GetBoundsInScreen().bottom();
529 gap3
= w3
->GetBoundsInScreen().y() - w1
->GetBoundsInScreen().bottom();
530 gap4
= work_area
.bottom() - w3
->GetBoundsInScreen().bottom();
532 EXPECT_NEAR(gap2
, min_dock_gap(), 1);
533 EXPECT_NEAR(gap3
, min_dock_gap(), 1);
537 // Adds three windows in bottom display and tests layout after a drag.
538 TEST_P(DockedWindowLayoutManagerTest
, ThreeWindowsDraggingSecondScreen
) {
539 if (!SupportsMultipleDisplays() || !SupportsHostWindowResize())
542 // Create two screen vertical layout.
543 UpdateDisplay("600x1000,600x1000");
544 // Layout the secondary display to the bottom of the primary.
545 DisplayLayout
layout(DisplayLayout::BOTTOM
, 0);
546 ASSERT_GT(Shell::GetScreen()->GetNumDisplays(), 1);
547 Shell::GetInstance()->display_manager()->
548 SetLayoutForCurrentDisplays(layout
);
550 scoped_ptr
<aura::Window
> w1(CreateTestWindow(gfx::Rect(0, 1000, 201, 310)));
551 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w1
.get(), 1000 + 20);
552 scoped_ptr
<aura::Window
> w2(CreateTestWindow(gfx::Rect(0, 1000, 210, 310)));
553 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w2
.get(), 1000 + 500);
554 scoped_ptr
<aura::Window
> w3(CreateTestWindow(gfx::Rect(0, 1000, 220, 310)));
555 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w3
.get(), 1000 + 600);
557 // All windows should be attached and snapped to the right side of the screen.
558 EXPECT_EQ(w1
->GetRootWindow()->bounds().right(),
559 w1
->GetBoundsInScreen().right());
560 EXPECT_EQ(kShellWindowId_DockedContainer
, w1
->parent()->id());
561 EXPECT_EQ(w2
->GetRootWindow()->bounds().right(),
562 w2
->GetBoundsInScreen().right());
563 EXPECT_EQ(kShellWindowId_DockedContainer
, w2
->parent()->id());
564 EXPECT_EQ(w3
->GetRootWindow()->bounds().right(),
565 w3
->GetBoundsInScreen().right());
566 EXPECT_EQ(kShellWindowId_DockedContainer
, w3
->parent()->id());
568 gfx::Rect work_area
=
569 Shell::GetScreen()->GetDisplayNearestWindow(w1
.get()).work_area();
570 // Test that the top and bottom windows are clamped in work area and
571 // that the overlaps between the windows differ at most by a pixel.
572 int gap1
= w1
->GetBoundsInScreen().y() - work_area
.y();
573 int gap2
= w2
->GetBoundsInScreen().y() - w1
->GetBoundsInScreen().bottom();
574 int gap3
= w3
->GetBoundsInScreen().y() - w2
->GetBoundsInScreen().bottom();
575 int gap4
= work_area
.bottom() - w3
->GetBoundsInScreen().bottom();
577 EXPECT_NEAR(gap2
, min_dock_gap(), 1);
578 EXPECT_NEAR(gap3
, min_dock_gap(), 1);
581 // Drag w1 below the point where w1 and w2 would swap places. This point is
582 // half way between the tops of those two windows.
583 // A bit more vertical drag is needed to account for a window bounds changing
584 // to its restore bounds during the drag.
585 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(w1
.get(), 0, 20));
586 DragMove(0, min_dock_gap() + w2
->bounds().height() / 2 + 10);
588 // During the drag the windows get rearranged and the top and the bottom
589 // should be limited by the work area.
590 EXPECT_EQ(work_area
.y(), w2
->GetBoundsInScreen().y());
591 EXPECT_GT(w1
->GetBoundsInScreen().y(), w2
->GetBoundsInScreen().y());
592 EXPECT_EQ(work_area
.bottom(), w3
->GetBoundsInScreen().bottom());
595 // Test the new windows order and that the overlaps differ at most by a pixel.
596 gap1
= w2
->GetBoundsInScreen().y() - work_area
.y();
597 gap2
= w1
->GetBoundsInScreen().y() - w2
->GetBoundsInScreen().bottom();
598 gap3
= w3
->GetBoundsInScreen().y() - w1
->GetBoundsInScreen().bottom();
599 gap4
= work_area
.bottom() - w3
->GetBoundsInScreen().bottom();
601 EXPECT_NEAR(gap2
, min_dock_gap(), 1);
602 EXPECT_NEAR(gap3
, min_dock_gap(), 1);
606 // Tests that a second window added to the dock is resized to match.
607 TEST_P(DockedWindowLayoutManagerTest
, TwoWindowsWidthNew
) {
608 if (!SupportsHostWindowResize())
611 scoped_ptr
<aura::Window
> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
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 get resized to ideal width.
615 EXPECT_EQ(ideal_width(), w1
->bounds().width());
617 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w2
.get(), 300);
618 // The second window should get resized to the existing dock.
619 EXPECT_EQ(ideal_width(), w2
->bounds().width());
622 // Tests that a first non-resizable window added to the dock is not resized.
623 TEST_P(DockedWindowLayoutManagerTest
, TwoWindowsWidthNonResizableFirst
) {
624 if (!SupportsHostWindowResize())
627 scoped_ptr
<aura::Window
> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
628 w1
->SetProperty(aura::client::kCanResizeKey
, false);
629 scoped_ptr
<aura::Window
> w2(CreateTestWindow(gfx::Rect(0, 0, 280, 202)));
630 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w1
.get(), 20);
631 // The first window should not get resized.
632 EXPECT_EQ(201, w1
->bounds().width());
634 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w2
.get(), 300);
635 // The second window should get resized to the first window's width.
636 EXPECT_EQ(w1
->bounds().width(), w2
->bounds().width());
639 // Tests that a second non-resizable window added to the dock is not resized.
640 TEST_P(DockedWindowLayoutManagerTest
, TwoWindowsWidthNonResizableSecond
) {
641 if (!SupportsHostWindowResize())
644 scoped_ptr
<aura::Window
> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
645 scoped_ptr
<aura::Window
> w2(CreateTestWindow(gfx::Rect(0, 0, 280, 202)));
646 w2
->SetProperty(aura::client::kCanResizeKey
, false);
647 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w1
.get(), 20);
648 // The first window should get resized to ideal width.
649 EXPECT_EQ(ideal_width(), w1
->bounds().width());
651 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w2
.get(), 300);
652 // The second window should not get resized.
653 EXPECT_EQ(280, w2
->bounds().width());
655 // The first window should get resized again - to match the second window.
656 EXPECT_EQ(w1
->bounds().width(), w2
->bounds().width());
659 // Test that restrictions on minimum and maximum width of windows are honored.
660 TEST_P(DockedWindowLayoutManagerTest
, TwoWindowsWidthRestrictions
) {
661 if (!SupportsHostWindowResize())
664 aura::test::TestWindowDelegate delegate1
;
665 delegate1
.set_maximum_size(gfx::Size(240, 0));
666 scoped_ptr
<aura::Window
> w1(CreateTestWindowWithDelegate(
667 gfx::Rect(0, 0, 201, 201), &delegate1
));
668 aura::test::TestWindowDelegate delegate2
;
669 delegate2
.set_minimum_size(gfx::Size(260, 0));
670 scoped_ptr
<aura::Window
> w2(CreateTestWindowWithDelegate(
671 gfx::Rect(0, 0, 280, 202), &delegate2
));
672 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w1
.get(), 20);
673 // The first window should get resized to its maximum width.
674 EXPECT_EQ(240, w1
->bounds().width());
676 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w2
.get(), 300);
677 // The second window should get resized to its minimum width.
678 EXPECT_EQ(260, w2
->bounds().width());
680 // The first window should be centered relative to the second.
681 EXPECT_EQ(w1
->bounds().CenterPoint().x(), w2
->bounds().CenterPoint().x());
684 // Test that restrictions on minimum width of windows are honored.
685 TEST_P(DockedWindowLayoutManagerTest
, WidthMoreThanMax
) {
686 if (!SupportsHostWindowResize())
689 aura::test::TestWindowDelegate delegate
;
690 delegate
.set_minimum_size(gfx::Size(400, 0));
691 scoped_ptr
<aura::Window
> window(CreateTestWindowWithDelegate(
692 gfx::Rect(0, 0, 400, 201), &delegate
));
693 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, window
.get(), 20);
695 // Secondary drag ensures that we are testing the minimum size restriction
696 // and not just failure to get past the tiling step in SnapSizer.
697 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(window
.get(),
702 // The window should not get docked even though it is dragged past the edge.
703 EXPECT_NE(window
->GetRootWindow()->bounds().right(),
704 window
->GetBoundsInScreen().right());
705 EXPECT_NE(kShellWindowId_DockedContainer
, window
->parent()->id());
708 // Docks three windows and tests that the very first window gets minimized.
709 TEST_P(DockedWindowLayoutManagerTest
, ThreeWindowsMinimize
) {
710 if (!SupportsHostWindowResize())
713 scoped_ptr
<aura::Window
> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
714 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w1
.get(), 20);
715 scoped_ptr
<aura::Window
> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 202)));
716 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w2
.get(), 200);
717 scoped_ptr
<aura::Window
> w3(CreateTestWindow(gfx::Rect(0, 0, 220, 204)));
718 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w3
.get(), 300);
720 // The last two windows should be attached and snapped to the right edge.
721 EXPECT_EQ(w2
->GetRootWindow()->bounds().right(),
722 w2
->GetBoundsInScreen().right());
723 EXPECT_EQ(kShellWindowId_DockedContainer
, w2
->parent()->id());
724 EXPECT_EQ(w3
->GetRootWindow()->bounds().right(),
725 w3
->GetBoundsInScreen().right());
726 EXPECT_EQ(kShellWindowId_DockedContainer
, w3
->parent()->id());
728 // The first window should get hidden but parented by the dock container.
729 EXPECT_TRUE(wm::GetWindowState(w1
.get())->IsMinimized());
730 EXPECT_TRUE(wm::GetWindowState(w1
.get())->IsDocked());
731 EXPECT_FALSE(w1
->IsVisible());
732 EXPECT_EQ(ui::SHOW_STATE_MINIMIZED
,
733 w1
->GetProperty(aura::client::kShowStateKey
));
734 EXPECT_EQ(ui::SHOW_STATE_DOCKED
,
735 w1
->GetProperty(aura::client::kRestoreShowStateKey
));
736 // The other two windows should be still docked.
737 EXPECT_FALSE(wm::GetWindowState(w2
.get())->IsMinimized());
738 EXPECT_TRUE(wm::GetWindowState(w2
.get())->IsDocked());
739 EXPECT_FALSE(wm::GetWindowState(w3
.get())->IsMinimized());
740 EXPECT_TRUE(wm::GetWindowState(w3
.get())->IsDocked());
741 EXPECT_EQ(kShellWindowId_DockedContainer
, w1
->parent()->id());
744 // Docks up to three windows and tests that they split vertical space.
745 TEST_P(DockedWindowLayoutManagerTest
, ThreeWindowsSplitHeightEvenly
) {
746 if (!SupportsHostWindowResize())
749 UpdateDisplay("600x1000");
750 scoped_ptr
<aura::Window
> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
751 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w1
.get(), 20);
752 scoped_ptr
<aura::Window
> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 202)));
753 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w2
.get(), 200);
755 // The two windows should be attached and snapped to the right edge.
756 EXPECT_EQ(w1
->GetRootWindow()->bounds().right(),
757 w1
->GetBoundsInScreen().right());
758 EXPECT_EQ(kShellWindowId_DockedContainer
, w1
->parent()->id());
759 EXPECT_EQ(w2
->GetRootWindow()->bounds().right(),
760 w2
->GetBoundsInScreen().right());
761 EXPECT_EQ(kShellWindowId_DockedContainer
, w2
->parent()->id());
763 // The two windows should be same size vertically and almost 1/2 of work area.
764 gfx::Rect work_area
=
765 Shell::GetScreen()->GetDisplayNearestWindow(w1
.get()).work_area();
766 EXPECT_NEAR(w1
->GetBoundsInScreen().height(),
767 w2
->GetBoundsInScreen().height(),
769 EXPECT_NEAR(work_area
.height() / 2, w1
->GetBoundsInScreen().height(),
772 // Create and dock the third window.
773 scoped_ptr
<aura::Window
> w3(CreateTestWindow(gfx::Rect(0, 0, 220, 204)));
774 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w3
.get(), 300);
776 // All three windows should be docked and snapped to the right edge.
777 EXPECT_EQ(kShellWindowId_DockedContainer
, w1
->parent()->id());
778 EXPECT_EQ(kShellWindowId_DockedContainer
, w2
->parent()->id());
779 EXPECT_EQ(kShellWindowId_DockedContainer
, w3
->parent()->id());
781 // All windows should be near same size vertically and about 1/3 of work area.
782 EXPECT_NEAR(w1
->GetBoundsInScreen().height(),
783 w2
->GetBoundsInScreen().height(),
785 EXPECT_NEAR(w2
->GetBoundsInScreen().height(),
786 w3
->GetBoundsInScreen().height(),
788 EXPECT_NEAR(work_area
.height() / 3, w1
->GetBoundsInScreen().height(),
792 // Docks two windows and tests that restrictions on vertical size are honored.
793 TEST_P(DockedWindowLayoutManagerTest
, TwoWindowsHeightRestrictions
) {
794 if (!SupportsHostWindowResize())
797 // The first window is fixed height.
798 aura::test::TestWindowDelegate delegate1
;
799 delegate1
.set_minimum_size(gfx::Size(0, 300));
800 delegate1
.set_maximum_size(gfx::Size(0, 300));
801 scoped_ptr
<aura::Window
> w1(CreateTestWindowWithDelegate(
802 gfx::Rect(0, 0, 201, 300), &delegate1
));
803 // The second window has maximum height.
804 aura::test::TestWindowDelegate delegate2
;
805 delegate2
.set_maximum_size(gfx::Size(0, 100));
806 scoped_ptr
<aura::Window
> w2(CreateTestWindowWithDelegate(
807 gfx::Rect(0, 0, 280, 90), &delegate2
));
809 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w1
.get(), 20);
810 DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT
, w2
.get(), 200);
812 // The two windows should be attached and snapped to the right edge.
813 EXPECT_EQ(w1
->GetRootWindow()->bounds().right(),
814 w1
->GetBoundsInScreen().right());
815 EXPECT_EQ(kShellWindowId_DockedContainer
, w1
->parent()->id());
816 EXPECT_EQ(w2
->GetRootWindow()->bounds().right(),
817 w2
->GetBoundsInScreen().right());
818 EXPECT_EQ(kShellWindowId_DockedContainer
, w2
->parent()->id());
820 // The two windows should have their heights restricted.
821 EXPECT_EQ(300, w1
->GetBoundsInScreen().height());
822 EXPECT_EQ(100, w2
->GetBoundsInScreen().height());
824 // w1 should be more than half of the work area height (even with a margin).
825 // w2 should be less than half of the work area height (even with a margin).
826 gfx::Rect work_area
=
827 Shell::GetScreen()->GetDisplayNearestWindow(w1
.get()).work_area();
828 EXPECT_GT(w1
->GetBoundsInScreen().height(), work_area
.height() / 2 + 10);
829 EXPECT_LT(w2
->GetBoundsInScreen().height(), work_area
.height() / 2 - 10);
832 // Tests that a docked window is moved to primary display when secondary display
833 // is disconnected and that it stays docked and properly positioned.
834 TEST_P(DockedWindowLayoutManagerTest
, DisplayDisconnectionMovesDocked
) {
835 if (!SupportsMultipleDisplays() || !SupportsHostWindowResize())
838 // Create a dual screen layout.
839 UpdateDisplay("600x700,800x600");
841 gfx::Rect
bounds(600, 0, 201, 201);
842 scoped_ptr
<aura::Window
> window(CreateTestWindow(bounds
));
843 // Drag pointer to the right edge of the second screen.
844 DragRelativeToEdge(DOCKED_EDGE_RIGHT
, window
.get(), 0);
846 // Simulate disconnection of the secondary display.
847 UpdateDisplay("600x700");
849 // The window should be still docked at the right edge.
850 // Its height should grow to match the new work area.
851 EXPECT_EQ(window
->GetRootWindow()->bounds().right(),
852 window
->GetBoundsInScreen().right());
853 EXPECT_EQ(kShellWindowId_DockedContainer
, window
->parent()->id());
854 EXPECT_EQ(ideal_width(), window
->bounds().width());
855 gfx::Rect work_area
=
856 Shell::GetScreen()->GetDisplayNearestWindow(window
.get()).work_area();
857 EXPECT_EQ(work_area
.height(), window
->GetBoundsInScreen().height());
860 // Tests run twice - on both panels and normal windows
861 INSTANTIATE_TEST_CASE_P(NormalOrPanel
,
862 DockedWindowLayoutManagerTest
,
863 testing::Values(ui::wm::WINDOW_TYPE_NORMAL
,
864 ui::wm::WINDOW_TYPE_PANEL
));