aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2016-09-01 06:16:18 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2017-02-02 19:17:35 +0000
commite2fd141372335f917c2d216051abb00d8b15f87c (patch)
tree8521c470e66d1a1badeb3c3020774abc66d639f7 /src
parent73e9dc0667935b7b403c10736775d24d6e22eb8c (diff)
QQuickWindow: deliver updates to handlers even if they don't grab
The "weak grab" concept depends on this. First we deliver to grabbers, then we deliver to non-grabbing handlers (but not to non-grabbing items). Avoid re-delivering to grabbing handlers which already received the same event. Change-Id: If51e1cd9372e3bed1daea3758e9ef8e37c0ba5e3 Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
Diffstat (limited to 'src')
-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
5 files changed, 79 insertions, 5 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;
}