summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2020-08-29 16:59:21 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2020-09-17 04:20:58 +0200
commit8932e80d0c8879a1e720fef825ed0d9c4e384a01 (patch)
treed4654c5d4a221d6a000d7e73a40be3d4170252f7
parentd1fc991c6e3c45a5f93c925d49e3fe77ce6ce455 (diff)
Add more QPointerEvent functions needed in Qt Quick
Change-Id: I87a874477b89eb3f5951930f03e305d896a24c2e Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r--src/gui/kernel/qevent.cpp59
-rw-r--r--src/gui/kernel/qevent.h31
-rw-r--r--src/gui/kernel/qevent_p.h6
-rw-r--r--src/gui/kernel/qpointingdevice.cpp93
-rw-r--r--src/gui/kernel/qpointingdevice.h1
-rw-r--r--src/gui/kernel/qpointingdevice_p.h5
6 files changed, 195 insertions, 0 deletions
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 811d2d1f20..6f4208fe84 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -606,6 +606,44 @@ QPointerEvent::~QPointerEvent()
}
/*!
+ Returns the point whose \l {QEventPoint::id()}{id} matches the given \a id,
+ or \c nullptr if no such point is found.
+*/
+QEventPoint *QPointerEvent::pointById(int id)
+{
+ for (auto &p : m_points) {
+ if (p.id() == id)
+ return &p;
+ }
+ return nullptr;
+}
+
+/*!
+ Returns \c true if every point in points() has an exclusiveGrabber().
+*/
+bool QPointerEvent::allPointsGrabbed() const
+{
+ for (const auto &p : points()) {
+ if (exclusiveGrabber(p) && passiveGrabbers(p).isEmpty())
+ return false;
+ }
+ return true;
+}
+
+/*!
+ Returns \c true if isPointAccepted() is \c true for every point in
+ points(); otherwise \c false.
+*/
+bool QPointerEvent::allPointsAccepted() const
+{
+ for (const auto &p : points()) {
+ if (!p.isAccepted())
+ return false;
+ }
+ return true;
+}
+
+/*!
Returns the source device from which this event originates.
This is the same as QInputEvent::device() but typecast for convenience.
@@ -844,6 +882,27 @@ QSinglePointEvent::QSinglePointEvent(QEvent::Type type, const QPointingDevice *d
m_points.append(mut);
}
+/*! \internal
+ Constructs a single-point event with the given \a point, which must be an instance
+ (or copy of one) that already exists in QPointingDevicePrivate::activePoints.
+ Unlike the other constructor, it does not modify the given \a point in any way.
+ This is useful when synthesizing a QMouseEvent from one point taken from a QTouchEvent, for example.
+
+ \sa QMutableSinglePointEvent()
+*/
+QSinglePointEvent::QSinglePointEvent(QEvent::Type type, const QPointingDevice *dev, const QEventPoint &point,
+ Qt::MouseButton button, Qt::MouseButtons buttons,
+ Qt::KeyboardModifiers modifiers, Qt::MouseEventSource source)
+ : QPointerEvent(type, dev, modifiers),
+ m_button(button),
+ m_mouseState(buttons),
+ m_source(source),
+ m_doubleClick(false),
+ m_reserved(0)
+{
+ m_points << point;
+}
+
/*!
Returns \c true if this event represents a \l {button()}{button} being pressed.
*/
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index 7f9a780959..ab87fc3c4b 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -63,8 +63,11 @@ QT_BEGIN_NAMESPACE
class QFile;
class QAction;
+class QMouseEvent;
class QPointerEvent;
class QScreen;
+class QTabletEvent;
+class QTouchEvent;
#if QT_CONFIG(gestures)
class QGesture;
#endif
@@ -94,6 +97,19 @@ struct QEventPointPrivate;
class Q_GUI_EXPORT QEventPoint
{
Q_GADGET
+ Q_PROPERTY(const QPointingDevice *device READ device)
+ Q_PROPERTY(int id READ id)
+ Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId)
+ Q_PROPERTY(State state READ state)
+ Q_PROPERTY(ulong timestamp READ timestamp)
+ Q_PROPERTY(qreal timeHeld READ timeHeld)
+ Q_PROPERTY(qreal pressure READ pressure)
+ Q_PROPERTY(qreal rotation READ rotation)
+ Q_PROPERTY(QSizeF ellipseDiameters READ ellipseDiameters)
+ Q_PROPERTY(QVector2D velocity READ velocity)
+ Q_PROPERTY(QPointF position READ position)
+ Q_PROPERTY(QPointF scenePosition READ scenePosition)
+ Q_PROPERTY(QPointF globalPosition READ globalPosition)
public:
enum State : quint8 {
Unknown = Qt::TouchPointUnknownState,
@@ -192,9 +208,12 @@ public:
qsizetype pointCount() const { return m_points.count(); }
QEventPoint &point(qsizetype i) { return m_points[i]; }
const QList<QEventPoint> &points() const { return m_points; }
+ QEventPoint *pointById(int id);
+ bool allPointsGrabbed() const;
virtual bool isPressEvent() const { return false; }
virtual bool isUpdateEvent() const { return false; }
virtual bool isReleaseEvent() const { return false; }
+ bool allPointsAccepted() const;
QObject *exclusiveGrabber(const QEventPoint &point) const;
void setExclusiveGrabber(const QEventPoint &point, QObject *exclusiveGrabber);
QList<QPointer <QObject>> passiveGrabbers(const QEventPoint &point) const;
@@ -229,6 +248,10 @@ public:
bool isReleaseEvent() const override;
protected:
+ QSinglePointEvent(Type type, const QPointingDevice *dev, const QEventPoint &point,
+ Qt::MouseButton button, Qt::MouseButtons buttons,
+ Qt::KeyboardModifiers modifiers, Qt::MouseEventSource source);
+
Qt::MouseButton m_button = Qt::NoButton;
Qt::MouseButtons m_mouseState = Qt::NoButton;
quint32 m_source : 8; // actually Qt::MouseEventSource
@@ -346,6 +369,12 @@ protected:
#if QT_CONFIG(wheelevent)
class Q_GUI_EXPORT QWheelEvent : public QSinglePointEvent
{
+ Q_GADGET
+ Q_PROPERTY(const QPointingDevice *device READ pointingDevice)
+ Q_PROPERTY(QPoint pixelDelta READ pixelDelta)
+ Q_PROPERTY(QPoint angleDelta READ angleDelta)
+ Q_PROPERTY(Qt::ScrollPhase phase READ phase)
+ Q_PROPERTY(bool inverted READ inverted)
public:
enum { DefaultDeltasPerStep = 120 };
@@ -360,6 +389,8 @@ public:
inline Qt::ScrollPhase phase() const { return Qt::ScrollPhase(m_phase); }
inline bool inverted() const { return m_invertedScrolling; }
+ inline bool isInverted() const { return m_invertedScrolling; }
+ inline bool hasPixelDelta() const { return !m_pixelDelta.isNull(); }
Qt::MouseEventSource source() const { return Qt::MouseEventSource(m_source); }
diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h
index 2bad2c0f5b..23a171e6ab 100644
--- a/src/gui/kernel/qevent_p.h
+++ b/src/gui/kernel/qevent_p.h
@@ -199,6 +199,12 @@ static_assert(sizeof(QMutableTouchEvent) == sizeof(QTouchEvent));
class Q_GUI_EXPORT QMutableSinglePointEvent : public QSinglePointEvent
{
public:
+ QMutableSinglePointEvent(Type type, const QPointingDevice *device, const QEventPoint &point,
+ Qt::MouseButton button = Qt::NoButton, Qt::MouseButtons buttons = Qt::NoButton,
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier,
+ Qt::MouseEventSource source = Qt::MouseEventSynthesizedByQt) :
+ QSinglePointEvent(type, device, point, button, buttons, modifiers, source) { }
+
static QMutableSinglePointEvent *from(QSinglePointEvent *e) { return static_cast<QMutableSinglePointEvent *>(e); }
static QMutableSinglePointEvent &from(QSinglePointEvent &e) { return static_cast<QMutableSinglePointEvent &>(e); }
diff --git a/src/gui/kernel/qpointingdevice.cpp b/src/gui/kernel/qpointingdevice.cpp
index 094193db4d..227c4ef2cc 100644
--- a/src/gui/kernel/qpointingdevice.cpp
+++ b/src/gui/kernel/qpointingdevice.cpp
@@ -354,6 +354,33 @@ const QPointingDevice *QPointingDevicePrivate::queryTabletDevice(QInputDevice::D
return nullptr;
}
+/*!
+ \internal
+ First, ensure that the \a cancelEvent's QTouchEvent::points() list contains
+ all points that have exclusive grabs. Then send the event to each object
+ that has an exclusive grab of any of the points.
+*/
+void QPointingDevicePrivate::sendTouchCancelEvent(QTouchEvent *cancelEvent)
+{
+ // An incoming TouchCancel event will typically not contain any points, but
+ // QQuickPointerHandler::onGrabChanged needs to be called for each point
+ // that has an exclusive grabber. Adding those points to the event makes it
+ // an easy iteration there.
+ if (cancelEvent->points().isEmpty()) {
+ for (auto &epd : activePoints.values()) {
+ if (epd.exclusiveGrabber)
+ QMutableTouchEvent::from(cancelEvent)->addPoint(epd.eventPoint);
+ }
+ }
+ for (auto &epd : activePoints.values()) {
+ if (epd.exclusiveGrabber)
+ QCoreApplication::sendEvent(epd.exclusiveGrabber, cancelEvent);
+ // The next touch event can only be a TouchBegin, so clean up.
+ cancelEvent->setExclusiveGrabber(epd.eventPoint, nullptr);
+ cancelEvent->clearPassiveGrabbers(epd.eventPoint);
+ }
+}
+
/*! \internal
Returns the active EventPointData instance with the given \a id, if available,
or \c nullptr if not.
@@ -422,6 +449,19 @@ QWindow *QPointingDevicePrivate::firstActiveWindow() const
return nullptr;
}
+/*! \internal
+ Return the exclusive grabber of the first point in activePoints.
+ This is mainly for autotests that try to verify the "current" grabber
+ outside the context of event delivery, which is something that the rest
+ of the codebase should not be doing.
+*/
+QObject *QPointingDevicePrivate::firstPointExclusiveGrabber() const
+{
+ if (activePoints.isEmpty())
+ return nullptr;
+ return activePoints.values().first().exclusiveGrabber;
+}
+
void QPointingDevicePrivate::setExclusiveGrabber(const QPointerEvent *event, const QEventPoint &point, QObject *exclusiveGrabber)
{
Q_Q(QPointingDevice);
@@ -446,6 +486,22 @@ void QPointingDevicePrivate::setExclusiveGrabber(const QPointerEvent *event, con
emit q->grabChanged(exclusiveGrabber, QPointingDevice::GrabExclusive, event, point);
}
+/*!
+ \internal
+ Call QEventPoint::setExclusiveGrabber(nullptr) on each active point that has a grabber.
+*/
+bool QPointingDevicePrivate::removeExclusiveGrabber(const QPointerEvent *event, const QObject *grabber)
+{
+ bool ret = false;
+ for (auto &pt : activePoints.values()) {
+ if (pt.exclusiveGrabber == grabber) {
+ setExclusiveGrabber(event, pt.eventPoint, nullptr);
+ ret = true;
+ }
+ }
+ return ret;
+}
+
bool QPointingDevicePrivate::addPassiveGrabber(const QPointerEvent *event, const QEventPoint &point, QObject *grabber)
{
Q_Q(QPointingDevice);
@@ -507,6 +563,43 @@ void QPointingDevicePrivate::clearPassiveGrabbers(const QPointerEvent *event, co
/*!
\internal
+ Removes the given \a grabber as both passive and exclusive grabber from all
+ points in activePoints where it's currently found. If \a cancel is \c true,
+ the transition emitted from the grabChanged() signal will be
+ \c CancelGrabExclusive or \c CancelGrabPassive. Otherwise it will be
+ \c UngrabExclusive or \c UngrabPassive.
+
+ \note This function provides a way to work around the limitation that we
+ normally change grabbers only during event delivery; but it's also more expensive.
+*/
+void QPointingDevicePrivate::removeGrabber(QObject *grabber, bool cancel)
+{
+ Q_Q(QPointingDevice);
+ for (auto ap : activePoints) {
+ auto &epd = ap.second;
+ if (epd.exclusiveGrabber.data() == grabber) {
+ qCDebug(lcPointerGrab) << name << "point" << epd.eventPoint.id() << epd.eventPoint.state()
+ << "@" << epd.eventPoint.scenePosition()
+ << ": grab" << grabber << "-> nullptr";
+ epd.exclusiveGrabber.clear();
+ emit q->grabChanged(grabber,
+ cancel ? QPointingDevice::CancelGrabExclusive : QPointingDevice::UngrabExclusive,
+ nullptr, epd.eventPoint);
+ }
+ int pi = epd.passiveGrabbers.indexOf(grabber);
+ if (pi >= 0) {
+ qCDebug(lcPointerGrab) << name << "point" << epd.eventPoint.id() << epd.eventPoint.state()
+ << ": removing passive grabber" << grabber;
+ epd.passiveGrabbers.removeAt(pi);
+ emit q->grabChanged(grabber,
+ cancel ? QPointingDevice::CancelGrabPassive : QPointingDevice::UngrabPassive,
+ nullptr, epd.eventPoint);
+ }
+ }
+}
+
+/*!
+ \internal
Finds the device instance belonging to the drawing or eraser end of a particular stylus,
identified by its \a deviceType, \a pointerType and \a uniqueId. If an existing device
is not found, a new one is created and registered, with a warning.
diff --git a/src/gui/kernel/qpointingdevice.h b/src/gui/kernel/qpointingdevice.h
index 476931432b..30c7c8ca1a 100644
--- a/src/gui/kernel/qpointingdevice.h
+++ b/src/gui/kernel/qpointingdevice.h
@@ -50,6 +50,7 @@ class QDebug;
class QEventPoint;
class QPointerEvent;
class QPointingDevicePrivate;
+class QPointerEvent;
class QScreen;
class Q_GUI_EXPORT QPointingDeviceUniqueId
diff --git a/src/gui/kernel/qpointingdevice_p.h b/src/gui/kernel/qpointingdevice_p.h
index 811f5ba01b..871c39939f 100644
--- a/src/gui/kernel/qpointingdevice_p.h
+++ b/src/gui/kernel/qpointingdevice_p.h
@@ -77,6 +77,8 @@ public:
activePoints.reserve(maxPoints);
}
+ void sendTouchCancelEvent(QTouchEvent *cancelEvent);
+
/*! \internal
This struct (stored in activePoints) holds persistent state between event deliveries.
*/
@@ -91,10 +93,13 @@ public:
QObject *firstActiveTarget() const;
QWindow *firstActiveWindow() const;
+ QObject *firstPointExclusiveGrabber() const;
void setExclusiveGrabber(const QPointerEvent *event, const QEventPoint &point, QObject *exclusiveGrabber);
+ bool removeExclusiveGrabber(const QPointerEvent *event, const QObject *grabber);
bool addPassiveGrabber(const QPointerEvent *event, const QEventPoint &point, QObject *grabber);
bool removePassiveGrabber(const QPointerEvent *event, const QEventPoint &point, QObject *grabber);
void clearPassiveGrabbers(const QPointerEvent *event, const QEventPoint &point);
+ void removeGrabber(QObject *grabber, bool cancel = false);
using EventPointMap = QFlatMap<int, EventPointData>;
mutable EventPointMap activePoints;