Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qgesturemanager.cpp
Go to the documentation of this file.
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
20#endif
21
22#include "qdebug.h"
23#include <QtCore/QLoggingCategory>
24#include <QtCore/QVarLengthArray>
25
26#ifndef QT_NO_GESTURES
27
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(panTouchPointVariable)) {
38 bool ok;
39 const int result = qEnvironmentVariableIntValue(panTouchPointVariable, &ok);
40 if (ok && result >= 1)
41 return result;
42 qWarning("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
53 : QObject(parent), m_lastCustomGestureId(Qt::CustomGesture)
54{
55 qRegisterMetaType<Qt::GestureState>();
56
57#if defined(Q_OS_MACOS)
61#else
66#endif
68}
69
71{
72 qDeleteAll(m_recognizers);
73 for (auto it = m_obsoleteGestures.cbegin(), end = m_obsoleteGestures.cend(); it != end; ++it) {
74 qDeleteAll(it.value());
75 delete it.key();
76 }
77}
78
80{
81 const QScopedPointer<QGesture> dummy(recognizer->create(nullptr));
82 if (Q_UNLIKELY(!dummy)) {
83 qWarning("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(type, recognizer);
94 return type;
95}
96
98{
100 m_recognizers.remove(type);
101 foreach (QGesture *g, m_gestureToRecognizer.keys()) {
102 QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g);
103 if (list.contains(recognizer)) {
104 m_deletedRecognizers.insert(g, 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 if (QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g)) {
114 m_gestureToRecognizer.remove(g);
115 m_obsoleteGestures[recognizer].insert(g);
116 }
117 }
118 }
119 ++iter;
120 }
121}
122
124{
125 const auto iter = m_objectGestures.find({target, type});
126 if (iter == m_objectGestures.end())
127 return;
128
129 const QList<QGesture *> &gestures = iter.value();
130 for (auto &e : m_obsoleteGestures) {
131 for (QGesture *g : gestures)
132 e -= g;
133 }
134 for (QGesture *g : gestures) {
135 m_deletedRecognizers.remove(g);
136 m_gestureToRecognizer.remove(g);
137 m_maybeGestures.remove(g);
138 m_activeGestures.remove(g);
139 m_gestureOwners.remove(g);
140 m_gestureTargets.remove(g);
141 m_gesturesToDelete.insert(g);
142 }
143
144 m_objectGestures.erase(iter);
145}
146
147// get or create a QGesture object that will represent the state for a given object, used by the recognizer
148QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recognizer, Qt::GestureType type)
149{
150 // if the widget is being deleted we should be careful not to
151 // create a new state, as it will create QWeakPointer which doesn't work
152 // from the destructor.
153 if (object->isWidgetType()) {
154 if (static_cast<QWidget *>(object)->d_func()->data.in_destructor)
155 return nullptr;
156 } else if (QGesture *g = qobject_cast<QGesture *>(object)) {
157 return g;
158#if QT_CONFIG(graphicsview)
159 } else {
160 Q_ASSERT(qobject_cast<QGraphicsObject *>(object));
161 QGraphicsObject *graphicsObject = static_cast<QGraphicsObject *>(object);
162 if (graphicsObject->QGraphicsItem::d_func()->inDestructor)
163 return nullptr;
164#endif
165 }
166
167 // check if the QGesture for this recognizer has already been created
168 const auto states = m_objectGestures.value(QGestureManager::ObjectGesture(object, type));
169 for (QGesture *state : states) {
170 if (m_gestureToRecognizer.value(state) == recognizer)
171 return state;
172 }
173
174 Q_ASSERT(recognizer);
175 QGesture *state = recognizer->create(object);
176 if (!state)
177 return nullptr;
178 state->setParent(this);
179 if (state->gestureType() == Qt::CustomGesture) {
180 // if the recognizer didn't fill in the gesture type, then this
181 // is a custom gesture with autogenerated id and we fill it.
182 state->d_func()->gestureType = type;
183 if (lcGestureManager().isDebugEnabled())
184 state->setObjectName(QString::number((int)type));
185 }
186 m_objectGestures[QGestureManager::ObjectGesture(object, type)].append(state);
187 m_gestureToRecognizer[state] = recognizer;
188 m_gestureOwners[state] = object;
189
190 return state;
191}
192
194{
195 bool result = false;
196 switch (t) {
204 case QEvent::TouchEnd:
214 result = true;
215 break;
216 default:
217 break;
218
219 }
220 return result;
221}
222
224 Qt::GestureType> &contexts,
225 QEvent *event)
226{
227 QSet<QGesture *> triggeredGestures;
228 QSet<QGesture *> finishedGestures;
229 QSet<QGesture *> newMaybeGestures;
230 QSet<QGesture *> notGestures;
231
232 // TODO: sort contexts by the gesture type and check if one of the contexts
233 // is already active.
234
235 bool consumeEventHint = false;
236
237 // filter the event through recognizers
239 ContextIterator contextEnd = contexts.end();
240 for (ContextIterator context = contexts.begin(); context != contextEnd; ++context) {
241 Qt::GestureType gestureType = context.value();
242 const QMultiMap<Qt::GestureType, QGestureRecognizer *> &const_recognizers = m_recognizers;
244 typeToRecognizerIterator = const_recognizers.lowerBound(gestureType),
245 typeToRecognizerEnd = const_recognizers.upperBound(gestureType);
246 for (; typeToRecognizerIterator != typeToRecognizerEnd; ++typeToRecognizerIterator) {
247 QGestureRecognizer *recognizer = typeToRecognizerIterator.value();
248 QObject *target = context.key();
249 QGesture *state = getState(target, recognizer, gestureType);
250 if (!state)
251 continue;
252 QGestureRecognizer::Result recognizerResult = recognizer->recognize(state, target, event);
253 QGestureRecognizer::Result recognizerState = recognizerResult & QGestureRecognizer::ResultState_Mask;
254 QGestureRecognizer::Result resultHint = recognizerResult & QGestureRecognizer::ResultHint_Mask;
255 if (recognizerState == QGestureRecognizer::TriggerGesture) {
256 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: gesture triggered: " << state << event;
257 triggeredGestures << state;
258 } else if (recognizerState == QGestureRecognizer::FinishGesture) {
259 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: gesture finished: " << state << event;
260 finishedGestures << state;
261 } else if (recognizerState == QGestureRecognizer::MayBeGesture) {
262 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: maybe gesture: " << state << event;
263 newMaybeGestures << state;
264 } else if (recognizerState == QGestureRecognizer::CancelGesture) {
265 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: not gesture: " << state << event;
266 notGestures << state;
267 } else if (recognizerState == QGestureRecognizer::Ignore) {
268 if (logIgnoredEvent(event->type()))
269 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: ignored the event: " << state << event;
270 } else {
271 if (logIgnoredEvent(event->type())) {
272 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: hm, lets assume the recognizer"
273 << "ignored the event: " << state << event;
274 }
275 }
276 if (resultHint & QGestureRecognizer::ConsumeEventHint) {
277 qCDebug(lcGestureManager) << "QGestureManager: we were asked to consume the event: "
278 << state << event;
279 consumeEventHint = true;
280 }
281 }
282 }
283 if (!triggeredGestures.isEmpty() || !finishedGestures.isEmpty()
284 || !newMaybeGestures.isEmpty() || !notGestures.isEmpty()) {
285 QSet<QGesture *> startedGestures = triggeredGestures - m_activeGestures;
286 triggeredGestures &= m_activeGestures;
287
288 // check if a running gesture switched back to maybe state
289 QSet<QGesture *> activeToMaybeGestures = m_activeGestures & newMaybeGestures;
290
291 // check if a maybe gesture switched to canceled - reset it but don't send an event
292 QSet<QGesture *> maybeToCanceledGestures = m_maybeGestures & notGestures;
293
294 // check if a running gesture switched back to not gesture state,
295 // i.e. were canceled
296 QSet<QGesture *> canceledGestures = m_activeGestures & notGestures;
297
298 // new gestures in maybe state
299 m_maybeGestures += newMaybeGestures;
300
301 // gestures that were in maybe state
302 QSet<QGesture *> notMaybeGestures = (startedGestures | triggeredGestures
303 | finishedGestures | canceledGestures
304 | notGestures);
305 m_maybeGestures -= notMaybeGestures;
306
307 Q_ASSERT((startedGestures & finishedGestures).isEmpty());
308 Q_ASSERT((startedGestures & newMaybeGestures).isEmpty());
309 Q_ASSERT((startedGestures & canceledGestures).isEmpty());
310 Q_ASSERT((finishedGestures & newMaybeGestures).isEmpty());
311 Q_ASSERT((finishedGestures & canceledGestures).isEmpty());
312 Q_ASSERT((canceledGestures & newMaybeGestures).isEmpty());
313
314 QSet<QGesture *> notStarted = finishedGestures - m_activeGestures;
315 if (!notStarted.isEmpty()) {
316 // there are some gestures that claim to be finished, but never started.
317 // probably those are "singleshot" gestures so we'll fake the started state.
318 foreach (QGesture *gesture, notStarted)
319 gesture->d_func()->state = Qt::GestureStarted;
320 QSet<QGesture *> undeliveredGestures;
321 deliverEvents(notStarted, &undeliveredGestures);
322 finishedGestures -= undeliveredGestures;
323 }
324
325 m_activeGestures += startedGestures;
326 // sanity check: all triggered gestures should already be in active gestures list
327 Q_ASSERT((m_activeGestures & triggeredGestures).size() == triggeredGestures.size());
328 m_activeGestures -= finishedGestures;
329 m_activeGestures -= activeToMaybeGestures;
330 m_activeGestures -= canceledGestures;
331
332 // set the proper gesture state on each gesture
333 foreach (QGesture *gesture, startedGestures)
334 gesture->d_func()->state = Qt::GestureStarted;
335 foreach (QGesture *gesture, triggeredGestures)
336 gesture->d_func()->state = Qt::GestureUpdated;
337 foreach (QGesture *gesture, finishedGestures)
338 gesture->d_func()->state = Qt::GestureFinished;
339 foreach (QGesture *gesture, canceledGestures)
340 gesture->d_func()->state = Qt::GestureCanceled;
341 foreach (QGesture *gesture, activeToMaybeGestures)
342 gesture->d_func()->state = Qt::GestureFinished;
343
344 if (!m_activeGestures.isEmpty() || !m_maybeGestures.isEmpty() ||
345 !startedGestures.isEmpty() || !triggeredGestures.isEmpty() ||
346 !finishedGestures.isEmpty() || !canceledGestures.isEmpty()) {
347 qCDebug(lcGestureManager) << "QGestureManager::filterEventThroughContexts:"
348 << "\n\tactiveGestures:" << m_activeGestures
349 << "\n\tmaybeGestures:" << m_maybeGestures
350 << "\n\tstarted:" << startedGestures
351 << "\n\ttriggered:" << triggeredGestures
352 << "\n\tfinished:" << finishedGestures
353 << "\n\tcanceled:" << canceledGestures
354 << "\n\tmaybe-canceled:" << maybeToCanceledGestures;
355 }
356
357 QSet<QGesture *> undeliveredGestures;
358 deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures,
359 &undeliveredGestures);
360
361 foreach (QGesture *g, startedGestures) {
362 if (undeliveredGestures.contains(g))
363 continue;
364 if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
365 qCDebug(lcGestureManager) << "lets try to cancel some";
366 // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
367 cancelGesturesForChildren(g);
368 }
369 }
370
371 m_activeGestures -= undeliveredGestures;
372
373 // reset gestures that ended
374 QSet<QGesture *> endedGestures =
375 finishedGestures + canceledGestures + undeliveredGestures + maybeToCanceledGestures;
376 foreach (QGesture *gesture, endedGestures) {
377 recycle(gesture);
378 m_gestureTargets.remove(gesture);
379 }
380 }
381 //Clean up the Gestures
382 qDeleteAll(m_gesturesToDelete);
383 m_gesturesToDelete.clear();
384
385 return consumeEventHint;
386}
387
388// Cancel all gestures of children of the widget that original is associated with
389void QGestureManager::cancelGesturesForChildren(QGesture *original)
390{
391 Q_ASSERT(original);
392 QWidget *originatingWidget = m_gestureTargets.value(original);
393 Q_ASSERT(originatingWidget);
394 if (!originatingWidget)
395 return;
396
397 // iterate over all active gestures and all maybe gestures
398 // for each find the owner
399 // if the owner is part of our sub-hierarchy, cancel it.
400
401 QSet<QGesture*> cancelledGestures;
402 QSet<QGesture*>::Iterator iter = m_activeGestures.begin();
403 while (iter != m_activeGestures.end()) {
404 QWidget *widget = m_gestureTargets.value(*iter);
405 // note that we don't touch the gestures for our originatingWidget
406 if (widget != originatingWidget && originatingWidget->isAncestorOf(widget)) {
407 qCDebug(lcGestureManager) << " found a gesture to cancel" << (*iter);
408 (*iter)->d_func()->state = Qt::GestureCanceled;
409 cancelledGestures << *iter;
410 iter = m_activeGestures.erase(iter);
411 } else {
412 ++iter;
413 }
414 }
415
416 // TODO handle 'maybe' gestures too
417
418 // sort them per target widget by cherry picking from almostCanceledGestures and delivering
419 QSet<QGesture *> almostCanceledGestures = cancelledGestures;
420 while (!almostCanceledGestures.isEmpty()) {
421 QWidget *target = nullptr;
422 QSet<QGesture*> gestures;
423 iter = almostCanceledGestures.begin();
424 // sort per target widget
425 while (iter != almostCanceledGestures.end()) {
426 QWidget *widget = m_gestureTargets.value(*iter);
427 if (target == nullptr)
428 target = widget;
429 if (target == widget) {
430 gestures << *iter;
431 iter = almostCanceledGestures.erase(iter);
432 } else {
433 ++iter;
434 }
435 }
437
438 QSet<QGesture*> undeliveredGestures;
439 deliverEvents(gestures, &undeliveredGestures);
440 }
441
442 for (iter = cancelledGestures.begin(); iter != cancelledGestures.end(); ++iter)
443 recycle(*iter);
444}
445
446void QGestureManager::cleanupGesturesForRemovedRecognizer(QGesture *gesture)
447{
448 QGestureRecognizer *recognizer = m_deletedRecognizers.value(gesture);
449 if (!recognizer) //The Gesture is removed while in the even loop, so the recognizers for this gestures was removed
450 return;
451 m_deletedRecognizers.remove(gesture);
452 if (m_deletedRecognizers.keys(recognizer).isEmpty()) {
453 // no more active gestures, cleanup!
454 qDeleteAll(m_obsoleteGestures.value(recognizer));
455 m_obsoleteGestures.remove(recognizer);
456 delete recognizer;
457 }
458}
459
460// return true if accepted (consumed)
462{
465 QWidget *w = receiver;
467 if (!w->d_func()->gestureContext.isEmpty()) {
468 for(ContextIterator it = w->d_func()->gestureContext.constBegin(),
469 e = w->d_func()->gestureContext.constEnd(); it != e; ++it) {
470 types.push_back(it.key());
471 contexts.insert(w, it.key());
472 }
473 }
474 // find all gesture contexts for the widget tree
475 w = w->isWindow() ? nullptr : w->parentWidget();
476 while (w)
477 {
478 for (ContextIterator it = w->d_func()->gestureContext.constBegin(),
479 e = w->d_func()->gestureContext.constEnd(); it != e; ++it) {
480 if (!(it.value() & Qt::DontStartGestureOnChildren)) {
481 if (!types.contains(it.key())) {
482 types.push_back(it.key());
483 contexts.insert(w, it.key());
484 }
485 }
486 }
487 if (w->isWindow())
488 break;
489 w = w->parentWidget();
490 }
491 return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event);
492}
493
494#if QT_CONFIG(graphicsview)
496{
499 QGraphicsObject *item = receiver;
500 if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) {
502 for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.constBegin(),
503 e = item->QGraphicsItem::d_func()->gestureContext.constEnd(); it != e; ++it) {
504 types.push_back(it.key());
505 contexts.insert(item, it.key());
506 }
507 }
508 // find all gesture contexts for the graphics object tree
510 while (item)
511 {
513 for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.constBegin(),
514 e = item->QGraphicsItem::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(item, it.key());
519 }
520 }
521 }
523 }
524 return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event);
525}
526#endif
527
529{
530 // if the receiver is actually a widget, we need to call the correct event
531 // filter method.
532 QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(receiver);
533
534 if (widgetWindow && widgetWindow->widget())
535 return filterEvent(widgetWindow->widget(), event);
536
537 QGesture *state = qobject_cast<QGesture *>(receiver);
538 if (!state || !m_gestureToRecognizer.contains(state))
539 return false;
541 contexts.insert(state, state->gestureType());
542 return filterEventThroughContexts(contexts, event);
543}
544
545void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures,
546 QHash<QWidget *, QList<QGesture *> > *conflicts,
547 QHash<QWidget *, QList<QGesture *> > *normal)
548{
550 GestureByTypes gestureByTypes;
551
552 // sort gestures by types
553 foreach (QGesture *gesture, gestures) {
554 QWidget *receiver = m_gestureTargets.value(gesture, nullptr);
555 Q_ASSERT(receiver);
556 if (receiver)
557 gestureByTypes[gesture->gestureType()].insert(receiver, gesture);
558 }
559
560 // for each gesture type
561 for (GestureByTypes::const_iterator git = gestureByTypes.cbegin(), gend = gestureByTypes.cend(); git != gend; ++git) {
562 const QHash<QWidget *, QGesture *> &gestures = git.value();
563 for (QHash<QWidget *, QGesture *>::const_iterator wit = gestures.cbegin(), wend = gestures.cend(); wit != wend; ++wit) {
564 QWidget *widget = wit.key();
566 while (w) {
568 = w->d_func()->gestureContext.constFind(git.key());
569 if (it != w->d_func()->gestureContext.constEnd()) {
570 // i.e. 'w' listens to gesture 'type'
571 if (!(it.value() & Qt::DontStartGestureOnChildren) && w != widget) {
572 // conflicting gesture!
573 (*conflicts)[widget].append(wit.value());
574 break;
575 }
576 }
577 if (w->isWindow()) {
578 w = nullptr;
579 break;
580 }
581 w = w->parentWidget();
582 }
583 if (!w)
584 (*normal)[widget].append(wit.value());
585 }
586 }
587}
588
589void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
590 QSet<QGesture *> *undeliveredGestures)
591{
592 if (gestures.isEmpty())
593 return;
594
595 typedef QHash<QWidget *, QList<QGesture *> > GesturesPerWidget;
596 GesturesPerWidget conflictedGestures;
597 GesturesPerWidget normalStartedGestures;
598
599 QSet<QGesture *> startedGestures;
600 // first figure out the initial receivers of gestures
601 for (QSet<QGesture *>::const_iterator it = gestures.begin(),
602 e = gestures.end(); it != e; ++it) {
603 QGesture *gesture = *it;
604 QWidget *target = m_gestureTargets.value(gesture, nullptr);
605 if (!target) {
606 // the gesture has just started and doesn't have a target yet.
607 Q_ASSERT(gesture->state() == Qt::GestureStarted);
608 if (gesture->hasHotSpot()) {
609 // guess the target widget using the hotspot of the gesture
610 QPoint pt = gesture->hotSpot().toPoint();
611 if (QWidget *topLevel = QApplication::topLevelAt(pt)) {
612 QWidget *child = topLevel->childAt(topLevel->mapFromGlobal(pt));
613 target = child ? child : topLevel;
614 }
615 } else {
616 // or use the context of the gesture
617 QObject *context = m_gestureOwners.value(gesture, 0);
618 if (context->isWidgetType())
619 target = static_cast<QWidget *>(context);
620 }
621 if (target)
622 m_gestureTargets.insert(gesture, target);
623 }
624
625 Qt::GestureType gestureType = gesture->gestureType();
626 Q_ASSERT(gestureType != Qt::CustomGesture);
627 Q_UNUSED(gestureType);
628
629 if (Q_UNLIKELY(!target)) {
630 qCDebug(lcGestureManager) << "QGestureManager::deliverEvent: could not find the target for gesture"
631 << gesture->gestureType();
632 qWarning("QGestureManager::deliverEvent: could not find the target for gesture");
633 undeliveredGestures->insert(gesture);
634 } else {
635 if (gesture->state() == Qt::GestureStarted) {
636 startedGestures.insert(gesture);
637 } else {
638 normalStartedGestures[target].append(gesture);
639 }
640 }
641 }
642
643 getGestureTargets(startedGestures, &conflictedGestures, &normalStartedGestures);
644 qCDebug(lcGestureManager) << "QGestureManager::deliverEvents:"
645 << "\nstarted: " << startedGestures
646 << "\nconflicted: " << conflictedGestures
647 << "\nnormal: " << normalStartedGestures
648 << "\n";
649
650 // if there are conflicting gestures, send the GestureOverride event
651 for (GesturesPerWidget::const_iterator it = conflictedGestures.constBegin(),
652 e = conflictedGestures.constEnd(); it != e; ++it) {
653 QWidget *receiver = it.key();
654 QList<QGesture *> gestures = it.value();
655 qCDebug(lcGestureManager) << "QGestureManager::deliverEvents: sending GestureOverride to"
656 << receiver
657 << "gestures:" << gestures;
658 QGestureEvent event(gestures);
659 event.t = QEvent::GestureOverride;
660 // mark event and individual gestures as ignored
661 event.ignore();
662 foreach(QGesture *g, gestures)
663 event.setAccepted(g, false);
664
666 bool eventAccepted = event.isAccepted();
667 const auto eventGestures = event.gestures();
668 for (QGesture *gesture : eventGestures) {
669 if (eventAccepted || event.isAccepted(gesture)) {
670 QWidget *w = event.m_targetWidgets.value(gesture->gestureType(), 0);
671 Q_ASSERT(w);
672 qCDebug(lcGestureManager) << "override event: gesture was accepted:" << gesture << w;
673 QList<QGesture *> &gestures = normalStartedGestures[w];
674 gestures.append(gesture);
675 // override the target
676 m_gestureTargets[gesture] = w;
677 } else {
678 qCDebug(lcGestureManager) << "override event: gesture wasn't accepted. putting back:" << gesture;
679 QList<QGesture *> &gestures = normalStartedGestures[receiver];
680 gestures.append(gesture);
681 }
682 }
683 }
684
685 // delivering gestures that are not in conflicted state
686 for (GesturesPerWidget::const_iterator it = normalStartedGestures.constBegin(),
687 e = normalStartedGestures.constEnd(); it != e; ++it) {
688 if (!it.value().isEmpty()) {
689 qCDebug(lcGestureManager) << "QGestureManager::deliverEvents: sending to" << it.key()
690 << "gestures:" << it.value();
691 QGestureEvent event(it.value());
693 bool eventAccepted = event.isAccepted();
694 const auto eventGestures = event.gestures();
695 for (QGesture *gesture : eventGestures) {
696 if (gesture->state() == Qt::GestureStarted &&
697 (eventAccepted || event.isAccepted(gesture))) {
698 QWidget *w = event.m_targetWidgets.value(gesture->gestureType(), 0);
699 Q_ASSERT(w);
700 qCDebug(lcGestureManager) << "started gesture was delivered and accepted by" << w;
701 m_gestureTargets[gesture] = w;
702 }
703 }
704 }
705 }
706}
707
709{
710 QGestureRecognizer *recognizer = m_gestureToRecognizer.value(gesture, 0);
711 if (recognizer) {
713 recognizer->reset(gesture);
714 m_activeGestures.remove(gesture);
715 } else {
716 cleanupGesturesForRemovedRecognizer(gesture);
717 }
718}
719
721{
723 return gm && gm->m_gestureOwners.key(o);
724}
725
727
728#endif // QT_NO_GESTURES
729
730#include "moc_qgesturemanager_p.cpp"
static QWidget * topLevelAt(const QPoint &p)
Returns the top-level widget at the given point; returns \nullptr if there is no such widget.
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
\inmodule QtCore
Definition qcoreevent.h:45
Type
This enum type defines the valid event types in Qt.
Definition qcoreevent.h:51
@ TabletMove
Definition qcoreevent.h:121
@ GraphicsSceneMouseMove
Definition qcoreevent.h:189
@ TabletEnterProximity
Definition qcoreevent.h:209
@ GestureOverride
Definition qcoreevent.h:254
@ GraphicsSceneMouseRelease
Definition qcoreevent.h:191
@ GraphicsSceneMousePress
Definition qcoreevent.h:190
@ MouseMove
Definition qcoreevent.h:63
@ TouchCancel
Definition qcoreevent.h:264
@ MouseButtonPress
Definition qcoreevent.h:60
@ TouchUpdate
Definition qcoreevent.h:242
@ TouchBegin
Definition qcoreevent.h:241
@ GraphicsSceneMouseDoubleClick
Definition qcoreevent.h:192
@ TabletRelease
Definition qcoreevent.h:127
@ TabletPress
Definition qcoreevent.h:126
@ MouseButtonDblClick
Definition qcoreevent.h:62
@ TabletLeaveProximity
Definition qcoreevent.h:210
@ MouseButtonRelease
Definition qcoreevent.h:61
The QGestureEvent class provides the description of triggered gestures.
Definition qgesture.h:244
void recycle(QGesture *gesture)
Qt::GestureType registerGestureRecognizer(QGestureRecognizer *recognizer)
bool filterEventThroughContexts(const QMultiMap< QObject *, Qt::GestureType > &contexts, QEvent *event)
static bool gesturePending(QObject *o)
bool filterEvent(QWidget *receiver, QEvent *event)
void unregisterGestureRecognizer(Qt::GestureType type)
static QGestureManager * instance(InstanceCreation ic=ForceCreation)
QGestureManager(QObject *parent)
void cleanupCachedGestures(QObject *target, Qt::GestureType type)
The QGestureRecognizer class provides the infrastructure for gesture recognition.\inmodule QtWidgets.
virtual void reset(QGesture *state)
This function is called by the framework to reset a given gesture.
virtual Result recognize(QGesture *state, QObject *watched, QEvent *event)=0
Handles the given event for the watched object, updating the state of the gesture object as required,...
virtual QGesture * create(QObject *target)
This function is called by Qt to create a new QGesture object for the given target (QWidget or QGraph...
The QGesture class represents a gesture, containing properties that describe the corresponding user i...
Definition qgesture.h:29
Qt::GestureState state
the current state of the gesture
Definition qgesture.h:33
@ CancelAllInContext
Definition qgesture.h:55
@ CancelNone
Definition qgesture.h:54
void setGestureCancelPolicy(GestureCancelPolicy policy)
Definition qgesture.cpp:179
Qt::GestureType gestureType
the type of the gesture
Definition qgesture.h:34
QPointF hotSpot
The point that is used to find the receiver for the gesture event.
Definition qgesture.h:37
bool hasHotSpot
whether the gesture has a hot-spot
Definition qgesture.h:38
QGraphicsObject * parentObject() const
The QGraphicsObject class provides a base class for all graphics items that require signals,...
\inmodule QtCore
Definition qhash.h:1135
\inmodule QtCore
Definition qhash.h:818
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:956
const_iterator cbegin() const noexcept
Definition qhash.h:1204
QList< Key > keys() const
Returns a list containing all the keys in the hash, in an arbitrary order.
Definition qhash.h:1076
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:991
T value(const Key &key) const noexcept
Definition qhash.h:1044
const_iterator cend() const noexcept
Definition qhash.h:1208
Key key(const T &value) const noexcept
Definition qhash.h:1018
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
Definition qlist.h:74
bool isEmpty() const noexcept
Definition qlist.h:390
void append(parameter_type t)
Definition qlist.h:441
Definition qmap.h:186
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:356
iterator erase(const_iterator it)
Definition qmap.h:618
iterator find(const Key &key)
Definition qmap.h:640
iterator end()
Definition qmap.h:601
const_iterator constBegin() const
Definition qmap.h:599
const_iterator constEnd() const
Definition qmap.h:603
const T & value() const
Definition qmap.h:1212
iterator lowerBound(const Key &key)
Definition qmap.h:1397
bool isEmpty() const
Definition qmap.h:913
iterator insert(const Key &key, const T &value)
Definition qmap.h:1425
size_type remove(const Key &key)
Definition qmap.h:944
iterator upperBound(const Key &key)
Definition qmap.h:1411
QList< T > values() const
Definition qmap.h:1078
\inmodule QtCore
Definition qobject.h:90
constexpr QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
Definition qpoint.h:394
\inmodule QtCore\reentrant
Definition qpoint.h:23
\inmodule QtCore
Definition qset.h:18
bool remove(const T &value)
Definition qset.h:63
iterator begin()
Definition qset.h:136
iterator end()
Definition qset.h:140
bool isEmpty() const
Definition qset.h:52
const_iterator constBegin() const noexcept
Definition qset.h:139
const_iterator constEnd() const noexcept
Definition qset.h:143
void clear()
Definition qset.h:61
iterator erase(const_iterator i)
Definition qset.h:145
const_iterator constFind(const T &value) const
Definition qset.h:161
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
QWidget * widget() const
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
QWidget * parentWidget() const
Returns the parent of this widget, or \nullptr if it does not have any parent widget.
Definition qwidget.h:904
bool isAncestorOf(const QWidget *child) const
Returns true if this widget is a parent, (or grandparent and so on to any level), of the given child,...
Definition qwidget.cpp:8868
QOpenGLWidget * widget
[1]
qDeleteAll(list.begin(), list.end())
double e
QSet< QString >::iterator it
else opt state
[0]
Combined button and popup list for selecting options.
@ GestureCanceled
@ GestureStarted
@ GestureUpdated
@ GestureFinished
GestureType
@ CustomGesture
@ DontStartGestureOnChildren
static void * context
#define Q_UNLIKELY(x)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
static bool logIgnoredEvent(QEvent::Type t)
static QT_BEGIN_NAMESPACE int panTouchPoints()
#define qWarning
Definition qlogging.h:162
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLsizei GLenum GLenum * types
GLuint object
[3]
GLenum type
GLenum target
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLboolean GLboolean g
struct _cl_event * event
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLuint * states
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define Q_UNUSED(x)
QList< int > list
[14]
QObject::connect nullptr
QGraphicsItem * item
QLayoutItem * child
[0]
bool contains(const AT &t) const noexcept
Definition qlist.h:44
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent