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#include <private/qquickwindow_p.h>
28#include <TouchRegistry.h>
32class CandidateItem : public QQuickItem
37 std::function<void(QTouchEvent*)> touchEventHandler;
40 void touchEvent(QTouchEvent *event) override;
43class tst_TouchGate : public QObject
47 tst_TouchGate(QObject *parent = nullptr);
49 void initTestCase(); // will be called before the first test function is executed
50 void cleanupTestCase(); // will be called after the last test function was executed.
52 void init(); // called right before each and every test function is executed
53 void cleanup(); // called right after each and every test function is executed
56 void onlyCandidate_passThrough();
57 void holdsEventsUntilGainsOwnership();
58 void holdsEventsUntilGainsOwnership_data();
59 void holdsEventsUntilGainsOwnership_repeatingTouchId();
60 void dontDispacthToDisabledOrInvisibleTarget();
61 void dontDispacthToDisabledOrInvisibleTarget_data();
64 void disabledWhileHoldingTouch();
67 QQuickView *createView();
68 TouchRegistry *touchRegistry;
73tst_TouchGate::tst_TouchGate(QObject *parent)
75 , touchRegistry(nullptr)
81void tst_TouchGate::initTestCase()
84 device = new QTouchDevice;
85 device->setType(QTouchDevice::TouchScreen);
86 QWindowSystemInterface::registerTouchDevice(device);
90void tst_TouchGate::cleanupTestCase()
94void tst_TouchGate::init()
96 touchRegistry = TouchRegistry::instance();
99 view->setSource(QUrl::fromLocalFile("touchGateExample.qml"));
101 QVERIFY(QTest::qWaitForWindowExposed(view));
102 QVERIFY(view->rootObject() != 0);
103 qApp->processEvents();
106void tst_TouchGate::cleanup()
111 delete touchRegistry;
112 touchRegistry = nullptr;
115QQuickView *tst_TouchGate::createView()
117 QQuickView *window = new QQuickView(0);
118 window->setResizeMode(QQuickView::SizeRootObjectToView);
119 window->resize(720, 720);
125 Simplest case. TouchGate is the only candidate for the touch point, thus it
126 will instantly gain ownership causing the event to pass through it directly to
129void tst_TouchGate::onlyCandidate_passThrough()
131 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
134 TestItem *testItem = new TestItem;
135 testItem->setWidth(touchGate->width());
136 testItem->setHeight(touchGate->height());
137 testItem->setParentItem(view->rootObject());
140 touchGate->setZ(1.0);
141 touchGate->setTargetItem(testItem);
143 QTest::touchEvent(view, device)
144 .press(0, QPoint(100,100));
146 QCOMPARE(testItem->touchEventsReceived.count(), 1);
147 QVERIFY(touchGate->m_storedEvents.isEmpty());
150void tst_TouchGate::holdsEventsUntilGainsOwnership()
152 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
154 QFETCH(bool, ownershipAfterTouchEnd);
156 TestItem *testItem = new TestItem;
157 testItem->setWidth(touchGate->width());
158 testItem->setHeight(touchGate->height());
159 testItem->setParentItem(view->rootObject());
162 touchGate->setZ(1.0);
163 touchGate->setTargetItem(testItem);
165 // Put it in front of touchGate
166 CandidateItem *candidateItem = new CandidateItem;
167 candidateItem->setWidth(touchGate->width());
168 candidateItem->setHeight(touchGate->height());
169 candidateItem->setParentItem(view->rootObject());
170 candidateItem->setZ(2.0);
172 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
173 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
177 QTest::touchEvent(view, device)
178 .press(0, QPoint(100,100));
180 QCOMPARE(testItem->touchEventsReceived.count(), 0);
182 QTest::touchEvent(view, device)
183 .move(0, QPoint(101,101));
185 QCOMPARE(testItem->touchEventsReceived.count(), 0);
187 if (!ownershipAfterTouchEnd) {
188 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
189 QQuickWindowPrivate *wp = QQuickWindowPrivate::get(testItem->window());
190 wp->flushDelayedTouchEvent();
191 // TouchGate should now open its flood gates and let testItem get all
192 // events from touch 0 produced so far
193 QCOMPARE(testItem->touchEventsReceived.count(), 2);
196 QTest::touchEvent(view, device)
197 .release(0, QPoint(101,101));
199 if (ownershipAfterTouchEnd) {
200 QCOMPARE(testItem->touchEventsReceived.count(), 0);
201 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
202 // TouchGate should now open its flood gates and let testItem get all
203 // events from touch 0 produced so far
206 QCOMPARE(testItem->touchEventsReceived.count(), 3);
208 QVERIFY(touchGate->m_storedEvents.isEmpty());
209 QVERIFY(touchGate->m_touchInfoMap.isEmpty());
212void tst_TouchGate::holdsEventsUntilGainsOwnership_data()
214 QTest::addColumn<bool>("ownershipAfterTouchEnd");
216 QTest::newRow("touch end after touch ownership") << false;
217 QTest::newRow("touch ownership after touch end") << true;
221 A touch point of id 0 starts and ends. Then the next touch point is also given
222 id 0. Check that TouchGate behaves correcly recognizing them as two distinct touch
225 Note that this won't be a problem with Mir as it assigns unique ids for the touch
228void tst_TouchGate::holdsEventsUntilGainsOwnership_repeatingTouchId()
230 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
233 TestItem *testItem = new TestItem;
234 testItem->setWidth(touchGate->width());
235 testItem->setHeight(touchGate->height());
236 testItem->setParentItem(view->rootObject());
239 touchGate->setZ(1.0);
240 touchGate->setTargetItem(testItem);
242 QTest::touchEvent(view, device)
243 .press(0, QPoint(100,100));
244 QTest::touchEvent(view, device)
245 .move(0, QPoint(101,101));
246 QTest::touchEvent(view, device)
247 .release(0, QPoint(101,101));
249 QCOMPARE(testItem->touchEventsReceived.count(), 3);
250 testItem->touchEventsReceived.clear();
252 // Put it in front of touchGate
253 CandidateItem *candidateItem = new CandidateItem;
254 candidateItem->setWidth(touchGate->width());
255 candidateItem->setHeight(touchGate->height());
256 candidateItem->setParentItem(view->rootObject());
257 candidateItem->setZ(2.0);
259 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
260 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
264 // A brand new touch, but with the same id as the previous one
265 QTest::touchEvent(view, device)
266 .press(0, QPoint(200,200));
267 QTest::touchEvent(view, device)
268 .move(0, QPoint(201,201));
269 QTest::touchEvent(view, device)
270 .release(0, QPoint(201,201));
272 QCOMPARE(testItem->touchEventsReceived.count(), 0);
274 touchRegistry->requestTouchOwnership(0, candidateItem);
276 QCOMPARE(testItem->touchEventsReceived.count(), 0);
278 QVERIFY(touchGate->m_storedEvents.isEmpty());
281void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget()
283 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
286 TestItem *testItem = new TestItem;
287 testItem->setWidth(touchGate->width());
288 testItem->setHeight(touchGate->height());
289 testItem->setParentItem(view->rootObject());
292 QFETCH(bool, isEnabled);
293 testItem->setEnabled(isEnabled);
295 QFETCH(bool, isVisible);
296 testItem->setVisible(isVisible);
298 touchGate->setZ(1.0);
299 touchGate->setTargetItem(testItem);
301 QTest::touchEvent(view, device)
302 .press(0, QPoint(100,100));
304 QCOMPARE(testItem->touchEventsReceived.count(), 0);
305 QVERIFY(touchGate->m_storedEvents.isEmpty());
308void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget_data()
310 QTest::addColumn<bool>("isEnabled");
311 QTest::addColumn<bool>("isVisible");
313 QTest::newRow("disabled visible") << false << true;
314 QTest::newRow("enabled invisible") << true << false;
315 QTest::newRow("disabled invisible") << false << false;
318void tst_TouchGate::disabledWhileHoldingTouch()
320 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
323 TestItem *testItem = new TestItem;
324 testItem->setWidth(touchGate->width());
325 testItem->setHeight(touchGate->height());
326 testItem->setParentItem(view->rootObject());
329 touchGate->setZ(1.0);
330 touchGate->setTargetItem(testItem);
332 QTest::touchEvent(view, device)
333 .press(0, QPoint(100,100));
335 QCOMPARE(testItem->touchEventsReceived.count(), 1);
336 testItem->touchEventsReceived.clear();
338 touchGate->setEnabled(false);
340 QTest::touchEvent(view, device)
341 .move(0, QPoint(101,101));
343 // Nothing new came as TouchGate didn't even get it because it's disabled
344 QCOMPARE(testItem->touchEventsReceived.count(), 0);
346 touchGate->setEnabled(true);
348 QTest::touchEvent(view, device)
349 .move(0, QPoint(102,102));
351 QTest::touchEvent(view, device)
352 .release(0, QPoint(102,102));
354 // Nothing new came because TouchGate has already discarded touch 0
355 QCOMPARE(testItem->touchEventsReceived.count(), 0);
357 QTest::touchEvent(view, device)
358 .press(1, QPoint(200,200));
360 QCOMPARE(testItem->touchEventsReceived.count(), 1);
362 // it got only the new touch point.
363 QSharedPointer<QTouchEvent> touchEvent = testItem->touchEventsReceived[0];
364 QCOMPARE(touchEvent->touchPoints().count(), 1);
365 QCOMPARE(touchEvent->touchPoints()[0].id(), 1);
369///////////// CandidateItem /////////////////////////////////////////////////////////////
371void CandidateItem::touchEvent(QTouchEvent *event)
373 touchEventHandler(event);
377QTEST_MAIN(tst_TouchGate)
379#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