Home | History | Annotate | Download | only in ash
      1 // Copyright (c) 2012 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/display/display_controller.h"
      6 #include "ash/display/display_manager.h"
      7 #include "ash/root_window_controller.h"
      8 #include "ash/screen_ash.h"
      9 #include "ash/shell.h"
     10 #include "ash/shell_window_ids.h"
     11 #include "ash/system/tray/system_tray.h"
     12 #include "ash/test/ash_test_base.h"
     13 #include "ash/wm/coordinate_conversion.h"
     14 #include "ash/wm/property_util.h"
     15 #include "ash/wm/window_cycle_controller.h"
     16 #include "ash/wm/window_properties.h"
     17 #include "ash/wm/window_util.h"
     18 #include "base/strings/string_util.h"
     19 #include "ui/aura/client/activation_client.h"
     20 #include "ui/aura/client/capture_client.h"
     21 #include "ui/aura/client/focus_client.h"
     22 #include "ui/aura/root_window.h"
     23 #include "ui/aura/test/event_generator.h"
     24 #include "ui/aura/test/test_windows.h"
     25 #include "ui/aura/test/window_test_api.h"
     26 #include "ui/aura/window.h"
     27 #include "ui/base/cursor/cursor.h"
     28 #include "ui/base/events/event_handler.h"
     29 #include "ui/gfx/display.h"
     30 #include "ui/gfx/screen.h"
     31 #include "ui/views/controls/textfield/textfield.h"
     32 #include "ui/views/widget/widget.h"
     33 #include "ui/views/widget/widget_delegate.h"
     34 
     35 namespace ash {
     36 namespace {
     37 
     38 void SetSecondaryDisplayLayout(DisplayLayout::Position position) {
     39   DisplayController* display_controller =
     40       Shell::GetInstance()->display_controller();
     41   DisplayLayout layout = display_controller->GetCurrentDisplayLayout();
     42   layout.position = position;
     43   display_controller->SetLayoutForCurrentDisplays(layout);
     44 }
     45 
     46 internal::DisplayManager* GetDisplayManager() {
     47   return Shell::GetInstance()->display_manager();
     48 }
     49 
     50 class ModalWidgetDelegate : public views::WidgetDelegateView {
     51  public:
     52   ModalWidgetDelegate() {}
     53   virtual ~ModalWidgetDelegate() {}
     54 
     55   // Overridden from views::WidgetDelegate:
     56   virtual views::View* GetContentsView() OVERRIDE {
     57     return this;
     58   }
     59   virtual ui::ModalType GetModalType() const OVERRIDE {
     60     return ui::MODAL_TYPE_SYSTEM;
     61   }
     62 
     63  private:
     64   DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate);
     65 };
     66 
     67 // An event handler which moves the target window to the secondary root window
     68 // at pre-handle phase of a mouse release event.
     69 class MoveWindowByClickEventHandler : public ui::EventHandler {
     70  public:
     71   explicit MoveWindowByClickEventHandler(aura::Window* target)
     72       : target_(target) {}
     73   virtual ~MoveWindowByClickEventHandler() {}
     74 
     75  private:
     76   // ui::EventHandler overrides:
     77   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
     78     if (event->type() == ui::ET_MOUSE_RELEASED) {
     79       Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
     80       DCHECK_LT(1u, root_windows.size());
     81       root_windows[1]->AddChild(target_);
     82     }
     83   }
     84 
     85   aura::Window* target_;
     86   DISALLOW_COPY_AND_ASSIGN(MoveWindowByClickEventHandler);
     87 };
     88 
     89 // An event handler which records the event's locations.
     90 class EventLocationRecordingEventHandler : public ui::EventHandler {
     91  public:
     92   explicit EventLocationRecordingEventHandler() {
     93     reset();
     94   }
     95   virtual ~EventLocationRecordingEventHandler() {}
     96 
     97   std::string GetLocationsAndReset() {
     98     std::string result =
     99         location_.ToString() + " " + root_location_.ToString();
    100     reset();
    101     return result;
    102   }
    103 
    104  private:
    105   // ui::EventHandler overrides:
    106   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
    107     if (event->type() == ui::ET_MOUSE_MOVED ||
    108         event->type() == ui::ET_MOUSE_DRAGGED) {
    109       location_ = event->location();
    110       root_location_ = event->root_location();
    111     }
    112   }
    113 
    114   void reset() {
    115     location_.SetPoint(-999, -999);
    116     root_location_.SetPoint(-999, -999);
    117   }
    118 
    119   gfx::Point root_location_;
    120   gfx::Point location_;
    121 
    122   DISALLOW_COPY_AND_ASSIGN(EventLocationRecordingEventHandler);
    123 };
    124 
    125 }  // namespace
    126 
    127 class ExtendedDesktopTest : public test::AshTestBase {
    128  public:
    129   views::Widget* CreateTestWidget(const gfx::Rect& bounds) {
    130     return CreateTestWidgetWithParentAndContext(
    131         NULL, CurrentContext(), bounds, false);
    132   }
    133 
    134   views::Widget* CreateTestWidgetWithParent(views::Widget* parent,
    135                                             const gfx::Rect& bounds,
    136                                             bool child) {
    137     CHECK(parent);
    138     return CreateTestWidgetWithParentAndContext(parent, NULL, bounds, child);
    139   }
    140 
    141   views::Widget* CreateTestWidgetWithParentAndContext(views::Widget* parent,
    142                                                       gfx::NativeView context,
    143                                                       const gfx::Rect& bounds,
    144                                                       bool child) {
    145     views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
    146     if (parent)
    147       params.parent = parent->GetNativeView();
    148     params.context = context;
    149     params.bounds = bounds;
    150     params.child = child;
    151     views::Widget* widget = new views::Widget;
    152     widget->Init(params);
    153     widget->Show();
    154     return widget;
    155   }
    156 };
    157 
    158 // Test conditions that root windows in extended desktop mode
    159 // must satisfy.
    160 TEST_F(ExtendedDesktopTest, Basic) {
    161   if (!SupportsMultipleDisplays())
    162     return;
    163 
    164   UpdateDisplay("1000x600,600x400");
    165   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    166 
    167   // All root windows must have the root window controller.
    168   ASSERT_EQ(2U, root_windows.size());
    169   for (Shell::RootWindowList::const_iterator iter = root_windows.begin();
    170        iter != root_windows.end(); ++iter) {
    171     EXPECT_TRUE(GetRootWindowController(*iter) != NULL);
    172   }
    173   // Make sure root windows share the same controllers.
    174   EXPECT_EQ(aura::client::GetFocusClient(root_windows[0]),
    175             aura::client::GetFocusClient(root_windows[1]));
    176   EXPECT_EQ(aura::client::GetActivationClient(root_windows[0]),
    177             aura::client::GetActivationClient(root_windows[1]));
    178   EXPECT_EQ(aura::client::GetCaptureClient(root_windows[0]),
    179             aura::client::GetCaptureClient(root_windows[1]));
    180 }
    181 
    182 TEST_F(ExtendedDesktopTest, Activation) {
    183   if (!SupportsMultipleDisplays())
    184     return;
    185 
    186   UpdateDisplay("1000x600,600x400");
    187   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    188 
    189   views::Widget* widget_on_1st = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
    190   views::Widget* widget_on_2nd =
    191       CreateTestWidget(gfx::Rect(1200, 10, 100, 100));
    192   EXPECT_EQ(root_windows[0], widget_on_1st->GetNativeView()->GetRootWindow());
    193   EXPECT_EQ(root_windows[1], widget_on_2nd->GetNativeView()->GetRootWindow());
    194 
    195   EXPECT_EQ(widget_on_2nd->GetNativeView(),
    196             aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
    197   EXPECT_TRUE(wm::IsActiveWindow(widget_on_2nd->GetNativeView()));
    198 
    199   aura::test::EventGenerator& event_generator(GetEventGenerator());
    200   // Clicking a window changes the active window and active root window.
    201   event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
    202   event_generator.ClickLeftButton();
    203 
    204   EXPECT_EQ(widget_on_1st->GetNativeView(),
    205             aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
    206   EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
    207 
    208   event_generator.MoveMouseToCenterOf(widget_on_2nd->GetNativeView());
    209   event_generator.ClickLeftButton();
    210 
    211   EXPECT_EQ(widget_on_2nd->GetNativeView(),
    212             aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
    213   EXPECT_TRUE(wm::IsActiveWindow(widget_on_2nd->GetNativeView()));
    214 }
    215 
    216 TEST_F(ExtendedDesktopTest, SystemModal) {
    217   if (!SupportsMultipleDisplays())
    218     return;
    219 
    220   UpdateDisplay("1000x600,600x400");
    221   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    222 
    223   views::Widget* widget_on_1st = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
    224   EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
    225   EXPECT_EQ(root_windows[0], widget_on_1st->GetNativeView()->GetRootWindow());
    226   EXPECT_EQ(root_windows[0], Shell::GetActiveRootWindow());
    227 
    228   // Open system modal. Make sure it's on 2nd root window and active.
    229   views::Widget* modal_widget = views::Widget::CreateWindowWithContextAndBounds(
    230       new ModalWidgetDelegate(),
    231       CurrentContext(),
    232       gfx::Rect(1200, 100, 100, 100));
    233   modal_widget->Show();
    234   EXPECT_TRUE(wm::IsActiveWindow(modal_widget->GetNativeView()));
    235   EXPECT_EQ(root_windows[1], modal_widget->GetNativeView()->GetRootWindow());
    236   EXPECT_EQ(root_windows[1], Shell::GetActiveRootWindow());
    237 
    238   aura::test::EventGenerator& event_generator(GetEventGenerator());
    239 
    240   // Clicking a widget on widget_on_1st display should not change activation.
    241   event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
    242   event_generator.ClickLeftButton();
    243   EXPECT_TRUE(wm::IsActiveWindow(modal_widget->GetNativeView()));
    244   EXPECT_EQ(root_windows[1], Shell::GetActiveRootWindow());
    245 
    246   // Close system modal and so clicking a widget should work now.
    247   modal_widget->Close();
    248   event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
    249   event_generator.ClickLeftButton();
    250   EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
    251   EXPECT_EQ(root_windows[0], Shell::GetActiveRootWindow());
    252 }
    253 
    254 TEST_F(ExtendedDesktopTest, TestCursor) {
    255   if (!SupportsMultipleDisplays())
    256     return;
    257 
    258   UpdateDisplay("1000x600,600x400");
    259   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    260   EXPECT_EQ(ui::kCursorPointer, root_windows[0]->last_cursor().native_type());
    261   EXPECT_EQ(ui::kCursorPointer, root_windows[1]->last_cursor().native_type());
    262   Shell::GetInstance()->cursor_manager()->SetCursor(ui::kCursorCopy);
    263   EXPECT_EQ(ui::kCursorCopy, root_windows[0]->last_cursor().native_type());
    264   EXPECT_EQ(ui::kCursorCopy, root_windows[1]->last_cursor().native_type());
    265 }
    266 
    267 TEST_F(ExtendedDesktopTest, TestCursorLocation) {
    268   if (!SupportsMultipleDisplays())
    269     return;
    270 
    271   UpdateDisplay("1000x600,600x400");
    272   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    273   aura::test::WindowTestApi root_window0_test_api(root_windows[0]);
    274   aura::test::WindowTestApi root_window1_test_api(root_windows[1]);
    275 
    276   root_windows[0]->MoveCursorTo(gfx::Point(10, 10));
    277   EXPECT_EQ("10,10", Shell::GetScreen()->GetCursorScreenPoint().ToString());
    278   EXPECT_TRUE(root_window0_test_api.ContainsMouse());
    279   EXPECT_FALSE(root_window1_test_api.ContainsMouse());
    280   root_windows[1]->MoveCursorTo(gfx::Point(10, 20));
    281   EXPECT_EQ("1010,20", Shell::GetScreen()->GetCursorScreenPoint().ToString());
    282   EXPECT_FALSE(root_window0_test_api.ContainsMouse());
    283   EXPECT_TRUE(root_window1_test_api.ContainsMouse());
    284   root_windows[0]->MoveCursorTo(gfx::Point(20, 10));
    285   EXPECT_EQ("20,10", Shell::GetScreen()->GetCursorScreenPoint().ToString());
    286   EXPECT_TRUE(root_window0_test_api.ContainsMouse());
    287   EXPECT_FALSE(root_window1_test_api.ContainsMouse());
    288 }
    289 
    290 TEST_F(ExtendedDesktopTest, CycleWindows) {
    291   if (!SupportsMultipleDisplays())
    292     return;
    293 
    294   UpdateDisplay("700x500,500x500");
    295   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    296 
    297   WindowCycleController* controller =
    298       Shell::GetInstance()->window_cycle_controller();
    299 
    300   views::Widget* d1_w1 = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
    301   EXPECT_EQ(root_windows[0], d1_w1->GetNativeView()->GetRootWindow());
    302   views::Widget* d2_w1 = CreateTestWidget(gfx::Rect(800, 10, 100, 100));
    303   EXPECT_EQ(root_windows[1], d2_w1->GetNativeView()->GetRootWindow());
    304   EXPECT_TRUE(wm::IsActiveWindow(d2_w1->GetNativeView()));
    305 
    306   controller->HandleCycleWindow(WindowCycleController::FORWARD, false);
    307   EXPECT_TRUE(wm::IsActiveWindow(d1_w1->GetNativeView()));
    308   controller->HandleCycleWindow(WindowCycleController::FORWARD, false);
    309   EXPECT_TRUE(wm::IsActiveWindow(d2_w1->GetNativeView()));
    310   controller->HandleCycleWindow(WindowCycleController::BACKWARD, false);
    311   EXPECT_TRUE(wm::IsActiveWindow(d1_w1->GetNativeView()));
    312   controller->HandleCycleWindow(WindowCycleController::BACKWARD, false);
    313   EXPECT_TRUE(wm::IsActiveWindow(d2_w1->GetNativeView()));
    314 
    315   // Cycle through all windows across root windows.
    316   views::Widget* d1_w2 = CreateTestWidget(gfx::Rect(10, 200, 100, 100));
    317   EXPECT_EQ(root_windows[0], d1_w2->GetNativeView()->GetRootWindow());
    318   views::Widget* d2_w2 = CreateTestWidget(gfx::Rect(800, 200, 100, 100));
    319   EXPECT_EQ(root_windows[1], d2_w2->GetNativeView()->GetRootWindow());
    320 
    321   controller->HandleCycleWindow(WindowCycleController::FORWARD, true);
    322   EXPECT_TRUE(wm::IsActiveWindow(d1_w2->GetNativeView()));
    323   controller->HandleCycleWindow(WindowCycleController::FORWARD, true);
    324   EXPECT_TRUE(wm::IsActiveWindow(d2_w1->GetNativeView()));
    325   controller->HandleCycleWindow(WindowCycleController::FORWARD, true);
    326   EXPECT_TRUE(wm::IsActiveWindow(d1_w1->GetNativeView()));
    327   controller->HandleCycleWindow(WindowCycleController::FORWARD, true);
    328   EXPECT_TRUE(wm::IsActiveWindow(d2_w2->GetNativeView()));
    329 
    330   // Backwards
    331   controller->HandleCycleWindow(WindowCycleController::BACKWARD, true);
    332   EXPECT_TRUE(wm::IsActiveWindow(d1_w1->GetNativeView()));
    333   controller->HandleCycleWindow(WindowCycleController::BACKWARD, true);
    334   EXPECT_TRUE(wm::IsActiveWindow(d2_w1->GetNativeView()));
    335   controller->HandleCycleWindow(WindowCycleController::BACKWARD, true);
    336   EXPECT_TRUE(wm::IsActiveWindow(d1_w2->GetNativeView()));
    337   controller->HandleCycleWindow(WindowCycleController::BACKWARD, true);
    338   EXPECT_TRUE(wm::IsActiveWindow(d2_w2->GetNativeView()));
    339 }
    340 
    341 TEST_F(ExtendedDesktopTest, GetRootWindowAt) {
    342   if (!SupportsMultipleDisplays())
    343     return;
    344 
    345   UpdateDisplay("700x500,500x500");
    346   SetSecondaryDisplayLayout(DisplayLayout::LEFT);
    347   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    348 
    349   EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-400, 100)));
    350   EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-1, 100)));
    351   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(0, 300)));
    352   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(700,300)));
    353 
    354   // Zero origin.
    355   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(0, 0)));
    356 
    357   // Out of range point should return the primary root window
    358   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(-600, 0)));
    359   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(701, 100)));
    360 }
    361 
    362 TEST_F(ExtendedDesktopTest, GetRootWindowMatching) {
    363   if (!SupportsMultipleDisplays())
    364     return;
    365 
    366   UpdateDisplay("700x500,500x500");
    367   SetSecondaryDisplayLayout(DisplayLayout::LEFT);
    368 
    369   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    370 
    371   // Containing rect.
    372   EXPECT_EQ(root_windows[1],
    373             wm::GetRootWindowMatching(gfx::Rect(-300, 10, 50, 50)));
    374   EXPECT_EQ(root_windows[0],
    375             wm::GetRootWindowMatching(gfx::Rect(100, 10, 50, 50)));
    376 
    377   // Intersecting rect.
    378   EXPECT_EQ(root_windows[1],
    379             wm::GetRootWindowMatching(gfx::Rect(-200, 0, 300, 300)));
    380   EXPECT_EQ(root_windows[0],
    381             wm::GetRootWindowMatching(gfx::Rect(-100, 0, 300, 300)));
    382 
    383   // Zero origin.
    384   EXPECT_EQ(root_windows[0],
    385             wm::GetRootWindowMatching(gfx::Rect(0, 0, 0, 0)));
    386   EXPECT_EQ(root_windows[0],
    387             wm::GetRootWindowMatching(gfx::Rect(0, 0, 1, 1)));
    388 
    389   // Empty rect.
    390   EXPECT_EQ(root_windows[1],
    391             wm::GetRootWindowMatching(gfx::Rect(-400, 100, 0, 0)));
    392   EXPECT_EQ(root_windows[0],
    393             wm::GetRootWindowMatching(gfx::Rect(100, 100, 0, 0)));
    394 
    395   // Out of range rect should return the primary root window.
    396   EXPECT_EQ(root_windows[0],
    397             wm::GetRootWindowMatching(gfx::Rect(-600, -300, 50, 50)));
    398   EXPECT_EQ(root_windows[0],
    399             wm::GetRootWindowMatching(gfx::Rect(0, 1000, 50, 50)));
    400 }
    401 
    402 TEST_F(ExtendedDesktopTest, Capture) {
    403   if (!SupportsMultipleDisplays())
    404     return;
    405 
    406   UpdateDisplay("1000x600,600x400");
    407   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    408 
    409   aura::test::EventCountDelegate r1_d1;
    410   aura::test::EventCountDelegate r1_d2;
    411   aura::test::EventCountDelegate r2_d1;
    412 
    413   scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
    414       &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
    415   scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
    416       &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
    417   scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
    418       &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
    419 
    420   r1_w1->SetCapture();
    421 
    422   EXPECT_EQ(r1_w1.get(),
    423             aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
    424 
    425   aura::test::EventGenerator generator2(root_windows[1]);
    426   generator2.MoveMouseToCenterOf(r2_w1.get());
    427   generator2.ClickLeftButton();
    428   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
    429   EXPECT_EQ("0 0", r2_d1.GetMouseButtonCountsAndReset());
    430   // The mouse is outside. On chromeos, the mouse is warped to the
    431   // dest root window, but it's not implemented on Win yet, so
    432   // no mouse move event on Win.
    433   EXPECT_EQ("1 1 0", r1_d1.GetMouseMotionCountsAndReset());
    434   EXPECT_EQ("1 1", r1_d1.GetMouseButtonCountsAndReset());
    435   // Emulate passive grab. (15,15) on 1st display is (-985,15) on 2nd
    436   // display.
    437   generator2.MoveMouseTo(-985, 15);
    438   EXPECT_EQ("0 1 0", r1_d1.GetMouseMotionCountsAndReset());
    439 
    440   r1_w2->SetCapture();
    441   EXPECT_EQ(r1_w2.get(),
    442             aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
    443   generator2.MoveMouseBy(10, 10);
    444   generator2.ClickLeftButton();
    445   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
    446   EXPECT_EQ("0 0", r2_d1.GetMouseButtonCountsAndReset());
    447   // mouse is already entered.
    448   EXPECT_EQ("0 1 0", r1_d2.GetMouseMotionCountsAndReset());
    449   EXPECT_EQ("1 1", r1_d2.GetMouseButtonCountsAndReset());
    450   r1_w2->ReleaseCapture();
    451   EXPECT_EQ(NULL, aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
    452   generator2.MoveMouseTo(15, 15);
    453   generator2.ClickLeftButton();
    454   EXPECT_EQ("1 1 0", r2_d1.GetMouseMotionCountsAndReset());
    455   EXPECT_EQ("1 1", r2_d1.GetMouseButtonCountsAndReset());
    456   // Make sure the mouse_moved_handler_ is properly reset.
    457   EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
    458   EXPECT_EQ("0 0", r1_d2.GetMouseButtonCountsAndReset());
    459 }
    460 
    461 TEST_F(ExtendedDesktopTest, MoveWindow) {
    462   if (!SupportsMultipleDisplays())
    463     return;
    464 
    465   UpdateDisplay("1000x600,600x400");
    466   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    467   views::Widget* d1 = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
    468 
    469   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
    470 
    471   d1->SetBounds(gfx::Rect(1010, 10, 100, 100));
    472   EXPECT_EQ("1010,10 100x100",
    473             d1->GetWindowBoundsInScreen().ToString());
    474 
    475   EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
    476 
    477   d1->SetBounds(gfx::Rect(10, 10, 100, 100));
    478   EXPECT_EQ("10,10 100x100",
    479             d1->GetWindowBoundsInScreen().ToString());
    480 
    481   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
    482 
    483   // Make sure the bounds which doesn't fit to the root window
    484   // works correctly.
    485   d1->SetBounds(gfx::Rect(1560, 30, 100, 100));
    486   EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
    487   EXPECT_EQ("1560,30 100x100",
    488             d1->GetWindowBoundsInScreen().ToString());
    489 
    490   // Setting outside of root windows will be moved to primary root window.
    491   // TODO(oshima): This one probably should pick the closest root window.
    492   d1->SetBounds(gfx::Rect(200, 10, 100, 100));
    493   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
    494 }
    495 
    496 // Verifies if the mouse event arrives to the window even when the window
    497 // moves to another root in a pre-target handler.  See: crbug.com/157583
    498 TEST_F(ExtendedDesktopTest, MoveWindowByMouseClick) {
    499   if (!SupportsMultipleDisplays())
    500     return;
    501 
    502   UpdateDisplay("1000x600,600x400");
    503 
    504   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    505   aura::test::EventCountDelegate delegate;
    506   scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
    507       &delegate, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
    508   MoveWindowByClickEventHandler event_handler(window.get());
    509   window->AddPreTargetHandler(&event_handler);
    510 
    511   aura::test::EventGenerator& event_generator(GetEventGenerator());
    512 
    513   event_generator.MoveMouseToCenterOf(window.get());
    514   event_generator.ClickLeftButton();
    515   // Both mouse pressed and released arrive at the window and its delegate.
    516   EXPECT_EQ("1 1", delegate.GetMouseButtonCountsAndReset());
    517   // Also event_handler moves the window to another root at mouse release.
    518   EXPECT_EQ(root_windows[1], window->GetRootWindow());
    519 }
    520 
    521 TEST_F(ExtendedDesktopTest, MoveWindowToDisplay) {
    522   if (!SupportsMultipleDisplays())
    523     return;
    524 
    525   UpdateDisplay("1000x1000,1000x1000");
    526   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    527 
    528   gfx::Display display0 = Shell::GetScreen()->GetDisplayMatching(
    529       root_windows[0]->GetBoundsInScreen());
    530   gfx::Display display1 = Shell::GetScreen()->GetDisplayMatching(
    531       root_windows[1]->GetBoundsInScreen());
    532   EXPECT_NE(display0.id(), display1.id());
    533 
    534   views::Widget* d1 = CreateTestWidget(gfx::Rect(10, 10, 1000, 100));
    535   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
    536 
    537   // Move the window where the window spans both root windows. Since the second
    538   // parameter is |display1|, the window should be shown on the secondary root.
    539   d1->GetNativeWindow()->SetBoundsInScreen(gfx::Rect(500, 10, 1000, 100),
    540                                            display1);
    541   EXPECT_EQ("500,10 1000x100",
    542             d1->GetWindowBoundsInScreen().ToString());
    543   EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
    544 
    545   // Move to the primary root.
    546   d1->GetNativeWindow()->SetBoundsInScreen(gfx::Rect(500, 10, 1000, 100),
    547                                            display0);
    548   EXPECT_EQ("500,10 1000x100",
    549             d1->GetWindowBoundsInScreen().ToString());
    550   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
    551 }
    552 
    553 TEST_F(ExtendedDesktopTest, MoveWindowWithTransient) {
    554   if (!SupportsMultipleDisplays())
    555     return;
    556 
    557   UpdateDisplay("1000x600,600x400");
    558   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    559   views::Widget* w1 = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
    560   views::Widget* w1_t1 = CreateTestWidgetWithParent(
    561       w1, gfx::Rect(50, 50, 50, 50), false /* transient */);
    562   // Transient child of the transient child.
    563   views::Widget* w1_t11 = CreateTestWidgetWithParent(
    564       w1_t1, gfx::Rect(1200, 70, 30, 30), false /* transient */);
    565 
    566   views::Widget* w11 = CreateTestWidgetWithParent(
    567       w1, gfx::Rect(10, 10, 40, 40), true /* child */);
    568   views::Widget* w11_t1 = CreateTestWidgetWithParent(
    569       w1, gfx::Rect(1300, 100, 80, 80), false /* transient */);
    570 
    571   EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
    572   EXPECT_EQ(root_windows[0], w11->GetNativeView()->GetRootWindow());
    573   EXPECT_EQ(root_windows[0], w1_t1->GetNativeView()->GetRootWindow());
    574   EXPECT_EQ(root_windows[0], w1_t11->GetNativeView()->GetRootWindow());
    575   EXPECT_EQ(root_windows[0], w11_t1->GetNativeView()->GetRootWindow());
    576   EXPECT_EQ("50,50 50x50",
    577             w1_t1->GetWindowBoundsInScreen().ToString());
    578   EXPECT_EQ("1200,70 30x30",
    579             w1_t11->GetWindowBoundsInScreen().ToString());
    580   EXPECT_EQ("20,20 40x40",
    581             w11->GetWindowBoundsInScreen().ToString());
    582   EXPECT_EQ("1300,100 80x80",
    583             w11_t1->GetWindowBoundsInScreen().ToString());
    584 
    585   w1->SetBounds(gfx::Rect(1100,10,100,100));
    586 
    587   EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
    588   EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
    589   EXPECT_EQ(root_windows[1], w1_t11->GetNativeView()->GetRootWindow());
    590   EXPECT_EQ(root_windows[1], w11->GetNativeView()->GetRootWindow());
    591   EXPECT_EQ(root_windows[1], w11_t1->GetNativeView()->GetRootWindow());
    592 
    593   EXPECT_EQ("1110,20 40x40",
    594             w11->GetWindowBoundsInScreen().ToString());
    595   // Transient window's screen bounds stays the same.
    596   EXPECT_EQ("50,50 50x50",
    597             w1_t1->GetWindowBoundsInScreen().ToString());
    598   EXPECT_EQ("1200,70 30x30",
    599             w1_t11->GetWindowBoundsInScreen().ToString());
    600   EXPECT_EQ("1300,100 80x80",
    601             w11_t1->GetWindowBoundsInScreen().ToString());
    602 
    603   // Transient window doesn't move between root window unless
    604   // its transient parent moves.
    605   w1_t1->SetBounds(gfx::Rect(10, 50, 50, 50));
    606   EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
    607   EXPECT_EQ("10,50 50x50",
    608             w1_t1->GetWindowBoundsInScreen().ToString());
    609 }
    610 
    611 // Test if the Window::ConvertPointToTarget works across root windows.
    612 // TODO(oshima): Move multiple display suport and this test to aura.
    613 TEST_F(ExtendedDesktopTest, ConvertPoint) {
    614   if (!SupportsMultipleDisplays())
    615     return;
    616   gfx::Screen* screen = Shell::GetInstance()->screen();
    617   UpdateDisplay("1000x600,600x400");
    618   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    619   gfx::Display display_1 = screen->GetDisplayNearestWindow(root_windows[0]);
    620   EXPECT_EQ("0,0", display_1.bounds().origin().ToString());
    621   gfx::Display display_2 = screen->GetDisplayNearestWindow(root_windows[1]);
    622   EXPECT_EQ("1000,0", display_2.bounds().origin().ToString());
    623 
    624   aura::Window* d1 =
    625       CreateTestWidget(gfx::Rect(10, 10, 100, 100))->GetNativeView();
    626   aura::Window* d2 =
    627       CreateTestWidget(gfx::Rect(1020, 20, 100, 100))->GetNativeView();
    628   EXPECT_EQ(root_windows[0], d1->GetRootWindow());
    629   EXPECT_EQ(root_windows[1], d2->GetRootWindow());
    630 
    631   // Convert point in the Root2's window to the Root1's window Coord.
    632   gfx::Point p(0, 0);
    633   aura::Window::ConvertPointToTarget(root_windows[1], root_windows[0], &p);
    634   EXPECT_EQ("1000,0", p.ToString());
    635   p.SetPoint(0, 0);
    636   aura::Window::ConvertPointToTarget(d2, d1, &p);
    637   EXPECT_EQ("1010,10", p.ToString());
    638 
    639   // Convert point in the Root1's window to the Root2's window Coord.
    640   p.SetPoint(0, 0);
    641   aura::Window::ConvertPointToTarget(root_windows[0], root_windows[1], &p);
    642   EXPECT_EQ("-1000,0", p.ToString());
    643   p.SetPoint(0, 0);
    644   aura::Window::ConvertPointToTarget(d1, d2, &p);
    645   EXPECT_EQ("-1010,-10", p.ToString());
    646 
    647   // Move the 2nd display to the bottom and test again.
    648   SetSecondaryDisplayLayout(DisplayLayout::BOTTOM);
    649 
    650   display_2 = screen->GetDisplayNearestWindow(root_windows[1]);
    651   EXPECT_EQ("0,600", display_2.bounds().origin().ToString());
    652 
    653   // Convert point in Root2's window to Root1's window Coord.
    654   p.SetPoint(0, 0);
    655   aura::Window::ConvertPointToTarget(root_windows[1], root_windows[0], &p);
    656   EXPECT_EQ("0,600", p.ToString());
    657   p.SetPoint(0, 0);
    658   aura::Window::ConvertPointToTarget(d2, d1, &p);
    659   EXPECT_EQ("10,610", p.ToString());
    660 
    661   // Convert point in Root1's window to Root2's window Coord.
    662   p.SetPoint(0, 0);
    663   aura::Window::ConvertPointToTarget(root_windows[0], root_windows[1], &p);
    664   EXPECT_EQ("0,-600", p.ToString());
    665   p.SetPoint(0, 0);
    666   aura::Window::ConvertPointToTarget(d1, d2, &p);
    667   EXPECT_EQ("-10,-610", p.ToString());
    668 }
    669 
    670 TEST_F(ExtendedDesktopTest, OpenSystemTray) {
    671   if (!SupportsMultipleDisplays())
    672     return;
    673 
    674   UpdateDisplay("500x600,600x400");
    675   SystemTray* tray = ash::Shell::GetInstance()->GetPrimarySystemTray();
    676   ASSERT_FALSE(tray->HasSystemBubble());
    677 
    678   aura::test::EventGenerator& event_generator(GetEventGenerator());
    679 
    680   // Opens the tray by a dummy click event and makes sure that adding/removing
    681   // displays doesn't break anything.
    682   event_generator.MoveMouseToCenterOf(tray->GetWidget()->GetNativeWindow());
    683   event_generator.ClickLeftButton();
    684   EXPECT_TRUE(tray->HasSystemBubble());
    685 
    686   UpdateDisplay("500x600");
    687   EXPECT_TRUE(tray->HasSystemBubble());
    688   UpdateDisplay("500x600,600x400");
    689   EXPECT_TRUE(tray->HasSystemBubble());
    690 
    691   // Closes the tray and again makes sure that adding/removing displays doesn't
    692   // break anything.
    693   event_generator.ClickLeftButton();
    694   RunAllPendingInMessageLoop();
    695 
    696   EXPECT_FALSE(tray->HasSystemBubble());
    697 
    698   UpdateDisplay("500x600");
    699   EXPECT_FALSE(tray->HasSystemBubble());
    700   UpdateDisplay("500x600,600x400");
    701   EXPECT_FALSE(tray->HasSystemBubble());
    702 }
    703 
    704 TEST_F(ExtendedDesktopTest, StayInSameRootWindow) {
    705   if (!SupportsMultipleDisplays())
    706     return;
    707 
    708   UpdateDisplay("100x100,200x200");
    709   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    710   views::Widget* w1 = CreateTestWidget(gfx::Rect(10, 10, 50, 50));
    711   EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
    712   w1->SetBounds(gfx::Rect(150, 10, 50, 50));
    713   EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow());
    714 
    715   // The widget stays in the same root if kStayInSameRootWindowKey is set to
    716   // true.
    717   w1->GetNativeView()->SetProperty(internal::kStayInSameRootWindowKey, true);
    718   w1->SetBounds(gfx::Rect(10, 10, 50, 50));
    719   EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow());
    720 
    721   // The widget should now move to the 1st root window without the property.
    722   w1->GetNativeView()->ClearProperty(internal::kStayInSameRootWindowKey);
    723   w1->SetBounds(gfx::Rect(10, 10, 50, 50));
    724   EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
    725 
    726   // a window in SettingsBubbleContainer and StatusContainer should
    727   // not move to another root window regardles of the bounds specified.
    728   aura::Window* settings_bubble_container =
    729       Shell::GetPrimaryRootWindowController()->GetContainer(
    730           internal::kShellWindowId_SettingBubbleContainer);
    731   aura::Window* window = aura::test::CreateTestWindowWithId(
    732       100, settings_bubble_container);
    733   window->SetBoundsInScreen(gfx::Rect(150, 10, 50, 50),
    734                             ScreenAsh::GetSecondaryDisplay());
    735   EXPECT_EQ(root_windows[0], window->GetRootWindow());
    736 
    737   aura::Window* status_container =
    738       Shell::GetPrimaryRootWindowController()->GetContainer(
    739           internal::kShellWindowId_StatusContainer);
    740   window = aura::test::CreateTestWindowWithId(100, status_container);
    741   window->SetBoundsInScreen(gfx::Rect(150, 10, 50, 50),
    742                             ScreenAsh::GetSecondaryDisplay());
    743   EXPECT_EQ(root_windows[0], window->GetRootWindow());
    744 }
    745 
    746 TEST_F(ExtendedDesktopTest, KeyEventsOnLockScreen) {
    747   if (!SupportsMultipleDisplays())
    748     return;
    749 
    750   UpdateDisplay("100x100,200x200");
    751   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
    752 
    753   // Create normal windows on both displays.
    754   views::Widget* widget1 = CreateTestWidget(
    755       Shell::GetScreen()->GetPrimaryDisplay().bounds());
    756   widget1->Show();
    757   EXPECT_EQ(root_windows[0], widget1->GetNativeView()->GetRootWindow());
    758   views::Widget* widget2 = CreateTestWidget(
    759       ScreenAsh::GetSecondaryDisplay().bounds());
    760   widget2->Show();
    761   EXPECT_EQ(root_windows[1], widget2->GetNativeView()->GetRootWindow());
    762 
    763   // Create a LockScreen window.
    764   views::Widget* lock_widget = CreateTestWidget(
    765       Shell::GetScreen()->GetPrimaryDisplay().bounds());
    766   views::Textfield* textfield = new views::Textfield;
    767   lock_widget->client_view()->AddChildView(textfield);
    768 
    769   ash::Shell::GetContainer(
    770       Shell::GetPrimaryRootWindow(),
    771       ash::internal::kShellWindowId_LockScreenContainer)->
    772       AddChild(lock_widget->GetNativeView());
    773   lock_widget->Show();
    774   textfield->RequestFocus();
    775 
    776   aura::client::FocusClient* focus_client =
    777       aura::client::GetFocusClient(root_windows[0]);
    778   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
    779 
    780   // The lock window should get events on both root windows.
    781   aura::test::EventGenerator& event_generator(GetEventGenerator());
    782 
    783   event_generator.set_current_root_window(root_windows[0]);
    784   event_generator.PressKey(ui::VKEY_A, 0);
    785   event_generator.ReleaseKey(ui::VKEY_A, 0);
    786   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
    787   EXPECT_EQ("a", UTF16ToASCII(textfield->text()));
    788 
    789   event_generator.set_current_root_window(root_windows[1]);
    790   event_generator.PressKey(ui::VKEY_B, 0);
    791   event_generator.ReleaseKey(ui::VKEY_B, 0);
    792   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
    793   EXPECT_EQ("ab", UTF16ToASCII(textfield->text()));
    794 
    795   // Deleting 2nd display. The lock window still should get the events.
    796   UpdateDisplay("100x100");
    797   event_generator.PressKey(ui::VKEY_C, 0);
    798   event_generator.ReleaseKey(ui::VKEY_C, 0);
    799   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
    800   EXPECT_EQ("abc", UTF16ToASCII(textfield->text()));
    801 
    802   // Creating 2nd display again, and lock window still should get events
    803   // on both root windows.
    804   UpdateDisplay("100x100,200x200");
    805   root_windows = Shell::GetAllRootWindows();
    806   event_generator.set_current_root_window(root_windows[0]);
    807   event_generator.PressKey(ui::VKEY_D, 0);
    808   event_generator.ReleaseKey(ui::VKEY_D, 0);
    809   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
    810   EXPECT_EQ("abcd", UTF16ToASCII(textfield->text()));
    811 
    812   event_generator.set_current_root_window(root_windows[1]);
    813   event_generator.PressKey(ui::VKEY_E, 0);
    814   event_generator.ReleaseKey(ui::VKEY_E, 0);
    815   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
    816   EXPECT_EQ("abcde", UTF16ToASCII(textfield->text()));
    817 }
    818 
    819 TEST_F(ExtendedDesktopTest, PassiveGrab) {
    820   if (!SupportsMultipleDisplays())
    821     return;
    822 
    823   EventLocationRecordingEventHandler event_handler;
    824   ash::Shell::GetInstance()->AddPreTargetHandler(&event_handler);
    825 
    826   UpdateDisplay("300x300,200x200");
    827 
    828   views::Widget* widget = CreateTestWidget(gfx::Rect(50, 50, 200, 200));
    829   widget->Show();
    830   ASSERT_EQ("50,50 200x200", widget->GetWindowBoundsInScreen().ToString());
    831 
    832   aura::test::EventGenerator& generator(GetEventGenerator());
    833   generator.MoveMouseTo(150, 150);
    834   EXPECT_EQ("100,100 150,150", event_handler.GetLocationsAndReset());
    835 
    836   generator.PressLeftButton();
    837   generator.MoveMouseTo(400, 150);
    838 
    839   EXPECT_EQ("350,100 400,150", event_handler.GetLocationsAndReset());
    840 
    841   generator.ReleaseLeftButton();
    842   EXPECT_EQ("-999,-999 -999,-999", event_handler.GetLocationsAndReset());
    843 
    844   generator.MoveMouseTo(400, 150);
    845   EXPECT_EQ("100,150 100,150", event_handler.GetLocationsAndReset());
    846 
    847   ash::Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
    848 }
    849 
    850 }  // namespace ash
    851