aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickwindow.cpp
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2020-07-23 13:56:26 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2020-09-18 20:56:25 +0200
commita97759a336c597327cb82eebc9f45c793aec32c9 (patch)
tree632bbee8568d38af56974e02df5810afcf48aedc /src/quick/items/qquickwindow.cpp
parent39f4d687fc37f48cbc181f42797c42be91b4a345 (diff)
Remove QQuickPointerEvent etc.; deliver QPointerEvents directly
QEventPoint does not have an accessor to get the QPointerEvent that it came from, because that's inconsistent with the idea that QPointerEvent instances are temporary, stack-allocated and movable (the pointer would often be wrong or null, therefore could not be relied upon). So most functions that worked directly with QQuickEventPoint before (which fortunately are still private API) now need to receive the QPointerEvent too, which we choose to pass by pointer. QEventPoint is always passed by reference (const where possible) to be consistent with functions in QPointerEvent that take QEventPoint by reference. QEventPoint::velocity() should be always in scene coordinates now, which saves us the trouble of transforming it to each item's coordinate system during delivery, but means that it will need to be done in handlers or applications sometimes. If we were going to transform it, it would be important to also store the sceneVelocity separately in QEventPoint so that the transformation could be done repeatedly for different items. Task-number: QTBUG-72173 Change-Id: I7ee164d2e6893c4e407fb7d579c75aa32843933a Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/quick/items/qquickwindow.cpp')
-rw-r--r--src/quick/items/qquickwindow.cpp1004
1 files changed, 402 insertions, 602 deletions
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;