1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "private/qgesturemanager_p.h"
41 #include "private/qstandardgestures_p.h"
42 #include "private/qwidget_p.h"
43 #include "private/qgesture_p.h"
44 #if QT_CONFIG(graphicsview)
45 #include "private/qgraphicsitem_p.h"
46 #include "qgraphicsitem.h"
47 #endif
48 #include "private/qevent_p.h"
49 #include "private/qapplication_p.h"
50 #include "private/qwidgetwindow_p.h"
51 #include "qgesture.h"
52 #include "qevent.h"
53 
54 #ifdef Q_OS_MACOS
55 #include "qmacgesturerecognizer_p.h"
56 #endif
57 
58 #include "qdebug.h"
59 #include <QtCore/QLoggingCategory>
60 
61 #ifndef QT_NO_GESTURES
62 
63 QT_BEGIN_NAMESPACE
64 
65 Q_LOGGING_CATEGORY(lcGestureManager, "qt.widgets.gestures")
66 
67 #if !defined(Q_OS_MACOS)
panTouchPoints()68 static inline int panTouchPoints()
69 {
70     // Override by environment variable for testing.
71     static const char panTouchPointVariable[] = "QT_PAN_TOUCHPOINTS";
72     if (qEnvironmentVariableIsSet(panTouchPointVariable)) {
73         bool ok;
74         const int result = qEnvironmentVariableIntValue(panTouchPointVariable, &ok);
75         if (ok && result >= 1)
76             return result;
77         qWarning("Ignoring invalid value of %s", panTouchPointVariable);
78     }
79     // Pan should use 1 finger on a touch screen and 2 fingers on touch pads etc.
80     // where 1 finger movements are used for mouse event synthetization. For now,
81     // default to 2 until all classes inheriting QScrollArea are fixed to handle it
82     // correctly.
83     return 2;
84 }
85 #endif
86 
QGestureManager(QObject * parent)87 QGestureManager::QGestureManager(QObject *parent)
88     : QObject(parent), state(NotGesture), m_lastCustomGestureId(Qt::CustomGesture)
89 {
90     qRegisterMetaType<Qt::GestureState>();
91 
92 #if defined(Q_OS_MACOS)
93     registerGestureRecognizer(new QMacSwipeGestureRecognizer);
94     registerGestureRecognizer(new QMacPinchGestureRecognizer);
95     registerGestureRecognizer(new QMacPanGestureRecognizer);
96 #else
97     registerGestureRecognizer(new QPanGestureRecognizer(panTouchPoints()));
98     registerGestureRecognizer(new QPinchGestureRecognizer);
99     registerGestureRecognizer(new QSwipeGestureRecognizer);
100     registerGestureRecognizer(new QTapGestureRecognizer);
101 #endif
102     registerGestureRecognizer(new QTapAndHoldGestureRecognizer);
103 }
104 
~QGestureManager()105 QGestureManager::~QGestureManager()
106 {
107     qDeleteAll(m_recognizers);
108     for (auto it = m_obsoleteGestures.cbegin(), end = m_obsoleteGestures.cend(); it != end; ++it) {
109         qDeleteAll(it.value());
110         delete it.key();
111     }
112 }
113 
registerGestureRecognizer(QGestureRecognizer * recognizer)114 Qt::GestureType QGestureManager::registerGestureRecognizer(QGestureRecognizer *recognizer)
115 {
116     const QScopedPointer<QGesture> dummy(recognizer->create(nullptr));
117     if (Q_UNLIKELY(!dummy)) {
118         qWarning("QGestureManager::registerGestureRecognizer: "
119                  "the recognizer fails to create a gesture object, skipping registration.");
120         return Qt::GestureType(0);
121     }
122     Qt::GestureType type = dummy->gestureType();
123     if (type == Qt::CustomGesture) {
124         // generate a new custom gesture id
125         ++m_lastCustomGestureId;
126         type = Qt::GestureType(m_lastCustomGestureId);
127     }
128     m_recognizers.insert(type, recognizer);
129     return type;
130 }
131 
unregisterGestureRecognizer(Qt::GestureType type)132 void QGestureManager::unregisterGestureRecognizer(Qt::GestureType type)
133 {
134     QList<QGestureRecognizer *> list = m_recognizers.values(type);
135     m_recognizers.remove(type);
136     foreach (QGesture *g, m_gestureToRecognizer.keys()) {
137         QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g);
138         if (list.contains(recognizer)) {
139             m_deletedRecognizers.insert(g, recognizer);
140         }
141     }
142 
143     QMap<ObjectGesture, QList<QGesture *> >::const_iterator iter = m_objectGestures.constBegin();
144     while (iter != m_objectGestures.constEnd()) {
145         ObjectGesture objectGesture = iter.key();
146         if (objectGesture.gesture == type) {
147             foreach (QGesture *g, iter.value()) {
148                 if (QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g)) {
149                     m_gestureToRecognizer.remove(g);
150                     m_obsoleteGestures[recognizer].insert(g);
151                 }
152             }
153         }
154         ++iter;
155     }
156 }
157 
cleanupCachedGestures(QObject * target,Qt::GestureType type)158 void QGestureManager::cleanupCachedGestures(QObject *target, Qt::GestureType type)
159 {
160     const auto iter = m_objectGestures.find({target, type});
161     if (iter == m_objectGestures.end())
162         return;
163 
164     const QList<QGesture *> &gestures = iter.value();
165     for (auto &e : m_obsoleteGestures) {
166         for (QGesture *g : gestures)
167             e -= g;
168     }
169     for (QGesture *g : gestures) {
170         m_deletedRecognizers.remove(g);
171         m_gestureToRecognizer.remove(g);
172         m_maybeGestures.remove(g);
173         m_activeGestures.remove(g);
174         m_gestureOwners.remove(g);
175         m_gestureTargets.remove(g);
176         m_gesturesToDelete.insert(g);
177     }
178 
179     m_objectGestures.erase(iter);
180 }
181 
182 // get or create a QGesture object that will represent the state for a given object, used by the recognizer
getState(QObject * object,QGestureRecognizer * recognizer,Qt::GestureType type)183 QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recognizer, Qt::GestureType type)
184 {
185     // if the widget is being deleted we should be careful not to
186     // create a new state, as it will create QWeakPointer which doesn't work
187     // from the destructor.
188     if (object->isWidgetType()) {
189         if (static_cast<QWidget *>(object)->d_func()->data.in_destructor)
190             return nullptr;
191     } else if (QGesture *g = qobject_cast<QGesture *>(object)) {
192         return g;
193 #if QT_CONFIG(graphicsview)
194     } else {
195         Q_ASSERT(qobject_cast<QGraphicsObject *>(object));
196         QGraphicsObject *graphicsObject = static_cast<QGraphicsObject *>(object);
197         if (graphicsObject->QGraphicsItem::d_func()->inDestructor)
198             return nullptr;
199 #endif
200     }
201 
202     // check if the QGesture for this recognizer has already been created
203     const auto states = m_objectGestures.value(QGestureManager::ObjectGesture(object, type));
204     for (QGesture *state : states) {
205         if (m_gestureToRecognizer.value(state) == recognizer)
206             return state;
207     }
208 
209     Q_ASSERT(recognizer);
210     QGesture *state = recognizer->create(object);
211     if (!state)
212         return nullptr;
213     state->setParent(this);
214     if (state->gestureType() == Qt::CustomGesture) {
215         // if the recognizer didn't fill in the gesture type, then this
216         // is a custom gesture with autogenerated id and we fill it.
217         state->d_func()->gestureType = type;
218         if (lcGestureManager().isDebugEnabled())
219             state->setObjectName(QString::number((int)type));
220     }
221     m_objectGestures[QGestureManager::ObjectGesture(object, type)].append(state);
222     m_gestureToRecognizer[state] = recognizer;
223     m_gestureOwners[state] = object;
224 
225     return state;
226 }
227 
logIgnoredEvent(QEvent::Type t)228 static bool logIgnoredEvent(QEvent::Type t)
229 {
230     bool result = false;
231     switch (t) {
232     case QEvent::MouseButtonPress:
233     case QEvent::MouseButtonRelease:
234     case QEvent::MouseButtonDblClick:
235     case QEvent::MouseMove:
236     case QEvent::TouchBegin:
237     case QEvent::TouchUpdate:
238     case QEvent::TouchCancel:
239     case QEvent::TouchEnd:
240     case QEvent::TabletEnterProximity:
241     case QEvent::TabletLeaveProximity:
242     case QEvent::TabletMove:
243     case QEvent::TabletPress:
244     case QEvent::TabletRelease:
245     case QEvent::GraphicsSceneMouseDoubleClick:
246     case QEvent::GraphicsSceneMousePress:
247     case QEvent::GraphicsSceneMouseRelease:
248     case QEvent::GraphicsSceneMouseMove:
249         result = true;
250         break;
251     default:
252         break;
253 
254     }
255     return result;
256 }
257 
filterEventThroughContexts(const QMultiMap<QObject *,Qt::GestureType> & contexts,QEvent * event)258 bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *,
259                                                  Qt::GestureType> &contexts,
260                                                  QEvent *event)
261 {
262     QSet<QGesture *> triggeredGestures;
263     QSet<QGesture *> finishedGestures;
264     QSet<QGesture *> newMaybeGestures;
265     QSet<QGesture *> notGestures;
266 
267     // TODO: sort contexts by the gesture type and check if one of the contexts
268     //       is already active.
269 
270     bool consumeEventHint = false;
271 
272     // filter the event through recognizers
273     typedef QMultiMap<QObject *, Qt::GestureType>::const_iterator ContextIterator;
274     ContextIterator contextEnd = contexts.end();
275     for (ContextIterator context = contexts.begin(); context != contextEnd; ++context) {
276         Qt::GestureType gestureType = context.value();
277         const QMap<Qt::GestureType, QGestureRecognizer *> &const_recognizers = m_recognizers;
278         QMap<Qt::GestureType, QGestureRecognizer *>::const_iterator
279                 typeToRecognizerIterator = const_recognizers.lowerBound(gestureType),
280                 typeToRecognizerEnd = const_recognizers.upperBound(gestureType);
281         for (; typeToRecognizerIterator != typeToRecognizerEnd; ++typeToRecognizerIterator) {
282             QGestureRecognizer *recognizer = typeToRecognizerIterator.value();
283             QObject *target = context.key();
284             QGesture *state = getState(target, recognizer, gestureType);
285             if (!state)
286                 continue;
287             QGestureRecognizer::Result recognizerResult = recognizer->recognize(state, target, event);
288             QGestureRecognizer::Result recognizerState = recognizerResult & QGestureRecognizer::ResultState_Mask;
289             QGestureRecognizer::Result resultHint = recognizerResult & QGestureRecognizer::ResultHint_Mask;
290             if (recognizerState == QGestureRecognizer::TriggerGesture) {
291                 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: gesture triggered: " << state << event;
292                 triggeredGestures << state;
293             } else if (recognizerState == QGestureRecognizer::FinishGesture) {
294                 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: gesture finished: " << state << event;
295                 finishedGestures << state;
296             } else if (recognizerState == QGestureRecognizer::MayBeGesture) {
297                 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: maybe gesture: " << state << event;
298                 newMaybeGestures << state;
299             } else if (recognizerState == QGestureRecognizer::CancelGesture) {
300                 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: not gesture: " << state << event;
301                 notGestures << state;
302             } else if (recognizerState == QGestureRecognizer::Ignore) {
303                 if (logIgnoredEvent(event->type()))
304                     qCDebug(lcGestureManager) << "QGestureManager:Recognizer: ignored the event: " << state << event;
305             } else {
306                 if (logIgnoredEvent(event->type())) {
307                     qCDebug(lcGestureManager) << "QGestureManager:Recognizer: hm, lets assume the recognizer"
308                         << "ignored the event: " << state << event;
309                 }
310             }
311             if (resultHint & QGestureRecognizer::ConsumeEventHint) {
312                 qCDebug(lcGestureManager) << "QGestureManager: we were asked to consume the event: "
313                         << state << event;
314                 consumeEventHint = true;
315             }
316         }
317     }
318     if (!triggeredGestures.isEmpty() || !finishedGestures.isEmpty()
319         || !newMaybeGestures.isEmpty() || !notGestures.isEmpty()) {
320         QSet<QGesture *> startedGestures = triggeredGestures - m_activeGestures;
321         triggeredGestures &= m_activeGestures;
322 
323         // check if a running gesture switched back to maybe state
324         QSet<QGesture *> activeToMaybeGestures = m_activeGestures & newMaybeGestures;
325 
326         // check if a maybe gesture switched to canceled - reset it but don't send an event
327         QSet<QGesture *> maybeToCanceledGestures = m_maybeGestures & notGestures;
328 
329         // check if a running gesture switched back to not gesture state,
330         // i.e. were canceled
331         QSet<QGesture *> canceledGestures = m_activeGestures & notGestures;
332 
333         // new gestures in maybe state
334         m_maybeGestures += newMaybeGestures;
335 
336         // gestures that were in maybe state
337         QSet<QGesture *> notMaybeGestures = (startedGestures | triggeredGestures
338                                              | finishedGestures | canceledGestures
339                                              | notGestures);
340         m_maybeGestures -= notMaybeGestures;
341 
342         Q_ASSERT((startedGestures & finishedGestures).isEmpty());
343         Q_ASSERT((startedGestures & newMaybeGestures).isEmpty());
344         Q_ASSERT((startedGestures & canceledGestures).isEmpty());
345         Q_ASSERT((finishedGestures & newMaybeGestures).isEmpty());
346         Q_ASSERT((finishedGestures & canceledGestures).isEmpty());
347         Q_ASSERT((canceledGestures & newMaybeGestures).isEmpty());
348 
349         QSet<QGesture *> notStarted = finishedGestures - m_activeGestures;
350         if (!notStarted.isEmpty()) {
351             // there are some gestures that claim to be finished, but never started.
352             // probably those are "singleshot" gestures so we'll fake the started state.
353             foreach (QGesture *gesture, notStarted)
354                 gesture->d_func()->state = Qt::GestureStarted;
355             QSet<QGesture *> undeliveredGestures;
356             deliverEvents(notStarted, &undeliveredGestures);
357             finishedGestures -= undeliveredGestures;
358         }
359 
360         m_activeGestures += startedGestures;
361         // sanity check: all triggered gestures should already be in active gestures list
362         Q_ASSERT((m_activeGestures & triggeredGestures).size() == triggeredGestures.size());
363         m_activeGestures -= finishedGestures;
364         m_activeGestures -= activeToMaybeGestures;
365         m_activeGestures -= canceledGestures;
366 
367         // set the proper gesture state on each gesture
368         foreach (QGesture *gesture, startedGestures)
369             gesture->d_func()->state = Qt::GestureStarted;
370         foreach (QGesture *gesture, triggeredGestures)
371             gesture->d_func()->state = Qt::GestureUpdated;
372         foreach (QGesture *gesture, finishedGestures)
373             gesture->d_func()->state = Qt::GestureFinished;
374         foreach (QGesture *gesture, canceledGestures)
375             gesture->d_func()->state = Qt::GestureCanceled;
376         foreach (QGesture *gesture, activeToMaybeGestures)
377             gesture->d_func()->state = Qt::GestureFinished;
378 
379         if (!m_activeGestures.isEmpty() || !m_maybeGestures.isEmpty() ||
380             !startedGestures.isEmpty() || !triggeredGestures.isEmpty() ||
381             !finishedGestures.isEmpty() || !canceledGestures.isEmpty()) {
382             qCDebug(lcGestureManager) << "QGestureManager::filterEventThroughContexts:"
383                     << "\n\tactiveGestures:" << m_activeGestures
384                     << "\n\tmaybeGestures:" << m_maybeGestures
385                     << "\n\tstarted:" << startedGestures
386                     << "\n\ttriggered:" << triggeredGestures
387                     << "\n\tfinished:" << finishedGestures
388                     << "\n\tcanceled:" << canceledGestures
389                     << "\n\tmaybe-canceled:" << maybeToCanceledGestures;
390         }
391 
392         QSet<QGesture *> undeliveredGestures;
393         deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures,
394                       &undeliveredGestures);
395 
396         foreach (QGesture *g, startedGestures) {
397             if (undeliveredGestures.contains(g))
398                 continue;
399             if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
400                 qCDebug(lcGestureManager) << "lets try to cancel some";
401                 // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
402                 cancelGesturesForChildren(g);
403             }
404         }
405 
406         m_activeGestures -= undeliveredGestures;
407 
408         // reset gestures that ended
409         QSet<QGesture *> endedGestures =
410                 finishedGestures + canceledGestures + undeliveredGestures + maybeToCanceledGestures;
411         foreach (QGesture *gesture, endedGestures) {
412             recycle(gesture);
413             m_gestureTargets.remove(gesture);
414         }
415     }
416     //Clean up the Gestures
417     qDeleteAll(m_gesturesToDelete);
418     m_gesturesToDelete.clear();
419 
420     return consumeEventHint;
421 }
422 
423 // Cancel all gestures of children of the widget that original is associated with
cancelGesturesForChildren(QGesture * original)424 void QGestureManager::cancelGesturesForChildren(QGesture *original)
425 {
426     Q_ASSERT(original);
427     QWidget *originatingWidget = m_gestureTargets.value(original);
428     Q_ASSERT(originatingWidget);
429     if (!originatingWidget)
430         return;
431 
432     // iterate over all active gestures and all maybe gestures
433     // for each find the owner
434     // if the owner is part of our sub-hierarchy, cancel it.
435 
436     QSet<QGesture*> cancelledGestures;
437     QSet<QGesture*>::Iterator iter = m_activeGestures.begin();
438     while (iter != m_activeGestures.end()) {
439         QWidget *widget = m_gestureTargets.value(*iter);
440         // note that we don't touch the gestures for our originatingWidget
441         if (widget != originatingWidget && originatingWidget->isAncestorOf(widget)) {
442             qCDebug(lcGestureManager) << "  found a gesture to cancel" << (*iter);
443             (*iter)->d_func()->state = Qt::GestureCanceled;
444             cancelledGestures << *iter;
445             iter = m_activeGestures.erase(iter);
446         } else {
447             ++iter;
448         }
449     }
450 
451     // TODO handle 'maybe' gestures too
452 
453     // sort them per target widget by cherry picking from almostCanceledGestures and delivering
454     QSet<QGesture *> almostCanceledGestures = cancelledGestures;
455     while (!almostCanceledGestures.isEmpty()) {
456         QWidget *target = nullptr;
457         QSet<QGesture*> gestures;
458         iter = almostCanceledGestures.begin();
459         // sort per target widget
460         while (iter != almostCanceledGestures.end()) {
461             QWidget *widget = m_gestureTargets.value(*iter);
462             if (target == nullptr)
463                 target = widget;
464             if (target == widget) {
465                 gestures << *iter;
466                 iter = almostCanceledGestures.erase(iter);
467             } else {
468                 ++iter;
469             }
470         }
471         Q_ASSERT(target);
472 
473         QSet<QGesture*> undeliveredGestures;
474         deliverEvents(gestures, &undeliveredGestures);
475     }
476 
477     for (iter = cancelledGestures.begin(); iter != cancelledGestures.end(); ++iter)
478         recycle(*iter);
479 }
480 
cleanupGesturesForRemovedRecognizer(QGesture * gesture)481 void QGestureManager::cleanupGesturesForRemovedRecognizer(QGesture *gesture)
482 {
483     QGestureRecognizer *recognizer = m_deletedRecognizers.value(gesture);
484     if(!recognizer) //The Gesture is removed while in the even loop, so the recognizers for this gestures was removed
485         return;
486     m_deletedRecognizers.remove(gesture);
487     if (m_deletedRecognizers.keys(recognizer).isEmpty()) {
488         // no more active gestures, cleanup!
489         qDeleteAll(m_obsoleteGestures.value(recognizer));
490         m_obsoleteGestures.remove(recognizer);
491         delete recognizer;
492     }
493 }
494 
495 // return true if accepted (consumed)
filterEvent(QWidget * receiver,QEvent * event)496 bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event)
497 {
498     QVarLengthArray<Qt::GestureType, 16> types;
499     QMultiMap<QObject *, Qt::GestureType> contexts;
500     QWidget *w = receiver;
501     typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator;
502     if (!w->d_func()->gestureContext.isEmpty()) {
503         for(ContextIterator it = w->d_func()->gestureContext.constBegin(),
504             e = w->d_func()->gestureContext.constEnd(); it != e; ++it) {
505             types.push_back(it.key());
506             contexts.insert(w, it.key());
507         }
508     }
509     // find all gesture contexts for the widget tree
510     w = w->isWindow() ? nullptr : w->parentWidget();
511     while (w)
512     {
513         for (ContextIterator it = w->d_func()->gestureContext.constBegin(),
514              e = w->d_func()->gestureContext.constEnd(); it != e; ++it) {
515             if (!(it.value() & Qt::DontStartGestureOnChildren)) {
516                 if (!types.contains(it.key())) {
517                     types.push_back(it.key());
518                     contexts.insert(w, it.key());
519                 }
520             }
521         }
522         if (w->isWindow())
523             break;
524         w = w->parentWidget();
525     }
526     return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event);
527 }
528 
529 #if QT_CONFIG(graphicsview)
filterEvent(QGraphicsObject * receiver,QEvent * event)530 bool QGestureManager::filterEvent(QGraphicsObject *receiver, QEvent *event)
531 {
532     QVarLengthArray<Qt::GestureType, 16> types;
533     QMultiMap<QObject *, Qt::GestureType> contexts;
534     QGraphicsObject *item = receiver;
535     if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) {
536         typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator;
537         for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.constBegin(),
538             e = item->QGraphicsItem::d_func()->gestureContext.constEnd(); it != e; ++it) {
539             types.push_back(it.key());
540             contexts.insert(item, it.key());
541         }
542     }
543     // find all gesture contexts for the graphics object tree
544     item = item->parentObject();
545     while (item)
546     {
547         typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator;
548         for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.constBegin(),
549              e = item->QGraphicsItem::d_func()->gestureContext.constEnd(); it != e; ++it) {
550             if (!(it.value() & Qt::DontStartGestureOnChildren)) {
551                 if (!types.contains(it.key())) {
552                     types.push_back(it.key());
553                     contexts.insert(item, it.key());
554                 }
555             }
556         }
557         item = item->parentObject();
558     }
559     return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event);
560 }
561 #endif
562 
filterEvent(QObject * receiver,QEvent * event)563 bool QGestureManager::filterEvent(QObject *receiver, QEvent *event)
564 {
565     // if the receiver is actually a widget, we need to call the correct event
566     // filter method.
567     QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(receiver);
568 
569     if (widgetWindow && widgetWindow->widget())
570         return filterEvent(widgetWindow->widget(), event);
571 
572     QGesture *state = qobject_cast<QGesture *>(receiver);
573     if (!state || !m_gestureToRecognizer.contains(state))
574         return false;
575     QMultiMap<QObject *, Qt::GestureType> contexts;
576     contexts.insert(state, state->gestureType());
577     return filterEventThroughContexts(contexts, event);
578 }
579 
getGestureTargets(const QSet<QGesture * > & gestures,QHash<QWidget *,QList<QGesture * >> * conflicts,QHash<QWidget *,QList<QGesture * >> * normal)580 void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures,
581     QHash<QWidget *, QList<QGesture *> > *conflicts,
582     QHash<QWidget *, QList<QGesture *> > *normal)
583 {
584     typedef QHash<Qt::GestureType, QHash<QWidget *, QGesture *> > GestureByTypes;
585     GestureByTypes gestureByTypes;
586 
587     // sort gestures by types
588     foreach (QGesture *gesture, gestures) {
589         QWidget *receiver = m_gestureTargets.value(gesture, nullptr);
590         Q_ASSERT(receiver);
591         if (receiver)
592             gestureByTypes[gesture->gestureType()].insert(receiver, gesture);
593     }
594 
595     // for each gesture type
596     for (GestureByTypes::const_iterator git = gestureByTypes.cbegin(), gend = gestureByTypes.cend(); git != gend; ++git) {
597         const QHash<QWidget *, QGesture *> &gestures = git.value();
598         for (QHash<QWidget *, QGesture *>::const_iterator wit = gestures.cbegin(), wend = gestures.cend(); wit != wend; ++wit) {
599             QWidget *widget = wit.key();
600             QWidget *w = widget->parentWidget();
601             while (w) {
602                 QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator it
603                         = w->d_func()->gestureContext.constFind(git.key());
604                 if (it != w->d_func()->gestureContext.constEnd()) {
605                     // i.e. 'w' listens to gesture 'type'
606                     if (!(it.value() & Qt::DontStartGestureOnChildren) && w != widget) {
607                         // conflicting gesture!
608                         (*conflicts)[widget].append(wit.value());
609                         break;
610                     }
611                 }
612                 if (w->isWindow()) {
613                     w = nullptr;
614                     break;
615                 }
616                 w = w->parentWidget();
617             }
618             if (!w)
619                 (*normal)[widget].append(wit.value());
620         }
621     }
622 }
623 
deliverEvents(const QSet<QGesture * > & gestures,QSet<QGesture * > * undeliveredGestures)624 void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
625                                     QSet<QGesture *> *undeliveredGestures)
626 {
627     if (gestures.isEmpty())
628         return;
629 
630     typedef QHash<QWidget *, QList<QGesture *> > GesturesPerWidget;
631     GesturesPerWidget conflictedGestures;
632     GesturesPerWidget normalStartedGestures;
633 
634     QSet<QGesture *> startedGestures;
635     // first figure out the initial receivers of gestures
636     for (QSet<QGesture *>::const_iterator it = gestures.begin(),
637          e = gestures.end(); it != e; ++it) {
638         QGesture *gesture = *it;
639         QWidget *target = m_gestureTargets.value(gesture, nullptr);
640         if (!target) {
641             // the gesture has just started and doesn't have a target yet.
642             Q_ASSERT(gesture->state() == Qt::GestureStarted);
643             if (gesture->hasHotSpot()) {
644                 // guess the target widget using the hotspot of the gesture
645                 QPoint pt = gesture->hotSpot().toPoint();
646                 if (QWidget *topLevel = QApplication::topLevelAt(pt)) {
647                     QWidget *child = topLevel->childAt(topLevel->mapFromGlobal(pt));
648                     target = child ? child : topLevel;
649                 }
650             } else {
651                 // or use the context of the gesture
652                 QObject *context = m_gestureOwners.value(gesture, 0);
653                 if (context->isWidgetType())
654                     target = static_cast<QWidget *>(context);
655             }
656             if (target)
657                 m_gestureTargets.insert(gesture, target);
658         }
659 
660         Qt::GestureType gestureType = gesture->gestureType();
661         Q_ASSERT(gestureType != Qt::CustomGesture);
662         Q_UNUSED(gestureType);
663 
664         if (Q_UNLIKELY(!target)) {
665             qCDebug(lcGestureManager) << "QGestureManager::deliverEvent: could not find the target for gesture"
666                     << gesture->gestureType();
667             qWarning("QGestureManager::deliverEvent: could not find the target for gesture");
668             undeliveredGestures->insert(gesture);
669         } else {
670             if (gesture->state() == Qt::GestureStarted) {
671                 startedGestures.insert(gesture);
672             } else {
673                 normalStartedGestures[target].append(gesture);
674             }
675         }
676     }
677 
678     getGestureTargets(startedGestures, &conflictedGestures, &normalStartedGestures);
679     qCDebug(lcGestureManager) << "QGestureManager::deliverEvents:"
680             << "\nstarted: " << startedGestures
681             << "\nconflicted: " << conflictedGestures
682             << "\nnormal: " << normalStartedGestures
683             << "\n";
684 
685     // if there are conflicting gestures, send the GestureOverride event
686     for (GesturesPerWidget::const_iterator it = conflictedGestures.constBegin(),
687         e = conflictedGestures.constEnd(); it != e; ++it) {
688         QWidget *receiver = it.key();
689         QList<QGesture *> gestures = it.value();
690         qCDebug(lcGestureManager) << "QGestureManager::deliverEvents: sending GestureOverride to"
691                 << receiver
692                 << "gestures:" << gestures;
693         QGestureEvent event(gestures);
694         event.t = QEvent::GestureOverride;
695         // mark event and individual gestures as ignored
696         event.ignore();
697         foreach(QGesture *g, gestures)
698             event.setAccepted(g, false);
699 
700         QCoreApplication::sendEvent(receiver, &event);
701         bool eventAccepted = event.isAccepted();
702         const auto eventGestures = event.gestures();
703         for (QGesture *gesture : eventGestures) {
704             if (eventAccepted || event.isAccepted(gesture)) {
705                 QWidget *w = event.m_targetWidgets.value(gesture->gestureType(), 0);
706                 Q_ASSERT(w);
707                 qCDebug(lcGestureManager) << "override event: gesture was accepted:" << gesture << w;
708                 QList<QGesture *> &gestures = normalStartedGestures[w];
709                 gestures.append(gesture);
710                 // override the target
711                 m_gestureTargets[gesture] = w;
712             } else {
713                 qCDebug(lcGestureManager) << "override event: gesture wasn't accepted. putting back:" << gesture;
714                 QList<QGesture *> &gestures = normalStartedGestures[receiver];
715                 gestures.append(gesture);
716             }
717         }
718     }
719 
720     // delivering gestures that are not in conflicted state
721     for (GesturesPerWidget::const_iterator it = normalStartedGestures.constBegin(),
722         e = normalStartedGestures.constEnd(); it != e; ++it) {
723         if (!it.value().isEmpty()) {
724             qCDebug(lcGestureManager) << "QGestureManager::deliverEvents: sending to" << it.key()
725                     << "gestures:" << it.value();
726             QGestureEvent event(it.value());
727             QCoreApplication::sendEvent(it.key(), &event);
728             bool eventAccepted = event.isAccepted();
729             const auto eventGestures = event.gestures();
730             for (QGesture *gesture : eventGestures) {
731                 if (gesture->state() == Qt::GestureStarted &&
732                     (eventAccepted || event.isAccepted(gesture))) {
733                     QWidget *w = event.m_targetWidgets.value(gesture->gestureType(), 0);
734                     Q_ASSERT(w);
735                     qCDebug(lcGestureManager) << "started gesture was delivered and accepted by" << w;
736                     m_gestureTargets[gesture] = w;
737                 }
738             }
739         }
740     }
741 }
742 
recycle(QGesture * gesture)743 void QGestureManager::recycle(QGesture *gesture)
744 {
745     QGestureRecognizer *recognizer = m_gestureToRecognizer.value(gesture, 0);
746     if (recognizer) {
747         gesture->setGestureCancelPolicy(QGesture::CancelNone);
748         recognizer->reset(gesture);
749         m_activeGestures.remove(gesture);
750     } else {
751         cleanupGesturesForRemovedRecognizer(gesture);
752     }
753 }
754 
gesturePending(QObject * o)755 bool QGestureManager::gesturePending(QObject *o)
756 {
757     const QGestureManager *gm = QGestureManager::instance(DontForceCreation);
758     return gm && gm->m_gestureOwners.key(o);
759 }
760 
761 QT_END_NAMESPACE
762 
763 #endif // QT_NO_GESTURES
764 
765 #include "moc_qgesturemanager_p.cpp"
766