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/display/mouse_cursor_event_filter.h"
6
7#include "ash/shell.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/window_event_dispatcher.h"
14#include "ui/gfx/display.h"
15#include "ui/gfx/screen.h"
16
17namespace ash {
18
19class MouseCursorEventFilterTest : public test::AshTestBase {
20 public:
21  MouseCursorEventFilterTest() {}
22  virtual ~MouseCursorEventFilterTest() {}
23
24 protected:
25  MouseCursorEventFilter* event_filter() {
26    return Shell::GetInstance()->mouse_cursor_filter();
27  }
28
29  bool WarpMouseCursorIfNecessary(aura::Window* target_root,
30                                  gfx::Point point_in_screen) {
31    bool is_warped = event_filter()->WarpMouseCursorIfNecessaryForTest(
32        target_root, point_in_screen);
33    event_filter()->reset_was_mouse_warped_for_test();
34    return is_warped;
35  }
36
37  bool WarpMouseCursorIfNecessaryWithDragRoot(
38      aura::Window* drag_source_root,
39      aura::Window* target_root,
40      gfx::Point point_in_screen) {
41    gfx::Point location = drag_source_root->bounds().CenterPoint();
42    ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, location,
43                           location, 0, 0);
44    ui::Event::DispatcherApi(&pressed).set_target(drag_source_root);
45    event_filter()->OnMouseEvent(&pressed);
46    bool is_warped = event_filter()->WarpMouseCursorIfNecessaryForTest(
47        target_root, point_in_screen);
48    event_filter()->reset_was_mouse_warped_for_test();
49
50    ui::MouseEvent released(ui::ET_MOUSE_RELEASED, location,
51                            location, 0, 0);
52    ui::Event::DispatcherApi(&released).set_target(drag_source_root);
53    event_filter()->OnMouseEvent(&released);
54    return is_warped;
55  }
56
57 private:
58  MouseCursorEventFilter* event_filter_;
59
60  DISALLOW_COPY_AND_ASSIGN(MouseCursorEventFilterTest);
61};
62
63// Verifies if the mouse pointer correctly moves to another display when there
64// are two displays.
65TEST_F(MouseCursorEventFilterTest, WarpMouse) {
66  if (!SupportsMultipleDisplays())
67    return;
68
69  UpdateDisplay("500x500,500x500");
70
71  ASSERT_EQ(
72      DisplayLayout::RIGHT,
73      Shell::GetInstance()->display_manager()->layout_store()->
74          default_display_layout().position);
75
76  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
77  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(11, 11)));
78  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(11, 11)));
79
80  // Touch the right edge of the primary root window. Pointer should warp.
81  EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(499, 11)));
82  EXPECT_EQ("501,11",  // by 2px.
83            aura::Env::GetInstance()->last_mouse_location().ToString());
84
85  // Touch the left edge of the secondary root window. Pointer should warp.
86  EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(500, 11)));
87  EXPECT_EQ("498,11",  // by 2px.
88            aura::Env::GetInstance()->last_mouse_location().ToString());
89
90  // Touch the left edge of the primary root window.
91  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(0, 11)));
92  // Touch the top edge of the primary root window.
93  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(11, 0)));
94  // Touch the bottom edge of the primary root window.
95  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0],
96                                          gfx::Point(11, 499)));
97  // Touch the right edge of the secondary root window.
98  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1],
99                                          gfx::Point(999, 11)));
100  // Touch the top edge of the secondary root window.
101  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(11, 0)));
102  // Touch the bottom edge of the secondary root window.
103  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1],
104                                          gfx::Point(11, 499)));
105}
106
107// Verifies if the mouse pointer correctly moves to another display even when
108// two displays are not the same size.
109TEST_F(MouseCursorEventFilterTest, WarpMouseDifferentSizeDisplays) {
110  if (!SupportsMultipleDisplays())
111    return;
112
113  UpdateDisplay("500x500,600x600");  // the second one is larger.
114
115  ASSERT_EQ(
116      DisplayLayout::RIGHT,
117      Shell::GetInstance()->display_manager()->
118          GetCurrentDisplayLayout().position);
119
120  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
121  aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(623, 123));
122
123  // Touch the left edge of the secondary root window. Pointer should NOT warp
124  // because 1px left of (0, 500) is outside the primary root window.
125  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(0, 500)));
126  EXPECT_EQ("623,123",  // by 2px.
127            aura::Env::GetInstance()->last_mouse_location().ToString());
128
129  // Touch the left edge of the secondary root window. Pointer should warp
130  // because 1px left of (0, 480) is inside the primary root window.
131  EXPECT_TRUE(
132      WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(500, 480)));
133  EXPECT_EQ("498,480",  // by 2px.
134            aura::Env::GetInstance()->last_mouse_location().ToString());
135}
136
137// Verifies if the mouse pointer correctly moves between displays with
138// different scale factors. In native coords mode, there is no
139// difference between drag and move.
140TEST_F(MouseCursorEventFilterTest, WarpMouseDifferentScaleDisplaysInNative) {
141  if (!SupportsMultipleDisplays())
142    return;
143
144  UpdateDisplay("500x500,600x600*2");
145
146  ASSERT_EQ(DisplayLayout::RIGHT,
147            Shell::GetInstance()
148                ->display_manager()
149                ->GetCurrentDisplayLayout()
150                .position);
151
152  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
153  aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(900, 123));
154
155  EXPECT_TRUE(event_filter()->WarpMouseCursorIfNecessaryForTest(
156      root_windows[0], gfx::Point(499, 123)));
157  EXPECT_EQ("500,123",
158            aura::Env::GetInstance()->last_mouse_location().ToString());
159
160  event_filter()->reset_was_mouse_warped_for_test();
161
162  // Touch the edge of 2nd display again and make sure it warps to
163  // 1st dislay.
164  EXPECT_TRUE(event_filter()->WarpMouseCursorIfNecessaryForTest(
165      root_windows[1], gfx::Point(500, 123)));
166  EXPECT_EQ("498,123",
167            aura::Env::GetInstance()->last_mouse_location().ToString());
168}
169
170// Verifies if MouseCursorEventFilter::set_mouse_warp_mode() works as expected.
171TEST_F(MouseCursorEventFilterTest, SetMouseWarpModeFlag) {
172  if (!SupportsMultipleDisplays())
173    return;
174
175  UpdateDisplay("500x500,500x500");
176
177  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
178  aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(1, 1));
179
180  event_filter()->set_mouse_warp_mode(MouseCursorEventFilter::WARP_NONE);
181  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0],
182                                          gfx::Point(499, 11)));
183  EXPECT_EQ("1,1",
184            aura::Env::GetInstance()->last_mouse_location().ToString());
185
186  event_filter()->set_mouse_warp_mode(MouseCursorEventFilter::WARP_ALWAYS);
187  EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(499, 11)));
188  EXPECT_EQ("501,11",
189            aura::Env::GetInstance()->last_mouse_location().ToString());
190}
191
192// Verifies if MouseCursorEventFilter's bounds calculation works correctly.
193TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnRight) {
194  if (!SupportsMultipleDisplays())
195    return;
196
197  UpdateDisplay("360x360,700x700");
198  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
199
200  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
201  DisplayLayout layout(DisplayLayout::RIGHT, 0);
202  display_manager->SetLayoutForCurrentDisplays(layout);
203  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
204  EXPECT_EQ("359,16 1x344", event_filter()->src_indicator_bounds_.ToString());
205  EXPECT_EQ("360,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
206  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
207  EXPECT_EQ("360,16 1x344", event_filter()->src_indicator_bounds_.ToString());
208  EXPECT_EQ("359,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
209
210  // Move 2nd display downwards a bit.
211  layout.offset = 5;
212  display_manager->SetLayoutForCurrentDisplays(layout);
213  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
214  // This is same as before because the 2nd display's y is above
215  // the indicator's x.
216  EXPECT_EQ("359,16 1x344", event_filter()->src_indicator_bounds_.ToString());
217  EXPECT_EQ("360,5 1x355", event_filter()->dst_indicator_bounds_.ToString());
218  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
219  EXPECT_EQ("360,21 1x339", event_filter()->src_indicator_bounds_.ToString());
220  EXPECT_EQ("359,5 1x355", event_filter()->dst_indicator_bounds_.ToString());
221
222  // Move it down further so that the shared edge is shorter than
223  // minimum hole size (160).
224  layout.offset = 200;
225  display_manager->SetLayoutForCurrentDisplays(layout);
226  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
227  EXPECT_EQ("359,200 1x160", event_filter()->src_indicator_bounds_.ToString());
228  EXPECT_EQ("360,200 1x160", event_filter()->dst_indicator_bounds_.ToString());
229  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
230  EXPECT_EQ("360,200 1x160", event_filter()->src_indicator_bounds_.ToString());
231  EXPECT_EQ("359,200 1x160", event_filter()->dst_indicator_bounds_.ToString());
232
233  // Now move 2nd display upwards
234  layout.offset = -5;
235  display_manager->SetLayoutForCurrentDisplays(layout);
236  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
237  EXPECT_EQ("359,16 1x344", event_filter()->src_indicator_bounds_.ToString());
238  EXPECT_EQ("360,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
239  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
240  // 16 px are reserved on 2nd display from top, so y must be
241  // (16 - 5) = 11
242  EXPECT_EQ("360,11 1x349", event_filter()->src_indicator_bounds_.ToString());
243  EXPECT_EQ("359,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
244
245  event_filter()->HideSharedEdgeIndicator();
246}
247
248TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnLeft) {
249  if (!SupportsMultipleDisplays())
250    return;
251
252  UpdateDisplay("360x360,700x700");
253  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
254
255  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
256  DisplayLayout layout(DisplayLayout::LEFT, 0);
257  display_manager->SetLayoutForCurrentDisplays(layout);
258  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
259  EXPECT_EQ("0,16 1x344", event_filter()->src_indicator_bounds_.ToString());
260  EXPECT_EQ("-1,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
261  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
262  EXPECT_EQ("-1,16 1x344", event_filter()->src_indicator_bounds_.ToString());
263  EXPECT_EQ("0,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
264
265  layout.offset = 250;
266  display_manager->SetLayoutForCurrentDisplays(layout);
267  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
268  EXPECT_EQ("0,250 1x110", event_filter()->src_indicator_bounds_.ToString());
269  EXPECT_EQ("-1,250 1x110", event_filter()->dst_indicator_bounds_.ToString());
270  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
271  EXPECT_EQ("-1,250 1x110", event_filter()->src_indicator_bounds_.ToString());
272  EXPECT_EQ("0,250 1x110", event_filter()->dst_indicator_bounds_.ToString());
273  event_filter()->HideSharedEdgeIndicator();
274}
275
276TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnTopBottom) {
277  if (!SupportsMultipleDisplays())
278    return;
279
280  UpdateDisplay("360x360,700x700");
281  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
282
283  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
284  DisplayLayout layout(DisplayLayout::TOP, 0);
285  display_manager->SetLayoutForCurrentDisplays(layout);
286  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
287  EXPECT_EQ("0,0 360x1", event_filter()->src_indicator_bounds_.ToString());
288  EXPECT_EQ("0,-1 360x1", event_filter()->dst_indicator_bounds_.ToString());
289  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
290  EXPECT_EQ("0,-1 360x1", event_filter()->src_indicator_bounds_.ToString());
291  EXPECT_EQ("0,0 360x1", event_filter()->dst_indicator_bounds_.ToString());
292
293  layout.offset = 250;
294  display_manager->SetLayoutForCurrentDisplays(layout);
295  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
296  EXPECT_EQ("250,0 110x1", event_filter()->src_indicator_bounds_.ToString());
297  EXPECT_EQ("250,-1 110x1", event_filter()->dst_indicator_bounds_.ToString());
298  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
299  EXPECT_EQ("250,-1 110x1", event_filter()->src_indicator_bounds_.ToString());
300  EXPECT_EQ("250,0 110x1", event_filter()->dst_indicator_bounds_.ToString());
301
302  layout.position = DisplayLayout::BOTTOM;
303  layout.offset = 0;
304  display_manager->SetLayoutForCurrentDisplays(layout);
305  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
306  EXPECT_EQ("0,359 360x1", event_filter()->src_indicator_bounds_.ToString());
307  EXPECT_EQ("0,360 360x1", event_filter()->dst_indicator_bounds_.ToString());
308  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
309  EXPECT_EQ("0,360 360x1", event_filter()->src_indicator_bounds_.ToString());
310  EXPECT_EQ("0,359 360x1", event_filter()->dst_indicator_bounds_.ToString());
311
312  event_filter()->HideSharedEdgeIndicator();
313}
314
315// Verifies cursor's device scale factor is updated when a cursor has moved
316// across root windows with different device scale factors
317// (http://crbug.com/154183).
318TEST_F(MouseCursorEventFilterTest, CursorDeviceScaleFactor) {
319  if (!SupportsMultipleDisplays())
320    return;
321
322  UpdateDisplay("400x400,800x800*2");
323  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
324  display_manager->SetLayoutForCurrentDisplays(
325      DisplayLayout(DisplayLayout::RIGHT, 0));
326  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
327  ASSERT_EQ(2U, root_windows.size());
328  test::CursorManagerTestApi cursor_test_api(
329      Shell::GetInstance()->cursor_manager());
330
331  EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
332  WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(399, 200));
333  EXPECT_EQ(2.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
334  WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(400, 200));
335  EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
336}
337
338}  // namespace ash
339