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 virtual bool ShouldActivate() const override
{
64 void CancelDrag(DragDropController
* controller
, bool* canceled
) {
65 if (controller
->IsDragDropInProgress()) {
67 controller
->DragCancel();
73 class WindowSelectorTest
: public test::AshTestBase
{
75 WindowSelectorTest() {}
76 virtual ~WindowSelectorTest() {}
78 virtual void SetUp() override
{
79 test::AshTestBase::SetUp();
80 ASSERT_TRUE(test::TestShelfDelegate::instance());
82 shelf_view_test_
.reset(new test::ShelfViewTestAPI(
83 test::ShelfTestAPI(Shelf::ForPrimaryDisplay()).shelf_view()));
84 shelf_view_test_
->SetAnimationDuration(1);
87 aura::Window
* CreateWindow(const gfx::Rect
& bounds
) {
88 return CreateTestWindowInShellWithDelegate(&delegate_
, -1, bounds
);
91 aura::Window
* CreateWindowWithId(const gfx::Rect
& bounds
, int id
) {
92 return CreateTestWindowInShellWithDelegate(&delegate_
, id
, bounds
);
94 aura::Window
* CreateNonActivatableWindow(const gfx::Rect
& bounds
) {
95 aura::Window
* window
= CreateWindow(bounds
);
96 aura::client::SetActivationDelegate(window
,
97 &non_activatable_activation_delegate_
);
98 EXPECT_FALSE(ash::wm::CanActivateWindow(window
));
102 aura::Window
* CreatePanelWindow(const gfx::Rect
& bounds
) {
103 aura::Window
* window
= CreateTestWindowInShellWithDelegateAndType(
104 NULL
, ui::wm::WINDOW_TYPE_PANEL
, 0, bounds
);
105 test::TestShelfDelegate::instance()->AddShelfItem(window
);
106 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
110 views::Widget
* CreatePanelWindowWidget(const gfx::Rect
& bounds
) {
111 views::Widget
* widget
= new views::Widget
;
112 views::Widget::InitParams params
;
113 params
.bounds
= bounds
;
114 params
.type
= views::Widget::InitParams::TYPE_PANEL
;
115 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
116 widget
->Init(params
);
118 ParentWindowInPrimaryRootWindow(widget
->GetNativeWindow());
122 bool WindowsOverlapping(aura::Window
* window1
, aura::Window
* window2
) {
123 gfx::RectF window1_bounds
= GetTransformedTargetBounds(window1
);
124 gfx::RectF window2_bounds
= GetTransformedTargetBounds(window2
);
125 return window1_bounds
.Intersects(window2_bounds
);
128 void ToggleOverview() {
129 ash::Shell::GetInstance()->window_selector_controller()->ToggleOverview();
132 gfx::Transform
GetTransformRelativeTo(gfx::PointF origin
,
133 const gfx::Transform
& transform
) {
135 t
.Translate(origin
.x(), origin
.y());
136 t
.PreconcatTransform(transform
);
137 t
.Translate(-origin
.x(), -origin
.y());
141 gfx::RectF
GetTransformedBounds(aura::Window
* window
) {
142 gfx::RectF
bounds(ScreenUtil::ConvertRectToScreen(
143 window
->parent(), window
->layer()->bounds()));
144 gfx::Transform
transform(GetTransformRelativeTo(bounds
.origin(),
145 window
->layer()->transform()));
146 transform
.TransformRect(&bounds
);
150 gfx::RectF
GetTransformedTargetBounds(aura::Window
* window
) {
151 gfx::RectF
bounds(ScreenUtil::ConvertRectToScreen(
152 window
->parent(), window
->layer()->GetTargetBounds()));
153 gfx::Transform
transform(GetTransformRelativeTo(bounds
.origin(),
154 window
->layer()->GetTargetTransform()));
155 transform
.TransformRect(&bounds
);
159 gfx::RectF
GetTransformedBoundsInRootWindow(aura::Window
* window
) {
160 gfx::RectF bounds
= gfx::Rect(window
->bounds().size());
161 aura::Window
* root
= window
->GetRootWindow();
162 CHECK(window
->layer());
163 CHECK(root
->layer());
164 gfx::Transform transform
;
165 if (!window
->layer()->GetTargetTransformRelativeTo(root
->layer(),
169 transform
.TransformRect(&bounds
);
173 void ClickWindow(aura::Window
* window
) {
174 ui::test::EventGenerator
event_generator(window
->GetRootWindow(), window
);
175 gfx::RectF target
= GetTransformedBounds(window
);
176 event_generator
.ClickLeftButton();
179 void SendKey(ui::KeyboardCode key
) {
180 ui::test::EventGenerator
event_generator(Shell::GetPrimaryRootWindow());
181 event_generator
.PressKey(key
, 0);
182 event_generator
.ReleaseKey(key
, 0);
186 return ash::Shell::GetInstance()->window_selector_controller()->
190 aura::Window
* GetFocusedWindow() {
191 return aura::client::GetFocusClient(
192 Shell::GetPrimaryRootWindow())->GetFocusedWindow();
195 const std::vector
<WindowSelectorItem
*>& GetWindowItemsForRoot(int index
) {
196 return ash::Shell::GetInstance()->window_selector_controller()->
197 window_selector_
->grid_list_
[index
]->window_list_
.get();
200 const aura::Window
* GetSelectedWindow() {
201 WindowSelector
* ws
= ash::Shell::GetInstance()->
202 window_selector_controller()->window_selector_
.get();
203 return ws
->grid_list_
[ws
->selected_grid_index_
]->
204 SelectedWindow()->SelectionWindow();
207 bool selection_widget_active() {
208 WindowSelector
* ws
= ash::Shell::GetInstance()->
209 window_selector_controller()->window_selector_
.get();
210 return ws
->grid_list_
[ws
->selected_grid_index_
]->is_selecting();
213 bool showing_filter_widget() {
214 WindowSelector
* ws
= ash::Shell::GetInstance()->
215 window_selector_controller()->window_selector_
.get();
216 return ws
->text_filter_widget_
->GetNativeWindow()->layer()->
217 GetTargetTransform().IsIdentity();
220 views::Widget
* GetCloseButton(ash::WindowSelectorItem
* window
) {
221 return window
->close_button_
.get();
224 views::Label
* GetLabelView(ash::WindowSelectorItem
* window
) {
225 return window
->window_label_view_
;
228 // Tests that a window is contained within a given WindowSelectorItem, and
229 // that both the window and its matching close button are within the same
231 void IsWindowAndCloseButtonInScreen(aura::Window
* window
,
232 WindowSelectorItem
* window_item
) {
233 aura::Window
* root_window
= window_item
->GetRootWindow();
234 EXPECT_TRUE(window_item
->Contains(window
));
235 EXPECT_TRUE(root_window
->GetBoundsInScreen().Contains(
236 ToEnclosingRect(GetTransformedTargetBounds(window
))));
237 EXPECT_TRUE(root_window
->GetBoundsInScreen().Contains(
238 ToEnclosingRect(GetTransformedTargetBounds(
239 GetCloseButton(window_item
)->GetNativeView()))));
242 void FilterItems(const base::StringPiece
& pattern
) {
243 ash::Shell::GetInstance()->
244 window_selector_controller()->window_selector_
.get()->
245 ContentsChanged(NULL
, base::UTF8ToUTF16(pattern
));
248 test::ShelfViewTestAPI
* shelf_view_test() {
249 return shelf_view_test_
.get();
252 views::Widget
* text_filter_widget() {
253 return ash::Shell::GetInstance()->
254 window_selector_controller()->window_selector_
.get()->
255 text_filter_widget_
.get();
259 aura::test::TestWindowDelegate delegate_
;
260 NonActivatableActivationDelegate non_activatable_activation_delegate_
;
261 scoped_ptr
<test::ShelfViewTestAPI
> shelf_view_test_
;
263 DISALLOW_COPY_AND_ASSIGN(WindowSelectorTest
);
266 // Tests that an a11y alert is sent on entering overview mode.
267 TEST_F(WindowSelectorTest
, A11yAlertOnOverviewMode
) {
268 gfx::Rect
bounds(0, 0, 400, 400);
269 AccessibilityDelegate
* delegate
=
270 ash::Shell::GetInstance()->accessibility_delegate();
271 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
272 EXPECT_NE(delegate
->GetLastAccessibilityAlert(),
273 A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED
);
275 EXPECT_EQ(delegate
->GetLastAccessibilityAlert(),
276 A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED
);
279 // Tests entering overview mode with two windows and selecting one by clicking.
280 TEST_F(WindowSelectorTest
, Basic
) {
281 gfx::Rect
bounds(0, 0, 400, 400);
282 aura::Window
* root_window
= Shell::GetPrimaryRootWindow();
283 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
284 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
285 scoped_ptr
<aura::Window
> panel1(CreatePanelWindow(bounds
));
286 scoped_ptr
<aura::Window
> panel2(CreatePanelWindow(bounds
));
287 EXPECT_TRUE(WindowsOverlapping(window1
.get(), window2
.get()));
288 EXPECT_TRUE(WindowsOverlapping(panel1
.get(), panel2
.get()));
289 wm::ActivateWindow(window2
.get());
290 EXPECT_FALSE(wm::IsActiveWindow(window1
.get()));
291 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
292 EXPECT_EQ(window2
.get(), GetFocusedWindow());
293 // Hide the cursor before entering overview to test that it will be shown.
294 aura::client::GetCursorClient(root_window
)->HideCursor();
296 // In overview mode the windows should no longer overlap and the text filter
297 // widget should be focused.
299 EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow());
300 EXPECT_FALSE(WindowsOverlapping(window1
.get(), window2
.get()));
301 EXPECT_FALSE(WindowsOverlapping(window1
.get(), panel1
.get()));
302 // Panels 1 and 2 should still be overlapping being in a single selector
304 EXPECT_TRUE(WindowsOverlapping(panel1
.get(), panel2
.get()));
306 // Clicking window 1 should activate it.
307 ClickWindow(window1
.get());
308 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
309 EXPECT_FALSE(wm::IsActiveWindow(window2
.get()));
310 EXPECT_EQ(window1
.get(), GetFocusedWindow());
312 // Cursor should have been unlocked.
313 EXPECT_FALSE(aura::client::GetCursorClient(root_window
)->IsCursorLocked());
316 // Tests selecting a window by tapping on it.
317 TEST_F(WindowSelectorTest
, BasicGesture
) {
318 gfx::Rect
bounds(0, 0, 400, 400);
319 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
320 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
321 wm::ActivateWindow(window1
.get());
322 EXPECT_EQ(window1
.get(), GetFocusedWindow());
324 EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow());
325 ui::test::EventGenerator
generator(Shell::GetPrimaryRootWindow(),
327 generator
.GestureTapAt(gfx::ToEnclosingRect(
328 GetTransformedTargetBounds(window2
.get())).CenterPoint());
329 EXPECT_EQ(window2
.get(), GetFocusedWindow());
332 // Tests that a window does not receive located events when in overview mode.
333 TEST_F(WindowSelectorTest
, WindowDoesNotReceiveEvents
) {
334 gfx::Rect
window_bounds(20, 10, 200, 300);
335 aura::Window
* root_window
= Shell::GetPrimaryRootWindow();
336 scoped_ptr
<aura::Window
> window(CreateWindow(window_bounds
));
338 gfx::Point
point1(window_bounds
.x() + 10, window_bounds
.y() + 10);
340 ui::MouseEvent
event1(ui::ET_MOUSE_PRESSED
, point1
, point1
,
341 ui::EF_NONE
, ui::EF_NONE
);
343 ui::EventTarget
* root_target
= root_window
;
344 ui::EventTargeter
* targeter
= root_target
->GetEventTargeter();
346 // The event should target the window because we are still not in overview
348 EXPECT_EQ(window
, static_cast<aura::Window
*>(
349 targeter
->FindTargetForEvent(root_target
, &event1
)));
353 // The bounds have changed, take that into account.
354 gfx::RectF bounds
= GetTransformedBoundsInRootWindow(window
.get());
355 gfx::Point
point2(bounds
.x() + 10, bounds
.y() + 10);
356 ui::MouseEvent
event2(ui::ET_MOUSE_PRESSED
, point2
, point2
,
357 ui::EF_NONE
, ui::EF_NONE
);
359 // Now the transparent window should be intercepting this event.
360 EXPECT_NE(window
, static_cast<aura::Window
*>(
361 targeter
->FindTargetForEvent(root_target
, &event2
)));
364 // Tests that clicking on the close button effectively closes the window.
365 TEST_F(WindowSelectorTest
, CloseButton
) {
366 scoped_ptr
<aura::Window
> window1(CreateWindow(gfx::Rect(200, 300, 250, 450)));
368 // We need a widget for the close button the work, a bare window will crash.
369 scoped_ptr
<views::Widget
> widget(new views::Widget
);
370 views::Widget::InitParams params
;
371 params
.bounds
= gfx::Rect(0, 0, 400, 400);
372 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
373 params
.parent
= window1
->parent();
374 widget
->Init(params
);
378 aura::Window
* window2
= widget
->GetNativeWindow();
379 gfx::RectF bounds
= GetTransformedBoundsInRootWindow(window2
);
380 gfx::Point
point(bounds
.top_right().x() - 1, bounds
.top_right().y() - 1);
381 ui::test::EventGenerator
event_generator(window2
->GetRootWindow(), point
);
383 EXPECT_FALSE(widget
->IsClosed());
384 event_generator
.ClickLeftButton();
385 EXPECT_TRUE(widget
->IsClosed());
388 // Tests entering overview mode with two windows and selecting one.
389 TEST_F(WindowSelectorTest
, FullscreenWindow
) {
390 gfx::Rect
bounds(0, 0, 400, 400);
391 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
392 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
393 scoped_ptr
<aura::Window
> panel1(CreatePanelWindow(bounds
));
394 wm::ActivateWindow(window1
.get());
396 const wm::WMEvent
toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN
);
397 wm::GetWindowState(window1
.get())->OnWMEvent(&toggle_fullscreen_event
);
398 // The panel is hidden in fullscreen mode.
399 EXPECT_FALSE(panel1
->IsVisible());
400 EXPECT_TRUE(wm::GetWindowState(window1
.get())->IsFullscreen());
402 // Enter overview and select the fullscreen window.
405 // The panel becomes temporarily visible for the overview.
406 EXPECT_TRUE(panel1
->IsVisible());
407 ClickWindow(window1
.get());
409 // The window is still fullscreen as it was selected. The panel should again
411 EXPECT_TRUE(wm::GetWindowState(window1
.get())->IsFullscreen());
412 EXPECT_FALSE(panel1
->IsVisible());
414 // Entering overview and selecting another window, the previous window remains
416 // TODO(flackr): Currently the panel remains hidden, but should become visible
419 ClickWindow(window2
.get());
420 EXPECT_TRUE(wm::GetWindowState(window1
.get())->IsFullscreen());
423 // Tests that the shelf dimming state is removed while in overview and restored
424 // on exiting overview.
425 TEST_F(WindowSelectorTest
, OverviewUndimsShelf
) {
426 gfx::Rect
bounds(0, 0, 400, 400);
427 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
428 wm::WindowState
* window_state
= wm::GetWindowState(window1
.get());
429 window_state
->Maximize();
430 ash::ShelfWidget
* shelf
= Shell::GetPrimaryRootWindowController()->shelf();
431 EXPECT_TRUE(shelf
->GetDimsShelf());
433 EXPECT_FALSE(shelf
->GetDimsShelf());
435 EXPECT_TRUE(shelf
->GetDimsShelf());
438 // Tests that entering overview when a fullscreen window is active in maximized
439 // mode correctly applies the transformations to the window and correctly
440 // updates the window bounds on exiting overview mode: http://crbug.com/401664.
441 TEST_F(WindowSelectorTest
, FullscreenWindowMaximizeMode
) {
442 gfx::Rect
bounds(0, 0, 400, 400);
443 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
444 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
445 Shell::GetInstance()->maximize_mode_controller()->
446 EnableMaximizeModeWindowManager(true);
447 wm::ActivateWindow(window2
.get());
448 wm::ActivateWindow(window1
.get());
449 gfx::Rect
normal_window_bounds(window1
->bounds());
450 const wm::WMEvent
toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN
);
451 wm::GetWindowState(window1
.get())->OnWMEvent(&toggle_fullscreen_event
);
452 gfx::Rect
fullscreen_window_bounds(window1
->bounds());
453 EXPECT_NE(normal_window_bounds
.ToString(),
454 fullscreen_window_bounds
.ToString());
455 EXPECT_EQ(fullscreen_window_bounds
.ToString(),
456 window2
->GetTargetBounds().ToString());
458 // Window 2 would normally resize to normal window bounds on showing the shelf
459 // for overview but this is deferred until overview is exited.
460 EXPECT_EQ(fullscreen_window_bounds
.ToString(),
461 window2
->GetTargetBounds().ToString());
462 EXPECT_FALSE(WindowsOverlapping(window1
.get(), window2
.get()));
465 // Since the fullscreen window is still active, window2 will still have the
467 EXPECT_EQ(fullscreen_window_bounds
.ToString(),
468 window2
->GetTargetBounds().ToString());
470 // Enter overview again and select window 2. Selecting window 2 should show
471 // the shelf bringing window2 back to the normal bounds.
473 ClickWindow(window2
.get());
474 EXPECT_EQ(normal_window_bounds
.ToString(),
475 window2
->GetTargetBounds().ToString());
478 // Tests that beginning window selection hides the app list.
479 TEST_F(WindowSelectorTest
, SelectingHidesAppList
) {
480 gfx::Rect
bounds(0, 0, 400, 400);
481 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
482 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
483 Shell::GetInstance()->ShowAppList(NULL
);
484 EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility());
486 EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility());
490 // Tests that a minimized window's visibility and layer visibility is correctly
491 // changed when entering overview and restored when leaving overview mode.
492 // Crashes after the skia roll in http://crrev.com/274114.
493 // http://crbug.com/379570
494 TEST_F(WindowSelectorTest
, DISABLED_MinimizedWindowVisibility
) {
495 gfx::Rect
bounds(0, 0, 400, 400);
496 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
497 wm::WindowState
* window_state
= wm::GetWindowState(window1
.get());
498 window_state
->Minimize();
499 EXPECT_FALSE(window1
->IsVisible());
500 EXPECT_FALSE(window1
->layer()->GetTargetVisibility());
502 ui::ScopedAnimationDurationScaleMode
test_duration_mode(
503 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION
);
505 EXPECT_TRUE(window1
->IsVisible());
506 EXPECT_TRUE(window1
->layer()->GetTargetVisibility());
509 ui::ScopedAnimationDurationScaleMode
test_duration_mode(
510 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION
);
512 EXPECT_FALSE(window1
->IsVisible());
513 EXPECT_FALSE(window1
->layer()->GetTargetVisibility());
517 // Tests that a bounds change during overview is corrected for.
518 TEST_F(WindowSelectorTest
, BoundsChangeDuringOverview
) {
519 scoped_ptr
<aura::Window
> window(CreateWindow(gfx::Rect(0, 0, 400, 400)));
521 gfx::Rect overview_bounds
=
522 ToEnclosingRect(GetTransformedTargetBounds(window
.get()));
523 window
->SetBounds(gfx::Rect(200, 0, 200, 200));
524 gfx::Rect new_overview_bounds
=
525 ToEnclosingRect(GetTransformedTargetBounds(window
.get()));
526 EXPECT_EQ(overview_bounds
.x(), new_overview_bounds
.x());
527 EXPECT_EQ(overview_bounds
.y(), new_overview_bounds
.y());
528 EXPECT_EQ(overview_bounds
.width(), new_overview_bounds
.width());
529 EXPECT_EQ(overview_bounds
.height(), new_overview_bounds
.height());
533 // Tests that a newly created window aborts overview.
534 TEST_F(WindowSelectorTest
, NewWindowCancelsOveriew
) {
535 gfx::Rect
bounds(0, 0, 400, 400);
536 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
537 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
539 EXPECT_TRUE(IsSelecting());
541 // A window being created should exit overview mode.
542 scoped_ptr
<aura::Window
> window3(CreateWindow(bounds
));
543 EXPECT_FALSE(IsSelecting());
546 // Tests that a window activation exits overview mode.
547 TEST_F(WindowSelectorTest
, ActivationCancelsOveriew
) {
548 gfx::Rect
bounds(0, 0, 400, 400);
549 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
550 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
553 EXPECT_TRUE(IsSelecting());
555 // A window being activated should exit overview mode.
557 EXPECT_FALSE(IsSelecting());
559 // window1 should be focused after exiting even though window2 was focused on
560 // entering overview because we exited due to an activation.
561 EXPECT_EQ(window1
.get(), GetFocusedWindow());
564 // Tests that exiting overview mode without selecting a window restores focus
565 // to the previously focused window.
566 TEST_F(WindowSelectorTest
, CancelRestoresFocus
) {
567 gfx::Rect
bounds(0, 0, 400, 400);
568 scoped_ptr
<aura::Window
> window(CreateWindow(bounds
));
569 wm::ActivateWindow(window
.get());
570 EXPECT_EQ(window
.get(), GetFocusedWindow());
572 // In overview mode, the text filter widget should be focused.
574 EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow());
576 // If canceling overview mode, focus should be restored.
578 EXPECT_EQ(window
.get(), GetFocusedWindow());
581 // Tests that overview mode is exited if the last remaining window is destroyed.
582 TEST_F(WindowSelectorTest
, LastWindowDestroyed
) {
583 gfx::Rect
bounds(0, 0, 400, 400);
584 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
585 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
590 EXPECT_FALSE(IsSelecting());
593 // Tests that entering overview mode restores a window to its original
595 TEST_F(WindowSelectorTest
, QuickReentryRestoresInitialTransform
) {
596 gfx::Rect
bounds(0, 0, 400, 400);
597 scoped_ptr
<aura::Window
> window(CreateWindow(bounds
));
598 gfx::Rect initial_bounds
= ToEnclosingRect(
599 GetTransformedBounds(window
.get()));
601 // Quickly exit and reenter overview mode. The window should still be
602 // animating when we reenter. We cannot short circuit animations for this but
603 // we also don't have to wait for them to complete.
605 ui::ScopedAnimationDurationScaleMode
test_duration_mode(
606 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION
);
610 EXPECT_NE(initial_bounds
, ToEnclosingRect(
611 GetTransformedTargetBounds(window
.get())));
613 EXPECT_FALSE(IsSelecting());
614 EXPECT_EQ(initial_bounds
, ToEnclosingRect(
615 GetTransformedTargetBounds(window
.get())));
618 // Tests that non-activatable windows are hidden when entering overview mode.
619 TEST_F(WindowSelectorTest
, NonActivatableWindowsHidden
) {
620 gfx::Rect
bounds(0, 0, 400, 400);
621 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
622 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
623 scoped_ptr
<aura::Window
> non_activatable_window(
624 CreateNonActivatableWindow(Shell::GetPrimaryRootWindow()->bounds()));
625 EXPECT_TRUE(non_activatable_window
->IsVisible());
627 EXPECT_FALSE(non_activatable_window
->IsVisible());
629 EXPECT_TRUE(non_activatable_window
->IsVisible());
631 // Test that a window behind the fullscreen non-activatable window can be
633 non_activatable_window
->parent()->StackChildAtTop(
634 non_activatable_window
.get());
636 ClickWindow(window1
.get());
637 EXPECT_FALSE(IsSelecting());
638 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
641 // Tests that windows with modal child windows are transformed with the modal
642 // child even though not activatable themselves.
643 TEST_F(WindowSelectorTest
, ModalChild
) {
644 gfx::Rect
bounds(0, 0, 400, 400);
645 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
646 scoped_ptr
<aura::Window
> child1(CreateWindow(bounds
));
647 child1
->SetProperty(aura::client::kModalKey
, ui::MODAL_TYPE_WINDOW
);
648 ::wm::AddTransientChild(window1
.get(), child1
.get());
649 EXPECT_EQ(window1
->parent(), child1
->parent());
651 EXPECT_TRUE(window1
->IsVisible());
652 EXPECT_TRUE(child1
->IsVisible());
653 EXPECT_EQ(ToEnclosingRect(GetTransformedTargetBounds(child1
.get())),
654 ToEnclosingRect(GetTransformedTargetBounds(window1
.get())));
658 // Tests that clicking a modal window's parent activates the modal window in
660 TEST_F(WindowSelectorTest
, ClickModalWindowParent
) {
661 scoped_ptr
<aura::Window
> window1(CreateWindow(gfx::Rect(0, 0, 180, 180)));
662 scoped_ptr
<aura::Window
> child1(CreateWindow(gfx::Rect(200, 0, 180, 180)));
663 child1
->SetProperty(aura::client::kModalKey
, ui::MODAL_TYPE_WINDOW
);
664 ::wm::AddTransientChild(window1
.get(), child1
.get());
665 EXPECT_FALSE(WindowsOverlapping(window1
.get(), child1
.get()));
666 EXPECT_EQ(window1
->parent(), child1
->parent());
668 // Given that their relative positions are preserved, the windows should still
670 EXPECT_FALSE(WindowsOverlapping(window1
.get(), child1
.get()));
671 ClickWindow(window1
.get());
672 EXPECT_FALSE(IsSelecting());
674 // Clicking on window1 should activate child1.
675 EXPECT_TRUE(wm::IsActiveWindow(child1
.get()));
678 // Tests that windows remain on the display they are currently on in overview
679 // mode, and that the close buttons are on matching displays.
680 TEST_F(WindowSelectorTest
, MultipleDisplays
) {
681 if (!SupportsMultipleDisplays())
684 UpdateDisplay("600x400,600x400");
685 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
686 gfx::Rect
bounds1(0, 0, 400, 400);
687 gfx::Rect
bounds2(650, 0, 400, 400);
689 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds1
));
690 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds1
));
691 scoped_ptr
<aura::Window
> window3(CreateWindow(bounds2
));
692 scoped_ptr
<aura::Window
> window4(CreateWindow(bounds2
));
693 scoped_ptr
<aura::Window
> panel1(CreatePanelWindow(bounds1
));
694 scoped_ptr
<aura::Window
> panel2(CreatePanelWindow(bounds1
));
695 scoped_ptr
<aura::Window
> panel3(CreatePanelWindow(bounds2
));
696 scoped_ptr
<aura::Window
> panel4(CreatePanelWindow(bounds2
));
697 EXPECT_EQ(root_windows
[0], window1
->GetRootWindow());
698 EXPECT_EQ(root_windows
[0], window2
->GetRootWindow());
699 EXPECT_EQ(root_windows
[1], window3
->GetRootWindow());
700 EXPECT_EQ(root_windows
[1], window4
->GetRootWindow());
702 EXPECT_EQ(root_windows
[0], panel1
->GetRootWindow());
703 EXPECT_EQ(root_windows
[0], panel2
->GetRootWindow());
704 EXPECT_EQ(root_windows
[1], panel3
->GetRootWindow());
705 EXPECT_EQ(root_windows
[1], panel4
->GetRootWindow());
707 // In overview mode, each window remains in the same root window.
709 EXPECT_EQ(root_windows
[0], window1
->GetRootWindow());
710 EXPECT_EQ(root_windows
[0], window2
->GetRootWindow());
711 EXPECT_EQ(root_windows
[1], window3
->GetRootWindow());
712 EXPECT_EQ(root_windows
[1], window4
->GetRootWindow());
713 EXPECT_EQ(root_windows
[0], panel1
->GetRootWindow());
714 EXPECT_EQ(root_windows
[0], panel2
->GetRootWindow());
715 EXPECT_EQ(root_windows
[1], panel3
->GetRootWindow());
716 EXPECT_EQ(root_windows
[1], panel4
->GetRootWindow());
718 const std::vector
<WindowSelectorItem
*>& primary_window_items
=
719 GetWindowItemsForRoot(0);
720 const std::vector
<WindowSelectorItem
*>& secondary_window_items
=
721 GetWindowItemsForRoot(1);
723 // Window indices are based on top-down order. The reverse of our creation.
724 IsWindowAndCloseButtonInScreen(window1
.get(), primary_window_items
[2]);
725 IsWindowAndCloseButtonInScreen(window2
.get(), primary_window_items
[1]);
726 IsWindowAndCloseButtonInScreen(window3
.get(), secondary_window_items
[2]);
727 IsWindowAndCloseButtonInScreen(window4
.get(), secondary_window_items
[1]);
729 IsWindowAndCloseButtonInScreen(panel1
.get(), primary_window_items
[0]);
730 IsWindowAndCloseButtonInScreen(panel2
.get(), primary_window_items
[0]);
731 IsWindowAndCloseButtonInScreen(panel3
.get(), secondary_window_items
[0]);
732 IsWindowAndCloseButtonInScreen(panel4
.get(), secondary_window_items
[0]);
734 EXPECT_TRUE(WindowsOverlapping(panel1
.get(), panel2
.get()));
735 EXPECT_TRUE(WindowsOverlapping(panel3
.get(), panel4
.get()));
736 EXPECT_FALSE(WindowsOverlapping(panel1
.get(), panel3
.get()));
739 // Tests shutting down during overview.
740 TEST_F(WindowSelectorTest
, Shutdown
) {
741 gfx::Rect
bounds(0, 0, 400, 400);
742 // These windows will be deleted when the test exits and the Shell instance
744 aura::Window
* window1(CreateWindow(bounds
));
745 aura::Window
* window2(CreateWindow(bounds
));
746 aura::Window
* window3(CreatePanelWindow(bounds
));
747 aura::Window
* window4(CreatePanelWindow(bounds
));
749 wm::ActivateWindow(window4
);
750 wm::ActivateWindow(window3
);
751 wm::ActivateWindow(window2
);
752 wm::ActivateWindow(window1
);
757 // Tests removing a display during overview.
758 TEST_F(WindowSelectorTest
, RemoveDisplay
) {
759 if (!SupportsMultipleDisplays())
762 UpdateDisplay("400x400,400x400");
763 gfx::Rect
bounds1(0, 0, 100, 100);
764 gfx::Rect
bounds2(450, 0, 100, 100);
765 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds1
));
766 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds2
));
767 scoped_ptr
<aura::Window
> window3(CreatePanelWindow(bounds1
));
768 scoped_ptr
<aura::Window
> window4(CreatePanelWindow(bounds2
));
770 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
771 EXPECT_EQ(root_windows
[0], window1
->GetRootWindow());
772 EXPECT_EQ(root_windows
[1], window2
->GetRootWindow());
773 EXPECT_EQ(root_windows
[0], window3
->GetRootWindow());
774 EXPECT_EQ(root_windows
[1], window4
->GetRootWindow());
776 wm::ActivateWindow(window4
.get());
777 wm::ActivateWindow(window3
.get());
778 wm::ActivateWindow(window2
.get());
779 wm::ActivateWindow(window1
.get());
782 EXPECT_TRUE(IsSelecting());
783 UpdateDisplay("400x400");
784 EXPECT_FALSE(IsSelecting());
787 // Tests starting overview during a drag and drop tracking operation.
788 // TODO(flackr): Fix memory corruption crash when running locally (not failing
789 // on bots). See http://crbug.com/342528.
790 TEST_F(WindowSelectorTest
, DISABLED_DragDropInProgress
) {
791 bool drag_canceled_by_test
= false;
792 gfx::Rect
bounds(0, 0, 400, 400);
793 scoped_ptr
<aura::Window
> window(CreateWindow(bounds
));
794 test::ShellTestApi
shell_test_api(Shell::GetInstance());
795 ash::DragDropController
* drag_drop_controller
=
796 shell_test_api
.drag_drop_controller();
797 ui::OSExchangeData data
;
798 base::MessageLoopForUI::current()->PostTask(FROM_HERE
,
799 base::Bind(&WindowSelectorTest::ToggleOverview
,
800 base::Unretained(this)));
801 base::MessageLoopForUI::current()->PostTask(FROM_HERE
,
802 base::Bind(&CancelDrag
, drag_drop_controller
, &drag_canceled_by_test
));
803 data
.SetString(base::UTF8ToUTF16("I am being dragged"));
804 drag_drop_controller
->StartDragAndDrop(data
, window
->GetRootWindow(),
805 window
.get(), gfx::Point(5, 5), ui::DragDropTypes::DRAG_MOVE
,
806 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE
);
807 RunAllPendingInMessageLoop();
808 EXPECT_FALSE(drag_canceled_by_test
);
809 ASSERT_TRUE(IsSelecting());
810 RunAllPendingInMessageLoop();
813 // Test that a label is created under the window on entering overview mode.
814 TEST_F(WindowSelectorTest
, CreateLabelUnderWindow
) {
815 scoped_ptr
<aura::Window
> window(CreateWindow(gfx::Rect(0, 0, 100, 100)));
816 base::string16 window_title
= base::UTF8ToUTF16("My window");
817 window
->SetTitle(window_title
);
819 WindowSelectorItem
* window_item
= GetWindowItemsForRoot(0).back();
820 views::Label
* label
= GetLabelView(window_item
);
821 // Has the label view been created?
824 // Verify the label matches the window title.
825 EXPECT_EQ(label
->text(), window_title
);
827 // Update the window title and check that the label is updated, too.
828 base::string16 updated_title
= base::UTF8ToUTF16("Updated title");
829 window
->SetTitle(updated_title
);
830 EXPECT_EQ(label
->text(), updated_title
);
832 // Labels are located based on target_bounds, not the actual window item
834 gfx::Rect
target_bounds(window_item
->target_bounds());
835 gfx::Rect
expected_label_bounds(target_bounds
.x(),
836 target_bounds
.bottom() - label
->
837 GetPreferredSize().height(),
838 target_bounds
.width(),
839 label
->GetPreferredSize().height());
840 gfx::Rect real_label_bounds
= label
->GetWidget()->GetNativeWindow()->bounds();
841 EXPECT_EQ(real_label_bounds
, expected_label_bounds
);
844 // Tests that a label is created for the active panel in a group of panels in
846 TEST_F(WindowSelectorTest
, CreateLabelUnderPanel
) {
847 scoped_ptr
<aura::Window
> panel1(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
848 scoped_ptr
<aura::Window
> panel2(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
849 base::string16 panel1_title
= base::UTF8ToUTF16("My panel");
850 base::string16 panel2_title
= base::UTF8ToUTF16("Another panel");
851 base::string16 updated_panel1_title
= base::UTF8ToUTF16("WebDriver Torso");
852 base::string16 updated_panel2_title
= base::UTF8ToUTF16("Da panel");
853 panel1
->SetTitle(panel1_title
);
854 panel2
->SetTitle(panel2_title
);
855 wm::ActivateWindow(panel1
.get());
857 WindowSelectorItem
* window_item
= GetWindowItemsForRoot(0).back();
858 views::Label
* label
= GetLabelView(window_item
);
859 // Has the label view been created?
862 // Verify the label matches the active window title.
863 EXPECT_EQ(label
->text(), panel1_title
);
864 // Verify that updating the title also updates the label.
865 panel1
->SetTitle(updated_panel1_title
);
866 EXPECT_EQ(label
->text(), updated_panel1_title
);
867 // After destroying the first panel, the label should match the second panel.
869 label
= GetLabelView(window_item
);
870 EXPECT_EQ(label
->text(), panel2_title
);
871 // Also test updating the title on the second panel.
872 panel2
->SetTitle(updated_panel2_title
);
873 EXPECT_EQ(label
->text(), updated_panel2_title
);
876 // Tests that overview updates the window positions if the display orientation
878 TEST_F(WindowSelectorTest
, DisplayOrientationChanged
) {
879 if (!SupportsHostWindowResize())
882 aura::Window
* root_window
= Shell::GetInstance()->GetPrimaryRootWindow();
883 UpdateDisplay("600x200");
884 EXPECT_EQ("0,0 600x200", root_window
->bounds().ToString());
885 gfx::Rect
window_bounds(0, 0, 150, 150);
886 ScopedVector
<aura::Window
> windows
;
887 for (int i
= 0; i
< 3; i
++) {
888 windows
.push_back(CreateWindow(window_bounds
));
892 for (ScopedVector
<aura::Window
>::iterator iter
= windows
.begin();
893 iter
!= windows
.end(); ++iter
) {
894 EXPECT_TRUE(root_window
->bounds().Contains(
895 ToEnclosingRect(GetTransformedTargetBounds(*iter
))));
898 // Rotate the display, windows should be repositioned to be within the screen
900 UpdateDisplay("600x200/r");
901 EXPECT_EQ("0,0 200x600", root_window
->bounds().ToString());
902 for (ScopedVector
<aura::Window
>::iterator iter
= windows
.begin();
903 iter
!= windows
.end(); ++iter
) {
904 EXPECT_TRUE(root_window
->bounds().Contains(
905 ToEnclosingRect(GetTransformedTargetBounds(*iter
))));
909 // Tests traversing some windows in overview mode with the tab key.
910 TEST_F(WindowSelectorTest
, BasicTabKeyNavigation
) {
911 gfx::Rect
bounds(0, 0, 100, 100);
912 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
913 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
916 SendKey(ui::VKEY_TAB
);
917 EXPECT_EQ(GetSelectedWindow(), window1
.get());
918 SendKey(ui::VKEY_TAB
);
919 EXPECT_EQ(GetSelectedWindow(), window2
.get());
920 SendKey(ui::VKEY_TAB
);
921 EXPECT_EQ(GetSelectedWindow(), window1
.get());
924 // Tests traversing some windows in overview mode with the arrow keys in every
925 // possible direction.
926 TEST_F(WindowSelectorTest
, BasicArrowKeyNavigation
) {
927 if (!SupportsHostWindowResize())
929 const size_t test_windows
= 9;
930 UpdateDisplay("800x600");
931 ScopedVector
<aura::Window
> windows
;
932 for (size_t i
= test_windows
; i
> 0; i
--)
933 windows
.push_back(CreateWindowWithId(gfx::Rect(0, 0, 100, 100), i
));
935 ui::KeyboardCode arrow_keys
[] = {
941 // Expected window layout, assuming that the text filtering feature is
942 // enabled by default (i.e., --ash-disable-text-filtering-in-overview-mode
943 // is not being used).
944 // +-------+ +-------+ +-------+ +-------+
945 // | 1 | | 2 | | 3 | | 4 |
946 // +-------+ +-------+ +-------+ +-------+
947 // +-------+ +-------+ +-------+ +-------+
948 // | 5 | | 6 | | 7 | | 8 |
949 // +-------+ +-------+ +-------+ +-------+
953 // Index for each window during a full loop plus wrapping around.
954 int index_path_for_direction
[][test_windows
+ 1] = {
955 {1, 2, 3, 4, 5, 6, 7, 8, 9, 1}, // Right
956 {1, 5, 9, 2, 6, 3, 7, 4, 8, 1}, // Down
957 {9, 8, 7, 6, 5, 4, 3, 2, 1, 9}, // Left
958 {8, 4, 7, 3, 6, 2, 9, 5, 1, 8} // Up
961 for (size_t key_index
= 0; key_index
< arraysize(arrow_keys
); key_index
++) {
963 for (size_t i
= 0; i
< test_windows
+ 1; i
++) {
964 SendKey(arrow_keys
[key_index
]);
965 // TODO(flackr): Add a more readable error message by constructing a
966 // string from the window IDs.
967 EXPECT_EQ(GetSelectedWindow()->id(),
968 index_path_for_direction
[key_index
][i
]);
974 // Tests basic selection across multiple monitors.
975 TEST_F(WindowSelectorTest
, BasicMultiMonitorArrowKeyNavigation
) {
976 if (!SupportsMultipleDisplays())
979 UpdateDisplay("400x400,400x400");
980 gfx::Rect
bounds1(0, 0, 100, 100);
981 gfx::Rect
bounds2(450, 0, 100, 100);
982 scoped_ptr
<aura::Window
> window4(CreateWindow(bounds2
));
983 scoped_ptr
<aura::Window
> window3(CreateWindow(bounds2
));
984 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds1
));
985 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds1
));
990 SendKey(ui::VKEY_RIGHT
);
991 EXPECT_EQ(GetSelectedWindow(), window1
.get());
992 SendKey(ui::VKEY_RIGHT
);
993 EXPECT_EQ(GetSelectedWindow(), window2
.get());
994 SendKey(ui::VKEY_RIGHT
);
995 EXPECT_EQ(GetSelectedWindow(), window3
.get());
996 SendKey(ui::VKEY_RIGHT
);
997 EXPECT_EQ(GetSelectedWindow(), window4
.get());
1000 // Tests selecting a window in overview mode with the return key.
1001 TEST_F(WindowSelectorTest
, SelectWindowWithReturnKey
) {
1002 gfx::Rect
bounds(0, 0, 100, 100);
1003 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
1004 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
1007 // Pressing the return key without a selection widget should not do anything.
1008 SendKey(ui::VKEY_RETURN
);
1009 EXPECT_TRUE(IsSelecting());
1011 // Select the first window.
1012 SendKey(ui::VKEY_RIGHT
);
1013 SendKey(ui::VKEY_RETURN
);
1014 ASSERT_FALSE(IsSelecting());
1015 EXPECT_TRUE(wm::IsActiveWindow(window1
.get()));
1017 // Select the second window.
1019 SendKey(ui::VKEY_RIGHT
);
1020 SendKey(ui::VKEY_RIGHT
);
1021 SendKey(ui::VKEY_RETURN
);
1022 EXPECT_FALSE(IsSelecting());
1023 EXPECT_TRUE(wm::IsActiveWindow(window2
.get()));
1026 // Tests that overview mode hides the callout widget.
1027 TEST_F(WindowSelectorTest
, WindowOverviewHidesCalloutWidgets
) {
1028 scoped_ptr
<aura::Window
> panel1(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
1029 scoped_ptr
<aura::Window
> panel2(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
1030 PanelLayoutManager
* panel_manager
=
1031 static_cast<PanelLayoutManager
*>(panel1
->parent()->layout_manager());
1033 // By default, panel callout widgets are visible.
1035 panel_manager
->GetCalloutWidgetForPanel(panel1
.get())->IsVisible());
1037 panel_manager
->GetCalloutWidgetForPanel(panel2
.get())->IsVisible());
1039 // Toggling the overview should hide the callout widgets.
1042 panel_manager
->GetCalloutWidgetForPanel(panel1
.get())->IsVisible());
1044 panel_manager
->GetCalloutWidgetForPanel(panel2
.get())->IsVisible());
1046 // Ending the overview should show them again.
1049 panel_manager
->GetCalloutWidgetForPanel(panel1
.get())->IsVisible());
1051 panel_manager
->GetCalloutWidgetForPanel(panel2
.get())->IsVisible());
1054 // Tests that when panels are grouped that the close button only closes the
1055 // currently active panel. After the removal window selection should still be
1056 // active, and the label should have changed. Removing the last panel should
1057 // cause selection to end.
1058 TEST_F(WindowSelectorTest
, CloseButtonOnPanels
) {
1059 scoped_ptr
<views::Widget
> widget1(CreatePanelWindowWidget(
1060 gfx::Rect(0, 0, 300, 100)));
1061 scoped_ptr
<views::Widget
> widget2(CreatePanelWindowWidget(
1062 gfx::Rect(100, 0, 100, 100)));
1063 aura::Window
* window1
= widget1
->GetNativeWindow();
1064 aura::Window
* window2
= widget2
->GetNativeWindow();
1065 base::string16 panel1_title
= base::UTF8ToUTF16("Panel 1");
1066 base::string16 panel2_title
= base::UTF8ToUTF16("Panel 2");
1067 window1
->SetTitle(panel1_title
);
1068 window2
->SetTitle(panel2_title
);
1069 wm::ActivateWindow(window1
);
1072 gfx::RectF bounds1
= GetTransformedBoundsInRootWindow(window1
);
1073 gfx::Point
point1(bounds1
.top_right().x() - 1, bounds1
.top_right().y() - 1);
1074 ui::test::EventGenerator
event_generator1(window1
->GetRootWindow(), point1
);
1076 EXPECT_FALSE(widget1
->IsClosed());
1077 event_generator1
.ClickLeftButton();
1078 EXPECT_TRUE(widget1
->IsClosed());
1079 RunAllPendingInMessageLoop();
1080 EXPECT_TRUE(IsSelecting());
1081 WindowSelectorItem
* window_item
= GetWindowItemsForRoot(0).front();
1082 EXPECT_FALSE(window_item
->empty());
1083 EXPECT_TRUE(window_item
->Contains(window2
));
1084 EXPECT_TRUE(GetCloseButton(window_item
)->IsVisible());
1087 views::Label
* label
= GetLabelView(window_item
);
1088 EXPECT_EQ(label
->text(), panel2_title
);
1090 gfx::RectF bounds2
= GetTransformedBoundsInRootWindow(window2
);
1091 gfx::Point
point2(bounds2
.top_right().x() - 1, bounds2
.top_right().y() - 1);
1092 ui::test::EventGenerator
event_generator2(window2
->GetRootWindow(), point2
);
1094 EXPECT_FALSE(widget2
->IsClosed());
1095 event_generator2
.ClickLeftButton();
1096 EXPECT_TRUE(widget2
->IsClosed());
1097 RunAllPendingInMessageLoop();
1098 EXPECT_FALSE(IsSelecting());
1101 // Creates three windows and tests filtering them by title.
1102 TEST_F(WindowSelectorTest
, BasicTextFiltering
) {
1103 gfx::Rect
bounds(0, 0, 100, 100);
1104 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
1105 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
1106 scoped_ptr
<aura::Window
> window0(CreateWindow(bounds
));
1107 base::string16 window2_title
= base::UTF8ToUTF16("Highway to test");
1108 base::string16 window1_title
= base::UTF8ToUTF16("For those about to test");
1109 base::string16 window0_title
= base::UTF8ToUTF16("We salute you");
1110 window0
->SetTitle(window0_title
);
1111 window1
->SetTitle(window1_title
);
1112 window2
->SetTitle(window2_title
);
1114 EXPECT_FALSE(selection_widget_active());
1115 EXPECT_FALSE(showing_filter_widget());
1116 FilterItems("Test");
1118 // The selection widget should appear when filtering starts, and should be
1119 // selecting the first matching window.
1120 EXPECT_TRUE(selection_widget_active());
1121 EXPECT_TRUE(showing_filter_widget());
1122 EXPECT_EQ(GetSelectedWindow(), window1
.get());
1124 // Window 0 has no "test" on it so it should be the only dimmed item.
1125 std::vector
<WindowSelectorItem
*> items
= GetWindowItemsForRoot(0);
1126 EXPECT_TRUE(items
[0]->dimmed());
1127 EXPECT_FALSE(items
[1]->dimmed());
1128 EXPECT_FALSE(items
[2]->dimmed());
1130 // No items match the search.
1131 FilterItems("I'm testing 'n testing");
1132 EXPECT_TRUE(items
[0]->dimmed());
1133 EXPECT_TRUE(items
[1]->dimmed());
1134 EXPECT_TRUE(items
[2]->dimmed());
1136 // All the items should match the empty string. The filter widget should also
1139 EXPECT_FALSE(showing_filter_widget());
1140 EXPECT_FALSE(items
[0]->dimmed());
1141 EXPECT_FALSE(items
[1]->dimmed());
1142 EXPECT_FALSE(items
[2]->dimmed());
1145 // Tests selecting in the overview with dimmed and undimmed items.
1146 TEST_F(WindowSelectorTest
, TextFilteringSelection
) {
1147 gfx::Rect
bounds(0, 0, 100, 100);
1148 scoped_ptr
<aura::Window
> window2(CreateWindow(bounds
));
1149 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
1150 scoped_ptr
<aura::Window
> window0(CreateWindow(bounds
));
1151 base::string16 window2_title
= base::UTF8ToUTF16("Rock and roll");
1152 base::string16 window1_title
= base::UTF8ToUTF16("Rock and");
1153 base::string16 window0_title
= base::UTF8ToUTF16("Rock");
1154 window0
->SetTitle(window0_title
);
1155 window1
->SetTitle(window1_title
);
1156 window2
->SetTitle(window2_title
);
1158 SendKey(ui::VKEY_RIGHT
);
1159 EXPECT_TRUE(selection_widget_active());
1160 EXPECT_EQ(GetSelectedWindow(), window0
.get());
1162 // Dim the first item, the selection should jump to the next item.
1163 std::vector
<WindowSelectorItem
*> items
= GetWindowItemsForRoot(0);
1164 FilterItems("Rock and");
1165 EXPECT_EQ(GetSelectedWindow(), window1
.get());
1167 // Cycle the selection, the dimmed window should not be selected.
1168 SendKey(ui::VKEY_RIGHT
);
1169 EXPECT_EQ(GetSelectedWindow(), window2
.get());
1170 SendKey(ui::VKEY_RIGHT
);
1171 EXPECT_EQ(GetSelectedWindow(), window1
.get());
1173 // Dimming all the items should hide the selection widget.
1175 EXPECT_FALSE(selection_widget_active());
1177 // Undimming one window should automatically select it.
1178 FilterItems("Rock and roll");
1179 EXPECT_EQ(GetSelectedWindow(), window2
.get());
1182 // Tests clicking on the desktop itself to cancel overview mode.
1183 TEST_F(WindowSelectorTest
, CancelOverviewOnMouseClick
) {
1184 // Overview disabled by default.
1185 EXPECT_FALSE(IsSelecting());
1187 // Point and bounds selected so that they don't intersect. This causes
1188 // events located at the point to be passed to DesktopBackgroundController,
1189 // and not the window.
1190 gfx::Point
point_in_background_page(0, 0);
1191 gfx::Rect
bounds(10, 10, 100, 100);
1192 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
1193 ui::test::EventGenerator
& generator
= GetEventGenerator();
1194 // Move mouse to point in the background page. Sending an event here will pass
1195 // it to the DesktopBackgroundController in both regular and overview mode.
1196 generator
.MoveMouseTo(point_in_background_page
);
1198 // Clicking on the background page while not in overview should not toggle
1200 generator
.ClickLeftButton();
1201 EXPECT_FALSE(IsSelecting());
1203 // Switch to overview mode.
1205 ASSERT_TRUE(IsSelecting());
1207 // Click should now exit overview mode.
1208 generator
.ClickLeftButton();
1209 EXPECT_FALSE(IsSelecting());
1212 // Tests tapping on the desktop itself to cancel overview mode.
1213 TEST_F(WindowSelectorTest
, CancelOverviewOnTap
) {
1214 // Overview disabled by default.
1215 EXPECT_FALSE(IsSelecting());
1217 // Point and bounds selected so that they don't intersect. This causes
1218 // events located at the point to be passed to DesktopBackgroundController,
1219 // and not the window.
1220 gfx::Point
point_in_background_page(0, 0);
1221 gfx::Rect
bounds(10, 10, 100, 100);
1222 scoped_ptr
<aura::Window
> window1(CreateWindow(bounds
));
1223 ui::test::EventGenerator
& generator
= GetEventGenerator();
1225 // Tapping on the background page while not in overview should not toggle
1227 generator
.GestureTapAt(point_in_background_page
);
1228 EXPECT_FALSE(IsSelecting());
1230 // Switch to overview mode.
1232 ASSERT_TRUE(IsSelecting());
1234 // Tap should now exit overview mode.
1235 generator
.GestureTapAt(point_in_background_page
);
1236 EXPECT_FALSE(IsSelecting());