1// Copyright 2014 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 "base/bind.h" 8#include "base/debug/trace_event.h" 9#include "base/logging.h" 10#include "base/message_loop/message_loop.h" 11#include "ui/aura/client/capture_client.h" 12#include "ui/aura/client/cursor_client.h" 13#include "ui/aura/client/event_client.h" 14#include "ui/aura/client/focus_client.h" 15#include "ui/aura/client/screen_position_client.h" 16#include "ui/aura/env.h" 17#include "ui/aura/window.h" 18#include "ui/aura/window_delegate.h" 19#include "ui/aura/window_targeter.h" 20#include "ui/aura/window_tracker.h" 21#include "ui/aura/window_tree_host.h" 22#include "ui/base/hit_test.h" 23#include "ui/compositor/dip_util.h" 24#include "ui/events/event.h" 25#include "ui/events/gestures/gesture_recognizer.h" 26#include "ui/events/gestures/gesture_types.h" 27 28typedef ui::EventDispatchDetails DispatchDetails; 29 30namespace aura { 31 32namespace { 33 34// Returns true if |target| has a non-client (frame) component at |location|, 35// in window coordinates. 36bool IsNonClientLocation(Window* target, const gfx::Point& location) { 37 if (!target->delegate()) 38 return false; 39 int hit_test_code = target->delegate()->GetNonClientComponent(location); 40 return hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE; 41} 42 43Window* ConsumerToWindow(ui::GestureConsumer* consumer) { 44 return consumer ? static_cast<Window*>(consumer) : NULL; 45} 46 47void SetLastMouseLocation(const Window* root_window, 48 const gfx::Point& location_in_root) { 49 client::ScreenPositionClient* client = 50 client::GetScreenPositionClient(root_window); 51 if (client) { 52 gfx::Point location_in_screen = location_in_root; 53 client->ConvertPointToScreen(root_window, &location_in_screen); 54 Env::GetInstance()->set_last_mouse_location(location_in_screen); 55 } else { 56 Env::GetInstance()->set_last_mouse_location(location_in_root); 57 } 58} 59 60bool IsEventCandidateForHold(const ui::Event& event) { 61 if (event.type() == ui::ET_TOUCH_MOVED) 62 return true; 63 if (event.type() == ui::ET_MOUSE_DRAGGED) 64 return true; 65 if (event.IsMouseEvent() && (event.flags() & ui::EF_IS_SYNTHESIZED)) 66 return true; 67 return false; 68} 69 70} // namespace 71 72//////////////////////////////////////////////////////////////////////////////// 73// WindowEventDispatcher, public: 74 75WindowEventDispatcher::WindowEventDispatcher(WindowTreeHost* host) 76 : host_(host), 77 touch_ids_down_(0), 78 mouse_pressed_handler_(NULL), 79 mouse_moved_handler_(NULL), 80 event_dispatch_target_(NULL), 81 old_dispatch_target_(NULL), 82 synthesize_mouse_move_(false), 83 move_hold_count_(0), 84 dispatching_held_event_(false), 85 observer_manager_(this), 86 repost_event_factory_(this), 87 held_event_factory_(this) { 88 ui::GestureRecognizer::Get()->AddGestureEventHelper(this); 89 Env::GetInstance()->AddObserver(this); 90} 91 92WindowEventDispatcher::~WindowEventDispatcher() { 93 TRACE_EVENT0("shutdown", "WindowEventDispatcher::Destructor"); 94 Env::GetInstance()->RemoveObserver(this); 95 ui::GestureRecognizer::Get()->RemoveGestureEventHelper(this); 96} 97 98void WindowEventDispatcher::RepostEvent(const ui::LocatedEvent& event) { 99 DCHECK(event.type() == ui::ET_MOUSE_PRESSED || 100 event.type() == ui::ET_GESTURE_TAP_DOWN); 101 // We allow for only one outstanding repostable event. This is used 102 // in exiting context menus. A dropped repost request is allowed. 103 if (event.type() == ui::ET_MOUSE_PRESSED) { 104 held_repostable_event_.reset( 105 new ui::MouseEvent( 106 static_cast<const ui::MouseEvent&>(event), 107 static_cast<aura::Window*>(event.target()), 108 window())); 109 base::MessageLoop::current()->PostNonNestableTask( 110 FROM_HERE, base::Bind( 111 base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents), 112 repost_event_factory_.GetWeakPtr())); 113 } else { 114 DCHECK(event.type() == ui::ET_GESTURE_TAP_DOWN); 115 held_repostable_event_.reset(); 116 // TODO(rbyers): Reposing of gestures is tricky to get 117 // right, so it's not yet supported. crbug.com/170987. 118 } 119} 120 121void WindowEventDispatcher::OnMouseEventsEnableStateChanged(bool enabled) { 122 // Send entered / exited so that visual state can be updated to match 123 // mouse events state. 124 PostSynthesizeMouseMove(); 125 // TODO(mazda): Add code to disable mouse events when |enabled| == false. 126} 127 128void WindowEventDispatcher::DispatchCancelModeEvent() { 129 ui::CancelModeEvent event; 130 Window* focused_window = client::GetFocusClient(window())->GetFocusedWindow(); 131 if (focused_window && !window()->Contains(focused_window)) 132 focused_window = NULL; 133 DispatchDetails details = 134 DispatchEvent(focused_window ? focused_window : window(), &event); 135 if (details.dispatcher_destroyed) 136 return; 137} 138 139void WindowEventDispatcher::DispatchGestureEvent(ui::GestureEvent* event) { 140 DispatchDetails details = DispatchHeldEvents(); 141 if (details.dispatcher_destroyed) 142 return; 143 144 Window* target = GetGestureTarget(event); 145 if (target) { 146 event->ConvertLocationToTarget(window(), target); 147 DispatchDetails details = DispatchEvent(target, event); 148 if (details.dispatcher_destroyed) 149 return; 150 } 151} 152 153void WindowEventDispatcher::DispatchMouseExitAtPoint(const gfx::Point& point) { 154 ui::MouseEvent event(ui::ET_MOUSE_EXITED, point, point, ui::EF_NONE, 155 ui::EF_NONE); 156 DispatchDetails details = 157 DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED); 158 if (details.dispatcher_destroyed) 159 return; 160} 161 162void WindowEventDispatcher::ProcessedTouchEvent(ui::TouchEvent* event, 163 Window* window, 164 ui::EventResult result) { 165 scoped_ptr<ui::GestureRecognizer::Gestures> gestures; 166 gestures.reset(ui::GestureRecognizer::Get()-> 167 ProcessTouchEventForGesture(*event, result, window)); 168 DispatchDetails details = ProcessGestures(gestures.get()); 169 if (details.dispatcher_destroyed) 170 return; 171} 172 173void WindowEventDispatcher::HoldPointerMoves() { 174 if (!move_hold_count_) 175 held_event_factory_.InvalidateWeakPtrs(); 176 ++move_hold_count_; 177 TRACE_EVENT_ASYNC_BEGIN0("ui", "WindowEventDispatcher::HoldPointerMoves", 178 this); 179} 180 181void WindowEventDispatcher::ReleasePointerMoves() { 182 --move_hold_count_; 183 DCHECK_GE(move_hold_count_, 0); 184 if (!move_hold_count_ && held_move_event_) { 185 // We don't want to call DispatchHeldEvents directly, because this might be 186 // called from a deep stack while another event, in which case dispatching 187 // another one may not be safe/expected. Instead we post a task, that we 188 // may cancel if HoldPointerMoves is called again before it executes. 189 base::MessageLoop::current()->PostNonNestableTask( 190 FROM_HERE, base::Bind( 191 base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents), 192 held_event_factory_.GetWeakPtr())); 193 } 194 TRACE_EVENT_ASYNC_END0("ui", "WindowEventDispatcher::HoldPointerMoves", this); 195} 196 197gfx::Point WindowEventDispatcher::GetLastMouseLocationInRoot() const { 198 gfx::Point location = Env::GetInstance()->last_mouse_location(); 199 client::ScreenPositionClient* client = 200 client::GetScreenPositionClient(window()); 201 if (client) 202 client->ConvertPointFromScreen(window(), &location); 203 return location; 204} 205 206void WindowEventDispatcher::OnHostLostMouseGrab() { 207 mouse_pressed_handler_ = NULL; 208 mouse_moved_handler_ = NULL; 209} 210 211void WindowEventDispatcher::OnCursorMovedToRootLocation( 212 const gfx::Point& root_location) { 213 SetLastMouseLocation(window(), root_location); 214 synthesize_mouse_move_ = false; 215} 216 217void WindowEventDispatcher::OnPostNotifiedWindowDestroying(Window* window) { 218 OnWindowHidden(window, WINDOW_DESTROYED); 219} 220 221//////////////////////////////////////////////////////////////////////////////// 222// WindowEventDispatcher, private: 223 224Window* WindowEventDispatcher::window() { 225 return host_->window(); 226} 227 228const Window* WindowEventDispatcher::window() const { 229 return host_->window(); 230} 231 232void WindowEventDispatcher::TransformEventForDeviceScaleFactor( 233 ui::LocatedEvent* event) { 234 event->UpdateForRootTransform(host_->GetInverseRootTransform()); 235} 236 237void WindowEventDispatcher::DispatchMouseExitToHidingWindow(Window* window) { 238 // The mouse capture is intentionally ignored. Think that a mouse enters 239 // to a window, the window sets the capture, the mouse exits the window, 240 // and then it releases the capture. In that case OnMouseExited won't 241 // be called. So it is natural not to emit OnMouseExited even though 242 // |window| is the capture window. 243 gfx::Point last_mouse_location = GetLastMouseLocationInRoot(); 244 if (window->Contains(mouse_moved_handler_) && 245 window->ContainsPointInRoot(last_mouse_location)) 246 DispatchMouseExitAtPoint(last_mouse_location); 247} 248 249ui::EventDispatchDetails WindowEventDispatcher::DispatchMouseEnterOrExit( 250 const ui::MouseEvent& event, 251 ui::EventType type) { 252 if (event.type() != ui::ET_MOUSE_CAPTURE_CHANGED && 253 !(event.flags() & ui::EF_IS_SYNTHESIZED)) { 254 SetLastMouseLocation(window(), event.root_location()); 255 } 256 257 if (!mouse_moved_handler_ || !mouse_moved_handler_->delegate() || 258 !window()->Contains(mouse_moved_handler_)) 259 return DispatchDetails(); 260 261 // |event| may be an event in the process of being dispatched to a target (in 262 // which case its locations will be in the event's target's coordinate 263 // system), or a synthetic event created in root-window (in which case, the 264 // event's target will be NULL, and the event will be in the root-window's 265 // coordinate system. 266 aura::Window* target = static_cast<Window*>(event.target()); 267 if (!target) 268 target = window(); 269 ui::MouseEvent translated_event(event, 270 target, 271 mouse_moved_handler_, 272 type, 273 event.flags() | ui::EF_IS_SYNTHESIZED); 274 return DispatchEvent(mouse_moved_handler_, &translated_event); 275} 276 277ui::EventDispatchDetails WindowEventDispatcher::ProcessGestures( 278 ui::GestureRecognizer::Gestures* gestures) { 279 DispatchDetails details; 280 if (!gestures || gestures->empty()) 281 return details; 282 283 Window* target = GetGestureTarget(gestures->get().at(0)); 284 if (!target) 285 return details; 286 287 for (size_t i = 0; i < gestures->size(); ++i) { 288 ui::GestureEvent* event = gestures->get().at(i); 289 event->ConvertLocationToTarget(window(), target); 290 details = DispatchEvent(target, event); 291 if (details.dispatcher_destroyed || details.target_destroyed) 292 break; 293 } 294 return details; 295} 296 297void WindowEventDispatcher::OnWindowHidden(Window* invisible, 298 WindowHiddenReason reason) { 299 // If the window the mouse was pressed in becomes invisible, it should no 300 // longer receive mouse events. 301 if (invisible->Contains(mouse_pressed_handler_)) 302 mouse_pressed_handler_ = NULL; 303 if (invisible->Contains(mouse_moved_handler_)) 304 mouse_moved_handler_ = NULL; 305 306 // If events are being dispatched from a nested message-loop, and the target 307 // of the outer loop is hidden or moved to another dispatcher during 308 // dispatching events in the inner loop, then reset the target for the outer 309 // loop. 310 if (invisible->Contains(old_dispatch_target_)) 311 old_dispatch_target_ = NULL; 312 313 invisible->CleanupGestureState(); 314 315 // Do not clear the capture, and the |event_dispatch_target_| if the 316 // window is moving across hosts, because the target itself is actually still 317 // visible and clearing them stops further event processing, which can cause 318 // unexpected behaviors. See crbug.com/157583 319 if (reason != WINDOW_MOVING) { 320 // We don't ask |invisible| here, because invisible may have been removed 321 // from the window hierarchy already by the time this function is called 322 // (OnWindowDestroyed). 323 client::CaptureClient* capture_client = 324 client::GetCaptureClient(host_->window()); 325 Window* capture_window = 326 capture_client ? capture_client->GetCaptureWindow() : NULL; 327 328 if (invisible->Contains(event_dispatch_target_)) 329 event_dispatch_target_ = NULL; 330 331 // If the ancestor of the capture window is hidden, release the capture. 332 // Note that this may delete the window so do not use capture_window 333 // after this. 334 if (invisible->Contains(capture_window) && invisible != window()) 335 capture_window->ReleaseCapture(); 336 } 337} 338 339Window* WindowEventDispatcher::GetGestureTarget(ui::GestureEvent* event) { 340 Window* target = NULL; 341 if (!event->IsEndingEvent()) { 342 // The window that received the start event (e.g. scroll begin) needs to 343 // receive the end event (e.g. scroll end). 344 target = client::GetCaptureWindow(window()); 345 } 346 if (!target) { 347 target = ConsumerToWindow( 348 ui::GestureRecognizer::Get()->GetTargetForGestureEvent(*event)); 349 } 350 351 return target; 352} 353 354//////////////////////////////////////////////////////////////////////////////// 355// WindowEventDispatcher, aura::client::CaptureDelegate implementation: 356 357void WindowEventDispatcher::UpdateCapture(Window* old_capture, 358 Window* new_capture) { 359 // |mouse_moved_handler_| may have been set to a Window in a different root 360 // (see below). Clear it here to ensure we don't end up referencing a stale 361 // Window. 362 if (mouse_moved_handler_ && !window()->Contains(mouse_moved_handler_)) 363 mouse_moved_handler_ = NULL; 364 365 if (old_capture && old_capture->GetRootWindow() == window() && 366 old_capture->delegate()) { 367 // Send a capture changed event with bogus location data. 368 ui::MouseEvent event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(), 369 gfx::Point(), 0, 0); 370 371 DispatchDetails details = DispatchEvent(old_capture, &event); 372 if (details.dispatcher_destroyed) 373 return; 374 375 old_capture->delegate()->OnCaptureLost(); 376 } 377 378 if (new_capture) { 379 // Make all subsequent mouse events go to the capture window. We shouldn't 380 // need to send an event here as OnCaptureLost() should take care of that. 381 if (mouse_moved_handler_ || Env::GetInstance()->IsMouseButtonDown()) 382 mouse_moved_handler_ = new_capture; 383 } else { 384 // Make sure mouse_moved_handler gets updated. 385 DispatchDetails details = SynthesizeMouseMoveEvent(); 386 if (details.dispatcher_destroyed) 387 return; 388 } 389 mouse_pressed_handler_ = NULL; 390} 391 392void WindowEventDispatcher::OnOtherRootGotCapture() { 393 mouse_moved_handler_ = NULL; 394 mouse_pressed_handler_ = NULL; 395} 396 397void WindowEventDispatcher::SetNativeCapture() { 398 host_->SetCapture(); 399} 400 401void WindowEventDispatcher::ReleaseNativeCapture() { 402 host_->ReleaseCapture(); 403} 404 405//////////////////////////////////////////////////////////////////////////////// 406// WindowEventDispatcher, ui::EventProcessor implementation: 407ui::EventTarget* WindowEventDispatcher::GetRootTarget() { 408 return window(); 409} 410 411void WindowEventDispatcher::PrepareEventForDispatch(ui::Event* event) { 412 if (dispatching_held_event_) { 413 // The held events are already in |window()|'s coordinate system. So it is 414 // not necessary to apply the transform to convert from the host's 415 // coordinate system to |window()|'s coordinate system. 416 return; 417 } 418 if (event->IsMouseEvent() || 419 event->IsScrollEvent() || 420 event->IsTouchEvent() || 421 event->IsGestureEvent()) { 422 TransformEventForDeviceScaleFactor(static_cast<ui::LocatedEvent*>(event)); 423 } 424} 425 426//////////////////////////////////////////////////////////////////////////////// 427// WindowEventDispatcher, ui::EventDispatcherDelegate implementation: 428 429bool WindowEventDispatcher::CanDispatchToTarget(ui::EventTarget* target) { 430 return event_dispatch_target_ == target; 431} 432 433ui::EventDispatchDetails WindowEventDispatcher::PreDispatchEvent( 434 ui::EventTarget* target, 435 ui::Event* event) { 436 Window* target_window = static_cast<Window*>(target); 437 CHECK(window()->Contains(target_window)); 438 439 if (!dispatching_held_event_) { 440 bool can_be_held = IsEventCandidateForHold(*event); 441 if (!move_hold_count_ || !can_be_held) { 442 if (can_be_held) 443 held_move_event_.reset(); 444 DispatchDetails details = DispatchHeldEvents(); 445 if (details.dispatcher_destroyed || details.target_destroyed) 446 return details; 447 } 448 } 449 450 if (event->IsMouseEvent()) { 451 PreDispatchMouseEvent(target_window, static_cast<ui::MouseEvent*>(event)); 452 } else if (event->IsScrollEvent()) { 453 PreDispatchLocatedEvent(target_window, 454 static_cast<ui::ScrollEvent*>(event)); 455 } else if (event->IsTouchEvent()) { 456 PreDispatchTouchEvent(target_window, static_cast<ui::TouchEvent*>(event)); 457 } 458 old_dispatch_target_ = event_dispatch_target_; 459 event_dispatch_target_ = static_cast<Window*>(target); 460 return DispatchDetails(); 461} 462 463ui::EventDispatchDetails WindowEventDispatcher::PostDispatchEvent( 464 ui::EventTarget* target, 465 const ui::Event& event) { 466 DispatchDetails details; 467 if (!target || target != event_dispatch_target_) 468 details.target_destroyed = true; 469 event_dispatch_target_ = old_dispatch_target_; 470 old_dispatch_target_ = NULL; 471#ifndef NDEBUG 472 DCHECK(!event_dispatch_target_ || window()->Contains(event_dispatch_target_)); 473#endif 474 475 if (event.IsTouchEvent() && !details.target_destroyed) { 476 // Do not let 'held' touch events contribute to any gestures unless it is 477 // being dispatched. 478 if (dispatching_held_event_ || !held_move_event_ || 479 !held_move_event_->IsTouchEvent()) { 480 ui::TouchEvent orig_event(static_cast<const ui::TouchEvent&>(event), 481 static_cast<Window*>(event.target()), window()); 482 // Get the list of GestureEvents from GestureRecognizer. 483 scoped_ptr<ui::GestureRecognizer::Gestures> gestures; 484 gestures.reset(ui::GestureRecognizer::Get()-> 485 ProcessTouchEventForGesture(orig_event, event.result(), 486 static_cast<Window*>(target))); 487 return ProcessGestures(gestures.get()); 488 } 489 } 490 491 return details; 492} 493 494//////////////////////////////////////////////////////////////////////////////// 495// WindowEventDispatcher, ui::GestureEventHelper implementation: 496 497bool WindowEventDispatcher::CanDispatchToConsumer( 498 ui::GestureConsumer* consumer) { 499 Window* consumer_window = ConsumerToWindow(consumer); 500 return (consumer_window && consumer_window->GetRootWindow() == window()); 501} 502 503void WindowEventDispatcher::DispatchCancelTouchEvent(ui::TouchEvent* event) { 504 DispatchDetails details = OnEventFromSource(event); 505 if (details.dispatcher_destroyed) 506 return; 507} 508 509//////////////////////////////////////////////////////////////////////////////// 510// WindowEventDispatcher, WindowObserver implementation: 511 512void WindowEventDispatcher::OnWindowDestroying(Window* window) { 513 if (!host_->window()->Contains(window)) 514 return; 515 516 DispatchMouseExitToHidingWindow(window); 517 SynthesizeMouseMoveAfterChangeToWindow(window); 518} 519 520void WindowEventDispatcher::OnWindowDestroyed(Window* window) { 521 // We observe all windows regardless of what root Window (if any) they're 522 // attached to. 523 observer_manager_.Remove(window); 524} 525 526void WindowEventDispatcher::OnWindowAddedToRootWindow(Window* attached) { 527 if (!observer_manager_.IsObserving(attached)) 528 observer_manager_.Add(attached); 529 530 if (!host_->window()->Contains(attached)) 531 return; 532 533 SynthesizeMouseMoveAfterChangeToWindow(attached); 534} 535 536void WindowEventDispatcher::OnWindowRemovingFromRootWindow(Window* detached, 537 Window* new_root) { 538 if (!host_->window()->Contains(detached)) 539 return; 540 541 DCHECK(client::GetCaptureWindow(window()) != window()); 542 543 DispatchMouseExitToHidingWindow(detached); 544 SynthesizeMouseMoveAfterChangeToWindow(detached); 545 546 // Hiding the window releases capture which can implicitly destroy the window 547 // so the window may no longer be valid after this call. 548 OnWindowHidden(detached, new_root ? WINDOW_MOVING : WINDOW_HIDDEN); 549} 550 551void WindowEventDispatcher::OnWindowVisibilityChanging(Window* window, 552 bool visible) { 553 if (!host_->window()->Contains(window)) 554 return; 555 556 DispatchMouseExitToHidingWindow(window); 557} 558 559void WindowEventDispatcher::OnWindowVisibilityChanged(Window* window, 560 bool visible) { 561 if (!host_->window()->Contains(window)) 562 return; 563 564 if (window->ContainsPointInRoot(GetLastMouseLocationInRoot())) 565 PostSynthesizeMouseMove(); 566 567 // Hiding the window releases capture which can implicitly destroy the window 568 // so the window may no longer be valid after this call. 569 if (!visible) 570 OnWindowHidden(window, WINDOW_HIDDEN); 571} 572 573void WindowEventDispatcher::OnWindowBoundsChanged(Window* window, 574 const gfx::Rect& old_bounds, 575 const gfx::Rect& new_bounds) { 576 if (!host_->window()->Contains(window)) 577 return; 578 579 if (window == host_->window()) { 580 TRACE_EVENT1("ui", "WindowEventDispatcher::OnWindowBoundsChanged(root)", 581 "size", new_bounds.size().ToString()); 582 583 DispatchDetails details = DispatchHeldEvents(); 584 if (details.dispatcher_destroyed) 585 return; 586 587 synthesize_mouse_move_ = false; 588 } 589 590 if (window->IsVisible() && !window->ignore_events()) { 591 gfx::Rect old_bounds_in_root = old_bounds, new_bounds_in_root = new_bounds; 592 Window::ConvertRectToTarget(window->parent(), host_->window(), 593 &old_bounds_in_root); 594 Window::ConvertRectToTarget(window->parent(), host_->window(), 595 &new_bounds_in_root); 596 gfx::Point last_mouse_location = GetLastMouseLocationInRoot(); 597 if (old_bounds_in_root.Contains(last_mouse_location) != 598 new_bounds_in_root.Contains(last_mouse_location)) { 599 PostSynthesizeMouseMove(); 600 } 601 } 602} 603 604void WindowEventDispatcher::OnWindowTransforming(Window* window) { 605 if (!host_->window()->Contains(window)) 606 return; 607 608 SynthesizeMouseMoveAfterChangeToWindow(window); 609} 610 611void WindowEventDispatcher::OnWindowTransformed(Window* window) { 612 if (!host_->window()->Contains(window)) 613 return; 614 615 SynthesizeMouseMoveAfterChangeToWindow(window); 616} 617 618/////////////////////////////////////////////////////////////////////////////// 619// WindowEventDispatcher, EnvObserver implementation: 620 621void WindowEventDispatcher::OnWindowInitialized(Window* window) { 622 observer_manager_.Add(window); 623} 624 625//////////////////////////////////////////////////////////////////////////////// 626// WindowEventDispatcher, private: 627 628ui::EventDispatchDetails WindowEventDispatcher::DispatchHeldEvents() { 629 if (!held_repostable_event_ && !held_move_event_) 630 return DispatchDetails(); 631 632 CHECK(!dispatching_held_event_); 633 dispatching_held_event_ = true; 634 635 DispatchDetails dispatch_details; 636 if (held_repostable_event_) { 637 if (held_repostable_event_->type() == ui::ET_MOUSE_PRESSED) { 638 scoped_ptr<ui::MouseEvent> mouse_event( 639 static_cast<ui::MouseEvent*>(held_repostable_event_.release())); 640 dispatch_details = OnEventFromSource(mouse_event.get()); 641 } else { 642 // TODO(rbyers): GESTURE_TAP_DOWN not yet supported: crbug.com/170987. 643 NOTREACHED(); 644 } 645 if (dispatch_details.dispatcher_destroyed) 646 return dispatch_details; 647 } 648 649 if (held_move_event_) { 650 // If a mouse move has been synthesized, the target location is suspect, 651 // so drop the held mouse event. 652 if (held_move_event_->IsTouchEvent() || 653 (held_move_event_->IsMouseEvent() && !synthesize_mouse_move_)) { 654 dispatch_details = OnEventFromSource(held_move_event_.get()); 655 } 656 if (!dispatch_details.dispatcher_destroyed) 657 held_move_event_.reset(); 658 } 659 660 if (!dispatch_details.dispatcher_destroyed) 661 dispatching_held_event_ = false; 662 return dispatch_details; 663} 664 665void WindowEventDispatcher::PostSynthesizeMouseMove() { 666 if (synthesize_mouse_move_) 667 return; 668 synthesize_mouse_move_ = true; 669 base::MessageLoop::current()->PostNonNestableTask( 670 FROM_HERE, 671 base::Bind(base::IgnoreResult( 672 &WindowEventDispatcher::SynthesizeMouseMoveEvent), 673 held_event_factory_.GetWeakPtr())); 674} 675 676void WindowEventDispatcher::SynthesizeMouseMoveAfterChangeToWindow( 677 Window* window) { 678 if (window->IsVisible() && 679 window->ContainsPointInRoot(GetLastMouseLocationInRoot())) { 680 PostSynthesizeMouseMove(); 681 } 682} 683 684ui::EventDispatchDetails WindowEventDispatcher::SynthesizeMouseMoveEvent() { 685 DispatchDetails details; 686 if (!synthesize_mouse_move_) 687 return details; 688 synthesize_mouse_move_ = false; 689 690 // If one of the mouse buttons is currently down, then do not synthesize a 691 // mouse-move event. In such cases, aura could synthesize a DRAGGED event 692 // instead of a MOVED event, but in multi-display/multi-host scenarios, the 693 // DRAGGED event can be synthesized in the incorrect host. So avoid 694 // synthesizing any events at all. 695 if (Env::GetInstance()->mouse_button_flags()) 696 return details; 697 698 gfx::Point root_mouse_location = GetLastMouseLocationInRoot(); 699 if (!window()->bounds().Contains(root_mouse_location)) 700 return details; 701 gfx::Point host_mouse_location = root_mouse_location; 702 host_->ConvertPointToHost(&host_mouse_location); 703 ui::MouseEvent event(ui::ET_MOUSE_MOVED, 704 host_mouse_location, 705 host_mouse_location, 706 ui::EF_IS_SYNTHESIZED, 707 0); 708 return OnEventFromSource(&event); 709} 710 711void WindowEventDispatcher::PreDispatchLocatedEvent(Window* target, 712 ui::LocatedEvent* event) { 713 int flags = event->flags(); 714 if (IsNonClientLocation(target, event->location())) 715 flags |= ui::EF_IS_NON_CLIENT; 716 event->set_flags(flags); 717 718 if (!dispatching_held_event_ && 719 (event->IsMouseEvent() || event->IsScrollEvent()) && 720 !(event->flags() & ui::EF_IS_SYNTHESIZED)) { 721 if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) 722 SetLastMouseLocation(window(), event->root_location()); 723 synthesize_mouse_move_ = false; 724 } 725} 726 727void WindowEventDispatcher::PreDispatchMouseEvent(Window* target, 728 ui::MouseEvent* event) { 729 client::CursorClient* cursor_client = client::GetCursorClient(window()); 730 // We allow synthesized mouse exit events through even if mouse events are 731 // disabled. This ensures that hover state, etc on controls like buttons is 732 // cleared. 733 if (cursor_client && 734 !cursor_client->IsMouseEventsEnabled() && 735 (event->flags() & ui::EF_IS_SYNTHESIZED) && 736 (event->type() != ui::ET_MOUSE_EXITED)) { 737 event->SetHandled(); 738 return; 739 } 740 741 if (IsEventCandidateForHold(*event) && !dispatching_held_event_) { 742 if (move_hold_count_) { 743 if (!(event->flags() & ui::EF_IS_SYNTHESIZED) && 744 event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) { 745 SetLastMouseLocation(window(), event->root_location()); 746 } 747 held_move_event_.reset(new ui::MouseEvent(*event, target, window())); 748 event->SetHandled(); 749 return; 750 } else { 751 // We may have a held event for a period between the time move_hold_count_ 752 // fell to 0 and the DispatchHeldEvents executes. Since we're going to 753 // dispatch the new event directly below, we can reset the old one. 754 held_move_event_.reset(); 755 } 756 } 757 758 const int kMouseButtonFlagMask = ui::EF_LEFT_MOUSE_BUTTON | 759 ui::EF_MIDDLE_MOUSE_BUTTON | 760 ui::EF_RIGHT_MOUSE_BUTTON; 761 switch (event->type()) { 762 case ui::ET_MOUSE_EXITED: 763 if (!target || target == window()) { 764 DispatchDetails details = 765 DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED); 766 if (details.dispatcher_destroyed) { 767 event->SetHandled(); 768 return; 769 } 770 mouse_moved_handler_ = NULL; 771 } 772 break; 773 case ui::ET_MOUSE_MOVED: 774 // Send an exit to the current |mouse_moved_handler_| and an enter to 775 // |target|. Take care that both us and |target| aren't destroyed during 776 // dispatch. 777 if (target != mouse_moved_handler_) { 778 aura::Window* old_mouse_moved_handler = mouse_moved_handler_; 779 WindowTracker live_window; 780 live_window.Add(target); 781 DispatchDetails details = 782 DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED); 783 if (details.dispatcher_destroyed) { 784 event->SetHandled(); 785 return; 786 } 787 // If the |mouse_moved_handler_| changes out from under us, assume a 788 // nested message loop ran and we don't need to do anything. 789 if (mouse_moved_handler_ != old_mouse_moved_handler) { 790 event->SetHandled(); 791 return; 792 } 793 if (!live_window.Contains(target) || details.target_destroyed) { 794 mouse_moved_handler_ = NULL; 795 event->SetHandled(); 796 return; 797 } 798 live_window.Remove(target); 799 800 mouse_moved_handler_ = target; 801 details = DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_ENTERED); 802 if (details.dispatcher_destroyed || details.target_destroyed) { 803 event->SetHandled(); 804 return; 805 } 806 } 807 break; 808 case ui::ET_MOUSE_PRESSED: 809 // Don't set the mouse pressed handler for non client mouse down events. 810 // These are only sent by Windows and are not always followed with non 811 // client mouse up events which causes subsequent mouse events to be 812 // sent to the wrong target. 813 if (!(event->flags() & ui::EF_IS_NON_CLIENT) && !mouse_pressed_handler_) 814 mouse_pressed_handler_ = target; 815 Env::GetInstance()->set_mouse_button_flags( 816 event->flags() & kMouseButtonFlagMask); 817 break; 818 case ui::ET_MOUSE_RELEASED: 819 mouse_pressed_handler_ = NULL; 820 Env::GetInstance()->set_mouse_button_flags(event->flags() & 821 kMouseButtonFlagMask & ~event->changed_button_flags()); 822 break; 823 default: 824 break; 825 } 826 827 PreDispatchLocatedEvent(target, event); 828} 829 830void WindowEventDispatcher::PreDispatchTouchEvent(Window* target, 831 ui::TouchEvent* event) { 832 switch (event->type()) { 833 case ui::ET_TOUCH_PRESSED: 834 touch_ids_down_ |= (1 << event->touch_id()); 835 Env::GetInstance()->set_touch_down(touch_ids_down_ != 0); 836 break; 837 838 // Handle ET_TOUCH_CANCELLED only if it has a native event. 839 case ui::ET_TOUCH_CANCELLED: 840 if (!event->HasNativeEvent()) 841 break; 842 // fallthrough 843 case ui::ET_TOUCH_RELEASED: 844 touch_ids_down_ = (touch_ids_down_ | (1 << event->touch_id())) ^ 845 (1 << event->touch_id()); 846 Env::GetInstance()->set_touch_down(touch_ids_down_ != 0); 847 break; 848 849 case ui::ET_TOUCH_MOVED: 850 if (move_hold_count_ && !dispatching_held_event_) { 851 held_move_event_.reset(new ui::TouchEvent(*event, target, window())); 852 event->SetHandled(); 853 return; 854 } 855 break; 856 857 default: 858 NOTREACHED(); 859 break; 860 } 861 PreDispatchLocatedEvent(target, event); 862} 863 864} // namespace aura 865