window_event_dispatcher.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
12da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// Copyright 2014 The Chromium Authors. All rights reserved.
22da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// Use of this source code is governed by a BSD-style license that can be
32da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// found in the LICENSE file.
42da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
52da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/aura/window_event_dispatcher.h"
62da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
72da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "base/bind.h"
82da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "base/debug/trace_event.h"
92da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "base/logging.h"
102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "base/message_loop/message_loop.h"
112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/aura/client/capture_client.h"
122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/aura/client/cursor_client.h"
132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/aura/client/event_client.h"
142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/aura/client/focus_client.h"
152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/aura/client/screen_position_client.h"
162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/aura/env.h"
172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/aura/window.h"
182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/aura/window_delegate.h"
192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/aura/window_targeter.h"
202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/aura/window_tracker.h"
212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/aura/window_tree_host.h"
222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/base/hit_test.h"
232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/compositor/dip_util.h"
242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/events/event.h"
252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/events/gestures/gesture_recognizer.h"
262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#include "ui/events/gestures/gesture_types.h"
272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
282da489cd246702bee5938545b18a6f710ed214bcJamie Gennistypedef ui::EventDispatchDetails DispatchDetails;
292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
302da489cd246702bee5938545b18a6f710ed214bcJamie Gennisnamespace aura {
312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
322da489cd246702bee5938545b18a6f710ed214bcJamie Gennisnamespace {
332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// Returns true if |target| has a non-client (frame) component at |location|,
352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// in window coordinates.
362da489cd246702bee5938545b18a6f710ed214bcJamie Gennisbool IsNonClientLocation(Window* target, const gfx::Point& location) {
372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (!target->delegate())
382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return false;
392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  int hit_test_code = target->delegate()->GetNonClientComponent(location);
402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE;
412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
432da489cd246702bee5938545b18a6f710ed214bcJamie GennisWindow* ConsumerToWindow(ui::GestureConsumer* consumer) {
442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return consumer ? static_cast<Window*>(consumer) : NULL;
452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
472da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid SetLastMouseLocation(const Window* root_window,
482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          const gfx::Point& location_in_root) {
492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  client::ScreenPositionClient* client =
502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      client::GetScreenPositionClient(root_window);
512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (client) {
522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    gfx::Point location_in_screen = location_in_root;
532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    client->ConvertPointToScreen(root_window, &location_in_screen);
542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    Env::GetInstance()->set_last_mouse_location(location_in_screen);
552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  } else {
562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    Env::GetInstance()->set_last_mouse_location(location_in_root);
572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
602da489cd246702bee5938545b18a6f710ed214bcJamie Gennisbool IsEventCandidateForHold(const ui::Event& event) {
612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (event.type() == ui::ET_TOUCH_MOVED)
622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return true;
632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (event.type() == ui::ET_MOUSE_DRAGGED)
642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return true;
652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (event.IsMouseEvent() && (event.flags() & ui::EF_IS_SYNTHESIZED))
662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return true;
672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return false;
682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}  // namespace
712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis////////////////////////////////////////////////////////////////////////////////
732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// WindowEventDispatcher, public:
742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
752da489cd246702bee5938545b18a6f710ed214bcJamie GennisWindowEventDispatcher::WindowEventDispatcher(WindowTreeHost* host)
762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    : host_(host),
772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      touch_ids_down_(0),
782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      mouse_pressed_handler_(NULL),
792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      mouse_moved_handler_(NULL),
802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      event_dispatch_target_(NULL),
812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      old_dispatch_target_(NULL),
822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      synthesize_mouse_move_(false),
832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      move_hold_count_(0),
842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      dispatching_held_event_(false),
852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      observer_manager_(this),
862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      repost_event_factory_(this),
872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      held_event_factory_(this) {
882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  ui::GestureRecognizer::Get()->AddGestureEventHelper(this);
892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  Env::GetInstance()->AddObserver(this);
902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
922da489cd246702bee5938545b18a6f710ed214bcJamie GennisWindowEventDispatcher::~WindowEventDispatcher() {
932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  TRACE_EVENT0("shutdown", "WindowEventDispatcher::Destructor");
942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  Env::GetInstance()->RemoveObserver(this);
952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  ui::GestureRecognizer::Get()->RemoveGestureEventHelper(this);
962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
982da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::RepostEvent(const ui::LocatedEvent& event) {
992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  DCHECK(event.type() == ui::ET_MOUSE_PRESSED ||
1002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis         event.type() == ui::ET_GESTURE_TAP_DOWN);
1012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // We allow for only one outstanding repostable event. This is used
1022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // in exiting context menus.  A dropped repost request is allowed.
1032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (event.type() == ui::ET_MOUSE_PRESSED) {
1042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    held_repostable_event_.reset(
1052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        new ui::MouseEvent(
1062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            static_cast<const ui::MouseEvent&>(event),
1072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            static_cast<aura::Window*>(event.target()),
1082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            window()));
1092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    base::MessageLoop::current()->PostNonNestableTask(
1102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        FROM_HERE, base::Bind(
1112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents),
1122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            repost_event_factory_.GetWeakPtr()));
1132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  } else {
1142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    DCHECK(event.type() == ui::ET_GESTURE_TAP_DOWN);
1152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    held_repostable_event_.reset();
1162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // TODO(rbyers): Reposing of gestures is tricky to get
1172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // right, so it's not yet supported.  crbug.com/170987.
1182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
1192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
1202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1212da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::OnMouseEventsEnableStateChanged(bool enabled) {
1222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // Send entered / exited so that visual state can be updated to match
1232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // mouse events state.
1242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  PostSynthesizeMouseMove();
1252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // TODO(mazda): Add code to disable mouse events when |enabled| == false.
1262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
1272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1282da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::DispatchCancelModeEvent() {
1292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  ui::CancelModeEvent event;
1302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  Window* focused_window = client::GetFocusClient(window())->GetFocusedWindow();
1312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (focused_window && !window()->Contains(focused_window))
1322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    focused_window = NULL;
1332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  DispatchDetails details =
1342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      DispatchEvent(focused_window ? focused_window : window(), &event);
1352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (details.dispatcher_destroyed)
1362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return;
1372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
1382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1392da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::DispatchGestureEvent(ui::GestureEvent* event) {
1402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  DispatchDetails details = DispatchHeldEvents();
1412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (details.dispatcher_destroyed)
1422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return;
1432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  Window* target = GetGestureTarget(event);
1442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (target) {
1452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    event->ConvertLocationToTarget(window(), target);
1462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    DispatchDetails details = DispatchEvent(target, event);
1472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if (details.dispatcher_destroyed)
1482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      return;
1492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
1502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
1512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1522da489cd246702bee5938545b18a6f710ed214bcJamie GennisDispatchDetails WindowEventDispatcher::DispatchMouseExitAtPoint(
1532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    const gfx::Point& point) {
1542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  ui::MouseEvent event(ui::ET_MOUSE_EXITED, point, point, ui::EF_NONE,
1552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                       ui::EF_NONE);
1562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED);
1572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
1582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1592da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::ProcessedTouchEvent(ui::TouchEvent* event,
1602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                                Window* window,
1612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                                ui::EventResult result) {
1622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // TODO(tdresser): Move this to PreDispatchTouchEvent, to enable eager
1632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // gesture detection. See crbug.com/410280.
1642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (!ui::GestureRecognizer::Get()
1652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis           ->ProcessTouchEventPreDispatch(*event, window)) {
1662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return;
1672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
1682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // Once we've fully migrated to the eager gesture detector, we won't need to
1702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // pass an event here.
1712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  scoped_ptr<ui::GestureRecognizer::Gestures> gestures(
1722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      ui::GestureRecognizer::Get()->ProcessTouchEventOnAsyncAck(
1732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          *event, result, window));
1742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  DispatchDetails details = ProcessGestures(gestures.get());
1752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (details.dispatcher_destroyed)
1762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return;
1772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
1782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1792da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::HoldPointerMoves() {
1802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (!move_hold_count_)
1812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    held_event_factory_.InvalidateWeakPtrs();
1822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  ++move_hold_count_;
1832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  TRACE_EVENT_ASYNC_BEGIN0("ui", "WindowEventDispatcher::HoldPointerMoves",
1842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                           this);
1852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
1862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1872da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::ReleasePointerMoves() {
1882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  --move_hold_count_;
1892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  DCHECK_GE(move_hold_count_, 0);
1902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (!move_hold_count_ && held_move_event_) {
1912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // We don't want to call DispatchHeldEvents directly, because this might be
1922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // called from a deep stack while another event, in which case dispatching
1932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // another one may not be safe/expected.  Instead we post a task, that we
1942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // may cancel if HoldPointerMoves is called again before it executes.
1952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    base::MessageLoop::current()->PostNonNestableTask(
1962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        FROM_HERE, base::Bind(
1972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents),
1982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          held_event_factory_.GetWeakPtr()));
1992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
2002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  TRACE_EVENT_ASYNC_END0("ui", "WindowEventDispatcher::HoldPointerMoves", this);
2012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
2022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2032da489cd246702bee5938545b18a6f710ed214bcJamie Gennisgfx::Point WindowEventDispatcher::GetLastMouseLocationInRoot() const {
2042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  gfx::Point location = Env::GetInstance()->last_mouse_location();
2052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  client::ScreenPositionClient* client =
2062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      client::GetScreenPositionClient(window());
2072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (client)
2082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    client->ConvertPointFromScreen(window(), &location);
2092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return location;
2102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
2112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2122da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::OnHostLostMouseGrab() {
2132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  mouse_pressed_handler_ = NULL;
2142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  mouse_moved_handler_ = NULL;
2152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
2162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2172da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::OnCursorMovedToRootLocation(
2182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    const gfx::Point& root_location) {
2192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  SetLastMouseLocation(window(), root_location);
2202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  synthesize_mouse_move_ = false;
2212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
2222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2232da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::OnPostNotifiedWindowDestroying(Window* window) {
2242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  OnWindowHidden(window, WINDOW_DESTROYED);
2252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
2262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis////////////////////////////////////////////////////////////////////////////////
2282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// WindowEventDispatcher, private:
2292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2302da489cd246702bee5938545b18a6f710ed214bcJamie GennisWindow* WindowEventDispatcher::window() {
2312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return host_->window();
2322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
2332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2342da489cd246702bee5938545b18a6f710ed214bcJamie Gennisconst Window* WindowEventDispatcher::window() const {
2352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return host_->window();
2362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
2372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2382da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::TransformEventForDeviceScaleFactor(
2392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    ui::LocatedEvent* event) {
2402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  event->UpdateForRootTransform(host_->GetInverseRootTransform());
2412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
2422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2432da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::DispatchMouseExitToHidingWindow(Window* window) {
2442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // The mouse capture is intentionally ignored. Think that a mouse enters
2452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // to a window, the window sets the capture, the mouse exits the window,
2462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // and then it releases the capture. In that case OnMouseExited won't
2472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // be called. So it is natural not to emit OnMouseExited even though
2482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // |window| is the capture window.
2492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  gfx::Point last_mouse_location = GetLastMouseLocationInRoot();
2502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (window->Contains(mouse_moved_handler_) &&
2512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      window->ContainsPointInRoot(last_mouse_location)) {
2522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    DispatchDetails details = DispatchMouseExitAtPoint(last_mouse_location);
2532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if (details.dispatcher_destroyed)
2542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      return;
2552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
2562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
2572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2582da489cd246702bee5938545b18a6f710ed214bcJamie Gennisui::EventDispatchDetails WindowEventDispatcher::DispatchMouseEnterOrExit(
2592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    const ui::MouseEvent& event,
2602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    ui::EventType type) {
2612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (event.type() != ui::ET_MOUSE_CAPTURE_CHANGED &&
2622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      !(event.flags() & ui::EF_IS_SYNTHESIZED)) {
2632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    SetLastMouseLocation(window(), event.root_location());
2642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
2652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (!mouse_moved_handler_ || !mouse_moved_handler_->delegate() ||
2672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      !window()->Contains(mouse_moved_handler_))
2682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return DispatchDetails();
2692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // |event| may be an event in the process of being dispatched to a target (in
2712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // which case its locations will be in the event's target's coordinate
2722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // system), or a synthetic event created in root-window (in which case, the
2732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // event's target will be NULL, and the event will be in the root-window's
2742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // coordinate system.
2752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  aura::Window* target = static_cast<Window*>(event.target());
2762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (!target)
2772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    target = window();
2782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  ui::MouseEvent translated_event(event,
2792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                  target,
2802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                  mouse_moved_handler_,
2812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                  type,
2822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                  event.flags() | ui::EF_IS_SYNTHESIZED);
2832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return DispatchEvent(mouse_moved_handler_, &translated_event);
2842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
2852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2862da489cd246702bee5938545b18a6f710ed214bcJamie Gennisui::EventDispatchDetails WindowEventDispatcher::ProcessGestures(
2872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    ui::GestureRecognizer::Gestures* gestures) {
2882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  DispatchDetails details;
2892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (!gestures || gestures->empty())
2902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return details;
2912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  Window* target = GetGestureTarget(gestures->get().at(0));
2932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (!target)
2942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return details;
2952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  for (size_t i = 0; i < gestures->size(); ++i) {
2972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    ui::GestureEvent* event = gestures->get().at(i);
2982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    event->ConvertLocationToTarget(window(), target);
2992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    details = DispatchEvent(target, event);
3002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if (details.dispatcher_destroyed || details.target_destroyed)
3012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      break;
3022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
3032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return details;
3042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
3052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3062da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::OnWindowHidden(Window* invisible,
3072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                           WindowHiddenReason reason) {
3082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // If the window the mouse was pressed in becomes invisible, it should no
3092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // longer receive mouse events.
3102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (invisible->Contains(mouse_pressed_handler_))
3112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    mouse_pressed_handler_ = NULL;
3122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (invisible->Contains(mouse_moved_handler_))
3132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    mouse_moved_handler_ = NULL;
3142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // If events are being dispatched from a nested message-loop, and the target
3162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // of the outer loop is hidden or moved to another dispatcher during
3172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // dispatching events in the inner loop, then reset the target for the outer
3182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // loop.
3192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (invisible->Contains(old_dispatch_target_))
3202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    old_dispatch_target_ = NULL;
3212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  invisible->CleanupGestureState();
3232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // Do not clear the capture, and the |event_dispatch_target_| if the
3252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // window is moving across hosts, because the target itself is actually still
3262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // visible and clearing them stops further event processing, which can cause
3272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // unexpected behaviors. See crbug.com/157583
3282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (reason != WINDOW_MOVING) {
3292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // We don't ask |invisible| here, because invisible may have been removed
3302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // from the window hierarchy already by the time this function is called
3312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // (OnWindowDestroyed).
3322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    client::CaptureClient* capture_client =
3332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        client::GetCaptureClient(host_->window());
3342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    Window* capture_window =
3352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        capture_client ? capture_client->GetCaptureWindow() : NULL;
3362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if (invisible->Contains(event_dispatch_target_))
3382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      event_dispatch_target_ = NULL;
3392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // If the ancestor of the capture window is hidden, release the capture.
3412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // Note that this may delete the window so do not use capture_window
3422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // after this.
3432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if (invisible->Contains(capture_window) && invisible != window())
3442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      capture_window->ReleaseCapture();
3452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
3462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
3472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3482da489cd246702bee5938545b18a6f710ed214bcJamie GennisWindow* WindowEventDispatcher::GetGestureTarget(ui::GestureEvent* event) {
3492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  Window* target = NULL;
3502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (!event->IsEndingEvent()) {
3512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // The window that received the start event (e.g. scroll begin) needs to
3522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // receive the end event (e.g. scroll end).
3532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    target = client::GetCaptureWindow(window());
3542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
3552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (!target) {
3562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    target = ConsumerToWindow(
3572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        ui::GestureRecognizer::Get()->GetTargetForGestureEvent(*event));
3582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
3592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return target;
3612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
3622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis////////////////////////////////////////////////////////////////////////////////
3642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// WindowEventDispatcher, aura::client::CaptureDelegate implementation:
3652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3662da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::UpdateCapture(Window* old_capture,
3672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                          Window* new_capture) {
3682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // |mouse_moved_handler_| may have been set to a Window in a different root
3692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // (see below). Clear it here to ensure we don't end up referencing a stale
3702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // Window.
3712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (mouse_moved_handler_ && !window()->Contains(mouse_moved_handler_))
3722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    mouse_moved_handler_ = NULL;
3732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (old_capture && old_capture->GetRootWindow() == window() &&
3752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      old_capture->delegate()) {
3762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // Send a capture changed event with bogus location data.
3772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    ui::MouseEvent event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(),
3782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         gfx::Point(), 0, 0);
3792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    DispatchDetails details = DispatchEvent(old_capture, &event);
3812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if (details.dispatcher_destroyed)
3822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      return;
3832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    old_capture->delegate()->OnCaptureLost();
3852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
3862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (new_capture) {
3882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // Make all subsequent mouse events go to the capture window. We shouldn't
3892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // need to send an event here as OnCaptureLost() should take care of that.
3902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if (mouse_moved_handler_ || Env::GetInstance()->IsMouseButtonDown())
3912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      mouse_moved_handler_ = new_capture;
3922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  } else {
3932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // Make sure mouse_moved_handler gets updated.
3942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    DispatchDetails details = SynthesizeMouseMoveEvent();
3952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if (details.dispatcher_destroyed)
3962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      return;
3972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
3982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  mouse_pressed_handler_ = NULL;
3992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
4002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4012da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::OnOtherRootGotCapture() {
4022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // Windows provides the TrackMouseEvents API which allows us to rely on the
4032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // OS to send us the mouse exit events (WM_MOUSELEAVE). Additionally on
4042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // desktop Windows, every top level window could potentially have its own
4052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // root window, in which case this function will get called whenever those
4062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // windows grab mouse capture. Sending mouse exit messages in these cases
4072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  // causes subtle bugs like (crbug.com/394672).
4082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#if !defined(OS_WIN)
4092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (mouse_moved_handler_) {
4102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // Dispatch a mouse exit to reset any state associated with hover. This is
4112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // important when going from no window having capture to a window having
4122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // capture because we do not dispatch ET_MOUSE_CAPTURE_CHANGED in this case.
4132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    DispatchDetails details = DispatchMouseExitAtPoint(
4142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        GetLastMouseLocationInRoot());
4152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if (details.dispatcher_destroyed)
4162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      return;
4172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
4182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#endif
4192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  mouse_moved_handler_ = NULL;
4212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  mouse_pressed_handler_ = NULL;
4222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
4232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4242da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::SetNativeCapture() {
4252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  host_->SetCapture();
4262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
4272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4282da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::ReleaseNativeCapture() {
4292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  host_->ReleaseCapture();
4302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
4312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis////////////////////////////////////////////////////////////////////////////////
4332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// WindowEventDispatcher, ui::EventProcessor implementation:
4342da489cd246702bee5938545b18a6f710ed214bcJamie Gennisui::EventTarget* WindowEventDispatcher::GetRootTarget() {
4352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return window();
4362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
4372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4382da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid WindowEventDispatcher::PrepareEventForDispatch(ui::Event* event) {
4392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (dispatching_held_event_) {
4402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // The held events are already in |window()|'s coordinate system. So it is
4412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // not necessary to apply the transform to convert from the host's
4422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // coordinate system to |window()|'s coordinate system.
4432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return;
4442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
4452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (event->IsLocatedEvent()) {
4462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    TransformEventForDeviceScaleFactor(static_cast<ui::LocatedEvent*>(event));
4472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
4482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
4492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis////////////////////////////////////////////////////////////////////////////////
4512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// WindowEventDispatcher, ui::EventDispatcherDelegate implementation:
4522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4532da489cd246702bee5938545b18a6f710ed214bcJamie Gennisbool WindowEventDispatcher::CanDispatchToTarget(ui::EventTarget* target) {
4542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return event_dispatch_target_ == target;
4552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
4562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4572da489cd246702bee5938545b18a6f710ed214bcJamie Gennisui::EventDispatchDetails WindowEventDispatcher::PreDispatchEvent(
4582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    ui::EventTarget* target,
4592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    ui::Event* event) {
4602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  Window* target_window = static_cast<Window*>(target);
4612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  CHECK(window()->Contains(target_window));
4622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (!dispatching_held_event_) {
4642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    bool can_be_held = IsEventCandidateForHold(*event);
4652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if (!move_hold_count_ || !can_be_held) {
4662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (can_be_held)
4672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        held_move_event_.reset();
4682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      DispatchDetails details = DispatchHeldEvents();
4692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (details.dispatcher_destroyed || details.target_destroyed)
4702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        return details;
4712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    }
4722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
4732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (event->IsMouseEvent()) {
4752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    PreDispatchMouseEvent(target_window, static_cast<ui::MouseEvent*>(event));
4762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  } else if (event->IsScrollEvent()) {
4772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    PreDispatchLocatedEvent(target_window,
4782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                            static_cast<ui::ScrollEvent*>(event));
4792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  } else if (event->IsTouchEvent()) {
4802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    PreDispatchTouchEvent(target_window, static_cast<ui::TouchEvent*>(event));
4812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
4822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  old_dispatch_target_ = event_dispatch_target_;
4832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  event_dispatch_target_ = static_cast<Window*>(target);
4842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return DispatchDetails();
4852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
4862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4872da489cd246702bee5938545b18a6f710ed214bcJamie Gennisui::EventDispatchDetails WindowEventDispatcher::PostDispatchEvent(
4882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    ui::EventTarget* target,
4892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    const ui::Event& event) {
4902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  DispatchDetails details;
4912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (!target || target != event_dispatch_target_)
4922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    details.target_destroyed = true;
4932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  event_dispatch_target_ = old_dispatch_target_;
4942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  old_dispatch_target_ = NULL;
4952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#ifndef NDEBUG
4962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  DCHECK(!event_dispatch_target_ || window()->Contains(event_dispatch_target_));
4972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#endif
4982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (event.IsTouchEvent() && !details.target_destroyed) {
5002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // Do not let 'held' touch events contribute to any gestures unless it is
5012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    // being dispatched.
5022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if (dispatching_held_event_ || !held_move_event_ ||
5032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        !held_move_event_->IsTouchEvent()) {
5042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // Once we've fully migrated to the eager gesture detector, we won't
5062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // need to pass an event here.
5072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      ui::TouchEvent orig_event(static_cast<const ui::TouchEvent&>(event),
5082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                static_cast<Window*>(event.target()),
5092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                window());
5102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (event.result() & ui::ER_CONSUMED)
5122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        orig_event.StopPropagation();
5132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // TODO(tdresser): Move this to PreDispatchTouchEvent, to enable eager
5152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // gesture detection. See crbug.com/410280.
5162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (!ui::GestureRecognizer::Get()
5172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis               ->ProcessTouchEventPreDispatch(orig_event,
5182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                              static_cast<Window*>(target))) {
5192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        return details;
5202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      }
5212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
5232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      gestures.reset(
5252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          ui::GestureRecognizer::Get()->ProcessTouchEventPostDispatch(
5262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis              orig_event, event.result(), static_cast<Window*>(target)));
5272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      return ProcessGestures(gestures.get());
5292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    }
5302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
5312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return details;
5332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
5342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis////////////////////////////////////////////////////////////////////////////////
5362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// WindowEventDispatcher, ui::GestureEventHelper implementation:
5372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5382da489cd246702bee5938545b18a6f710ed214bcJamie Gennisbool WindowEventDispatcher::CanDispatchToConsumer(
5392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    ui::GestureConsumer* consumer) {
5402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  Window* consumer_window = ConsumerToWindow(consumer);
5412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return (consumer_window && consumer_window->GetRootWindow() == window());
5422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis}
5432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5442da489cd246702bee5938545b18a6f710ed214bcJamie Gennisvoid 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
557void WindowEventDispatcher::OnWindowDestroying(Window* window) {
558  if (!host_->window()->Contains(window))
559    return;
560
561  DispatchMouseExitToHidingWindow(window);
562  SynthesizeMouseMoveAfterChangeToWindow(window);
563}
564
565void 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
571void 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
581void 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
596void WindowEventDispatcher::OnWindowVisibilityChanging(Window* window,
597                                                       bool visible) {
598  if (!host_->window()->Contains(window))
599    return;
600
601  DispatchMouseExitToHidingWindow(window);
602}
603
604void 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
618void 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
649void WindowEventDispatcher::OnWindowTransforming(Window* window) {
650  if (!host_->window()->Contains(window))
651    return;
652
653  SynthesizeMouseMoveAfterChangeToWindow(window);
654}
655
656void WindowEventDispatcher::OnWindowTransformed(Window* window) {
657  if (!host_->window()->Contains(window))
658    return;
659
660  SynthesizeMouseMoveAfterChangeToWindow(window);
661}
662
663///////////////////////////////////////////////////////////////////////////////
664// WindowEventDispatcher, EnvObserver implementation:
665
666void WindowEventDispatcher::OnWindowInitialized(Window* window) {
667  observer_manager_.Add(window);
668}
669
670////////////////////////////////////////////////////////////////////////////////
671// WindowEventDispatcher, private:
672
673ui::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
710void 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
721void WindowEventDispatcher::SynthesizeMouseMoveAfterChangeToWindow(
722    Window* window) {
723  if (window->IsVisible() &&
724      window->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
725    PostSynthesizeMouseMove();
726  }
727}
728
729ui::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
756void 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
772void 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
875void 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