2 * Copyright (C) 2014 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/>.
19#include <QCoreApplication>
22#include <TouchOwnershipEvent.h>
23#include <TouchRegistry.h>
25#pragma GCC diagnostic push
26#pragma GCC diagnostic ignored "-pedantic"
27#include <private/qquickitem_p.h>
28#pragma GCC diagnostic pop
31#include <DebugHelpers.h>
35bool TouchGate::event(QEvent *e)
37 if (e->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
38 touchOwnershipEvent(static_cast<TouchOwnershipEvent *>(e));
41 return QQuickItem::event(e);
45void TouchGate::touchEvent(QTouchEvent *event)
48 qDebug() << "[TouchGate] got touch event" << qPrintable(touchEventToString(event));
52 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
54 for (int i = 0; i < touchPoints.count(); ++i) {
55 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
57 if (touchPoint.state() == Qt::TouchPointPressed) {
58 Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
59 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
60 m_touchInfoMap[touchPoint.id()].ended = false;
61 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(), this);
64 goodToGo &= m_touchInfoMap.contains(touchPoint.id())
65 && m_touchInfoMap[touchPoint.id()].ownership == OwnershipGranted;
67 if (touchPoint.state() == Qt::TouchPointReleased && m_touchInfoMap.contains(touchPoint.id())) {
68 m_touchInfoMap[touchPoint.id()].ended = true;
74 if (m_storedEvents.isEmpty()) {
75 // let it pass through
76 dispatchTouchEventToTarget(event);
78 // Retain the event to ensure TouchGate dispatches them in order.
79 // Otherwise the current event would come before the stored ones, which are older.
81 qDebug("[TouchGate] Storing event because thouches %s are still pending ownership.",
82 qPrintable(oldestPendingTouchIdsString()));
84 storeTouchEvent(event);
87 // Retain events that have unowned touches
88 storeTouchEvent(event);
92void TouchGate::touchOwnershipEvent(TouchOwnershipEvent *event)
94 // TODO: Optimization: batch those actions as TouchOwnershipEvents
95 // might come one right after the other.
97 Q_ASSERT(m_touchInfoMap.contains(event->touchId()));
99 TouchInfo &touchInfo = m_touchInfoMap[event->touchId()];
101 if (event->gained()) {
103 qDebug() << "[TouchGate] Got ownership of touch " << event->touchId();
105 touchInfo.ownership = OwnershipGranted;
108 qDebug() << "[TouchGate] Lost ownership of touch " << event->touchId();
110 m_touchInfoMap.remove(event->touchId());
111 removeTouchFromStoredEvents(event->touchId());
114 dispatchFullyOwnedEvents();
117bool TouchGate::isTouchPointOwned(int touchId) const
119 return m_touchInfoMap[touchId].ownership == OwnershipGranted;
122void TouchGate::storeTouchEvent(const QTouchEvent *event)
125 qDebug() << "[TouchGate] Storing" << qPrintable(touchEventToString(event));
128 QTouchEvent *clonedEvent = new QTouchEvent(event->type(),
131 event->touchPointStates(),
132 event->touchPoints());
134 m_storedEvents.append(clonedEvent);
137void TouchGate::removeTouchFromStoredEvents(int touchId)
140 while (i < m_storedEvents.count()) {
141 QTouchEvent *event = m_storedEvents[i];
142 bool removed = removeTouchFromEvent(touchId, event);
144 if (removed && event->touchPoints().isEmpty()) {
145 m_storedEvents.removeAt(i);
152bool TouchGate::removeTouchFromEvent(int touchId, QTouchEvent *event)
154 const QList<QTouchEvent::TouchPoint> &eventTouchPoints = event->touchPoints();
156 int indexToRemove = -1;
157 for (int i = 0; i < eventTouchPoints.count() && indexToRemove < 0; ++i) {
158 if (eventTouchPoints[i].id() == touchId) {
163 if (indexToRemove >= 0) {
164 QList<QTouchEvent::TouchPoint> newTouchPointsList = eventTouchPoints;
165 newTouchPointsList.removeAt(indexToRemove);
166 event->setTouchPoints(newTouchPointsList);
173void TouchGate::dispatchFullyOwnedEvents()
175 while (!m_storedEvents.isEmpty() && eventIsFullyOwned(m_storedEvents.first())) {
176 QTouchEvent *event = m_storedEvents.first();
177 m_storedEvents.removeFirst();
178 dispatchTouchEventToTarget(event);
184QString TouchGate::oldestPendingTouchIdsString()
186 Q_ASSERT(!m_storedEvents.isEmpty());
190 auto touchPoints = m_storedEvents.first()->touchPoints();
191 for (int i = 0; i < touchPoints.count(); ++i) {
192 if (!isTouchPointOwned(touchPoints[i].id())) {
193 if (!str.isEmpty()) {
196 str.append(QString::number(touchPoints[i].id()));
204bool TouchGate::eventIsFullyOwned(const QTouchEvent *event) const
206 auto touchPoints = event->touchPoints();
207 for (int i = 0; i < touchPoints.count(); ++i) {
208 if (!isTouchPointOwned(touchPoints[i].id())) {
216void TouchGate::setTargetItem(QQuickItem *item)
218 // TODO: changing the target item while dispatch of touch events is taking place will
221 if (item == m_targetItem.data())
225 Q_EMIT targetItemChanged(item);
228void TouchGate::dispatchTouchEventToTarget(QTouchEvent* event)
230 removeTouchInfoForEndedTouches(event);
232 if (m_targetItem.isNull()) {
233 qWarning("[TouchGate] Cannot dispatch touch event because target item is null");
237 QQuickItem *targetItem = m_targetItem.data();
239 if (!targetItem->isEnabled() || !targetItem->isVisible()) {
241 qDebug() << "[TouchGate] Cannot dispatch touch event to" << targetItem
242 << "because it's disabled or invisible.";
247 // Map touch points to targetItem coordinates
248 QList<QTouchEvent::TouchPoint> touchPoints = event->touchPoints();
249 transformTouchPoints(touchPoints, QQuickItemPrivate::get(targetItem)->windowToItemTransform());
250 QTouchEvent *eventForTargetItem = touchEventWithPoints(*event, touchPoints);
253 qDebug() << "[TouchGate] dispatching" << qPrintable(touchEventToString(eventForTargetItem))
254 << "to" << targetItem;
257 QCoreApplication::sendEvent(targetItem, eventForTargetItem);
259 delete eventForTargetItem;
262// NB: From QQuickWindow
263void TouchGate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
265 QMatrix4x4 transformMatrix(transform);
266 for (int i=0; i<touchPoints.count(); i++) {
267 QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
268 touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
269 touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
270 touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
271 touchPoint.setVelocity(transformMatrix.mapVector(touchPoint.velocity()).toVector2D());
275// NB: From QQuickWindow
276QTouchEvent *TouchGate::touchEventWithPoints(const QTouchEvent &event,
277 const QList<QTouchEvent::TouchPoint> &newPoints)
279 Qt::TouchPointStates eventStates = 0;
280 for (int i=0; i<newPoints.count(); i++)
281 eventStates |= newPoints[i].state();
282 // if all points have the same state, set the event type accordingly
283 QEvent::Type eventType = event.type();
284 switch (eventStates) {
285 case Qt::TouchPointPressed:
286 eventType = QEvent::TouchBegin;
288 case Qt::TouchPointReleased:
289 eventType = QEvent::TouchEnd;
292 eventType = QEvent::TouchUpdate;
296 QTouchEvent *touchEvent = new QTouchEvent(eventType);
297 touchEvent->setWindow(event.window());
298 touchEvent->setTarget(event.target());
299 touchEvent->setDevice(event.device());
300 touchEvent->setModifiers(event.modifiers());
301 touchEvent->setTouchPoints(newPoints);
302 touchEvent->setTouchPointStates(eventStates);
303 touchEvent->setTimestamp(event.timestamp());
304 touchEvent->accept();
308void TouchGate::removeTouchInfoForEndedTouches(QTouchEvent *event)
310 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
312 for (int i = 0; i < touchPoints.size(); ++i) {\
313 const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
315 if (touchPoint.state() == Qt::TouchPointReleased) {
316 Q_ASSERT(m_touchInfoMap.contains(touchPoint.id()));
317 Q_ASSERT(m_touchInfoMap[touchPoint.id()].ended);
318 Q_ASSERT(m_touchInfoMap[touchPoint.id()].ownership == OwnershipGranted);
319 m_touchInfoMap.remove(touchPoint.id());
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