summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Dzyubenko <denis.dzyubenko@nokia.com>2009-10-19 14:20:02 +0200
committerDenis Dzyubenko <denis.dzyubenko@nokia.com>2009-10-22 16:59:19 +0200
commit0c7254e1c5a20450495afe80c1ad5246e5e48314 (patch)
tree0178591741e39aaeb8c7514eea8c60177d4faa9c
parent0b61c5e284462376afab15ac9189d759b859ec46 (diff)
Improvements for gesture event delivery
When delivering GestureOverride events by default both the event and individual gestures will be ignored. We also store the acceptance state of individual gesture in the event and not in the gesture object, along with its target. Reviewed-by: Thomas Zander
-rw-r--r--src/gui/kernel/qapplication.cpp32
-rw-r--r--src/gui/kernel/qevent.cpp48
-rw-r--r--src/gui/kernel/qevent.h7
-rw-r--r--src/gui/kernel/qevent_p.h14
-rw-r--r--src/gui/kernel/qgesture_p.h3
-rw-r--r--src/gui/kernel/qgesturemanager.cpp28
-rw-r--r--tests/auto/gestures/tst_gestures.cpp66
7 files changed, 156 insertions, 42 deletions
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index af1c1c8196..7c38d4b299 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -4170,41 +4170,41 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
if (wd->gestureContext.contains(type)) {
allGestures.removeAt(i);
gestures.append(g);
- gestureEvent->setAccepted(g, false);
} else {
++i;
}
}
- if (!gestures.isEmpty()) {
+ if (!gestures.isEmpty()) { // we have gestures for this w
QGestureEvent ge(gestures);
ge.t = gestureEvent->t;
ge.spont = gestureEvent->spont;
ge.m_accept = wasAccepted;
+ ge.d_func()->accepted = gestureEvent->d_func()->accepted;
res = d->notify_helper(w, &ge);
gestureEvent->spont = false;
eventAccepted = ge.isAccepted();
- if (res && eventAccepted && allGestures.isEmpty())
- break;
- if (!eventAccepted) {
- // ### two ways to ignore the event/gesture
-
- // if the whole event wasn't accepted, put back those
- // gestures that were not accepted.
- for (int i = 0; i < gestures.size(); ++i) {
- QGesture *g = gestures.at(i);
- if (!ge.isAccepted(g))
- allGestures.append(g);
+ for (int i = 0; i < gestures.size(); ++i) {
+ QGesture *g = gestures.at(i);
+ if ((res && eventAccepted) || (!eventAccepted && ge.isAccepted(g))) {
+ // if the gesture was accepted, mark the target widget for it
+ gestureEvent->d_func()->targetWidgets[g->gestureType()] = w;
+ gestureEvent->setAccepted(g, true);
+ } else if (!eventAccepted && !ge.isAccepted(g)) {
+ // if the gesture was explicitly ignored by the application,
+ // put it back so a parent can get it
+ allGestures.append(g);
}
}
}
- if (allGestures.isEmpty())
+ if (allGestures.isEmpty()) // everything delivered
break;
if (w->isWindow())
break;
w = w->parentWidget();
}
- gestureEvent->m_accept = eventAccepted;
- gestureEvent->gestures_ = allGestures;
+ foreach (QGesture *g, allGestures)
+ gestureEvent->setAccepted(g, false);
+ gestureEvent->m_accept = false; // to make sure we check individual gestures
} else {
res = d->notify_helper(receiver, e);
}
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index e49de02fb7..1c6a8203cb 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -4223,8 +4223,17 @@ QTouchEvent::TouchPoint &QTouchEvent::TouchPoint::operator=(const QTouchEvent::T
Creates new QGestureEvent containing a list of \a gestures.
*/
QGestureEvent::QGestureEvent(const QList<QGesture *> &gestures)
- : QEvent(QEvent::Gesture), gestures_(gestures)
+ : QEvent(QEvent::Gesture)
{
+ d = reinterpret_cast<QEventPrivate *>(new QGestureEventPrivate(gestures));
+}
+
+/*!
+ Destroys QGestureEvent.
+*/
+QGestureEvent::~QGestureEvent()
+{
+ delete reinterpret_cast<QGestureEventPrivate *>(d);
}
/*!
@@ -4232,7 +4241,7 @@ QGestureEvent::QGestureEvent(const QList<QGesture *> &gestures)
*/
QList<QGesture *> QGestureEvent::allGestures() const
{
- return gestures_;
+ return d_func()->gestures;
}
/*!
@@ -4240,9 +4249,10 @@ QList<QGesture *> QGestureEvent::allGestures() const
*/
QGesture *QGestureEvent::gesture(Qt::GestureType type) const
{
- for(int i = 0; i < gestures_.size(); ++i)
- if (gestures_.at(i)->gestureType() == type)
- return gestures_.at(i);
+ const QGestureEventPrivate *d = d_func();
+ for(int i = 0; i < d->gestures.size(); ++i)
+ if (d->gestures.at(i)->gestureType() == type)
+ return d->gestures.at(i);
return 0;
}
@@ -4251,7 +4261,7 @@ QGesture *QGestureEvent::gesture(Qt::GestureType type) const
*/
QList<QGesture *> QGestureEvent::activeGestures() const
{
- return gestures_;
+ return d_func()->gestures;
}
/*!
@@ -4259,7 +4269,7 @@ QList<QGesture *> QGestureEvent::activeGestures() const
*/
QList<QGesture *> QGestureEvent::canceledGestures() const
{
- return gestures_;
+ return d_func()->gestures;
}
/*!
@@ -4279,7 +4289,7 @@ void QGestureEvent::setAccepted(QGesture *gesture, bool value)
{
setAccepted(false);
if (gesture)
- gesture->d_func()->accept = value;
+ d_func()->accepted[gesture->gestureType()] = value;
}
/*!
@@ -4315,7 +4325,7 @@ void QGestureEvent::ignore(QGesture *gesture)
*/
bool QGestureEvent::isAccepted(QGesture *gesture) const
{
- return gesture ? gesture->d_func()->accept : false;
+ return gesture ? d_func()->accepted.value(gesture->gestureType(), true) : false;
}
/*!
@@ -4323,7 +4333,7 @@ bool QGestureEvent::isAccepted(QGesture *gesture) const
*/
void QGestureEvent::setWidget(QWidget *widget)
{
- widget_ = widget;
+ d_func()->widget = widget;
}
/*!
@@ -4331,7 +4341,23 @@ void QGestureEvent::setWidget(QWidget *widget)
*/
QWidget *QGestureEvent::widget() const
{
- return widget_;
+ return d_func()->widget;
+}
+
+/*!
+ \internal
+*/
+QGestureEventPrivate *QGestureEvent::d_func()
+{
+ return reinterpret_cast<QGestureEventPrivate *>(d);
+}
+
+/*!
+ \internal
+*/
+const QGestureEventPrivate *QGestureEvent::d_func() const
+{
+ return reinterpret_cast<const QGestureEventPrivate *>(d);
}
#ifdef Q_NO_USING_KEYWORD
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index 1ba2d41949..5eefc2d3eb 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -820,10 +820,12 @@ protected:
};
class QGesture;
+class QGestureEventPrivate;
class Q_GUI_EXPORT QGestureEvent : public QEvent
{
public:
QGestureEvent(const QList<QGesture *> &gestures);
+ ~QGestureEvent();
QList<QGesture *> allGestures() const;
QGesture *gesture(Qt::GestureType type) const;
@@ -854,10 +856,11 @@ public:
QWidget *widget() const;
private:
- QList<QGesture *> gestures_;
- QWidget *widget_;
+ QGestureEventPrivate *d_func();
+ const QGestureEventPrivate *d_func() const;
friend class QApplication;
+ friend class QGestureManager;
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h
index c7a4975ea5..6e6ab01e97 100644
--- a/src/gui/kernel/qevent_p.h
+++ b/src/gui/kernel/qevent_p.h
@@ -150,6 +150,20 @@ public:
#endif
};
+class QGestureEventPrivate
+{
+public:
+ inline QGestureEventPrivate(const QList<QGesture *> &list)
+ : gestures(list), widget(0)
+ {
+ }
+
+ QList<QGesture *> gestures;
+ QWidget *widget;
+ QMap<Qt::GestureType, bool> accepted;
+ QMap<Qt::GestureType, QWidget *> targetWidgets;
+};
+
QT_END_NAMESPACE
#endif // QEVENT_P_H
diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h
index 7f69a4e906..10887f6bab 100644
--- a/src/gui/kernel/qgesture_p.h
+++ b/src/gui/kernel/qgesture_p.h
@@ -68,7 +68,7 @@ class QGesturePrivate : public QObjectPrivate
public:
QGesturePrivate()
: gestureType(Qt::CustomGesture), state(Qt::NoGesture), isHotSpotSet(false),
- targetObject(0), accept(true)
+ targetObject(0)
{
}
@@ -77,7 +77,6 @@ public:
QPointF hotSpot;
bool isHotSpotSet;
QObject *targetObject;
- bool accept;
};
class QPanGesturePrivate : public QGesturePrivate
diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp
index f8e1e49f97..b4913f0992 100644
--- a/src/gui/kernel/qgesturemanager.cpp
+++ b/src/gui/kernel/qgesturemanager.cpp
@@ -44,6 +44,7 @@
#include "private/qwidget_p.h"
#include "private/qgesture_p.h"
#include "private/qgraphicsitem_p.h"
+#include "private/qevent_p.h"
#include "qgesture.h"
#include "qevent.h"
#include "qgraphicsitem.h"
@@ -478,17 +479,26 @@ void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
<< "gestures:" << gestures;
QGestureEvent event(gestures);
event.t = QEvent::GestureOverride;
+ // mark event and individual gestures as ignored
event.ignore();
+ foreach(QGesture *g, gestures)
+ event.setAccepted(g, false);
+
QApplication::sendEvent(receiver, &event);
- if (!event.isAccepted()) {
- // nobody accepted the GestureOverride, put gestures that were not
- // accepted back to deliver as usual
- QList<QGesture *> &gestures = normalStartedGestures[receiver];
- foreach(QGesture *gesture, event.allGestures()) {
- if (!event.isAccepted(gesture)) {
- DEBUG() << "override event wasn't accepted. putting back:" << gesture;
- gestures.append(gesture);
- }
+ bool eventAccepted = event.isAccepted();
+ foreach(QGesture *gesture, event.allGestures()) {
+ if (eventAccepted || event.isAccepted(gesture)) {
+ QWidget *w = event.d_func()->targetWidgets.value(gesture->gestureType(), 0);
+ Q_ASSERT(w);
+ DEBUG() << "override event: gesture was accepted:" << gesture << w;
+ QList<QGesture *> &gestures = normalStartedGestures[w];
+ gestures.append(gesture);
+ // override the target
+ gestureTargets[gesture] = w;
+ } else {
+ DEBUG() << "override event: gesture wasn't accepted. putting back:" << gesture;
+ QList<QGesture *> &gestures = normalStartedGestures[receiver];
+ gestures.append(gesture);
}
}
}
diff --git a/tests/auto/gestures/tst_gestures.cpp b/tests/auto/gestures/tst_gestures.cpp
index 4d072bcff8..28dd40caa7 100644
--- a/tests/auto/gestures/tst_gestures.cpp
+++ b/tests/auto/gestures/tst_gestures.cpp
@@ -144,6 +144,49 @@ public:
}
};
+// same as CustomGestureRecognizer but triggers early without the maybe state
+class CustomContinuousGestureRecognizer : public QGestureRecognizer
+{
+public:
+ CustomContinuousGestureRecognizer()
+ {
+ if (!CustomEvent::EventType)
+ CustomEvent::EventType = QEvent::registerEventType();
+ }
+
+ QGesture* createGesture(QObject *)
+ {
+ return new CustomGesture;
+ }
+
+ QGestureRecognizer::Result filterEvent(QGesture *state, QObject*, QEvent *event)
+ {
+ if (event->type() == CustomEvent::EventType) {
+ QGestureRecognizer::Result result = QGestureRecognizer::ConsumeEventHint;
+ CustomGesture *g = static_cast<CustomGesture*>(state);
+ CustomEvent *e = static_cast<CustomEvent*>(event);
+ g->serial = e->serial;
+ if (e->hasHotSpot)
+ g->setHotSpot(e->hotSpot);
+ if (g->serial >= CustomGesture::SerialFinishedThreshold)
+ result |= QGestureRecognizer::GestureFinished;
+ else if (g->serial >= CustomGesture::SerialMaybeThreshold)
+ result |= QGestureRecognizer::GestureTriggered;
+ else
+ result = QGestureRecognizer::NotGesture;
+ return result;
+ }
+ return QGestureRecognizer::Ignore;
+ }
+
+ void reset(QGesture *state)
+ {
+ CustomGesture *g = static_cast<CustomGesture*>(state);
+ g->serial = 0;
+ QGestureRecognizer::reset(state);
+ }
+};
+
class GestureWidget : public QWidget
{
Q_OBJECT
@@ -163,6 +206,7 @@ public:
gestureOverrideEventsReceived = 0;
events.clear();
overrideEvents.clear();
+ ignoredGestures.clear();
}
int customEventsReceived;
@@ -450,7 +494,7 @@ void tst_Gestures::conflictingGestures()
sendCustomGesture(&event, child);
QCOMPARE(child->gestureOverrideEventsReceived, 1);
- QCOMPARE(child->gestureEventsReceived, 0);
+ QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
QCOMPARE(parent.gestureOverrideEventsReceived, 0);
QCOMPARE(parent.gestureEventsReceived, 0);
@@ -467,7 +511,7 @@ void tst_Gestures::conflictingGestures()
QCOMPARE(child->gestureOverrideEventsReceived, 1);
QCOMPARE(child->gestureEventsReceived, 0);
QCOMPARE(parent.gestureOverrideEventsReceived, 1);
- QCOMPARE(parent.gestureEventsReceived, 0);
+ QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
parent.reset();
child->reset();
@@ -475,6 +519,7 @@ void tst_Gestures::conflictingGestures()
// nobody accepts the override, we will send normal events to the closest context (to the child)
parent.acceptGestureOverride = false;
child->acceptGestureOverride = false;
+ child->ignoredGestures << CustomGesture::GestureType;
// sending events to the child and making sure there is no conflict
sendCustomGesture(&event, child);
@@ -482,6 +527,23 @@ void tst_Gestures::conflictingGestures()
QCOMPARE(child->gestureOverrideEventsReceived, 1);
QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
QCOMPARE(parent.gestureOverrideEventsReceived, 1);
+ QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
+
+ parent.reset();
+ child->reset();
+
+ Qt::GestureType ContinuousGesture = qApp->registerGestureRecognizer(new CustomContinuousGestureRecognizer);
+ static const int ContinuousGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
+ child->grabGesture(ContinuousGesture);
+ // child accepts override. And it also receives another custom gesture.
+ parent.acceptGestureOverride = false;
+ child->acceptGestureOverride = true;
+ sendCustomGesture(&event, child);
+
+ QCOMPARE(child->gestureOverrideEventsReceived, 1);
+ QVERIFY(child->gestureEventsReceived > TotalGestureEventsCount);
+ QCOMPARE(child->events.all.count(), TotalGestureEventsCount + ContinuousGestureEventsCount);
+ QCOMPARE(parent.gestureOverrideEventsReceived, 0);
QCOMPARE(parent.gestureEventsReceived, 0);
}