summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qevent.h
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2020-09-03 21:34:31 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2020-09-16 11:33:03 +0200
commit2692237bb1b0c0f50b7cc5d920eb8ab065063d47 (patch)
tree8f114b0313fcf04f128e265efaaabc8a130b2f6e /src/gui/kernel/qevent.h
parent4ceef8a3a6d64474344cac4a6ed4b32b09d38367 (diff)
Track grab state in QPointingDevicePrivate::activePoints
QQuickEventPoint instances were very long-lived and got reused from one event to the next. That was initially done because they were "heavy" QObjects; but it also became useful to store state in them between events. But this is in conflict with the ubiquitous event replay code that assumes it's OK to hold an event instance (especially a QMouseEvent) for any length of time, and then send it to some widget, item or window. Clearly QEventPoints must be stored in the QPointerEvent, if we are to avoid the need for workarounds to keep such old code working. And now they have d-pointers, so copying is cheap. But replay code will need to detach() their QEventPoints now. QEventPoint is useful as an object to hold state, but we now store the truly persistent state separately in an EventPointData struct, in QPointingDevicePrivate::activePoints. Incoming events merely update the persistent points, then we deliver those instead. Thus when event handler code modifies state, it will be remembered even when the delivery is done and the QPA event is destroyed. This gets us a step closer to supporting multiple simultaneous mice. Within pointer events, the points are moved up to QPointerEvent itself: QList<QEventPoint> m_points; This means pointCount(), point(int i) and points() can be non-virtual. However in any QSinglePointEvent, the list only contains one point. We hope that pessimization is worthwhile for the sake of removing virtual functions, simplifying code in event classes themselves, and enabling the use of the range-for loop over points() with any kind of QPointerEvent, not just QTouchEvent. points() is a nicer API for the sake of range-for looping; but point() is more suited to being non-const. In QML it's expected to be OK to emit a signal with a QPointerEvent by value: that will involve copying the event. But QEventPoint instances are explicitly shared, so calling setAccepted() modifies the instance in activePoints (EventPointData.eventPoint.d->accept); and the grabbers are stored separately and thus preserved between events. In code such as MouseArea { onPressed: mouse.accepted = false } we can either continue to emit the QQuickMouseEvent wrapper or perhaps QEvent::setAccepted() could become virtual and set the eventpoint's accepted flag instead, so that it will survive after the event copy that QML sees is discarded. The grabChanged() signal is useful to keep QQuickWindow informed when items or handlers change exclusive or passive grabbers. When a release happens at a different location than the last move event, Qt synthesizes an additional move. But it would be "boring" if QEventPoint::lastXPosition() accessors in any released eventpoint always returned the same as the current QEventPoint::xPosition()s just because of that; and it would mean that the velocity() must always be zero on release, which would make it hard to use the final velocity to drive an animation. So now we expect the lastPositions to be different than current positions in a released eventpoint. De-inline some functions whose implementations might be subject to change later on. Improve documentation. Since we have an accessor for pressTimestamp(), we might as well add one for timestamp() too. That way users get enough information to calculate instantaneous velocity, since the plan is for velocity() to be somewhat smoothed. Change-Id: I2733d847139a1b1bea33c00275459dcd2a145ffc Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/gui/kernel/qevent.h')
-rw-r--r--src/gui/kernel/qevent.h42
1 files changed, 25 insertions, 17 deletions
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index e4a35ed994..195fd1ae77 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -79,7 +79,7 @@ public:
inline Qt::KeyboardModifiers modifiers() const { return m_modState; }
inline void setModifiers(Qt::KeyboardModifiers modifiers) { m_modState = modifiers; }
inline ulong timestamp() const { return m_timeStamp; }
- inline void setTimestamp(ulong timestamp) { m_timeStamp = timestamp; }
+ virtual void setTimestamp(ulong timestamp) { m_timeStamp = timestamp; }
protected:
QInputEvent(Type type, PointerEventTag, const QInputDevice *m_dev, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
@@ -156,6 +156,7 @@ public:
const QPointingDevice *device() const;
int id() const;
QPointingDeviceUniqueId uniqueId() const;
+ ulong timestamp() const;
ulong pressTimestamp() const;
qreal timeHeld() const;
qreal pressure() const;
@@ -172,20 +173,24 @@ private:
};
#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QEventPoint *);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QEventPoint &);
#endif
class Q_GUI_EXPORT QPointerEvent : public QInputEvent
{
public:
- explicit QPointerEvent(Type type, const QPointingDevice *dev, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
+ explicit QPointerEvent(Type type, const QPointingDevice *dev,
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier, const QList<QEventPoint> &points = {});
virtual ~QPointerEvent();
const QPointingDevice *pointingDevice() const;
QPointingDevice::PointerType pointerType() const {
return pointingDevice() ? pointingDevice()->pointerType() : QPointingDevice::PointerType::Unknown;
}
- virtual int pointCount() const = 0;
- virtual const QEventPoint &point(int i) const = 0;
+ void setTimestamp(ulong timestamp) override;
+ qsizetype pointCount() const { return m_points.count(); }
+ QEventPoint &point(qsizetype i) { return m_points[i]; }
+ const QList<QEventPoint> &points() const { return m_points; }
virtual bool isPressEvent() const { return false; }
virtual bool isUpdateEvent() const { return false; }
virtual bool isReleaseEvent() const { return false; }
@@ -195,6 +200,9 @@ public:
void clearPassiveGrabbers(const QEventPoint &point);
bool addPassiveGrabber(const QEventPoint &point, QObject *grabber);
bool removePassiveGrabber(const QEventPoint &point, QObject *grabber);
+
+protected:
+ QList<QEventPoint> m_points;
};
class Q_GUI_EXPORT QSinglePointEvent : public QPointerEvent
@@ -204,22 +212,22 @@ public:
const QPointF &scenePos, const QPointF &globalPos,
Qt::MouseButton button = Qt::NoButton, Qt::MouseButtons buttons = Qt::NoButton,
Qt::KeyboardModifiers modifiers = Qt::NoModifier);
- int pointCount() const override { return 1; }
- const QEventPoint &point(int i) const override { Q_ASSERT(i == 0); return m_point; }
inline Qt::MouseButton button() const { return m_button; }
inline Qt::MouseButtons buttons() const { return m_mouseState; }
- inline QPointF position() const { return m_point.position(); }
- inline QPointF scenePosition() const { return m_point.scenePosition(); }
- inline QPointF globalPosition() const { return m_point.globalPosition(); }
+ inline QPointF position() const
+ { Q_ASSERT(!m_points.isEmpty()); return m_points.first().position(); }
+ inline QPointF scenePosition() const
+ { Q_ASSERT(!m_points.isEmpty()); return m_points.first().scenePosition(); }
+ inline QPointF globalPosition() const
+ { Q_ASSERT(!m_points.isEmpty()); return m_points.first().globalPosition(); }
bool isPressEvent() const override;
bool isUpdateEvent() const override;
bool isReleaseEvent() const override;
protected:
- QEventPoint m_point;
Qt::MouseButton m_button = Qt::NoButton;
Qt::MouseButtons m_mouseState = Qt::NoButton;
quint32 m_source : 8; // actually Qt::MouseEventSource
@@ -400,8 +408,8 @@ public:
QT_DEPRECATED_VERSION_X_6_0("use pointingDevice().uniqueId()")
inline qint64 uniqueId() const { return pointingDevice() ? pointingDevice()->uniqueId().numericId() : -1; }
#endif
- inline qreal pressure() const { return point(0).pressure(); }
- inline qreal rotation() const { return point(0).rotation(); }
+ inline qreal pressure() const { Q_ASSERT(!points().isEmpty()); return points().first().pressure(); }
+ inline qreal rotation() const { Q_ASSERT(!points().isEmpty()); return points().first().rotation(); }
inline int z() const { return m_z; }
inline qreal tangentialPressure() const { return m_tangential; }
inline int xTilt() const { return m_xTilt; }
@@ -950,12 +958,12 @@ public:
#endif
~QTouchEvent();
- int pointCount() const override { return m_touchPoints.count(); }
- const QEventPoint &point(int i) const override { return m_touchPoints.at(i); }
-
inline QObject *target() const { return m_target; }
inline QEventPoint::States touchPointStates() const { return m_touchPointStates; }
- const QList<QEventPoint> &touchPoints() const { return m_touchPoints; }
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED_VERSION_X_6_0("Use points()")
+ const QList<QEventPoint> &touchPoints() const { return points(); }
+#endif
bool isPressEvent() const override;
bool isUpdateEvent() const override;
bool isReleaseEvent() const override;
@@ -963,7 +971,7 @@ public:
protected:
QObject *m_target = nullptr;
QEventPoint::States m_touchPointStates = QEventPoint::State::Unknown;
- QList<QEventPoint> m_touchPoints;
+ quint32 m_reserved : 24;
};
class Q_GUI_EXPORT QScrollPrepareEvent : public QEvent