diff options
48 files changed, 1243 insertions, 3359 deletions
diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp index 492897b68b..0794b86b11 100644 --- a/src/quick/handlers/qquickdraghandler.cpp +++ b/src/quick/handlers/qquickdraghandler.cpp @@ -110,10 +110,10 @@ QPointF QQuickDragHandler::targetCentroidPosition() return pos; } -void QQuickDragHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) +void QQuickDragHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, QPointerEvent *event, QEventPoint &point) { - QQuickMultiPointHandler::onGrabChanged(grabber, transition, point); - if (grabber == this && transition == QQuickEventPoint::GrabExclusive && target()) { + QQuickMultiPointHandler::onGrabChanged(grabber, transition, event, point); + if (grabber == this && transition == QPointingDevice::GrabExclusive && target()) { // In case the grab got handed over from another grabber, we might not get the Press. auto isDescendant = [](QQuickItem *parent, QQuickItem *target) { @@ -162,7 +162,7 @@ void QQuickDragHandler::onActiveChanged() QQuickMultiPointHandler::onActiveChanged(); if (active()) { if (auto parent = parentItem()) { - if (currentEvent()->asPointerTouchEvent()) + if (QQuickWindowPrivate::isTouchEvent(currentEvent())) parent->setKeepTouchGrab(true); // tablet and mouse are treated the same by Item's legacy event handling, and // touch becomes synth-mouse for Flickable, so we need to prevent stealing @@ -179,7 +179,7 @@ void QQuickDragHandler::onActiveChanged() } } -void QQuickDragHandler::handlePointerEventImpl(QQuickPointerEvent *event) +void QQuickDragHandler::handlePointerEventImpl(QPointerEvent *event) { QQuickMultiPointHandler::handlePointerEventImpl(event); event->setAccepted(true); @@ -199,18 +199,19 @@ void QQuickDragHandler::handlePointerEventImpl(QQuickPointerEvent *event) // and in approximately the same direction qreal minAngle = 361; qreal maxAngle = -361; - bool allOverThreshold = !event->isReleaseEvent(); - QVector <QQuickEventPoint *> chosenPoints; + bool allOverThreshold = !event->isEndEvent(); + QVector<QEventPoint> chosenPoints; - if (event->isPressEvent()) + if (event->isBeginEvent()) m_pressedInsideTarget = target() && currentPoints().count() > 0; for (const QQuickHandlerPoint &p : currentPoints()) { if (!allOverThreshold) break; - QQuickEventPoint *point = event->pointById(p.id()); - chosenPoints << point; - setPassiveGrab(point); + auto point = event->pointById(p.id()); + Q_ASSERT(point); + chosenPoints << *point; + setPassiveGrab(event, *point); // Calculate drag delta, taking into account the axis enabled constraint // i.e. if xAxis is not enabled, then ignore the horizontal component of the actual movement QVector2D accumulatedDragDelta = QVector2D(point->scenePosition() - point->scenePressPosition()); @@ -237,7 +238,7 @@ void QQuickDragHandler::handlePointerEventImpl(QQuickPointerEvent *event) if (allOverThreshold && !overThreshold) allOverThreshold = false; - if (event->isPressEvent()) { + if (event->isBeginEvent()) { // m_pressedInsideTarget should stay true iff ALL points in which DragHandler is interested // have been pressed inside the target() Item. (E.g. in a Slider the parent might be the // whole control while the target is just the knob.) @@ -250,7 +251,7 @@ void QQuickDragHandler::handlePointerEventImpl(QQuickPointerEvent *event) // (That affects behavior for mouse but not for touch, because Flickable only handles mouse.) // So we have to compensate by accepting the event here to avoid any parent Flickable from // getting the event via direct delivery and grabbing too soon. - point->setAccepted(event->asPointerMouseEvent()); // stop propagation iff it's a mouse event + point->setAccepted(QQuickWindowPrivate::isMouseEvent(event)); // stop propagation iff it's a mouse event } } if (allOverThreshold) { @@ -258,7 +259,7 @@ void QQuickDragHandler::handlePointerEventImpl(QQuickPointerEvent *event) if (angleDiff > 180) angleDiff = 360 - angleDiff; qCDebug(lcDragHandler) << "angle min" << minAngle << "max" << maxAngle << "range" << angleDiff; - if (angleDiff < DragAngleToleranceDegrees && grabPoints(chosenPoints)) + if (angleDiff < DragAngleToleranceDegrees && grabPoints(event, chosenPoints)) setActive(true); } } diff --git a/src/quick/handlers/qquickdraghandler_p.h b/src/quick/handlers/qquickdraghandler_p.h index 1315f79114..c1ff108e13 100644 --- a/src/quick/handlers/qquickdraghandler_p.h +++ b/src/quick/handlers/qquickdraghandler_p.h @@ -77,7 +77,7 @@ public: explicit QQuickDragHandler(QQuickItem *parent = nullptr); - void handlePointerEventImpl(QQuickPointerEvent *event) override; + void handlePointerEventImpl(QPointerEvent *event) override; QQuickDragAxis *xAxis() { return &m_xAxis; } QQuickDragAxis *yAxis() { return &m_yAxis; } @@ -95,7 +95,7 @@ Q_SIGNALS: protected: void onActiveChanged() override; - void onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) override; + void onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, QPointerEvent *event, QEventPoint &point) override; private: void ungrab(); diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp index 2990215719..3cd1bccbfc 100644 --- a/src/quick/handlers/qquickhandlerpoint.cpp +++ b/src/quick/handlers/qquickhandlerpoint.cpp @@ -49,7 +49,7 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_TOUCH_TARGET) \inqmlmodule QtQuick \brief An event point. - A QML representation of a QQuickEventPoint. + A QML representation of a QEventPoint. It's possible to make bindings to properties of a handler's current \l {SinglePointHandler::point}{point} or @@ -98,46 +98,44 @@ void QQuickHandlerPoint::reset() m_pressedModifiers = Qt::NoModifier; } -void QQuickHandlerPoint::reset(const QQuickEventPoint *point) +void QQuickHandlerPoint::reset(const QPointerEvent *event, const QEventPoint &point) { - m_id = point->pointId(); - m_device = point->pointerEvent()->device(); - const QQuickPointerEvent *event = point->pointerEvent(); - switch (point->state()) { - case QQuickEventPoint::Pressed: - m_pressPosition = point->position(); - m_scenePressPosition = point->scenePosition(); - m_pressedButtons = event->buttons(); + m_id = point.id(); + m_device = event->pointingDevice(); + switch (point.state()) { + case QEventPoint::Pressed: + m_pressPosition = point.position(); + m_scenePressPosition = point.scenePosition(); break; default: break; } - m_scenePressPosition = point->scenePressPosition(); - m_pressedButtons = event->buttons(); + const bool isTouch = QQuickWindowPrivate::isTouchEvent(event); + if (!isTouch) + m_pressedButtons = static_cast<const QSinglePointEvent *>(event)->buttons(); m_pressedModifiers = event->modifiers(); - if (event->asPointerTouchEvent()) { - const QQuickEventTouchPoint *tp = static_cast<const QQuickEventTouchPoint *>(point); - m_uniqueId = tp->uniqueId(); - m_rotation = tp->rotation(); - m_pressure = tp->pressure(); - m_ellipseDiameters = tp->ellipseDiameters(); + if (isTouch) { + m_uniqueId = point.uniqueId(); + m_rotation = point.rotation(); + m_pressure = point.pressure(); + m_ellipseDiameters = point.ellipseDiameters(); #if QT_CONFIG(tabletevent) - } else if (event->asPointerTabletEvent()) { - m_uniqueId = event->device()->uniqueId(); - m_rotation = static_cast<const QQuickEventTabletPoint *>(point)->rotation(); - m_pressure = static_cast<const QQuickEventTabletPoint *>(point)->pressure(); + } else if (QQuickWindowPrivate::isTabletEvent(event)) { + m_uniqueId = event->pointingDevice()->uniqueId(); + m_rotation = point.rotation(); + m_pressure = point.pressure(); m_ellipseDiameters = QSizeF(); #endif } else { - m_uniqueId = event->device()->uniqueId(); + m_uniqueId = event->pointingDevice()->uniqueId(); m_rotation = 0; - m_pressure = event->buttons() ? 1 : 0; + m_pressure = m_pressedButtons ? 1 : 0; m_ellipseDiameters = QSizeF(); } - m_position = point->position(); - m_scenePosition = point->scenePosition(); - if (point->state() == QQuickEventPoint::Updated) - m_velocity = point->velocity(); + m_position = point.position(); + m_scenePosition = point.scenePosition(); + if (point.state() == QEventPoint::Updated) + m_velocity = point.velocity(); } void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points) diff --git a/src/quick/handlers/qquickhandlerpoint_p.h b/src/quick/handlers/qquickhandlerpoint_p.h index fd3b365e32..8e175281f2 100644 --- a/src/quick/handlers/qquickhandlerpoint_p.h +++ b/src/quick/handlers/qquickhandlerpoint_p.h @@ -96,7 +96,7 @@ public: void localize(QQuickItem *item); void reset(); - void reset(const QQuickEventPoint *point); + void reset(const QPointerEvent *event, const QEventPoint &point); void reset(const QVector<QQuickHandlerPoint> &points); private: diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp index 76e5bc0605..cdb9b2578c 100644 --- a/src/quick/handlers/qquickhoverhandler.cpp +++ b/src/quick/handlers/qquickhoverhandler.cpp @@ -89,12 +89,12 @@ void QQuickHoverHandler::componentComplete() QQuickItemPrivate::get(parentItem())->setHasHoverInChild(true); } -bool QQuickHoverHandler::wantsPointerEvent(QQuickPointerEvent *event) +bool QQuickHoverHandler::wantsPointerEvent(QPointerEvent *event) { - QQuickEventPoint *point = event->point(0); - if (QQuickPointerDeviceHandler::wantsPointerEvent(event) && wantsEventPoint(point) && parentContains(point)) { + auto &point = event->point(0); + if (QQuickPointerDeviceHandler::wantsPointerEvent(event) && wantsEventPoint(event, point) && parentContains(point)) { // assume this is a mouse or tablet event, so there's only one point - setPointId(point->pointId()); + setPointId(point.id()); return true; } @@ -106,22 +106,22 @@ bool QQuickHoverHandler::wantsPointerEvent(QQuickPointerEvent *event) // the hovered property to transition to false prematurely. // If a QQuickPointerTabletEvent caused the hovered property to become true, // then only another QQuickPointerTabletEvent can make it become false. - if (!(m_hoveredTablet && event->asPointerMouseEvent())) + if (!(m_hoveredTablet && QQuickWindowPrivate::isMouseEvent(event))) setHovered(false); return false; } -void QQuickHoverHandler::handleEventPoint(QQuickEventPoint *point) +void QQuickHoverHandler::handleEventPoint(QPointerEvent *ev, QEventPoint &point) { bool hovered = true; - if (point->state() == QQuickEventPoint::Released && - point->pointerEvent()->device()->pointerType() == QPointingDevice::PointerType::Finger) + if (point.state() == QEventPoint::Released && + ev->pointingDevice()->pointerType() == QPointingDevice::PointerType::Finger) hovered = false; - else if (point->pointerEvent()->asPointerTabletEvent()) + else if (QQuickWindowPrivate::isTabletEvent(ev)) m_hoveredTablet = true; setHovered(hovered); - setPassiveGrab(point); + setPassiveGrab(ev, point); } /*! diff --git a/src/quick/handlers/qquickhoverhandler_p.h b/src/quick/handlers/qquickhoverhandler_p.h index 4b9d0a9f39..fe9a3bcde3 100644 --- a/src/quick/handlers/qquickhoverhandler_p.h +++ b/src/quick/handlers/qquickhoverhandler_p.h @@ -76,8 +76,8 @@ Q_SIGNALS: protected: void componentComplete() override; - bool wantsPointerEvent(QQuickPointerEvent *event) override; - void handleEventPoint(QQuickEventPoint *point) override; + bool wantsPointerEvent(QPointerEvent *event) override; + void handleEventPoint(QPointerEvent *ev, QEventPoint &point) override; private: void setHovered(bool hovered); diff --git a/src/quick/handlers/qquickmultipointhandler.cpp b/src/quick/handlers/qquickmultipointhandler.cpp index f404788de4..97cb958aa6 100644 --- a/src/quick/handlers/qquickmultipointhandler.cpp +++ b/src/quick/handlers/qquickmultipointhandler.cpp @@ -64,18 +64,18 @@ QQuickMultiPointHandler::QQuickMultiPointHandler(QQuickItem *parent, int minimum { } -bool QQuickMultiPointHandler::wantsPointerEvent(QQuickPointerEvent *event) +bool QQuickMultiPointHandler::wantsPointerEvent(QPointerEvent *event) { Q_D(QQuickMultiPointHandler); if (!QQuickPointerDeviceHandler::wantsPointerEvent(event)) return false; - if (event->asPointerScrollEvent()) + if (event->type() == QEvent::Wheel) return false; bool ret = false; #if QT_CONFIG(gestures) - if (event->asPointerNativeGestureEvent() && event->point(0)->state() != QQuickEventPoint::Released) + if (event->type() == QEvent::NativeGesture && event->point(0).state() != QEventPoint::Released) ret = true; #endif @@ -86,7 +86,7 @@ bool QQuickMultiPointHandler::wantsPointerEvent(QQuickPointerEvent *event) // are all still there in the event, we're good to go (do not reset // currentPoints, because we don't want to lose the pressPosition, and do // not want to reshuffle the order either). - const QVector<QQuickEventPoint *> candidatePoints = eligiblePoints(event); + const auto candidatePoints = eligiblePoints(event); if (candidatePoints.count() != d->currentPoints.count()) { d->currentPoints.clear(); if (active()) { @@ -103,7 +103,7 @@ bool QQuickMultiPointHandler::wantsPointerEvent(QQuickPointerEvent *event) const int c = candidatePoints.count(); d->currentPoints.resize(c); for (int i = 0; i < c; ++i) { - d->currentPoints[i].reset(candidatePoints[i]); + d->currentPoints[i].reset(event, candidatePoints[i]); d->currentPoints[i].localize(parentItem()); } } else { @@ -112,7 +112,7 @@ bool QQuickMultiPointHandler::wantsPointerEvent(QQuickPointerEvent *event) return ret; } -void QQuickMultiPointHandler::handlePointerEventImpl(QQuickPointerEvent *event) +void QQuickMultiPointHandler::handlePointerEventImpl(QPointerEvent *event) { Q_D(QQuickMultiPointHandler); QQuickPointerHandler::handlePointerEventImpl(event); @@ -120,9 +120,8 @@ void QQuickMultiPointHandler::handlePointerEventImpl(QQuickPointerEvent *event) // is _not_ a shallow copy of the QQuickPointerTouchEvent::m_touchPoints vector. // So we have to update our currentPoints instances based on the given event. for (QQuickHandlerPoint &p : d->currentPoints) { - const QQuickEventPoint *ep = event->pointById(p.id()); - if (ep) - p.reset(ep); + if (const QEventPoint *ep = event->pointById(p.id())) + p.reset(event, *ep); } QPointF sceneGrabPos = d->centroid.sceneGrabPosition(); d->centroid.reset(d->currentPoints); @@ -146,36 +145,35 @@ void QQuickMultiPointHandler::onActiveChanged() } } -void QQuickMultiPointHandler::onGrabChanged(QQuickPointerHandler *, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *) +void QQuickMultiPointHandler::onGrabChanged(QQuickPointerHandler *, QPointingDevice::GrabTransition transition, QPointerEvent *, QEventPoint &) { Q_D(QQuickMultiPointHandler); // If another handler or item takes over this set of points, assume it has // decided that it's the better fit for them. Don't immediately re-grab // at the next opportunity. This should help to avoid grab cycles // (e.g. between DragHandler and PinchHandler). - if (transition == QQuickEventPoint::UngrabExclusive || transition == QQuickEventPoint::CancelGrabExclusive) + if (transition == QPointingDevice::UngrabExclusive || transition == QPointingDevice::CancelGrabExclusive) d->currentPoints.clear(); } -QVector<QQuickEventPoint *> QQuickMultiPointHandler::eligiblePoints(QQuickPointerEvent *event) +QVector<QEventPoint> QQuickMultiPointHandler::eligiblePoints(QPointerEvent *event) { - QVector<QQuickEventPoint *> ret; - int c = event->pointCount(); + QVector<QEventPoint> ret; // If one or more points are newly pressed or released, all non-released points are candidates for this handler. // In other cases however, check whether it would be OK to steal the grab if the handler chooses to do that. - bool stealingAllowed = event->isPressEvent() || event->isReleaseEvent(); - for (int i = 0; i < c; ++i) { - QQuickEventPoint *p = event->point(i); - if (QQuickPointerMouseEvent *me = event->asPointerMouseEvent()) { - if (me->buttons() == Qt::NoButton) + bool stealingAllowed = event->isBeginEvent() || event->isEndEvent(); + for (int i = 0; i < event->pointCount(); ++i) { + auto &p = QMutableEventPoint::from(event->point(i)); + if (QQuickWindowPrivate::isMouseEvent(event)) { + if (static_cast<QMouseEvent *>(event)->buttons() == Qt::NoButton) continue; } if (!stealingAllowed) { - QObject *exclusiveGrabber = p->exclusiveGrabber(); - if (exclusiveGrabber && exclusiveGrabber != this && !canGrab(p)) + QObject *exclusiveGrabber = event->exclusiveGrabber(p); + if (exclusiveGrabber && exclusiveGrabber != this && !canGrab(event, p)) continue; } - if (p->state() != QQuickEventPoint::Released && wantsEventPoint(p)) + if (p.state() != QEventPoint::Released && wantsEventPoint(event, p)) ret << p; } return ret; @@ -274,7 +272,7 @@ QVector<QQuickHandlerPoint> &QQuickMultiPointHandler::currentPoints() return d->currentPoints; } -bool QQuickMultiPointHandler::hasCurrentPoints(QQuickPointerEvent *event) +bool QQuickMultiPointHandler::hasCurrentPoints(QPointerEvent *event) { Q_D(const QQuickMultiPointHandler); if (event->pointCount() < d->currentPoints.size() || d->currentPoints.size() == 0) @@ -282,10 +280,10 @@ bool QQuickMultiPointHandler::hasCurrentPoints(QQuickPointerEvent *event) // TODO optimize: either ensure the points are sorted, // or use std::equal with a predicate for (const QQuickHandlerPoint &p : qAsConst(d->currentPoints)) { - const QQuickEventPoint *ep = event->pointById(p.id()); + const QEventPoint *ep = event->pointById(p.id()); if (!ep) return false; - if (ep->state() == QQuickEventPoint::Released) + if (ep->state() == QEventPoint::Released) return false; } return true; @@ -358,26 +356,28 @@ qreal QQuickMultiPointHandler::averageAngleDelta(const QVector<PointData> &old, return avgAngleDelta; } -void QQuickMultiPointHandler::acceptPoints(const QVector<QQuickEventPoint *> &points) +void QQuickMultiPointHandler::acceptPoints(const QVector<QEventPoint> &points) { - for (QQuickEventPoint* point : points) - point->setAccepted(); + // "auto point" is a copy, but it's OK because + // setAccepted() changes QEventPointPrivate::accept via the shared d-pointer + for (auto point : points) + point.setAccepted(); } -bool QQuickMultiPointHandler::grabPoints(const QVector<QQuickEventPoint *> &points) +bool QQuickMultiPointHandler::grabPoints(QPointerEvent *event, const QVector<QEventPoint> &points) { if (points.isEmpty()) return false; bool allowed = true; - for (QQuickEventPoint* point : points) { - if (point->exclusiveGrabber() != this && !canGrab(point)) { + for (auto &point : points) { + if (event->exclusiveGrabber(point) != this && !canGrab(event, point)) { allowed = false; break; } } if (allowed) { - for (QQuickEventPoint* point : points) - setExclusiveGrab(point); + for (auto point : points) + setExclusiveGrab(event, point); } return allowed; } diff --git a/src/quick/handlers/qquickmultipointhandler_p.h b/src/quick/handlers/qquickmultipointhandler_p.h index c0751aa5c5..01cd78f9db 100644 --- a/src/quick/handlers/qquickmultipointhandler_p.h +++ b/src/quick/handlers/qquickmultipointhandler_p.h @@ -91,22 +91,22 @@ protected: qreal angle; }; - bool wantsPointerEvent(QQuickPointerEvent *event) override; - void handlePointerEventImpl(QQuickPointerEvent *event) override; + bool wantsPointerEvent(QPointerEvent *event) override; + void handlePointerEventImpl(QPointerEvent *event) override; void onActiveChanged() override; - void onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) override; - QVector<QQuickHandlerPoint> ¤tPoints(); + void onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, QPointerEvent *event, QEventPoint &point) override; + QList<QQuickHandlerPoint> ¤tPoints(); QQuickHandlerPoint &mutableCentroid(); - bool hasCurrentPoints(QQuickPointerEvent *event); - QVector<QQuickEventPoint *> eligiblePoints(QQuickPointerEvent *event); + bool hasCurrentPoints(QPointerEvent *event); + QVector<QEventPoint> eligiblePoints(QPointerEvent *event); qreal averageTouchPointDistance(const QPointF &ref); qreal averageStartingDistance(const QPointF &ref); qreal averageTouchPointAngle(const QPointF &ref); qreal averageStartingAngle(const QPointF &ref); QVector<PointData> angles(const QPointF &ref) const; static qreal averageAngleDelta(const QVector<PointData> &old, const QVector<PointData> &newAngles); - void acceptPoints(const QVector<QQuickEventPoint *> &points); - bool grabPoints(const QVector<QQuickEventPoint *> &points); + void acceptPoints(const QVector<QEventPoint> &points); + bool grabPoints(QPointerEvent *event, const QVector<QEventPoint> &points); void moveTarget(QPointF pos); Q_DECLARE_PRIVATE(QQuickMultiPointHandler) diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp index 8413b8b721..b1dca9a905 100644 --- a/src/quick/handlers/qquickpinchhandler.cpp +++ b/src/quick/handlers/qquickpinchhandler.cpp @@ -153,15 +153,16 @@ void QQuickPinchHandler::setMaximumRotation(qreal maximumRotation) emit maximumRotationChanged(); } -bool QQuickPinchHandler::wantsPointerEvent(QQuickPointerEvent *event) +bool QQuickPinchHandler::wantsPointerEvent(QPointerEvent *event) { if (!QQuickMultiPointHandler::wantsPointerEvent(event)) return false; #if QT_CONFIG(gestures) - if (const auto gesture = event->asPointerNativeGestureEvent()) { + if (event->type() == QEvent::NativeGesture) { + const auto gesture = static_cast<const QNativeGestureEvent *>(event); if (minimumPointCount() == 2) { - switch (gesture->type()) { + switch (gesture->gestureType()) { case Qt::BeginNativeGesture: case Qt::EndNativeGesture: case Qt::ZoomNativeGesture: @@ -243,7 +244,7 @@ void QQuickPinchHandler::onActiveChanged() } } -void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) +void QQuickPinchHandler::handlePointerEventImpl(QPointerEvent *event) { if (Q_UNLIKELY(lcPinchHandler().isDebugEnabled())) { for (const QQuickHandlerPoint &p : currentPoints()) @@ -253,9 +254,10 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) qreal dist = 0; #if QT_CONFIG(gestures) - if (const auto gesture = event->asPointerNativeGestureEvent()) { - mutableCentroid().reset(event->point(0)); - switch (gesture->type()) { + if (event->type() == QEvent::NativeGesture) { + const auto gesture = static_cast<const QNativeGestureEvent *>(event); + mutableCentroid().reset(event, event->point(0)); + switch (gesture->gestureType()) { case Qt::EndNativeGesture: m_activeScale = 1; m_activeRotation = 0; @@ -283,11 +285,12 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) } else #endif // QT_CONFIG(gestures) { - const bool containsReleasedPoints = event->isReleaseEvent(); - QVector<QQuickEventPoint *> chosenPoints; + const bool containsReleasedPoints = event->isEndEvent(); + QVector<QEventPoint> chosenPoints; for (const QQuickHandlerPoint &p : currentPoints()) { - QQuickEventPoint *ep = event->pointById(p.id()); - chosenPoints << ep; + auto ep = event->pointById(p.id()); + Q_ASSERT(ep); + chosenPoints << *ep; } if (!active()) { // Verify that at least one of the points has moved beyond threshold needed to activate the handler @@ -300,14 +303,14 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) const int dragThresholdSquared = dragThreshold * dragThreshold; double accumulatedCentroidDistance = 0; // Used to detect scale - if (event->isPressEvent()) + if (event->isBeginEvent()) m_accumulatedStartCentroidDistance = 0; // Used to detect scale float accumulatedMovementMagnitude = 0; - for (QQuickEventPoint *point : qAsConst(chosenPoints)) { + for (auto &point : chosenPoints) { if (!containsReleasedPoints) { - accumulatedDrag += QVector2D(point->scenePressPosition() - point->scenePosition()); + accumulatedDrag += QVector2D(point.scenePressPosition() - point.scenePosition()); /* In order to detect a drag, we want to check if all points have moved more or less in the same direction. @@ -341,20 +344,20 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) was moved, but the relative position between each finger remained very much the same). This is then used to rule out if there is a rotation or scale. */ - QVector2D pressCentroidRelativePosition = QVector2D(point->scenePosition()) - currentCentroid; - QVector2D currentCentroidRelativePosition = QVector2D(point->scenePressPosition()) - pressCentroid; + QVector2D pressCentroidRelativePosition = QVector2D(point.scenePosition()) - currentCentroid; + QVector2D currentCentroidRelativePosition = QVector2D(point.scenePressPosition()) - pressCentroid; QVector2D centroidRelativeMovement = currentCentroidRelativePosition - pressCentroidRelativePosition; accumulatedMovementMagnitude += centroidRelativeMovement.length(); accumulatedCentroidDistance += qreal(pressCentroidRelativePosition.length()); - if (event->isPressEvent()) - m_accumulatedStartCentroidDistance += qreal((QVector2D(point->scenePressPosition()) - pressCentroid).length()); + if (event->isBeginEvent()) + m_accumulatedStartCentroidDistance += qreal((QVector2D(point.scenePressPosition()) - pressCentroid).length()); } else { - setPassiveGrab(point); + setPassiveGrab(event, point); } - if (point->state() == QQuickEventPoint::Pressed) { - point->setAccepted(false); // don't stop propagation - setPassiveGrab(point); + if (point.state() == QEventPoint::Pressed) { + point.setAccepted(false); // don't stop propagation + setPassiveGrab(event, point); } Q_D(QQuickMultiPointHandler); if (d->dragOverThreshold(point)) @@ -376,17 +379,17 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) if (numberOfPointsDraggedOverThreshold >= 1) { if (requiredNumberOfPointsDraggedOverThreshold && avgDrag.lengthSquared() >= dragThresholdSquared && accumulatedMovementMagnitude < dragThreshold) { // Drag - if (grabPoints(chosenPoints)) + if (grabPoints(event, chosenPoints)) setActive(true); } else if (distanceToCentroidDelta > dragThreshold) { // all points should in accumulation have been moved beyond threshold (?) // Scale - if (grabPoints(chosenPoints)) + if (grabPoints(event, chosenPoints)) setActive(true); } else if (distanceToCentroidDelta < dragThreshold && (centroidMovementDelta < dragThreshold)) { // Rotate // Since it wasn't a scale and if we exceeded the dragthreshold, and the // centroid didn't moved much, the points must have been moved around the centroid. - if (grabPoints(chosenPoints)) + if (grabPoints(event, chosenPoints)) setActive(true); } } diff --git a/src/quick/handlers/qquickpinchhandler_p.h b/src/quick/handlers/qquickpinchhandler_p.h index b4e9fa0336..8099982d46 100644 --- a/src/quick/handlers/qquickpinchhandler_p.h +++ b/src/quick/handlers/qquickpinchhandler_p.h @@ -106,9 +106,9 @@ signals: void updated(); protected: - bool wantsPointerEvent(QQuickPointerEvent *event) override; + bool wantsPointerEvent(QPointerEvent *event) override; void onActiveChanged() override; - void handlePointerEventImpl(QQuickPointerEvent *event) override; + void handlePointerEventImpl(QPointerEvent *event) override; private: // properties diff --git a/src/quick/handlers/qquickpointerdevicehandler.cpp b/src/quick/handlers/qquickpointerdevicehandler.cpp index 592abb6660..a27aec7d56 100644 --- a/src/quick/handlers/qquickpointerdevicehandler.cpp +++ b/src/quick/handlers/qquickpointerdevicehandler.cpp @@ -290,7 +290,7 @@ void QQuickPointerDeviceHandler::setAcceptedModifiers(Qt::KeyboardModifiers acce emit acceptedModifiersChanged(); } -bool QQuickPointerDeviceHandler::wantsPointerEvent(QQuickPointerEvent *event) +bool QQuickPointerDeviceHandler::wantsPointerEvent(QPointerEvent *event) { Q_D(QQuickPointerDeviceHandler); if (!QQuickPointerHandler::wantsPointerEvent(event)) @@ -301,14 +301,15 @@ bool QQuickPointerDeviceHandler::wantsPointerEvent(QQuickPointerEvent *event) << "modifiers" << d->acceptedModifiers; if (!d->acceptedDevices.testFlag(event->device()->type())) return false; - if (!d->acceptedPointerTypes.testFlag(event->device()->pointerType())) + if (!d->acceptedPointerTypes.testFlag(event->pointingDevice()->pointerType())) return false; if (d->acceptedModifiers != Qt::KeyboardModifierMask && event->modifiers() != d->acceptedModifiers) return false; // HoverHandler sets acceptedButtons to Qt::NoButton to indicate that button state is irrelevant. - if (event->device()->pointerType() != QPointingDevice::PointerType::Finger && acceptedButtons() != Qt::NoButton && - (event->buttons() & acceptedButtons()) == 0 && (event->button() & acceptedButtons()) == 0 - && !event->asPointerScrollEvent()) + if (event->pointingDevice()->pointerType() != QPointingDevice::PointerType::Finger && + acceptedButtons() != Qt::NoButton && event->type() != QEvent::Wheel && + (static_cast<QSinglePointEvent *>(event)->buttons() & acceptedButtons()) == 0 && + (static_cast<QSinglePointEvent *>(event)->button() & acceptedButtons()) == 0) return false; return true; } diff --git a/src/quick/handlers/qquickpointerdevicehandler_p.h b/src/quick/handlers/qquickpointerdevicehandler_p.h index 28c88db2b7..6091646c14 100644 --- a/src/quick/handlers/qquickpointerdevicehandler_p.h +++ b/src/quick/handlers/qquickpointerdevicehandler_p.h @@ -87,7 +87,7 @@ Q_SIGNALS: protected: QQuickPointerDeviceHandler(QQuickPointerDeviceHandlerPrivate &dd, QQuickItem *parent = nullptr); - bool wantsPointerEvent(QQuickPointerEvent *event) override; + bool wantsPointerEvent(QPointerEvent *event) override; Q_DECLARE_PRIVATE(QQuickPointerDeviceHandler) }; diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp index ce59a35b62..0dc2435b4e 100644 --- a/src/quick/handlers/qquickpointerhandler.cpp +++ b/src/quick/handlers/qquickpointerhandler.cpp @@ -247,31 +247,32 @@ bool QQuickPointerHandler::isCursorShapeExplicitlySet() const call its parent class's implementation in addition to (usually after) whatever custom behavior it implements. */ -void QQuickPointerHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) +void QQuickPointerHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, + QPointerEvent *event, QEventPoint &point) { + Q_UNUSED(event); qCDebug(lcPointerHandlerGrab) << point << transition << grabber; - Q_ASSERT(point); if (grabber == this) { bool wasCanceled = false; switch (transition) { - case QQuickEventPoint::GrabPassive: - case QQuickEventPoint::GrabExclusive: + case QPointingDevice::GrabPassive: + case QPointingDevice::GrabExclusive: break; - case QQuickEventPoint::CancelGrabPassive: - case QQuickEventPoint::CancelGrabExclusive: + case QPointingDevice::CancelGrabPassive: + case QPointingDevice::CancelGrabExclusive: wasCanceled = true; // the grab was stolen by something else Q_FALLTHROUGH(); - case QQuickEventPoint::UngrabPassive: - case QQuickEventPoint::UngrabExclusive: + case QPointingDevice::UngrabPassive: + case QPointingDevice::UngrabExclusive: setActive(false); - point->setAccepted(false); + point.setAccepted(false); if (auto par = parentItem()) { Q_D(const QQuickPointerHandler); par->setKeepMouseGrab(d->hadKeepMouseGrab); par->setKeepTouchGrab(d->hadKeepTouchGrab); } break; - case QQuickEventPoint::OverrideGrabPassive: + case QPointingDevice::OverrideGrabPassive: // Passive grab is still there, but we won't receive point updates right now. // No need to notify about this. return; @@ -297,13 +298,13 @@ void QQuickPointerHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEv grab, or it may acquire an exclusive grab if the gesture clearly must not be interpreted in another way by another handler. */ -void QQuickPointerHandler::setPassiveGrab(QQuickEventPoint *point, bool grab) +void QQuickPointerHandler::setPassiveGrab(QPointerEvent *event, const QEventPoint &point, bool grab) { qCDebug(lcPointerHandlerGrab) << point << grab; if (grab) { - point->setGrabberPointerHandler(this, false); + event->addPassiveGrabber(point, this); } else { - point->removePassiveGrabber(this); + event->removePassiveGrabber(point, this); } } @@ -318,11 +319,11 @@ void QQuickPointerHandler::setPassiveGrab(QQuickEventPoint *point, bool grab) also calls approveGrabTransition() on the handler which is about to lose its grab. Either one can deny the takeover. */ -bool QQuickPointerHandler::canGrab(QQuickEventPoint *point) +bool QQuickPointerHandler::canGrab(QPointerEvent *event, const QEventPoint &point) { - QQuickPointerHandler *existingPhGrabber = point->grabberPointerHandler(); - return approveGrabTransition(point, this) && - (existingPhGrabber ? existingPhGrabber->approveGrabTransition(point, this) : true); + QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point)); + return approveGrabTransition(event, point, this) && + (existingPhGrabber ? existingPhGrabber->approveGrabTransition(event, point, this) : true); } /*! @@ -331,15 +332,15 @@ bool QQuickPointerHandler::canGrab(QQuickEventPoint *point) will take the grab, and once on the instance which would thereby lose its grab, in case of a takeover scenario. */ -bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObject *proposedGrabber) +bool QQuickPointerHandler::approveGrabTransition(QPointerEvent *event, const QEventPoint &point, QObject *proposedGrabber) { Q_D(const QQuickPointerHandler); bool allowed = false; if (proposedGrabber == this) { - QObject* existingGrabber = point->exclusiveGrabber(); + QObject* existingGrabber = event->exclusiveGrabber(point); allowed = (existingGrabber == nullptr) || ((d->grabPermissions & CanTakeOverFromAnything) == CanTakeOverFromAnything); if (existingGrabber) { - if (QQuickPointerHandler *existingPhGrabber = point->grabberPointerHandler()) { + if (QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point))) { if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfDifferentType) && existingPhGrabber->metaObject()->className() != metaObject()->className()) allowed = true; @@ -347,9 +348,9 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec existingPhGrabber->metaObject()->className() == metaObject()->className()) allowed = true; } else if ((d->grabPermissions & CanTakeOverFromItems)) { - QQuickItem * existingItemGrabber = point->grabberItem(); - if (existingItemGrabber && !((existingItemGrabber->keepMouseGrab() && point->pointerEvent()->asPointerMouseEvent()) || - (existingItemGrabber->keepTouchGrab() && point->pointerEvent()->asPointerTouchEvent()))) { + QQuickItem * existingItemGrabber = qobject_cast<QQuickItem *>(event->exclusiveGrabber(point)); + if (existingItemGrabber && !((existingItemGrabber->keepMouseGrab() && QQuickWindowPrivate::isMouseEvent(event)) || + (existingItemGrabber->keepTouchGrab() && QQuickWindowPrivate::isTouchEvent(event)))) { allowed = true; // If the handler wants to steal the exclusive grab from an Item, the Item can usually veto // by having its keepMouseGrab flag set. But an exception is if that Item is a parent that @@ -361,8 +362,8 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec if (existingItemGrabber->keepMouseGrab() && !(existingItemGrabber->filtersChildMouseEvents() && existingItemGrabber->isAncestorOf(parentItem()))) { QQuickWindowPrivate *winPriv = QQuickWindowPrivate::get(parentItem()->window()); - if (winPriv->isDeliveringTouchAsMouse() && point->pointId() == winPriv->touchMouseId) { - qCDebug(lcPointerHandlerGrab) << this << "wants to grab touchpoint" << point->pointId() + if (winPriv->isDeliveringTouchAsMouse() && point.id() == winPriv->touchMouseId) { + qCDebug(lcPointerHandlerGrab) << this << "wants to grab touchpoint" << point.id() << "but declines to steal grab from touch-mouse grabber with keepMouseGrab=true" << existingItemGrabber; allowed = false; } @@ -388,7 +389,7 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec allowed = true; } } - qCDebug(lcPointerHandlerGrab) << "point" << Qt::hex << point->pointId() << "permission" << + qCDebug(lcPointerHandlerGrab) << "point" << Qt::hex << point.id() << "permission" << QMetaEnum::fromType<GrabPermissions>().valueToKeys(grabPermissions()) << ':' << this << (allowed ? "approved to" : "denied to") << proposedGrabber; return allowed; @@ -449,7 +450,7 @@ void QQuickPointerHandler::componentComplete() { } -QQuickPointerEvent *QQuickPointerHandler::currentEvent() +QPointerEvent *QQuickPointerHandler::currentEvent() { Q_D(const QQuickPointerHandler); return d->currentEvent; @@ -463,52 +464,60 @@ QQuickPointerEvent *QQuickPointerHandler::currentEvent() specified. Returns false if permission is denied either by this handler or by the handler or item from which this handler would take over */ -bool QQuickPointerHandler::setExclusiveGrab(QQuickEventPoint *point, bool grab) +bool QQuickPointerHandler::setExclusiveGrab(QPointerEvent *ev, const QEventPoint &point, bool grab) { - if ((grab && point->exclusiveGrabber() == this) || (!grab && point->exclusiveGrabber() != this)) + if ((grab && ev->exclusiveGrabber(point) == this) || (!grab && ev->exclusiveGrabber(point) != this)) return true; // TODO m_hadKeepMouseGrab m_hadKeepTouchGrab bool allowed = true; if (grab) { - allowed = canGrab(point); + allowed = canGrab(ev, point); } else { - QQuickPointerHandler *existingPhGrabber = point->grabberPointerHandler(); + QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(ev->exclusiveGrabber(point)); // Ask before allowing one handler to cancel another's grab - if (existingPhGrabber && existingPhGrabber != this && !existingPhGrabber->approveGrabTransition(point, nullptr)) + if (existingPhGrabber && existingPhGrabber != this && !existingPhGrabber->approveGrabTransition(ev, point, nullptr)) allowed = false; } qCDebug(lcPointerHandlerGrab) << point << (grab ? "grab" : "ungrab") << (allowed ? "allowed" : "forbidden") << - point->exclusiveGrabber() << "->" << (grab ? this : nullptr); + ev->exclusiveGrabber(point) << "->" << (grab ? this : nullptr); if (allowed) - point->setGrabberPointerHandler(grab ? this : nullptr, true); + ev->setExclusiveGrabber(point, grab ? this : nullptr); return allowed; } /*! Cancel any existing grab of the given \a point. */ -void QQuickPointerHandler::cancelAllGrabs(QQuickEventPoint *point) +void QQuickPointerHandler::cancelAllGrabs(QPointerEvent *event, QEventPoint &point) { qCDebug(lcPointerHandlerGrab) << point; - point->cancelAllGrabs(this); + if (event->exclusiveGrabber(point) == this) { + event->setExclusiveGrabber(point, nullptr); + onGrabChanged(this, QPointingDevice::CancelGrabExclusive, event, point); + } + if (event->removePassiveGrabber(point, this)) + onGrabChanged(this, QPointingDevice::CancelGrabPassive, event, point); } -QPointF QQuickPointerHandler::eventPos(const QQuickEventPoint *point) const +QPointF QQuickPointerHandler::eventPos(const QEventPoint &point) const { - return (target() ? target()->mapFromScene(point->scenePosition()) : point->scenePosition()); + return (target() ? target()->mapFromScene(point.scenePosition()) : point.scenePosition()); } -bool QQuickPointerHandler::parentContains(const QQuickEventPoint *point) const +bool QQuickPointerHandler::parentContains(const QEventPoint &point) const +{ + return parentContains(point.scenePosition()); +} + +bool QQuickPointerHandler::parentContains(const QPointF &scenePosition) const { - if (!point) - return false; if (QQuickItem *par = parentItem()) { if (par->window()) { - QPoint screenPosition = par->window()->mapToGlobal(point->scenePosition().toPoint()); + QPoint screenPosition = par->window()->mapToGlobal(scenePosition.toPoint()); if (!par->window()->geometry().contains(screenPosition)) return false; } - QPointF p = par->mapFromScene(point->scenePosition()); + QPointF p = par->mapFromScene(scenePosition); qreal m = margin(); if (m > 0) return p.x() >= -m && p.y() >= -m && p.x() <= par->width() + m && p.y() <= par->height() + m; @@ -582,7 +591,29 @@ QQuickItem *QQuickPointerHandler::target() const return d->target; } -void QQuickPointerHandler::handlePointerEvent(QQuickPointerEvent *event) +/*! \internal + Pointer Handlers do most of their work in implementations of virtual functions + that are called directly from QQuickItem, not by direct event handling. + But it's convenient to deliver TouchCancel events via QCoreApplication::sendEvent(). + Perhaps it will turn out that more events could be delivered this way. +*/ +bool QQuickPointerHandler::event(QEvent *e) +{ + switch (e->type()) { + case QEvent::TouchCancel: { + auto te = static_cast<QTouchEvent *>(e); + for (int i = 0; i < te->pointCount(); ++i) + onGrabChanged(this, QPointingDevice::CancelGrabExclusive, te, te->point(i)); + return true; + break; + } + default: + return QObject::event(e); + break; + } +} + +void QQuickPointerHandler::handlePointerEvent(QPointerEvent *event) { bool wants = wantsPointerEvent(event); qCDebug(lcPointerHandlerDispatch) << metaObject()->className() << objectName() @@ -592,27 +623,30 @@ void QQuickPointerHandler::handlePointerEvent(QQuickPointerEvent *event) handlePointerEventImpl(event); } else { setActive(false); - int pCount = event->pointCount(); - for (int i = 0; i < pCount; ++i) { - QQuickEventPoint *pt = event->point(i); - if (pt->grabberPointerHandler() == this && pt->state() != QQuickEventPoint::Stationary) - pt->cancelExclusiveGrab(); + for (int i = 0; i < event->pointCount(); ++i) { + auto &pt = event->point(i); + if (event->exclusiveGrabber(pt) == this && pt.state() != QEventPoint::Stationary) { + event->setExclusiveGrabber(pt, nullptr); + onGrabChanged(this, QPointingDevice::CancelGrabExclusive, event, pt); + } } } QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->device()).append(this); } -bool QQuickPointerHandler::wantsPointerEvent(QQuickPointerEvent *event) +bool QQuickPointerHandler::wantsPointerEvent(QPointerEvent *event) { Q_D(const QQuickPointerHandler); Q_UNUSED(event); return d->enabled; } -bool QQuickPointerHandler::wantsEventPoint(QQuickEventPoint *point) +bool QQuickPointerHandler::wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) { - bool ret = point->exclusiveGrabber() == this || point->passiveGrabbers().contains(this) || parentContains(point); - qCDebug(lcPointerHandlerDispatch) << Qt::hex << point->pointId() << "@" << point->scenePosition() + Q_UNUSED(event); + bool ret = event->exclusiveGrabber(point) == this || + event->passiveGrabbers(point).contains(this) || parentContains(point); + qCDebug(lcPointerHandlerDispatch) << Qt::hex << point.id() << "@" << point.scenePosition() << metaObject()->className() << objectName() << ret; return ret; } @@ -638,7 +672,7 @@ void QQuickPointerHandler::setActive(bool active) } } -void QQuickPointerHandler::handlePointerEventImpl(QQuickPointerEvent *event) +void QQuickPointerHandler::handlePointerEventImpl(QPointerEvent *event) { Q_D(QQuickPointerHandler); d->currentEvent = event; @@ -689,14 +723,14 @@ QQuickPointerHandlerPrivate::QQuickPointerHandlerPrivate() } template <typename TEventPoint> -bool QQuickPointerHandlerPrivate::dragOverThreshold(qreal d, Qt::Axis axis, const TEventPoint *p) const +bool QQuickPointerHandlerPrivate::dragOverThreshold(qreal d, Qt::Axis axis, const TEventPoint &p) const { Q_Q(const QQuickPointerHandler); QStyleHints *styleHints = qApp->styleHints(); bool overThreshold = qAbs(d) > q->dragThreshold(); const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0); if (!overThreshold && dragVelocityLimitAvailable) { - qreal velocity = qreal(axis == Qt::XAxis ? p->velocity().x() : p->velocity().y()); + qreal velocity = qreal(axis == Qt::XAxis ? p.velocity().x() : p.velocity().y()); overThreshold |= qAbs(velocity) > styleHints->startDragVelocity(); } return overThreshold; @@ -709,9 +743,9 @@ bool QQuickPointerHandlerPrivate::dragOverThreshold(QVector2D delta) const return qAbs(delta.x()) > threshold || qAbs(delta.y()) > threshold; } -bool QQuickPointerHandlerPrivate::dragOverThreshold(const QQuickEventPoint *point) const +bool QQuickPointerHandlerPrivate::dragOverThreshold(const QEventPoint &point) const { - QPointF delta = point->scenePosition() - point->scenePressPosition(); + QPointF delta = point.scenePosition() - point.scenePressPosition(); return (dragOverThreshold(delta.x(), Qt::XAxis, point) || dragOverThreshold(delta.y(), Qt::YAxis, point)); } diff --git a/src/quick/handlers/qquickpointerhandler_p.h b/src/quick/handlers/qquickpointerhandler_p.h index 3e7876b3d9..8d7fdcdcad 100644 --- a/src/quick/handlers/qquickpointerhandler_p.h +++ b/src/quick/handlers/qquickpointerhandler_p.h @@ -110,7 +110,7 @@ public: QQuickItem * parentItem() const; - void handlePointerEvent(QQuickPointerEvent *event); + void handlePointerEvent(QPointerEvent *event); GrabPermissions grabPermissions() const; void setGrabPermissions(GrabPermissions grabPermissions); @@ -135,9 +135,9 @@ Q_SIGNALS: void targetChanged(); void marginChanged(); Q_REVISION(2, 15) void dragThresholdChanged(); - void grabChanged(QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point); + void grabChanged(QPointingDevice::GrabTransition transition, QEventPoint point); void grabPermissionChanged(); - void canceled(QQuickEventPoint *point); + void canceled(QEventPoint point); #if QT_CONFIG(cursor) Q_REVISION(2, 15) void cursorShapeChanged(); #endif @@ -147,24 +147,26 @@ protected: void classBegin() override; void componentComplete() override; + bool event(QEvent *) override; - QQuickPointerEvent *currentEvent(); - virtual bool wantsPointerEvent(QQuickPointerEvent *event); - virtual bool wantsEventPoint(QQuickEventPoint *point); - virtual void handlePointerEventImpl(QQuickPointerEvent *event); + QPointerEvent *currentEvent(); + virtual bool wantsPointerEvent(QPointerEvent *event); + virtual bool wantsEventPoint(const QPointerEvent *event, const QEventPoint &point); + virtual void handlePointerEventImpl(QPointerEvent *event); void setActive(bool active); virtual void onTargetChanged(QQuickItem *oldTarget) { Q_UNUSED(oldTarget); } virtual void onActiveChanged() { } - virtual void onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point); - virtual bool canGrab(QQuickEventPoint *point); - virtual bool approveGrabTransition(QQuickEventPoint *point, QObject *proposedGrabber); - void setPassiveGrab(QQuickEventPoint *point, bool grab = true); - bool setExclusiveGrab(QQuickEventPoint *point, bool grab = true); - void cancelAllGrabs(QQuickEventPoint *point); - QPointF eventPos(const QQuickEventPoint *point) const; - bool parentContains(const QQuickEventPoint *point) const; - - friend class QQuickEventPoint; + virtual void onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, + QPointerEvent *event, QEventPoint &point); + virtual bool canGrab(QPointerEvent *event, const QEventPoint &point); + virtual bool approveGrabTransition(QPointerEvent *event, const QEventPoint &point, QObject *proposedGrabber); + void setPassiveGrab(QPointerEvent *event, const QEventPoint &point, bool grab = true); + bool setExclusiveGrab(QPointerEvent *ev, const QEventPoint &point, bool grab = true); + void cancelAllGrabs(QPointerEvent *event, QEventPoint &point); + QPointF eventPos(const QEventPoint &point) const; + bool parentContains(const QEventPoint &point) const; + bool parentContains(const QPointF &scenePosition) const; + friend class QQuickItemPrivate; friend class QQuickWindowPrivate; diff --git a/src/quick/handlers/qquickpointerhandler_p_p.h b/src/quick/handlers/qquickpointerhandler_p_p.h index 03b36c6dae..99120523d8 100644 --- a/src/quick/handlers/qquickpointerhandler_p_p.h +++ b/src/quick/handlers/qquickpointerhandler_p_p.h @@ -69,14 +69,14 @@ public: QQuickPointerHandlerPrivate(); template<typename TEventPoint> - bool dragOverThreshold(qreal d, Qt::Axis axis, const TEventPoint *p) const; + bool dragOverThreshold(qreal d, Qt::Axis axis, const TEventPoint &p) const; bool dragOverThreshold(QVector2D delta) const; - bool dragOverThreshold(const QQuickEventPoint *point) const; + bool dragOverThreshold(const QEventPoint &point) const; static QVector<QObject *> &deviceDeliveryTargets(const QInputDevice *device); - QQuickPointerEvent *currentEvent = nullptr; + QPointerEvent *currentEvent = nullptr; QQuickItem *target = nullptr; qreal m_margin = 0; qint16 dragThreshold = -1; // -1 means use the platform default diff --git a/src/quick/handlers/qquickpointhandler.cpp b/src/quick/handlers/qquickpointhandler.cpp index 30f62332ba..c3dd997e4a 100644 --- a/src/quick/handlers/qquickpointhandler.cpp +++ b/src/quick/handlers/qquickpointhandler.cpp @@ -120,11 +120,11 @@ QQuickPointHandler::QQuickPointHandler(QQuickItem *parent) setIgnoreAdditionalPoints(); } -bool QQuickPointHandler::wantsEventPoint(QQuickEventPoint *pt) +bool QQuickPointHandler::wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) { // On press, we want it unless a sibling of the same type also does. - if (pt->state() == QQuickEventPoint::Pressed && QQuickSinglePointHandler::wantsEventPoint(pt)) { - for (const QQuickPointerHandler *grabber : pt->passiveGrabbers()) { + if (point.state() == QEventPoint::Pressed && QQuickSinglePointHandler::wantsEventPoint(event, point)) { + for (const QObject *grabber : event->passiveGrabbers(point)) { if (grabber && grabber->parent() == parent() && grabber->metaObject()->className() == metaObject()->className()) return false; @@ -132,28 +132,29 @@ bool QQuickPointHandler::wantsEventPoint(QQuickEventPoint *pt) return true; } // If we've already been interested in a point, stay interested, even if it has strayed outside bounds. - return (pt->state() != QQuickEventPoint::Pressed && point().id() == pt->pointId()); + return (point.state() != QEventPoint::Pressed && + QQuickSinglePointHandler::point().id() == point.id()); } -void QQuickPointHandler::handleEventPoint(QQuickEventPoint *point) +void QQuickPointHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point) { - switch (point->state()) { - case QQuickEventPoint::Pressed: - if (point->pointerEvent()->asPointerTouchEvent() || - (point->pointerEvent()->buttons() & acceptedButtons()) != Qt::NoButton) { - setPassiveGrab(point); + switch (point.state()) { + case QEventPoint::Pressed: + if (QQuickWindowPrivate::isTouchEvent(event) || + (static_cast<const QSinglePointEvent *>(event)->buttons() & acceptedButtons()) != Qt::NoButton) { + setPassiveGrab(event, point); setActive(true); } break; - case QQuickEventPoint::Released: - if (point->pointerEvent()->asPointerTouchEvent() || - (point->pointerEvent()->buttons() & acceptedButtons()) == Qt::NoButton) + case QEventPoint::Released: + if (QQuickWindowPrivate::isTouchEvent(event) || + (static_cast<const QSinglePointEvent *>(event)->buttons() & acceptedButtons()) == Qt::NoButton) setActive(false); break; default: break; } - point->setAccepted(false); // Just lurking... don't interfere with propagation + point.setAccepted(false); // Just lurking... don't interfere with propagation emit translationChanged(); } diff --git a/src/quick/handlers/qquickpointhandler_p.h b/src/quick/handlers/qquickpointhandler_p.h index cedbc1c539..cec48b193d 100644 --- a/src/quick/handlers/qquickpointhandler_p.h +++ b/src/quick/handlers/qquickpointhandler_p.h @@ -71,8 +71,8 @@ Q_SIGNALS: void translationChanged(); protected: - bool wantsEventPoint(QQuickEventPoint *pt) override; - void handleEventPoint(QQuickEventPoint *point) override; + bool wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) override; + void handleEventPoint(QPointerEvent *event, QEventPoint &point) override; }; QT_END_NAMESPACE diff --git a/src/quick/handlers/qquicksinglepointhandler.cpp b/src/quick/handlers/qquicksinglepointhandler.cpp index 89081b4e84..18636991e6 100644 --- a/src/quick/handlers/qquicksinglepointhandler.cpp +++ b/src/quick/handlers/qquicksinglepointhandler.cpp @@ -69,7 +69,7 @@ QQuickSinglePointHandler::QQuickSinglePointHandler(QQuickSinglePointHandlerPriva { } -bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event) +bool QQuickSinglePointHandler::wantsPointerEvent(QPointerEvent *event) { Q_D(QQuickSinglePointHandler); if (!QQuickPointerDeviceHandler::wantsPointerEvent(event)) @@ -81,17 +81,16 @@ bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event) // If we no longer want it, cancel the grab. int candidatePointCount = 0; bool missing = true; - QQuickEventPoint *point = nullptr; - int c = event->pointCount(); - for (int i = 0; i < c; ++i) { - QQuickEventPoint *p = event->point(i); - const bool found = (p->pointId() == d->pointInfo.id()); + QEventPoint *point = nullptr; + for (int i = 0; i < event->pointCount(); ++i) { + auto &p = event->point(i); + const bool found = (p.id() == d->pointInfo.id()); if (found) missing = false; - if (wantsEventPoint(p)) { + if (wantsEventPoint(event, p)) { ++candidatePointCount; if (found) - point = p; + point = &p; } } if (missing) @@ -102,7 +101,7 @@ bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event) point->setAccepted(); return true; } else { - point->cancelAllGrabs(this); + cancelAllGrabs(event, *point); } } else { return false; @@ -110,62 +109,63 @@ bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event) } else { // We have not yet chosen a point; choose the first one for which wantsEventPoint() returns true. int candidatePointCount = 0; - int c = event->pointCount(); - QQuickEventPoint *chosen = nullptr; - for (int i = 0; i < c && !chosen; ++i) { - QQuickEventPoint *p = event->point(i); - if (!p->exclusiveGrabber() && wantsEventPoint(p)) { - if (!chosen) - chosen = p; + QEventPoint *chosen = nullptr; + for (int i = 0; i < event->pointCount(); ++i) { + auto &p = event->point(i); + if (!event->exclusiveGrabber(p) && wantsEventPoint(event, p)) { ++candidatePointCount; + if (!chosen) { + chosen = &p; + break; + } } } if (chosen && candidatePointCount == 1) { - setPointId(chosen->pointId()); + setPointId(chosen->id()); chosen->setAccepted(); } } return d->pointInfo.id() != -1; } -void QQuickSinglePointHandler::handlePointerEventImpl(QQuickPointerEvent *event) +void QQuickSinglePointHandler::handlePointerEventImpl(QPointerEvent *event) { Q_D(QQuickSinglePointHandler); QQuickPointerDeviceHandler::handlePointerEventImpl(event); - QQuickEventPoint *currentPoint = event->pointById(d->pointInfo.id()); + QEventPoint *currentPoint = const_cast<QEventPoint *>(event->pointById(d->pointInfo.id())); Q_ASSERT(currentPoint); - d->pointInfo.reset(currentPoint); - handleEventPoint(currentPoint); - if (currentPoint->state() == QQuickEventPoint::Released && (event->buttons() & acceptedButtons()) == Qt::NoButton) { - setExclusiveGrab(currentPoint, false); + d->pointInfo.reset(event, *currentPoint); + handleEventPoint(event, *currentPoint); + if (currentPoint->state() == QEventPoint::Released && (static_cast<QSinglePointEvent *>(event)->buttons() & acceptedButtons()) == Qt::NoButton) { + setExclusiveGrab(event, *currentPoint, false); d->reset(); } emit pointChanged(); } -void QQuickSinglePointHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) +void QQuickSinglePointHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, QPointerEvent *event, QEventPoint &point) { Q_D(QQuickSinglePointHandler); if (grabber != this) return; switch (transition) { - case QQuickEventPoint::GrabExclusive: - d->pointInfo.m_sceneGrabPosition = point->sceneGrabPosition(); + case QPointingDevice::GrabExclusive: + d->pointInfo.m_sceneGrabPosition = point.sceneGrabPosition(); setActive(true); - QQuickPointerHandler::onGrabChanged(grabber, transition, point); + QQuickPointerHandler::onGrabChanged(grabber, transition, event, point); break; - case QQuickEventPoint::GrabPassive: - d->pointInfo.m_sceneGrabPosition = point->sceneGrabPosition(); - QQuickPointerHandler::onGrabChanged(grabber, transition, point); + case QPointingDevice::GrabPassive: + d->pointInfo.m_sceneGrabPosition = point.sceneGrabPosition(); + QQuickPointerHandler::onGrabChanged(grabber, transition, event, point); break; - case QQuickEventPoint::OverrideGrabPassive: + case QPointingDevice::OverrideGrabPassive: return; // don't emit - case QQuickEventPoint::UngrabPassive: - case QQuickEventPoint::UngrabExclusive: - case QQuickEventPoint::CancelGrabPassive: - case QQuickEventPoint::CancelGrabExclusive: + case QPointingDevice::UngrabPassive: + case QPointingDevice::UngrabExclusive: + case QPointingDevice::CancelGrabPassive: + case QPointingDevice::CancelGrabExclusive: // the grab is lost or relinquished, so the point is no longer relevant - QQuickPointerHandler::onGrabChanged(grabber, transition, point); + QQuickPointerHandler::onGrabChanged(grabber, transition, event, point); d->reset(); break; } @@ -177,11 +177,11 @@ void QQuickSinglePointHandler::setIgnoreAdditionalPoints(bool v) d->ignoreAdditionalPoints = v; } -void QQuickSinglePointHandler::moveTarget(QPointF pos, QQuickEventPoint *point) +void QQuickSinglePointHandler::moveTarget(QPointF pos, QEventPoint &point) { Q_D(QQuickSinglePointHandler); target()->setPosition(pos); - d->pointInfo.m_scenePosition = point->scenePosition(); + d->pointInfo.m_scenePosition = point.scenePosition(); d->pointInfo.m_position = target()->mapFromScene(d->pointInfo.m_scenePosition); } diff --git a/src/quick/handlers/qquicksinglepointhandler_p.h b/src/quick/handlers/qquicksinglepointhandler_p.h index edc55aaaf6..85ab4f24d4 100644 --- a/src/quick/handlers/qquicksinglepointhandler_p.h +++ b/src/quick/handlers/qquicksinglepointhandler_p.h @@ -74,16 +74,16 @@ Q_SIGNALS: protected: QQuickSinglePointHandler(QQuickSinglePointHandlerPrivate &dd, QQuickItem *parent); - bool wantsPointerEvent(QQuickPointerEvent *event) override; - void handlePointerEventImpl(QQuickPointerEvent *event) override; - virtual void handleEventPoint(QQuickEventPoint *point) = 0; + bool wantsPointerEvent(QPointerEvent *event) override; + void handlePointerEventImpl(QPointerEvent *event) override; + virtual void handleEventPoint(QPointerEvent *event, QEventPoint &point) = 0; - QQuickEventPoint *currentPoint(QQuickPointerEvent *ev); - void onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) override; + QEventPoint ¤tPoint(QPointerEvent *ev); + void onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, QPointerEvent *event, QEventPoint &point) override; void setIgnoreAdditionalPoints(bool v = true); - void moveTarget(QPointF pos, QQuickEventPoint *point); + void moveTarget(QPointF pos, QEventPoint &point); void setPointId(int id); diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp index 2fabd39709..c8525cfcb0 100644 --- a/src/quick/handlers/qquicktaphandler.cpp +++ b/src/quick/handlers/qquicktaphandler.cpp @@ -97,11 +97,10 @@ QQuickTapHandler::QQuickTapHandler(QQuickItem *parent) } } -bool QQuickTapHandler::wantsEventPoint(QQuickEventPoint *point) +bool QQuickTapHandler::wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) { - if (!point->pointerEvent()->asPointerMouseEvent() && - !point->pointerEvent()->asPointerTouchEvent() && - !point->pointerEvent()->asPointerTabletEvent() ) + if (!QQuickWindowPrivate::isMouseEvent(event) && !QQuickWindowPrivate::isTouchEvent(event) && + !QQuickWindowPrivate::isTabletEvent(event)) return false; // If the user has not violated any constraint, it could be a tap. // Otherwise we want to give up the grab so that a competing handler @@ -113,12 +112,12 @@ bool QQuickTapHandler::wantsEventPoint(QQuickEventPoint *point) m_longPressTimer.stop(); m_holdTimer.invalidate(); } - switch (point->state()) { - case QQuickEventPoint::Pressed: - case QQuickEventPoint::Released: + switch (point.state()) { + case QEventPoint::Pressed: + case QEventPoint::Released: ret = parentContains(point); break; - case QQuickEventPoint::Updated: + case QEventPoint::Updated: switch (m_gesturePolicy) { case DragThreshold: ret = !overThreshold && parentContains(point); @@ -127,35 +126,39 @@ bool QQuickTapHandler::wantsEventPoint(QQuickEventPoint *point) ret = parentContains(point); break; case ReleaseWithinBounds: - ret = point->pointId() == this->point().id(); + ret = point.id() == this->point().id(); break; } break; - case QQuickEventPoint::Stationary: + case QEventPoint::Stationary: // If the point hasn't moved since last time, the return value should be the same as last time. // If we return false here, QQuickPointerHandler::handlePointerEvent() will call setActive(false). - ret = point->pointId() == this->point().id(); + ret = point.id() == this->point().id(); + break; + case QEventPoint::Unknown: break; } // If this is the grabber, returning false from this function will cancel the grab, // so onGrabChanged(this, CancelGrabExclusive, point) and setPressed(false) will be called. // But when m_gesturePolicy is DragThreshold, we don't get an exclusive grab, but // we still don't want to be pressed anymore. - if (!ret && point->pointId() == this->point().id()) - setPressed(false, true, point); + if (!ret && point.id() == this->point().id()) + setPressed(false, true, const_cast<QPointerEvent *>(event), const_cast<QEventPoint &>(point)); return ret; } -void QQuickTapHandler::handleEventPoint(QQuickEventPoint *point) +void QQuickTapHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point) { - switch (point->state()) { - case QQuickEventPoint::Pressed: - setPressed(true, false, point); + switch (point.state()) { + case QEventPoint::Pressed: + setPressed(true, false, event, point); break; - case QQuickEventPoint::Released: - if ((point->pointerEvent()->buttons() & acceptedButtons()) == Qt::NoButton) - setPressed(false, false, point); + case QEventPoint::Released: { + if (QQuickWindowPrivate::isTouchEvent(event) || + (static_cast<const QSinglePointEvent *>(event)->buttons() & acceptedButtons()) == Qt::NoButton) + setPressed(false, false, event, point); break; + } default: break; } @@ -253,7 +256,7 @@ void QQuickTapHandler::setGesturePolicy(QQuickTapHandler::GesturePolicy gestureP \l gesturePolicy. When the event point is released or the policy is violated, \e pressed will change to false. */ -void QQuickTapHandler::setPressed(bool press, bool cancel, QQuickEventPoint *point) +void QQuickTapHandler::setPressed(bool press, bool cancel, QPointerEvent *event, QEventPoint &point) { if (m_pressed != press) { qCDebug(lcTapHandler) << objectName() << "pressed" << m_pressed << "->" << press << (cancel ? "CANCEL" : "") << point; @@ -270,17 +273,17 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QQuickEventPoint *poi if (press) { // on press, grab before emitting changed signals if (m_gesturePolicy == DragThreshold) - setPassiveGrab(point, press); + setPassiveGrab(event, point, press); else - setExclusiveGrab(point, press); + setExclusiveGrab(event, point, press); } if (!cancel && !press && parentContains(point)) { - if (point->timeHeld() < longPressThreshold()) { + if (point.timeHeld() < longPressThreshold()) { // Assuming here that pointerEvent()->timestamp() is in ms. - qreal ts = point->pointerEvent()->timestamp() / 1000.0; + qreal ts = event->timestamp() / 1000.0; if (ts - m_lastTapTimestamp < m_multiTapInterval && - QVector2D(point->scenePosition() - m_lastTapPos).lengthSquared() < - (point->pointerEvent()->device()->type() == QInputDevice::DeviceType::Mouse ? + QVector2D(point.scenePosition() - m_lastTapPos).lengthSquared() < + (event->device()->type() == QInputDevice::DeviceType::Mouse ? m_mouseMultiClickDistanceSquared : m_touchMultiTapDistanceSquared)) ++m_tapCount; else @@ -293,19 +296,19 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QQuickEventPoint *poi else if (m_tapCount == 2) emit doubleTapped(point); m_lastTapTimestamp = ts; - m_lastTapPos = point->scenePosition(); + m_lastTapPos = point.scenePosition(); } else { - qCDebug(lcTapHandler) << objectName() << "tap threshold" << longPressThreshold() << "exceeded:" << point->timeHeld(); + qCDebug(lcTapHandler) << objectName() << "tap threshold" << longPressThreshold() << "exceeded:" << point.timeHeld(); } } emit pressedChanged(); if (!press && m_gesturePolicy != DragThreshold) { // on release, ungrab after emitting changed signals - setExclusiveGrab(point, press); + setExclusiveGrab(event, point, press); } if (cancel) { emit canceled(point); - setExclusiveGrab(point, false); + setExclusiveGrab(event, point, false); // In case there is a filtering parent (Flickable), we should not give up the passive grab, // so that it can continue to filter future events. d_func()->reset(); @@ -314,12 +317,13 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QQuickEventPoint *poi } } -void QQuickTapHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) +void QQuickTapHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, + QPointerEvent *ev, QEventPoint &point) { - QQuickSinglePointHandler::onGrabChanged(grabber, transition, point); - bool isCanceled = transition == QQuickEventPoint::CancelGrabExclusive || transition == QQuickEventPoint::CancelGrabPassive; - if (grabber == this && (isCanceled || point->state() == QQuickEventPoint::Released)) - setPressed(false, isCanceled, point); + QQuickSinglePointHandler::onGrabChanged(grabber, transition, ev, point); + bool isCanceled = transition == QPointingDevice::CancelGrabExclusive || transition == QPointingDevice::CancelGrabPassive; + if (grabber == this && (isCanceled || point.state() == QEventPoint::Released)) + setPressed(false, isCanceled, ev, point); } void QQuickTapHandler::connectPreRenderSignal(bool conn) diff --git a/src/quick/handlers/qquicktaphandler_p.h b/src/quick/handlers/qquicktaphandler_p.h index d5c16b071f..d75547eee2 100644 --- a/src/quick/handlers/qquicktaphandler_p.h +++ b/src/quick/handlers/qquicktaphandler_p.h @@ -97,19 +97,20 @@ Q_SIGNALS: void timeHeldChanged(); void longPressThresholdChanged(); void gesturePolicyChanged(); - void tapped(QQuickEventPoint *eventPoint); - void singleTapped(QQuickEventPoint *eventPoint); - void doubleTapped(QQuickEventPoint *eventPoint); + void tapped(QEventPoint eventPoint); + void singleTapped(QEventPoint eventPoint); + void doubleTapped(QEventPoint eventPoint); void longPressed(); protected: - void onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) override; + void onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, + QPointerEvent *ev, QEventPoint &point) override; void timerEvent(QTimerEvent *event) override; - bool wantsEventPoint(QQuickEventPoint *point) override; - void handleEventPoint(QQuickEventPoint *point) override; + bool wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) override; + void handleEventPoint(QPointerEvent *event, QEventPoint &point) override; private: - void setPressed(bool press, bool cancel, QQuickEventPoint *point); + void setPressed(bool press, bool cancel, QPointerEvent *event, QEventPoint &point); int longPressThresholdMilliseconds() const; void connectPreRenderSignal(bool conn = true); void updateTimeHeld(); diff --git a/src/quick/handlers/qquickwheelhandler.cpp b/src/quick/handlers/qquickwheelhandler.cpp index b55d9aa27b..b9c112a0d2 100644 --- a/src/quick/handlers/qquickwheelhandler.cpp +++ b/src/quick/handlers/qquickwheelhandler.cpp @@ -360,60 +360,62 @@ void QQuickWheelHandler::setTargetTransformAroundCursor(bool ttac) emit targetTransformAroundCursorChanged(); } -bool QQuickWheelHandler::wantsPointerEvent(QQuickPointerEvent *event) +bool QQuickWheelHandler::wantsPointerEvent(QPointerEvent *event) { if (!event) return false; - QQuickPointerScrollEvent *scroll = event->asPointerScrollEvent(); - if (!scroll) + if (event->type() != QEvent::Wheel) return false; + QWheelEvent *we = static_cast<QWheelEvent *>(event); if (!acceptedDevices().testFlag(QPointingDevice::DeviceType::TouchPad) - && scroll->synthSource() != Qt::MouseEventNotSynthesized) + && we->source() != Qt::MouseEventNotSynthesized) return false; if (!active()) { switch (orientation()) { case Qt::Horizontal: - if (qFuzzyIsNull(scroll->angleDelta().x()) && qFuzzyIsNull(scroll->pixelDelta().x())) + if (!(we->angleDelta().x()) && !(we->pixelDelta().x())) return false; break; case Qt::Vertical: - if (qFuzzyIsNull(scroll->angleDelta().y()) && qFuzzyIsNull(scroll->pixelDelta().y())) + if (!(we->angleDelta().y()) && !(we->pixelDelta().y())) return false; break; } } - QQuickEventPoint *point = event->point(0); - if (QQuickPointerDeviceHandler::wantsPointerEvent(event) && wantsEventPoint(point) && parentContains(point)) { - setPointId(point->pointId()); + auto &point = event->point(0); + if (QQuickPointerDeviceHandler::wantsPointerEvent(event) && wantsEventPoint(event, point) && parentContains(point)) { + setPointId(point.id()); return true; } return false; } -void QQuickWheelHandler::handleEventPoint(QQuickEventPoint *point) +void QQuickWheelHandler::handleEventPoint(QPointerEvent *ev, QEventPoint &point) { Q_D(QQuickWheelHandler); - QQuickPointerScrollEvent *event = point->pointerEvent()->asPointerScrollEvent(); + if (ev->type() != QEvent::Wheel) + return; + const QWheelEvent *event = static_cast<const QWheelEvent *>(ev); setActive(true); // ScrollEnd will not happen unless it was already active (see setActive(false) below) - point->setAccepted(); + point.setAccepted(); qreal inversion = !d->invertible && event->isInverted() ? -1 : 1; qreal angleDelta = inversion * qreal(orientation() == Qt::Horizontal ? event->angleDelta().x() : event->angleDelta().y()) / 8; d->rotation += angleDelta; emit rotationChanged(); - emit wheel(event); + emit wheel(*event); if (!d->propertyName.isEmpty() && target()) { QQuickItem *t = target(); // writing target()'s property is done via QMetaProperty::write() so that any registered interceptors can react. if (d->propertyName == QLatin1String("scale")) { qreal multiplier = qPow(d->targetScaleMultiplier, angleDelta * d->rotationScale / 15); // wheel "clicks" - const QPointF centroidParentPos = t->parentItem()->mapFromScene(point->scenePosition()); + const QPointF centroidParentPos = t->parentItem()->mapFromScene(point.scenePosition()); const QPointF positionWas = t->position(); const qreal scaleWas = t->scale(); const qreal activePropertyValue = scaleWas * multiplier; qCDebug(lcWheelHandler) << objectName() << "angle delta" << event->angleDelta() << "pixel delta" << event->pixelDelta() - << "@" << point->position() << "in parent" << centroidParentPos - << "in scene" << point->scenePosition() + << "@" << point.position() << "in parent" << centroidParentPos + << "in scene" << point.scenePosition() << "multiplier" << multiplier << "scale" << scaleWas << "->" << activePropertyValue; d->targetMetaProperty().write(t, activePropertyValue); @@ -429,10 +431,10 @@ void QQuickWheelHandler::handleEventPoint(QQuickEventPoint *point) const QPointF positionWas = t->position(); const qreal rotationWas = t->rotation(); const qreal activePropertyValue = rotationWas + angleDelta * d->rotationScale; - const QPointF centroidParentPos = t->parentItem()->mapFromScene(point->scenePosition()); + const QPointF centroidParentPos = t->parentItem()->mapFromScene(point.scenePosition()); qCDebug(lcWheelHandler) << objectName() << "angle delta" << event->angleDelta() << "pixel delta" << event->pixelDelta() - << "@" << point->position() << "in parent" << centroidParentPos - << "in scene" << point->scenePosition() << "rotation" << t->rotation() + << "@" << point.position() << "in parent" << centroidParentPos + << "in scene" << point.scenePosition() << "rotation" << t->rotation() << "->" << activePropertyValue; d->targetMetaProperty().write(t, activePropertyValue); if (d->targetTransformAroundCursor) { @@ -444,8 +446,9 @@ void QQuickWheelHandler::handleEventPoint(QQuickEventPoint *point) t->setPosition(adjPos); } } else { - qCDebug(lcWheelHandler) << objectName() << "angle delta" << event->angleDelta() << "scaled" << angleDelta << "total" << d->rotation << "pixel delta" << event->pixelDelta() - << "@" << point->position() << "in scene" << point->scenePosition() << "rotation" << t->rotation(); + qCDebug(lcWheelHandler) << objectName() << "angle delta" << event->angleDelta() << "scaled" << angleDelta + << "total" << d->rotation << "pixel delta" << event->pixelDelta() + << "@" << point.position() << "in scene" << point.scenePosition() << "rotation" << t->rotation(); qreal delta = 0; if (event->hasPixelDelta()) { delta = inversion * d->rotationScale * qreal(orientation() == Qt::Horizontal ? event->pixelDelta().x() : event->pixelDelta().y()); diff --git a/src/quick/handlers/qquickwheelhandler_p.h b/src/quick/handlers/qquickwheelhandler_p.h index 021cd23679..b1688a3c2a 100644 --- a/src/quick/handlers/qquickwheelhandler_p.h +++ b/src/quick/handlers/qquickwheelhandler_p.h @@ -103,7 +103,7 @@ public: void setTargetTransformAroundCursor(bool ttac); Q_SIGNALS: - void wheel(QQuickPointerScrollEvent *event); + void wheel(QWheelEvent event); void orientationChanged(); void invertibleChanged(); @@ -115,8 +115,8 @@ Q_SIGNALS: void targetTransformAroundCursorChanged(); protected: - bool wantsPointerEvent(QQuickPointerEvent *event) override; - void handleEventPoint(QQuickEventPoint *point) override; + bool wantsPointerEvent(QPointerEvent *event) override; + void handleEventPoint(QPointerEvent *event, QEventPoint &point) override; void onTargetChanged(QQuickItem *oldTarget) override; void onActiveChanged() override; void timerEvent(QTimerEvent *event) override; diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 66e850f59c..ab7b407af5 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -51,7 +51,6 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcPointerEvents, "qt.quick.pointer.events") -Q_LOGGING_CATEGORY(lcPtrGrab, "qt.quick.pointer.grab") /*! \qmltype KeyEvent @@ -470,1639 +469,4 @@ Item { \l inverted always returns false. */ -/*! - \qmltype PointerDevice - \instantiates QPointingDevice - \inqmlmodule QtQuick - \ingroup qtquick-input-events - - \brief Provides information about a pointing device. - - A pointing device can be a mouse, a touchscreen, or a stylus on a graphics - tablet. - - \sa PointerEvent, PointerHandler -*/ - -/*! - \readonly - \qmlproperty enumeration QtQuick::PointerDevice::type - - This property holds the type of the pointing device. - - Valid values are: - - \value DeviceType.Unknown - the device cannot be identified - \value DeviceType.Mouse - a mouse - \value DeviceType.TouchScreen - a touchscreen providing absolute coordinates - \value DeviceType.TouchPad - a trackpad or touchpad providing relative coordinates - \value DeviceType.Stylus - a pen-like device - \value DeviceType.Airbrush - a stylus with a thumbwheel to adjust - \l {QTabletEvent::tangentialPressure}{tangentialPressure} - \value DeviceType.Puck - a device that is similar to a flat mouse with a - transparent circle with cross-hairs - (same as \l {QTabletEvent::Puck} {Puck}) - \value DeviceType.AllDevices - any of the above; used as a default value for construction - - \sa QPointingDevice::DeviceType -*/ - -/*! - \readonly - \qmlproperty enumeration QtQuick::PointerDevice::pointerType - - This property holds a value indicating what is interacting with - the device. Think of the device as having a planar 2D surface, and - the value of this property as identifying what interacts with the - device. - - There is some redundancy between this property and \l {PointerDevice::type}. - If a tocuchscreen is used, then the device is TouchScreen and - pointerType is Finger (always). - - Valid values are: - - \value PointerDevice.Generic - a mouse or something acting like a mouse (the core pointer on X11) - \value PointerDevice.Finger - the user's finger - \value PointerDevice.Pen - the drawing end of a stylus - \value PointerDevice.Eraser - the other end of the stylus (if it has a virtual eraser on the other end) - \value PointerDevice.Cursor - a cursor in the pre-computer sense of the word - \value PointerDevice.AllPointerTypes - any of the above (used as a default value in constructors) -*/ - -/*! - \readonly - \qmlproperty enumeration QtQuick::PointerDevice::capabilities - - This property holds a bitwise combination of the capabilities of the - pointing device. It tells you under which conditions events are sent, - and which properties of PointerEvent are expected to be valid. - - Valid values are: - - \value Capability.Position - the \l {QtQuick::EventPoint::position}{position} and - \l {QtQuick::EventPoint::scenePosition}{scenePosition} properties - \value Capability.Area - the \l {QtQuick::EventTouchPoint::ellipseDiameters}{ellipseDiameters} property - \value Capability.Pressure - the \l {QtQuick::EventTouchPoint::pressure}{pressure} property - \value Capability.Velocity - the \l {QtQuick::EventPoint::velocity}{velocity} property - \value Capability.Scroll - a \l {QtQuick::PointerDevice::type}{Mouse} has a wheel, or the - operating system recognizes scroll gestures on a - \l {QtQuick::PointerDevice::type}{TouchPad} - \value Capability.Hover - events are sent even when no button is pressed, or the finger or stylus - is not in contact with the surface - \value Capability.Rotation - the \l {QtQuick::EventTouchPoint::rotation}{rotation} property - \value Capability.XTilt - horizontal angle between a stylus and the axis perpendicular to the surface - \value Capability.YTilt - vertical angle between a stylus and the axis perpendicular to the surface - - \sa QPointingDevice::capabilities -*/ - - -// debugging helpers -static const char *pointStateString(const QQuickEventPoint *point) -{ - static const QMetaEnum stateMetaEnum = point->metaObject()->enumerator(point->metaObject()->indexOfEnumerator("State")); - return stateMetaEnum.valueToKey(point->state()); -} - -static const QString pointDeviceName(const QQuickEventPoint *point) -{ - auto device = static_cast<const QQuickPointerEvent *>(point->parent())->device(); - QString deviceName = (device ? device->name() : QLatin1String("null device")); - deviceName.resize(16, u' '); // shorten, and align in case of sequential output - return deviceName; -} - -/*! - \qmltype EventPoint - \qmlabstract - \instantiates QQuickEventPoint - \inqmlmodule QtQuick - \ingroup qtquick-input-events - \brief Provides information about an individual point within a PointerEvent. - - A PointerEvent contains an EventPoint for each point of contact: one corresponding - to the mouse cursor, or one for each finger touching a touchscreen. - - \sa PointerEvent, PointerHandler -*/ - -/*! - \readonly - \qmlproperty point QtQuick::EventPoint::position - - This property holds the coordinates of the position supplied by the event, - relative to the upper-left corner of the Item which has the PointerHandler. - If a contact patch is available from the pointing device, this point - represents its centroid. -*/ - -/*! - \readonly - \qmlproperty point QtQuick::EventPoint::scenePosition - - This property holds the coordinates of the position supplied by the event, - relative to the scene. If a contact patch is available from the - \l {QtQuick::PointerEvent::device} {device}, this point represents its centroid. -*/ - -/*! - \readonly - \qmlproperty point QtQuick::EventPoint::scenePressPosition - - This property holds the scene-relative position at which the press event - (on a touch device) or most recent change in QQuickPointerEvent::buttons() - (on a mouse or tablet stylus) occurred. -*/ - -/*! - \readonly - \qmlproperty point QtQuick::EventPoint::sceneGrabPosition - - This property holds the scene-relative position at which the EventPoint was - located when setGrabber() was called most recently. -*/ - -/*! - \readonly - \qmlproperty vector2d QtQuick::EventPoint::velocity - - This property holds average recent velocity: how fast and in which - direction the event point has been moving recently. -*/ - -/*! - \readonly - \qmlproperty int QtQuick::EventPoint::state - - This property tells what the user is currently doing at this point. - - It can be one of: - \value Pressed - The user's finger is now pressing a touchscreen, button or stylus - which was not pressed already - \value Updated - The touchpoint or position is being moved, with no change in pressed state - \value Stationary - The touchpoint or position is not being moved, and there is also - no change in pressed state - \value Released - The user's finger has now released a touch point, button or stylus - which was pressed -*/ - -/*! - \readonly - \qmlproperty int QtQuick::EventPoint::pointId - - This property holds the ID of the event, if any. - - Touchpoints have automatically-incrementing IDs: each time the user - presses a finger against the touchscreen, it will be a larger number. - In other cases, it will be -1. - - \sa {QtQuick::EventTouchPoint::uniqueId}{uniqueId} -*/ - -/*! - \readonly - \qmlproperty bool QtQuick::EventPoint::accepted - - Setting \a accepted to true prevents the event from being propagated to - Items below the PointerHandler's Item. - - Generally, if the handler acts on the mouse event, then it should be - accepted so that items lower in the stacking order do not also respond to - the same event. -*/ - -/*! - \readonly - \qmlproperty real QtQuick::EventPoint::timeHeld - - This property holds the amount of time in seconds that the button or touchpoint has - been held. It can be used to detect a "long press", and can drive an - animation to show progress toward activation of the "long press" action. -*/ - -void QQuickEventPoint::reset(QEventPoint::State state, const QPointF &scenePos, int pointId, ulong timestamp, const QVector2D &velocity) -{ - m_scenePos = scenePos; - m_pointId = pointId; - m_accept = false; - m_state = static_cast<QQuickEventPoint::State>(state); - m_timestamp = timestamp; - if (state == QEventPoint::State::Pressed) { - m_pressTimestamp = timestamp; - m_scenePressPos = scenePos; - } - m_velocity = (Q_LIKELY(velocity.isNull()) ? estimatedVelocity() : velocity); -} - -void QQuickEventPoint::localizePosition(QQuickItem *target) -{ - if (target) - m_pos = target->mapFromScene(scenePosition()); - else - m_pos = QPointF(); -} - -/*! - If this point has an exclusive grabber, returns a pointer to it; else - returns null, if there is no grabber. The grabber could be either - an Item or a PointerHandler. -*/ -QObject *QQuickEventPoint::exclusiveGrabber() const -{ - return m_exclusiveGrabber.data(); -} - -/*! - Set the given Item or PointerHandler as the exclusive grabber of this point. - If there was already an exclusive grab, it will be canceled. If there - were passive grabbers, they will continue to lurk, but the exclusive grab - is a behavioral override of the passive grab as long as it remains. - If you already know whether the grabber is to be an Item or a PointerHandler, - you should instead call setGrabberItem() or setGrabberPointerHandler(), - because it is slightly more efficient. -*/ -void QQuickEventPoint::setExclusiveGrabber(QObject *grabber) -{ - if (QQuickPointerHandler *phGrabber = qmlobject_cast<QQuickPointerHandler *>(grabber)) - setGrabberPointerHandler(phGrabber, true); - else - setGrabberItem(static_cast<QQuickItem *>(grabber)); -} - -/*! - If the exclusive grabber of this point is an Item, returns a - pointer to that Item; else returns null, if there is no grabber or if - the grabber is a PointerHandler. -*/ -QQuickItem *QQuickEventPoint::grabberItem() const -{ - return (m_grabberIsHandler ? nullptr : static_cast<QQuickItem *>(m_exclusiveGrabber.data())); -} - -/*! - Set the given Item \a grabber as the exclusive grabber of this point. - If there was already an exclusive grab, it will be canceled. If there - were passive grabbers, they will continue to lurk, but the exclusive grab - is a behavioral override of the passive grab as long as it remains. -*/ -void QQuickEventPoint::setGrabberItem(QQuickItem *grabber) -{ - if (grabber != m_exclusiveGrabber.data()) { - QQuickPointerHandler *oldGrabberHandler = grabberPointerHandler(); - if (oldGrabberHandler && !oldGrabberHandler->approveGrabTransition(this, grabber)) - return; - if (Q_UNLIKELY(lcPtrGrab().isDebugEnabled())) { - qCDebug(lcPtrGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this) << "@" << m_scenePos - << ": grab" << m_exclusiveGrabber << "->" << grabber; - } - QQuickItem *oldGrabberItem = grabberItem(); - m_exclusiveGrabber = QPointer<QObject>(grabber); - m_grabberIsHandler = false; - m_sceneGrabPos = m_scenePos; - if (oldGrabberHandler) { - oldGrabberHandler->onGrabChanged(oldGrabberHandler, (grabber ? CancelGrabExclusive : UngrabExclusive), this); - } else if (oldGrabberItem && oldGrabberItem != grabber && grabber && grabber->window()) { - QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(grabber->window()); - windowPriv->sendUngrabEvent(oldGrabberItem, windowPriv->isDeliveringTouchAsMouse()); - } - if (grabber) { - for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers) - if (passiveGrabber) - passiveGrabber->onGrabChanged(passiveGrabber, OverrideGrabPassive, this); - } - } -} - -/*! - If the exclusive grabber of this point is a PointerHandler, returns a - pointer to that handler; else returns null, if there is no grabber or if - the grabber is an Item. -*/ -QQuickPointerHandler *QQuickEventPoint::grabberPointerHandler() const -{ - return (m_grabberIsHandler ? static_cast<QQuickPointerHandler *>(m_exclusiveGrabber.data()) : nullptr); -} - -/*! - Set the given PointerHandler \a grabber as grabber of this point. If \a - exclusive is true, it will override any other grabs; if false, \a grabber - will be added to the list of passive grabbers of this point. -*/ -void QQuickEventPoint::setGrabberPointerHandler(QQuickPointerHandler *grabber, bool exclusive) -{ - if (Q_UNLIKELY(lcPtrGrab().isDebugEnabled())) { - if (exclusive) { - if (m_exclusiveGrabber != grabber) - qCDebug(lcPtrGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this) - << ": grab (exclusive)" << m_exclusiveGrabber << "->" << grabber; - } else { - qCDebug(lcPtrGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this) - << ": grab (passive)" << grabber; - } - } - if (exclusive) { - if (grabber != m_exclusiveGrabber.data()) { - QQuickPointerHandler *oldGrabberHandler = grabberPointerHandler(); - QQuickItem *oldGrabberItem = grabberItem(); - m_exclusiveGrabber = QPointer<QObject>(grabber); - m_grabberIsHandler = true; - m_sceneGrabPos = m_scenePos; - if (grabber) { - grabber->onGrabChanged(grabber, GrabExclusive, this); - for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers) { - if (!passiveGrabber.isNull() && passiveGrabber != grabber) - passiveGrabber->onGrabChanged(grabber, OverrideGrabPassive, this); - } - } - if (oldGrabberHandler) { - oldGrabberHandler->onGrabChanged(oldGrabberHandler, (grabber ? CancelGrabExclusive : UngrabExclusive), this); - } else if (oldGrabberItem) { - if (pointerEvent()->asPointerTouchEvent()) - oldGrabberItem->touchUngrabEvent(); - else if (pointerEvent()->asPointerMouseEvent()) - oldGrabberItem->mouseUngrabEvent(); - } - // touchUngrabEvent() can result in the grabber being set to null (MPTA does that, for example). - // So set it again to ensure that final state is what we want. - m_exclusiveGrabber = QPointer<QObject>(grabber); - m_grabberIsHandler = true; - m_sceneGrabPos = m_scenePos; - } - } else { - if (!grabber) { - qDebug() << "can't set passive grabber to null"; - return; - } - auto ptr = QPointer<QQuickPointerHandler>(grabber); - if (!m_passiveGrabbers.contains(ptr)) { - m_passiveGrabbers.append(ptr); - grabber->onGrabChanged(grabber, GrabPassive, this); - } - } -} - -/*! - If this point has an existing exclusive grabber (Item or PointerHandler), - inform the grabber that its grab is canceled, and remove it as grabber. - This normally happens when the grab is stolen by another Item. -*/ -void QQuickEventPoint::cancelExclusiveGrab() -{ - if (m_exclusiveGrabber.isNull()) - qWarning("cancelGrab: no grabber"); - else - cancelExclusiveGrabImpl(); -} - -void QQuickEventPoint::cancelExclusiveGrabImpl(QTouchEvent *cancelEvent) -{ - if (m_exclusiveGrabber.isNull()) - return; - if (Q_UNLIKELY(lcPtrGrab().isDebugEnabled())) { - qCDebug(lcPtrGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this) - << ": grab (exclusive)" << m_exclusiveGrabber << "-> nullptr"; - } - if (auto handler = grabberPointerHandler()) { - handler->onGrabChanged(handler, CancelGrabExclusive, this); - } else if (auto item = grabberItem()) { - if (cancelEvent) - QCoreApplication::sendEvent(item, cancelEvent); - else - item->touchUngrabEvent(); - } - m_exclusiveGrabber.clear(); -} - -/*! - If this point has the given \a handler as a passive grabber, - inform the grabber that its grab is canceled, and remove it as grabber. - This normally happens when another Item or PointerHandler does an exclusive grab. -*/ -void QQuickEventPoint::cancelPassiveGrab(QQuickPointerHandler *handler) -{ - if (removePassiveGrabber(handler)) { - if (Q_UNLIKELY(lcPtrGrab().isDebugEnabled())) { - qCDebug(lcPtrGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this) - << ": grab (passive)" << handler << "removed"; - } - handler->onGrabChanged(handler, CancelGrabPassive, this); - } -} - -/*! - If this point has the given \a handler as a passive grabber, remove it as grabber. - Returns true if it was removed, false if it wasn't a grabber. -*/ -bool QQuickEventPoint::removePassiveGrabber(QQuickPointerHandler *handler) -{ - return m_passiveGrabbers.removeOne(handler); -} - -/*! - If the given \a handler is grabbing this point passively, exclusively - or both, cancel the grab and remove it as grabber. - This normally happens when the handler decides that the behavior of this - point can no longer satisfy the handler's behavioral constraints within - the remainder of the gesture which the user is performing: for example - the handler tries to detect a tap but a drag is occurring instead, or - it tries to detect a drag in one direction but the drag is going in - another direction. In such cases the handler no longer needs or wants - to be informed of any further movements of this point. -*/ -void QQuickEventPoint::cancelAllGrabs(QQuickPointerHandler *handler) -{ - if (m_exclusiveGrabber == handler) { - handler->onGrabChanged(handler, CancelGrabExclusive, this); - m_exclusiveGrabber.clear(); - } - cancelPassiveGrab(handler); -} - -/*! - Sets this point as \a accepted (true) or rejected (false). - - During delivery of the current event to the Items in the scene, each Item - or Pointer Handler should accept the points for which it is taking - responsibility. As soon as all points within the event are accepted, event - propagation stops. However accepting the point does not imply any kind of - grab, passive or exclusive. - - \sa setExclusiveGrabber, QQuickPointerHandler::setPassiveGrab, QQuickPointerHandler::setExclusiveGrab -*/ -void QQuickEventPoint::setAccepted(bool accepted) -{ - if (m_accept != accepted) { - qCDebug(lcPointerEvents) << this << m_accept << "->" << accepted; - m_accept = accepted; - } -} - - -/*! - \qmltype EventTouchPoint - \qmlabstract - \instantiates QQuickEventTouchPoint - \inqmlmodule QtQuick - \ingroup qtquick-input-events - \brief Provides information about an individual touch point within a PointerEvent. - - \sa PointerEvent, PointerHandler -*/ - -/*! - \readonly - \qmlproperty QPointerUniqueId QtQuick::EventTouchPoint::uniqueId - - This property holds the unique ID of the fiducial or stylus in use, if any. - - On touchscreens that can track physical objects (such as knobs or game - pieces) in addition to fingers, each object usually has a unique ID. - Likewise, each stylus that can be used with a graphics tablet usually has a - unique serial number. Qt so far only supports numeric IDs. You can get the - actual number as uniqueId.numeric, but that is a device-specific detail. - In the future, there may be support for non-numeric IDs, so you should - not assume that the number is meaningful. - - If you need to identify specific objects, your application should provide - UI for registering objects and mapping them to functionality: allow the - user to select a meaning, virtual tool, or action, prompt the user to bring - the object into proximity, and store a mapping from uniqueId to its - purpose, for example in \l Settings. -*/ - -/*! - \readonly - \qmlproperty qreal QtQuick::EventTouchPoint::rotation - - This property holds the rotation angle of the stylus on a graphics tablet - or the contact patch of a touchpoint on a touchscreen. - - It is valid only with certain tablet stylus devices and touchscreens that - can measure the rotation angle. Otherwise, it will be zero. -*/ - -/*! - \readonly - \qmlproperty qreal QtQuick::EventTouchPoint::pressure - - This property tells how hard the user is pressing the stylus on a graphics - tablet or the finger against a touchscreen, in the range from \c 0 (no - measurable pressure) to \c 1.0 (maximum pressure which the device can - measure). - - It is valid only with certain tablets and touchscreens that can measure - pressure. Otherwise, it will be \c 1.0 when pressed. -*/ - -/*! - \readonly - \qmlproperty size QtQuick::EventTouchPoint::ellipseDiameters - - This property holds the diameters of the contact patch, if the event - comes from a touchpoint and the \l {QtQuick::PointerEvent::device} {device} - provides this information. - - A touchpoint is modeled as an elliptical area where the finger is - pressed against the touchscreen. (In fact, it could also be - modeled as a bitmap; but in that case we expect an elliptical - bounding estimate to be fitted to the contact patch before the - event is sent.) The harder the user presses, the larger the - contact patch; so, these diameters provide an alternate way of - detecting pressure, in case the device does not include a separate - pressure sensor. The ellipse is centered on - \l {QtQuick::EventPoint::scenePosition} {scenePosition} - (\l {QtQuick::EventPoint::position} {position} in the PointerHandler's - Item's local coordinates). The \l rotation property provides the - rotation of the ellipse, if known. It is expected that if the - \l rotation is zero, the verticalDiameter of the ellipse is the - larger one (the major axis), because of the usual hand position, - reaching upward or outward across the surface. - - If the contact patch is unknown, or the \l {QtQuick::PointerEvent::device} {device} - is not a touchscreen, these values will be zero. -*/ - -QQuickEventTouchPoint::QQuickEventTouchPoint(QQuickPointerTouchEvent *parent) - : QQuickEventPoint(parent), m_rotation(0), m_pressure(0) -{} - -void QQuickEventTouchPoint::reset(const QEventPoint &tp, ulong timestamp) -{ - QQuickEventPoint::reset(tp.state(), tp.scenePosition(), tp.id(), timestamp, tp.velocity()); - m_exclusiveGrabber.clear(); - m_passiveGrabbers.clear(); - m_rotation = tp.rotation(); - m_pressure = tp.pressure(); - m_ellipseDiameters = tp.ellipseDiameters(); - m_uniqueId = tp.uniqueId(); -} - -struct PointVelocityData { - QVector2D velocity; - QPointF pos; - ulong timestamp = 0; -}; - -typedef QMap<quint64, PointVelocityData> PointDataForPointIdMap; -Q_GLOBAL_STATIC(PointDataForPointIdMap, g_previousPointData) -static const int PointVelocityAgeLimit = 500; // milliseconds - -/*! - \internal - Estimates the velocity based on a weighted average of all previous velocities. - The older the velocity is, the less significant it becomes for the estimate. -*/ -QVector2D QQuickEventPoint::estimatedVelocity() const -{ - auto prevPointIt = g_previousPointData->find(m_pointId); - auto end = g_previousPointData->end(); - if (prevPointIt == end) { - // cleanup events older than PointVelocityAgeLimit - for (auto it = g_previousPointData->begin(); it != end; ) { - if (m_timestamp - it->timestamp > PointVelocityAgeLimit) - it = g_previousPointData->erase(it); - else - ++it; - } - prevPointIt = g_previousPointData->insert(m_pointId, PointVelocityData()); - } - - auto &prevPoint = prevPointIt.value(); - const ulong timeElapsed = m_timestamp - prevPoint.timestamp; - if (timeElapsed == 0) // in case we call estimatedVelocity() twice on the same QQuickEventPoint - return m_velocity; - - QVector2D newVelocity; - if (prevPoint.timestamp != 0) - newVelocity = QVector2D(m_scenePos - prevPoint.pos) / timeElapsed; - - // VERY simple kalman filter: does a weighted average - // where the older velocities get less and less significant - static const float KalmanGain = 0.7f; - QVector2D filteredVelocity = newVelocity * KalmanGain + m_velocity * (1.0f - KalmanGain); - - prevPoint.velocity = filteredVelocity; - prevPoint.pos = m_scenePos; - prevPoint.timestamp = m_timestamp; - return filteredVelocity; -} - -/*! - \qmltype PointerEvent - \instantiates QQuickPointerEvent - \inqmlmodule QtQuick - \ingroup qtquick-input-events - - \brief Provides information about an event from a pointing device. - - A PointerEvent is an event describing contact or movement across a surface, - provided by a mouse, a touchpoint (single finger on a touchscreen), or a - stylus on a graphics tablet. The \l {QtQuick::PointerEvent::device} {device} - property provides more information about where the event came from. - - \sa PointerHandler - - \image touchpoint-metrics.png -*/ - -/*! - \internal - \class QQuickPointerEvent - - QQuickPointerEvent is used as a long-lived object to store data related to - an event from a pointing device, such as a mouse, touch or tablet event, - during event delivery. It also provides properties which may be used later - to expose the event to QML, the same as is done with QQuickMouseEvent, - QQuickTouchPoint, QQuickKeyEvent, etc. Since only one event can be - delivered at a time, this class is effectively a singleton. We don't worry - about the QObject overhead because the instances are long-lived: we don't - dynamically create and destroy objects of this type for each event. -*/ - -/*! - \readonly - \qmlproperty enumeration QtQuick::PointerEvent::button - - This property holds the \l {Qt::MouseButton}{button} that caused the event, - if any. If the \l {QtQuick::PointerEvent::device} {device} does not have - buttons, or the event is a hover event, it will be \c Qt.NoButton. -*/ - -/*! - \readonly - \qmlproperty int QtQuick::PointerEvent::buttons - - This property holds the combination of mouse or stylus - \l {Qt::MouseButton}{buttons} pressed when the event was generated. For move - events, this is all buttons that are pressed down. For press events, this - includes the button that caused the event, as well as any others that were - already held. For release events, this excludes the button that caused the - event. -*/ - -/*! - \readonly - \qmlproperty int QtQuick::PointerEvent::modifiers - - This property holds the \l {Qt::KeyboardModifier}{keyboard modifier} flags - that existed immediately before the event occurred. - - It contains a bitwise combination of the following flags: - \value Qt.NoModifier - No modifier key is pressed. - \value Qt.ShiftModifier - A Shift key on the keyboard is pressed. - \value Qt.ControlModifier - A Ctrl key on the keyboard is pressed. - \value Qt.AltModifier - An Alt key on the keyboard is pressed. - \value Qt.MetaModifier - A Meta key on the keyboard is pressed. - \value Qt.KeypadModifier - A keypad button is pressed. - - For example, to react to a Shift key + Left mouse button click: - \qml - Item { - TapHandler { - onTapped: { - if ((event.button == Qt.LeftButton) && (event.modifiers & Qt.ShiftModifier)) - doSomething(); - } - } - } - \endqml -*/ - -/*! - \readonly - \qmlproperty PointerDevice QtQuick::PointerEvent::device - - This property holds the device that generated the event. -*/ - -QQuickPointerEvent::~QQuickPointerEvent() -{} - -QQuickPointerMouseEvent::QQuickPointerMouseEvent(QObject *parent, const QPointingDevice *device) - : QQuickSinglePointEvent(parent, device) -{ - m_point = new QQuickEventPoint(this); -} - -QQuickPointerEvent *QQuickPointerMouseEvent::reset(QEvent *event) -{ - auto ev = static_cast<QMouseEvent*>(event); - m_event = ev; - if (!event) - return this; - - QQuickPointerHandlerPrivate::deviceDeliveryTargets(ev->device()).clear(); - m_button = ev->button(); - m_pressedButtons = ev->buttons(); - QEventPoint::State state = QEventPoint::State::Stationary; - switch (ev->type()) { - case QEvent::MouseButtonPress: - m_point->clearPassiveGrabbers(); - Q_FALLTHROUGH(); - case QEvent::MouseButtonDblClick: - state = QEventPoint::State::Pressed; - break; - case QEvent::MouseButtonRelease: - state = QEventPoint::State::Released; - break; - case QEvent::MouseMove: - state = QEventPoint::State::Updated; - break; - default: - break; - } - m_point->reset(state, ev->scenePosition(), ev->point(0).id(), ev->timestamp()); - return this; -} - -void QQuickSinglePointEvent::localize(QQuickItem *target) -{ - m_point->localizePosition(target); -} - -QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event) -{ - auto ev = static_cast<QTouchEvent*>(event); - m_event = ev; - if (!event) - return this; - - QQuickPointerHandlerPrivate::deviceDeliveryTargets(ev->device()).clear(); - m_button = Qt::NoButton; - m_pressedButtons = Qt::NoButton; - - const QList<QEventPoint> &tps = ev->touchPoints(); - int newPointCount = tps.count(); - m_touchPoints.reserve(newPointCount); - - for (int i = m_touchPoints.size(); i < newPointCount; ++i) - m_touchPoints.insert(i, new QQuickEventTouchPoint(this)); - - // Make sure the grabbers and on-pressed values are right from one event to the next - struct ToPreserve { - int pointId; // just for double-checking - ulong pressTimestamp; - QPointF scenePressPos; - QPointF sceneGrabPos; - QObject * grabber; - QVector <QPointer <QQuickPointerHandler> > passiveGrabbers; - - ToPreserve() : pointId(0), pressTimestamp(0), grabber(nullptr) {} - }; - QVector<ToPreserve> preserves(newPointCount); // jar of pickled touchpoints, in order of points in the _new_ event - - // Copy stuff we need to preserve, because the order of points might have changed in the event. - // The ID is all that we can rely on (release might remove the first point etc). - for (int i = 0; i < newPointCount; ++i) { - int pid = tps.at(i).id(); - if (auto point = pointById(pid)) { - preserves[i].pointId = pid; - preserves[i].pressTimestamp = point->m_pressTimestamp; - preserves[i].scenePressPos = point->scenePressPosition(); - preserves[i].sceneGrabPos = point->sceneGrabPosition(); - preserves[i].grabber = point->exclusiveGrabber(); - preserves[i].passiveGrabbers = point->passiveGrabbers(); - } - } - - for (int i = 0; i < newPointCount; ++i) { - auto point = m_touchPoints.at(i); - point->reset(tps.at(i), ev->timestamp()); - const auto &preserved = preserves.at(i); - if (point->state() == QQuickEventPoint::Pressed) { - if (preserved.grabber) - qWarning() << "TouchPointPressed without previous release event" << point; - point->setGrabberItem(nullptr); - point->clearPassiveGrabbers(); - } else { - // Restore the grabbers without notifying (don't call onGrabChanged) - Q_ASSERT(preserved.pointId == 0 || preserved.pointId == point->pointId()); - point->m_pressTimestamp = preserved.pressTimestamp; - point->m_scenePressPos = preserved.scenePressPos; - point->m_sceneGrabPos = preserved.sceneGrabPos; - point->m_exclusiveGrabber = preserved.grabber; - point->m_grabberIsHandler = (qmlobject_cast<QQuickPointerHandler *>(point->m_exclusiveGrabber) != nullptr); - point->m_passiveGrabbers = preserved.passiveGrabbers; - } - } - m_pointCount = newPointCount; - return this; -} - -void QQuickPointerTouchEvent::localize(QQuickItem *target) -{ - for (auto point : qAsConst(m_touchPoints)) - point->localizePosition(target); -} - -#if QT_CONFIG(gestures) -QQuickPointerNativeGestureEvent::QQuickPointerNativeGestureEvent(QObject *parent, const QPointingDevice *device) - : QQuickSinglePointEvent(parent, device) -{ - m_point = new QQuickEventPoint(this); -} - -QQuickPointerEvent *QQuickPointerNativeGestureEvent::reset(QEvent *event) -{ - auto ev = static_cast<QNativeGestureEvent*>(event); - m_event = ev; - if (!event) - return this; - - QQuickPointerHandlerPrivate::deviceDeliveryTargets(ev->device()).clear(); - QEventPoint::State state = QEventPoint::State::Updated; - switch (type()) { - case Qt::BeginNativeGesture: - state = QEventPoint::State::Pressed; - break; - case Qt::EndNativeGesture: - state = QEventPoint::State::Released; - break; - default: - break; - } - m_point->reset(state, ev->scenePosition(), ev->point(0).id(), ev->timestamp()); - return this; -} -#endif // QT_CONFIG(gestures) - -QQuickEventPoint *QQuickSinglePointEvent::point(int i) const -{ - if (i == 0) - return m_point; - return nullptr; -} - - -/*! - \qmltype PointerScrollEvent - \instantiates QQuickPointerScrollEvent - \inqmlmodule QtQuick - \ingroup qtquick-input-events - \brief Provides information about a scrolling event, such as from a mouse wheel. - - \sa WheelHandler -*/ - -/*! - \internal - \class QQuickPointerScrollEvent -*/ - -/*! - \readonly - \qmlproperty PointerDevice QtQuick::PointerScrollEvent::device - - This property holds the device that generated the event. -*/ - -/*! - \qmlproperty int QtQuick::PointerScrollEvent::buttons - - This property holds the mouse buttons pressed when the wheel event was generated. - - It contains a bitwise combination of: - \list - \li \l {Qt::LeftButton} {Qt.LeftButton} - \li \l {Qt::RightButton} {Qt.RightButton} - \li \l {Qt::MiddleButton} {Qt.MiddleButton} - \endlist -*/ - -/*! - \readonly - \qmlproperty int QtQuick::PointerScrollEvent::modifiers - - This property holds the \l {Qt::KeyboardModifier}{keyboard modifier} keys - that were pressed immediately before the event occurred. - - It contains a bitwise combination of the following flags: - \value Qt.NoModifier - No modifier key is pressed. - \value Qt.ShiftModifier - A Shift key on the keyboard is pressed. - \value Qt.ControlModifier - A Ctrl key on the keyboard is pressed. - \value Qt.AltModifier - An Alt key on the keyboard is pressed. - \value Qt.MetaModifier - A Meta key on the keyboard is pressed. - \value Qt.KeypadModifier - A keypad button is pressed. - - For example, to react to a Shift key + Left mouse button click: - \qml - Item { - TapHandler { - onTapped: { - if ((event.button == Qt.LeftButton) && (event.modifiers & Qt.ShiftModifier)) - doSomething(); - } - } - } - \endqml -*/ - -/*! - \qmlproperty point QtQuick::PointerScrollEvent::angleDelta - - This property holds the distance that the wheel is rotated in wheel degrees. - The x and y cordinate of this property holds the delta in horizontal and - vertical orientation. - - A positive value indicates that the wheel was rotated up/right; - a negative value indicates that the wheel was rotated down/left. - - Most mouse types work in steps of 15 degrees, in which case the delta value is a - multiple of 120; i.e., 120 units * 1/8 = 15 degrees. -*/ - -/*! - \qmlproperty point QtQuick::PointerScrollEvent::pixelDelta - - This property holds the delta in screen pixels and is available in platforms that - have high-resolution trackpads, such as \macos. - The x and y coordinates of this property hold the delta in horizontal and - vertical orientation. The value should be used directly to scroll content on screen. - - For platforms without high-resolution touchpad support, pixelDelta will - always be (0,0), and angleDelta should be used instead. -*/ - -/*! - \qmlproperty bool QtQuick::PointerScrollEvent::hasAngleDelta - - Returns whether the \l angleDelta property has a non-null value. -*/ - -/*! - \qmlproperty bool QtQuick::PointerScrollEvent::hasPixelDelta - - Returns whether the \l pixelDelta property has a non-null value. -*/ - -/*! - \qmlproperty bool QtQuick::PointerScrollEvent::inverted - - Returns whether the delta values delivered with the event are inverted. - - Normally, a vertical wheel will produce a PointerScrollEvent with positive delta - values if the top of the wheel is rotating away from the hand operating it. - Similarly, a horizontal wheel movement will produce a PointerScrollEvent with - positive delta values if the top of the wheel is moved to the left. - - However, on some platforms this is configurable, so that the same - operations described above will produce negative delta values (but with the - same magnitude). In a QML component (such as a tumbler or a slider) where - it is appropriate to synchronize the movement or rotation of an item with - the direction of the wheel, regardless of the system settings, the wheel - event handler can use the inverted property to decide whether to negate the - \l angleDelta or \l pixelDelta values. - - \note Many platforms provide no such information. On such platforms, - \c inverted always returns false. -*/ -QQuickPointerScrollEvent::QQuickPointerScrollEvent(QObject *parent, const QPointingDevice *device) - : QQuickSinglePointEvent(parent, device) -{ - m_point = new QQuickEventPoint(this); -} - -QQuickPointerEvent *QQuickPointerScrollEvent::reset(QEvent *event) -{ - m_event = static_cast<QPointerEvent*>(event); - if (!event) - return this; -#if QT_CONFIG(wheelevent) - if (event->type() == QEvent::Wheel) { - auto ev = static_cast<QWheelEvent*>(event); - QQuickPointerHandlerPrivate::deviceDeliveryTargets(ev->device()).clear(); - // m_button = Qt::NoButton; - m_pressedButtons = ev->buttons(); - m_angleDelta = QVector2D(ev->angleDelta()); - m_pixelDelta = QVector2D(ev->pixelDelta()); - m_phase = ev->phase(); - m_synthSource = ev->source(); - m_inverted = ev->inverted(); - m_point->reset(QEventPoint::State::Updated, ev->position(), ev->point(0).id(), ev->timestamp()); - } -#endif - // TODO else if (event->type() == QEvent::Scroll) ... - return this; -} - -void QQuickPointerScrollEvent::localize(QQuickItem *target) -{ - m_point->localizePosition(target); -} - -QQuickEventPoint *QQuickPointerTouchEvent::point(int i) const -{ - if (i >= 0 && i < m_pointCount) - return m_touchPoints.at(i); - return nullptr; -} - -QQuickEventPoint::QQuickEventPoint(QQuickPointerEvent *parent) - : QObject(parent), m_pointId(0), m_exclusiveGrabber(nullptr), m_timestamp(0), m_pressTimestamp(0), - m_state(QQuickEventPoint::Released), m_accept(false), m_grabberIsHandler(false) -{ - Q_UNUSED(m_reserved); -} - -QQuickPointerEvent *QQuickEventPoint::pointerEvent() const -{ - return static_cast<QQuickPointerEvent *>(parent()); -} - -bool QQuickSinglePointEvent::allPointsAccepted() const -{ - return m_point->isAccepted(); -} - -bool QQuickSinglePointEvent::allUpdatedPointsAccepted() const -{ - return m_point->state() == QQuickEventPoint::Pressed || m_point->isAccepted(); -} - -bool QQuickSinglePointEvent::allPointsGrabbed() const -{ - return m_point->exclusiveGrabber() != nullptr; -} - -QMouseEvent *QQuickPointerMouseEvent::asMouseEvent(const QPointF &localPos) const -{ - if (!m_event) - return nullptr; - static_cast<QMutableSinglePointEvent *>(m_event)->mutablePoint().setPosition(localPos); - return static_cast<QMouseEvent *>(m_event); -} - -/*! - Returns the exclusive grabber of this event, if any, in a vector. -*/ -QVector<QObject *> QQuickSinglePointEvent::exclusiveGrabbers() const -{ - QVector<QObject *> result; - if (QObject *grabber = m_point->exclusiveGrabber()) - result << grabber; - return result; -} - -/*! - Remove all passive and exclusive grabbers of this event, without notifying. -*/ -void QQuickSinglePointEvent::clearGrabbers() const -{ - m_point->setGrabberItem(nullptr); - m_point->clearPassiveGrabbers(); -} - -/*! - Returns whether the given \a handler is the exclusive grabber of this event. -*/ -bool QQuickSinglePointEvent::hasExclusiveGrabber(const QQuickPointerHandler *handler) const -{ - return handler && (m_point->exclusiveGrabber() == handler); -} - -bool QQuickPointerMouseEvent::isPressEvent() const -{ - if (!m_event) - return false; - auto me = static_cast<QMouseEvent*>(m_event); - return ((me->type() == QEvent::MouseButtonPress || me->type() == QEvent::MouseButtonDblClick) && - (me->buttons() & me->button()) == me->buttons()); -} - -bool QQuickPointerMouseEvent::isDoubleClickEvent() const -{ - if (!m_event) - return false; - auto me = static_cast<QMouseEvent*>(m_event); - return (me->type() == QEvent::MouseButtonDblClick); -} - -bool QQuickPointerMouseEvent::isUpdateEvent() const -{ - if (!m_event) - return false; - auto me = static_cast<QMouseEvent*>(m_event); - return me->type() == QEvent::MouseMove; -} - -bool QQuickPointerMouseEvent::isReleaseEvent() const -{ - if (!m_event) - return false; - auto me = static_cast<QMouseEvent*>(m_event); - return me && me->type() == QEvent::MouseButtonRelease; -} - -bool QQuickPointerTouchEvent::allPointsAccepted() const -{ - for (int i = 0; i < m_pointCount; ++i) { - if (!m_touchPoints.at(i)->isAccepted()) - return false; - } - return true; -} - -bool QQuickPointerTouchEvent::allUpdatedPointsAccepted() const -{ - for (int i = 0; i < m_pointCount; ++i) { - auto point = m_touchPoints.at(i); - if (point->state() != QQuickEventPoint::Pressed && !point->isAccepted()) - return false; - } - return true; -} - -bool QQuickPointerTouchEvent::allPointsGrabbed() const -{ - for (int i = 0; i < m_pointCount; ++i) { - if (!m_touchPoints.at(i)->exclusiveGrabber()) - return false; - } - return true; -} - -/*! - Returns the exclusive grabbers of all points in this event, if any, in a vector. -*/ -QVector<QObject *> QQuickPointerTouchEvent::exclusiveGrabbers() const -{ - QVector<QObject *> result; - for (int i = 0; i < m_pointCount; ++i) { - if (QObject *grabber = m_touchPoints.at(i)->exclusiveGrabber()) { - if (!result.contains(grabber)) - result << grabber; - } - } - return result; -} - -/*! - Remove all passive and exclusive grabbers of all touchpoints in this event, - without notifying. -*/ -void QQuickPointerTouchEvent::clearGrabbers() const -{ - for (auto point: m_touchPoints) { - point->setGrabberItem(nullptr); - point->clearPassiveGrabbers(); - } -} - -QEventPoint::States QQuickPointerTouchEvent::touchPointStates() const -{ - return m_event - ? static_cast<QTouchEvent*>(m_event)->touchPointStates() - : QEventPoint::States(); -} - -/*! - Returns whether the given \a handler is the exclusive grabber of any - touchpoint within this event. -*/ -bool QQuickPointerTouchEvent::hasExclusiveGrabber(const QQuickPointerHandler *handler) const -{ - for (auto point: m_touchPoints) - if (point->exclusiveGrabber() == handler) - return true; - return false; -} - -bool QQuickPointerTouchEvent::isPressEvent() const -{ - return touchPointStates() & QEventPoint::State::Pressed; -} - -bool QQuickPointerTouchEvent::isUpdateEvent() const -{ - return touchPointStates() & (QEventPoint::State::Updated | QEventPoint::State::Stationary); -} - -bool QQuickPointerTouchEvent::isReleaseEvent() const -{ - return touchPointStates() & QEventPoint::State::Released; -} - -QVector<QPointF> QQuickPointerEvent::unacceptedPressedPointScenePositions() const -{ - QVector<QPointF> points; - for (int i = 0; i < pointCount(); ++i) { - if (!point(i)->isAccepted() && point(i)->state() == QQuickEventPoint::Pressed) - points << point(i)->scenePosition(); - } - return points; -} - -/*! - \internal - Populate the reusable synth-mouse event from one touchpoint. - It's required that isTouchEvent() be true when this is called. - If the touchpoint cannot be found, this returns nullptr. - Ownership of the event is NOT transferred to the caller. -*/ -QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const -{ - const QEventPoint *p = touchPointById(pointID); - if (!p) - return nullptr; - QEvent::Type type; - Qt::MouseButton buttons = Qt::LeftButton; - switch (p->state()) { - case QEventPoint::State::Pressed: - type = QEvent::MouseButtonPress; - break; - case QEventPoint::State::Updated: - case QEventPoint::State::Stationary: - type = QEvent::MouseMove; - break; - case QEventPoint::State::Released: - type = QEvent::MouseButtonRelease; - buttons = Qt::NoButton; - break; - default: - Q_ASSERT(false); - return nullptr; - } - m_synthMouseEvent = QMouseEvent(type, relativeTo->mapFromScene(p->scenePosition()), - p->scenePosition(), p->globalPosition(), Qt::LeftButton, buttons, m_event->modifiers(), - Qt::MouseEventSynthesizedByQt, device()); - m_synthMouseEvent.setAccepted(true); - m_synthMouseEvent.setTimestamp(m_event->timestamp()); - // ### Qt 6: try to always have valid velocity in every QEventPoint (either from the platform, or synthesized in QtGui). - // QQuickFlickablePrivate::handleMouseMoveEvent() checks for QInputDevice::Capability::Velocity - // and if it is set, then it does not need to do its own velocity calculations. - // But because m_synthMouseEvent gets the same device() where the (usually) touch event came from, - // the capability won't be set, in practice, until we have the velocity in place. - QMutableSinglePointEvent::from(m_synthMouseEvent).mutablePoint().setVelocity(p->velocity()); - return &m_synthMouseEvent; -} - -#if QT_CONFIG(tabletevent) -QQuickPointerTabletEvent::QQuickPointerTabletEvent(QObject *parent, const QPointingDevice *device) - : QQuickSinglePointEvent(parent, device) -{ - m_point = new QQuickEventTabletPoint(this); -} - -QQuickPointerEvent *QQuickPointerTabletEvent::reset(QEvent *event) -{ - auto ev = static_cast<QTabletEvent*>(event); - m_event = ev; - if (!event) - return this; - - QQuickPointerHandlerPrivate::deviceDeliveryTargets(ev->device()).clear(); - m_button = ev->button(); - m_pressedButtons = ev->buttons(); - static_cast<QQuickEventTabletPoint *>(m_point)->reset(ev); - return this; -} - -QQuickEventTabletPoint::QQuickEventTabletPoint(QQuickPointerTabletEvent *parent) - : QQuickEventPoint(parent) -{ -} - -void QQuickEventTabletPoint::reset(const QTabletEvent *ev) -{ - QEventPoint::State state = QEventPoint::State::Stationary; - switch (ev->type()) { - case QEvent::TabletPress: - state = QEventPoint::State::Pressed; - clearPassiveGrabbers(); - break; - case QEvent::TabletRelease: - state = QEventPoint::State::Released; - break; - case QEvent::TabletMove: - state = QEventPoint::State::Updated; - break; - default: - break; - } - QQuickEventPoint::reset(state, ev->position(), 1, ev->timestamp()); - m_rotation = ev->rotation(); - m_pressure = ev->pressure(); - m_tangentialPressure = ev->tangentialPressure(); - m_tilt = QVector2D(ev->xTilt(), ev->yTilt()); -} - -bool QQuickPointerTabletEvent::isPressEvent() const -{ - auto me = static_cast<QTabletEvent *>(m_event); - return me->type() == QEvent::TabletPress; -} - -bool QQuickPointerTabletEvent::isUpdateEvent() const -{ - auto me = static_cast<QTabletEvent *>(m_event); - return me->type() == QEvent::TabletMove; -} - -bool QQuickPointerTabletEvent::isReleaseEvent() const -{ - auto me = static_cast<QTabletEvent *>(m_event); - return me->type() == QEvent::TabletRelease; -} - -QTabletEvent *QQuickPointerTabletEvent::asTabletEvent() const -{ - return static_cast<QTabletEvent *>(m_event); -} -#endif // QT_CONFIG(tabletevent) - -#if QT_CONFIG(gestures) -bool QQuickPointerNativeGestureEvent::isPressEvent() const -{ - return type() == Qt::BeginNativeGesture; -} - -bool QQuickPointerNativeGestureEvent::isUpdateEvent() const -{ - switch (type()) { - case Qt::BeginNativeGesture: - case Qt::EndNativeGesture: - return false; - default: - return true; - } -} - -bool QQuickPointerNativeGestureEvent::isReleaseEvent() const -{ - return type() == Qt::EndNativeGesture; -} - -Qt::NativeGestureType QQuickPointerNativeGestureEvent::type() const -{ - return static_cast<QNativeGestureEvent *>(m_event)->gestureType(); -} - -qreal QQuickPointerNativeGestureEvent::value() const -{ - return static_cast<QNativeGestureEvent *>(m_event)->value(); -} -#endif // QT_CONFIG(gestures) - -/*! - Returns whether the scroll event has Qt::ScrollBegin phase. On touchpads - which provide phase information, this is true when the fingers are placed - on the touchpad and scrolling begins. On other devices where this - information is not available, it remains false. -*/ -bool QQuickPointerScrollEvent::isPressEvent() const -{ - return phase() == Qt::ScrollBegin; -} - -/*! - Returns true when the scroll event has Qt::ScrollUpdate phase, or when the - phase is unknown. Some multi-touch-capable touchpads and trackpads provide - phase information; whereas ordinary mouse wheels and other types of - trackpads do not, and in such cases this is always true. -*/ -bool QQuickPointerScrollEvent::isUpdateEvent() const -{ - return phase() == Qt::ScrollUpdate || phase() == Qt::NoScrollPhase; -} - -/*! - Returns whether the scroll event has Qt::ScrollBegin phase. On touchpads - which provide phase information, this is true when the fingers are lifted - from the touchpad. On other devices where this information is not - available, it remains false. -*/ -bool QQuickPointerScrollEvent::isReleaseEvent() const -{ - return phase() == Qt::ScrollEnd; -} - -/*! - \internal - Returns a pointer to the QQuickEventPoint which has the \a pointId as - \l {QQuickEventPoint::pointId}{pointId}. - Returns nullptr if there is no point with that ID. - - \fn QQuickPointerEvent::pointById(int pointId) const -*/ -QQuickEventPoint *QQuickSinglePointEvent::pointById(int pointId) const -{ - if (m_point && pointId == m_point->pointId()) - return m_point; - return nullptr; -} - -QQuickEventPoint *QQuickPointerTouchEvent::pointById(int pointId) const -{ - auto it = std::find_if(m_touchPoints.constBegin(), m_touchPoints.constEnd(), - [pointId](const QQuickEventTouchPoint *tp) { return tp->pointId() == pointId; } ); - if (it != m_touchPoints.constEnd()) - return *it; - return nullptr; -} - -/*! - \internal - Returns a pointer to the original TouchPoint which has the same - \l {QEventPoint::id}{id} as \a pointId, if the original event is a - QTouchEvent, and if that point is found. Otherwise, returns nullptr. -*/ -const QEventPoint *QQuickPointerTouchEvent::touchPointById(int pointId) const -{ - const QTouchEvent *ev = asTouchEvent(); - if (!ev) - return nullptr; - const QList<QEventPoint> &tps = ev->touchPoints(); - auto it = std::find_if(tps.constBegin(), tps.constEnd(), - [pointId](QEventPoint const& tp) { return tp.id() == pointId; } ); - // return the pointer to the actual TP in QTouchEvent::_touchPoints - return (it == tps.constEnd() ? nullptr : &*it); -} - -/*! - \internal - Make a new QTouchEvent, giving it a subset of the original touch points. - - Returns a nullptr if all points are stationary, or there are no points inside the item, - or none of the points were pressed inside and the item was not grabbing any of them - and isFiltering is false. When isFiltering is true, it is assumed that the item - cares about all points which are inside its bounds, because most filtering items - need to monitor eventpoint movements until a drag threshold is exceeded or the - requirements for a gesture to be recognized are met in some other way. -*/ -QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool isFiltering) const -{ - QList<QEventPoint> touchPoints; - QEventPoint::States eventStates; // TODO maybe avoid accumulating this, since the touchevent ctor doesn't need it - // TODO maybe add QQuickItem::mapVector2DFromScene(QVector2D) to avoid needing QQuickItemPrivate here - // Or else just document that velocity is always scene-relative and is not scaled and rotated with the item - // but that would require changing tst_qquickwindow::touchEvent_velocity(): it expects transformed velocity - - bool anyPressOrReleaseInside = false; - bool anyStationaryWithModifiedPropertyInside = false; - bool anyGrabber = false; - QMatrix4x4 transformMatrix(QQuickItemPrivate::get(item)->windowToItemTransform()); - for (int i = 0; i < m_pointCount; ++i) { - auto p = m_touchPoints.at(i); - if (p->isAccepted()) - continue; - // include points where item is the grabber - bool isGrabber = p->exclusiveGrabber() == item; - if (isGrabber) - anyGrabber = true; - // include points inside the bounds if no other item is the grabber or if the item is filtering - bool isInside = item->contains(item->mapFromScene(p->scenePosition())); - bool hasAnotherGrabber = p->exclusiveGrabber() && p->exclusiveGrabber() != item; - - // filtering: (childMouseEventFilter) include points that are grabbed by children of the target item - bool grabberIsChild = false; - auto parent = p->grabberItem(); - while (isFiltering && parent) { - if (parent == item) { - grabberIsChild = true; - break; - } - parent = parent->parentItem(); - } - - bool filterRelevant = isFiltering && grabberIsChild; - if (!(isGrabber || (isInside && (!hasAnotherGrabber || isFiltering)) || filterRelevant)) - continue; - if ((p->state() == QQuickEventPoint::Pressed || p->state() == QQuickEventPoint::Released) && isInside) - anyPressOrReleaseInside = true; - // we don't use QMutableEventPoint::from() because it's fine to have const here - const QMutableEventPoint *tp = static_cast<const QMutableEventPoint *>(touchPointById(p->pointId())); - if (tp) { - if (isInside && tp->stationaryWithModifiedProperty()) - anyStationaryWithModifiedPropertyInside = true; - eventStates |= tp->state(); - QMutableEventPoint tpCopy(*tp); - tpCopy.setPosition(item->mapFromScene(tp->scenePosition())); - tpCopy.setVelocity(transformMatrix.mapVector(tpCopy.velocity()).toVector2D()); - touchPoints << tpCopy; - } - } - - // Now touchPoints will have only points which are inside the item. - // But if none of them were just pressed inside, and the item has no other reason to care, ignore them anyway. - if ((eventStates == QEventPoint::State::Stationary && !anyStationaryWithModifiedPropertyInside) || - touchPoints.isEmpty() || (!anyPressOrReleaseInside && !anyGrabber && !isFiltering)) - return nullptr; - - // if all points have the same state, set the event type accordingly - const QTouchEvent &event = *asTouchEvent(); - QEvent::Type eventType = event.type(); - switch (eventStates) { - case QEventPoint::State::Pressed: - eventType = QEvent::TouchBegin; - break; - case QEventPoint::State::Released: - eventType = QEvent::TouchEnd; - break; - default: - eventType = QEvent::TouchUpdate; - break; - } - - QMutableTouchEvent *touchEvent = new QMutableTouchEvent(eventType, event.pointingDevice(), - event.modifiers(), touchPoints); - touchEvent->setTarget(item); - touchEvent->setTimestamp(event.timestamp()); - touchEvent->accept(); - return touchEvent; -} - -QTouchEvent *QQuickPointerTouchEvent::asTouchEvent() const -{ - return static_cast<QTouchEvent *>(m_event); -} - -#ifndef QT_NO_DEBUG_STREAM - -Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerEvent *event) -{ - QDebugStateSaver saver(dbg); - dbg.nospace(); - if (!event) { - dbg << "QQuickPointerEvent(0)"; - return dbg; - } - dbg << "QQuickPointerEvent("; - dbg << event->timestamp(); - if (event->device()) { - dbg << " dev:"; - QtDebugUtils::formatQEnum(dbg, event->device()->type()); - dbg << " " << event->device()->name(); - } else { - dbg << " dev: null"; - } - if (event->buttons() != Qt::NoButton) { - dbg << " buttons:"; - QtDebugUtils::formatQEnum(dbg, event->buttons()); - } - dbg << " ["; - int c = event->pointCount(); - for (int i = 0; i < c; ++i) - dbg << event->point(i) << ' '; - dbg << "])"; - return dbg; -} - -Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *event) -{ - QDebugStateSaver saver(dbg); - dbg.nospace(); - if (!event) { - dbg << "QQuickEventPoint(0)"; - return dbg; - } - dbg << "QQuickEventPoint(accepted:" << event->isAccepted() - << " state:"; - QtDebugUtils::formatQEnum(dbg, event->state()); - dbg << " scenePos:" << event->scenePosition() << " id:" << Qt::hex << event->pointId() << Qt::dec - << " timeHeld:" << event->timeHeld() << ')'; - return dbg; -} - -#endif - QT_END_NAMESPACE diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index b491445323..9b89d8300e 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -68,14 +68,8 @@ QT_BEGIN_NAMESPACE class QPointingDevice; -class QQuickPointerEvent; -class QQuickPointerMouseEvent; -#if QT_CONFIG(gestures) -class QQuickPointerNativeGestureEvent; -#endif -class QQuickPointerScrollEvent; -class QQuickPointerTabletEvent; -class QQuickPointerTouchEvent; +class QPointerEvent; +class QMouseEvent; class QQuickPointerHandler; class QQuickKeyEvent : public QObject @@ -267,441 +261,6 @@ private: bool _accepted = true; }; -class Q_QUICK_PRIVATE_EXPORT QQuickEventPoint : public QObject -{ - Q_OBJECT - Q_PROPERTY(QQuickPointerEvent *event READ pointerEvent CONSTANT) - Q_PROPERTY(QPointF position READ position CONSTANT) - Q_PROPERTY(QPointF scenePosition READ scenePosition CONSTANT) - Q_PROPERTY(QPointF scenePressPosition READ scenePressPosition CONSTANT) - Q_PROPERTY(QPointF sceneGrabPosition READ sceneGrabPosition CONSTANT) - Q_PROPERTY(State state READ state CONSTANT) - Q_PROPERTY(int pointId READ pointId CONSTANT) - Q_PROPERTY(qreal timeHeld READ timeHeld CONSTANT) - Q_PROPERTY(QVector2D velocity READ velocity CONSTANT) - Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted) - Q_PROPERTY(QObject *exclusiveGrabber READ exclusiveGrabber WRITE setExclusiveGrabber) - - QML_NAMED_ELEMENT(EventPoint) - QML_UNCREATABLE("EventPoint is only available as a member of PointerEvent.") - QML_ADDED_IN_VERSION(2, 12) - -public: - enum State { - Pressed = QEventPoint::State::Pressed, - Updated = QEventPoint::State::Updated, - Stationary = QEventPoint::State::Stationary, - Released = QEventPoint::State::Released - }; - Q_DECLARE_FLAGS(States, State) - Q_FLAG(States) - - enum GrabTransition { - GrabPassive = 0x01, - UngrabPassive = 0x02, - CancelGrabPassive = 0x03, - OverrideGrabPassive = 0x04, - GrabExclusive = 0x10, - UngrabExclusive = 0x20, - CancelGrabExclusive = 0x30, - }; - Q_ENUM(GrabTransition) - - QQuickEventPoint(QQuickPointerEvent *parent); - - void reset(QEventPoint::State state, const QPointF &scenePosition, int pointId, ulong timestamp, const QVector2D &velocity = QVector2D()); - void localizePosition(QQuickItem *target); - - QQuickPointerEvent *pointerEvent() const; - QPointF position() const { return m_pos; } - QPointF scenePosition() const { return m_scenePos; } - QPointF scenePressPosition() const { return m_scenePressPos; } - QPointF sceneGrabPosition() const { return m_sceneGrabPos; } - QVector2D velocity() const { return m_velocity; } - State state() const { return m_state; } - int pointId() const { return m_pointId; } - qreal timeHeld() const { return (m_timestamp - m_pressTimestamp) / 1000.0; } - bool isAccepted() const { return m_accept; } - void setAccepted(bool accepted = true); - QObject *exclusiveGrabber() const; - void setExclusiveGrabber(QObject *exclusiveGrabber); - - QQuickItem *grabberItem() const; - void setGrabberItem(QQuickItem *exclusiveGrabber); - - QQuickPointerHandler *grabberPointerHandler() const; - void setGrabberPointerHandler(QQuickPointerHandler *exclusiveGrabber, bool exclusive = false); - - void cancelExclusiveGrab(); - void cancelPassiveGrab(QQuickPointerHandler *handler); - bool removePassiveGrabber(QQuickPointerHandler *handler); - void cancelAllGrabs(QQuickPointerHandler *handler); - - QVector<QPointer <QQuickPointerHandler> > passiveGrabbers() const { return m_passiveGrabbers; } - void setPassiveGrabbers(const QVector<QPointer <QQuickPointerHandler> > &grabbers) { m_passiveGrabbers = grabbers; } - void clearPassiveGrabbers() { m_passiveGrabbers.clear(); } - -protected: - void cancelExclusiveGrabImpl(QTouchEvent *cancelEvent = nullptr); - -private: - QVector2D estimatedVelocity() const; - -protected: - QPointF m_pos; - QPointF m_scenePos; - QPointF m_scenePressPos; - QPointF m_sceneGrabPos; - QVector2D m_velocity; - int m_pointId; - QPointer<QObject> m_exclusiveGrabber; - QVector<QPointer <QQuickPointerHandler> > m_passiveGrabbers; - ulong m_timestamp; - ulong m_pressTimestamp; - State m_state; - bool m_accept : 1; - bool m_grabberIsHandler : 1; - int m_reserved : 29; - - friend class QQuickPointerTouchEvent; - friend class QQuickWindowPrivate; - - Q_DISABLE_COPY(QQuickEventPoint) -}; - -class Q_QUICK_PRIVATE_EXPORT QQuickEventTouchPoint : public QQuickEventPoint -{ - Q_OBJECT - Q_PROPERTY(qreal rotation READ rotation) - Q_PROPERTY(qreal pressure READ pressure) - Q_PROPERTY(QSizeF ellipseDiameters READ ellipseDiameters) - Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId) - - QML_NAMED_ELEMENT(EventTouchPoint) - QML_UNCREATABLE("EventTouchPoint is only available as a member of PointerEvent.") - QML_ADDED_IN_VERSION(2, 12) - -public: - QQuickEventTouchPoint(QQuickPointerTouchEvent *parent); - - void reset(const QEventPoint &tp, ulong timestamp); - - qreal rotation() const { return m_rotation; } - qreal pressure() const { return m_pressure; } - QSizeF ellipseDiameters() const { return m_ellipseDiameters; } - QPointingDeviceUniqueId uniqueId() const { return m_uniqueId; } - -private: - qreal m_rotation; - qreal m_pressure; - QSizeF m_ellipseDiameters; - QPointingDeviceUniqueId m_uniqueId; - - friend class QQuickPointerTouchEvent; - - Q_DISABLE_COPY(QQuickEventTouchPoint) -}; - -class Q_QUICK_PRIVATE_EXPORT QQuickPointerEvent : public QObject -{ - Q_OBJECT - Q_PROPERTY(QPointingDevice *device READ device CONSTANT) - Q_PROPERTY(Qt::KeyboardModifiers modifiers READ modifiers CONSTANT) - Q_PROPERTY(Qt::MouseButtons button READ button CONSTANT) - Q_PROPERTY(Qt::MouseButtons buttons READ buttons CONSTANT) - - QML_NAMED_ELEMENT(PointerEvent) - QML_UNCREATABLE("PointerEvent is only available as a parameter of several signals in PointerHandler") - QML_ADDED_IN_VERSION(2, 12) - -public: - QQuickPointerEvent(QObject *parent = nullptr, const QPointingDevice *device = nullptr) - : QObject(parent) - , m_device(device) - , m_pressedButtons(Qt::NoButton) - {} - - ~QQuickPointerEvent() override; - -public: // property accessors - // non-const only because of QML engine limitations (similar to QTBUG-61749) - QPointingDevice *device() const { return const_cast<QPointingDevice *>(m_device); } - Qt::KeyboardModifiers modifiers() const { return m_event ? m_event->modifiers() : Qt::NoModifier; } - Qt::MouseButton button() const { return m_button; } - Qt::MouseButtons buttons() const { return m_pressedButtons; } - -public: // helpers for C++ only (during event delivery) - virtual QQuickPointerEvent *reset(QEvent *ev) = 0; - virtual void localize(QQuickItem *target) = 0; - - virtual bool isPressEvent() const = 0; - virtual bool isDoubleClickEvent() const { return false; } - virtual bool isUpdateEvent() const = 0; - virtual bool isReleaseEvent() const = 0; - virtual QQuickPointerMouseEvent *asPointerMouseEvent() { return nullptr; } - virtual QQuickPointerTouchEvent *asPointerTouchEvent() { return nullptr; } - virtual QQuickPointerTabletEvent *asPointerTabletEvent() { return nullptr; } -#if QT_CONFIG(gestures) - virtual QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() { return nullptr; } -#endif - virtual QQuickPointerScrollEvent *asPointerScrollEvent() { return nullptr; } - virtual const QQuickPointerMouseEvent *asPointerMouseEvent() const { return nullptr; } - virtual const QQuickPointerTouchEvent *asPointerTouchEvent() const { return nullptr; } - virtual const QQuickPointerTabletEvent *asPointerTabletEvent() const { return nullptr; } -#if QT_CONFIG(gestures) - virtual const QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() const { return nullptr; } -#endif - virtual const QQuickPointerScrollEvent *asPointerScrollEvent() const { return nullptr; } - virtual bool allPointsAccepted() const = 0; - virtual bool allUpdatedPointsAccepted() const = 0; - virtual bool allPointsGrabbed() const = 0; - bool isAccepted() { return m_event ? m_event->isAccepted() : false; } - void setAccepted(bool accepted) { if (m_event) m_event->setAccepted(accepted); } - QVector<QPointF> unacceptedPressedPointScenePositions() const; - - virtual int pointCount() const = 0; - virtual QQuickEventPoint *point(int i) const = 0; - virtual QQuickEventPoint *pointById(int pointId) const = 0; - virtual QVector<QObject *> exclusiveGrabbers() const = 0; - virtual void clearGrabbers() const = 0; - virtual bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const = 0; - - ulong timestamp() const { return m_event ? m_event->timestamp() : 0; } - -protected: - const QPointingDevice *m_device = nullptr; - QPointerEvent *m_event = nullptr; // original event as received by QQuickWindow - Qt::MouseButton m_button = Qt::NoButton; - Qt::MouseButtons m_pressedButtons; - - friend class QQuickWindowPrivate; - - Q_DISABLE_COPY(QQuickPointerEvent) -}; - -class Q_QUICK_PRIVATE_EXPORT QQuickSinglePointEvent : public QQuickPointerEvent -{ - Q_OBJECT -public: - QQuickSinglePointEvent(QObject *parent, const QPointingDevice *device) - : QQuickPointerEvent(parent, device) { } - - void localize(QQuickItem *target) override; - int pointCount() const override { return 1; } - QQuickEventPoint *point(int i) const override; - QQuickEventPoint *pointById(int pointId) const override; - bool allPointsAccepted() const override; - bool allUpdatedPointsAccepted() const override; - bool allPointsGrabbed() const override; - QVector<QObject *> exclusiveGrabbers() const override; - void clearGrabbers() const override; - bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const override; - -protected: - QQuickEventPoint *m_point = nullptr; - - Q_DISABLE_COPY(QQuickSinglePointEvent) -}; - -class Q_QUICK_PRIVATE_EXPORT QQuickPointerMouseEvent : public QQuickSinglePointEvent -{ - Q_OBJECT - - QML_NAMED_ELEMENT(PointerMouseEvent) - QML_UNCREATABLE("PointerMouseEvent is only available as a parameter of several signals in PointerHandler") - QML_ADDED_IN_VERSION(2, 12) - -public: - QQuickPointerMouseEvent(QObject *parent, const QPointingDevice *device); - - QQuickPointerEvent *reset(QEvent *) override; - bool isPressEvent() const override; - bool isDoubleClickEvent() const override; - bool isUpdateEvent() const override; - bool isReleaseEvent() const override; - QQuickPointerMouseEvent *asPointerMouseEvent() override { return this; } - const QQuickPointerMouseEvent *asPointerMouseEvent() const override { return this; } - - QMouseEvent *asMouseEvent(const QPointF& localPos) const; - - Q_DISABLE_COPY(QQuickPointerMouseEvent) -}; - -class Q_QUICK_PRIVATE_EXPORT QQuickPointerTouchEvent : public QQuickPointerEvent -{ - Q_OBJECT - - QML_NAMED_ELEMENT(PointerTouchEvent) - QML_UNCREATABLE("PointerTouchEvent is only available as a parameter of several signals in PointerHandler") - QML_ADDED_IN_VERSION(2, 12) - -public: - QQuickPointerTouchEvent(QObject *parent = nullptr, const QPointingDevice *device = nullptr) - : QQuickPointerEvent(parent, device) - , m_synthMouseEvent(QEvent::MouseMove, QPointF(), Qt::NoButton, Qt::NoButton, Qt::NoModifier) - {} - - QQuickPointerEvent *reset(QEvent *) override; - void localize(QQuickItem *target) override; - bool isPressEvent() const override; - bool isUpdateEvent() const override; - bool isReleaseEvent() const override; - QQuickPointerTouchEvent *asPointerTouchEvent() override { return this; } - const QQuickPointerTouchEvent *asPointerTouchEvent() const override { return this; } - int pointCount() const override { return m_pointCount; } - QQuickEventPoint *point(int i) const override; - QQuickEventPoint *pointById(int pointId) const override; - const QEventPoint *touchPointById(int pointId) const; - bool allPointsAccepted() const override; - bool allUpdatedPointsAccepted() const override; - bool allPointsGrabbed() const override; - QVector<QObject *> exclusiveGrabbers() const override; - void clearGrabbers() const override; - bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const override; - - QMouseEvent *syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const; - QTouchEvent *touchEventForItem(QQuickItem *item, bool isFiltering = false) const; - - QTouchEvent *asTouchEvent() const; - -private: - QEventPoint::States touchPointStates() const; - - int m_pointCount = 0; - QVector<QQuickEventTouchPoint *> m_touchPoints; - mutable QMouseEvent m_synthMouseEvent; - - Q_DISABLE_COPY(QQuickPointerTouchEvent) -}; - -#if QT_CONFIG(tabletevent) -class Q_QUICK_PRIVATE_EXPORT QQuickEventTabletPoint : public QQuickEventPoint -{ - Q_OBJECT - Q_PROPERTY(qreal rotation READ rotation) - Q_PROPERTY(qreal pressure READ pressure) - Q_PROPERTY(qreal tangentialPressure READ tangentialPressure) - Q_PROPERTY(QVector2D tilt READ tilt) - - QML_NAMED_ELEMENT(EventTabletPoint) - QML_UNCREATABLE("EventTouchPoint is only available as a member of PointerEvent.") - QML_ADDED_IN_VERSION(2, 15) - -public: - QQuickEventTabletPoint(QQuickPointerTabletEvent *parent); - - void reset(const QTabletEvent *e); - - qreal rotation() const { return m_rotation; } - qreal pressure() const { return m_pressure; } - qreal tangentialPressure() const { return m_tangentialPressure; } - QVector2D tilt() const { return m_tilt; } - -private: - qreal m_rotation; - qreal m_pressure; - qreal m_tangentialPressure; - QVector2D m_tilt; - - friend class QQuickPointerTouchEvent; - - Q_DISABLE_COPY(QQuickEventTabletPoint) -}; - -class Q_QUICK_PRIVATE_EXPORT QQuickPointerTabletEvent : public QQuickSinglePointEvent -{ - Q_OBJECT -public: - QQuickPointerTabletEvent(QObject *parent, const QPointingDevice *device); - - QQuickPointerEvent *reset(QEvent *) override; - bool isPressEvent() const override; - bool isUpdateEvent() const override; - bool isReleaseEvent() const override; - QQuickPointerTabletEvent *asPointerTabletEvent() override { return this; } - const QQuickPointerTabletEvent *asPointerTabletEvent() const override { return this; } - const QQuickEventTabletPoint *tabletPoint() const { return static_cast<QQuickEventTabletPoint *>(m_point); } - - QTabletEvent *asTabletEvent() const; - - Q_DISABLE_COPY(QQuickPointerTabletEvent) -}; -#endif // QT_CONFIG(tabletevent) - -#if QT_CONFIG(gestures) -class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickSinglePointEvent -{ - Q_OBJECT - Q_PROPERTY(Qt::NativeGestureType type READ type CONSTANT) - Q_PROPERTY(qreal value READ value CONSTANT) - -public: - QQuickPointerNativeGestureEvent(QObject *parent, const QPointingDevice *device); - - QQuickPointerEvent *reset(QEvent *) override; - bool isPressEvent() const override; - bool isUpdateEvent() const override; - bool isReleaseEvent() const override; - QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() override { return this; } - const QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() const override { return this; } - Qt::NativeGestureType type() const; - qreal value() const; - - Q_DISABLE_COPY(QQuickPointerNativeGestureEvent) -}; -#endif // QT_CONFIG(gestures) - -class Q_QUICK_PRIVATE_EXPORT QQuickPointerScrollEvent : public QQuickSinglePointEvent -{ - Q_OBJECT - Q_PROPERTY(QVector2D angleDelta READ angleDelta CONSTANT) - Q_PROPERTY(QVector2D pixelDelta READ pixelDelta CONSTANT) - Q_PROPERTY(bool hasAngleDelta READ hasAngleDelta CONSTANT) - Q_PROPERTY(bool hasPixelDelta READ hasPixelDelta CONSTANT) - Q_PROPERTY(bool inverted READ isInverted CONSTANT) - - QML_NAMED_ELEMENT(PointerScrollEvent) - QML_UNCREATABLE("PointerScrollEvent is only available via the WheelHandler::wheel signal.") - QML_ADDED_IN_VERSION(2, 14) - -public: - QQuickPointerScrollEvent(QObject *parent, const QPointingDevice *device); - - QQuickPointerEvent *reset(QEvent *) override; - void localize(QQuickItem *target) override; - bool isPressEvent() const override; - bool isUpdateEvent() const override; - bool isReleaseEvent() const override; - QQuickPointerScrollEvent *asPointerScrollEvent() override { return this; } - const QQuickPointerScrollEvent *asPointerScrollEvent() const override { return this; } - QVector2D angleDelta() const { return m_angleDelta; } - QVector2D pixelDelta() const { return m_pixelDelta; } - bool hasAngleDelta() const { return !angleDelta().isNull(); } - bool hasPixelDelta() const { return !pixelDelta().isNull(); } - bool isInverted() const { return m_inverted; } - Qt::ScrollPhase phase() const { return m_phase; } - -private: - // TODO remove this if it's obsolete - Qt::MouseEventSource synthSource() const { return m_synthSource; } - -private: - QVector2D m_angleDelta; - QVector2D m_pixelDelta; - Qt::ScrollPhase m_phase = Qt::NoScrollPhase; - Qt::MouseEventSource m_synthSource = Qt::MouseEventNotSynthesized; - bool m_inverted = false; - - friend class QQuickWindowPrivate; - friend class QQuickWheelHandler; - - Q_DISABLE_COPY(QQuickPointerScrollEvent) -}; - -Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug, const QQuickPointerEvent *); -Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug, const QQuickEventPoint *); -//Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug, const QQuickEventTouchPoint *); TODO maybe - QT_END_NAMESPACE QML_DECLARE_TYPE(QQuickKeyEvent) @@ -710,7 +269,6 @@ QML_DECLARE_TYPE(QQuickWheelEvent) QML_DECLARE_TYPE(QQuickCloseEvent) QML_DECLARE_TYPE(QPointingDevice) QML_DECLARE_TYPE(QPointingDeviceUniqueId) -QML_DECLARE_TYPE(QQuickPointerEvent) -Q_DECLARE_METATYPE(QQuickEventPoint::GrabTransition) +QML_DECLARE_TYPE(QPointerEvent) #endif // QQUICKEVENTS_P_P_H diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 0a3c1a71c9..d20f23466b 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -1606,19 +1606,7 @@ void QQuickFlickablePrivate::captureDelayedPress(QQuickItem *item, QMouseEvent * if (!isInnermostPressDelay(item)) return; - // delayedPressEvent = QQuickWindowPrivate::cloneMouseEvent(event); // TODO make it OK to tell the truth about the device - - // temporary hack to keep the Qt 5 solution for QTBUG-78818 working the same for now: - // when QQuickWindowPrivate::pointerEventInstance() is called, it has to look like a mouse event from a mouse, - // not a mouse event that actually comes from a touchscreen (which is what it actually is). - // Otherwise a nested MultiPointTouchArea will receive a delayed touch - // (which is what we actually want, later on; but the code isn't ready for that yet). - delayedPressEvent = new QMouseEvent(QEvent::MouseButtonPress, event->position(), - event->scenePosition(), event->globalPosition(), event->button(), event->buttons(), - event->modifiers(), Qt::MouseEventSynthesizedByQt); - QMutableSinglePointEvent::from(delayedPressEvent)->setTimestamp(event->timestamp()); - // end of hack - + delayedPressEvent = QQuickWindowPrivate::cloneMouseEvent(event); delayedPressEvent->setAccepted(false); delayedPressTimer.start(pressDelay, q); } diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 8bf5e4f4bf..8e6bb0f224 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -3015,7 +3015,6 @@ void QQuickItemPrivate::derefWindow() QQuickWindowPrivate *c = QQuickWindowPrivate::get(window); if (polishScheduled) c->itemsToPolish.removeOne(q); - c->removeGrabber(q); #if QT_CONFIG(cursor) if (c->cursorItem == q) { c->cursorItem = nullptr; @@ -5249,12 +5248,12 @@ void QQuickItemPrivate::deliverShortcutOverrideEvent(QKeyEvent *event) } } -bool QQuickItemPrivate::anyPointerHandlerWants(QQuickEventPoint *point) const +bool QQuickItemPrivate::anyPointerHandlerWants(const QPointerEvent *event, const QEventPoint &point) const { if (!hasPointerHandlers()) return false; for (QQuickPointerHandler *handler : extra->pointerHandlers) { - if (handler->wantsEventPoint(point)) + if (handler->wantsEventPoint(event, point)) return true; } return false; @@ -5267,13 +5266,22 @@ bool QQuickItemPrivate::anyPointerHandlerWants(QQuickEventPoint *point) const delivery to any handler which is the exclusive grabber of any point within this event (because delivery to exclusive grabbers is handled separately). */ -bool QQuickItemPrivate::handlePointerEvent(QQuickPointerEvent *event, bool avoidExclusiveGrabber) +bool QQuickItemPrivate::handlePointerEvent(QPointerEvent *event, bool avoidExclusiveGrabber) { bool delivered = false; - QVector<QObject *> &eventDeliveryTargets = QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->device()); if (extra.isAllocated()) { for (QQuickPointerHandler *handler : extra->pointerHandlers) { - if ((!avoidExclusiveGrabber || !event->hasExclusiveGrabber(handler)) && !eventDeliveryTargets.contains(handler)) { + bool avoidThisHandler = false; + if (avoidExclusiveGrabber) { + for (auto &p : event->points()) { + if (event->exclusiveGrabber(p) == handler) { + avoidThisHandler = true; + break; + } + } + } + if (!avoidThisHandler && + !QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->device()).contains(handler)) { handler->handlePointerEvent(event); delivered = true; } @@ -7623,6 +7631,8 @@ QQuickPointerHandler *QQuickItemPrivate::effectiveCursorHandler() const #endif /*! + \obsolete Use QPointerEvent::setExclusiveGrabber() + Grabs the mouse input. This item will receive all mouse events until ungrabMouse() is called. @@ -7637,18 +7647,21 @@ QQuickPointerHandler *QQuickItemPrivate::effectiveCursorHandler() const void QQuickItem::grabMouse() { Q_D(QQuickItem); - if (!d->window || d->window->mouseGrabberItem() == this) + if (!d->window) return; QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(d->window); - bool fromTouch = windowPriv->isDeliveringTouchAsMouse(); - auto point = fromTouch ? - windowPriv->pointerEventInstance(windowPriv->touchMouseDevice)->pointById(windowPriv->touchMouseId) : - windowPriv->pointerEventInstance(QPointingDevice::primaryPointingDevice())->point(0); - if (point) - point->setGrabberItem(this); + auto eventInDelivery = windowPriv->eventInDelivery(); + if (!eventInDelivery) { + qWarning() << "cannot grab mouse: no event is currently being delivered"; + return; + } + auto epd = windowPriv->mousePointData(); + eventInDelivery->setExclusiveGrabber(epd->eventPoint, this); } /*! + \obsolete Use QPointerEvent::setExclusiveGrabber() + Releases the mouse grab following a call to grabMouse(). Note that this function should only be called when the item wants @@ -7663,10 +7676,18 @@ void QQuickItem::ungrabMouse() if (!d->window) return; QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(d->window); - windowPriv->removeGrabber(this, true, windowPriv->isDeliveringTouchAsMouse()); + auto eventInDelivery = windowPriv->eventInDelivery(); + if (!eventInDelivery) { + // do it the expensive way + windowPriv->removeGrabber(this); + return; + } + const auto &eventPoint = windowPriv->mousePointData()->eventPoint; + if (eventInDelivery->exclusiveGrabber(eventPoint) != this) + return; + eventInDelivery->setExclusiveGrabber(eventPoint, this); } - /*! Returns whether mouse input should exclusively remain with this item. @@ -7701,32 +7722,31 @@ void QQuickItem::setKeepMouseGrab(bool keep) } /*! + \obsolete Use QPointerEvent::setExclusiveGrabber(). Grabs the touch points specified by \a ids. These touch points will be owned by the item until they are released. Alternatively, the grab can be stolen by a filtering item like Flickable. Use setKeepTouchGrab() to prevent the grab from being stolen. - - \sa ungrabTouchPoints(), setKeepTouchGrab() */ void QQuickItem::grabTouchPoints(const QList<int> &ids) { - Q_D(QQuickItem); - if (!d->window) + QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window()); + auto event = windowPriv->eventInDelivery(); + if (Q_UNLIKELY(!event)) { + qWarning() << "cannot grab: no event is currently being delivered"; return; - QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(d->window); - windowPriv->grabTouchPoints(this, ids); + } + for (auto pt : event->points()) { + if (ids.contains(pt.id())) + event->setExclusiveGrabber(pt, this); + } } /*! + \obsolete Use QEventPoint::setExclusiveGrabber() instead. Ungrabs the touch points owned by this item. - - \note there is hardly any reason to call this function. It should only be - called when an item does not want to receive any further events, so no - move or release events will be delivered after calling this function. - - \sa grabTouchPoints() */ void QQuickItem::ungrabTouchPoints() { @@ -8338,6 +8358,97 @@ QQuickItemLayer *QQuickItemPrivate::layer() const #endif } +/*! + \internal + Create a modified copy of the given \a event intended for delivery to this + item, containing pointers to only the QEventPoint instances that are + relevant to this item, and transforming their positions to this item's + coordinate system. + + Returns an invalid event with type \l QEvent::None if all points are + stationary, or there are no points inside the item, or none of the points + were pressed inside and the item was not grabbing any of them and + \a isFiltering is false. + + When \a isFiltering is true, it is assumed that the item cares about all + points which are inside its bounds, because most filtering items need to + monitor eventpoint movements until a drag threshold is exceeded or the + requirements for a gesture to be recognized are met in some other way. +*/ +QTouchEvent QQuickItemPrivate::localizedTouchEvent(const QTouchEvent *event, bool isFiltering) +{ + Q_Q(QQuickItem); + QList<QEventPoint> touchPoints; + QEventPoint::States eventStates; + + bool anyPressOrReleaseInside = false; + bool anyStationaryWithModifiedPropertyInside = false; + bool anyGrabber = false; + for (auto &p : event->points()) { + if (p.isAccepted()) + continue; + // include points where item is the grabber + auto pointGrabber = event->exclusiveGrabber(p); + bool isGrabber = (pointGrabber == q); + if (isGrabber) + anyGrabber = true; + // include points inside the bounds if no other item is the grabber or if the item is filtering + const auto localPos = q->mapFromScene(p.scenePosition()); + bool isInside = q->contains(localPos); + bool hasAnotherGrabber = pointGrabber && pointGrabber != q; + + // filtering: (childMouseEventFilter) include points that are grabbed by children of the target item + bool grabberIsChild = false; + auto parent = qobject_cast<QQuickItem*>(pointGrabber); + while (isFiltering && parent) { + if (parent == q) { + grabberIsChild = true; + break; + } + parent = parent->parentItem(); + } + + bool filterRelevant = isFiltering && grabberIsChild; + if (!(isGrabber || (isInside && (!hasAnotherGrabber || isFiltering)) || filterRelevant)) + continue; + if ((p.state() == QEventPoint::State::Pressed || p.state() == QEventPoint::State::Released) && isInside) + anyPressOrReleaseInside = true; + QEventPoint pCopy(p); + QMutableEventPoint mut = QMutableEventPoint::from(pCopy); + if (isInside && mut.stationaryWithModifiedProperty()) + anyStationaryWithModifiedPropertyInside = true; + eventStates |= p.state(); + mut.setPosition(localPos); + touchPoints << mut; + } + + // Now touchPoints will have only points which are inside the item. + // But if none of them were just pressed inside, and the item has no other reason to care, ignore them anyway. + if ((eventStates == QEventPoint::State::Stationary && !anyStationaryWithModifiedPropertyInside) || + touchPoints.isEmpty() || (!anyPressOrReleaseInside && !anyGrabber && !isFiltering)) + return QTouchEvent(QEvent::None); + + // if all points have the same state, set the event type accordingly + QEvent::Type eventType = event->type(); + switch (eventStates) { + case QEventPoint::State::Pressed: + eventType = QEvent::TouchBegin; + break; + case QEventPoint::State::Released: + eventType = QEvent::TouchEnd; + break; + default: + eventType = QEvent::TouchUpdate; + break; + } + + QMutableTouchEvent ret(eventType, event->pointingDevice(), event->modifiers(), touchPoints); + ret.setTarget(q); + ret.setTimestamp(event->timestamp()); + ret.accept(); + return ret; +} + bool QQuickItemPrivate::hasPointerHandlers() const { return extra.isAllocated() && !extra->pointerHandlers.isEmpty(); diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index 3f75eca5e1..775bc6edbe 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -462,7 +462,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_resourceObjectDeleted(QObject *)) Q_PRIVATE_SLOT(d_func(), quint64 _q_createJSWrapper(QV4::ExecutionEngine *)) - friend class QQuickEventPoint; + friend class QEventPoint; friend class QQuickWindow; friend class QQuickWindowPrivate; friend class QSGRenderer; diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 2461ea29f7..68c5d59dfe 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -281,6 +281,7 @@ public: QQuickItemLayer *layer() const; + QTouchEvent localizedTouchEvent(const QTouchEvent *event, bool isFiltering); bool hasPointerHandlers() const; bool hasHoverHandlers() const; virtual void addPointerHandler(QQuickPointerHandler *h); @@ -613,8 +614,8 @@ public: #endif void deliverShortcutOverrideEvent(QKeyEvent *); - bool anyPointerHandlerWants(QQuickEventPoint *point) const; - virtual bool handlePointerEvent(QQuickPointerEvent *, bool avoidExclusiveGrabber = false); + bool anyPointerHandlerWants(const QPointerEvent *event, const QEventPoint &point) const; + virtual bool handlePointerEvent(QPointerEvent *, bool avoidExclusiveGrabber = false); virtual void setVisible(bool visible); diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp index cebfe74df0..8b666628e3 100644 --- a/src/quick/items/qquickmultipointtoucharea.cpp +++ b/src/quick/items/qquickmultipointtoucharea.cpp @@ -45,6 +45,7 @@ #include <private/qquickwindow_p.h> #include <private/qguiapplication_p.h> #include <QtGui/private/qevent_p.h> +#include <QtGui/private/qpointingdevice_p.h> #include <QEvent> #include <QMouseEvent> #include <QDebug> @@ -553,20 +554,19 @@ void QQuickMultiPointTouchArea::touchEvent(QTouchEvent *event) } } -void QQuickMultiPointTouchArea::grabGesture() +void QQuickMultiPointTouchArea::grabGesture(QPointingDevice *dev) { _stealMouse = true; grabMouse(); setKeepMouseGrab(true); - QList<int> ids; - ids.reserve(_touchPoints.size()); + QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(dev); for (auto it = _touchPoints.keyBegin(), end = _touchPoints.keyEnd(); it != end; ++it) { if (*it != -1) // -1 might be the mouse-point, but we already grabbed the mouse above. - ids.append(*it); + if (auto pt = devPriv->queryPointById(*it)) + pt->exclusiveGrabber = this; } - grabTouchPoints(ids); setKeepTouchGrab(true); } @@ -579,13 +579,17 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) clearTouchLists(); QList<QEventPoint> touchPoints; QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window()); + QPointingDevice *dev = nullptr; switch (event->type()) { case QEvent::TouchBegin: case QEvent::TouchUpdate: - case QEvent::TouchEnd: - touchPoints = static_cast<QTouchEvent*>(event)->touchPoints(); + case QEvent::TouchEnd: { + QTouchEvent* te = static_cast<QTouchEvent*>(event); + touchPoints = te->points(); + dev = const_cast<QPointingDevice *>(te->pointingDevice()); break; + } case QEvent::MouseButtonPress: _mouseQpaTouchPoint = QEventPoint(windowPriv->touchMouseId); _touchMouseDevice = windowPriv->touchMouseDevice; @@ -593,7 +597,8 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) case QEvent::MouseMove: case QEvent::MouseButtonRelease: { QMouseEvent *me = static_cast<QMouseEvent*>(event); - _mouseQpaTouchPoint = me->point(0); + _mouseQpaTouchPoint = me->points().first(); + dev = const_cast<QPointingDevice *>(me->pointingDevice()); if (event->type() == QEvent::MouseButtonPress) { addTouchPoint(me); started = true; @@ -623,7 +628,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) } } if (numTouchPoints >= _minimumTouchPoints && numTouchPoints <= _maximumTouchPoints) { - for (const QEventPoint &p : qAsConst(touchPoints)) { + for (QEventPoint &p : touchPoints) { QEventPoint::State touchPointState = p.state(); int id = p.id(); if (touchPointState & QEventPoint::State::Released) { @@ -633,7 +638,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) addTouchPoint(&p); started = true; } else if ((touchPointState & QEventPoint::State::Updated) || - QMutableEventPoint::from(const_cast<QEventPoint &>(p)).stationaryWithModifiedProperty()) { + QMutableEventPoint::from(p).stationaryWithModifiedProperty()) { // React to a stationary point with a property change (velocity, pressure) as if the point moved. (QTBUG-77142) QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id)); Q_ASSERT(dtp); @@ -668,8 +673,8 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) QQuickGrabGestureEvent event; event._touchPoints = _touchPoints.values(); emit gestureStarted(&event); - if (event.wantsGrab()) - grabGesture(); + if (event.wantsGrab() && dev) + grabGesture(dev); } } @@ -957,7 +962,7 @@ bool QQuickMultiPointTouchArea::childMouseEventFilter(QQuickItem *receiver, QEve _lastFilterableTouchPointIds.clear(); Q_FALLTHROUGH(); case QEvent::TouchUpdate: - for (auto tp : static_cast<QTouchEvent*>(event)->touchPoints()) { + for (const auto &tp : static_cast<QTouchEvent*>(event)->points()) { if (tp.state() == QEventPoint::State::Pressed) _lastFilterableTouchPointIds << tp.id(); } @@ -998,7 +1003,7 @@ bool QQuickMultiPointTouchArea::shouldFilter(QEvent *event) case QEvent::TouchUpdate: case QEvent::TouchEnd: { QTouchEvent *te = static_cast<QTouchEvent*>(event); - for (const QEventPoint &point : te->touchPoints()) { + for (const QEventPoint &point : te->points()) { if (contains(mapFromScene(point.scenePosition()))) { containsPoint = true; break; diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h index 693ceea50c..16e490adab 100644 --- a/src/quick/items/qquickmultipointtoucharea_p.h +++ b/src/quick/items/qquickmultipointtoucharea_p.h @@ -281,7 +281,7 @@ protected: bool sendMouseEvent(QMouseEvent *event); bool shouldFilter(QEvent *event); - void grabGesture(); + void grabGesture(QPointingDevice *dev); QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override; #ifdef Q_OS_OSX void hoverEnterEvent(QHoverEvent *event) override; diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp index c021e5181c..6a5dda483d 100644 --- a/src/quick/items/qquickpincharea.cpp +++ b/src/quick/items/qquickpincharea.cpp @@ -335,10 +335,9 @@ void QQuickPinchArea::touchEvent(QTouchEvent *event) case QEvent::TouchBegin: case QEvent::TouchUpdate: d->touchPoints.clear(); - for (int i = 0; i < event->touchPoints().count(); ++i) { - if (!(event->touchPoints().at(i).state() & QEventPoint::State::Released)) { - d->touchPoints << event->touchPoints().at(i); - } + for (auto &tp : event->points()) { + if (!(tp.state() & QEventPoint::State::Released)) + d->touchPoints << tp; } updatePinch(); break; @@ -639,11 +638,12 @@ bool QQuickPinchArea::childMouseEventFilter(QQuickItem *i, QEvent *e) clearPinch(); Q_FALLTHROUGH(); case QEvent::TouchUpdate: { - QTouchEvent *touch = static_cast<QTouchEvent*>(e); + const auto &points = static_cast<QTouchEvent*>(e)->points(); d->touchPoints.clear(); - for (int i = 0; i < touch->touchPoints().count(); ++i) - if (!(touch->touchPoints().at(i).state() & QEventPoint::State::Released)) - d->touchPoints << touch->touchPoints().at(i); + for (auto &tp : points) { + if (!(tp.state() & QEventPoint::State::Released)) + d->touchPoints << tp; + } updatePinch(); } e->setAccepted(d->inPinch); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 96527d955b..06c2df41a9 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -97,9 +97,12 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch") +Q_LOGGING_CATEGORY(lcTouchCmprs, "qt.quick.touch.compression") Q_LOGGING_CATEGORY(DBG_TOUCH_TARGET, "qt.quick.touch.target") Q_LOGGING_CATEGORY(DBG_MOUSE, "qt.quick.mouse") Q_LOGGING_CATEGORY(DBG_MOUSE_TARGET, "qt.quick.mouse.target") +Q_LOGGING_CATEGORY(lcPtr, "qt.quick.pointer") +Q_LOGGING_CATEGORY(lcPtrGrab, "qt.quick.pointer.grab") Q_LOGGING_CATEGORY(lcTablet, "qt.quick.tablet") Q_LOGGING_CATEGORY(lcWheelTarget, "qt.quick.wheel.target") Q_LOGGING_CATEGORY(lcGestureTarget, "qt.quick.gesture.target") @@ -855,23 +858,18 @@ QQmlListProperty<QObject> QQuickWindowPrivate::data() QQuickWindowPrivate::data_removeLast); } -QMouseEvent *QQuickWindowPrivate::touchToMouseEvent(QEvent::Type type, const QEventPoint &p, QTouchEvent *event, QQuickItem *item, bool transformNeeded) +QMouseEvent QQuickWindowPrivate::touchToMouseEvent(QEvent::Type type, const QEventPoint &p, QTouchEvent *event, QQuickItem *item) { + Q_UNUSED(item) Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)); - // The touch point local position and velocity are not yet transformed. - QMouseEvent *me = new QMouseEvent(type, transformNeeded ? item->mapFromScene(p.scenePosition()) : p.position(), p.scenePosition(), p.globalPosition(), - Qt::LeftButton, (type == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton), event->modifiers(), - Qt::MouseEventSynthesizedByQt, event->pointingDevice()); - me->setAccepted(true); - me->setTimestamp(event->timestamp()); - QVector2D transformedVelocity = p.velocity(); - if (transformNeeded) { - QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - QMatrix4x4 transformMatrix(itemPrivate->windowToItemTransform()); - transformedVelocity = transformMatrix.mapVector(p.velocity()).toVector2D(); - } - QMutableSinglePointEvent::from(me)->mutablePoint().setVelocity(transformedVelocity); - return me; + QMutableSinglePointEvent ret(type, event->pointingDevice(), p, + (type == QEvent::MouseMove ? Qt::NoButton : Qt::LeftButton), + (type == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton), + event->modifiers(), Qt::MouseEventSynthesizedByQt); + ret.setAccepted(true); + ret.setTimestamp(event->timestamp()); + static_assert(sizeof(QMutableSinglePointEvent) == sizeof(QMouseEvent)); + return *reinterpret_cast<QMouseEvent*>(&ret); } bool QQuickWindowPrivate::checkIfDoubleTapped(ulong newPressEventTimestamp, QPoint newPressPos) @@ -900,18 +898,37 @@ bool QQuickWindowPrivate::checkIfDoubleTapped(ulong newPressEventTimestamp, QPoi return doubleClicked; } +QPointerEvent *QQuickWindowPrivate::eventInDelivery() const +{ + if (eventsInDelivery.isEmpty()) + return nullptr; + return eventsInDelivery.top(); +} + +/*! \internal + A helper function for the benefit of obsolete APIs like QQuickItem::grabMouse() + that don't have the currently-being-delivered event in context. + Returns the device the currently-being-delivered event comse from. +*/ +QPointingDevicePrivate::EventPointData *QQuickWindowPrivate::mousePointData() +{ + if (eventsInDelivery.isEmpty()) + return nullptr; + auto devPriv = QPointingDevicePrivate::get(const_cast<QPointingDevice*>(eventsInDelivery.top()->pointingDevice())); + return devPriv->pointById(isDeliveringTouchAsMouse() ? touchMouseId : 0); +} + void QQuickWindowPrivate::cancelTouchMouseSynthesis() { - qCDebug(DBG_TOUCH_TARGET); + qCDebug(DBG_TOUCH_TARGET) << "id" << touchMouseId << "on" << touchMouseDevice; touchMouseId = -1; touchMouseDevice = nullptr; } -bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEvent *pointerEvent) +bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QTouchEvent *pointerEvent) { Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)); - Q_Q(QQuickWindow); - auto device = pointerEvent->device(); + auto device = pointerEvent->pointingDevice(); // A touch event from a trackpad is likely to be followed by a mouse or gesture event, so mouse event synth is redundant if (device->type() == QInputDevice::DeviceType::TouchPad && device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation)) { @@ -920,15 +937,14 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve } // FIXME: make this work for mouse events too and get rid of the asTouchEvent in here. - Q_ASSERT(pointerEvent->asPointerTouchEvent()); - QScopedPointer<QTouchEvent> event(pointerEvent->asPointerTouchEvent()->touchEventForItem(item)); - if (event.isNull()) + QTouchEvent event = QQuickItemPrivate::get(item)->localizedTouchEvent(pointerEvent, false); + if (!event.points().count()) return false; // For each point, check if it is accepted, if not, try the next point. // Any of the fingers can become the mouse one. // This can happen because a mouse area might not accept an event at some point but another. - for (auto &p : event->points()) { + for (auto &p : event.points()) { // A new touch point if (touchMouseId == -1 && p.state() & QEventPoint::State::Pressed) { QPointF pos = item->mapFromScene(p.scenePosition()); @@ -938,26 +954,25 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve break; qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << Qt::hex << p.id() << "->" << item; - QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event.data(), item, false)); + QMouseEvent mousePress = touchToMouseEvent(QEvent::MouseButtonPress, p, &event, item); // Send a single press and see if that's accepted - QCoreApplication::sendEvent(item, mousePress.data()); - event->setAccepted(mousePress->isAccepted()); - if (mousePress->isAccepted()) { + QCoreApplication::sendEvent(item, &mousePress); + event.setAccepted(mousePress.isAccepted()); + if (mousePress.isAccepted()) { touchMouseDevice = device; touchMouseId = p.id(); - if (!q->mouseGrabberItem()) - item->grabMouse(); - if (auto pointerEventPoint = pointerEvent->pointById(p.id())) - pointerEventPoint->setGrabberItem(item); + const auto &pt = mousePress.point(0); + if (!mousePress.exclusiveGrabber(pt)) + mousePress.setExclusiveGrabber(pt, item); - if (checkIfDoubleTapped(event->timestamp(), p.globalPosition().toPoint())) { + if (checkIfDoubleTapped(event.timestamp(), p.globalPosition().toPoint())) { // since we synth the mouse event from from touch, we respect the // QPlatformTheme::TouchDoubleTapDistance instead of QPlatformTheme::MouseDoubleClickDistance - QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event.data(), item, false)); - QCoreApplication::sendEvent(item, mouseDoubleClick.data()); - event->setAccepted(mouseDoubleClick->isAccepted()); - if (!mouseDoubleClick->isAccepted()) + QMouseEvent mouseDoubleClick = touchToMouseEvent(QEvent::MouseButtonDblClick, p, &event, item); + QCoreApplication::sendEvent(item, &mouseDoubleClick); + event.setAccepted(mouseDoubleClick.isAccepted()); + if (!mouseDoubleClick.isAccepted()) cancelTouchMouseSynthesis(); } @@ -974,52 +989,49 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve if (moveDelta.x() >= doubleTapDistance || moveDelta.y() >= doubleTapDistance) touchMousePressTimestamp = 0; // Got dragged too far, dismiss the double tap } - if (QQuickItem *mouseGrabberItem = q->mouseGrabberItem()) { - QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event.data(), mouseGrabberItem, false)); - QCoreApplication::sendEvent(item, me.data()); - event->setAccepted(me->isAccepted()); - if (me->isAccepted()) { + if (QQuickItem *mouseGrabberItem = qmlobject_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(p))) { + QMouseEvent me = touchToMouseEvent(QEvent::MouseMove, p, &event, mouseGrabberItem); + QCoreApplication::sendEvent(item, &me); + event.setAccepted(me.isAccepted()); + if (me.isAccepted()) qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << Qt::hex << p.id() << "->" << mouseGrabberItem; - } - return event->isAccepted(); + return event.isAccepted(); } else { // 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.data(), item, false)); + QMouseEvent me = touchToMouseEvent(QEvent::MouseMove, p, &event, item); if (lastMousePosition.isNull()) - lastMousePosition = me->scenePosition(); + lastMousePosition = me.scenePosition(); QPointF last = lastMousePosition; - lastMousePosition = me->scenePosition(); + lastMousePosition = me.scenePosition(); - bool accepted = me->isAccepted(); - bool delivered = deliverHoverEvent(contentItem, me->scenePosition(), last, me->modifiers(), me->timestamp(), accepted); - if (!delivered) { - //take care of any exits - accepted = clearHover(me->timestamp()); - } - me->setAccepted(accepted); + bool accepted = me.isAccepted(); + bool delivered = deliverHoverEvent(contentItem, me.scenePosition(), last, me.modifiers(), me.timestamp(), accepted); + // take care of any exits + if (!delivered) + clearHover(me.timestamp()); break; } } else if (p.state() & QEventPoint::State::Released) { // currently handled point was released - if (QQuickItem *mouseGrabberItem = q->mouseGrabberItem()) { - QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event.data(), mouseGrabberItem, false)); - QCoreApplication::sendEvent(item, me.data()); + if (QQuickItem *mouseGrabberItem = qmlobject_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(p))) { + QMouseEvent me = touchToMouseEvent(QEvent::MouseButtonRelease, p, &event, mouseGrabberItem); + QCoreApplication::sendEvent(item, &me); if (item->acceptHoverEvents() && p.globalPosition() != QGuiApplicationPrivate::lastCursorPosition) { QPointF localMousePos(qInf(), qInf()); if (QWindow *w = item->window()) localMousePos = item->mapFromScene(w->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint())); QMouseEvent mm(QEvent::MouseMove, localMousePos, QGuiApplicationPrivate::lastCursorPosition, - Qt::NoButton, Qt::NoButton, event->modifiers()); + Qt::NoButton, Qt::NoButton, event.modifiers()); QCoreApplication::sendEvent(item, &mm); } - if (q->mouseGrabberItem()) // might have ungrabbed due to event - q->mouseGrabberItem()->ungrabMouse(); + if (pointerEvent->exclusiveGrabber(p) == mouseGrabberItem) // might have ungrabbed due to event + pointerEvent->setExclusiveGrabber(p, nullptr); cancelTouchMouseSynthesis(); - return me->isAccepted(); + return me.isAccepted(); } } break; @@ -1028,74 +1040,34 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve return false; } -void QQuickWindowPrivate::grabTouchPoints(QObject *grabber, const QVector<int> &ids) -{ - QQuickPointerEvent *ev = nullptr; - for (int i = 0; i < ids.count(); ++i) { - int id = ids.at(i); - if (Q_UNLIKELY(id < 0)) { - qWarning("ignoring grab of touchpoint %d", id); - continue; - } - if (id == touchMouseId) { - auto point = pointerEventInstance(touchMouseDevice)->pointById(id); - auto touchMouseGrabber = point->grabberItem(); - if (touchMouseGrabber) { - point->setExclusiveGrabber(nullptr); - touchMouseGrabber->mouseUngrabEvent(); - touchMouseGrabber->touchUngrabEvent(); - cancelTouchMouseSynthesis(); - } - qCDebug(DBG_MOUSE_TARGET) << "grabTouchPoints: mouse grabber changed due to grabTouchPoints:" << touchMouseGrabber << "-> null"; - } - - // optimization to avoid the loop over devices below: - // all ids are probably from the same event, so we don't have to search - if (ev) { - auto point = ev->pointById(id); - if (point && point->exclusiveGrabber() != grabber) { - point->setExclusiveGrabber(grabber); - continue; // next id in the ids loop - } - } - // search all devices for a QQuickPointerEvent instance that is delivering the point with id - const auto devs = QPointingDevice::devices(); - for (auto device : devs) { - if (device->type() != QInputDevice::DeviceType::TouchScreen) - continue; - QQuickPointerEvent *pev = pointerEventInstance(static_cast<const QPointingDevice *>(device)); - auto point = pev->pointById(id); - if (point) { - ev = pev; - if (point->exclusiveGrabber() != grabber) - point->setExclusiveGrabber(grabber); - break; // out of touchDevices loop - } - } - } -} - /*! Ungrabs all touchpoint grabs and/or the mouse grab from the given item \a grabber. This should not be called when processing a release event - that's redundant. It is called in other cases, when the points may not be released, but the item nevertheless must lose its grab due to becoming disabled, invisible, etc. - QQuickEventPoint::setGrabberItem() calls touchUngrabEvent() when all points are released, + QPointerEvent::setExclusiveGrabber() calls touchUngrabEvent() when all points are released, but if not all points are released, it cannot be sure whether to call touchUngrabEvent() or not; so we have to do it here. */ void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool touch) { Q_Q(QQuickWindow); - if (Q_LIKELY(mouse) && q->mouseGrabberItem() == grabber) { - bool fromTouch = isDeliveringTouchAsMouse(); - auto point = fromTouch ? - pointerEventInstance(touchMouseDevice)->pointById(touchMouseId) : - pointerEventInstance(QPointingDevice::primaryPointingDevice())->point(0); - QQuickItem *oldGrabber = point->grabberItem(); + if (eventsInDelivery.isEmpty()) { + // do it the expensive way + for (auto dev : knownPointingDevices) { + auto devPriv = QPointingDevicePrivate::get(const_cast<QPointingDevice *>(dev)); + devPriv->removeGrabber(grabber); + } + return; + } + auto eventInDelivery = eventsInDelivery.top(); + if (Q_LIKELY(mouse) && q->mouseGrabberItem() == grabber && eventInDelivery) { + const bool fromTouch = isDeliveringTouchAsMouse(); + auto point = eventInDelivery->pointById(fromTouch ? touchMouseId : 0); + Q_ASSERT(point); + QQuickItem *oldGrabber = qobject_cast<QQuickItem *>(eventInDelivery->exclusiveGrabber(*point)); qCDebug(DBG_MOUSE_TARGET) << "removeGrabber" << oldGrabber << "-> null"; - point->setGrabberItem(nullptr); - sendUngrabEvent(oldGrabber, fromTouch); + eventInDelivery->setExclusiveGrabber(*point, nullptr); } if (Q_LIKELY(touch)) { bool ungrab = false; @@ -1103,14 +1075,9 @@ void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool to for (auto device : touchDevices) { if (device->type() != QInputDevice::DeviceType::TouchScreen) continue; - if (auto pointerEvent = queryPointerEventInstance(static_cast<const QPointingDevice *>(device))) { - for (int i = 0; i < pointerEvent->pointCount(); ++i) { - if (pointerEvent->point(i)->exclusiveGrabber() == grabber) { - pointerEvent->point(i)->setGrabberItem(nullptr); - ungrab = true; - } - } - } + if (QPointingDevicePrivate::get(const_cast<QPointingDevice *>(static_cast<const QPointingDevice *>(device)))-> + removeExclusiveGrabber(eventInDelivery, grabber)) + ungrab = true; } if (ungrab) grabber->touchUngrabEvent(); @@ -1691,8 +1658,6 @@ QQuickWindow::~QQuickWindow() QQuickRootItem *root = d->contentItem; d->contentItem = nullptr; delete root; - qDeleteAll(d->pointerEventInstances); - d->pointerEventInstances.clear(); d->renderJobMutex.lock(); qDeleteAll(d->beforeSynchronizingJobs); @@ -1897,38 +1862,21 @@ QObject *QQuickWindow::focusObject() const /*! - Returns the item which currently has the mouse grab. + \obsolete Use QPointerEvent::exclusiveGrabber() + Returns the item which currently has the mouse grab. */ -// TODO deprecate this, or take seat name as an argument QQuickItem *QQuickWindow::mouseGrabberItem() const { Q_D(const QQuickWindow); - - if (d->isDeliveringTouchAsMouse()) { - if (QQuickPointerEvent *event = d->queryPointerEventInstance(d->touchMouseDevice)) { - auto point = event->pointById(d->touchMouseId); - return point ? point->grabberItem() : nullptr; - } - } else { - const QPointingDevice *mouse = QPointingDevice::primaryPointingDevice(); - if (mouse->type() != QInputDevice::DeviceType::Mouse) { - // TODO don't assume the first mouse is the core pointer (but so far there is normally only one) - for (const auto *dev : QInputDevice::devices()) { - if (dev->type() == QInputDevice::DeviceType::Mouse) { - mouse = static_cast<const QPointingDevice *>(dev); - break; - } - } - } - if (QQuickPointerEvent *event = d->queryPointerEventInstance(mouse)) { - Q_ASSERT(event->pointCount()); - return event->point(0)->grabberItem(); - } + auto epd = const_cast<QQuickWindowPrivate *>(d)->mousePointData(); + if (!epd && d->eventsInDelivery.isEmpty()) { + qCDebug(DBG_MOUSE, "mouse grabber ambiguous: no event is currently being delivered"); + return qmlobject_cast<QQuickItem *>(QPointingDevicePrivate::get(QPointingDevice::primaryPointingDevice())-> + firstPointExclusiveGrabber()); } - return nullptr; + return qobject_cast<QQuickItem *>(epd->exclusiveGrabber); } - bool QQuickWindowPrivate::clearHover(ulong timestamp) { Q_Q(QQuickWindow); @@ -1940,20 +1888,6 @@ bool QQuickWindowPrivate::clearHover(ulong timestamp) bool accepted = false; for (QQuickItem* item : qAsConst(hoverItems)) { accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), timestamp, true) || accepted; -#if QT_CONFIG(cursor) - QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - if (itemPrivate->hasPointerHandlers()) { - pos = q->mapFromGlobal(QCursor::pos()); - const auto dev = QPointingDevice::primaryPointingDevice(); - QQuickPointerEvent *pointerEvent = pointerEventInstance(dev, QEvent::MouseMove); - pointerEvent->point(0)->reset(QEventPoint::State::Updated, pos, int(dev->systemId()), timestamp, QVector2D()); - pointerEvent->point(0)->setAccepted(true); - pointerEvent->localize(item); - for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) - if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) - hh->handlePointerEvent(pointerEvent); - } -#endif } hoverItems.clear(); return accepted; @@ -2037,7 +1971,7 @@ bool QQuickWindow::event(QEvent *e) } #if QT_CONFIG(gestures) case QEvent::NativeGesture: - d->deliverSinglePointEventUntilAccepted(d->pointerEventInstance(e)); + d->deliverSinglePointEventUntilAccepted(static_cast<QPointerEvent *>(e)); break; #endif case QEvent::ShortcutOverride: @@ -2123,20 +2057,21 @@ void QQuickWindowPrivate::deliverKeyEvent(QKeyEvent *e) QMouseEvent *QQuickWindowPrivate::cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos) { QMouseEvent *me = new QMouseEvent(*event); - QMutableEventPoint &point = QMutableSinglePointEvent::from(me)->mutablePoint(); + QMutableEventPoint &point = QMutableEventPoint::from(event->point(0)); point.setTimestamp(event->timestamp()); point.setPosition(transformedLocalPos ? *transformedLocalPos : event->position()); return me; } -void QQuickWindowPrivate::deliverToPassiveGrabbers(const QVector<QPointer <QQuickPointerHandler> > &passiveGrabbers, - QQuickPointerEvent *pointerEvent) +void QQuickWindowPrivate::deliverToPassiveGrabbers(const QVector<QPointer <QObject> > &passiveGrabbers, + QPointerEvent *pointerEvent) { const QVector<QObject *> &eventDeliveryTargets = QQuickPointerHandlerPrivate::deviceDeliveryTargets(pointerEvent->device()); QVarLengthArray<QPair<QQuickItem *, bool>, 4> sendFilteredPointerEventResult; hasFiltered.clear(); - for (auto handler : passiveGrabbers) { + for (auto o : passiveGrabbers) { + QQuickPointerHandler *handler = qobject_cast<QQuickPointerHandler *>(o); // a null pointer in passiveGrabbers is unlikely, unless the grabbing handler was deleted dynamically if (Q_LIKELY(handler) && !eventDeliveryTargets.contains(handler)) { bool alreadyFiltered = false; @@ -2154,97 +2089,13 @@ void QQuickWindowPrivate::deliverToPassiveGrabbers(const QVector<QPointer <QQuic sendFilteredPointerEventResult << qMakePair(par, alreadyFiltered); } if (!alreadyFiltered) { - pointerEvent->localize(handler->parentItem()); + localizePointerEvent(pointerEvent, handler->parentItem()); handler->handlePointerEvent(pointerEvent); } } } } - - -void QQuickWindowPrivate::deliverMouseEvent(QQuickPointerMouseEvent *pointerEvent) -{ - Q_Q(QQuickWindow); - auto point = pointerEvent->point(0); - lastMousePosition = point->scenePosition(); - const bool mouseIsReleased = (point->state() == QQuickEventPoint::Released && pointerEvent->buttons() == Qt::NoButton); - QQuickItem *grabberItem = point->grabberItem(); - if (!grabberItem && isDeliveringTouchAsMouse()) - grabberItem = q->mouseGrabberItem(); - - if (grabberItem) { - bool handled = false; - hasFiltered.clear(); - if (sendFilteredPointerEvent(pointerEvent, grabberItem)) - handled = true; - // if the grabber is an Item: - // if the update consists of changing button state, don't accept it unless - // the button is one in which the grabber is interested - Qt::MouseButtons acceptedButtons = grabberItem->acceptedMouseButtons(); - if (!handled && pointerEvent->button() != Qt::NoButton && acceptedButtons - && !(acceptedButtons & pointerEvent->button())) { - pointerEvent->setAccepted(false); - handled = true; - } - - // send update - if (!handled) { - QPointF localPos = grabberItem->mapFromScene(lastMousePosition); - auto me = pointerEvent->asMouseEvent(localPos); - me->accept(); - QCoreApplication::sendEvent(grabberItem, me); - point->setAccepted(me->isAccepted()); - } - - // release event: ungrab if no buttons are pressed anymore - if (mouseIsReleased) - removeGrabber(grabberItem, true, isDeliveringTouchAsMouse()); - deliverToPassiveGrabbers(point->passiveGrabbers(), pointerEvent); - } else if (auto handler = point->grabberPointerHandler()) { - pointerEvent->localize(handler->parentItem()); - hasFiltered.clear(); - if (!sendFilteredPointerEvent(pointerEvent, handler->parentItem())) - handler->handlePointerEvent(pointerEvent); - if (mouseIsReleased) - point->setGrabberPointerHandler(nullptr, true); - deliverToPassiveGrabbers(point->passiveGrabbers(), pointerEvent); - } else { - bool delivered = false; - if (pointerEvent->isPressEvent()) { - // send initial press - delivered = deliverPressOrReleaseEvent(pointerEvent); - } else if (pointerEvent->device()->type() == QInputDevice::DeviceType::Mouse) { - // if this is an update or release from an actual mouse, - // and the point wasn't grabbed, deliver only to PointerHandlers: - // passive grabbers first, then the rest - deliverToPassiveGrabbers(point->passiveGrabbers(), pointerEvent); - - // If some points weren't grabbed, deliver to non-grabber PointerHandlers in reverse paint order - if (!pointerEvent->allPointsGrabbed() && pointerEvent->buttons()) { - QVector<QQuickItem *> targetItems = pointerTargets(contentItem, point, false, false); - for (QQuickItem *item : targetItems) { - QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - if (!itemPrivate->extra.isAllocated() || itemPrivate->extra->pointerHandlers.isEmpty()) - continue; - pointerEvent->localize(item); - hasFiltered.clear(); - if (!sendFilteredPointerEvent(pointerEvent, item)) { - if (itemPrivate->handlePointerEvent(pointerEvent, true)) // avoid re-delivering to grabbers - delivered = true; - } - if (point->exclusiveGrabber()) - break; - } - } - } - - if (!delivered) - // make sure not to accept unhandled events - pointerEvent->setAccepted(false); - } -} - bool QQuickWindowPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, ulong timestamp, @@ -2291,14 +2142,13 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce } if (itemPrivate->hasPointerHandlers()) { - const auto dev = QPointingDevice::primaryPointingDevice(); - QQuickPointerEvent *pointerEvent = pointerEventInstance(dev, QEvent::MouseMove); - pointerEvent->point(0)->reset(QEventPoint::State::Updated, scenePos, dev->systemId(), timestamp, QVector2D()); - pointerEvent->point(0)->setAccepted(true); - pointerEvent->localize(item); + const QPointF localPos = item->mapFromScene(scenePos); + QMouseEvent hoverEvent(QEvent::MouseMove, localPos, scenePos, q->mapToGlobal(scenePos), Qt::NoButton, Qt::NoButton, modifiers); + hoverEvent.setTimestamp(timestamp); + hoverEvent.setAccepted(true); for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) - hh->handlePointerEvent(pointerEvent); + hh->handlePointerEvent(&hoverEvent); } if (itemPrivate->hoverEnabled) { @@ -2355,49 +2205,26 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce // Simple delivery of non-mouse, non-touch Pointer Events: visit the items and handlers // in the usual reverse-paint-order until propagation is stopped -bool QQuickWindowPrivate::deliverSinglePointEventUntilAccepted(QQuickPointerEvent *event) +bool QQuickWindowPrivate::deliverSinglePointEventUntilAccepted(QPointerEvent *event) { - Q_ASSERT(event->pointCount() == 1); - QQuickEventPoint *point = event->point(0); - QVector<QQuickItem *> targetItems = pointerTargets(contentItem, point, false, false); + Q_ASSERT(event->points().count() == 1); + QEventPoint &point = event->point(0); + QVector<QQuickItem *> targetItems = pointerTargets(contentItem, event, point, false, false); + point.setAccepted(false); for (QQuickItem *item : targetItems) { QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - event->localize(item); + localizePointerEvent(event, item); // Let Pointer Handlers have the first shot itemPrivate->handlePointerEvent(event); - if (point->isAccepted()) + if (point.isAccepted()) + return true; + event->accept(); + QCoreApplication::sendEvent(item, event); + if (event->isAccepted()) { + qCDebug(lcWheelTarget) << event << "->" << item; return true; - QPointF g = item->window()->mapToGlobal(point->scenePosition().toPoint()); -#if QT_CONFIG(wheelevent) - // Let the Item have a chance to handle it - if (QQuickPointerScrollEvent *pse = event->asPointerScrollEvent()) { - QWheelEvent wheel(point->position(), g, pse->pixelDelta().toPoint(), pse->angleDelta().toPoint(), - pse->buttons(), pse->modifiers(), pse->phase(), - pse->isInverted(), pse->synthSource()); - wheel.setTimestamp(pse->timestamp()); - wheel.accept(); - QCoreApplication::sendEvent(item, &wheel); - if (wheel.isAccepted()) { - qCDebug(lcWheelTarget) << &wheel << "->" << item; - event->setAccepted(true); - return true; - } - } -#endif -#if QT_CONFIG(gestures) - if (QQuickPointerNativeGestureEvent *pnge = event->asPointerNativeGestureEvent()) { - QNativeGestureEvent nge(pnge->type(), pnge->device(), point->position(), point->scenePosition(), g, - pnge->value(), 0L, 0L); // TODO can't copy things I can't access - nge.accept(); - QCoreApplication::sendEvent(item, &nge); - if (nge.isAccepted()) { - qCDebug(lcGestureTarget) << &nge << "->" << item; - event->setAccepted(true); - return true; - } } -#endif // gestures } return false; // it wasn't handled @@ -2411,14 +2238,14 @@ void QQuickWindow::wheelEvent(QWheelEvent *event) Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel, event->angleDelta().x(), event->angleDelta().y()); - qCDebug(DBG_MOUSE) << "QQuickWindow::wheelEvent()" << event->pixelDelta() << event->angleDelta() << event->phase(); + qCDebug(DBG_MOUSE) << event; //if the actual wheel event was accepted, accept the compatibility wheel event and return early if (d->lastWheelEventAccepted && event->angleDelta().isNull() && event->phase() == Qt::ScrollUpdate) return; event->ignore(); - d->deliverPointerEvent(d->pointerEventInstance(event)); + d->deliverSinglePointEventUntilAccepted(event); d->lastWheelEventAccepted = event->isAccepted(); } #endif // wheelevent @@ -2430,37 +2257,123 @@ void QQuickWindow::tabletEvent(QTabletEvent *event) Q_D(QQuickWindow); qCDebug(lcTablet) << event; // TODO Qt 6: make sure TabletEnterProximity and TabletLeaveProximity are delivered here - d->deliverPointerEvent(d->pointerEventInstance(event)); + d->deliverPointerEvent(event); } #endif // tabletevent bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event) { qCDebug(DBG_TOUCH) << event; - Q_Q(QQuickWindow); - if (QQuickItem *grabber = q->mouseGrabberItem()) - sendUngrabEvent(grabber, true); - cancelTouchMouseSynthesis(); + if (isDeliveringTouchAsMouse()) { + if (QQuickItem *grabber = qmlobject_cast<QQuickItem *>(event->exclusiveGrabber(touchMouseId))) + sendUngrabEvent(grabber, true); + } - // A TouchCancel event will typically not contain any points. + // An incoming TouchCancel event will typically not contain any points, + // but sendTouchCancelEvent() adds the points that have grabbers to the event. // Deliver it to all items and handlers that have active touches. - QQuickPointerEvent *pointerEvent = pointerEventInstance(event->pointingDevice()); - for (int i = 0; i < pointerEvent->pointCount(); ++i) - pointerEvent->point(i)->cancelExclusiveGrabImpl(event); + const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(event->pointingDevice()))-> + sendTouchCancelEvent(event); - // The next touch event can only be a TouchBegin, so clean up. - pointerEvent->clearGrabbers(); return true; } void QQuickWindowPrivate::deliverDelayedTouchEvent() { // Deliver and delete delayedTouch. - // Set delayedTouch to 0 before delivery to avoid redelivery in case of + // Set delayedTouch to nullptr before delivery to avoid redelivery in case of // event loop recursions (e.g if it the touch starts a dnd session). QScopedPointer<QTouchEvent> e(delayedTouch.take()); - deliverPointerEvent(pointerEventInstance(e.data())); + qCDebug(lcTouchCmprs) << "delivering" << e.data(); + deliverPointerEvent(e.data()); +} + +bool QQuickWindowPrivate::allUpdatedPointsAccepted(const QPointerEvent *ev) +{ + for (auto &point : ev->points()) { + if (point.state() != QEventPoint::State::Pressed && !point.isAccepted()) + return false; + } + return true; +} + +/*! \internal + Localize \a ev for delivery to \a dest. + + Unlike QMutableTouchEvent::localized(), this modifies the QEventPoint + instances in \a ev, which is more efficient than making a copy. +*/ +void QQuickWindowPrivate::localizePointerEvent(QPointerEvent *ev, const QQuickItem *dest) +{ + for (int i = 0; i < ev->pointCount(); ++i) { + auto &point = QMutableEventPoint::from(ev->point(i)); + QMutableEventPoint::from(point).setPosition(dest->mapFromScene(point.scenePosition())); + } +} + +QList<QObject *> QQuickWindowPrivate::exclusiveGrabbers(QPointerEvent *ev) +{ + QList<QObject *> result; + for (const QEventPoint &point : ev->points()) { + if (QObject *grabber = ev->exclusiveGrabber(point)) { + if (!result.contains(grabber)) + result << grabber; + } + } + return result; +} + +bool QQuickWindowPrivate::isMouseEvent(const QPointerEvent *ev) +{ + switch (ev->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + return true; + default: + return false; + } +} + +bool QQuickWindowPrivate::isTouchEvent(const QPointerEvent *ev) +{ + switch (ev->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + case QEvent::TouchCancel: + return true; + default: + return false; + } +} + +bool QQuickWindowPrivate::isTabletEvent(const QPointerEvent *ev) +{ + switch (ev->type()) { + case QEvent::TabletPress: + case QEvent::TabletMove: + case QEvent::TabletRelease: + case QEvent::TabletEnterProximity: + case QEvent::TabletLeaveProximity: + return true; + default: + return false; + } +} + +/*! \internal + Add the given \a point. +*/ +void QMutableTouchEvent::addPoint(const QEventPoint &point) +{ + m_points.append(point); + auto &added = m_points.last(); + if (!added.device()) + QMutableEventPoint::from(added).setDevice(pointingDevice()); + m_touchPointStates |= point.state(); } bool QQuickWindowPrivate::compressTouchEvent(QTouchEvent *event) @@ -2468,13 +2381,14 @@ bool QQuickWindowPrivate::compressTouchEvent(QTouchEvent *event) Q_Q(QQuickWindow); QEventPoint::States states = event->touchPointStates(); if (states.testFlag(QEventPoint::State::Pressed) || states.testFlag(QEventPoint::State::Released)) { - // we can only compress something that isn't a press or release + // we can only compress an event that doesn't include any pressed or released points return false; } if (!delayedTouch) { delayedTouch.reset(new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), event->points())); delayedTouch->setTimestamp(event->timestamp()); + qCDebug(lcTouchCmprs) << "delayed" << delayedTouch.data(); if (renderControl) QQuickRenderControlPrivate::get(renderControl)->maybeUpdate(); else if (windowManager) @@ -2510,6 +2424,7 @@ bool QQuickWindowPrivate::compressTouchEvent(QTouchEvent *event) // TODO optimize, or move event compression elsewhere delayedTouch.reset(new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), tpts)); delayedTouch->setTimestamp(event->timestamp()); + qCDebug(lcTouchCmprs) << "coalesced" << delayedTouch.data(); return true; } } @@ -2529,6 +2444,7 @@ bool QQuickWindowPrivate::compressTouchEvent(QTouchEvent *event) void QQuickWindowPrivate::handleTouchEvent(QTouchEvent *event) { translateTouchEvent(event); + // TODO remove: touch and mouse should be independent until we come to touch->mouse synth if (event->pointCount()) { auto &point = event->point(0); if (point.state() == QEventPoint::State::Released) { @@ -2543,14 +2459,16 @@ void QQuickWindowPrivate::handleTouchEvent(QTouchEvent *event) static bool qquickwindow_no_touch_compression = qEnvironmentVariableIsSet("QML_NO_TOUCH_COMPRESSION"); if (qquickwindow_no_touch_compression || pointerEventRecursionGuard) { - deliverPointerEvent(pointerEventInstance(event)); + deliverPointerEvent(event); return; } if (!compressTouchEvent(event)) { - if (delayedTouch) + if (delayedTouch) { deliverDelayedTouchEvent(); - deliverPointerEvent(pointerEventInstance(event)); + qCDebug(lcTouchCmprs) << "resuming delivery" << event; + } + deliverPointerEvent(event); } } @@ -2591,12 +2509,12 @@ void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event) case QEvent::MouseButtonPress: Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, event->button(), event->buttons()); - deliverPointerEvent(pointerEventInstance(event)); + deliverPointerEvent(event); break; case QEvent::MouseButtonRelease: Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, event->button(), event->buttons()); - deliverPointerEvent(pointerEventInstance(event)); + deliverPointerEvent(event); #if QT_CONFIG(cursor) updateCursor(event->scenePosition()); #endif @@ -2605,7 +2523,7 @@ void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event) Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick, event->button(), event->buttons()); if (allowDoubleClick) - deliverPointerEvent(pointerEventInstance(event)); + deliverPointerEvent(event); break; case QEvent::MouseMove: { Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove, @@ -2616,8 +2534,7 @@ void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event) #if QT_CONFIG(cursor) updateCursor(event->scenePosition()); #endif - auto pointerEvent = pointerEventInstance(event->pointingDevice()); - if (!pointerEvent->pointCount() || !pointerEvent->point(0)->exclusiveGrabber()) { + if (!event->points().count() || !event->exclusiveGrabber(event->point(0))) { QPointF last = lastMousePosition.isNull() ? event->scenePosition() : lastMousePosition; lastMousePosition = event->scenePosition(); @@ -2629,7 +2546,7 @@ void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event) } event->setAccepted(accepted); } - deliverPointerEvent(pointerEventInstance(event)); + deliverPointerEvent(event); break; } default: @@ -2660,6 +2577,7 @@ void QQuickWindowPrivate::flushFrameSynchronousEvents() // For instance, during animation (including the case of a ListView // whose delegates contain MouseAreas), a MouseArea needs to know // whether it has moved into a position where it is now under the cursor. + // TODO do this for each known mouse device or come up with a different strategy if (!q->mouseGrabberItem() && !lastMousePosition.isNull() && dirtyItemList) { bool accepted = false; bool delivered = deliverHoverEvent(contentItem, lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), 0, accepted); @@ -2669,136 +2587,71 @@ void QQuickWindowPrivate::flushFrameSynchronousEvents() #endif } -QQuickPointerEvent *QQuickWindowPrivate::queryPointerEventInstance(const QPointingDevice *device, QEvent::Type eventType) const +void QQuickWindowPrivate::onGrabChanged(QObject *grabber, QPointingDevice::GrabTransition transition, + const QPointerEvent *event, const QEventPoint &point) { - // Search for a matching reusable event object. - for (QQuickPointerEvent *e : pointerEventInstances) { - // If device can generate native gestures (e.g. a trackpad), there might be multiple QQuickPointerEvents: - // QQuickPointerNativeGestureEvent, QQuickPointerScrollEvent, and QQuickPointerTouchEvent. - // Use eventType to disambiguate. -#if QT_CONFIG(gestures) - if ((eventType == QEvent::NativeGesture) != bool(e->asPointerNativeGestureEvent())) - continue; -#endif - if ((eventType == QEvent::Wheel) != bool(e->asPointerScrollEvent())) - continue; - // Otherwise we assume there's only one event type per device. - // More disambiguation tests might need to be added above if that changes later. - if (e->device() == device) - return e; - } - return nullptr; -} - -QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(const QPointingDevice *device, QEvent::Type eventType) const -{ - QQuickPointerEvent *ev = queryPointerEventInstance(device, eventType); - if (ev) - return ev; - QQuickWindow *q = const_cast<QQuickWindow*>(q_func()); - switch (device->type()) { - case QInputDevice::DeviceType::Mouse: - // QWindowSystemInterface::handleMouseEvent() does not take a device parameter: - // we assume all mouse events come from one mouse (the "core pointer"). - // So when the event is a mouse event, device == QPointingDevice::primaryPointingDevice() - if (eventType == QEvent::Wheel) - ev = new QQuickPointerScrollEvent(q, device); - else - ev = new QQuickPointerMouseEvent(q, device); + qCDebug(lcPtrGrab) << grabber << transition << event << point; + // event can be null, if the signal was emitted from QPointingDevicePrivate::removeGrabber(grabber) + switch (transition) { + case QPointingDevice::UngrabExclusive: + if (point.device()->type() == QInputDevice::DeviceType::Mouse || isDeliveringTouchAsMouse()) + sendUngrabEvent(qobject_cast<QQuickItem *>(grabber), isDeliveringTouchAsMouse()); break; - case QInputDevice::DeviceType::TouchPad: - case QInputDevice::DeviceType::TouchScreen: -#if QT_CONFIG(gestures) - if (eventType == QEvent::NativeGesture) - ev = new QQuickPointerNativeGestureEvent(q, device); - else // assume QEvent::Type is one of TouchBegin/Update/End -#endif - ev = new QQuickPointerTouchEvent(q, device); - break; -#if QT_CONFIG(tabletevent) - case QInputDevice::DeviceType::Stylus: - case QPointingDevice::DeviceType::Airbrush: - case QPointingDevice::DeviceType::Puck: - ev = new QQuickPointerTabletEvent(q, device); - break; -#endif default: break; } - pointerEventInstances << ev; - return ev; } -/*! - \internal - Returns a QQuickPointerEvent instance suitable for wrapping and delivering \a event. - - There is a unique instance per QPointingDevice, which is determined - from \a event's device. -*/ -QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QEvent *event) const +void QQuickWindowPrivate::ensureDeviceConnected(const QPointingDevice *dev) { - const QPointingDevice *dev = nullptr; - switch (event->type()) { - case QEvent::MouseButtonPress: - case QEvent::MouseButtonRelease: - case QEvent::MouseButtonDblClick: - case QEvent::MouseMove: - case QEvent::Wheel: - case QEvent::TouchBegin: - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - case QEvent::TouchCancel: -#if QT_CONFIG(tabletevent) - case QEvent::TabletPress: - case QEvent::TabletMove: - case QEvent::TabletRelease: - case QEvent::TabletEnterProximity: - case QEvent::TabletLeaveProximity: -#endif -#if QT_CONFIG(gestures) - case QEvent::NativeGesture: -#endif - dev = static_cast<QPointerEvent *>(event)->pointingDevice(); - break; - default: - break; - } - - Q_ASSERT(dev); - return pointerEventInstance(dev, event->type())->reset(event); + if (knownPointingDevices.contains(dev)) + return; + knownPointingDevices.append(dev); + connect(dev, &QPointingDevice::grabChanged, this, &QQuickWindowPrivate::onGrabChanged); } -void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event) +void QQuickWindowPrivate::deliverPointerEvent(QPointerEvent *event) { - Q_Q(QQuickWindow); // If users spin the eventloop as a result of event delivery, we disable // event compression and send events directly. This is because we consider // the usecase a bit evil, but we at least don't want to lose events. ++pointerEventRecursionGuard; + eventsInDelivery.push(event); skipDelivery.clear(); - if (event->asPointerMouseEvent()) { - deliverMouseEvent(event->asPointerMouseEvent()); - // failsafe: never allow any kind of grab to persist after release - if (event->isReleaseEvent() && event->buttons() == Qt::NoButton) { - QQuickItem *oldGrabber = q->mouseGrabberItem(); - event->clearGrabbers(); - sendUngrabEvent(oldGrabber, false); + QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->pointingDevice()).clear(); + qCDebug(lcPtr) << "delivering" << event; + for (int i = 0; i < event->pointCount(); ++i) + event->point(i).setAccepted(false); + + if (event->isBeginEvent()) { + ensureDeviceConnected(event->pointingDevice()); + if (!deliverPressOrReleaseEvent(event)) + event->setAccepted(false); + } + if (!allUpdatedPointsAccepted(event)) + deliverUpdatedPoints(event); + if (event->isEndEvent()) + deliverPressOrReleaseEvent(event, true); + + // failsafe: never allow any kind of grab to persist after release + if (event->isEndEvent()) { + if (isTouchEvent(event)) { + for (int i = 0; i < event->pointCount(); ++i) { + auto &point = event->point(i); + event->setExclusiveGrabber(point, nullptr); + event->clearPassiveGrabbers(point); + } + // never allow touch->mouse synthesis to persist either + cancelTouchMouseSynthesis(); + } else if (static_cast<QSinglePointEvent *>(event)->buttons() == Qt::NoButton) { + auto &firstPt = event->point(0); + event->setExclusiveGrabber(firstPt, nullptr); + event->clearPassiveGrabbers(firstPt); } - } else if (event->asPointerTouchEvent()) { - deliverTouchEvent(event->asPointerTouchEvent()); - } else { - deliverSinglePointEventUntilAccepted(event); - // If any handler got interested in the tablet event, we don't want to receive a synth-mouse event from QtGui - // TODO Qt 6: QTabletEvent will be accepted by default, like other events - if (event->asPointerTabletEvent() && - (!event->point(0)->passiveGrabbers().isEmpty() || event->point(0)->exclusiveGrabber())) - event->setAccepted(true); } - event->reset(nullptr); - + eventsInDelivery.pop(); --pointerEventRecursionGuard; } @@ -2807,11 +2660,12 @@ void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event) // If checkMouseButtons is true, it means we are finding targets for a mouse event, so no item for which acceptedMouseButtons() is NoButton will be added. // If checkAcceptsTouch is true, it means we are finding targets for a touch event, so either acceptTouchEvents() must return true OR // it must accept a synth. mouse event, thus if acceptTouchEvents() returns false but acceptedMouseButtons() is true, gets added; if not, it doesn't. -QVector<QQuickItem *> QQuickWindowPrivate::pointerTargets(QQuickItem *item, QQuickEventPoint *point, bool checkMouseButtons, bool checkAcceptsTouch) const +QVector<QQuickItem *> QQuickWindowPrivate::pointerTargets(QQuickItem *item, const QPointerEvent *event, const QEventPoint &point, + bool checkMouseButtons, bool checkAcceptsTouch) const { QVector<QQuickItem *> targets; auto itemPrivate = QQuickItemPrivate::get(item); - QPointF itemPos = item->mapFromScene(point->scenePosition()); + QPointF itemPos = item->mapFromScene(point.scenePosition()); bool relevant = item->contains(itemPos); // if the item clips, we can potentially return early if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) { @@ -2821,7 +2675,7 @@ QVector<QQuickItem *> QQuickWindowPrivate::pointerTargets(QQuickItem *item, QQui if (itemPrivate->hasPointerHandlers()) { if (!relevant) - if (itemPrivate->anyPointerHandlerWants(point)) + if (itemPrivate->anyPointerHandlerWants(event, point)) relevant = true; } else { if (relevant && checkMouseButtons && item->acceptedMouseButtons() == Qt::NoButton) @@ -2844,7 +2698,7 @@ QVector<QQuickItem *> QQuickWindowPrivate::pointerTargets(QQuickItem *item, QQui continue; if (child != item) - targets << pointerTargets(child, point, checkMouseButtons, checkAcceptsTouch); + targets << pointerTargets(child, event, point, checkMouseButtons, checkAcceptsTouch); else targets << child; } @@ -2874,45 +2728,14 @@ QVector<QQuickItem *> QQuickWindowPrivate::mergePointerTargets(const QVector<QQu return targets; } -void QQuickWindowPrivate::deliverTouchEvent(QQuickPointerTouchEvent *event) -{ - qCDebug(DBG_TOUCH) << " - delivering" << event->asTouchEvent(); - - if (event->isPressEvent()) - deliverPressOrReleaseEvent(event); - if (!event->allUpdatedPointsAccepted()) - deliverUpdatedTouchPoints(event); - if (event->isReleaseEvent()) - deliverPressOrReleaseEvent(event, true); - - // Remove released points from itemForTouchPointId - bool allReleased = true; - int pointCount = event->pointCount(); - for (int i = 0; i < pointCount; ++i) { - QQuickEventPoint *point = event->point(i); - if (point->state() == QQuickEventPoint::Released) { - int id = point->pointId(); - qCDebug(DBG_TOUCH_TARGET) << "TP" << Qt::hex << id << "released"; - point->setGrabberItem(nullptr); - if (id == touchMouseId) - cancelTouchMouseSynthesis(); - } else { - allReleased = false; - } - } - - if (allReleased) { - if (Q_UNLIKELY(!event->exclusiveGrabbers().isEmpty())) - qWarning() << "No release received for some grabbers" << event->exclusiveGrabbers(); - event->clearGrabbers(); - } -} - -// Deliver touch points to existing grabbers -void QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *event) +/*! \internal + Deliver updated points to existing grabbers. +*/ +void QQuickWindowPrivate::deliverUpdatedPoints(QPointerEvent *event) { bool done = false; - const auto grabbers = event->exclusiveGrabbers(); + const auto grabbers = exclusiveGrabbers(event); + hasFiltered.clear(); for (auto grabber : grabbers) { // The grabber is guaranteed to be either an item or a handler. QQuickItem *receiver = qmlobject_cast<QQuickItem *>(grabber); @@ -2923,22 +2746,19 @@ void QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *eve hasFiltered.clear(); if (sendFilteredPointerEvent(event, receiver)) done = true; - event->localize(receiver); + localizePointerEvent(event, receiver); handler->handlePointerEvent(event); } if (done) break; // If the grabber is an item or the grabbing handler didn't handle it, // then deliver the event to the item (which may have multiple handlers). - deliverMatchingPointsToItem(receiver, event); + deliverMatchingPointsToItem(receiver, true, event); } // Deliver to each eventpoint's passive grabbers (but don't visit any handler more than once) - int pointCount = event->pointCount(); - for (int i = 0; i < pointCount; ++i) { - QQuickEventPoint *point = event->point(i); - deliverToPassiveGrabbers(point->passiveGrabbers(), event); - } + for (auto &point : event->points()) + deliverToPassiveGrabbers(event->passiveGrabbers(point), event); if (done) return; @@ -2946,11 +2766,10 @@ void QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *eve // If some points weren't grabbed, deliver only to non-grabber PointerHandlers in reverse paint order if (!event->allPointsGrabbed()) { QVector<QQuickItem *> targetItems; - for (int i = 0; i < pointCount; ++i) { - QQuickEventPoint *point = event->point(i); - if (point->state() == QQuickEventPoint::Pressed) + for (auto &point : event->points()) { + if (point.state() == QEventPoint::Pressed) continue; // presses were delivered earlier; not the responsibility of deliverUpdatedTouchPoints - QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, point, false, false); + QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, event, point, false, false); if (targetItems.count()) { targetItems = mergePointerTargets(targetItems, targetItemsForPoint); } else { @@ -2961,7 +2780,7 @@ void QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *eve if (grabbers.contains(item)) continue; QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - event->localize(item); + localizePointerEvent(event, item); itemPrivate->handlePointerEvent(event, true); // avoid re-delivering to grabbers if (event->allPointsGrabbed()) break; @@ -2970,13 +2789,12 @@ void QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *eve } // Deliver an event containing newly pressed or released touch points -bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event, bool handlersOnly) +bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QPointerEvent *event, bool handlersOnly) { - int pointCount = event->pointCount(); QVector<QQuickItem *> targetItems; - bool isTouchEvent = (event->asPointerTouchEvent() != nullptr); - if (isTouchEvent && event->isPressEvent() && isDeliveringTouchAsMouse()) { - if (const QQuickEventPoint *point = pointerEventInstance(touchMouseDevice)->pointById(touchMouseId)) { + const bool isTouch = isTouchEvent(event); + if (isTouch && event->isBeginEvent() && isDeliveringTouchAsMouse()) { + if (auto point = const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(touchMouseDevice))->queryPointById(touchMouseId)) { // When a second point is pressed, if the first point's existing // grabber was a pointer handler while a filtering parent is filtering // the same first point _as mouse_: we're starting over with delivery, @@ -2986,20 +2804,17 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event, // synth-mouse and perhaps grab it. Ideally we would always do this // when a new touchpoint is pressed, but this compromise fixes // QTBUG-70998 and avoids breaking tst_FlickableInterop::touchDragSliderAndFlickable - if (point->grabberPointerHandler()) + if (qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point->eventPoint))) cancelTouchMouseSynthesis(); } else { qCWarning(DBG_TOUCH_TARGET) << "during delivery of touch press, synth-mouse ID" << Qt::hex << touchMouseId << "is missing from" << event; } } - for (int i = 0; i < pointCount; ++i) { - auto point = event->point(i); - if (point->state() == QQuickEventPoint::Pressed && !event->isDoubleClickEvent()) - point->clearPassiveGrabbers(); - point->setAccepted(false); // because otherwise touchEventForItem will ignore it - if (point->grabberPointerHandler() && point->state() == QQuickEventPoint::Released) - point->setGrabberPointerHandler(nullptr, true); - QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, point, !isTouchEvent, isTouchEvent); + for (int i = 0; i < event->pointCount(); ++i) { + auto &point = event->point(i); + if (point.state() == QEventPoint::Pressed && event->type() != QEvent::MouseButtonDblClick) + event->clearPassiveGrabbers(point); + QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, event, point, !isTouch, isTouch); if (targetItems.count()) { targetItems = mergePointerTargets(targetItems, targetItemsForPoint); } else { @@ -3008,15 +2823,11 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event, } for (QQuickItem *item : targetItems) { - if (!event->m_event) { - qWarning("event went missing during delivery! (nested sendEvent() is not allowed)"); - break; - } hasFiltered.clear(); if (!handlersOnly && sendFilteredPointerEvent(event, item)) { if (event->isAccepted()) { for (int i = 0; i < event->pointCount(); ++i) - event->point(i)->setAccepted(); + event->point(i).setAccepted(); return true; } skipDelivery.append(item); @@ -3026,11 +2837,7 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event, // nor to any item which already had a chance to filter. if (skipDelivery.contains(item)) continue; - if (!event->m_event) { - qWarning("event went missing during delivery! (nested sendEvent() is not allowed)"); - break; - } - deliverMatchingPointsToItem(item, event, handlersOnly); + deliverMatchingPointsToItem(item, false, event, handlersOnly); if (event->allPointsAccepted()) handlersOnly = true; } @@ -3038,77 +2845,78 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event, return event->allPointsAccepted(); } -void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPointerEvent *pointerEvent, bool handlersOnly) +void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, bool isGrabber, QPointerEvent *pointerEvent, bool handlersOnly) { - Q_Q(QQuickWindow); QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - pointerEvent->localize(item); + localizePointerEvent(pointerEvent, item); + bool isMouse = isMouseEvent(pointerEvent); // Let the Item's handlers (if any) have the event first. // However, double click should never be delivered to handlers. - if (!pointerEvent->isDoubleClickEvent()) { + if (pointerEvent->type() != QEvent::MouseButtonDblClick) { bool wasAccepted = pointerEvent->allPointsAccepted(); itemPrivate->handlePointerEvent(pointerEvent); - allowDoubleClick = wasAccepted || !(pointerEvent->asPointerMouseEvent() && pointerEvent->isPressEvent() && pointerEvent->allPointsAccepted()); + allowDoubleClick = wasAccepted || !(isMouse && pointerEvent->isBeginEvent() && pointerEvent->allPointsAccepted()); } if (handlersOnly) return; // If all points are released and the item is not the grabber, it doesn't get the event. // But if at least one point is still pressed, we might be in a potential gesture-takeover scenario. - if (pointerEvent->isReleaseEvent() && !pointerEvent->isUpdateEvent() - && !pointerEvent->exclusiveGrabbers().contains(item)) + if (pointerEvent->isEndEvent() && !pointerEvent->isUpdateEvent() + && !exclusiveGrabbers(pointerEvent).contains(item)) return; // TODO: unite this mouse point delivery with the synthetic mouse event below - auto event = pointerEvent->asPointerMouseEvent(); - if (event && item->acceptedMouseButtons() & event->button()) { - auto point = event->point(0); - // The only reason to already have a mouse grabber here is - // synthetic events - flickable sends one when setPressDelay is used. - auto oldMouseGrabber = q->mouseGrabberItem(); - QPointF localPos = item->mapFromScene(point->scenePosition()); - QMouseEvent *me = event->asMouseEvent(localPos); - me->accept(); - QCoreApplication::sendEvent(item, me); - if (me->isAccepted()) { - auto mouseGrabber = q->mouseGrabberItem(); - if (mouseGrabber && mouseGrabber != item && mouseGrabber != oldMouseGrabber) { - item->mouseUngrabEvent(); - } else if (item->isEnabled() && item->isVisible()) { - item->grabMouse(); - } - point->setAccepted(true); + if (isMouse && (isGrabber || (item->acceptedMouseButtons() & static_cast<QSinglePointEvent *>(pointerEvent)->button()))) { + // The only reason to already have a mouse grabber here is + // synthetic events - flickable sends one when setPressDelay is used. + auto oldMouseGrabber = pointerEvent->exclusiveGrabber(pointerEvent->point(0)); + pointerEvent->accept(); + if (isGrabber && sendFilteredPointerEvent(pointerEvent, item)) + return; + localizePointerEvent(pointerEvent, item); + QCoreApplication::sendEvent(item, pointerEvent); + if (pointerEvent->isAccepted()) { + auto &point = pointerEvent->point(0); + auto mouseGrabber = pointerEvent->exclusiveGrabber(point); + if (mouseGrabber && mouseGrabber != item && mouseGrabber != oldMouseGrabber) { + // we don't need item->mouseUngrabEvent() because QQuickWindowPrivate::onGrabChanged does it + } else if (item->isEnabled() && item->isVisible()) { + pointerEvent->setExclusiveGrabber(point, item); } + point.setAccepted(true); + } return; } - QQuickPointerTouchEvent *ptEvent = pointerEvent->asPointerTouchEvent(); - if (!ptEvent) + if (!isTouchEvent(pointerEvent)) return; - QScopedPointer<QTouchEvent> touchEvent(ptEvent->touchEventForItem(item)); - if (!touchEvent) - return; - - qCDebug(DBG_TOUCH) << "considering delivering " << touchEvent.data() << " to " << item; bool eventAccepted = false; + QTouchEvent touchEvent = QQuickItemPrivate::get(item)->localizedTouchEvent(static_cast<QTouchEvent *>(pointerEvent), false); + if (touchEvent.type() == QEvent::None) + return; // no points inside this item - // If any parent filters the event, we're done. - hasFiltered.clear(); - if (sendFilteredPointerEvent(pointerEvent, item)) - return; + if (item->acceptTouchEvents()) { + qCDebug(DBG_TOUCH) << "considering delivering" << &touchEvent << " to " << item; - // Deliver the touch event to the given item - qCDebug(DBG_TOUCH) << " - actually delivering " << touchEvent.data() << " to " << item; - QCoreApplication::sendEvent(item, touchEvent.data()); - eventAccepted = touchEvent->isAccepted(); + // If any parent filters the event, we're done. + hasFiltered.clear(); + if (sendFilteredPointerEvent(pointerEvent, item)) + return; + + // Deliver the touch event to the given item + qCDebug(DBG_TOUCH) << "actually delivering" << &touchEvent << " to " << item; + QCoreApplication::sendEvent(item, &touchEvent); + eventAccepted = touchEvent.isAccepted(); + } // If the touch event wasn't accepted, synthesize a mouse event and see if the item wants it. if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) { if (!eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) { // send mouse event - if (deliverTouchAsMouse(item, ptEvent)) + if (deliverTouchAsMouse(item, &touchEvent)) eventAccepted = true; } } @@ -3116,24 +2924,21 @@ void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo if (eventAccepted) { // If the touch was accepted (regardless by whom or in what form), // update accepted new points. - bool isPressOrRelease = pointerEvent->isPressEvent() || pointerEvent->isReleaseEvent(); - for (const auto &point: touchEvent->points()) { - if (auto pointerEventPoint = ptEvent->pointById(point.id())) { - pointerEventPoint->setAccepted(); - if (isPressOrRelease) - pointerEventPoint->setGrabberItem(item); - } + bool isPressOrRelease = pointerEvent->isBeginEvent() || pointerEvent->isEndEvent(); + for (int i = 0; i < touchEvent.pointCount(); ++i) { + auto &point = QMutableEventPoint::from(touchEvent.point(i)); + point.setAccepted(); + if (isPressOrRelease) + pointerEvent->setExclusiveGrabber(point, item); } } else { // But if the event was not accepted then we know this item // will not be interested in further updates for those touchpoint IDs either. - for (const auto &point: touchEvent->points()) { + for (const auto &point: touchEvent.points()) { if (point.state() == QEventPoint::State::Pressed) { - if (auto *tp = ptEvent->pointById(point.id())) { - if (tp->exclusiveGrabber() == item) { - qCDebug(DBG_TOUCH_TARGET) << "TP" << Qt::hex << point.id() << "disassociated"; - tp->setGrabberItem(nullptr); - } + if (pointerEvent->exclusiveGrabber(point) == item) { + qCDebug(DBG_TOUCH_TARGET) << "TP" << Qt::hex << point.id() << "disassociated"; + pointerEvent->setExclusiveGrabber(point, nullptr); } } } @@ -3342,11 +3147,7 @@ QPair<QQuickItem*, QQuickPointerHandler*> QQuickWindowPrivate::findCursorItemAnd } if (itemPrivate->hasCursorHandler) { if (auto handler = itemPrivate->effectiveCursorHandler()) { - QQuickPointerEvent *pointerEvent = pointerEventInstance(QPointingDevice::primaryPointingDevice(), QEvent::MouseMove); - pointerEvent->point(0)->reset(QEventPoint::State::Updated, scenePos, 0, 0); - pointerEvent->point(0)->setAccepted(true); - pointerEvent->localize(item); - if (handler->parentContains(pointerEvent->point(0))) + if (handler->parentContains(scenePos)) return {item, handler}; } } @@ -3361,12 +3162,12 @@ QPair<QQuickItem*, QQuickPointerHandler*> QQuickWindowPrivate::findCursorItemAnd } #endif -bool QQuickWindowPrivate::sendFilteredPointerEvent(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent) +bool QQuickWindowPrivate::sendFilteredPointerEvent(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent) { return sendFilteredPointerEventImpl(event, receiver, filteringParent ? filteringParent : receiver->parentItem()); } -bool QQuickWindowPrivate::sendFilteredPointerEventImpl(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent) +bool QQuickWindowPrivate::sendFilteredPointerEventImpl(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent) { if (!allowChildEventFiltering) return false; @@ -3375,58 +3176,58 @@ bool QQuickWindowPrivate::sendFilteredPointerEventImpl(QQuickPointerEvent *event bool filtered = false; if (filteringParent->filtersChildMouseEvents() && !hasFiltered.contains(filteringParent)) { hasFiltered.append(filteringParent); - if (QQuickPointerMouseEvent *pme = event->asPointerMouseEvent()) { + if (isMouseEvent(event)) { + auto me = static_cast<QMouseEvent *>(event); if (receiver->acceptedMouseButtons()) { - QPointF localPos = receiver->mapFromScene(pme->point(0)->scenePosition()); - QMouseEvent *me = pme->asMouseEvent(localPos); const bool wasAccepted = me->isAccepted(); - me->setAccepted(true); - auto oldMouseGrabber = pme->point(0)->grabberItem(); - if (filteringParent->childMouseEventFilter(receiver, me)) { + Q_ASSERT(event->pointCount()); + localizePointerEvent(event, receiver); + event->setAccepted(true); + auto oldMouseGrabber = event->exclusiveGrabber(event->point(0)); + if (filteringParent->childMouseEventFilter(receiver, const_cast<QMouseEvent *>(me))) { qCDebug(DBG_MOUSE) << "mouse event intercepted by childMouseEventFilter of " << filteringParent; skipDelivery.append(filteringParent); filtered = true; - if (me->isAccepted() && pme->isPressEvent()) { - auto mouseGrabber = pme->point(0)->grabberItem(); + if (me->isAccepted() && me->isBeginEvent()) { + auto &point = event->point(0); + auto mouseGrabber = event->exclusiveGrabber(point); if (mouseGrabber && mouseGrabber != receiver && mouseGrabber != oldMouseGrabber) { receiver->mouseUngrabEvent(); } else { - pme->point(0)->setGrabberItem(receiver); + event->setExclusiveGrabber(point, receiver); } } } else { // Restore accepted state if the event was not filtered. - me->setAccepted(wasAccepted); + const_cast<QMouseEvent *>(me)->setAccepted(wasAccepted); } } - } else if (QQuickPointerTouchEvent *pte = event->asPointerTouchEvent()) { -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + } else if (isTouchEvent(event)) { + auto te = static_cast<QTouchEvent *>(event); bool acceptsTouchEvents = receiver->acceptTouchEvents(); -#else - // In versions prior to Qt 6, we can't trust item->acceptTouchEvents() here, because it defaults to true. - bool acceptsTouchEvents = false; -#endif - auto device = pte->device(); + auto device = te->device(); if (device->type() == QInputDevice::DeviceType::TouchPad && device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation)) { qCDebug(DBG_TOUCH_TARGET) << "skipping filtering of synth-mouse event from" << device; } else if (acceptsTouchEvents || receiver->acceptedMouseButtons()) { // get a touch event customized for delivery to filteringParent - QScopedPointer<QTouchEvent> filteringParentTouchEvent(pte->touchEventForItem(receiver, true)); - if (filteringParentTouchEvent) { - if (filteringParent->childMouseEventFilter(receiver, filteringParentTouchEvent.data())) { + // TODO should not be necessary? because QQuickWindowPrivate::deliverMatchingPointsToItem() does it + QTouchEvent filteringParentTouchEvent = + QQuickItemPrivate::get(receiver)->localizedTouchEvent(te, true); + if (filteringParentTouchEvent.type() != QEvent::None) { + if (filteringParent->childMouseEventFilter(receiver, &filteringParentTouchEvent)) { qCDebug(DBG_TOUCH) << "touch event intercepted by childMouseEventFilter of " << filteringParent; skipDelivery.append(filteringParent); - for (const auto &point: filteringParentTouchEvent->points()) { - QQuickEventPoint *pt = event->pointById(point.id()); - pt->setAccepted(); - pt->setGrabberItem(filteringParent); + for (qsizetype i = 0; i < filteringParentTouchEvent.pointCount(); ++i) { + auto &point = QMutableEventPoint::from(filteringParentTouchEvent.point(i)); + point.setAccepted(); + te->setExclusiveGrabber(point, filteringParent); } return true; - } else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) { + } + else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) { // filteringParent didn't filter the touch event. Give it a chance to filter a synthetic mouse event. - for (auto &tp : filteringParentTouchEvent->points()) { - + for (auto &tp : filteringParentTouchEvent.points()) { QEvent::Type t; switch (tp.state()) { case QEventPoint::State::Pressed: @@ -3447,21 +3248,20 @@ bool QQuickWindowPrivate::sendFilteredPointerEventImpl(QQuickPointerEvent *event if (touchMouseUnset || touchMouseId == tp.id()) { // convert filteringParentTouchEvent (which is already transformed wrt local position, velocity, etc.) // into a synthetic mouse event, and let childMouseEventFilter() have another chance with that - QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, tp, filteringParentTouchEvent.data(), receiver, false)); + QMouseEvent mouseEvent = touchToMouseEvent(t, tp, &filteringParentTouchEvent, receiver); // If a filtering item calls QQuickWindow::mouseGrabberItem(), it should // report the touchpoint's grabber. Whenever we send a synthetic mouse event, // touchMouseId and touchMouseDevice must be set, even if it's only temporarily and isn't grabbed. touchMouseId = tp.id(); - touchMouseDevice = event->device(); - const QPointingDevice *dev = touchMouseDevice; - if (filteringParent->childMouseEventFilter(receiver, mouseEvent.data())) { + touchMouseDevice = event->pointingDevice(); + if (filteringParent->childMouseEventFilter(receiver, &mouseEvent)) { qCDebug(DBG_TOUCH) << "touch event intercepted as synth mouse event by childMouseEventFilter of " << filteringParent; skipDelivery.append(filteringParent); if (t != QEvent::MouseButtonRelease) { qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << Qt::hex << tp.id() << "->" << filteringParent; - pointerEventInstance(dev)->pointById(tp.id())->setGrabberItem(filteringParent); + filteringParentTouchEvent.setExclusiveGrabber(tp, filteringParent); touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set - if (mouseEvent->isAccepted()) + if (mouseEvent.isAccepted()) filteringParent->grabMouse(); } filtered = true; diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 2046fb0462..632cf1b6da 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -64,8 +64,10 @@ #include <QtCore/qmutex.h> #include <QtCore/qwaitcondition.h> #include <QtCore/qrunnable.h> +#include <QtCore/qstack.h> #include <QtGui/private/qevent_p.h> +#include <QtGui/private/qpointingdevice_p.h> #include <QtGui/private/qwindow_p.h> #include <QtGui/qevent.h> #include <QtGui/qstylehints.h> @@ -150,28 +152,33 @@ public: #if QT_CONFIG(quick_draganddrop) QQuickDragGrabber *dragGrabber; #endif - int touchMouseId; + QStack<QPointerEvent *> eventsInDelivery; + + int touchMouseId; // only for obsolete stuff like QQuickItem::grabMouse() + // TODO get rid of these const QPointingDevice *touchMouseDevice; - bool checkIfDoubleTapped(ulong newPressEventTimestamp, QPoint newPressPos); ulong touchMousePressTimestamp; QPoint touchMousePressPos; // in screen coordiantes + bool isDeliveringTouchAsMouse() const { return touchMouseId != -1 && touchMouseDevice; } void cancelTouchMouseSynthesis(); + bool checkIfDoubleTapped(ulong newPressEventTimestamp, QPoint newPressPos); + QPointingDevicePrivate::EventPointData *mousePointData(); + QPointerEvent *eventInDelivery() const; + // Mouse positions are saved in widget coordinates QPointF lastMousePosition; - bool deliverTouchAsMouse(QQuickItem *item, QQuickPointerEvent *pointerEvent); - bool isDeliveringTouchAsMouse() const { return touchMouseId != -1 && touchMouseDevice; } + bool deliverTouchAsMouse(QQuickItem *item, QTouchEvent *pointerEvent); void translateTouchEvent(QTouchEvent *touchEvent); - void grabTouchPoints(QObject *grabber, const QVector<int> &ids); void removeGrabber(QQuickItem *grabber, bool mouse = true, bool touch = true); void sendUngrabEvent(QQuickItem *grabber, bool touch); + void onGrabChanged(QObject *grabber, QPointingDevice::GrabTransition transition, const QPointerEvent *event, const QEventPoint &point); static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = nullptr); - void deliverToPassiveGrabbers(const QVector<QPointer <QQuickPointerHandler> > &passiveGrabbers, QQuickPointerEvent *pointerEvent); - void deliverMouseEvent(QQuickPointerMouseEvent *pointerEvent); + void deliverToPassiveGrabbers(const QVector<QPointer<QObject> > &passiveGrabbers, QPointerEvent *pointerEvent); bool sendFilteredMouseEvent(QEvent *event, QQuickItem *receiver, QQuickItem *filteringParent); - bool sendFilteredPointerEvent(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent = nullptr); - bool sendFilteredPointerEventImpl(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent); - bool deliverSinglePointEventUntilAccepted(QQuickPointerEvent *); + bool sendFilteredPointerEvent(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent = nullptr); + bool sendFilteredPointerEventImpl(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent); + bool deliverSinglePointEventUntilAccepted(QPointerEvent *); // entry point of events to the window void handleTouchEvent(QTouchEvent *); @@ -180,22 +187,25 @@ public: void flushFrameSynchronousEvents(); void deliverDelayedTouchEvent(); - // the device-specific event instances which are reused during event delivery - mutable QVector<QQuickPointerEvent *> pointerEventInstances; - QQuickPointerEvent *queryPointerEventInstance(const QPointingDevice *device, QEvent::Type eventType = QEvent::None) const; - QQuickPointerEvent *pointerEventInstance(const QPointingDevice *device, QEvent::Type eventType = QEvent::None) const; + // utility functions that used to be in QQuickPointerEvent et al. + bool allUpdatedPointsAccepted(const QPointerEvent *ev); + void localizePointerEvent(QPointerEvent *ev, const QQuickItem *dest); + QList<QObject *> exclusiveGrabbers(QPointerEvent *ev); + static bool isMouseEvent(const QPointerEvent *ev); + static bool isTouchEvent(const QPointerEvent *ev); + static bool isTabletEvent(const QPointerEvent *ev); // delivery of pointer events: - QMouseEvent *touchToMouseEvent(QEvent::Type type, const QEventPoint &p, QTouchEvent *event, QQuickItem *item, bool transformNeeded = true); - QQuickPointerEvent *pointerEventInstance(QEvent *ev) const; - void deliverPointerEvent(QQuickPointerEvent *); - void deliverTouchEvent(QQuickPointerTouchEvent *); + QMouseEvent touchToMouseEvent(QEvent::Type type, const QEventPoint &p, QTouchEvent *event, QQuickItem *item); + void ensureDeviceConnected(const QPointingDevice *dev); + void deliverPointerEvent(QPointerEvent *); bool deliverTouchCancelEvent(QTouchEvent *); - bool deliverPressOrReleaseEvent(QQuickPointerEvent *, bool handlersOnly = false); - void deliverUpdatedTouchPoints(QQuickPointerTouchEvent *event); - void deliverMatchingPointsToItem(QQuickItem *item, QQuickPointerEvent *pointerEvent, bool handlersOnly = false); + bool deliverPressOrReleaseEvent(QPointerEvent *, bool handlersOnly = false); + void deliverUpdatedPoints(QPointerEvent *event); + void deliverMatchingPointsToItem(QQuickItem *item, bool isGrabber, QPointerEvent *pointerEvent, bool handlersOnly = false); - QVector<QQuickItem *> pointerTargets(QQuickItem *, QQuickEventPoint *point, bool checkMouseButtons, bool checkAcceptsTouch) const; + QVector<QQuickItem *> pointerTargets(QQuickItem *, const QPointerEvent *event, const QEventPoint &point, + bool checkMouseButtons, bool checkAcceptsTouch) const; QVector<QQuickItem *> mergePointerTargets(const QVector<QQuickItem *> &list1, const QVector<QQuickItem *> &list2) const; // hover delivery @@ -277,6 +287,7 @@ public: QQuickRenderControl *renderControl; QScopedPointer<QQuickAnimatorController> animationController; QScopedPointer<QMutableTouchEvent> delayedTouch; + QList<const QPointingDevice *> knownPointingDevices; int pointerEventRecursionGuard; diff --git a/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp b/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp index 26b6e0540b..44d0e9a27a 100644 --- a/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp +++ b/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp @@ -34,6 +34,7 @@ #include <QtQuick/private/qquickmousearea_p.h> #include <QtQuick/qquickitem.h> #include <QtQuick/qquickview.h> +#include <QtGui/private/qpointingdevice_p.h> #include "../../../shared/util.h" #include "../../shared/viewtestutil.h" @@ -76,7 +77,6 @@ void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaMouse QScopedPointer<QQuickView> windowPtr; createView(windowPtr, "dragTakeOverFromSibling.qml"); QQuickView * window = windowPtr.data(); - auto pointerEvent = QQuickWindowPrivate::get(window)->pointerEventInstance(QPointingDevice::primaryPointingDevice()); QPointer<QQuickPointerHandler> handler = window->rootObject()->findChild<QQuickPointerHandler*>(); QVERIFY(handler); @@ -92,10 +92,12 @@ void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaMouse // DragHandler keeps monitoring, due to its passive grab, // and eventually steals the exclusive grab from MA int dragStoleGrab = 0; + auto devPriv = QPointingDevicePrivate::get(QPointingDevice::primaryPointingDevice()); for (int i = 0; i < 4; ++i) { p1 += QPoint(dragThreshold / 2, 0); QTest::mouseMove(window, p1); - if (!dragStoleGrab && pointerEvent->point(0)->exclusiveGrabber() == handler) + + if (!dragStoleGrab && devPriv->pointById(0)->exclusiveGrabber == handler) dragStoleGrab = i; } if (dragStoleGrab) @@ -124,7 +126,7 @@ void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch QScopedPointer<QQuickView> windowPtr; createView(windowPtr, "dragTakeOverFromSibling.qml"); QQuickView * window = windowPtr.data(); - auto pointerEvent = QQuickWindowPrivate::get(window)->pointerEventInstance(touchDevice); + auto devPriv = QPointingDevicePrivate::get(QPointingDevice::primaryPointingDevice()); QPointer<QQuickPointerHandler> handler = window->rootObject()->findChild<QQuickPointerHandler*>(); QVERIFY(handler); @@ -137,8 +139,8 @@ void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch touch.press(1, p1).commit(); QQuickTouchUtils::flush(window); - QTRY_VERIFY(pointerEvent->point(0)->passiveGrabbers().contains(handler)); - QCOMPARE(pointerEvent->point(0)->grabberItem(), ma); + QTRY_VERIFY(devPriv->pointById(0)->passiveGrabbers.contains(handler.data())); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, ma); QCOMPARE(window->mouseGrabberItem(), ma); QCOMPARE(ma->pressed(), true); @@ -150,7 +152,7 @@ void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch p1 += QPoint(dragThreshold / 2, 0); touch.move(1, p1).commit(); QQuickTouchUtils::flush(window); - if (!dragStoleGrab && pointerEvent->point(0)->exclusiveGrabber() == handler) + if (!dragStoleGrab && devPriv->pointById(0)->exclusiveGrabber == handler) dragStoleGrab = i; } if (dragStoleGrab) diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp index 82e9b4e71f..9a278cd570 100644 --- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp +++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp @@ -35,6 +35,7 @@ #include <QtQuick/private/qquickpinchhandler_p.h> #include <QtQuick/qquickitem.h> #include <QtQuick/qquickview.h> +#include <QtGui/private/qpointingdevice_p.h> #include "../../../shared/util.h" #include "../../shared/viewtestutil.h" @@ -108,9 +109,9 @@ void tst_MptaInterop::touchDrag() QPoint p1 = mpta->mapToScene(QPointF(20, 20)).toPoint(); touch.press(1, p1).commit(); QQuickTouchUtils::flush(window); - auto pointerEvent = QQuickWindowPrivate::get(window)->pointerEventInstance(touchDevice); + auto devPriv = QPointingDevicePrivate::get(touchDevice); QCOMPARE(tp.at(0)->property("pressed").toBool(), true); - QTRY_VERIFY(pointerEvent->point(0)->passiveGrabbers().contains(drag)); + QTRY_VERIFY(devPriv->pointById(0)->passiveGrabbers.contains(drag)); // Start moving // DragHandler keeps monitoring, due to its passive grab, @@ -120,7 +121,7 @@ void tst_MptaInterop::touchDrag() p1 += QPoint(dragThreshold / 2, 0); touch.move(1, p1).commit(); QQuickTouchUtils::flush(window); - if (!dragStoleGrab && pointerEvent->point(0)->exclusiveGrabber() == drag) + if (!dragStoleGrab && devPriv->pointById(0)->exclusiveGrabber == drag) dragStoleGrab = i; } if (dragStoleGrab) @@ -150,7 +151,7 @@ void tst_MptaInterop::touchesThenPinch() QSignalSpy mptaReleasedSpy(mpta, SIGNAL(released(QList<QObject*>))); QSignalSpy mptaCanceledSpy(mpta, SIGNAL(canceled(QList<QObject*>))); QTest::QTouchEventSequence touch = QTest::touchEvent(window, touchDevice); - auto pointerEvent = QQuickWindowPrivate::get(window)->pointerEventInstance(touchDevice); + auto devPriv = QPointingDevicePrivate::get(touchDevice); // Press one touchpoint: // DragHandler gets a passive grab @@ -159,8 +160,8 @@ void tst_MptaInterop::touchesThenPinch() QPoint p1 = mpta->mapToScene(QPointF(20, 20)).toPoint(); touch.press(1, p1).commit(); QQuickTouchUtils::flush(window); - QTRY_COMPARE(pointerEvent->point(0)->exclusiveGrabber(), mpta); - QTRY_COMPARE(pointerEvent->point(0)->passiveGrabbers().first(), drag); + QTRY_COMPARE(devPriv->pointById(0)->exclusiveGrabber, mpta); + QTRY_COMPARE(devPriv->pointById(0)->passiveGrabbers.first(), drag); // Press a second touchpoint: MPTA grabs it QPoint p2 = mpta->mapToScene(QPointF(200, 30)).toPoint(); @@ -179,9 +180,9 @@ void tst_MptaInterop::touchesThenPinch() QCOMPARE(tp.at(2)->property("pressed").toBool(), true); QCOMPARE(mptaPressedSpy.count(), 3); QCOMPARE(mptaCanceledSpy.count(), 0); - QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), mpta); - QCOMPARE(pointerEvent->point(1)->exclusiveGrabber(), mpta); - QCOMPARE(pointerEvent->point(2)->exclusiveGrabber(), mpta); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, mpta); + QCOMPARE(devPriv->pointById(1)->exclusiveGrabber, mpta); + QCOMPARE(devPriv->pointById(2)->exclusiveGrabber, mpta); QVERIFY(!pinch->active()); // Start moving: PinchHandler steals the exclusive grab from MPTA as soon as dragThreshold is exceeded @@ -197,7 +198,7 @@ void tst_MptaInterop::touchesThenPinch() p3 = xform.map(p3); touch.move(1, p1).move(2, p2).move(3, p3).commit(); QQuickTouchUtils::flush(window); - if (!pinchStoleGrab && pointerEvent->point(0)->exclusiveGrabber() == pinch) { + if (!pinchStoleGrab && devPriv->pointById(0)->exclusiveGrabber == pinch) { pinchStoleGrab = i; QCOMPARE(tp.at(0)->property("pressed").toBool(), false); QCOMPARE(tp.at(1)->property("pressed").toBool(), false); @@ -212,10 +213,10 @@ void tst_MptaInterop::touchesThenPinch() QPoint p4 = mpta->mapToScene(QPointF(300, 200)).toPoint(); touch.move(1, p1).move(2, p2).move(3, p3).press(4, p4).commit(); // PinchHandler deactivates, which lets MPTA grab all the points - QTRY_COMPARE(pointerEvent->point(0)->exclusiveGrabber(), mpta); - QCOMPARE(pointerEvent->point(1)->exclusiveGrabber(), mpta); - QCOMPARE(pointerEvent->point(2)->exclusiveGrabber(), mpta); - QCOMPARE(pointerEvent->point(3)->exclusiveGrabber(), mpta); + QTRY_COMPARE(devPriv->pointById(0)->exclusiveGrabber, mpta); + QCOMPARE(devPriv->pointById(1)->exclusiveGrabber, mpta); + QCOMPARE(devPriv->pointById(2)->exclusiveGrabber, mpta); + QCOMPARE(devPriv->pointById(3)->exclusiveGrabber, mpta); // Move some more... MPTA keeps reacting for (int i = 0; i < 8; ++i) { p1 += QPoint(4, 4); @@ -223,10 +224,10 @@ void tst_MptaInterop::touchesThenPinch() p3 += QPoint(-4, 4); p4 += QPoint(-4, -4); touch.move(1, p1).move(2, p2).move(3, p3).move(4, p4).commit(); - QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), mpta); - QCOMPARE(pointerEvent->point(1)->exclusiveGrabber(), mpta); - QCOMPARE(pointerEvent->point(2)->exclusiveGrabber(), mpta); - QCOMPARE(pointerEvent->point(3)->exclusiveGrabber(), mpta); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, mpta); + QCOMPARE(devPriv->pointById(1)->exclusiveGrabber, mpta); + QCOMPARE(devPriv->pointById(2)->exclusiveGrabber, mpta); + QCOMPARE(devPriv->pointById(3)->exclusiveGrabber, mpta); QCOMPARE(tp.at(0)->property("pressed").toBool(), true); QCOMPARE(tp.at(1)->property("pressed").toBool(), true); QCOMPARE(tp.at(2)->property("pressed").toBool(), true); @@ -241,9 +242,9 @@ void tst_MptaInterop::touchesThenPinch() p2 += QPoint(4, 4); p3 -= QPoint(-4, 4); touch.move(1, p1).move(2, p2).move(3, p3).commit(); - QTRY_COMPARE(pointerEvent->point(0)->exclusiveGrabber(), pinch); - QCOMPARE(pointerEvent->point(1)->exclusiveGrabber(), pinch); - QCOMPARE(pointerEvent->point(2)->exclusiveGrabber(), pinch); + QTRY_COMPARE(devPriv->pointById(0)->exclusiveGrabber, pinch); + QCOMPARE(devPriv->pointById(1)->exclusiveGrabber, pinch); + QCOMPARE(devPriv->pointById(2)->exclusiveGrabber, pinch); } // Release the first finger @@ -267,12 +268,12 @@ void tst_MptaInterop::touchesThenPinch() p2 += QPoint(8, -8); touch.move(2, p2).commit(); QQuickTouchUtils::flush(window); - QVERIFY(pointerEvent->point(0)->passiveGrabbers().contains(drag)); - if (!dragTookGrab && pointerEvent->point(0)->exclusiveGrabber() == drag) + QVERIFY(devPriv->pointById(0)->passiveGrabbers.contains(drag)); + if (!dragTookGrab && devPriv->pointById(0)->exclusiveGrabber == drag) dragTookGrab = i; } qCDebug(lcPointerTests) << "drag started after" << dragTookGrab << "moves; ended with translation" << drag->translation(); - QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), drag); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, drag); QTRY_VERIFY(drag->translation().x() > 0); touch.release(2, p2).commit(); @@ -304,7 +305,7 @@ void tst_MptaInterop::dragHandlerInParentStealingGrabFromItem() // QTBUG-75025 QScopedPointer<QQuickView> windowPtr; createView(windowPtr, "dragParentOfMPTA.qml"); QQuickView * window = windowPtr.data(); - auto pointerEvent = QQuickWindowPrivate::get(window)->pointerEventInstance(QPointingDevice::primaryPointingDevice()); + auto devPriv = QPointingDevicePrivate::get(touchDevice); QPointer<QQuickPointerHandler> handler = window->rootObject()->findChild<QQuickPointerHandler*>(); QVERIFY(handler); @@ -326,7 +327,7 @@ void tst_MptaInterop::dragHandlerInParentStealingGrabFromItem() // QTBUG-75025 for (int i = 0; i < 4; ++i) { point += QPoint(dragThreshold / 2, 0); QTest::mouseMove(window, point); - if (!dragStoleGrab && pointerEvent->point(0)->exclusiveGrabber() == handler) + if (!dragStoleGrab && devPriv->pointById(0)->exclusiveGrabber == handler) dragStoleGrab = i; } if (dragStoleGrab) diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp index a5884659b3..9c9ca2fe00 100644 --- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp @@ -35,6 +35,7 @@ #include <QtQuick/private/qquicktaphandler_p.h> #include <QtQuick/qquickitem.h> #include <QtQuick/qquickview.h> +#include <QtGui/private/qpointingdevice_p.h> #include "../../../shared/util.h" #include "../../shared/viewtestutil.h" @@ -90,15 +91,14 @@ void tst_DragHandler::createView(QScopedPointer<QQuickView> &window, const char QSet<QQuickPointerHandler*> tst_DragHandler::passiveGrabbers(QQuickWindow *window, int pointId /*= 0*/) { + Q_UNUSED(window); QSet<QQuickPointerHandler*> result; - QQuickWindowPrivate *winp = QQuickWindowPrivate::get(window); - QQuickPointerEvent *pointerEvent = winp->pointerEventInstance(touchDevice); - for (int i = 0; i < pointerEvent->pointCount(); ++i) { - QQuickEventPoint *eventPoint = pointerEvent->point(i); - QVector<QPointer <QQuickPointerHandler> > passives = eventPoint->passiveGrabbers(); - if (!pointId || eventPoint->pointId() == pointId) { + auto devPriv = QPointingDevicePrivate::get(touchDevice); + for (auto &epd : devPriv->activePoints.values()) { + auto passives = epd.passiveGrabbers; + if (!pointId || epd.eventPoint.id() == pointId) { for (auto it = passives.constBegin(); it != passives.constEnd(); ++it) - result << it->data(); + result << qobject_cast<QQuickPointerHandler *>(it->data()); } } return result; @@ -263,7 +263,7 @@ void tst_DragHandler::mouseDrag() p1 += QPoint(dragThreshold, 0); QTest::mouseMove(window, p1); if (shouldDrag) { - QTRY_VERIFY(dragHandler->centroid().velocity().x() > 0); +// QTRY_VERIFY(dragHandler->centroid().velocity().x() > 0); // TODO QTBUG-33891 QCOMPARE(centroidChangedSpy.count(), 2); QVERIFY(!dragHandler->active()); #if QT_CONFIG(cursor) @@ -294,7 +294,7 @@ void tst_DragHandler::mouseDrag() QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos); QCOMPARE(dragHandler->translation().x(), dragThreshold + 20.0); QCOMPARE(dragHandler->translation().y(), 0.0); - QVERIFY(dragHandler->centroid().velocity().x() > 0); +// QVERIFY(dragHandler->centroid().velocity().x() > 0); // TODO QTBUG-33891 QCOMPARE(centroidChangedSpy.count(), 4); #if QT_CONFIG(cursor) QCOMPARE(window->cursor().shape(), Qt::ClosedHandCursor); diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp index 6f81e6b566..a4ff2477bb 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -30,6 +30,7 @@ #include <private/qdebug_p.h> #include <QtGui/qstylehints.h> +#include <QtGui/private/qpointingdevice_p.h> #include <QtQuick/private/qquickpointerhandler_p.h> #include <QtQuick/qquickitem.h> #include <QtQuick/qquickview.h> @@ -58,7 +59,7 @@ public: Destination destination; QEvent::Type type; // if this represents a QEvent that was received QEventPoint::State state; // if this represents an event (pointer, touch or mouse) - int grabTransition; // if this represents an onGrabChanged() notification (QQuickEventPoint::GrabTransition) + int grabTransition; // if this represents an onGrabChanged() notification (QPointingDevice::GrabTransition) QPointF posWrtItem; QPointF posWrtScene; }; @@ -75,7 +76,7 @@ QDebug operator<<(QDebug dbg, const class Event &event) { QtDebugUtils::formatQEnum(dbg, event.state); if (event.grabTransition) { dbg << ' '; - QtDebugUtils::formatQEnum(dbg, QQuickEventPoint::GrabTransition(event.grabTransition)); + QtDebugUtils::formatQEnum(dbg, QPointingDevice::GrabTransition(event.grabTransition)); } dbg << " @ "; QtDebugUtils::formatQPoint(dbg, event.posWrtItem); @@ -99,13 +100,13 @@ public: {} inline int grabTransition(bool accept, QEventPoint::State state) { - return (accept && (state != QEventPoint::State::Released)) ? (int)QQuickEventPoint::GrabExclusive : (int)NoGrab; + return (accept && (state != QEventPoint::State::Released)) ? (int)QPointingDevice::GrabExclusive : (int)NoGrab; } void touchEvent(QTouchEvent *event) { qCDebug(lcPointerTests) << event << "will accept?" << acceptTouch; - for (const QEventPoint &tp : event->touchPoints()) + for (auto &tp : event->points()) eventList.append(Event(Event::TouchDestination, event->type(), tp.state(), grabTransition(acceptTouch, tp.state()), tp.position(), tp.scenePosition())); event->setAccepted(acceptTouch); } @@ -137,7 +138,7 @@ public: void mouseUngrabEvent() { qCDebug(lcPointerTests); - eventList.append(Event(Event::MouseDestination, QEvent::UngrabMouse, QEventPoint::State::Released, QQuickEventPoint::UngrabExclusive, QPoint(0,0), QPoint(0,0))); + eventList.append(Event(Event::MouseDestination, QEvent::UngrabMouse, QEventPoint::State::Released, QPointingDevice::UngrabExclusive, QPoint(0,0), QPoint(0,0))); } bool event(QEvent *event) @@ -161,8 +162,9 @@ public: event->type() == QEvent::TouchCancel || event->type() == QEvent::TouchEnd) { QTouchEvent *touch = static_cast<QTouchEvent*>(event); - for (const QEventPoint &tp : touch->touchPoints()) - eventList.append(Event(Event::FilterDestination, event->type(), tp.state(), QQuickEventPoint::GrabExclusive, tp.position(), tp.scenePosition())); + for (auto &tp : touch->points()) + eventList.append(Event(Event::FilterDestination, event->type(), tp.state(), + QPointingDevice::GrabExclusive, tp.position(), tp.scenePosition())); if (filterTouch) event->accept(); return true; @@ -183,42 +185,43 @@ public: class EventHandler : public QQuickPointerHandler { public: - void handlePointerEventImpl(QQuickPointerEvent *event) override + void handlePointerEventImpl(QPointerEvent *event) override { QQuickPointerHandler::handlePointerEventImpl(event); if (!enabled()) return; - if (event->isPressEvent()) + if (event->isBeginEvent()) ++pressEventCount; - if (event->isReleaseEvent()) + if (event->isEndEvent()) ++releaseEventCount; EventItem *item = qmlobject_cast<EventItem *>(target()); if (!item) { - event->point(0)->setGrabberPointerHandler(this); + event->setExclusiveGrabber(event->point(0), this); return; } qCDebug(lcPointerTests) << item->objectName() << event; - int c = event->pointCount(); - for (int i = 0; i < c; ++i) { - QQuickEventPoint *point = event->point(i); + for (auto point : event->points()) { if (item->acceptPointer) - point->setAccepted(item->acceptPointer); // does NOT imply a grab + point.setAccepted(item->acceptPointer); // does NOT imply a grab if (item->grabPointer) - setExclusiveGrab(point, true); - qCDebug(lcPointerTests) << " " << i << ":" << point << "accepted?" << item->acceptPointer << "grabbed?" << (point->exclusiveGrabber() == this); + setExclusiveGrab(event, point, true); + qCDebug(lcPointerTests) << " " << point << "accepted?" << item->acceptPointer + << "grabbed?" << (event->exclusiveGrabber(point) == this); item->eventList.append(Event(Event::HandlerDestination, QEvent::Pointer, - static_cast<QEventPoint::State>(point->state()), - item->grabPointer ? (int)QQuickEventPoint::GrabExclusive : (int)NoGrab, - eventPos(point), point->scenePosition())); + static_cast<QEventPoint::State>(point.state()), + item->grabPointer ? (int)QPointingDevice::GrabExclusive : (int)NoGrab, + eventPos(point), point.scenePosition())); } } - void onGrabChanged(QQuickPointerHandler *, QQuickEventPoint::GrabTransition stateChange, QQuickEventPoint *point) override + void onGrabChanged(QQuickPointerHandler *, QPointingDevice::GrabTransition stateChange, + QPointerEvent *ev, QEventPoint &point) override { + Q_UNUSED(ev); EventItem *item = qmlobject_cast<EventItem *>(target()); if (item) item->eventList.append(Event(Event::HandlerDestination, QEvent::None, - static_cast<QEventPoint::State>(point->state()), stateChange, eventPos(point), point->scenePosition())); + static_cast<QEventPoint::State>(point.state()), stateChange, eventPos(point), point.scenePosition())); } int pressEventCount = 0; @@ -342,15 +345,15 @@ void tst_PointerHandlers::touchEventDelivery() QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, NoGrab); - QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, QEventPoint::State::Pressed, QQuickEventPoint::GrabExclusive); - auto pointerEvent = QQuickWindowPrivate::get(window)->pointerEventInstance(touchDevice); - QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), eventItem1); + QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, QEventPoint::State::Pressed, QPointingDevice::GrabExclusive); + auto devPriv = QPointingDevicePrivate::get(touchDevice); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, eventItem1); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 4); QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Updated, NoGrab); - QCOMPARE_EVENT(3, Event::TouchDestination, QEvent::TouchUpdate, QEventPoint::State::Updated, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(3, Event::TouchDestination, QEvent::TouchUpdate, QEventPoint::State::Updated, QPointingDevice::GrabExclusive); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 6); @@ -372,7 +375,7 @@ void tst_PointerHandlers::touchEventDelivery() QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, NoGrab); QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, QEventPoint::State::Pressed, NoGrab); if (synthMouse) - QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, QPointingDevice::GrabExclusive); QCOMPARE(window->mouseGrabberItem(), synthMouse ? eventItem1 : nullptr); QPointF localPos = eventItem1->mapFromScene(p1); @@ -391,7 +394,7 @@ void tst_PointerHandlers::touchEventDelivery() if (synthMouse) { QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Updated, NoGrab); QCOMPARE_EVENT(4, Event::TouchDestination, QEvent::TouchUpdate, QEventPoint::State::Updated, NoGrab); - QCOMPARE_EVENT(5, Event::MouseDestination, QEvent::MouseMove, QEventPoint::State::Updated, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(5, Event::MouseDestination, QEvent::MouseMove, QEventPoint::State::Updated, QPointingDevice::GrabExclusive); } QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); @@ -400,7 +403,7 @@ void tst_PointerHandlers::touchEventDelivery() QCOMPARE_EVENT(6, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Released, NoGrab); QCOMPARE_EVENT(7, Event::TouchDestination, QEvent::TouchEnd, QEventPoint::State::Released, NoGrab); QCOMPARE_EVENT(8, Event::MouseDestination, QEvent::MouseButtonRelease, QEventPoint::State::Released, NoGrab); - QCOMPARE_EVENT(9, Event::MouseDestination, QEvent::UngrabMouse, QEventPoint::State::Released, QQuickEventPoint::UngrabExclusive); + QCOMPARE_EVENT(9, Event::MouseDestination, QEvent::UngrabMouse, QEventPoint::State::Released, QPointingDevice::UngrabExclusive); } else { QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Released, NoGrab); } @@ -421,7 +424,7 @@ void tst_PointerHandlers::touchEventDelivery() QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, QEventPoint::State::Pressed, NoGrab); if (synthMouse) QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, NoGrab); - QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), nullptr); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, nullptr); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); @@ -442,13 +445,13 @@ void tst_PointerHandlers::touchEventDelivery() QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, NoGrab); - QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, QEventPoint::State::Pressed, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, QEventPoint::State::Pressed, QPointingDevice::GrabExclusive); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 4); QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Updated, NoGrab); - QCOMPARE_EVENT(3, Event::TouchDestination, QEvent::TouchUpdate, QEventPoint::State::Updated, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(3, Event::TouchDestination, QEvent::TouchUpdate, QEventPoint::State::Updated, QPointingDevice::GrabExclusive); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 6); @@ -463,19 +466,19 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::None, QEventPoint::State::Pressed, QQuickEventPoint::GrabExclusive); - QCOMPARE_EVENT(1, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::None, QEventPoint::State::Pressed, QPointingDevice::GrabExclusive); + QCOMPARE_EVENT(1, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, QPointingDevice::GrabExclusive); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Updated, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Updated, QPointingDevice::GrabExclusive); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 5); qCDebug(lcPointerTests) << eventItem1->eventList; - QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Released, QQuickEventPoint::GrabExclusive); - QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::None, QEventPoint::State::Released, QQuickEventPoint::UngrabExclusive); + QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Released, QPointingDevice::GrabExclusive); + QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::None, QEventPoint::State::Released, QPointingDevice::UngrabExclusive); eventItem1->eventList.clear(); } @@ -510,7 +513,7 @@ void tst_PointerHandlers::mouseEventDelivery() QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); QCOMPARE(eventItem1->eventList.size(), 2); QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, NoGrab); - QCOMPARE_EVENT(1, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(1, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, QPointingDevice::GrabExclusive); QCOMPARE(window->mouseGrabberItem(), eventItem1); QPointF localPos = eventItem1->mapFromScene(p1); @@ -523,11 +526,11 @@ void tst_PointerHandlers::mouseEventDelivery() p1 += QPoint(10, 0); QTest::mouseMove(window, p1); QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseMove, QEventPoint::State::Updated, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseMove, QEventPoint::State::Updated, QPointingDevice::GrabExclusive); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); QCOMPARE(eventItem1->eventList.size(), 5); QCOMPARE_EVENT(3, Event::MouseDestination, QEvent::MouseButtonRelease, QEventPoint::State::Released, NoGrab); - QCOMPARE_EVENT(4, Event::MouseDestination, QEvent::UngrabMouse, QEventPoint::State::Released, QQuickEventPoint::UngrabExclusive); + QCOMPARE_EVENT(4, Event::MouseDestination, QEvent::UngrabMouse, QEventPoint::State::Released, QPointingDevice::UngrabExclusive); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -540,17 +543,17 @@ void tst_PointerHandlers::mouseEventDelivery() p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); QTRY_COMPARE(eventItem1->eventList.size(), 3); - QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::None, QEventPoint::State::Pressed, QQuickEventPoint::GrabExclusive); - QCOMPARE_EVENT(1, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::None, QEventPoint::State::Pressed, QPointingDevice::GrabExclusive); + QCOMPARE_EVENT(1, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, QPointingDevice::GrabExclusive); QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, 0); p1 += QPoint(10, 0); QTest::mouseMove(window, p1); QCOMPARE(eventItem1->eventList.size(), 4); - QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Updated, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Updated, QPointingDevice::GrabExclusive); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); QCOMPARE(eventItem1->eventList.size(), 6); - QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Released, QQuickEventPoint::GrabExclusive); - QCOMPARE_EVENT(5, Event::HandlerDestination, QEvent::None, QEventPoint::State::Released, QQuickEventPoint::UngrabExclusive); + QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Released, QPointingDevice::GrabExclusive); + QCOMPARE_EVENT(5, Event::HandlerDestination, QEvent::None, QEventPoint::State::Released, QPointingDevice::UngrabExclusive); eventItem1->eventList.clear(); } @@ -568,11 +571,11 @@ void tst_PointerHandlers::touchReleaseOutside_data() QTest::newRow("reject and ignore") << false << false << 6 << 5 << (int)Event::TouchDestination << (int)QEvent::TouchEnd << (int)QEventPoint::State::Released << (int)NoGrab; QTest::newRow("reject and grab") << false << true << 5 << 4 << (int)Event::HandlerDestination - << (int)QEvent::None << (int)QEventPoint::State::Released << (int)QQuickEventPoint::UngrabExclusive; + << (int)QEvent::None << (int)QEventPoint::State::Released << (int)QPointingDevice::UngrabExclusive; QTest::newRow("accept and ignore") << true << false << 1 << 0 << (int)Event::HandlerDestination << (int)QEvent::Pointer << (int)QEventPoint::State::Pressed << (int)NoGrab; QTest::newRow("accept and grab") << true << true << 5 << 4 << (int)Event::HandlerDestination - << (int)QEvent::None << (int)QEventPoint::State::Released << (int)QQuickEventPoint::UngrabExclusive; + << (int)QEvent::None << (int)QEventPoint::State::Released << (int)QPointingDevice::UngrabExclusive; } void tst_PointerHandlers::touchReleaseOutside() diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp index 89de571abd..43b1affc09 100644 --- a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp @@ -685,8 +685,8 @@ void tst_TapHandler::componentUserBehavioralOverride() QQuickTapHandler *userTapHandler = button->findChild<QQuickTapHandler*>("override"); QVERIFY(userTapHandler); QSignalSpy tappedSpy(button, SIGNAL(tapped())); - QSignalSpy innerGrabChangedSpy(innerTapHandler, SIGNAL(grabChanged(QQuickEventPoint::GrabTransition, QQuickEventPoint *))); - QSignalSpy userGrabChangedSpy(userTapHandler, SIGNAL(grabChanged(QQuickEventPoint::GrabTransition, QQuickEventPoint *))); + QSignalSpy innerGrabChangedSpy(innerTapHandler, SIGNAL(grabChanged(QPointingDevice::GrabTransition, QEventPoint *))); + QSignalSpy userGrabChangedSpy(userTapHandler, SIGNAL(grabChanged(QPointingDevice::GrabTransition, QEventPoint *))); QSignalSpy innerPressedChangedSpy(innerTapHandler, SIGNAL(pressedChanged())); QSignalSpy userPressedChangedSpy(userTapHandler, SIGNAL(pressedChanged())); @@ -715,7 +715,7 @@ void tst_TapHandler::rightLongPressIgnoreWheel() QQuickTapHandler *tap = window->rootObject()->findChild<QQuickTapHandler*>(); QVERIFY(tap); - QSignalSpy tappedSpy(tap, SIGNAL(tapped(QQuickEventPoint *))); + QSignalSpy tappedSpy(tap, SIGNAL(tapped(QEventPoint *))); QSignalSpy longPressedSpy(tap, SIGNAL(longPressed())); QPoint p1(100, 100); diff --git a/tests/auto/quick/qquickflickable/data/nestedPressDelay.qml b/tests/auto/quick/qquickflickable/data/nestedPressDelay.qml index bdb866ce65..3cc0987141 100644 --- a/tests/auto/quick/qquickflickable/data/nestedPressDelay.qml +++ b/tests/auto/quick/qquickflickable/data/nestedPressDelay.qml @@ -1,6 +1,7 @@ import QtQuick 2.0 Flickable { + objectName: "outerFlickable" property bool pressed: ma.pressed width: 240 height: 320 diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index f6a6ab17b4..0a75690904 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -65,11 +65,7 @@ public: , ungrabs(0) , m_active(false) { -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) setAcceptTouchEvents(true); -#else - setAcceptedMouseButtons(Qt::LeftButton); // not really, but we want touch events -#endif } QPointF pos() const { return m_pos; } @@ -97,8 +93,8 @@ public: protected: void touchEvent(QTouchEvent *ev) override { - QCOMPARE(ev->touchPoints().count(), 1); - auto touchpoint = ev->touchPoints().first(); + QCOMPARE(ev->points().count(), 1); + auto touchpoint = ev->points().first(); switch (touchpoint.state()) { case QEventPoint::State::Pressed: QVERIFY(!m_active); @@ -115,6 +111,7 @@ protected: ++touchReleases; emit activeChanged(); case QEventPoint::State::Stationary: + case QEventPoint::State::Unknown: break; } touchPointStates << touchpoint.state(); @@ -1566,6 +1563,8 @@ void tst_qquickflickable::cancelOnHide() void tst_qquickflickable::cancelOnMouseGrab() { + QSKIP("need a realistic test scenario: can no longer grab mouse between events"); + QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("cancel.qml")); QTRY_COMPARE(window->status(), QQuickView::Ready); diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp index 47f7943d12..1cb5591519 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp +++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -36,6 +36,7 @@ #include <QtQuick/qquickview.h> #include <QtGui/QScreen> #include <QtGui/private/qevent_p.h> +#include <QtGui/private/qpointingdevice_p.h> #include "../../shared/util.h" #include "../shared/viewtestutil.h" @@ -814,7 +815,6 @@ void tst_QQuickMultiPointTouchArea::inFlickableWithPressDelay() // QTBUG-78818 const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); QScopedPointer<QQuickView> window(createAndShowView("inFlickable.qml")); QVERIFY(window->rootObject() != nullptr); - QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window.data()); QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(window->rootObject()); QVERIFY(flickable != nullptr); @@ -831,8 +831,8 @@ void tst_QQuickMultiPointTouchArea::inFlickableWithPressDelay() // QTBUG-78818 QTest::touchEvent(window.data(), device).press(0, p1); QQuickTouchUtils::flush(window.data()); QTRY_COMPARE(point11->pressed(), true); - auto pointerEvent = windowPriv->pointerEventInstance(device); - QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), mpta); + auto devPriv = QPointingDevicePrivate::get(device); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, mpta); // release: MPTA receives TouchEnd (which is asymmetric with mouse press); does NOT emit canceled. QTest::touchEvent(window.data(), device).release(0, p1); @@ -843,18 +843,18 @@ void tst_QQuickMultiPointTouchArea::inFlickableWithPressDelay() // QTBUG-78818 QTest::touchEvent(window.data(), device).press(0, p1); QQuickTouchUtils::flush(window.data()); QTRY_COMPARE(point11->pressed(), true); // wait until pressDelay exceeded - QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), mpta); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, mpta); // drag past the threshold: Flickable takes over the grab, MPTA gets touchUngrab and is no longer pressed int i = 0; - for (; i < 10 && window->mouseGrabberItem() != flickable; ++i) { + for (; i < 10 && devPriv->firstPointExclusiveGrabber() != flickable; ++i) { p1 += QPoint(0,dragThreshold); QTest::touchEvent(window.data(), device).move(0, p1); QQuickTouchUtils::flush(window.data()); } - QCOMPARE(window->mouseGrabberItem(), flickable); + QCOMPARE(devPriv->firstPointExclusiveGrabber(), flickable); qCDebug(lcTests, "Flickable stole grab from MPTA after %d moves", i); - QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), flickable); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, flickable); QCOMPARE(point11->pressed(), false); QVERIFY(flickable->property("cancelCount").toInt() > 0); // actually 2 because 2 touchPoints are declared... but only one was really cancelled diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index cfccfe88ba..dd95ab1808 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -85,12 +85,23 @@ static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, QEventPoint:: const QList<QEventPoint>& touchPoints = QList<QEventPoint>()) { TouchEventData d = { type, nullptr, w, states, touchPoints }; + for (auto &pt : d.touchPoints) + QMutableEventPoint::from(pt).detach(); + return d; +} +static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, QEventPoint::States states, + const QList<QEventPoint*>& touchPoints) +{ + QList <QEventPoint> pts; + for (auto pt : touchPoints) + pts << *pt; + TouchEventData d = { type, nullptr, w, states, pts }; return d; } static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, QEventPoint::States states, const QEventPoint &touchPoint) { - QList<QEventPoint> points; - points << touchPoint; + QList<QEventPoint*> points; + points << const_cast<QEventPoint *>(&touchPoint); return makeTouchData(type, w, states, points); } @@ -157,6 +168,7 @@ public: { border()->setWidth(1); setAcceptedMouseButtons(Qt::LeftButton); + setAcceptTouchEvents(true); setFiltersChildMouseEvents(true); } @@ -165,7 +177,7 @@ public: setEnabled(true); setVisible(true); - lastEvent = makeTouchData(QEvent::None, window(), {}, QList<QEventPoint>());//CHECK_VALID + lastEvent = makeTouchData(QEvent::None, window());//CHECK_VALID lastVelocity = lastVelocityFromMouseMove = QVector2D(); lastMousePos = QPointF(); @@ -204,10 +216,11 @@ public: event->ignore(); return; } + qCDebug(lcTests) << objectName() << event; ++touchEventCount; - lastEvent = makeTouchData(event->type(), nullptr, event->touchPointStates(), event->touchPoints()); - if (event->device()->capabilities().testFlag(QPointingDevice::Capability::Velocity) && !event->touchPoints().isEmpty()) { - lastVelocity = event->touchPoints().first().velocity(); + lastEvent = makeTouchData(event->type(), nullptr, event->touchPointStates(), event->points()); + if (event->device()->capabilities().testFlag(QPointingDevice::Capability::Velocity) && !event->points().isEmpty()) { + lastVelocity = event->points().first().velocity(); } else { lastVelocity = QVector2D(); } @@ -232,7 +245,7 @@ public: return; } mouseMoveCount = ++mouseMoveNum; - lastVelocityFromMouseMove = e->point(0).velocity(); + lastVelocityFromMouseMove = e->points().first().velocity(); lastMouseCapabilityFlags = e->device()->capabilities(); lastMousePos = e->position().toPoint(); } @@ -248,6 +261,7 @@ public: } void mouseUngrabEvent() { + qCDebug(lcTests) << objectName(); ++mouseUngrabEventCount; } @@ -340,6 +354,7 @@ public: { setSize(QSizeF(300, 300)); setAcceptedMouseButtons(Qt::LeftButton); + setAcceptTouchEvents(true); } protected: @@ -477,8 +492,6 @@ private slots: void testHoverTimestamp(); void test_circleMapItem(); - void pointerEventTypeAndPointCount(); - void grabContentItemToImage(); void testDragEventPropertyPropagation(); @@ -727,8 +740,11 @@ void tst_qquickwindow::touchEvent_basic() QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1); + // Since qtbase 2692237bb1b0c0f50b7cc5d920eb8ab065063d47, if the point didn't have a different position on release, + // then lastPosition is not changed. So in this case, it still holds the press position. I.e. on release, + // it's the last position that was actually different. COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, window, QEventPoint::State::Released, - makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos)))); + makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos))); COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, makeTouchPoint(bottomItem, pos))); topItem->reset(); bottomItem->reset(); @@ -910,7 +926,7 @@ void tst_qquickwindow::touchEvent_cancel() QWindowSystemInterface::handleTouchCancelEvent(nullptr, touchDevice); QCoreApplication::processEvents(); - d = makeTouchData(QEvent::TouchCancel, window); + d = makeTouchData(QEvent::TouchCancel, window, QEventPoint::State::Pressed, makeTouchPoint(item, pos)); COMPARE_TOUCH_DATA(item->lastEvent, d); delete item; @@ -1031,18 +1047,18 @@ void tst_qquickwindow::touchEvent_velocity() QCOMPARE(item->lastEvent.touchPoints.count(), 1); QCOMPARE(item->lastVelocity, velocity); - // Now have a transformation on the item and check if velocity and position are transformed accordingly. + // Now have a transformation on the item and check if position is transformed accordingly. + // (In Qt 6, transforming the velocity is an exercise left to the user. This saves work + // during delivery. If we want it to be transformed, we should add QEventPoint::sceneVelocity + // so that we can keep transforming it repeatedly during Item-localization.) item->setRotation(90); // clockwise - QMatrix4x4 transformMatrix; - transformMatrix.rotate(-90, 0, 0, 1); // counterclockwise - QVector2D transformedVelocity = transformMatrix.mapVector(velocity).toVector2D(); points[0].setPosition(points[0].position() + QPointF(5, 5)); points[0].setGlobalPosition(points[0].globalPosition() + QPointF(5, 5)); QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); - QCOMPARE(item->lastVelocity, transformedVelocity); + QCOMPARE(item->lastVelocity, velocity); QPoint itemLocalPos = item->mapFromScene(points[0].position()).toPoint(); QPoint itemLocalPosFromEvent = item->lastEvent.touchPoints[0].position().toPoint(); QCOMPARE(itemLocalPos, itemLocalPosFromEvent); @@ -1183,9 +1199,6 @@ void tst_qquickwindow::mouseFromTouch_basic() // Now the same with a transformation. item->setRotation(90); // clockwise - QMatrix4x4 transformMatrix; - transformMatrix.rotate(-90, 0, 0, 1); // counterclockwise - QVector2D transformedVelocity = transformMatrix.mapVector(velocity).toVector2D(); points[0].setState(QEventPoint::State::Pressed); points[0].setVelocity(velocity); tp.setPosition(localPos); @@ -1202,8 +1215,7 @@ void tst_qquickwindow::mouseFromTouch_basic() QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); QCOMPARE(item->lastMousePos.toPoint(), item->mapFromScene(points[0].position()).toPoint()); - QEXPECT_FAIL(0, "fails after pointer event refactoring in qtbase", Abort); - QCOMPARE(item->lastVelocityFromMouseMove, transformedVelocity); + QCOMPARE(item->lastVelocityFromMouseMove, velocity); // Velocity is always in scene coords points[0].setState(QEventPoint::State::Released); QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, @@ -1242,8 +1254,11 @@ void tst_qquickwindow::synthMouseFromTouch() QPoint p1 = QPoint(20, 20); QPoint p2 = QPoint(30, 30); QTest::touchEvent(window.data(), touchDevice).press(0, p1, window.data()); + QQuickTouchUtils::flush(window.data()); QTest::touchEvent(window.data(), touchDevice).move(0, p2, window.data()); + QQuickTouchUtils::flush(window.data()); QTest::touchEvent(window.data(), touchDevice).release(0, p2, window.data()); + QQuickTouchUtils::flush(window.data()); QCOMPARE(item->m_touchEvents.count(), !synthMouse && !acceptTouch ? 1 : 3); QCOMPARE(item->m_mouseEvents.count(), (acceptTouch || !synthMouse) ? 0 : 3); @@ -1295,7 +1310,8 @@ void tst_qquickwindow::synthMouseDoubleClickFromTouch() const int eventCount = item->m_mouseEvents.count(); QVERIFY(eventCount >= 2); - const int nDoubleClicks = std::count_if(item->m_mouseEvents.constBegin(), item->m_mouseEvents.constEnd(), [](const QMouseEvent &ev) { return (ev.type() == QEvent::MouseButtonDblClick); } ); + const int nDoubleClicks = std::count_if(item->m_mouseEvents.constBegin(), item->m_mouseEvents.constEnd(), + [](const QMouseEvent &ev) { return (ev.type() == QEvent::MouseButtonDblClick); } ); const bool foundDoubleClick = (nDoubleClicks == 1); QCOMPARE(foundDoubleClick, expectedSynthesizedDoubleClickEvent); @@ -2834,58 +2850,6 @@ void tst_qquickwindow::test_circleMapItem() QCOMPARE(topSpy.count(), 1); } -void tst_qquickwindow::pointerEventTypeAndPointCount() -{ - QPointF localPosition(33, 66); - QPointF scenePosition(133, 166); - QPointF screenPosition(333, 366); - QMouseEvent me(QEvent::MouseButtonPress, localPosition, scenePosition, screenPosition, - Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); - QMutableTouchEvent te(QEvent::TouchBegin, touchDevice, Qt::NoModifier, - QList<QEventPoint>() << QEventPoint(1)); - - - QQuickPointerMouseEvent pme(nullptr, QPointingDevice::primaryPointingDevice()); - pme.reset(&me); - QCOMPARE(pme.asMouseEvent(localPosition), &me); - QVERIFY(pme.asPointerMouseEvent()); - QVERIFY(!pme.asPointerTouchEvent()); - QVERIFY(!pme.asPointerTabletEvent()); -// QVERIFY(!pe->asTabletEvent()); // TODO - QCOMPARE(pme.pointCount(), 1); - QCOMPARE(pme.point(0)->scenePosition(), scenePosition); - QCOMPARE(pme.asMouseEvent(localPosition)->position(), localPosition); - QCOMPARE(pme.asMouseEvent(localPosition)->globalPosition(), screenPosition); - - QQuickPointerTouchEvent pte(nullptr, touchDevice); - pte.reset(&te); - QCOMPARE(pte.asTouchEvent(), &te); - QVERIFY(!pte.asPointerMouseEvent()); - QVERIFY(pte.asPointerTouchEvent()); - QVERIFY(!pte.asPointerTabletEvent()); - QVERIFY(pte.asTouchEvent()); -// QVERIFY(!pte.asTabletEvent()); // TODO - QCOMPARE(pte.pointCount(), 1); - QCOMPARE(pte.touchPointById(1)->id(), 1); - QVERIFY(!pte.touchPointById(0)); - - te = QMutableTouchEvent(QEvent::TouchBegin, touchDevice, Qt::NoModifier, - QList<QEventPoint>() << QEventPoint(1) << QEventPoint(2)); - pte.reset(&te); - QCOMPARE(pte.pointCount(), 2); - QCOMPARE(pte.touchPointById(1)->id(), 1); - QCOMPARE(pte.touchPointById(2)->id(), 2); - QVERIFY(!pte.touchPointById(0)); - - te = QMutableTouchEvent(QEvent::TouchBegin, touchDevice, Qt::NoModifier, - QList<QEventPoint>() << QEventPoint(2)); - pte.reset(&te); - QCOMPARE(pte.pointCount(), 1); - QCOMPARE(pte.touchPointById(2)->id(), 2); - QVERIFY(!pte.touchPointById(1)); - QVERIFY(!pte.touchPointById(0)); -} - void tst_qquickwindow::grabContentItemToImage() { QQmlEngine engine; diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp index 1c53a3abe2..2deaf31079 100644 --- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp +++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp @@ -32,6 +32,7 @@ #include <QtGui/qstylehints.h> #include <private/qdebug_p.h> +#include <QtGui/private/qpointingdevice_p.h> #include <QtQuick/qquickview.h> #include <QtQuick/qquickitem.h> @@ -56,9 +57,12 @@ struct Event :type(t), mousePos(mouse), mousePosGlobal(global) {} - Event(QEvent::Type t, QList<QEventPoint> touch) - :type(t), points(touch) - {} + Event(QEvent::Type t, const QList<QEventPoint> &touch) + :type(t) + { + for (auto &tp : touch) + points << tp; + } QEvent::Type type; QPoint mousePos; @@ -93,48 +97,57 @@ public: : QQuickItem(parent) { setAcceptedMouseButtons(Qt::LeftButton); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) setAcceptTouchEvents(true); -#endif } void touchEvent(QTouchEvent *event) { - eventList.append(Event(event->type(), event->touchPoints())); - QList<QEventPoint> tps = event->touchPoints(); - Q_ASSERT(!tps.isEmpty()); - point0 = tps.first().id(); + qCDebug(lcTests) << event << "accepting?" << acceptTouch; + eventList.append(Event(event->type(), event->points())); + Q_ASSERT(event->pointCount() > 0); + point0 = event->point(0).id(); event->setAccepted(acceptTouch); emit onTouchEvent(this); } void mousePressEvent(QMouseEvent *event) { + qCDebug(lcTests) << event << "accepting?" << acceptMouse; eventList.append(Event(event->type(), event->position().toPoint(), event->globalPosition().toPoint())); + mouseGrabber = event->exclusiveGrabber(event->points().first()); event->setAccepted(acceptMouse); } void mouseMoveEvent(QMouseEvent *event) { + qCDebug(lcTests) << event << "accepting?" << acceptMouse; eventList.append(Event(event->type(), event->position().toPoint(), event->globalPosition().toPoint())); + mouseGrabber = event->exclusiveGrabber(event->points().first()); event->setAccepted(acceptMouse); } void mouseReleaseEvent(QMouseEvent *event) { + qCDebug(lcTests) << event << "accepting?" << acceptMouse; eventList.append(Event(event->type(), event->position().toPoint(), event->globalPosition().toPoint())); + mouseGrabber = event->exclusiveGrabber(event->points().first()); event->setAccepted(acceptMouse); } void mouseDoubleClickEvent(QMouseEvent *event) { + qCDebug(lcTests) << event << "accepting?" << acceptMouse; eventList.append(Event(event->type(), event->position().toPoint(), event->globalPosition().toPoint())); + mouseGrabber = event->exclusiveGrabber(event->points().first()); event->setAccepted(acceptMouse); } void mouseUngrabEvent() { + qCDebug(lcTests); eventList.append(Event(QEvent::UngrabMouse, QPoint(0,0), QPoint(0,0))); + mouseGrabber = nullptr; } void touchUngrabEvent() { + qCDebug(lcTests); ++touchUngrabCount; } @@ -143,6 +156,7 @@ public: } QList<Event> eventList; + QObject *mouseGrabber = nullptr; int touchUngrabCount = 0; bool acceptMouse = false; bool acceptTouch = false; @@ -154,11 +168,11 @@ public: event->type() == QEvent::TouchUpdate || event->type() == QEvent::TouchCancel || event->type() == QEvent::TouchEnd) { + qCDebug(lcTests) << event; QTouchEvent *touch = static_cast<QTouchEvent*>(event); - eventList.append(Event(event->type(), touch->touchPoints())); - QList<QEventPoint> tps = touch->touchPoints(); - Q_ASSERT(!tps.isEmpty()); - point0 = tps.first().id(); + eventList.append(Event(event->type(), touch->points())); + Q_ASSERT(touch->pointCount() > 0); + point0 = touch->point(0).id(); if (filterTouch) event->accept(); return true; @@ -168,6 +182,37 @@ public: int point0 = -1; }; +class GrabMonitor : public QObject +{ +public: + QObject *exclusiveGrabber = nullptr; + bool fromMouseEvent = false; + bool canceled = false; + + void onGrabChanged(QObject *grabber, QPointingDevice::GrabTransition transition, const QPointerEvent *event, const QEventPoint &point) + { + qCDebug(lcTests) << grabber << transition << event << point << point.device(); + switch (transition) { + case QPointingDevice::GrabTransition::GrabExclusive: + exclusiveGrabber = grabber; + fromMouseEvent = event && QQuickWindowPrivate::isMouseEvent(event); + canceled = false; + break; + case QPointingDevice::GrabTransition::UngrabExclusive: + exclusiveGrabber = nullptr; + canceled = false; + break; + case QPointingDevice::GrabTransition::CancelGrabExclusive: + exclusiveGrabber = nullptr; + canceled = true; + break; + default: + // ignore the passive grabs since this test doesn't involve pointer handlers + break; + } + } +}; + class tst_TouchMouse : public QQmlDataTest { Q_OBJECT @@ -219,6 +264,7 @@ private: QQuickView *createView(); QPointingDevice *device = QTest::createTouchDevice(); QList<Event> filteredEventList; + GrabMonitor grabMonitor; }; QQuickView *tst_TouchMouse::createView() @@ -231,6 +277,7 @@ void tst_TouchMouse::initTestCase() { QQmlDataTest::initTestCase(); qmlRegisterType<EventItem>("Qt.test", 1, 0, "EventItem"); + connect(device, &QPointingDevice::grabChanged, &grabMonitor, &GrabMonitor::onGrabChanged); } void tst_TouchMouse::simpleTouchEvent_data() @@ -254,6 +301,7 @@ void tst_TouchMouse::simpleTouchEvent() EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); QVERIFY(eventItem1); + auto devPriv = QPointingDevicePrivate::get(device); // Do not accept touch or mouse QPoint p1; @@ -302,7 +350,7 @@ void tst_TouchMouse::simpleTouchEvent() QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); if (synthMouse) QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); - QCOMPARE(window->mouseGrabberItem(), synthMouse ? eventItem1 : nullptr); + QCOMPARE(devPriv->firstPointExclusiveGrabber(), synthMouse ? eventItem1 : nullptr); QPoint localPos = eventItem1->mapFromScene(p1).toPoint(); QPoint globalPos = window->mapToGlobal(p1); @@ -612,9 +660,9 @@ void tst_TouchMouse::buttonOnFlickable() QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window.data()); QVERIFY(windowPriv->touchMouseId != -1); - auto pointerEvent = windowPriv->pointerEventInstance(device); - QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), eventItem1); - QCOMPARE(window->mouseGrabberItem(), eventItem1); + auto devPriv = QPointingDevicePrivate::get(device); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, eventItem1); + QCOMPARE(grabMonitor.exclusiveGrabber, eventItem1); int dragDelta = -qApp->styleHints()->startDragDistance(); p1 += QPoint(0, dragDelta); @@ -628,15 +676,14 @@ void tst_TouchMouse::buttonOnFlickable() QTest::touchEvent(window.data(), device).move(0, p3, window.data()); QQuickTouchUtils::flush(window.data()); - // we cannot really know when the events get grabbed away QVERIFY(eventItem1->eventList.size() >= 4); QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchUpdate); QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove); - QCOMPARE(window->mouseGrabberItem(), flickable); + QCOMPARE(grabMonitor.exclusiveGrabber, flickable); QVERIFY(windowPriv->touchMouseId != -1); - QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), flickable); - QVERIFY(flickable->isMovingVertically()); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, flickable); +// QVERIFY(flickable->isMovingVertically()); // it will move after a couple more mouse moves QTest::touchEvent(window.data(), device).release(0, p3, window.data()); QQuickTouchUtils::flush(window.data()); @@ -673,9 +720,9 @@ void tst_TouchMouse::touchButtonOnFlickable() QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window.data()); QVERIFY(windowPriv->touchMouseId == -1); - auto pointerEvent = windowPriv->pointerEventInstance(device); - QCOMPARE(pointerEvent->point(0)->grabberItem(), eventItem2); - QCOMPARE(window->mouseGrabberItem(), nullptr); + auto devPriv = QPointingDevicePrivate::get(device); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, eventItem2); + QCOMPARE(grabMonitor.exclusiveGrabber, eventItem2); int dragDelta = qApp->styleHints()->startDragDistance() * -0.7; p1 += QPoint(0, dragDelta); @@ -693,9 +740,9 @@ void tst_TouchMouse::touchButtonOnFlickable() QTRY_COMPARE(eventItem2->touchUngrabCount, 1); QVERIFY(eventItem2->eventList.size() > 2); QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchUpdate); - QCOMPARE(window->mouseGrabberItem(), flickable); + QCOMPARE(grabMonitor.exclusiveGrabber, flickable); QVERIFY(windowPriv->touchMouseId != -1); - QCOMPARE(pointerEvent->point(0)->grabberItem(), flickable); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, flickable); QVERIFY(flickable->isMovingVertically()); QTest::touchEvent(window.data(), device).release(0, p3, window.data()); @@ -809,10 +856,10 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() // flickable should have the mouse grab, and have moved the itemForTouchPointId // for the touchMouseId to the new grabber. - QCOMPARE(window->mouseGrabberItem(), flickable); + QCOMPARE(grabMonitor.exclusiveGrabber, flickable); QVERIFY(windowPriv->touchMouseId != -1); - auto pointerEvent = windowPriv->pointerEventInstance(device); - QCOMPARE(pointerEvent->point(0)->grabberItem(), flickable); + auto devPriv = QPointingDevicePrivate::get(device); + QCOMPARE(devPriv->pointById(0)->exclusiveGrabber, flickable); } QTest::touchEvent(window.data(), device).release(0, pEnd, window.data()); @@ -1243,8 +1290,6 @@ void tst_TouchMouse::mouseOnFlickableOnPinch() pinchSequence.move(0, p, window.data()).commit(); QQuickTouchUtils::flush(window.data()); - QCOMPARE(window->mouseGrabberItem(), flickable); - // Add a second finger, this should lead to stealing p1 = QPoint(40, 100); p2 = QPoint(60, 100); @@ -1348,21 +1393,20 @@ void tst_TouchMouse::touchGrabCausesMouseUngrab() QCOMPARE(leftItem->eventList.size(), 2); QCOMPARE(leftItem->eventList.at(0).type, QEvent::TouchBegin); QCOMPARE(leftItem->eventList.at(1).type, QEvent::MouseButtonPress); - QCOMPARE(window->mouseGrabberItem(), leftItem); + QCOMPARE(grabMonitor.exclusiveGrabber, leftItem); leftItem->eventList.clear(); rightItem->acceptTouch = true; - { - QList<int> ids; - ids.append(leftItem->point0); - rightItem->grabTouchPoints(ids); - } + auto devPriv = QPointingDevicePrivate::get(device); + auto epd = devPriv->queryPointById(0); + QVERIFY(epd); + devPriv->setExclusiveGrabber(nullptr, epd->eventPoint, rightItem); // leftItem should have lost the mouse as the touch point that was being used to emulate it // has been grabbed by another item. QCOMPARE(leftItem->eventList.size(), 1); QCOMPARE(leftItem->eventList.at(0).type, QEvent::UngrabMouse); - QCOMPARE(window->mouseGrabberItem(), (QQuickItem*)nullptr); + QCOMPARE(grabMonitor.exclusiveGrabber, rightItem); } void tst_TouchMouse::touchPointDeliveryOrder() @@ -1556,6 +1600,7 @@ void tst_TouchMouse::implicitUngrab() QQuickViewTestUtil::centerOnScreen(window.data()); QQuickViewTestUtil::moveMouseAway(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); + QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window.data()); QQuickItem *root = window->rootObject(); QVERIFY(root != nullptr); @@ -1564,12 +1609,13 @@ void tst_TouchMouse::implicitUngrab() QPoint p1(20, 20); QTest::touchEvent(window.data(), device).press(0, p1); - QCOMPARE(window->mouseGrabberItem(), eventItem); + QCOMPARE(grabMonitor.exclusiveGrabber, eventItem); eventItem->eventList.clear(); eventItem->setEnabled(false); QVERIFY(!eventItem->eventList.isEmpty()); QCOMPARE(eventItem->eventList.at(0).type, QEvent::UngrabMouse); QTest::touchEvent(window.data(), device).release(0, p1); // clean up potential state + QCOMPARE(windowPriv->touchMouseId, -1); eventItem->setEnabled(true); QTest::touchEvent(window.data(), device).press(0, p1); diff --git a/tests/manual/pointer/inputinspector.cpp b/tests/manual/pointer/inputinspector.cpp index ff921fab0f..b919c489f4 100644 --- a/tests/manual/pointer/inputinspector.cpp +++ b/tests/manual/pointer/inputinspector.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the manual tests of the Qt Toolkit. @@ -27,9 +27,9 @@ ****************************************************************************/ #include "inputinspector.h" -#include <QtQuick/QQuickWindow> #include <QtQuick/QQuickItem> #include <QtQuick/private/qquickpointerhandler_p.h> +#include <QtGui/private/qpointingdevice_p.h> #include <QtCore/QSet> static const int timerInterval = 100; @@ -139,23 +139,13 @@ const QPointingDevice *InputInspector::pointerDevice() const QVector<QObject*> InputInspector::passiveGrabbers_helper(int pointId /*= 0*/) const { QVector<QObject*> result; - QSet<QObject*> visited; const QPointingDevice *device = pointerDevice(); if (device && source()) { - QQuickWindowPrivate *winPriv = QQuickWindowPrivate::get(source()); - QQuickPointerEvent *pointerEvent = winPriv->pointerEventInstance(device); - if (pointerEvent) { - for (int i = 0; i < pointerEvent->pointCount(); ++i) { - QQuickEventPoint *eventPoint = pointerEvent->point(i); - QVector<QPointer <QQuickPointerHandler> > passives = eventPoint->passiveGrabbers(); - if (!pointId || eventPoint->pointId() == pointId) { - for (auto it = passives.constBegin(); it != passives.constEnd(); ++it) { - QObject *handler = it->data(); - if (!visited.contains(handler)) { - result << it->data(); - visited << handler; - } - } + for (auto eventPoint : QPointingDevicePrivate::get(device)->activePoints) { + if (!pointId || eventPoint.id() == pointId) { + for (auto pg : eventPoint.passiveGrabbers()) { + if (!result.contains(pg)) + result << pg; } } } @@ -166,21 +156,13 @@ QVector<QObject*> InputInspector::passiveGrabbers_helper(int pointId /*= 0*/) co QVector<QObject*> InputInspector::exclusiveGrabbers_helper(int pointId /*= 0*/) const { QVector<QObject*> result; - QSet<QObject*> visited; const QPointingDevice *device = pointerDevice(); if (device && source()) { - QQuickWindowPrivate *winPriv = QQuickWindowPrivate::get(source()); - QQuickPointerEvent *pointerEvent = winPriv->pointerEventInstance(device); - if (pointerEvent) { - for (int i = 0; i < pointerEvent->pointCount(); ++i) { - QQuickEventPoint *eventPoint = pointerEvent->point(i); - if (!pointId || eventPoint->pointId() == pointId) { - if (QObject *exclusiveGrabber = eventPoint->exclusiveGrabber()) { - if (!visited.contains(exclusiveGrabber)) { - result << exclusiveGrabber; - visited << exclusiveGrabber; - } - } + for (auto eventPoint : QPointingDevicePrivate::get(device)->activePoints) { + if (!pointId || eventPoint.id() == pointId) { + if (auto g = eventPoint.exclusiveGrabber()) { + if (!result.contains(g)) + result << g; } } } diff --git a/tests/manual/pointer/inputinspector.h b/tests/manual/pointer/inputinspector.h index 0ef0a96987..31d99cf25d 100644 --- a/tests/manual/pointer/inputinspector.h +++ b/tests/manual/pointer/inputinspector.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the manual tests of the Qt Toolkit. @@ -30,7 +30,7 @@ #define INPUTINSPECTOR_H #include <QObject> -class QQuickWindow; +#include <QtQuick/QQuickWindow> class QQuickPointerHandler; class QPointingDevice; diff --git a/tests/manual/pointer/singlePointHandlerProperties.qml b/tests/manual/pointer/singlePointHandlerProperties.qml index c2500770f0..9bebf23810 100644 --- a/tests/manual/pointer/singlePointHandlerProperties.qml +++ b/tests/manual/pointer/singlePointHandlerProperties.qml @@ -140,7 +140,7 @@ Rectangle { id: pointHandler target: null acceptedButtons: Qt.AllButtons - onGrabChanged: if (active) { // 'point' is an implicit parameter referencing to a QQuickEventPoint instance + onGrabChanged: if (active) { // 'point' is an implicit parameter referencing to a QEventPoint instance console.log("grabbed " + point.pointId + " @ " + point.sceneGrabPos) grabbingLocationIndicator.createObject(root, {"x": point.sceneGrabPosition.x, "y": point.sceneGrabPosition.y - 16}) } diff --git a/tests/manual/pointer/tapHandler.qml b/tests/manual/pointer/tapHandler.qml index 8c1fac9a2f..6e51fc6fda 100644 --- a/tests/manual/pointer/tapHandler.qml +++ b/tests/manual/pointer/tapHandler.qml @@ -53,7 +53,7 @@ Item { borderBlink.blinkColor = "red" borderBlink.start() } - onTapped: { // 'eventPoint' is a signal parameter of type QQuickEventPoint* + onTapped: { // 'eventPoint' is a signal parameter of type QEventPoint* console.log("tapped button " + eventPoint.event.button + " @ " + eventPoint.scenePosition + " on device '" + eventPoint.event.device.name + "' " + (tapCount > 1 ? (tapCount + " times") : "for the first time")) if (tapCount > 1) { |