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