OLD | NEW |
(Empty) | |
| 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/shell.h" |
| 10 #include "ash/shell_window_ids.h" |
| 11 #include "ash/test/ash_test_base.h" |
| 12 #include "ash/test/cursor_manager_test_api.h" |
| 13 #include "ash/wm/cursor_manager.h" |
| 14 #include "ash/wm/drag_window_controller.h" |
| 15 #include "ash/wm/shelf_layout_manager.h" |
| 16 #include "base/stringprintf.h" |
| 17 #include "ui/aura/root_window.h" |
| 18 #include "ui/aura/test/test_window_delegate.h" |
| 19 #include "ui/base/hit_test.h" |
| 20 #include "ui/gfx/insets.h" |
| 21 #include "ui/gfx/screen.h" |
| 22 #include "ui/views/widget/widget.h" |
| 23 |
| 24 namespace ash { |
| 25 namespace internal { |
| 26 namespace { |
| 27 |
| 28 const int kRootHeight = 600; |
| 29 |
| 30 } // namespace |
| 31 |
| 32 class DragWindowResizerTest : public test::AshTestBase { |
| 33 public: |
| 34 DragWindowResizerTest() : window_(NULL) {} |
| 35 virtual ~DragWindowResizerTest() {} |
| 36 |
| 37 virtual void SetUp() OVERRIDE { |
| 38 AshTestBase::SetUp(); |
| 39 UpdateDisplay(StringPrintf("800x%d", kRootHeight)); |
| 40 |
| 41 aura::RootWindow* root = Shell::GetPrimaryRootWindow(); |
| 42 gfx::Rect root_bounds(root->bounds()); |
| 43 EXPECT_EQ(kRootHeight, root_bounds.height()); |
| 44 EXPECT_EQ(800, root_bounds.width()); |
| 45 Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets()); |
| 46 window_.reset(new aura::Window(&delegate_)); |
| 47 window_->SetType(aura::client::WINDOW_TYPE_NORMAL); |
| 48 window_->Init(ui::LAYER_NOT_DRAWN); |
| 49 SetDefaultParentByPrimaryRootWindow(window_.get()); |
| 50 window_->set_id(1); |
| 51 } |
| 52 |
| 53 virtual void TearDown() OVERRIDE { |
| 54 window_.reset(); |
| 55 AshTestBase::TearDown(); |
| 56 } |
| 57 |
| 58 protected: |
| 59 gfx::Point CalculateDragPoint(const DragWindowResizer& resizer, |
| 60 int delta_x, |
| 61 int delta_y) const { |
| 62 gfx::Point location = resizer.GetInitialLocationInParentForTest(); |
| 63 location.set_x(location.x() + delta_x); |
| 64 location.set_y(location.y() + delta_y); |
| 65 return location; |
| 66 } |
| 67 |
| 68 internal::ShelfLayoutManager* shelf_layout_manager() { |
| 69 return Shell::GetPrimaryRootWindowController()->shelf(); |
| 70 } |
| 71 |
| 72 static DragWindowResizer* CreateDragWindowResizer( |
| 73 aura::Window* window, |
| 74 const gfx::Point& point_in_parent, |
| 75 int window_component) { |
| 76 return static_cast<DragWindowResizer*>(CreateWindowResizer( |
| 77 window, point_in_parent, window_component).release()); |
| 78 } |
| 79 |
| 80 aura::test::TestWindowDelegate delegate_; |
| 81 scoped_ptr<aura::Window> window_; |
| 82 |
| 83 private: |
| 84 DISALLOW_COPY_AND_ASSIGN(DragWindowResizerTest); |
| 85 }; |
| 86 |
| 87 // Verifies a window can be moved from the primary display to another. |
| 88 TEST_F(DragWindowResizerTest, WindowDragWithMultiDisplays) { |
| 89 // The secondary display is logically on the right, but on the system (e.g. X) |
| 90 // layer, it's below the primary one. See UpdateDisplay() in ash_test_base.cc. |
| 91 UpdateDisplay("800x600,800x600"); |
| 92 shelf_layout_manager()->LayoutShelf(); |
| 93 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); |
| 94 ASSERT_EQ(2U, root_windows.size()); |
| 95 |
| 96 window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), |
| 97 Shell::GetScreen()->GetPrimaryDisplay()); |
| 98 EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| 99 { |
| 100 // Grab (0, 0) of the window. |
| 101 scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( |
| 102 window_.get(), gfx::Point(), HTCAPTION)); |
| 103 ASSERT_TRUE(resizer.get()); |
| 104 // Drag the pointer to the right. Once it reaches the right edge of the |
| 105 // primary display, it warps to the secondary. |
| 106 resizer->Drag(CalculateDragPoint(*resizer, 800, 10), 0); |
| 107 resizer->CompleteDrag(0); |
| 108 // The whole window is on the secondary display now. The parent should be |
| 109 // changed. |
| 110 EXPECT_EQ(root_windows[1], window_->GetRootWindow()); |
| 111 EXPECT_EQ("0,10 50x60", window_->bounds().ToString()); |
| 112 } |
| 113 |
| 114 window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), |
| 115 Shell::GetScreen()->GetPrimaryDisplay()); |
| 116 EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| 117 { |
| 118 // Grab (0, 0) of the window and move the pointer to (790, 10). |
| 119 scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( |
| 120 window_.get(), gfx::Point(), HTCAPTION)); |
| 121 ASSERT_TRUE(resizer.get()); |
| 122 resizer->Drag(CalculateDragPoint(*resizer, 790, 10), 0); |
| 123 resizer->CompleteDrag(0); |
| 124 // Since the pointer is still on the primary root window, the parent should |
| 125 // not be changed. |
| 126 EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| 127 EXPECT_EQ("790,10 50x60", window_->bounds().ToString()); |
| 128 } |
| 129 |
| 130 window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), |
| 131 Shell::GetScreen()->GetPrimaryDisplay()); |
| 132 EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| 133 { |
| 134 // Grab the top-right edge of the window and move the pointer to (0, 10) |
| 135 // in the secondary root window's coordinates. |
| 136 scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( |
| 137 window_.get(), gfx::Point(49, 0), HTCAPTION)); |
| 138 ASSERT_TRUE(resizer.get()); |
| 139 resizer->Drag(CalculateDragPoint(*resizer, 751, 10), ui::EF_CONTROL_DOWN); |
| 140 resizer->CompleteDrag(0); |
| 141 // Since the pointer is on the secondary, the parent should be changed |
| 142 // even though only small fraction of the window is within the secondary |
| 143 // root window's bounds. |
| 144 EXPECT_EQ(root_windows[1], window_->GetRootWindow()); |
| 145 EXPECT_EQ("-49,10 50x60", window_->bounds().ToString()); |
| 146 } |
| 147 } |
| 148 |
| 149 // Verifies a window can be moved from the secondary display to primary. |
| 150 TEST_F(DragWindowResizerTest, WindowDragWithMultiDisplaysRightToLeft) { |
| 151 UpdateDisplay("800x600,800x600"); |
| 152 shelf_layout_manager()->LayoutShelf(); |
| 153 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); |
| 154 ASSERT_EQ(2U, root_windows.size()); |
| 155 |
| 156 window_->SetBoundsInScreen( |
| 157 gfx::Rect(800, 00, 50, 60), |
| 158 Shell::GetScreen()->GetDisplayNearestWindow(root_windows[1])); |
| 159 EXPECT_EQ(root_windows[1], window_->GetRootWindow()); |
| 160 { |
| 161 // Grab (0, 0) of the window. |
| 162 scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( |
| 163 window_.get(), gfx::Point(), HTCAPTION)); |
| 164 ASSERT_TRUE(resizer.get()); |
| 165 // Move the mouse near the right edge, (798, 0), of the primary display. |
| 166 resizer->Drag(CalculateDragPoint(*resizer, -2, 0), ui::EF_CONTROL_DOWN); |
| 167 resizer->CompleteDrag(0); |
| 168 EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| 169 EXPECT_EQ("798,0 50x60", window_->bounds().ToString()); |
| 170 } |
| 171 } |
| 172 |
| 173 // Verifies the drag window is shown correctly. |
| 174 TEST_F(DragWindowResizerTest, DragWindowController) { |
| 175 UpdateDisplay("800x600,800x600"); |
| 176 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); |
| 177 ASSERT_EQ(2U, root_windows.size()); |
| 178 |
| 179 window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), |
| 180 Shell::GetScreen()->GetPrimaryDisplay()); |
| 181 EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| 182 EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); |
| 183 { |
| 184 scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( |
| 185 window_.get(), gfx::Point(), HTCAPTION)); |
| 186 ASSERT_TRUE(resizer.get()); |
| 187 EXPECT_FALSE(resizer->drag_window_controller_.get()); |
| 188 |
| 189 // The pointer is inside the primary root. The drag window controller |
| 190 // should be NULL. |
| 191 resizer->Drag(CalculateDragPoint(*resizer, 10, 10), 0); |
| 192 EXPECT_FALSE(resizer->drag_window_controller_.get()); |
| 193 |
| 194 // The window spans both root windows. |
| 195 resizer->Drag(CalculateDragPoint(*resizer, 798, 10), 0); |
| 196 DragWindowController* controller = |
| 197 resizer->drag_window_controller_.get(); |
| 198 ASSERT_TRUE(controller); |
| 199 |
| 200 ASSERT_TRUE(controller->drag_widget_); |
| 201 ui::Layer* drag_layer = |
| 202 controller->drag_widget_->GetNativeWindow()->layer(); |
| 203 ASSERT_TRUE(drag_layer); |
| 204 // Check if |resizer->layer_| is properly set to the drag widget. |
| 205 const std::vector<ui::Layer*>& layers = drag_layer->children(); |
| 206 EXPECT_FALSE(layers.empty()); |
| 207 EXPECT_EQ(controller->layer_, layers.back()); |
| 208 |
| 209 // |window_| should be opaque since the pointer is still on the primary |
| 210 // root window. The drag window should be semi-transparent. |
| 211 EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); |
| 212 ASSERT_TRUE(controller->drag_widget_); |
| 213 EXPECT_GT(1.0f, drag_layer->opacity()); |
| 214 |
| 215 // Enter the pointer to the secondary display. |
| 216 resizer->Drag(CalculateDragPoint(*resizer, 800, 10), 0); |
| 217 controller = resizer->drag_window_controller_.get(); |
| 218 ASSERT_TRUE(controller); |
| 219 // |window_| should be transparent, and the drag window should be opaque. |
| 220 EXPECT_GT(1.0f, window_->layer()->opacity()); |
| 221 EXPECT_FLOAT_EQ(1.0f, drag_layer->opacity()); |
| 222 |
| 223 resizer->CompleteDrag(0); |
| 224 EXPECT_EQ(root_windows[1], window_->GetRootWindow()); |
| 225 EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); |
| 226 } |
| 227 |
| 228 // Do the same test with RevertDrag(). |
| 229 window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), |
| 230 Shell::GetScreen()->GetPrimaryDisplay()); |
| 231 EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| 232 EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); |
| 233 { |
| 234 scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( |
| 235 window_.get(), gfx::Point(), HTCAPTION)); |
| 236 ASSERT_TRUE(resizer.get()); |
| 237 EXPECT_FALSE(resizer->drag_window_controller_.get()); |
| 238 |
| 239 resizer->Drag(CalculateDragPoint(*resizer, 0, 610), 0); |
| 240 resizer->RevertDrag(); |
| 241 EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| 242 EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); |
| 243 } |
| 244 } |
| 245 |
| 246 // Verifies if the resizer sets and resets |
| 247 // MouseCursorEventFilter::mouse_warp_mode_ as expected. |
| 248 TEST_F(DragWindowResizerTest, WarpMousePointer) { |
| 249 MouseCursorEventFilter* event_filter = |
| 250 Shell::GetInstance()->mouse_cursor_filter(); |
| 251 ASSERT_TRUE(event_filter); |
| 252 window_->SetBounds(gfx::Rect(0, 0, 50, 60)); |
| 253 |
| 254 EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, |
| 255 event_filter->mouse_warp_mode_); |
| 256 { |
| 257 scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( |
| 258 window_.get(), gfx::Point(), HTCAPTION)); |
| 259 // While dragging a window, warp should be allowed. |
| 260 EXPECT_EQ(MouseCursorEventFilter::WARP_DRAG, |
| 261 event_filter->mouse_warp_mode_); |
| 262 resizer->CompleteDrag(0); |
| 263 } |
| 264 EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, |
| 265 event_filter->mouse_warp_mode_); |
| 266 |
| 267 { |
| 268 scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( |
| 269 window_.get(), gfx::Point(), HTCAPTION)); |
| 270 EXPECT_EQ(MouseCursorEventFilter::WARP_DRAG, |
| 271 event_filter->mouse_warp_mode_); |
| 272 resizer->RevertDrag(); |
| 273 } |
| 274 EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, |
| 275 event_filter->mouse_warp_mode_); |
| 276 |
| 277 { |
| 278 scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( |
| 279 window_.get(), gfx::Point(), HTRIGHT)); |
| 280 // While resizing a window, warp should NOT be allowed. |
| 281 EXPECT_EQ(MouseCursorEventFilter::WARP_NONE, |
| 282 event_filter->mouse_warp_mode_); |
| 283 resizer->CompleteDrag(0); |
| 284 } |
| 285 EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, |
| 286 event_filter->mouse_warp_mode_); |
| 287 |
| 288 { |
| 289 scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( |
| 290 window_.get(), gfx::Point(), HTRIGHT)); |
| 291 EXPECT_EQ(MouseCursorEventFilter::WARP_NONE, |
| 292 event_filter->mouse_warp_mode_); |
| 293 resizer->RevertDrag(); |
| 294 } |
| 295 EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, |
| 296 event_filter->mouse_warp_mode_); |
| 297 } |
| 298 |
| 299 // Verifies cursor's device scale factor is updated whe a window is moved across |
| 300 // root windows with different device scale factors (http://crbug.com/154183). |
| 301 TEST_F(DragWindowResizerTest, CursorDeviceScaleFactor) { |
| 302 // The secondary display is logically on the right, but on the system (e.g. X) |
| 303 // layer, it's below the primary one. See UpdateDisplay() in ash_test_base.cc. |
| 304 UpdateDisplay("400x400,800x800*2"); |
| 305 shelf_layout_manager()->LayoutShelf(); |
| 306 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); |
| 307 ASSERT_EQ(2U, root_windows.size()); |
| 308 |
| 309 test::CursorManagerTestApi cursor_test_api( |
| 310 Shell::GetInstance()->cursor_manager()); |
| 311 MouseCursorEventFilter* event_filter = |
| 312 Shell::GetInstance()->mouse_cursor_filter(); |
| 313 // Move window from the root window with 1.0 device scale factor to the root |
| 314 // window with 2.0 device scale factor. |
| 315 { |
| 316 window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), |
| 317 Shell::GetScreen()->GetPrimaryDisplay()); |
| 318 EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| 319 // Grab (0, 0) of the window. |
| 320 scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( |
| 321 window_.get(), gfx::Point(), HTCAPTION)); |
| 322 EXPECT_EQ(1.0f, cursor_test_api.GetDeviceScaleFactor()); |
| 323 ASSERT_TRUE(resizer.get()); |
| 324 resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0); |
| 325 event_filter->WarpMouseCursorIfNecessary(root_windows[0], |
| 326 gfx::Point(399, 200)); |
| 327 EXPECT_EQ(2.0f, cursor_test_api.GetDeviceScaleFactor()); |
| 328 resizer->CompleteDrag(0); |
| 329 EXPECT_EQ(2.0f, cursor_test_api.GetDeviceScaleFactor()); |
| 330 } |
| 331 |
| 332 // Move window from the root window with 2.0 device scale factor to the root |
| 333 // window with 1.0 device scale factor. |
| 334 { |
| 335 window_->SetBoundsInScreen( |
| 336 gfx::Rect(600, 0, 50, 60), |
| 337 Shell::GetScreen()->GetDisplayNearestWindow(root_windows[1])); |
| 338 EXPECT_EQ(root_windows[1], window_->GetRootWindow()); |
| 339 // Grab (0, 0) of the window. |
| 340 scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( |
| 341 window_.get(), gfx::Point(), HTCAPTION)); |
| 342 EXPECT_EQ(2.0f, cursor_test_api.GetDeviceScaleFactor()); |
| 343 ASSERT_TRUE(resizer.get()); |
| 344 resizer->Drag(CalculateDragPoint(*resizer, -200, 200), 0); |
| 345 event_filter->WarpMouseCursorIfNecessary(root_windows[1], |
| 346 gfx::Point(400, 200)); |
| 347 EXPECT_EQ(1.0f, cursor_test_api.GetDeviceScaleFactor()); |
| 348 resizer->CompleteDrag(0); |
| 349 EXPECT_EQ(1.0f, cursor_test_api.GetDeviceScaleFactor()); |
| 350 } |
| 351 } |
| 352 |
| 353 } // namespace internal |
| 354 } // namespace ash |
OLD | NEW |