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"
12#include "private/qevent_p.h"
13#include "private/qapplication_p.h"
14#include "private/qwidgetwindow_p.h"
23#include <QtCore/QLoggingCategory>
24#include <QtCore/QVarLengthArray>
32#if !defined(Q_OS_MACOS)
36 static const char panTouchPointVariable[] =
"QT_PAN_TOUCHPOINTS";
42 qWarning(
"Ignoring invalid value of %s", panTouchPointVariable);
53 :
QObject(parent), m_lastCustomGestureId(
Qt::CustomGesture)
55 qRegisterMetaType<Qt::GestureState>();
57#if defined(Q_OS_MACOS)
81 const QScopedPointer<QGesture> dummy(recognizer->
create(
nullptr));
83 qWarning(
"QGestureManager::registerGestureRecognizer: "
84 "the recognizer fails to create a gesture object, skipping registration.");
90 ++m_lastCustomGestureId;
101 for (
const auto &[
g, recognizer] : std::as_const(m_gestureToRecognizer).asKeyValueRange()) {
103 m_deletedRecognizers.
insert(
g, recognizer);
107 for (
const auto &[objectGesture, gestures] : std::as_const(m_objectGestures).asKeyValueRange()) {
108 if (objectGesture.gesture ==
type) {
111 if (
it != m_gestureToRecognizer.
cend() &&
it.value()) {
113 m_gestureToRecognizer.
erase(
it);
114 m_obsoleteGestures[recognizer].
insert(
g);
124 if (
iter == m_objectGestures.
end())
127 const QList<QGesture *> &gestures =
iter.value();
128 for (
auto &e : m_obsoleteGestures) {
133 m_deletedRecognizers.
remove(
g);
134 m_gestureToRecognizer.
remove(
g);
151 if (
object->isWidgetType()) {
152 if (
static_cast<QWidget *
>(
object)->d_func()->
data.in_destructor)
154 }
else if (
QGesture *
g = qobject_cast<QGesture *>(
object)) {
156#if QT_CONFIG(graphicsview)
158 Q_ASSERT(qobject_cast<QGraphicsObject *>(
object));
160 if (graphicsObject->QGraphicsItem::d_func()->inDestructor)
166 const auto states = m_objectGestures.
value(QGestureManager::ObjectGesture(
object,
type));
168 if (m_gestureToRecognizer.
value(
state) == recognizer)
176 state->setParent(
this);
181 if (lcGestureManager().isDebugEnabled())
184 m_objectGestures[QGestureManager::ObjectGesture(
object,
type)].append(
state);
185 m_gestureToRecognizer[
state] = recognizer;
225 QSet<QGesture *> triggeredGestures;
226 QSet<QGesture *> finishedGestures;
227 QSet<QGesture *> newMaybeGestures;
228 QSet<QGesture *> notGestures;
233 bool consumeEventHint =
false;
237 ContextIterator contextEnd = contexts.end();
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) {
254 qCDebug(lcGestureManager) <<
"QGestureManager:Recognizer: gesture triggered: " <<
state <<
event;
255 triggeredGestures <<
state;
257 qCDebug(lcGestureManager) <<
"QGestureManager:Recognizer: gesture finished: " <<
state <<
event;
258 finishedGestures <<
state;
260 qCDebug(lcGestureManager) <<
"QGestureManager:Recognizer: maybe gesture: " <<
state <<
event;
261 newMaybeGestures <<
state;
263 qCDebug(lcGestureManager) <<
"QGestureManager:Recognizer: not gesture: " <<
state <<
event;
264 notGestures <<
state;
267 qCDebug(lcGestureManager) <<
"QGestureManager:Recognizer: ignored the event: " <<
state <<
event;
270 qCDebug(lcGestureManager) <<
"QGestureManager:Recognizer: hm, lets assume the recognizer"
275 qCDebug(lcGestureManager) <<
"QGestureManager: we were asked to consume the event: "
277 consumeEventHint =
true;
281 if (!triggeredGestures.isEmpty() || !finishedGestures.isEmpty()
282 || !newMaybeGestures.isEmpty() || !notGestures.isEmpty()) {
283 const QSet<QGesture *> startedGestures = triggeredGestures - m_activeGestures;
284 triggeredGestures &= m_activeGestures;
287 const QSet<QGesture *> activeToMaybeGestures = m_activeGestures & newMaybeGestures;
290 QSet<QGesture *> maybeToCanceledGestures = m_maybeGestures & notGestures;
294 const QSet<QGesture *> canceledGestures = m_activeGestures & notGestures;
297 m_maybeGestures += newMaybeGestures;
300 QSet<QGesture *> notMaybeGestures = (startedGestures | triggeredGestures
301 | finishedGestures | canceledGestures
303 m_maybeGestures -= notMaybeGestures;
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());
312 const QSet<QGesture *> notStarted = finishedGestures - m_activeGestures;
313 if (!notStarted.isEmpty()) {
316 for (
QGesture *gesture : notStarted)
318 QSet<QGesture *> undeliveredGestures;
319 deliverEvents(notStarted, &undeliveredGestures);
320 finishedGestures -= undeliveredGestures;
323 m_activeGestures += startedGestures;
325 Q_ASSERT((m_activeGestures & triggeredGestures).
size() == triggeredGestures.size());
326 m_activeGestures -= finishedGestures;
327 m_activeGestures -= activeToMaybeGestures;
328 m_activeGestures -= canceledGestures;
331 for (
QGesture *gesture : startedGestures)
333 for (
QGesture *gesture : std::as_const(triggeredGestures))
335 for (
QGesture *gesture : std::as_const(finishedGestures))
337 for (
QGesture *gesture : canceledGestures)
339 for (
QGesture *gesture : activeToMaybeGestures)
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;
355 QSet<QGesture *> undeliveredGestures;
356 deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures,
357 &undeliveredGestures);
360 if (undeliveredGestures.contains(
g))
363 qCDebug(lcGestureManager) <<
"lets try to cancel some";
365 cancelGesturesForChildren(
g);
369 m_activeGestures -= undeliveredGestures;
372 const QSet<QGesture *> endedGestures =
373 finishedGestures + canceledGestures + undeliveredGestures + maybeToCanceledGestures;
374 for (
QGesture *gesture : endedGestures) {
376 m_gestureTargets.
remove(gesture);
381 m_gesturesToDelete.
clear();
383 return consumeEventHint;
387void QGestureManager::cancelGesturesForChildren(
QGesture *original)
390 QWidget *originatingWidget = m_gestureTargets.
value(original);
392 if (!originatingWidget)
399 QSet<QGesture*> cancelledGestures;
401 while (
iter != m_activeGestures.
end()) {
405 qCDebug(lcGestureManager) <<
" found a gesture to cancel" << (*iter);
407 cancelledGestures << *
iter;
417 QSet<QGesture *> almostCanceledGestures = cancelledGestures;
418 while (!almostCanceledGestures.isEmpty()) {
420 QSet<QGesture*> gestures;
421 iter = almostCanceledGestures.begin();
423 while (
iter != almostCanceledGestures.end()) {
429 iter = almostCanceledGestures.erase(
iter);
436 QSet<QGesture*> undeliveredGestures;
437 deliverEvents(gestures, &undeliveredGestures);
440 for (
iter = cancelledGestures.begin();
iter != cancelledGestures.end(); ++
iter)
444void QGestureManager::cleanupGesturesForRemovedRecognizer(
QGesture *gesture)
449 m_deletedRecognizers.
remove(gesture);
450 if (m_deletedRecognizers.
keys(recognizer).
isEmpty()) {
453 m_obsoleteGestures.
remove(recognizer);
461 QVarLengthArray<Qt::GestureType, 16>
types;
462 QMultiMap<QObject *, Qt::GestureType> contexts;
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) {
469 contexts.insert(
w,
it.key());
473 w =
w->isWindow() ?
nullptr :
w->parentWidget();
476 for (ContextIterator
it =
w->d_func()->gestureContext.
constBegin(),
477 e =
w->d_func()->gestureContext.constEnd();
it != e; ++
it) {
479 if (!
types.contains(
it.key())) {
481 contexts.insert(
w,
it.key());
487 w =
w->parentWidget();
492#if QT_CONFIG(graphicsview)
495 QVarLengthArray<Qt::GestureType, 16>
types;
496 QMultiMap<QObject *, Qt::GestureType> contexts;
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) {
503 contexts.insert(
item,
it.key());
511 for (ContextIterator
it =
item->QGraphicsItem::d_func()->gestureContext.constBegin(),
512 e =
item->QGraphicsItem::d_func()->gestureContext.constEnd();
it != e; ++
it) {
514 if (!
types.contains(
it.key())) {
516 contexts.insert(
item,
it.key());
530 QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(receiver);
532 if (widgetWindow && widgetWindow->widget())
538 QMultiMap<QObject *, Qt::GestureType> contexts;
543void QGestureManager::getGestureTargets(
const QSet<QGesture*> &gestures,
547 typedef QHash<Qt::GestureType, QHash<QWidget *, QGesture *> > GestureByTypes;
548 GestureByTypes gestureByTypes;
551 for (
QGesture *gesture : gestures) {
552 QWidget *receiver = m_gestureTargets.
value(gesture,
nullptr);
555 gestureByTypes[gesture->
gestureType()].insert(receiver, gesture);
559 for (GestureByTypes::const_iterator git = gestureByTypes.cbegin(), gend = gestureByTypes.cend(); git != gend; ++git) {
560 const QHash<QWidget *, QGesture *> &gestures = git.value();
566 =
w->d_func()->gestureContext.
constFind(git.key());
567 if (
it !=
w->d_func()->gestureContext.
constEnd()) {
571 (*conflicts)[
widget].append(wit.value());
579 w =
w->parentWidget();
582 (*normal)[
widget].append(wit.value());
587void QGestureManager::deliverEvents(
const QSet<QGesture *> &gestures,
588 QSet<QGesture *> *undeliveredGestures)
590 if (gestures.isEmpty())
593 typedef QHash<QWidget *, QList<QGesture *> > GesturesPerWidget;
594 GesturesPerWidget conflictedGestures;
595 GesturesPerWidget normalStartedGestures;
597 QSet<QGesture *> startedGestures;
600 e = gestures.end();
it != e; ++
it) {
610 QWidget *
child = topLevel->childAt(topLevel->mapFromGlobal(pt));
629 qCDebug(lcGestureManager) <<
"QGestureManager::deliverEvent: could not find the target for gesture"
631 qWarning(
"QGestureManager::deliverEvent: could not find the target for gesture");
632 undeliveredGestures->insert(gesture);
635 startedGestures.insert(gesture);
637 normalStartedGestures[
target].append(gesture);
642 getGestureTargets(startedGestures, &conflictedGestures, &normalStartedGestures);
643 qCDebug(lcGestureManager) <<
"QGestureManager::deliverEvents:"
644 <<
"\nstarted: " << startedGestures
645 <<
"\nconflicted: " << conflictedGestures
646 <<
"\nnormal: " << normalStartedGestures
650 for (GesturesPerWidget::const_iterator
it = conflictedGestures.
constBegin(),
651 e = conflictedGestures.constEnd();
it != e; ++
it) {
653 const QList<QGesture *> &gestures =
it.value();
654 qCDebug(lcGestureManager) <<
"QGestureManager::deliverEvents: sending GestureOverride to"
656 <<
"gestures:" << gestures;
665 bool eventAccepted =
event.isAccepted();
666 const auto eventGestures =
event.gestures();
667 for (
QGesture *gesture : eventGestures) {
668 if (eventAccepted ||
event.isAccepted(gesture)) {
671 qCDebug(lcGestureManager) <<
"override event: gesture was accepted:" << gesture <<
w;
672 QList<QGesture *> &gestures = normalStartedGestures[
w];
673 gestures.append(gesture);
675 m_gestureTargets[gesture] =
w;
677 qCDebug(lcGestureManager) <<
"override event: gesture wasn't accepted. putting back:" << gesture;
678 QList<QGesture *> &gestures = normalStartedGestures[receiver];
679 gestures.append(gesture);
685 for (GesturesPerWidget::const_iterator
it = normalStartedGestures.
constBegin(),
686 e = normalStartedGestures.constEnd();
it != e; ++
it) {
688 qCDebug(lcGestureManager) <<
"QGestureManager::deliverEvents: sending to" <<
it.key()
689 <<
"gestures:" <<
it.value();
692 bool eventAccepted =
event.isAccepted();
693 const auto eventGestures =
event.gestures();
694 for (
QGesture *gesture : eventGestures) {
696 (eventAccepted ||
event.isAccepted(gesture))) {
699 qCDebug(lcGestureManager) <<
"started gesture was delivered and accepted by" <<
w;
700 m_gestureTargets[gesture] =
w;
712 recognizer->
reset(gesture);
713 m_activeGestures.
remove(gesture);
715 cleanupGesturesForRemovedRecognizer(gesture);
722 return gm && gm->m_gestureOwners.key(
o);
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.
Type
This enum type defines the valid event types in Qt.
@ GraphicsSceneMouseRelease
@ GraphicsSceneMousePress
@ GraphicsSceneMouseDoubleClick
The QGestureEvent class provides the description of triggered gestures.
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...
Qt::GestureState state
the current state of the gesture
void setGestureCancelPolicy(GestureCancelPolicy policy)
Qt::GestureType gestureType
the type of the gesture
QPointF hotSpot
The point that is used to find the receiver for the gesture event.
bool hasHotSpot
whether the gesture has a hot-spot
QGraphicsObject * parentObject() const
The QGraphicsObject class provides a base class for all graphics items that require signals,...
bool remove(const Key &key)
Removes the item that has the key from the hash.
const_iterator cbegin() const noexcept
const_iterator constFind(const Key &key) const noexcept
QList< Key > keys() const
Returns a list containing all the keys in the hash, in an arbitrary order.
iterator erase(const_iterator it)
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
T value(const Key &key) const noexcept
const_iterator cend() const noexcept
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
bool isEmpty() const noexcept
T value(const Key &key, const T &defaultValue=T()) const
iterator erase(const_iterator it)
iterator find(const Key &key)
iterator insert(const Key &key, const T &value)
size_type remove(const Key &key)
QList< T > values() const
constexpr QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
\inmodule QtCore\reentrant
bool remove(const T &value)
const_iterator constBegin() const noexcept
const_iterator constEnd() const noexcept
iterator erase(const_iterator i)
const_iterator constFind(const T &value) const
iterator insert(const T &value)
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
Combined button and popup list for selecting options.
@ DontStartGestureOnChildren
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 Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLsizei GLenum GLenum * types
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
bool contains(const AT &t) const noexcept