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);
132 window->engine()->addImportPath(QLatin1String(UBUNTU_GESTURES_PLUGIN_DIR));
138 Simplest case. TouchGate is the only candidate for the touch point, thus it
139 will instantly gain ownership causing the event to pass through it directly to
142void tst_TouchGate::onlyCandidate_passThrough()
144 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
147 TestItem *testItem = new TestItem;
148 testItem->setWidth(touchGate->width());
149 testItem->setHeight(touchGate->height());
150 testItem->setParentItem(view->rootObject());
153 touchGate->setZ(1.0);
154 touchGate->setTargetItem(testItem);
156 QTest::touchEvent(view, device)
157 .press(0, QPoint(100,100));
159 QCOMPARE(testItem->touchEventsReceived.count(), 1);
160 QVERIFY(touchGate->m_storedEvents.isEmpty());
163void tst_TouchGate::holdsEventsUntilGainsOwnership()
165 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
167 QFETCH(bool, ownershipAfterTouchEnd);
169 TestItem *testItem = new TestItem;
170 testItem->setWidth(touchGate->width());
171 testItem->setHeight(touchGate->height());
172 testItem->setParentItem(view->rootObject());
175 touchGate->setZ(1.0);
176 touchGate->setTargetItem(testItem);
178 // Put it in front of touchGate
179 CandidateItem *candidateItem = new CandidateItem;
180 candidateItem->setWidth(touchGate->width());
181 candidateItem->setHeight(touchGate->height());
182 candidateItem->setParentItem(view->rootObject());
183 candidateItem->setZ(2.0);
185 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
186 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
190 QTest::touchEvent(view, device)
191 .press(0, QPoint(100,100));
193 QCOMPARE(testItem->touchEventsReceived.count(), 0);
195 QTest::touchEvent(view, device)
196 .move(0, QPoint(101,101));
198 QCOMPARE(testItem->touchEventsReceived.count(), 0);
200 if (!ownershipAfterTouchEnd) {
201 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
202#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
203 QQuickWindowPrivate *wp = QQuickWindowPrivate::get(testItem->window());
204 wp->flushDelayedTouchEvent();
206 // TouchGate should now open its flood gates and let testItem get all
207 // events from touch 0 produced so far
208 QCOMPARE(testItem->touchEventsReceived.count(), 2);
211 QTest::touchEvent(view, device)
212 .release(0, QPoint(101,101));
214 if (ownershipAfterTouchEnd) {
215 QCOMPARE(testItem->touchEventsReceived.count(), 0);
216 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
217 // TouchGate should now open its flood gates and let testItem get all
218 // events from touch 0 produced so far
221 QCOMPARE(testItem->touchEventsReceived.count(), 3);
223 QVERIFY(touchGate->m_storedEvents.isEmpty());
224 QVERIFY(touchGate->m_touchInfoMap.isEmpty());
227void tst_TouchGate::holdsEventsUntilGainsOwnership_data()
229 QTest::addColumn<bool>("ownershipAfterTouchEnd");
231 QTest::newRow("touch end after touch ownership") << false;
232 QTest::newRow("touch ownership after touch end") << true;
236 A touch point of id 0 starts and ends. Then the next touch point is also given
237 id 0. Check that TouchGate behaves correcly recognizing them as two distinct touch
240 Note that this won't be a problem with Mir as it assigns unique ids for the touch
243void tst_TouchGate::holdsEventsUntilGainsOwnership_repeatingTouchId()
245 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
248 TestItem *testItem = new TestItem;
249 testItem->setWidth(touchGate->width());
250 testItem->setHeight(touchGate->height());
251 testItem->setParentItem(view->rootObject());
254 touchGate->setZ(1.0);
255 touchGate->setTargetItem(testItem);
257 QTest::touchEvent(view, device)
258 .press(0, QPoint(100,100));
259 QTest::touchEvent(view, device)
260 .move(0, QPoint(101,101));
261 QTest::touchEvent(view, device)
262 .release(0, QPoint(101,101));
264 QCOMPARE(testItem->touchEventsReceived.count(), 3);
265 testItem->touchEventsReceived.clear();
267 // Put it in front of touchGate
268 CandidateItem *candidateItem = new CandidateItem;
269 candidateItem->setWidth(touchGate->width());
270 candidateItem->setHeight(touchGate->height());
271 candidateItem->setParentItem(view->rootObject());
272 candidateItem->setZ(2.0);
274 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
275 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
279 // A brand new touch, but with the same id as the previous one
280 QTest::touchEvent(view, device)
281 .press(0, QPoint(200,200));
282 QTest::touchEvent(view, device)
283 .move(0, QPoint(201,201));
284 QTest::touchEvent(view, device)
285 .release(0, QPoint(201,201));
287 QCOMPARE(testItem->touchEventsReceived.count(), 0);
289 touchRegistry->requestTouchOwnership(0, candidateItem);
291 QCOMPARE(testItem->touchEventsReceived.count(), 0);
293 QVERIFY(touchGate->m_storedEvents.isEmpty());
296void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget()
298 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
301 TestItem *testItem = new TestItem;
302 testItem->setWidth(touchGate->width());
303 testItem->setHeight(touchGate->height());
304 testItem->setParentItem(view->rootObject());
307 QFETCH(bool, isEnabled);
308 testItem->setEnabled(isEnabled);
310 QFETCH(bool, isVisible);
311 testItem->setVisible(isVisible);
313 touchGate->setZ(1.0);
314 touchGate->setTargetItem(testItem);
316 QTest::touchEvent(view, device)
317 .press(0, QPoint(100,100));
319 QCOMPARE(testItem->touchEventsReceived.count(), 0);
320 QVERIFY(touchGate->m_storedEvents.isEmpty());
323void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget_data()
325 QTest::addColumn<bool>("isEnabled");
326 QTest::addColumn<bool>("isVisible");
328 QTest::newRow("disabled visible") << false << true;
329 QTest::newRow("enabled invisible") << true << false;
330 QTest::newRow("disabled invisible") << false << false;
333void tst_TouchGate::disabledWhileHoldingTouch()
335 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
338 TestItem *testItem = new TestItem;
339 testItem->setWidth(touchGate->width());
340 testItem->setHeight(touchGate->height());
341 testItem->setParentItem(view->rootObject());
344 touchGate->setZ(1.0);
345 touchGate->setTargetItem(testItem);
347 QTest::touchEvent(view, device)
348 .press(0, QPoint(100,100));
350 QCOMPARE(testItem->touchEventsReceived.count(), 1);
351 testItem->touchEventsReceived.clear();
353 touchGate->setEnabled(false);
355 QTest::touchEvent(view, device)
356 .move(0, QPoint(101,101));
358 // Nothing new came as TouchGate didn't even get it because it's disabled
359 QCOMPARE(testItem->touchEventsReceived.count(), 0);
361 touchGate->setEnabled(true);
363 QTest::touchEvent(view, device)
364 .move(0, QPoint(102,102));
366 QTest::touchEvent(view, device)
367 .release(0, QPoint(102,102));
369 // Nothing new came because TouchGate has already discarded touch 0
370 QCOMPARE(testItem->touchEventsReceived.count(), 0);
372 QTest::touchEvent(view, device)
373 .press(1, QPoint(200,200));
375 QCOMPARE(testItem->touchEventsReceived.count(), 1);
377 // it got only the new touch point.
378 QSharedPointer<QTouchEvent> touchEvent = testItem->touchEventsReceived[0];
379 QCOMPARE(touchEvent->touchPoints().count(), 1);
380 QCOMPARE(touchEvent->touchPoints()[0].id(), 1);
384///////////// TestItem /////////////////////////////////////////////////////////////
386void TestItem::touchEvent(QTouchEvent *event)
388 QTouchEvent *clonedEvent = new QTouchEvent(event->type(),
391 event->touchPointStates(),
392 event->touchPoints());
394 touchEventsReceived.append(QSharedPointer<QTouchEvent>(clonedEvent));
397///////////// CandidateItem /////////////////////////////////////////////////////////////
399void CandidateItem::touchEvent(QTouchEvent *event)
401 touchEventHandler(event);
405QTEST_MAIN(tst_TouchGate)
407#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