on xenial help sign in
Work around bug in Qt
commit0213407448cdb8257b741ef4f6a3c1cb7e8bc276 authorDaniel d'Andrada <daniel.dandrada@canonical.com> dateTue 7 Oct 2014, 10:02 (12 years ago) parent5921748
5 files changed+99−1
plugins/Ubuntu/Gestures/DirectionalDragArea.cpp+16 qml/Launcher/Launcher.qml+1−1 tests/plugins/Ubuntu/Gestures/CMakeLists.txt+5 tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp+76 tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml+1
plugins/Ubuntu/Gestures/DirectionalDragArea.cpp+16
@@ -19,9 +19,15 @@
1919
2020#include "DirectionalDragArea.h"
2121
22+#include <QQuickWindow>
2223#include <QtCore/qmath.h>
2324#include <QDebug>
2425
26+#pragma GCC diagnostic push
27+#pragma GCC diagnostic ignored "-pedantic"
28+#include <private/qquickwindow_p.h>
29+#pragma GCC diagnostic pop
30+
2531// local
2632#include "TouchOwnershipEvent.h"
2733#include "TouchRegistry.h"
@@ -248,6 +254,16 @@ void DirectionalDragArea::touchOwnershipEvent(TouchOwnershipEvent *event)
248254 QVector<int> ids;
249255 ids.append(event->touchId());
250256 grabTouchPoints(ids);
257+
258+ // Work around for Qt bug. If we grab a touch that is being used for mouse pointer
259+ // emulation it will cause the emulation logic to go nuts.
260+ // Thus we have to also grab the mouse in this case.
261+ if (window()) {
262+ QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(window());
263+ if (windowPrivate->touchMouseId == event->touchId()) {
264+ grabMouse();
265+ }
266+ }
251267 } else {
252268 // We still wanna know when it ends for keeping the composition time window up-to-date
253269 TouchRegistry::instance()->addTouchWatcher(m_touchId, this);
qml/Launcher/Launcher.qml+1−1
@@ -222,7 +222,7 @@ Item {
222222
223223 direction: Direction.Rightwards
224224
225− enabled: root.available
225+ enabled: root.available && root.state == ""
226226 width: root.dragAreaWidth
227227 height: root.height
228228
tests/plugins/Ubuntu/Gestures/CMakeLists.txt+5
@@ -1,5 +1,10 @@
11include(QmlTest)
22
3+# DANGER! DANGER! Using Qt's private API!
4+include_directories(
5+ ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
6+)
7+
38include_directories(
49 ${CMAKE_SOURCE_DIR}/plugins/Ubuntu/Gestures
510 ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp+76
@@ -19,6 +19,7 @@
1919#include <QtQuick/QQuickView>
2020#include <QtQml/QQmlEngine>
2121#include <QPointer>
22+#include <private/qquickmousearea_p.h>
2223
2324// C++ std lib
2425#include <functional>
@@ -87,6 +88,30 @@ public:
8788 qint64 m_msecsSinceReference;
8889};
8990
91+/*
92+ QQuickMouseArea::canceled() signal is not registered in the meta object system.
93+ So using a QSignalSpy to track it won't work. Thus the only way to connect to it
94+ is using its method address directly.
95+ */
96+class MouseAreaSpy : public QObject
97+{
98+ Q_OBJECT
99+public:
100+ MouseAreaSpy(QQuickMouseArea *mouseArea)
101+ : canceledCount(0)
102+ {
103+ connect(mouseArea, &QQuickMouseArea::canceled,
104+ this, &MouseAreaSpy::onMouseAreaCanceled);
105+ }
106+
107+ int canceledCount;
108+
109+private Q_SLOTS:
110+ void onMouseAreaCanceled() {
111+ ++canceledCount;
112+ }
113+};
114+
90115class tst_DirectionalDragArea: public GestureTest
91116{
92117 Q_OBJECT
@@ -120,6 +145,7 @@ private Q_SLOTS:
120145 void withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition_data();
121146 void tappedSignal();
122147 void tappedSignal_data();
148+ void gettingTouchOwnershipMakesMouseAreaBehindGetCanceled();
123149
124150private:
125151 void passTime(qint64 timeSpanMs);
@@ -1213,6 +1239,56 @@ void tst_DirectionalDragArea::tappedSignal_data()
12131239 QTest::newRow("default gesture recognition") << false;
12141240}
12151241
1242+void tst_DirectionalDragArea::gettingTouchOwnershipMakesMouseAreaBehindGetCanceled()
1243+{
1244+ DirectionalDragArea *edgeDragArea =
1245+ m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1246+ QVERIFY(edgeDragArea != nullptr);
1247+ edgeDragArea->setRecognitionTimer(fakeTimer);
1248+ edgeDragArea->setTimeSource(fakeTimeSource);
1249+
1250+ QQuickMouseArea *mouseArea =
1251+ m_view->rootObject()->findChild<QQuickMouseArea*>("mouseArea");
1252+ QVERIFY(mouseArea != nullptr);
1253+
1254+ MouseAreaSpy mouseAreaSpy(mouseArea);
1255+
1256+ QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
1257+ QPointF touchPoint = initialTouchPos;
1258+
1259+ qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2;
1260+ QPointF dragDirectionVector(1.0f, 0.0f); // rightwards
1261+ qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
1262+ QPointF touchMovement = dragDirectionVector * movementStepDistance;
1263+ int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
1264+ int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
1265+
1266+ QCOMPARE(mouseArea->pressed(), false);
1267+
1268+ QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
1269+
1270+ // The TouchBegin passes through the DirectionalDragArea and reaches the MouseArea behind it,
1271+ // where it's converted to a MouseEvent by QQuickWindow and sent to the MouseArea which then
1272+ // accepts it. Making it get pressed.
1273+ QCOMPARE(mouseArea->pressed(), true);
1274+ QCOMPARE(mouseAreaSpy.canceledCount, 0);
1275+
1276+ for (int i = 0; i < totalMovementSteps; ++i) {
1277+ touchPoint += touchMovement;
1278+ passTime(movementTimeStepMs);
1279+ QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
1280+ }
1281+
1282+ // As the DirectionalDragArea recognizes the gesture, it grabs the touch from the MouseArea,
1283+ // which should make the MouseArea get a cancelation event, which will then cause it to
1284+ // reset its state (going back to "unpressed"/"released").
1285+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
1286+ QCOMPARE(mouseArea->pressed(), false);
1287+ QCOMPARE(mouseAreaSpy.canceledCount, 1);
1288+
1289+ QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
1290+}
1291+
12161292////////////////////////// TouchMemento /////////////////////////////
12171293
12181294TouchMemento::TouchMemento(const QTouchEvent *touchEvent)
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml+1
@@ -24,6 +24,7 @@ Rectangle {
2424
2525 MouseArea {
2626 id: mouseArea
27+ objectName: "mouseArea"
2728 anchors.fill: parent
2829 onClicked: {
2930 hpLauncher.reset()