on daa5708 help sign in
unity8/plugins/Ubuntu/Gestures/TouchGate.cpp
253 lines 7.5 kB history raw
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
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.
7 *
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.
12 *
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/>.
15 */
17#include "TouchGate.h"
19#include <QCoreApplication>
20#include <QDebug>
22#include <TouchOwnershipEvent.h>
23#include <TouchRegistry.h>
25#if TOUCHGATE_DEBUG
26#include <DebugHelpers.h>
27#endif
29bool TouchGate::event(QEvent *e)
31 if (e->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
32 touchOwnershipEvent(static_cast<TouchOwnershipEvent *>(e));
33 return true;
34 } else {
35 return QQuickItem::event(e);
36 }
39void TouchGate::touchEvent(QTouchEvent *event)
41 #if TOUCHGATE_DEBUG
42 qDebug() << "[TouchGate] got touch event" << qPrintable(touchEventToString(event));
43 #endif
44 event->accept();
46 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
47 bool goodToGo = true;
48 for (int i = 0; i < touchPoints.count(); ++i) {
49 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
51 if (touchPoint.state() == Qt::TouchPointPressed) {
52 Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
53 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
54 m_touchInfoMap[touchPoint.id()].ended = false;
55 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(), this);
57 Q_EMIT pressed();
58 }
60 goodToGo &= m_touchInfoMap.contains(touchPoint.id())
61 && m_touchInfoMap[touchPoint.id()].ownership == OwnershipGranted;
63 if (touchPoint.state() == Qt::TouchPointReleased && m_touchInfoMap.contains(touchPoint.id())) {
64 m_touchInfoMap[touchPoint.id()].ended = true;
65 }
67 }
69 if (goodToGo) {
70 if (m_storedEvents.isEmpty()) {
71 // let it pass through
72 dispatchTouchEventToTarget(event);
73 } else {
74 // Retain the event to ensure TouchGate dispatches them in order.
75 // Otherwise the current event would come before the stored ones, which are older.
76 #if TOUCHGATE_DEBUG
77 qDebug("[TouchGate] Storing event because thouches %s are still pending ownership.",
78 qPrintable(oldestPendingTouchIdsString()));
79 #endif
80 storeTouchEvent(event);
81 }
82 } else {
83 // Retain events that have unowned touches
84 storeTouchEvent(event);
85 }
88void TouchGate::touchOwnershipEvent(TouchOwnershipEvent *event)
90 // TODO: Optimization: batch those actions as TouchOwnershipEvents
91 // might come one right after the other.
93 Q_ASSERT(m_touchInfoMap.contains(event->touchId()));
95 TouchInfo &touchInfo = m_touchInfoMap[event->touchId()];
97 if (event->gained()) {
98 #if TOUCHGATE_DEBUG
99 qDebug() << "[TouchGate] Got ownership of touch " << event->touchId();
100 #endif
101 touchInfo.ownership = OwnershipGranted;
102 } else {
103 #if TOUCHGATE_DEBUG
104 qDebug() << "[TouchGate] Lost ownership of touch " << event->touchId();
105 #endif
106 m_touchInfoMap.remove(event->touchId());
107 removeTouchFromStoredEvents(event->touchId());
108 }
110 dispatchFullyOwnedEvents();
113bool TouchGate::isTouchPointOwned(int touchId) const
115 return m_touchInfoMap[touchId].ownership == OwnershipGranted;
118void TouchGate::storeTouchEvent(const QTouchEvent *event)
120 #if TOUCHGATE_DEBUG
121 qDebug() << "[TouchGate] Storing" << qPrintable(touchEventToString(event));
122 #endif
124 TouchEvent clonedEvent(event);
125 m_storedEvents.append(std::move(clonedEvent));
128void TouchGate::removeTouchFromStoredEvents(int touchId)
130 int i = 0;
131 while (i < m_storedEvents.count()) {
132 TouchEvent &event = m_storedEvents[i];
133 bool removed = event.removeTouch(touchId);
135 if (removed && event.touchPoints.isEmpty()) {
136 m_storedEvents.removeAt(i);
137 } else {
138 ++i;
139 }
140 }
143void TouchGate::dispatchFullyOwnedEvents()
145 while (!m_storedEvents.isEmpty() && eventIsFullyOwned(m_storedEvents.first())) {
146 TouchEvent event = m_storedEvents.takeFirst();
147 dispatchTouchEventToTarget(event);
148 }
151#if TOUCHGATE_DEBUG
152QString TouchGate::oldestPendingTouchIdsString()
154 Q_ASSERT(!m_storedEvents.isEmpty());
156 QString str;
158 const auto &touchPoints = m_storedEvents.first().touchPoints;
159 for (int i = 0; i < touchPoints.count(); ++i) {
160 if (!isTouchPointOwned(touchPoints[i].id())) {
161 if (!str.isEmpty()) {
162 str.append(", ");
163 }
164 str.append(QString::number(touchPoints[i].id()));
165 }
166 }
168 return str;
170#endif
172bool TouchGate::eventIsFullyOwned(const TouchGate::TouchEvent &event) const
174 for (int i = 0; i < event.touchPoints.count(); ++i) {
175 if (!isTouchPointOwned(event.touchPoints[i].id())) {
176 return false;
177 }
178 }
180 return true;
183void TouchGate::setTargetItem(QQuickItem *item)
185 // TODO: changing the target item while dispatch of touch events is taking place will
186 // create a mess
188 if (item == m_dispatcher.targetItem())
189 return;
191 m_dispatcher.setTargetItem(item);
192 Q_EMIT targetItemChanged(item);
195void TouchGate::dispatchTouchEventToTarget(const TouchEvent &event)
197 removeTouchInfoForEndedTouches(event.touchPoints);
198 m_dispatcher.dispatch(event.eventType,
199 event.device,
200 event.modifiers,
201 event.touchPoints,
202 event.window,
203 event.timestamp);
206void TouchGate::dispatchTouchEventToTarget(QTouchEvent* event)
208 removeTouchInfoForEndedTouches(event->touchPoints());
209 m_dispatcher.dispatch(event->type(),
210 event->device(),
211 event->modifiers(),
212 event->touchPoints(),
213 event->window(),
214 event->timestamp());
217void TouchGate::removeTouchInfoForEndedTouches(const QList<QTouchEvent::TouchPoint> &touchPoints)
219 for (int i = 0; i < touchPoints.size(); ++i) {\
220 const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
222 if (touchPoint.state() == Qt::TouchPointReleased) {
223 Q_ASSERT(m_touchInfoMap.contains(touchPoint.id()));
224 Q_ASSERT(m_touchInfoMap[touchPoint.id()].ended);
225 Q_ASSERT(m_touchInfoMap[touchPoint.id()].ownership == OwnershipGranted);
226 m_touchInfoMap.remove(touchPoint.id());
227 }
228 }
231TouchGate::TouchEvent::TouchEvent(const QTouchEvent *event)
232 : eventType(event->type())
233 , device(event->device())
234 , modifiers(event->modifiers())
235 , touchPoints(event->touchPoints())
236 , target(qobject_cast<QQuickItem*>(event->target()))
237 , window(event->window())
238 , timestamp(event->timestamp())
242bool TouchGate::TouchEvent::removeTouch(int touchId)
244 bool removed = false;
245 for (int i = 0; i < touchPoints.count() && !removed; ++i) {
246 if (touchPoints[i].id() == touchId) {
247 touchPoints.removeAt(i);
248 removed = true;
249 }
250 }
252 return removed;