summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qguiapplication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel/qguiapplication.cpp')
-rw-r--r--src/gui/kernel/qguiapplication.cpp249
1 files changed, 101 insertions, 148 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 15955e2287..2bbeef4c30 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -59,6 +59,7 @@
#include <QtCore/qmutex.h>
#include <QtCore/private/qthread_p.h>
#include <QtCore/private/qlocking_p.h>
+#include <QtCore/private/qflatmap_p.h>
#include <QtCore/qdir.h>
#include <QtCore/qlibraryinfo.h>
#include <QtCore/qnumeric.h>
@@ -155,7 +156,7 @@ bool QGuiApplicationPrivate::highDpiScalingUpdated = false;
QPointer<QWindow> QGuiApplicationPrivate::currentDragWindow;
-QList<QGuiApplicationPrivate::TabletPointData> QGuiApplicationPrivate::tabletDevicePoints;
+QList<QGuiApplicationPrivate::TabletPointData> QGuiApplicationPrivate::tabletDevicePoints; // TODO remove
QPlatformIntegration *QGuiApplicationPrivate::platform_integration = nullptr;
QPlatformTheme *QGuiApplicationPrivate::platform_theme = nullptr;
@@ -177,10 +178,7 @@ QString *QGuiApplicationPrivate::desktopFileName = nullptr;
QPalette *QGuiApplicationPrivate::app_pal = nullptr; // default application palette
-ulong QGuiApplicationPrivate::mousePressTime = 0;
Qt::MouseButton QGuiApplicationPrivate::mousePressButton = Qt::NoButton;
-int QGuiApplicationPrivate::mousePressX = 0; // TODO use QPointF and store it in QPointingDevicePrivate
-int QGuiApplicationPrivate::mousePressY = 0;
static int mouseDoubleClickDistance = -1;
static int touchDoubleTapDistance = -1;
@@ -716,8 +714,6 @@ QGuiApplication::~QGuiApplication()
QGuiApplicationPrivate::highDpiScalingUpdated = false;
QGuiApplicationPrivate::currentDragWindow = nullptr;
QGuiApplicationPrivate::tabletDevicePoints.clear();
- QGuiApplicationPrivate::mousePressTime = 0;
- QGuiApplicationPrivate::mousePressX = QGuiApplicationPrivate::mousePressY = 0;
}
QGuiApplicationPrivate::QGuiApplicationPrivate(int &argc, char **argv, int flags)
@@ -1195,6 +1191,7 @@ QString QGuiApplication::platformName()
}
Q_LOGGING_CATEGORY(lcQpaPluginLoading, "qt.qpa.plugin");
+Q_LOGGING_CATEGORY(lcPtrDispatch, "qt.pointer.dispatch");
static void init_platform(const QString &pluginNamesWithArguments, const QString &platformPluginPath, const QString &platformThemeName, int &argc, char **argv)
{
@@ -2132,9 +2129,13 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
QEvent::Type type = QEvent::None;
Qt::MouseButton button = Qt::NoButton;
QWindow *window = e->window.data();
+ const QPointingDevice *device = static_cast<const QPointingDevice *>(e->device);
+ Q_ASSERT(device);
+ QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(const_cast<QPointingDevice*>(device));
bool positionChanged = QGuiApplicationPrivate::lastCursorPosition != e->globalPos;
bool mouseMove = false;
bool mousePress = false;
+ QPointF globalPoint = e->globalPos;
if (e->enhancedMouseEvent()) {
type = e->buttonType;
@@ -2207,27 +2208,24 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
modifier_buttons = e->modifiers;
QPointF localPoint = e->localPos;
- QPointF globalPoint = e->globalPos;
- const QPointF lastGlobalPosition = QGuiApplicationPrivate::lastCursorPosition;
bool doubleClick = false;
+ auto persistentEPD = devPriv->pointById(0);
+ const auto &persistentPoint = QMutableEventPoint::from(persistentEPD->eventPoint);
if (mouseMove) {
QGuiApplicationPrivate::lastCursorPosition = globalPoint;
const auto doubleClickDistance = (e->device && e->device->type() == QInputDevice::DeviceType::Mouse ?
mouseDoubleClickDistance : touchDoubleTapDistance);
- if (qAbs(globalPoint.x() - mousePressX) > doubleClickDistance ||
- qAbs(globalPoint.y() - mousePressY) > doubleClickDistance)
+ const auto pressPos = persistentPoint.globalPressPosition();
+ if (qAbs(globalPoint.x() - pressPos.x()) > doubleClickDistance ||
+ qAbs(globalPoint.y() - pressPos.y()) > doubleClickDistance)
mousePressButton = Qt::NoButton;
} else {
mouse_buttons = e->buttons;
if (mousePress) {
ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
- doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton;
- mousePressTime = e->timestamp;
+ doubleClick = e->timestamp - persistentPoint.pressTimestamp() < doubleClickInterval && button == mousePressButton;
mousePressButton = button;
- const QPoint point = QGuiApplicationPrivate::lastCursorPosition.toPoint();
- mousePressX = point.x();
- mousePressY = point.y();
}
}
@@ -2252,7 +2250,6 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
if (!window)
return;
- const QPointingDevice *device = static_cast<const QPointingDevice *>(e->device);
#ifndef QT_NO_CURSOR
if (!e->synthetic()) {
if (const QScreen *screen = window->screen())
@@ -2268,11 +2265,8 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
#endif
QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, e->buttons, e->modifiers, e->source, device);
+ // ev now contains a detached copy of the QEventPoint from QPointingDevicePrivate::activePoints
ev.setTimestamp(e->timestamp);
- QMutableEventPoint &mutPt = QMutableSinglePointEvent::from(ev).mutablePoint();
- mutPt.setGlobalLastPosition(lastGlobalPosition);
- mutPt.setGlobalPressPosition(QPointF(mousePressX, mousePressY));
-
if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
// a modal window is blocking this window, don't allow mouse events through
return;
@@ -2330,6 +2324,10 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent);
}
}
+ if (type == QEvent::MouseButtonRelease && e->buttons == Qt::NoButton) {
+ ev.setExclusiveGrabber(persistentPoint, nullptr);
+ ev.clearPassiveGrabbers(persistentPoint);
+ }
}
void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::WheelEvent *e)
@@ -2806,38 +2804,28 @@ void QGuiApplicationPrivate::processContextMenuEvent(QWindowSystemInterfacePriva
}
#endif
-Q_GUI_EXPORT size_t qHash(const QGuiApplicationPrivate::ActiveTouchPointsKey &k, size_t seed)
-{
- return (qHash(k.device) + k.touchPointId) ^ seed;
-}
-
-Q_GUI_EXPORT bool operator==(const QGuiApplicationPrivate::ActiveTouchPointsKey &a,
- const QGuiApplicationPrivate::ActiveTouchPointsKey &b)
-{
- return a.device == b.device
- && a.touchPointId == b.touchPointId;
-}
-
void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::TouchEvent *e)
{
- QGuiApplicationPrivate *d = self;
modifier_buttons = e->modifiers;
- const QPointingDevice *device = static_cast<const QPointingDevice *>(e->device);
+ QPointingDevice *device = const_cast<QPointingDevice *>(static_cast<const QPointingDevice *>(e->device));
+ QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(device);
if (e->touchType == QEvent::TouchCancel) {
// The touch sequence has been canceled (e.g. by the compositor).
// Send the TouchCancel to all windows with active touches and clean up.
QTouchEvent touchEvent(QEvent::TouchCancel, device, e->modifiers);
touchEvent.setTimestamp(e->timestamp);
- QHash<ActiveTouchPointsKey, ActiveTouchPointsValue>::const_iterator it
- = self->activeTouchPoints.constBegin(), ite = self->activeTouchPoints.constEnd();
QSet<QWindow *> windowsNeedingCancel;
- while (it != ite) {
- QWindow *w = it->window.data();
+
+ for (auto &epd : devPriv->activePoints.values()) {
+ auto &mut = QMutableEventPoint::from(const_cast<QEventPoint &>(epd.eventPoint));
+ QWindow *w = mut.window();
if (w)
windowsNeedingCancel.insert(w);
- ++it;
+ mut.setWindow(nullptr);
+ mut.setTarget(nullptr);
}
+
for (QSet<QWindow *>::const_iterator winIt = windowsNeedingCancel.constBegin(),
winItEnd = windowsNeedingCancel.constEnd(); winIt != winItEnd; ++winIt) {
QGuiApplication::sendSpontaneousEvent(*winIt, &touchEvent);
@@ -2863,7 +2851,6 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
}
self->synthesizedMousePoints.clear();
}
- self->activeTouchPoints.clear();
self->lastTouchType = e->touchType;
return;
}
@@ -2874,110 +2861,88 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
self->lastTouchType = e->touchType;
- QWindow *window = e->window.data();
- // TODO get rid of this QPair; we don't need to accumulate combined states here anymore
- typedef QPair<QEventPoint::States, QList<QEventPoint> > StatesAndTouchPoints;
- QHash<QWindow *, StatesAndTouchPoints> windowsNeedingEvents;
bool stationaryTouchPointChangedProperty = false;
-
- for (int i = 0; i < e->points.count(); ++i) {
- QMutableEventPoint touchPoint = QMutableEventPoint::from(e->points[i]);
-
+ QPointer<QWindow> window = e->window; // the platform hopefully tells us which window received the event
+ QVarLengthArray<QMutableTouchEvent, 2> touchEvents;
+
+ // For each temporary QEventPoint from the QPA TouchEvent:
+ // - update the persistent QEventPoint in QPointingDevicePrivate::activePoints with current values
+ // - determine which window to deliver it to
+ // - add it to the QTouchEvent instance for that window (QMutableTouchEvent::target() will be QWindow*, for now)
+ for (auto &tempPt : e->points) {
// update state
- QPointer<QWindow> w;
- QEventPoint previousTouchPoint;
- ActiveTouchPointsKey touchInfoKey(device, touchPoint.id());
- ActiveTouchPointsValue &touchInfo = d->activeTouchPoints[touchInfoKey];
- switch (touchPoint.state()) {
+ auto epd = devPriv->pointById(tempPt.id());
+ auto &mut = QMutableEventPoint::from(const_cast<QEventPoint &>(epd->eventPoint));
+ epd->eventPoint.setAccepted(false);
+ switch (tempPt.state()) {
case QEventPoint::State::Pressed:
- if (e->device && e->device->type() == QInputDevice::DeviceType::TouchPad) {
- // on touch-pads, send all touch points to the same widget
- w = d->activeTouchPoints.isEmpty()
- ? QPointer<QWindow>()
- : d->activeTouchPoints.constBegin().value().window;
- }
-
- if (!w) {
- // determine which window this event will go to
- if (!window)
- window = QGuiApplication::topLevelAt(touchPoint.globalPosition().toPoint());
- if (!window)
- continue;
- w = window;
- }
-
- touchInfo.window = w;
- touchPoint.setGlobalPressPosition(touchPoint.globalPosition());
- touchPoint.setGlobalLastPosition(touchPoint.globalPosition());
- if (touchPoint.pressure() < 0)
- touchPoint.setPressure(1);
-
- touchInfo.touchPoint = touchPoint;
+ // On touchpads, send all touch points to the same window.
+ if (!window && e->device && e->device->type() == QInputDevice::DeviceType::TouchPad)
+ window = devPriv->firstActiveWindow();
+ // If the QPA event didn't tell us which window, find the one under the touchpoint position.
+ if (!window)
+ window = QGuiApplication::topLevelAt(tempPt.globalPosition().toPoint());
+ mut.setWindow(window);
break;
case QEventPoint::State::Released:
- w = touchInfo.window;
- if (!w)
- continue;
-
- previousTouchPoint = touchInfo.touchPoint;
- touchPoint.setGlobalPressPosition(previousTouchPoint.globalPressPosition());
- touchPoint.setGlobalLastPosition(previousTouchPoint.globalPosition());
- touchPoint.setPressure(0);
-
+ if (Q_UNLIKELY(window != mut.window())) {
+ qCWarning(lcPtrDispatch) << "delivering touch release to same window" << mut.window() << "not" << window.data();
+ window = mut.window();
+ }
break;
- default:
- w = touchInfo.window;
- if (!w)
- continue;
-
- previousTouchPoint = touchInfo.touchPoint;
- touchPoint.setGlobalPressPosition(previousTouchPoint.globalPressPosition());
- touchPoint.setGlobalLastPosition(previousTouchPoint.globalPosition());
- if (touchPoint.pressure() < 0)
- touchPoint.setPressure(1);
-
- // Stationary points might not be delivered down to the receiving item
- // and get their position transformed, keep the old values instead.
- if (touchPoint.state() == QEventPoint::State::Stationary) {
- if (touchInfo.touchPoint.velocity() != touchPoint.velocity()) {
- touchInfo.touchPoint.setVelocity(touchPoint.velocity());
- touchPoint.setStationaryWithModifiedProperty();
- stationaryTouchPointChangedProperty = true;
- }
- if (!qFuzzyCompare(touchInfo.touchPoint.pressure(), touchPoint.pressure())) {
- touchInfo.touchPoint.setPressure(touchPoint.pressure());
- touchPoint.setStationaryWithModifiedProperty();
- stationaryTouchPointChangedProperty = true;
- }
- } else {
- touchInfo.touchPoint = touchPoint;
+ default: // update or stationary
+ if (Q_UNLIKELY(window != mut.window())) {
+ qCWarning(lcPtrDispatch) << "delivering touch update to same window" << mut.window() << "not" << window.data();
+ window = mut.window();
}
break;
}
+ // If we somehow still don't have a window, we can't deliver this touchpoint. (should never happen)
+ if (Q_UNLIKELY(!window)) {
+ qCWarning(lcPtrDispatch) << "skipping" << &tempPt << ": no target window";
+ continue;
+ }
+ mut.updateFrom(tempPt);
- Q_ASSERT(w.data() != nullptr);
+ Q_ASSERT(window.data() != nullptr);
// make the *scene* position the same as the *global* position
- // Note: touchPoint is a reference to the one from activeTouchPoints, so we can modify it.
- touchPoint.setScenePosition(touchPoint.globalPosition());
+ mut.setScenePosition(tempPt.globalPosition());
+
+ // store the scene position as local position, for now
+ mut.setPosition(window->mapFromGlobal(tempPt.globalPosition()));
- StatesAndTouchPoints &maskAndPoints = windowsNeedingEvents[w.data()];
- maskAndPoints.first |= touchPoint.state();
- maskAndPoints.second.append(touchPoint);
+ // setTimeStamp has side effects, so we do it last
+ mut.setTimestamp(e->timestamp);
+
+ // add the touchpoint to the event that will be delivered to the window
+ bool added = false;
+ for (QMutableTouchEvent &ev : touchEvents) {
+ if (ev.target() == window.data()) {
+ ev.addPoint(mut);
+ added = true;
+ break;
+ }
+ }
+ if (!added) {
+ QMutableTouchEvent mte(e->touchType, device, e->modifiers, {mut});
+ mte.setTimestamp(e->timestamp);
+ mte.setTarget(window.data());
+ touchEvents.append(mte);
+ }
}
- if (windowsNeedingEvents.isEmpty())
+ if (touchEvents.isEmpty())
return;
- QHash<QWindow *, StatesAndTouchPoints>::ConstIterator it = windowsNeedingEvents.constBegin();
- const QHash<QWindow *, StatesAndTouchPoints>::ConstIterator end = windowsNeedingEvents.constEnd();
- for (; it != end; ++it) {
- QWindow *w = it.key();
+ for (QMutableTouchEvent &touchEvent : touchEvents) {
+ QWindow *window = static_cast<QWindow *>(touchEvent.target());
+ auto &points = touchEvent.points();
QEvent::Type eventType;
- switch (it.value().first) {
+ switch (touchEvent.touchPointStates()) {
case QEventPoint::State::Pressed:
eventType = QEvent::TouchBegin;
break;
@@ -2994,32 +2959,22 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
break;
}
- if (w->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
+ if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
// a modal window is blocking this window, don't allow touch events through
- // QTBUG-37371 temporary fix; TODO: revisit in 5.4 when we have a forwarding solution
- if (eventType == QEvent::TouchEnd) {
+ // QTBUG-37371 temporary fix; TODO: revisit when we have a forwarding solution
+ if (touchEvent.type() == QEvent::TouchEnd) {
// but don't leave dangling state: e.g.
// QQuickWindowPrivate::itemForTouchPointId needs to be cleared.
- QTouchEvent touchEvent(QEvent::TouchCancel,
- device,
- e->modifiers);
+ QTouchEvent touchEvent(QEvent::TouchCancel, device, e->modifiers);
touchEvent.setTimestamp(e->timestamp);
- QGuiApplication::sendSpontaneousEvent(w, &touchEvent);
+ QGuiApplication::sendSpontaneousEvent(window, &touchEvent);
}
continue;
}
- const auto &touchpoints = it.value().second;
- QMutableTouchEvent touchEvent(eventType, device, e->modifiers, touchpoints);
- touchEvent.setTimestamp(e->timestamp);
-
- for (QEventPoint &pt : touchEvent.touchPoints()) {
- auto &touchPoint = QMutableEventPoint::from(pt);
- touchPoint.setPosition(w->mapFromGlobal(touchPoint.globalPosition()));
- }
+ QGuiApplication::sendSpontaneousEvent(window, &touchEvent);
- QGuiApplication::sendSpontaneousEvent(w, &touchEvent);
if (!e->synthetic() && !touchEvent.isAccepted() && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) {
// exclude devices which generate their own mouse events
if (!(touchEvent.device()->capabilities().testFlag(QInputDevice::Capability::MouseEmulation))) {
@@ -3042,15 +2997,15 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
Qt::MouseButton button = mouseType == QEvent::MouseMove ? Qt::NoButton : Qt::LeftButton;
Qt::MouseButtons buttons = mouseType == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton;
- const auto &points = touchEvent.touchPoints();
for (const QEventPoint &touchPoint : points) {
if (touchPoint.id() == m_fakeMouseSourcePointId) {
if (eventType != QEvent::TouchEnd)
- self->synthesizedMousePoints.insert(w, SynthesizedMouseData(
- touchPoint.position(), touchPoint.globalPosition(), w));
+ self->synthesizedMousePoints.insert(window, SynthesizedMouseData(
+ touchPoint.position(), touchPoint.globalPosition(), window));
// All touch events that are not accepted by the application will be translated to
// left mouse button events instead (see AA_SynthesizeMouseForUnhandledTouchEvents docs).
- QWindowSystemInterfacePrivate::MouseEvent fake(w, e->timestamp,
+ // TODO why go through QPA? Why not just send a QMouseEvent right from here?
+ QWindowSystemInterfacePrivate::MouseEvent fake(window, e->timestamp,
touchPoint.position(),
touchPoint.globalPosition(),
buttons,
@@ -3069,13 +3024,11 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
}
}
- // Remove released points from the hash table only after the event is
- // delivered. When the receiver is a widget, QApplication will access
- // activeTouchPoints during delivery and therefore nothing can be removed
- // before sending the event.
+ // Remove released points from QPointingDevicePrivate::activePoints only after the event is
+ // delivered. Widgets and Qt Quick are allowed to access them at any time before this.
for (const QEventPoint &touchPoint : e->points) {
if (touchPoint.state() == QEventPoint::State::Released)
- d->activeTouchPoints.remove(ActiveTouchPointsKey(device, touchPoint.id()));
+ devPriv->removePointById(touchPoint.id());
}
}