aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/items/qquickflickable.cpp2
-rw-r--r--src/quick/items/qquickpincharea.cpp10
-rw-r--r--src/quick/items/qquickwindow.cpp122
-rw-r--r--src/quick/items/qquickwindow_p.h9
-rw-r--r--tests/auto/quick/touchmouse/tst_touchmouse.cpp7
5 files changed, 94 insertions, 56 deletions
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index ee71ea8a76..3f072359d2 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -1380,7 +1380,7 @@ void QQuickFlickablePrivate::replayDelayedPress()
// Use the event handler that will take care of finding the proper item to propagate the event
replayingPressEvent = true;
- QQuickWindowPrivate::get(w)->deliverMouseEvent(mouseEvent.data());
+ QCoreApplication::sendEvent(w, mouseEvent.data());
replayingPressEvent = false;
}
}
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index 234f78c380..d8478806c6 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -268,8 +268,6 @@ QQuickPinchArea::QQuickPinchArea(QQuickItem *parent)
{
Q_D(QQuickPinchArea);
d->init();
- setAcceptedMouseButtons(Qt::LeftButton);
- setFiltersChildMouseEvents(true);
#ifdef Q_OS_OSX
setAcceptHoverEvents(true); // needed to enable touch events on mouse hover.
#endif
@@ -413,6 +411,12 @@ void QQuickPinchArea::updatePinch()
QTouchEvent::TouchPoint touchPoint1 = d->touchPoints.at(0);
QTouchEvent::TouchPoint touchPoint2 = d->touchPoints.at(d->touchPoints. count() >= 2 ? 1 : 0);
+ if (touchPoint1.state() == Qt::TouchPointPressed)
+ d->sceneStartPoint1 = touchPoint1.scenePos();
+
+ if (touchPoint2.state() == Qt::TouchPointPressed)
+ d->sceneStartPoint2 = touchPoint2.scenePos();
+
QRectF bounds = clipRect();
// Pinch is not started unless there are exactly two touch points
// AND one or more of the points has just now been pressed (wasn't pressed already)
@@ -421,8 +425,6 @@ void QQuickPinchArea::updatePinch()
&& (touchPoint1.state() & Qt::TouchPointPressed || touchPoint2.state() & Qt::TouchPointPressed) &&
bounds.contains(touchPoint1.pos()) && bounds.contains(touchPoint2.pos())) {
d->id1 = touchPoint1.id();
- d->sceneStartPoint1 = touchPoint1.scenePos();
- d->sceneStartPoint2 = touchPoint2.scenePos();
d->pinchActivated = true;
d->initPinch = true;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 0233e93443..12be33d790 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -556,7 +556,7 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
// handler spins the event loop all subsequent moves and releases get lost.
touchMouseId = p.id();
itemForTouchPointId[touchMouseId] = item;
- QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event, item));
+ QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event, item, false));
// Send a single press and see if that's accepted
if (!mouseGrabberItem)
@@ -575,18 +575,21 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
}
if (mousePress->isAccepted() && checkIfDoubleClicked(event->timestamp())) {
- QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item));
+ QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item, false));
QCoreApplication::sendEvent(item, mouseDoubleClick.data());
event->setAccepted(mouseDoubleClick->isAccepted());
if (mouseDoubleClick->isAccepted()) {
+ touchMouseIdCandidates.clear();
return true;
} else {
touchMouseId = -1;
}
}
// The event was accepted, we are done.
- if (mousePress->isAccepted())
+ if (mousePress->isAccepted()) {
+ touchMouseIdCandidates.clear();
return true;
+ }
// The event was not accepted but touchMouseId was set.
if (touchMouseId != -1)
return false;
@@ -596,7 +599,7 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
} else if (p.id() == touchMouseId) {
if (p.state() & Qt::TouchPointMoved) {
if (mouseGrabberItem) {
- QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, mouseGrabberItem));
+ QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, mouseGrabberItem, false));
QCoreApplication::sendEvent(item, me.data());
event->setAccepted(me->isAccepted());
if (me->isAccepted()) {
@@ -607,7 +610,7 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
// no grabber, check if we care about mouse hover
// FIXME: this should only happen once, not recursively... I'll ignore it just ignore hover now.
// hover for touch???
- QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, item));
+ QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, item, false));
if (lastMousePosition.isNull())
lastMousePosition = me->windowPos();
QPointF last = lastMousePosition;
@@ -626,7 +629,7 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
// currently handled point was released
touchMouseId = -1;
if (mouseGrabberItem) {
- QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event, mouseGrabberItem));
+ QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event, mouseGrabberItem, false));
QCoreApplication::sendEvent(item, me.data());
if (mouseGrabberItem) // might have ungrabbed due to event
mouseGrabberItem->ungrabMouse();
@@ -1887,7 +1890,8 @@ void QQuickWindowPrivate::reallyDeliverTouchEvent(QTouchEvent *event)
// or some item accepted a point and should receive an update
if (newPoints.count() > 0 || updatedPoints.count() > 0) {
QSet<int> acceptedNewPoints;
- event->setAccepted(deliverTouchPoints(contentItem, event, newPoints, &acceptedNewPoints, &updatedPoints));
+ QSet<QQuickItem *> hasFiltered;
+ event->setAccepted(deliverTouchPoints(contentItem, event, newPoints, &acceptedNewPoints, &updatedPoints, &hasFiltered));
} else
event->ignore();
@@ -1898,6 +1902,7 @@ void QQuickWindowPrivate::reallyDeliverTouchEvent(QTouchEvent *event)
itemForTouchPointId.remove(touchPoints[i].id());
if (touchPoints[i].id() == touchMouseId)
touchMouseId = -1;
+ touchMouseIdCandidates.remove(touchPoints[i].id());
}
}
}
@@ -1910,7 +1915,9 @@ void QQuickWindowPrivate::reallyDeliverTouchEvent(QTouchEvent *event)
}
// This function recurses and sends the events to the individual items
-bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
+bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints,
+ QSet<int> *acceptedNewPoints, QHash<QQuickItem *,
+ QList<QTouchEvent::TouchPoint> > *updatedPoints, QSet<QQuickItem *> *hasFiltered)
{
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
@@ -1929,7 +1936,7 @@ bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even
QQuickItem *child = children.at(ii);
if (!child->isEnabled() || !child->isVisible() || QQuickItemPrivate::get(child)->culled)
continue;
- if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
+ if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints, hasFiltered))
return true;
}
@@ -1979,7 +1986,7 @@ bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even
// with only the subset of TouchPoints which are relevant to that item: that's matchingPoints.
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
transformTouchPoints(matchingPoints, itemPrivate->windowToItemTransform());
- deliverMatchingPointsToItem(item, event, acceptedNewPoints, matchingNewPoints, matchingPoints);
+ deliverMatchingPointsToItem(item, event, acceptedNewPoints, matchingNewPoints, matchingPoints, hasFiltered);
}
// record the fact that this item has been visited already
@@ -1993,7 +2000,7 @@ bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even
// only the points that are relevant for this item. Thus the need for
// matchingPoints to already be that set of interesting points.
// They are all pre-transformed, too.
-bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints)
+bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints, QSet<QQuickItem *> *hasFiltered)
{
QScopedPointer<QTouchEvent> touchEvent(touchEventWithPoints(*event, matchingPoints));
touchEvent.data()->setTarget(item);
@@ -2001,7 +2008,7 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv
// First check whether the parent wants to be a filter,
// and if the parent accepts the event we are done.
- if (sendFilteredTouchEvent(item->parentItem(), item, event)) {
+ if (sendFilteredTouchEvent(item->parentItem(), item, event, hasFiltered)) {
// If the touch was accepted (regardless by whom or in what form),
// update acceptedNewPoints
foreach (int id, matchingNewPoints)
@@ -2021,7 +2028,7 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (!touchEventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) {
// send mouse event
- event->setAccepted(translateTouchToMouse(item, event));
+ event->setAccepted(translateTouchToMouse(item, touchEvent.data()));
if (event->isAccepted()) {
touchEventAccepted = true;
}
@@ -2271,7 +2278,7 @@ QQuickItem *QQuickWindowPrivate::findCursorItem(QQuickItem *item, const QPointF
}
#endif
-bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event)
+bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event, QSet<QQuickItem *> *hasFiltered)
{
if (!target)
return false;
@@ -2279,13 +2286,14 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem
bool filtered = false;
QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
- if (targetPrivate->filtersChildMouseEvents) {
+ if (targetPrivate->filtersChildMouseEvents && !hasFiltered->contains(target)) {
+ hasFiltered->insert(target);
QScopedPointer<QTouchEvent> targetEvent(touchEventForItemBounds(target, *event));
if (!targetEvent->touchPoints().isEmpty()) {
- QVector<int> touchIds;
- for (int i = 0; i < event->touchPoints().size(); ++i)
- touchIds.append(event->touchPoints().at(i).id());
if (target->childMouseEventFilter(item, targetEvent.data())) {
+ QVector<int> touchIds;
+ for (int i = 0; i < targetEvent->touchPoints().size(); ++i)
+ touchIds.append(targetEvent->touchPoints().at(i).id());
target->grabTouchPoints(touchIds);
if (mouseGrabberItem) {
mouseGrabberItem->ungrabMouse();
@@ -2294,38 +2302,54 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem
filtered = true;
}
- // Only offer a mouse event to the filter if we have one point
- if (targetEvent->touchPoints().count() == 1) {
+ for (int i = 0; i < targetEvent->touchPoints().size(); ++i) {
+ const QTouchEvent::TouchPoint &tp = targetEvent->touchPoints().at(i);
+
QEvent::Type t;
- const QTouchEvent::TouchPoint &tp = targetEvent->touchPoints().first();
switch (tp.state()) {
case Qt::TouchPointPressed:
t = QEvent::MouseButtonPress;
+ if (touchMouseId == -1) {
+ // We don't want to later filter touches as a mouse event if they were pressed
+ // while a touchMouseId was already active.
+ // Remember this touch as a potential to become the touchMouseId.
+ touchMouseIdCandidates.insert(tp.id());
+ }
break;
case Qt::TouchPointReleased:
t = QEvent::MouseButtonRelease;
break;
+ case Qt::TouchPointStationary:
+ continue;
default:
- // move or stationary
t = QEvent::MouseMove;
break;
}
- // targetEvent is already transformed wrt local position, velocity, etc.
- QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, targetEvent->touchPoints().first(), event, item, false));
- if (target->childMouseEventFilter(item, mouseEvent.data())) {
- itemForTouchPointId[tp.id()] = target;
- touchMouseId = tp.id();
- target->grabMouse();
- filtered = true;
+ // Only deliver mouse event if it is the touchMouseId or it could become the touchMouseId
+ if ((touchMouseIdCandidates.contains(tp.id()) && touchMouseId == -1) || touchMouseId == tp.id()) {
+ // targetEvent is already transformed wrt local position, velocity, etc.
+ QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, tp, event, item, false));
+ if (target->childMouseEventFilter(item, mouseEvent.data())) {
+ if (t != QEvent::MouseButtonRelease) {
+ itemForTouchPointId[tp.id()] = target;
+ touchMouseId = tp.id();
+ target->grabMouse();
+ }
+ touchMouseIdCandidates.clear();
+ filtered = true;
+ }
+ // Only one event can be filtered as a mouse event.
+ break;
}
}
}
}
- return sendFilteredTouchEvent(target->parentItem(), item, event) || filtered;
+
+ return sendFilteredTouchEvent(target->parentItem(), item, event, hasFiltered) || filtered;
}
-bool QQuickWindowPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
+bool QQuickWindowPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event, QSet<QQuickItem *> *hasFiltered)
{
if (!target)
return false;
@@ -2333,11 +2357,13 @@ bool QQuickWindowPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem
bool filtered = false;
QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
- if (targetPrivate->filtersChildMouseEvents)
+ if (targetPrivate->filtersChildMouseEvents && !hasFiltered->contains(target)) {
+ hasFiltered->insert(target);
if (target->childMouseEventFilter(item, event))
filtered = true;
+ }
- return sendFilteredMouseEvent(target->parentItem(), item, event) || filtered;
+ return sendFilteredMouseEvent(target->parentItem(), item, event, hasFiltered) || filtered;
}
bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int startDragThreshold)
@@ -2478,18 +2504,22 @@ bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e)
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
- case QEvent::MouseMove:
- // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
- if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
- // accept because qml items by default accept and have to explicitly opt out of accepting
- e->accept();
- QCoreApplication::sendEvent(item, e);
+ case QEvent::MouseMove: {
+ // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
+ QSet<QQuickItem *> hasFiltered;
+ if (!d->sendFilteredMouseEvent(item->parentItem(), item, e, &hasFiltered)) {
+ // accept because qml items by default accept and have to explicitly opt out of accepting
+ e->accept();
+ QCoreApplication::sendEvent(item, e);
+ }
}
break;
- case QEvent::UngrabMouse:
- if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
- e->accept();
- item->mouseUngrabEvent();
+ case QEvent::UngrabMouse: {
+ QSet<QQuickItem *> hasFiltered;
+ if (!d->sendFilteredMouseEvent(item->parentItem(), item, e, &hasFiltered)) {
+ e->accept();
+ item->mouseUngrabEvent();
+ }
}
break;
#ifndef QT_NO_WHEELEVENT
@@ -2511,8 +2541,10 @@ bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e)
break;
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
- case QEvent::TouchEnd:
- d->sendFilteredTouchEvent(item->parentItem(), item, static_cast<QTouchEvent *>(e));
+ case QEvent::TouchEnd: {
+ QSet<QQuickItem*> hasFiltered;
+ d->sendFilteredTouchEvent(item->parentItem(), item, static_cast<QTouchEvent *>(e), &hasFiltered);
+ }
break;
default:
break;
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 8f0696914e..93ceefe5af 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -137,21 +137,21 @@ public:
static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = 0);
bool deliverInitialMousePressEvent(QQuickItem *, QMouseEvent *);
bool deliverMouseEvent(QMouseEvent *);
- bool sendFilteredMouseEvent(QQuickItem *, QQuickItem *, QEvent *);
+ bool sendFilteredMouseEvent(QQuickItem *, QQuickItem *, QEvent *, QSet<QQuickItem *> *);
#ifndef QT_NO_WHEELEVENT
bool deliverWheelEvent(QQuickItem *, QWheelEvent *);
#endif
bool deliverTouchPoints(QQuickItem *, QTouchEvent *, const QList<QTouchEvent::TouchPoint> &, QSet<int> *,
- QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *);
+ QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *, QSet<QQuickItem*> *filtered);
void deliverTouchEvent(QTouchEvent *);
void reallyDeliverTouchEvent(QTouchEvent *);
bool deliverTouchCancelEvent(QTouchEvent *);
void flushDelayedTouchEvent();
bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted);
- bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints);
+ bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints, QSet<QQuickItem*> *filtered);
QTouchEvent *touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent);
QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints);
- bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event);
+ bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event, QSet<QQuickItem*> *filtered);
bool sendHoverEvent(QEvent::Type, QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos,
Qt::KeyboardModifiers modifiers, bool accepted);
bool clearHover();
@@ -239,6 +239,7 @@ public:
// Keeps track of which touch point (int) was last accepted by which item
QHash<int, QQuickItem *> itemForTouchPointId;
+ QSet<int> touchMouseIdCandidates;
mutable QQuickWindowIncubationController *incubationController;
diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp
index 1d947b4d8c..f39a22e131 100644
--- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp
+++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp
@@ -661,6 +661,7 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable()
// but we'll get the delayed mouse press after a delay
QTRY_COMPARE(eventItem1->eventList.size(), 1);
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
+ QCOMPARE(filteredEventList.count(), 1);
// eventItem1 should have the mouse grab, and have moved the itemForTouchPointId
// for the touchMouseId to the new grabber.
@@ -690,8 +691,9 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable()
QTest::touchEvent(window, device).release(0, p3, window);
QQuickTouchUtils::flush(window);
- // We should not have received any synthesised mouse events from Qt gui.
- QCOMPARE(filteredEventList.count(), 0);
+ // We should not have received any synthesised mouse events from Qt gui,
+ // just the delayed press.
+ QCOMPARE(filteredEventList.count(), 1);
delete window;
}
@@ -916,6 +918,7 @@ void tst_TouchMouse::pinchOnFlickable()
p1 -= QPoint(10, 0);
p2 += QPoint(10, 0);
pinchSequence.move(0, p1, window).move(1, p2, window).commit();
+ QVERIFY(!flickable->isDragging());
QQuickTouchUtils::flush(window);
pinchSequence.release(0, p1, window).release(1, p2, window).commit();
QQuickTouchUtils::flush(window);