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 <UbuntuGestures/private/touchregistry_p.h>
34class CandidateItem : public QQuickItem
39 std::function<void(QTouchEvent*)> touchEventHandler;
42 void touchEvent(QTouchEvent *event) override;
45class tst_TouchGate : public QObject
49 tst_TouchGate(QObject *parent = nullptr);
51 void initTestCase(); // will be called before the first test function is executed
52 void cleanupTestCase(); // will be called after the last test function was executed.
54 void init(); // called right before each and every test function is executed
55 void cleanup(); // called right after each and every test function is executed
58 void onlyCandidate_passThrough();
59 void holdsEventsUntilGainsOwnership();
60 void holdsEventsUntilGainsOwnership_data();
61 void holdsEventsUntilGainsOwnership_repeatingTouchId();
62 void dontDispacthToDisabledOrInvisibleTarget();
63 void dontDispacthToDisabledOrInvisibleTarget_data();
66 void disabledWhileHoldingTouch();
69 QQuickView *createView();
70 TouchRegistry *touchRegistry;
75tst_TouchGate::tst_TouchGate(QObject *parent)
77 , touchRegistry(nullptr)
83void tst_TouchGate::initTestCase()
86 device = new QTouchDevice;
87 device->setType(QTouchDevice::TouchScreen);
88 QWindowSystemInterface::registerTouchDevice(device);
92void tst_TouchGate::cleanupTestCase()
96void tst_TouchGate::init()
98 touchRegistry = TouchRegistry::instance();
101 view->setSource(QUrl::fromLocalFile("touchGateExample.qml"));
103 QVERIFY(QTest::qWaitForWindowExposed(view));
104 QVERIFY(view->rootObject() != 0);
105 qApp->processEvents();
108void tst_TouchGate::cleanup()
113 delete touchRegistry;
114 touchRegistry = nullptr;
117QQuickView *tst_TouchGate::createView()
119 QQuickView *window = new QQuickView(0);
120 window->setResizeMode(QQuickView::SizeRootObjectToView);
121 window->resize(720, 720);
127 Simplest case. TouchGate is the only candidate for the touch point, thus it
128 will instantly gain ownership causing the event to pass through it directly to
131void tst_TouchGate::onlyCandidate_passThrough()
133 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
136 TestItem *testItem = new TestItem;
137 testItem->setWidth(touchGate->width());
138 testItem->setHeight(touchGate->height());
139 testItem->setParentItem(view->rootObject());
142 touchGate->setZ(1.0);
143 touchGate->setTargetItem(testItem);
145 QTest::touchEvent(view, device)
146 .press(0, QPoint(100,100));
148 QCOMPARE(testItem->touchEventsReceived.count(), 1);
149 QVERIFY(touchGate->m_storedEvents.isEmpty());
152void tst_TouchGate::holdsEventsUntilGainsOwnership()
154 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
156 QFETCH(bool, ownershipAfterTouchEnd);
158 TestItem *testItem = new TestItem;
159 testItem->setWidth(touchGate->width());
160 testItem->setHeight(touchGate->height());
161 testItem->setParentItem(view->rootObject());
164 touchGate->setZ(1.0);
165 touchGate->setTargetItem(testItem);
167 // Put it in front of touchGate
168 CandidateItem *candidateItem = new CandidateItem;
169 candidateItem->setWidth(touchGate->width());
170 candidateItem->setHeight(touchGate->height());
171 candidateItem->setParentItem(view->rootObject());
172 candidateItem->setZ(2.0);
174 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
175 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
179 QTest::touchEvent(view, device)
180 .press(0, QPoint(100,100));
182 QCOMPARE(testItem->touchEventsReceived.count(), 0);
184 QTest::touchEvent(view, device)
185 .move(0, QPoint(101,101));
187 QCOMPARE(testItem->touchEventsReceived.count(), 0);
189 if (!ownershipAfterTouchEnd) {
190 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
191 QQuickWindowPrivate *wp = QQuickWindowPrivate::get(testItem->window());
192 wp->flushDelayedTouchEvent();
193 // TouchGate should now open its flood gates and let testItem get all
194 // events from touch 0 produced so far
195 QCOMPARE(testItem->touchEventsReceived.count(), 2);
198 QTest::touchEvent(view, device)
199 .release(0, QPoint(101,101));
201 if (ownershipAfterTouchEnd) {
202 QCOMPARE(testItem->touchEventsReceived.count(), 0);
203 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
204 // TouchGate should now open its flood gates and let testItem get all
205 // events from touch 0 produced so far
208 QCOMPARE(testItem->touchEventsReceived.count(), 3);
210 QVERIFY(touchGate->m_storedEvents.isEmpty());
211 QVERIFY(touchGate->m_touchInfoMap.isEmpty());
214void tst_TouchGate::holdsEventsUntilGainsOwnership_data()
216 QTest::addColumn<bool>("ownershipAfterTouchEnd");
218 QTest::newRow("touch end after touch ownership") << false;
219 QTest::newRow("touch ownership after touch end") << true;
223 A touch point of id 0 starts and ends. Then the next touch point is also given
224 id 0. Check that TouchGate behaves correcly recognizing them as two distinct touch
227 Note that this won't be a problem with Mir as it assigns unique ids for the touch
230void tst_TouchGate::holdsEventsUntilGainsOwnership_repeatingTouchId()
232 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
235 TestItem *testItem = new TestItem;
236 testItem->setWidth(touchGate->width());
237 testItem->setHeight(touchGate->height());
238 testItem->setParentItem(view->rootObject());
241 touchGate->setZ(1.0);
242 touchGate->setTargetItem(testItem);
244 QTest::touchEvent(view, device)
245 .press(0, QPoint(100,100));
246 QTest::touchEvent(view, device)
247 .move(0, QPoint(101,101));
248 QTest::touchEvent(view, device)
249 .release(0, QPoint(101,101));
251 QCOMPARE(testItem->touchEventsReceived.count(), 3);
252 testItem->touchEventsReceived.clear();
254 // Put it in front of touchGate
255 CandidateItem *candidateItem = new CandidateItem;
256 candidateItem->setWidth(touchGate->width());
257 candidateItem->setHeight(touchGate->height());
258 candidateItem->setParentItem(view->rootObject());
259 candidateItem->setZ(2.0);
261 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
262 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
266 // A brand new touch, but with the same id as the previous one
267 QTest::touchEvent(view, device)
268 .press(0, QPoint(200,200));
269 QTest::touchEvent(view, device)
270 .move(0, QPoint(201,201));
271 QTest::touchEvent(view, device)
272 .release(0, QPoint(201,201));
274 QCOMPARE(testItem->touchEventsReceived.count(), 0);
276 touchRegistry->requestTouchOwnership(0, candidateItem);
278 QCOMPARE(testItem->touchEventsReceived.count(), 0);
280 QVERIFY(touchGate->m_storedEvents.isEmpty());
283void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget()
285 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
288 TestItem *testItem = new TestItem;
289 testItem->setWidth(touchGate->width());
290 testItem->setHeight(touchGate->height());
291 testItem->setParentItem(view->rootObject());
294 QFETCH(bool, isEnabled);
295 testItem->setEnabled(isEnabled);
297 QFETCH(bool, isVisible);
298 testItem->setVisible(isVisible);
300 touchGate->setZ(1.0);
301 touchGate->setTargetItem(testItem);
303 QTest::touchEvent(view, device)
304 .press(0, QPoint(100,100));
306 QCOMPARE(testItem->touchEventsReceived.count(), 0);
307 QVERIFY(touchGate->m_storedEvents.isEmpty());
310void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget_data()
312 QTest::addColumn<bool>("isEnabled");
313 QTest::addColumn<bool>("isVisible");
315 QTest::newRow("disabled visible") << false << true;
316 QTest::newRow("enabled invisible") << true << false;
317 QTest::newRow("disabled invisible") << false << false;
320void tst_TouchGate::disabledWhileHoldingTouch()
322 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
325 TestItem *testItem = new TestItem;
326 testItem->setWidth(touchGate->width());
327 testItem->setHeight(touchGate->height());
328 testItem->setParentItem(view->rootObject());
331 touchGate->setZ(1.0);
332 touchGate->setTargetItem(testItem);
334 QTest::touchEvent(view, device)
335 .press(0, QPoint(100,100));
337 QCOMPARE(testItem->touchEventsReceived.count(), 1);
338 testItem->touchEventsReceived.clear();
340 touchGate->setEnabled(false);
342 QTest::touchEvent(view, device)
343 .move(0, QPoint(101,101));
345 // Nothing new came as TouchGate didn't even get it because it's disabled
346 QCOMPARE(testItem->touchEventsReceived.count(), 0);
348 touchGate->setEnabled(true);
350 QTest::touchEvent(view, device)
351 .move(0, QPoint(102,102));
353 QTest::touchEvent(view, device)
354 .release(0, QPoint(102,102));
356 // Nothing new came because TouchGate has already discarded touch 0
357 QCOMPARE(testItem->touchEventsReceived.count(), 0);
359 QTest::touchEvent(view, device)
360 .press(1, QPoint(200,200));
362 QCOMPARE(testItem->touchEventsReceived.count(), 1);
364 // it got only the new touch point.
365 QSharedPointer<QTouchEvent> touchEvent = testItem->touchEventsReceived[0];
366 QCOMPARE(touchEvent->touchPoints().count(), 1);
367 QCOMPARE(touchEvent->touchPoints()[0].id(), 1);
371///////////// CandidateItem /////////////////////////////////////////////////////////////
373void CandidateItem::touchEvent(QTouchEvent *event)
375 touchEventHandler(event);
379QTEST_MAIN(tst_TouchGate)
381#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