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

source code of qtbase/src/widgets/kernel/qgesturemanager.cpp