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 "ui/aura/window_event_dispatcher.h" 6 7 #include <vector> 8 9 #include "base/bind.h" 10 #include "base/run_loop.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 #include "ui/aura/client/capture_client.h" 13 #include "ui/aura/client/event_client.h" 14 #include "ui/aura/client/focus_client.h" 15 #include "ui/aura/env.h" 16 #include "ui/aura/test/aura_test_base.h" 17 #include "ui/aura/test/env_test_helper.h" 18 #include "ui/aura/test/test_cursor_client.h" 19 #include "ui/aura/test/test_screen.h" 20 #include "ui/aura/test/test_window_delegate.h" 21 #include "ui/aura/test/test_windows.h" 22 #include "ui/aura/window.h" 23 #include "ui/aura/window_tracker.h" 24 #include "ui/base/hit_test.h" 25 #include "ui/events/event.h" 26 #include "ui/events/event_handler.h" 27 #include "ui/events/event_utils.h" 28 #include "ui/events/gestures/gesture_configuration.h" 29 #include "ui/events/keycodes/keyboard_codes.h" 30 #include "ui/events/test/event_generator.h" 31 #include "ui/events/test/test_event_handler.h" 32 #include "ui/gfx/point.h" 33 #include "ui/gfx/rect.h" 34 #include "ui/gfx/screen.h" 35 #include "ui/gfx/transform.h" 36 37 namespace aura { 38 namespace { 39 40 // A delegate that always returns a non-client component for hit tests. 41 class NonClientDelegate : public test::TestWindowDelegate { 42 public: 43 NonClientDelegate() 44 : non_client_count_(0), 45 mouse_event_count_(0), 46 mouse_event_flags_(0x0) { 47 } 48 virtual ~NonClientDelegate() {} 49 50 int non_client_count() const { return non_client_count_; } 51 gfx::Point non_client_location() const { return non_client_location_; } 52 int mouse_event_count() const { return mouse_event_count_; } 53 gfx::Point mouse_event_location() const { return mouse_event_location_; } 54 int mouse_event_flags() const { return mouse_event_flags_; } 55 56 virtual int GetNonClientComponent(const gfx::Point& location) const OVERRIDE { 57 NonClientDelegate* self = const_cast<NonClientDelegate*>(this); 58 self->non_client_count_++; 59 self->non_client_location_ = location; 60 return HTTOPLEFT; 61 } 62 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { 63 mouse_event_count_++; 64 mouse_event_location_ = event->location(); 65 mouse_event_flags_ = event->flags(); 66 event->SetHandled(); 67 } 68 69 private: 70 int non_client_count_; 71 gfx::Point non_client_location_; 72 int mouse_event_count_; 73 gfx::Point mouse_event_location_; 74 int mouse_event_flags_; 75 76 DISALLOW_COPY_AND_ASSIGN(NonClientDelegate); 77 }; 78 79 // A simple event handler that consumes key events. 80 class ConsumeKeyHandler : public ui::test::TestEventHandler { 81 public: 82 ConsumeKeyHandler() {} 83 virtual ~ConsumeKeyHandler() {} 84 85 // Overridden from ui::EventHandler: 86 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE { 87 ui::test::TestEventHandler::OnKeyEvent(event); 88 event->StopPropagation(); 89 } 90 91 private: 92 DISALLOW_COPY_AND_ASSIGN(ConsumeKeyHandler); 93 }; 94 95 bool IsFocusedWindow(aura::Window* window) { 96 return client::GetFocusClient(window)->GetFocusedWindow() == window; 97 } 98 99 } // namespace 100 101 typedef test::AuraTestBase WindowEventDispatcherTest; 102 103 TEST_F(WindowEventDispatcherTest, OnHostMouseEvent) { 104 // Create two non-overlapping windows so we don't have to worry about which 105 // is on top. 106 scoped_ptr<NonClientDelegate> delegate1(new NonClientDelegate()); 107 scoped_ptr<NonClientDelegate> delegate2(new NonClientDelegate()); 108 const int kWindowWidth = 123; 109 const int kWindowHeight = 45; 110 gfx::Rect bounds1(100, 200, kWindowWidth, kWindowHeight); 111 gfx::Rect bounds2(300, 400, kWindowWidth, kWindowHeight); 112 scoped_ptr<aura::Window> window1(CreateTestWindowWithDelegate( 113 delegate1.get(), -1234, bounds1, root_window())); 114 scoped_ptr<aura::Window> window2(CreateTestWindowWithDelegate( 115 delegate2.get(), -5678, bounds2, root_window())); 116 117 // Send a mouse event to window1. 118 gfx::Point point(101, 201); 119 ui::MouseEvent event1( 120 ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON, 121 ui::EF_LEFT_MOUSE_BUTTON); 122 DispatchEventUsingWindowDispatcher(&event1); 123 124 // Event was tested for non-client area for the target window. 125 EXPECT_EQ(1, delegate1->non_client_count()); 126 EXPECT_EQ(0, delegate2->non_client_count()); 127 // The non-client component test was in local coordinates. 128 EXPECT_EQ(gfx::Point(1, 1), delegate1->non_client_location()); 129 // Mouse event was received by target window. 130 EXPECT_EQ(1, delegate1->mouse_event_count()); 131 EXPECT_EQ(0, delegate2->mouse_event_count()); 132 // Event was in local coordinates. 133 EXPECT_EQ(gfx::Point(1, 1), delegate1->mouse_event_location()); 134 // Non-client flag was set. 135 EXPECT_TRUE(delegate1->mouse_event_flags() & ui::EF_IS_NON_CLIENT); 136 } 137 138 TEST_F(WindowEventDispatcherTest, RepostEvent) { 139 // Test RepostEvent in RootWindow. It only works for Mouse Press. 140 EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown()); 141 gfx::Point point(10, 10); 142 ui::MouseEvent event( 143 ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON, 144 ui::EF_LEFT_MOUSE_BUTTON); 145 host()->dispatcher()->RepostEvent(event); 146 RunAllPendingInMessageLoop(); 147 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); 148 } 149 150 // Check that we correctly track the state of the mouse buttons in response to 151 // button press and release events. 152 TEST_F(WindowEventDispatcherTest, MouseButtonState) { 153 EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown()); 154 155 gfx::Point location; 156 scoped_ptr<ui::MouseEvent> event; 157 158 // Press the left button. 159 event.reset(new ui::MouseEvent( 160 ui::ET_MOUSE_PRESSED, 161 location, 162 location, 163 ui::EF_LEFT_MOUSE_BUTTON, 164 ui::EF_LEFT_MOUSE_BUTTON)); 165 DispatchEventUsingWindowDispatcher(event.get()); 166 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); 167 168 // Additionally press the right. 169 event.reset(new ui::MouseEvent( 170 ui::ET_MOUSE_PRESSED, 171 location, 172 location, 173 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON, 174 ui::EF_RIGHT_MOUSE_BUTTON)); 175 DispatchEventUsingWindowDispatcher(event.get()); 176 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); 177 178 // Release the left button. 179 event.reset(new ui::MouseEvent( 180 ui::ET_MOUSE_RELEASED, 181 location, 182 location, 183 ui::EF_RIGHT_MOUSE_BUTTON, 184 ui::EF_LEFT_MOUSE_BUTTON)); 185 DispatchEventUsingWindowDispatcher(event.get()); 186 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); 187 188 // Release the right button. We should ignore the Shift-is-down flag. 189 event.reset(new ui::MouseEvent( 190 ui::ET_MOUSE_RELEASED, 191 location, 192 location, 193 ui::EF_SHIFT_DOWN, 194 ui::EF_RIGHT_MOUSE_BUTTON)); 195 DispatchEventUsingWindowDispatcher(event.get()); 196 EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown()); 197 198 // Press the middle button. 199 event.reset(new ui::MouseEvent( 200 ui::ET_MOUSE_PRESSED, 201 location, 202 location, 203 ui::EF_MIDDLE_MOUSE_BUTTON, 204 ui::EF_MIDDLE_MOUSE_BUTTON)); 205 DispatchEventUsingWindowDispatcher(event.get()); 206 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); 207 } 208 209 TEST_F(WindowEventDispatcherTest, TranslatedEvent) { 210 scoped_ptr<Window> w1(test::CreateTestWindowWithDelegate(NULL, 1, 211 gfx::Rect(50, 50, 100, 100), root_window())); 212 213 gfx::Point origin(100, 100); 214 ui::MouseEvent root(ui::ET_MOUSE_PRESSED, origin, origin, 0, 0); 215 216 EXPECT_EQ("100,100", root.location().ToString()); 217 EXPECT_EQ("100,100", root.root_location().ToString()); 218 219 ui::MouseEvent translated_event( 220 root, static_cast<Window*>(root_window()), w1.get(), 221 ui::ET_MOUSE_ENTERED, root.flags()); 222 EXPECT_EQ("50,50", translated_event.location().ToString()); 223 EXPECT_EQ("100,100", translated_event.root_location().ToString()); 224 } 225 226 namespace { 227 228 class TestEventClient : public client::EventClient { 229 public: 230 static const int kNonLockWindowId = 100; 231 static const int kLockWindowId = 200; 232 233 explicit TestEventClient(Window* root_window) 234 : root_window_(root_window), 235 lock_(false) { 236 client::SetEventClient(root_window_, this); 237 Window* lock_window = 238 test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_); 239 lock_window->set_id(kLockWindowId); 240 Window* non_lock_window = 241 test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_); 242 non_lock_window->set_id(kNonLockWindowId); 243 } 244 virtual ~TestEventClient() { 245 client::SetEventClient(root_window_, NULL); 246 } 247 248 // Starts/stops locking. Locking prevents windows other than those inside 249 // the lock container from receiving events, getting focus etc. 250 void Lock() { 251 lock_ = true; 252 } 253 void Unlock() { 254 lock_ = false; 255 } 256 257 Window* GetLockWindow() { 258 return const_cast<Window*>( 259 static_cast<const TestEventClient*>(this)->GetLockWindow()); 260 } 261 const Window* GetLockWindow() const { 262 return root_window_->GetChildById(kLockWindowId); 263 } 264 Window* GetNonLockWindow() { 265 return root_window_->GetChildById(kNonLockWindowId); 266 } 267 268 private: 269 // Overridden from client::EventClient: 270 virtual bool CanProcessEventsWithinSubtree( 271 const Window* window) const OVERRIDE { 272 return lock_ ? 273 window->Contains(GetLockWindow()) || GetLockWindow()->Contains(window) : 274 true; 275 } 276 277 virtual ui::EventTarget* GetToplevelEventTarget() OVERRIDE { 278 return NULL; 279 } 280 281 Window* root_window_; 282 bool lock_; 283 284 DISALLOW_COPY_AND_ASSIGN(TestEventClient); 285 }; 286 287 } // namespace 288 289 TEST_F(WindowEventDispatcherTest, CanProcessEventsWithinSubtree) { 290 TestEventClient client(root_window()); 291 test::TestWindowDelegate d; 292 293 ui::test::TestEventHandler nonlock_ef; 294 ui::test::TestEventHandler lock_ef; 295 client.GetNonLockWindow()->AddPreTargetHandler(&nonlock_ef); 296 client.GetLockWindow()->AddPreTargetHandler(&lock_ef); 297 298 Window* w1 = test::CreateTestWindowWithBounds(gfx::Rect(10, 10, 20, 20), 299 client.GetNonLockWindow()); 300 w1->set_id(1); 301 Window* w2 = test::CreateTestWindowWithBounds(gfx::Rect(30, 30, 20, 20), 302 client.GetNonLockWindow()); 303 w2->set_id(2); 304 scoped_ptr<Window> w3( 305 test::CreateTestWindowWithDelegate(&d, 3, gfx::Rect(30, 30, 20, 20), 306 client.GetLockWindow())); 307 308 w1->Focus(); 309 EXPECT_TRUE(IsFocusedWindow(w1)); 310 311 client.Lock(); 312 313 // Since we're locked, the attempt to focus w2 will be ignored. 314 w2->Focus(); 315 EXPECT_TRUE(IsFocusedWindow(w1)); 316 EXPECT_FALSE(IsFocusedWindow(w2)); 317 318 { 319 // Attempting to send a key event to w1 (not in the lock container) should 320 // cause focus to be reset. 321 ui::test::EventGenerator generator(root_window()); 322 generator.PressKey(ui::VKEY_SPACE, 0); 323 EXPECT_EQ(NULL, client::GetFocusClient(w1)->GetFocusedWindow()); 324 EXPECT_FALSE(IsFocusedWindow(w1)); 325 } 326 327 { 328 // Events sent to a window not in the lock container will not be processed. 329 // i.e. never sent to the non-lock container's event filter. 330 ui::test::EventGenerator generator(root_window(), w1); 331 generator.ClickLeftButton(); 332 EXPECT_EQ(0, nonlock_ef.num_mouse_events()); 333 334 // Events sent to a window in the lock container will be processed. 335 ui::test::EventGenerator generator3(root_window(), w3.get()); 336 generator3.PressLeftButton(); 337 EXPECT_EQ(1, lock_ef.num_mouse_events()); 338 } 339 340 // Prevent w3 from being deleted by the hierarchy since its delegate is owned 341 // by this scope. 342 w3->parent()->RemoveChild(w3.get()); 343 } 344 345 TEST_F(WindowEventDispatcherTest, IgnoreUnknownKeys) { 346 ConsumeKeyHandler handler; 347 root_window()->AddPreTargetHandler(&handler); 348 349 ui::KeyEvent unknown_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, ui::EF_NONE); 350 DispatchEventUsingWindowDispatcher(&unknown_event); 351 EXPECT_FALSE(unknown_event.handled()); 352 EXPECT_EQ(0, handler.num_key_events()); 353 354 handler.Reset(); 355 ui::KeyEvent known_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE); 356 DispatchEventUsingWindowDispatcher(&known_event); 357 EXPECT_TRUE(known_event.handled()); 358 EXPECT_EQ(1, handler.num_key_events()); 359 360 handler.Reset(); 361 ui::KeyEvent ime_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, 362 ui::EF_IME_FABRICATED_KEY); 363 DispatchEventUsingWindowDispatcher(&ime_event); 364 EXPECT_TRUE(ime_event.handled()); 365 EXPECT_EQ(1, handler.num_key_events()); 366 367 handler.Reset(); 368 ui::KeyEvent unknown_key_with_char_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, 369 ui::EF_NONE); 370 unknown_key_with_char_event.set_character(0x00e4 /* "" */); 371 DispatchEventUsingWindowDispatcher(&unknown_key_with_char_event); 372 EXPECT_TRUE(unknown_key_with_char_event.handled()); 373 EXPECT_EQ(1, handler.num_key_events()); 374 } 375 376 TEST_F(WindowEventDispatcherTest, NoDelegateWindowReceivesKeyEvents) { 377 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL)); 378 w1->Show(); 379 w1->Focus(); 380 381 ui::test::TestEventHandler handler; 382 w1->AddPreTargetHandler(&handler); 383 ui::KeyEvent key_press(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE); 384 DispatchEventUsingWindowDispatcher(&key_press); 385 EXPECT_TRUE(key_press.handled()); 386 EXPECT_EQ(1, handler.num_key_events()); 387 388 w1->RemovePreTargetHandler(&handler); 389 } 390 391 // Tests that touch-events that are beyond the bounds of the root-window do get 392 // propagated to the event filters correctly with the root as the target. 393 TEST_F(WindowEventDispatcherTest, TouchEventsOutsideBounds) { 394 ui::test::TestEventHandler handler; 395 root_window()->AddPreTargetHandler(&handler); 396 397 gfx::Point position = root_window()->bounds().origin(); 398 position.Offset(-10, -10); 399 ui::TouchEvent press( 400 ui::ET_TOUCH_PRESSED, position, 0, ui::EventTimeForNow()); 401 DispatchEventUsingWindowDispatcher(&press); 402 EXPECT_EQ(1, handler.num_touch_events()); 403 404 position = root_window()->bounds().origin(); 405 position.Offset(root_window()->bounds().width() + 10, 406 root_window()->bounds().height() + 10); 407 ui::TouchEvent release( 408 ui::ET_TOUCH_RELEASED, position, 0, ui::EventTimeForNow()); 409 DispatchEventUsingWindowDispatcher(&release); 410 EXPECT_EQ(2, handler.num_touch_events()); 411 } 412 413 // Tests that scroll events are dispatched correctly. 414 TEST_F(WindowEventDispatcherTest, ScrollEventDispatch) { 415 base::TimeDelta now = ui::EventTimeForNow(); 416 ui::test::TestEventHandler handler; 417 root_window()->AddPreTargetHandler(&handler); 418 419 test::TestWindowDelegate delegate; 420 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate)); 421 w1->SetBounds(gfx::Rect(20, 20, 40, 40)); 422 423 // A scroll event on the root-window itself is dispatched. 424 ui::ScrollEvent scroll1(ui::ET_SCROLL, 425 gfx::Point(10, 10), 426 now, 427 0, 428 0, -10, 429 0, -10, 430 2); 431 DispatchEventUsingWindowDispatcher(&scroll1); 432 EXPECT_EQ(1, handler.num_scroll_events()); 433 434 // Scroll event on a window should be dispatched properly. 435 ui::ScrollEvent scroll2(ui::ET_SCROLL, 436 gfx::Point(25, 30), 437 now, 438 0, 439 -10, 0, 440 -10, 0, 441 2); 442 DispatchEventUsingWindowDispatcher(&scroll2); 443 EXPECT_EQ(2, handler.num_scroll_events()); 444 root_window()->RemovePreTargetHandler(&handler); 445 } 446 447 namespace { 448 449 // FilterFilter that tracks the types of events it's seen. 450 class EventFilterRecorder : public ui::EventHandler { 451 public: 452 typedef std::vector<ui::EventType> Events; 453 typedef std::vector<gfx::Point> EventLocations; 454 typedef std::vector<int> EventFlags; 455 456 EventFilterRecorder() 457 : wait_until_event_(ui::ET_UNKNOWN) { 458 } 459 460 const Events& events() const { return events_; } 461 462 const EventLocations& mouse_locations() const { return mouse_locations_; } 463 gfx::Point mouse_location(int i) const { return mouse_locations_[i]; } 464 const EventLocations& touch_locations() const { return touch_locations_; } 465 const EventLocations& gesture_locations() const { return gesture_locations_; } 466 const EventFlags& mouse_event_flags() const { return mouse_event_flags_; } 467 468 void WaitUntilReceivedEvent(ui::EventType type) { 469 wait_until_event_ = type; 470 run_loop_.reset(new base::RunLoop()); 471 run_loop_->Run(); 472 } 473 474 Events GetAndResetEvents() { 475 Events events = events_; 476 Reset(); 477 return events; 478 } 479 480 void Reset() { 481 events_.clear(); 482 mouse_locations_.clear(); 483 touch_locations_.clear(); 484 gesture_locations_.clear(); 485 mouse_event_flags_.clear(); 486 } 487 488 // ui::EventHandler overrides: 489 virtual void OnEvent(ui::Event* event) OVERRIDE { 490 ui::EventHandler::OnEvent(event); 491 events_.push_back(event->type()); 492 if (wait_until_event_ == event->type() && run_loop_) { 493 run_loop_->Quit(); 494 wait_until_event_ = ui::ET_UNKNOWN; 495 } 496 } 497 498 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { 499 mouse_locations_.push_back(event->location()); 500 mouse_event_flags_.push_back(event->flags()); 501 } 502 503 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE { 504 touch_locations_.push_back(event->location()); 505 } 506 507 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 508 gesture_locations_.push_back(event->location()); 509 } 510 511 bool HasReceivedEvent(ui::EventType type) { 512 return std::find(events_.begin(), events_.end(), type) != events_.end(); 513 } 514 515 private: 516 scoped_ptr<base::RunLoop> run_loop_; 517 ui::EventType wait_until_event_; 518 519 Events events_; 520 EventLocations mouse_locations_; 521 EventLocations touch_locations_; 522 EventLocations gesture_locations_; 523 EventFlags mouse_event_flags_; 524 525 DISALLOW_COPY_AND_ASSIGN(EventFilterRecorder); 526 }; 527 528 // Converts an EventType to a string. 529 std::string EventTypeToString(ui::EventType type) { 530 switch (type) { 531 case ui::ET_TOUCH_RELEASED: 532 return "TOUCH_RELEASED"; 533 534 case ui::ET_TOUCH_CANCELLED: 535 return "TOUCH_CANCELLED"; 536 537 case ui::ET_TOUCH_PRESSED: 538 return "TOUCH_PRESSED"; 539 540 case ui::ET_TOUCH_MOVED: 541 return "TOUCH_MOVED"; 542 543 case ui::ET_MOUSE_PRESSED: 544 return "MOUSE_PRESSED"; 545 546 case ui::ET_MOUSE_DRAGGED: 547 return "MOUSE_DRAGGED"; 548 549 case ui::ET_MOUSE_RELEASED: 550 return "MOUSE_RELEASED"; 551 552 case ui::ET_MOUSE_MOVED: 553 return "MOUSE_MOVED"; 554 555 case ui::ET_MOUSE_ENTERED: 556 return "MOUSE_ENTERED"; 557 558 case ui::ET_MOUSE_EXITED: 559 return "MOUSE_EXITED"; 560 561 case ui::ET_GESTURE_SCROLL_BEGIN: 562 return "GESTURE_SCROLL_BEGIN"; 563 564 case ui::ET_GESTURE_SCROLL_END: 565 return "GESTURE_SCROLL_END"; 566 567 case ui::ET_GESTURE_SCROLL_UPDATE: 568 return "GESTURE_SCROLL_UPDATE"; 569 570 case ui::ET_GESTURE_PINCH_BEGIN: 571 return "GESTURE_PINCH_BEGIN"; 572 573 case ui::ET_GESTURE_PINCH_END: 574 return "GESTURE_PINCH_END"; 575 576 case ui::ET_GESTURE_PINCH_UPDATE: 577 return "GESTURE_PINCH_UPDATE"; 578 579 case ui::ET_GESTURE_TAP: 580 return "GESTURE_TAP"; 581 582 case ui::ET_GESTURE_TAP_DOWN: 583 return "GESTURE_TAP_DOWN"; 584 585 case ui::ET_GESTURE_TAP_CANCEL: 586 return "GESTURE_TAP_CANCEL"; 587 588 case ui::ET_GESTURE_SHOW_PRESS: 589 return "GESTURE_SHOW_PRESS"; 590 591 case ui::ET_GESTURE_BEGIN: 592 return "GESTURE_BEGIN"; 593 594 case ui::ET_GESTURE_END: 595 return "GESTURE_END"; 596 597 default: 598 // We should explicitly require each event type. 599 NOTREACHED() << "Received unexpected event: " << type; 600 break; 601 } 602 return ""; 603 } 604 605 std::string EventTypesToString(const EventFilterRecorder::Events& events) { 606 std::string result; 607 for (size_t i = 0; i < events.size(); ++i) { 608 if (i != 0) 609 result += " "; 610 result += EventTypeToString(events[i]); 611 } 612 return result; 613 } 614 615 } // namespace 616 617 #if defined(OS_WIN) && defined(ARCH_CPU_X86) 618 #define MAYBE(x) DISABLED_##x 619 #else 620 #define MAYBE(x) x 621 #endif 622 623 // Verifies a repost mouse event targets the window with capture (if there is 624 // one). 625 // Flaky on 32-bit Windows bots. http://crbug.com/388290 626 TEST_F(WindowEventDispatcherTest, MAYBE(RepostTargetsCaptureWindow)) { 627 // Set capture on |window| generate a mouse event (that is reposted) and not 628 // over |window| and verify |window| gets it (|window| gets it because it has 629 // capture). 630 EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown()); 631 EventFilterRecorder recorder; 632 scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), NULL)); 633 window->SetBounds(gfx::Rect(20, 20, 40, 30)); 634 window->AddPreTargetHandler(&recorder); 635 window->SetCapture(); 636 const ui::MouseEvent press_event( 637 ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), 638 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); 639 host()->dispatcher()->RepostEvent(press_event); 640 RunAllPendingInMessageLoop(); // Necessitated by RepostEvent(). 641 // Mouse moves/enters may be generated. We only care about a pressed. 642 EXPECT_TRUE(EventTypesToString(recorder.events()).find("MOUSE_PRESSED") != 643 std::string::npos) << EventTypesToString(recorder.events()); 644 } 645 646 TEST_F(WindowEventDispatcherTest, MouseMovesHeld) { 647 EventFilterRecorder recorder; 648 root_window()->AddPreTargetHandler(&recorder); 649 650 test::TestWindowDelegate delegate; 651 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 652 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); 653 654 ui::MouseEvent mouse_move_event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0), 655 gfx::Point(0, 0), 0, 0); 656 DispatchEventUsingWindowDispatcher(&mouse_move_event); 657 // Discard MOUSE_ENTER. 658 recorder.Reset(); 659 660 host()->dispatcher()->HoldPointerMoves(); 661 662 // Check that we don't immediately dispatch the MOUSE_DRAGGED event. 663 ui::MouseEvent mouse_dragged_event(ui::ET_MOUSE_DRAGGED, gfx::Point(0, 0), 664 gfx::Point(0, 0), 0, 0); 665 DispatchEventUsingWindowDispatcher(&mouse_dragged_event); 666 EXPECT_TRUE(recorder.events().empty()); 667 668 // Check that we do dispatch the held MOUSE_DRAGGED event before another type 669 // of event. 670 ui::MouseEvent mouse_pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(0, 0), 671 gfx::Point(0, 0), 0, 0); 672 DispatchEventUsingWindowDispatcher(&mouse_pressed_event); 673 EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED", 674 EventTypesToString(recorder.events())); 675 recorder.Reset(); 676 677 // Check that we coalesce held MOUSE_DRAGGED events. 678 ui::MouseEvent mouse_dragged_event2(ui::ET_MOUSE_DRAGGED, gfx::Point(10, 10), 679 gfx::Point(10, 10), 0, 0); 680 DispatchEventUsingWindowDispatcher(&mouse_dragged_event); 681 DispatchEventUsingWindowDispatcher(&mouse_dragged_event2); 682 EXPECT_TRUE(recorder.events().empty()); 683 DispatchEventUsingWindowDispatcher(&mouse_pressed_event); 684 EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED", 685 EventTypesToString(recorder.events())); 686 recorder.Reset(); 687 688 // Check that on ReleasePointerMoves, held events are not dispatched 689 // immediately, but posted instead. 690 DispatchEventUsingWindowDispatcher(&mouse_dragged_event); 691 host()->dispatcher()->ReleasePointerMoves(); 692 EXPECT_TRUE(recorder.events().empty()); 693 RunAllPendingInMessageLoop(); 694 EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(recorder.events())); 695 recorder.Reset(); 696 697 // However if another message comes in before the dispatch of the posted 698 // event, check that the posted event is dispatched before this new event. 699 host()->dispatcher()->HoldPointerMoves(); 700 DispatchEventUsingWindowDispatcher(&mouse_dragged_event); 701 host()->dispatcher()->ReleasePointerMoves(); 702 DispatchEventUsingWindowDispatcher(&mouse_pressed_event); 703 EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED", 704 EventTypesToString(recorder.events())); 705 recorder.Reset(); 706 RunAllPendingInMessageLoop(); 707 EXPECT_TRUE(recorder.events().empty()); 708 709 // Check that if the other message is another MOUSE_DRAGGED, we still coalesce 710 // them. 711 host()->dispatcher()->HoldPointerMoves(); 712 DispatchEventUsingWindowDispatcher(&mouse_dragged_event); 713 host()->dispatcher()->ReleasePointerMoves(); 714 DispatchEventUsingWindowDispatcher(&mouse_dragged_event2); 715 EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(recorder.events())); 716 recorder.Reset(); 717 RunAllPendingInMessageLoop(); 718 EXPECT_TRUE(recorder.events().empty()); 719 720 // Check that synthetic mouse move event has a right location when issued 721 // while holding pointer moves. 722 ui::MouseEvent mouse_dragged_event3(ui::ET_MOUSE_DRAGGED, gfx::Point(28, 28), 723 gfx::Point(28, 28), 0, 0); 724 host()->dispatcher()->HoldPointerMoves(); 725 DispatchEventUsingWindowDispatcher(&mouse_dragged_event); 726 DispatchEventUsingWindowDispatcher(&mouse_dragged_event2); 727 window->SetBounds(gfx::Rect(15, 15, 80, 80)); 728 DispatchEventUsingWindowDispatcher(&mouse_dragged_event3); 729 RunAllPendingInMessageLoop(); 730 EXPECT_TRUE(recorder.events().empty()); 731 host()->dispatcher()->ReleasePointerMoves(); 732 RunAllPendingInMessageLoop(); 733 EXPECT_EQ("MOUSE_MOVED", EventTypesToString(recorder.events())); 734 EXPECT_EQ(gfx::Point(13, 13), recorder.mouse_location(0)); 735 recorder.Reset(); 736 root_window()->RemovePreTargetHandler(&recorder); 737 } 738 739 TEST_F(WindowEventDispatcherTest, TouchMovesHeld) { 740 EventFilterRecorder recorder; 741 root_window()->AddPreTargetHandler(&recorder); 742 743 test::TestWindowDelegate delegate; 744 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 745 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window())); 746 747 // Starting the touch and throwing out the first few events, since the system 748 // is going to generate synthetic mouse events that are not relevant to the 749 // test. 750 ui::TouchEvent touch_pressed_event( 751 ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, ui::EventTimeForNow()); 752 DispatchEventUsingWindowDispatcher(&touch_pressed_event); 753 recorder.WaitUntilReceivedEvent(ui::ET_GESTURE_SHOW_PRESS); 754 recorder.Reset(); 755 756 host()->dispatcher()->HoldPointerMoves(); 757 758 // Check that we don't immediately dispatch the TOUCH_MOVED event. 759 ui::TouchEvent touch_moved_event( 760 ui::ET_TOUCH_MOVED, gfx::Point(10, 10), 0, ui::EventTimeForNow()); 761 ui::TouchEvent touch_moved_event2( 762 ui::ET_TOUCH_MOVED, gfx::Point(11, 10), 0, ui::EventTimeForNow()); 763 ui::TouchEvent touch_moved_event3( 764 ui::ET_TOUCH_MOVED, gfx::Point(12, 10), 0, ui::EventTimeForNow()); 765 766 DispatchEventUsingWindowDispatcher(&touch_moved_event); 767 EXPECT_TRUE(recorder.events().empty()); 768 769 // Check that on ReleasePointerMoves, held events are not dispatched 770 // immediately, but posted instead. 771 DispatchEventUsingWindowDispatcher(&touch_moved_event2); 772 host()->dispatcher()->ReleasePointerMoves(); 773 EXPECT_TRUE(recorder.events().empty()); 774 775 RunAllPendingInMessageLoop(); 776 EXPECT_EQ("TOUCH_MOVED", EventTypesToString(recorder.events())); 777 recorder.Reset(); 778 779 // If another touch event occurs then the held touch should be dispatched 780 // immediately before it. 781 ui::TouchEvent touch_released_event( 782 ui::ET_TOUCH_RELEASED, gfx::Point(10, 10), 0, ui::EventTimeForNow()); 783 recorder.Reset(); 784 host()->dispatcher()->HoldPointerMoves(); 785 DispatchEventUsingWindowDispatcher(&touch_moved_event3); 786 DispatchEventUsingWindowDispatcher(&touch_released_event); 787 EXPECT_EQ("TOUCH_MOVED TOUCH_RELEASED GESTURE_TAP GESTURE_END", 788 EventTypesToString(recorder.events())); 789 recorder.Reset(); 790 host()->dispatcher()->ReleasePointerMoves(); 791 RunAllPendingInMessageLoop(); 792 EXPECT_TRUE(recorder.events().empty()); 793 } 794 795 // Verifies that a direct call to ProcessedTouchEvent() with a 796 // TOUCH_PRESSED event does not cause a crash. 797 TEST_F(WindowEventDispatcherTest, CallToProcessedTouchEvent) { 798 test::TestWindowDelegate delegate; 799 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 800 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window())); 801 802 ui::TouchEvent touch( 803 ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1, ui::EventTimeForNow()); 804 host()->dispatcher()->ProcessedTouchEvent( 805 &touch, window.get(), ui::ER_UNHANDLED); 806 } 807 808 // This event handler requests the dispatcher to start holding pointer-move 809 // events when it receives the first scroll-update gesture. 810 class HoldPointerOnScrollHandler : public ui::test::TestEventHandler { 811 public: 812 HoldPointerOnScrollHandler(WindowEventDispatcher* dispatcher, 813 EventFilterRecorder* filter) 814 : dispatcher_(dispatcher), 815 filter_(filter), 816 holding_moves_(false) {} 817 virtual ~HoldPointerOnScrollHandler() {} 818 819 private: 820 // ui::test::TestEventHandler: 821 virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE { 822 if (!holding_moves_ && gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) { 823 holding_moves_ = true; 824 dispatcher_->HoldPointerMoves(); 825 filter_->Reset(); 826 } else if (gesture->type() == ui::ET_GESTURE_SCROLL_END) { 827 dispatcher_->ReleasePointerMoves(); 828 holding_moves_ = false; 829 } 830 } 831 832 WindowEventDispatcher* dispatcher_; 833 EventFilterRecorder* filter_; 834 bool holding_moves_; 835 836 DISALLOW_COPY_AND_ASSIGN(HoldPointerOnScrollHandler); 837 }; 838 839 // Tests that touch-move events don't contribute to an in-progress scroll 840 // gesture if touch-move events are being held by the dispatcher. 841 TEST_F(WindowEventDispatcherTest, TouchMovesHeldOnScroll) { 842 EventFilterRecorder recorder; 843 root_window()->AddPreTargetHandler(&recorder); 844 test::TestWindowDelegate delegate; 845 HoldPointerOnScrollHandler handler(host()->dispatcher(), &recorder); 846 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 847 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window())); 848 window->AddPreTargetHandler(&handler); 849 850 ui::test::EventGenerator generator(root_window()); 851 generator.GestureScrollSequence( 852 gfx::Point(60, 60), gfx::Point(10, 60), 853 base::TimeDelta::FromMilliseconds(100), 25); 854 855 // |handler| will have reset |filter| and started holding the touch-move 856 // events when scrolling started. At the end of the scroll (i.e. upon 857 // touch-release), the held touch-move event will have been dispatched first, 858 // along with the subsequent events (i.e. touch-release, scroll-end, and 859 // gesture-end). 860 const EventFilterRecorder::Events& events = recorder.events(); 861 EXPECT_EQ( 862 "TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED " 863 "GESTURE_SCROLL_END GESTURE_END", 864 EventTypesToString(events)); 865 ASSERT_EQ(2u, recorder.touch_locations().size()); 866 EXPECT_EQ(gfx::Point(-40, 10).ToString(), 867 recorder.touch_locations()[0].ToString()); 868 EXPECT_EQ(gfx::Point(-40, 10).ToString(), 869 recorder.touch_locations()[1].ToString()); 870 } 871 872 // Tests that a 'held' touch-event does contribute to gesture event when it is 873 // dispatched. 874 TEST_F(WindowEventDispatcherTest, HeldTouchMoveContributesToGesture) { 875 EventFilterRecorder recorder; 876 root_window()->AddPreTargetHandler(&recorder); 877 878 const gfx::Point location(20, 20); 879 ui::TouchEvent press( 880 ui::ET_TOUCH_PRESSED, location, 0, ui::EventTimeForNow()); 881 DispatchEventUsingWindowDispatcher(&press); 882 EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_TOUCH_PRESSED)); 883 recorder.Reset(); 884 885 host()->dispatcher()->HoldPointerMoves(); 886 887 ui::TouchEvent move(ui::ET_TOUCH_MOVED, 888 location + gfx::Vector2d(100, 100), 889 0, 890 ui::EventTimeForNow()); 891 DispatchEventUsingWindowDispatcher(&move); 892 EXPECT_FALSE(recorder.HasReceivedEvent(ui::ET_TOUCH_MOVED)); 893 EXPECT_FALSE(recorder.HasReceivedEvent(ui::ET_GESTURE_SCROLL_BEGIN)); 894 recorder.Reset(); 895 896 host()->dispatcher()->ReleasePointerMoves(); 897 EXPECT_FALSE(recorder.HasReceivedEvent(ui::ET_TOUCH_MOVED)); 898 RunAllPendingInMessageLoop(); 899 EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_TOUCH_MOVED)); 900 EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_SCROLL_BEGIN)); 901 EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_SCROLL_UPDATE)); 902 903 root_window()->RemovePreTargetHandler(&recorder); 904 } 905 906 // Tests that synthetic mouse events are ignored when mouse 907 // events are disabled. 908 TEST_F(WindowEventDispatcherTest, DispatchSyntheticMouseEvents) { 909 EventFilterRecorder recorder; 910 root_window()->AddPreTargetHandler(&recorder); 911 912 test::TestWindowDelegate delegate; 913 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 914 &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window())); 915 window->Show(); 916 window->SetCapture(); 917 918 test::TestCursorClient cursor_client(root_window()); 919 920 // Dispatch a non-synthetic mouse event when mouse events are enabled. 921 ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, gfx::Point(10, 10), 922 gfx::Point(10, 10), 0, 0); 923 DispatchEventUsingWindowDispatcher(&mouse1); 924 EXPECT_FALSE(recorder.events().empty()); 925 recorder.Reset(); 926 927 // Dispatch a synthetic mouse event when mouse events are enabled. 928 ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, gfx::Point(10, 10), 929 gfx::Point(10, 10), ui::EF_IS_SYNTHESIZED, 0); 930 DispatchEventUsingWindowDispatcher(&mouse2); 931 EXPECT_FALSE(recorder.events().empty()); 932 recorder.Reset(); 933 934 // Dispatch a synthetic mouse event when mouse events are disabled. 935 cursor_client.DisableMouseEvents(); 936 DispatchEventUsingWindowDispatcher(&mouse2); 937 EXPECT_TRUE(recorder.events().empty()); 938 root_window()->RemovePreTargetHandler(&recorder); 939 } 940 941 // Tests that a mouse-move event is not synthesized when a mouse-button is down. 942 TEST_F(WindowEventDispatcherTest, DoNotSynthesizeWhileButtonDown) { 943 EventFilterRecorder recorder; 944 test::TestWindowDelegate delegate; 945 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 946 &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window())); 947 window->Show(); 948 949 window->AddPreTargetHandler(&recorder); 950 // Dispatch a non-synthetic mouse event when mouse events are enabled. 951 ui::MouseEvent mouse1(ui::ET_MOUSE_PRESSED, gfx::Point(10, 10), 952 gfx::Point(10, 10), ui::EF_LEFT_MOUSE_BUTTON, 953 ui::EF_LEFT_MOUSE_BUTTON); 954 DispatchEventUsingWindowDispatcher(&mouse1); 955 ASSERT_EQ(1u, recorder.events().size()); 956 EXPECT_EQ(ui::ET_MOUSE_PRESSED, recorder.events()[0]); 957 window->RemovePreTargetHandler(&recorder); 958 recorder.Reset(); 959 960 // Move |window| away from underneath the cursor. 961 root_window()->AddPreTargetHandler(&recorder); 962 window->SetBounds(gfx::Rect(30, 30, 100, 100)); 963 EXPECT_TRUE(recorder.events().empty()); 964 RunAllPendingInMessageLoop(); 965 EXPECT_TRUE(recorder.events().empty()); 966 root_window()->RemovePreTargetHandler(&recorder); 967 } 968 969 #if defined(OS_WIN) && defined(ARCH_CPU_X86) 970 #define MAYBE(x) DISABLED_##x 971 #else 972 #define MAYBE(x) x 973 #endif 974 975 // Tests synthetic mouse events generated when window bounds changes such that 976 // the cursor previously outside the window becomes inside, or vice versa. 977 // Do not synthesize events if the window ignores events or is invisible. 978 // Flaky on 32-bit Windows bots. http://crbug.com/388272 979 TEST_F(WindowEventDispatcherTest, 980 MAYBE(SynthesizeMouseEventsOnWindowBoundsChanged)) { 981 test::TestWindowDelegate delegate; 982 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 983 &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window())); 984 window->Show(); 985 window->SetCapture(); 986 987 EventFilterRecorder recorder; 988 window->AddPreTargetHandler(&recorder); 989 990 // Dispatch a non-synthetic mouse event to place cursor inside window bounds. 991 ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(10, 10), 992 gfx::Point(10, 10), 0, 0); 993 DispatchEventUsingWindowDispatcher(&mouse); 994 EXPECT_FALSE(recorder.events().empty()); 995 recorder.Reset(); 996 997 // Update the window bounds so that cursor is now outside the window. 998 // This should trigger a synthetic MOVED event. 999 gfx::Rect bounds1(20, 20, 100, 100); 1000 window->SetBounds(bounds1); 1001 RunAllPendingInMessageLoop(); 1002 ASSERT_FALSE(recorder.events().empty()); 1003 ASSERT_FALSE(recorder.mouse_event_flags().empty()); 1004 EXPECT_EQ(ui::ET_MOUSE_MOVED, recorder.events().back()); 1005 EXPECT_EQ(ui::EF_IS_SYNTHESIZED, recorder.mouse_event_flags().back()); 1006 recorder.Reset(); 1007 1008 // Set window to ignore events. 1009 window->set_ignore_events(true); 1010 1011 // Update the window bounds so that cursor is back inside the window. 1012 // This should not trigger a synthetic event. 1013 gfx::Rect bounds2(5, 5, 100, 100); 1014 window->SetBounds(bounds2); 1015 RunAllPendingInMessageLoop(); 1016 EXPECT_TRUE(recorder.events().empty()); 1017 recorder.Reset(); 1018 1019 // Set window to accept events but invisible. 1020 window->set_ignore_events(false); 1021 window->Hide(); 1022 recorder.Reset(); 1023 1024 // Update the window bounds so that cursor is outside the window. 1025 // This should not trigger a synthetic event. 1026 window->SetBounds(bounds1); 1027 RunAllPendingInMessageLoop(); 1028 EXPECT_TRUE(recorder.events().empty()); 1029 } 1030 1031 // Tests that a mouse exit is dispatched to the last known cursor location 1032 // when the cursor becomes invisible. 1033 TEST_F(WindowEventDispatcherTest, DispatchMouseExitWhenCursorHidden) { 1034 EventFilterRecorder recorder; 1035 root_window()->AddPreTargetHandler(&recorder); 1036 1037 test::TestWindowDelegate delegate; 1038 gfx::Point window_origin(7, 18); 1039 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 1040 &delegate, 1234, gfx::Rect(window_origin, gfx::Size(100, 100)), 1041 root_window())); 1042 window->Show(); 1043 1044 // Dispatch a mouse move event into the window. 1045 gfx::Point mouse_location(gfx::Point(15, 25)); 1046 ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, mouse_location, 1047 mouse_location, 0, 0); 1048 EXPECT_TRUE(recorder.events().empty()); 1049 DispatchEventUsingWindowDispatcher(&mouse1); 1050 EXPECT_FALSE(recorder.events().empty()); 1051 recorder.Reset(); 1052 1053 // Hide the cursor and verify a mouse exit was dispatched. 1054 host()->OnCursorVisibilityChanged(false); 1055 EXPECT_FALSE(recorder.events().empty()); 1056 EXPECT_EQ("MOUSE_EXITED", EventTypesToString(recorder.events())); 1057 1058 // Verify the mouse exit was dispatched at the correct location 1059 // (in the correct coordinate space). 1060 int translated_x = mouse_location.x() - window_origin.x(); 1061 int translated_y = mouse_location.y() - window_origin.y(); 1062 gfx::Point translated_point(translated_x, translated_y); 1063 EXPECT_EQ(recorder.mouse_location(0).ToString(), translated_point.ToString()); 1064 root_window()->RemovePreTargetHandler(&recorder); 1065 } 1066 1067 // Tests that a synthetic mouse exit is dispatched to the last known cursor 1068 // location after mouse events are disabled on the cursor client. 1069 TEST_F(WindowEventDispatcherTest, 1070 DispatchSyntheticMouseExitAfterMouseEventsDisabled) { 1071 EventFilterRecorder recorder; 1072 root_window()->AddPreTargetHandler(&recorder); 1073 1074 test::TestWindowDelegate delegate; 1075 gfx::Point window_origin(7, 18); 1076 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 1077 &delegate, 1234, gfx::Rect(window_origin, gfx::Size(100, 100)), 1078 root_window())); 1079 window->Show(); 1080 1081 // Dispatch a mouse move event into the window. 1082 gfx::Point mouse_location(gfx::Point(15, 25)); 1083 ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, mouse_location, 1084 mouse_location, 0, 0); 1085 EXPECT_TRUE(recorder.events().empty()); 1086 DispatchEventUsingWindowDispatcher(&mouse1); 1087 EXPECT_FALSE(recorder.events().empty()); 1088 recorder.Reset(); 1089 1090 test::TestCursorClient cursor_client(root_window()); 1091 cursor_client.DisableMouseEvents(); 1092 1093 gfx::Point mouse_exit_location(gfx::Point(150, 150)); 1094 ui::MouseEvent mouse2(ui::ET_MOUSE_EXITED, gfx::Point(150, 150), 1095 gfx::Point(150, 150), ui::EF_IS_SYNTHESIZED, 0); 1096 DispatchEventUsingWindowDispatcher(&mouse2); 1097 1098 EXPECT_FALSE(recorder.events().empty()); 1099 // We get the mouse exited event twice in our filter. Once during the 1100 // predispatch phase and during the actual dispatch. 1101 EXPECT_EQ("MOUSE_EXITED MOUSE_EXITED", EventTypesToString(recorder.events())); 1102 1103 // Verify the mouse exit was dispatched at the correct location 1104 // (in the correct coordinate space). 1105 int translated_x = mouse_exit_location.x() - window_origin.x(); 1106 int translated_y = mouse_exit_location.y() - window_origin.y(); 1107 gfx::Point translated_point(translated_x, translated_y); 1108 EXPECT_EQ(recorder.mouse_location(0).ToString(), translated_point.ToString()); 1109 root_window()->RemovePreTargetHandler(&recorder); 1110 } 1111 1112 class DeletingEventFilter : public ui::EventHandler { 1113 public: 1114 DeletingEventFilter() 1115 : delete_during_pre_handle_(false) {} 1116 virtual ~DeletingEventFilter() {} 1117 1118 void Reset(bool delete_during_pre_handle) { 1119 delete_during_pre_handle_ = delete_during_pre_handle; 1120 } 1121 1122 private: 1123 // Overridden from ui::EventHandler: 1124 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE { 1125 if (delete_during_pre_handle_) 1126 delete event->target(); 1127 } 1128 1129 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { 1130 if (delete_during_pre_handle_) 1131 delete event->target(); 1132 } 1133 1134 bool delete_during_pre_handle_; 1135 1136 DISALLOW_COPY_AND_ASSIGN(DeletingEventFilter); 1137 }; 1138 1139 class DeletingWindowDelegate : public test::TestWindowDelegate { 1140 public: 1141 DeletingWindowDelegate() 1142 : window_(NULL), 1143 delete_during_handle_(false), 1144 got_event_(false) {} 1145 virtual ~DeletingWindowDelegate() {} 1146 1147 void Reset(Window* window, bool delete_during_handle) { 1148 window_ = window; 1149 delete_during_handle_ = delete_during_handle; 1150 got_event_ = false; 1151 } 1152 bool got_event() const { return got_event_; } 1153 1154 private: 1155 // Overridden from WindowDelegate: 1156 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE { 1157 if (delete_during_handle_) 1158 delete window_; 1159 got_event_ = true; 1160 } 1161 1162 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { 1163 if (delete_during_handle_) 1164 delete window_; 1165 got_event_ = true; 1166 } 1167 1168 Window* window_; 1169 bool delete_during_handle_; 1170 bool got_event_; 1171 1172 DISALLOW_COPY_AND_ASSIGN(DeletingWindowDelegate); 1173 }; 1174 1175 TEST_F(WindowEventDispatcherTest, DeleteWindowDuringDispatch) { 1176 // Verifies that we can delete a window during each phase of event handling. 1177 // Deleting the window should not cause a crash, only prevent further 1178 // processing from occurring. 1179 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL)); 1180 DeletingWindowDelegate d11; 1181 Window* w11 = CreateNormalWindow(11, w1.get(), &d11); 1182 WindowTracker tracker; 1183 DeletingEventFilter w1_filter; 1184 w1->AddPreTargetHandler(&w1_filter); 1185 client::GetFocusClient(w1.get())->FocusWindow(w11); 1186 1187 ui::test::EventGenerator generator(root_window(), w11); 1188 1189 // First up, no one deletes anything. 1190 tracker.Add(w11); 1191 d11.Reset(w11, false); 1192 1193 generator.PressLeftButton(); 1194 EXPECT_TRUE(tracker.Contains(w11)); 1195 EXPECT_TRUE(d11.got_event()); 1196 generator.ReleaseLeftButton(); 1197 1198 // Delegate deletes w11. This will prevent the post-handle step from applying. 1199 w1_filter.Reset(false); 1200 d11.Reset(w11, true); 1201 generator.PressKey(ui::VKEY_A, 0); 1202 EXPECT_FALSE(tracker.Contains(w11)); 1203 EXPECT_TRUE(d11.got_event()); 1204 1205 // Pre-handle step deletes w11. This will prevent the delegate and the post- 1206 // handle steps from applying. 1207 w11 = CreateNormalWindow(11, w1.get(), &d11); 1208 w1_filter.Reset(true); 1209 d11.Reset(w11, false); 1210 generator.PressLeftButton(); 1211 EXPECT_FALSE(tracker.Contains(w11)); 1212 EXPECT_FALSE(d11.got_event()); 1213 } 1214 1215 namespace { 1216 1217 // A window delegate that detaches the parent of the target's parent window when 1218 // it receives a tap event. 1219 class DetachesParentOnTapDelegate : public test::TestWindowDelegate { 1220 public: 1221 DetachesParentOnTapDelegate() {} 1222 virtual ~DetachesParentOnTapDelegate() {} 1223 1224 private: 1225 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 1226 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { 1227 event->SetHandled(); 1228 return; 1229 } 1230 1231 if (event->type() == ui::ET_GESTURE_TAP) { 1232 Window* parent = static_cast<Window*>(event->target())->parent(); 1233 parent->parent()->RemoveChild(parent); 1234 event->SetHandled(); 1235 } 1236 } 1237 1238 DISALLOW_COPY_AND_ASSIGN(DetachesParentOnTapDelegate); 1239 }; 1240 1241 } // namespace 1242 1243 // Tests that the gesture recognizer is reset for all child windows when a 1244 // window hides. No expectations, just checks that the test does not crash. 1245 TEST_F(WindowEventDispatcherTest, 1246 GestureRecognizerResetsTargetWhenParentHides) { 1247 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL)); 1248 DetachesParentOnTapDelegate delegate; 1249 scoped_ptr<Window> parent(CreateNormalWindow(22, w1.get(), NULL)); 1250 Window* child = CreateNormalWindow(11, parent.get(), &delegate); 1251 ui::test::EventGenerator generator(root_window(), child); 1252 generator.GestureTapAt(gfx::Point(40, 40)); 1253 } 1254 1255 namespace { 1256 1257 // A window delegate that processes nested gestures on tap. 1258 class NestedGestureDelegate : public test::TestWindowDelegate { 1259 public: 1260 NestedGestureDelegate(ui::test::EventGenerator* generator, 1261 const gfx::Point tap_location) 1262 : generator_(generator), 1263 tap_location_(tap_location), 1264 gesture_end_count_(0) {} 1265 virtual ~NestedGestureDelegate() {} 1266 1267 int gesture_end_count() const { return gesture_end_count_; } 1268 1269 private: 1270 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 1271 switch (event->type()) { 1272 case ui::ET_GESTURE_TAP_DOWN: 1273 event->SetHandled(); 1274 break; 1275 case ui::ET_GESTURE_TAP: 1276 if (generator_) 1277 generator_->GestureTapAt(tap_location_); 1278 event->SetHandled(); 1279 break; 1280 case ui::ET_GESTURE_END: 1281 ++gesture_end_count_; 1282 break; 1283 default: 1284 break; 1285 } 1286 } 1287 1288 ui::test::EventGenerator* generator_; 1289 const gfx::Point tap_location_; 1290 int gesture_end_count_; 1291 DISALLOW_COPY_AND_ASSIGN(NestedGestureDelegate); 1292 }; 1293 1294 } // namespace 1295 1296 // Tests that gesture end is delivered after nested gesture processing. 1297 TEST_F(WindowEventDispatcherTest, GestureEndDeliveredAfterNestedGestures) { 1298 NestedGestureDelegate d1(NULL, gfx::Point()); 1299 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &d1)); 1300 w1->SetBounds(gfx::Rect(0, 0, 100, 100)); 1301 1302 ui::test::EventGenerator nested_generator(root_window(), w1.get()); 1303 NestedGestureDelegate d2(&nested_generator, w1->bounds().CenterPoint()); 1304 scoped_ptr<Window> w2(CreateNormalWindow(1, root_window(), &d2)); 1305 w2->SetBounds(gfx::Rect(100, 0, 100, 100)); 1306 1307 // Tap on w2 which triggers nested gestures for w1. 1308 ui::test::EventGenerator generator(root_window(), w2.get()); 1309 generator.GestureTapAt(w2->bounds().CenterPoint()); 1310 1311 // Both windows should get their gesture end events. 1312 EXPECT_EQ(1, d1.gesture_end_count()); 1313 EXPECT_EQ(1, d2.gesture_end_count()); 1314 } 1315 1316 // Tests whether we can repost the Tap down gesture event. 1317 TEST_F(WindowEventDispatcherTest, RepostTapdownGestureTest) { 1318 EventFilterRecorder recorder; 1319 root_window()->AddPreTargetHandler(&recorder); 1320 1321 test::TestWindowDelegate delegate; 1322 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 1323 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); 1324 1325 ui::GestureEventDetails details(ui::ET_GESTURE_TAP_DOWN); 1326 gfx::Point point(10, 10); 1327 ui::GestureEvent event(point.x(), 1328 point.y(), 1329 0, 1330 ui::EventTimeForNow(), 1331 details); 1332 host()->dispatcher()->RepostEvent(event); 1333 RunAllPendingInMessageLoop(); 1334 // TODO(rbyers): Currently disabled - crbug.com/170987 1335 EXPECT_FALSE(EventTypesToString(recorder.events()).find("GESTURE_TAP_DOWN") != 1336 std::string::npos); 1337 recorder.Reset(); 1338 root_window()->RemovePreTargetHandler(&recorder); 1339 } 1340 1341 // This class inherits from the EventFilterRecorder class which provides a 1342 // facility to record events. This class additionally provides a facility to 1343 // repost the ET_GESTURE_TAP_DOWN gesture to the target window and records 1344 // events after that. 1345 class RepostGestureEventRecorder : public EventFilterRecorder { 1346 public: 1347 RepostGestureEventRecorder(aura::Window* repost_source, 1348 aura::Window* repost_target) 1349 : repost_source_(repost_source), 1350 repost_target_(repost_target), 1351 reposted_(false), 1352 done_cleanup_(false) {} 1353 1354 virtual ~RepostGestureEventRecorder() {} 1355 1356 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE { 1357 if (reposted_ && event->type() == ui::ET_TOUCH_PRESSED) { 1358 done_cleanup_ = true; 1359 Reset(); 1360 } 1361 EventFilterRecorder::OnTouchEvent(event); 1362 } 1363 1364 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 1365 EXPECT_EQ(done_cleanup_ ? repost_target_ : repost_source_, event->target()); 1366 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { 1367 if (!reposted_) { 1368 EXPECT_NE(repost_target_, event->target()); 1369 reposted_ = true; 1370 repost_target_->GetHost()->dispatcher()->RepostEvent(*event); 1371 // Ensure that the reposted gesture event above goes to the 1372 // repost_target_; 1373 repost_source_->GetRootWindow()->RemoveChild(repost_source_); 1374 return; 1375 } 1376 } 1377 EventFilterRecorder::OnGestureEvent(event); 1378 } 1379 1380 // Ignore mouse events as they don't fire at all times. This causes 1381 // the GestureRepostEventOrder test to fail randomly. 1382 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {} 1383 1384 private: 1385 aura::Window* repost_source_; 1386 aura::Window* repost_target_; 1387 // set to true if we reposted the ET_GESTURE_TAP_DOWN event. 1388 bool reposted_; 1389 // set true if we're done cleaning up after hiding repost_source_; 1390 bool done_cleanup_; 1391 DISALLOW_COPY_AND_ASSIGN(RepostGestureEventRecorder); 1392 }; 1393 1394 // Tests whether events which are generated after the reposted gesture event 1395 // are received after that. In this case the scroll sequence events should 1396 // be received after the reposted gesture event. 1397 TEST_F(WindowEventDispatcherTest, GestureRepostEventOrder) { 1398 // Expected events at the end for the repost_target window defined below. 1399 const char kExpectedTargetEvents[] = 1400 // TODO)(rbyers): Gesture event reposting is disabled - crbug.com/279039. 1401 // "GESTURE_BEGIN GESTURE_TAP_DOWN " 1402 "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED " 1403 "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE TOUCH_MOVED " 1404 "GESTURE_SCROLL_UPDATE TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED " 1405 "GESTURE_SCROLL_END GESTURE_END"; 1406 // We create two windows. 1407 // The first window (repost_source) is the one to which the initial tap 1408 // gesture is sent. It reposts this event to the second window 1409 // (repost_target). 1410 // We then generate the scroll sequence for repost_target and look for two 1411 // ET_GESTURE_TAP_DOWN events in the event list at the end. 1412 test::TestWindowDelegate delegate; 1413 scoped_ptr<aura::Window> repost_target(CreateTestWindowWithDelegate( 1414 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); 1415 1416 scoped_ptr<aura::Window> repost_source(CreateTestWindowWithDelegate( 1417 &delegate, 1, gfx::Rect(0, 0, 50, 50), root_window())); 1418 1419 RepostGestureEventRecorder repost_event_recorder(repost_source.get(), 1420 repost_target.get()); 1421 root_window()->AddPreTargetHandler(&repost_event_recorder); 1422 1423 // Generate a tap down gesture for the repost_source. This will be reposted 1424 // to repost_target. 1425 ui::test::EventGenerator repost_generator(root_window(), repost_source.get()); 1426 repost_generator.GestureTapAt(gfx::Point(40, 40)); 1427 RunAllPendingInMessageLoop(); 1428 1429 ui::test::EventGenerator scroll_generator(root_window(), repost_target.get()); 1430 scroll_generator.GestureScrollSequence( 1431 gfx::Point(80, 80), 1432 gfx::Point(100, 100), 1433 base::TimeDelta::FromMilliseconds(100), 1434 3); 1435 RunAllPendingInMessageLoop(); 1436 1437 int tap_down_count = 0; 1438 for (size_t i = 0; i < repost_event_recorder.events().size(); ++i) { 1439 if (repost_event_recorder.events()[i] == ui::ET_GESTURE_TAP_DOWN) 1440 ++tap_down_count; 1441 } 1442 1443 // We expect two tap down events. One from the repost and the other one from 1444 // the scroll sequence posted above. 1445 // TODO(rbyers): Currently disabled - crbug.com/170987 1446 EXPECT_EQ(1, tap_down_count); 1447 1448 EXPECT_EQ(kExpectedTargetEvents, 1449 EventTypesToString(repost_event_recorder.events())); 1450 root_window()->RemovePreTargetHandler(&repost_event_recorder); 1451 } 1452 1453 class OnMouseExitDeletingEventFilter : public EventFilterRecorder { 1454 public: 1455 OnMouseExitDeletingEventFilter() : window_to_delete_(NULL) {} 1456 virtual ~OnMouseExitDeletingEventFilter() {} 1457 1458 void set_window_to_delete(Window* window_to_delete) { 1459 window_to_delete_ = window_to_delete; 1460 } 1461 1462 private: 1463 // Overridden from ui::EventHandler: 1464 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { 1465 EventFilterRecorder::OnMouseEvent(event); 1466 if (window_to_delete_) { 1467 delete window_to_delete_; 1468 window_to_delete_ = NULL; 1469 } 1470 } 1471 1472 Window* window_to_delete_; 1473 1474 DISALLOW_COPY_AND_ASSIGN(OnMouseExitDeletingEventFilter); 1475 }; 1476 1477 // Tests that RootWindow drops mouse-moved event that is supposed to be sent to 1478 // a child, but the child is destroyed because of the synthesized mouse-exit 1479 // event generated on the previous mouse_moved_handler_. 1480 TEST_F(WindowEventDispatcherTest, DeleteWindowDuringMouseMovedDispatch) { 1481 // Create window 1 and set its event filter. Window 1 will take ownership of 1482 // the event filter. 1483 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL)); 1484 OnMouseExitDeletingEventFilter w1_filter; 1485 w1->AddPreTargetHandler(&w1_filter); 1486 w1->SetBounds(gfx::Rect(20, 20, 60, 60)); 1487 EXPECT_EQ(NULL, host()->dispatcher()->mouse_moved_handler()); 1488 1489 ui::test::EventGenerator generator(root_window(), w1.get()); 1490 1491 // Move mouse over window 1 to set it as the |mouse_moved_handler_| for the 1492 // root window. 1493 generator.MoveMouseTo(51, 51); 1494 EXPECT_EQ(w1.get(), host()->dispatcher()->mouse_moved_handler()); 1495 1496 // Create window 2 under the mouse cursor and stack it above window 1. 1497 Window* w2 = CreateNormalWindow(2, root_window(), NULL); 1498 w2->SetBounds(gfx::Rect(30, 30, 40, 40)); 1499 root_window()->StackChildAbove(w2, w1.get()); 1500 1501 // Set window 2 as the window that is to be deleted when a mouse-exited event 1502 // happens on window 1. 1503 w1_filter.set_window_to_delete(w2); 1504 1505 // Move mosue over window 2. This should generate a mouse-exited event for 1506 // window 1 resulting in deletion of window 2. The original mouse-moved event 1507 // that was targeted to window 2 should be dropped since window 2 is 1508 // destroyed. This test passes if no crash happens. 1509 generator.MoveMouseTo(52, 52); 1510 EXPECT_EQ(NULL, host()->dispatcher()->mouse_moved_handler()); 1511 1512 // Check events received by window 1. 1513 EXPECT_EQ("MOUSE_ENTERED MOUSE_MOVED MOUSE_EXITED", 1514 EventTypesToString(w1_filter.events())); 1515 } 1516 1517 namespace { 1518 1519 // Used to track if OnWindowDestroying() is invoked and if there is a valid 1520 // RootWindow at such time. 1521 class ValidRootDuringDestructionWindowObserver : public aura::WindowObserver { 1522 public: 1523 ValidRootDuringDestructionWindowObserver(bool* got_destroying, 1524 bool* has_valid_root) 1525 : got_destroying_(got_destroying), 1526 has_valid_root_(has_valid_root) { 1527 } 1528 1529 // WindowObserver: 1530 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { 1531 *got_destroying_ = true; 1532 *has_valid_root_ = (window->GetRootWindow() != NULL); 1533 } 1534 1535 private: 1536 bool* got_destroying_; 1537 bool* has_valid_root_; 1538 1539 DISALLOW_COPY_AND_ASSIGN(ValidRootDuringDestructionWindowObserver); 1540 }; 1541 1542 } // namespace 1543 1544 // Verifies GetRootWindow() from ~Window returns a valid root. 1545 TEST_F(WindowEventDispatcherTest, ValidRootDuringDestruction) { 1546 bool got_destroying = false; 1547 bool has_valid_root = false; 1548 ValidRootDuringDestructionWindowObserver observer(&got_destroying, 1549 &has_valid_root); 1550 { 1551 scoped_ptr<WindowTreeHost> host( 1552 WindowTreeHost::Create(gfx::Rect(0, 0, 100, 100))); 1553 host->InitHost(); 1554 // Owned by WindowEventDispatcher. 1555 Window* w1 = CreateNormalWindow(1, host->window(), NULL); 1556 w1->AddObserver(&observer); 1557 } 1558 EXPECT_TRUE(got_destroying); 1559 EXPECT_TRUE(has_valid_root); 1560 } 1561 1562 namespace { 1563 1564 // See description above DontResetHeldEvent for details. 1565 class DontResetHeldEventWindowDelegate : public test::TestWindowDelegate { 1566 public: 1567 explicit DontResetHeldEventWindowDelegate(aura::Window* root) 1568 : root_(root), 1569 mouse_event_count_(0) {} 1570 virtual ~DontResetHeldEventWindowDelegate() {} 1571 1572 int mouse_event_count() const { return mouse_event_count_; } 1573 1574 // TestWindowDelegate: 1575 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { 1576 if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 && 1577 mouse_event_count_++ == 0) { 1578 ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, 1579 gfx::Point(10, 10), gfx::Point(10, 10), 1580 ui::EF_SHIFT_DOWN, 0); 1581 root_->GetHost()->dispatcher()->RepostEvent(mouse_event); 1582 } 1583 } 1584 1585 private: 1586 Window* root_; 1587 int mouse_event_count_; 1588 1589 DISALLOW_COPY_AND_ASSIGN(DontResetHeldEventWindowDelegate); 1590 }; 1591 1592 } // namespace 1593 1594 // Verifies RootWindow doesn't reset |RootWindow::held_repostable_event_| after 1595 // dispatching. This is done by using DontResetHeldEventWindowDelegate, which 1596 // tracks the number of events with ui::EF_SHIFT_DOWN set (all reposted events 1597 // have EF_SHIFT_DOWN). When the first event is seen RepostEvent() is used to 1598 // schedule another reposted event. 1599 TEST_F(WindowEventDispatcherTest, DontResetHeldEvent) { 1600 DontResetHeldEventWindowDelegate delegate(root_window()); 1601 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate)); 1602 w1->SetBounds(gfx::Rect(0, 0, 40, 40)); 1603 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, 1604 gfx::Point(10, 10), gfx::Point(10, 10), 1605 ui::EF_SHIFT_DOWN, 0); 1606 root_window()->GetHost()->dispatcher()->RepostEvent(pressed); 1607 ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED, 1608 gfx::Point(10, 10), gfx::Point(10, 10), 0, 0); 1609 // Dispatch an event to flush event scheduled by way of RepostEvent(). 1610 DispatchEventUsingWindowDispatcher(&pressed2); 1611 // Delegate should have seen reposted event (identified by way of 1612 // EF_SHIFT_DOWN). Dispatch another event to flush the second 1613 // RepostedEvent(). 1614 EXPECT_EQ(1, delegate.mouse_event_count()); 1615 DispatchEventUsingWindowDispatcher(&pressed2); 1616 EXPECT_EQ(2, delegate.mouse_event_count()); 1617 } 1618 1619 namespace { 1620 1621 // See description above DeleteHostFromHeldMouseEvent for details. 1622 class DeleteHostFromHeldMouseEventDelegate 1623 : public test::TestWindowDelegate { 1624 public: 1625 explicit DeleteHostFromHeldMouseEventDelegate(WindowTreeHost* host) 1626 : host_(host), 1627 got_mouse_event_(false), 1628 got_destroy_(false) { 1629 } 1630 virtual ~DeleteHostFromHeldMouseEventDelegate() {} 1631 1632 bool got_mouse_event() const { return got_mouse_event_; } 1633 bool got_destroy() const { return got_destroy_; } 1634 1635 // TestWindowDelegate: 1636 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { 1637 if ((event->flags() & ui::EF_SHIFT_DOWN) != 0) { 1638 got_mouse_event_ = true; 1639 delete host_; 1640 } 1641 } 1642 virtual void OnWindowDestroyed(Window* window) OVERRIDE { 1643 got_destroy_ = true; 1644 } 1645 1646 private: 1647 WindowTreeHost* host_; 1648 bool got_mouse_event_; 1649 bool got_destroy_; 1650 1651 DISALLOW_COPY_AND_ASSIGN(DeleteHostFromHeldMouseEventDelegate); 1652 }; 1653 1654 } // namespace 1655 1656 // Verifies if a WindowTreeHost is deleted from dispatching a held mouse event 1657 // we don't crash. 1658 TEST_F(WindowEventDispatcherTest, DeleteHostFromHeldMouseEvent) { 1659 // Should be deleted by |delegate|. 1660 WindowTreeHost* h2 = WindowTreeHost::Create(gfx::Rect(0, 0, 100, 100)); 1661 h2->InitHost(); 1662 DeleteHostFromHeldMouseEventDelegate delegate(h2); 1663 // Owned by |h2|. 1664 Window* w1 = CreateNormalWindow(1, h2->window(), &delegate); 1665 w1->SetBounds(gfx::Rect(0, 0, 40, 40)); 1666 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, 1667 gfx::Point(10, 10), gfx::Point(10, 10), 1668 ui::EF_SHIFT_DOWN, 0); 1669 h2->dispatcher()->RepostEvent(pressed); 1670 // RunAllPendingInMessageLoop() to make sure the |pressed| is run. 1671 RunAllPendingInMessageLoop(); 1672 EXPECT_TRUE(delegate.got_mouse_event()); 1673 EXPECT_TRUE(delegate.got_destroy()); 1674 } 1675 1676 TEST_F(WindowEventDispatcherTest, WindowHideCancelsActiveTouches) { 1677 EventFilterRecorder recorder; 1678 root_window()->AddPreTargetHandler(&recorder); 1679 1680 test::TestWindowDelegate delegate; 1681 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 1682 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); 1683 1684 gfx::Point position1 = root_window()->bounds().origin(); 1685 ui::TouchEvent press( 1686 ui::ET_TOUCH_PRESSED, position1, 0, ui::EventTimeForNow()); 1687 DispatchEventUsingWindowDispatcher(&press); 1688 1689 EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN", 1690 EventTypesToString(recorder.GetAndResetEvents())); 1691 1692 window->Hide(); 1693 1694 EXPECT_EQ(ui::ET_TOUCH_CANCELLED, recorder.events()[0]); 1695 EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_TAP_CANCEL)); 1696 EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_END)); 1697 EXPECT_EQ(3U, recorder.events().size()); 1698 root_window()->RemovePreTargetHandler(&recorder); 1699 } 1700 1701 TEST_F(WindowEventDispatcherTest, WindowHideCancelsActiveGestures) { 1702 EventFilterRecorder recorder; 1703 root_window()->AddPreTargetHandler(&recorder); 1704 1705 test::TestWindowDelegate delegate; 1706 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 1707 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); 1708 1709 gfx::Point position1 = root_window()->bounds().origin(); 1710 gfx::Point position2 = root_window()->bounds().CenterPoint(); 1711 ui::TouchEvent press( 1712 ui::ET_TOUCH_PRESSED, position1, 0, ui::EventTimeForNow()); 1713 DispatchEventUsingWindowDispatcher(&press); 1714 1715 ui::TouchEvent move( 1716 ui::ET_TOUCH_MOVED, position2, 0, ui::EventTimeForNow()); 1717 DispatchEventUsingWindowDispatcher(&move); 1718 1719 ui::TouchEvent press2( 1720 ui::ET_TOUCH_PRESSED, position1, 1, ui::EventTimeForNow()); 1721 DispatchEventUsingWindowDispatcher(&press2); 1722 1723 // TODO(tdresser): once the unified Gesture Recognizer has stuck, remove the 1724 // special casing here. See crbug.com/332418 for details. 1725 std::string expected = 1726 "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED " 1727 "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE " 1728 "TOUCH_PRESSED GESTURE_BEGIN GESTURE_PINCH_BEGIN"; 1729 1730 std::string expected_ugr = 1731 "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED " 1732 "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE " 1733 "TOUCH_PRESSED GESTURE_BEGIN"; 1734 1735 std::string events_string = EventTypesToString(recorder.GetAndResetEvents()); 1736 EXPECT_TRUE((expected == events_string) || (expected_ugr == events_string)); 1737 1738 window->Hide(); 1739 1740 expected = 1741 "TOUCH_CANCELLED GESTURE_PINCH_END GESTURE_END TOUCH_CANCELLED " 1742 "GESTURE_SCROLL_END GESTURE_END"; 1743 expected_ugr = 1744 "TOUCH_CANCELLED GESTURE_SCROLL_END GESTURE_END TOUCH_CANCELLED " 1745 "GESTURE_END"; 1746 1747 events_string = EventTypesToString(recorder.GetAndResetEvents()); 1748 EXPECT_TRUE((expected == events_string) || (expected_ugr == events_string)); 1749 1750 root_window()->RemovePreTargetHandler(&recorder); 1751 } 1752 1753 // Places two windows side by side. Presses down on one window, and starts a 1754 // scroll. Sets capture on the other window and ensures that the "ending" events 1755 // aren't sent to the window which gained capture. 1756 TEST_F(WindowEventDispatcherTest, EndingEventDoesntRetarget) { 1757 EventFilterRecorder recorder1; 1758 EventFilterRecorder recorder2; 1759 scoped_ptr<Window> window1(CreateNormalWindow(1, root_window(), NULL)); 1760 window1->SetBounds(gfx::Rect(0, 0, 40, 40)); 1761 1762 scoped_ptr<Window> window2(CreateNormalWindow(2, root_window(), NULL)); 1763 window2->SetBounds(gfx::Rect(40, 0, 40, 40)); 1764 1765 window1->AddPreTargetHandler(&recorder1); 1766 window2->AddPreTargetHandler(&recorder2); 1767 1768 gfx::Point position = window1->bounds().origin(); 1769 ui::TouchEvent press( 1770 ui::ET_TOUCH_PRESSED, position, 0, ui::EventTimeForNow()); 1771 DispatchEventUsingWindowDispatcher(&press); 1772 1773 gfx::Point position2 = window1->bounds().CenterPoint(); 1774 ui::TouchEvent move( 1775 ui::ET_TOUCH_MOVED, position2, 0, ui::EventTimeForNow()); 1776 DispatchEventUsingWindowDispatcher(&move); 1777 1778 window2->SetCapture(); 1779 1780 EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED " 1781 "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE " 1782 "TOUCH_CANCELLED GESTURE_SCROLL_END GESTURE_END", 1783 EventTypesToString(recorder1.events())); 1784 1785 EXPECT_TRUE(recorder2.events().empty()); 1786 } 1787 1788 namespace { 1789 1790 // This class creates and manages a window which is destroyed as soon as 1791 // capture is lost. This is the case for the drag and drop capture window. 1792 class CaptureWindowTracker : public test::TestWindowDelegate { 1793 public: 1794 CaptureWindowTracker() {} 1795 virtual ~CaptureWindowTracker() {} 1796 1797 void CreateCaptureWindow(aura::Window* root_window) { 1798 capture_window_.reset(test::CreateTestWindowWithDelegate( 1799 this, -1234, gfx::Rect(20, 20, 20, 20), root_window)); 1800 capture_window_->SetCapture(); 1801 } 1802 1803 void reset() { 1804 capture_window_.reset(); 1805 } 1806 1807 virtual void OnCaptureLost() OVERRIDE { 1808 capture_window_.reset(); 1809 } 1810 1811 virtual void OnWindowDestroyed(Window* window) OVERRIDE { 1812 TestWindowDelegate::OnWindowDestroyed(window); 1813 capture_window_.reset(); 1814 } 1815 1816 aura::Window* capture_window() { return capture_window_.get(); } 1817 1818 private: 1819 scoped_ptr<aura::Window> capture_window_; 1820 1821 DISALLOW_COPY_AND_ASSIGN(CaptureWindowTracker); 1822 }; 1823 1824 } 1825 1826 // Verifies handling loss of capture by the capture window being hidden. 1827 TEST_F(WindowEventDispatcherTest, CaptureWindowHidden) { 1828 CaptureWindowTracker capture_window_tracker; 1829 capture_window_tracker.CreateCaptureWindow(root_window()); 1830 capture_window_tracker.capture_window()->Hide(); 1831 EXPECT_EQ(NULL, capture_window_tracker.capture_window()); 1832 } 1833 1834 // Verifies handling loss of capture by the capture window being destroyed. 1835 TEST_F(WindowEventDispatcherTest, CaptureWindowDestroyed) { 1836 CaptureWindowTracker capture_window_tracker; 1837 capture_window_tracker.CreateCaptureWindow(root_window()); 1838 capture_window_tracker.reset(); 1839 EXPECT_EQ(NULL, capture_window_tracker.capture_window()); 1840 } 1841 1842 class ExitMessageLoopOnMousePress : public ui::test::TestEventHandler { 1843 public: 1844 ExitMessageLoopOnMousePress() {} 1845 virtual ~ExitMessageLoopOnMousePress() {} 1846 1847 protected: 1848 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { 1849 ui::test::TestEventHandler::OnMouseEvent(event); 1850 if (event->type() == ui::ET_MOUSE_PRESSED) 1851 base::MessageLoopForUI::current()->Quit(); 1852 } 1853 1854 private: 1855 DISALLOW_COPY_AND_ASSIGN(ExitMessageLoopOnMousePress); 1856 }; 1857 1858 class WindowEventDispatcherTestWithMessageLoop 1859 : public WindowEventDispatcherTest { 1860 public: 1861 WindowEventDispatcherTestWithMessageLoop() {} 1862 virtual ~WindowEventDispatcherTestWithMessageLoop() {} 1863 1864 void RunTest() { 1865 // Reset any event the window may have received when bringing up the window 1866 // (e.g. mouse-move events if the mouse cursor is over the window). 1867 handler_.Reset(); 1868 1869 // Start a nested message-loop, post an event to be dispatched, and then 1870 // terminate the message-loop. When the message-loop unwinds and gets back, 1871 // the reposted event should not have fired. 1872 scoped_ptr<ui::MouseEvent> mouse(new ui::MouseEvent(ui::ET_MOUSE_PRESSED, 1873 gfx::Point(10, 10), 1874 gfx::Point(10, 10), 1875 ui::EF_NONE, 1876 ui::EF_NONE)); 1877 message_loop()->PostTask( 1878 FROM_HERE, 1879 base::Bind(&WindowEventDispatcherTestWithMessageLoop::RepostEventHelper, 1880 host()->dispatcher(), 1881 base::Passed(&mouse))); 1882 message_loop()->PostTask(FROM_HERE, message_loop()->QuitClosure()); 1883 1884 base::MessageLoop::ScopedNestableTaskAllower allow(message_loop()); 1885 base::RunLoop loop; 1886 loop.Run(); 1887 EXPECT_EQ(0, handler_.num_mouse_events()); 1888 1889 // Let the current message-loop run. The event-handler will terminate the 1890 // message-loop when it receives the reposted event. 1891 } 1892 1893 base::MessageLoop* message_loop() { 1894 return base::MessageLoopForUI::current(); 1895 } 1896 1897 protected: 1898 virtual void SetUp() OVERRIDE { 1899 WindowEventDispatcherTest::SetUp(); 1900 window_.reset(CreateNormalWindow(1, root_window(), NULL)); 1901 window_->AddPreTargetHandler(&handler_); 1902 } 1903 1904 virtual void TearDown() OVERRIDE { 1905 window_.reset(); 1906 WindowEventDispatcherTest::TearDown(); 1907 } 1908 1909 private: 1910 // Used to avoid a copying |event| when binding to a closure. 1911 static void RepostEventHelper(WindowEventDispatcher* dispatcher, 1912 scoped_ptr<ui::MouseEvent> event) { 1913 dispatcher->RepostEvent(*event); 1914 } 1915 1916 scoped_ptr<Window> window_; 1917 ExitMessageLoopOnMousePress handler_; 1918 1919 DISALLOW_COPY_AND_ASSIGN(WindowEventDispatcherTestWithMessageLoop); 1920 }; 1921 1922 TEST_F(WindowEventDispatcherTestWithMessageLoop, EventRepostedInNonNestedLoop) { 1923 CHECK(!message_loop()->is_running()); 1924 // Perform the test in a callback, so that it runs after the message-loop 1925 // starts. 1926 message_loop()->PostTask( 1927 FROM_HERE, base::Bind( 1928 &WindowEventDispatcherTestWithMessageLoop::RunTest, 1929 base::Unretained(this))); 1930 message_loop()->Run(); 1931 } 1932 1933 class WindowEventDispatcherTestInHighDPI : public WindowEventDispatcherTest { 1934 public: 1935 WindowEventDispatcherTestInHighDPI() {} 1936 virtual ~WindowEventDispatcherTestInHighDPI() {} 1937 1938 protected: 1939 virtual void SetUp() OVERRIDE { 1940 WindowEventDispatcherTest::SetUp(); 1941 test_screen()->SetDeviceScaleFactor(2.f); 1942 } 1943 }; 1944 1945 TEST_F(WindowEventDispatcherTestInHighDPI, EventLocationTransform) { 1946 test::TestWindowDelegate delegate; 1947 scoped_ptr<aura::Window> child(test::CreateTestWindowWithDelegate(&delegate, 1948 1234, gfx::Rect(20, 20, 100, 100), root_window())); 1949 child->Show(); 1950 1951 ui::test::TestEventHandler handler_child; 1952 ui::test::TestEventHandler handler_root; 1953 root_window()->AddPreTargetHandler(&handler_root); 1954 child->AddPreTargetHandler(&handler_child); 1955 1956 { 1957 ui::MouseEvent move(ui::ET_MOUSE_MOVED, 1958 gfx::Point(30, 30), gfx::Point(30, 30), 1959 ui::EF_NONE, ui::EF_NONE); 1960 DispatchEventUsingWindowDispatcher(&move); 1961 EXPECT_EQ(0, handler_child.num_mouse_events()); 1962 EXPECT_EQ(1, handler_root.num_mouse_events()); 1963 } 1964 1965 { 1966 ui::MouseEvent move(ui::ET_MOUSE_MOVED, 1967 gfx::Point(50, 50), gfx::Point(50, 50), 1968 ui::EF_NONE, ui::EF_NONE); 1969 DispatchEventUsingWindowDispatcher(&move); 1970 // The child receives an ENTER, and a MOVED event. 1971 EXPECT_EQ(2, handler_child.num_mouse_events()); 1972 // The root receives both the ENTER and the MOVED events dispatched to 1973 // |child|, as well as an EXIT event. 1974 EXPECT_EQ(3, handler_root.num_mouse_events()); 1975 } 1976 1977 child->RemovePreTargetHandler(&handler_child); 1978 root_window()->RemovePreTargetHandler(&handler_root); 1979 } 1980 1981 TEST_F(WindowEventDispatcherTestInHighDPI, TouchMovesHeldOnScroll) { 1982 EventFilterRecorder recorder; 1983 root_window()->AddPreTargetHandler(&recorder); 1984 test::TestWindowDelegate delegate; 1985 HoldPointerOnScrollHandler handler(host()->dispatcher(), &recorder); 1986 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 1987 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window())); 1988 window->AddPreTargetHandler(&handler); 1989 1990 ui::test::EventGenerator generator(root_window()); 1991 generator.GestureScrollSequence( 1992 gfx::Point(120, 120), gfx::Point(20, 120), 1993 base::TimeDelta::FromMilliseconds(100), 25); 1994 1995 // |handler| will have reset |filter| and started holding the touch-move 1996 // events when scrolling started. At the end of the scroll (i.e. upon 1997 // touch-release), the held touch-move event will have been dispatched first, 1998 // along with the subsequent events (i.e. touch-release, scroll-end, and 1999 // gesture-end). 2000 const EventFilterRecorder::Events& events = recorder.events(); 2001 EXPECT_EQ( 2002 "TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED " 2003 "GESTURE_SCROLL_END GESTURE_END", 2004 EventTypesToString(events)); 2005 ASSERT_EQ(2u, recorder.touch_locations().size()); 2006 EXPECT_EQ(gfx::Point(-40, 10).ToString(), 2007 recorder.touch_locations()[0].ToString()); 2008 EXPECT_EQ(gfx::Point(-40, 10).ToString(), 2009 recorder.touch_locations()[1].ToString()); 2010 } 2011 2012 class SelfDestructDelegate : public test::TestWindowDelegate { 2013 public: 2014 SelfDestructDelegate() {} 2015 virtual ~SelfDestructDelegate() {} 2016 2017 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { 2018 window_.reset(); 2019 } 2020 2021 void set_window(scoped_ptr<aura::Window> window) { 2022 window_ = window.Pass(); 2023 } 2024 bool has_window() const { return !!window_.get(); } 2025 2026 private: 2027 scoped_ptr<aura::Window> window_; 2028 DISALLOW_COPY_AND_ASSIGN(SelfDestructDelegate); 2029 }; 2030 2031 TEST_F(WindowEventDispatcherTest, SynthesizedLocatedEvent) { 2032 ui::test::EventGenerator generator(root_window()); 2033 generator.MoveMouseTo(10, 10); 2034 EXPECT_EQ("10,10", 2035 Env::GetInstance()->last_mouse_location().ToString()); 2036 2037 // Synthesized event should not update the mouse location. 2038 ui::MouseEvent mouseev(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), 2039 ui::EF_IS_SYNTHESIZED, 0); 2040 generator.Dispatch(&mouseev); 2041 EXPECT_EQ("10,10", 2042 Env::GetInstance()->last_mouse_location().ToString()); 2043 2044 generator.MoveMouseTo(0, 0); 2045 EXPECT_EQ("0,0", 2046 Env::GetInstance()->last_mouse_location().ToString()); 2047 2048 // Make sure the location gets updated when a syntheiszed enter 2049 // event destroyed the window. 2050 SelfDestructDelegate delegate; 2051 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 2052 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window())); 2053 delegate.set_window(window.Pass()); 2054 EXPECT_TRUE(delegate.has_window()); 2055 2056 generator.MoveMouseTo(100, 100); 2057 EXPECT_FALSE(delegate.has_window()); 2058 EXPECT_EQ("100,100", 2059 Env::GetInstance()->last_mouse_location().ToString()); 2060 } 2061 2062 class StaticFocusClient : public client::FocusClient { 2063 public: 2064 explicit StaticFocusClient(Window* focused) 2065 : focused_(focused) {} 2066 virtual ~StaticFocusClient() {} 2067 2068 private: 2069 // client::FocusClient: 2070 virtual void AddObserver(client::FocusChangeObserver* observer) OVERRIDE {} 2071 virtual void RemoveObserver(client::FocusChangeObserver* observer) OVERRIDE {} 2072 virtual void FocusWindow(Window* window) OVERRIDE {} 2073 virtual void ResetFocusWithinActiveWindow(Window* window) OVERRIDE {} 2074 virtual Window* GetFocusedWindow() OVERRIDE { return focused_; } 2075 2076 Window* focused_; 2077 2078 DISALLOW_COPY_AND_ASSIGN(StaticFocusClient); 2079 }; 2080 2081 // Tests that host-cancel-mode event can be dispatched to a dispatcher safely 2082 // when the focused window does not live in the dispatcher's tree. 2083 TEST_F(WindowEventDispatcherTest, HostCancelModeWithFocusedWindowOutside) { 2084 test::TestWindowDelegate delegate; 2085 scoped_ptr<Window> focused(CreateTestWindowWithDelegate(&delegate, 123, 2086 gfx::Rect(20, 30, 100, 50), NULL)); 2087 StaticFocusClient focus_client(focused.get()); 2088 client::SetFocusClient(root_window(), &focus_client); 2089 EXPECT_FALSE(root_window()->Contains(focused.get())); 2090 EXPECT_EQ(focused.get(), 2091 client::GetFocusClient(root_window())->GetFocusedWindow()); 2092 host()->dispatcher()->DispatchCancelModeEvent(); 2093 EXPECT_EQ(focused.get(), 2094 client::GetFocusClient(root_window())->GetFocusedWindow()); 2095 } 2096 2097 // Dispatches a mouse-move event to |target| when it receives a mouse-move 2098 // event. 2099 class DispatchEventHandler : public ui::EventHandler { 2100 public: 2101 explicit DispatchEventHandler(Window* target) 2102 : target_(target), 2103 dispatched_(false) {} 2104 virtual ~DispatchEventHandler() {} 2105 2106 bool dispatched() const { return dispatched_; } 2107 private: 2108 // ui::EventHandler: 2109 virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE { 2110 if (mouse->type() == ui::ET_MOUSE_MOVED) { 2111 ui::MouseEvent move(ui::ET_MOUSE_MOVED, target_->bounds().CenterPoint(), 2112 target_->bounds().CenterPoint(), ui::EF_NONE, ui::EF_NONE); 2113 ui::EventDispatchDetails details = 2114 target_->GetHost()->dispatcher()->OnEventFromSource(&move); 2115 ASSERT_FALSE(details.dispatcher_destroyed); 2116 EXPECT_FALSE(details.target_destroyed); 2117 EXPECT_EQ(target_, move.target()); 2118 dispatched_ = true; 2119 } 2120 ui::EventHandler::OnMouseEvent(mouse); 2121 } 2122 2123 Window* target_; 2124 bool dispatched_; 2125 2126 DISALLOW_COPY_AND_ASSIGN(DispatchEventHandler); 2127 }; 2128 2129 // Moves |window| to |root_window| when it receives a mouse-move event. 2130 class MoveWindowHandler : public ui::EventHandler { 2131 public: 2132 MoveWindowHandler(Window* window, Window* root_window) 2133 : window_to_move_(window), 2134 root_window_to_move_to_(root_window) {} 2135 virtual ~MoveWindowHandler() {} 2136 2137 private: 2138 // ui::EventHandler: 2139 virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE { 2140 if (mouse->type() == ui::ET_MOUSE_MOVED) { 2141 root_window_to_move_to_->AddChild(window_to_move_); 2142 } 2143 ui::EventHandler::OnMouseEvent(mouse); 2144 } 2145 2146 Window* window_to_move_; 2147 Window* root_window_to_move_to_; 2148 2149 DISALLOW_COPY_AND_ASSIGN(MoveWindowHandler); 2150 }; 2151 2152 // Tests that nested event dispatch works correctly if the target of the older 2153 // event being dispatched is moved to a different dispatcher in response to an 2154 // event in the inner loop. 2155 TEST_F(WindowEventDispatcherTest, NestedEventDispatchTargetMoved) { 2156 scoped_ptr<WindowTreeHost> second_host( 2157 WindowTreeHost::Create(gfx::Rect(20, 30, 100, 50))); 2158 second_host->InitHost(); 2159 Window* second_root = second_host->window(); 2160 2161 // Create two windows parented to |root_window()|. 2162 test::TestWindowDelegate delegate; 2163 scoped_ptr<Window> first(CreateTestWindowWithDelegate(&delegate, 123, 2164 gfx::Rect(20, 10, 10, 20), root_window())); 2165 scoped_ptr<Window> second(CreateTestWindowWithDelegate(&delegate, 234, 2166 gfx::Rect(40, 10, 50, 20), root_window())); 2167 2168 // Setup a handler on |first| so that it dispatches an event to |second| when 2169 // |first| receives an event. 2170 DispatchEventHandler dispatch_event(second.get()); 2171 first->AddPreTargetHandler(&dispatch_event); 2172 2173 // Setup a handler on |second| so that it moves |first| into |second_root| 2174 // when |second| receives an event. 2175 MoveWindowHandler move_window(first.get(), second_root); 2176 second->AddPreTargetHandler(&move_window); 2177 2178 // Some sanity checks: |first| is inside |root_window()|'s tree. 2179 EXPECT_EQ(root_window(), first->GetRootWindow()); 2180 // The two root windows are different. 2181 EXPECT_NE(root_window(), second_root); 2182 2183 // Dispatch an event to |first|. 2184 ui::MouseEvent move(ui::ET_MOUSE_MOVED, first->bounds().CenterPoint(), 2185 first->bounds().CenterPoint(), ui::EF_NONE, ui::EF_NONE); 2186 ui::EventDispatchDetails details = 2187 host()->dispatcher()->OnEventFromSource(&move); 2188 ASSERT_FALSE(details.dispatcher_destroyed); 2189 EXPECT_TRUE(details.target_destroyed); 2190 EXPECT_EQ(first.get(), move.target()); 2191 EXPECT_TRUE(dispatch_event.dispatched()); 2192 EXPECT_EQ(second_root, first->GetRootWindow()); 2193 2194 first->RemovePreTargetHandler(&dispatch_event); 2195 second->RemovePreTargetHandler(&move_window); 2196 } 2197 2198 class AlwaysMouseDownInputStateLookup : public InputStateLookup { 2199 public: 2200 AlwaysMouseDownInputStateLookup() {} 2201 virtual ~AlwaysMouseDownInputStateLookup() {} 2202 2203 private: 2204 // InputStateLookup: 2205 virtual bool IsMouseButtonDown() const OVERRIDE { return true; } 2206 2207 DISALLOW_COPY_AND_ASSIGN(AlwaysMouseDownInputStateLookup); 2208 }; 2209 2210 TEST_F(WindowEventDispatcherTest, 2211 CursorVisibilityChangedWhileCaptureWindowInAnotherDispatcher) { 2212 test::EventCountDelegate delegate; 2213 scoped_ptr<Window> window(CreateTestWindowWithDelegate(&delegate, 123, 2214 gfx::Rect(20, 10, 10, 20), root_window())); 2215 window->Show(); 2216 2217 scoped_ptr<WindowTreeHost> second_host( 2218 WindowTreeHost::Create(gfx::Rect(20, 30, 100, 50))); 2219 second_host->InitHost(); 2220 WindowEventDispatcher* second_dispatcher = second_host->dispatcher(); 2221 2222 // Install an InputStateLookup on the Env that always claims that a 2223 // mouse-button is down. 2224 test::EnvTestHelper(Env::GetInstance()).SetInputStateLookup( 2225 scoped_ptr<InputStateLookup>(new AlwaysMouseDownInputStateLookup())); 2226 2227 window->SetCapture(); 2228 2229 // Because the mouse button is down, setting the capture on |window| will set 2230 // it as the mouse-move handler for |root_window()|. 2231 EXPECT_EQ(window.get(), host()->dispatcher()->mouse_moved_handler()); 2232 2233 // This does not set |window| as the mouse-move handler for the second 2234 // dispatcher. 2235 EXPECT_EQ(NULL, second_dispatcher->mouse_moved_handler()); 2236 2237 // However, some capture-client updates the capture in each root-window on a 2238 // capture. Emulate that here. Because of this, the second dispatcher also has 2239 // |window| as the mouse-move handler. 2240 client::CaptureDelegate* second_capture_delegate = second_dispatcher; 2241 second_capture_delegate->UpdateCapture(NULL, window.get()); 2242 EXPECT_EQ(window.get(), second_dispatcher->mouse_moved_handler()); 2243 2244 // Reset the mouse-event counts for |window|. 2245 delegate.GetMouseMotionCountsAndReset(); 2246 2247 // Notify both hosts that the cursor is now hidden. This should send a single 2248 // mouse-exit event to |window|. 2249 host()->OnCursorVisibilityChanged(false); 2250 second_host->OnCursorVisibilityChanged(false); 2251 EXPECT_EQ("0 0 1", delegate.GetMouseMotionCountsAndReset()); 2252 } 2253 2254 TEST_F(WindowEventDispatcherTest, 2255 RedirectedEventToDifferentDispatcherLocation) { 2256 scoped_ptr<WindowTreeHost> second_host( 2257 WindowTreeHost::Create(gfx::Rect(20, 30, 100, 50))); 2258 second_host->InitHost(); 2259 client::SetCaptureClient(second_host->window(), 2260 client::GetCaptureClient(root_window())); 2261 2262 test::EventCountDelegate delegate; 2263 scoped_ptr<Window> window_first(CreateTestWindowWithDelegate(&delegate, 123, 2264 gfx::Rect(20, 10, 10, 20), root_window())); 2265 window_first->Show(); 2266 2267 scoped_ptr<Window> window_second(CreateTestWindowWithDelegate(&delegate, 12, 2268 gfx::Rect(10, 10, 20, 30), second_host->window())); 2269 window_second->Show(); 2270 2271 window_second->SetCapture(); 2272 EXPECT_EQ(window_second.get(), 2273 client::GetCaptureWindow(root_window())); 2274 2275 // Send an event to the first host. Make sure it goes to |window_second| in 2276 // |second_host| instead (since it has capture). 2277 EventFilterRecorder recorder_first; 2278 window_first->AddPreTargetHandler(&recorder_first); 2279 EventFilterRecorder recorder_second; 2280 window_second->AddPreTargetHandler(&recorder_second); 2281 const gfx::Point event_location(25, 15); 2282 ui::MouseEvent mouse(ui::ET_MOUSE_PRESSED, event_location, 2283 event_location, ui::EF_LEFT_MOUSE_BUTTON, 2284 ui::EF_LEFT_MOUSE_BUTTON); 2285 DispatchEventUsingWindowDispatcher(&mouse); 2286 EXPECT_TRUE(recorder_first.events().empty()); 2287 ASSERT_EQ(1u, recorder_second.events().size()); 2288 EXPECT_EQ(ui::ET_MOUSE_PRESSED, recorder_second.events()[0]); 2289 EXPECT_EQ(event_location.ToString(), 2290 recorder_second.mouse_locations()[0].ToString()); 2291 } 2292 2293 class AsyncWindowDelegate : public test::TestWindowDelegate { 2294 public: 2295 AsyncWindowDelegate(WindowEventDispatcher* dispatcher) 2296 : dispatcher_(dispatcher) {} 2297 2298 void set_window(Window* window) { 2299 window_ = window; 2300 } 2301 private: 2302 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE { 2303 // Convert touch event back to root window coordinates. 2304 event->ConvertLocationToTarget(window_, window_->GetRootWindow()); 2305 dispatcher_->ProcessedTouchEvent(event, window_, ui::ER_UNHANDLED); 2306 event->StopPropagation(); 2307 } 2308 2309 WindowEventDispatcher* dispatcher_; 2310 Window* window_; 2311 2312 DISALLOW_COPY_AND_ASSIGN(AsyncWindowDelegate); 2313 }; 2314 2315 // Tests that gesture events dispatched through the asynchronous flow have 2316 // co-ordinates in the right co-ordinate space. 2317 TEST_F(WindowEventDispatcherTest, GestureEventCoordinates) { 2318 const float kX = 67.3f; 2319 const float kY = 97.8f; 2320 2321 const int kWindowOffset = 50; 2322 EventFilterRecorder recorder; 2323 root_window()->AddPreTargetHandler(&recorder); 2324 AsyncWindowDelegate delegate(host()->dispatcher()); 2325 HoldPointerOnScrollHandler handler(host()->dispatcher(), &recorder); 2326 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( 2327 &delegate, 2328 1, 2329 gfx::Rect(kWindowOffset, kWindowOffset, 100, 100), 2330 root_window())); 2331 window->AddPreTargetHandler(&handler); 2332 2333 delegate.set_window(window.get()); 2334 2335 ui::TouchEvent touch_pressed_event( 2336 ui::ET_TOUCH_PRESSED, gfx::PointF(kX, kY), 0, ui::EventTimeForNow()); 2337 2338 DispatchEventUsingWindowDispatcher(&touch_pressed_event); 2339 2340 ASSERT_EQ(1u, recorder.touch_locations().size()); 2341 EXPECT_EQ(gfx::Point(kX - kWindowOffset, kY - kWindowOffset).ToString(), 2342 recorder.touch_locations()[0].ToString()); 2343 2344 ASSERT_EQ(2u, recorder.gesture_locations().size()); 2345 EXPECT_EQ(gfx::Point(kX - kWindowOffset, kY - kWindowOffset).ToString(), 2346 recorder.gesture_locations()[0].ToString()); 2347 } 2348 2349 } // namespace aura 2350