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