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