Mac: Fix performance issues with remote CoreAnimation
[chromium-blink-merge.git] / ash / wm / overview / window_selector_unittest.cc
blob952260e9d7704a24c1bdb3d2c032e721913f964e
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.
5 #include <algorithm>
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"
53 namespace ash {
54 namespace {
56 class NonActivatableActivationDelegate
57 : public aura::client::ActivationDelegate {
58 public:
59 bool ShouldActivate() const override { return false; }
62 void CancelDrag(DragDropController* controller, bool* canceled) {
63 if (controller->IsDragDropInProgress()) {
64 *canceled = true;
65 controller->DragCancel();
69 } // namespace
71 class WindowSelectorTest : public test::AshTestBase {
72 public:
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));
97 return 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();
105 return window;
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);
115 widget->Show();
116 ParentWindowInPrimaryRootWindow(widget->GetNativeWindow());
117 return widget;
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) {
132 gfx::Transform t;
133 t.Translate(origin.x(), origin.y());
134 t.PreconcatTransform(transform);
135 t.Translate(-origin.x(), -origin.y());
136 return t;
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);
145 return 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);
154 return 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(),
164 &transform)) {
165 return gfx::RectF();
167 transform.TransformRect(&bounds);
168 return 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);
183 bool IsSelecting() {
184 return ash::Shell::GetInstance()->window_selector_controller()->
185 IsSelecting();
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
228 // screen.
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();
256 private:
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);
272 ToggleOverview();
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.
296 ToggleOverview();
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
301 // item.
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());
321 ToggleOverview();
322 EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow());
323 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
324 window2.get());
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);
342 widget->Show();
344 ToggleOverview();
346 gfx::Rect bounds =
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 a window does not receive located events when in overview mode.
364 TEST_F(WindowSelectorTest, WindowDoesNotReceiveEvents) {
365 gfx::Rect window_bounds(20, 10, 200, 300);
366 aura::Window* root_window = Shell::GetPrimaryRootWindow();
367 scoped_ptr<aura::Window> window(CreateWindow(window_bounds));
369 gfx::Point point1(window_bounds.x() + 10, window_bounds.y() + 10);
371 ui::MouseEvent event1(ui::ET_MOUSE_PRESSED, point1, point1,
372 ui::EF_NONE, ui::EF_NONE);
374 ui::EventTarget* root_target = root_window;
375 ui::EventTargeter* targeter = root_target->GetEventTargeter();
377 // The event should target the window because we are still not in overview
378 // mode.
379 EXPECT_EQ(window, static_cast<aura::Window*>(
380 targeter->FindTargetForEvent(root_target, &event1)));
382 ToggleOverview();
384 // The bounds have changed, take that into account.
385 gfx::RectF bounds = GetTransformedBoundsInRootWindow(window.get());
386 gfx::Point point2(bounds.x() + 10, bounds.y() + 10);
387 ui::MouseEvent event2(ui::ET_MOUSE_PRESSED, point2, point2,
388 ui::EF_NONE, ui::EF_NONE);
390 // Now the transparent window should be intercepting this event.
391 EXPECT_NE(window, static_cast<aura::Window*>(
392 targeter->FindTargetForEvent(root_target, &event2)));
395 // Tests that clicking on the close button effectively closes the window.
396 TEST_F(WindowSelectorTest, CloseButton) {
397 scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(200, 300, 250, 450)));
399 // We need a widget for the close button to work, a bare window will crash.
400 scoped_ptr<views::Widget> widget(new views::Widget);
401 views::Widget::InitParams params;
402 params.bounds = gfx::Rect(0, 0, 400, 400);
403 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
404 params.parent = window1->parent();
405 widget->Init(params);
406 widget->Show();
407 ToggleOverview();
409 aura::Window* window2 = widget->GetNativeWindow();
410 gfx::RectF bounds = GetTransformedBoundsInRootWindow(window2);
411 gfx::Point point(bounds.top_right().x() - 1, bounds.top_right().y() - 1);
412 ui::test::EventGenerator event_generator(window2->GetRootWindow(), point);
414 EXPECT_FALSE(widget->IsClosed());
415 event_generator.ClickLeftButton();
416 EXPECT_TRUE(widget->IsClosed());
419 // Tests entering overview mode with two windows and selecting one.
420 TEST_F(WindowSelectorTest, FullscreenWindow) {
421 gfx::Rect bounds(0, 0, 400, 400);
422 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
423 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
424 scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
425 wm::ActivateWindow(window1.get());
427 const wm::WMEvent toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
428 wm::GetWindowState(window1.get())->OnWMEvent(&toggle_fullscreen_event);
429 // The panel is hidden in fullscreen mode.
430 EXPECT_FALSE(panel1->IsVisible());
431 EXPECT_TRUE(wm::GetWindowState(window1.get())->IsFullscreen());
433 // Enter overview and select the fullscreen window.
434 ToggleOverview();
436 // The panel becomes temporarily visible for the overview.
437 EXPECT_TRUE(panel1->IsVisible());
438 ClickWindow(window1.get());
440 // The window is still fullscreen as it was selected. The panel should again
441 // be hidden.
442 EXPECT_TRUE(wm::GetWindowState(window1.get())->IsFullscreen());
443 EXPECT_FALSE(panel1->IsVisible());
445 // Entering overview and selecting another window, the previous window remains
446 // fullscreen.
447 // TODO(flackr): Currently the panel remains hidden, but should become visible
448 // again.
449 ToggleOverview();
450 ClickWindow(window2.get());
451 EXPECT_TRUE(wm::GetWindowState(window1.get())->IsFullscreen());
454 // Tests that the shelf dimming state is removed while in overview and restored
455 // on exiting overview.
456 TEST_F(WindowSelectorTest, OverviewUndimsShelf) {
457 gfx::Rect bounds(0, 0, 400, 400);
458 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
459 wm::WindowState* window_state = wm::GetWindowState(window1.get());
460 window_state->Maximize();
461 ash::ShelfWidget* shelf = Shell::GetPrimaryRootWindowController()->shelf();
462 EXPECT_TRUE(shelf->GetDimsShelf());
463 ToggleOverview();
464 EXPECT_FALSE(shelf->GetDimsShelf());
465 ToggleOverview();
466 EXPECT_TRUE(shelf->GetDimsShelf());
469 // Tests that entering overview when a fullscreen window is active in maximized
470 // mode correctly applies the transformations to the window and correctly
471 // updates the window bounds on exiting overview mode: http://crbug.com/401664.
472 TEST_F(WindowSelectorTest, FullscreenWindowMaximizeMode) {
473 gfx::Rect bounds(0, 0, 400, 400);
474 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
475 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
476 Shell::GetInstance()->maximize_mode_controller()->
477 EnableMaximizeModeWindowManager(true);
478 wm::ActivateWindow(window2.get());
479 wm::ActivateWindow(window1.get());
480 gfx::Rect normal_window_bounds(window1->bounds());
481 const wm::WMEvent toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
482 wm::GetWindowState(window1.get())->OnWMEvent(&toggle_fullscreen_event);
483 gfx::Rect fullscreen_window_bounds(window1->bounds());
484 EXPECT_NE(normal_window_bounds.ToString(),
485 fullscreen_window_bounds.ToString());
486 EXPECT_EQ(fullscreen_window_bounds.ToString(),
487 window2->GetTargetBounds().ToString());
488 ToggleOverview();
489 // Window 2 would normally resize to normal window bounds on showing the shelf
490 // for overview but this is deferred until overview is exited.
491 EXPECT_EQ(fullscreen_window_bounds.ToString(),
492 window2->GetTargetBounds().ToString());
493 EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get()));
494 ToggleOverview();
496 // Since the fullscreen window is still active, window2 will still have the
497 // larger bounds.
498 EXPECT_EQ(fullscreen_window_bounds.ToString(),
499 window2->GetTargetBounds().ToString());
501 // Enter overview again and select window 2. Selecting window 2 should show
502 // the shelf bringing window2 back to the normal bounds.
503 ToggleOverview();
504 ClickWindow(window2.get());
505 EXPECT_EQ(normal_window_bounds.ToString(),
506 window2->GetTargetBounds().ToString());
509 // Tests that beginning window selection hides the app list.
510 TEST_F(WindowSelectorTest, SelectingHidesAppList) {
511 gfx::Rect bounds(0, 0, 400, 400);
512 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
513 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
514 Shell::GetInstance()->ShowAppList(NULL);
515 EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility());
516 ToggleOverview();
517 EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility());
518 ToggleOverview();
521 // Tests that a minimized window's visibility and layer visibility is correctly
522 // changed when entering overview and restored when leaving overview mode.
523 // Crashes after the skia roll in http://crrev.com/274114.
524 // http://crbug.com/379570
525 TEST_F(WindowSelectorTest, DISABLED_MinimizedWindowVisibility) {
526 gfx::Rect bounds(0, 0, 400, 400);
527 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
528 wm::WindowState* window_state = wm::GetWindowState(window1.get());
529 window_state->Minimize();
530 EXPECT_FALSE(window1->IsVisible());
531 EXPECT_FALSE(window1->layer()->GetTargetVisibility());
533 ui::ScopedAnimationDurationScaleMode test_duration_mode(
534 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
535 ToggleOverview();
536 EXPECT_TRUE(window1->IsVisible());
537 EXPECT_TRUE(window1->layer()->GetTargetVisibility());
540 ui::ScopedAnimationDurationScaleMode test_duration_mode(
541 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
542 ToggleOverview();
543 EXPECT_FALSE(window1->IsVisible());
544 EXPECT_FALSE(window1->layer()->GetTargetVisibility());
548 // Tests that a bounds change during overview is corrected for.
549 TEST_F(WindowSelectorTest, BoundsChangeDuringOverview) {
550 scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 400, 400)));
551 ToggleOverview();
552 gfx::Rect overview_bounds =
553 ToEnclosingRect(GetTransformedTargetBounds(window.get()));
554 window->SetBounds(gfx::Rect(200, 0, 200, 200));
555 gfx::Rect new_overview_bounds =
556 ToEnclosingRect(GetTransformedTargetBounds(window.get()));
557 EXPECT_EQ(overview_bounds.x(), new_overview_bounds.x());
558 EXPECT_EQ(overview_bounds.y(), new_overview_bounds.y());
559 EXPECT_EQ(overview_bounds.width(), new_overview_bounds.width());
560 EXPECT_EQ(overview_bounds.height(), new_overview_bounds.height());
561 ToggleOverview();
564 // Tests that a newly created window aborts overview.
565 TEST_F(WindowSelectorTest, NewWindowCancelsOveriew) {
566 gfx::Rect bounds(0, 0, 400, 400);
567 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
568 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
569 ToggleOverview();
570 EXPECT_TRUE(IsSelecting());
572 // A window being created should exit overview mode.
573 scoped_ptr<aura::Window> window3(CreateWindow(bounds));
574 EXPECT_FALSE(IsSelecting());
577 // Tests that a window activation exits overview mode.
578 TEST_F(WindowSelectorTest, ActivationCancelsOveriew) {
579 gfx::Rect bounds(0, 0, 400, 400);
580 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
581 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
582 window2->Focus();
583 ToggleOverview();
584 EXPECT_TRUE(IsSelecting());
586 // A window being activated should exit overview mode.
587 window1->Focus();
588 EXPECT_FALSE(IsSelecting());
590 // window1 should be focused after exiting even though window2 was focused on
591 // entering overview because we exited due to an activation.
592 EXPECT_EQ(window1.get(), GetFocusedWindow());
595 // Tests that exiting overview mode without selecting a window restores focus
596 // to the previously focused window.
597 TEST_F(WindowSelectorTest, CancelRestoresFocus) {
598 gfx::Rect bounds(0, 0, 400, 400);
599 scoped_ptr<aura::Window> window(CreateWindow(bounds));
600 wm::ActivateWindow(window.get());
601 EXPECT_EQ(window.get(), GetFocusedWindow());
603 // In overview mode, the text filter widget should be focused.
604 ToggleOverview();
605 EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow());
607 // If canceling overview mode, focus should be restored.
608 ToggleOverview();
609 EXPECT_EQ(window.get(), GetFocusedWindow());
612 // Tests that overview mode is exited if the last remaining window is destroyed.
613 TEST_F(WindowSelectorTest, LastWindowDestroyed) {
614 gfx::Rect bounds(0, 0, 400, 400);
615 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
616 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
617 ToggleOverview();
619 window1.reset();
620 window2.reset();
621 EXPECT_FALSE(IsSelecting());
624 // Tests that entering overview mode restores a window to its original
625 // target location.
626 TEST_F(WindowSelectorTest, QuickReentryRestoresInitialTransform) {
627 gfx::Rect bounds(0, 0, 400, 400);
628 scoped_ptr<aura::Window> window(CreateWindow(bounds));
629 gfx::Rect initial_bounds = ToEnclosingRect(
630 GetTransformedBounds(window.get()));
631 ToggleOverview();
632 // Quickly exit and reenter overview mode. The window should still be
633 // animating when we reenter. We cannot short circuit animations for this but
634 // we also don't have to wait for them to complete.
636 ui::ScopedAnimationDurationScaleMode test_duration_mode(
637 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
638 ToggleOverview();
639 ToggleOverview();
641 EXPECT_NE(initial_bounds, ToEnclosingRect(
642 GetTransformedTargetBounds(window.get())));
643 ToggleOverview();
644 EXPECT_FALSE(IsSelecting());
645 EXPECT_EQ(initial_bounds, ToEnclosingRect(
646 GetTransformedTargetBounds(window.get())));
649 // Tests that non-activatable windows are hidden when entering overview mode.
650 TEST_F(WindowSelectorTest, NonActivatableWindowsHidden) {
651 gfx::Rect bounds(0, 0, 400, 400);
652 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
653 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
654 scoped_ptr<aura::Window> non_activatable_window(
655 CreateNonActivatableWindow(Shell::GetPrimaryRootWindow()->bounds()));
656 EXPECT_TRUE(non_activatable_window->IsVisible());
657 ToggleOverview();
658 EXPECT_FALSE(non_activatable_window->IsVisible());
659 ToggleOverview();
660 EXPECT_TRUE(non_activatable_window->IsVisible());
662 // Test that a window behind the fullscreen non-activatable window can be
663 // clicked.
664 non_activatable_window->parent()->StackChildAtTop(
665 non_activatable_window.get());
666 ToggleOverview();
667 ClickWindow(window1.get());
668 EXPECT_FALSE(IsSelecting());
669 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
672 // Tests that windows with modal child windows are transformed with the modal
673 // child even though not activatable themselves.
674 TEST_F(WindowSelectorTest, ModalChild) {
675 gfx::Rect bounds(0, 0, 400, 400);
676 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
677 scoped_ptr<aura::Window> child1(CreateWindow(bounds));
678 child1->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
679 ::wm::AddTransientChild(window1.get(), child1.get());
680 EXPECT_EQ(window1->parent(), child1->parent());
681 ToggleOverview();
682 EXPECT_TRUE(window1->IsVisible());
683 EXPECT_TRUE(child1->IsVisible());
684 EXPECT_EQ(ToEnclosingRect(GetTransformedTargetBounds(child1.get())),
685 ToEnclosingRect(GetTransformedTargetBounds(window1.get())));
686 ToggleOverview();
689 // Tests that clicking a modal window's parent activates the modal window in
690 // overview.
691 TEST_F(WindowSelectorTest, ClickModalWindowParent) {
692 scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 180, 180)));
693 scoped_ptr<aura::Window> child1(CreateWindow(gfx::Rect(200, 0, 180, 180)));
694 child1->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
695 ::wm::AddTransientChild(window1.get(), child1.get());
696 EXPECT_FALSE(WindowsOverlapping(window1.get(), child1.get()));
697 EXPECT_EQ(window1->parent(), child1->parent());
698 ToggleOverview();
699 // Given that their relative positions are preserved, the windows should still
700 // not overlap.
701 EXPECT_FALSE(WindowsOverlapping(window1.get(), child1.get()));
702 ClickWindow(window1.get());
703 EXPECT_FALSE(IsSelecting());
705 // Clicking on window1 should activate child1.
706 EXPECT_TRUE(wm::IsActiveWindow(child1.get()));
709 // Tests that windows remain on the display they are currently on in overview
710 // mode, and that the close buttons are on matching displays.
711 TEST_F(WindowSelectorTest, MultipleDisplays) {
712 if (!SupportsMultipleDisplays())
713 return;
715 UpdateDisplay("600x400,600x400");
716 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
717 gfx::Rect bounds1(0, 0, 400, 400);
718 gfx::Rect bounds2(650, 0, 400, 400);
720 scoped_ptr<aura::Window> window1(CreateWindow(bounds1));
721 scoped_ptr<aura::Window> window2(CreateWindow(bounds1));
722 scoped_ptr<aura::Window> window3(CreateWindow(bounds2));
723 scoped_ptr<aura::Window> window4(CreateWindow(bounds2));
724 scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds1));
725 scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds1));
726 scoped_ptr<aura::Window> panel3(CreatePanelWindow(bounds2));
727 scoped_ptr<aura::Window> panel4(CreatePanelWindow(bounds2));
728 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
729 EXPECT_EQ(root_windows[0], window2->GetRootWindow());
730 EXPECT_EQ(root_windows[1], window3->GetRootWindow());
731 EXPECT_EQ(root_windows[1], window4->GetRootWindow());
733 EXPECT_EQ(root_windows[0], panel1->GetRootWindow());
734 EXPECT_EQ(root_windows[0], panel2->GetRootWindow());
735 EXPECT_EQ(root_windows[1], panel3->GetRootWindow());
736 EXPECT_EQ(root_windows[1], panel4->GetRootWindow());
738 // In overview mode, each window remains in the same root window.
739 ToggleOverview();
740 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
741 EXPECT_EQ(root_windows[0], window2->GetRootWindow());
742 EXPECT_EQ(root_windows[1], window3->GetRootWindow());
743 EXPECT_EQ(root_windows[1], window4->GetRootWindow());
744 EXPECT_EQ(root_windows[0], panel1->GetRootWindow());
745 EXPECT_EQ(root_windows[0], panel2->GetRootWindow());
746 EXPECT_EQ(root_windows[1], panel3->GetRootWindow());
747 EXPECT_EQ(root_windows[1], panel4->GetRootWindow());
749 const std::vector<WindowSelectorItem*>& primary_window_items =
750 GetWindowItemsForRoot(0);
751 const std::vector<WindowSelectorItem*>& secondary_window_items =
752 GetWindowItemsForRoot(1);
754 // Window indices are based on top-down order. The reverse of our creation.
755 IsWindowAndCloseButtonInScreen(window1.get(), primary_window_items[2]);
756 IsWindowAndCloseButtonInScreen(window2.get(), primary_window_items[1]);
757 IsWindowAndCloseButtonInScreen(window3.get(), secondary_window_items[2]);
758 IsWindowAndCloseButtonInScreen(window4.get(), secondary_window_items[1]);
760 IsWindowAndCloseButtonInScreen(panel1.get(), primary_window_items[0]);
761 IsWindowAndCloseButtonInScreen(panel2.get(), primary_window_items[0]);
762 IsWindowAndCloseButtonInScreen(panel3.get(), secondary_window_items[0]);
763 IsWindowAndCloseButtonInScreen(panel4.get(), secondary_window_items[0]);
765 EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get()));
766 EXPECT_TRUE(WindowsOverlapping(panel3.get(), panel4.get()));
767 EXPECT_FALSE(WindowsOverlapping(panel1.get(), panel3.get()));
770 // Tests shutting down during overview.
771 TEST_F(WindowSelectorTest, Shutdown) {
772 gfx::Rect bounds(0, 0, 400, 400);
773 // These windows will be deleted when the test exits and the Shell instance
774 // is shut down.
775 aura::Window* window1(CreateWindow(bounds));
776 aura::Window* window2(CreateWindow(bounds));
777 aura::Window* window3(CreatePanelWindow(bounds));
778 aura::Window* window4(CreatePanelWindow(bounds));
780 wm::ActivateWindow(window4);
781 wm::ActivateWindow(window3);
782 wm::ActivateWindow(window2);
783 wm::ActivateWindow(window1);
785 ToggleOverview();
788 // Tests removing a display during overview.
789 TEST_F(WindowSelectorTest, RemoveDisplay) {
790 if (!SupportsMultipleDisplays())
791 return;
793 UpdateDisplay("400x400,400x400");
794 gfx::Rect bounds1(0, 0, 100, 100);
795 gfx::Rect bounds2(450, 0, 100, 100);
796 scoped_ptr<aura::Window> window1(CreateWindow(bounds1));
797 scoped_ptr<aura::Window> window2(CreateWindow(bounds2));
798 scoped_ptr<aura::Window> window3(CreatePanelWindow(bounds1));
799 scoped_ptr<aura::Window> window4(CreatePanelWindow(bounds2));
801 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
802 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
803 EXPECT_EQ(root_windows[1], window2->GetRootWindow());
804 EXPECT_EQ(root_windows[0], window3->GetRootWindow());
805 EXPECT_EQ(root_windows[1], window4->GetRootWindow());
807 wm::ActivateWindow(window4.get());
808 wm::ActivateWindow(window3.get());
809 wm::ActivateWindow(window2.get());
810 wm::ActivateWindow(window1.get());
812 ToggleOverview();
813 EXPECT_TRUE(IsSelecting());
814 UpdateDisplay("400x400");
815 EXPECT_FALSE(IsSelecting());
818 // Tests starting overview during a drag and drop tracking operation.
819 // TODO(flackr): Fix memory corruption crash when running locally (not failing
820 // on bots). See http://crbug.com/342528.
821 TEST_F(WindowSelectorTest, DISABLED_DragDropInProgress) {
822 bool drag_canceled_by_test = false;
823 gfx::Rect bounds(0, 0, 400, 400);
824 scoped_ptr<aura::Window> window(CreateWindow(bounds));
825 test::ShellTestApi shell_test_api(Shell::GetInstance());
826 ash::DragDropController* drag_drop_controller =
827 shell_test_api.drag_drop_controller();
828 ui::OSExchangeData data;
829 base::MessageLoopForUI::current()->PostTask(FROM_HERE,
830 base::Bind(&WindowSelectorTest::ToggleOverview,
831 base::Unretained(this)));
832 base::MessageLoopForUI::current()->PostTask(FROM_HERE,
833 base::Bind(&CancelDrag, drag_drop_controller, &drag_canceled_by_test));
834 data.SetString(base::UTF8ToUTF16("I am being dragged"));
835 drag_drop_controller->StartDragAndDrop(data, window->GetRootWindow(),
836 window.get(), gfx::Point(5, 5), ui::DragDropTypes::DRAG_MOVE,
837 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
838 RunAllPendingInMessageLoop();
839 EXPECT_FALSE(drag_canceled_by_test);
840 ASSERT_TRUE(IsSelecting());
841 RunAllPendingInMessageLoop();
844 // Test that a label is created under the window on entering overview mode.
845 TEST_F(WindowSelectorTest, CreateLabelUnderWindow) {
846 scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 100, 100)));
847 base::string16 window_title = base::UTF8ToUTF16("My window");
848 window->SetTitle(window_title);
849 ToggleOverview();
850 WindowSelectorItem* window_item = GetWindowItemsForRoot(0).back();
851 views::Label* label = GetLabelView(window_item);
852 // Has the label view been created?
853 ASSERT_TRUE(label);
855 // Verify the label matches the window title.
856 EXPECT_EQ(label->text(), window_title);
858 // Update the window title and check that the label is updated, too.
859 base::string16 updated_title = base::UTF8ToUTF16("Updated title");
860 window->SetTitle(updated_title);
861 EXPECT_EQ(label->text(), updated_title);
863 // Labels are located based on target_bounds, not the actual window item
864 // bounds.
865 gfx::Rect target_bounds(window_item->target_bounds());
866 gfx::Rect expected_label_bounds(target_bounds.x(),
867 target_bounds.bottom() - label->
868 GetPreferredSize().height(),
869 target_bounds.width(),
870 label->GetPreferredSize().height());
871 gfx::Rect real_label_bounds = label->GetWidget()->GetNativeWindow()->bounds();
872 EXPECT_EQ(real_label_bounds, expected_label_bounds);
875 // Tests that a label is created for the active panel in a group of panels in
876 // overview mode.
877 TEST_F(WindowSelectorTest, CreateLabelUnderPanel) {
878 scoped_ptr<aura::Window> panel1(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
879 scoped_ptr<aura::Window> panel2(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
880 base::string16 panel1_title = base::UTF8ToUTF16("My panel");
881 base::string16 panel2_title = base::UTF8ToUTF16("Another panel");
882 base::string16 updated_panel1_title = base::UTF8ToUTF16("WebDriver Torso");
883 base::string16 updated_panel2_title = base::UTF8ToUTF16("Da panel");
884 panel1->SetTitle(panel1_title);
885 panel2->SetTitle(panel2_title);
886 wm::ActivateWindow(panel1.get());
887 ToggleOverview();
888 WindowSelectorItem* window_item = GetWindowItemsForRoot(0).back();
889 views::Label* label = GetLabelView(window_item);
890 // Has the label view been created?
891 ASSERT_TRUE(label);
893 // Verify the label matches the active window title.
894 EXPECT_EQ(label->text(), panel1_title);
895 // Verify that updating the title also updates the label.
896 panel1->SetTitle(updated_panel1_title);
897 EXPECT_EQ(label->text(), updated_panel1_title);
898 // After destroying the first panel, the label should match the second panel.
899 panel1.reset();
900 label = GetLabelView(window_item);
901 EXPECT_EQ(label->text(), panel2_title);
902 // Also test updating the title on the second panel.
903 panel2->SetTitle(updated_panel2_title);
904 EXPECT_EQ(label->text(), updated_panel2_title);
907 // Tests that overview updates the window positions if the display orientation
908 // changes.
909 TEST_F(WindowSelectorTest, DisplayOrientationChanged) {
910 if (!SupportsHostWindowResize())
911 return;
913 aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow();
914 UpdateDisplay("600x200");
915 EXPECT_EQ("0,0 600x200", root_window->bounds().ToString());
916 gfx::Rect window_bounds(0, 0, 150, 150);
917 ScopedVector<aura::Window> windows;
918 for (int i = 0; i < 3; i++) {
919 windows.push_back(CreateWindow(window_bounds));
922 ToggleOverview();
923 for (ScopedVector<aura::Window>::iterator iter = windows.begin();
924 iter != windows.end(); ++iter) {
925 EXPECT_TRUE(root_window->bounds().Contains(
926 ToEnclosingRect(GetTransformedTargetBounds(*iter))));
929 // Rotate the display, windows should be repositioned to be within the screen
930 // bounds.
931 UpdateDisplay("600x200/r");
932 EXPECT_EQ("0,0 200x600", root_window->bounds().ToString());
933 for (ScopedVector<aura::Window>::iterator iter = windows.begin();
934 iter != windows.end(); ++iter) {
935 EXPECT_TRUE(root_window->bounds().Contains(
936 ToEnclosingRect(GetTransformedTargetBounds(*iter))));
940 // Tests traversing some windows in overview mode with the tab key.
941 TEST_F(WindowSelectorTest, BasicTabKeyNavigation) {
942 gfx::Rect bounds(0, 0, 100, 100);
943 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
944 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
945 ToggleOverview();
947 SendKey(ui::VKEY_TAB);
948 EXPECT_EQ(GetSelectedWindow(), window1.get());
949 SendKey(ui::VKEY_TAB);
950 EXPECT_EQ(GetSelectedWindow(), window2.get());
951 SendKey(ui::VKEY_TAB);
952 EXPECT_EQ(GetSelectedWindow(), window1.get());
955 // Tests traversing some windows in overview mode with the arrow keys in every
956 // possible direction.
957 TEST_F(WindowSelectorTest, BasicArrowKeyNavigation) {
958 if (!SupportsHostWindowResize())
959 return;
960 const size_t test_windows = 9;
961 UpdateDisplay("800x600");
962 ScopedVector<aura::Window> windows;
963 for (size_t i = test_windows; i > 0; i--)
964 windows.push_back(CreateWindowWithId(gfx::Rect(0, 0, 100, 100), i));
966 ui::KeyboardCode arrow_keys[] = {
967 ui::VKEY_RIGHT,
968 ui::VKEY_DOWN,
969 ui::VKEY_LEFT,
970 ui::VKEY_UP
972 // Expected window layout, assuming that the text filtering feature is
973 // enabled by default (i.e., --ash-disable-text-filtering-in-overview-mode
974 // is not being used).
975 // +-------+ +-------+ +-------+ +-------+
976 // | 1 | | 2 | | 3 | | 4 |
977 // +-------+ +-------+ +-------+ +-------+
978 // +-------+ +-------+ +-------+ +-------+
979 // | 5 | | 6 | | 7 | | 8 |
980 // +-------+ +-------+ +-------+ +-------+
981 // +-------+
982 // | 9 |
983 // +-------+
984 // Index for each window during a full loop plus wrapping around.
985 int index_path_for_direction[][test_windows + 1] = {
986 {1, 2, 3, 4, 5, 6, 7, 8, 9, 1}, // Right
987 {1, 5, 9, 2, 6, 3, 7, 4, 8, 1}, // Down
988 {9, 8, 7, 6, 5, 4, 3, 2, 1, 9}, // Left
989 {8, 4, 7, 3, 6, 2, 9, 5, 1, 8} // Up
992 for (size_t key_index = 0; key_index < arraysize(arrow_keys); key_index++) {
993 ToggleOverview();
994 for (size_t i = 0; i < test_windows + 1; i++) {
995 SendKey(arrow_keys[key_index]);
996 // TODO(flackr): Add a more readable error message by constructing a
997 // string from the window IDs.
998 EXPECT_EQ(GetSelectedWindow()->id(),
999 index_path_for_direction[key_index][i]);
1001 ToggleOverview();
1005 // Tests basic selection across multiple monitors.
1006 TEST_F(WindowSelectorTest, BasicMultiMonitorArrowKeyNavigation) {
1007 if (!SupportsMultipleDisplays())
1008 return;
1010 UpdateDisplay("400x400,400x400");
1011 gfx::Rect bounds1(0, 0, 100, 100);
1012 gfx::Rect bounds2(450, 0, 100, 100);
1013 scoped_ptr<aura::Window> window4(CreateWindow(bounds2));
1014 scoped_ptr<aura::Window> window3(CreateWindow(bounds2));
1015 scoped_ptr<aura::Window> window2(CreateWindow(bounds1));
1016 scoped_ptr<aura::Window> window1(CreateWindow(bounds1));
1019 ToggleOverview();
1021 SendKey(ui::VKEY_RIGHT);
1022 EXPECT_EQ(GetSelectedWindow(), window1.get());
1023 SendKey(ui::VKEY_RIGHT);
1024 EXPECT_EQ(GetSelectedWindow(), window2.get());
1025 SendKey(ui::VKEY_RIGHT);
1026 EXPECT_EQ(GetSelectedWindow(), window3.get());
1027 SendKey(ui::VKEY_RIGHT);
1028 EXPECT_EQ(GetSelectedWindow(), window4.get());
1031 // Tests selecting a window in overview mode with the return key.
1032 TEST_F(WindowSelectorTest, SelectWindowWithReturnKey) {
1033 gfx::Rect bounds(0, 0, 100, 100);
1034 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
1035 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
1036 ToggleOverview();
1038 // Pressing the return key without a selection widget should not do anything.
1039 SendKey(ui::VKEY_RETURN);
1040 EXPECT_TRUE(IsSelecting());
1042 // Select the first window.
1043 SendKey(ui::VKEY_RIGHT);
1044 SendKey(ui::VKEY_RETURN);
1045 ASSERT_FALSE(IsSelecting());
1046 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
1048 // Select the second window.
1049 ToggleOverview();
1050 SendKey(ui::VKEY_RIGHT);
1051 SendKey(ui::VKEY_RIGHT);
1052 SendKey(ui::VKEY_RETURN);
1053 EXPECT_FALSE(IsSelecting());
1054 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
1057 // Tests that overview mode hides the callout widget.
1058 TEST_F(WindowSelectorTest, WindowOverviewHidesCalloutWidgets) {
1059 scoped_ptr<aura::Window> panel1(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
1060 scoped_ptr<aura::Window> panel2(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
1061 PanelLayoutManager* panel_manager =
1062 static_cast<PanelLayoutManager*>(panel1->parent()->layout_manager());
1064 // By default, panel callout widgets are visible.
1065 EXPECT_TRUE(
1066 panel_manager->GetCalloutWidgetForPanel(panel1.get())->IsVisible());
1067 EXPECT_TRUE(
1068 panel_manager->GetCalloutWidgetForPanel(panel2.get())->IsVisible());
1070 // Toggling the overview should hide the callout widgets.
1071 ToggleOverview();
1072 EXPECT_FALSE(
1073 panel_manager->GetCalloutWidgetForPanel(panel1.get())->IsVisible());
1074 EXPECT_FALSE(
1075 panel_manager->GetCalloutWidgetForPanel(panel2.get())->IsVisible());
1077 // Ending the overview should show them again.
1078 ToggleOverview();
1079 EXPECT_TRUE(
1080 panel_manager->GetCalloutWidgetForPanel(panel1.get())->IsVisible());
1081 EXPECT_TRUE(
1082 panel_manager->GetCalloutWidgetForPanel(panel2.get())->IsVisible());
1085 // Tests that when panels are grouped that the close button only closes the
1086 // currently active panel. After the removal window selection should still be
1087 // active, and the label should have changed. Removing the last panel should
1088 // cause selection to end.
1089 TEST_F(WindowSelectorTest, CloseButtonOnPanels) {
1090 scoped_ptr<views::Widget> widget1(CreatePanelWindowWidget(
1091 gfx::Rect(0, 0, 300, 100)));
1092 scoped_ptr<views::Widget> widget2(CreatePanelWindowWidget(
1093 gfx::Rect(100, 0, 100, 100)));
1094 aura::Window* window1 = widget1->GetNativeWindow();
1095 aura::Window* window2 = widget2->GetNativeWindow();
1096 base::string16 panel1_title = base::UTF8ToUTF16("Panel 1");
1097 base::string16 panel2_title = base::UTF8ToUTF16("Panel 2");
1098 window1->SetTitle(panel1_title);
1099 window2->SetTitle(panel2_title);
1100 wm::ActivateWindow(window1);
1101 ToggleOverview();
1103 gfx::RectF bounds1 = GetTransformedBoundsInRootWindow(window1);
1104 gfx::Point point1(bounds1.top_right().x() - 1, bounds1.top_right().y() - 1);
1105 ui::test::EventGenerator event_generator1(window1->GetRootWindow(), point1);
1107 EXPECT_FALSE(widget1->IsClosed());
1108 event_generator1.ClickLeftButton();
1109 EXPECT_TRUE(widget1->IsClosed());
1110 RunAllPendingInMessageLoop();
1111 EXPECT_TRUE(IsSelecting());
1112 WindowSelectorItem* window_item = GetWindowItemsForRoot(0).front();
1113 EXPECT_FALSE(window_item->empty());
1114 EXPECT_TRUE(window_item->Contains(window2));
1115 EXPECT_TRUE(GetCloseButton(window_item)->IsVisible());
1118 views::Label* label = GetLabelView(window_item);
1119 EXPECT_EQ(label->text(), panel2_title);
1121 gfx::RectF bounds2 = GetTransformedBoundsInRootWindow(window2);
1122 gfx::Point point2(bounds2.top_right().x() - 1, bounds2.top_right().y() - 1);
1123 ui::test::EventGenerator event_generator2(window2->GetRootWindow(), point2);
1125 EXPECT_FALSE(widget2->IsClosed());
1126 event_generator2.ClickLeftButton();
1127 EXPECT_TRUE(widget2->IsClosed());
1128 RunAllPendingInMessageLoop();
1129 EXPECT_FALSE(IsSelecting());
1132 // Creates three windows and tests filtering them by title.
1133 TEST_F(WindowSelectorTest, BasicTextFiltering) {
1134 gfx::Rect bounds(0, 0, 100, 100);
1135 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
1136 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
1137 scoped_ptr<aura::Window> window0(CreateWindow(bounds));
1138 base::string16 window2_title = base::UTF8ToUTF16("Highway to test");
1139 base::string16 window1_title = base::UTF8ToUTF16("For those about to test");
1140 base::string16 window0_title = base::UTF8ToUTF16("We salute you");
1141 window0->SetTitle(window0_title);
1142 window1->SetTitle(window1_title);
1143 window2->SetTitle(window2_title);
1144 ToggleOverview();
1145 EXPECT_FALSE(selection_widget_active());
1146 EXPECT_FALSE(showing_filter_widget());
1147 FilterItems("Test");
1149 // The selection widget should appear when filtering starts, and should be
1150 // selecting the first matching window.
1151 EXPECT_TRUE(selection_widget_active());
1152 EXPECT_TRUE(showing_filter_widget());
1153 EXPECT_EQ(GetSelectedWindow(), window1.get());
1155 // Window 0 has no "test" on it so it should be the only dimmed item.
1156 std::vector<WindowSelectorItem*> items = GetWindowItemsForRoot(0);
1157 EXPECT_TRUE(items[0]->dimmed());
1158 EXPECT_FALSE(items[1]->dimmed());
1159 EXPECT_FALSE(items[2]->dimmed());
1161 // No items match the search.
1162 FilterItems("I'm testing 'n testing");
1163 EXPECT_TRUE(items[0]->dimmed());
1164 EXPECT_TRUE(items[1]->dimmed());
1165 EXPECT_TRUE(items[2]->dimmed());
1167 // All the items should match the empty string. The filter widget should also
1168 // disappear.
1169 FilterItems("");
1170 EXPECT_FALSE(showing_filter_widget());
1171 EXPECT_FALSE(items[0]->dimmed());
1172 EXPECT_FALSE(items[1]->dimmed());
1173 EXPECT_FALSE(items[2]->dimmed());
1176 // Tests selecting in the overview with dimmed and undimmed items.
1177 TEST_F(WindowSelectorTest, TextFilteringSelection) {
1178 gfx::Rect bounds(0, 0, 100, 100);
1179 scoped_ptr<aura::Window> window2(CreateWindow(bounds));
1180 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
1181 scoped_ptr<aura::Window> window0(CreateWindow(bounds));
1182 base::string16 window2_title = base::UTF8ToUTF16("Rock and roll");
1183 base::string16 window1_title = base::UTF8ToUTF16("Rock and");
1184 base::string16 window0_title = base::UTF8ToUTF16("Rock");
1185 window0->SetTitle(window0_title);
1186 window1->SetTitle(window1_title);
1187 window2->SetTitle(window2_title);
1188 ToggleOverview();
1189 SendKey(ui::VKEY_RIGHT);
1190 EXPECT_TRUE(selection_widget_active());
1191 EXPECT_EQ(GetSelectedWindow(), window0.get());
1193 // Dim the first item, the selection should jump to the next item.
1194 std::vector<WindowSelectorItem*> items = GetWindowItemsForRoot(0);
1195 FilterItems("Rock and");
1196 EXPECT_EQ(GetSelectedWindow(), window1.get());
1198 // Cycle the selection, the dimmed window should not be selected.
1199 SendKey(ui::VKEY_RIGHT);
1200 EXPECT_EQ(GetSelectedWindow(), window2.get());
1201 SendKey(ui::VKEY_RIGHT);
1202 EXPECT_EQ(GetSelectedWindow(), window1.get());
1204 // Dimming all the items should hide the selection widget.
1205 FilterItems("Pop");
1206 EXPECT_FALSE(selection_widget_active());
1208 // Undimming one window should automatically select it.
1209 FilterItems("Rock and roll");
1210 EXPECT_EQ(GetSelectedWindow(), window2.get());
1213 // Tests clicking on the desktop itself to cancel overview mode.
1214 TEST_F(WindowSelectorTest, CancelOverviewOnMouseClick) {
1215 // Overview disabled by default.
1216 EXPECT_FALSE(IsSelecting());
1218 // Point and bounds selected so that they don't intersect. This causes
1219 // events located at the point to be passed to DesktopBackgroundController,
1220 // and not the window.
1221 gfx::Point point_in_background_page(0, 0);
1222 gfx::Rect bounds(10, 10, 100, 100);
1223 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
1224 ui::test::EventGenerator& generator = GetEventGenerator();
1225 // Move mouse to point in the background page. Sending an event here will pass
1226 // it to the DesktopBackgroundController in both regular and overview mode.
1227 generator.MoveMouseTo(point_in_background_page);
1229 // Clicking on the background page while not in overview should not toggle
1230 // overview.
1231 generator.ClickLeftButton();
1232 EXPECT_FALSE(IsSelecting());
1234 // Switch to overview mode.
1235 ToggleOverview();
1236 ASSERT_TRUE(IsSelecting());
1238 // Click should now exit overview mode.
1239 generator.ClickLeftButton();
1240 EXPECT_FALSE(IsSelecting());
1243 // Tests tapping on the desktop itself to cancel overview mode.
1244 TEST_F(WindowSelectorTest, CancelOverviewOnTap) {
1245 // Overview disabled by default.
1246 EXPECT_FALSE(IsSelecting());
1248 // Point and bounds selected so that they don't intersect. This causes
1249 // events located at the point to be passed to DesktopBackgroundController,
1250 // and not the window.
1251 gfx::Point point_in_background_page(0, 0);
1252 gfx::Rect bounds(10, 10, 100, 100);
1253 scoped_ptr<aura::Window> window1(CreateWindow(bounds));
1254 ui::test::EventGenerator& generator = GetEventGenerator();
1256 // Tapping on the background page while not in overview should not toggle
1257 // overview.
1258 generator.GestureTapAt(point_in_background_page);
1259 EXPECT_FALSE(IsSelecting());
1261 // Switch to overview mode.
1262 ToggleOverview();
1263 ASSERT_TRUE(IsSelecting());
1265 // Tap should now exit overview mode.
1266 generator.GestureTapAt(point_in_background_page);
1267 EXPECT_FALSE(IsSelecting());
1270 } // namespace ash