window_selector_unittest.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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. 4 5#include <algorithm> 6 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/mru_window_tracker.h" 21#include "ash/wm/overview/window_grid.h" 22#include "ash/wm/overview/window_selector.h" 23#include "ash/wm/overview/window_selector_controller.h" 24#include "ash/wm/overview/window_selector_item.h" 25#include "ash/wm/panels/panel_layout_manager.h" 26#include "ash/wm/window_state.h" 27#include "ash/wm/window_util.h" 28#include "ash/wm/wm_event.h" 29#include "base/basictypes.h" 30#include "base/compiler_specific.h" 31#include "base/memory/scoped_vector.h" 32#include "base/run_loop.h" 33#include "base/strings/string_piece.h" 34#include "base/strings/utf_string_conversions.h" 35#include "ui/aura/client/aura_constants.h" 36#include "ui/aura/client/cursor_client.h" 37#include "ui/aura/client/focus_client.h" 38#include "ui/aura/test/test_window_delegate.h" 39#include "ui/aura/test/test_windows.h" 40#include "ui/aura/window.h" 41#include "ui/aura/window_event_dispatcher.h" 42#include "ui/compositor/scoped_animation_duration_scale_mode.h" 43#include "ui/events/test/event_generator.h" 44#include "ui/gfx/rect_conversions.h" 45#include "ui/gfx/transform.h" 46#include "ui/views/controls/label.h" 47#include "ui/views/widget/native_widget_aura.h" 48#include "ui/views/widget/widget_delegate.h" 49#include "ui/wm/core/window_util.h" 50#include "ui/wm/public/activation_delegate.h" 51 52namespace ash { 53namespace { 54 55class NonActivatableActivationDelegate 56 : public aura::client::ActivationDelegate { 57 public: 58 virtual bool ShouldActivate() const OVERRIDE { 59 return false; 60 } 61}; 62 63void CancelDrag(DragDropController* controller, bool* canceled) { 64 if (controller->IsDragDropInProgress()) { 65 *canceled = true; 66 controller->DragCancel(); 67 } 68} 69 70} // namespace 71 72class WindowSelectorTest : public test::AshTestBase { 73 public: 74 WindowSelectorTest() {} 75 virtual ~WindowSelectorTest() {} 76 77 virtual void SetUp() OVERRIDE { 78 test::AshTestBase::SetUp(); 79 ASSERT_TRUE(test::TestShelfDelegate::instance()); 80 81 shelf_view_test_.reset(new test::ShelfViewTestAPI( 82 test::ShelfTestAPI(Shelf::ForPrimaryDisplay()).shelf_view())); 83 shelf_view_test_->SetAnimationDuration(1); 84 } 85 86 aura::Window* CreateWindow(const gfx::Rect& bounds) { 87 return CreateTestWindowInShellWithDelegate(&delegate_, -1, bounds); 88 } 89 90 aura::Window* CreateWindowWithId(const gfx::Rect& bounds, int id) { 91 return CreateTestWindowInShellWithDelegate(&delegate_, id, bounds); 92 } 93 aura::Window* CreateNonActivatableWindow(const gfx::Rect& bounds) { 94 aura::Window* window = CreateWindow(bounds); 95 aura::client::SetActivationDelegate(window, 96 &non_activatable_activation_delegate_); 97 EXPECT_FALSE(ash::wm::CanActivateWindow(window)); 98 return window; 99 } 100 101 aura::Window* CreatePanelWindow(const gfx::Rect& bounds) { 102 aura::Window* window = CreateTestWindowInShellWithDelegateAndType( 103 NULL, ui::wm::WINDOW_TYPE_PANEL, 0, bounds); 104 test::TestShelfDelegate::instance()->AddShelfItem(window); 105 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 106 return window; 107 } 108 109 views::Widget* CreatePanelWindowWidget(const gfx::Rect& bounds) { 110 views::Widget* widget = new views::Widget; 111 views::Widget::InitParams params; 112 params.bounds = bounds; 113 params.type = views::Widget::InitParams::TYPE_PANEL; 114 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 115 widget->Init(params); 116 widget->Show(); 117 ParentWindowInPrimaryRootWindow(widget->GetNativeWindow()); 118 return widget; 119 } 120 121 bool WindowsOverlapping(aura::Window* window1, aura::Window* window2) { 122 gfx::RectF window1_bounds = GetTransformedTargetBounds(window1); 123 gfx::RectF window2_bounds = GetTransformedTargetBounds(window2); 124 return window1_bounds.Intersects(window2_bounds); 125 } 126 127 void ToggleOverview() { 128 ash::Shell::GetInstance()->window_selector_controller()->ToggleOverview(); 129 } 130 131 gfx::Transform GetTransformRelativeTo(gfx::PointF origin, 132 const gfx::Transform& transform) { 133 gfx::Transform t; 134 t.Translate(origin.x(), origin.y()); 135 t.PreconcatTransform(transform); 136 t.Translate(-origin.x(), -origin.y()); 137 return t; 138 } 139 140 gfx::RectF GetTransformedBounds(aura::Window* window) { 141 gfx::RectF bounds(ScreenUtil::ConvertRectToScreen( 142 window->parent(), window->layer()->bounds())); 143 gfx::Transform transform(GetTransformRelativeTo(bounds.origin(), 144 window->layer()->transform())); 145 transform.TransformRect(&bounds); 146 return bounds; 147 } 148 149 gfx::RectF GetTransformedTargetBounds(aura::Window* window) { 150 gfx::RectF bounds(ScreenUtil::ConvertRectToScreen( 151 window->parent(), window->layer()->GetTargetBounds())); 152 gfx::Transform transform(GetTransformRelativeTo(bounds.origin(), 153 window->layer()->GetTargetTransform())); 154 transform.TransformRect(&bounds); 155 return bounds; 156 } 157 158 gfx::RectF GetTransformedBoundsInRootWindow(aura::Window* window) { 159 gfx::RectF bounds = gfx::Rect(window->bounds().size()); 160 aura::Window* root = window->GetRootWindow(); 161 CHECK(window->layer()); 162 CHECK(root->layer()); 163 gfx::Transform transform; 164 if (!window->layer()->GetTargetTransformRelativeTo(root->layer(), 165 &transform)) { 166 return gfx::RectF(); 167 } 168 transform.TransformRect(&bounds); 169 return bounds; 170 } 171 172 void ClickWindow(aura::Window* window) { 173 ui::test::EventGenerator event_generator(window->GetRootWindow(), window); 174 gfx::RectF target = GetTransformedBounds(window); 175 event_generator.ClickLeftButton(); 176 } 177 178 void SendKey(ui::KeyboardCode key) { 179 ui::test::EventGenerator event_generator(Shell::GetPrimaryRootWindow()); 180 event_generator.PressKey(key, 0); 181 event_generator.ReleaseKey(key, 0); 182 } 183 184 bool IsSelecting() { 185 return ash::Shell::GetInstance()->window_selector_controller()-> 186 IsSelecting(); 187 } 188 189 aura::Window* GetFocusedWindow() { 190 return aura::client::GetFocusClient( 191 Shell::GetPrimaryRootWindow())->GetFocusedWindow(); 192 } 193 194 const std::vector<WindowSelectorItem*>& GetWindowItemsForRoot(int index) { 195 return ash::Shell::GetInstance()->window_selector_controller()-> 196 window_selector_->grid_list_[index]->window_list_.get(); 197 } 198 199 const aura::Window* GetSelectedWindow() { 200 WindowSelector* ws = ash::Shell::GetInstance()-> 201 window_selector_controller()->window_selector_.get(); 202 return ws->grid_list_[ws->selected_grid_index_]-> 203 SelectedWindow()->SelectionWindow(); 204 } 205 206 bool selection_widget_active() { 207 WindowSelector* ws = ash::Shell::GetInstance()-> 208 window_selector_controller()->window_selector_.get(); 209 return ws->grid_list_[ws->selected_grid_index_]->is_selecting(); 210 } 211 212 bool showing_filter_widget() { 213 WindowSelector* ws = ash::Shell::GetInstance()-> 214 window_selector_controller()->window_selector_.get(); 215 return ws->text_filter_widget_->GetNativeWindow()->layer()-> 216 GetTargetTransform().IsIdentity(); 217 } 218 219 views::Widget* GetCloseButton(ash::WindowSelectorItem* window) { 220 return window->close_button_.get(); 221 } 222 223 views::Label* GetLabelView(ash::WindowSelectorItem* window) { 224 return window->window_label_view_; 225 } 226 227 // Tests that a window is contained within a given WindowSelectorItem, and 228 // that both the window and its matching close button are within the same 229 // screen. 230 void IsWindowAndCloseButtonInScreen(aura::Window* window, 231 WindowSelectorItem* window_item) { 232 aura::Window* root_window = window_item->GetRootWindow(); 233 EXPECT_TRUE(window_item->Contains(window)); 234 EXPECT_TRUE(root_window->GetBoundsInScreen().Contains( 235 ToEnclosingRect(GetTransformedTargetBounds(window)))); 236 EXPECT_TRUE(root_window->GetBoundsInScreen().Contains( 237 ToEnclosingRect(GetTransformedTargetBounds( 238 GetCloseButton(window_item)->GetNativeView())))); 239 } 240 241 void FilterItems(const base::StringPiece& pattern) { 242 ash::Shell::GetInstance()-> 243 window_selector_controller()->window_selector_.get()-> 244 ContentsChanged(NULL, base::UTF8ToUTF16(pattern)); 245 } 246 247 test::ShelfViewTestAPI* shelf_view_test() { 248 return shelf_view_test_.get(); 249 } 250 251 views::Widget* text_filter_widget() { 252 return ash::Shell::GetInstance()-> 253 window_selector_controller()->window_selector_.get()-> 254 text_filter_widget_.get(); 255 } 256 257 private: 258 aura::test::TestWindowDelegate delegate_; 259 NonActivatableActivationDelegate non_activatable_activation_delegate_; 260 scoped_ptr<test::ShelfViewTestAPI> shelf_view_test_; 261 262 DISALLOW_COPY_AND_ASSIGN(WindowSelectorTest); 263}; 264 265// Tests that an a11y alert is sent on entering overview mode. 266TEST_F(WindowSelectorTest, A11yAlertOnOverviewMode) { 267 gfx::Rect bounds(0, 0, 400, 400); 268 AccessibilityDelegate* delegate = 269 ash::Shell::GetInstance()->accessibility_delegate(); 270 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 271 EXPECT_NE(delegate->GetLastAccessibilityAlert(), 272 A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED); 273 ToggleOverview(); 274 EXPECT_EQ(delegate->GetLastAccessibilityAlert(), 275 A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED); 276} 277 278// Tests entering overview mode with two windows and selecting one by clicking. 279TEST_F(WindowSelectorTest, Basic) { 280 gfx::Rect bounds(0, 0, 400, 400); 281 aura::Window* root_window = Shell::GetPrimaryRootWindow(); 282 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 283 scoped_ptr<aura::Window> window2(CreateWindow(bounds)); 284 scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds)); 285 scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds)); 286 EXPECT_TRUE(WindowsOverlapping(window1.get(), window2.get())); 287 EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get())); 288 wm::ActivateWindow(window2.get()); 289 EXPECT_FALSE(wm::IsActiveWindow(window1.get())); 290 EXPECT_TRUE(wm::IsActiveWindow(window2.get())); 291 EXPECT_EQ(window2.get(), GetFocusedWindow()); 292 // Hide the cursor before entering overview to test that it will be shown. 293 aura::client::GetCursorClient(root_window)->HideCursor(); 294 295 // In overview mode the windows should no longer overlap and the text filter 296 // widget should be focused. 297 ToggleOverview(); 298 EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow()); 299 EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get())); 300 EXPECT_FALSE(WindowsOverlapping(window1.get(), panel1.get())); 301 // Panels 1 and 2 should still be overlapping being in a single selector 302 // item. 303 EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get())); 304 305 // Clicking window 1 should activate it. 306 ClickWindow(window1.get()); 307 EXPECT_TRUE(wm::IsActiveWindow(window1.get())); 308 EXPECT_FALSE(wm::IsActiveWindow(window2.get())); 309 EXPECT_EQ(window1.get(), GetFocusedWindow()); 310 311 // Cursor should have been unlocked. 312 EXPECT_FALSE(aura::client::GetCursorClient(root_window)->IsCursorLocked()); 313} 314 315// Tests selecting a window by tapping on it. 316TEST_F(WindowSelectorTest, BasicGesture) { 317 gfx::Rect bounds(0, 0, 400, 400); 318 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 319 scoped_ptr<aura::Window> window2(CreateWindow(bounds)); 320 wm::ActivateWindow(window1.get()); 321 EXPECT_EQ(window1.get(), GetFocusedWindow()); 322 ToggleOverview(); 323 EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow()); 324 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), 325 window2.get()); 326 generator.GestureTapAt(gfx::ToEnclosingRect( 327 GetTransformedTargetBounds(window2.get())).CenterPoint()); 328 EXPECT_EQ(window2.get(), GetFocusedWindow()); 329} 330 331// Tests that a window does not receive located events when in overview mode. 332TEST_F(WindowSelectorTest, WindowDoesNotReceiveEvents) { 333 gfx::Rect window_bounds(20, 10, 200, 300); 334 aura::Window* root_window = Shell::GetPrimaryRootWindow(); 335 scoped_ptr<aura::Window> window(CreateWindow(window_bounds)); 336 337 gfx::Point point1(window_bounds.x() + 10, window_bounds.y() + 10); 338 339 ui::MouseEvent event1(ui::ET_MOUSE_PRESSED, point1, point1, 340 ui::EF_NONE, ui::EF_NONE); 341 342 ui::EventTarget* root_target = root_window; 343 ui::EventTargeter* targeter = root_target->GetEventTargeter(); 344 345 // The event should target the window because we are still not in overview 346 // mode. 347 EXPECT_EQ(window, static_cast<aura::Window*>( 348 targeter->FindTargetForEvent(root_target, &event1))); 349 350 ToggleOverview(); 351 352 // The bounds have changed, take that into account. 353 gfx::RectF bounds = GetTransformedBoundsInRootWindow(window.get()); 354 gfx::Point point2(bounds.x() + 10, bounds.y() + 10); 355 ui::MouseEvent event2(ui::ET_MOUSE_PRESSED, point2, point2, 356 ui::EF_NONE, ui::EF_NONE); 357 358 // Now the transparent window should be intercepting this event. 359 EXPECT_NE(window, static_cast<aura::Window*>( 360 targeter->FindTargetForEvent(root_target, &event2))); 361} 362 363// Tests that clicking on the close button effectively closes the window. 364TEST_F(WindowSelectorTest, CloseButton) { 365 scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(200, 300, 250, 450))); 366 367 // We need a widget for the close button the work, a bare window will crash. 368 scoped_ptr<views::Widget> widget(new views::Widget); 369 views::Widget::InitParams params; 370 params.bounds = gfx::Rect(0, 0, 400, 400); 371 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 372 params.parent = window1->parent(); 373 widget->Init(params); 374 widget->Show(); 375 ToggleOverview(); 376 377 aura::Window* window2 = widget->GetNativeWindow(); 378 gfx::RectF bounds = GetTransformedBoundsInRootWindow(window2); 379 gfx::Point point(bounds.top_right().x() - 1, bounds.top_right().y() - 1); 380 ui::test::EventGenerator event_generator(window2->GetRootWindow(), point); 381 382 EXPECT_FALSE(widget->IsClosed()); 383 event_generator.ClickLeftButton(); 384 EXPECT_TRUE(widget->IsClosed()); 385} 386 387// Tests entering overview mode with two windows and selecting one. 388TEST_F(WindowSelectorTest, FullscreenWindow) { 389 gfx::Rect bounds(0, 0, 400, 400); 390 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 391 scoped_ptr<aura::Window> window2(CreateWindow(bounds)); 392 scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds)); 393 wm::ActivateWindow(window1.get()); 394 395 const wm::WMEvent toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN); 396 wm::GetWindowState(window1.get())->OnWMEvent(&toggle_fullscreen_event); 397 // The panel is hidden in fullscreen mode. 398 EXPECT_FALSE(panel1->IsVisible()); 399 EXPECT_TRUE(wm::GetWindowState(window1.get())->IsFullscreen()); 400 401 // Enter overview and select the fullscreen window. 402 ToggleOverview(); 403 404 // The panel becomes temporarily visible for the overview. 405 EXPECT_TRUE(panel1->IsVisible()); 406 ClickWindow(window1.get()); 407 408 // The window is still fullscreen as it was selected. The panel should again 409 // be hidden. 410 EXPECT_TRUE(wm::GetWindowState(window1.get())->IsFullscreen()); 411 EXPECT_FALSE(panel1->IsVisible()); 412 413 // Entering overview and selecting another window, the previous window remains 414 // fullscreen. 415 // TODO(flackr): Currently the panel remains hidden, but should become visible 416 // again. 417 ToggleOverview(); 418 ClickWindow(window2.get()); 419 EXPECT_TRUE(wm::GetWindowState(window1.get())->IsFullscreen()); 420} 421 422// Tests that the shelf dimming state is removed while in overview and restored 423// on exiting overview. 424TEST_F(WindowSelectorTest, OverviewUndimsShelf) { 425 gfx::Rect bounds(0, 0, 400, 400); 426 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 427 wm::WindowState* window_state = wm::GetWindowState(window1.get()); 428 window_state->Maximize(); 429 ash::ShelfWidget* shelf = Shell::GetPrimaryRootWindowController()->shelf(); 430 EXPECT_TRUE(shelf->GetDimsShelf()); 431 ToggleOverview(); 432 EXPECT_FALSE(shelf->GetDimsShelf()); 433 ToggleOverview(); 434 EXPECT_TRUE(shelf->GetDimsShelf()); 435} 436 437// Tests that beginning window selection hides the app list. 438TEST_F(WindowSelectorTest, SelectingHidesAppList) { 439 gfx::Rect bounds(0, 0, 400, 400); 440 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 441 scoped_ptr<aura::Window> window2(CreateWindow(bounds)); 442 Shell::GetInstance()->ShowAppList(NULL); 443 EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility()); 444 ToggleOverview(); 445 EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility()); 446 ToggleOverview(); 447} 448 449// Tests that a minimized window's visibility and layer visibility is correctly 450// changed when entering overview and restored when leaving overview mode. 451// Crashes after the skia roll in http://crrev.com/274114. 452// http://crbug.com/379570 453TEST_F(WindowSelectorTest, DISABLED_MinimizedWindowVisibility) { 454 gfx::Rect bounds(0, 0, 400, 400); 455 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 456 wm::WindowState* window_state = wm::GetWindowState(window1.get()); 457 window_state->Minimize(); 458 EXPECT_FALSE(window1->IsVisible()); 459 EXPECT_FALSE(window1->layer()->GetTargetVisibility()); 460 { 461 ui::ScopedAnimationDurationScaleMode test_duration_mode( 462 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); 463 ToggleOverview(); 464 EXPECT_TRUE(window1->IsVisible()); 465 EXPECT_TRUE(window1->layer()->GetTargetVisibility()); 466 } 467 { 468 ui::ScopedAnimationDurationScaleMode test_duration_mode( 469 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); 470 ToggleOverview(); 471 EXPECT_FALSE(window1->IsVisible()); 472 EXPECT_FALSE(window1->layer()->GetTargetVisibility()); 473 } 474} 475 476// Tests that a bounds change during overview is corrected for. 477TEST_F(WindowSelectorTest, BoundsChangeDuringOverview) { 478 scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 400, 400))); 479 ToggleOverview(); 480 gfx::Rect overview_bounds = 481 ToEnclosingRect(GetTransformedTargetBounds(window.get())); 482 window->SetBounds(gfx::Rect(200, 0, 200, 200)); 483 gfx::Rect new_overview_bounds = 484 ToEnclosingRect(GetTransformedTargetBounds(window.get())); 485 EXPECT_EQ(overview_bounds.x(), new_overview_bounds.x()); 486 EXPECT_EQ(overview_bounds.y(), new_overview_bounds.y()); 487 EXPECT_EQ(overview_bounds.width(), new_overview_bounds.width()); 488 EXPECT_EQ(overview_bounds.height(), new_overview_bounds.height()); 489 ToggleOverview(); 490} 491 492// Tests that a newly created window aborts overview. 493TEST_F(WindowSelectorTest, NewWindowCancelsOveriew) { 494 gfx::Rect bounds(0, 0, 400, 400); 495 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 496 scoped_ptr<aura::Window> window2(CreateWindow(bounds)); 497 ToggleOverview(); 498 EXPECT_TRUE(IsSelecting()); 499 500 // A window being created should exit overview mode. 501 scoped_ptr<aura::Window> window3(CreateWindow(bounds)); 502 EXPECT_FALSE(IsSelecting()); 503} 504 505// Tests that a window activation exits overview mode. 506TEST_F(WindowSelectorTest, ActivationCancelsOveriew) { 507 gfx::Rect bounds(0, 0, 400, 400); 508 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 509 scoped_ptr<aura::Window> window2(CreateWindow(bounds)); 510 window2->Focus(); 511 ToggleOverview(); 512 EXPECT_TRUE(IsSelecting()); 513 514 // A window being activated should exit overview mode. 515 window1->Focus(); 516 EXPECT_FALSE(IsSelecting()); 517 518 // window1 should be focused after exiting even though window2 was focused on 519 // entering overview because we exited due to an activation. 520 EXPECT_EQ(window1.get(), GetFocusedWindow()); 521} 522 523// Tests that exiting overview mode without selecting a window restores focus 524// to the previously focused window. 525TEST_F(WindowSelectorTest, CancelRestoresFocus) { 526 gfx::Rect bounds(0, 0, 400, 400); 527 scoped_ptr<aura::Window> window(CreateWindow(bounds)); 528 wm::ActivateWindow(window.get()); 529 EXPECT_EQ(window.get(), GetFocusedWindow()); 530 531 // In overview mode, the text filter widget should be focused. 532 ToggleOverview(); 533 EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow()); 534 535 // If canceling overview mode, focus should be restored. 536 ToggleOverview(); 537 EXPECT_EQ(window.get(), GetFocusedWindow()); 538} 539 540// Tests that overview mode is exited if the last remaining window is destroyed. 541TEST_F(WindowSelectorTest, LastWindowDestroyed) { 542 gfx::Rect bounds(0, 0, 400, 400); 543 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 544 scoped_ptr<aura::Window> window2(CreateWindow(bounds)); 545 ToggleOverview(); 546 547 window1.reset(); 548 window2.reset(); 549 EXPECT_FALSE(IsSelecting()); 550} 551 552// Tests that entering overview mode restores a window to its original 553// target location. 554TEST_F(WindowSelectorTest, QuickReentryRestoresInitialTransform) { 555 gfx::Rect bounds(0, 0, 400, 400); 556 scoped_ptr<aura::Window> window(CreateWindow(bounds)); 557 gfx::Rect initial_bounds = ToEnclosingRect( 558 GetTransformedBounds(window.get())); 559 ToggleOverview(); 560 // Quickly exit and reenter overview mode. The window should still be 561 // animating when we reenter. We cannot short circuit animations for this but 562 // we also don't have to wait for them to complete. 563 { 564 ui::ScopedAnimationDurationScaleMode test_duration_mode( 565 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); 566 ToggleOverview(); 567 ToggleOverview(); 568 } 569 EXPECT_NE(initial_bounds, ToEnclosingRect( 570 GetTransformedTargetBounds(window.get()))); 571 ToggleOverview(); 572 EXPECT_FALSE(IsSelecting()); 573 EXPECT_EQ(initial_bounds, ToEnclosingRect( 574 GetTransformedTargetBounds(window.get()))); 575} 576 577// Tests that non-activatable windows are hidden when entering overview mode. 578TEST_F(WindowSelectorTest, NonActivatableWindowsHidden) { 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 scoped_ptr<aura::Window> non_activatable_window( 583 CreateNonActivatableWindow(Shell::GetPrimaryRootWindow()->bounds())); 584 EXPECT_TRUE(non_activatable_window->IsVisible()); 585 ToggleOverview(); 586 EXPECT_FALSE(non_activatable_window->IsVisible()); 587 ToggleOverview(); 588 EXPECT_TRUE(non_activatable_window->IsVisible()); 589 590 // Test that a window behind the fullscreen non-activatable window can be 591 // clicked. 592 non_activatable_window->parent()->StackChildAtTop( 593 non_activatable_window.get()); 594 ToggleOverview(); 595 ClickWindow(window1.get()); 596 EXPECT_FALSE(IsSelecting()); 597 EXPECT_TRUE(wm::IsActiveWindow(window1.get())); 598} 599 600// Tests that windows with modal child windows are transformed with the modal 601// child even though not activatable themselves. 602TEST_F(WindowSelectorTest, ModalChild) { 603 gfx::Rect bounds(0, 0, 400, 400); 604 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 605 scoped_ptr<aura::Window> child1(CreateWindow(bounds)); 606 child1->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW); 607 ::wm::AddTransientChild(window1.get(), child1.get()); 608 EXPECT_EQ(window1->parent(), child1->parent()); 609 ToggleOverview(); 610 EXPECT_TRUE(window1->IsVisible()); 611 EXPECT_TRUE(child1->IsVisible()); 612 EXPECT_EQ(ToEnclosingRect(GetTransformedTargetBounds(child1.get())), 613 ToEnclosingRect(GetTransformedTargetBounds(window1.get()))); 614 ToggleOverview(); 615} 616 617// Tests that clicking a modal window's parent activates the modal window in 618// overview. 619TEST_F(WindowSelectorTest, ClickModalWindowParent) { 620 scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 180, 180))); 621 scoped_ptr<aura::Window> child1(CreateWindow(gfx::Rect(200, 0, 180, 180))); 622 child1->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW); 623 ::wm::AddTransientChild(window1.get(), child1.get()); 624 EXPECT_FALSE(WindowsOverlapping(window1.get(), child1.get())); 625 EXPECT_EQ(window1->parent(), child1->parent()); 626 ToggleOverview(); 627 // Given that their relative positions are preserved, the windows should still 628 // not overlap. 629 EXPECT_FALSE(WindowsOverlapping(window1.get(), child1.get())); 630 ClickWindow(window1.get()); 631 EXPECT_FALSE(IsSelecting()); 632 633 // Clicking on window1 should activate child1. 634 EXPECT_TRUE(wm::IsActiveWindow(child1.get())); 635} 636 637// Tests that windows remain on the display they are currently on in overview 638// mode, and that the close buttons are on matching displays. 639TEST_F(WindowSelectorTest, MultipleDisplays) { 640 if (!SupportsMultipleDisplays()) 641 return; 642 643 UpdateDisplay("600x400,600x400"); 644 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 645 gfx::Rect bounds1(0, 0, 400, 400); 646 gfx::Rect bounds2(650, 0, 400, 400); 647 648 scoped_ptr<aura::Window> window1(CreateWindow(bounds1)); 649 scoped_ptr<aura::Window> window2(CreateWindow(bounds1)); 650 scoped_ptr<aura::Window> window3(CreateWindow(bounds2)); 651 scoped_ptr<aura::Window> window4(CreateWindow(bounds2)); 652 scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds1)); 653 scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds1)); 654 scoped_ptr<aura::Window> panel3(CreatePanelWindow(bounds2)); 655 scoped_ptr<aura::Window> panel4(CreatePanelWindow(bounds2)); 656 EXPECT_EQ(root_windows[0], window1->GetRootWindow()); 657 EXPECT_EQ(root_windows[0], window2->GetRootWindow()); 658 EXPECT_EQ(root_windows[1], window3->GetRootWindow()); 659 EXPECT_EQ(root_windows[1], window4->GetRootWindow()); 660 661 EXPECT_EQ(root_windows[0], panel1->GetRootWindow()); 662 EXPECT_EQ(root_windows[0], panel2->GetRootWindow()); 663 EXPECT_EQ(root_windows[1], panel3->GetRootWindow()); 664 EXPECT_EQ(root_windows[1], panel4->GetRootWindow()); 665 666 // In overview mode, each window remains in the same root window. 667 ToggleOverview(); 668 EXPECT_EQ(root_windows[0], window1->GetRootWindow()); 669 EXPECT_EQ(root_windows[0], window2->GetRootWindow()); 670 EXPECT_EQ(root_windows[1], window3->GetRootWindow()); 671 EXPECT_EQ(root_windows[1], window4->GetRootWindow()); 672 EXPECT_EQ(root_windows[0], panel1->GetRootWindow()); 673 EXPECT_EQ(root_windows[0], panel2->GetRootWindow()); 674 EXPECT_EQ(root_windows[1], panel3->GetRootWindow()); 675 EXPECT_EQ(root_windows[1], panel4->GetRootWindow()); 676 677 const std::vector<WindowSelectorItem*>& primary_window_items = 678 GetWindowItemsForRoot(0); 679 const std::vector<WindowSelectorItem*>& secondary_window_items = 680 GetWindowItemsForRoot(1); 681 682 // Window indices are based on top-down order. The reverse of our creation. 683 IsWindowAndCloseButtonInScreen(window1.get(), primary_window_items[2]); 684 IsWindowAndCloseButtonInScreen(window2.get(), primary_window_items[1]); 685 IsWindowAndCloseButtonInScreen(window3.get(), secondary_window_items[2]); 686 IsWindowAndCloseButtonInScreen(window4.get(), secondary_window_items[1]); 687 688 IsWindowAndCloseButtonInScreen(panel1.get(), primary_window_items[0]); 689 IsWindowAndCloseButtonInScreen(panel2.get(), primary_window_items[0]); 690 IsWindowAndCloseButtonInScreen(panel3.get(), secondary_window_items[0]); 691 IsWindowAndCloseButtonInScreen(panel4.get(), secondary_window_items[0]); 692 693 EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get())); 694 EXPECT_TRUE(WindowsOverlapping(panel3.get(), panel4.get())); 695 EXPECT_FALSE(WindowsOverlapping(panel1.get(), panel3.get())); 696} 697 698// Tests shutting down during overview. 699TEST_F(WindowSelectorTest, Shutdown) { 700 gfx::Rect bounds(0, 0, 400, 400); 701 // These windows will be deleted when the test exits and the Shell instance 702 // is shut down. 703 aura::Window* window1(CreateWindow(bounds)); 704 aura::Window* window2(CreateWindow(bounds)); 705 aura::Window* window3(CreatePanelWindow(bounds)); 706 aura::Window* window4(CreatePanelWindow(bounds)); 707 708 wm::ActivateWindow(window4); 709 wm::ActivateWindow(window3); 710 wm::ActivateWindow(window2); 711 wm::ActivateWindow(window1); 712 713 ToggleOverview(); 714} 715 716// Tests removing a display during overview. 717TEST_F(WindowSelectorTest, RemoveDisplay) { 718 if (!SupportsMultipleDisplays()) 719 return; 720 721 UpdateDisplay("400x400,400x400"); 722 gfx::Rect bounds1(0, 0, 100, 100); 723 gfx::Rect bounds2(450, 0, 100, 100); 724 scoped_ptr<aura::Window> window1(CreateWindow(bounds1)); 725 scoped_ptr<aura::Window> window2(CreateWindow(bounds2)); 726 scoped_ptr<aura::Window> window3(CreatePanelWindow(bounds1)); 727 scoped_ptr<aura::Window> window4(CreatePanelWindow(bounds2)); 728 729 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 730 EXPECT_EQ(root_windows[0], window1->GetRootWindow()); 731 EXPECT_EQ(root_windows[1], window2->GetRootWindow()); 732 EXPECT_EQ(root_windows[0], window3->GetRootWindow()); 733 EXPECT_EQ(root_windows[1], window4->GetRootWindow()); 734 735 wm::ActivateWindow(window4.get()); 736 wm::ActivateWindow(window3.get()); 737 wm::ActivateWindow(window2.get()); 738 wm::ActivateWindow(window1.get()); 739 740 ToggleOverview(); 741 EXPECT_TRUE(IsSelecting()); 742 UpdateDisplay("400x400"); 743 EXPECT_FALSE(IsSelecting()); 744} 745 746// Tests starting overview during a drag and drop tracking operation. 747// TODO(flackr): Fix memory corruption crash when running locally (not failing 748// on bots). See http://crbug.com/342528. 749TEST_F(WindowSelectorTest, DISABLED_DragDropInProgress) { 750 bool drag_canceled_by_test = false; 751 gfx::Rect bounds(0, 0, 400, 400); 752 scoped_ptr<aura::Window> window(CreateWindow(bounds)); 753 test::ShellTestApi shell_test_api(Shell::GetInstance()); 754 ash::DragDropController* drag_drop_controller = 755 shell_test_api.drag_drop_controller(); 756 ui::OSExchangeData data; 757 base::MessageLoopForUI::current()->PostTask(FROM_HERE, 758 base::Bind(&WindowSelectorTest::ToggleOverview, 759 base::Unretained(this))); 760 base::MessageLoopForUI::current()->PostTask(FROM_HERE, 761 base::Bind(&CancelDrag, drag_drop_controller, &drag_canceled_by_test)); 762 data.SetString(base::UTF8ToUTF16("I am being dragged")); 763 drag_drop_controller->StartDragAndDrop(data, window->GetRootWindow(), 764 window.get(), gfx::Point(5, 5), ui::DragDropTypes::DRAG_MOVE, 765 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE); 766 RunAllPendingInMessageLoop(); 767 EXPECT_FALSE(drag_canceled_by_test); 768 ASSERT_TRUE(IsSelecting()); 769 RunAllPendingInMessageLoop(); 770} 771 772// Test that a label is created under the window on entering overview mode. 773TEST_F(WindowSelectorTest, CreateLabelUnderWindow) { 774 scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 100, 100))); 775 base::string16 window_title = base::UTF8ToUTF16("My window"); 776 window->SetTitle(window_title); 777 ToggleOverview(); 778 WindowSelectorItem* window_item = GetWindowItemsForRoot(0).back(); 779 views::Label* label = GetLabelView(window_item); 780 // Has the label view been created? 781 ASSERT_TRUE(label); 782 783 // Verify the label matches the window title. 784 EXPECT_EQ(label->text(), window_title); 785 786 // Update the window title and check that the label is updated, too. 787 base::string16 updated_title = base::UTF8ToUTF16("Updated title"); 788 window->SetTitle(updated_title); 789 EXPECT_EQ(label->text(), updated_title); 790 791 // Labels are located based on target_bounds, not the actual window item 792 // bounds. 793 gfx::Rect target_bounds(window_item->target_bounds()); 794 gfx::Rect expected_label_bounds(target_bounds.x(), 795 target_bounds.bottom() - label-> 796 GetPreferredSize().height(), 797 target_bounds.width(), 798 label->GetPreferredSize().height()); 799 gfx::Rect real_label_bounds = label->GetWidget()->GetNativeWindow()->bounds(); 800 EXPECT_EQ(real_label_bounds, expected_label_bounds); 801} 802 803// Tests that a label is created for the active panel in a group of panels in 804// overview mode. 805TEST_F(WindowSelectorTest, CreateLabelUnderPanel) { 806 scoped_ptr<aura::Window> panel1(CreatePanelWindow(gfx::Rect(0, 0, 100, 100))); 807 scoped_ptr<aura::Window> panel2(CreatePanelWindow(gfx::Rect(0, 0, 100, 100))); 808 base::string16 panel1_title = base::UTF8ToUTF16("My panel"); 809 base::string16 panel2_title = base::UTF8ToUTF16("Another panel"); 810 base::string16 updated_panel1_title = base::UTF8ToUTF16("WebDriver Torso"); 811 base::string16 updated_panel2_title = base::UTF8ToUTF16("Da panel"); 812 panel1->SetTitle(panel1_title); 813 panel2->SetTitle(panel2_title); 814 wm::ActivateWindow(panel1.get()); 815 ToggleOverview(); 816 WindowSelectorItem* window_item = GetWindowItemsForRoot(0).back(); 817 views::Label* label = GetLabelView(window_item); 818 // Has the label view been created? 819 ASSERT_TRUE(label); 820 821 // Verify the label matches the active window title. 822 EXPECT_EQ(label->text(), panel1_title); 823 // Verify that updating the title also updates the label. 824 panel1->SetTitle(updated_panel1_title); 825 EXPECT_EQ(label->text(), updated_panel1_title); 826 // After destroying the first panel, the label should match the second panel. 827 panel1.reset(); 828 label = GetLabelView(window_item); 829 EXPECT_EQ(label->text(), panel2_title); 830 // Also test updating the title on the second panel. 831 panel2->SetTitle(updated_panel2_title); 832 EXPECT_EQ(label->text(), updated_panel2_title); 833} 834 835// Tests that overview updates the window positions if the display orientation 836// changes. 837TEST_F(WindowSelectorTest, DisplayOrientationChanged) { 838 if (!SupportsHostWindowResize()) 839 return; 840 841 aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); 842 UpdateDisplay("600x200"); 843 EXPECT_EQ("0,0 600x200", root_window->bounds().ToString()); 844 gfx::Rect window_bounds(0, 0, 150, 150); 845 ScopedVector<aura::Window> windows; 846 for (int i = 0; i < 3; i++) { 847 windows.push_back(CreateWindow(window_bounds)); 848 } 849 850 ToggleOverview(); 851 for (ScopedVector<aura::Window>::iterator iter = windows.begin(); 852 iter != windows.end(); ++iter) { 853 EXPECT_TRUE(root_window->bounds().Contains( 854 ToEnclosingRect(GetTransformedTargetBounds(*iter)))); 855 } 856 857 // Rotate the display, windows should be repositioned to be within the screen 858 // bounds. 859 UpdateDisplay("600x200/r"); 860 EXPECT_EQ("0,0 200x600", root_window->bounds().ToString()); 861 for (ScopedVector<aura::Window>::iterator iter = windows.begin(); 862 iter != windows.end(); ++iter) { 863 EXPECT_TRUE(root_window->bounds().Contains( 864 ToEnclosingRect(GetTransformedTargetBounds(*iter)))); 865 } 866} 867 868// Tests traversing some windows in overview mode with the tab key. 869TEST_F(WindowSelectorTest, BasicTabKeyNavigation) { 870 gfx::Rect bounds(0, 0, 100, 100); 871 scoped_ptr<aura::Window> window2(CreateWindow(bounds)); 872 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 873 ToggleOverview(); 874 875 SendKey(ui::VKEY_TAB); 876 EXPECT_EQ(GetSelectedWindow(), window1.get()); 877 SendKey(ui::VKEY_TAB); 878 EXPECT_EQ(GetSelectedWindow(), window2.get()); 879 SendKey(ui::VKEY_TAB); 880 EXPECT_EQ(GetSelectedWindow(), window1.get()); 881} 882 883// Tests traversing some windows in overview mode with the arrow keys in every 884// possible direction. 885TEST_F(WindowSelectorTest, BasicArrowKeyNavigation) { 886 if (!SupportsHostWindowResize()) 887 return; 888 const size_t test_windows = 9; 889 UpdateDisplay("800x600"); 890 ScopedVector<aura::Window> windows; 891 for (size_t i = test_windows; i > 0; i--) 892 windows.push_back(CreateWindowWithId(gfx::Rect(0, 0, 100, 100), i)); 893 894 ui::KeyboardCode arrow_keys[] = { 895 ui::VKEY_RIGHT, 896 ui::VKEY_DOWN, 897 ui::VKEY_LEFT, 898 ui::VKEY_UP 899 }; 900 // Expected window layout, assuming that the text filtering feature is 901 // enabled by default (i.e., --ash-disable-text-filtering-in-overview-mode 902 // is not being used). 903 // +-------+ +-------+ +-------+ +-------+ 904 // | 1 | | 2 | | 3 | | 4 | 905 // +-------+ +-------+ +-------+ +-------+ 906 // +-------+ +-------+ +-------+ +-------+ 907 // | 5 | | 6 | | 7 | | 8 | 908 // +-------+ +-------+ +-------+ +-------+ 909 // +-------+ 910 // | 9 | 911 // +-------+ 912 // Index for each window during a full loop plus wrapping around. 913 int index_path_for_direction[][test_windows + 1] = { 914 {1, 2, 3, 4, 5, 6, 7, 8, 9, 1}, // Right 915 {1, 5, 9, 2, 6, 3, 7, 4, 8, 1}, // Down 916 {9, 8, 7, 6, 5, 4, 3, 2, 1, 9}, // Left 917 {8, 4, 7, 3, 6, 2, 9, 5, 1, 8} // Up 918 }; 919 920 for (size_t key_index = 0; key_index < arraysize(arrow_keys); key_index++) { 921 ToggleOverview(); 922 for (size_t i = 0; i < test_windows + 1; i++) { 923 SendKey(arrow_keys[key_index]); 924 // TODO(flackr): Add a more readable error message by constructing a 925 // string from the window IDs. 926 EXPECT_EQ(GetSelectedWindow()->id(), 927 index_path_for_direction[key_index][i]); 928 } 929 ToggleOverview(); 930 } 931} 932 933// Tests basic selection across multiple monitors. 934TEST_F(WindowSelectorTest, BasicMultiMonitorArrowKeyNavigation) { 935 if (!SupportsMultipleDisplays()) 936 return; 937 938 UpdateDisplay("400x400,400x400"); 939 gfx::Rect bounds1(0, 0, 100, 100); 940 gfx::Rect bounds2(450, 0, 100, 100); 941 scoped_ptr<aura::Window> window4(CreateWindow(bounds2)); 942 scoped_ptr<aura::Window> window3(CreateWindow(bounds2)); 943 scoped_ptr<aura::Window> window2(CreateWindow(bounds1)); 944 scoped_ptr<aura::Window> window1(CreateWindow(bounds1)); 945 946 947 ToggleOverview(); 948 949 SendKey(ui::VKEY_RIGHT); 950 EXPECT_EQ(GetSelectedWindow(), window1.get()); 951 SendKey(ui::VKEY_RIGHT); 952 EXPECT_EQ(GetSelectedWindow(), window2.get()); 953 SendKey(ui::VKEY_RIGHT); 954 EXPECT_EQ(GetSelectedWindow(), window3.get()); 955 SendKey(ui::VKEY_RIGHT); 956 EXPECT_EQ(GetSelectedWindow(), window4.get()); 957} 958 959// Tests selecting a window in overview mode with the return key. 960TEST_F(WindowSelectorTest, SelectWindowWithReturnKey) { 961 gfx::Rect bounds(0, 0, 100, 100); 962 scoped_ptr<aura::Window> window2(CreateWindow(bounds)); 963 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 964 ToggleOverview(); 965 966 // Pressing the return key without a selection widget should not do anything. 967 SendKey(ui::VKEY_RETURN); 968 EXPECT_TRUE(IsSelecting()); 969 970 // Select the first window. 971 SendKey(ui::VKEY_RIGHT); 972 SendKey(ui::VKEY_RETURN); 973 ASSERT_FALSE(IsSelecting()); 974 EXPECT_TRUE(wm::IsActiveWindow(window1.get())); 975 976 // Select the second window. 977 ToggleOverview(); 978 SendKey(ui::VKEY_RIGHT); 979 SendKey(ui::VKEY_RIGHT); 980 SendKey(ui::VKEY_RETURN); 981 EXPECT_FALSE(IsSelecting()); 982 EXPECT_TRUE(wm::IsActiveWindow(window2.get())); 983} 984 985// Tests that overview mode hides the callout widget. 986TEST_F(WindowSelectorTest, WindowOverviewHidesCalloutWidgets) { 987 scoped_ptr<aura::Window> panel1(CreatePanelWindow(gfx::Rect(0, 0, 100, 100))); 988 scoped_ptr<aura::Window> panel2(CreatePanelWindow(gfx::Rect(0, 0, 100, 100))); 989 PanelLayoutManager* panel_manager = 990 static_cast<PanelLayoutManager*>(panel1->parent()->layout_manager()); 991 992 // By default, panel callout widgets are visible. 993 EXPECT_TRUE( 994 panel_manager->GetCalloutWidgetForPanel(panel1.get())->IsVisible()); 995 EXPECT_TRUE( 996 panel_manager->GetCalloutWidgetForPanel(panel2.get())->IsVisible()); 997 998 // Toggling the overview should hide the callout widgets. 999 ToggleOverview(); 1000 EXPECT_FALSE( 1001 panel_manager->GetCalloutWidgetForPanel(panel1.get())->IsVisible()); 1002 EXPECT_FALSE( 1003 panel_manager->GetCalloutWidgetForPanel(panel2.get())->IsVisible()); 1004 1005 // Ending the overview should show them again. 1006 ToggleOverview(); 1007 EXPECT_TRUE( 1008 panel_manager->GetCalloutWidgetForPanel(panel1.get())->IsVisible()); 1009 EXPECT_TRUE( 1010 panel_manager->GetCalloutWidgetForPanel(panel2.get())->IsVisible()); 1011} 1012 1013// Tests that when panels are grouped that the close button only closes the 1014// currently active panel. After the removal window selection should still be 1015// active, and the label should have changed. Removing the last panel should 1016// cause selection to end. 1017TEST_F(WindowSelectorTest, CloseButtonOnPanels) { 1018 scoped_ptr<views::Widget> widget1(CreatePanelWindowWidget( 1019 gfx::Rect(0, 0, 300, 100))); 1020 scoped_ptr<views::Widget> widget2(CreatePanelWindowWidget( 1021 gfx::Rect(100, 0, 100, 100))); 1022 aura::Window* window1 = widget1->GetNativeWindow(); 1023 aura::Window* window2 = widget2->GetNativeWindow(); 1024 base::string16 panel1_title = base::UTF8ToUTF16("Panel 1"); 1025 base::string16 panel2_title = base::UTF8ToUTF16("Panel 2"); 1026 window1->SetTitle(panel1_title); 1027 window2->SetTitle(panel2_title); 1028 wm::ActivateWindow(window1); 1029 ToggleOverview(); 1030 1031 gfx::RectF bounds1 = GetTransformedBoundsInRootWindow(window1); 1032 gfx::Point point1(bounds1.top_right().x() - 1, bounds1.top_right().y() - 1); 1033 ui::test::EventGenerator event_generator1(window1->GetRootWindow(), point1); 1034 1035 EXPECT_FALSE(widget1->IsClosed()); 1036 event_generator1.ClickLeftButton(); 1037 EXPECT_TRUE(widget1->IsClosed()); 1038 RunAllPendingInMessageLoop(); 1039 EXPECT_TRUE(IsSelecting()); 1040 WindowSelectorItem* window_item = GetWindowItemsForRoot(0).front(); 1041 EXPECT_FALSE(window_item->empty()); 1042 EXPECT_TRUE(window_item->Contains(window2)); 1043 EXPECT_TRUE(GetCloseButton(window_item)->IsVisible()); 1044 1045 1046 views::Label* label = GetLabelView(window_item); 1047 EXPECT_EQ(label->text(), panel2_title); 1048 1049 gfx::RectF bounds2 = GetTransformedBoundsInRootWindow(window2); 1050 gfx::Point point2(bounds2.top_right().x() - 1, bounds2.top_right().y() - 1); 1051 ui::test::EventGenerator event_generator2(window2->GetRootWindow(), point2); 1052 1053 EXPECT_FALSE(widget2->IsClosed()); 1054 event_generator2.ClickLeftButton(); 1055 EXPECT_TRUE(widget2->IsClosed()); 1056 RunAllPendingInMessageLoop(); 1057 EXPECT_FALSE(IsSelecting()); 1058} 1059 1060// Creates three windows and tests filtering them by title. 1061TEST_F(WindowSelectorTest, BasicTextFiltering) { 1062 gfx::Rect bounds(0, 0, 100, 100); 1063 scoped_ptr<aura::Window> window2(CreateWindow(bounds)); 1064 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 1065 scoped_ptr<aura::Window> window0(CreateWindow(bounds)); 1066 base::string16 window2_title = base::UTF8ToUTF16("Highway to test"); 1067 base::string16 window1_title = base::UTF8ToUTF16("For those about to test"); 1068 base::string16 window0_title = base::UTF8ToUTF16("We salute you"); 1069 window0->SetTitle(window0_title); 1070 window1->SetTitle(window1_title); 1071 window2->SetTitle(window2_title); 1072 ToggleOverview(); 1073 EXPECT_FALSE(selection_widget_active()); 1074 EXPECT_FALSE(showing_filter_widget()); 1075 FilterItems("Test"); 1076 1077 // The selection widget should appear when filtering starts, and should be 1078 // selecting the first matching window. 1079 EXPECT_TRUE(selection_widget_active()); 1080 EXPECT_TRUE(showing_filter_widget()); 1081 EXPECT_EQ(GetSelectedWindow(), window1.get()); 1082 1083 // Window 0 has no "test" on it so it should be the only dimmed item. 1084 std::vector<WindowSelectorItem*> items = GetWindowItemsForRoot(0); 1085 EXPECT_TRUE(items[0]->dimmed()); 1086 EXPECT_FALSE(items[1]->dimmed()); 1087 EXPECT_FALSE(items[2]->dimmed()); 1088 1089 // No items match the search. 1090 FilterItems("I'm testing 'n testing"); 1091 EXPECT_TRUE(items[0]->dimmed()); 1092 EXPECT_TRUE(items[1]->dimmed()); 1093 EXPECT_TRUE(items[2]->dimmed()); 1094 1095 // All the items should match the empty string. The filter widget should also 1096 // disappear. 1097 FilterItems(""); 1098 EXPECT_FALSE(showing_filter_widget()); 1099 EXPECT_FALSE(items[0]->dimmed()); 1100 EXPECT_FALSE(items[1]->dimmed()); 1101 EXPECT_FALSE(items[2]->dimmed()); 1102} 1103 1104// Tests selecting in the overview with dimmed and undimmed items. 1105TEST_F(WindowSelectorTest, TextFilteringSelection) { 1106 gfx::Rect bounds(0, 0, 100, 100); 1107 scoped_ptr<aura::Window> window2(CreateWindow(bounds)); 1108 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 1109 scoped_ptr<aura::Window> window0(CreateWindow(bounds)); 1110 base::string16 window2_title = base::UTF8ToUTF16("Rock and roll"); 1111 base::string16 window1_title = base::UTF8ToUTF16("Rock and"); 1112 base::string16 window0_title = base::UTF8ToUTF16("Rock"); 1113 window0->SetTitle(window0_title); 1114 window1->SetTitle(window1_title); 1115 window2->SetTitle(window2_title); 1116 ToggleOverview(); 1117 SendKey(ui::VKEY_RIGHT); 1118 EXPECT_TRUE(selection_widget_active()); 1119 EXPECT_EQ(GetSelectedWindow(), window0.get()); 1120 1121 // Dim the first item, the selection should jump to the next item. 1122 std::vector<WindowSelectorItem*> items = GetWindowItemsForRoot(0); 1123 FilterItems("Rock and"); 1124 EXPECT_EQ(GetSelectedWindow(), window1.get()); 1125 1126 // Cycle the selection, the dimmed window should not be selected. 1127 SendKey(ui::VKEY_RIGHT); 1128 EXPECT_EQ(GetSelectedWindow(), window2.get()); 1129 SendKey(ui::VKEY_RIGHT); 1130 EXPECT_EQ(GetSelectedWindow(), window1.get()); 1131 1132 // Dimming all the items should hide the selection widget. 1133 FilterItems("Pop"); 1134 EXPECT_FALSE(selection_widget_active()); 1135 1136 // Undimming one window should automatically select it. 1137 FilterItems("Rock and roll"); 1138 EXPECT_EQ(GetSelectedWindow(), window2.get()); 1139} 1140 1141// Tests clicking on the desktop itself to cancel overview mode. 1142TEST_F(WindowSelectorTest, CancelOverviewOnMouseClick) { 1143 // Overview disabled by default. 1144 EXPECT_FALSE(IsSelecting()); 1145 1146 // Point and bounds selected so that they don't intersect. This causes 1147 // events located at the point to be passed to DesktopBackgroundController, 1148 // and not the window. 1149 gfx::Point point_in_background_page(0, 0); 1150 gfx::Rect bounds(10, 10, 100, 100); 1151 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 1152 ui::test::EventGenerator& generator = GetEventGenerator(); 1153 // Move mouse to point in the background page. Sending an event here will pass 1154 // it to the DesktopBackgroundController in both regular and overview mode. 1155 generator.MoveMouseTo(point_in_background_page); 1156 1157 // Clicking on the background page while not in overview should not toggle 1158 // overview. 1159 generator.ClickLeftButton(); 1160 EXPECT_FALSE(IsSelecting()); 1161 1162 // Switch to overview mode. 1163 ToggleOverview(); 1164 ASSERT_TRUE(IsSelecting()); 1165 1166 // Click should now exit overview mode. 1167 generator.ClickLeftButton(); 1168 EXPECT_FALSE(IsSelecting()); 1169} 1170 1171// Tests tapping on the desktop itself to cancel overview mode. 1172TEST_F(WindowSelectorTest, CancelOverviewOnTap) { 1173 // Overview disabled by default. 1174 EXPECT_FALSE(IsSelecting()); 1175 1176 // Point and bounds selected so that they don't intersect. This causes 1177 // events located at the point to be passed to DesktopBackgroundController, 1178 // and not the window. 1179 gfx::Point point_in_background_page(0, 0); 1180 gfx::Rect bounds(10, 10, 100, 100); 1181 scoped_ptr<aura::Window> window1(CreateWindow(bounds)); 1182 ui::test::EventGenerator& generator = GetEventGenerator(); 1183 1184 // Tapping on the background page while not in overview should not toggle 1185 // overview. 1186 generator.GestureTapAt(point_in_background_page); 1187 EXPECT_FALSE(IsSelecting()); 1188 1189 // Switch to overview mode. 1190 ToggleOverview(); 1191 ASSERT_TRUE(IsSelecting()); 1192 1193 // Tap should now exit overview mode. 1194 generator.GestureTapAt(point_in_background_page); 1195 EXPECT_FALSE(IsSelecting()); 1196} 1197 1198} // namespace ash 1199