Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
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{
99 QList<QGestureRecognizer *> list = m_recognizers.values(type);
100 m_recognizers.remove(type);
101 for (const auto &[g, recognizer] : std::as_const(m_gestureToRecognizer).asKeyValueRange()) {
102 if (list.contains(recognizer)) {
103 m_deletedRecognizers.insert(g, recognizer);
104 }
105 }
106
107 for (const auto &[objectGesture, gestures] : std::as_const(m_objectGestures).asKeyValueRange()) {
108 if (objectGesture.gesture == type) {
109 for (QGesture *g : gestures) {
110 auto it = m_gestureToRecognizer.constFind(g);
111 if (it != m_gestureToRecognizer.cend() && it.value()) {
112 QGestureRecognizer *recognizer = it.value();
113 m_gestureToRecognizer.erase(it);
114 m_obsoleteGestures[recognizer].insert(g);
115 }
116 }
117 }
118 }
119}
120
122{
123 const auto iter = m_objectGestures.find({target, type});
124 if (iter == m_objectGestures.end())
125 return;
126
127 const QList<QGesture *> &gestures = iter.value();
128 for (auto &e : m_obsoleteGestures) {
129 for (QGesture *g : gestures)
130 e -= g;
131 }
132 for (QGesture *g : gestures) {
133 m_deletedRecognizers.remove(g);
134 m_gestureToRecognizer.remove(g);
135 m_maybeGestures.remove(g);
136 m_activeGestures.remove(g);
137 m_gestureOwners.remove(g);
138 m_gestureTargets.remove(g);
139 m_gesturesToDelete.insert(g);
140 }
141
142 m_objectGestures.erase(iter);
143}
144
145// get or create a QGesture object that will represent the state for a given object, used by the recognizer
146QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recognizer, Qt::GestureType type)
147{
148 // if the widget is being deleted we should be careful not to
149 // create a new state, as it will create QWeakPointer which doesn't work
150 // from the destructor.
151 if (object->isWidgetType()) {
152 if (static_cast<QWidget *>(object)->d_func()->data.in_destructor)
153 return nullptr;
154 } else if (QGesture *g = qobject_cast<QGesture *>(object)) {
155 return g;
156#if QT_CONFIG(graphicsview)
157 } else {
158 Q_ASSERT(qobject_cast<QGraphicsObject *>(object));
159 QGraphicsObject *graphicsObject = static_cast<QGraphicsObject *>(object);
160 if (graphicsObject->QGraphicsItem::d_func()->inDestructor)
161 return nullptr;
162#endif
163 }
164
165 // check if the QGesture for this recognizer has already been created
166 const auto states = m_objectGestures.value(QGestureManager::ObjectGesture(object, type));
167 for (QGesture *state : states) {
168 if (m_gestureToRecognizer.value(state) == recognizer)
169 return state;
170 }
171
172 Q_ASSERT(recognizer);
173 QGesture *state = recognizer->create(object);
174 if (!state)
175 return nullptr;
176 state->setParent(this);
177 if (state->gestureType() == Qt::CustomGesture) {
178 // if the recognizer didn't fill in the gesture type, then this
179 // is a custom gesture with autogenerated id and we fill it.
180 state->d_func()->gestureType = type;
181 if (lcGestureManager().isDebugEnabled())
182 state->setObjectName(QString::number((int)type));
183 }
184 m_objectGestures[QGestureManager::ObjectGesture(object, type)].append(state);
185 m_gestureToRecognizer[state] = recognizer;
186 m_gestureOwners[state] = object;
187
188 return state;
189}
190
192{
193 bool result = false;
194 switch (t) {
202 case QEvent::TouchEnd:
212 result = true;
213 break;
214 default:
215 break;
216
217 }
218 return result;
219}
220
222 Qt::GestureType> &contexts,
223 QEvent *event)
224{
225 QSet<QGesture *> triggeredGestures;
226 QSet<QGesture *> finishedGestures;
227 QSet<QGesture *> newMaybeGestures;
228 QSet<QGesture *> notGestures;
229
230 // TODO: sort contexts by the gesture type and check if one of the contexts
231 // is already active.
232
233 bool consumeEventHint = false;
234
235 // filter the event through recognizers
237 ContextIterator contextEnd = contexts.end();
238 for (ContextIterator context = contexts.begin(); context != contextEnd; ++context) {
239 Qt::GestureType gestureType = context.value();
240 const QMultiMap<Qt::GestureType, QGestureRecognizer *> &const_recognizers = m_recognizers;
242 typeToRecognizerIterator = const_recognizers.lowerBound(gestureType),
243 typeToRecognizerEnd = const_recognizers.upperBound(gestureType);
244 for (; typeToRecognizerIterator != typeToRecognizerEnd; ++typeToRecognizerIterator) {
245 QGestureRecognizer *recognizer = typeToRecognizerIterator.value();
246 QObject *target = context.key();
247 QGesture *state = getState(target, recognizer, gestureType);
248 if (!state)
249 continue;
250 QGestureRecognizer::Result recognizerResult = recognizer->recognize(state, target, event);
251 QGestureRecognizer::Result recognizerState = recognizerResult & QGestureRecognizer::ResultState_Mask;
252 QGestureRecognizer::Result resultHint = recognizerResult & QGestureRecognizer::ResultHint_Mask;
253 if (recognizerState == QGestureRecognizer::TriggerGesture) {
254 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: gesture triggered: " << state << event;
255 triggeredGestures << state;
256 } else if (recognizerState == QGestureRecognizer::FinishGesture) {
257 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: gesture finished: " << state << event;
258 finishedGestures << state;
259 } else if (recognizerState == QGestureRecognizer::MayBeGesture) {
260 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: maybe gesture: " << state << event;
261 newMaybeGestures << state;
262 } else if (recognizerState == QGestureRecognizer::CancelGesture) {
263 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: not gesture: " << state << event;
264 notGestures << state;
265 } else if (recognizerState == QGestureRecognizer::Ignore) {
266 if (logIgnoredEvent(event->type()))
267 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: ignored the event: " << state << event;
268 } else {
269 if (logIgnoredEvent(event->type())) {
270 qCDebug(lcGestureManager) << "QGestureManager:Recognizer: hm, lets assume the recognizer"
271 << "ignored the event: " << state << event;
272 }
273 }
274 if (resultHint & QGestureRecognizer::ConsumeEventHint) {
275 qCDebug(lcGestureManager) << "QGestureManager: we were asked to consume the event: "
276 << state << event;
277 consumeEventHint = true;
278 }
279 }
280 }
281 if (!triggeredGestures.isEmpty() || !finishedGestures.isEmpty()
282 || !newMaybeGestures.isEmpty() || !notGestures.isEmpty()) {
283 const QSet<QGesture *> startedGestures = triggeredGestures - m_activeGestures;
284 triggeredGestures &= m_activeGestures;
285
286 // check if a running gesture switched back to maybe state
287 const QSet<QGesture *> activeToMaybeGestures = m_activeGestures & newMaybeGestures;
288
289 // check if a maybe gesture switched to canceled - reset it but don't send an event
290 QSet<QGesture *> maybeToCanceledGestures = m_maybeGestures & notGestures;
291
292 // check if a running gesture switched back to not gesture state,
293 // i.e. were canceled
294 const QSet<QGesture *> canceledGestures = m_activeGestures & notGestures;
295
296 // new gestures in maybe state
297 m_maybeGestures += newMaybeGestures;
298
299 // gestures that were in maybe state
300 QSet<QGesture *> notMaybeGestures = (startedGestures | triggeredGestures
301 | finishedGestures | canceledGestures
302 | notGestures);
303 m_maybeGestures -= notMaybeGestures;
304
305 Q_ASSERT((startedGestures & finishedGestures).isEmpty());
306 Q_ASSERT((startedGestures & newMaybeGestures).isEmpty());
307 Q_ASSERT((startedGestures & canceledGestures).isEmpty());
308 Q_ASSERT((finishedGestures & newMaybeGestures).isEmpty());
309 Q_ASSERT((finishedGestures & canceledGestures).isEmpty());
310 Q_ASSERT((canceledGestures & newMaybeGestures).isEmpty());
311
312 const QSet<QGesture *> notStarted = finishedGestures - m_activeGestures;
313 if (!notStarted.isEmpty()) {
314 // there are some gestures that claim to be finished, but never started.
315 // probably those are "singleshot" gestures so we'll fake the started state.
316 for (QGesture *gesture : notStarted)
317 gesture->d_func()->state = Qt::GestureStarted;
318 QSet<QGesture *> undeliveredGestures;
319 deliverEvents(notStarted, &undeliveredGestures);
320 finishedGestures -= undeliveredGestures;
321 }
322
323 m_activeGestures += startedGestures;
324 // sanity check: all triggered gestures should already be in active gestures list
325 Q_ASSERT((m_activeGestures & triggeredGestures).size() == triggeredGestures.size());
326 m_activeGestures -= finishedGestures;
327 m_activeGestures -= activeToMaybeGestures;
328 m_activeGestures -= canceledGestures;
329
330 // set the proper gesture state on each gesture
331 for (QGesture *gesture : startedGestures)
332 gesture->d_func()->state = Qt::GestureStarted;
333 for (QGesture *gesture : std::as_const(triggeredGestures))
334 gesture->d_func()->state = Qt::GestureUpdated;
335 for (QGesture *gesture : std::as_const(finishedGestures))
336 gesture->d_func()->state = Qt::GestureFinished;
337 for (QGesture *gesture : canceledGestures)
338 gesture->d_func()->state = Qt::GestureCanceled;
339 for (QGesture *gesture : activeToMaybeGestures)
340 gesture->d_func()->state = Qt::GestureFinished;
341
342 if (!m_activeGestures.isEmpty() || !m_maybeGestures.isEmpty() ||
343 !startedGestures.isEmpty() || !triggeredGestures.isEmpty() ||
344 !finishedGestures.isEmpty() || !canceledGestures.isEmpty()) {
345 qCDebug(lcGestureManager) << "QGestureManager::filterEventThroughContexts:"
346 << "\n\tactiveGestures:" << m_activeGestures
347 << "\n\tmaybeGestures:" << m_maybeGestures
348 << "\n\tstarted:" << startedGestures
349 << "\n\ttriggered:" << triggeredGestures
350 << "\n\tfinished:" << finishedGestures
351 << "\n\tcanceled:" << canceledGestures
352 << "\n\tmaybe-canceled:" << maybeToCanceledGestures;
353 }
354
355 QSet<QGesture *> undeliveredGestures;
356 deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures,
357 &undeliveredGestures);
358
359 for (QGesture *g : startedGestures) {
360 if (undeliveredGestures.contains(g))
361 continue;
362 if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
363 qCDebug(lcGestureManager) << "lets try to cancel some";
364 // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
365 cancelGesturesForChildren(g);
366 }
367 }
368
369 m_activeGestures -= undeliveredGestures;
370
371 // reset gestures that ended
372 const QSet<QGesture *> endedGestures =
373 finishedGestures + canceledGestures + undeliveredGestures + maybeToCanceledGestures;
374 for (QGesture *gesture : endedGestures) {
375 recycle(gesture);
376 m_gestureTargets.remove(gesture);
377 }
378 }
379 //Clean up the Gestures
380 qDeleteAll(m_gesturesToDelete);
381 m_gesturesToDelete.clear();
382
383 return consumeEventHint;
384}
385
386// Cancel all gestures of children of the widget that original is associated with
387void QGestureManager::cancelGesturesForChildren(QGesture *original)
388{
389 Q_ASSERT(original);
390 QWidget *originatingWidget = m_gestureTargets.value(original);
391 Q_ASSERT(originatingWidget);
392 if (!originatingWidget)
393 return;
394
395 // iterate over all active gestures and all maybe gestures
396 // for each find the owner
397 // if the owner is part of our sub-hierarchy, cancel it.
398
399 QSet<QGesture*> cancelledGestures;
400 QSet<QGesture*>::Iterator iter = m_activeGestures.begin();
401 while (iter != m_activeGestures.end()) {
402 QWidget *widget = m_gestureTargets.value(*iter);
403 // note that we don't touch the gestures for our originatingWidget
404 if (widget != originatingWidget && originatingWidget->isAncestorOf(widget)) {
405 qCDebug(lcGestureManager) << " found a gesture to cancel" << (*iter);
406 (*iter)->d_func()->state = Qt::GestureCanceled;
407 cancelledGestures << *iter;
408 iter = m_activeGestures.erase(iter);
409 } else {
410 ++iter;
411 }
412 }
413
414 // TODO handle 'maybe' gestures too
415
416 // sort them per target widget by cherry picking from almostCanceledGestures and delivering
417 QSet<QGesture *> almostCanceledGestures = cancelledGestures;
418 while (!almostCanceledGestures.isEmpty()) {
419 QWidget *target = nullptr;
420 QSet<QGesture*> gestures;
421 iter = almostCanceledGestures.begin();
422 // sort per target widget
423 while (iter != almostCanceledGestures.end()) {
424 QWidget *widget = m_gestureTargets.value(*iter);
425 if (target == nullptr)
426 target = widget;
427 if (target == widget) {
428 gestures << *iter;
429 iter = almostCanceledGestures.erase(iter);
430 } else {
431 ++iter;
432 }
433 }
435
436 QSet<QGesture*> undeliveredGestures;
437 deliverEvents(gestures, &undeliveredGestures);
438 }
439
440 for (iter = cancelledGestures.begin(); iter != cancelledGestures.end(); ++iter)
441 recycle(*iter);
442}
443
444void QGestureManager::cleanupGesturesForRemovedRecognizer(QGesture *gesture)
445{
446 QGestureRecognizer *recognizer = m_deletedRecognizers.value(gesture);
447 if (!recognizer) //The Gesture is removed while in the even loop, so the recognizers for this gestures was removed
448 return;
449 m_deletedRecognizers.remove(gesture);
450 if (m_deletedRecognizers.keys(recognizer).isEmpty()) {
451 // no more active gestures, cleanup!
452 qDeleteAll(m_obsoleteGestures.value(recognizer));
453 m_obsoleteGestures.remove(recognizer);
454 delete recognizer;
455 }
456}
457
458// return true if accepted (consumed)
460{
461 QVarLengthArray<Qt::GestureType, 16> types;
462 QMultiMap<QObject *, Qt::GestureType> contexts;
463 QWidget *w = receiver;
465 if (!w->d_func()->gestureContext.isEmpty()) {
466 for(ContextIterator it = w->d_func()->gestureContext.constBegin(),
467 e = w->d_func()->gestureContext.constEnd(); it != e; ++it) {
468 types.push_back(it.key());
469 contexts.insert(w, it.key());
470 }
471 }
472 // find all gesture contexts for the widget tree
473 w = w->isWindow() ? nullptr : w->parentWidget();
474 while (w)
475 {
476 for (ContextIterator it = w->d_func()->gestureContext.constBegin(),
477 e = w->d_func()->gestureContext.constEnd(); it != e; ++it) {
478 if (!(it.value() & Qt::DontStartGestureOnChildren)) {
479 if (!types.contains(it.key())) {
480 types.push_back(it.key());
481 contexts.insert(w, it.key());
482 }
483 }
484 }
485 if (w->isWindow())
486 break;
487 w = w->parentWidget();
488 }
489 return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event);
490}
491
492#if QT_CONFIG(graphicsview)
494{
495 QVarLengthArray<Qt::GestureType, 16> types;
496 QMultiMap<QObject *, Qt::GestureType> contexts;
497 QGraphicsObject *item = receiver;
498 if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) {
500 for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.constBegin(),
501 e = item->QGraphicsItem::d_func()->gestureContext.constEnd(); it != e; ++it) {
502 types.push_back(it.key());
503 contexts.insert(item, it.key());
504 }
505 }
506 // find all gesture contexts for the graphics object tree
508 while (item)
509 {
511 for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.constBegin(),
512 e = item->QGraphicsItem::d_func()->gestureContext.constEnd(); it != e; ++it) {
513 if (!(it.value() & Qt::DontStartGestureOnChildren)) {
514 if (!types.contains(it.key())) {
515 types.push_back(it.key());
516 contexts.insert(item, it.key());
517 }
518 }
519 }
521 }
522 return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event);
523}
524#endif
525
527{
528 // if the receiver is actually a widget, we need to call the correct event
529 // filter method.
530 QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(receiver);
531
532 if (widgetWindow && widgetWindow->widget())
533 return filterEvent(widgetWindow->widget(), event);
534
535 QGesture *state = qobject_cast<QGesture *>(receiver);
536 if (!state || !m_gestureToRecognizer.contains(state))
537 return false;
538 QMultiMap<QObject *, Qt::GestureType> contexts;
539 contexts.insert(state, state->gestureType());
540 return filterEventThroughContexts(contexts, event);
541}
542
543void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures,
544 QHash<QWidget *, QList<QGesture *> > *conflicts,
545 QHash<QWidget *, QList<QGesture *> > *normal)
546{
547 typedef QHash<Qt::GestureType, QHash<QWidget *, QGesture *> > GestureByTypes;
548 GestureByTypes gestureByTypes;
549
550 // sort gestures by types
551 for (QGesture *gesture : gestures) {
552 QWidget *receiver = m_gestureTargets.value(gesture, nullptr);
553 Q_ASSERT(receiver);
554 if (receiver)
555 gestureByTypes[gesture->gestureType()].insert(receiver, gesture);
556 }
557
558 // for each gesture type
559 for (GestureByTypes::const_iterator git = gestureByTypes.cbegin(), gend = gestureByTypes.cend(); git != gend; ++git) {
560 const QHash<QWidget *, QGesture *> &gestures = git.value();
561 for (QHash<QWidget *, QGesture *>::const_iterator wit = gestures.cbegin(), wend = gestures.cend(); wit != wend; ++wit) {
562 QWidget *widget = wit.key();
564 while (w) {
566 = w->d_func()->gestureContext.constFind(git.key());
567 if (it != w->d_func()->gestureContext.constEnd()) {
568 // i.e. 'w' listens to gesture 'type'
569 if (!(it.value() & Qt::DontStartGestureOnChildren) && w != widget) {
570 // conflicting gesture!
571 (*conflicts)[widget].append(wit.value());
572 break;
573 }
574 }
575 if (w->isWindow()) {
576 w = nullptr;
577 break;
578 }
579 w = w->parentWidget();
580 }
581 if (!w)
582 (*normal)[widget].append(wit.value());
583 }
584 }
585}
586
587void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
588 QSet<QGesture *> *undeliveredGestures)
589{
590 if (gestures.isEmpty())
591 return;
592
593 typedef QHash<QWidget *, QList<QGesture *> > GesturesPerWidget;
594 GesturesPerWidget conflictedGestures;
595 GesturesPerWidget normalStartedGestures;
596
597 QSet<QGesture *> startedGestures;
598 // first figure out the initial receivers of gestures
599 for (QSet<QGesture *>::const_iterator it = gestures.begin(),
600 e = gestures.end(); it != e; ++it) {
601 QGesture *gesture = *it;
602 QWidget *target = m_gestureTargets.value(gesture, nullptr);
603 if (!target) {
604 // the gesture has just started and doesn't have a target yet.
605 Q_ASSERT(gesture->state() == Qt::GestureStarted);
606 if (gesture->hasHotSpot()) {
607 // guess the target widget using the hotspot of the gesture
608 QPoint pt = gesture->hotSpot().toPoint();
609 if (QWidget *topLevel = QApplication::topLevelAt(pt)) {
610 QWidget *child = topLevel->childAt(topLevel->mapFromGlobal(pt));
611 target = child ? child : topLevel;
612 }
613 }
614 if (!target) {
615 // or use the context of the gesture
616 QObject *context = m_gestureOwners.value(gesture, 0);
617 if (context->isWidgetType())
618 target = static_cast<QWidget *>(context);
619 }
620 if (target)
621 m_gestureTargets.insert(gesture, target);
622 }
623
624 Qt::GestureType gestureType = gesture->gestureType();
625 Q_ASSERT(gestureType != Qt::CustomGesture);
626 Q_UNUSED(gestureType);
627
628 if (Q_UNLIKELY(!target)) {
629 qCDebug(lcGestureManager) << "QGestureManager::deliverEvent: could not find the target for gesture"
630 << gesture->gestureType();
631 qWarning("QGestureManager::deliverEvent: could not find the target for gesture");
632 undeliveredGestures->insert(gesture);
633 } else {
634 if (gesture->state() == Qt::GestureStarted) {
635 startedGestures.insert(gesture);
636 } else {
637 normalStartedGestures[target].append(gesture);
638 }
639 }
640 }
641
642 getGestureTargets(startedGestures, &conflictedGestures, &normalStartedGestures);
643 qCDebug(lcGestureManager) << "QGestureManager::deliverEvents:"
644 << "\nstarted: " << startedGestures
645 << "\nconflicted: " << conflictedGestures
646 << "\nnormal: " << normalStartedGestures
647 << "\n";
648
649 // if there are conflicting gestures, send the GestureOverride event
650 for (GesturesPerWidget::const_iterator it = conflictedGestures.constBegin(),
651 e = conflictedGestures.constEnd(); it != e; ++it) {
652 QWidget *receiver = it.key();
653 const QList<QGesture *> &gestures = it.value();
654 qCDebug(lcGestureManager) << "QGestureManager::deliverEvents: sending GestureOverride to"
655 << receiver
656 << "gestures:" << gestures;
657 QGestureEvent event(gestures);
658 event.t = QEvent::GestureOverride;
659 // mark event and individual gestures as ignored
660 event.ignore();
661 for (QGesture *g : gestures)
662 event.setAccepted(g, false);
663
665 bool eventAccepted = event.isAccepted();
666 const auto eventGestures = event.gestures();
667 for (QGesture *gesture : eventGestures) {
668 if (eventAccepted || event.isAccepted(gesture)) {
669 QWidget *w = event.m_targetWidgets.value(gesture->gestureType(), 0);
670 Q_ASSERT(w);
671 qCDebug(lcGestureManager) << "override event: gesture was accepted:" << gesture << w;
672 QList<QGesture *> &gestures = normalStartedGestures[w];
673 gestures.append(gesture);
674 // override the target
675 m_gestureTargets[gesture] = w;
676 } else {
677 qCDebug(lcGestureManager) << "override event: gesture wasn't accepted. putting back:" << gesture;
678 QList<QGesture *> &gestures = normalStartedGestures[receiver];
679 gestures.append(gesture);
680 }
681 }
682 }
683
684 // delivering gestures that are not in conflicted state
685 for (GesturesPerWidget::const_iterator it = normalStartedGestures.constBegin(),
686 e = normalStartedGestures.constEnd(); it != e; ++it) {
687 if (!it.value().isEmpty()) {
688 qCDebug(lcGestureManager) << "QGestureManager::deliverEvents: sending to" << it.key()
689 << "gestures:" << it.value();
690 QGestureEvent event(it.value());
692 bool eventAccepted = event.isAccepted();
693 const auto eventGestures = event.gestures();
694 for (QGesture *gesture : eventGestures) {
695 if (gesture->state() == Qt::GestureStarted &&
696 (eventAccepted || event.isAccepted(gesture))) {
697 QWidget *w = event.m_targetWidgets.value(gesture->gestureType(), 0);
698 Q_ASSERT(w);
699 qCDebug(lcGestureManager) << "started gesture was delivered and accepted by" << w;
700 m_gestureTargets[gesture] = w;
701 }
702 }
703 }
704 }
705}
706
708{
709 QGestureRecognizer *recognizer = m_gestureToRecognizer.value(gesture, 0);
710 if (recognizer) {
712 recognizer->reset(gesture);
713 m_activeGestures.remove(gesture);
714 } else {
715 cleanupGesturesForRemovedRecognizer(gesture);
716 }
717}
718
720{
722 return gm && gm->m_gestureOwners.key(o);
723}
724
726
727#endif // QT_NO_GESTURES
728
729#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:1145
\inmodule QtCore
Definition qhash.h:820
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:958
const_iterator cbegin() const noexcept
Definition qhash.h:1214
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:1299
QList< Key > keys() const
Returns a list containing all the keys in the hash, in an arbitrary order.
Definition qhash.h:1086
iterator erase(const_iterator it)
Definition qhash.h:1233
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:1007
T value(const Key &key) const noexcept
Definition qhash.h:1054
const_iterator cend() const noexcept
Definition qhash.h:1218
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
bool isEmpty() const noexcept
Definition qlist.h:401
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:357
iterator erase(const_iterator it)
Definition qmap.h:619
iterator find(const Key &key)
Definition qmap.h:641
iterator end()
Definition qmap.h:602
iterator insert(const Key &key, const T &value)
Definition qmap.h:1452
size_type remove(const Key &key)
Definition qmap.h:971
QList< T > values() const
Definition qmap.h:1105
\inmodule QtCore
Definition qobject.h:103
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:404
\inmodule QtCore\reentrant
Definition qpoint.h:25
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
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:8084
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:8822
QOpenGLWidget * widget
[1]
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
else opt state
[0]
Combined button and popup list for selecting options.
Definition qcompare.h:63
@ 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:166
#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]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLenum target
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:45