From cf0d96f4c8584a7eb9eeca304932f6ea88894b27 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com>
Date: Tue, 18 Nov 2014 12:19:22 +0100
Subject: [PATCH] QWidgetTextControl: Suppress drag selection for
 OS-synthesized mouse events.

Add a convenience function to QApplicationPrivate returning
the source of mouse events to be able to detect synthesized
mouse events.

Change-Id: I09f82ed917586cd3de8b4146fc6638d19d428163
Task-number: QTBUG-40461
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
---
 src/widgets/kernel/qapplication.cpp        | 26 ++++++++++++++++++++++
 src/widgets/kernel/qapplication_p.h        |  1 +
 src/widgets/widgets/qwidgettextcontrol.cpp |  9 +++++++-
 3 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index 269fe452c1c..82b9fec37f6 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -53,6 +53,7 @@
 #include "qtranslator.h"
 #include "qvariant.h"
 #include "qwidget.h"
+#include "qgraphicssceneevent.h"
 #include "private/qdnd_p.h"
 #include "private/qguiapplication_p.h"
 #include "qcolormap.h"
@@ -2286,6 +2287,31 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool
     return w;
 }
 
+Qt::MouseEventSource QApplicationPrivate::mouseEventSource(const QEvent *e)
+{
+    switch (e->type()) {
+    case QEvent::NonClientAreaMouseButtonDblClick:
+    case QEvent::NonClientAreaMouseButtonPress:
+    case QEvent::NonClientAreaMouseButtonRelease:
+    case QEvent::NonClientAreaMouseMove:
+    case QEvent::MouseButtonDblClick:
+    case QEvent::MouseButtonPress:
+    case QEvent::MouseButtonRelease:
+    case QEvent::MouseMove:
+        return static_cast<const QMouseEvent *>(e)->source();
+#ifndef QT_NO_GRAPHICSVIEW
+    case QEvent::GraphicsSceneMouseDoubleClick:
+    case QEvent::GraphicsSceneMousePress:
+    case QEvent::GraphicsSceneMouseRelease:
+    case QEvent::GraphicsSceneMouseMove:
+        return static_cast<const QGraphicsSceneMouseEvent *>(e)->source();
+#endif // !QT_NO_GRAPHICSVIEW
+    default:
+        break;
+    }
+    return Qt::MouseEventNotSynthesized;
+}
+
 /*!
     \fn void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, const QPointF &globalPosF)
     \internal
diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h
index 7d97235c66b..b24b592fbe2 100644
--- a/src/widgets/kernel/qapplication_p.h
+++ b/src/widgets/kernel/qapplication_p.h
@@ -168,6 +168,7 @@ public:
     static void setFocusWidget(QWidget *focus, Qt::FocusReason reason);
     static QWidget *focusNextPrevChild_helper(QWidget *toplevel, bool next,
                                               bool *wrappingOccurred = 0);
+    static Qt::MouseEventSource mouseEventSource(const QEvent *e);
 
 #ifndef QT_NO_GRAPHICSVIEW
     // Maintain a list of all scenes to ensure font and palette propagation to
diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp
index dfec6a14d4d..8f017b7b870 100644
--- a/src/widgets/widgets/qwidgettextcontrol.cpp
+++ b/src/widgets/widgets/qwidgettextcontrol.cpp
@@ -1580,8 +1580,10 @@ void QWidgetTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton butto
             cursor.clearSelection();
         }
     }
+    // Do not start selection on a mouse event synthesized from a touch event.
     if (!(button & Qt::LeftButton) ||
-        !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))) {
+        !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))
+        || QApplicationPrivate::mouseEventSource(e) != Qt::MouseEventNotSynthesized) {
             e->ignore();
             return;
     }
@@ -1752,6 +1754,11 @@ void QWidgetTextControlPrivate::mouseReleaseEvent(QEvent *e, Qt::MouseButton but
 {
     Q_Q(QWidgetTextControl);
 
+    if (QApplicationPrivate::mouseEventSource(e) != Qt::MouseEventNotSynthesized) {
+        setCursorPosition(pos); // Emulate Tap to set cursor for events synthesized from touch.
+        return;
+    }
+
     const QTextCursor oldSelection = cursor;
     if (sendMouseEventToInputContext(
             e, QEvent::MouseButtonRelease, button, pos, modifiers, buttons, globalPos)) {
-- 
GitLab