aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/items/qquickevents.cpp27
-rw-r--r--src/quick/items/qquickevents_p_p.h6
-rw-r--r--src/quick/items/qquickitem.cpp9
-rw-r--r--src/quick/items/qquickitem_p.h2
-rw-r--r--src/quick/items/qquickwindow.cpp40
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp57
6 files changed, 112 insertions, 29 deletions
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 0c18cb4104..a68e72b0b7 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -835,6 +835,11 @@ bool QQuickPointerMouseEvent::allPointsAccepted() const {
return m_mousePoint->isAccepted();
}
+bool QQuickPointerMouseEvent::allPointsGrabbed() const
+{
+ return m_mousePoint->grabber() != nullptr;
+}
+
QMouseEvent *QQuickPointerMouseEvent::asMouseEvent(const QPointF &localPos) const
{
auto event = static_cast<QMouseEvent *>(m_event);
@@ -854,6 +859,11 @@ void QQuickPointerMouseEvent::clearGrabbers() const {
m_mousePoint->setGrabberItem(nullptr);
}
+bool QQuickPointerMouseEvent::hasGrabber(const QQuickPointerHandler *handler) const
+{
+ return m_mousePoint->grabber() == handler;
+}
+
bool QQuickPointerMouseEvent::isPressEvent() const
{
auto me = static_cast<QMouseEvent*>(m_event);
@@ -869,6 +879,15 @@ bool QQuickPointerTouchEvent::allPointsAccepted() const {
return true;
}
+bool QQuickPointerTouchEvent::allPointsGrabbed() const
+{
+ for (int i = 0; i < m_pointCount; ++i) {
+ if (!m_touchPoints.at(i)->grabber())
+ return false;
+ }
+ return true;
+}
+
QVector<QObject *> QQuickPointerTouchEvent::grabbers() const
{
QVector<QObject *> result;
@@ -887,6 +906,14 @@ void QQuickPointerTouchEvent::clearGrabbers() const {
point->setGrabber(nullptr);
}
+bool QQuickPointerTouchEvent::hasGrabber(const QQuickPointerHandler *handler) const
+{
+ for (auto point: m_touchPoints)
+ if (point->grabber() == handler)
+ return true;
+ return false;
+}
+
bool QQuickPointerTouchEvent::isPressEvent() const
{
return static_cast<QTouchEvent*>(m_event)->touchPointStates() & Qt::TouchPointPressed;
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index 4a78e98705..bbfc34dacf 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -393,6 +393,7 @@ public: // helpers for C++ only (during event delivery)
virtual const QQuickPointerTabletEvent *asPointerTabletEvent() const { return nullptr; }
bool isValid() const { return m_event != nullptr; }
virtual bool allPointsAccepted() const = 0;
+ virtual bool allPointsGrabbed() const = 0;
bool isAccepted() { return m_event->isAccepted(); }
void setAccepted(bool accepted) { m_event->setAccepted(accepted); }
QVector<QPointF> unacceptedPressedPointScenePositions() const;
@@ -402,6 +403,7 @@ public: // helpers for C++ only (during event delivery)
virtual QQuickEventPoint *pointById(quint64 pointId) const = 0;
virtual QVector<QObject *> grabbers() const = 0;
virtual void clearGrabbers() const = 0;
+ virtual bool hasGrabber(const QQuickPointerHandler *handler) const = 0;
ulong timestamp() const { return m_event->timestamp(); }
@@ -430,8 +432,10 @@ public:
QQuickEventPoint *point(int i) const override;
QQuickEventPoint *pointById(quint64 pointId) const override;
bool allPointsAccepted() const override;
+ bool allPointsGrabbed() const override;
QVector<QObject *> grabbers() const override;
void clearGrabbers() const override;
+ bool hasGrabber(const QQuickPointerHandler *handler) const override;
QMouseEvent *asMouseEvent(const QPointF& localPos) const;
@@ -461,8 +465,10 @@ public:
QQuickEventPoint *pointById(quint64 pointId) const override;
const QTouchEvent::TouchPoint *touchPointById(int pointId) const;
bool allPointsAccepted() const override;
+ bool allPointsGrabbed() const override;
QVector<QObject *> grabbers() const override;
void clearGrabbers() const override;
+ bool hasGrabber(const QQuickPointerHandler *handler) const override;
QMouseEvent *syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const;
QTouchEvent *touchEventForItem(QQuickItem *item, bool isFiltering = false) const;
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 98cc3112df..46e381db7d 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -5091,15 +5091,20 @@ void QQuickItemPrivate::deliverShortcutOverrideEvent(QKeyEvent *event)
}
}
-void QQuickItemPrivate::handlePointerEvent(QQuickPointerEvent *event)
+bool QQuickItemPrivate::handlePointerEvent(QQuickPointerEvent *event, bool avoidGrabber)
{
Q_Q(QQuickItem);
+ bool delivered = false;
if (extra.isAllocated()) {
for (QQuickPointerHandler *handler : extra->pointerHandlers) {
qCDebug(lcPointerHandlerDispatch) << " delivering" << event << "to" << handler << "on" << q;
- handler->handlePointerEvent(event);
+ if (!avoidGrabber || !event->hasGrabber(handler)) {
+ handler->handlePointerEvent(event);
+ delivered = true;
+ }
}
}
+ return delivered;
}
/*!
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index e7ead7fa87..b39c437da5 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -563,7 +563,7 @@ public:
#endif
void deliverShortcutOverrideEvent(QKeyEvent *);
- virtual void handlePointerEvent(QQuickPointerEvent *);
+ virtual bool handlePointerEvent(QQuickPointerEvent *, bool avoidGrabber = false);
bool isTransparentForPositioner() const;
void setTransparentForPositioner(bool trans);
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 6897240fbd..f7d6b245b2 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1685,11 +1685,23 @@ void QQuickWindowPrivate::deliverMouseEvent(QQuickPointerMouseEvent *pointerEven
if (me->type() == QEvent::MouseButtonRelease && !me->buttons() && q->mouseGrabberItem())
q->mouseGrabberItem()->ungrabMouse();
} else {
- // send initial press
bool delivered = false;
if (pointerEvent->isPressEvent()) {
+ // send initial press
QSet<QQuickItem*> hasFiltered;
delivered = deliverPressEvent(pointerEvent, &hasFiltered);
+ } else if (pointerEvent->device()->type() == QQuickPointerDevice::Mouse) {
+ // if this is an update or release from an actual mouse,
+ // and the point wasn't grabbed, deliver only to non-grabber PointerHandlers
+ QVector<QQuickItem *> targetItems = pointerTargets(contentItem, point->scenePos(), false);
+ for (QQuickItem *item : targetItems) {
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ pointerEvent->localize(item);
+ if (itemPrivate->handlePointerEvent(pointerEvent, true)) // avoid re-delivering to grabbers
+ delivered = true;
+ if (point->grabber())
+ break;
+ }
}
if (!delivered)
@@ -2082,7 +2094,6 @@ void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event)
accepted = clearHover(event->timestamp());
}
event->setAccepted(accepted);
- return;
}
deliverPointerEvent(pointerEventInstance(event));
break;
@@ -2271,6 +2282,31 @@ bool QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *eve
deliverMatchingPointsToItem(receiver, event, hasFiltered);
}
+ // If some points weren't grabbed, deliver only to non-grabber PointerHandlers
+ if (!event->allPointsGrabbed()) {
+ QVector<QQuickItem *> targetItems;
+ int pointCount = event->pointCount();
+ for (int i = 0; i < pointCount; ++i) {
+ QQuickEventPoint *point = event->point(i);
+ QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, point->scenePos(), false);
+ if (targetItems.count()) {
+ targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
+ } else {
+ targetItems = targetItemsForPoint;
+ }
+ }
+
+ for (QQuickItem *item: targetItems) {
+ if (grabbers.contains(item))
+ continue;
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ event->localize(item);
+ itemPrivate->handlePointerEvent(event, true); // avoid re-delivering to grabbers
+ if (event->allPointsGrabbed())
+ break;
+ }
+ }
+
return false;
}
diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp
index 94bb44a12b..8f65ec6d7f 100644
--- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp
@@ -76,7 +76,7 @@ class EventItem : public QQuickItem
Q_OBJECT
public:
EventItem(QQuickItem *parent = 0)
- : QQuickItem(parent), acceptPointer(false), acceptMouse(false), acceptTouch(false), filterTouch(false)
+ : QQuickItem(parent), acceptPointer(false), grabPointer(false), acceptMouse(false), acceptTouch(false), filterTouch(false)
{}
void touchEvent(QTouchEvent *event)
@@ -125,6 +125,7 @@ public:
QList<Event> eventList;
bool acceptPointer;
+ bool grabPointer;
bool acceptMouse;
bool acceptTouch;
bool filterTouch; // when used as event filter
@@ -159,10 +160,11 @@ class EventHandler : public QQuickPointerHandler
int c = event->pointCount();
for (int i = 0; i < c; ++i) {
QQuickEventPoint *point = event->point(i);
- point->setAccepted(item->acceptPointer); // has no effect: grabbing is up to us
if (item->acceptPointer)
- setGrab(point, true);
- qCDebug(lcPointerTests) << " " << i << ":" << point << "grabbed?" << item->acceptPointer;
+ point->setAccepted(item->acceptPointer); // non-exclusive grab
+ if (item->grabPointer)
+ setGrab(point, true); // exclusive grab
+ qCDebug(lcPointerTests) << " " << i << ":" << point << "accepted?" << item->acceptPointer << "grabbed?" << (point->grabber() == this);
item->eventList.append(Event(QEvent::Pointer, eventPos(point), point->scenePos()));
}
}
@@ -236,17 +238,20 @@ void tst_PointerHandlers::touchEventDelivery()
QPoint p1 = QPoint(20, 20);
QTest::touchEvent(window, touchDevice).press(0, p1, window);
QQuickTouchUtils::flush(window);
- QTRY_COMPARE(eventItem1->eventList.size(), 3);
+ QTRY_COMPARE(eventItem1->eventList.size(), 4);
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer);
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin);
QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress);
+ QCOMPARE(eventItem1->eventList.at(3).type, QEvent::Pointer);
p1 += QPoint(10, 0);
QTest::touchEvent(window, touchDevice).move(0, p1, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE(eventItem1->eventList.size(), 5);
+ QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer);
QTest::touchEvent(window, touchDevice).release(0, p1, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE(eventItem1->eventList.size(), 6);
+ QCOMPARE(eventItem1->eventList.at(5).type, QEvent::Pointer);
eventItem1->eventList.clear();
// Accept touch
@@ -321,18 +326,19 @@ void tst_PointerHandlers::touchEventDelivery()
p1 = QPoint(20, 20);
QTest::touchEvent(window, touchDevice).press(0, p1, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE(eventItem1->eventList.size(), 4);
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer);
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin);
QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress);
+ QCOMPARE(eventItem1->eventList.at(3).type, QEvent::Pointer);
QCOMPARE(pointerEvent->point(0)->grabber(), nullptr);
p1 += QPoint(10, 0);
QTest::touchEvent(window, touchDevice).move(0, p1, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE(eventItem1->eventList.size(), 5);
QTest::touchEvent(window, touchDevice).release(0, p1, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE(eventItem1->eventList.size(), 6);
eventItem1->eventList.clear();
// wait to avoid getting a double click event
@@ -362,6 +368,7 @@ void tst_PointerHandlers::touchEventDelivery()
// Accept pointer events
eventItem1->acceptPointer = true;
+ eventItem1->grabPointer = true;
p1 = QPoint(20, 20);
QTest::touchEvent(window, touchDevice).press(0, p1, window);
QQuickTouchUtils::flush(window);
@@ -398,12 +405,12 @@ void tst_PointerHandlers::mouseEventDelivery()
// Do not accept anything
QPoint p1 = QPoint(20, 20);
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
- QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.size(), 3);
p1 += QPoint(10, 0);
QTest::mouseMove(window, p1);
- QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.size(), 4);
QTest::mouseRelease(window, Qt::LeftButton);
- QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.size(), 4);
eventItem1->eventList.clear();
// wait to avoid getting a double click event
@@ -415,9 +422,10 @@ void tst_PointerHandlers::mouseEventDelivery()
eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
p1 = QPoint(20, 20);
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
- QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.size(), 3);
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer);
- QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
+ QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer);
+ QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress);
QCOMPARE(window->mouseGrabberItem(), eventItem1);
QPointF localPos = eventItem1->mapFromScene(p1);
@@ -429,30 +437,31 @@ void tst_PointerHandlers::mouseEventDelivery()
p1 += QPoint(10, 0);
QTest::mouseMove(window, p1);
- QCOMPARE(eventItem1->eventList.size(), 3);
- QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseMove);
+ QCOMPARE(eventItem1->eventList.size(), 4);
+ QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
- QCOMPARE(eventItem1->eventList.size(), 5);
- QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease);
- QCOMPARE(eventItem1->eventList.at(4).type, QEvent::UngrabMouse);
+ QCOMPARE(eventItem1->eventList.size(), 6);
+ QCOMPARE(eventItem1->eventList.at(4).type, QEvent::MouseButtonRelease);
+ QCOMPARE(eventItem1->eventList.at(5).type, QEvent::UngrabMouse);
eventItem1->eventList.clear();
// wait to avoid getting a double click event
QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
- // Accept pointer events
+ // Grab pointer events
eventItem1->acceptMouse = false;
eventItem1->acceptPointer = true;
+ eventItem1->grabPointer = true;
p1 = QPoint(20, 20);
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
- QTRY_COMPARE(eventItem1->eventList.size(), 1);
+ QTRY_COMPARE(eventItem1->eventList.size(), 2);
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer);
p1 += QPoint(10, 0);
QTest::mouseMove(window, p1);
- QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.size(), 3);
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
- QCOMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE(eventItem1->eventList.size(), 4);
QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer);
eventItem1->eventList.clear();