Home | History | Annotate | Download | only in wm
      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/wm/drag_window_resizer.h"
      6 
      7 #include "ash/display/mouse_cursor_event_filter.h"
      8 #include "ash/root_window_controller.h"
      9 #include "ash/shelf/shelf_layout_manager.h"
     10 #include "ash/shell.h"
     11 #include "ash/shell_window_ids.h"
     12 #include "ash/test/ash_test_base.h"
     13 #include "ash/test/cursor_manager_test_api.h"
     14 #include "ash/wm/drag_window_controller.h"
     15 #include "ash/wm/window_util.h"
     16 #include "base/strings/string_number_conversions.h"
     17 #include "base/strings/stringprintf.h"
     18 #include "ui/aura/client/aura_constants.h"
     19 #include "ui/aura/test/test_window_delegate.h"
     20 #include "ui/aura/window_event_dispatcher.h"
     21 #include "ui/base/hit_test.h"
     22 #include "ui/base/ui_base_types.h"
     23 #include "ui/compositor/layer_tree_owner.h"
     24 #include "ui/gfx/insets.h"
     25 #include "ui/gfx/screen.h"
     26 #include "ui/views/widget/widget.h"
     27 #include "ui/wm/core/window_util.h"
     28 
     29 namespace ash {
     30 namespace {
     31 
     32 const int kRootHeight = 600;
     33 
     34 }  // namespace
     35 
     36 class DragWindowResizerTest : public test::AshTestBase {
     37  public:
     38   DragWindowResizerTest() {}
     39   virtual ~DragWindowResizerTest() {}
     40 
     41   virtual void SetUp() OVERRIDE {
     42     AshTestBase::SetUp();
     43     UpdateDisplay(base::StringPrintf("800x%d", kRootHeight));
     44 
     45     aura::Window* root = Shell::GetPrimaryRootWindow();
     46     gfx::Rect root_bounds(root->bounds());
     47     EXPECT_EQ(kRootHeight, root_bounds.height());
     48     EXPECT_EQ(800, root_bounds.width());
     49     Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
     50     window_.reset(new aura::Window(&delegate_));
     51     window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
     52     window_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
     53     ParentWindowInPrimaryRootWindow(window_.get());
     54     window_->set_id(1);
     55 
     56     always_on_top_window_.reset(new aura::Window(&delegate2_));
     57     always_on_top_window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
     58     always_on_top_window_->SetProperty(aura::client::kAlwaysOnTopKey, true);
     59     always_on_top_window_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
     60     ParentWindowInPrimaryRootWindow(always_on_top_window_.get());
     61     always_on_top_window_->set_id(2);
     62 
     63     system_modal_window_.reset(new aura::Window(&delegate3_));
     64     system_modal_window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
     65     system_modal_window_->SetProperty(aura::client::kModalKey,
     66                                       ui::MODAL_TYPE_SYSTEM);
     67     system_modal_window_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
     68     ParentWindowInPrimaryRootWindow(system_modal_window_.get());
     69     system_modal_window_->set_id(3);
     70 
     71     transient_child_ = new aura::Window(&delegate4_);
     72     transient_child_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
     73     transient_child_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
     74     ParentWindowInPrimaryRootWindow(transient_child_);
     75     transient_child_->set_id(4);
     76 
     77     transient_parent_.reset(new aura::Window(&delegate5_));
     78     transient_parent_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
     79     transient_parent_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
     80     ParentWindowInPrimaryRootWindow(transient_parent_.get());
     81     ::wm::AddTransientChild(transient_parent_.get(), transient_child_);
     82     transient_parent_->set_id(5);
     83 
     84     panel_window_.reset(new aura::Window(&delegate6_));
     85     panel_window_->SetType(ui::wm::WINDOW_TYPE_PANEL);
     86     panel_window_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
     87     ParentWindowInPrimaryRootWindow(panel_window_.get());
     88   }
     89 
     90   virtual void TearDown() OVERRIDE {
     91     window_.reset();
     92     always_on_top_window_.reset();
     93     system_modal_window_.reset();
     94     transient_parent_.reset();
     95     panel_window_.reset();
     96     AshTestBase::TearDown();
     97   }
     98 
     99  protected:
    100   gfx::Point CalculateDragPoint(const WindowResizer& resizer,
    101                                 int delta_x,
    102                                 int delta_y) const {
    103     gfx::Point location = resizer.GetInitialLocation();
    104     location.set_x(location.x() + delta_x);
    105     location.set_y(location.y() + delta_y);
    106     return location;
    107   }
    108 
    109   ShelfLayoutManager* shelf_layout_manager() {
    110     return Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
    111   }
    112 
    113   static WindowResizer* CreateDragWindowResizer(
    114       aura::Window* window,
    115       const gfx::Point& point_in_parent,
    116       int window_component) {
    117     return CreateWindowResizer(
    118         window,
    119         point_in_parent,
    120         window_component,
    121         aura::client::WINDOW_MOVE_SOURCE_MOUSE).release();
    122   }
    123 
    124   bool WarpMouseCursorIfNecessary(aura::Window* target_root,
    125                                   const gfx::Point& point_in_screen) {
    126     MouseCursorEventFilter* event_filter =
    127         Shell::GetInstance()->mouse_cursor_filter();
    128     bool is_warped = event_filter->WarpMouseCursorIfNecessaryForTest(
    129         target_root, point_in_screen);
    130     event_filter->reset_was_mouse_warped_for_test();
    131     return is_warped;
    132   }
    133 
    134   aura::test::TestWindowDelegate delegate_;
    135   aura::test::TestWindowDelegate delegate2_;
    136   aura::test::TestWindowDelegate delegate3_;
    137   aura::test::TestWindowDelegate delegate4_;
    138   aura::test::TestWindowDelegate delegate5_;
    139   aura::test::TestWindowDelegate delegate6_;
    140 
    141   scoped_ptr<aura::Window> window_;
    142   scoped_ptr<aura::Window> always_on_top_window_;
    143   scoped_ptr<aura::Window> system_modal_window_;
    144   scoped_ptr<aura::Window> panel_window_;
    145   aura::Window* transient_child_;
    146   scoped_ptr<aura::Window> transient_parent_;
    147 
    148  private:
    149   DISALLOW_COPY_AND_ASSIGN(DragWindowResizerTest);
    150 };
    151 
    152 // Verifies a window can be moved from the primary display to another.
    153 TEST_F(DragWindowResizerTest, WindowDragWithMultiDisplays) {
    154   if (!SupportsMultipleDisplays())
    155     return;
    156 
    157   // The secondary display is logically on the right, but on the system (e.g. X)
    158   // layer, it's below the primary one. See UpdateDisplay() in ash_test_base.cc.
    159   UpdateDisplay("800x600,400x300");
    160   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    161   ASSERT_EQ(2U, root_windows.size());
    162 
    163   window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
    164                              Shell::GetScreen()->GetPrimaryDisplay());
    165   EXPECT_EQ(root_windows[0], window_->GetRootWindow());
    166   {
    167     // Grab (0, 0) of the window.
    168     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    169         window_.get(), gfx::Point(), HTCAPTION));
    170     ASSERT_TRUE(resizer.get());
    171     // Drag the pointer to the right. Once it reaches the right edge of the
    172     // primary display, it warps to the secondary.
    173     resizer->Drag(CalculateDragPoint(*resizer, 800, 10), 0);
    174     resizer->CompleteDrag();
    175     // The whole window is on the secondary display now. The parent should be
    176     // changed.
    177     EXPECT_EQ(root_windows[1], window_->GetRootWindow());
    178     EXPECT_EQ("0,10 50x60", window_->bounds().ToString());
    179   }
    180 
    181   window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
    182                              Shell::GetScreen()->GetPrimaryDisplay());
    183   EXPECT_EQ(root_windows[0], window_->GetRootWindow());
    184   {
    185     // Grab (0, 0) of the window and move the pointer to (790, 10).
    186     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    187         window_.get(), gfx::Point(), HTCAPTION));
    188     ASSERT_TRUE(resizer.get());
    189     resizer->Drag(CalculateDragPoint(*resizer, 795, 10), 0);
    190     // Window should be adjusted for minimum visibility (10px) during the drag.
    191     EXPECT_EQ("790,10 50x60", window_->bounds().ToString());
    192     resizer->CompleteDrag();
    193     // Since the pointer is still on the primary root window, the parent should
    194     // not be changed.
    195     // Window origin should be adjusted for minimum visibility (10px).
    196     EXPECT_EQ(root_windows[0], window_->GetRootWindow());
    197     EXPECT_EQ("790,10 50x60", window_->bounds().ToString());
    198   }
    199 
    200   window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
    201                              Shell::GetScreen()->GetPrimaryDisplay());
    202   EXPECT_EQ(root_windows[0], window_->GetRootWindow());
    203   {
    204     // Grab the top-right edge of the window and move the pointer to (0, 10)
    205     // in the secondary root window's coordinates.
    206     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    207         window_.get(), gfx::Point(49, 0), HTCAPTION));
    208     ASSERT_TRUE(resizer.get());
    209     resizer->Drag(CalculateDragPoint(*resizer, 751, 10), ui::EF_CONTROL_DOWN);
    210     resizer->CompleteDrag();
    211     // Since the pointer is on the secondary, the parent should be changed
    212     // even though only small fraction of the window is within the secondary
    213     // root window's bounds.
    214     EXPECT_EQ(root_windows[1], window_->GetRootWindow());
    215     // Window origin should be adjusted for minimum visibility (10px).
    216     int expected_x = -50 + 10;
    217     EXPECT_EQ(base::IntToString(expected_x) + ",10 50x60",
    218               window_->bounds().ToString());
    219   }
    220   // Dropping a window that is larger than the destination work area
    221   // will shrink to fit to the work area.
    222   window_->SetBoundsInScreen(gfx::Rect(0, 0, 700, 500),
    223                              Shell::GetScreen()->GetPrimaryDisplay());
    224   EXPECT_EQ(root_windows[0], window_->GetRootWindow());
    225   {
    226     // Grab the top-right edge of the window and move the pointer to (0, 10)
    227     // in the secondary root window's coordinates.
    228     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    229         window_.get(), gfx::Point(699, 0), HTCAPTION));
    230     ASSERT_TRUE(resizer.get());
    231     resizer->Drag(CalculateDragPoint(*resizer, 101, 10), ui::EF_CONTROL_DOWN);
    232     resizer->CompleteDrag();
    233     EXPECT_EQ(root_windows[1], window_->GetRootWindow());
    234     // Window size should be adjusted to fit to the work area
    235     EXPECT_EQ("400x253", window_->bounds().size().ToString());
    236     gfx::Rect window_bounds_in_screen = window_->GetBoundsInScreen();
    237     gfx::Rect intersect(window_->GetRootWindow()->GetBoundsInScreen());
    238     intersect.Intersect(window_bounds_in_screen);
    239 
    240     EXPECT_LE(10, intersect.width());
    241     EXPECT_LE(10, intersect.height());
    242     EXPECT_TRUE(window_bounds_in_screen.Contains(gfx::Point(800, 10)));
    243   }
    244 
    245   // Dropping a window that is larger than the destination work area
    246   // will shrink to fit to the work area.
    247   window_->SetBoundsInScreen(gfx::Rect(0, 0, 700, 500),
    248                              Shell::GetScreen()->GetPrimaryDisplay());
    249   EXPECT_EQ(root_windows[0], window_->GetRootWindow());
    250   {
    251     // Grab the top-left edge of the window and move the pointer to (150, 10)
    252     // in the secondary root window's coordinates. Make sure the window is
    253     // shrink in such a way that it keeps the cursor within.
    254     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    255         window_.get(), gfx::Point(0, 0), HTCAPTION));
    256     ASSERT_TRUE(resizer.get());
    257     resizer->Drag(CalculateDragPoint(*resizer, 799, 10), ui::EF_CONTROL_DOWN);
    258     resizer->Drag(CalculateDragPoint(*resizer, 850, 10), ui::EF_CONTROL_DOWN);
    259     resizer->CompleteDrag();
    260     EXPECT_EQ(root_windows[1], window_->GetRootWindow());
    261     // Window size should be adjusted to fit to the work area
    262     EXPECT_EQ("400x253", window_->bounds().size().ToString());
    263     gfx::Rect window_bounds_in_screen = window_->GetBoundsInScreen();
    264     gfx::Rect intersect(window_->GetRootWindow()->GetBoundsInScreen());
    265     intersect.Intersect(window_bounds_in_screen);
    266     EXPECT_LE(10, intersect.width());
    267     EXPECT_LE(10, intersect.height());
    268     EXPECT_TRUE(window_bounds_in_screen.Contains(gfx::Point(850, 10)));
    269   }
    270 }
    271 
    272 // Verifies that dragging the active window to another display makes the new
    273 // root window the active root window.
    274 TEST_F(DragWindowResizerTest, WindowDragWithMultiDisplaysActiveRoot) {
    275   if (!SupportsMultipleDisplays())
    276     return;
    277 
    278   // The secondary display is logically on the right, but on the system (e.g. X)
    279   // layer, it's below the primary one. See UpdateDisplay() in ash_test_base.cc.
    280   UpdateDisplay("800x600,800x600");
    281   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    282   ASSERT_EQ(2U, root_windows.size());
    283 
    284   aura::test::TestWindowDelegate delegate;
    285   scoped_ptr<aura::Window> window(new aura::Window(&delegate));
    286   window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
    287   window->Init(aura::WINDOW_LAYER_TEXTURED);
    288   ParentWindowInPrimaryRootWindow(window.get());
    289   window->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
    290                             Shell::GetScreen()->GetPrimaryDisplay());
    291   window->Show();
    292   EXPECT_TRUE(ash::wm::CanActivateWindow(window.get()));
    293   ash::wm::ActivateWindow(window.get());
    294   EXPECT_EQ(root_windows[0], window->GetRootWindow());
    295   EXPECT_EQ(root_windows[0], ash::Shell::GetTargetRootWindow());
    296   {
    297     // Grab (0, 0) of the window.
    298     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    299         window.get(), gfx::Point(), HTCAPTION));
    300     ASSERT_TRUE(resizer.get());
    301     // Drag the pointer to the right. Once it reaches the right edge of the
    302     // primary display, it warps to the secondary.
    303     resizer->Drag(CalculateDragPoint(*resizer, 800, 10), 0);
    304     resizer->CompleteDrag();
    305     // The whole window is on the secondary display now. The parent should be
    306     // changed.
    307     EXPECT_EQ(root_windows[1], window->GetRootWindow());
    308     EXPECT_EQ(root_windows[1], ash::Shell::GetTargetRootWindow());
    309   }
    310 }
    311 
    312 // Verifies a window can be moved from the secondary display to primary.
    313 TEST_F(DragWindowResizerTest, WindowDragWithMultiDisplaysRightToLeft) {
    314   if (!SupportsMultipleDisplays())
    315     return;
    316 
    317   UpdateDisplay("800x600,800x600");
    318   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    319   ASSERT_EQ(2U, root_windows.size());
    320 
    321   window_->SetBoundsInScreen(
    322       gfx::Rect(800, 00, 50, 60),
    323       Shell::GetScreen()->GetDisplayNearestWindow(root_windows[1]));
    324   EXPECT_EQ(root_windows[1], window_->GetRootWindow());
    325   {
    326     // Grab (0, 0) of the window.
    327     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    328         window_.get(), gfx::Point(), HTCAPTION));
    329     ASSERT_TRUE(resizer.get());
    330     // Move the mouse near the right edge, (798, 0), of the primary display.
    331     resizer->Drag(CalculateDragPoint(*resizer, -2, 0), ui::EF_CONTROL_DOWN);
    332     resizer->CompleteDrag();
    333     EXPECT_EQ(root_windows[0], window_->GetRootWindow());
    334     // Window origin should be adjusted for minimum visibility (10px).
    335     int expected_x = 800 - 10;
    336     EXPECT_EQ(base::IntToString(expected_x) + ",0 50x60",
    337               window_->bounds().ToString());
    338   }
    339 }
    340 
    341 // Verifies the drag window is shown correctly.
    342 TEST_F(DragWindowResizerTest, DragWindowController) {
    343   if (!SupportsMultipleDisplays())
    344     return;
    345 
    346   UpdateDisplay("800x600,800x600");
    347   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    348   ASSERT_EQ(2U, root_windows.size());
    349 
    350   window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
    351                              Shell::GetScreen()->GetPrimaryDisplay());
    352   EXPECT_EQ(root_windows[0], window_->GetRootWindow());
    353   EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity());
    354   {
    355     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    356         window_.get(), gfx::Point(), HTCAPTION));
    357     ASSERT_TRUE(resizer.get());
    358     DragWindowResizer* drag_resizer = DragWindowResizer::instance_;
    359     ASSERT_TRUE(drag_resizer);
    360     EXPECT_FALSE(drag_resizer->drag_window_controller_.get());
    361 
    362     // The pointer is inside the primary root. The drag window controller
    363     // should be NULL.
    364     resizer->Drag(CalculateDragPoint(*resizer, 10, 10), 0);
    365     EXPECT_FALSE(drag_resizer->drag_window_controller_.get());
    366 
    367     // The window spans both root windows.
    368     resizer->Drag(CalculateDragPoint(*resizer, 798, 10), 0);
    369     DragWindowController* controller =
    370         drag_resizer->drag_window_controller_.get();
    371     ASSERT_TRUE(controller);
    372 
    373     ASSERT_TRUE(controller->drag_widget_);
    374     ui::Layer* drag_layer =
    375         controller->drag_widget_->GetNativeWindow()->layer();
    376     ASSERT_TRUE(drag_layer);
    377     // Check if |resizer->layer_| is properly set to the drag widget.
    378     const std::vector<ui::Layer*>& layers = drag_layer->children();
    379     EXPECT_FALSE(layers.empty());
    380     EXPECT_EQ(controller->layer_owner_->root(), layers.back());
    381 
    382     // |window_| should be opaque since the pointer is still on the primary
    383     // root window. The drag window should be semi-transparent.
    384     EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity());
    385     ASSERT_TRUE(controller->drag_widget_);
    386     EXPECT_GT(1.0f, drag_layer->opacity());
    387 
    388     // Enter the pointer to the secondary display.
    389     resizer->Drag(CalculateDragPoint(*resizer, 800, 10), 0);
    390     controller = drag_resizer->drag_window_controller_.get();
    391     ASSERT_TRUE(controller);
    392     // |window_| should be transparent, and the drag window should be opaque.
    393     EXPECT_GT(1.0f, window_->layer()->opacity());
    394     EXPECT_FLOAT_EQ(1.0f, drag_layer->opacity());
    395 
    396     resizer->CompleteDrag();
    397     EXPECT_EQ(root_windows[1], window_->GetRootWindow());
    398     EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity());
    399   }
    400 
    401   // Do the same test with RevertDrag().
    402   window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
    403                              Shell::GetScreen()->GetPrimaryDisplay());
    404   EXPECT_EQ(root_windows[0], window_->GetRootWindow());
    405   EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity());
    406   {
    407     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    408         window_.get(), gfx::Point(), HTCAPTION));
    409     ASSERT_TRUE(resizer.get());
    410     DragWindowResizer* drag_resizer = DragWindowResizer::instance_;
    411     ASSERT_TRUE(drag_resizer);
    412     EXPECT_FALSE(drag_resizer->drag_window_controller_.get());
    413 
    414     resizer->Drag(CalculateDragPoint(*resizer, 0, 610), 0);
    415     resizer->RevertDrag();
    416     EXPECT_EQ(root_windows[0], window_->GetRootWindow());
    417     EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity());
    418   }
    419 }
    420 
    421 // Verifies if the resizer sets and resets
    422 // MouseCursorEventFilter::mouse_warp_mode_ as expected.
    423 TEST_F(DragWindowResizerTest, WarpMousePointer) {
    424   MouseCursorEventFilter* event_filter =
    425       Shell::GetInstance()->mouse_cursor_filter();
    426   ASSERT_TRUE(event_filter);
    427   window_->SetBounds(gfx::Rect(0, 0, 50, 60));
    428 
    429   EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS,
    430             event_filter->mouse_warp_mode_);
    431   {
    432     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    433         window_.get(), gfx::Point(), HTCAPTION));
    434     // While dragging a window, warp should be allowed.
    435     EXPECT_EQ(MouseCursorEventFilter::WARP_DRAG,
    436               event_filter->mouse_warp_mode_);
    437     resizer->CompleteDrag();
    438   }
    439   EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS,
    440             event_filter->mouse_warp_mode_);
    441 
    442   {
    443     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    444         window_.get(), gfx::Point(), HTCAPTION));
    445     EXPECT_EQ(MouseCursorEventFilter::WARP_DRAG,
    446               event_filter->mouse_warp_mode_);
    447     resizer->RevertDrag();
    448   }
    449   EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS,
    450             event_filter->mouse_warp_mode_);
    451 
    452   {
    453     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    454         window_.get(), gfx::Point(), HTRIGHT));
    455     // While resizing a window, warp should NOT be allowed.
    456     EXPECT_EQ(MouseCursorEventFilter::WARP_NONE,
    457               event_filter->mouse_warp_mode_);
    458     resizer->CompleteDrag();
    459   }
    460   EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS,
    461             event_filter->mouse_warp_mode_);
    462 
    463   {
    464     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    465         window_.get(), gfx::Point(), HTRIGHT));
    466     EXPECT_EQ(MouseCursorEventFilter::WARP_NONE,
    467               event_filter->mouse_warp_mode_);
    468     resizer->RevertDrag();
    469   }
    470   EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS,
    471             event_filter->mouse_warp_mode_);
    472 }
    473 
    474 // Verifies cursor's device scale factor is updated whe a window is moved across
    475 // root windows with different device scale factors (http://crbug.com/154183).
    476 TEST_F(DragWindowResizerTest, CursorDeviceScaleFactor) {
    477   if (!SupportsMultipleDisplays())
    478     return;
    479 
    480   // The secondary display is logically on the right, but on the system (e.g. X)
    481   // layer, it's below the primary one. See UpdateDisplay() in ash_test_base.cc.
    482   UpdateDisplay("400x400,800x800*2");
    483   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    484   ASSERT_EQ(2U, root_windows.size());
    485 
    486   test::CursorManagerTestApi cursor_test_api(
    487       Shell::GetInstance()->cursor_manager());
    488   // Move window from the root window with 1.0 device scale factor to the root
    489   // window with 2.0 device scale factor.
    490   {
    491     window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
    492                                Shell::GetScreen()->GetPrimaryDisplay());
    493     EXPECT_EQ(root_windows[0], window_->GetRootWindow());
    494     // Grab (0, 0) of the window.
    495     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    496         window_.get(), gfx::Point(), HTCAPTION));
    497     EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
    498     ASSERT_TRUE(resizer.get());
    499     resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
    500     WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(399, 200));
    501     EXPECT_EQ(2.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
    502     resizer->CompleteDrag();
    503     EXPECT_EQ(2.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
    504   }
    505 
    506   // Move window from the root window with 2.0 device scale factor to the root
    507   // window with 1.0 device scale factor.
    508   {
    509     // Make sure the window is on the default container first.
    510     aura::Window* default_container =
    511         GetRootWindowController(root_windows[1])
    512             ->GetContainer(kShellWindowId_DefaultContainer);
    513     default_container->AddChild(window_.get());
    514     window_->SetBoundsInScreen(
    515         gfx::Rect(600, 0, 50, 60),
    516         Shell::GetScreen()->GetDisplayNearestWindow(root_windows[1]));
    517     EXPECT_EQ(root_windows[1], window_->GetRootWindow());
    518     // Grab (0, 0) of the window.
    519     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    520         window_.get(), gfx::Point(), HTCAPTION));
    521     EXPECT_EQ(2.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
    522     ASSERT_TRUE(resizer.get());
    523     resizer->Drag(CalculateDragPoint(*resizer, -200, 200), 0);
    524     WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(400, 200));
    525     EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
    526     resizer->CompleteDrag();
    527     EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
    528   }
    529 }
    530 
    531 // Verifies several kinds of windows can be moved across displays.
    532 TEST_F(DragWindowResizerTest, MoveWindowAcrossDisplays) {
    533   if (!SupportsMultipleDisplays())
    534     return;
    535 
    536   // The secondary display is logically on the right, but on the system (e.g. X)
    537   // layer, it's below the primary one. See UpdateDisplay() in ash_test_base.cc.
    538   UpdateDisplay("400x400,400x400");
    539 
    540   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    541   ASSERT_EQ(2U, root_windows.size());
    542 
    543   // Normal window can be moved across display.
    544   {
    545     aura::Window* window = window_.get();
    546     window->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
    547                               Shell::GetScreen()->GetPrimaryDisplay());
    548     // Grab (0, 0) of the window.
    549     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    550         window, gfx::Point(), HTCAPTION));
    551     ASSERT_TRUE(resizer.get());
    552     resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
    553     EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0],
    554                                            gfx::Point(399, 200)));
    555     resizer->CompleteDrag();
    556   }
    557 
    558   // Always on top window can be moved across display.
    559   {
    560     aura::Window* window = always_on_top_window_.get();
    561     window->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
    562                               Shell::GetScreen()->GetPrimaryDisplay());
    563     // Grab (0, 0) of the window.
    564     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    565         window, gfx::Point(), HTCAPTION));
    566     ASSERT_TRUE(resizer.get());
    567     resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
    568     EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0],
    569                                            gfx::Point(399, 200)));
    570     resizer->CompleteDrag();
    571   }
    572 
    573   // System modal window can be moved across display.
    574   {
    575     aura::Window* window = system_modal_window_.get();
    576     window->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
    577                               Shell::GetScreen()->GetPrimaryDisplay());
    578     // Grab (0, 0) of the window.
    579     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    580         window, gfx::Point(), HTCAPTION));
    581     ASSERT_TRUE(resizer.get());
    582     resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
    583     EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0],
    584                                            gfx::Point(399, 200)));
    585     resizer->CompleteDrag();
    586   }
    587 
    588   // Transient window cannot be moved across display.
    589   {
    590     aura::Window* window = transient_child_;
    591     window->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
    592                               Shell::GetScreen()->GetPrimaryDisplay());
    593     // Grab (0, 0) of the window.
    594     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    595         window, gfx::Point(), HTCAPTION));
    596     ASSERT_TRUE(resizer.get());
    597     resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
    598     EXPECT_FALSE(WarpMouseCursorIfNecessary(
    599         root_windows[0],
    600         gfx::Point(399, 200)));
    601     resizer->CompleteDrag();
    602   }
    603 
    604   // The parent of transient window can be moved across display.
    605   {
    606     aura::Window* window = transient_parent_.get();
    607     window->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
    608                               Shell::GetScreen()->GetPrimaryDisplay());
    609     // Grab (0, 0) of the window.
    610     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    611         window, gfx::Point(), HTCAPTION));
    612     ASSERT_TRUE(resizer.get());
    613     resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
    614     EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0],
    615                                            gfx::Point(399, 200)));
    616     resizer->CompleteDrag();
    617   }
    618 
    619   // Panel window can be moved across display.
    620   {
    621     aura::Window* window = panel_window_.get();
    622     window->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
    623                               Shell::GetScreen()->GetPrimaryDisplay());
    624     // Grab (0, 0) of the window.
    625     scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
    626         window, gfx::Point(), HTCAPTION));
    627     ASSERT_TRUE(resizer.get());
    628     resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
    629     EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0],
    630                                            gfx::Point(399, 200)));
    631     resizer->CompleteDrag();
    632   }
    633 }
    634 
    635 }  // namespace ash
    636