Disable TabDragController tests that fail with a real compositor.
[chromium-blink-merge.git] / ash / wm / solo_window_tracker_unittest.cc
blob25a8d2140861786a432ca86bad487831d0bcf83b
1 // Copyright 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/solo_window_tracker.h"
7 #include "ash/ash_constants.h"
8 #include "ash/ash_switches.h"
9 #include "ash/root_window_controller.h"
10 #include "ash/screen_ash.h"
11 #include "ash/shell.h"
12 #include "ash/shell_window_ids.h"
13 #include "ash/test/ash_test_base.h"
14 #include "ash/wm/window_resizer.h"
15 #include "ash/wm/window_state.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "ui/aura/client/aura_constants.h"
18 #include "ui/aura/root_window.h"
19 #include "ui/aura/test/event_generator.h"
20 #include "ui/aura/window.h"
21 #include "ui/aura/window_observer.h"
22 #include "ui/base/hit_test.h"
23 #include "ui/gfx/screen.h"
25 namespace ash {
27 namespace {
29 class WindowRepaintChecker : public aura::WindowObserver {
30 public:
31 explicit WindowRepaintChecker(aura::Window* window)
32 : window_(window),
33 is_paint_scheduled_(false) {
34 window_->AddObserver(this);
37 virtual ~WindowRepaintChecker() {
38 if (window_)
39 window_->RemoveObserver(this);
42 bool IsPaintScheduledAndReset() {
43 bool result = is_paint_scheduled_;
44 is_paint_scheduled_ = false;
45 return result;
48 private:
49 // aura::WindowObserver overrides:
50 virtual void OnWindowPaintScheduled(aura::Window* window,
51 const gfx::Rect& region) OVERRIDE {
52 is_paint_scheduled_ = true;
54 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
55 DCHECK_EQ(window_, window);
56 window_ = NULL;
59 aura::Window* window_;
60 bool is_paint_scheduled_;
62 DISALLOW_COPY_AND_ASSIGN(WindowRepaintChecker);
65 } // namespace
67 class SoloWindowTrackerTest : public test::AshTestBase {
68 public:
69 SoloWindowTrackerTest() {
71 virtual ~SoloWindowTrackerTest() {
74 // Helpers methods to create test windows in the primary root window.
75 aura::Window* CreateWindowInPrimary() {
76 aura::Window* window = new aura::Window(NULL);
77 window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
78 window->Init(aura::WINDOW_LAYER_TEXTURED);
79 window->SetBounds(gfx::Rect(100, 100));
80 ParentWindowInPrimaryRootWindow(window);
81 return window;
83 aura::Window* CreateAlwaysOnTopWindowInPrimary() {
84 aura::Window* window = new aura::Window(NULL);
85 window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
86 window->Init(aura::WINDOW_LAYER_TEXTURED);
87 window->SetBounds(gfx::Rect(100, 100));
88 window->SetProperty(aura::client::kAlwaysOnTopKey, true);
89 ParentWindowInPrimaryRootWindow(window);
90 return window;
92 aura::Window* CreatePanelWindowInPrimary() {
93 aura::Window* window = new aura::Window(NULL);
94 window->SetType(ui::wm::WINDOW_TYPE_PANEL);
95 window->Init(aura::WINDOW_LAYER_TEXTURED);
96 window->SetBounds(gfx::Rect(100, 100));
97 ParentWindowInPrimaryRootWindow(window);
98 return window;
101 // Drag |window| to the dock.
102 void DockWindow(aura::Window* window) {
103 // Because the tests use windows without delegates,
104 // aura::test::EventGenerator cannot be used.
105 gfx::Point drag_to =
106 ash::ScreenUtil::GetDisplayBoundsInParent(window).top_right();
107 scoped_ptr<WindowResizer> resizer(CreateWindowResizer(
108 window,
109 window->bounds().origin(),
110 HTCAPTION,
111 aura::client::WINDOW_MOVE_SOURCE_MOUSE));
112 resizer->Drag(drag_to, 0);
113 resizer->CompleteDrag();
114 EXPECT_EQ(internal::kShellWindowId_DockedContainer,
115 window->parent()->id());
118 // Drag |window| out of the dock.
119 void UndockWindow(aura::Window* window) {
120 gfx::Point drag_to =
121 ash::ScreenUtil::GetDisplayWorkAreaBoundsInParent(window).top_right() -
122 gfx::Vector2d(10, 0);
123 scoped_ptr<WindowResizer> resizer(CreateWindowResizer(
124 window,
125 window->bounds().origin(),
126 HTCAPTION,
127 aura::client::WINDOW_MOVE_SOURCE_MOUSE));
128 resizer->Drag(drag_to, 0);
129 resizer->CompleteDrag();
130 EXPECT_NE(internal::kShellWindowId_DockedContainer,
131 window->parent()->id());
134 // Returns the primary display.
135 gfx::Display GetPrimaryDisplay() {
136 return ash::Shell::GetInstance()->GetScreen()->GetPrimaryDisplay();
139 // Returns the secondary display.
140 gfx::Display GetSecondaryDisplay() {
141 return ScreenUtil::GetSecondaryDisplay();
144 // Returns the window which uses the solo header, if any, on the primary
145 // display.
146 aura::Window* GetWindowWithSoloHeaderInPrimary() {
147 return GetWindowWithSoloHeader(Shell::GetPrimaryRootWindow());
150 // Returns the window which uses the solo header, if any, in |root|.
151 aura::Window* GetWindowWithSoloHeader(aura::Window* root) {
152 SoloWindowTracker* solo_window_tracker =
153 internal::GetRootWindowController(root)->solo_window_tracker();
154 return solo_window_tracker ?
155 solo_window_tracker->GetWindowWithSoloHeader() : NULL;
158 private:
159 DISALLOW_COPY_AND_ASSIGN(SoloWindowTrackerTest);
162 TEST_F(SoloWindowTrackerTest, Basic) {
163 scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
164 w1->Show();
166 // We only have one window, so it should use a solo header.
167 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
169 // Create a second window.
170 scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
171 w2->Show();
173 // Now there are two windows, so we should not use solo headers.
174 EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
176 // Hide one window. Solo should be enabled.
177 w2->Hide();
178 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
180 // Show that window. Solo should be disabled.
181 w2->Show();
182 EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
184 // Minimize the first window. Solo should be enabled.
185 wm::GetWindowState(w1.get())->Minimize();
186 EXPECT_EQ(w2.get(), GetWindowWithSoloHeaderInPrimary());
188 // Close the minimized window.
189 w1.reset();
190 EXPECT_EQ(w2.get(), GetWindowWithSoloHeaderInPrimary());
192 // Open an always-on-top window (which lives in a different container).
193 scoped_ptr<aura::Window> w3(CreateAlwaysOnTopWindowInPrimary());
194 w3->Show();
195 EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
197 // Close the always-on-top window.
198 w3.reset();
199 EXPECT_EQ(w2.get(), GetWindowWithSoloHeaderInPrimary());
202 // Test that docked windows never use the solo header and that the presence of a
203 // docked window prevents all other windows from the using the solo window
204 // header.
205 TEST_F(SoloWindowTrackerTest, DockedWindow) {
206 if (!switches::UseDockedWindows() || !SupportsHostWindowResize())
207 return;
209 scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
210 w1->Show();
211 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
213 DockWindow(w1.get());
214 EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
216 UndockWindow(w1.get());
217 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
219 scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
220 w2->Show();
221 EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
223 DockWindow(w2.get());
224 EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
226 wm::GetWindowState(w2.get())->Minimize();
227 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
230 // Panels should not "count" for computing solo window headers, and the panel
231 // itself should never use the solo header.
232 TEST_F(SoloWindowTrackerTest, Panel) {
233 scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
234 w1->Show();
236 // We only have one window, so it should use a solo header.
237 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
239 // Create a panel window.
240 scoped_ptr<aura::Window> w2(CreatePanelWindowInPrimary());
241 w2->Show();
243 // Despite two windows, the first window should still be considered "solo"
244 // because panels aren't included in the computation.
245 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
247 // Even after closing the first window, the panel is still not considered
248 // solo.
249 w1.reset();
250 EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
253 // Modal dialogs should not use solo headers.
254 TEST_F(SoloWindowTrackerTest, Modal) {
255 scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
256 w1->Show();
258 // We only have one window, so it should use a solo header.
259 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
261 // Create a fake modal window.
262 scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
263 w2->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
264 w2->Show();
266 // Despite two windows, the first window should still be considered "solo"
267 // because modal windows aren't included in the computation.
268 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
271 // Constrained windows should not use solo headers.
272 TEST_F(SoloWindowTrackerTest, Constrained) {
273 scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
274 w1->Show();
276 // We only have one window, so it should use a solo header.
277 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
279 // Create a fake constrained window.
280 scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
281 w2->SetProperty(aura::client::kConstrainedWindowKey, true);
282 w2->Show();
284 // Despite two windows, the first window should still be considered "solo"
285 // because constrained windows aren't included in the computation.
286 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
289 // Non-drawing windows should not affect the solo computation.
290 TEST_F(SoloWindowTrackerTest, NotDrawn) {
291 aura::Window* w = CreateWindowInPrimary();
292 w->Show();
294 // We only have one window, so it should use a solo header.
295 EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
297 // Create non-drawing window similar to DragDropTracker.
298 aura::Window* not_drawn = new aura::Window(NULL);
299 not_drawn->SetType(ui::wm::WINDOW_TYPE_NORMAL);
300 not_drawn->Init(aura::WINDOW_LAYER_NOT_DRAWN);
301 ParentWindowInPrimaryRootWindow(not_drawn);
302 not_drawn->Show();
304 // Despite two windows, the first window should still be considered "solo"
305 // because non-drawing windows aren't included in the computation.
306 EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
309 TEST_F(SoloWindowTrackerTest, MultiDisplay) {
310 if (!SupportsMultipleDisplays())
311 return;
313 UpdateDisplay("1000x600,600x400");
315 scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
316 w1->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
317 w1->Show();
318 WindowRepaintChecker checker1(w1.get());
319 scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
320 w2->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
321 w2->Show();
322 WindowRepaintChecker checker2(w2.get());
324 // Now there are two windows in the same display, so we should not use solo
325 // headers.
326 EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
327 EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
329 // Moves the second window to the secondary display. Both w1/w2 should be
330 // solo.
331 w2->SetBoundsInScreen(gfx::Rect(1200, 0, 100, 100),
332 ScreenUtil::GetSecondaryDisplay());
333 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
334 EXPECT_EQ(w2.get(), GetWindowWithSoloHeader(w2->GetRootWindow()));
335 EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
336 EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
338 // Open two more windows in the primary display.
339 scoped_ptr<aura::Window> w3(CreateWindowInPrimary());
340 w3->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
341 w3->Show();
342 scoped_ptr<aura::Window> w4(CreateWindowInPrimary());
343 w4->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
344 w4->Show();
346 // Because the primary display has three windows w1, w3, and w4, they
347 // shouldn't be solo. w2 should be solo.
348 EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
349 EXPECT_EQ(w2.get(), GetWindowWithSoloHeader(w2->GetRootWindow()));
350 EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
352 // Move w4 to the secondary display. Now w2 shouldn't be solo anymore.
353 w4->SetBoundsInScreen(gfx::Rect(1200, 0, 100, 100), GetSecondaryDisplay());
354 EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
355 EXPECT_EQ(NULL, GetWindowWithSoloHeader(w2->GetRootWindow()));
356 EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
358 // Moves w3 to the secondary display too. Now w1 should be solo again.
359 w3->SetBoundsInScreen(gfx::Rect(1200, 0, 100, 100), GetSecondaryDisplay());
360 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
361 EXPECT_EQ(NULL, GetWindowWithSoloHeader(w2->GetRootWindow()));
362 EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
364 // Change w3's state to maximize. Doesn't affect w1.
365 wm::GetWindowState(w3.get())->Maximize();
366 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
367 EXPECT_EQ(NULL, GetWindowWithSoloHeader(w2->GetRootWindow()));
369 // Close w3 and w4.
370 w3.reset();
371 w4.reset();
372 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
373 EXPECT_EQ(w2.get(), GetWindowWithSoloHeader(w2->GetRootWindow()));
374 EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
376 // Move w2 back to the primary display.
377 w2->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
378 EXPECT_EQ(w1->GetRootWindow(), w2->GetRootWindow());
379 EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
380 EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
381 EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
383 // Close w2.
384 w2.reset();
385 EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
386 EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
389 TEST_F(SoloWindowTrackerTest, ChildWindowVisibility) {
390 aura::Window* w = CreateWindowInPrimary();
391 w->Show();
393 // We only have one window, so it should use a solo header.
394 EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
396 // Create a child window. This should not affect the solo-ness of |w1|.
397 aura::Window* child = new aura::Window(NULL);
398 child->SetType(ui::wm::WINDOW_TYPE_CONTROL);
399 child->Init(aura::WINDOW_LAYER_TEXTURED);
400 child->SetBounds(gfx::Rect(100, 100));
401 w->AddChild(child);
402 child->Show();
403 EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
405 // Changing the visibility of |child| should not affect the solo-ness of |w1|.
406 child->Hide();
407 EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
410 TEST_F(SoloWindowTrackerTest, CreateAndDeleteSingleWindow) {
411 // Ensure that creating/deleting a window works well and doesn't cause
412 // crashes. See crbug.com/155634
413 scoped_ptr<aura::Window> w(CreateWindowInPrimary());
414 w->Show();
416 // We only have one window, so it should use a solo header.
417 EXPECT_EQ(w.get(), GetWindowWithSoloHeaderInPrimary());
419 // Close the window.
420 w.reset();
421 EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
423 // Recreate another window again.
424 w.reset(CreateWindowInPrimary());
425 w->Show();
426 EXPECT_EQ(w.get(), GetWindowWithSoloHeaderInPrimary());
429 } // namespace ash