1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2019 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQml module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include <QtTest/QtTest> |
30 | |
31 | #include <QtQml/qqmlengine.h> |
32 | #include <QtQml/qqmlproperty.h> |
33 | #include <QtQuick/private/qquickdraghandler_p.h> |
34 | #include <QtQuick/private/qquickmousearea_p.h> |
35 | #include <QtQuick/qquickitem.h> |
36 | #include <QtQuick/qquickview.h> |
37 | |
38 | #include "../../../shared/util.h" |
39 | #include "../../shared/viewtestutil.h" |
40 | |
41 | Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests" ) |
42 | |
43 | class tst_MouseAreaInterop : public QQmlDataTest |
44 | { |
45 | Q_OBJECT |
46 | public: |
47 | tst_MouseAreaInterop() |
48 | : touchDevice(QTest::createTouchDevice()) |
49 | , touchPointerDevice(QQuickPointerDevice::touchDevice(d: touchDevice)) |
50 | {} |
51 | |
52 | private slots: |
53 | void dragHandlerInSiblingStealingGrabFromMouseAreaViaMouse(); |
54 | void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch_data(); |
55 | void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch(); |
56 | |
57 | private: |
58 | void createView(QScopedPointer<QQuickView> &window, const char *fileName); |
59 | QTouchDevice *touchDevice; |
60 | QQuickPointerDevice *touchPointerDevice; |
61 | }; |
62 | |
63 | void tst_MouseAreaInterop::createView(QScopedPointer<QQuickView> &window, const char *fileName) |
64 | { |
65 | window.reset(other: new QQuickView); |
66 | window->setSource(testFileUrl(fileName)); |
67 | QTRY_COMPARE(window->status(), QQuickView::Ready); |
68 | QQuickViewTestUtil::centerOnScreen(window: window.data()); |
69 | QQuickViewTestUtil::moveMouseAway(window: window.data()); |
70 | |
71 | window->show(); |
72 | QVERIFY(QTest::qWaitForWindowActive(window.data())); |
73 | QVERIFY(window->rootObject() != nullptr); |
74 | } |
75 | |
76 | void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaMouse() |
77 | { |
78 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
79 | QScopedPointer<QQuickView> windowPtr; |
80 | createView(window&: windowPtr, fileName: "dragTakeOverFromSibling.qml" ); |
81 | QQuickView * window = windowPtr.data(); |
82 | auto pointerEvent = QQuickWindowPrivate::get(c: window)->pointerEventInstance(device: QQuickPointerDevice::genericMouseDevice()); |
83 | |
84 | QPointer<QQuickPointerHandler> handler = window->rootObject()->findChild<QQuickPointerHandler*>(); |
85 | QVERIFY(handler); |
86 | QQuickMouseArea *ma = window->rootObject()->findChild<QQuickMouseArea*>(); |
87 | QVERIFY(ma); |
88 | |
89 | QPoint p1(150, 150); |
90 | QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); |
91 | QCOMPARE(window->mouseGrabberItem(), ma); |
92 | QCOMPARE(ma->pressed(), true); |
93 | |
94 | // Start dragging |
95 | // DragHandler keeps monitoring, due to its passive grab, |
96 | // and eventually steals the exclusive grab from MA |
97 | int dragStoleGrab = 0; |
98 | for (int i = 0; i < 4; ++i) { |
99 | p1 += QPoint(dragThreshold / 2, 0); |
100 | QTest::mouseMove(window, pos: p1); |
101 | if (!dragStoleGrab && pointerEvent->point(i: 0)->exclusiveGrabber() == handler) |
102 | dragStoleGrab = i; |
103 | } |
104 | if (dragStoleGrab) |
105 | qCDebug(lcPointerTests, "DragHandler stole the grab after %d events" , dragStoleGrab); |
106 | QVERIFY(dragStoleGrab > 1); |
107 | QCOMPARE(handler->active(), true); |
108 | QCOMPARE(ma->pressed(), false); |
109 | |
110 | QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); |
111 | QCOMPARE(handler->active(), false); |
112 | } |
113 | |
114 | void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch_data() |
115 | { |
116 | QTest::addColumn<bool>(name: "preventStealing" ); |
117 | |
118 | QTest::newRow(dataTag: "allow stealing" ) << false; |
119 | QTest::newRow(dataTag: "prevent stealing" ) << true; |
120 | } |
121 | |
122 | void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch() // QTBUG-77624 and QTBUG-79163 |
123 | { |
124 | QFETCH(bool, preventStealing); |
125 | |
126 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
127 | QScopedPointer<QQuickView> windowPtr; |
128 | createView(window&: windowPtr, fileName: "dragTakeOverFromSibling.qml" ); |
129 | QQuickView * window = windowPtr.data(); |
130 | auto pointerEvent = QQuickWindowPrivate::get(c: window)->pointerEventInstance(device: touchPointerDevice); |
131 | |
132 | QPointer<QQuickPointerHandler> handler = window->rootObject()->findChild<QQuickPointerHandler*>(); |
133 | QVERIFY(handler); |
134 | QQuickMouseArea *ma = window->rootObject()->findChild<QQuickMouseArea*>(); |
135 | QVERIFY(ma); |
136 | ma->setPreventStealing(preventStealing); |
137 | |
138 | QPoint p1(150, 150); |
139 | QTest::QTouchEventSequence touch = QTest::touchEvent(window, device: touchDevice); |
140 | |
141 | touch.press(touchId: 1, pt: p1).commit(); |
142 | QQuickTouchUtils::flush(window); |
143 | QTRY_VERIFY(pointerEvent->point(0)->passiveGrabbers().contains(handler)); |
144 | QCOMPARE(pointerEvent->point(0)->grabberItem(), ma); |
145 | QCOMPARE(window->mouseGrabberItem(), ma); |
146 | QCOMPARE(ma->pressed(), true); |
147 | |
148 | // Start dragging |
149 | // DragHandler keeps monitoring, due to its passive grab, |
150 | // and eventually steals the exclusive grab from MA if MA allows it |
151 | int dragStoleGrab = 0; |
152 | for (int i = 0; i < 4; ++i) { |
153 | p1 += QPoint(dragThreshold / 2, 0); |
154 | touch.move(touchId: 1, pt: p1).commit(); |
155 | QQuickTouchUtils::flush(window); |
156 | if (!dragStoleGrab && pointerEvent->point(i: 0)->exclusiveGrabber() == handler) |
157 | dragStoleGrab = i; |
158 | } |
159 | if (dragStoleGrab) |
160 | qCDebug(lcPointerTests, "DragHandler stole the grab after %d events" , dragStoleGrab); |
161 | if (preventStealing) { |
162 | QCOMPARE(dragStoleGrab, 0); |
163 | QCOMPARE(handler->active(), false); |
164 | QCOMPARE(ma->pressed(), true); |
165 | } else { |
166 | QVERIFY(dragStoleGrab > 1); |
167 | QCOMPARE(handler->active(), true); |
168 | QCOMPARE(ma->pressed(), false); |
169 | } |
170 | |
171 | touch.release(touchId: 1, pt: p1).commit(); |
172 | QQuickTouchUtils::flush(window); |
173 | QCOMPARE(handler->active(), false); |
174 | } |
175 | |
176 | QTEST_MAIN(tst_MouseAreaInterop) |
177 | |
178 | #include "tst_mousearea_interop.moc" |
179 | |