source: trunk/src/gui/kernel/qgesturemanager.cpp@ 769

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 28.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "private/qgesturemanager_p.h"
43#include "private/qstandardgestures_p.h"
44#include "private/qwidget_p.h"
45#include "private/qgesture_p.h"
46#include "private/qgraphicsitem_p.h"
47#include "private/qevent_p.h"
48#include "private/qapplication_p.h"
49#include "qgesture.h"
50#include "qevent.h"
51#include "qgraphicsitem.h"
52
53#ifdef Q_WS_MAC
54#include "qmacgesturerecognizer_mac_p.h"
55#endif
56#if defined(Q_OS_WIN) && !defined(QT_NO_NATIVE_GESTURES)
57#include "qwinnativepangesturerecognizer_win_p.h"
58#endif
59
60#include "qdebug.h"
61
62// #define GESTURE_DEBUG
63#ifndef GESTURE_DEBUG
64# define DEBUG if (0) qDebug
65#else
66# define DEBUG qDebug
67#endif
68
69QT_BEGIN_NAMESPACE
70
71QGestureManager::QGestureManager(QObject *parent)
72 : QObject(parent), state(NotGesture), m_lastCustomGestureId(0)
73{
74 qRegisterMetaType<Qt::GestureState>();
75
76#if defined(Q_WS_MAC)
77 registerGestureRecognizer(new QMacSwipeGestureRecognizer);
78 registerGestureRecognizer(new QMacPinchGestureRecognizer);
79 #if defined(QT_MAC_USE_COCOA)
80 registerGestureRecognizer(new QMacPanGestureRecognizer);
81 #endif
82#else
83 registerGestureRecognizer(new QPanGestureRecognizer);
84 registerGestureRecognizer(new QPinchGestureRecognizer);
85 registerGestureRecognizer(new QSwipeGestureRecognizer);
86 registerGestureRecognizer(new QTapGestureRecognizer);
87#endif
88#if defined(Q_OS_WIN)
89 #if !defined(QT_NO_NATIVE_GESTURES)
90 if (QApplicationPrivate::HasTouchSupport)
91 registerGestureRecognizer(new QWinNativePanGestureRecognizer);
92 #endif
93#else
94 registerGestureRecognizer(new QTapAndHoldGestureRecognizer);
95#endif
96}
97
98QGestureManager::~QGestureManager()
99{
100 qDeleteAll(m_recognizers.values());
101 foreach (QGestureRecognizer *recognizer, m_obsoleteGestures.keys()) {
102 qDeleteAll(m_obsoleteGestures.value(recognizer));
103 delete recognizer;
104 }
105 m_obsoleteGestures.clear();
106}
107
108Qt::GestureType QGestureManager::registerGestureRecognizer(QGestureRecognizer *recognizer)
109{
110 QGesture *dummy = recognizer->create(0);
111 if (!dummy) {
112 qWarning("QGestureManager::registerGestureRecognizer: "
113 "the recognizer fails to create a gesture object, skipping registration.");
114 return Qt::GestureType(0);
115 }
116 Qt::GestureType type = dummy->gestureType();
117 if (type == Qt::CustomGesture) {
118 // generate a new custom gesture id
119 ++m_lastCustomGestureId;
120 type = Qt::GestureType(Qt::CustomGesture + m_lastCustomGestureId);
121 }
122 m_recognizers.insertMulti(type, recognizer);
123 delete dummy;
124 return type;
125}
126
127void QGestureManager::unregisterGestureRecognizer(Qt::GestureType type)
128{
129 QList<QGestureRecognizer *> list = m_recognizers.values(type);
130 m_recognizers.remove(type);
131 foreach (QGesture *g, m_gestureToRecognizer.keys()) {
132 QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g);
133 if (list.contains(recognizer)) {
134 m_deletedRecognizers.insert(g, recognizer);
135 m_gestureToRecognizer.remove(g);
136 }
137 }
138
139 foreach (QGestureRecognizer *recognizer, list) {
140 QList<QGesture *> obsoleteGestures;
141 QMap<ObjectGesture, QList<QGesture *> >::Iterator iter = m_objectGestures.begin();
142 while (iter != m_objectGestures.end()) {
143 ObjectGesture objectGesture = iter.key();
144 if (objectGesture.gesture == type)
145 obsoleteGestures << iter.value();
146 ++iter;
147 }
148 m_obsoleteGestures.insert(recognizer, obsoleteGestures);
149 }
150}
151
152void QGestureManager::cleanupCachedGestures(QObject *target, Qt::GestureType type)
153{
154 QMap<ObjectGesture, QList<QGesture *> >::Iterator iter = m_objectGestures.begin();
155 while (iter != m_objectGestures.end()) {
156 ObjectGesture objectGesture = iter.key();
157 if (objectGesture.gesture == type && target == objectGesture.object.data()) {
158 qDeleteAll(iter.value());
159 iter = m_objectGestures.erase(iter);
160 } else {
161 ++iter;
162 }
163 }
164}
165
166// get or create a QGesture object that will represent the state for a given object, used by the recognizer
167QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recognizer, Qt::GestureType type)
168{
169 // if the widget is being deleted we should be carefull and not to
170 // create a new state, as it will create QWeakPointer which doesnt work
171 // from the destructor.
172 if (object->isWidgetType()) {
173 if (static_cast<QWidget *>(object)->d_func()->data.in_destructor)
174 return 0;
175 } else if (QGesture *g = qobject_cast<QGesture *>(object)) {
176 return g;
177#ifndef QT_NO_GRAPHICSVIEW
178 } else {
179 Q_ASSERT(qobject_cast<QGraphicsObject *>(object));
180#endif
181 }
182
183 // check if the QGesture for this recognizer has already been created
184 foreach (QGesture *state, m_objectGestures.value(QGestureManager::ObjectGesture(object, type))) {
185 if (m_gestureToRecognizer.value(state) == recognizer)
186 return state;
187 }
188
189 Q_ASSERT(recognizer);
190 QGesture *state = recognizer->create(object);
191 if (!state)
192 return 0;
193 state->setParent(this);
194 if (state->gestureType() == Qt::CustomGesture) {
195 // if the recognizer didn't fill in the gesture type, then this
196 // is a custom gesture with autogenerated id and we fill it.
197 state->d_func()->gestureType = type;
198#if defined(GESTURE_DEBUG)
199 state->setObjectName(QString::number((int)type));
200#endif
201 }
202 m_objectGestures[QGestureManager::ObjectGesture(object, type)].append(state);
203 m_gestureToRecognizer[state] = recognizer;
204 m_gestureOwners[state] = object;
205
206 return state;
207}
208
209bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *,
210 Qt::GestureType> &contexts,
211 QEvent *event)
212{
213 QSet<QGesture *> triggeredGestures;
214 QSet<QGesture *> finishedGestures;
215 QSet<QGesture *> newMaybeGestures;
216 QSet<QGesture *> notGestures;
217
218 // TODO: sort contexts by the gesture type and check if one of the contexts
219 // is already active.
220
221 bool ret = false;
222
223 // filter the event through recognizers
224 typedef QMultiMap<QObject *, Qt::GestureType>::const_iterator ContextIterator;
225 for (ContextIterator cit = contexts.begin(), ce = contexts.end(); cit != ce; ++cit) {
226 Qt::GestureType gestureType = cit.value();
227 QMap<Qt::GestureType, QGestureRecognizer *>::const_iterator
228 rit = m_recognizers.lowerBound(gestureType),
229 re = m_recognizers.upperBound(gestureType);
230 for (; rit != re; ++rit) {
231 QGestureRecognizer *recognizer = rit.value();
232 QObject *target = cit.key();
233 QGesture *state = getState(target, recognizer, gestureType);
234 if (!state)
235 continue;
236 QGestureRecognizer::Result result = recognizer->recognize(state, target, event);
237 QGestureRecognizer::Result type = result & QGestureRecognizer::ResultState_Mask;
238 result &= QGestureRecognizer::ResultHint_Mask;
239 if (type == QGestureRecognizer::TriggerGesture) {
240 DEBUG() << "QGestureManager:Recognizer: gesture triggered: " << state;
241 triggeredGestures << state;
242 } else if (type == QGestureRecognizer::FinishGesture) {
243 DEBUG() << "QGestureManager:Recognizer: gesture finished: " << state;
244 finishedGestures << state;
245 } else if (type == QGestureRecognizer::MayBeGesture) {
246 DEBUG() << "QGestureManager:Recognizer: maybe gesture: " << state;
247 newMaybeGestures << state;
248 } else if (type == QGestureRecognizer::CancelGesture) {
249 DEBUG() << "QGestureManager:Recognizer: not gesture: " << state;
250 notGestures << state;
251 } else if (type == QGestureRecognizer::Ignore) {
252 DEBUG() << "QGestureManager:Recognizer: ignored the event: " << state;
253 } else {
254 DEBUG() << "QGestureManager:Recognizer: hm, lets assume the recognizer"
255 << "ignored the event: " << state;
256 }
257 if (result & QGestureRecognizer::ConsumeEventHint) {
258 DEBUG() << "QGestureManager: we were asked to consume the event: "
259 << state;
260 ret = true;
261 }
262 }
263 }
264 if (triggeredGestures.isEmpty() && finishedGestures.isEmpty()
265 && newMaybeGestures.isEmpty() && notGestures.isEmpty())
266 return ret;
267
268 QSet<QGesture *> startedGestures = triggeredGestures - m_activeGestures;
269 triggeredGestures &= m_activeGestures;
270
271 // check if a running gesture switched back to maybe state
272 QSet<QGesture *> activeToMaybeGestures = m_activeGestures & newMaybeGestures;
273
274 // check if a running gesture switched back to not gesture state,
275 // i.e. were canceled
276 QSet<QGesture *> canceledGestures = m_activeGestures & notGestures;
277
278 // start timers for new gestures in maybe state
279 foreach (QGesture *state, newMaybeGestures) {
280 QBasicTimer &timer = m_maybeGestures[state];
281 if (!timer.isActive())
282 timer.start(3000, this);
283 }
284 // kill timers for gestures that were in maybe state
285 QSet<QGesture *> notMaybeGestures = (startedGestures | triggeredGestures
286 | finishedGestures | canceledGestures
287 | notGestures);
288 foreach(QGesture *gesture, notMaybeGestures) {
289 QHash<QGesture *, QBasicTimer>::iterator it =
290 m_maybeGestures.find(gesture);
291 if (it != m_maybeGestures.end()) {
292 it.value().stop();
293 m_maybeGestures.erase(it);
294 }
295 }
296
297 Q_ASSERT((startedGestures & finishedGestures).isEmpty());
298 Q_ASSERT((startedGestures & newMaybeGestures).isEmpty());
299 Q_ASSERT((startedGestures & canceledGestures).isEmpty());
300 Q_ASSERT((finishedGestures & newMaybeGestures).isEmpty());
301 Q_ASSERT((finishedGestures & canceledGestures).isEmpty());
302 Q_ASSERT((canceledGestures & newMaybeGestures).isEmpty());
303
304 QSet<QGesture *> notStarted = finishedGestures - m_activeGestures;
305 if (!notStarted.isEmpty()) {
306 // there are some gestures that claim to be finished, but never started.
307 // probably those are "singleshot" gestures so we'll fake the started state.
308 foreach (QGesture *gesture, notStarted)
309 gesture->d_func()->state = Qt::GestureStarted;
310 QSet<QGesture *> undeliveredGestures;
311 deliverEvents(notStarted, &undeliveredGestures);
312 finishedGestures -= undeliveredGestures;
313 }
314
315 m_activeGestures += startedGestures;
316 // sanity check: all triggered gestures should already be in active gestures list
317 Q_ASSERT((m_activeGestures & triggeredGestures).size() == triggeredGestures.size());
318 m_activeGestures -= finishedGestures;
319 m_activeGestures -= activeToMaybeGestures;
320 m_activeGestures -= canceledGestures;
321
322 // set the proper gesture state on each gesture
323 foreach (QGesture *gesture, startedGestures)
324 gesture->d_func()->state = Qt::GestureStarted;
325 foreach (QGesture *gesture, triggeredGestures)
326 gesture->d_func()->state = Qt::GestureUpdated;
327 foreach (QGesture *gesture, finishedGestures)
328 gesture->d_func()->state = Qt::GestureFinished;
329 foreach (QGesture *gesture, canceledGestures)
330 gesture->d_func()->state = Qt::GestureCanceled;
331 foreach (QGesture *gesture, activeToMaybeGestures)
332 gesture->d_func()->state = Qt::GestureFinished;
333
334 if (!m_activeGestures.isEmpty() || !m_maybeGestures.isEmpty() ||
335 !startedGestures.isEmpty() || !triggeredGestures.isEmpty() ||
336 !finishedGestures.isEmpty() || !canceledGestures.isEmpty()) {
337 DEBUG() << "QGestureManager::filterEventThroughContexts:"
338 << "\n\tactiveGestures:" << m_activeGestures
339 << "\n\tmaybeGestures:" << m_maybeGestures.keys()
340 << "\n\tstarted:" << startedGestures
341 << "\n\ttriggered:" << triggeredGestures
342 << "\n\tfinished:" << finishedGestures
343 << "\n\tcanceled:" << canceledGestures;
344 }
345
346 QSet<QGesture *> undeliveredGestures;
347 deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures,
348 &undeliveredGestures);
349
350 foreach (QGesture *g, startedGestures) {
351 if (undeliveredGestures.contains(g))
352 continue;
353 if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
354 DEBUG() << "lets try to cancel some";
355 // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
356 cancelGesturesForChildren(g);
357 }
358 }
359
360 m_activeGestures -= undeliveredGestures;
361
362 // reset gestures that ended
363 QSet<QGesture *> endedGestures =
364 finishedGestures + canceledGestures + undeliveredGestures;
365 foreach (QGesture *gesture, endedGestures) {
366 recycle(gesture);
367 m_gestureTargets.remove(gesture);
368 }
369 return ret;
370}
371
372// Cancel all gestures of children of the widget that original is associated with
373void QGestureManager::cancelGesturesForChildren(QGesture *original)
374{
375 Q_ASSERT(original);
376 QWidget *originatingWidget = m_gestureTargets.value(original);
377 Q_ASSERT(originatingWidget);
378
379 // iterate over all active gestures and all maybe gestures
380 // for each find the owner
381 // if the owner is part of our sub-hierarchy, cancel it.
382
383 QSet<QGesture*> cancelledGestures;
384 QSet<QGesture*>::Iterator iter = m_activeGestures.begin();
385 while (iter != m_activeGestures.end()) {
386 QWidget *widget = m_gestureTargets.value(*iter);
387 // note that we don't touch the gestures for our originatingWidget
388 if (widget != originatingWidget && originatingWidget->isAncestorOf(widget)) {
389 DEBUG() << " found a gesture to cancel" << (*iter);
390 (*iter)->d_func()->state = Qt::GestureCanceled;
391 cancelledGestures << *iter;
392 iter = m_activeGestures.erase(iter);
393 } else {
394 ++iter;
395 }
396 }
397
398 // TODO handle 'maybe' gestures too
399
400 // sort them per target widget by cherry picking from almostCanceledGestures and delivering
401 QSet<QGesture *> almostCanceledGestures = cancelledGestures;
402 while (!almostCanceledGestures.isEmpty()) {
403 QWidget *target = 0;
404 QSet<QGesture*> gestures;
405 iter = almostCanceledGestures.begin();
406 // sort per target widget
407 while (iter != almostCanceledGestures.end()) {
408 QWidget *widget = m_gestureTargets.value(*iter);
409 if (target == 0)
410 target = widget;
411 if (target == widget) {
412 gestures << *iter;
413 iter = almostCanceledGestures.erase(iter);
414 } else {
415 ++iter;
416 }
417 }
418 Q_ASSERT(target);
419
420 QSet<QGesture*> undeliveredGestures;
421 deliverEvents(gestures, &undeliveredGestures);
422 }
423
424 for (iter = cancelledGestures.begin(); iter != cancelledGestures.end(); ++iter)
425 recycle(*iter);
426}
427
428void QGestureManager::cleanupGesturesForRemovedRecognizer(QGesture *gesture)
429{
430 QGestureRecognizer *recognizer = m_deletedRecognizers.value(gesture);
431 Q_ASSERT(recognizer);
432 m_deletedRecognizers.remove(gesture);
433 if (m_deletedRecognizers.keys(recognizer).isEmpty()) {
434 // no more active gestures, cleanup!
435 qDeleteAll(m_obsoleteGestures.value(recognizer));
436 m_obsoleteGestures.remove(recognizer);
437 delete recognizer;
438 }
439}
440
441// return true if accepted (consumed)
442bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event)
443{
444 QMap<Qt::GestureType, int> types;
445 QMultiMap<QObject *, Qt::GestureType> contexts;
446 QWidget *w = receiver;
447 typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator;
448 if (!w->d_func()->gestureContext.isEmpty()) {
449 for(ContextIterator it = w->d_func()->gestureContext.begin(),
450 e = w->d_func()->gestureContext.end(); it != e; ++it) {
451 types.insert(it.key(), 0);
452 contexts.insertMulti(w, it.key());
453 }
454 }
455 // find all gesture contexts for the widget tree
456 w = w->isWindow() ? 0 : w->parentWidget();
457 while (w)
458 {
459 for (ContextIterator it = w->d_func()->gestureContext.begin(),
460 e = w->d_func()->gestureContext.end(); it != e; ++it) {
461 if (!(it.value() & Qt::DontStartGestureOnChildren)) {
462 if (!types.contains(it.key())) {
463 types.insert(it.key(), 0);
464 contexts.insertMulti(w, it.key());
465 }
466 }
467 }
468 if (w->isWindow())
469 break;
470 w = w->parentWidget();
471 }
472 return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event);
473}
474
475#ifndef QT_NO_GRAPHICSVIEW
476bool QGestureManager::filterEvent(QGraphicsObject *receiver, QEvent *event)
477{
478 QMap<Qt::GestureType, int> types;
479 QMultiMap<QObject *, Qt::GestureType> contexts;
480 QGraphicsObject *item = receiver;
481 if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) {
482 typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator;
483 for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(),
484 e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) {
485 types.insert(it.key(), 0);
486 contexts.insertMulti(item, it.key());
487 }
488 }
489 // find all gesture contexts for the graphics object tree
490 item = item->parentObject();
491 while (item)
492 {
493 typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator;
494 for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(),
495 e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) {
496 if (!(it.value() & Qt::DontStartGestureOnChildren)) {
497 if (!types.contains(it.key())) {
498 types.insert(it.key(), 0);
499 contexts.insertMulti(item, it.key());
500 }
501 }
502 }
503 item = item->parentObject();
504 }
505 return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event);
506}
507#endif
508
509bool QGestureManager::filterEvent(QObject *receiver, QEvent *event)
510{
511 if (!m_gestureToRecognizer.contains(static_cast<QGesture *>(receiver)))
512 return false;
513 QGesture *state = static_cast<QGesture *>(receiver);
514 QMultiMap<QObject *, Qt::GestureType> contexts;
515 contexts.insert(state, state->gestureType());
516 return filterEventThroughContexts(contexts, event);
517}
518
519void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures,
520 QMap<QWidget *, QList<QGesture *> > *conflicts,
521 QMap<QWidget *, QList<QGesture *> > *normal)
522{
523 typedef QHash<Qt::GestureType, QHash<QWidget *, QGesture *> > GestureByTypes;
524 GestureByTypes gestureByTypes;
525
526 // sort gestures by types
527 foreach (QGesture *gesture, gestures) {
528 QWidget *receiver = m_gestureTargets.value(gesture, 0);
529 Q_ASSERT(receiver);
530 gestureByTypes[gesture->gestureType()].insert(receiver, gesture);
531 }
532
533 // for each gesture type
534 foreach (Qt::GestureType type, gestureByTypes.keys()) {
535 QHash<QWidget *, QGesture *> gestures = gestureByTypes.value(type);
536 foreach (QWidget *widget, gestures.keys()) {
537 QWidget *w = widget->parentWidget();
538 while (w) {
539 QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator it
540 = w->d_func()->gestureContext.find(type);
541 if (it != w->d_func()->gestureContext.end()) {
542 // i.e. 'w' listens to gesture 'type'
543 Qt::GestureFlags flags = it.value();
544 if (!(it.value() & Qt::DontStartGestureOnChildren) && w != widget) {
545 // conflicting gesture!
546 (*conflicts)[widget].append(gestures[widget]);
547 break;
548 }
549 }
550 if (w->isWindow()) {
551 w = 0;
552 break;
553 }
554 w = w->parentWidget();
555 }
556 if (!w)
557 (*normal)[widget].append(gestures[widget]);
558 }
559 }
560}
561
562void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
563 QSet<QGesture *> *undeliveredGestures)
564{
565 if (gestures.isEmpty())
566 return;
567
568 typedef QMap<QWidget *, QList<QGesture *> > GesturesPerWidget;
569 GesturesPerWidget conflictedGestures;
570 GesturesPerWidget normalStartedGestures;
571
572 QSet<QGesture *> startedGestures;
573 // first figure out the initial receivers of gestures
574 for (QSet<QGesture *>::const_iterator it = gestures.begin(),
575 e = gestures.end(); it != e; ++it) {
576 QGesture *gesture = *it;
577 QWidget *target = m_gestureTargets.value(gesture, 0);
578 if (!target) {
579 // the gesture has just started and doesn't have a target yet.
580 Q_ASSERT(gesture->state() == Qt::GestureStarted);
581 if (gesture->hasHotSpot()) {
582 // guess the target widget using the hotspot of the gesture
583 QPoint pt = gesture->hotSpot().toPoint();
584 if (QWidget *w = qApp->topLevelAt(pt)) {
585 target = w->childAt(w->mapFromGlobal(pt));
586 }
587 } else {
588 // or use the context of the gesture
589 QObject *context = m_gestureOwners.value(gesture, 0);
590 if (context->isWidgetType())
591 target = static_cast<QWidget *>(context);
592 }
593 if (target)
594 m_gestureTargets.insert(gesture, target);
595 }
596
597 Qt::GestureType gestureType = gesture->gestureType();
598 Q_ASSERT(gestureType != Qt::CustomGesture);
599 Q_UNUSED(gestureType);
600
601 if (target) {
602 if (gesture->state() == Qt::GestureStarted) {
603 startedGestures.insert(gesture);
604 } else {
605 normalStartedGestures[target].append(gesture);
606 }
607 } else {
608 DEBUG() << "QGestureManager::deliverEvent: could not find the target for gesture"
609 << gesture->gestureType();
610 qWarning("QGestureManager::deliverEvent: could not find the target for gesture");
611 undeliveredGestures->insert(gesture);
612 }
613 }
614
615 getGestureTargets(startedGestures, &conflictedGestures, &normalStartedGestures);
616 DEBUG() << "QGestureManager::deliverEvents:"
617 << "\nstarted: " << startedGestures
618 << "\nconflicted: " << conflictedGestures
619 << "\nnormal: " << normalStartedGestures
620 << "\n";
621
622 // if there are conflicting gestures, send the GestureOverride event
623 for (GesturesPerWidget::const_iterator it = conflictedGestures.begin(),
624 e = conflictedGestures.end(); it != e; ++it) {
625 QWidget *receiver = it.key();
626 QList<QGesture *> gestures = it.value();
627 DEBUG() << "QGestureManager::deliverEvents: sending GestureOverride to"
628 << receiver
629 << "gestures:" << gestures;
630 QGestureEvent event(gestures);
631 event.t = QEvent::GestureOverride;
632 // mark event and individual gestures as ignored
633 event.ignore();
634 foreach(QGesture *g, gestures)
635 event.setAccepted(g, false);
636
637 QApplication::sendEvent(receiver, &event);
638 bool eventAccepted = event.isAccepted();
639 foreach(QGesture *gesture, event.gestures()) {
640 if (eventAccepted || event.isAccepted(gesture)) {
641 QWidget *w = event.d_func()->targetWidgets.value(gesture->gestureType(), 0);
642 Q_ASSERT(w);
643 DEBUG() << "override event: gesture was accepted:" << gesture << w;
644 QList<QGesture *> &gestures = normalStartedGestures[w];
645 gestures.append(gesture);
646 // override the target
647 m_gestureTargets[gesture] = w;
648 } else {
649 DEBUG() << "override event: gesture wasn't accepted. putting back:" << gesture;
650 QList<QGesture *> &gestures = normalStartedGestures[receiver];
651 gestures.append(gesture);
652 }
653 }
654 }
655
656 // delivering gestures that are not in conflicted state
657 for (GesturesPerWidget::const_iterator it = normalStartedGestures.begin(),
658 e = normalStartedGestures.end(); it != e; ++it) {
659 if (!it.value().isEmpty()) {
660 DEBUG() << "QGestureManager::deliverEvents: sending to" << it.key()
661 << "gestures:" << it.value();
662 QGestureEvent event(it.value());
663 QApplication::sendEvent(it.key(), &event);
664 bool eventAccepted = event.isAccepted();
665 foreach (QGesture *gesture, event.gestures()) {
666 if (gesture->state() == Qt::GestureStarted &&
667 (eventAccepted || event.isAccepted(gesture))) {
668 QWidget *w = event.d_func()->targetWidgets.value(gesture->gestureType(), 0);
669 Q_ASSERT(w);
670 DEBUG() << "started gesture was delivered and accepted by" << w;
671 m_gestureTargets[gesture] = w;
672 }
673 }
674 }
675 }
676}
677
678void QGestureManager::timerEvent(QTimerEvent *event)
679{
680 QHash<QGesture *, QBasicTimer>::iterator it = m_maybeGestures.begin(),
681 e = m_maybeGestures.end();
682 for (; it != e; ) {
683 QBasicTimer &timer = it.value();
684 Q_ASSERT(timer.isActive());
685 if (timer.timerId() == event->timerId()) {
686 timer.stop();
687 QGesture *gesture = it.key();
688 it = m_maybeGestures.erase(it);
689 DEBUG() << "QGestureManager::timerEvent: gesture stopped due to timeout:"
690 << gesture;
691 recycle(gesture);
692 } else {
693 ++it;
694 }
695 }
696}
697
698void QGestureManager::recycle(QGesture *gesture)
699{
700 QGestureRecognizer *recognizer = m_gestureToRecognizer.value(gesture, 0);
701 if (recognizer) {
702 gesture->setGestureCancelPolicy(QGesture::CancelNone);
703 recognizer->reset(gesture);
704 } else {
705 cleanupGesturesForRemovedRecognizer(gesture);
706 }
707}
708
709QT_END_NAMESPACE
710
711#include "moc_qgesturemanager_p.cpp"
Note: See TracBrowser for help on using the repository browser.