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_util.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "ui/aura/client/aura_constants.h"
18 #include "ui/aura/client/screen_position_client.h"
19 #include "ui/aura/env.h"
20 #include "ui/aura/test/test_windows.h"
21 #include "ui/aura/window.h"
22 #include "ui/gfx/rect.h"
23 #include "ui/gfx/screen.h"
29 using aura::test::CreateTestWindowWithId
;
30 using aura::test::TestWindowDelegate
;
33 typedef test::AshTestBase WindowCycleControllerTest
;
35 TEST_F(WindowCycleControllerTest
, HandleCycleWindowBaseCases
) {
36 WindowCycleController
* controller
=
37 Shell::GetInstance()->window_cycle_controller();
39 // Cycling doesn't crash if there are no windows.
40 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
42 // Create a single test window.
43 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
44 wm::ActivateWindow(window0
.get());
45 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
47 // Cycling works for a single window, even though nothing changes.
48 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
49 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
52 // Verifies if there is only one window and it isn't active that cycling
54 TEST_F(WindowCycleControllerTest
, SingleWindowNotActive
) {
55 WindowCycleController
* controller
=
56 Shell::GetInstance()->window_cycle_controller();
58 // Create a single test window.
59 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
60 wm::ActivateWindow(window0
.get());
61 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
63 // Rotate focus, this should move focus to another window that isn't part of
64 // the default container.
65 Shell::GetInstance()->RotateFocus(Shell::FORWARD
);
66 EXPECT_FALSE(wm::IsActiveWindow(window0
.get()));
68 // Cycling should activate the window.
69 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
70 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
73 TEST_F(WindowCycleControllerTest
, HandleCycleWindow
) {
74 WindowCycleController
* controller
=
75 Shell::GetInstance()->window_cycle_controller();
77 // Set up several windows to use to test cycling. Create them in reverse
78 // order so they are stacked 0 over 1 over 2.
79 scoped_ptr
<Window
> window2(CreateTestWindowInShellWithId(2));
80 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
81 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
82 wm::ActivateWindow(window0
.get());
84 // Simulate pressing and releasing Alt-tab.
85 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
86 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
88 // Window lists should return the topmost window in front.
89 ASSERT_TRUE(controller
->windows());
90 ASSERT_EQ(3u, controller
->windows()->windows().size());
91 ASSERT_EQ(window0
.get(), controller
->windows()->windows()[0]);
92 ASSERT_EQ(window1
.get(), controller
->windows()->windows()[1]);
93 ASSERT_EQ(window2
.get(), controller
->windows()->windows()[2]);
95 controller
->AltKeyReleased();
96 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
98 // Pressing and releasing Alt-tab again should cycle back to the most-
99 // recently-used window in the current child order.
100 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
101 controller
->AltKeyReleased();
102 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
104 // Pressing Alt-tab multiple times without releasing Alt should cycle through
105 // all the windows and wrap around.
106 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
107 EXPECT_TRUE(controller
->IsCycling());
108 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
110 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
111 EXPECT_TRUE(controller
->IsCycling());
112 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
114 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
115 EXPECT_TRUE(controller
->IsCycling());
116 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
118 controller
->AltKeyReleased();
119 EXPECT_FALSE(controller
->IsCycling());
120 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
122 // Reset our stacking order.
123 wm::ActivateWindow(window2
.get());
124 wm::ActivateWindow(window1
.get());
125 wm::ActivateWindow(window0
.get());
127 // Likewise we can cycle backwards through all the windows.
128 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, true);
129 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
130 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, true);
131 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
132 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, true);
133 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
134 controller
->AltKeyReleased();
135 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
137 // Passing false for is_alt_down does not start a cycle gesture.
138 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
139 EXPECT_FALSE(controller
->IsCycling());
140 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
142 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
143 EXPECT_FALSE(controller
->IsCycling());
144 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
146 // When the screen is locked, cycling window does not take effect.
147 Shell::GetInstance()->session_state_delegate()->LockScreen();
148 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
149 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
150 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
151 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, false);
152 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
154 Shell::GetInstance()->session_state_delegate()->UnlockScreen();
155 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
156 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
157 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
158 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
159 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
161 // When a modal window is active, cycling window does not take effect.
162 aura::Window
* modal_container
=
163 ash::Shell::GetContainer(
164 Shell::GetPrimaryRootWindow(),
165 internal::kShellWindowId_SystemModalContainer
);
166 scoped_ptr
<Window
> modal_window(
167 CreateTestWindowWithId(-2, modal_container
));
168 modal_window
->SetProperty(aura::client::kModalKey
, ui::MODAL_TYPE_SYSTEM
);
169 wm::ActivateWindow(modal_window
.get());
170 EXPECT_TRUE(wm::IsActiveWindow(modal_window
.get()));
171 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
172 EXPECT_TRUE(wm::IsActiveWindow(modal_window
.get()));
173 EXPECT_FALSE(wm::IsActiveWindow(window0
.get()));
174 EXPECT_FALSE(wm::IsActiveWindow(window1
.get()));
175 EXPECT_FALSE(wm::IsActiveWindow(window2
.get()));
176 controller
->HandleCycleWindow(WindowCycleController::BACKWARD
, false);
177 EXPECT_TRUE(wm::IsActiveWindow(modal_window
.get()));
178 EXPECT_FALSE(wm::IsActiveWindow(window0
.get()));
179 EXPECT_FALSE(wm::IsActiveWindow(window1
.get()));
180 EXPECT_FALSE(wm::IsActiveWindow(window2
.get()));
183 // Cycles between a maximized and normal window.
184 TEST_F(WindowCycleControllerTest
, MaximizedWindow
) {
185 // Create a couple of test windows.
186 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
187 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
189 wm::MaximizeWindow(window1
.get());
190 wm::ActivateWindow(window1
.get());
191 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
193 // Rotate focus, this should move focus to window0.
194 WindowCycleController
* controller
=
195 Shell::GetInstance()->window_cycle_controller();
196 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
197 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
200 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
201 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
204 // Cycles to a minimized window.
205 TEST_F(WindowCycleControllerTest
, Minimized
) {
206 // Create a couple of test windows.
207 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
208 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
210 wm::MinimizeWindow(window1
.get());
211 wm::ActivateWindow(window0
.get());
212 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
214 // Rotate focus, this should move focus to window1 and unminimize it.
215 WindowCycleController
* controller
=
216 Shell::GetInstance()->window_cycle_controller();
217 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
218 EXPECT_FALSE(wm::IsWindowMinimized(window1
.get()));
219 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
221 // One more time back to w0.
222 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, false);
223 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
226 TEST_F(WindowCycleControllerTest
, AlwaysOnTopWindow
) {
227 WindowCycleController
* controller
=
228 Shell::GetInstance()->window_cycle_controller();
230 // Set up several windows to use to test cycling.
231 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
232 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
234 Window
* top_container
=
236 Shell::GetPrimaryRootWindow(),
237 internal::kShellWindowId_AlwaysOnTopContainer
);
238 scoped_ptr
<Window
> window2(CreateTestWindowWithId(2, top_container
));
239 wm::ActivateWindow(window0
.get());
241 // Simulate pressing and releasing Alt-tab.
242 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
243 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
245 // Window lists should return the topmost window in front.
246 ASSERT_TRUE(controller
->windows());
247 ASSERT_EQ(3u, controller
->windows()->windows().size());
248 EXPECT_EQ(window0
.get(), controller
->windows()->windows()[0]);
249 EXPECT_EQ(window2
.get(), controller
->windows()->windows()[1]);
250 EXPECT_EQ(window1
.get(), controller
->windows()->windows()[2]);
252 controller
->AltKeyReleased();
253 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
255 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
256 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
258 controller
->AltKeyReleased();
260 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
261 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
263 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
264 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
266 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
267 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
270 TEST_F(WindowCycleControllerTest
, AlwaysOnTopMultiWindow
) {
271 WindowCycleController
* controller
=
272 Shell::GetInstance()->window_cycle_controller();
274 // Set up several windows to use to test cycling.
275 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
276 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
278 Window
* top_container
=
280 Shell::GetPrimaryRootWindow(),
281 internal::kShellWindowId_AlwaysOnTopContainer
);
282 scoped_ptr
<Window
> window2(CreateTestWindowWithId(2, top_container
));
283 scoped_ptr
<Window
> window3(CreateTestWindowWithId(3, top_container
));
284 wm::ActivateWindow(window0
.get());
286 // Simulate pressing and releasing Alt-tab.
287 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
288 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
290 // Window lists should return the topmost window in front.
291 ASSERT_TRUE(controller
->windows());
292 ASSERT_EQ(4u, controller
->windows()->windows().size());
293 EXPECT_EQ(window0
.get(), controller
->windows()->windows()[0]);
294 EXPECT_EQ(window3
.get(), controller
->windows()->windows()[1]);
295 EXPECT_EQ(window2
.get(), controller
->windows()->windows()[2]);
296 EXPECT_EQ(window1
.get(), controller
->windows()->windows()[3]);
298 controller
->AltKeyReleased();
299 EXPECT_TRUE(wm::IsActiveWindow(window3
.get()));
301 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
302 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
304 controller
->AltKeyReleased();
306 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
307 EXPECT_TRUE(wm::IsActiveWindow(window3
.get()));
309 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
310 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
312 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
313 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
315 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
316 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
319 TEST_F(WindowCycleControllerTest
, AlwaysOnTopMultipleRootWindows
) {
320 if (!SupportsMultipleDisplays())
323 // Set up a second root window
324 UpdateDisplay("1000x600,600x400");
325 Shell::RootWindowList root_windows
= Shell::GetAllRootWindows();
326 ASSERT_EQ(2U, root_windows
.size());
328 WindowCycleController
* controller
=
329 Shell::GetInstance()->window_cycle_controller();
331 Shell::GetInstance()->set_active_root_window(root_windows
[0]);
333 // Create two windows in the primary root.
334 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
335 EXPECT_EQ(root_windows
[0], window0
->GetRootWindow());
336 Window
* top_container0
=
339 internal::kShellWindowId_AlwaysOnTopContainer
);
340 scoped_ptr
<Window
> window1(CreateTestWindowWithId(1, top_container0
));
341 EXPECT_EQ(root_windows
[0], window1
->GetRootWindow());
343 // And two on the secondary root.
344 Shell::GetInstance()->set_active_root_window(root_windows
[1]);
345 scoped_ptr
<Window
> window2(CreateTestWindowInShellWithId(2));
346 EXPECT_EQ(root_windows
[1], window2
->GetRootWindow());
348 Window
* top_container1
=
351 internal::kShellWindowId_AlwaysOnTopContainer
);
352 scoped_ptr
<Window
> window3(CreateTestWindowWithId(3, top_container1
));
353 EXPECT_EQ(root_windows
[1], window3
->GetRootWindow());
355 // Move the active root window to the secondary.
356 Shell::GetInstance()->set_active_root_window(root_windows
[1]);
358 wm::ActivateWindow(window2
.get());
360 EXPECT_EQ(root_windows
[0], window0
->GetRootWindow());
361 EXPECT_EQ(root_windows
[0], window1
->GetRootWindow());
362 EXPECT_EQ(root_windows
[1], window2
->GetRootWindow());
363 EXPECT_EQ(root_windows
[1], window3
->GetRootWindow());
365 // Simulate pressing and releasing Alt-tab.
366 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
367 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
369 // Window lists should return the topmost window in front.
370 ASSERT_TRUE(controller
->windows());
371 ASSERT_EQ(4u, controller
->windows()->windows().size());
372 EXPECT_EQ(window2
.get(), controller
->windows()->windows()[0]);
373 EXPECT_EQ(window3
.get(), controller
->windows()->windows()[1]);
374 EXPECT_EQ(window1
.get(), controller
->windows()->windows()[2]);
375 EXPECT_EQ(window0
.get(), controller
->windows()->windows()[3]);
377 controller
->AltKeyReleased();
378 EXPECT_TRUE(wm::IsActiveWindow(window3
.get()));
380 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
381 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
383 controller
->AltKeyReleased();
385 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
386 EXPECT_TRUE(wm::IsActiveWindow(window3
.get()));
388 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
389 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
391 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
392 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
394 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
395 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
398 TEST_F(WindowCycleControllerTest
, MostRecentlyUsed
) {
399 WindowCycleController
* controller
=
400 Shell::GetInstance()->window_cycle_controller();
402 // Set up several windows to use to test cycling.
403 scoped_ptr
<Window
> window0(CreateTestWindowInShellWithId(0));
404 scoped_ptr
<Window
> window1(CreateTestWindowInShellWithId(1));
405 scoped_ptr
<Window
> window2(CreateTestWindowInShellWithId(2));
407 wm::ActivateWindow(window0
.get());
409 // Simulate pressing and releasing Alt-tab.
410 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
411 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
413 // Window lists should return the topmost window in front.
414 ASSERT_TRUE(controller
->windows());
415 ASSERT_EQ(3u, controller
->windows()->windows().size());
416 EXPECT_EQ(window0
.get(), controller
->windows()->windows()[0]);
417 EXPECT_EQ(window2
.get(), controller
->windows()->windows()[1]);
418 EXPECT_EQ(window1
.get(), controller
->windows()->windows()[2]);
420 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
421 controller
->AltKeyReleased();
422 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
425 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
426 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
428 controller
->AltKeyReleased();
430 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
431 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
433 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
434 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
436 controller
->HandleCycleWindow(WindowCycleController::FORWARD
, true);
437 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));