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

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

trunk: Merged in qt 4.6.1 sources.

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