diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index e5264da..ccd2bd4 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -701,9 +701,11 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
 
 #ifndef QT_NO_GESTURES
     QHash<QGesture *, QGraphicsObject *>::iterator it;
-    for (it = gestureTargets.begin(); it != gestureTargets.end();) {
+    QGestureManager *mgr = QApplicationPrivate::instance()->gestureManager;
+    QHash<QGesture *, QGraphicsObject *> &m_gestureGraphicsTargets = mgr->m_gestureGraphicsTargets;
+    for (it = m_gestureGraphicsTargets.begin(); it != m_gestureGraphicsTargets.end();) {
         if (it.value() == item)
-            it = gestureTargets.erase(it);
+            it = m_gestureGraphicsTargets.erase(it);
         else
             ++it;
     }
@@ -1185,7 +1187,22 @@ bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event)
 #ifndef QT_NO_GESTURES
         QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
         if (gestureManager) {
-            if (gestureManager->filterEvent(object, event))
+            QMultiMap<QObject *, Qt::GestureType> contexts = gestureManager->getGestureContexts(object);
+            QGestureManagerFilteredGestures result;
+            bool consume = gestureManager->filterEventThroughContexts(contexts, event, &result);
+            QSet<QGesture *> undeliveredGestures;
+            QWidget *viewport = views.at(0)->viewport(); // ####
+            // ### singleshot gestures
+            deliverGestures(viewport, result, &undeliveredGestures);
+
+            // forget about targets for gestures that have ended
+            QSet<QGesture *> endedGestures =
+                    result.finishedGestures + result.canceledGestures + undeliveredGestures + result.maybeToCanceledGestures;
+            foreach (QGesture *g, endedGestures) {
+                gestureManager->recycle(g);
+            }
+
+            if (consume)
                 return true;
         }
 #endif // QT_NO_GESTURES
@@ -3531,12 +3548,6 @@ bool QGraphicsScene::event(QEvent *event)
     case QEvent::TouchEnd:
         d->touchEventHandler(static_cast<QTouchEvent *>(event));
         break;
-#ifndef QT_NO_GESTURES
-    case QEvent::Gesture:
-    case QEvent::GestureOverride:
-        d->gestureEventHandler(static_cast<QGestureEvent *>(event));
-        break;
-#endif // QT_NO_GESTURES
     default:
         return QObject::event(event);
     }
@@ -6045,19 +6056,39 @@ void QGraphicsScenePrivate::gestureTargetsAtHotSpots(const QSet<QGesture *> &ges
         *normal = normalGestures;
 }
 
-void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
+void QGraphicsScenePrivate::deliverGestures(QWidget *viewport, const QGestureManagerFilteredGestures &input,
+                                            QSet<QGesture *> *undeliveredGestures)
+{
+    QSet<QGesture *> allGestures = input.startedGestures+input.triggeredGestures+input.finishedGestures+input.canceledGestures+input.singleshotGestures;
+    deliverGestures(viewport, allGestures, undeliveredGestures);
+
+    if (!input.singleshotGestures.isEmpty()) {
+        QGestureManager *mgr = QApplicationPrivate::instance()->gestureManager;
+        QSet<QGesture *> gestures;
+        // get singleshots that were not canceled
+        gestures = input.singleshotGestures & mgr->m_gestureGraphicsTargets.keys().toSet();
+        foreach (QGesture *g, gestures)
+            g->d_func()->state = Qt::GestureFinished;
+        deliverGestures(viewport, gestures, undeliveredGestures);
+    }
+}
+
+void QGraphicsScenePrivate::deliverGestures(QWidget *viewport, const QSet<QGesture *> &allGestures,
+                                            QSet<QGesture *> *undeliveredGestures)
 {
-    QWidget *viewport = event->widget();
-    if (!viewport)
+    if (allGestures.isEmpty())
         return;
+    Q_ASSERT(viewport);
     QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(viewport->parent());
     if (!graphicsView)
         return;
 
-    QList<QGesture *> allGestures = event->gestures();
     DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
             << "Gestures:" <<  allGestures;
 
+    QGestureManager *mgr = QApplicationPrivate::instance()->gestureManager;
+    QHash<QGesture *, QGraphicsObject *> &m_gestureGraphicsTargets = mgr->m_gestureGraphicsTargets;
+
     QSet<QGesture *> startedGestures;
     QPoint delta = viewport->mapFromGlobal(QPoint());
     QTransform toScene = QTransform::fromTranslate(delta.x(), delta.y())
@@ -6070,7 +6101,7 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
             gesture->d_func()->sceneHotSpot = QPointF();
         }
 
-        QGraphicsObject *target = gestureTargets.value(gesture, 0);
+        QGraphicsObject *target = m_gestureGraphicsTargets.value(gesture, 0);
         if (!target) {
             // when we are not in started mode but don't have a target
             // then the only one interested in gesture is the view/scene
@@ -6078,6 +6109,7 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
                 startedGestures.insert(gesture);
         }
     }
+    *undeliveredGestures = startedGestures;
 
     if (!startedGestures.isEmpty()) {
         QSet<QGesture *> normalGestures; // that have just one target
@@ -6088,7 +6120,8 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
         qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
         DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
                 << "Normal gestures:" << normalGestures
-                << "Conflicting gestures:" << conflictedGestures;
+                << "Conflicting gestures:" << conflictedGestures
+                << "Cached targets:" << cachedTargetItems;
 
         // deliver conflicted gestures as override events AND remember
         // initial gesture targets
@@ -6098,8 +6131,12 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
 
                 // get gestures to deliver to the current item
                 QSet<QGesture *> gestures = conflictedGestures & cachedItemGestures.value(item.data());
-                if (gestures.isEmpty())
+                if (gestures.isEmpty()) {
+                    DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
+                            << "nothing to deliver to"
+                            << item.data();
                     continue;
+                }
 
                 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
                         << "delivering override to"
@@ -6107,7 +6144,7 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
                 // send gesture override
                 QGestureEvent ev(gestures.toList());
                 ev.t = QEvent::GestureOverride;
-                ev.setWidget(event->widget());
+                ev.setWidget(viewport);
                 // mark event and individual gestures as ignored
                 ev.ignore();
                 foreach(QGesture *g, gestures)
@@ -6119,7 +6156,7 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
                         conflictedGestures.remove(g);
                         // mark the item as a gesture target
                         if (item) {
-                            gestureTargets.insert(g, item.data());
+                            m_gestureGraphicsTargets.insert(g, item.data());
                             QHash<QGraphicsObject *, QSet<QGesture *> >::iterator it, e;
                             it = cachedItemGestures.begin();
                             e = cachedItemGestures.end();
@@ -6134,8 +6171,8 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
                     // remember the first item that received the override event
                     // as it most likely become a target if noone else accepts
                     // the override event
-                    if (!gestureTargets.contains(g) && item)
-                        gestureTargets.insert(g, item.data());
+                    if (!m_gestureGraphicsTargets.contains(g) && item)
+                        m_gestureGraphicsTargets.insert(g, item.data());
 
                 }
                 if (conflictedGestures.isEmpty())
@@ -6150,8 +6187,8 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
 
                 // get gestures to deliver to the current item
                 foreach (QGesture *g, cachedItemGestures.value(item)) {
-                    if (!gestureTargets.contains(g)) {
-                        gestureTargets.insert(g, item);
+                    if (!m_gestureGraphicsTargets.contains(g)) {
+                        m_gestureGraphicsTargets.insert(g, item);
                         normalGestures.remove(g);
                     }
                 }
@@ -6161,13 +6198,13 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
 
 
     // deliver all gesture events
-    QSet<QGesture *> undeliveredGestures;
     QSet<QGesture *> parentPropagatedGestures;
+    QSet<QGesture *> notYetDeliveredGestures;
     foreach (QGesture *gesture, allGestures) {
-        if (QGraphicsObject *target = gestureTargets.value(gesture, 0)) {
+        if (QGraphicsObject *target = m_gestureGraphicsTargets.value(gesture, 0)) {
             cachedItemGestures[target].insert(gesture);
             cachedTargetItems.append(target);
-            undeliveredGestures.insert(gesture);
+            notYetDeliveredGestures.insert(gesture);
             QGraphicsItemPrivate *d = target->QGraphicsItem::d_func();
             const Qt::GestureFlags flags = d->gestureContext.value(gesture->gestureType());
             if (flags & Qt::IgnoredGesturesPropagateToParent)
@@ -6182,7 +6219,7 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
     for (int i = 0; i < cachedTargetItems.size(); ++i) {
         QWeakPointer<QGraphicsObject> receiver = cachedTargetItems.at(i);
         QSet<QGesture *> gestures =
-                undeliveredGestures & cachedItemGestures.value(receiver.data());
+                notYetDeliveredGestures & cachedItemGestures.value(receiver.data());
         gestures -= cachedAlreadyDeliveredGestures.value(receiver.data());
 
         if (gestures.isEmpty())
@@ -6195,7 +6232,7 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
                 << "delivering to"
                 << receiver.data() << gestures;
         QGestureEvent ev(gestures.toList());
-        ev.setWidget(event->widget());
+        ev.setWidget(viewport);
         sendEvent(receiver.data(), &ev);
         QSet<QGesture *> ignoredGestures;
         foreach (QGesture *g, gestures) {
@@ -6205,18 +6242,19 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
                 // want to receive partial gestures).
                 // ### wont' work if the target was destroyed in the event
                 //     we will just stop delivering it.
-                if (receiver && receiver.data() == gestureTargets.value(g, 0))
+                if (receiver && receiver.data() == m_gestureGraphicsTargets.value(g, 0))
                     ignoredGestures.insert(g);
             } else {
                 if (receiver && g->state() == Qt::GestureStarted) {
                     // someone accepted the propagated initial GestureStarted
                     // event, let it be the new target for all following events.
-                    gestureTargets[g] = receiver.data();
+                    m_gestureGraphicsTargets[g] = receiver.data();
                 }
-                undeliveredGestures.remove(g);
+                notYetDeliveredGestures.remove(g);
+                undeliveredGestures->remove(g);
             }
         }
-        if (undeliveredGestures.isEmpty())
+        if (notYetDeliveredGestures.isEmpty())
             break;
 
         // ignoredGestures list is only filled when delivering to the gesture
@@ -6279,7 +6317,7 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
         switch (g->state()) {
         case Qt::GestureFinished:
         case Qt::GestureCanceled:
-            gestureTargets.remove(g);
+            m_gestureGraphicsTargets.remove(g);
             break;
         default:
             break;
@@ -6294,7 +6332,9 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
 void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original)
 {
     Q_ASSERT(original);
-    QGraphicsItem *originalItem = gestureTargets.value(original);
+    QGestureManager *mgr = QApplicationPrivate::instance()->gestureManager;
+    QHash<QGesture *, QGraphicsObject *> &m_gestureGraphicsTargets = mgr->m_gestureGraphicsTargets;
+    QGraphicsItem *originalItem = m_gestureGraphicsTargets.value(original);
     if (originalItem == 0) // we only act on accepted gestures, which implies it has a target.
         return;
 
@@ -6302,8 +6342,8 @@ void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original)
     // if the owner is part of our sub-hierarchy, cancel it.
 
     QSet<QGesture *> canceledGestures;
-    QHash<QGesture *, QGraphicsObject *>::Iterator iter = gestureTargets.begin();
-    while (iter != gestureTargets.end()) {
+    QHash<QGesture *, QGraphicsObject *>::Iterator iter = m_gestureGraphicsTargets.begin();
+    while (iter != m_gestureGraphicsTargets.end()) {
         QGraphicsObject *item = iter.value();
         // note that we don't touch the gestures for our originalItem
         if (item != originalItem && originalItem->isAncestorOf(item)) {
@@ -6323,7 +6363,7 @@ void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original)
         setIter = almostCanceledGestures.begin();
         // sort per target item
         while (setIter != almostCanceledGestures.end()) {
-            QGraphicsObject *item = gestureTargets.value(*setIter);
+            QGraphicsObject *item = m_gestureGraphicsTargets.value(*setIter);
             if (target == 0)
                 target = item;
             if (target == item) {
@@ -6370,7 +6410,7 @@ void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original)
     Q_ASSERT(gestureManager); // it would be very odd if we got called without a manager.
     for (setIter = canceledGestures.begin(); setIter != canceledGestures.end(); ++setIter) {
         gestureManager->recycle(*setIter);
-        gestureTargets.remove(*setIter);
+        m_gestureGraphicsTargets.remove(*setIter);
     }
 }
 
diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h
index f8615f4..a3a96b6 100644
--- a/src/gui/graphicsview/qgraphicsscene.h
+++ b/src/gui/graphicsview/qgraphicsscene.h
@@ -315,6 +315,7 @@ private:
     friend class QGraphicsItemEffectSourcePrivate;
 #ifndef QT_NO_GESTURES
     friend class QGesture;
+    friend class QGestureManager;
 #endif
 };
 
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index f28dfe9..5186e4b 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -77,6 +77,7 @@ QT_BEGIN_NAMESPACE
 class QGraphicsSceneIndex;
 class QGraphicsView;
 class QGraphicsWidget;
+class QGestureManagerFilteredGestures;
 
 class Q_AUTOTEST_EXPORT QGraphicsScenePrivate : public QObjectPrivate
 {
@@ -302,9 +303,11 @@ public:
 #ifndef QT_NO_GESTURES
     QHash<QGraphicsObject *, QSet<QGesture *> > cachedItemGestures;
     QHash<QGraphicsObject *, QSet<QGesture *> > cachedAlreadyDeliveredGestures;
-    QHash<QGesture *, QGraphicsObject *> gestureTargets;
     QHash<Qt::GestureType, int>  grabbedGestures;
-    void gestureEventHandler(QGestureEvent *event);
+    void deliverGestures(QWidget *viewport, const QGestureManagerFilteredGestures &allGestures,
+                         QSet<QGesture *> *undeliveredGestures);
+    void deliverGestures(QWidget *viewport, const QSet<QGesture *> &allGestures,
+                         QSet<QGesture *> *undeliveredGestures);
     void gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures,
                            Qt::GestureFlag flag,
                            QHash<QGraphicsObject *, QSet<QGesture *> > *targets,
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index 0674610..90c8dab 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -2840,21 +2840,6 @@ bool QGraphicsView::viewportEvent(QEvent *event)
 
         return true;
     }
-#ifndef QT_NO_GESTURES
-    case QEvent::Gesture:
-    case QEvent::GestureOverride:
-    {
-        if (!isEnabled())
-            return false;
-
-        if (d->scene && d->sceneInteractionAllowed) {
-            QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(event);
-            gestureEvent->setWidget(viewport());
-            (void) QApplication::sendEvent(d->scene, gestureEvent);
-        }
-        return true;
-    }
-#endif // QT_NO_GESTURES
     default:
         break;
     }
diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp
index f5688f4..79a5304 100644
--- a/src/gui/kernel/qgesture.cpp
+++ b/src/gui/kernel/qgesture.cpp
@@ -41,6 +41,9 @@
 
 #include "qgesture.h"
 #include "private/qgesture_p.h"
+#ifndef QT_NO_DEBUG_STREAM
+#include "qdebug.h"
+#endif
 
 #ifndef QT_NO_GESTURES
 
@@ -726,6 +729,23 @@ void QTapAndHoldGesture::setPosition(const QPointF &value)
     d_func()->position = value;
 }
 
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, QGesture *g)
+{
+    if (!g) {
+        debug << "QGesture(0)";
+        return debug;
+    }
+
+    debug.nospace() << g->metaObject()->className();
+    debug.nospace() << "(this=" << (void*)g
+          << ", type=" << g->gestureType()
+          << ", state=" << g->state()
+          << ")";
+    return debug;
+}
+#endif
+
 QT_END_NAMESPACE
 
 #endif // QT_NO_GESTURES
diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h
index 8c10895..3b2fb67 100644
--- a/src/gui/kernel/qgesture.h
+++ b/src/gui/kernel/qgesture.h
@@ -255,6 +255,10 @@ public:
     friend class QTapAndHoldGestureRecognizer;
 };
 
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug debug, QGesture *gesture);
+#endif
+
 QT_END_NAMESPACE
 
 Q_DECLARE_METATYPE(QGesture::GestureCancelPolicy)
diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp
index e43a560..a77c493 100644
--- a/src/gui/kernel/qgesturemanager.cpp
+++ b/src/gui/kernel/qgesturemanager.cpp
@@ -41,9 +41,11 @@
 
 #include "private/qgesturemanager_p.h"
 #include "private/qstandardgestures_p.h"
+#include "private/qobject_p.h"
 #include "private/qwidget_p.h"
 #include "private/qgesture_p.h"
 #include "private/qgraphicsitem_p.h"
+#include "private/qgraphicsscene_p.h"
 #include "private/qevent_p.h"
 #include "private/qapplication_p.h"
 #include "qgesture.h"
@@ -167,6 +169,8 @@ void QGestureManager::cleanupCachedGestures(QObject *target, Qt::GestureType typ
                 m_deletedRecognizers.remove(g);
                 m_gestureToRecognizer.remove(g);
             }
+            m_maybeGestures -= gestures;
+            m_activeGestures -= gestures;
             qDeleteAll(gestures);
             iter = m_objectGestures.erase(iter);
         } else {
@@ -223,10 +227,11 @@ QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recogni
 
 bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *,
                                                  Qt::GestureType> &contexts,
-                                                 QEvent *event)
+                                                 QEvent *event,
+                                                 QGestureManagerFilteredGestures *result)
 {
-    QSet<QGesture *> triggeredGestures;
-    QSet<QGesture *> finishedGestures;
+    QSet<QGesture *> &triggeredGestures = result->triggeredGestures;
+    QSet<QGesture *> &finishedGestures = result->finishedGestures;
     QSet<QGesture *> newMaybeGestures;
     QSet<QGesture *> notGestures;
 
@@ -252,22 +257,22 @@ bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *,
             QGestureRecognizer::Result type = result & QGestureRecognizer::ResultState_Mask;
             result &= QGestureRecognizer::ResultHint_Mask;
             if (type == QGestureRecognizer::TriggerGesture) {
-                DEBUG() << "QGestureManager:Recognizer: gesture triggered: " << state;
+                DEBUG() << "QGestureManager:Recognizer: gesture triggered: " << event->type() << state;
                 triggeredGestures << state;
             } else if (type == QGestureRecognizer::FinishGesture) {
-                DEBUG() << "QGestureManager:Recognizer: gesture finished: " << state;
+                DEBUG() << "QGestureManager:Recognizer: gesture finished: " << event->type() << state;
                 finishedGestures << state;
             } else if (type == QGestureRecognizer::MayBeGesture) {
-                DEBUG() << "QGestureManager:Recognizer: maybe gesture: " << state;
+                DEBUG() << "QGestureManager:Recognizer: maybe gesture: " << event->type() << state;
                 newMaybeGestures << state;
             } else if (type == QGestureRecognizer::CancelGesture) {
-                DEBUG() << "QGestureManager:Recognizer: not gesture: " << state;
+                DEBUG() << "QGestureManager:Recognizer: not gesture: " << event->type() << state;
                 notGestures << state;
             } else if (type == QGestureRecognizer::Ignore) {
-                DEBUG() << "QGestureManager:Recognizer: ignored the event: " << state;
+                DEBUG() << "QGestureManager:Recognizer: ignored the event: " << event->type() << state;
             } else {
                 DEBUG() << "QGestureManager:Recognizer: hm, lets assume the recognizer"
-                        << "ignored the event: " << state;
+                        << "ignored the event: " << event->type() << state;
             }
             if (result & QGestureRecognizer::ConsumeEventHint) {
                 DEBUG() << "QGestureManager: we were asked to consume the event: "
@@ -280,18 +285,21 @@ bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *,
         && newMaybeGestures.isEmpty() && notGestures.isEmpty())
         return ret;
 
-    QSet<QGesture *> startedGestures = triggeredGestures - m_activeGestures;
+    QSet<QGesture *> &startedGestures = result->startedGestures;
+    startedGestures = triggeredGestures - m_activeGestures;
     triggeredGestures &= m_activeGestures;
 
     // check if a running gesture switched back to maybe state
     QSet<QGesture *> activeToMaybeGestures = m_activeGestures & newMaybeGestures;
 
     // check if a maybe gesture switched to canceled - reset it but don't send an event
-    QSet<QGesture *> maybeToCanceledGestures = m_maybeGestures & notGestures;
+    QSet<QGesture *> &maybeToCanceledGestures = result->maybeToCanceledGestures;
+    maybeToCanceledGestures = m_maybeGestures & notGestures;
 
     // check if a running gesture switched back to not gesture state,
     // i.e. were canceled
-    QSet<QGesture *> canceledGestures = m_activeGestures & notGestures;
+    QSet<QGesture *> &canceledGestures = result->canceledGestures;
+    canceledGestures = m_activeGestures & notGestures;
 
     // new gestures in maybe state
     m_maybeGestures += newMaybeGestures;
@@ -315,9 +323,11 @@ bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *,
         // probably those are "singleshot" gestures so we'll fake the started state.
         foreach (QGesture *gesture, notStarted)
             gesture->d_func()->state = Qt::GestureStarted;
-        QSet<QGesture *> undeliveredGestures;
-        deliverEvents(notStarted, &undeliveredGestures);
-        finishedGestures -= undeliveredGestures;
+        result->singleshotGestures = notStarted;
+        finishedGestures -= notStarted;
+//        QSet<QGesture *> undeliveredGestures;
+//        deliverEvents(notStarted, &undeliveredGestures); //#####
+//        finishedGestures -= undeliveredGestures;
     }
 
     m_activeGestures += startedGestures;
@@ -352,29 +362,30 @@ bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *,
                 << "\n\tmaybe-canceled:" << maybeToCanceledGestures;
     }
 
-    QSet<QGesture *> undeliveredGestures;
-    deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures,
-                  &undeliveredGestures);
-
-    foreach (QGesture *g, startedGestures) {
-        if (undeliveredGestures.contains(g))
-            continue;
-        if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
-            DEBUG() << "lets try to cancel some";
-            // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
-            cancelGesturesForChildren(g);
-        }
-    }
-
-    m_activeGestures -= undeliveredGestures;
+//    QSet<QGesture *> undeliveredGestures;
+//    deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures,
+//                  &undeliveredGestures);
+
+//    foreach (QGesture *g, startedGestures) {
+//        if (undeliveredGestures.contains(g))
+//            continue;
+//        if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
+//            DEBUG() << "lets try to cancel some";
+//            // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
+//            cancelGesturesForChildren(g);
+//        }
+//    }
+
+//    m_activeGestures -= undeliveredGestures;
+
+//    // reset gestures that ended
+//    QSet<QGesture *> endedGestures =
+//            finishedGestures + canceledGestures + undeliveredGestures + maybeToCanceledGestures;
+//    foreach (QGesture *gesture, endedGestures) {
+//        recycle(gesture);
+//        m_gestureTargets.remove(gesture);
+//    }
 
-    // reset gestures that ended
-    QSet<QGesture *> endedGestures =
-            finishedGestures + canceledGestures + undeliveredGestures + maybeToCanceledGestures;
-    foreach (QGesture *gesture, endedGestures) {
-        recycle(gesture);
-        m_gestureTargets.remove(gesture);
-    }
     return ret;
 }
 
@@ -410,7 +421,7 @@ void QGestureManager::cancelGesturesForChildren(QGesture *original)
     QSet<QGesture *> almostCanceledGestures = cancelledGestures;
     while (!almostCanceledGestures.isEmpty()) {
         QWidget *target = 0;
-        QSet<QGesture*> gestures;
+        QGestureManagerFilteredGestures gestures;
         iter = almostCanceledGestures.begin();
         // sort per target widget
         while (iter != almostCanceledGestures.end()) {
@@ -418,7 +429,7 @@ void QGestureManager::cancelGesturesForChildren(QGesture *original)
             if (target == 0)
                 target = widget;
             if (target == widget) {
-                gestures << *iter;
+                gestures.canceledGestures << *iter;
                 iter = almostCanceledGestures.erase(iter);
             } else {
                 ++iter;
@@ -430,8 +441,10 @@ void QGestureManager::cancelGesturesForChildren(QGesture *original)
         deliverEvents(gestures, &undeliveredGestures);
     }
 
-    for (iter = cancelledGestures.begin(); iter != cancelledGestures.end(); ++iter)
+    for (iter = cancelledGestures.begin(); iter != cancelledGestures.end(); ++iter) {
+        DEBUG() << "QGestureManager::cancelGesturesForChildren(): recycling canceled gesture" << *iter;
         recycle(*iter);
+    }
 }
 
 void QGestureManager::cleanupGesturesForRemovedRecognizer(QGesture *gesture)
@@ -478,11 +491,38 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event)
             break;
         w = w->parentWidget();
     }
-    return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event);
+    QGestureManagerFilteredGestures result;
+    if (contexts.isEmpty())
+        return false;
+    bool consume = filterEventThroughContexts(contexts, event, &result);
+
+    // ### singleshot gestures
+    QSet<QGesture *> undeliveredGestures;
+    deliverEvents(result, &undeliveredGestures);
+
+    foreach (QGesture *g, result.startedGestures) {
+        if (undeliveredGestures.contains(g))
+            continue;
+        if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
+            DEBUG() << "lets try to cancel some";
+            // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
+            cancelGesturesForChildren(g);
+        }
+    }
+
+    // reset gestures that ended
+    QSet<QGesture *> endedGestures =
+            result.finishedGestures + result.canceledGestures + undeliveredGestures + result.maybeToCanceledGestures;
+    foreach (QGesture *gesture, endedGestures) {
+        DEBUG() << "QGestureManager::filterEvent(): recycling ended gesture" << gesture;
+        recycle(gesture);
+    }
+
+    return consume;
 }
 
 #ifndef QT_NO_GRAPHICSVIEW
-bool QGestureManager::filterEvent(QGraphicsObject *receiver, QEvent *event)
+QMultiMap<QObject *, Qt::GestureType> QGestureManager::getGestureContexts(QGraphicsObject *receiver)
 {
     QMap<Qt::GestureType, int> types;
     QMultiMap<QObject *, Qt::GestureType> contexts;
@@ -511,7 +551,7 @@ bool QGestureManager::filterEvent(QGraphicsObject *receiver, QEvent *event)
         }
         item = item->parentObject();
     }
-    return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event);
+    return contexts;
 }
 #endif
 
@@ -522,7 +562,41 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event)
     QGesture *state = static_cast<QGesture *>(receiver);
     QMultiMap<QObject *, Qt::GestureType> contexts;
     contexts.insert(state, state->gestureType());
-    return filterEventThroughContexts(contexts, event);
+    QGestureManagerFilteredGestures result;
+    bool consume = filterEventThroughContexts(contexts, event, &result);
+
+    QSet<QGesture *> undeliveredGestures;
+    QObject *owner = m_gestureOwners[state];
+    // ### singleshot gestures
+    if (QObjectPrivate::get(owner)->isWidget) {
+        deliverEvents(result, &undeliveredGestures);
+    } else {
+        Q_ASSERT(qobject_cast<QGraphicsObject *>(owner));
+        QGraphicsObject *obj = static_cast<QGraphicsObject *>(owner);
+        QGraphicsScene *scene = obj->scene();
+        QWidget *viewport = scene->d_func()->views.at(0)->viewport(); //#####
+        scene->d_func()->deliverGestures(viewport, result, &undeliveredGestures);
+    }
+
+    foreach (QGesture *g, result.startedGestures) {
+        if (undeliveredGestures.contains(g))
+            continue;
+        if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
+            DEBUG() << "lets try to cancel some";
+            // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
+            cancelGesturesForChildren(g);
+        }
+    }
+
+    // reset gestures that ended
+    QSet<QGesture *> endedGestures =
+            result.finishedGestures + result.canceledGestures + undeliveredGestures + result.maybeToCanceledGestures;
+    foreach (QGesture *gesture, endedGestures) {
+        DEBUG() << "QGestureManager::filterEvent(): recycling ended gesture" << gesture;
+        recycle(gesture);
+    }
+
+    return consume;
 }
 
 void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures,
@@ -568,9 +642,10 @@ void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures,
     }
 }
 
-void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
+void QGestureManager::deliverEvents(const QGestureManagerFilteredGestures &input,
                                     QSet<QGesture *> *undeliveredGestures)
 {
+    QSet<QGesture *> gestures = input.startedGestures+input.triggeredGestures+input.finishedGestures+input.canceledGestures;
     if (gestures.isEmpty())
         return;
 
@@ -690,10 +765,12 @@ void QGestureManager::recycle(QGesture *gesture)
     if (recognizer) {
         gesture->setGestureCancelPolicy(QGesture::CancelNone);
         recognizer->reset(gesture);
-        m_activeGestures.remove(gesture);
     } else {
         cleanupGesturesForRemovedRecognizer(gesture);
     }
+    m_activeGestures.remove(gesture);
+    m_maybeGestures.remove(gesture);
+    m_gestureTargets.remove(gesture);
 }
 
 QT_END_NAMESPACE
diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h
index 747cb1a..89521e0 100644
--- a/src/gui/kernel/qgesturemanager_p.h
+++ b/src/gui/kernel/qgesturemanager_p.h
@@ -62,9 +62,19 @@
 
 QT_BEGIN_NAMESPACE
 
+struct QGestureManagerFilteredGestures
+{
+    QSet<QGesture *> startedGestures;
+    QSet<QGesture *> triggeredGestures;
+    QSet<QGesture *> finishedGestures;
+    QSet<QGesture *> canceledGestures;
+    QSet<QGesture *> maybeToCanceledGestures;
+    QSet<QGesture *> singleshotGestures;
+};
+
 class QBasicTimer;
 class QGraphicsObject;
-class QGestureManager : public QObject
+class Q_AUTOTEST_EXPORT QGestureManager : public QObject
 {
     Q_OBJECT
 public:
@@ -77,7 +87,7 @@ public:
     bool filterEvent(QWidget *receiver, QEvent *event);
     bool filterEvent(QObject *receiver, QEvent *event);
 #ifndef QT_NO_GRAPHICSVIEW
-    bool filterEvent(QGraphicsObject *receiver, QEvent *event);
+    QMultiMap<QObject *, Qt::GestureType> getGestureContexts(QGraphicsObject *receiver);
 #endif //QT_NO_GRAPHICSVIEW
 
     static QGestureManager* instance(); // declared in qapplication.cpp
@@ -86,11 +96,11 @@ public:
 
     void recycle(QGesture *gesture);
 
-protected:
+public:
     bool filterEventThroughContexts(const QMultiMap<QObject *, Qt::GestureType> &contexts,
-                                    QEvent *event);
+                                    QEvent *event, QGestureManagerFilteredGestures *result);
 
-private:
+//private:
     QMultiMap<Qt::GestureType, QGestureRecognizer *> m_recognizers;
 
     QSet<QGesture *> m_activeGestures;
@@ -123,8 +133,8 @@ private:
     QMap<ObjectGesture, QList<QGesture *> > m_objectGestures;
     QHash<QGesture *, QGestureRecognizer *> m_gestureToRecognizer;
     QHash<QGesture *, QObject *> m_gestureOwners;
-
     QHash<QGesture *, QWidget *> m_gestureTargets;
+    QHash<QGesture *, QGraphicsObject *> m_gestureGraphicsTargets;
 
     int m_lastCustomGestureId;
 
@@ -134,7 +144,7 @@ private:
 
     QGesture *getState(QObject *widget, QGestureRecognizer *recognizer,
                        Qt::GestureType gesture);
-    void deliverEvents(const QSet<QGesture *> &gestures,
+    void deliverEvents(const QGestureManagerFilteredGestures &gestures,
                        QSet<QGesture *> *undeliveredGestures);
     void getGestureTargets(const QSet<QGesture*> &gestures,
                            QMap<QWidget *, QList<QGesture *> > *conflicts,
diff --git a/tests/auto/gestures/tst_gestures.cpp b/tests/auto/gestures/tst_gestures.cpp
index a968520..b6c641e 100644
--- a/tests/auto/gestures/tst_gestures.cpp
+++ b/tests/auto/gestures/tst_gestures.cpp
@@ -44,6 +44,7 @@
 #include "../../shared/util.h"
 
 #include <qevent.h>
+#include <qgraphicssceneevent.h>
 #include <qwidget.h>
 #include <qlayout.h>
 #include <qgesture.h>
@@ -52,6 +53,7 @@
 #include <qgraphicswidget.h>
 #include <qgraphicsview.h>
 #include <qmainwindow.h>
+#include <private/qgesturemanager_p.h>
 
 #include <qdebug.h>
 
@@ -361,6 +363,10 @@ private slots:
     void partialGesturePropagation();
     void testQGestureRecognizerCleanup();
     void testReuseCanceledGestures();
+    void deleteViewport();
+    void unfinishedGesture();
+    void asyncGesture_data();
+    void asyncGesture();
 };
 
 tst_Gestures::tst_Gestures()
@@ -373,6 +379,9 @@ tst_Gestures::~tst_Gestures()
 
 void tst_Gestures::initTestCase()
 {
+    QVERIFY(QGestureManager::instance());
+    QVERIFY(QGestureManager::instance()->m_activeGestures.isEmpty());
+    QVERIFY(QGestureManager::instance()->m_maybeGestures.isEmpty());
     CustomGesture::GestureType = QGestureRecognizer::registerRecognizer(new CustomGestureRecognizer);
     QVERIFY(CustomGesture::GestureType != Qt::GestureType(0));
     QVERIFY(CustomGesture::GestureType != Qt::CustomGesture);
@@ -427,22 +436,26 @@ void tst_Gestures::consumeEventHint()
 
 void tst_Gestures::autoCancelingGestures()
 {
-    GestureWidget widget;
-    widget.grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+    GestureWidget *widget = new GestureWidget;
+    widget->grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
     // send partial gesture. The gesture will be in the "maybe" state, but will
     // never get enough events to fire, so Qt will have to kill it.
     CustomEvent ev;
     for (int i = CustomGesture::SerialMaybeThreshold;
          i < CustomGesture::SerialStartedThreshold; ++i) {
         ev.serial = i;
-        QApplication::sendEvent(&widget, &ev);
+        QApplication::sendEvent(widget, &ev);
     }
-    // wait long enough so the gesture manager will cancel the gesture
-    QTest::qWait(5000);
-    QCOMPARE(widget.customEventsReceived, CustomGesture::SerialStartedThreshold - CustomGesture::SerialMaybeThreshold);
-    QCOMPARE(widget.gestureEventsReceived, 0);
-    QCOMPARE(widget.gestureOverrideEventsReceived, 0);
-    QCOMPARE(widget.events.all.size(), 0);
+    QCOMPARE(widget->customEventsReceived, CustomGesture::SerialStartedThreshold - CustomGesture::SerialMaybeThreshold);
+    QCOMPARE(widget->gestureEventsReceived, 0);
+    QCOMPARE(widget->gestureOverrideEventsReceived, 0);
+    QCOMPARE(widget->events.all.size(), 0);
+
+    delete widget;
+
+    QVERIFY(QGestureManager::instance());
+    QVERIFY(QGestureManager::instance()->m_activeGestures.isEmpty());
+    QVERIFY(QGestureManager::instance()->m_maybeGestures.isEmpty());
 }
 
 void tst_Gestures::gestureOverChild()
@@ -871,9 +884,6 @@ void tst_Gestures::graphicsItemGesture()
     CustomEvent event;
     // gesture without hotspot should not be delivered to items in the view
     QTest::ignoreMessage(QtWarningMsg, "QGestureManager::deliverEvent: could not find the target for gesture");
-    QTest::ignoreMessage(QtWarningMsg, "QGestureManager::deliverEvent: could not find the target for gesture");
-    QTest::ignoreMessage(QtWarningMsg, "QGestureManager::deliverEvent: could not find the target for gesture");
-    QTest::ignoreMessage(QtWarningMsg, "QGestureManager::deliverEvent: could not find the target for gesture");
     sendCustomGesture(&event, item, &scene);
 
     QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
@@ -1832,6 +1842,54 @@ void tst_Gestures::panelStacksBehindParent()
 
 void tst_Gestures::deleteGestureTargetWidget()
 {
+    GestureWidget a("A");
+    GestureWidget *A = &a;
+    GestureWidget *B = new GestureWidget("B", A);
+
+    A->grabGesture(CustomGesture::GestureType);
+    B->grabGesture(CustomGesture::GestureType);
+
+    QVERIFY(QGestureManager::instance());
+    QVERIFY(QGestureManager::instance()->m_activeGestures.isEmpty());
+    QVERIFY(QGestureManager::instance()->m_maybeGestures.isEmpty());
+    CustomEvent event;
+
+    connect(B, SIGNAL(gestureUpdated(QEvent::Type,QGesture*)),
+            B, SLOT(deleteLater()));
+    sendCustomGesture(&event, B);
+
+    QVERIFY(QGestureManager::instance()->m_activeGestures.isEmpty());
+    QVERIFY(QGestureManager::instance()->m_maybeGestures.isEmpty());
+
+    B = new GestureWidget("B2", A);
+    connect(B, SIGNAL(gestureStarted(QEvent::Type,QGesture*)),
+            B, SLOT(deleteLater()));
+    sendCustomGesture(&event, B);
+    QVERIFY(QGestureManager::instance()->m_activeGestures.isEmpty());
+    QVERIFY(QGestureManager::instance()->m_maybeGestures.isEmpty());
+}
+
+void tst_Gestures::unfinishedGesture()
+{
+    GestureWidget *widget = new GestureWidget("widget");
+
+    widget->grabGesture(CustomGesture::GestureType);
+
+    // send partial gesture. The gesture will be in the "maybe" state, but will
+    // never get enough events to fire. And then we delete the widget.
+    CustomEvent ev;
+    for (int i = CustomGesture::SerialMaybeThreshold;
+         i < CustomGesture::SerialStartedThreshold; ++i) {
+        ev.serial = i;
+        QApplication::sendEvent(widget, &ev);
+    }
+    QCOMPARE(widget->customEventsReceived, CustomGesture::SerialStartedThreshold - CustomGesture::SerialMaybeThreshold);
+    QCOMPARE(widget->gestureEventsReceived, 0);
+    QCOMPARE(widget->gestureOverrideEventsReceived, 0);
+    QCOMPARE(widget->events.all.size(), 0);
+
+    widget->ungrabGesture(CustomGesture::GestureType);
+    delete widget;
 }
 
 void tst_Gestures::deleteGestureTargetItem_data()
@@ -1917,6 +1975,7 @@ void tst_Gestures::deleteGestureTargetItem()
 
 class GraphicsView : public QGraphicsView
 {
+    Q_OBJECT
 public:
     GraphicsView(QGraphicsScene *scene, QWidget *parent = 0)
         : QGraphicsView(scene, parent)
@@ -1924,6 +1983,15 @@ public:
     }
 
     using QGraphicsView::setViewportMargins;
+
+public Q_SLOTS:
+    void changeViewport()
+    {
+        static int ViewportCount = 0;
+        QWidget *viewport = new QWidget;
+        viewport->setObjectName(QString("Viewport-%1").arg(++ViewportCount));
+        setViewport(viewport);
+    }
 };
 
 // just making sure that even if the graphicsview has margins hotspot still
@@ -2050,7 +2118,6 @@ void tst_Gestures::testQGestureRecognizerCleanup()
     QGestureRecognizer::registerRecognizer(def);
     PanRecognizer *plt = new PanRecognizer(PanRecognizer::Platform);
     QGestureRecognizer::registerRecognizer(plt);
-    qDebug () << "register: default =" << def << "; platform =" << plt;
 
     // ^-- Qt singleton QGManager initialization
 
@@ -2088,19 +2155,19 @@ public:
     }
 
     Result recognize(QGesture *gesture, QObject *, QEvent *event) {
-        QMouseEvent *me = static_cast<QMouseEvent *>(event);
+        QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(event);
         Qt::MouseButton mouseButton(m_type == LmbType ? Qt::LeftButton : Qt::RightButton);
 
         switch(event->type()) {
-        case QEvent::MouseButtonPress:
+        case QEvent::GraphicsSceneMousePress:
             if (me->button() == mouseButton && gesture->state() == Qt::NoGesture) {
-                gesture->setHotSpot(QPointF(me->globalPos()));
+                gesture->setHotSpot(QPointF(me->screenPos()));
                 if (m_type == RmbAndCancelAllType)
                     gesture->setGestureCancelPolicy(QGesture::CancelAllInContext);
                 return QGestureRecognizer::TriggerGesture;
             }
             break;
-        case QEvent::MouseButtonRelease:
+        case QEvent::GraphicsSceneMouseRelease:
             if (me->button() == mouseButton && gesture->state() > Qt::NoGesture)
                 return QGestureRecognizer::FinishGesture;
         default:
@@ -2183,11 +2250,6 @@ void tst_Gestures::testReuseCanceledGestures()
     scene->addItem(container);
 
     mw.setCentralWidget(gv);
-
-    // Viewport needs to grab all gestures that widgets in scene grab
-    gv->viewport()->grabGesture(cancellingGestureTypeId);
-    gv->viewport()->grabGesture(tapGestureTypeId);
-
     mw.show();
     QTest::qWaitForWindowShown(&mw);
 
@@ -2301,5 +2363,112 @@ void tst_Gestures::conflictingGesturesInGraphicsView()
     QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
 }
 
+void tst_Gestures::deleteViewport()
+{
+    QGraphicsScene scene;
+    GraphicsView view(&scene);
+    view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+    GestureItem *item1 = new GestureItem("item1");
+    item1->grabGesture(CustomGesture::GestureType);
+    item1->size = QRectF(0, 0, 100, 100);
+    item1->setZValue(2);
+    scene.addItem(item1);
+
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    view.ensureVisible(scene.sceneRect());
+
+    CustomEvent event;
+
+    qDebug() << "checking finished";
+    connect(item1, SIGNAL(gestureFinished(QEvent::Type,QGesture*)),
+            &view, SLOT(changeViewport()));
+    event.hotSpot = mapToGlobal(item1->boundingRect().center(), item1, &view);
+    event.hasHotSpot = true;
+    sendCustomGesture(&event, item1, &scene);
+    // we should not crash.
+
+    qDebug() << "checking updated";
+    connect(item1, SIGNAL(gestureUpdated(QEvent::Type,QGesture*)),
+            &view, SLOT(changeViewport()));
+    event.hotSpot = mapToGlobal(item1->boundingRect().center(), item1, &view);
+    event.hasHotSpot = true;
+    sendCustomGesture(&event, item1, &scene);
+    // we should not crash.
+
+    qDebug() << "checking started";
+    connect(item1, SIGNAL(gestureStarted(QEvent::Type,QGesture*)),
+            &view, SLOT(changeViewport()));
+    event.hotSpot = mapToGlobal(item1->boundingRect().center(), item1, &view);
+    event.hasHotSpot = true;
+    sendCustomGesture(&event, item1, &scene);
+    // we should not crash.
+}
+
+void tst_Gestures::asyncGesture_data()
+{
+    QTest::addColumn<int>("button");
+
+    QTest::newRow("trigger-to-async") << (int)Qt::LeftButton;
+    QTest::newRow("ignored-to-async") << (int)Qt::RightButton;
+}
+
+void tst_Gestures::asyncGesture()
+{
+    QFETCH(int, button);
+    class AsyncGestureRecognizer : public QGestureRecognizer
+    {
+    public:
+        AsyncGestureRecognizer()
+        {
+        }
+
+        QGestureRecognizer::Result recognize(QGesture *state, QObject *receiver, QEvent *event)
+        {
+            if (event->type() == QEvent::GraphicsSceneMousePress) {
+                QGraphicsSceneMouseEvent *e =
+                        static_cast<QGraphicsSceneMouseEvent *>(event);
+                qDebug() << "press" << state;
+                state->setHotSpot(e->screenPos());
+                state->startTimer(20);
+                event->accept();
+                if (e->button() == Qt::LeftButton)
+                    return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint;
+                return QGestureRecognizer::MayBeGesture | QGestureRecognizer::ConsumeEventHint;
+            } else if (event->type() == QEvent::Timer) {
+                qDebug() << "timer";
+                Q_ASSERT(state == receiver);
+                QTimerEvent *e = static_cast<QTimerEvent *>(event);
+                state->killTimer(e->timerId());
+                return QGestureRecognizer::FinishGesture;
+            }
+            return QGestureRecognizer::Ignore;
+        }
+    };
+
+    Qt::GestureType gestureType = QGestureRecognizer::registerRecognizer(new AsyncGestureRecognizer);
+
+    QGraphicsScene scene;
+    GraphicsView view(&scene);
+    view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+    GestureItem *item1 = new GestureItem("item1");
+    item1->grabGesture(gestureType);
+    item1->size = QRectF(0, 0, 100, 100);
+    item1->setZValue(2);
+    scene.addItem(item1);
+
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+    view.ensureVisible(scene.sceneRect());
+
+    QPoint pt = view.mapFromScene(item1->mapToScene(10,10));
+    QTest::mouseClick(view.viewport(), Qt::MouseButton(button), 0, pt);
+    QTest::qWait(100);
+    QTRY_COMPARE(item1->gestureEventsReceived, 2);
+    QGestureRecognizer::unregisterRecognizer(gestureType);
+}
+
 QTEST_MAIN(tst_Gestures)
 #include "tst_gestures.moc"
