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.
5 #include "ash/display/mouse_cursor_event_filter.h"
8 #include "ash/test/ash_test_base.h"
9 #include "ash/test/cursor_manager_test_api.h"
10 #include "ash/display/display_layout_store.h"
11 #include "ash/display/display_manager.h"
12 #include "ui/aura/env.h"
13 #include "ui/aura/root_window.h"
14 #include "ui/gfx/display.h"
15 #include "ui/gfx/screen.h"
21 gfx::Display GetPrimaryDisplay() {
22 return Shell::GetScreen()->GetDisplayNearestWindow(
23 Shell::GetAllRootWindows()[0]);
26 gfx::Display GetSecondaryDisplay() {
27 return Shell::GetScreen()->GetDisplayNearestWindow(
28 Shell::GetAllRootWindows()[1]);
33 class MouseCursorEventFilterTest : public test::AshTestBase {
35 MouseCursorEventFilterTest() {}
36 virtual ~MouseCursorEventFilterTest() {}
39 MouseCursorEventFilter* event_filter() {
40 return Shell::GetInstance()->mouse_cursor_filter();
43 bool WarpMouseCursorIfNecessary(aura::RootWindow* target_root,
44 gfx::Point point_in_screen) {
45 bool is_warped = event_filter()->WarpMouseCursorIfNecessary(
46 target_root, point_in_screen);
47 event_filter()->reset_was_mouse_warped_for_test();
51 bool WarpMouseCursorIfNecessaryWithDragRoot(
52 aura::RootWindow* drag_source_root,
53 aura::RootWindow* target_root,
54 gfx::Point point_in_screen) {
55 gfx::Point location = drag_source_root->bounds().CenterPoint();
56 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, location,
58 ui::Event::DispatcherApi(&pressed).set_target(drag_source_root);
59 event_filter()->OnMouseEvent(&pressed);
60 bool is_warped = event_filter()->WarpMouseCursorIfNecessary(
61 target_root, point_in_screen);
62 event_filter()->reset_was_mouse_warped_for_test();
64 ui::MouseEvent released(ui::ET_MOUSE_RELEASED, location,
66 ui::Event::DispatcherApi(&released).set_target(drag_source_root);
67 event_filter()->OnMouseEvent(&released);
72 MouseCursorEventFilter* event_filter_;
74 DISALLOW_COPY_AND_ASSIGN(MouseCursorEventFilterTest);
77 // Verifies if the mouse pointer correctly moves to another display when there
79 TEST_F(MouseCursorEventFilterTest, WarpMouse) {
80 if (!SupportsMultipleDisplays())
83 UpdateDisplay("500x500,500x500");
87 Shell::GetInstance()->display_manager()->layout_store()->
88 default_display_layout().position);
90 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
91 EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(11, 11)));
92 EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(11, 11)));
94 // Touch the right edge of the primary root window. Pointer should warp.
95 EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(499, 11)));
96 EXPECT_EQ("501,11", // by 2px.
97 aura::Env::GetInstance()->last_mouse_location().ToString());
99 // Touch the left edge of the secondary root window. Pointer should warp.
100 EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(500, 11)));
101 EXPECT_EQ("498,11", // by 2px.
102 aura::Env::GetInstance()->last_mouse_location().ToString());
104 // Touch the left edge of the primary root window.
105 EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(0, 11)));
106 // Touch the top edge of the primary root window.
107 EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(11, 0)));
108 // Touch the bottom edge of the primary root window.
109 EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0],
110 gfx::Point(11, 499)));
111 // Touch the right edge of the secondary root window.
112 EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1],
113 gfx::Point(999, 11)));
114 // Touch the top edge of the secondary root window.
115 EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(11, 0)));
116 // Touch the bottom edge of the secondary root window.
117 EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1],
118 gfx::Point(11, 499)));
121 // Verifies if the mouse pointer correctly moves to another display even when
122 // two displays are not the same size.
123 TEST_F(MouseCursorEventFilterTest, WarpMouseDifferentSizeDisplays) {
124 if (!SupportsMultipleDisplays())
127 UpdateDisplay("500x500,600x600"); // the second one is larger.
130 DisplayLayout::RIGHT,
131 Shell::GetInstance()->display_manager()->
132 GetCurrentDisplayLayout().position);
134 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
135 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(623, 123));
137 // Touch the left edge of the secondary root window. Pointer should NOT warp
138 // because 1px left of (0, 500) is outside the primary root window.
139 EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(0, 500)));
140 EXPECT_EQ("623,123", // by 2px.
141 aura::Env::GetInstance()->last_mouse_location().ToString());
143 // Touch the left edge of the secondary root window. Pointer should warp
144 // because 1px left of (0, 499) is inside the primary root window.
145 EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[1],
146 gfx::Point(500, 499)));
147 EXPECT_EQ("498,499", // by 2px.
148 aura::Env::GetInstance()->last_mouse_location().ToString());
151 // Verifies if the mouse pointer correctly moves between displays with
152 // different scale factors.
153 TEST_F(MouseCursorEventFilterTest, WarpMouseDifferentScaleDisplays) {
154 if (!SupportsMultipleDisplays())
157 UpdateDisplay("500x500,600x600*2");
160 DisplayLayout::RIGHT,
161 Shell::GetInstance()->display_manager()->
162 GetCurrentDisplayLayout().position);
164 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
165 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(900, 123));
167 // This emulates the dragging to the 2nd display, which has
168 // higher scale factor, by having 2nd display's root as target
169 // but have the edge of 1st display.
170 EXPECT_TRUE(WarpMouseCursorIfNecessaryWithDragRoot(
171 root_windows[1], root_windows[1], gfx::Point(498, 123)));
173 aura::Env::GetInstance()->last_mouse_location().ToString());
175 // Touch the edge of 2nd display again and make sure it warps to
177 EXPECT_TRUE(WarpMouseCursorIfNecessaryWithDragRoot(
178 root_windows[1], root_windows[1], gfx::Point(500, 123)));
180 aura::Env::GetInstance()->last_mouse_location().ToString());
182 // Draging back from 1x to 2x.
183 EXPECT_TRUE(WarpMouseCursorIfNecessaryWithDragRoot(
184 root_windows[1], root_windows[0], gfx::Point(500, 123)));
186 aura::Env::GetInstance()->last_mouse_location().ToString());
188 UpdateDisplay("500x500*2,600x600");
189 // Draging back from 1x to 2x.
190 EXPECT_TRUE(WarpMouseCursorIfNecessaryWithDragRoot(
191 root_windows[0], root_windows[1], gfx::Point(250, 123)));
193 aura::Env::GetInstance()->last_mouse_location().ToString());
196 TEST_F(MouseCursorEventFilterTest, DoNotWarpTwice) {
197 if (!SupportsMultipleDisplays())
200 UpdateDisplay("500x500,600x600");
202 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
203 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(623, 123));
205 // Touch the right edge of the primary root window. Pointer should warp.
206 EXPECT_TRUE(event_filter()->WarpMouseCursorIfNecessary(root_windows[0],
207 gfx::Point(499, 11)));
208 EXPECT_EQ("501,11", // by 2px.
209 aura::Env::GetInstance()->last_mouse_location().ToString());
211 // Touch the left edge of the secondary root window immediately. This should
213 EXPECT_FALSE(event_filter()->WarpMouseCursorIfNecessary(root_windows[1],
214 gfx::Point(500, 11)));
216 // Touch the left edge of the secondary root window again, pointer should
217 // warp for this time.
218 EXPECT_TRUE(event_filter()->WarpMouseCursorIfNecessary(root_windows[1],
219 gfx::Point(500, 11)));
220 EXPECT_EQ("498,11", // by 2px.
221 aura::Env::GetInstance()->last_mouse_location().ToString());
224 // Verifies if MouseCursorEventFilter::set_mouse_warp_mode() works as expected.
225 TEST_F(MouseCursorEventFilterTest, SetMouseWarpModeFlag) {
226 if (!SupportsMultipleDisplays())
229 UpdateDisplay("500x500,500x500");
231 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
232 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(1, 1));
234 event_filter()->set_mouse_warp_mode(MouseCursorEventFilter::WARP_NONE);
235 EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0],
236 gfx::Point(499, 11)));
238 aura::Env::GetInstance()->last_mouse_location().ToString());
240 event_filter()->set_mouse_warp_mode(MouseCursorEventFilter::WARP_ALWAYS);
241 EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(499, 11)));
243 aura::Env::GetInstance()->last_mouse_location().ToString());
246 // Verifies if MouseCursorEventFilter's bounds calculation works correctly.
247 TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnRight) {
248 if (!SupportsMultipleDisplays())
251 UpdateDisplay("360x360,700x700");
252 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
254 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
255 DisplayLayout layout(DisplayLayout::RIGHT, 0);
256 display_manager->SetLayoutForCurrentDisplays(layout);
257 event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
258 EXPECT_EQ("359,16 1x344", event_filter()->src_indicator_bounds_.ToString());
259 EXPECT_EQ("360,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
260 event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
261 EXPECT_EQ("360,16 1x344", event_filter()->src_indicator_bounds_.ToString());
262 EXPECT_EQ("359,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
264 // Move 2nd display downwards a bit.
266 display_manager->SetLayoutForCurrentDisplays(layout);
267 event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
268 // This is same as before because the 2nd display's y is above
269 // the indicator's x.
270 EXPECT_EQ("359,16 1x344", event_filter()->src_indicator_bounds_.ToString());
271 EXPECT_EQ("360,5 1x355", event_filter()->dst_indicator_bounds_.ToString());
272 event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
273 EXPECT_EQ("360,21 1x339", event_filter()->src_indicator_bounds_.ToString());
274 EXPECT_EQ("359,5 1x355", event_filter()->dst_indicator_bounds_.ToString());
276 // Move it down further so that the shared edge is shorter than
277 // minimum hole size (160).
279 display_manager->SetLayoutForCurrentDisplays(layout);
280 event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
281 EXPECT_EQ("359,200 1x160", event_filter()->src_indicator_bounds_.ToString());
282 EXPECT_EQ("360,200 1x160", event_filter()->dst_indicator_bounds_.ToString());
283 event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
284 EXPECT_EQ("360,200 1x160", event_filter()->src_indicator_bounds_.ToString());
285 EXPECT_EQ("359,200 1x160", event_filter()->dst_indicator_bounds_.ToString());
287 // Now move 2nd display upwards
289 display_manager->SetLayoutForCurrentDisplays(layout);
290 event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
291 EXPECT_EQ("359,16 1x344", event_filter()->src_indicator_bounds_.ToString());
292 EXPECT_EQ("360,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
293 event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
294 // 16 px are reserved on 2nd display from top, so y must be
296 EXPECT_EQ("360,11 1x349", event_filter()->src_indicator_bounds_.ToString());
297 EXPECT_EQ("359,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
299 event_filter()->HideSharedEdgeIndicator();
302 TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnLeft) {
303 if (!SupportsMultipleDisplays())
306 UpdateDisplay("360x360,700x700");
307 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
309 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
310 DisplayLayout layout(DisplayLayout::LEFT, 0);
311 display_manager->SetLayoutForCurrentDisplays(layout);
312 event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
313 EXPECT_EQ("0,16 1x344", event_filter()->src_indicator_bounds_.ToString());
314 EXPECT_EQ("-1,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
315 event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
316 EXPECT_EQ("-1,16 1x344", event_filter()->src_indicator_bounds_.ToString());
317 EXPECT_EQ("0,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
320 display_manager->SetLayoutForCurrentDisplays(layout);
321 event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
322 EXPECT_EQ("0,250 1x110", event_filter()->src_indicator_bounds_.ToString());
323 EXPECT_EQ("-1,250 1x110", event_filter()->dst_indicator_bounds_.ToString());
324 event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
325 EXPECT_EQ("-1,250 1x110", event_filter()->src_indicator_bounds_.ToString());
326 EXPECT_EQ("0,250 1x110", event_filter()->dst_indicator_bounds_.ToString());
327 event_filter()->HideSharedEdgeIndicator();
330 TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnTopBottom) {
331 if (!SupportsMultipleDisplays())
334 UpdateDisplay("360x360,700x700");
335 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
337 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
338 DisplayLayout layout(DisplayLayout::TOP, 0);
339 display_manager->SetLayoutForCurrentDisplays(layout);
340 event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
341 EXPECT_EQ("0,0 360x1", event_filter()->src_indicator_bounds_.ToString());
342 EXPECT_EQ("0,-1 360x1", event_filter()->dst_indicator_bounds_.ToString());
343 event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
344 EXPECT_EQ("0,-1 360x1", event_filter()->src_indicator_bounds_.ToString());
345 EXPECT_EQ("0,0 360x1", event_filter()->dst_indicator_bounds_.ToString());
348 display_manager->SetLayoutForCurrentDisplays(layout);
349 event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
350 EXPECT_EQ("250,0 110x1", event_filter()->src_indicator_bounds_.ToString());
351 EXPECT_EQ("250,-1 110x1", event_filter()->dst_indicator_bounds_.ToString());
352 event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
353 EXPECT_EQ("250,-1 110x1", event_filter()->src_indicator_bounds_.ToString());
354 EXPECT_EQ("250,0 110x1", event_filter()->dst_indicator_bounds_.ToString());
356 layout.position = DisplayLayout::BOTTOM;
358 display_manager->SetLayoutForCurrentDisplays(layout);
359 event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
360 EXPECT_EQ("0,359 360x1", event_filter()->src_indicator_bounds_.ToString());
361 EXPECT_EQ("0,360 360x1", event_filter()->dst_indicator_bounds_.ToString());
362 event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
363 EXPECT_EQ("0,360 360x1", event_filter()->src_indicator_bounds_.ToString());
364 EXPECT_EQ("0,359 360x1", event_filter()->dst_indicator_bounds_.ToString());
366 event_filter()->HideSharedEdgeIndicator();
369 // Verifies cursor's device scale factor is updated when a cursor has moved
370 // across root windows with different device scale factors
371 // (http://crbug.com/154183).
372 TEST_F(MouseCursorEventFilterTest, CursorDeviceScaleFactor) {
373 if (!SupportsMultipleDisplays())
376 UpdateDisplay("400x400,800x800*2");
377 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
378 display_manager->SetLayoutForCurrentDisplays(
379 DisplayLayout(DisplayLayout::RIGHT, 0));
380 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
381 ASSERT_EQ(2U, root_windows.size());
382 test::CursorManagerTestApi cursor_test_api(
383 Shell::GetInstance()->cursor_manager());
385 EXPECT_EQ(1.0f, cursor_test_api.GetDisplay().device_scale_factor());
386 WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(399, 200));
387 EXPECT_EQ(2.0f, cursor_test_api.GetDisplay().device_scale_factor());
388 WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(400, 200));
389 EXPECT_EQ(1.0f, cursor_test_api.GetDisplay().device_scale_factor());
392 } // namespace internal