From 64a5a8cb4268b15ea6ec734a00114ef30f9381fb Mon Sep 17 00:00:00 2001
From: "varunjain@chromium.org"
 <varunjain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Mon, 21 Oct 2013 13:31:45 +0000
Subject: Gesture recognizer must be a singleton accross all aura::RootWindows

BUG=279317

Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=229753

R=sadrul@chromium.org, sky@chromium.org

Review URL: https://codereview.chromium.org/25350006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@229796 0039d316-1c4b-4281-b951-d872f2087c98
---
 ash/drag_drop/drag_drop_controller.cc              |  2 +-
 ash/wm/toplevel_window_event_handler.cc            |  2 +-
 .../browser/ui/views/tabs/tab_drag_controller.cc   | 22 ++++++-
 .../renderer_host/render_widget_host_view_guest.cc | 21 ++++--
 .../renderer_host/render_widget_host_view_guest.h  |  5 +-
 .../renderer_host/render_widget_host_view_win.cc   | 19 ++++--
 .../renderer_host/render_widget_host_view_win.h    |  5 +-
 ui/aura/client/default_capture_client.cc           |  4 +-
 ui/aura/gestures/gesture_recognizer_unittest.cc    | 75 +++++++++++++---------
 ui/aura/root_window.cc                             | 47 ++++++--------
 ui/aura/root_window.h                              | 15 +----
 ui/events/gestures/gesture_recognizer.h            | 14 +++-
 ui/events/gestures/gesture_recognizer_impl.cc      | 72 ++++++++++++++++++---
 ui/events/gestures/gesture_recognizer_impl.h       | 26 ++++++--
 ui/events/gestures/gesture_sequence.cc             |  7 +-
 ui/events/gestures/gesture_sequence.h              | 14 +++-
 ui/events/gestures/gesture_types.h                 |  6 +-
 ui/views/corewm/capture_controller.cc              |  7 +-
 ui/views/corewm/capture_controller_unittest.cc     |  4 +-
 .../widget/desktop_aura/desktop_capture_client.cc  |  6 +-
 20 files changed, 251 insertions(+), 122 deletions(-)

diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc
index 48e7c35..d335465 100644
--- a/ash/drag_drop/drag_drop_controller.cc
+++ b/ash/drag_drop/drag_drop_controller.cc
@@ -181,7 +181,7 @@ int DragDropController::StartDragAndDrop(
     // We need to transfer the current gesture sequence and the GR's touch event
     // queue to the |drag_drop_tracker_|'s capture window so that when it takes
     // capture, it still gets a valid gesture state.
-    root_window->gesture_recognizer()->TransferEventsTo(source_window,
+    ui::GestureRecognizer::Get()->TransferEventsTo(source_window,
         tracker->capture_window());
     // We also send a gesture end to the source window so it can clear state.
     // TODO(varunjain): Remove this whole block when gesture sequence
diff --git a/ash/wm/toplevel_window_event_handler.cc b/ash/wm/toplevel_window_event_handler.cc
index f76d33d..f6d5902 100644
--- a/ash/wm/toplevel_window_event_handler.cc
+++ b/ash/wm/toplevel_window_event_handler.cc
@@ -341,7 +341,7 @@ aura::client::WindowMoveResult ToplevelWindowEventHandler::RunMoveLoop(
   if (move_source == aura::client::WINDOW_MOVE_SOURCE_TOUCH &&
       aura::Env::GetInstance()->is_touch_down()) {
     in_gesture_drag_ = true;
-    bool has_point = root_window->gesture_recognizer()->
+    bool has_point = ui::GestureRecognizer::Get()->
         GetLastTouchPointForTarget(source, &drag_location);
     DCHECK(has_point);
   } else {
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 6f13d81..ba0564b 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -59,6 +59,11 @@
 #include "ui/events/gestures/gesture_recognizer.h"
 #endif
 
+#if defined(OS_WIN) && defined(USE_AURA)
+#include "ui/aura/window.h"
+#include "ui/events/gestures/gesture_recognizer.h"
+#endif
+
 using content::OpenURLParams;
 using content::UserMetricsAction;
 using content::WebContents;
@@ -897,6 +902,18 @@ TabDragController::DragBrowserToNewTabStrip(
       target_tabstrip->GetWidget()->SetCapture(attached_tabstrip_);
     else
       browser_widget->ReleaseCapture();
+#if defined(OS_WIN) && defined(USE_AURA)
+    // The Gesture recognizer does not work well currently when capture changes
+    // while a touch gesture is in progress. So we need to manually transfer
+    // gesture sequence and the GR's touch events queue to the new window. This
+    // should really be done somewhere in capture change code and or inside the
+    // GR. But we currently do not have a consistent way for doing it that would
+    // work in all cases. Hence this hack.
+    ui::GestureRecognizer::Get()->TransferEventsTo(
+        browser_widget->GetNativeView(),
+        target_tabstrip->GetWidget()->GetNativeView());
+#endif
+
     // The window is going away. Since the drag is still on going we don't want
     // that to effect the position of any windows.
     SetWindowPositionManaged(browser_widget->GetNativeView(), false);
@@ -2227,9 +2244,8 @@ gfx::Point TabDragController::GetCursorScreenPoint() {
     aura::Window* widget_window = widget->GetNativeWindow();
     DCHECK(widget_window->GetRootWindow());
     gfx::Point touch_point;
-    bool got_touch_point = widget_window->GetRootWindow()->
-        gesture_recognizer()->GetLastTouchPointForTarget(widget_window,
-                                                         &touch_point);
+    bool got_touch_point = ui::GestureRecognizer::Get()->
+        GetLastTouchPointForTarget(widget_window, &touch_point);
     DCHECK(got_touch_point);
     ash::wm::ConvertPointToScreen(widget_window->GetRootWindow(), &touch_point);
     return touch_point;
diff --git a/content/browser/renderer_host/render_widget_host_view_guest.cc b/content/browser/renderer_host/render_widget_host_view_guest.cc
index 05730b9..a339329 100644
--- a/content/browser/renderer_host/render_widget_host_view_guest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_guest.cc
@@ -54,12 +54,16 @@ RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
       is_hidden_(host_->is_hidden()),
       platform_view_(static_cast<RenderWidgetHostViewPort*>(platform_view)) {
 #if defined(OS_WIN) || defined(USE_AURA)
-  gesture_recognizer_.reset(ui::GestureRecognizer::Create(this));
+  gesture_recognizer_.reset(ui::GestureRecognizer::Create());
+  gesture_recognizer_->AddGestureEventHelper(this);
 #endif  // defined(OS_WIN) || defined(USE_AURA)
   host_->SetView(this);
 }
 
 RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() {
+#if defined(OS_WIN) || defined(USE_AURA)
+  gesture_recognizer_->RemoveGestureEventHelper(this);
+#endif  // defined(OS_WIN) || defined(USE_AURA)
 }
 
 RenderWidgetHost* RenderWidgetHostViewGuest::GetRenderWidgetHost() const {
@@ -507,21 +511,26 @@ void RenderWidgetHostViewGuest::DestroyGuestView() {
   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
 }
 
-bool RenderWidgetHostViewGuest::DispatchLongPressGestureEvent(
+bool RenderWidgetHostViewGuest::CanDispatchToConsumer(
+    ui::GestureConsumer* consumer) {
+  CHECK_EQ(static_cast<RenderWidgetHostViewGuest*>(consumer), this);
+  return true;
+}
+
+void RenderWidgetHostViewGuest::DispatchLongPressGestureEvent(
     ui::GestureEvent* event) {
-  return ForwardGestureEventToRenderer(event);
+  ForwardGestureEventToRenderer(event);
 }
 
-bool RenderWidgetHostViewGuest::DispatchCancelTouchEvent(
+void RenderWidgetHostViewGuest::DispatchCancelTouchEvent(
     ui::TouchEvent* event) {
   if (!host_)
-    return false;
+    return;
 
   WebKit::WebTouchEvent cancel_event;
   cancel_event.type = WebKit::WebInputEvent::TouchCancel;
   cancel_event.timeStampSeconds = event->time_stamp().InSecondsF();
   host_->ForwardTouchEventWithLatencyInfo(cancel_event, *event->latency());
-  return true;
 }
 
 bool RenderWidgetHostViewGuest::ForwardGestureEventToRenderer(
diff --git a/content/browser/renderer_host/render_widget_host_view_guest.h b/content/browser/renderer_host/render_widget_host_view_guest.h
index 079410b..84435e4 100644
--- a/content/browser/renderer_host/render_widget_host_view_guest.h
+++ b/content/browser/renderer_host/render_widget_host_view_guest.h
@@ -186,8 +186,9 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
 #endif
 
   // Overridden from ui::GestureEventHelper.
-  virtual bool DispatchLongPressGestureEvent(ui::GestureEvent* event) OVERRIDE;
-  virtual bool DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE;
+  virtual bool CanDispatchToConsumer(ui::GestureConsumer* consumer) OVERRIDE;
+  virtual void DispatchLongPressGestureEvent(ui::GestureEvent* event) OVERRIDE;
+  virtual void DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE;
 
  protected:
   friend class RenderWidgetHostView;
diff --git a/content/browser/renderer_host/render_widget_host_view_win.cc b/content/browser/renderer_host/render_widget_host_view_win.cc
index 0694e10..a440e6b 100644
--- a/content/browser/renderer_host/render_widget_host_view_win.cc
+++ b/content/browser/renderer_host/render_widget_host_view_win.cc
@@ -411,14 +411,16 @@ RenderWidgetHostViewWin::RenderWidgetHostViewWin(RenderWidgetHost* widget)
       pointer_down_context_(false),
       last_touch_location_(-1, -1),
       touch_events_enabled_(ui::AreTouchEventsEnabled()),
-      gesture_recognizer_(ui::GestureRecognizer::Create(this)) {
+      gesture_recognizer_(ui::GestureRecognizer::Create()) {
   render_widget_host_->SetView(this);
   registrar_.Add(this,
                  NOTIFICATION_RENDERER_PROCESS_TERMINATED,
                  NotificationService::AllBrowserContextsAndSources());
+  gesture_recognizer_->AddGestureEventHelper(this);
 }
 
 RenderWidgetHostViewWin::~RenderWidgetHostViewWin() {
+  gesture_recognizer_->RemoveGestureEventHelper(this);
   UnlockMouse();
   ResetTooltip();
 }
@@ -944,16 +946,22 @@ void RenderWidgetHostViewWin::UpdateDesiredTouchMode() {
   }
 }
 
-bool RenderWidgetHostViewWin::DispatchLongPressGestureEvent(
+bool RenderWidgetHostViewWin::CanDispatchToConsumer(
+    ui::GestureConsumer* consumer) {
+  CHECK_EQ(static_cast<RenderWidgetHostViewWin*>(consumer), this);
+  return true;
+}
+
+void RenderWidgetHostViewWin::DispatchLongPressGestureEvent(
     ui::GestureEvent* event) {
-  return ForwardGestureEventToRenderer(event);
+  ForwardGestureEventToRenderer(event);
 }
 
-bool RenderWidgetHostViewWin::DispatchCancelTouchEvent(
+void RenderWidgetHostViewWin::DispatchCancelTouchEvent(
     ui::TouchEvent* event) {
   if (!render_widget_host_ || !touch_events_enabled_ ||
       !render_widget_host_->ShouldForwardTouchEvent()) {
-    return false;
+    return;
   }
   DCHECK(event->type() == WebKit::WebInputEvent::TouchCancel);
   WebKit::WebTouchEvent cancel_event;
@@ -961,7 +969,6 @@ bool RenderWidgetHostViewWin::DispatchCancelTouchEvent(
   cancel_event.timeStampSeconds = event->time_stamp().InSecondsF();
   render_widget_host_->ForwardTouchEventWithLatencyInfo(
       cancel_event, *event->latency());
-  return true;
 }
 
 void RenderWidgetHostViewWin::SetHasHorizontalScrollbar(
diff --git a/content/browser/renderer_host/render_widget_host_view_win.h b/content/browser/renderer_host/render_widget_host_view_win.h
index 84705bb..c9eca60 100644
--- a/content/browser/renderer_host/render_widget_host_view_win.h
+++ b/content/browser/renderer_host/render_widget_host_view_win.h
@@ -259,8 +259,9 @@ class RenderWidgetHostViewWin
   virtual void FatalAccessibilityTreeError() OVERRIDE;
 
   // Overridden from ui::GestureEventHelper.
-  virtual bool DispatchLongPressGestureEvent(ui::GestureEvent* event) OVERRIDE;
-  virtual bool DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE;
+  virtual bool CanDispatchToConsumer(ui::GestureConsumer* consumer) OVERRIDE;
+  virtual void DispatchLongPressGestureEvent(ui::GestureEvent* event) OVERRIDE;
+  virtual void DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE;
 
   // Overridden from ui::TextInputClient for Win8/metro TSF support.
   // Following methods are not used in existing IMM32 related implementation.
diff --git a/ui/aura/client/default_capture_client.cc b/ui/aura/client/default_capture_client.cc
index 9b5fff5..dae3b7d 100644
--- a/ui/aura/client/default_capture_client.cc
+++ b/ui/aura/client/default_capture_client.cc
@@ -23,8 +23,8 @@ void DefaultCaptureClient::SetCapture(Window* window) {
   if (capture_window_ == window)
     return;
   if (window) {
-    root_window_->gesture_recognizer()->
-        TransferEventsTo(capture_window_, window);
+    ui::GestureRecognizer::Get()->TransferEventsTo(
+        capture_window_, window);
   }
 
   Window* old_capture_window = capture_window_;
diff --git a/ui/aura/gestures/gesture_recognizer_unittest.cc b/ui/aura/gestures/gesture_recognizer_unittest.cc
index 38aca7f..a8db300 100644
--- a/ui/aura/gestures/gesture_recognizer_unittest.cc
+++ b/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -453,8 +453,8 @@ class TestOneShotGestureSequenceTimer
 
 class TimerTestGestureSequence : public ui::GestureSequence {
  public:
-  explicit TimerTestGestureSequence(ui::GestureEventHelper* helper)
-      : ui::GestureSequence(helper) {
+  explicit TimerTestGestureSequence(ui::GestureSequenceDelegate* delegate)
+      : ui::GestureSequence(delegate) {
   }
 
   void ForceTimeout() {
@@ -476,8 +476,7 @@ class TimerTestGestureSequence : public ui::GestureSequence {
 
 class TestGestureRecognizer : public ui::GestureRecognizerImpl {
  public:
-  explicit TestGestureRecognizer(RootWindow* root_window)
-      : GestureRecognizerImpl(root_window) {
+  TestGestureRecognizer() : GestureRecognizerImpl() {
   }
 
   ui::GestureSequence* GetGestureSequenceForTesting(Window* window) {
@@ -490,13 +489,12 @@ class TestGestureRecognizer : public ui::GestureRecognizerImpl {
 
 class TimerTestGestureRecognizer : public TestGestureRecognizer {
  public:
-  explicit TimerTestGestureRecognizer(RootWindow* root_window)
-      : TestGestureRecognizer(root_window) {
+  TimerTestGestureRecognizer() : TestGestureRecognizer() {
   }
 
   virtual ui::GestureSequence* CreateSequence(
-      ui::GestureEventHelper* helper) OVERRIDE {
-    return new TimerTestGestureSequence(helper);
+      ui::GestureSequenceDelegate* delegate) OVERRIDE {
+    return new TimerTestGestureSequence(delegate);
   }
 
  private:
@@ -507,6 +505,26 @@ base::TimeDelta GetTime() {
   return ui::EventTimeForNow();
 }
 
+class ScopedGestureRecognizerSetter {
+ public:
+  // Takes ownership of |new_gr|.
+  explicit ScopedGestureRecognizerSetter(ui::GestureRecognizer* new_gr)
+      : new_gr_(new_gr) {
+    original_gr_ = ui::GestureRecognizer::Get();
+    ui::SetGestureRecognizerForTesting(new_gr_.get());
+  }
+
+  virtual ~ScopedGestureRecognizerSetter() {
+    ui::SetGestureRecognizerForTesting(original_gr_);
+  }
+
+ private:
+  ui::GestureRecognizer* original_gr_;
+  scoped_ptr<ui::GestureRecognizer> new_gr_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedGestureRecognizerSetter);
+};
+
 class TimedEvents {
  private:
   int simulated_now_;
@@ -1254,9 +1272,9 @@ TEST_F(GestureRecognizerTest, GestureEventLongPress) {
   delegate->Reset();
 
   TimerTestGestureRecognizer* gesture_recognizer =
-      new TimerTestGestureRecognizer(root_window());
+      new TimerTestGestureRecognizer();
 
-  root_window()->SetGestureRecognizerForTesting(gesture_recognizer);
+  ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
 
   ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
                         kTouchId, tes.Now());
@@ -1300,12 +1318,12 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledByScroll) {
   delegate->Reset();
 
   TimerTestGestureRecognizer* gesture_recognizer =
-      new TimerTestGestureRecognizer(root_window());
+      new TimerTestGestureRecognizer();
   TimerTestGestureSequence* gesture_sequence =
       static_cast<TimerTestGestureSequence*>(
           gesture_recognizer->GetGestureSequenceForTesting(window.get()));
 
-  root_window()->SetGestureRecognizerForTesting(gesture_recognizer);
+  ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
 
   ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
                         kTouchId, tes.Now());
@@ -1346,9 +1364,9 @@ TEST_F(GestureRecognizerTest, GestureEventLongTap) {
   delegate->Reset();
 
   TimerTestGestureRecognizer* gesture_recognizer =
-      new TimerTestGestureRecognizer(root_window());
+      new TimerTestGestureRecognizer();
 
-  root_window()->SetGestureRecognizerForTesting(gesture_recognizer);
+  ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
 
   ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
                         kTouchId, tes.Now());
@@ -1392,12 +1410,12 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap) {
       delegate.get(), -1234, bounds, root_window()));
 
   TimerTestGestureRecognizer* gesture_recognizer =
-      new TimerTestGestureRecognizer(root_window());
+      new TimerTestGestureRecognizer();
   TimerTestGestureSequence* gesture_sequence =
       static_cast<TimerTestGestureSequence*>(
           gesture_recognizer->GetGestureSequenceForTesting(window.get()));
 
-  root_window()->SetGestureRecognizerForTesting(gesture_recognizer);
+  ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
 
   delegate->Reset();
   ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
@@ -2058,10 +2076,9 @@ TEST_F(GestureRecognizerTest, GestureEventIgnoresDisconnectedEvents) {
 // Check that a touch is locked to the window of the closest current touch
 // within max_separation_for_gesture_touches_in_pixels
 TEST_F(GestureRecognizerTest, GestureEventTouchLockSelectsCorrectWindow) {
-  ui::GestureRecognizer* gesture_recognizer =
-      new ui::GestureRecognizerImpl(root_window());
+  ui::GestureRecognizer* gesture_recognizer = new ui::GestureRecognizerImpl();
   TimedEvents tes;
-  root_window()->SetGestureRecognizerForTesting(gesture_recognizer);
+  ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
 
   ui::GestureConsumer* target;
   const int kNumWindows = 4;
@@ -2146,9 +2163,9 @@ TEST_F(GestureRecognizerTest, GestureEventTouchLockSelectsCorrectWindow) {
 // by the root window's gesture sequence.
 TEST_F(GestureRecognizerTest, GestureEventOutsideRootWindowTap) {
   TestGestureRecognizer* gesture_recognizer =
-      new TestGestureRecognizer(root_window());
+      new TestGestureRecognizer();
   TimedEvents tes;
-  root_window()->SetGestureRecognizerForTesting(gesture_recognizer);
+  ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
 
   scoped_ptr<aura::Window> window(CreateTestWindowWithBounds(
       gfx::Rect(-100, -100, 2000, 2000), root_window()));
@@ -2298,8 +2315,8 @@ TEST_F(GestureRecognizerTest, CaptureSendsGestureEnd) {
   scoped_ptr<GestureEventConsumeDelegate> delegate(
       new GestureEventConsumeDelegate());
   TestGestureRecognizer* gesture_recognizer =
-      new TestGestureRecognizer(root_window());
-  root_window()->SetGestureRecognizerForTesting(gesture_recognizer);
+      new TestGestureRecognizer();
+  ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
 
   scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
       delegate.get(), -1234, gfx::Rect(10, 10, 300, 300), root_window()));
@@ -2378,8 +2395,8 @@ TEST_F(GestureRecognizerTest, PressDoesNotCrash) {
   scoped_ptr<GestureEventConsumeDelegate> delegate(
       new GestureEventConsumeDelegate());
   TestGestureRecognizer* gesture_recognizer =
-      new TestGestureRecognizer(root_window());
-  root_window()->SetGestureRecognizerForTesting(gesture_recognizer);
+      new TestGestureRecognizer();
+  ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
   TimedEvents tes;
 
   scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
@@ -2815,9 +2832,9 @@ TEST_F(GestureRecognizerTest, FlushAllOnHide) {
   root_window()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
   window->Hide();
   EXPECT_EQ(NULL,
-            root_window()->gesture_recognizer()->GetTouchLockedTarget(&press1));
+      ui::GestureRecognizer::Get()->GetTouchLockedTarget(&press1));
   EXPECT_EQ(NULL,
-            root_window()->gesture_recognizer()->GetTouchLockedTarget(&press2));
+      ui::GestureRecognizer::Get()->GetTouchLockedTarget(&press2));
 }
 
 TEST_F(GestureRecognizerTest, LongPressTimerStopsOnPreventDefaultedTouchMoves) {
@@ -2831,12 +2848,12 @@ TEST_F(GestureRecognizerTest, LongPressTimerStopsOnPreventDefaultedTouchMoves) {
   TimedEvents tes;
 
   TimerTestGestureRecognizer* gesture_recognizer =
-      new TimerTestGestureRecognizer(root_window());
+      new TimerTestGestureRecognizer();
   TimerTestGestureSequence* gesture_sequence =
       static_cast<TimerTestGestureSequence*>(
           gesture_recognizer->GetGestureSequenceForTesting(window.get()));
 
-  root_window()->SetGestureRecognizerForTesting(gesture_recognizer);
+  ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
 
   delegate->Reset();
   ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
diff --git a/ui/aura/root_window.cc b/ui/aura/root_window.cc
index 9014524..500f307 100644
--- a/ui/aura/root_window.cc
+++ b/ui/aura/root_window.cc
@@ -145,7 +145,6 @@ RootWindow::RootWindow(const CreateParams& params)
       mouse_pressed_handler_(NULL),
       mouse_moved_handler_(NULL),
       event_dispatch_target_(NULL),
-      gesture_recognizer_(ui::GestureRecognizer::Create(this)),
       synthesize_mouse_move_(false),
       move_hold_count_(0),
       event_factory_(this),
@@ -159,11 +158,14 @@ RootWindow::RootWindow(const CreateParams& params)
   prop_.reset(new ui::ViewProp(host_->GetAcceleratedWidget(),
                                kRootWindowForAcceleratedWidget,
                                this));
+  ui::GestureRecognizer::Get()->AddGestureEventHelper(this);
 }
 
 RootWindow::~RootWindow() {
   TRACE_EVENT0("shutdown", "RootWindow::Destructor");
 
+  ui::GestureRecognizer::Get()->RemoveGestureEventHelper(this);
+
   // Make sure to destroy the compositor before terminating so that state is
   // cleared and we don't hit asserts.
   compositor_.reset();
@@ -324,7 +326,7 @@ Window* RootWindow::GetGestureTarget(ui::GestureEvent* event) {
   Window* target = client::GetCaptureWindow(this);
   if (!target) {
     target = ConsumerToWindow(
-        gesture_recognizer_->GetTargetForGestureEvent(event));
+        ui::GestureRecognizer::Get()->GetTargetForGestureEvent(event));
   }
 
   return target;
@@ -445,15 +447,11 @@ void RootWindow::ProcessedTouchEvent(ui::TouchEvent* event,
                                      Window* window,
                                      ui::EventResult result) {
   scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
-  gestures.reset(gesture_recognizer_->ProcessTouchEventForGesture(
-      *event, result, window));
+  gestures.reset(ui::GestureRecognizer::Get()->
+      ProcessTouchEventForGesture(*event, result, window));
   ProcessGestures(gestures.get());
 }
 
-void RootWindow::SetGestureRecognizerForTesting(ui::GestureRecognizer* gr) {
-  gesture_recognizer_.reset(gr);
-}
-
 gfx::AcceleratedWidget RootWindow::GetAcceleratedWidget() {
   return host_->GetAcceleratedWidget();
 }
@@ -656,7 +654,7 @@ void RootWindow::OnWindowHidden(Window* invisible, WindowHiddenReason reason) {
 }
 
 void RootWindow::CleanupGestureRecognizerState(Window* window) {
-  gesture_recognizer_->CleanupStateForConsumer(window);
+  ui::GestureRecognizer::Get()->CleanupStateForConsumer(window);
   const Windows& windows = window->children();
   for (Windows::const_iterator iter = windows.begin();
       iter != windows.end();
@@ -712,14 +710,6 @@ void RootWindow::OnDeviceScaleFactorChanged(
 
 void RootWindow::UpdateCapture(Window* old_capture,
                                Window* new_capture) {
-  if (!new_capture && old_capture && old_capture->GetRootWindow() != this) {
-    // If we no longer contain the window that had capture make sure we clean
-    // state in the GestureRecognizer. Since we don't contain the window we'll
-    // never get notification of its destruction and clean up state.
-    // We do this early on as OnCaptureLost() may delete |old_capture|.
-    gesture_recognizer_->CleanupStateForConsumer(old_capture);
-  }
-
   // |mouse_moved_handler_| may have been set to a Window in a different root
   // (see below). Clear it here to ensure we don't end up referencing a stale
   // Window.
@@ -767,12 +757,17 @@ bool RootWindow::CanDispatchToTarget(ui::EventTarget* target) {
 ////////////////////////////////////////////////////////////////////////////////
 // RootWindow, ui::GestureEventHelper implementation:
 
-bool RootWindow::DispatchLongPressGestureEvent(ui::GestureEvent* event) {
-  return DispatchGestureEvent(event);
+bool RootWindow::CanDispatchToConsumer(ui::GestureConsumer* consumer) {
+  Window* window = ConsumerToWindow(consumer);;
+  return (window && window->GetRootWindow() == this);
+}
+
+void RootWindow::DispatchLongPressGestureEvent(ui::GestureEvent* event) {
+  DispatchGestureEvent(event);
 }
 
-bool RootWindow::DispatchCancelTouchEvent(ui::TouchEvent* event) {
-  return OnHostTouchEvent(event);
+void RootWindow::DispatchCancelTouchEvent(ui::TouchEvent* event) {
+  OnHostTouchEvent(event);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1062,10 +1057,10 @@ bool RootWindow::DispatchTouchEventImpl(ui::TouchEvent* event) {
   Window* target = client::GetCaptureWindow(this);
   if (!target) {
     target = ConsumerToWindow(
-        gesture_recognizer_->GetTouchLockedTarget(event));
+        ui::GestureRecognizer::Get()->GetTouchLockedTarget(event));
     if (!target) {
-      target = ConsumerToWindow(
-          gesture_recognizer_->GetTargetForLocation(event->location()));
+      target = ConsumerToWindow(ui::GestureRecognizer::Get()->
+          GetTargetForLocation(event->location()));
     }
   }
 
@@ -1096,8 +1091,8 @@ bool RootWindow::DispatchTouchEventImpl(ui::TouchEvent* event) {
 
   // Get the list of GestureEvents from GestureRecognizer.
   scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
-  gestures.reset(gesture_recognizer_->ProcessTouchEventForGesture(
-      event_for_gr, result, target));
+  gestures.reset(ui::GestureRecognizer::Get()->
+      ProcessTouchEventForGesture(event_for_gr, result, target));
 
   return ProcessGestures(gestures.get()) ? true : handled;
 }
diff --git a/ui/aura/root_window.h b/ui/aura/root_window.h
index b8c4455..7c84fa7 100644
--- a/ui/aura/root_window.h
+++ b/ui/aura/root_window.h
@@ -208,13 +208,6 @@ class AURA_EXPORT RootWindow : public Window,
                            Window* window,
                            ui::EventResult result);
 
-  ui::GestureRecognizer* gesture_recognizer() const {
-    return gesture_recognizer_.get();
-  }
-
-  // Provided only for testing:
-  void SetGestureRecognizerForTesting(ui::GestureRecognizer* gr);
-
   // Returns the accelerated widget from the RootWindowHost.
   gfx::AcceleratedWidget GetAcceleratedWidget();
 
@@ -318,8 +311,9 @@ class AURA_EXPORT RootWindow : public Window,
   virtual bool CanDispatchToTarget(EventTarget* target) OVERRIDE;
 
   // Overridden from ui::GestureEventHelper.
-  virtual bool DispatchLongPressGestureEvent(ui::GestureEvent* event) OVERRIDE;
-  virtual bool DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE;
+  virtual bool CanDispatchToConsumer(ui::GestureConsumer* consumer) OVERRIDE;
+  virtual void DispatchLongPressGestureEvent(ui::GestureEvent* event) OVERRIDE;
+  virtual void DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE;
 
   // Overridden from ui::LayerAnimationObserver:
   virtual void OnLayerAnimationEnded(
@@ -386,9 +380,6 @@ class AURA_EXPORT RootWindow : public Window,
   Window* mouse_moved_handler_;
   Window* event_dispatch_target_;
 
-  // The gesture_recognizer_ for this.
-  scoped_ptr<ui::GestureRecognizer> gesture_recognizer_;
-
   bool synthesize_mouse_move_;
   bool waiting_on_compositing_end_;
   bool draw_on_compositing_end_;
diff --git a/ui/events/gestures/gesture_recognizer.h b/ui/events/gestures/gesture_recognizer.h
index 604dd41..fd5136d 100644
--- a/ui/events/gestures/gesture_recognizer.h
+++ b/ui/events/gestures/gesture_recognizer.h
@@ -17,7 +17,8 @@ namespace ui {
 // into gestures.
 class EVENTS_EXPORT GestureRecognizer {
  public:
-  static GestureRecognizer* Create(GestureEventHelper* helper);
+  static GestureRecognizer* Create();
+  static GestureRecognizer* Get();
 
   // List of GestureEvent*.
   typedef ScopedVector<GestureEvent> Gestures;
@@ -64,6 +65,17 @@ class EVENTS_EXPORT GestureRecognizer {
   // |consumer| false is returned and |point| is untouched.
   virtual bool GetLastTouchPointForTarget(GestureConsumer* consumer,
                                           gfx::Point* point) = 0;
+
+  // Subscribes |helper| for dispatching async gestures such as long press.
+  // The Gesture Recognizer does NOT take ownership of |helper| and it is the
+  // responsibility of the |helper| to call |RemoveGestureEventHelper()| on
+  // destruction.
+  virtual void AddGestureEventHelper(GestureEventHelper* helper) = 0;
+
+  // Unsubscribes |helper| from async gesture dispatch.
+  // Since the GestureRecognizer does not own the |helper|, it is not deleted
+  // and must be cleaned up appropriately by the caller.
+  virtual void RemoveGestureEventHelper(GestureEventHelper* helper) = 0;
 };
 
 }  // namespace ui
diff --git a/ui/events/gestures/gesture_recognizer_impl.cc b/ui/events/gestures/gesture_recognizer_impl.cc
index a472a0c..3e1d02a 100644
--- a/ui/events/gestures/gesture_recognizer_impl.cc
+++ b/ui/events/gestures/gesture_recognizer_impl.cc
@@ -99,8 +99,7 @@ void TransferTouchIdToConsumerMap(
 ////////////////////////////////////////////////////////////////////////////////
 // GestureRecognizerImpl, public:
 
-GestureRecognizerImpl::GestureRecognizerImpl(GestureEventHelper* helper)
-    : helper_(helper) {
+GestureRecognizerImpl::GestureRecognizerImpl() {
   gesture_consumer_ignorer_.reset(new GestureConsumerIgnorer());
 }
 
@@ -159,13 +158,15 @@ void GestureRecognizerImpl::TransferEventsTo(GestureConsumer* current_consumer,
   // Don't send a cancel to |current_consumer|, unless |new_consumer| is NULL.
   for (TouchIdToConsumerMap::iterator i = touch_id_target_.begin();
        i != touch_id_target_.end(); ++i) {
-    if (i->second != new_consumer &&
+    if (i->second && i->second != new_consumer &&
         (i->second != current_consumer || new_consumer == NULL) &&
         i->second != gesture_consumer_ignorer_.get()) {
       TouchEvent touch_event(ui::ET_TOUCH_CANCELLED, gfx::Point(0, 0),
                              ui::EF_IS_SYNTHESIZED, i->first,
                              ui::EventTimeForNow(), 0.0f, 0.0f, 0.0f, 0.0f);
-      helper_->DispatchCancelTouchEvent(&touch_event);
+      GestureEventHelper* helper = FindDispatchHelperForConsumer(i->second);
+      if (helper)
+        helper->DispatchCancelTouchEvent(&touch_event);
       DCHECK_EQ(gesture_consumer_ignorer_.get(), i->second);
     }
   }
@@ -194,8 +195,8 @@ bool GestureRecognizerImpl::GetLastTouchPointForTarget(
 // GestureRecognizerImpl, protected:
 
 GestureSequence* GestureRecognizerImpl::CreateSequence(
-    GestureEventHelper* helper) {
-  return new GestureSequence(helper);
+    GestureSequenceDelegate* delegate) {
+  return new GestureSequence(delegate);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -205,7 +206,7 @@ GestureSequence* GestureRecognizerImpl::GetGestureSequenceForConsumer(
     GestureConsumer* consumer) {
   GestureSequence* gesture_sequence = consumer_sequence_[consumer];
   if (!gesture_sequence) {
-    gesture_sequence = CreateSequence(helper_);
+    gesture_sequence = CreateSequence(this);
     consumer_sequence_[consumer] = gesture_sequence;
   }
   return gesture_sequence;
@@ -243,9 +244,62 @@ void GestureRecognizerImpl::CleanupStateForConsumer(GestureConsumer* consumer) {
   RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_);
 }
 
+void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
+  helpers_.push_back(helper);
+}
+
+void GestureRecognizerImpl::RemoveGestureEventHelper(
+    GestureEventHelper* helper) {
+  std::vector<GestureEventHelper*>::iterator it = std::find(helpers_.begin(),
+      helpers_.end(), helper);
+  if (it != helpers_.end())
+    helpers_.erase(it);
+}
+
+void GestureRecognizerImpl::DispatchLongPressGestureEvent(GestureEvent* event) {
+  GestureConsumer* consumer = GetTargetForGestureEvent(event);
+  if (consumer) {
+    GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
+    if (helper)
+      helper->DispatchLongPressGestureEvent(event);
+  }
+}
+
+GestureEventHelper* GestureRecognizerImpl::FindDispatchHelperForConsumer(
+    GestureConsumer* consumer) {
+  std::vector<GestureEventHelper*>::iterator it;
+  for (it = helpers_.begin(); it != helpers_.end(); ++it) {
+    if ((*it)->CanDispatchToConsumer(consumer))
+      return (*it);
+  }
+  return NULL;
+}
+
 // GestureRecognizer, static
-GestureRecognizer* GestureRecognizer::Create(GestureEventHelper* helper) {
-  return new GestureRecognizerImpl(helper);
+GestureRecognizer* GestureRecognizer::Create() {
+  return new GestureRecognizerImpl();
+}
+
+static GestureRecognizerImpl* g_gesture_recognizer_instance = NULL;
+
+// GestureRecognizer, static
+GestureRecognizer* GestureRecognizer::Get() {
+  if (!g_gesture_recognizer_instance)
+    g_gesture_recognizer_instance = new GestureRecognizerImpl();
+  return g_gesture_recognizer_instance;
+}
+
+void SetGestureRecognizerForTesting(GestureRecognizer* gesture_recognizer) {
+  // Transfer helpers to the new GR.
+  std::vector<GestureEventHelper*>& helpers =
+      g_gesture_recognizer_instance->helpers();
+  std::vector<GestureEventHelper*>::iterator it;
+  for (it = helpers.begin(); it != helpers.end(); ++it)
+    gesture_recognizer->AddGestureEventHelper(*it);
+
+  helpers.clear();
+  g_gesture_recognizer_instance =
+      static_cast<GestureRecognizerImpl*>(gesture_recognizer);
 }
 
 }  // namespace ui
diff --git a/ui/events/gestures/gesture_recognizer_impl.h b/ui/events/gestures/gesture_recognizer_impl.h
index 2ede77d5..35ddaac 100644
--- a/ui/events/gestures/gesture_recognizer_impl.h
+++ b/ui/events/gestures/gesture_recognizer_impl.h
@@ -13,6 +13,7 @@
 #include "ui/events/event_constants.h"
 #include "ui/events/events_export.h"
 #include "ui/events/gestures/gesture_recognizer.h"
+#include "ui/events/gestures/gesture_sequence.h"
 #include "ui/gfx/point.h"
 
 namespace ui {
@@ -22,13 +23,16 @@ class GestureEventHelper;
 class GestureSequence;
 class TouchEvent;
 
-class EVENTS_EXPORT GestureRecognizerImpl : public GestureRecognizer {
+class EVENTS_EXPORT GestureRecognizerImpl : public GestureRecognizer,
+                                            public GestureSequenceDelegate {
  public:
   typedef std::map<int, GestureConsumer*> TouchIdToConsumerMap;
 
-  explicit GestureRecognizerImpl(GestureEventHelper* helper);
+  GestureRecognizerImpl();
   virtual ~GestureRecognizerImpl();
 
+  std::vector<GestureEventHelper*>& helpers() { return helpers_; }
+
   // Overridden from GestureRecognizer
   virtual GestureConsumer* GetTouchLockedTarget(TouchEvent* event) OVERRIDE;
   virtual GestureConsumer* GetTargetForGestureEvent(
@@ -41,7 +45,7 @@ class EVENTS_EXPORT GestureRecognizerImpl : public GestureRecognizer {
                                           gfx::Point* point) OVERRIDE;
 
  protected:
-  virtual GestureSequence* CreateSequence(GestureEventHelper* helper);
+  virtual GestureSequence* CreateSequence(GestureSequenceDelegate* delegate);
   virtual GestureSequence* GetGestureSequenceForConsumer(GestureConsumer* c);
 
  private:
@@ -54,6 +58,15 @@ class EVENTS_EXPORT GestureRecognizerImpl : public GestureRecognizer {
       ui::EventResult result,
       GestureConsumer* target) OVERRIDE;
   virtual void CleanupStateForConsumer(GestureConsumer* consumer) OVERRIDE;
+  virtual void AddGestureEventHelper(GestureEventHelper* helper) OVERRIDE;
+  virtual void RemoveGestureEventHelper(GestureEventHelper* helper) OVERRIDE;
+
+  // Overridden from ui::GestureSequenceDelegate.
+  virtual void DispatchLongPressGestureEvent(GestureEvent* event) OVERRIDE;
+
+  // Convenience method to find the GestureEventHelper that can dispatch events
+  // to a specific |consumer|.
+  GestureEventHelper* FindDispatchHelperForConsumer(GestureConsumer* consumer);
 
   std::map<GestureConsumer*, GestureSequence*> consumer_sequence_;
 
@@ -67,11 +80,16 @@ class EVENTS_EXPORT GestureRecognizerImpl : public GestureRecognizer {
   // Touches cancelled by touch capture are routed to the
   // gesture_consumer_ignorer_.
   scoped_ptr<GestureConsumer> gesture_consumer_ignorer_;
-  GestureEventHelper* helper_;
+
+  std::vector<GestureEventHelper*> helpers_;
 
   DISALLOW_COPY_AND_ASSIGN(GestureRecognizerImpl);
 };
 
+// Provided only for testing:
+EVENTS_EXPORT void SetGestureRecognizerForTesting(
+    GestureRecognizer* gesture_recognizer);
+
 }  // namespace ui
 
 #endif  // UI_EVENTS_GESTURES_GESTURE_RECOGNIZER_IMPL_H_
diff --git a/ui/events/gestures/gesture_sequence.cc b/ui/events/gestures/gesture_sequence.cc
index d364ed2..e728cbc 100644
--- a/ui/events/gestures/gesture_sequence.cc
+++ b/ui/events/gestures/gesture_sequence.cc
@@ -381,14 +381,15 @@ void UpdateGestureEventLatencyInfo(const TouchEvent& event,
 ////////////////////////////////////////////////////////////////////////////////
 // GestureSequence Public:
 
-GestureSequence::GestureSequence(GestureEventHelper* helper)
+GestureSequence::GestureSequence(GestureSequenceDelegate* delegate)
     : state_(GS_NO_GESTURE),
       flags_(0),
       pinch_distance_start_(0.f),
       pinch_distance_current_(0.f),
       scroll_type_(ST_FREE),
       point_count_(0),
-      helper_(helper) {
+      delegate_(delegate) {
+  CHECK(delegate_);
 }
 
 GestureSequence::~GestureSequence() {
@@ -1057,7 +1058,7 @@ void GestureSequence::AppendLongPressGestureEvent() {
       flags_,
       base::Time::FromDoubleT(point->last_touch_time()),
       1 << point->touch_id()));
-  helper_->DispatchLongPressGestureEvent(gesture.get());
+  delegate_->DispatchLongPressGestureEvent(gesture.get());
 }
 
 void GestureSequence::AppendLongTapGestureEvent(const GesturePoint& point,
diff --git a/ui/events/gestures/gesture_sequence.h b/ui/events/gestures/gesture_sequence.h
index 50d9000..9715194 100644
--- a/ui/events/gestures/gesture_sequence.h
+++ b/ui/events/gestures/gesture_sequence.h
@@ -31,13 +31,23 @@ enum ScrollType {
   ST_VERTICAL,
 };
 
+// Delegates dispatch of gesture events for which the GestureSequence does not
+// have enough context to dispatch itself.
+class EVENTS_EXPORT GestureSequenceDelegate {
+ public:
+  virtual void DispatchLongPressGestureEvent(GestureEvent* event) = 0;
+
+ protected:
+  virtual ~GestureSequenceDelegate() {}
+};
+
 // A GestureSequence recognizes gestures from touch sequences.
 class EVENTS_EXPORT GestureSequence {
  public:
   // Maximum number of points in a single gesture.
   static const int kMaxGesturePoints = 12;
 
-  explicit GestureSequence(GestureEventHelper* consumer);
+  explicit GestureSequence(GestureSequenceDelegate* delegate);
   virtual ~GestureSequence();
 
   typedef GestureRecognizer::Gestures Gestures;
@@ -219,7 +229,7 @@ class EVENTS_EXPORT GestureSequence {
   // Location of the last touch event.
   gfx::Point last_touch_location_;
 
-  GestureEventHelper* helper_;
+  GestureSequenceDelegate* delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(GestureSequence);
 };
diff --git a/ui/events/gestures/gesture_types.h b/ui/events/gestures/gesture_types.h
index e87a219..b15788a 100644
--- a/ui/events/gestures/gesture_types.h
+++ b/ui/events/gestures/gesture_types.h
@@ -206,8 +206,10 @@ class EVENTS_EXPORT GestureEventHelper {
   virtual ~GestureEventHelper() {
   }
 
-  virtual bool DispatchLongPressGestureEvent(GestureEvent* event) = 0;
-  virtual bool DispatchCancelTouchEvent(TouchEvent* event) = 0;
+  // Returns true if this helper can dispatch events to |consumer|.
+  virtual bool CanDispatchToConsumer(GestureConsumer* consumer) = 0;
+  virtual void DispatchLongPressGestureEvent(GestureEvent* event) = 0;
+  virtual void DispatchCancelTouchEvent(TouchEvent* event) = 0;
 };
 
 }  // namespace ui
diff --git a/ui/views/corewm/capture_controller.cc b/ui/views/corewm/capture_controller.cc
index c39a9ab..1276c82b 100644
--- a/ui/views/corewm/capture_controller.cc
+++ b/ui/views/corewm/capture_controller.cc
@@ -49,11 +49,8 @@ void CaptureController::SetCapture(aura::Window* new_capture_window) {
   // along (and so shouldn't be canceled) and those that got moved, so
   // just leave them all where they are.
   if (new_capture_window) {
-    for (RootWindows::const_iterator i = root_windows.begin();
-         i != root_windows.end(); ++i) {
-      (*i)->gesture_recognizer()->TransferEventsTo(
-          old_capture_window, new_capture_window);
-    }
+    ui::GestureRecognizer::Get()->TransferEventsTo(old_capture_window,
+        new_capture_window);
   }
 
   capture_window_ = new_capture_window;
diff --git a/ui/views/corewm/capture_controller_unittest.cc b/ui/views/corewm/capture_controller_unittest.cc
index 46a8a2e..edb2410 100644
--- a/ui/views/corewm/capture_controller_unittest.cc
+++ b/ui/views/corewm/capture_controller_unittest.cc
@@ -161,8 +161,8 @@ TEST_F(CaptureControllerTest, TouchTargetResetOnCaptureChange) {
   ui::TouchEvent touch_event(
       ui::ET_TOUCH_PRESSED, gfx::Point(), 0, 0, ui::EventTimeForNow(), 1.0f,
       1.0f, 1.0f, 1.0f);
-  EXPECT_EQ(static_cast<ui::GestureConsumer*>(NULL),
-            root_window()->gesture_recognizer()->GetTouchLockedTarget(
+  EXPECT_EQ(static_cast<ui::GestureConsumer*>(w2.get()),
+            ui::GestureRecognizer::Get()->GetTouchLockedTarget(
                 &touch_event));
 }
 
diff --git a/ui/views/widget/desktop_aura/desktop_capture_client.cc b/ui/views/widget/desktop_aura/desktop_capture_client.cc
index 118b5f2..5a5ec4e 100644
--- a/ui/views/widget/desktop_aura/desktop_capture_client.cc
+++ b/ui/views/widget/desktop_aura/desktop_capture_client.cc
@@ -48,10 +48,8 @@ void DesktopCaptureClient::SetCapture(aura::Window* new_capture_window) {
   // along (and so shouldn't be canceled) and those that got moved, so
   // just leave them all where they are.
   if (new_capture_window) {
-    for (Roots::const_iterator i = roots.begin(); i != roots.end(); ++i) {
-      (*i)->gesture_recognizer()->TransferEventsTo(
-          old_capture_window, new_capture_window);
-    }
+    ui::GestureRecognizer::Get()->TransferEventsTo(old_capture_window,
+        new_capture_window);
   }
 
   capture_window_ = new_capture_window;
-- 
cgit v1.1