diff --git a/src/widgets/util/qflickgesture.cpp b/src/widgets/util/qflickgesture.cpp
index b59fe0d5..374178c3 100644
--- a/src/widgets/util/qflickgesture.cpp
+++ b/src/widgets/util/qflickgesture.cpp
@@ -46,6 +46,7 @@
 #include "qgraphicsscene.h"
 #include "qgraphicssceneevent.h"
 #include "qgraphicsview.h"
+#include "qstylehints.h"
 #endif
 #include "qscroller.h"
 #include <QtGui/qtouchdevice.h>
@@ -68,13 +69,246 @@ QT_BEGIN_NAMESPACE
 
 extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
 
-static QMouseEvent *copyMouseEvent(QEvent *e)
+PressDelayHandler::PressDelayHandler(QObject *parent)
+    : QObject(parent)
+    , m_pressDelayTimer(0)
+    , m_sendingEvent(false)
+    , m_pressTarget(nullptr)
+{ }
+
+PressDelayHandler* PressDelayHandler::create(Qt::MouseButton button)
+{
+    switch (button) {
+    case Qt::LeftButton:
+        return new MousePressDelayHandler(QCoreApplication::instance());
+        break;
+    case Qt::NoButton:
+        return new TouchPressDelayHandler(QCoreApplication::instance());
+    default:
+        break;
+    }
+    return new MousePressDelayHandler(QCoreApplication::instance());
+}
+
+bool PressDelayHandler::shouldEventBeIgnored() const
+{
+    return m_sendingEvent;
+}
+
+bool PressDelayHandler::isDelaying() const
+{
+    return hasSavedDelayEvent();
+}
+
+void PressDelayHandler::pressed(QEvent *e, int delay)
+{
+    if (!hasSavedDelayEvent()) {
+        qFGDebug("QFG: consuming/delaying press");
+        m_pressDelayEvent.reset(copyEvent(e));
+        saveDelayEventInfo(e);
+        m_pressDelayTimer = startTimer(delay);
+    } else {
+        qFGDebug("QFG: NOT consuming/delaying press");
+    }
+
+}
+
+bool PressDelayHandler::released(QEvent *e, bool scrollerWasActive, bool scrollerIsActive)
+{
+    // stop the timer
+    stopTimer();
+
+    bool result = scrollerWasActive || scrollerIsActive;
+
+    // we still haven't even sent the press, so do it now
+    if (hasSavedDelayEvent() && pressTarget() && !scrollerIsActive) {
+
+        qFGDebug() << "QFG: re-sending press (due to release) for " << pressTarget();
+        sendSpontaneousEvent(m_pressDelayEvent.data(), pressTarget(), UngrabMouseBefore);
+
+        qFGDebug() << "QFG: faking release (due to release) for " << pressTarget();
+        sendSpontaneousEvent(e, pressTarget(), 0);
+
+        result = true; // consume this event
+    } else if (pressTarget() && scrollerIsActive) {
+        // we grabbed the mouse expicitly when the scroller became active, so undo that now
+        qFGDebug() << "QFG: ungrab mouse which grabbed when the scroller became active";
+        sendSpontaneousEvent(nullptr, pressTarget(), UngrabMouseBefore);
+    }
+
+    resetDelayEvent();
+    resetPressTarget();
+    return result;
+}
+
+void PressDelayHandler::scrollerWasIntercepted()
+{
+    qFGDebug("QFG: deleting delayed press, since scroller was only intercepted");
+    if (hasSavedDelayEvent()) {
+        // we still haven't even sent the press, so just throw it away now
+        stopTimer();
+    }
+    resetPressTarget();
+}
+
+void PressDelayHandler::scrollerBecameActive()
+{
+    if (hasSavedDelayEvent()) {
+        // we still haven't even sent the press, so just throw it away now
+        qFGDebug("QFG: deleting delayed mouse press, since scroller is active now");
+        stopTimer();
+        resetDelayEvent();
+        resetPressTarget();
+    } else if (pressTarget()) {
+        // we did send a press, so we need to fake a release now
+        releaseAllPressed();
+        // don't clear the pressTarget just yet, since we need to explicitly ungrab the mouse on release!
+    }
+}
+
+void PressDelayHandler::timerEvent(QTimerEvent *e)
+{
+    if (e->timerId() == m_pressDelayTimer) {
+        if (hasSavedDelayEvent() && pressTarget()) {
+            qFGDebug() << "QFG: timer event: re-sending press to " << pressTarget();
+            sendSpontaneousEvent(m_pressDelayEvent.data(), pressTarget(), UngrabMouseBefore);
+        }
+        resetDelayEvent();
+
+        stopTimer();
+    }
+}
+
+void PressDelayHandler::stopTimer()
+{
+    if (m_pressDelayTimer) {
+        killTimer(m_pressDelayTimer);
+        m_pressDelayTimer = 0;
+    }
+}
+
+void PressDelayHandler::sendSpontaneousEvent(QEvent *e, QObject *target, int flags)
+{
+#if QT_CONFIG(graphicsview)
+    if (flags & UngrabMouseBefore)
+        ungrabMouse(mouseGrabberItem());
+#else
+    Q_UNUSED(flags);
+#endif
+
+    m_sendingEvent = true;
+    sendEvent(e, target);
+    m_sendingEvent = false;
+
+#if QT_CONFIG(graphicsview)
+    if (flags & RegrabMouseAfterwards)
+        grabMouse(mouseGrabberItem());
+#endif
+}
+
+QPointer<QObject> PressDelayHandler::pressTarget() const
+{
+    return m_pressTarget;
+}
+
+void PressDelayHandler::setPressTarget(QObject* pressTarget)
+{
+    m_pressTarget = pressTarget;
+}
+
+void PressDelayHandler::resetPressTarget()
+{
+    m_pressTarget = nullptr;
+}
+
+bool PressDelayHandler::hasSavedDelayEvent() const
+{
+    return !m_pressDelayEvent.isNull();
+}
+
+void PressDelayHandler::resetDelayEvent()
+{
+    m_pressDelayEvent.reset(nullptr);
+}
+
+QGraphicsItem* PressDelayHandler::mouseGrabberItem()
+{
+    QGraphicsItem *grabber = nullptr;
+
+    QWidget* targetWidget = nullptr;
+    if (pressTarget().data()->isWidgetType()) {
+        targetWidget = dynamic_cast<QWidget*>(pressTarget().data());
+    }
+    else {
+        targetWidget = QApplication::widgetAt(QCursor::pos());
+    }
+    if (!targetWidget)
+        return nullptr;
+
+    if (targetWidget->parentWidget()) {
+        if (QGraphicsView *gv = qobject_cast<QGraphicsView *>(targetWidget->parentWidget())) {
+            if (gv->scene())
+                grabber = gv->scene()->mouseGrabberItem();
+        }
+    }
+    return grabber;
+}
+
+void PressDelayHandler::grabMouse(QGraphicsItem* grabber)
+{
+    if (!grabber)
+        return;
+
+    // GraphicsView Mouse Handling Workaround #2:
+    // we need to re-grab the mouse after sending a faked mouse
+    // release, since we still need the mouse moves for the gesture
+    // (the scene will clear the item's mouse grabber status on
+    // release).
+    qFGDebug() << "QFG: re-grabbing" << grabber;
+    grabber->grabMouse();
+}
+
+void PressDelayHandler::ungrabMouse(QGraphicsItem* grabber)
+{
+    if (!grabber)
+        return;
+
+    // GraphicsView Mouse Handling Workaround #1:
+    // we need to ungrab the mouse before re-sending the press,
+    // since the scene had already set the mouse grabber to the
+    // original (and consumed) event's receiver
+    qFGDebug() << "QFG: ungrabbing" << grabber;
+    grabber->ungrabMouse();
+}
+
+MousePressDelayHandler::MousePressDelayHandler(QObject *parent)
+    : PressDelayHandler(parent)
+    , m_mouseButton(Qt::NoButton)
+    , m_mouseEventSource(Qt::MouseEventNotSynthesized)
+{
+    qFGDebug("QFG: create MousePressDelayHandler");
+}
+
+void MousePressDelayHandler::saveDelayEventInfo(QEvent* e)
+{
+    QMouseEvent* me = dynamic_cast<QMouseEvent*>(e);
+    if (!me) {
+        qWarning() << "MousePressDelayHandler handling event not QMouseEvent";
+        return;
+    }
+
+    setPressTarget(QApplication::widgetAt(me->globalPos()));
+    m_mouseButton = me->button();
+    m_mouseEventSource = me->source();
+}
+
+QEvent* MousePressDelayHandler::copyEvent(QEvent *e)
 {
     switch (e->type()) {
     case QEvent::MouseButtonPress:
     case QEvent::MouseButtonRelease:
     case QEvent::MouseMove: {
-        QMouseEvent *me = static_cast<QMouseEvent *>(e);
+        QMouseEvent *me = dynamic_cast<QMouseEvent *>(e);
         QMouseEvent *cme = new QMouseEvent(me->type(), QPoint(0, 0), me->windowPos(), me->screenPos(),
                                            me->button(), me->buttons(), me->modifiers(), me->source());
         return cme;
@@ -83,10 +317,10 @@ static QMouseEvent *copyMouseEvent(QEvent *e)
     case QEvent::GraphicsSceneMousePress:
     case QEvent::GraphicsSceneMouseRelease:
     case QEvent::GraphicsSceneMouseMove: {
-        QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(e);
+        QGraphicsSceneMouseEvent *me = dynamic_cast<QGraphicsSceneMouseEvent *>(e);
 #if 1
         QEvent::Type met = me->type() == QEvent::GraphicsSceneMousePress ? QEvent::MouseButtonPress :
-                           (me->type() == QEvent::GraphicsSceneMouseRelease ? QEvent::MouseButtonRelease : QEvent::MouseMove);
+                               (me->type() == QEvent::GraphicsSceneMouseRelease ? QEvent::MouseButtonRelease : QEvent::MouseMove);
         QMouseEvent *cme = new QMouseEvent(met, QPoint(0, 0), QPoint(0, 0), me->screenPos(),
                                            me->button(), me->buttons(), me->modifiers(), me->source());
         return cme;
@@ -114,222 +348,189 @@ static QMouseEvent *copyMouseEvent(QEvent *e)
     }
 #endif // QT_CONFIG(graphicsview)
     default:
-        return 0;
+        return nullptr;
     }
 }
 
-class PressDelayHandler : public QObject
+void MousePressDelayHandler::sendEvent(QEvent *e, QObject* target)
 {
-private:
-    PressDelayHandler(QObject *parent = 0)
-        : QObject(parent)
-        , pressDelayTimer(0)
-        , sendingEvent(false)
-        , mouseButton(Qt::NoButton)
-        , mouseTarget(0)
-        , mouseEventSource(Qt::MouseEventNotSynthesized)
-    { }
-
-    static PressDelayHandler *inst;
-
-public:
-    enum {
-        UngrabMouseBefore = 1,
-        RegrabMouseAfterwards = 2
-    };
+    QMouseEvent* me = dynamic_cast<QMouseEvent*>(e);
+    QWidget* targetWidget = dynamic_cast<QWidget*>(target);
 
-    static PressDelayHandler *instance()
-    {
-        static PressDelayHandler *inst = 0;
-        if (!inst)
-            inst = new PressDelayHandler(QCoreApplication::instance());
-        return inst;
+    if (!targetWidget) {
+        return;
     }
 
-    bool shouldEventBeIgnored(QEvent *) const
-    {
-        return sendingEvent;
+    if (me) {
+        QMouseEvent copy(me->type(), targetWidget->mapFromGlobal(me->globalPos()),
+                         targetWidget->topLevelWidget()->mapFromGlobal(me->globalPos()), me->screenPos(),
+                         me->button(), me->buttons(), me->modifiers(), me->source());
+        qt_sendSpontaneousEvent(targetWidget, &copy);
     }
+}
 
-    bool isDelaying() const
-    {
-        return !pressDelayEvent.isNull();
-    }
+void MousePressDelayHandler::releaseAllPressed()
+{
+    QPoint farFarAway(-QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX);
 
-    void pressed(QEvent *e, int delay)
-    {
-        if (!pressDelayEvent) {
-            pressDelayEvent.reset(copyMouseEvent(e));
-            pressDelayTimer = startTimer(delay);
-            mouseTarget = QApplication::widgetAt(pressDelayEvent->globalPos());
-            mouseButton = pressDelayEvent->button();
-            mouseEventSource = pressDelayEvent->source();
-            qFGDebug("QFG: consuming/delaying mouse press");
-        } else {
-            qFGDebug("QFG: NOT consuming/delaying mouse press");
-        }
-        e->setAccepted(true);
-    }
+    qFGDebug() << "QFG: sending a fake mouse release at far-far-away to " << pressTarget();
+    QMouseEvent re(QEvent::MouseButtonRelease, QPoint(), farFarAway, farFarAway,
+                   m_mouseButton, QApplication::mouseButtons() & ~m_mouseButton,
+                   QApplication::keyboardModifiers(), m_mouseEventSource);
+    sendSpontaneousEvent(&re, pressTarget(), RegrabMouseAfterwards);
+}
 
-    bool released(QEvent *e, bool scrollerWasActive, bool scrollerIsActive)
-    {
-        // consume this event if the scroller was or is active
-        bool result = scrollerWasActive || scrollerIsActive;
+TouchPressDelayHandler::TouchPressDelayHandler(QObject *parent)
+    : PressDelayHandler(parent)
+{
+    qFGDebug("QFG: create TouchPressDelayHandler");
+}
 
-        // stop the timer
-        if (pressDelayTimer) {
-            killTimer(pressDelayTimer);
-            pressDelayTimer = 0;
-        }
-        // we still haven't even sent the press, so do it now
-        if (pressDelayEvent && mouseTarget && !scrollerIsActive) {
-            QScopedPointer<QMouseEvent> releaseEvent(copyMouseEvent(e));
+void TouchPressDelayHandler::saveDelayEventInfo(QEvent* e)
+{
+    QTouchEvent* te = dynamic_cast<QTouchEvent*>(e);
+    if (!te) {
+        qWarning() << "TouchPressDelayHandler handling event not QTouchEvent";
+    }
+    setPressTarget(te->window());
+    m_touchBeginPoint = te->touchPoints().at(0);
+    m_device = te->device();
+}
 
-            qFGDebug() << "QFG: re-sending mouse press (due to release) for " << mouseTarget;
-            sendMouseEvent(pressDelayEvent.data(), UngrabMouseBefore);
+void TouchPressDelayHandler::releaseAllPressed()
+{
+    qFGDebug() << "QFG: sending a fake touch cancel to " << pressTarget();
+    QTouchEvent te(QEvent::TouchCancel, m_device, QApplication::keyboardModifiers(),
+                   Qt::TouchPointReleased, QList<QTouchEvent::TouchPoint>{m_touchBeginPoint});
+    te.setWindow(dynamic_cast<QWindow*>(pressTarget().data()));
+    sendSpontaneousEvent(&te, pressTarget(), 0);
+}
 
-            qFGDebug() << "QFG: faking mouse release (due to release) for " << mouseTarget;
-            sendMouseEvent(releaseEvent.data());
+void TouchPressDelayHandler::sendEvent(QEvent *e, QObject* target)
+{
+    QTouchEvent* te = dynamic_cast<QTouchEvent*>(e);
+    QWindow* targetWindow = dynamic_cast<QWindow*>(target);
 
-            result = true; // consume this event
-        } else if (mouseTarget && scrollerIsActive) {
-            // we grabbed the mouse expicitly when the scroller became active, so undo that now
-            sendMouseEvent(0, UngrabMouseBefore);
-        }
-        pressDelayEvent.reset(0);
-        mouseTarget = 0;
-        return result;
-    }
-
-    void scrollerWasIntercepted()
-    {
-        qFGDebug("QFG: deleting delayed mouse press, since scroller was only intercepted");
-        if (pressDelayEvent) {
-            // we still haven't even sent the press, so just throw it away now
-            if (pressDelayTimer) {
-                killTimer(pressDelayTimer);
-                pressDelayTimer = 0;
-            }
-            pressDelayEvent.reset(0);
-        }
-        mouseTarget = 0;
+    if (!targetWindow) {
+        return;
+    }
+    if (!te) {
+        return;
     }
 
-    void scrollerBecameActive()
-    {
-        if (pressDelayEvent) {
-            // we still haven't even sent the press, so just throw it away now
-            qFGDebug("QFG: deleting delayed mouse press, since scroller is active now");
-            if (pressDelayTimer) {
-                killTimer(pressDelayTimer);
-                pressDelayTimer = 0;
-            }
-            pressDelayEvent.reset(0);
-            mouseTarget = 0;
-        } else if (mouseTarget) {
-            // we did send a press, so we need to fake a release now
-
-            // release all pressed mouse buttons
-            /* Qt::MouseButtons mouseButtons = QApplication::mouseButtons();
-            for (int i = 0; i < 32; ++i) {
-                if (mouseButtons & (1 << i)) {
-                    Qt::MouseButton b = static_cast<Qt::MouseButton>(1 << i);
-                    mouseButtons &= ~b;
-                    QPoint farFarAway(-QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX);
-
-                    qFGDebug() << "QFG: sending a fake mouse release at far-far-away to " << mouseTarget;
-                    QMouseEvent re(QEvent::MouseButtonRelease, QPoint(), farFarAway,
-                                   b, mouseButtons, QApplication::keyboardModifiers());
-                    sendMouseEvent(&re);
-                }
-            }*/
-
-            QPoint farFarAway(-QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX);
-
-            qFGDebug() << "QFG: sending a fake mouse release at far-far-away to " << mouseTarget;
-            QMouseEvent re(QEvent::MouseButtonRelease, QPoint(), farFarAway, farFarAway,
-                           mouseButton, QApplication::mouseButtons() & ~mouseButton,
-                           QApplication::keyboardModifiers(), mouseEventSource);
-            sendMouseEvent(&re, RegrabMouseAfterwards);
-            // don't clear the mouseTarget just yet, since we need to explicitly ungrab the mouse on release!
-        }
+    // map to window pos for send to window
+    QTouchEvent::TouchPoint touchPoint = (!te->touchPoints().empty()) ? te->touchPoints().at(0) : QTouchEvent::TouchPoint();
+    const QPointF screenPos = touchPoint.screenPos();
+    const QPointF delta = screenPos - screenPos.toPoint();
+    const QPointF windowPos = targetWindow->mapFromGlobal(screenPos.toPoint()) + delta;
+    const QPointF startPos = targetWindow->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta;
+    const QPointF lastPos = targetWindow->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta;
+
+    touchPoint.setPos(windowPos);
+    touchPoint.setStartPos(startPos);
+    touchPoint.setLastPos(lastPos);
+
+    qFGDebug() << "QFG: sending" << te->type() << "event to" << targetWindow;
+    // send touch event to window because there is a grab mechanism for touch events
+    QTouchEvent copy(te->type(), te->device(), te->modifiers(),
+                     te->touchPointStates(), QList<QTouchEvent::TouchPoint>{touchPoint});
+    copy.setWindow(targetWindow);
+    qt_sendSpontaneousEvent(targetWindow, &copy);
+
+    // when Qt::AA_SynthesizeMouseForUnhandledTouchEvents is set,
+    // Qt will send a fake mouse eventif touch event not accept.
+    // The touch event we send here will not send the fake mouse event,
+    // so send it here.
+    if ((qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents) && !copy.isAccepted())
+        || copy.type() == QEvent::TouchCancel) {
+        sendMouseEventFromTouch(&copy, targetWindow);
     }
+}
 
-protected:
-    void timerEvent(QTimerEvent *e) override
-    {
-        if (e->timerId() == pressDelayTimer) {
-            if (pressDelayEvent && mouseTarget) {
-                qFGDebug() << "QFG: timer event: re-sending mouse press to " << mouseTarget;
-                sendMouseEvent(pressDelayEvent.data(), UngrabMouseBefore);
-            }
-            pressDelayEvent.reset(0);
+void TouchPressDelayHandler::sendMouseEventFromTouch(QTouchEvent *te, QWindow *target)
+{
+    if (te->type() == QEvent::TouchCancel) {
+        QPoint farFarAway(-QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX);
+
+        qFGDebug() << "QFG: sending a fake mouse release at far-far-away to " << pressTarget();
+        QMouseEvent fake(QEvent::MouseButtonRelease, QPoint(), farFarAway, farFarAway,
+                       Qt::LeftButton, QApplication::mouseButtons() & ~Qt::LeftButton,
+                       QApplication::keyboardModifiers(), Qt::MouseEventSynthesizedByQt);
+        qt_sendSpontaneousEvent(target, &fake);
+        return;
+    }
 
-            if (pressDelayTimer) {
-                killTimer(pressDelayTimer);
-                pressDelayTimer = 0;
-            }
+    QTouchEvent::TouchPoint touchPoint = te->touchPoints().at(0);
+    const QPointF screenPos = touchPoint.screenPos();
+    const QPointF delta = screenPos - screenPos.toPoint();
+    const QPointF pos = target->mapFromGlobal(screenPos.toPoint()) + delta;
+
+    QEvent::Type mouseEventType = QEvent::MouseMove;
+    Qt::MouseButton button = Qt::NoButton;
+    Qt::MouseButtons buttons = Qt::LeftButton;
+
+    switch (touchPoint.state()) {
+    case Qt::TouchPointPressed:
+        if (isDoubleClick()) {
+            mouseEventType = QEvent::MouseButtonDblClick;
+            button = Qt::NoButton;
+            m_mousePressTime = QTime();
         }
+        else {
+            mouseEventType = QEvent::MouseButtonPress;
+            button = Qt::LeftButton;
+            m_mousePressTime = QTime::currentTime();
+        }
+        break;
+    case Qt::TouchPointReleased:
+        mouseEventType = QEvent::MouseButtonRelease;
+        button = Qt::LeftButton;
+        buttons = Qt::NoButton;
+        break;
+    default:
+        break;
     }
 
-    void sendMouseEvent(QMouseEvent *me, int flags = 0)
-    {
-        if (mouseTarget) {
-            sendingEvent = true;
+    // will not synthesize QEvent::NonClientAreaMouseButtonDblClick from touch
+    qFGDebug() << "QFG: send fake mouse event to" << target;
+    QMouseEvent fake(mouseEventType, pos, pos, screenPos,
+                     button, buttons, QApplication::keyboardModifiers(), Qt::MouseEventSynthesizedByQt);
+    qt_sendSpontaneousEvent(target, &fake);
+}
 
-#if QT_CONFIG(graphicsview)
-            QGraphicsItem *grabber = 0;
-            if (mouseTarget->parentWidget()) {
-                if (QGraphicsView *gv = qobject_cast<QGraphicsView *>(mouseTarget->parentWidget())) {
-                    if (gv->scene())
-                        grabber = gv->scene()->mouseGrabberItem();
-                }
-            }
+bool TouchPressDelayHandler::isDoubleClick() const
+{
+    // if not save time, return false then save current time
+    if (m_mousePressTime.isNull())
+        return false;
 
-            if (grabber && (flags & UngrabMouseBefore)) {
-                // GraphicsView Mouse Handling Workaround #1:
-                // we need to ungrab the mouse before re-sending the press,
-                // since the scene had already set the mouse grabber to the
-                // original (and consumed) event's receiver
-                qFGDebug() << "QFG: ungrabbing" << grabber;
-                grabber->ungrabMouse();
-            }
-#else
-            Q_UNUSED(flags);
-#endif // QT_CONFIG(graphicsview)
+    int doubleClickInterval = static_cast<int>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
+    int elapsed = m_mousePressTime.msecsTo(QTime::currentTime());
+    bool doubleClick = elapsed < doubleClickInterval;
 
-            if (me) {
-                QMouseEvent copy(me->type(), mouseTarget->mapFromGlobal(me->globalPos()),
-                                 mouseTarget->topLevelWidget()->mapFromGlobal(me->globalPos()), me->screenPos(),
-                                 me->button(), me->buttons(), me->modifiers(), me->source());
-                qt_sendSpontaneousEvent(mouseTarget, &copy);
-            }
+    return doubleClick;
+}
 
-#if QT_CONFIG(graphicsview)
-            if (grabber && (flags & RegrabMouseAfterwards)) {
-                // GraphicsView Mouse Handling Workaround #2:
-                // we need to re-grab the mouse after sending a faked mouse
-                // release, since we still need the mouse moves for the gesture
-                // (the scene will clear the item's mouse grabber status on
-                // release).
-                qFGDebug() << "QFG: re-grabbing" << grabber;
-                grabber->grabMouse();
-            }
-#endif
-            sendingEvent = false;
-        }
+QEvent* TouchPressDelayHandler::copyEvent(QEvent *e)
+{
+    switch (e->type()) {
+    case QEvent::TouchBegin:
+    case QEvent::TouchUpdate:
+    case QEvent::TouchEnd:
+    case QEvent::TouchCancel: {
+        QTouchEvent* te = dynamic_cast<QTouchEvent*>(e);
+        QTouchEvent* copy = new QTouchEvent(te->type(), te->device(), te->modifiers(),
+                                            te->touchPointStates(), te->touchPoints());
+        copy->setWindow(te->window());
+        return copy;
+        break;
+    }
+    default:
+        break;
     }
 
-
-private:
-    int pressDelayTimer;
-    QScopedPointer<QMouseEvent> pressDelayEvent;
-    bool sendingEvent;
-    Qt::MouseButton mouseButton;
-    QPointer<QWidget> mouseTarget;
-    Qt::MouseEventSource mouseEventSource;
-};
-
+    return nullptr;
+}
 
 /*!
     \internal
@@ -354,13 +555,14 @@ QFlickGesture::QFlickGesture(QObject *receiver, Qt::MouseButton button, QObject
     d_func()->receiver = receiver;
     d_func()->receiverScroller = (receiver && QScroller::hasScroller(receiver)) ? QScroller::scroller(receiver) : 0;
     d_func()->button = button;
+    d_func()->pressDelayHandler = PressDelayHandler::create(button);
 }
 
 QFlickGesture::~QFlickGesture()
 { }
 
 QFlickGesturePrivate::QFlickGesturePrivate()
-    : receiverScroller(0), button(Qt::NoButton), macIgnoreWheel(false)
+    : receiverScroller(0), button(Qt::NoButton), macIgnoreWheel(false), pressDelayHandler(nullptr)
 { }
 
 
@@ -417,7 +619,7 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state,
 #endif
 
     // this is only set for events that we inject into the event loop via sendEvent()
-    if (PressDelayHandler::instance()->shouldEventBeIgnored(event)) {
+    if (d->pressDelayHandler->shouldEventBeIgnored()) {
         //qFGDebug() << state << "QFG: ignored event: " << event->type();
         return Ignore;
     }
@@ -637,7 +839,7 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state,
 #if QT_CONFIG(graphicsview)
          || gsme
 #endif
-         ) && scrollerIsActive)
+         || te) && scrollerIsActive)
         result |= ConsumeEventHint;
 
     // The only problem with this approach is that we consume the
@@ -649,11 +851,11 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state,
 #if QT_CONFIG(graphicsview)
         || gsme
 #endif
-        ) {
+        || te) {
         if (!scrollerWasDragging && !scrollerWasScrolling && scrollerIsActive)
-            PressDelayHandler::instance()->scrollerBecameActive();
+            d->pressDelayHandler->scrollerBecameActive();
         else if (scrollerWasScrolling && (scroller->state() == QScroller::Dragging || scroller->state() == QScroller::Inactive))
-            PressDelayHandler::instance()->scrollerWasIntercepted();
+            d->pressDelayHandler->scrollerWasIntercepted();
     }
 
     if (!inputType) {
@@ -661,6 +863,7 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state,
     } else {
         switch (event->type()) {
         case QEvent::MouseButtonPress:
+        case QEvent::TouchBegin:
 #if QT_CONFIG(graphicsview)
         case QEvent::GraphicsSceneMousePress:
 #endif
@@ -669,24 +872,21 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state,
                 if (pressDelay > 0) {
                     result |= ConsumeEventHint;
 
-                    PressDelayHandler::instance()->pressed(event, pressDelay);
+                    d->pressDelayHandler->pressed(event, pressDelay);
                     event->accept();
                 }
             }
-            Q_FALLTHROUGH();
-        case QEvent::TouchBegin:
             q->setHotSpot(globalPos);
             result |= scrollerIsActive ? TriggerGesture : MayBeGesture;
             break;
 
         case QEvent::MouseMove:
+        case QEvent::TouchUpdate:
 #if QT_CONFIG(graphicsview)
         case QEvent::GraphicsSceneMouseMove:
 #endif
-            if (PressDelayHandler::instance()->isDelaying())
+            if (d->pressDelayHandler->isDelaying())
                 result |= ConsumeEventHint;
-            Q_FALLTHROUGH();
-        case QEvent::TouchUpdate:
             result |= scrollerIsActive ? TriggerGesture : Ignore;
             break;
 
@@ -694,10 +894,9 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state,
         case QEvent::GraphicsSceneMouseRelease:
 #endif
         case QEvent::MouseButtonRelease:
-            if (PressDelayHandler::instance()->released(event, scrollerWasDragging || scrollerWasScrolling, scrollerIsActive))
-                result |= ConsumeEventHint;
-            Q_FALLTHROUGH();
         case QEvent::TouchEnd:
+            if (d->pressDelayHandler->released(event, scrollerWasDragging || scrollerWasScrolling, scrollerIsActive))
+                result |= ConsumeEventHint;
             result |= scrollerIsActive ? FinishGesture : CancelGesture;
             break;
 
diff --git a/src/widgets/util/qflickgesture_p.h b/src/widgets/util/qflickgesture_p.h
index 74a0f2a0..108f2ed0 100644
--- a/src/widgets/util/qflickgesture_p.h
+++ b/src/widgets/util/qflickgesture_p.h
@@ -89,7 +89,7 @@ public:
     QScroller *receiverScroller;
     Qt::MouseButton button; // NoButton == Touch
     bool macIgnoreWheel;
-    static PressDelayHandler *pressDelayHandler;
+    PressDelayHandler *pressDelayHandler;
 };
 
 class QFlickGestureRecognizer : public QGestureRecognizer
@@ -105,6 +105,93 @@ private:
     Qt::MouseButton button; // NoButton == Touch
 };
 
+class PressDelayHandler : public QObject
+{
+
+public:
+    PressDelayHandler(QObject *parent = nullptr);
+    enum {
+        UngrabMouseBefore = 1,
+        RegrabMouseAfterwards = 2
+    };
+
+    static PressDelayHandler* create(Qt::MouseButton button = Qt::LeftButton);
+
+    bool shouldEventBeIgnored() const;
+    bool isDelaying() const;
+
+    void pressed(QEvent *e, int delay);
+    bool released(QEvent *e, bool scrollerWasActive, bool scrollerIsActive);
+
+    void scrollerWasIntercepted();
+    void scrollerBecameActive();
+
+protected:
+    void timerEvent(QTimerEvent *e) override;
+    void sendSpontaneousEvent(QEvent *e, QObject *target, int flags);
+    QPointer<QObject> pressTarget() const;
+    void setPressTarget(QObject* pressTarget);
+    void resetPressTarget();
+
+private:
+    virtual void saveDelayEventInfo(QEvent* e) = 0;
+    virtual QEvent* copyEvent(QEvent* e) = 0;
+
+    virtual void sendEvent(QEvent *e, QObject* target) = 0;
+    virtual void releaseAllPressed() = 0;
+
+    QGraphicsItem* mouseGrabberItem();
+    void grabMouse(QGraphicsItem* grabber);
+    void ungrabMouse(QGraphicsItem* grabber);
+
+    bool hasSavedDelayEvent() const;
+    void resetDelayEvent();
+    void stopTimer();
+
+private:
+    int m_pressDelayTimer;
+    bool m_sendingEvent;
+    QScopedPointer<QEvent> m_pressDelayEvent;
+    QPointer<QObject> m_pressTarget;
+};
+
+class MousePressDelayHandler : public PressDelayHandler
+{
+public:
+    MousePressDelayHandler(QObject *parent = nullptr);
+
+private:
+    void saveDelayEventInfo(QEvent* e) override;
+
+    QEvent* copyEvent(QEvent *e) override;
+    void sendEvent(QEvent *e, QObject* target) override;
+    void releaseAllPressed() override;
+
+    Qt::MouseButton m_mouseButton;
+    Qt::MouseEventSource m_mouseEventSource;
+};
+
+class TouchPressDelayHandler : public PressDelayHandler
+{
+public:
+    TouchPressDelayHandler(QObject *parent = nullptr);
+
+private:
+    void saveDelayEventInfo(QEvent* e) override;
+
+    QEvent* copyEvent(QEvent *e) override;
+    void sendEvent(QEvent *e, QObject* target) override;
+    void releaseAllPressed() override;
+
+    void sendMouseEventFromTouch(QTouchEvent *te, QWindow *target);
+    bool isDoubleClick() const;
+
+    QPointer<QWidget> m_targetWidget;
+    QTouchDevice* m_device;
+    QTouchEvent::TouchPoint m_touchBeginPoint;
+    QTime m_mousePressTime;
+};
+
 QT_END_NAMESPACE
 
 #endif // QT_NO_GESTURES
