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>
36class CandidateItem : public QQuickItem
41 std::function<void(QTouchEvent*)> touchEventHandler;
44 void touchEvent(QTouchEvent *event) override;
47class tst_TouchGate : public QObject
51 tst_TouchGate(QObject *parent = nullptr);
53 void initTestCase(); // will be called before the first test function is executed
54 void cleanupTestCase(); // will be called after the last test function was executed.
56 void init(); // called right before each and every test function is executed
57 void cleanup(); // called right after each and every test function is executed
60 void onlyCandidate_passThrough();
61 void holdsEventsUntilGainsOwnership();
62 void holdsEventsUntilGainsOwnership_data();
63 void holdsEventsUntilGainsOwnership_repeatingTouchId();
64 void dontDispacthToDisabledOrInvisibleTarget();
65 void dontDispacthToDisabledOrInvisibleTarget_data();
68 void disabledWhileHoldingTouch();
71 QQuickView *createView();
72 TouchRegistry *touchRegistry;
77tst_TouchGate::tst_TouchGate(QObject *parent)
79 , touchRegistry(nullptr)
85void tst_TouchGate::initTestCase()
88 device = new QTouchDevice;
89 device->setType(QTouchDevice::TouchScreen);
90 QWindowSystemInterface::registerTouchDevice(device);
94void tst_TouchGate::cleanupTestCase()
98void tst_TouchGate::init()
100 touchRegistry = TouchRegistry::instance();
103 view->setSource(QUrl::fromLocalFile(testDataDir() + "/plugins/Ubuntu/Gestures/touchGateExample.qml"));
105 QVERIFY(QTest::qWaitForWindowExposed(view));
106 QVERIFY(view->rootObject() != 0);
107 qApp->processEvents();
110void tst_TouchGate::cleanup()
115 delete touchRegistry;
116 touchRegistry = nullptr;
119QQuickView *tst_TouchGate::createView()
121 QQuickView *window = new QQuickView(0);
122 window->setResizeMode(QQuickView::SizeRootObjectToView);
123 window->resize(720, 720);
129 Simplest case. TouchGate is the only candidate for the touch point, thus it
130 will instantly gain ownership causing the event to pass through it directly to
133void tst_TouchGate::onlyCandidate_passThrough()
135 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
138 TestItem *testItem = new TestItem;
139 testItem->setWidth(touchGate->width());
140 testItem->setHeight(touchGate->height());
141 testItem->setParentItem(view->rootObject());
144 touchGate->setZ(1.0);
145 touchGate->setTargetItem(testItem);
147 QTest::touchEvent(view, device)
148 .press(0, QPoint(100,100));
150 QCOMPARE(testItem->touchEventsReceived.count(), 1);
151 QVERIFY(touchGate->m_storedEvents.isEmpty());
154void tst_TouchGate::holdsEventsUntilGainsOwnership()
156 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
158 QFETCH(bool, ownershipAfterTouchEnd);
160 TestItem *testItem = new TestItem;
161 testItem->setWidth(touchGate->width());
162 testItem->setHeight(touchGate->height());
163 testItem->setParentItem(view->rootObject());
166 touchGate->setZ(1.0);
167 touchGate->setTargetItem(testItem);
169 // Put it in front of touchGate
170 CandidateItem *candidateItem = new CandidateItem;
171 candidateItem->setWidth(touchGate->width());
172 candidateItem->setHeight(touchGate->height());
173 candidateItem->setParentItem(view->rootObject());
174 candidateItem->setZ(2.0);
176 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
177 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
181 QTest::touchEvent(view, device)
182 .press(0, QPoint(100,100));
184 QCOMPARE(testItem->touchEventsReceived.count(), 0);
186 QTest::touchEvent(view, device)
187 .move(0, QPoint(101,101));
189 QCOMPARE(testItem->touchEventsReceived.count(), 0);
191 if (!ownershipAfterTouchEnd) {
192 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
193 QQuickWindowPrivate *wp = QQuickWindowPrivate::get(testItem->window());
194 wp->flushDelayedTouchEvent();
195 // TouchGate should now open its flood gates and let testItem get all
196 // events from touch 0 produced so far
197 QCOMPARE(testItem->touchEventsReceived.count(), 2);
200 QTest::touchEvent(view, device)
201 .release(0, QPoint(101,101));
203 if (ownershipAfterTouchEnd) {
204 QCOMPARE(testItem->touchEventsReceived.count(), 0);
205 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
206 // TouchGate should now open its flood gates and let testItem get all
207 // events from touch 0 produced so far
210 QCOMPARE(testItem->touchEventsReceived.count(), 3);
212 QVERIFY(touchGate->m_storedEvents.isEmpty());
213 QVERIFY(touchGate->m_touchInfoMap.isEmpty());
216void tst_TouchGate::holdsEventsUntilGainsOwnership_data()
218 QTest::addColumn<bool>("ownershipAfterTouchEnd");
220 QTest::newRow("touch end after touch ownership") << false;
221 QTest::newRow("touch ownership after touch end") << true;
225 A touch point of id 0 starts and ends. Then the next touch point is also given
226 id 0. Check that TouchGate behaves correcly recognizing them as two distinct touch
229 Note that this won't be a problem with Mir as it assigns unique ids for the touch
232void tst_TouchGate::holdsEventsUntilGainsOwnership_repeatingTouchId()
234 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
237 TestItem *testItem = new TestItem;
238 testItem->setWidth(touchGate->width());
239 testItem->setHeight(touchGate->height());
240 testItem->setParentItem(view->rootObject());
243 touchGate->setZ(1.0);
244 touchGate->setTargetItem(testItem);
246 QTest::touchEvent(view, device)
247 .press(0, QPoint(100,100));
248 QTest::touchEvent(view, device)
249 .move(0, QPoint(101,101));
250 QTest::touchEvent(view, device)
251 .release(0, QPoint(101,101));
253 QCOMPARE(testItem->touchEventsReceived.count(), 3);
254 testItem->touchEventsReceived.clear();
256 // Put it in front of touchGate
257 CandidateItem *candidateItem = new CandidateItem;
258 candidateItem->setWidth(touchGate->width());
259 candidateItem->setHeight(touchGate->height());
260 candidateItem->setParentItem(view->rootObject());
261 candidateItem->setZ(2.0);
263 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
264 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
268 // A brand new touch, but with the same id as the previous one
269 QTest::touchEvent(view, device)
270 .press(0, QPoint(200,200));
271 QTest::touchEvent(view, device)
272 .move(0, QPoint(201,201));
273 QTest::touchEvent(view, device)
274 .release(0, QPoint(201,201));
276 QCOMPARE(testItem->touchEventsReceived.count(), 0);
278 touchRegistry->requestTouchOwnership(0, candidateItem);
280 QCOMPARE(testItem->touchEventsReceived.count(), 0);
282 QVERIFY(touchGate->m_storedEvents.isEmpty());
285void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget()
287 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
290 TestItem *testItem = new TestItem;
291 testItem->setWidth(touchGate->width());
292 testItem->setHeight(touchGate->height());
293 testItem->setParentItem(view->rootObject());
296 QFETCH(bool, isEnabled);
297 testItem->setEnabled(isEnabled);
299 QFETCH(bool, isVisible);
300 testItem->setVisible(isVisible);
302 touchGate->setZ(1.0);
303 touchGate->setTargetItem(testItem);
305 QTest::touchEvent(view, device)
306 .press(0, QPoint(100,100));
308 QCOMPARE(testItem->touchEventsReceived.count(), 0);
309 QVERIFY(touchGate->m_storedEvents.isEmpty());
312void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget_data()
314 QTest::addColumn<bool>("isEnabled");
315 QTest::addColumn<bool>("isVisible");
317 QTest::newRow("disabled visible") << false << true;
318 QTest::newRow("enabled invisible") << true << false;
319 QTest::newRow("disabled invisible") << false << false;
322void tst_TouchGate::disabledWhileHoldingTouch()
324 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
327 TestItem *testItem = new TestItem;
328 testItem->setWidth(touchGate->width());
329 testItem->setHeight(touchGate->height());
330 testItem->setParentItem(view->rootObject());
333 touchGate->setZ(1.0);
334 touchGate->setTargetItem(testItem);
336 QTest::touchEvent(view, device)
337 .press(0, QPoint(100,100));
339 QCOMPARE(testItem->touchEventsReceived.count(), 1);
340 testItem->touchEventsReceived.clear();
342 touchGate->setEnabled(false);
344 QTest::touchEvent(view, device)
345 .move(0, QPoint(101,101));
347 // Nothing new came as TouchGate didn't even get it because it's disabled
348 QCOMPARE(testItem->touchEventsReceived.count(), 0);
350 touchGate->setEnabled(true);
352 QTest::touchEvent(view, device)
353 .move(0, QPoint(102,102));
355 QTest::touchEvent(view, device)
356 .release(0, QPoint(102,102));
358 // Nothing new came because TouchGate has already discarded touch 0
359 QCOMPARE(testItem->touchEventsReceived.count(), 0);
361 QTest::touchEvent(view, device)
362 .press(1, QPoint(200,200));
364 QCOMPARE(testItem->touchEventsReceived.count(), 1);
366 // it got only the new touch point.
367 QSharedPointer<QTouchEvent> touchEvent = testItem->touchEventsReceived[0];
368 QCOMPARE(touchEvent->touchPoints().count(), 1);
369 QCOMPARE(touchEvent->touchPoints()[0].id(), 1);
373///////////// CandidateItem /////////////////////////////////////////////////////////////
375void CandidateItem::touchEvent(QTouchEvent *event)
377 touchEventHandler(event);
381QTEST_MAIN(tst_TouchGate)
383#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