summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDenis Dzyubenko <denis.dzyubenko@nokia.com>2009-10-15 19:00:24 (GMT)
committerDenis Dzyubenko <denis.dzyubenko@nokia.com>2009-10-22 14:59:18 (GMT)
commit0b61c5e284462376afab15ac9189d759b859ec46 (patch)
treed959820f8e4f3664d45ee971fee508422ab116ee /src
parentc5c1b878891b5ace5a71b95ea62229e26722fdba (diff)
downloadQt-0b61c5e284462376afab15ac9189d759b859ec46.zip
Qt-0b61c5e284462376afab15ac9189d759b859ec46.tar.gz
Qt-0b61c5e284462376afab15ac9189d759b859ec46.tar.bz2
Improving gesture event delivery for widgets.
Reviewed-by: trustme
Diffstat (limited to 'src')
-rw-r--r--src/gui/kernel/qapplication.cpp1
-rw-r--r--src/gui/kernel/qevent.h2
-rw-r--r--src/gui/kernel/qgesturemanager.cpp214
-rw-r--r--src/gui/kernel/qgesturemanager_p.h12
4 files changed, 148 insertions, 81 deletions
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index aee8afc..af1c1c8 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -4204,6 +4204,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
w = w->parentWidget();
}
gestureEvent->m_accept = eventAccepted;
+ gestureEvent->gestures_ = allGestures;
} else {
res = d->notify_helper(receiver, e);
}
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index 6cba5fb..1ba2d41 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -856,6 +856,8 @@ public:
private:
QList<QGesture *> gestures_;
QWidget *widget_;
+
+ friend class QApplication;
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp
index 8928d1c..f8e1e49 100644
--- a/src/gui/kernel/qgesturemanager.cpp
+++ b/src/gui/kernel/qgesturemanager.cpp
@@ -122,7 +122,7 @@ QGesture *QGestureManager::getState(QObject *object, Qt::GestureType type)
Q_ASSERT(qobject_cast<QGraphicsObject *>(object));
}
- QWeakPointer<QGesture> state =
+ QGesture *state =
objectGestures.value(QGestureManager::ObjectGesture(object, type));
if (!state) {
QGestureRecognizer *recognizer = recognizers.value(type);
@@ -130,21 +130,25 @@ QGesture *QGestureManager::getState(QObject *object, Qt::GestureType type)
state = recognizer->createGesture(object);
if (!state)
return 0;
- if (state.data()->gestureType() == Qt::CustomGesture) {
+ if (state->gestureType() == Qt::CustomGesture) {
// if the recognizer didn't fill in the gesture type, then this
// is a custom gesture with autogenerated it and we fill it.
- state.data()->d_func()->gestureType = type;
+ state->d_func()->gestureType = type;
+#if defined(GESTURE_DEBUG)
+ state->setObjectName(QString::number((int)type));
+#endif
}
objectGestures.insert(QGestureManager::ObjectGesture(object, type), state);
- gestureToRecognizer[state.data()] = recognizer;
+ gestureToRecognizer[state] = recognizer;
+ gestureOwners[state] = object;
}
}
- return state.data();
+ return state;
}
bool QGestureManager::filterEventThroughContexts(const QMap<QObject *,
Qt::GestureType> &contexts,
- QObject *receiver, QEvent *event)
+ QEvent *event)
{
QSet<QGesture *> triggeredGestures;
QSet<QGesture *> finishedGestures;
@@ -152,6 +156,9 @@ bool QGestureManager::filterEventThroughContexts(const QMap<QObject *,
QSet<QGesture *> canceledGestures;
QSet<QGesture *> notGestures;
+ // TODO: sort contexts by the gesture type and check if one of the contexts
+ // is already active.
+
// filter the event through recognizers
typedef QMap<QObject *, Qt::GestureType>::const_iterator ContextIterator;
for (ContextIterator cit = contexts.begin(), ce = contexts.end(); cit != ce; ++cit) {
@@ -237,7 +244,7 @@ bool QGestureManager::filterEventThroughContexts(const QMap<QObject *,
foreach (QGesture *gesture, notStarted)
gesture->d_func()->state = Qt::GestureStarted;
QSet<QGesture *> undeliveredGestures;
- deliverEvents(notStarted, receiver, &undeliveredGestures);
+ deliverEvents(notStarted, &undeliveredGestures);
finishedGestures -= undeliveredGestures;
}
@@ -274,7 +281,7 @@ bool QGestureManager::filterEventThroughContexts(const QMap<QObject *,
QSet<QGesture *> undeliveredGestures;
deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures,
- receiver, &undeliveredGestures);
+ &undeliveredGestures);
activeGestures -= undeliveredGestures;
@@ -292,38 +299,47 @@ bool QGestureManager::filterEventThroughContexts(const QMap<QObject *,
bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event)
{
+ QSet<Qt::GestureType> types;
QMap<QObject *, Qt::GestureType> contexts;
QWidget *w = receiver;
+ typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator;
if (!w->d_func()->gestureContext.isEmpty()) {
- typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator;
for(ContextIterator it = w->d_func()->gestureContext.begin(),
e = w->d_func()->gestureContext.end(); it != e; ++it) {
+ types.insert(it.key());
contexts.insertMulti(w, it.key());
}
}
// find all gesture contexts for the widget tree
- w = w->parentWidget();
+ w = w->isWindow() ? 0 : w->parentWidget();
while (w)
{
- typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator;
for (ContextIterator it = w->d_func()->gestureContext.begin(),
e = w->d_func()->gestureContext.end(); it != e; ++it) {
- if (it.value() == Qt::WidgetWithChildrenGesture)
- contexts.insertMulti(w, it.key());
+ if (it.value() == Qt::WidgetWithChildrenGesture) {
+ if (!types.contains(it.key())) {
+ types.insert(it.key());
+ contexts.insertMulti(w, it.key());
+ }
+ }
}
+ if (w->isWindow())
+ break;
w = w->parentWidget();
}
- return filterEventThroughContexts(contexts , receiver, event);
+ return filterEventThroughContexts(contexts, event);
}
-bool QGestureManager::filterEvent(QGraphicsObject *graphicsObject, QEvent *event)
+bool QGestureManager::filterEvent(QGraphicsObject *receiver, QEvent *event)
{
+ QSet<Qt::GestureType> types;
QMap<QObject *, Qt::GestureType> contexts;
- QGraphicsObject *item = graphicsObject;
+ QGraphicsObject *item = receiver;
if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) {
typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator;
for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(),
e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) {
+ types.insert(it.key());
contexts.insertMulti(item, it.key());
}
}
@@ -334,55 +350,110 @@ bool QGestureManager::filterEvent(QGraphicsObject *graphicsObject, QEvent *event
typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator;
for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(),
e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) {
- if (it.value() == Qt::ItemWithChildrenGesture)
- contexts.insertMulti(item, it.key());
+ if (it.value() == Qt::ItemWithChildrenGesture) {
+ if (!types.contains(it.key()))
+ contexts.insertMulti(item, it.key());
+ }
}
item = item->parentObject();
}
- return filterEventThroughContexts(contexts, graphicsObject, event);
+ return filterEventThroughContexts(contexts, event);
}
bool QGestureManager::filterEvent(QGesture *state, QEvent *event)
{
QMap<QObject *, Qt::GestureType> contexts;
contexts.insert(state, state->gestureType());
- return filterEventThroughContexts(contexts, 0, event);
+ return filterEventThroughContexts(contexts, event);
+}
+
+void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures,
+ QMap<QWidget *, QList<QGesture *> > *conflicts,
+ QMap<QWidget *, QList<QGesture *> > *normal)
+{
+ typedef QHash<Qt::GestureType, QHash<QWidget *, QGesture *> > GestureByTypes;
+ GestureByTypes gestureByTypes;
+
+ // sort gestures by types
+ foreach (QGesture *gesture, gestures) {
+ QWidget *receiver = gestureTargets.value(gesture, 0);
+ Q_ASSERT(receiver);
+ gestureByTypes[gesture->gestureType()].insert(receiver, gesture);
+ }
+
+ // for each gesture type
+ foreach (Qt::GestureType type, gestureByTypes.keys()) {
+ QHash<QWidget *, QGesture *> gestures = gestureByTypes.value(type);
+ foreach (QWidget *widget, gestures.keys()) {
+ QWidget *w = widget->parentWidget();
+ while (w) {
+ QMap<Qt::GestureType, Qt::GestureContext>::const_iterator it
+ = w->d_func()->gestureContext.find(type);
+ if (it != w->d_func()->gestureContext.end()) {
+ // i.e. 'w' listens to gesture 'type'
+ Qt::GestureContext context = it.value();
+ if (context == Qt::WidgetWithChildrenGesture && w != widget) {
+ // conflicting gesture!
+ (*conflicts)[widget].append(gestures[widget]);
+ break;
+ }
+ }
+ if (w->isWindow()) {
+ w = 0;
+ break;
+ }
+ w = w->parentWidget();
+ }
+ if (!w)
+ (*normal)[widget].append(gestures[widget]);
+ }
+ }
}
-void QGestureManager::deliverEvents(const QSet<QGesture*> &gestures,
- QObject *lastReceiver,
+void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
QSet<QGesture *> *undeliveredGestures)
{
if (gestures.isEmpty())
return;
- // group gestures by widgets
- typedef QMap<QObject *, QList<QGesture *> > GesturesPerReceiver;
- GesturesPerReceiver groupedGestures;
- // for conflicted gestures the key is always the innermost widget (i.e. the child)
- GesturesPerReceiver conflictedGestures;
- typedef QMultiHash<QWidget *, QGesture *> WidgetMultiGestures;
- WidgetMultiGestures widgetMultiGestures;
+ typedef QMap<QWidget *, QList<QGesture *> > GesturesPerWidget;
+ GesturesPerWidget conflictedGestures;
+ GesturesPerWidget normalStartedGestures;
- foreach (QGesture *gesture, gestures) {
- QObject *target = gestureTargets.value(gesture, 0);
+ QSet<QGesture *> startedGestures;
+ // first figure out the initial receivers of gestures
+ for (QSet<QGesture *>::const_iterator it = gestures.begin(),
+ e = gestures.end(); it != e; ++it) {
+ QGesture *gesture = *it;
+ QWidget *target = gestureTargets.value(gesture, 0);
if (!target) {
+ // the gesture has just started and doesn't have a target yet.
Q_ASSERT(gesture->state() == Qt::GestureStarted);
if (gesture->hasHotSpot()) {
- // guess the target using the hotspot of the gesture
+ // guess the target widget using the hotspot of the gesture
QPoint pt = gesture->hotSpot().toPoint();
if (QWidget *w = qApp->topLevelAt(pt)) {
target = w->childAt(w->mapFromGlobal(pt));
}
+ } else {
+ // or use the context of the gesture
+ QObject *context = gestureOwners.value(gesture, 0);
+ if (context->isWidgetType())
+ target = static_cast<QWidget *>(context);
}
- if (!target)
- target = lastReceiver;
+ if (target)
+ gestureTargets.insert(gesture, target);
}
+
+ Qt::GestureType gestureType = gesture->gestureType();
+ Q_ASSERT(gestureType != Qt::CustomGesture);
+
if (target) {
- gestureTargets.insert(gesture, target);
- if (target->isWidgetType())
- widgetMultiGestures.insert(static_cast<QWidget *>(target), gesture);
- groupedGestures[target].append(gesture);
+ if (gesture->state() == Qt::GestureStarted) {
+ startedGestures.insert(gesture);
+ } else {
+ normalStartedGestures[target].append(gesture);
+ }
} else {
qWarning() << "QGestureManager::deliverEvent: could not find the target for gesture"
<< gesture->gestureType();
@@ -390,56 +461,44 @@ void QGestureManager::deliverEvents(const QSet<QGesture*> &gestures,
}
}
- typedef WidgetMultiGestures::const_iterator WidgetMultiGesturesIterator;
- for (WidgetMultiGesturesIterator it = widgetMultiGestures.begin(),
- e = widgetMultiGestures.end(); it != e; ++it) {
- QWidget *widget1 = it.key();
- QGesture *gesture1 = it.value();
- WidgetMultiGesturesIterator cit = it;
- for (++cit; cit != e; ++cit) {
- QWidget *widget2 = cit.key();
- QGesture *gesture2 = cit.value();
- if (gesture1->gestureType() != gesture2->gestureType())
- continue;
- // TODO: ugly, rewrite this.
- if ((widget1 && widget2 && widget2->isAncestorOf(widget1))) {
- groupedGestures[widget2].removeOne(gesture2);
- groupedGestures[widget1].removeOne(gesture1);
- conflictedGestures[widget1].append(gesture1);
- } else if ((widget1 && widget2 && widget1->isAncestorOf(widget2))) {
- groupedGestures[widget2].removeOne(gesture2);
- groupedGestures[widget1].removeOne(gesture1);
- conflictedGestures[widget2].append(gesture2);
- }
- }
- }
-
- DEBUG() << "deliverEvents: conflicted =" << conflictedGestures.values()
- << " grouped =" << groupedGestures.values();
+ getGestureTargets(startedGestures, &conflictedGestures, &normalStartedGestures);
+ DEBUG() << "QGestureManager::deliverEvents:"
+ << "\nstarted: " << startedGestures
+ << "\nconflicted: " << conflictedGestures
+ << "\nnormal: " << normalStartedGestures
+ << "\n";
// if there are conflicting gestures, send the GestureOverride event
- for (GesturesPerReceiver::const_iterator it = conflictedGestures.begin(),
+ for (GesturesPerWidget::const_iterator it = conflictedGestures.begin(),
e = conflictedGestures.end(); it != e; ++it) {
+ QWidget *receiver = it.key();
+ QList<QGesture *> gestures = it.value();
DEBUG() << "QGestureManager::deliverEvents: sending GestureOverride to"
- << it.key()
- << " gestures:" << it.value();
- QGestureEvent event(it.value());
+ << receiver
+ << "gestures:" << gestures;
+ QGestureEvent event(gestures);
event.t = QEvent::GestureOverride;
event.ignore();
- QApplication::sendEvent(it.key(), &event);
+ QApplication::sendEvent(receiver, &event);
if (!event.isAccepted()) {
- // nobody accepted the GestureOverride, put it back to deliver to
- // the closest context (i.e. to the inner-most widget).
- DEBUG() <<" override was not accepted";
- groupedGestures[it.key()].append(it.value());
+ // 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);
+ }
+ }
}
}
- for (GesturesPerReceiver::const_iterator it = groupedGestures.begin(),
- e = groupedGestures.end(); it != e; ++it) {
+ // delivering gestures that are not in conflicted state
+ for (GesturesPerWidget::const_iterator it = normalStartedGestures.begin(),
+ e = normalStartedGestures.end(); it != e; ++it) {
if (!it.value().isEmpty()) {
DEBUG() << "QGestureManager::deliverEvents: sending to" << it.key()
- << " gestures:" << it.value();
+ << "gestures:" << it.value();
QGestureEvent event(it.value());
QApplication::sendEvent(it.key(), &event);
}
@@ -457,7 +516,8 @@ void QGestureManager::timerEvent(QTimerEvent *event)
timer.stop();
QGesture *gesture = it.key();
it = maybeGestures.erase(it);
- DEBUG() << "QGestureManager::timerEvent: gesture stopped due to timeout:" << gesture;
+ DEBUG() << "QGestureManager::timerEvent: gesture stopped due to timeout:"
+ << gesture;
QGestureRecognizer *recognizer = gestureToRecognizer.value(gesture, 0);
if (recognizer)
recognizer->reset(gesture);
diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h
index 5fc02ab..f0e7225 100644
--- a/src/gui/kernel/qgesturemanager_p.h
+++ b/src/gui/kernel/qgesturemanager_p.h
@@ -82,7 +82,7 @@ public:
protected:
void timerEvent(QTimerEvent *event);
bool filterEventThroughContexts(const QMap<QObject *, Qt::GestureType> &contexts,
- QObject *receiver, QEvent *event);
+ QEvent *event);
private:
QMultiMap<Qt::GestureType, QGestureRecognizer *> recognizers;
@@ -114,16 +114,20 @@ private:
}
};
- QMap<ObjectGesture, QWeakPointer<QGesture> > objectGestures;
+ QMap<ObjectGesture, QGesture *> objectGestures;
QMap<QGesture *, QGestureRecognizer *> gestureToRecognizer;
+ QHash<QGesture *, QObject *> gestureOwners;
- QHash<QGesture *, QObject *> gestureTargets;
+ QHash<QGesture *, QWidget *> gestureTargets;
int lastCustomGestureId;
QGesture *getState(QObject *widget, Qt::GestureType gesture);
- void deliverEvents(const QSet<QGesture *> &gestures, QObject *lastReceiver,
+ void deliverEvents(const QSet<QGesture *> &gestures,
QSet<QGesture *> *undeliveredGestures);
+ void getGestureTargets(const QSet<QGesture*> &gestures,
+ QMap<QWidget *, QList<QGesture *> > *conflicts,
+ QMap<QWidget *, QList<QGesture *> > *normal);
};
QT_END_NAMESPACE