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   Window* target = GetGestureTarget(event);
    144   if (target) {
    145     event->ConvertLocationToTarget(window(), target);
    146     DispatchDetails details = DispatchEvent(target, event);
    147     if (details.dispatcher_destroyed)
    148       return;
    149   }
    150 }
    151 
    152 DispatchDetails WindowEventDispatcher::DispatchMouseExitAtPoint(
    153     const gfx::Point& point) {
    154   ui::MouseEvent event(ui::ET_MOUSE_EXITED, point, point, ui::EF_NONE,
    155                        ui::EF_NONE);
    156   return DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED);
    157 }
    158 
    159 void WindowEventDispatcher::ProcessedTouchEvent(ui::TouchEvent* event,
    160                                                 Window* window,
    161                                                 ui::EventResult result) {
    162   // TODO(tdresser): Move this to PreDispatchTouchEvent, to enable eager
    163   // gesture detection. See crbug.com/410280.
    164   if (!ui::GestureRecognizer::Get()
    165            ->ProcessTouchEventPreDispatch(*event, window)) {
    166     return;
    167   }
    168 
    169   // Once we've fully migrated to the eager gesture detector, we won't need to
    170   // pass an event here.
    171   scoped_ptr<ui::GestureRecognizer::Gestures> gestures(
    172       ui::GestureRecognizer::Get()->ProcessTouchEventOnAsyncAck(
    173           *event, result, window));
    174   DispatchDetails details = ProcessGestures(gestures.get());
    175   if (details.dispatcher_destroyed)
    176     return;
    177 }
    178 
    179 void WindowEventDispatcher::HoldPointerMoves() {
    180   if (!move_hold_count_)
    181     held_event_factory_.InvalidateWeakPtrs();
    182   ++move_hold_count_;
    183   TRACE_EVENT_ASYNC_BEGIN0("ui", "WindowEventDispatcher::HoldPointerMoves",
    184                            this);
    185 }
    186 
    187 void WindowEventDispatcher::ReleasePointerMoves() {
    188   --move_hold_count_;
    189   DCHECK_GE(move_hold_count_, 0);
    190   if (!move_hold_count_ && held_move_event_) {
    191     // We don't want to call DispatchHeldEvents directly, because this might be
    192     // called from a deep stack while another event, in which case dispatching
    193     // another one may not be safe/expected.  Instead we post a task, that we
    194     // may cancel if HoldPointerMoves is called again before it executes.
    195     base::MessageLoop::current()->PostNonNestableTask(
    196         FROM_HERE, base::Bind(
    197           base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents),
    198           held_event_factory_.GetWeakPtr()));
    199   }
    200   TRACE_EVENT_ASYNC_END0("ui", "WindowEventDispatcher::HoldPointerMoves", this);
    201 }
    202 
    203 gfx::Point WindowEventDispatcher::GetLastMouseLocationInRoot() const {
    204   gfx::Point location = Env::GetInstance()->last_mouse_location();
    205   client::ScreenPositionClient* client =
    206       client::GetScreenPositionClient(window());
    207   if (client)
    208     client->ConvertPointFromScreen(window(), &location);
    209   return location;
    210 }
    211 
    212 void WindowEventDispatcher::OnHostLostMouseGrab() {
    213   mouse_pressed_handler_ = NULL;
    214   mouse_moved_handler_ = NULL;
    215 }
    216 
    217 void WindowEventDispatcher::OnCursorMovedToRootLocation(
    218     const gfx::Point& root_location) {
    219   SetLastMouseLocation(window(), root_location);
    220   synthesize_mouse_move_ = false;
    221 }
    222 
    223 void WindowEventDispatcher::OnPostNotifiedWindowDestroying(Window* window) {
    224   OnWindowHidden(window, WINDOW_DESTROYED);
    225 }
    226 
    227 ////////////////////////////////////////////////////////////////////////////////
    228 // WindowEventDispatcher, private:
    229 
    230 Window* WindowEventDispatcher::window() {
    231   return host_->window();
    232 }
    233 
    234 const Window* WindowEventDispatcher::window() const {
    235   return host_->window();
    236 }
    237 
    238 void WindowEventDispatcher::TransformEventForDeviceScaleFactor(
    239     ui::LocatedEvent* event) {
    240   event->UpdateForRootTransform(host_->GetInverseRootTransform());
    241 }
    242 
    243 void WindowEventDispatcher::DispatchMouseExitToHidingWindow(Window* window) {
    244   // The mouse capture is intentionally ignored. Think that a mouse enters
    245   // to a window, the window sets the capture, the mouse exits the window,
    246   // and then it releases the capture. In that case OnMouseExited won't
    247   // be called. So it is natural not to emit OnMouseExited even though
    248   // |window| is the capture window.
    249   gfx::Point last_mouse_location = GetLastMouseLocationInRoot();
    250   if (window->Contains(mouse_moved_handler_) &&
    251       window->ContainsPointInRoot(last_mouse_location)) {
    252     DispatchDetails details = DispatchMouseExitAtPoint(last_mouse_location);
    253     if (details.dispatcher_destroyed)
    254       return;
    255   }
    256 }
    257 
    258 ui::EventDispatchDetails WindowEventDispatcher::DispatchMouseEnterOrExit(
    259     const ui::MouseEvent& event,
    260     ui::EventType type) {
    261   if (event.type() != ui::ET_MOUSE_CAPTURE_CHANGED &&
    262       !(event.flags() & ui::EF_IS_SYNTHESIZED)) {
    263     SetLastMouseLocation(window(), event.root_location());
    264   }
    265 
    266   if (!mouse_moved_handler_ || !mouse_moved_handler_->delegate() ||
    267       !window()->Contains(mouse_moved_handler_))
    268     return DispatchDetails();
    269 
    270   // |event| may be an event in the process of being dispatched to a target (in
    271   // which case its locations will be in the event's target's coordinate
    272   // system), or a synthetic event created in root-window (in which case, the
    273   // event's target will be NULL, and the event will be in the root-window's
    274   // coordinate system.
    275   aura::Window* target = static_cast<Window*>(event.target());
    276   if (!target)
    277     target = window();
    278   ui::MouseEvent translated_event(event,
    279                                   target,
    280                                   mouse_moved_handler_,
    281                                   type,
    282                                   event.flags() | ui::EF_IS_SYNTHESIZED);
    283   return DispatchEvent(mouse_moved_handler_, &translated_event);
    284 }
    285 
    286 ui::EventDispatchDetails WindowEventDispatcher::ProcessGestures(
    287     ui::GestureRecognizer::Gestures* gestures) {
    288   DispatchDetails details;
    289   if (!gestures || gestures->empty())
    290     return details;
    291 
    292   Window* target = GetGestureTarget(gestures->get().at(0));
    293   if (!target)
    294     return details;
    295 
    296   for (size_t i = 0; i < gestures->size(); ++i) {
    297     ui::GestureEvent* event = gestures->get().at(i);
    298     event->ConvertLocationToTarget(window(), target);
    299     details = DispatchEvent(target, event);
    300     if (details.dispatcher_destroyed || details.target_destroyed)
    301       break;
    302   }
    303   return details;
    304 }
    305 
    306 void WindowEventDispatcher::OnWindowHidden(Window* invisible,
    307                                            WindowHiddenReason reason) {
    308   // If the window the mouse was pressed in becomes invisible, it should no
    309   // longer receive mouse events.
    310   if (invisible->Contains(mouse_pressed_handler_))
    311     mouse_pressed_handler_ = NULL;
    312   if (invisible->Contains(mouse_moved_handler_))
    313     mouse_moved_handler_ = NULL;
    314 
    315   // If events are being dispatched from a nested message-loop, and the target
    316   // of the outer loop is hidden or moved to another dispatcher during
    317   // dispatching events in the inner loop, then reset the target for the outer
    318   // loop.
    319   if (invisible->Contains(old_dispatch_target_))
    320     old_dispatch_target_ = NULL;
    321 
    322   invisible->CleanupGestureState();
    323 
    324   // Do not clear the capture, and the |event_dispatch_target_| if the
    325   // window is moving across hosts, because the target itself is actually still
    326   // visible and clearing them stops further event processing, which can cause
    327   // unexpected behaviors. See crbug.com/157583
    328   if (reason != WINDOW_MOVING) {
    329     // We don't ask |invisible| here, because invisible may have been removed
    330     // from the window hierarchy already by the time this function is called
    331     // (OnWindowDestroyed).
    332     client::CaptureClient* capture_client =
    333         client::GetCaptureClient(host_->window());
    334     Window* capture_window =
    335         capture_client ? capture_client->GetCaptureWindow() : NULL;
    336 
    337     if (invisible->Contains(event_dispatch_target_))
    338       event_dispatch_target_ = NULL;
    339 
    340     // If the ancestor of the capture window is hidden, release the capture.
    341     // Note that this may delete the window so do not use capture_window
    342     // after this.
    343     if (invisible->Contains(capture_window) && invisible != window())
    344       capture_window->ReleaseCapture();
    345   }
    346 }
    347 
    348 Window* WindowEventDispatcher::GetGestureTarget(ui::GestureEvent* event) {
    349   Window* target = NULL;
    350   if (!event->IsEndingEvent()) {
    351     // The window that received the start event (e.g. scroll begin) needs to
    352     // receive the end event (e.g. scroll end).
    353     target = client::GetCaptureWindow(window());
    354   }
    355   if (!target) {
    356     target = ConsumerToWindow(
    357         ui::GestureRecognizer::Get()->GetTargetForGestureEvent(*event));
    358   }
    359 
    360   return target;
    361 }
    362 
    363 ////////////////////////////////////////////////////////////////////////////////
    364 // WindowEventDispatcher, aura::client::CaptureDelegate implementation:
    365 
    366 void WindowEventDispatcher::UpdateCapture(Window* old_capture,
    367                                           Window* new_capture) {
    368   // |mouse_moved_handler_| may have been set to a Window in a different root
    369   // (see below). Clear it here to ensure we don't end up referencing a stale
    370   // Window.
    371   if (mouse_moved_handler_ && !window()->Contains(mouse_moved_handler_))
    372     mouse_moved_handler_ = NULL;
    373 
    374   if (old_capture && old_capture->GetRootWindow() == window() &&
    375       old_capture->delegate()) {
    376     // Send a capture changed event with bogus location data.
    377     ui::MouseEvent event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(),
    378                          gfx::Point(), 0, 0);
    379 
    380     DispatchDetails details = DispatchEvent(old_capture, &event);
    381     if (details.dispatcher_destroyed)
    382       return;
    383 
    384     old_capture->delegate()->OnCaptureLost();
    385   }
    386 
    387   if (new_capture) {
    388     // Make all subsequent mouse events go to the capture window. We shouldn't
    389     // need to send an event here as OnCaptureLost() should take care of that.
    390     if (mouse_moved_handler_ || Env::GetInstance()->IsMouseButtonDown())
    391       mouse_moved_handler_ = new_capture;
    392   } else {
    393     // Make sure mouse_moved_handler gets updated.
    394     DispatchDetails details = SynthesizeMouseMoveEvent();
    395     if (details.dispatcher_destroyed)
    396       return;
    397   }
    398   mouse_pressed_handler_ = NULL;
    399 }
    400 
    401 void WindowEventDispatcher::OnOtherRootGotCapture() {
    402   // Windows provides the TrackMouseEvents API which allows us to rely on the
    403   // OS to send us the mouse exit events (WM_MOUSELEAVE). Additionally on
    404   // desktop Windows, every top level window could potentially have its own
    405   // root window, in which case this function will get called whenever those
    406   // windows grab mouse capture. Sending mouse exit messages in these cases
    407   // causes subtle bugs like (crbug.com/394672).
    408 #if !defined(OS_WIN)
    409   if (mouse_moved_handler_) {
    410     // Dispatch a mouse exit to reset any state associated with hover. This is
    411     // important when going from no window having capture to a window having
    412     // capture because we do not dispatch ET_MOUSE_CAPTURE_CHANGED in this case.
    413     DispatchDetails details = DispatchMouseExitAtPoint(
    414         GetLastMouseLocationInRoot());
    415     if (details.dispatcher_destroyed)
    416       return;
    417   }
    418 #endif
    419 
    420   mouse_moved_handler_ = NULL;
    421   mouse_pressed_handler_ = NULL;
    422 }
    423 
    424 void WindowEventDispatcher::SetNativeCapture() {
    425   host_->SetCapture();
    426 }
    427 
    428 void WindowEventDispatcher::ReleaseNativeCapture() {
    429   host_->ReleaseCapture();
    430 }
    431 
    432 ////////////////////////////////////////////////////////////////////////////////
    433 // WindowEventDispatcher, ui::EventProcessor implementation:
    434 ui::EventTarget* WindowEventDispatcher::GetRootTarget() {
    435   return window();
    436 }
    437 
    438 void WindowEventDispatcher::PrepareEventForDispatch(ui::Event* event) {
    439   if (dispatching_held_event_) {
    440     // The held events are already in |window()|'s coordinate system. So it is
    441     // not necessary to apply the transform to convert from the host's
    442     // coordinate system to |window()|'s coordinate system.
    443     return;
    444   }
    445   if (event->IsLocatedEvent()) {
    446     TransformEventForDeviceScaleFactor(static_cast<ui::LocatedEvent*>(event));
    447   }
    448 }
    449 
    450 ////////////////////////////////////////////////////////////////////////////////
    451 // WindowEventDispatcher, ui::EventDispatcherDelegate implementation:
    452 
    453 bool WindowEventDispatcher::CanDispatchToTarget(ui::EventTarget* target) {
    454   return event_dispatch_target_ == target;
    455 }
    456 
    457 ui::EventDispatchDetails WindowEventDispatcher::PreDispatchEvent(
    458     ui::EventTarget* target,
    459     ui::Event* event) {
    460   Window* target_window = static_cast<Window*>(target);
    461   CHECK(window()->Contains(target_window));
    462 
    463   if (!dispatching_held_event_) {
    464     bool can_be_held = IsEventCandidateForHold(*event);
    465     if (!move_hold_count_ || !can_be_held) {
    466       if (can_be_held)
    467         held_move_event_.reset();
    468       DispatchDetails details = DispatchHeldEvents();
    469       if (details.dispatcher_destroyed || details.target_destroyed)
    470         return details;
    471     }
    472   }
    473 
    474   if (event->IsMouseEvent()) {
    475     PreDispatchMouseEvent(target_window, static_cast<ui::MouseEvent*>(event));
    476   } else if (event->IsScrollEvent()) {
    477     PreDispatchLocatedEvent(target_window,
    478                             static_cast<ui::ScrollEvent*>(event));
    479   } else if (event->IsTouchEvent()) {
    480     PreDispatchTouchEvent(target_window, static_cast<ui::TouchEvent*>(event));
    481   }
    482   old_dispatch_target_ = event_dispatch_target_;
    483   event_dispatch_target_ = static_cast<Window*>(target);
    484   return DispatchDetails();
    485 }
    486 
    487 ui::EventDispatchDetails WindowEventDispatcher::PostDispatchEvent(
    488     ui::EventTarget* target,
    489     const ui::Event& event) {
    490   DispatchDetails details;
    491   if (!target || target != event_dispatch_target_)
    492     details.target_destroyed = true;
    493   event_dispatch_target_ = old_dispatch_target_;
    494   old_dispatch_target_ = NULL;
    495 #ifndef NDEBUG
    496   DCHECK(!event_dispatch_target_ || window()->Contains(event_dispatch_target_));
    497 #endif
    498 
    499   if (event.IsTouchEvent() && !details.target_destroyed) {
    500     // Do not let 'held' touch events contribute to any gestures unless it is
    501     // being dispatched.
    502     if (dispatching_held_event_ || !held_move_event_ ||
    503         !held_move_event_->IsTouchEvent()) {
    504 
    505       // Once we've fully migrated to the eager gesture detector, we won't
    506       // need to pass an event here.
    507       ui::TouchEvent orig_event(static_cast<const ui::TouchEvent&>(event),
    508                                 static_cast<Window*>(event.target()),
    509                                 window());
    510 
    511       if (event.result() & ui::ER_CONSUMED)
    512         orig_event.StopPropagation();
    513 
    514       // TODO(tdresser): Move this to PreDispatchTouchEvent, to enable eager
    515       // gesture detection. See crbug.com/410280.
    516       if (!ui::GestureRecognizer::Get()
    517                ->ProcessTouchEventPreDispatch(orig_event,
    518                                               static_cast<Window*>(target))) {
    519         return details;
    520       }
    521 
    522       scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
    523 
    524       gestures.reset(
    525           ui::GestureRecognizer::Get()->ProcessTouchEventPostDispatch(
    526               orig_event, event.result(), static_cast<Window*>(target)));
    527 
    528       return ProcessGestures(gestures.get());
    529     }
    530   }
    531 
    532   return details;
    533 }
    534 
    535 ////////////////////////////////////////////////////////////////////////////////
    536 // WindowEventDispatcher, ui::GestureEventHelper implementation:
    537 
    538 bool WindowEventDispatcher::CanDispatchToConsumer(
    539     ui::GestureConsumer* consumer) {
    540   Window* consumer_window = ConsumerToWindow(consumer);
    541   return (consumer_window && consumer_window->GetRootWindow() == window());
    542 }
    543 
    544 void WindowEventDispatcher::DispatchCancelTouchEvent(ui::TouchEvent* event) {
    545   // The touchcancel event's location is based on the last known location of
    546   // the pointer, in dips. OnEventFromSource expects events with co-ordinates
    547   // in raw pixels, so we convert back to raw pixels here.
    548   event->UpdateForRootTransform(host_->GetRootTransform());
    549   DispatchDetails details = OnEventFromSource(event);
    550   if (details.dispatcher_destroyed)
    551     return;
    552 }
    553 
    554 ////////////////////////////////////////////////////////////////////////////////
    555 // WindowEventDispatcher, WindowObserver implementation:
    556 
    557 void WindowEventDispatcher::OnWindowDestroying(Window* window) {
    558   if (!host_->window()->Contains(window))
    559     return;
    560 
    561   DispatchMouseExitToHidingWindow(window);
    562   SynthesizeMouseMoveAfterChangeToWindow(window);
    563 }
    564 
    565 void WindowEventDispatcher::OnWindowDestroyed(Window* window) {
    566   // We observe all windows regardless of what root Window (if any) they're
    567   // attached to.
    568   observer_manager_.Remove(window);
    569 }
    570 
    571 void WindowEventDispatcher::OnWindowAddedToRootWindow(Window* attached) {
    572   if (!observer_manager_.IsObserving(attached))
    573     observer_manager_.Add(attached);
    574 
    575   if (!host_->window()->Contains(attached))
    576     return;
    577 
    578   SynthesizeMouseMoveAfterChangeToWindow(attached);
    579 }
    580 
    581 void WindowEventDispatcher::OnWindowRemovingFromRootWindow(Window* detached,
    582                                                            Window* new_root) {
    583   if (!host_->window()->Contains(detached))
    584     return;
    585 
    586   DCHECK(client::GetCaptureWindow(window()) != window());
    587 
    588   DispatchMouseExitToHidingWindow(detached);
    589   SynthesizeMouseMoveAfterChangeToWindow(detached);
    590 
    591   // Hiding the window releases capture which can implicitly destroy the window
    592   // so the window may no longer be valid after this call.
    593   OnWindowHidden(detached, new_root ? WINDOW_MOVING : WINDOW_HIDDEN);
    594 }
    595 
    596 void WindowEventDispatcher::OnWindowVisibilityChanging(Window* window,
    597                                                        bool visible) {
    598   if (!host_->window()->Contains(window))
    599     return;
    600 
    601   DispatchMouseExitToHidingWindow(window);
    602 }
    603 
    604 void WindowEventDispatcher::OnWindowVisibilityChanged(Window* window,
    605                                                       bool visible) {
    606   if (!host_->window()->Contains(window))
    607     return;
    608 
    609   if (window->ContainsPointInRoot(GetLastMouseLocationInRoot()))
    610     PostSynthesizeMouseMove();
    611 
    612   // Hiding the window releases capture which can implicitly destroy the window
    613   // so the window may no longer be valid after this call.
    614   if (!visible)
    615     OnWindowHidden(window, WINDOW_HIDDEN);
    616 }
    617 
    618 void WindowEventDispatcher::OnWindowBoundsChanged(Window* window,
    619                                                   const gfx::Rect& old_bounds,
    620                                                   const gfx::Rect& new_bounds) {
    621   if (!host_->window()->Contains(window))
    622     return;
    623 
    624   if (window == host_->window()) {
    625     TRACE_EVENT1("ui", "WindowEventDispatcher::OnWindowBoundsChanged(root)",
    626                  "size", new_bounds.size().ToString());
    627 
    628     DispatchDetails details = DispatchHeldEvents();
    629     if (details.dispatcher_destroyed)
    630       return;
    631 
    632     synthesize_mouse_move_ = false;
    633   }
    634 
    635   if (window->IsVisible() && !window->ignore_events()) {
    636     gfx::Rect old_bounds_in_root = old_bounds, new_bounds_in_root = new_bounds;
    637     Window::ConvertRectToTarget(window->parent(), host_->window(),
    638                                 &old_bounds_in_root);
    639     Window::ConvertRectToTarget(window->parent(), host_->window(),
    640                                 &new_bounds_in_root);
    641     gfx::Point last_mouse_location = GetLastMouseLocationInRoot();
    642     if (old_bounds_in_root.Contains(last_mouse_location) !=
    643         new_bounds_in_root.Contains(last_mouse_location)) {
    644       PostSynthesizeMouseMove();
    645     }
    646   }
    647 }
    648 
    649 void WindowEventDispatcher::OnWindowTransforming(Window* window) {
    650   if (!host_->window()->Contains(window))
    651     return;
    652 
    653   SynthesizeMouseMoveAfterChangeToWindow(window);
    654 }
    655 
    656 void WindowEventDispatcher::OnWindowTransformed(Window* window) {
    657   if (!host_->window()->Contains(window))
    658     return;
    659 
    660   SynthesizeMouseMoveAfterChangeToWindow(window);
    661 }
    662 
    663 ///////////////////////////////////////////////////////////////////////////////
    664 // WindowEventDispatcher, EnvObserver implementation:
    665 
    666 void WindowEventDispatcher::OnWindowInitialized(Window* window) {
    667   observer_manager_.Add(window);
    668 }
    669 
    670 ////////////////////////////////////////////////////////////////////////////////
    671 // WindowEventDispatcher, private:
    672 
    673 ui::EventDispatchDetails WindowEventDispatcher::DispatchHeldEvents() {
    674   if (!held_repostable_event_ && !held_move_event_)
    675     return DispatchDetails();
    676 
    677   CHECK(!dispatching_held_event_);
    678   dispatching_held_event_ = true;
    679 
    680   DispatchDetails dispatch_details;
    681   if (held_repostable_event_) {
    682     if (held_repostable_event_->type() == ui::ET_MOUSE_PRESSED) {
    683       scoped_ptr<ui::MouseEvent> mouse_event(
    684           static_cast<ui::MouseEvent*>(held_repostable_event_.release()));
    685       dispatch_details = OnEventFromSource(mouse_event.get());
    686     } else {
    687       // TODO(rbyers): GESTURE_TAP_DOWN not yet supported: crbug.com/170987.
    688       NOTREACHED();
    689     }
    690     if (dispatch_details.dispatcher_destroyed)
    691       return dispatch_details;
    692   }
    693 
    694   if (held_move_event_) {
    695     // If a mouse move has been synthesized, the target location is suspect,
    696     // so drop the held mouse event.
    697     if (held_move_event_->IsTouchEvent() ||
    698         (held_move_event_->IsMouseEvent() && !synthesize_mouse_move_)) {
    699       dispatch_details = OnEventFromSource(held_move_event_.get());
    700     }
    701     if (!dispatch_details.dispatcher_destroyed)
    702       held_move_event_.reset();
    703   }
    704 
    705   if (!dispatch_details.dispatcher_destroyed)
    706     dispatching_held_event_ = false;
    707   return dispatch_details;
    708 }
    709 
    710 void WindowEventDispatcher::PostSynthesizeMouseMove() {
    711   if (synthesize_mouse_move_)
    712     return;
    713   synthesize_mouse_move_ = true;
    714   base::MessageLoop::current()->PostNonNestableTask(
    715       FROM_HERE,
    716       base::Bind(base::IgnoreResult(
    717           &WindowEventDispatcher::SynthesizeMouseMoveEvent),
    718           held_event_factory_.GetWeakPtr()));
    719 }
    720 
    721 void WindowEventDispatcher::SynthesizeMouseMoveAfterChangeToWindow(
    722     Window* window) {
    723   if (window->IsVisible() &&
    724       window->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
    725     PostSynthesizeMouseMove();
    726   }
    727 }
    728 
    729 ui::EventDispatchDetails WindowEventDispatcher::SynthesizeMouseMoveEvent() {
    730   DispatchDetails details;
    731   if (!synthesize_mouse_move_)
    732     return details;
    733   synthesize_mouse_move_ = false;
    734 
    735   // If one of the mouse buttons is currently down, then do not synthesize a
    736   // mouse-move event. In such cases, aura could synthesize a DRAGGED event
    737   // instead of a MOVED event, but in multi-display/multi-host scenarios, the
    738   // DRAGGED event can be synthesized in the incorrect host. So avoid
    739   // synthesizing any events at all.
    740   if (Env::GetInstance()->mouse_button_flags())
    741     return details;
    742 
    743   gfx::Point root_mouse_location = GetLastMouseLocationInRoot();
    744   if (!window()->bounds().Contains(root_mouse_location))
    745     return details;
    746   gfx::Point host_mouse_location = root_mouse_location;
    747   host_->ConvertPointToHost(&host_mouse_location);
    748   ui::MouseEvent event(ui::ET_MOUSE_MOVED,
    749                        host_mouse_location,
    750                        host_mouse_location,
    751                        ui::EF_IS_SYNTHESIZED,
    752                        0);
    753   return OnEventFromSource(&event);
    754 }
    755 
    756 void WindowEventDispatcher::PreDispatchLocatedEvent(Window* target,
    757                                                     ui::LocatedEvent* event) {
    758   int flags = event->flags();
    759   if (IsNonClientLocation(target, event->location()))
    760     flags |= ui::EF_IS_NON_CLIENT;
    761   event->set_flags(flags);
    762 
    763   if (!dispatching_held_event_ &&
    764       (event->IsMouseEvent() || event->IsScrollEvent()) &&
    765       !(event->flags() & ui::EF_IS_SYNTHESIZED)) {
    766     if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)
    767       SetLastMouseLocation(window(), event->root_location());
    768     synthesize_mouse_move_ = false;
    769   }
    770 }
    771 
    772 void WindowEventDispatcher::PreDispatchMouseEvent(Window* target,
    773                                                   ui::MouseEvent* event) {
    774   client::CursorClient* cursor_client = client::GetCursorClient(window());
    775   // We allow synthesized mouse exit events through even if mouse events are
    776   // disabled. This ensures that hover state, etc on controls like buttons is
    777   // cleared.
    778   if (cursor_client &&
    779       !cursor_client->IsMouseEventsEnabled() &&
    780       (event->flags() & ui::EF_IS_SYNTHESIZED) &&
    781       (event->type() != ui::ET_MOUSE_EXITED)) {
    782     event->SetHandled();
    783     return;
    784   }
    785 
    786   if (IsEventCandidateForHold(*event) && !dispatching_held_event_) {
    787     if (move_hold_count_) {
    788       if (!(event->flags() & ui::EF_IS_SYNTHESIZED) &&
    789           event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
    790         SetLastMouseLocation(window(), event->root_location());
    791       }
    792       held_move_event_.reset(new ui::MouseEvent(*event, target, window()));
    793       event->SetHandled();
    794       return;
    795     } else {
    796       // We may have a held event for a period between the time move_hold_count_
    797       // fell to 0 and the DispatchHeldEvents executes. Since we're going to
    798       // dispatch the new event directly below, we can reset the old one.
    799       held_move_event_.reset();
    800     }
    801   }
    802 
    803   const int kMouseButtonFlagMask = ui::EF_LEFT_MOUSE_BUTTON |
    804                                    ui::EF_MIDDLE_MOUSE_BUTTON |
    805                                    ui::EF_RIGHT_MOUSE_BUTTON;
    806   switch (event->type()) {
    807     case ui::ET_MOUSE_EXITED:
    808       if (!target || target == window()) {
    809         DispatchDetails details =
    810             DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED);
    811         if (details.dispatcher_destroyed) {
    812           event->SetHandled();
    813           return;
    814         }
    815         mouse_moved_handler_ = NULL;
    816       }
    817       break;
    818     case ui::ET_MOUSE_MOVED:
    819       // Send an exit to the current |mouse_moved_handler_| and an enter to
    820       // |target|. Take care that both us and |target| aren't destroyed during
    821       // dispatch.
    822       if (target != mouse_moved_handler_) {
    823         aura::Window* old_mouse_moved_handler = mouse_moved_handler_;
    824         WindowTracker live_window;
    825         live_window.Add(target);
    826         DispatchDetails details =
    827             DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED);
    828         if (details.dispatcher_destroyed) {
    829           event->SetHandled();
    830           return;
    831         }
    832         // If the |mouse_moved_handler_| changes out from under us, assume a
    833         // nested message loop ran and we don't need to do anything.
    834         if (mouse_moved_handler_ != old_mouse_moved_handler) {
    835           event->SetHandled();
    836           return;
    837         }
    838         if (!live_window.Contains(target) || details.target_destroyed) {
    839           mouse_moved_handler_ = NULL;
    840           event->SetHandled();
    841           return;
    842         }
    843         live_window.Remove(target);
    844 
    845         mouse_moved_handler_ = target;
    846         details = DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_ENTERED);
    847         if (details.dispatcher_destroyed || details.target_destroyed) {
    848           event->SetHandled();
    849           return;
    850         }
    851       }
    852       break;
    853     case ui::ET_MOUSE_PRESSED:
    854       // Don't set the mouse pressed handler for non client mouse down events.
    855       // These are only sent by Windows and are not always followed with non
    856       // client mouse up events which causes subsequent mouse events to be
    857       // sent to the wrong target.
    858       if (!(event->flags() & ui::EF_IS_NON_CLIENT) && !mouse_pressed_handler_)
    859         mouse_pressed_handler_ = target;
    860       Env::GetInstance()->set_mouse_button_flags(
    861           event->flags() & kMouseButtonFlagMask);
    862       break;
    863     case ui::ET_MOUSE_RELEASED:
    864       mouse_pressed_handler_ = NULL;
    865       Env::GetInstance()->set_mouse_button_flags(event->flags() &
    866           kMouseButtonFlagMask & ~event->changed_button_flags());
    867       break;
    868     default:
    869       break;
    870   }
    871 
    872   PreDispatchLocatedEvent(target, event);
    873 }
    874 
    875 void WindowEventDispatcher::PreDispatchTouchEvent(Window* target,
    876                                                   ui::TouchEvent* event) {
    877   switch (event->type()) {
    878     case ui::ET_TOUCH_PRESSED:
    879       touch_ids_down_ |= (1 << event->touch_id());
    880       Env::GetInstance()->set_touch_down(touch_ids_down_ != 0);
    881       break;
    882 
    883       // Handle ET_TOUCH_CANCELLED only if it has a native event.
    884     case ui::ET_TOUCH_CANCELLED:
    885       if (!event->HasNativeEvent())
    886         break;
    887       // fallthrough
    888     case ui::ET_TOUCH_RELEASED:
    889       touch_ids_down_ = (touch_ids_down_ | (1 << event->touch_id())) ^
    890             (1 << event->touch_id());
    891       Env::GetInstance()->set_touch_down(touch_ids_down_ != 0);
    892       break;
    893 
    894     case ui::ET_TOUCH_MOVED:
    895       if (move_hold_count_ && !dispatching_held_event_) {
    896         held_move_event_.reset(new ui::TouchEvent(*event, target, window()));
    897         event->SetHandled();
    898         return;
    899       }
    900       break;
    901 
    902     default:
    903       NOTREACHED();
    904       break;
    905   }
    906 
    907   PreDispatchLocatedEvent(target, event);
    908 }
    909 
    910 }  // namespace aura
    911