Home | History | Annotate | Download | only in aura
      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 
     28 typedef ui::EventDispatchDetails DispatchDetails;
     29 
     30 namespace aura {
     31 
     32 namespace {
     33 
     34 // Returns true if |target| has a non-client (frame) component at |location|,
     35 // in window coordinates.
     36 bool 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 
     43 Window* ConsumerToWindow(ui::GestureConsumer* consumer) {
     44   return consumer ? static_cast<Window*>(consumer) : NULL;
     45 }
     46 
     47 void 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 
     60 bool 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 
     75 WindowEventDispatcher::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 
     92 WindowEventDispatcher::~WindowEventDispatcher() {
     93   TRACE_EVENT0("shutdown", "WindowEventDispatcher::Destructor");
     94   Env::GetInstance()->RemoveObserver(this);
     95   ui::GestureRecognizer::Get()->RemoveGestureEventHelper(this);
     96 }
     97 
     98 void 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 
    121 void 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 
    128 void 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 
    139 void 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 
    153 void 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 
    162 void 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 
    173 void 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 
    181 void 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 
    197 gfx::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 
    206 void WindowEventDispatcher::OnHostLostMouseGrab() {
    207   mouse_pressed_handler_ = NULL;
    208   mouse_moved_handler_ = NULL;
    209 }
    210 
    211 void WindowEventDispatcher::OnCursorMovedToRootLocation(
    212     const gfx::Point& root_location) {
    213   SetLastMouseLocation(window(), root_location);
    214   synthesize_mouse_move_ = false;
    215 }
    216 
    217 void WindowEventDispatcher::OnPostNotifiedWindowDestroying(Window* window) {
    218   OnWindowHidden(window, WINDOW_DESTROYED);
    219 }
    220 
    221 ////////////////////////////////////////////////////////////////////////////////
    222 // WindowEventDispatcher, private:
    223 
    224 Window* WindowEventDispatcher::window() {
    225   return host_->window();
    226 }
    227 
    228 const Window* WindowEventDispatcher::window() const {
    229   return host_->window();
    230 }
    231 
    232 void WindowEventDispatcher::TransformEventForDeviceScaleFactor(
    233     ui::LocatedEvent* event) {
    234   event->UpdateForRootTransform(host_->GetInverseRootTransform());
    235 }
    236 
    237 void 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 
    249 ui::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 
    277 ui::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 
    297 void 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 
    339 Window* 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 
    357 void 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 
    392 void WindowEventDispatcher::OnOtherRootGotCapture() {
    393   mouse_moved_handler_ = NULL;
    394   mouse_pressed_handler_ = NULL;
    395 }
    396 
    397 void WindowEventDispatcher::SetNativeCapture() {
    398   host_->SetCapture();
    399 }
    400 
    401 void WindowEventDispatcher::ReleaseNativeCapture() {
    402   host_->ReleaseCapture();
    403 }
    404 
    405 ////////////////////////////////////////////////////////////////////////////////
    406 // WindowEventDispatcher, ui::EventProcessor implementation:
    407 ui::EventTarget* WindowEventDispatcher::GetRootTarget() {
    408   return window();
    409 }
    410 
    411 void 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 
    429 bool WindowEventDispatcher::CanDispatchToTarget(ui::EventTarget* target) {
    430   return event_dispatch_target_ == target;
    431 }
    432 
    433 ui::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 
    463 ui::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 
    497 bool WindowEventDispatcher::CanDispatchToConsumer(
    498     ui::GestureConsumer* consumer) {
    499   Window* consumer_window = ConsumerToWindow(consumer);
    500   return (consumer_window && consumer_window->GetRootWindow() == window());
    501 }
    502 
    503 void 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 
    512 void WindowEventDispatcher::OnWindowDestroying(Window* window) {
    513   if (!host_->window()->Contains(window))
    514     return;
    515 
    516   DispatchMouseExitToHidingWindow(window);
    517   SynthesizeMouseMoveAfterChangeToWindow(window);
    518 }
    519 
    520 void 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 
    526 void 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 
    536 void 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 
    551 void WindowEventDispatcher::OnWindowVisibilityChanging(Window* window,
    552                                                        bool visible) {
    553   if (!host_->window()->Contains(window))
    554     return;
    555 
    556   DispatchMouseExitToHidingWindow(window);
    557 }
    558 
    559 void 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 
    573 void 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 
    604 void WindowEventDispatcher::OnWindowTransforming(Window* window) {
    605   if (!host_->window()->Contains(window))
    606     return;
    607 
    608   SynthesizeMouseMoveAfterChangeToWindow(window);
    609 }
    610 
    611 void WindowEventDispatcher::OnWindowTransformed(Window* window) {
    612   if (!host_->window()->Contains(window))
    613     return;
    614 
    615   SynthesizeMouseMoveAfterChangeToWindow(window);
    616 }
    617 
    618 ///////////////////////////////////////////////////////////////////////////////
    619 // WindowEventDispatcher, EnvObserver implementation:
    620 
    621 void WindowEventDispatcher::OnWindowInitialized(Window* window) {
    622   observer_manager_.Add(window);
    623 }
    624 
    625 ////////////////////////////////////////////////////////////////////////////////
    626 // WindowEventDispatcher, private:
    627 
    628 ui::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 
    665 void 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 
    676 void WindowEventDispatcher::SynthesizeMouseMoveAfterChangeToWindow(
    677     Window* window) {
    678   if (window->IsVisible() &&
    679       window->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
    680     PostSynthesizeMouseMove();
    681   }
    682 }
    683 
    684 ui::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 
    711 void 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 
    727 void 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 
    830 void 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