blob: 09e1c7af5c455a3203875bab61c40893df3eafd6 [file] [log] [blame]
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001// 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"
Ben Murdoch9ab55632013-07-18 11:57:30 +010015#include "ash/wm/window_util.h"
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +000016#include "base/strings/string_number_conversions.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010017#include "base/strings/stringprintf.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000018#include "ui/aura/client/aura_constants.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000019#include "ui/aura/test/test_window_delegate.h"
Torne (Richard Coles)a1401312014-03-18 10:20:56 +000020#include "ui/aura/window_event_dispatcher.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000021#include "ui/base/hit_test.h"
22#include "ui/base/ui_base_types.h"
Torne (Richard Coles)a1401312014-03-18 10:20:56 +000023#include "ui/compositor/layer_tree_owner.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000024#include "ui/gfx/insets.h"
25#include "ui/gfx/screen.h"
26#include "ui/views/widget/widget.h"
Torne (Richard Coles)a1401312014-03-18 10:20:56 +000027#include "ui/wm/core/window_util.h"
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +000028
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000029namespace ash {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000030namespace {
31
32const int kRootHeight = 600;
33
34} // namespace
35
36class DragWindowResizerTest : public test::AshTestBase {
37 public:
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010038 DragWindowResizerTest() {}
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000039 virtual ~DragWindowResizerTest() {}
40
41 virtual void SetUp() OVERRIDE {
42 AshTestBase::SetUp();
43 UpdateDisplay(base::StringPrintf("800x%d", kRootHeight));
44
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +000045 aura::Window* root = Shell::GetPrimaryRootWindow();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000046 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_));
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000051 window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
52 window_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +000053 ParentWindowInPrimaryRootWindow(window_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000054 window_->set_id(1);
55
56 always_on_top_window_.reset(new aura::Window(&delegate2_));
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000057 always_on_top_window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000058 always_on_top_window_->SetProperty(aura::client::kAlwaysOnTopKey, true);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000059 always_on_top_window_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +000060 ParentWindowInPrimaryRootWindow(always_on_top_window_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000061 always_on_top_window_->set_id(2);
62
63 system_modal_window_.reset(new aura::Window(&delegate3_));
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000064 system_modal_window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000065 system_modal_window_->SetProperty(aura::client::kModalKey,
66 ui::MODAL_TYPE_SYSTEM);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000067 system_modal_window_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +000068 ParentWindowInPrimaryRootWindow(system_modal_window_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000069 system_modal_window_->set_id(3);
70
71 transient_child_ = new aura::Window(&delegate4_);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000072 transient_child_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
73 transient_child_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +000074 ParentWindowInPrimaryRootWindow(transient_child_);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000075 transient_child_->set_id(4);
76
77 transient_parent_.reset(new aura::Window(&delegate5_));
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000078 transient_parent_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
79 transient_parent_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +000080 ParentWindowInPrimaryRootWindow(transient_parent_.get());
Torne (Richard Coles)a1401312014-03-18 10:20:56 +000081 ::wm::AddTransientChild(transient_parent_.get(), transient_child_);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000082 transient_parent_->set_id(5);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010083
84 panel_window_.reset(new aura::Window(&delegate6_));
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000085 panel_window_->SetType(ui::wm::WINDOW_TYPE_PANEL);
86 panel_window_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +000087 ParentWindowInPrimaryRootWindow(panel_window_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000088 }
89
90 virtual void TearDown() OVERRIDE {
91 window_.reset();
92 always_on_top_window_.reset();
93 system_modal_window_.reset();
94 transient_parent_.reset();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010095 panel_window_.reset();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000096 AshTestBase::TearDown();
97 }
98
99 protected:
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100100 gfx::Point CalculateDragPoint(const WindowResizer& resizer,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000101 int delta_x,
102 int delta_y) const {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100103 gfx::Point location = resizer.GetInitialLocation();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000104 location.set_x(location.x() + delta_x);
105 location.set_y(location.y() + delta_y);
106 return location;
107 }
108
Ben Murdochc5cede92014-04-10 11:22:14 +0100109 ShelfLayoutManager* shelf_layout_manager() {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000110 return Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
111 }
112
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100113 static WindowResizer* CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000114 aura::Window* window,
115 const gfx::Point& point_in_parent,
116 int window_component) {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100117 return CreateWindowResizer(
118 window,
119 point_in_parent,
120 window_component,
121 aura::client::WINDOW_MOVE_SOURCE_MOUSE).release();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000122 }
123
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000124 bool WarpMouseCursorIfNecessary(aura::Window* target_root,
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100125 const gfx::Point& point_in_screen) {
126 MouseCursorEventFilter* event_filter =
127 Shell::GetInstance()->mouse_cursor_filter();
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100128 bool is_warped = event_filter->WarpMouseCursorIfNecessaryForTest(
129 target_root, point_in_screen);
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100130 event_filter->reset_was_mouse_warped_for_test();
131 return is_warped;
132 }
133
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000134 aura::test::TestWindowDelegate delegate_;
135 aura::test::TestWindowDelegate delegate2_;
136 aura::test::TestWindowDelegate delegate3_;
137 aura::test::TestWindowDelegate delegate4_;
138 aura::test::TestWindowDelegate delegate5_;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100139 aura::test::TestWindowDelegate delegate6_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000140
141 scoped_ptr<aura::Window> window_;
142 scoped_ptr<aura::Window> always_on_top_window_;
143 scoped_ptr<aura::Window> system_modal_window_;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100144 scoped_ptr<aura::Window> panel_window_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000145 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.
153TEST_F(DragWindowResizerTest, WindowDragWithMultiDisplays) {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100154 if (!SupportsMultipleDisplays())
155 return;
156
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000157 // 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.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000159 UpdateDisplay("800x600,400x300");
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000160 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000161 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.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100168 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000169 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);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000174 resizer->CompleteDrag();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000175 // 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).
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100186 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000187 window_.get(), gfx::Point(), HTCAPTION));
188 ASSERT_TRUE(resizer.get());
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000189 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());
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000192 resizer->CompleteDrag();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000193 // Since the pointer is still on the primary root window, the parent should
194 // not be changed.
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000195 // Window origin should be adjusted for minimum visibility (10px).
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000196 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.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100206 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000207 window_.get(), gfx::Point(49, 0), HTCAPTION));
208 ASSERT_TRUE(resizer.get());
209 resizer->Drag(CalculateDragPoint(*resizer, 751, 10), ui::EF_CONTROL_DOWN);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000210 resizer->CompleteDrag();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000211 // 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());
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000215 // 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());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000219 }
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000220 // 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 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000270}
271
Ben Murdoch9ab55632013-07-18 11:57:30 +0100272// Verifies that dragging the active window to another display makes the new
273// root window the active root window.
274TEST_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");
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000281 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
Ben Murdoch9ab55632013-07-18 11:57:30 +0100282 ASSERT_EQ(2U, root_windows.size());
283
284 aura::test::TestWindowDelegate delegate;
285 scoped_ptr<aura::Window> window(new aura::Window(&delegate));
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000286 window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
287 window->Init(aura::WINDOW_LAYER_TEXTURED);
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +0000288 ParentWindowInPrimaryRootWindow(window.get());
Ben Murdoch9ab55632013-07-18 11:57:30 +0100289 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());
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100295 EXPECT_EQ(root_windows[0], ash::Shell::GetTargetRootWindow());
Ben Murdoch9ab55632013-07-18 11:57:30 +0100296 {
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);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000304 resizer->CompleteDrag();
Ben Murdoch9ab55632013-07-18 11:57:30 +0100305 // The whole window is on the secondary display now. The parent should be
306 // changed.
307 EXPECT_EQ(root_windows[1], window->GetRootWindow());
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100308 EXPECT_EQ(root_windows[1], ash::Shell::GetTargetRootWindow());
Ben Murdoch9ab55632013-07-18 11:57:30 +0100309 }
310}
311
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000312// Verifies a window can be moved from the secondary display to primary.
313TEST_F(DragWindowResizerTest, WindowDragWithMultiDisplaysRightToLeft) {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100314 if (!SupportsMultipleDisplays())
315 return;
316
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000317 UpdateDisplay("800x600,800x600");
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000318 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000319 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.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100327 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000328 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);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000332 resizer->CompleteDrag();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000333 EXPECT_EQ(root_windows[0], window_->GetRootWindow());
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000334 // 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());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000338 }
339}
340
341// Verifies the drag window is shown correctly.
342TEST_F(DragWindowResizerTest, DragWindowController) {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100343 if (!SupportsMultipleDisplays())
344 return;
345
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000346 UpdateDisplay("800x600,800x600");
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000347 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000348 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 {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100355 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000356 window_.get(), gfx::Point(), HTCAPTION));
357 ASSERT_TRUE(resizer.get());
Ben Murdochc5cede92014-04-10 11:22:14 +0100358 DragWindowResizer* drag_resizer = DragWindowResizer::instance_;
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100359 ASSERT_TRUE(drag_resizer);
360 EXPECT_FALSE(drag_resizer->drag_window_controller_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000361
362 // The pointer is inside the primary root. The drag window controller
363 // should be NULL.
364 resizer->Drag(CalculateDragPoint(*resizer, 10, 10), 0);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100365 EXPECT_FALSE(drag_resizer->drag_window_controller_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000366
367 // The window spans both root windows.
368 resizer->Drag(CalculateDragPoint(*resizer, 798, 10), 0);
369 DragWindowController* controller =
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100370 drag_resizer->drag_window_controller_.get();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000371 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());
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000380 EXPECT_EQ(controller->layer_owner_->root(), layers.back());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000381
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);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100390 controller = drag_resizer->drag_window_controller_.get();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000391 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
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000396 resizer->CompleteDrag();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000397 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 {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100407 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000408 window_.get(), gfx::Point(), HTCAPTION));
409 ASSERT_TRUE(resizer.get());
Ben Murdochc5cede92014-04-10 11:22:14 +0100410 DragWindowResizer* drag_resizer = DragWindowResizer::instance_;
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100411 ASSERT_TRUE(drag_resizer);
412 EXPECT_FALSE(drag_resizer->drag_window_controller_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000413
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.
423TEST_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 {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100432 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000433 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_);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000437 resizer->CompleteDrag();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000438 }
439 EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS,
440 event_filter->mouse_warp_mode_);
441
442 {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100443 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000444 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 {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100453 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000454 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_);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000458 resizer->CompleteDrag();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000459 }
460 EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS,
461 event_filter->mouse_warp_mode_);
462
463 {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100464 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000465 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).
476TEST_F(DragWindowResizerTest, CursorDeviceScaleFactor) {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100477 if (!SupportsMultipleDisplays())
478 return;
479
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000480 // 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");
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000483 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000484 ASSERT_EQ(2U, root_windows.size());
485
486 test::CursorManagerTestApi cursor_test_api(
487 Shell::GetInstance()->cursor_manager());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000488 // 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.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100495 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000496 window_.get(), gfx::Point(), HTCAPTION));
Ben Murdoch0529e5d2014-04-24 10:50:13 +0100497 EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000498 ASSERT_TRUE(resizer.get());
499 resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100500 WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(399, 200));
Ben Murdoch0529e5d2014-04-24 10:50:13 +0100501 EXPECT_EQ(2.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000502 resizer->CompleteDrag();
Ben Murdoch0529e5d2014-04-24 10:50:13 +0100503 EXPECT_EQ(2.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000504 }
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 {
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000509 // Make sure the window is on the default container first.
510 aura::Window* default_container =
Ben Murdochc5cede92014-04-10 11:22:14 +0100511 GetRootWindowController(root_windows[1])
512 ->GetContainer(kShellWindowId_DefaultContainer);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000513 default_container->AddChild(window_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000514 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.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100519 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000520 window_.get(), gfx::Point(), HTCAPTION));
Ben Murdoch0529e5d2014-04-24 10:50:13 +0100521 EXPECT_EQ(2.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000522 ASSERT_TRUE(resizer.get());
523 resizer->Drag(CalculateDragPoint(*resizer, -200, 200), 0);
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100524 WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(400, 200));
Ben Murdoch0529e5d2014-04-24 10:50:13 +0100525 EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000526 resizer->CompleteDrag();
Ben Murdoch0529e5d2014-04-24 10:50:13 +0100527 EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000528 }
529}
530
531// Verifies several kinds of windows can be moved across displays.
532TEST_F(DragWindowResizerTest, MoveWindowAcrossDisplays) {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100533 if (!SupportsMultipleDisplays())
534 return;
535
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000536 // 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");
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000539
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000540 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000541 ASSERT_EQ(2U, root_windows.size());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000542
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.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100549 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000550 window, gfx::Point(), HTCAPTION));
551 ASSERT_TRUE(resizer.get());
552 resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100553 EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0],
554 gfx::Point(399, 200)));
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000555 resizer->CompleteDrag();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000556 }
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.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100564 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000565 window, gfx::Point(), HTCAPTION));
566 ASSERT_TRUE(resizer.get());
567 resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100568 EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0],
569 gfx::Point(399, 200)));
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000570 resizer->CompleteDrag();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000571 }
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.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100579 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000580 window, gfx::Point(), HTCAPTION));
581 ASSERT_TRUE(resizer.get());
582 resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100583 EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0],
584 gfx::Point(399, 200)));
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000585 resizer->CompleteDrag();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000586 }
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.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100594 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000595 window, gfx::Point(), HTCAPTION));
596 ASSERT_TRUE(resizer.get());
597 resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100598 EXPECT_FALSE(WarpMouseCursorIfNecessary(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000599 root_windows[0],
600 gfx::Point(399, 200)));
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000601 resizer->CompleteDrag();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000602 }
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.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100610 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000611 window, gfx::Point(), HTCAPTION));
612 ASSERT_TRUE(resizer.get());
613 resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100614 EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0],
615 gfx::Point(399, 200)));
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000616 resizer->CompleteDrag();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000617 }
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100618
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.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100625 scoped_ptr<WindowResizer> resizer(CreateDragWindowResizer(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100626 window, gfx::Point(), HTCAPTION));
627 ASSERT_TRUE(resizer.get());
628 resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0);
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100629 EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0],
630 gfx::Point(399, 200)));
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000631 resizer->CompleteDrag();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100632 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000633}
634
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000635} // namespace ash