window_selector_unittest.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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 "ash/launcher/launcher.h"
6#include "ash/root_window_controller.h"
7#include "ash/screen_ash.h"
8#include "ash/shelf/shelf_widget.h"
9#include "ash/shell.h"
10#include "ash/test/ash_test_base.h"
11#include "ash/test/launcher_test_api.h"
12#include "ash/test/shelf_view_test_api.h"
13#include "ash/test/shell_test_api.h"
14#include "ash/test/test_launcher_delegate.h"
15#include "ash/wm/mru_window_tracker.h"
16#include "ash/wm/overview/window_selector.h"
17#include "ash/wm/overview/window_selector_controller.h"
18#include "ash/wm/window_state.h"
19#include "ash/wm/window_util.h"
20#include "base/basictypes.h"
21#include "base/compiler_specific.h"
22#include "base/memory/scoped_vector.h"
23#include "base/run_loop.h"
24#include "ui/aura/client/activation_delegate.h"
25#include "ui/aura/client/aura_constants.h"
26#include "ui/aura/client/cursor_client.h"
27#include "ui/aura/client/focus_client.h"
28#include "ui/aura/root_window.h"
29#include "ui/aura/test/event_generator.h"
30#include "ui/aura/test/test_window_delegate.h"
31#include "ui/aura/test/test_windows.h"
32#include "ui/aura/window.h"
33#include "ui/compositor/scoped_animation_duration_scale_mode.h"
34#include "ui/gfx/rect_conversions.h"
35#include "ui/gfx/transform.h"
36
37namespace ash {
38namespace internal {
39
40namespace {
41
42class NonActivatableActivationDelegate
43    : public aura::client::ActivationDelegate {
44 public:
45  virtual bool ShouldActivate() const OVERRIDE {
46    return false;
47  }
48};
49
50bool IsWindowAbove(aura::Window* w1, aura::Window* w2) {
51  aura::Window* parent = w1->parent();
52  DCHECK_EQ(parent, w2->parent());
53  for (aura::Window::Windows::const_iterator iter = parent->children().begin();
54       iter != parent->children().end(); ++iter) {
55    if (*iter == w1)
56      return false;
57    if (*iter == w2)
58      return true;
59  }
60  NOTREACHED();
61  return false;
62}
63
64aura::Window* GetWindowByName(aura::Window* container,
65                              const std::string& name) {
66  aura::Window* window = NULL;
67  for (aura::Window::Windows::const_iterator iter =
68       container->children().begin(); iter != container->children().end();
69       ++iter) {
70    if ((*iter)->name() == name) {
71      // The name should be unique.
72      DCHECK(!window);
73      window = *iter;
74    }
75  }
76  return window;
77}
78
79// Returns the copy of |window| created for overview. It is found using the
80// window name which should be the same as the source window's name with a
81// special suffix, and in the same container as the source window.
82aura::Window* GetCopyWindow(aura::Window* window) {
83  aura::Window* copy_window = NULL;
84  std::string copy_name = window->name() + " (Copy)";
85  std::vector<aura::Window*> containers(
86      Shell::GetContainersFromAllRootWindows(window->parent()->id(), NULL));
87  for (std::vector<aura::Window*>::iterator iter = containers.begin();
88       iter != containers.end(); ++iter) {
89    aura::Window* found = GetWindowByName(*iter, copy_name);
90    if (found) {
91      // There should only be one copy window.
92      DCHECK(!copy_window);
93      copy_window = found;
94    }
95  }
96  return copy_window;
97}
98
99}  // namespace
100
101class WindowSelectorTest : public test::AshTestBase {
102 public:
103  WindowSelectorTest() {}
104  virtual ~WindowSelectorTest() {}
105
106  virtual void SetUp() OVERRIDE {
107    test::AshTestBase::SetUp();
108    ASSERT_TRUE(test::TestLauncherDelegate::instance());
109
110    shelf_view_test_.reset(new test::ShelfViewTestAPI(
111        test::LauncherTestAPI(Launcher::ForPrimaryDisplay()).shelf_view()));
112    shelf_view_test_->SetAnimationDuration(1);
113  }
114
115  aura::Window* CreateWindow(const gfx::Rect& bounds) {
116    return CreateTestWindowInShellWithDelegate(&delegate_, -1, bounds);
117  }
118
119  aura::Window* CreateNonActivatableWindow(const gfx::Rect& bounds) {
120    aura::Window* window = CreateWindow(bounds);
121    aura::client::SetActivationDelegate(window,
122                                        &non_activatable_activation_delegate_);
123    EXPECT_FALSE(ash::wm::CanActivateWindow(window));
124    return window;
125  }
126
127  aura::Window* CreatePanelWindow(const gfx::Rect& bounds) {
128    aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
129        NULL, aura::client::WINDOW_TYPE_PANEL, 0, bounds);
130    test::TestLauncherDelegate::instance()->AddLauncherItem(window);
131    shelf_view_test()->RunMessageLoopUntilAnimationsDone();
132    return window;
133  }
134
135  bool WindowsOverlapping(aura::Window* window1, aura::Window* window2) {
136    gfx::RectF window1_bounds = GetTransformedTargetBounds(window1);
137    gfx::RectF window2_bounds = GetTransformedTargetBounds(window2);
138    return window1_bounds.Intersects(window2_bounds);
139  }
140
141  void ToggleOverview() {
142    ash::Shell::GetInstance()->window_selector_controller()->ToggleOverview();
143  }
144
145  void Cycle(WindowSelector::Direction direction) {
146    ash::Shell::GetInstance()->window_selector_controller()->
147        HandleCycleWindow(direction);
148  }
149
150  void StopCycling() {
151    ash::Shell::GetInstance()->window_selector_controller()->window_selector_->
152        SelectWindow();
153  }
154
155  void FireOverviewStartTimer() {
156    // Calls the method to start overview mode which is normally called by the
157    // timer. The timer will still fire and call this method triggering the
158    // DCHECK that overview mode was not already started, except that we call
159    // StopCycling before the timer has a chance to fire.
160    ash::Shell::GetInstance()->window_selector_controller()->window_selector_->
161        StartOverview();
162  }
163
164  gfx::Transform GetTransformRelativeTo(gfx::PointF origin,
165                                        const gfx::Transform& transform) {
166    gfx::Transform t;
167    t.Translate(origin.x(), origin.y());
168    t.PreconcatTransform(transform);
169    t.Translate(-origin.x(), -origin.y());
170    return t;
171  }
172
173  gfx::RectF GetTransformedBounds(aura::Window* window) {
174    gfx::RectF bounds(ash::ScreenAsh::ConvertRectToScreen(
175        window->parent(), window->layer()->bounds()));
176    gfx::Transform transform(GetTransformRelativeTo(bounds.origin(),
177        window->layer()->transform()));
178    transform.TransformRect(&bounds);
179    return bounds;
180  }
181
182  gfx::RectF GetTransformedTargetBounds(aura::Window* window) {
183    gfx::RectF bounds(ash::ScreenAsh::ConvertRectToScreen(
184        window->parent(), window->layer()->GetTargetBounds()));
185    gfx::Transform transform(GetTransformRelativeTo(bounds.origin(),
186        window->layer()->GetTargetTransform()));
187    transform.TransformRect(&bounds);
188    return bounds;
189  }
190
191  void ClickWindow(aura::Window* window) {
192    aura::test::EventGenerator event_generator(window->GetRootWindow(), window);
193    gfx::RectF target = GetTransformedBounds(window);
194    event_generator.ClickLeftButton();
195  }
196
197  bool IsSelecting() {
198    return ash::Shell::GetInstance()->window_selector_controller()->
199        IsSelecting();
200  }
201
202  aura::Window* GetFocusedWindow() {
203    return aura::client::GetFocusClient(
204        Shell::GetPrimaryRootWindow())->GetFocusedWindow();
205  }
206
207  test::ShelfViewTestAPI* shelf_view_test() {
208    return shelf_view_test_.get();
209  }
210
211 private:
212  aura::test::TestWindowDelegate delegate_;
213  NonActivatableActivationDelegate non_activatable_activation_delegate_;
214  scoped_ptr<test::ShelfViewTestAPI> shelf_view_test_;
215
216  DISALLOW_COPY_AND_ASSIGN(WindowSelectorTest);
217};
218
219// Tests entering overview mode with two windows and selecting one.
220TEST_F(WindowSelectorTest, Basic) {
221  gfx::Rect bounds(0, 0, 400, 400);
222  aura::Window* root_window = Shell::GetPrimaryRootWindow();
223  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
224  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
225  scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
226  scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds));
227  EXPECT_TRUE(WindowsOverlapping(window1.get(), window2.get()));
228  EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get()));
229  wm::ActivateWindow(window2.get());
230  EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
231  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
232  EXPECT_EQ(window2.get(), GetFocusedWindow());
233  // Hide the cursor before entering overview to test that it will be shown.
234  aura::client::GetCursorClient(root_window)->HideCursor();
235
236  // In overview mode the windows should no longer overlap and focus should
237  // be removed from the window.
238  ToggleOverview();
239  EXPECT_EQ(NULL, GetFocusedWindow());
240  EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get()));
241  EXPECT_FALSE(WindowsOverlapping(window1.get(), panel1.get()));
242  // Panels 1 and 2 should still be overlapping being in a single selector
243  // item.
244  EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get()));
245
246  // The cursor should be visible and locked as a pointer
247  EXPECT_EQ(ui::kCursorPointer,
248            root_window->GetDispatcher()->last_cursor().native_type());
249  EXPECT_TRUE(aura::client::GetCursorClient(root_window)->IsCursorLocked());
250  EXPECT_TRUE(aura::client::GetCursorClient(root_window)->IsCursorVisible());
251
252  // Clicking window 1 should activate it.
253  ClickWindow(window1.get());
254  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
255  EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
256  EXPECT_EQ(window1.get(), GetFocusedWindow());
257
258  // Cursor should have been unlocked.
259  EXPECT_FALSE(aura::client::GetCursorClient(root_window)->IsCursorLocked());
260}
261
262// Tests that the shelf dimming state is removed while in overview and restored
263// on exiting overview.
264TEST_F(WindowSelectorTest, OverviewUndimsShelf) {
265  gfx::Rect bounds(0, 0, 400, 400);
266  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
267  wm::WindowState* window_state = wm::GetWindowState(window1.get());
268  window_state->Maximize();
269  ash::ShelfWidget* shelf = Shell::GetPrimaryRootWindowController()->shelf();
270  EXPECT_TRUE(shelf->GetDimsShelf());
271  ToggleOverview();
272  EXPECT_FALSE(shelf->GetDimsShelf());
273  ToggleOverview();
274  EXPECT_TRUE(shelf->GetDimsShelf());
275}
276
277// Tests that beginning window selection hides the app list.
278TEST_F(WindowSelectorTest, SelectingHidesAppList) {
279  gfx::Rect bounds(0, 0, 400, 400);
280  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
281  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
282  Shell::GetInstance()->ToggleAppList(NULL);
283  EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility());
284  ToggleOverview();
285  EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility());
286  ToggleOverview();
287
288  // The app list uses an animation to fade out. If it is toggled on immediately
289  // after being removed the old widget is re-used and it does not gain focus.
290  // When running under normal circumstances this shouldn't be possible, but
291  // it is in a test without letting the message loop run.
292  RunAllPendingInMessageLoop();
293
294  Shell::GetInstance()->ToggleAppList(NULL);
295  EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility());
296  Cycle(WindowSelector::FORWARD);
297  EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility());
298  StopCycling();
299}
300
301// Tests that a minimized window's visibility and layer visibility is correctly
302// changed when entering overview and restored when leaving overview mode.
303TEST_F(WindowSelectorTest, MinimizedWindowVisibility) {
304  gfx::Rect bounds(0, 0, 400, 400);
305  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
306  wm::WindowState* window_state = wm::GetWindowState(window1.get());
307  window_state->Minimize();
308  EXPECT_FALSE(window1->IsVisible());
309  EXPECT_FALSE(window1->layer()->GetTargetVisibility());
310  {
311    ui::ScopedAnimationDurationScaleMode normal_duration_mode(
312        ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
313    ToggleOverview();
314    EXPECT_TRUE(window1->IsVisible());
315    EXPECT_TRUE(window1->layer()->GetTargetVisibility());
316  }
317  {
318    ui::ScopedAnimationDurationScaleMode normal_duration_mode(
319        ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
320    ToggleOverview();
321    EXPECT_FALSE(window1->IsVisible());
322    EXPECT_FALSE(window1->layer()->GetTargetVisibility());
323  }
324}
325
326// Tests that a bounds change during overview is corrected for.
327TEST_F(WindowSelectorTest, BoundsChangeDuringOverview) {
328  scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 400, 400)));
329  ToggleOverview();
330  gfx::Rect overview_bounds =
331      ToEnclosingRect(GetTransformedTargetBounds(window.get()));
332  window->SetBounds(gfx::Rect(200, 0, 200, 200));
333  gfx::Rect new_overview_bounds =
334      ToEnclosingRect(GetTransformedTargetBounds(window.get()));
335  EXPECT_EQ(overview_bounds.x(), new_overview_bounds.x());
336  EXPECT_EQ(overview_bounds.y(), new_overview_bounds.y());
337  EXPECT_EQ(overview_bounds.width(), new_overview_bounds.width());
338  EXPECT_EQ(overview_bounds.height(), new_overview_bounds.height());
339  ToggleOverview();
340}
341
342// Tests entering overview mode with three windows and cycling through them.
343TEST_F(WindowSelectorTest, BasicCycle) {
344  gfx::Rect bounds(0, 0, 400, 400);
345  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
346  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
347  scoped_ptr<aura::Window> window3(CreateWindow(bounds));
348  wm::ActivateWindow(window3.get());
349  wm::ActivateWindow(window2.get());
350  wm::ActivateWindow(window1.get());
351  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
352  EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
353  EXPECT_FALSE(wm::IsActiveWindow(window3.get()));
354
355  Cycle(WindowSelector::FORWARD);
356  EXPECT_TRUE(IsSelecting());
357  Cycle(WindowSelector::FORWARD);
358  StopCycling();
359  EXPECT_FALSE(IsSelecting());
360  EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
361  EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
362  EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
363}
364
365// Tests that cycling through windows preserves the window stacking order.
366TEST_F(WindowSelectorTest, CyclePreservesStackingOrder) {
367  gfx::Rect bounds(0, 0, 400, 400);
368  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
369  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
370  scoped_ptr<aura::Window> window3(CreateWindow(bounds));
371  wm::ActivateWindow(window3.get());
372  wm::ActivateWindow(window2.get());
373  wm::ActivateWindow(window1.get());
374  // Window order from top to bottom is 1, 2, 3.
375  EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get()));
376  EXPECT_TRUE(IsWindowAbove(window2.get(), window3.get()));
377
378  // On window 2.
379  Cycle(WindowSelector::FORWARD);
380  EXPECT_TRUE(IsWindowAbove(window2.get(), window1.get()));
381  EXPECT_TRUE(IsWindowAbove(window1.get(), window3.get()));
382
383  // On window 3.
384  Cycle(WindowSelector::FORWARD);
385  EXPECT_TRUE(IsWindowAbove(window3.get(), window1.get()));
386  EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get()));
387
388  // Back on window 1.
389  Cycle(WindowSelector::FORWARD);
390  EXPECT_TRUE(IsWindowAbove(window1.get(), window2.get()));
391  EXPECT_TRUE(IsWindowAbove(window2.get(), window3.get()));
392  StopCycling();
393}
394
395// Tests that cycling through windows shows and minimizes windows as they
396// are passed.
397TEST_F(WindowSelectorTest, CyclePreservesMinimization) {
398  gfx::Rect bounds(0, 0, 400, 400);
399  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
400  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
401  wm::ActivateWindow(window2.get());
402  wm::GetWindowState(window2.get())->Minimize();
403  wm::ActivateWindow(window1.get());
404  EXPECT_TRUE(wm::IsWindowMinimized(window2.get()));
405
406  // On window 2.
407  Cycle(WindowSelector::FORWARD);
408  EXPECT_FALSE(wm::IsWindowMinimized(window2.get()));
409
410  // Back on window 1.
411  Cycle(WindowSelector::FORWARD);
412  EXPECT_TRUE(wm::IsWindowMinimized(window2.get()));
413
414  StopCycling();
415  EXPECT_TRUE(wm::IsWindowMinimized(window2.get()));
416}
417
418// Tests beginning cycling while in overview mode.
419TEST_F(WindowSelectorTest, OverviewTransitionToCycle) {
420  gfx::Rect bounds(0, 0, 400, 400);
421  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
422  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
423  wm::ActivateWindow(window2.get());
424  wm::ActivateWindow(window1.get());
425
426  ToggleOverview();
427  Cycle(WindowSelector::FORWARD);
428  StopCycling();
429
430  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
431  EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
432  EXPECT_EQ(window2.get(), GetFocusedWindow());
433}
434
435// Tests cycles between panel and normal windows.
436TEST_F(WindowSelectorTest, CyclePanels) {
437  gfx::Rect bounds(0, 0, 400, 400);
438  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
439  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
440  scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
441  scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds));
442  wm::ActivateWindow(window2.get());
443  wm::ActivateWindow(window1.get());
444  wm::ActivateWindow(panel2.get());
445  wm::ActivateWindow(panel1.get());
446  EXPECT_TRUE(wm::IsActiveWindow(panel1.get()));
447
448  // Cycling once should select window1 since the panels are grouped into a
449  // single selectable item.
450  Cycle(WindowSelector::FORWARD);
451  StopCycling();
452  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
453
454  // Cycling again should select the most recently used panel.
455  Cycle(WindowSelector::FORWARD);
456  StopCycling();
457  EXPECT_TRUE(wm::IsActiveWindow(panel1.get()));
458}
459
460// Tests the visibility of panel windows during cycling.
461TEST_F(WindowSelectorTest, CyclePanelVisibility) {
462  gfx::Rect bounds(0, 0, 400, 400);
463  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
464  scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
465  wm::ActivateWindow(panel1.get());
466  wm::ActivateWindow(window1.get());
467
468  Cycle(WindowSelector::FORWARD);
469  FireOverviewStartTimer();
470  EXPECT_EQ(1.0f, panel1->layer()->GetTargetOpacity());
471  StopCycling();
472}
473
474// Tests cycles between panel and normal windows.
475TEST_F(WindowSelectorTest, CyclePanelsDestroyed) {
476  gfx::Rect bounds(0, 0, 400, 400);
477  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
478  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
479  scoped_ptr<aura::Window> window3(CreateWindow(bounds));
480  scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
481  scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds));
482  wm::ActivateWindow(window3.get());
483  wm::ActivateWindow(panel2.get());
484  wm::ActivateWindow(panel1.get());
485  wm::ActivateWindow(window2.get());
486  wm::ActivateWindow(window1.get());
487  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
488
489  // Cycling once highlights window2.
490  Cycle(WindowSelector::FORWARD);
491  // All panels are destroyed.
492  panel1.reset();
493  panel2.reset();
494  // Cycling again should now select window3.
495  Cycle(WindowSelector::FORWARD);
496  StopCycling();
497  EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
498}
499
500// Tests cycles between panel and normal windows.
501TEST_F(WindowSelectorTest, CycleMruPanelDestroyed) {
502  gfx::Rect bounds(0, 0, 400, 400);
503  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
504  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
505  scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
506  scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds));
507  wm::ActivateWindow(panel2.get());
508  wm::ActivateWindow(panel1.get());
509  wm::ActivateWindow(window2.get());
510  wm::ActivateWindow(window1.get());
511  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
512
513  // Cycling once highlights window2.
514  Cycle(WindowSelector::FORWARD);
515  // Panel 1 is the next item as the MRU panel, removing it should make panel 2
516  // the next window to be selected.
517  panel1.reset();
518  // Cycling again should now select window3.
519  Cycle(WindowSelector::FORWARD);
520  StopCycling();
521  EXPECT_TRUE(wm::IsActiveWindow(panel2.get()));
522}
523
524// Tests that a newly created window aborts overview.
525TEST_F(WindowSelectorTest, NewWindowCancelsOveriew) {
526  gfx::Rect bounds(0, 0, 400, 400);
527  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
528  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
529  ToggleOverview();
530  EXPECT_TRUE(IsSelecting());
531
532  // A window being created should exit overview mode.
533  scoped_ptr<aura::Window> window3(CreateWindow(bounds));
534  EXPECT_FALSE(IsSelecting());
535}
536
537// Tests that a window activation exits overview mode.
538TEST_F(WindowSelectorTest, ActivationCancelsOveriew) {
539  gfx::Rect bounds(0, 0, 400, 400);
540  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
541  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
542  window2->Focus();
543  ToggleOverview();
544  EXPECT_TRUE(IsSelecting());
545
546  // A window being activated should exit overview mode.
547  window1->Focus();
548  EXPECT_FALSE(IsSelecting());
549
550  // window1 should be focused after exiting even though window2 was focused on
551  // entering overview because we exited due to an activation.
552  EXPECT_EQ(window1.get(), GetFocusedWindow());
553}
554
555// Verifies that overview mode only begins after a delay when cycling.
556TEST_F(WindowSelectorTest, CycleOverviewDelay) {
557  gfx::Rect bounds(0, 0, 400, 400);
558  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
559  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
560  EXPECT_TRUE(WindowsOverlapping(window1.get(), window2.get()));
561
562  // When cycling first starts, the windows will still be overlapping.
563  Cycle(WindowSelector::FORWARD);
564  EXPECT_TRUE(IsSelecting());
565  EXPECT_TRUE(WindowsOverlapping(window1.get(), window2.get()));
566
567  // Once the overview timer fires, the windows should no longer overlap.
568  FireOverviewStartTimer();
569  EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get()));
570  StopCycling();
571}
572
573// Tests that exiting overview mode without selecting a window restores focus
574// to the previously focused window.
575TEST_F(WindowSelectorTest, CancelRestoresFocus) {
576  gfx::Rect bounds(0, 0, 400, 400);
577  scoped_ptr<aura::Window> window(CreateWindow(bounds));
578  wm::ActivateWindow(window.get());
579  EXPECT_EQ(window.get(), GetFocusedWindow());
580
581  // In overview mode, focus should be removed.
582  ToggleOverview();
583  EXPECT_EQ(NULL, GetFocusedWindow());
584
585  // If canceling overview mode, focus should be restored.
586  ToggleOverview();
587  EXPECT_EQ(window.get(), GetFocusedWindow());
588}
589
590// Tests that overview mode is exited if the last remaining window is destroyed.
591TEST_F(WindowSelectorTest, LastWindowDestroyed) {
592  gfx::Rect bounds(0, 0, 400, 400);
593  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
594  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
595  ToggleOverview();
596
597  window1.reset();
598  window2.reset();
599  EXPECT_FALSE(IsSelecting());
600}
601
602// Tests that entering overview mode restores a window to its original
603// target location.
604TEST_F(WindowSelectorTest, QuickReentryRestoresInitialTransform) {
605  gfx::Rect bounds(0, 0, 400, 400);
606  scoped_ptr<aura::Window> window(CreateWindow(bounds));
607  gfx::Rect initial_bounds = ToEnclosingRect(
608      GetTransformedBounds(window.get()));
609  ToggleOverview();
610  // Quickly exit and reenter overview mode. The window should still be
611  // animating when we reenter. We cannot short circuit animations for this but
612  // we also don't have to wait for them to complete.
613  {
614    ui::ScopedAnimationDurationScaleMode normal_duration_mode(
615        ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
616    ToggleOverview();
617    ToggleOverview();
618  }
619  EXPECT_NE(initial_bounds, ToEnclosingRect(
620      GetTransformedTargetBounds(window.get())));
621  ToggleOverview();
622  EXPECT_FALSE(IsSelecting());
623  EXPECT_EQ(initial_bounds, ToEnclosingRect(
624      GetTransformedTargetBounds(window.get())));
625}
626
627// Tests that non-activatable windows are hidden when entering overview mode.
628TEST_F(WindowSelectorTest, NonActivatableWindowsHidden) {
629  gfx::Rect bounds(0, 0, 400, 400);
630  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
631  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
632  scoped_ptr<aura::Window> non_activatable_window(
633      CreateNonActivatableWindow(Shell::GetPrimaryRootWindow()->bounds()));
634  EXPECT_TRUE(non_activatable_window->IsVisible());
635  ToggleOverview();
636  EXPECT_FALSE(non_activatable_window->IsVisible());
637  ToggleOverview();
638  EXPECT_TRUE(non_activatable_window->IsVisible());
639
640  // Test that a window behind the fullscreen non-activatable window can be
641  // clicked.
642  non_activatable_window->parent()->StackChildAtTop(
643      non_activatable_window.get());
644  ToggleOverview();
645  ClickWindow(window1.get());
646  EXPECT_FALSE(IsSelecting());
647  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
648}
649
650// Tests that windows with modal child windows are transformed with the modal
651// child even though not activatable themselves.
652TEST_F(WindowSelectorTest, ModalChild) {
653  gfx::Rect bounds(0, 0, 400, 400);
654  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
655  scoped_ptr<aura::Window> child1(CreateWindow(bounds));
656  child1->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
657  window1->AddTransientChild(child1.get());
658  EXPECT_EQ(window1->parent(), child1->parent());
659  ToggleOverview();
660  EXPECT_TRUE(window1->IsVisible());
661  EXPECT_TRUE(child1->IsVisible());
662  EXPECT_EQ(ToEnclosingRect(GetTransformedTargetBounds(child1.get())),
663      ToEnclosingRect(GetTransformedTargetBounds(window1.get())));
664  ToggleOverview();
665}
666
667// Tests that clicking a modal window's parent activates the modal window in
668// overview.
669TEST_F(WindowSelectorTest, ClickModalWindowParent) {
670  scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 180, 180)));
671  scoped_ptr<aura::Window> child1(CreateWindow(gfx::Rect(200, 0, 180, 180)));
672  child1->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
673  window1->AddTransientChild(child1.get());
674  EXPECT_FALSE(WindowsOverlapping(window1.get(), child1.get()));
675  EXPECT_EQ(window1->parent(), child1->parent());
676  ToggleOverview();
677  // Given that their relative positions are preserved, the windows should still
678  // not overlap.
679  EXPECT_FALSE(WindowsOverlapping(window1.get(), child1.get()));
680  ClickWindow(window1.get());
681  EXPECT_FALSE(IsSelecting());
682
683  // Clicking on window1 should activate child1.
684  EXPECT_TRUE(wm::IsActiveWindow(child1.get()));
685}
686
687// Tests that windows remain on the display they are currently on in overview
688// mode.
689TEST_F(WindowSelectorTest, MultipleDisplays) {
690  if (!SupportsMultipleDisplays())
691    return;
692
693  UpdateDisplay("600x400,600x400");
694  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
695  gfx::Rect bounds1(0, 0, 400, 400);
696  gfx::Rect bounds2(650, 0, 400, 400);
697
698  scoped_ptr<aura::Window> window1(CreateWindow(bounds1));
699  scoped_ptr<aura::Window> window2(CreateWindow(bounds1));
700  scoped_ptr<aura::Window> window3(CreateWindow(bounds2));
701  scoped_ptr<aura::Window> window4(CreateWindow(bounds2));
702  scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds1));
703  scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds1));
704  scoped_ptr<aura::Window> panel3(CreatePanelWindow(bounds2));
705  scoped_ptr<aura::Window> panel4(CreatePanelWindow(bounds2));
706  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
707  EXPECT_EQ(root_windows[0], window2->GetRootWindow());
708  EXPECT_EQ(root_windows[1], window3->GetRootWindow());
709  EXPECT_EQ(root_windows[1], window4->GetRootWindow());
710
711  EXPECT_EQ(root_windows[0], panel1->GetRootWindow());
712  EXPECT_EQ(root_windows[0], panel2->GetRootWindow());
713  EXPECT_EQ(root_windows[1], panel3->GetRootWindow());
714  EXPECT_EQ(root_windows[1], panel4->GetRootWindow());
715
716  // In overview mode, each window remains in the same root window.
717  ToggleOverview();
718  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
719  EXPECT_EQ(root_windows[0], window2->GetRootWindow());
720  EXPECT_EQ(root_windows[1], window3->GetRootWindow());
721  EXPECT_EQ(root_windows[1], window4->GetRootWindow());
722  EXPECT_EQ(root_windows[0], panel1->GetRootWindow());
723  EXPECT_EQ(root_windows[0], panel2->GetRootWindow());
724  EXPECT_EQ(root_windows[1], panel3->GetRootWindow());
725  EXPECT_EQ(root_windows[1], panel4->GetRootWindow());
726
727  EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
728      ToEnclosingRect(GetTransformedTargetBounds(window1.get()))));
729  EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
730      ToEnclosingRect(GetTransformedTargetBounds(window2.get()))));
731  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
732      ToEnclosingRect(GetTransformedTargetBounds(window3.get()))));
733  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
734      ToEnclosingRect(GetTransformedTargetBounds(window4.get()))));
735
736  EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
737      ToEnclosingRect(GetTransformedTargetBounds(panel1.get()))));
738  EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
739      ToEnclosingRect(GetTransformedTargetBounds(panel2.get()))));
740  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
741      ToEnclosingRect(GetTransformedTargetBounds(panel3.get()))));
742  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
743      ToEnclosingRect(GetTransformedTargetBounds(panel4.get()))));
744  EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get()));
745  EXPECT_TRUE(WindowsOverlapping(panel3.get(), panel4.get()));
746  EXPECT_FALSE(WindowsOverlapping(panel1.get(), panel3.get()));
747}
748
749// Verifies that the single display overview used during alt tab cycling uses
750// the display of the initial window by default.
751TEST_F(WindowSelectorTest, CycleOverviewUsesInitialDisplay) {
752  if (!SupportsMultipleDisplays())
753    return;
754
755  UpdateDisplay("400x400,400x400");
756  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
757
758  scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 100, 100)));
759  scoped_ptr<aura::Window> window2(CreateWindow(gfx::Rect(450, 0, 100, 100)));
760  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
761  EXPECT_EQ(root_windows[1], window2->GetRootWindow());
762  wm::ActivateWindow(window2.get());
763  wm::ActivateWindow(window1.get());
764  EXPECT_EQ(root_windows[0], Shell::GetTargetRootWindow());
765
766  Cycle(WindowSelector::FORWARD);
767  FireOverviewStartTimer();
768
769  EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
770      ToEnclosingRect(GetTransformedTargetBounds(window1.get()))));
771  EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
772      ToEnclosingRect(GetTransformedTargetBounds(window2.get()))));
773  StopCycling();
774}
775
776// Verifies that the windows being shown on another display are copied.
777TEST_F(WindowSelectorTest, CycleMultipleDisplaysCopiesWindows) {
778  if (!SupportsMultipleDisplays())
779    return;
780
781  UpdateDisplay("400x400,400x400");
782  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
783
784  gfx::Rect root1_rect(0, 0, 100, 100);
785  gfx::Rect root2_rect(450, 0, 100, 100);
786  scoped_ptr<aura::Window> unmoved1(CreateWindow(root2_rect));
787  scoped_ptr<aura::Window> unmoved2(CreateWindow(root2_rect));
788  scoped_ptr<aura::Window> moved1_trans_parent(CreateWindow(root1_rect));
789  scoped_ptr<aura::Window> moved1(CreateWindow(root1_rect));
790  unmoved1->SetName("unmoved1");
791  unmoved2->SetName("unmoved2");
792  moved1->SetName("moved1");
793  moved1->SetProperty(aura::client::kModalKey,
794                      ui::MODAL_TYPE_WINDOW);
795  moved1_trans_parent->AddTransientChild(moved1.get());
796  moved1_trans_parent->SetName("moved1_trans_parent");
797
798  EXPECT_EQ(root_windows[0], moved1->GetRootWindow());
799  EXPECT_EQ(root_windows[0], moved1_trans_parent->GetRootWindow());
800  EXPECT_EQ(root_windows[1], unmoved1->GetRootWindow());
801  EXPECT_EQ(root_windows[1], unmoved2->GetRootWindow());
802  wm::ActivateWindow(unmoved2.get());
803  wm::ActivateWindow(unmoved1.get());
804
805  Cycle(WindowSelector::FORWARD);
806  FireOverviewStartTimer();
807
808  // All windows are moved to second root window.
809  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
810      ToEnclosingRect(GetTransformedTargetBounds(unmoved1.get()))));
811  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
812      ToEnclosingRect(GetTransformedTargetBounds(unmoved2.get()))));
813  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
814      ToEnclosingRect(GetTransformedTargetBounds(moved1.get()))));
815  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
816      ToEnclosingRect(GetTransformedTargetBounds(moved1_trans_parent.get()))));
817
818  // unmoved1 and unmoved2 were already on the correct display and should not
819  // have been copied.
820  EXPECT_TRUE(!GetCopyWindow(unmoved1.get()));
821  EXPECT_TRUE(!GetCopyWindow(unmoved2.get()));
822
823  // moved1 and its transient parent moved1_trans_parent should have also been
824  // copied for displaying on root_windows[1].
825  aura::Window* copy1 = GetCopyWindow(moved1.get());
826  aura::Window* copy1_trans_parent = GetCopyWindow(moved1_trans_parent.get());
827  ASSERT_FALSE(!copy1);
828  ASSERT_FALSE(!copy1_trans_parent);
829
830  // Verify that the bounds and transform of the copy match the original window
831  // but that it is on the other root window.
832  EXPECT_EQ(root_windows[1], copy1->GetRootWindow());
833  EXPECT_EQ(moved1->GetBoundsInScreen(), copy1->GetBoundsInScreen());
834  EXPECT_EQ(moved1->layer()->GetTargetTransform(),
835            copy1->layer()->GetTargetTransform());
836  StopCycling();
837
838  // After cycling the copy windows should have been destroyed.
839  RunAllPendingInMessageLoop();
840  EXPECT_TRUE(!GetCopyWindow(moved1.get()));
841  EXPECT_TRUE(!GetCopyWindow(moved1_trans_parent.get()));
842}
843
844// Tests that beginning to cycle from overview mode moves windows to the
845// active display.
846TEST_F(WindowSelectorTest, MultipleDisplaysOverviewTransitionToCycle) {
847  if (!SupportsMultipleDisplays())
848    return;
849
850  UpdateDisplay("400x400,400x400");
851  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
852
853  scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 100, 100)));
854  scoped_ptr<aura::Window> window2(CreateWindow(gfx::Rect(450, 0, 100, 100)));
855  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
856  EXPECT_EQ(root_windows[1], window2->GetRootWindow());
857  wm::ActivateWindow(window2.get());
858  wm::ActivateWindow(window1.get());
859
860  ToggleOverview();
861  EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
862      ToEnclosingRect(GetTransformedTargetBounds(window1.get()))));
863  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
864      ToEnclosingRect(GetTransformedTargetBounds(window2.get()))));
865
866  Cycle(WindowSelector::FORWARD);
867  EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
868      ToEnclosingRect(GetTransformedTargetBounds(window1.get()))));
869  EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
870      ToEnclosingRect(GetTransformedTargetBounds(window2.get()))));
871  StopCycling();
872}
873
874// Tests that a bounds change during overview is corrected for.
875TEST_F(WindowSelectorTest, BoundsChangeDuringCycleOnOtherDisplay) {
876  if (!SupportsMultipleDisplays())
877    return;
878
879  UpdateDisplay("400x400,400x400");
880  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
881
882  scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 100, 100)));
883  scoped_ptr<aura::Window> window2(CreateWindow(gfx::Rect(450, 0, 100, 100)));
884  scoped_ptr<aura::Window> window3(CreateWindow(gfx::Rect(450, 0, 100, 100)));
885  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
886  EXPECT_EQ(root_windows[1], window2->GetRootWindow());
887  EXPECT_EQ(root_windows[1], window3->GetRootWindow());
888  wm::ActivateWindow(window1.get());
889  wm::ActivateWindow(window2.get());
890  wm::ActivateWindow(window3.get());
891
892  Cycle(WindowSelector::FORWARD);
893  FireOverviewStartTimer();
894
895  gfx::Rect overview_bounds(
896      ToEnclosingRect(GetTransformedTargetBounds(window1.get())));
897  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(overview_bounds));
898
899  // Change the position and size of window1 (being displayed on the second
900  // root window) and it should remain within the same bounds.
901  window1->SetBounds(gfx::Rect(100, 0, 200, 200));
902  gfx::Rect new_overview_bounds =
903      ToEnclosingRect(GetTransformedTargetBounds(window1.get()));
904  EXPECT_EQ(overview_bounds.x(), new_overview_bounds.x());
905  EXPECT_EQ(overview_bounds.y(), new_overview_bounds.y());
906  EXPECT_EQ(overview_bounds.width(), new_overview_bounds.width());
907  EXPECT_EQ(overview_bounds.height(), new_overview_bounds.height());
908  StopCycling();
909}
910
911}  // namespace internal
912}  // namespace ash
913