2 * Copyright (C) 2014-2015 Canonical, Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17#include <qpa/qwindowsysteminterface.h>
21#include <QSharedPointer>
22#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
23 #include <private/qquickwindow_p.h>
30#include <TouchRegistry.h>
32class TestItem : public QQuickItem
37 QList<QSharedPointer<QTouchEvent>> touchEventsReceived;
40 void touchEvent(QTouchEvent *event) override;
43class CandidateItem : public QQuickItem
48 std::function<void(QTouchEvent*)> touchEventHandler;
51 void touchEvent(QTouchEvent *event) override;
54class tst_TouchGate : public QObject
58 tst_TouchGate(QObject *parent = nullptr);
60 void initTestCase(); // will be called before the first test function is executed
61 void cleanupTestCase(); // will be called after the last test function was executed.
63 void init(); // called right before each and every test function is executed
64 void cleanup(); // called right after each and every test function is executed
67 void onlyCandidate_passThrough();
68 void holdsEventsUntilGainsOwnership();
69 void holdsEventsUntilGainsOwnership_data();
70 void holdsEventsUntilGainsOwnership_repeatingTouchId();
71 void dontDispacthToDisabledOrInvisibleTarget();
72 void dontDispacthToDisabledOrInvisibleTarget_data();
75 void disabledWhileHoldingTouch();
78 QQuickView *createView();
79 TouchRegistry *touchRegistry;
84tst_TouchGate::tst_TouchGate(QObject *parent)
86 , touchRegistry(nullptr)
92void tst_TouchGate::initTestCase()
95 device = new QTouchDevice;
96 device->setType(QTouchDevice::TouchScreen);
97 QWindowSystemInterface::registerTouchDevice(device);
101void tst_TouchGate::cleanupTestCase()
105void tst_TouchGate::init()
107 touchRegistry = new TouchRegistry;
110 view->installEventFilter(touchRegistry);
111 view->setSource(QUrl::fromLocalFile("touchGateExample.qml"));
113 QVERIFY(QTest::qWaitForWindowExposed(view));
114 QVERIFY(view->rootObject() != 0);
115 qApp->processEvents();
118void tst_TouchGate::cleanup()
123 delete touchRegistry;
124 touchRegistry = nullptr;
127QQuickView *tst_TouchGate::createView()
129 QQuickView *window = new QQuickView(0);
130 window->setResizeMode(QQuickView::SizeRootObjectToView);
131 window->resize(720, 720);
137 Simplest case. TouchGate is the only candidate for the touch point, thus it
138 will instantly gain ownership causing the event to pass through it directly to
141void tst_TouchGate::onlyCandidate_passThrough()
143 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
146 TestItem *testItem = new TestItem;
147 testItem->setWidth(touchGate->width());
148 testItem->setHeight(touchGate->height());
149 testItem->setParentItem(view->rootObject());
152 touchGate->setZ(1.0);
153 touchGate->setTargetItem(testItem);
155 QTest::touchEvent(view, device)
156 .press(0, QPoint(100,100));
158 QCOMPARE(testItem->touchEventsReceived.count(), 1);
159 QVERIFY(touchGate->m_storedEvents.isEmpty());
162void tst_TouchGate::holdsEventsUntilGainsOwnership()
164 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
166 QFETCH(bool, ownershipAfterTouchEnd);
168 TestItem *testItem = new TestItem;
169 testItem->setWidth(touchGate->width());
170 testItem->setHeight(touchGate->height());
171 testItem->setParentItem(view->rootObject());
174 touchGate->setZ(1.0);
175 touchGate->setTargetItem(testItem);
177 // Put it in front of touchGate
178 CandidateItem *candidateItem = new CandidateItem;
179 candidateItem->setWidth(touchGate->width());
180 candidateItem->setHeight(touchGate->height());
181 candidateItem->setParentItem(view->rootObject());
182 candidateItem->setZ(2.0);
184 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
185 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
189 QTest::touchEvent(view, device)
190 .press(0, QPoint(100,100));
192 QCOMPARE(testItem->touchEventsReceived.count(), 0);
194 QTest::touchEvent(view, device)
195 .move(0, QPoint(101,101));
197 QCOMPARE(testItem->touchEventsReceived.count(), 0);
199 if (!ownershipAfterTouchEnd) {
200 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
201#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
202 QQuickWindowPrivate *wp = QQuickWindowPrivate::get(testItem->window());
203 wp->flushDelayedTouchEvent();
205 // TouchGate should now open its flood gates and let testItem get all
206 // events from touch 0 produced so far
207 QCOMPARE(testItem->touchEventsReceived.count(), 2);
210 QTest::touchEvent(view, device)
211 .release(0, QPoint(101,101));
213 if (ownershipAfterTouchEnd) {
214 QCOMPARE(testItem->touchEventsReceived.count(), 0);
215 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
216 // TouchGate should now open its flood gates and let testItem get all
217 // events from touch 0 produced so far
220 QCOMPARE(testItem->touchEventsReceived.count(), 3);
222 QVERIFY(touchGate->m_storedEvents.isEmpty());
223 QVERIFY(touchGate->m_touchInfoMap.isEmpty());
226void tst_TouchGate::holdsEventsUntilGainsOwnership_data()
228 QTest::addColumn<bool>("ownershipAfterTouchEnd");
230 QTest::newRow("touch end after touch ownership") << false;
231 QTest::newRow("touch ownership after touch end") << true;
235 A touch point of id 0 starts and ends. Then the next touch point is also given
236 id 0. Check that TouchGate behaves correcly recognizing them as two distinct touch
239 Note that this won't be a problem with Mir as it assigns unique ids for the touch
242void tst_TouchGate::holdsEventsUntilGainsOwnership_repeatingTouchId()
244 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
247 TestItem *testItem = new TestItem;
248 testItem->setWidth(touchGate->width());
249 testItem->setHeight(touchGate->height());
250 testItem->setParentItem(view->rootObject());
253 touchGate->setZ(1.0);
254 touchGate->setTargetItem(testItem);
256 QTest::touchEvent(view, device)
257 .press(0, QPoint(100,100));
258 QTest::touchEvent(view, device)
259 .move(0, QPoint(101,101));
260 QTest::touchEvent(view, device)
261 .release(0, QPoint(101,101));
263 QCOMPARE(testItem->touchEventsReceived.count(), 3);
264 testItem->touchEventsReceived.clear();
266 // Put it in front of touchGate
267 CandidateItem *candidateItem = new CandidateItem;
268 candidateItem->setWidth(touchGate->width());
269 candidateItem->setHeight(touchGate->height());
270 candidateItem->setParentItem(view->rootObject());
271 candidateItem->setZ(2.0);
273 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
274 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
278 // A brand new touch, but with the same id as the previous one
279 QTest::touchEvent(view, device)
280 .press(0, QPoint(200,200));
281 QTest::touchEvent(view, device)
282 .move(0, QPoint(201,201));
283 QTest::touchEvent(view, device)
284 .release(0, QPoint(201,201));
286 QCOMPARE(testItem->touchEventsReceived.count(), 0);
288 touchRegistry->requestTouchOwnership(0, candidateItem);
290 QCOMPARE(testItem->touchEventsReceived.count(), 0);
292 QVERIFY(touchGate->m_storedEvents.isEmpty());
295void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget()
297 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
300 TestItem *testItem = new TestItem;
301 testItem->setWidth(touchGate->width());
302 testItem->setHeight(touchGate->height());
303 testItem->setParentItem(view->rootObject());
306 QFETCH(bool, isEnabled);
307 testItem->setEnabled(isEnabled);
309 QFETCH(bool, isVisible);
310 testItem->setVisible(isVisible);
312 touchGate->setZ(1.0);
313 touchGate->setTargetItem(testItem);
315 QTest::touchEvent(view, device)
316 .press(0, QPoint(100,100));
318 QCOMPARE(testItem->touchEventsReceived.count(), 0);
319 QVERIFY(touchGate->m_storedEvents.isEmpty());
322void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget_data()
324 QTest::addColumn<bool>("isEnabled");
325 QTest::addColumn<bool>("isVisible");
327 QTest::newRow("disabled visible") << false << true;
328 QTest::newRow("enabled invisible") << true << false;
329 QTest::newRow("disabled invisible") << false << false;
332void tst_TouchGate::disabledWhileHoldingTouch()
334 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
337 TestItem *testItem = new TestItem;
338 testItem->setWidth(touchGate->width());
339 testItem->setHeight(touchGate->height());
340 testItem->setParentItem(view->rootObject());
343 touchGate->setZ(1.0);
344 touchGate->setTargetItem(testItem);
346 QTest::touchEvent(view, device)
347 .press(0, QPoint(100,100));
349 QCOMPARE(testItem->touchEventsReceived.count(), 1);
350 testItem->touchEventsReceived.clear();
352 touchGate->setEnabled(false);
354 QTest::touchEvent(view, device)
355 .move(0, QPoint(101,101));
357 // Nothing new came as TouchGate didn't even get it because it's disabled
358 QCOMPARE(testItem->touchEventsReceived.count(), 0);
360 touchGate->setEnabled(true);
362 QTest::touchEvent(view, device)
363 .move(0, QPoint(102,102));
365 QTest::touchEvent(view, device)
366 .release(0, QPoint(102,102));
368 // Nothing new came because TouchGate has already discarded touch 0
369 QCOMPARE(testItem->touchEventsReceived.count(), 0);
371 QTest::touchEvent(view, device)
372 .press(1, QPoint(200,200));
374 QCOMPARE(testItem->touchEventsReceived.count(), 1);
376 // it got only the new touch point.
377 QSharedPointer<QTouchEvent> touchEvent = testItem->touchEventsReceived[0];
378 QCOMPARE(touchEvent->touchPoints().count(), 1);
379 QCOMPARE(touchEvent->touchPoints()[0].id(), 1);
383///////////// TestItem /////////////////////////////////////////////////////////////
385void TestItem::touchEvent(QTouchEvent *event)
387 QTouchEvent *clonedEvent = new QTouchEvent(event->type(),
390 event->touchPointStates(),
391 event->touchPoints());
393 touchEventsReceived.append(QSharedPointer<QTouchEvent>(clonedEvent));
396///////////// CandidateItem /////////////////////////////////////////////////////////////
398void CandidateItem::touchEvent(QTouchEvent *event)
400 touchEventHandler(event);
404QTEST_MAIN(tst_TouchGate)
406#include "tst_TouchGate.moc"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list