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