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