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/session_state_delegate.h"
10 #include "ash/shell.h"
11 #include "ash/shell_window_ids.h"
12 #include "ash/test/ash_test_base.h"
13 #include "ash/test/test_shell_delegate.h"
14 #include "ash/wm/window_cycle_list.h"
15 #include "ash/wm/window_state.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/root_window.h"
22 #include "ui/aura/test/test_windows.h"
23 #include "ui/aura/window.h"
24 #include "ui/gfx/rect.h"
25 #include "ui/gfx/screen.h"
31 using aura::test::CreateTestWindowWithId
;
32 using aura::test::TestWindowDelegate
;
35 typedef test::AshTestBase WindowCycleControllerTest
;
37 TEST_F(WindowCycleControllerTest
, HandleCycleWindowBaseCases
) {
38 WindowCycleController
* controller
=
39 Shell::GetInstance()->window_cycle_controller();
41 // Cycling doesn't crash if there are no windows.
42 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
44 // Create a single test window.
45 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
46 wm::ActivateWindow(window0
.get());
47 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
49 // Cycling works for a single window, even though nothing changes.
50 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
51 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
54 // Verifies if there is only one window and it isn't active that cycling
56 TEST_F(WindowCycleControllerTest
, SingleWindowNotActive
) {
57 WindowCycleController
* controller
=
58 Shell::GetInstance()->window_cycle_controller();
60 // Create a single test window.
61 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
62 wm::ActivateWindow(window0
.get());
63 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
65 // Rotate focus, this should move focus to another window that isn't part of
66 // the default container.
67 Shell::GetInstance()->RotateFocus(Shell::FORWARD
);
68 EXPECT_FALSE(wm::IsActiveWindow(window0
.get()));
70 // Cycling should activate the window.
71 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
72 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
75 TEST_F(WindowCycleControllerTest
, HandleCycleWindow
) {
76 WindowCycleController
* controller
=
77 Shell::GetInstance()->window_cycle_controller();
79 // Set up several windows to use to test cycling. Create them in reverse
80 // order so they are stacked 0 over 1 over 2.
81 scoped_ptr
<Window
> window2(CreateTestWindowInShellWithId(2));
82 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
83 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
84 wm::ActivateWindow(window0
.get());
86 // Simulate pressing and releasing Alt-tab.
87 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
88 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
90 // Window lists should return the topmost window in front.
91 ASSERT_TRUE(controller
->windows());
92 ASSERT_EQ(3u, controller
->windows()->windows().size());
93 ASSERT_EQ(window0
.get(), controller
->windows()->windows()[0]);
94 ASSERT_EQ(window1
.get(), controller
->windows()->windows()[1]);
95 ASSERT_EQ(window2
.get(), controller
->windows()->windows()[2]);
97 controller
->AltKeyReleased();
98 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
100 // Pressing and releasing Alt-tab again should cycle back to the most-
101 // recently-used window in the current child order.
102 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
103 controller
->AltKeyReleased();
104 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
106 // Pressing Alt-tab multiple times without releasing Alt should cycle through
107 // all the windows and wrap around.
108 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
109 EXPECT_TRUE(controller
->IsCycling());
110 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
112 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
113 EXPECT_TRUE(controller
->IsCycling());
114 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
116 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
117 EXPECT_TRUE(controller
->IsCycling());
118 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
120 controller
->AltKeyReleased();
121 EXPECT_FALSE(controller
->IsCycling());
122 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
124 // Reset our stacking order.
125 wm::ActivateWindow(window2
.get());
126 wm::ActivateWindow(window1
.get());
127 wm::ActivateWindow(window0
.get());
129 // Likewise we can cycle backwards through all the windows.
130 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, true);
131 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
132 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, true);
133 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
134 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, true);
135 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
136 controller
->AltKeyReleased();
137 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
139 // Passing false for is_alt_down does not start a cycle gesture.
140 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
141 EXPECT_FALSE(controller
->IsCycling());
142 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
144 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
145 EXPECT_FALSE(controller
->IsCycling());
146 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
148 // When the screen is locked, cycling window does not take effect.
149 Shell::GetInstance()->session_state_delegate()->LockScreen();
150 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
151 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
152 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
153 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, false);
154 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
156 Shell::GetInstance()->session_state_delegate()->UnlockScreen();
157 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
158 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
159 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
160 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
161 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
163 // When a modal window is active, cycling window does not take effect.
164 aura::Window
* modal_container
=
165 ash::Shell::GetContainer(
166 Shell::GetPrimaryRootWindow(),
167 internal::kShellWindowId_SystemModalContainer
);
168 scoped_ptr
<Window
> modal_window(
169 CreateTestWindowWithId(-2, modal_container
));
170 modal_window
->SetProperty(aura::client::kModalKey
, ui::MODAL_TYPE_SYSTEM
);
171 wm::ActivateWindow(modal_window
.get());
172 EXPECT_TRUE(wm::IsActiveWindow(modal_window
.get()));
173 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
174 EXPECT_TRUE(wm::IsActiveWindow(modal_window
.get()));
175 EXPECT_FALSE(wm::IsActiveWindow(window0
.get()));
176 EXPECT_FALSE(wm::IsActiveWindow(window1
.get()));
177 EXPECT_FALSE(wm::IsActiveWindow(window2
.get()));
178 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, false);
179 EXPECT_TRUE(wm::IsActiveWindow(modal_window
.get()));
180 EXPECT_FALSE(wm::IsActiveWindow(window0
.get()));
181 EXPECT_FALSE(wm::IsActiveWindow(window1
.get()));
182 EXPECT_FALSE(wm::IsActiveWindow(window2
.get()));
185 // Cycles between a maximized and normal window.
186 TEST_F(WindowCycleControllerTest
, MaximizedWindow
) {
187 // Create a couple of test windows.
188 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
189 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
190 wm::WindowState
* window1_state
= wm::GetWindowState(window1
.get());
191 window1_state
->Maximize();
192 window1_state
->Activate();
193 EXPECT_TRUE(window1_state
->IsActive());
195 // Rotate focus, this should move focus to window0.
196 WindowCycleController
* controller
=
197 Shell::GetInstance()->window_cycle_controller();
198 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
199 EXPECT_TRUE(wm::GetWindowState(window0
.get())->IsActive());
202 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
203 EXPECT_TRUE(window1_state
->IsActive());
206 // Cycles to a minimized window.
207 TEST_F(WindowCycleControllerTest
, Minimized
) {
208 // Create a couple of test windows.
209 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
210 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
211 wm::WindowState
* window0_state
= wm::GetWindowState(window0
.get());
212 wm::WindowState
* window1_state
= wm::GetWindowState(window1
.get());
214 window1_state
->Minimize();
215 window0_state
->Activate();
216 EXPECT_TRUE(window0_state
->IsActive());
218 // Rotate focus, this should move focus to window1 and unminimize it.
219 WindowCycleController
* controller
=
220 Shell::GetInstance()->window_cycle_controller();
221 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
222 EXPECT_FALSE(window1_state
->IsMinimized());
223 EXPECT_TRUE(window1_state
->IsActive());
225 // One more time back to w0.
226 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
227 EXPECT_TRUE(window0_state
->IsActive());
230 TEST_F(WindowCycleControllerTest
, AlwaysOnTopWindow
) {
231 WindowCycleController
* controller
=
232 Shell::GetInstance()->window_cycle_controller();
234 // Set up several windows to use to test cycling.
235 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
236 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
238 Window
* top_container
=
240 Shell::GetPrimaryRootWindow(),
241 internal::kShellWindowId_AlwaysOnTopContainer
);
242 scoped_ptr
<Window
> window2(CreateTestWindowWithId(2, top_container
));
243 wm::ActivateWindow(window0
.get());
245 // Simulate pressing and releasing Alt-tab.
246 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
247 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
249 // Window lists should return the topmost window in front.
250 ASSERT_TRUE(controller
->windows());
251 ASSERT_EQ(3u, controller
->windows()->windows().size());
252 EXPECT_EQ(window0
.get(), controller
->windows()->windows()[0]);
253 EXPECT_EQ(window2
.get(), controller
->windows()->windows()[1]);
254 EXPECT_EQ(window1
.get(), controller
->windows()->windows()[2]);
256 controller
->AltKeyReleased();
257 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
259 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
260 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
262 controller
->AltKeyReleased();
264 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
265 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
267 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
268 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
270 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
271 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
274 TEST_F(WindowCycleControllerTest
, AlwaysOnTopMultiWindow
) {
275 WindowCycleController
* controller
=
276 Shell::GetInstance()->window_cycle_controller();
278 // Set up several windows to use to test cycling.
279 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
280 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
282 Window
* top_container
=
284 Shell::GetPrimaryRootWindow(),
285 internal::kShellWindowId_AlwaysOnTopContainer
);
286 scoped_ptr
<Window
> window2(CreateTestWindowWithId(2, top_container
));
287 scoped_ptr
<Window
> window3(CreateTestWindowWithId(3, top_container
));
288 wm::ActivateWindow(window0
.get());
290 // Simulate pressing and releasing Alt-tab.
291 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
292 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
294 // Window lists should return the topmost window in front.
295 ASSERT_TRUE(controller
->windows());
296 ASSERT_EQ(4u, controller
->windows()->windows().size());
297 EXPECT_EQ(window0
.get(), controller
->windows()->windows()[0]);
298 EXPECT_EQ(window3
.get(), controller
->windows()->windows()[1]);
299 EXPECT_EQ(window2
.get(), controller
->windows()->windows()[2]);
300 EXPECT_EQ(window1
.get(), controller
->windows()->windows()[3]);
302 controller
->AltKeyReleased();
303 EXPECT_TRUE(wm::IsActiveWindow(window3
.get()));
305 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
306 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
308 controller
->AltKeyReleased();
310 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
311 EXPECT_TRUE(wm::IsActiveWindow(window3
.get()));
313 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
314 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
316 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
317 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
319 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
320 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
323 TEST_F(WindowCycleControllerTest
, AlwaysOnTopMultipleRootWindows
) {
324 if (!SupportsMultipleDisplays())
327 // Set up a second root window
328 UpdateDisplay("1000x600,600x400");
329 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
330 ASSERT_EQ(2U, root_windows
.size());
332 WindowCycleController
* controller
=
333 Shell::GetInstance()->window_cycle_controller();
335 Shell::GetInstance()->set_target_root_window(root_windows
[0]);
337 // Create two windows in the primary root.
338 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
339 EXPECT_EQ(root_windows
[0], window0
->GetRootWindow());
340 Window
* top_container0
=
343 internal::kShellWindowId_AlwaysOnTopContainer
);
344 scoped_ptr
<Window
> window1(CreateTestWindowWithId(1, top_container0
));
345 EXPECT_EQ(root_windows
[0], window1
->GetRootWindow());
347 // And two on the secondary root.
348 Shell::GetInstance()->set_target_root_window(root_windows
[1]);
349 scoped_ptr
<Window
> window2(CreateTestWindowInShellWithId(2));
350 EXPECT_EQ(root_windows
[1], window2
->GetRootWindow());
352 Window
* top_container1
=
355 internal::kShellWindowId_AlwaysOnTopContainer
);
356 scoped_ptr
<Window
> window3(CreateTestWindowWithId(3, top_container1
));
357 EXPECT_EQ(root_windows
[1], window3
->GetRootWindow());
359 // Move the active root window to the secondary.
360 Shell::GetInstance()->set_target_root_window(root_windows
[1]);
362 wm::ActivateWindow(window2
.get());
364 EXPECT_EQ(root_windows
[0], window0
->GetRootWindow());
365 EXPECT_EQ(root_windows
[0], window1
->GetRootWindow());
366 EXPECT_EQ(root_windows
[1], window2
->GetRootWindow());
367 EXPECT_EQ(root_windows
[1], window3
->GetRootWindow());
369 // Simulate pressing and releasing Alt-tab.
370 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
371 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
373 // Window lists should return the topmost window in front.
374 ASSERT_TRUE(controller
->windows());
375 ASSERT_EQ(4u, controller
->windows()->windows().size());
376 EXPECT_EQ(window2
.get(), controller
->windows()->windows()[0]);
377 EXPECT_EQ(window3
.get(), controller
->windows()->windows()[1]);
378 EXPECT_EQ(window1
.get(), controller
->windows()->windows()[2]);
379 EXPECT_EQ(window0
.get(), controller
->windows()->windows()[3]);
381 controller
->AltKeyReleased();
382 EXPECT_TRUE(wm::IsActiveWindow(window3
.get()));
384 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
385 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
387 controller
->AltKeyReleased();
389 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
390 EXPECT_TRUE(wm::IsActiveWindow(window3
.get()));
392 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
393 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
395 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
396 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
398 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
399 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
402 TEST_F(WindowCycleControllerTest
, MostRecentlyUsed
) {
403 WindowCycleController
* controller
=
404 Shell::GetInstance()->window_cycle_controller();
406 // Set up several windows to use to test cycling.
407 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
408 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
409 scoped_ptr
<Window
> window2(CreateTestWindowInShellWithId(2));
411 wm::ActivateWindow(window0
.get());
413 // Simulate pressing and releasing Alt-tab.
414 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
415 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
417 // Window lists should return the topmost window in front.
418 ASSERT_TRUE(controller
->windows());
419 ASSERT_EQ(3u, controller
->windows()->windows().size());
420 EXPECT_EQ(window0
.get(), controller
->windows()->windows()[0]);
421 EXPECT_EQ(window2
.get(), controller
->windows()->windows()[1]);
422 EXPECT_EQ(window1
.get(), controller
->windows()->windows()[2]);
424 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
425 controller
->AltKeyReleased();
426 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
429 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
430 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
432 controller
->AltKeyReleased();
434 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
435 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
437 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
438 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
440 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
441 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));