1 // Copyright (c) 2012 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/window_cycle_controller.h"
9 #include "ash/display/display_controller.h"
10 #include "ash/display/display_manager.h"
11 #include "ash/shell.h"
12 #include "ash/shell_window_ids.h"
13 #include "ash/test/ash_test_base.h"
14 #include "ash/test/test_shell_delegate.h"
15 #include "ash/wm/window_cycle_list.h"
16 #include "ash/wm/window_util.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "ui/aura/client/aura_constants.h"
19 #include "ui/aura/client/screen_position_client.h"
20 #include "ui/aura/env.h"
21 #include "ui/aura/test/test_windows.h"
22 #include "ui/aura/window.h"
23 #include "ui/gfx/rect.h"
24 #include "ui/gfx/screen.h"
30 using aura::test::CreateTestWindowWithId
;
31 using aura::test::TestWindowDelegate
;
34 typedef test::AshTestBase WindowCycleControllerTest
;
36 TEST_F(WindowCycleControllerTest
, HandleCycleWindowBaseCases
) {
37 WindowCycleController
* controller
=
38 Shell::GetInstance()->window_cycle_controller();
40 // Cycling doesn't crash if there are no windows.
41 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
43 // Create a single test window.
44 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
45 wm::ActivateWindow(window0
.get());
46 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
48 // Cycling works for a single window, even though nothing changes.
49 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
50 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
53 // Verifies if there is only one window and it isn't active that cycling
55 TEST_F(WindowCycleControllerTest
, SingleWindowNotActive
) {
56 WindowCycleController
* controller
=
57 Shell::GetInstance()->window_cycle_controller();
59 // Create a single test window.
60 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
61 wm::ActivateWindow(window0
.get());
62 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
64 // Rotate focus, this should move focus to another window that isn't part of
65 // the default container.
66 Shell::GetInstance()->RotateFocus(Shell::FORWARD
);
67 EXPECT_FALSE(wm::IsActiveWindow(window0
.get()));
69 // Cycling should activate the window.
70 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
71 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
74 TEST_F(WindowCycleControllerTest
, HandleCycleWindow
) {
75 WindowCycleController
* controller
=
76 Shell::GetInstance()->window_cycle_controller();
78 // Set up several windows to use to test cycling. Create them in reverse
79 // order so they are stacked 0 over 1 over 2.
80 scoped_ptr
<Window
> window2(CreateTestWindowInShellWithId(2));
81 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
82 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
83 wm::ActivateWindow(window0
.get());
85 // Simulate pressing and releasing Alt-tab.
86 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
87 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
89 // Window lists should return the topmost window in front.
90 ASSERT_TRUE(controller
->windows());
91 ASSERT_EQ(3u, controller
->windows()->windows().size());
92 ASSERT_EQ(window0
.get(), controller
->windows()->windows()[0]);
93 ASSERT_EQ(window1
.get(), controller
->windows()->windows()[1]);
94 ASSERT_EQ(window2
.get(), controller
->windows()->windows()[2]);
96 controller
->AltKeyReleased();
97 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
99 // Pressing and releasing Alt-tab again should cycle back to the most-
100 // recently-used window in the current child order.
101 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
102 controller
->AltKeyReleased();
103 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
105 // Pressing Alt-tab multiple times without releasing Alt should cycle through
106 // all the windows and wrap around.
107 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
108 EXPECT_TRUE(controller
->IsCycling());
109 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
111 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
112 EXPECT_TRUE(controller
->IsCycling());
113 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
115 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
116 EXPECT_TRUE(controller
->IsCycling());
117 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
119 controller
->AltKeyReleased();
120 EXPECT_FALSE(controller
->IsCycling());
121 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
123 // Reset our stacking order.
124 wm::ActivateWindow(window2
.get());
125 wm::ActivateWindow(window1
.get());
126 wm::ActivateWindow(window0
.get());
128 // Likewise we can cycle backwards through all the windows.
129 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, true);
130 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
131 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, true);
132 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
133 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, true);
134 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
135 controller
->AltKeyReleased();
136 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
138 // Passing false for is_alt_down does not start a cycle gesture.
139 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
140 EXPECT_FALSE(controller
->IsCycling());
141 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
143 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
144 EXPECT_FALSE(controller
->IsCycling());
145 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
147 // When the screen is locked, cycling window does not take effect.
148 Shell::GetInstance()->delegate()->LockScreen();
149 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
150 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
151 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
152 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, false);
153 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
155 Shell::GetInstance()->delegate()->UnlockScreen();
156 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
157 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
158 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
159 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
160 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
162 // When a modal window is active, cycling window does not take effect.
163 aura::Window
* modal_container
=
164 ash::Shell::GetContainer(
165 Shell::GetPrimaryRootWindow(),
166 internal::kShellWindowId_SystemModalContainer
);
167 scoped_ptr
<Window
> modal_window(
168 CreateTestWindowWithId(-2, modal_container
));
169 modal_window
->SetProperty(aura::client::kModalKey
, ui::MODAL_TYPE_SYSTEM
);
170 wm::ActivateWindow(modal_window
.get());
171 EXPECT_TRUE(wm::IsActiveWindow(modal_window
.get()));
172 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
173 EXPECT_TRUE(wm::IsActiveWindow(modal_window
.get()));
174 EXPECT_FALSE(wm::IsActiveWindow(window0
.get()));
175 EXPECT_FALSE(wm::IsActiveWindow(window1
.get()));
176 EXPECT_FALSE(wm::IsActiveWindow(window2
.get()));
177 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, false);
178 EXPECT_TRUE(wm::IsActiveWindow(modal_window
.get()));
179 EXPECT_FALSE(wm::IsActiveWindow(window0
.get()));
180 EXPECT_FALSE(wm::IsActiveWindow(window1
.get()));
181 EXPECT_FALSE(wm::IsActiveWindow(window2
.get()));
184 // Cycles between a maximized and normal window.
185 TEST_F(WindowCycleControllerTest
, MaximizedWindow
) {
186 // Create a couple of test windows.
187 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
188 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
190 wm::MaximizeWindow(window1
.get());
191 wm::ActivateWindow(window1
.get());
192 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
194 // Rotate focus, this should move focus to window0.
195 WindowCycleController
* controller
=
196 Shell::GetInstance()->window_cycle_controller();
197 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
198 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
201 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
202 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
205 // Cycles to a minimized window.
206 TEST_F(WindowCycleControllerTest
, Minimized
) {
207 // Create a couple of test windows.
208 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
209 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
211 wm::MinimizeWindow(window1
.get());
212 wm::ActivateWindow(window0
.get());
213 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
215 // Rotate focus, this should move focus to window1 and unminimize it.
216 WindowCycleController
* controller
=
217 Shell::GetInstance()->window_cycle_controller();
218 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
219 EXPECT_FALSE(wm::IsWindowMinimized(window1
.get()));
220 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
222 // One more time back to w0.
223 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
224 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
227 TEST_F(WindowCycleControllerTest
, AlwaysOnTopWindow
) {
228 WindowCycleController
* controller
=
229 Shell::GetInstance()->window_cycle_controller();
231 // Set up several windows to use to test cycling.
232 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
233 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
235 Window
* top_container
=
237 Shell::GetPrimaryRootWindow(),
238 internal::kShellWindowId_AlwaysOnTopContainer
);
239 scoped_ptr
<Window
> window2(CreateTestWindowWithId(2, top_container
));
240 wm::ActivateWindow(window0
.get());
242 // Simulate pressing and releasing Alt-tab.
243 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
244 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
246 // Window lists should return the topmost window in front.
247 ASSERT_TRUE(controller
->windows());
248 ASSERT_EQ(3u, controller
->windows()->windows().size());
249 EXPECT_EQ(window0
.get(), controller
->windows()->windows()[0]);
250 EXPECT_EQ(window2
.get(), controller
->windows()->windows()[1]);
251 EXPECT_EQ(window1
.get(), controller
->windows()->windows()[2]);
253 controller
->AltKeyReleased();
254 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
256 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
257 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
259 controller
->AltKeyReleased();
261 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
262 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
264 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
265 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
267 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
268 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
271 TEST_F(WindowCycleControllerTest
, AlwaysOnTopMultiWindow
) {
272 WindowCycleController
* controller
=
273 Shell::GetInstance()->window_cycle_controller();
275 // Set up several windows to use to test cycling.
276 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
277 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
279 Window
* top_container
=
281 Shell::GetPrimaryRootWindow(),
282 internal::kShellWindowId_AlwaysOnTopContainer
);
283 scoped_ptr
<Window
> window2(CreateTestWindowWithId(2, top_container
));
284 scoped_ptr
<Window
> window3(CreateTestWindowWithId(3, top_container
));
285 wm::ActivateWindow(window0
.get());
287 // Simulate pressing and releasing Alt-tab.
288 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
289 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
291 // Window lists should return the topmost window in front.
292 ASSERT_TRUE(controller
->windows());
293 ASSERT_EQ(4u, controller
->windows()->windows().size());
294 EXPECT_EQ(window0
.get(), controller
->windows()->windows()[0]);
295 EXPECT_EQ(window3
.get(), controller
->windows()->windows()[1]);
296 EXPECT_EQ(window2
.get(), controller
->windows()->windows()[2]);
297 EXPECT_EQ(window1
.get(), controller
->windows()->windows()[3]);
299 controller
->AltKeyReleased();
300 EXPECT_TRUE(wm::IsActiveWindow(window3
.get()));
302 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
303 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
305 controller
->AltKeyReleased();
307 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
308 EXPECT_TRUE(wm::IsActiveWindow(window3
.get()));
310 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
311 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
313 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
314 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
316 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
317 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
321 // Multiple displays are not supported on Windows Ash. http://crbug.com/165962
322 #define MAYBE_AlwaysOnTopMultipleRootWindows \
323 DISABLED_AlwaysOnTopMultipleRootWindows
325 #define MAYBE_AlwaysOnTopMultipleRootWindows \
326 AlwaysOnTopMultipleRootWindows
330 TEST_F(WindowCycleControllerTest
, MAYBE_AlwaysOnTopMultipleRootWindows
) {
331 // Set up a second root window
332 UpdateDisplay("1000x600,600x400");
333 Shell::RootWindowList root_windows
= Shell::GetAllRootWindows();
334 ASSERT_EQ(2U, root_windows
.size());
336 WindowCycleController
* controller
=
337 Shell::GetInstance()->window_cycle_controller();
339 Shell::GetInstance()->set_active_root_window(root_windows
[0]);
341 // Create two windows in the primary root.
342 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
343 EXPECT_EQ(root_windows
[0], window0
->GetRootWindow());
344 Window
* top_container0
=
347 internal::kShellWindowId_AlwaysOnTopContainer
);
348 scoped_ptr
<Window
> window1(CreateTestWindowWithId(1, top_container0
));
349 EXPECT_EQ(root_windows
[0], window1
->GetRootWindow());
351 // And two on the secondary root.
352 Shell::GetInstance()->set_active_root_window(root_windows
[1]);
353 scoped_ptr
<Window
> window2(CreateTestWindowInShellWithId(2));
354 EXPECT_EQ(root_windows
[1], window2
->GetRootWindow());
356 Window
* top_container1
=
359 internal::kShellWindowId_AlwaysOnTopContainer
);
360 scoped_ptr
<Window
> window3(CreateTestWindowWithId(3, top_container1
));
361 EXPECT_EQ(root_windows
[1], window3
->GetRootWindow());
363 // Move the active root window to the secondary.
364 Shell::GetInstance()->set_active_root_window(root_windows
[1]);
366 wm::ActivateWindow(window2
.get());
368 EXPECT_EQ(root_windows
[0], window0
->GetRootWindow());
369 EXPECT_EQ(root_windows
[0], window1
->GetRootWindow());
370 EXPECT_EQ(root_windows
[1], window2
->GetRootWindow());
371 EXPECT_EQ(root_windows
[1], window3
->GetRootWindow());
373 // Simulate pressing and releasing Alt-tab.
374 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
375 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
377 // Window lists should return the topmost window in front.
378 ASSERT_TRUE(controller
->windows());
379 ASSERT_EQ(4u, controller
->windows()->windows().size());
380 EXPECT_EQ(window2
.get(), controller
->windows()->windows()[0]);
381 EXPECT_EQ(window3
.get(), controller
->windows()->windows()[1]);
382 EXPECT_EQ(window1
.get(), controller
->windows()->windows()[2]);
383 EXPECT_EQ(window0
.get(), controller
->windows()->windows()[3]);
385 controller
->AltKeyReleased();
386 EXPECT_TRUE(wm::IsActiveWindow(window3
.get()));
388 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
389 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
391 controller
->AltKeyReleased();
393 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
394 EXPECT_TRUE(wm::IsActiveWindow(window3
.get()));
396 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
397 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
399 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
400 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
402 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
403 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
406 TEST_F(WindowCycleControllerTest
, MostRecentlyUsed
) {
407 WindowCycleController
* controller
=
408 Shell::GetInstance()->window_cycle_controller();
410 // Set up several windows to use to test cycling.
411 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
412 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
413 scoped_ptr
<Window
> window2(CreateTestWindowInShellWithId(2));
415 wm::ActivateWindow(window0
.get());
417 // Simulate pressing and releasing Alt-tab.
418 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
419 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
421 // Window lists should return the topmost window in front.
422 ASSERT_TRUE(controller
->windows());
423 ASSERT_EQ(3u, controller
->windows()->windows().size());
424 EXPECT_EQ(window0
.get(), controller
->windows()->windows()[0]);
425 EXPECT_EQ(window2
.get(), controller
->windows()->windows()[1]);
426 EXPECT_EQ(window1
.get(), controller
->windows()->windows()[2]);
428 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
429 controller
->AltKeyReleased();
430 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
433 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
434 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
436 controller
->AltKeyReleased();
438 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
439 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
441 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
442 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
444 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
445 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));