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.
7 #include "ash/accessibility_delegate.h"
8 #include "ash/drag_drop/drag_drop_controller.h"
9 #include "ash/root_window_controller.h"
10 #include "ash/screen_util.h"
11 #include "ash/shelf/shelf.h"
12 #include "ash/shelf/shelf_widget.h"
13 #include "ash/shell.h"
14 #include "ash/shell_window_ids.h"
15 #include "ash/test/ash_test_base.h"
16 #include "ash/test/shelf_test_api.h"
17 #include "ash/test/shelf_view_test_api.h"
18 #include "ash/test/shell_test_api.h"
19 #include "ash/test/test_shelf_delegate.h"
20 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
21 #include "ash/wm/mru_window_tracker.h"
22 #include "ash/wm/overview/window_grid.h"
23 #include "ash/wm/overview/window_selector.h"
24 #include "ash/wm/overview/window_selector_controller.h"
25 #include "ash/wm/overview/window_selector_item.h"
26 #include "ash/wm/panels/panel_layout_manager.h"
27 #include "ash/wm/window_state.h"
28 #include "ash/wm/window_util.h"
29 #include "ash/wm/wm_event.h"
30 #include "base/basictypes.h"
31 #include "base/compiler_specific.h"
32 #include "base/memory/scoped_vector.h"
33 #include "base/run_loop.h"
34 #include "base/strings/string_piece.h"
35 #include "base/strings/utf_string_conversions.h"
36 #include "ui/aura/client/aura_constants.h"
37 #include "ui/aura/client/cursor_client.h"
38 #include "ui/aura/client/focus_client.h"
39 #include "ui/aura/test/test_window_delegate.h"
40 #include "ui/aura/test/test_windows.h"
41 #include "ui/aura/window.h"
42 #include "ui/aura/window_event_dispatcher.h"
43 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
44 #include "ui/events/test/event_generator.h"
45 #include "ui/gfx/rect_conversions.h"
46 #include "ui/gfx/transform.h"
47 #include "ui/views/controls/label.h"
48 #include "ui/views/widget/native_widget_aura.h"
49 #include "ui/views/widget/widget_delegate.h"
50 #include "ui/wm/core/window_util.h"
51 #include "ui/wm/public/activation_delegate.h"
56 class NonActivatableActivationDelegate
57 : public aura::client::ActivationDelegate
{
59 bool ShouldActivate() const override
{ return false; }
62 void CancelDrag(DragDropController
* controller
, bool* canceled
) {
63 if (controller
->IsDragDropInProgress()) {
65 controller
->DragCancel();
71 class WindowSelectorTest
: public test::AshTestBase
{
73 WindowSelectorTest() {}
74 ~WindowSelectorTest() override
{}
76 void SetUp() override
{
77 test::AshTestBase::SetUp();
78 ASSERT_TRUE(test::TestShelfDelegate::instance());
80 shelf_view_test_
.reset(new test::ShelfViewTestAPI(
81 test::ShelfTestAPI(Shelf::ForPrimaryDisplay()).shelf_view()));
82 shelf_view_test_
->SetAnimationDuration(1);
85 aura::Window
* CreateWindow(const gfx::Rect
& bounds
) {
86 return CreateTestWindowInShellWithDelegate(&delegate_
, -1, bounds
);
89 aura::Window
* CreateWindowWithId(const gfx::Rect
& bounds
, int id
) {
90 return CreateTestWindowInShellWithDelegate(&delegate_
, id
, bounds
);
92 aura::Window
* CreateNonActivatableWindow(const gfx::Rect
& bounds
) {
93 aura::Window
* window
= CreateWindow(bounds
);
94 aura::client::SetActivationDelegate(window
,
95 &non_activatable_activation_delegate_
);
96 EXPECT_FALSE(ash::wm::CanActivateWindow(window
));
100 aura::Window
* CreatePanelWindow(const gfx::Rect
& bounds
) {
101 aura::Window
* window
= CreateTestWindowInShellWithDelegateAndType(
102 NULL
, ui::wm::WINDOW_TYPE_PANEL
, 0, bounds
);
103 test::TestShelfDelegate::instance()->AddShelfItem(window
);
104 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
108 views::Widget
* CreatePanelWindowWidget(const gfx::Rect
& bounds
) {
109 views::Widget
* widget
= new views::Widget
;
110 views::Widget::InitParams params
;
111 params
.bounds
= bounds
;
112 params
.type
= views::Widget::InitParams::TYPE_PANEL
;
113 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
114 widget
->Init(params
);
116 ParentWindowInPrimaryRootWindow(widget
->GetNativeWindow());
120 bool WindowsOverlapping(aura::Window
* window1
, aura::Window
* window2
) {
121 gfx::RectF window1_bounds
= GetTransformedTargetBounds(window1
);
122 gfx::RectF window2_bounds
= GetTransformedTargetBounds(window2
);
123 return window1_bounds
.Intersects(window2_bounds
);
126 void ToggleOverview() {
127 ash::Shell::GetInstance()->window_selector_controller()->ToggleOverview();
130 gfx::Transform
GetTransformRelativeTo(gfx::PointF origin
,
131 const gfx::Transform
& transform
) {
133 t
.Translate(origin
.x(), origin
.y());
134 t
.PreconcatTransform(transform
);
135 t
.Translate(-origin
.x(), -origin
.y());
139 gfx::RectF
GetTransformedBounds(aura::Window
* window
) {
140 gfx::RectF
bounds(ScreenUtil::ConvertRectToScreen(
141 window
->parent(), window
->layer()->bounds()));
142 gfx::Transform
transform(GetTransformRelativeTo(bounds
.origin(),
143 window
->layer()->transform()));
144 transform
.TransformRect(&bounds
);
148 gfx::RectF
GetTransformedTargetBounds(aura::Window
* window
) {
149 gfx::RectF
bounds(ScreenUtil::ConvertRectToScreen(
150 window
->parent(), window
->layer()->GetTargetBounds()));
151 gfx::Transform
transform(GetTransformRelativeTo(bounds
.origin(),
152 window
->layer()->GetTargetTransform()));
153 transform
.TransformRect(&bounds
);
157 gfx::RectF
GetTransformedBoundsInRootWindow(aura::Window
* window
) {
158 gfx::RectF bounds
= gfx::Rect(window
->bounds().size());
159 aura::Window
* root
= window
->GetRootWindow();
160 CHECK(window
->layer());
161 CHECK(root
->layer());
162 gfx::Transform transform
;
163 if (!window
->layer()->GetTargetTransformRelativeTo(root
->layer(),
167 transform
.TransformRect(&bounds
);
171 void ClickWindow(aura::Window
* window
) {
172 ui::test::EventGenerator
event_generator(window
->GetRootWindow(), window
);
173 gfx::RectF target
= GetTransformedBounds(window
);
174 event_generator
.ClickLeftButton();
177 void SendKey(ui::KeyboardCode key
) {
178 ui::test::EventGenerator
event_generator(Shell::GetPrimaryRootWindow());
179 event_generator
.PressKey(key
, 0);
180 event_generator
.ReleaseKey(key
, 0);
184 return ash::Shell::GetInstance()->window_selector_controller()->
188 aura::Window
* GetFocusedWindow() {
189 return aura::client::GetFocusClient(
190 Shell::GetPrimaryRootWindow())->GetFocusedWindow();
193 const std::vector
<WindowSelectorItem
*>& GetWindowItemsForRoot(int index
) {
194 return ash::Shell::GetInstance()->window_selector_controller()->
195 window_selector_
->grid_list_
[index
]->window_list_
.get();
198 const aura::Window
* GetSelectedWindow() {
199 WindowSelector
* ws
= ash::Shell::GetInstance()->
200 window_selector_controller()->window_selector_
.get();
201 return ws
->grid_list_
[ws
->selected_grid_index_
]->
202 SelectedWindow()->SelectionWindow();
205 bool selection_widget_active() {
206 WindowSelector
* ws
= ash::Shell::GetInstance()->
207 window_selector_controller()->window_selector_
.get();
208 return ws
->grid_list_
[ws
->selected_grid_index_
]->is_selecting();
211 bool showing_filter_widget() {
212 WindowSelector
* ws
= ash::Shell::GetInstance()->
213 window_selector_controller()->window_selector_
.get();
214 return ws
->text_filter_widget_
->GetNativeWindow()->layer()->
215 GetTargetTransform().IsIdentity();
218 views::Widget
* GetCloseButton(ash::WindowSelectorItem
* window
) {
219 return window
->close_button_
.get();
222 views::Label
* GetLabelView(ash::WindowSelectorItem
* window
) {
223 return window
->window_label_view_
;
226 // Tests that a window is contained within a given WindowSelectorItem, and
227 // that both the window and its matching close button are within the same
229 void IsWindowAndCloseButtonInScreen(aura::Window
* window
,
230 WindowSelectorItem
* window_item
) {
231 aura::Window
* root_window
= window_item
->GetRootWindow();
232 EXPECT_TRUE(window_item
->Contains(window
));
233 EXPECT_TRUE(root_window
->GetBoundsInScreen().Contains(
234 ToEnclosingRect(GetTransformedTargetBounds(window
))));
235 EXPECT_TRUE(root_window
->GetBoundsInScreen().Contains(
236 ToEnclosingRect(GetTransformedTargetBounds(
237 GetCloseButton(window_item
)->GetNativeView()))));
240 void FilterItems(const base::StringPiece
& pattern
) {
241 ash::Shell::GetInstance()->
242 window_selector_controller()->window_selector_
.get()->
243 ContentsChanged(NULL
, base::UTF8ToUTF16(pattern
));
246 test::ShelfViewTestAPI
* shelf_view_test() {
247 return shelf_view_test_
.get();
250 views::Widget
* text_filter_widget() {
251 return ash::Shell::GetInstance()->
252 window_selector_controller()->window_selector_
.get()->
253 text_filter_widget_
.get();
257 aura::test::TestWindowDelegate delegate_
;
258 NonActivatableActivationDelegate non_activatable_activation_delegate_
;
259 scoped_ptr
<test::ShelfViewTestAPI
> shelf_view_test_
;
261 DISALLOW_COPY_AND_ASSIGN(WindowSelectorTest
);
264 // Tests that an a11y alert is sent on entering overview mode.
265 TEST_F(WindowSelectorTest
, A11yAlertOnOverviewMode
) {
266 gfx::Rect
bounds(0, 0, 400, 400);
267 AccessibilityDelegate
* delegate
=
268 ash::Shell::GetInstance()->accessibility_delegate();
269 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
270 EXPECT_NE(delegate
->GetLastAccessibilityAlert(),
271 ui::A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED
);
273 EXPECT_EQ(delegate
->GetLastAccessibilityAlert(),
274 ui::A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED
);
277 // Tests entering overview mode with two windows and selecting one by clicking.
278 TEST_F(WindowSelectorTest
, Basic
) {
279 gfx::Rect
bounds(0, 0, 400, 400);
280 aura::Window
* root_window
= Shell::GetPrimaryRootWindow();
281 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
282 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
283 scoped_ptr
<aura::Window
> panel1(CreatePanelWindow(bounds
));
284 scoped_ptr
<aura::Window
> panel2(CreatePanelWindow(bounds
));
285 EXPECT_TRUE(WindowsOverlapping(window1
.get(), window2
.get()));
286 EXPECT_TRUE(WindowsOverlapping(panel1
.get(), panel2
.get()));
287 wm::ActivateWindow(window2
.get());
288 EXPECT_FALSE(wm::IsActiveWindow(window1
.get()));
289 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
290 EXPECT_EQ(window2
.get(), GetFocusedWindow());
291 // Hide the cursor before entering overview to test that it will be shown.
292 aura::client::GetCursorClient(root_window
)->HideCursor();
294 // In overview mode the windows should no longer overlap and the text filter
295 // widget should be focused.
297 EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow());
298 EXPECT_FALSE(WindowsOverlapping(window1
.get(), window2
.get()));
299 EXPECT_FALSE(WindowsOverlapping(window1
.get(), panel1
.get()));
300 // Panels 1 and 2 should still be overlapping being in a single selector
302 EXPECT_TRUE(WindowsOverlapping(panel1
.get(), panel2
.get()));
304 // Clicking window 1 should activate it.
305 ClickWindow(window1
.get());
306 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
307 EXPECT_FALSE(wm::IsActiveWindow(window2
.get()));
308 EXPECT_EQ(window1
.get(), GetFocusedWindow());
310 // Cursor should have been unlocked.
311 EXPECT_FALSE(aura::client::GetCursorClient(root_window
)->IsCursorLocked());
314 // Tests selecting a window by tapping on it.
315 TEST_F(WindowSelectorTest
, BasicGesture
) {
316 gfx::Rect
bounds(0, 0, 400, 400);
317 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
318 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
319 wm::ActivateWindow(window1
.get());
320 EXPECT_EQ(window1
.get(), GetFocusedWindow());
322 EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow());
323 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
325 generator
.GestureTapAt(gfx::ToEnclosingRect(
326 GetTransformedTargetBounds(window2
.get())).CenterPoint());
327 EXPECT_EQ(window2
.get(), GetFocusedWindow());
330 // Tests that we do not crash and overview mode remains engaged if the desktop
331 // is tapped while a finger is already down over a window.
332 TEST_F(WindowSelectorTest
, NoCrashWithDesktopTap
) {
333 scoped_ptr
<aura::Window
> window(CreateWindow(gfx::Rect(200, 300, 250, 450)));
335 // We need a widget for the close button to work, a bare window will crash.
336 scoped_ptr
<views::Widget
> widget(new views::Widget
);
337 views::Widget::InitParams params
;
338 params
.bounds
= gfx::Rect(0, 0, 400, 400);
339 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
340 params
.parent
= window
->parent();
341 widget
->Init(params
);
347 gfx::ToEnclosingRect(GetTransformedBoundsInRootWindow(window
.get()));
348 ui::test::EventGenerator
event_generator(window
->GetRootWindow(),
349 bounds
.CenterPoint());
351 // Press down on the window.
352 const int kTouchId
= 19;
353 event_generator
.PressTouchId(kTouchId
);
355 // Tap on the desktop, which should not cause a crash. Overview mode should
356 // remain engaged because the transparent widget over the window has capture.
357 event_generator
.GestureTapAt(gfx::Point(0, 0));
358 EXPECT_TRUE(IsSelecting());
360 event_generator
.ReleaseTouchId(kTouchId
);
363 // Tests that we do not crash and a window is selected when appropriate when
364 // we click on a window during touch.
365 TEST_F(WindowSelectorTest
, ClickOnWindowDuringTouch
) {
366 gfx::Rect
bounds(0, 0, 400, 400);
367 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
368 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
369 wm::ActivateWindow(window2
.get());
370 EXPECT_FALSE(wm::IsActiveWindow(window1
.get()));
371 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
375 gfx::Rect window1_bounds
=
376 gfx::ToEnclosingRect(GetTransformedBoundsInRootWindow(window1
.get()));
377 ui::test::EventGenerator
event_generator(window1
->GetRootWindow(),
378 window1_bounds
.CenterPoint());
380 // Clicking on |window2| while touching on |window1| should not cause a
381 // crash, and overview mode should remain engaged because |window1|
383 const int kTouchId
= 19;
384 event_generator
.PressTouchId(kTouchId
);
385 event_generator
.MoveMouseToCenterOf(window2
.get());
386 event_generator
.ClickLeftButton();
387 EXPECT_TRUE(IsSelecting());
388 event_generator
.ReleaseTouchId(kTouchId
);
390 // Clicking on |window1| while touching on |window1| should not cause
391 // a crash, overview mode should be disengaged, and |window1| should
393 event_generator
.MoveMouseToCenterOf(window1
.get());
394 event_generator
.PressTouchId(kTouchId
);
395 event_generator
.ClickLeftButton();
396 EXPECT_FALSE(IsSelecting());
397 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
398 EXPECT_FALSE(wm::IsActiveWindow(window2
.get()));
399 event_generator
.ReleaseTouchId(kTouchId
);
402 // Tests that a window does not receive located events when in overview mode.
403 TEST_F(WindowSelectorTest
, WindowDoesNotReceiveEvents
) {
404 gfx::Rect
window_bounds(20, 10, 200, 300);
405 aura::Window
* root_window
= Shell::GetPrimaryRootWindow();
406 scoped_ptr
<aura::Window
> window(CreateWindow(window_bounds
));
408 gfx::Point
point1(window_bounds
.x() + 10, window_bounds
.y() + 10);
410 ui::MouseEvent
event1(ui::ET_MOUSE_PRESSED
, point1
, point1
,
411 ui::EF_NONE
, ui::EF_NONE
);
413 ui::EventTarget
* root_target
= root_window
;
414 ui::EventTargeter
* targeter
= root_target
->GetEventTargeter();
416 // The event should target the window because we are still not in overview
418 EXPECT_EQ(window
, static_cast<aura::Window
*>(
419 targeter
->FindTargetForEvent(root_target
, &event1
)));
423 // The bounds have changed, take that into account.
424 gfx::RectF bounds
= GetTransformedBoundsInRootWindow(window
.get());
425 gfx::Point
point2(bounds
.x() + 10, bounds
.y() + 10);
426 ui::MouseEvent
event2(ui::ET_MOUSE_PRESSED
, point2
, point2
,
427 ui::EF_NONE
, ui::EF_NONE
);
429 // Now the transparent window should be intercepting this event.
430 EXPECT_NE(window
, static_cast<aura::Window
*>(
431 targeter
->FindTargetForEvent(root_target
, &event2
)));
434 // Tests that clicking on the close button effectively closes the window.
435 TEST_F(WindowSelectorTest
, CloseButton
) {
436 scoped_ptr
<aura::Window
> window1(CreateWindow(gfx::Rect(200, 300, 250, 450)));
438 // We need a widget for the close button to work, a bare window will crash.
439 scoped_ptr
<views::Widget
> widget(new views::Widget
);
440 views::Widget::InitParams params
;
441 params
.bounds
= gfx::Rect(0, 0, 400, 400);
442 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
443 params
.parent
= window1
->parent();
444 widget
->Init(params
);
448 aura::Window
* window2
= widget
->GetNativeWindow();
449 gfx::RectF bounds
= GetTransformedBoundsInRootWindow(window2
);
450 gfx::Point
point(bounds
.top_right().x() - 1, bounds
.top_right().y() - 1);
451 ui::test::EventGenerator
event_generator(window2
->GetRootWindow(), point
);
453 EXPECT_FALSE(widget
->IsClosed());
454 event_generator
.ClickLeftButton();
455 EXPECT_TRUE(widget
->IsClosed());
458 // Tests entering overview mode with two windows and selecting one.
459 TEST_F(WindowSelectorTest
, FullscreenWindow
) {
460 gfx::Rect
bounds(0, 0, 400, 400);
461 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
462 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
463 scoped_ptr
<aura::Window
> panel1(CreatePanelWindow(bounds
));
464 wm::ActivateWindow(window1
.get());
466 const wm::WMEvent
toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN
);
467 wm::GetWindowState(window1
.get())->OnWMEvent(&toggle_fullscreen_event
);
468 // The panel is hidden in fullscreen mode.
469 EXPECT_FALSE(panel1
->IsVisible());
470 EXPECT_TRUE(wm::GetWindowState(window1
.get())->IsFullscreen());
472 // Enter overview and select the fullscreen window.
475 // The panel becomes temporarily visible for the overview.
476 EXPECT_TRUE(panel1
->IsVisible());
477 ClickWindow(window1
.get());
479 // The window is still fullscreen as it was selected. The panel should again
481 EXPECT_TRUE(wm::GetWindowState(window1
.get())->IsFullscreen());
482 EXPECT_FALSE(panel1
->IsVisible());
484 // Entering overview and selecting another window, the previous window remains
486 // TODO(flackr): Currently the panel remains hidden, but should become visible
489 ClickWindow(window2
.get());
490 EXPECT_TRUE(wm::GetWindowState(window1
.get())->IsFullscreen());
493 // Tests that the shelf dimming state is removed while in overview and restored
494 // on exiting overview.
495 TEST_F(WindowSelectorTest
, OverviewUndimsShelf
) {
496 gfx::Rect
bounds(0, 0, 400, 400);
497 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
498 wm::WindowState
* window_state
= wm::GetWindowState(window1
.get());
499 window_state
->Maximize();
500 ash::ShelfWidget
* shelf
= Shell::GetPrimaryRootWindowController()->shelf();
501 EXPECT_TRUE(shelf
->GetDimsShelf());
503 EXPECT_FALSE(shelf
->GetDimsShelf());
505 EXPECT_TRUE(shelf
->GetDimsShelf());
508 // Tests that entering overview when a fullscreen window is active in maximized
509 // mode correctly applies the transformations to the window and correctly
510 // updates the window bounds on exiting overview mode: http://crbug.com/401664.
511 TEST_F(WindowSelectorTest
, FullscreenWindowMaximizeMode
) {
512 gfx::Rect
bounds(0, 0, 400, 400);
513 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
514 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
515 Shell::GetInstance()->maximize_mode_controller()->
516 EnableMaximizeModeWindowManager(true);
517 wm::ActivateWindow(window2
.get());
518 wm::ActivateWindow(window1
.get());
519 gfx::Rect
normal_window_bounds(window1
->bounds());
520 const wm::WMEvent
toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN
);
521 wm::GetWindowState(window1
.get())->OnWMEvent(&toggle_fullscreen_event
);
522 gfx::Rect
fullscreen_window_bounds(window1
->bounds());
523 EXPECT_NE(normal_window_bounds
.ToString(),
524 fullscreen_window_bounds
.ToString());
525 EXPECT_EQ(fullscreen_window_bounds
.ToString(),
526 window2
->GetTargetBounds().ToString());
528 // Window 2 would normally resize to normal window bounds on showing the shelf
529 // for overview but this is deferred until overview is exited.
530 EXPECT_EQ(fullscreen_window_bounds
.ToString(),
531 window2
->GetTargetBounds().ToString());
532 EXPECT_FALSE(WindowsOverlapping(window1
.get(), window2
.get()));
535 // Since the fullscreen window is still active, window2 will still have the
537 EXPECT_EQ(fullscreen_window_bounds
.ToString(),
538 window2
->GetTargetBounds().ToString());
540 // Enter overview again and select window 2. Selecting window 2 should show
541 // the shelf bringing window2 back to the normal bounds.
543 ClickWindow(window2
.get());
544 EXPECT_EQ(normal_window_bounds
.ToString(),
545 window2
->GetTargetBounds().ToString());
548 // Tests that beginning window selection hides the app list.
549 TEST_F(WindowSelectorTest
, SelectingHidesAppList
) {
550 gfx::Rect
bounds(0, 0, 400, 400);
551 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
552 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
553 Shell::GetInstance()->ShowAppList(NULL
);
554 EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility());
556 EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility());
560 // Tests that a minimized window's visibility and layer visibility is correctly
561 // changed when entering overview and restored when leaving overview mode.
562 // Crashes after the skia roll in http://crrev.com/274114.
563 // http://crbug.com/379570
564 TEST_F(WindowSelectorTest
, DISABLED_MinimizedWindowVisibility
) {
565 gfx::Rect
bounds(0, 0, 400, 400);
566 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
567 wm::WindowState
* window_state
= wm::GetWindowState(window1
.get());
568 window_state
->Minimize();
569 EXPECT_FALSE(window1
->IsVisible());
570 EXPECT_FALSE(window1
->layer()->GetTargetVisibility());
572 ui::ScopedAnimationDurationScaleMode
test_duration_mode(
573 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION
);
575 EXPECT_TRUE(window1
->IsVisible());
576 EXPECT_TRUE(window1
->layer()->GetTargetVisibility());
579 ui::ScopedAnimationDurationScaleMode
test_duration_mode(
580 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION
);
582 EXPECT_FALSE(window1
->IsVisible());
583 EXPECT_FALSE(window1
->layer()->GetTargetVisibility());
587 // Tests that a bounds change during overview is corrected for.
588 TEST_F(WindowSelectorTest
, BoundsChangeDuringOverview
) {
589 scoped_ptr
<aura::Window
> window(CreateWindow(gfx::Rect(0, 0, 400, 400)));
591 gfx::Rect overview_bounds
=
592 ToEnclosingRect(GetTransformedTargetBounds(window
.get()));
593 window
->SetBounds(gfx::Rect(200, 0, 200, 200));
594 gfx::Rect new_overview_bounds
=
595 ToEnclosingRect(GetTransformedTargetBounds(window
.get()));
596 EXPECT_EQ(overview_bounds
.x(), new_overview_bounds
.x());
597 EXPECT_EQ(overview_bounds
.y(), new_overview_bounds
.y());
598 EXPECT_EQ(overview_bounds
.width(), new_overview_bounds
.width());
599 EXPECT_EQ(overview_bounds
.height(), new_overview_bounds
.height());
603 // Tests that a newly created window aborts overview.
604 TEST_F(WindowSelectorTest
, NewWindowCancelsOveriew
) {
605 gfx::Rect
bounds(0, 0, 400, 400);
606 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
607 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
609 EXPECT_TRUE(IsSelecting());
611 // A window being created should exit overview mode.
612 scoped_ptr
<aura::Window
> window3(CreateWindow(bounds
));
613 EXPECT_FALSE(IsSelecting());
616 // Tests that a window activation exits overview mode.
617 TEST_F(WindowSelectorTest
, ActivationCancelsOveriew
) {
618 gfx::Rect
bounds(0, 0, 400, 400);
619 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
620 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
623 EXPECT_TRUE(IsSelecting());
625 // A window being activated should exit overview mode.
627 EXPECT_FALSE(IsSelecting());
629 // window1 should be focused after exiting even though window2 was focused on
630 // entering overview because we exited due to an activation.
631 EXPECT_EQ(window1
.get(), GetFocusedWindow());
634 // Tests that exiting overview mode without selecting a window restores focus
635 // to the previously focused window.
636 TEST_F(WindowSelectorTest
, CancelRestoresFocus
) {
637 gfx::Rect
bounds(0, 0, 400, 400);
638 scoped_ptr
<aura::Window
> window(CreateWindow(bounds
));
639 wm::ActivateWindow(window
.get());
640 EXPECT_EQ(window
.get(), GetFocusedWindow());
642 // In overview mode, the text filter widget should be focused.
644 EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow());
646 // If canceling overview mode, focus should be restored.
648 EXPECT_EQ(window
.get(), GetFocusedWindow());
651 // Tests that overview mode is exited if the last remaining window is destroyed.
652 TEST_F(WindowSelectorTest
, LastWindowDestroyed
) {
653 gfx::Rect
bounds(0, 0, 400, 400);
654 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
655 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
660 EXPECT_FALSE(IsSelecting());
663 // Tests that entering overview mode restores a window to its original
665 TEST_F(WindowSelectorTest
, QuickReentryRestoresInitialTransform
) {
666 gfx::Rect
bounds(0, 0, 400, 400);
667 scoped_ptr
<aura::Window
> window(CreateWindow(bounds
));
668 gfx::Rect initial_bounds
= ToEnclosingRect(
669 GetTransformedBounds(window
.get()));
671 // Quickly exit and reenter overview mode. The window should still be
672 // animating when we reenter. We cannot short circuit animations for this but
673 // we also don't have to wait for them to complete.
675 ui::ScopedAnimationDurationScaleMode
test_duration_mode(
676 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION
);
680 EXPECT_NE(initial_bounds
, ToEnclosingRect(
681 GetTransformedTargetBounds(window
.get())));
683 EXPECT_FALSE(IsSelecting());
684 EXPECT_EQ(initial_bounds
, ToEnclosingRect(
685 GetTransformedTargetBounds(window
.get())));
688 // Tests that non-activatable windows are hidden when entering overview mode.
689 TEST_F(WindowSelectorTest
, NonActivatableWindowsHidden
) {
690 gfx::Rect
bounds(0, 0, 400, 400);
691 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
692 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
693 scoped_ptr
<aura::Window
> non_activatable_window(
694 CreateNonActivatableWindow(Shell::GetPrimaryRootWindow()->bounds()));
695 EXPECT_TRUE(non_activatable_window
->IsVisible());
697 EXPECT_FALSE(non_activatable_window
->IsVisible());
699 EXPECT_TRUE(non_activatable_window
->IsVisible());
701 // Test that a window behind the fullscreen non-activatable window can be
703 non_activatable_window
->parent()->StackChildAtTop(
704 non_activatable_window
.get());
706 ClickWindow(window1
.get());
707 EXPECT_FALSE(IsSelecting());
708 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
711 // Tests that windows with modal child windows are transformed with the modal
712 // child even though not activatable themselves.
713 TEST_F(WindowSelectorTest
, ModalChild
) {
714 gfx::Rect
bounds(0, 0, 400, 400);
715 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
716 scoped_ptr
<aura::Window
> child1(CreateWindow(bounds
));
717 child1
->SetProperty(aura::client::kModalKey
, ui::MODAL_TYPE_WINDOW
);
718 ::wm::AddTransientChild(window1
.get(), child1
.get());
719 EXPECT_EQ(window1
->parent(), child1
->parent());
721 EXPECT_TRUE(window1
->IsVisible());
722 EXPECT_TRUE(child1
->IsVisible());
723 EXPECT_EQ(ToEnclosingRect(GetTransformedTargetBounds(child1
.get())),
724 ToEnclosingRect(GetTransformedTargetBounds(window1
.get())));
728 // Tests that clicking a modal window's parent activates the modal window in
730 TEST_F(WindowSelectorTest
, ClickModalWindowParent
) {
731 scoped_ptr
<aura::Window
> window1(CreateWindow(gfx::Rect(0, 0, 180, 180)));
732 scoped_ptr
<aura::Window
> child1(CreateWindow(gfx::Rect(200, 0, 180, 180)));
733 child1
->SetProperty(aura::client::kModalKey
, ui::MODAL_TYPE_WINDOW
);
734 ::wm::AddTransientChild(window1
.get(), child1
.get());
735 EXPECT_FALSE(WindowsOverlapping(window1
.get(), child1
.get()));
736 EXPECT_EQ(window1
->parent(), child1
->parent());
738 // Given that their relative positions are preserved, the windows should still
740 EXPECT_FALSE(WindowsOverlapping(window1
.get(), child1
.get()));
741 ClickWindow(window1
.get());
742 EXPECT_FALSE(IsSelecting());
744 // Clicking on window1 should activate child1.
745 EXPECT_TRUE(wm::IsActiveWindow(child1
.get()));
748 // Tests that windows remain on the display they are currently on in overview
749 // mode, and that the close buttons are on matching displays.
750 TEST_F(WindowSelectorTest
, MultipleDisplays
) {
751 if (!SupportsMultipleDisplays())
754 UpdateDisplay("600x400,600x400");
755 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
756 gfx::Rect
bounds1(0, 0, 400, 400);
757 gfx::Rect
bounds2(650, 0, 400, 400);
759 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds1
));
760 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds1
));
761 scoped_ptr
<aura::Window
> window3(CreateWindow(bounds2
));
762 scoped_ptr
<aura::Window
> window4(CreateWindow(bounds2
));
763 scoped_ptr
<aura::Window
> panel1(CreatePanelWindow(bounds1
));
764 scoped_ptr
<aura::Window
> panel2(CreatePanelWindow(bounds1
));
765 scoped_ptr
<aura::Window
> panel3(CreatePanelWindow(bounds2
));
766 scoped_ptr
<aura::Window
> panel4(CreatePanelWindow(bounds2
));
767 EXPECT_EQ(root_windows
[0], window1
->GetRootWindow());
768 EXPECT_EQ(root_windows
[0], window2
->GetRootWindow());
769 EXPECT_EQ(root_windows
[1], window3
->GetRootWindow());
770 EXPECT_EQ(root_windows
[1], window4
->GetRootWindow());
772 EXPECT_EQ(root_windows
[0], panel1
->GetRootWindow());
773 EXPECT_EQ(root_windows
[0], panel2
->GetRootWindow());
774 EXPECT_EQ(root_windows
[1], panel3
->GetRootWindow());
775 EXPECT_EQ(root_windows
[1], panel4
->GetRootWindow());
777 // In overview mode, each window remains in the same root window.
779 EXPECT_EQ(root_windows
[0], window1
->GetRootWindow());
780 EXPECT_EQ(root_windows
[0], window2
->GetRootWindow());
781 EXPECT_EQ(root_windows
[1], window3
->GetRootWindow());
782 EXPECT_EQ(root_windows
[1], window4
->GetRootWindow());
783 EXPECT_EQ(root_windows
[0], panel1
->GetRootWindow());
784 EXPECT_EQ(root_windows
[0], panel2
->GetRootWindow());
785 EXPECT_EQ(root_windows
[1], panel3
->GetRootWindow());
786 EXPECT_EQ(root_windows
[1], panel4
->GetRootWindow());
788 const std::vector
<WindowSelectorItem
*>& primary_window_items
=
789 GetWindowItemsForRoot(0);
790 const std::vector
<WindowSelectorItem
*>& secondary_window_items
=
791 GetWindowItemsForRoot(1);
793 // Window indices are based on top-down order. The reverse of our creation.
794 IsWindowAndCloseButtonInScreen(window1
.get(), primary_window_items
[2]);
795 IsWindowAndCloseButtonInScreen(window2
.get(), primary_window_items
[1]);
796 IsWindowAndCloseButtonInScreen(window3
.get(), secondary_window_items
[2]);
797 IsWindowAndCloseButtonInScreen(window4
.get(), secondary_window_items
[1]);
799 IsWindowAndCloseButtonInScreen(panel1
.get(), primary_window_items
[0]);
800 IsWindowAndCloseButtonInScreen(panel2
.get(), primary_window_items
[0]);
801 IsWindowAndCloseButtonInScreen(panel3
.get(), secondary_window_items
[0]);
802 IsWindowAndCloseButtonInScreen(panel4
.get(), secondary_window_items
[0]);
804 EXPECT_TRUE(WindowsOverlapping(panel1
.get(), panel2
.get()));
805 EXPECT_TRUE(WindowsOverlapping(panel3
.get(), panel4
.get()));
806 EXPECT_FALSE(WindowsOverlapping(panel1
.get(), panel3
.get()));
809 // Tests shutting down during overview.
810 TEST_F(WindowSelectorTest
, Shutdown
) {
811 gfx::Rect
bounds(0, 0, 400, 400);
812 // These windows will be deleted when the test exits and the Shell instance
814 aura::Window
* window1(CreateWindow(bounds
));
815 aura::Window
* window2(CreateWindow(bounds
));
816 aura::Window
* window3(CreatePanelWindow(bounds
));
817 aura::Window
* window4(CreatePanelWindow(bounds
));
819 wm::ActivateWindow(window4
);
820 wm::ActivateWindow(window3
);
821 wm::ActivateWindow(window2
);
822 wm::ActivateWindow(window1
);
827 // Tests removing a display during overview.
828 TEST_F(WindowSelectorTest
, RemoveDisplay
) {
829 if (!SupportsMultipleDisplays())
832 UpdateDisplay("400x400,400x400");
833 gfx::Rect
bounds1(0, 0, 100, 100);
834 gfx::Rect
bounds2(450, 0, 100, 100);
835 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds1
));
836 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds2
));
837 scoped_ptr
<aura::Window
> window3(CreatePanelWindow(bounds1
));
838 scoped_ptr
<aura::Window
> window4(CreatePanelWindow(bounds2
));
840 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
841 EXPECT_EQ(root_windows
[0], window1
->GetRootWindow());
842 EXPECT_EQ(root_windows
[1], window2
->GetRootWindow());
843 EXPECT_EQ(root_windows
[0], window3
->GetRootWindow());
844 EXPECT_EQ(root_windows
[1], window4
->GetRootWindow());
846 wm::ActivateWindow(window4
.get());
847 wm::ActivateWindow(window3
.get());
848 wm::ActivateWindow(window2
.get());
849 wm::ActivateWindow(window1
.get());
852 EXPECT_TRUE(IsSelecting());
853 UpdateDisplay("400x400");
854 EXPECT_FALSE(IsSelecting());
857 // Tests starting overview during a drag and drop tracking operation.
858 // TODO(flackr): Fix memory corruption crash when running locally (not failing
859 // on bots). See http://crbug.com/342528.
860 TEST_F(WindowSelectorTest
, DISABLED_DragDropInProgress
) {
861 bool drag_canceled_by_test
= false;
862 gfx::Rect
bounds(0, 0, 400, 400);
863 scoped_ptr
<aura::Window
> window(CreateWindow(bounds
));
864 test::ShellTestApi
shell_test_api(Shell::GetInstance());
865 ash::DragDropController
* drag_drop_controller
=
866 shell_test_api
.drag_drop_controller();
867 ui::OSExchangeData data
;
868 base::MessageLoopForUI::current()->PostTask(FROM_HERE
,
869 base::Bind(&WindowSelectorTest::ToggleOverview
,
870 base::Unretained(this)));
871 base::MessageLoopForUI::current()->PostTask(FROM_HERE
,
872 base::Bind(&CancelDrag
, drag_drop_controller
, &drag_canceled_by_test
));
873 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
874 drag_drop_controller
->StartDragAndDrop(data
, window
->GetRootWindow(),
875 window
.get(), gfx::Point(5, 5), ui::DragDropTypes::DRAG_MOVE
,
876 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE
);
877 RunAllPendingInMessageLoop();
878 EXPECT_FALSE(drag_canceled_by_test
);
879 ASSERT_TRUE(IsSelecting());
880 RunAllPendingInMessageLoop();
883 // Test that a label is created under the window on entering overview mode.
884 TEST_F(WindowSelectorTest
, CreateLabelUnderWindow
) {
885 scoped_ptr
<aura::Window
> window(CreateWindow(gfx::Rect(0, 0, 100, 100)));
886 base::string16 window_title
= base::UTF8ToUTF16("My window");
887 window
->SetTitle(window_title
);
889 WindowSelectorItem
* window_item
= GetWindowItemsForRoot(0).back();
890 views::Label
* label
= GetLabelView(window_item
);
891 // Has the label view been created?
894 // Verify the label matches the window title.
895 EXPECT_EQ(label
->text(), window_title
);
897 // Update the window title and check that the label is updated, too.
898 base::string16 updated_title
= base::UTF8ToUTF16("Updated title");
899 window
->SetTitle(updated_title
);
900 EXPECT_EQ(label
->text(), updated_title
);
902 // Labels are located based on target_bounds, not the actual window item
904 gfx::Rect
target_bounds(window_item
->target_bounds());
905 gfx::Rect
expected_label_bounds(target_bounds
.x(),
906 target_bounds
.bottom() - label
->
907 GetPreferredSize().height(),
908 target_bounds
.width(),
909 label
->GetPreferredSize().height());
910 gfx::Rect real_label_bounds
= label
->GetWidget()->GetNativeWindow()->bounds();
911 EXPECT_EQ(real_label_bounds
, expected_label_bounds
);
914 // Tests that a label is created for the active panel in a group of panels in
916 TEST_F(WindowSelectorTest
, CreateLabelUnderPanel
) {
917 scoped_ptr
<aura::Window
> panel1(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
918 scoped_ptr
<aura::Window
> panel2(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
919 base::string16 panel1_title
= base::UTF8ToUTF16("My panel");
920 base::string16 panel2_title
= base::UTF8ToUTF16("Another panel");
921 base::string16 updated_panel1_title
= base::UTF8ToUTF16("WebDriver Torso");
922 base::string16 updated_panel2_title
= base::UTF8ToUTF16("Da panel");
923 panel1
->SetTitle(panel1_title
);
924 panel2
->SetTitle(panel2_title
);
925 wm::ActivateWindow(panel1
.get());
927 WindowSelectorItem
* window_item
= GetWindowItemsForRoot(0).back();
928 views::Label
* label
= GetLabelView(window_item
);
929 // Has the label view been created?
932 // Verify the label matches the active window title.
933 EXPECT_EQ(label
->text(), panel1_title
);
934 // Verify that updating the title also updates the label.
935 panel1
->SetTitle(updated_panel1_title
);
936 EXPECT_EQ(label
->text(), updated_panel1_title
);
937 // After destroying the first panel, the label should match the second panel.
939 label
= GetLabelView(window_item
);
940 EXPECT_EQ(label
->text(), panel2_title
);
941 // Also test updating the title on the second panel.
942 panel2
->SetTitle(updated_panel2_title
);
943 EXPECT_EQ(label
->text(), updated_panel2_title
);
946 // Tests that overview updates the window positions if the display orientation
948 TEST_F(WindowSelectorTest
, DisplayOrientationChanged
) {
949 if (!SupportsHostWindowResize())
952 aura::Window
* root_window
= Shell::GetInstance()->GetPrimaryRootWindow();
953 UpdateDisplay("600x200");
954 EXPECT_EQ("0,0 600x200", root_window
->bounds().ToString());
955 gfx::Rect
window_bounds(0, 0, 150, 150);
956 ScopedVector
<aura::Window
> windows
;
957 for (int i
= 0; i
< 3; i
++) {
958 windows
.push_back(CreateWindow(window_bounds
));
962 for (ScopedVector
<aura::Window
>::iterator iter
= windows
.begin();
963 iter
!= windows
.end(); ++iter
) {
964 EXPECT_TRUE(root_window
->bounds().Contains(
965 ToEnclosingRect(GetTransformedTargetBounds(*iter
))));
968 // Rotate the display, windows should be repositioned to be within the screen
970 UpdateDisplay("600x200/r");
971 EXPECT_EQ("0,0 200x600", root_window
->bounds().ToString());
972 for (ScopedVector
<aura::Window
>::iterator iter
= windows
.begin();
973 iter
!= windows
.end(); ++iter
) {
974 EXPECT_TRUE(root_window
->bounds().Contains(
975 ToEnclosingRect(GetTransformedTargetBounds(*iter
))));
979 // Tests traversing some windows in overview mode with the tab key.
980 TEST_F(WindowSelectorTest
, BasicTabKeyNavigation
) {
981 gfx::Rect
bounds(0, 0, 100, 100);
982 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
983 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
986 SendKey(ui::VKEY_TAB
);
987 EXPECT_EQ(GetSelectedWindow(), window1
.get());
988 SendKey(ui::VKEY_TAB
);
989 EXPECT_EQ(GetSelectedWindow(), window2
.get());
990 SendKey(ui::VKEY_TAB
);
991 EXPECT_EQ(GetSelectedWindow(), window1
.get());
994 // Tests traversing some windows in overview mode with the arrow keys in every
995 // possible direction.
996 TEST_F(WindowSelectorTest
, BasicArrowKeyNavigation
) {
997 if (!SupportsHostWindowResize())
999 const size_t test_windows
= 9;
1000 UpdateDisplay("800x600");
1001 ScopedVector
<aura::Window
> windows
;
1002 for (size_t i
= test_windows
; i
> 0; i
--)
1003 windows
.push_back(CreateWindowWithId(gfx::Rect(0, 0, 100, 100), i
));
1005 ui::KeyboardCode arrow_keys
[] = {
1011 // Expected window layout, assuming that the text filtering feature is
1012 // enabled by default (i.e., --ash-disable-text-filtering-in-overview-mode
1013 // is not being used).
1014 // +-------+ +-------+ +-------+ +-------+
1015 // | 1 | | 2 | | 3 | | 4 |
1016 // +-------+ +-------+ +-------+ +-------+
1017 // +-------+ +-------+ +-------+ +-------+
1018 // | 5 | | 6 | | 7 | | 8 |
1019 // +-------+ +-------+ +-------+ +-------+
1023 // Index for each window during a full loop plus wrapping around.
1024 int index_path_for_direction
[][test_windows
+ 1] = {
1025 {1, 2, 3, 4, 5, 6, 7, 8, 9, 1}, // Right
1026 {1, 5, 9, 2, 6, 3, 7, 4, 8, 1}, // Down
1027 {9, 8, 7, 6, 5, 4, 3, 2, 1, 9}, // Left
1028 {8, 4, 7, 3, 6, 2, 9, 5, 1, 8} // Up
1031 for (size_t key_index
= 0; key_index
< arraysize(arrow_keys
); key_index
++) {
1033 for (size_t i
= 0; i
< test_windows
+ 1; i
++) {
1034 SendKey(arrow_keys
[key_index
]);
1035 // TODO(flackr): Add a more readable error message by constructing a
1036 // string from the window IDs.
1037 EXPECT_EQ(GetSelectedWindow()->id(),
1038 index_path_for_direction
[key_index
][i
]);
1044 // Tests basic selection across multiple monitors.
1045 TEST_F(WindowSelectorTest
, BasicMultiMonitorArrowKeyNavigation
) {
1046 if (!SupportsMultipleDisplays())
1049 UpdateDisplay("400x400,400x400");
1050 gfx::Rect
bounds1(0, 0, 100, 100);
1051 gfx::Rect
bounds2(450, 0, 100, 100);
1052 scoped_ptr
<aura::Window
> window4(CreateWindow(bounds2
));
1053 scoped_ptr
<aura::Window
> window3(CreateWindow(bounds2
));
1054 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds1
));
1055 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds1
));
1060 SendKey(ui::VKEY_RIGHT
);
1061 EXPECT_EQ(GetSelectedWindow(), window1
.get());
1062 SendKey(ui::VKEY_RIGHT
);
1063 EXPECT_EQ(GetSelectedWindow(), window2
.get());
1064 SendKey(ui::VKEY_RIGHT
);
1065 EXPECT_EQ(GetSelectedWindow(), window3
.get());
1066 SendKey(ui::VKEY_RIGHT
);
1067 EXPECT_EQ(GetSelectedWindow(), window4
.get());
1070 // Tests selecting a window in overview mode with the return key.
1071 TEST_F(WindowSelectorTest
, SelectWindowWithReturnKey
) {
1072 gfx::Rect
bounds(0, 0, 100, 100);
1073 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
1074 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
1077 // Pressing the return key without a selection widget should not do anything.
1078 SendKey(ui::VKEY_RETURN
);
1079 EXPECT_TRUE(IsSelecting());
1081 // Select the first window.
1082 SendKey(ui::VKEY_RIGHT
);
1083 SendKey(ui::VKEY_RETURN
);
1084 ASSERT_FALSE(IsSelecting());
1085 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
1087 // Select the second window.
1089 SendKey(ui::VKEY_RIGHT
);
1090 SendKey(ui::VKEY_RIGHT
);
1091 SendKey(ui::VKEY_RETURN
);
1092 EXPECT_FALSE(IsSelecting());
1093 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
1096 // Tests that overview mode hides the callout widget.
1097 TEST_F(WindowSelectorTest
, WindowOverviewHidesCalloutWidgets
) {
1098 scoped_ptr
<aura::Window
> panel1(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
1099 scoped_ptr
<aura::Window
> panel2(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
1100 PanelLayoutManager
* panel_manager
=
1101 static_cast<PanelLayoutManager
*>(panel1
->parent()->layout_manager());
1103 // By default, panel callout widgets are visible.
1105 panel_manager
->GetCalloutWidgetForPanel(panel1
.get())->IsVisible());
1107 panel_manager
->GetCalloutWidgetForPanel(panel2
.get())->IsVisible());
1109 // Toggling the overview should hide the callout widgets.
1112 panel_manager
->GetCalloutWidgetForPanel(panel1
.get())->IsVisible());
1114 panel_manager
->GetCalloutWidgetForPanel(panel2
.get())->IsVisible());
1116 // Ending the overview should show them again.
1119 panel_manager
->GetCalloutWidgetForPanel(panel1
.get())->IsVisible());
1121 panel_manager
->GetCalloutWidgetForPanel(panel2
.get())->IsVisible());
1124 // Tests that when panels are grouped that the close button only closes the
1125 // currently active panel. After the removal window selection should still be
1126 // active, and the label should have changed. Removing the last panel should
1127 // cause selection to end.
1128 TEST_F(WindowSelectorTest
, CloseButtonOnPanels
) {
1129 scoped_ptr
<views::Widget
> widget1(CreatePanelWindowWidget(
1130 gfx::Rect(0, 0, 300, 100)));
1131 scoped_ptr
<views::Widget
> widget2(CreatePanelWindowWidget(
1132 gfx::Rect(100, 0, 100, 100)));
1133 aura::Window
* window1
= widget1
->GetNativeWindow();
1134 aura::Window
* window2
= widget2
->GetNativeWindow();
1135 base::string16 panel1_title
= base::UTF8ToUTF16("Panel 1");
1136 base::string16 panel2_title
= base::UTF8ToUTF16("Panel 2");
1137 window1
->SetTitle(panel1_title
);
1138 window2
->SetTitle(panel2_title
);
1139 wm::ActivateWindow(window1
);
1142 gfx::RectF bounds1
= GetTransformedBoundsInRootWindow(window1
);
1143 gfx::Point
point1(bounds1
.top_right().x() - 1, bounds1
.top_right().y() - 1);
1144 ui::test::EventGenerator
event_generator1(window1
->GetRootWindow(), point1
);
1146 EXPECT_FALSE(widget1
->IsClosed());
1147 event_generator1
.ClickLeftButton();
1148 EXPECT_TRUE(widget1
->IsClosed());
1149 RunAllPendingInMessageLoop();
1150 EXPECT_TRUE(IsSelecting());
1151 WindowSelectorItem
* window_item
= GetWindowItemsForRoot(0).front();
1152 EXPECT_FALSE(window_item
->empty());
1153 EXPECT_TRUE(window_item
->Contains(window2
));
1154 EXPECT_TRUE(GetCloseButton(window_item
)->IsVisible());
1157 views::Label
* label
= GetLabelView(window_item
);
1158 EXPECT_EQ(label
->text(), panel2_title
);
1160 gfx::RectF bounds2
= GetTransformedBoundsInRootWindow(window2
);
1161 gfx::Point
point2(bounds2
.top_right().x() - 1, bounds2
.top_right().y() - 1);
1162 ui::test::EventGenerator
event_generator2(window2
->GetRootWindow(), point2
);
1164 EXPECT_FALSE(widget2
->IsClosed());
1165 event_generator2
.ClickLeftButton();
1166 EXPECT_TRUE(widget2
->IsClosed());
1167 RunAllPendingInMessageLoop();
1168 EXPECT_FALSE(IsSelecting());
1171 // Creates three windows and tests filtering them by title.
1172 TEST_F(WindowSelectorTest
, BasicTextFiltering
) {
1173 gfx::Rect
bounds(0, 0, 100, 100);
1174 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
1175 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
1176 scoped_ptr
<aura::Window
> window0(CreateWindow(bounds
));
1177 base::string16 window2_title
= base::UTF8ToUTF16("Highway to test");
1178 base::string16 window1_title
= base::UTF8ToUTF16("For those about to test");
1179 base::string16 window0_title
= base::UTF8ToUTF16("We salute you");
1180 window0
->SetTitle(window0_title
);
1181 window1
->SetTitle(window1_title
);
1182 window2
->SetTitle(window2_title
);
1184 EXPECT_FALSE(selection_widget_active());
1185 EXPECT_FALSE(showing_filter_widget());
1186 FilterItems("Test");
1188 // The selection widget should appear when filtering starts, and should be
1189 // selecting the first matching window.
1190 EXPECT_TRUE(selection_widget_active());
1191 EXPECT_TRUE(showing_filter_widget());
1192 EXPECT_EQ(GetSelectedWindow(), window1
.get());
1194 // Window 0 has no "test" on it so it should be the only dimmed item.
1195 std::vector
<WindowSelectorItem
*> items
= GetWindowItemsForRoot(0);
1196 EXPECT_TRUE(items
[0]->dimmed());
1197 EXPECT_FALSE(items
[1]->dimmed());
1198 EXPECT_FALSE(items
[2]->dimmed());
1200 // No items match the search.
1201 FilterItems("I'm testing 'n testing");
1202 EXPECT_TRUE(items
[0]->dimmed());
1203 EXPECT_TRUE(items
[1]->dimmed());
1204 EXPECT_TRUE(items
[2]->dimmed());
1206 // All the items should match the empty string. The filter widget should also
1209 EXPECT_FALSE(showing_filter_widget());
1210 EXPECT_FALSE(items
[0]->dimmed());
1211 EXPECT_FALSE(items
[1]->dimmed());
1212 EXPECT_FALSE(items
[2]->dimmed());
1215 // Tests selecting in the overview with dimmed and undimmed items.
1216 TEST_F(WindowSelectorTest
, TextFilteringSelection
) {
1217 gfx::Rect
bounds(0, 0, 100, 100);
1218 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
1219 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
1220 scoped_ptr
<aura::Window
> window0(CreateWindow(bounds
));
1221 base::string16 window2_title
= base::UTF8ToUTF16("Rock and roll");
1222 base::string16 window1_title
= base::UTF8ToUTF16("Rock and");
1223 base::string16 window0_title
= base::UTF8ToUTF16("Rock");
1224 window0
->SetTitle(window0_title
);
1225 window1
->SetTitle(window1_title
);
1226 window2
->SetTitle(window2_title
);
1228 SendKey(ui::VKEY_RIGHT
);
1229 EXPECT_TRUE(selection_widget_active());
1230 EXPECT_EQ(GetSelectedWindow(), window0
.get());
1232 // Dim the first item, the selection should jump to the next item.
1233 std::vector
<WindowSelectorItem
*> items
= GetWindowItemsForRoot(0);
1234 FilterItems("Rock and");
1235 EXPECT_EQ(GetSelectedWindow(), window1
.get());
1237 // Cycle the selection, the dimmed window should not be selected.
1238 SendKey(ui::VKEY_RIGHT
);
1239 EXPECT_EQ(GetSelectedWindow(), window2
.get());
1240 SendKey(ui::VKEY_RIGHT
);
1241 EXPECT_EQ(GetSelectedWindow(), window1
.get());
1243 // Dimming all the items should hide the selection widget.
1245 EXPECT_FALSE(selection_widget_active());
1247 // Undimming one window should automatically select it.
1248 FilterItems("Rock and roll");
1249 EXPECT_EQ(GetSelectedWindow(), window2
.get());
1252 // Tests clicking on the desktop itself to cancel overview mode.
1253 TEST_F(WindowSelectorTest
, CancelOverviewOnMouseClick
) {
1254 // Overview disabled by default.
1255 EXPECT_FALSE(IsSelecting());
1257 // Point and bounds selected so that they don't intersect. This causes
1258 // events located at the point to be passed to DesktopBackgroundController,
1259 // and not the window.
1260 gfx::Point
point_in_background_page(0, 0);
1261 gfx::Rect
bounds(10, 10, 100, 100);
1262 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
1263 ui::test::EventGenerator
& generator
= GetEventGenerator();
1264 // Move mouse to point in the background page. Sending an event here will pass
1265 // it to the DesktopBackgroundController in both regular and overview mode.
1266 generator
.MoveMouseTo(point_in_background_page
);
1268 // Clicking on the background page while not in overview should not toggle
1270 generator
.ClickLeftButton();
1271 EXPECT_FALSE(IsSelecting());
1273 // Switch to overview mode.
1275 ASSERT_TRUE(IsSelecting());
1277 // Click should now exit overview mode.
1278 generator
.ClickLeftButton();
1279 EXPECT_FALSE(IsSelecting());
1282 // Tests tapping on the desktop itself to cancel overview mode.
1283 TEST_F(WindowSelectorTest
, CancelOverviewOnTap
) {
1284 // Overview disabled by default.
1285 EXPECT_FALSE(IsSelecting());
1287 // Point and bounds selected so that they don't intersect. This causes
1288 // events located at the point to be passed to DesktopBackgroundController,
1289 // and not the window.
1290 gfx::Point
point_in_background_page(0, 0);
1291 gfx::Rect
bounds(10, 10, 100, 100);
1292 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
1293 ui::test::EventGenerator
& generator
= GetEventGenerator();
1295 // Tapping on the background page while not in overview should not toggle
1297 generator
.GestureTapAt(point_in_background_page
);
1298 EXPECT_FALSE(IsSelecting());
1300 // Switch to overview mode.
1302 ASSERT_TRUE(IsSelecting());
1304 // Tap should now exit overview mode.
1305 generator
.GestureTapAt(point_in_background_page
);
1306 EXPECT_FALSE(IsSelecting());