window_event_dispatcher.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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(ui::EF_NONE); 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 for (size_t i = 0; i < gestures->size(); ++i) { 285 ui::GestureEvent* event = gestures->get().at(i); 286 event->ConvertLocationToTarget(window(), target); 287 details = DispatchEvent(target, event); 288 if (details.dispatcher_destroyed || details.target_destroyed) 289 break; 290 } 291 return details; 292} 293 294void WindowEventDispatcher::OnWindowHidden(Window* invisible, 295 WindowHiddenReason reason) { 296 // If the window the mouse was pressed in becomes invisible, it should no 297 // longer receive mouse events. 298 if (invisible->Contains(mouse_pressed_handler_)) 299 mouse_pressed_handler_ = NULL; 300 if (invisible->Contains(mouse_moved_handler_)) 301 mouse_moved_handler_ = NULL; 302 303 // If events are being dispatched from a nested message-loop, and the target 304 // of the outer loop is hidden or moved to another dispatcher during 305 // dispatching events in the inner loop, then reset the target for the outer 306 // loop. 307 if (invisible->Contains(old_dispatch_target_)) 308 old_dispatch_target_ = NULL; 309 310 invisible->CleanupGestureState(); 311 312 // Do not clear the capture, and the |event_dispatch_target_| if the 313 // window is moving across hosts, because the target itself is actually still 314 // visible and clearing them stops further event processing, which can cause 315 // unexpected behaviors. See crbug.com/157583 316 if (reason != WINDOW_MOVING) { 317 // We don't ask |invisible| here, because invisible may have been removed 318 // from the window hierarchy already by the time this function is called 319 // (OnWindowDestroyed). 320 client::CaptureClient* capture_client = 321 client::GetCaptureClient(host_->window()); 322 Window* capture_window = 323 capture_client ? capture_client->GetCaptureWindow() : NULL; 324 325 if (invisible->Contains(event_dispatch_target_)) 326 event_dispatch_target_ = NULL; 327 328 // If the ancestor of the capture window is hidden, release the capture. 329 // Note that this may delete the window so do not use capture_window 330 // after this. 331 if (invisible->Contains(capture_window) && invisible != window()) 332 capture_window->ReleaseCapture(); 333 } 334} 335 336Window* WindowEventDispatcher::GetGestureTarget(ui::GestureEvent* event) { 337 Window* target = NULL; 338 if (!event->IsEndingEvent()) { 339 // The window that received the start event (e.g. scroll begin) needs to 340 // receive the end event (e.g. scroll end). 341 target = client::GetCaptureWindow(window()); 342 } 343 if (!target) { 344 target = ConsumerToWindow( 345 ui::GestureRecognizer::Get()->GetTargetForGestureEvent(*event)); 346 } 347 348 return target; 349} 350 351//////////////////////////////////////////////////////////////////////////////// 352// WindowEventDispatcher, aura::client::CaptureDelegate implementation: 353 354void WindowEventDispatcher::UpdateCapture(Window* old_capture, 355 Window* new_capture) { 356 // |mouse_moved_handler_| may have been set to a Window in a different root 357 // (see below). Clear it here to ensure we don't end up referencing a stale 358 // Window. 359 if (mouse_moved_handler_ && !window()->Contains(mouse_moved_handler_)) 360 mouse_moved_handler_ = NULL; 361 362 if (old_capture && old_capture->GetRootWindow() == window() && 363 old_capture->delegate()) { 364 // Send a capture changed event with bogus location data. 365 ui::MouseEvent event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(), 366 gfx::Point(), 0, 0); 367 368 DispatchDetails details = DispatchEvent(old_capture, &event); 369 if (details.dispatcher_destroyed) 370 return; 371 372 old_capture->delegate()->OnCaptureLost(); 373 } 374 375 if (new_capture) { 376 // Make all subsequent mouse events go to the capture window. We shouldn't 377 // need to send an event here as OnCaptureLost() should take care of that. 378 if (mouse_moved_handler_ || Env::GetInstance()->IsMouseButtonDown()) 379 mouse_moved_handler_ = new_capture; 380 } else { 381 // Make sure mouse_moved_handler gets updated. 382 DispatchDetails details = SynthesizeMouseMoveEvent(ui::EF_NONE); 383 if (details.dispatcher_destroyed) 384 return; 385 } 386 mouse_pressed_handler_ = NULL; 387} 388 389void WindowEventDispatcher::OnOtherRootGotCapture() { 390 mouse_moved_handler_ = NULL; 391 mouse_pressed_handler_ = NULL; 392} 393 394void WindowEventDispatcher::SetNativeCapture() { 395 host_->SetCapture(); 396} 397 398void WindowEventDispatcher::ReleaseNativeCapture() { 399 host_->ReleaseCapture(); 400} 401 402//////////////////////////////////////////////////////////////////////////////// 403// WindowEventDispatcher, ui::EventProcessor implementation: 404ui::EventTarget* WindowEventDispatcher::GetRootTarget() { 405 return window(); 406} 407 408void WindowEventDispatcher::PrepareEventForDispatch(ui::Event* event) { 409 if (dispatching_held_event_) { 410 // The held events are already in |window()|'s coordinate system. So it is 411 // not necessary to apply the transform to convert from the host's 412 // coordinate system to |window()|'s coordinate system. 413 return; 414 } 415 if (event->IsMouseEvent() || 416 event->IsScrollEvent() || 417 event->IsTouchEvent() || 418 event->IsGestureEvent()) { 419 TransformEventForDeviceScaleFactor(static_cast<ui::LocatedEvent*>(event)); 420 } 421} 422 423//////////////////////////////////////////////////////////////////////////////// 424// WindowEventDispatcher, ui::EventDispatcherDelegate implementation: 425 426bool WindowEventDispatcher::CanDispatchToTarget(ui::EventTarget* target) { 427 return event_dispatch_target_ == target; 428} 429 430ui::EventDispatchDetails WindowEventDispatcher::PreDispatchEvent( 431 ui::EventTarget* target, 432 ui::Event* event) { 433 Window* target_window = static_cast<Window*>(target); 434 CHECK(window()->Contains(target_window)); 435 436 if (!dispatching_held_event_) { 437 bool can_be_held = IsEventCandidateForHold(*event); 438 if (!move_hold_count_ || !can_be_held) { 439 if (can_be_held) 440 held_move_event_.reset(); 441 DispatchDetails details = DispatchHeldEvents(); 442 if (details.dispatcher_destroyed || details.target_destroyed) 443 return details; 444 } 445 } 446 447 if (event->IsMouseEvent()) { 448 PreDispatchMouseEvent(target_window, static_cast<ui::MouseEvent*>(event)); 449 } else if (event->IsScrollEvent()) { 450 PreDispatchLocatedEvent(target_window, 451 static_cast<ui::ScrollEvent*>(event)); 452 } else if (event->IsTouchEvent()) { 453 PreDispatchTouchEvent(target_window, static_cast<ui::TouchEvent*>(event)); 454 } 455 old_dispatch_target_ = event_dispatch_target_; 456 event_dispatch_target_ = static_cast<Window*>(target); 457 return DispatchDetails(); 458} 459 460ui::EventDispatchDetails WindowEventDispatcher::PostDispatchEvent( 461 ui::EventTarget* target, 462 const ui::Event& event) { 463 DispatchDetails details; 464 if (!target || target != event_dispatch_target_) 465 details.target_destroyed = true; 466 event_dispatch_target_ = old_dispatch_target_; 467 old_dispatch_target_ = NULL; 468#ifndef NDEBUG 469 DCHECK(!event_dispatch_target_ || window()->Contains(event_dispatch_target_)); 470#endif 471 472 if (event.IsTouchEvent() && !details.target_destroyed) { 473 // Do not let 'held' touch events contribute to any gestures. 474 if (!held_move_event_ || !held_move_event_->IsTouchEvent()) { 475 ui::TouchEvent orig_event(static_cast<const ui::TouchEvent&>(event), 476 static_cast<Window*>(event.target()), window()); 477 // Get the list of GestureEvents from GestureRecognizer. 478 scoped_ptr<ui::GestureRecognizer::Gestures> gestures; 479 gestures.reset(ui::GestureRecognizer::Get()-> 480 ProcessTouchEventForGesture(orig_event, event.result(), 481 static_cast<Window*>(target))); 482 return ProcessGestures(gestures.get()); 483 } 484 } 485 486 return details; 487} 488 489//////////////////////////////////////////////////////////////////////////////// 490// WindowEventDispatcher, ui::GestureEventHelper implementation: 491 492bool WindowEventDispatcher::CanDispatchToConsumer( 493 ui::GestureConsumer* consumer) { 494 Window* consumer_window = ConsumerToWindow(consumer); 495 return (consumer_window && consumer_window->GetRootWindow() == window()); 496} 497 498void WindowEventDispatcher::DispatchPostponedGestureEvent( 499 ui::GestureEvent* event) { 500 DispatchGestureEvent(event); 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(ui::EF_NONE); 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 // Constrain the mouse position within the new root Window size. 588 gfx::Point point; 589 if (host_->QueryMouseLocation(&point)) { 590 SetLastMouseLocation( 591 host_->window(), 592 ui::ConvertPointToDIP(host_->window()->layer(), point)); 593 } 594 synthesize_mouse_move_ = false; 595 } 596 597 if (window->IsVisible() && !window->ignore_events()) { 598 gfx::Rect old_bounds_in_root = old_bounds, new_bounds_in_root = new_bounds; 599 Window::ConvertRectToTarget(window->parent(), host_->window(), 600 &old_bounds_in_root); 601 Window::ConvertRectToTarget(window->parent(), host_->window(), 602 &new_bounds_in_root); 603 gfx::Point last_mouse_location = GetLastMouseLocationInRoot(); 604 if (old_bounds_in_root.Contains(last_mouse_location) != 605 new_bounds_in_root.Contains(last_mouse_location)) { 606 PostSynthesizeMouseMove(Env::GetInstance()->mouse_button_flags()); 607 } 608 } 609} 610 611void WindowEventDispatcher::OnWindowTransforming(Window* window) { 612 if (!host_->window()->Contains(window)) 613 return; 614 615 SynthesizeMouseMoveAfterChangeToWindow(window); 616} 617 618void WindowEventDispatcher::OnWindowTransformed(Window* window) { 619 if (!host_->window()->Contains(window)) 620 return; 621 622 SynthesizeMouseMoveAfterChangeToWindow(window); 623} 624 625/////////////////////////////////////////////////////////////////////////////// 626// WindowEventDispatcher, EnvObserver implementation: 627 628void WindowEventDispatcher::OnWindowInitialized(Window* window) { 629 observer_manager_.Add(window); 630} 631 632//////////////////////////////////////////////////////////////////////////////// 633// WindowEventDispatcher, private: 634 635ui::EventDispatchDetails WindowEventDispatcher::DispatchHeldEvents() { 636 if (!held_repostable_event_ && !held_move_event_) 637 return DispatchDetails(); 638 639 CHECK(!dispatching_held_event_); 640 dispatching_held_event_ = true; 641 642 DispatchDetails dispatch_details; 643 if (held_repostable_event_) { 644 if (held_repostable_event_->type() == ui::ET_MOUSE_PRESSED) { 645 scoped_ptr<ui::MouseEvent> mouse_event( 646 static_cast<ui::MouseEvent*>(held_repostable_event_.release())); 647 dispatch_details = OnEventFromSource(mouse_event.get()); 648 } else { 649 // TODO(rbyers): GESTURE_TAP_DOWN not yet supported: crbug.com/170987. 650 NOTREACHED(); 651 } 652 if (dispatch_details.dispatcher_destroyed) 653 return dispatch_details; 654 } 655 656 if (held_move_event_) { 657 // If a mouse move has been synthesized, the target location is suspect, 658 // so drop the held mouse event. 659 if (held_move_event_->IsTouchEvent() || 660 (held_move_event_->IsMouseEvent() && !synthesize_mouse_move_)) { 661 dispatch_details = OnEventFromSource(held_move_event_.get()); 662 } 663 if (!dispatch_details.dispatcher_destroyed) 664 held_move_event_.reset(); 665 } 666 667 if (!dispatch_details.dispatcher_destroyed) 668 dispatching_held_event_ = false; 669 return dispatch_details; 670} 671 672void WindowEventDispatcher::PostSynthesizeMouseMove(int mouse_button_flags) { 673 if (synthesize_mouse_move_) 674 return; 675 synthesize_mouse_move_ = true; 676 base::MessageLoop::current()->PostNonNestableTask( 677 FROM_HERE, 678 base::Bind(base::IgnoreResult( 679 &WindowEventDispatcher::SynthesizeMouseMoveEvent), 680 held_event_factory_.GetWeakPtr(), 681 mouse_button_flags)); 682} 683 684void WindowEventDispatcher::SynthesizeMouseMoveAfterChangeToWindow( 685 Window* window) { 686 if (window->IsVisible() && 687 window->ContainsPointInRoot(GetLastMouseLocationInRoot())) { 688 PostSynthesizeMouseMove(ui::EF_NONE); 689 } 690} 691 692ui::EventDispatchDetails WindowEventDispatcher::SynthesizeMouseMoveEvent( 693 int mouse_button_flags) { 694 DispatchDetails details; 695 if (!synthesize_mouse_move_) 696 return details; 697 synthesize_mouse_move_ = false; 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( 704 mouse_button_flags ? ui::ET_MOUSE_DRAGGED : ui::ET_MOUSE_MOVED, 705 host_mouse_location, 706 host_mouse_location, 707 ui::EF_IS_SYNTHESIZED | mouse_button_flags, 708 0); 709 return OnEventFromSource(&event); 710} 711 712void WindowEventDispatcher::PreDispatchLocatedEvent(Window* target, 713 ui::LocatedEvent* event) { 714 int flags = event->flags(); 715 if (IsNonClientLocation(target, event->location())) 716 flags |= ui::EF_IS_NON_CLIENT; 717 event->set_flags(flags); 718 719 if (!dispatching_held_event_ && 720 (event->IsMouseEvent() || event->IsScrollEvent()) && 721 !(event->flags() & ui::EF_IS_SYNTHESIZED)) { 722 if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) 723 SetLastMouseLocation(window(), event->root_location()); 724 synthesize_mouse_move_ = false; 725 } 726} 727 728void WindowEventDispatcher::PreDispatchMouseEvent(Window* target, 729 ui::MouseEvent* event) { 730 client::CursorClient* cursor_client = client::GetCursorClient(window()); 731 // We allow synthesized mouse exit events through even if mouse events are 732 // disabled. This ensures that hover state, etc on controls like buttons is 733 // cleared. 734 if (cursor_client && 735 !cursor_client->IsMouseEventsEnabled() && 736 (event->flags() & ui::EF_IS_SYNTHESIZED) && 737 (event->type() != ui::ET_MOUSE_EXITED)) { 738 event->SetHandled(); 739 return; 740 } 741 742 if (IsEventCandidateForHold(*event) && !dispatching_held_event_) { 743 if (move_hold_count_) { 744 if (!(event->flags() & ui::EF_IS_SYNTHESIZED) && 745 event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) { 746 SetLastMouseLocation(window(), event->root_location()); 747 } 748 held_move_event_.reset(new ui::MouseEvent(*event, target, window())); 749 event->SetHandled(); 750 return; 751 } else { 752 // We may have a held event for a period between the time move_hold_count_ 753 // fell to 0 and the DispatchHeldEvents executes. Since we're going to 754 // dispatch the new event directly below, we can reset the old one. 755 held_move_event_.reset(); 756 } 757 } 758 759 const int kMouseButtonFlagMask = ui::EF_LEFT_MOUSE_BUTTON | 760 ui::EF_MIDDLE_MOUSE_BUTTON | 761 ui::EF_RIGHT_MOUSE_BUTTON; 762 switch (event->type()) { 763 case ui::ET_MOUSE_EXITED: 764 if (!target || target == window()) { 765 DispatchDetails details = 766 DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED); 767 if (details.dispatcher_destroyed) { 768 event->SetHandled(); 769 return; 770 } 771 mouse_moved_handler_ = NULL; 772 } 773 break; 774 case ui::ET_MOUSE_MOVED: 775 // Send an exit to the current |mouse_moved_handler_| and an enter to 776 // |target|. Take care that both us and |target| aren't destroyed during 777 // dispatch. 778 if (target != mouse_moved_handler_) { 779 aura::Window* old_mouse_moved_handler = mouse_moved_handler_; 780 WindowTracker live_window; 781 live_window.Add(target); 782 DispatchDetails details = 783 DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED); 784 if (details.dispatcher_destroyed) { 785 event->SetHandled(); 786 return; 787 } 788 // If the |mouse_moved_handler_| changes out from under us, assume a 789 // nested message loop ran and we don't need to do anything. 790 if (mouse_moved_handler_ != old_mouse_moved_handler) { 791 event->SetHandled(); 792 return; 793 } 794 if (!live_window.Contains(target) || details.target_destroyed) { 795 mouse_moved_handler_ = NULL; 796 event->SetHandled(); 797 return; 798 } 799 live_window.Remove(target); 800 801 mouse_moved_handler_ = target; 802 details = DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_ENTERED); 803 if (details.dispatcher_destroyed || details.target_destroyed) { 804 event->SetHandled(); 805 return; 806 } 807 } 808 break; 809 case ui::ET_MOUSE_PRESSED: 810 // Don't set the mouse pressed handler for non client mouse down events. 811 // These are only sent by Windows and are not always followed with non 812 // client mouse up events which causes subsequent mouse events to be 813 // sent to the wrong target. 814 if (!(event->flags() & ui::EF_IS_NON_CLIENT) && !mouse_pressed_handler_) 815 mouse_pressed_handler_ = target; 816 Env::GetInstance()->set_mouse_button_flags( 817 event->flags() & kMouseButtonFlagMask); 818 break; 819 case ui::ET_MOUSE_RELEASED: 820 mouse_pressed_handler_ = NULL; 821 Env::GetInstance()->set_mouse_button_flags(event->flags() & 822 kMouseButtonFlagMask & ~event->changed_button_flags()); 823 break; 824 default: 825 break; 826 } 827 828 PreDispatchLocatedEvent(target, event); 829} 830 831void WindowEventDispatcher::PreDispatchTouchEvent(Window* target, 832 ui::TouchEvent* event) { 833 switch (event->type()) { 834 case ui::ET_TOUCH_PRESSED: 835 touch_ids_down_ |= (1 << event->touch_id()); 836 Env::GetInstance()->set_touch_down(touch_ids_down_ != 0); 837 break; 838 839 // Handle ET_TOUCH_CANCELLED only if it has a native event. 840 case ui::ET_TOUCH_CANCELLED: 841 if (!event->HasNativeEvent()) 842 break; 843 // fallthrough 844 case ui::ET_TOUCH_RELEASED: 845 touch_ids_down_ = (touch_ids_down_ | (1 << event->touch_id())) ^ 846 (1 << event->touch_id()); 847 Env::GetInstance()->set_touch_down(touch_ids_down_ != 0); 848 break; 849 850 case ui::ET_TOUCH_MOVED: 851 if (move_hold_count_ && !dispatching_held_event_) { 852 held_move_event_.reset(new ui::TouchEvent(*event, target, window())); 853 event->SetHandled(); 854 return; 855 } 856 break; 857 858 default: 859 NOTREACHED(); 860 break; 861 } 862 PreDispatchLocatedEvent(target, event); 863} 864 865} // namespace aura 866