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