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 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())
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);
263 window1
->SetBounds(gfx::Rect(250, 32, 231, 320));
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.
277 window2
->SetBounds(gfx::Rect(250, 48, 150, 300));
280 // |window1| should be flush left and |window2| flush right.
282 base::IntToString(docked_width(manager
) + min_dock_gap()) +
283 ",32 231x320", window1
->bounds().ToString());
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())
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);
313 window1
->SetBounds(gfx::Rect(16, 32, 231, 320));
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.
327 window2
->SetBounds(gfx::Rect(32, 48, 256, 512));
330 // |window1| should be flush left and |window2| flush right.
331 EXPECT_EQ("0,32 231x320", window1
->bounds().ToString());
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())
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);
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.
386 // |window1| should be flush left and |window2| flush right.
387 EXPECT_EQ("600,32 231x320", window1
->GetBoundsInScreen().ToString());
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())
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();
420 EXPECT_NEAR(gap2
, min_dock_gap(), 1);
424 // Adds two non-overlapping windows and tests layout after a drag.
425 TEST_P(DockedWindowLayoutManagerTest
, TwoWindowsDragging
) {
426 if (!SupportsHostWindowResize())
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());
443 ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(w2
.get(), 0, 20));
444 DragMove(0, -w2
->bounds().height() / 2 - min_dock_gap() - 1);
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();
454 EXPECT_NEAR(gap2
, min_dock_gap(), 1);
458 // Adds three overlapping windows and tests layout after a drag.
459 TEST_P(DockedWindowLayoutManagerTest
, ThreeWindowsDragging
) {
460 if (!SupportsHostWindowResize())
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();
491 EXPECT_NEAR(gap2
, min_dock_gap(), 1);
492 EXPECT_NEAR(gap3
, min_dock_gap(), 1);
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());
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();
515 EXPECT_NEAR(gap2
, min_dock_gap(), 1);
516 EXPECT_NEAR(gap3
, min_dock_gap(), 1);
520 // Adds three windows in bottom display and tests layout after a drag.
521 TEST_P(DockedWindowLayoutManagerTest
, ThreeWindowsDraggingSecondScreen
) {
522 if (!SupportsMultipleDisplays() || !SupportsHostWindowResize())
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();
560 EXPECT_NEAR(gap2
, min_dock_gap(), 1);
561 EXPECT_NEAR(gap3
, min_dock_gap(), 1);
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());
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();
584 EXPECT_NEAR(gap2
, min_dock_gap(), 1);
585 EXPECT_NEAR(gap3
, min_dock_gap(), 1);
589 // Tests that a second window added to the dock is resized to match.
590 TEST_P(DockedWindowLayoutManagerTest
, TwoWindowsWidthNew
) {
591 if (!SupportsHostWindowResize())
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())
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())
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())
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())
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(),
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())
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())
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(),
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(),
769 // Docks two windows and tests that restrictions on vertical size are honored.
770 TEST_P(DockedWindowLayoutManagerTest
, TwoWindowsHeightRestrictions
) {
771 if (!SupportsHostWindowResize())
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())
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
));