aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickitem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickitem.cpp')
-rw-r--r--src/quick/items/qquickitem.cpp165
1 files changed, 138 insertions, 27 deletions
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();