From d68419faf424df2492425baca789742f1a239af3 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 18 Nov 2020 23:55:25 +0100 Subject: Remove QQuickItem::windowDeactivateEvent(); cancel grabs instead When a QQuickWindow is deactivated, visiting every item in the entire scene to tell them the news isn't very efficient, especially considering that the only item that overrode this virtual function has been QQMouseArea, throughout the lifetime of Qt 5. If it's important to cancel grabs of MouseAreas, then it's equally important to cancel grabs of MultiPointTouchArea, pointer handlers, etc. It should be OK to delete the virtual function since it was never documented, and marked \internal, so hopefully no users are depending on it. The existing tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate() test continues to pass, which proves that the WindowDeactivate event still has the desired effect on MouseArea. Change-Id: I0109370aba14096fb7777a83cf1b6763ac58013f Reviewed-by: Richard Moe Gustavsen Reviewed-by: Volker Hilsheimer --- src/quick/items/qquickitem.cpp | 11 ---------- src/quick/items/qquickitem.h | 1 - src/quick/items/qquickmousearea.cpp | 6 ------ src/quick/items/qquickmousearea_p.h | 1 - src/quick/items/qquickwindow.cpp | 40 ++++++++++++++++++++++++++++++++++--- src/quick/items/qquickwindow_p.h | 1 + 6 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 5dcc191053..fa2f388fe6 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -4226,17 +4226,6 @@ bool QQuickItem::childMouseEventFilter(QQuickItem *item, QEvent *event) return false; } -/*! - \internal - */ -void QQuickItem::windowDeactivateEvent() -{ - const auto children = childItems(); - for (QQuickItem* item : children) { - item->windowDeactivateEvent(); - } -} - #if QT_CONFIG(im) /*! This method is only relevant for input items. diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index 7b72b6032d..c7bc2f54c3 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -449,7 +449,6 @@ protected: virtual void dropEvent(QDropEvent *); #endif virtual bool childMouseEventFilter(QQuickItem *, QEvent *); - virtual void windowDeactivateEvent(); virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); virtual void releaseResources(); diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp index b306c0ddf4..6e7688a734 100644 --- a/src/quick/items/qquickmousearea.cpp +++ b/src/quick/items/qquickmousearea.cpp @@ -1038,12 +1038,6 @@ void QQuickMouseArea::timerEvent(QTimerEvent *event) } } -void QQuickMouseArea::windowDeactivateEvent() -{ - ungrabMouse(); - QQuickItem::windowDeactivateEvent(); -} - void QQuickMouseArea::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) { Q_D(QQuickMouseArea); diff --git a/src/quick/items/qquickmousearea_p.h b/src/quick/items/qquickmousearea_p.h index c368f43b30..e0f7397f06 100644 --- a/src/quick/items/qquickmousearea_p.h +++ b/src/quick/items/qquickmousearea_p.h @@ -180,7 +180,6 @@ protected: #endif bool childMouseEventFilter(QQuickItem *i, QEvent *e) override; void timerEvent(QTimerEvent *event) override; - void windowDeactivateEvent() override; void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; void itemChange(ItemChange change, const ItemChangeData& value) override; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 3721620bf2..0515a62b1e 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -849,7 +849,7 @@ void QQuickWindow::handleApplicationStateChanged(Qt::ApplicationState state) { Q_D(QQuickWindow); if (state != Qt::ApplicationActive && d->contentItem) - d->contentItem->windowDeactivateEvent(); + d->handleWindowDeactivate(); } /*! @@ -1945,8 +1945,7 @@ bool QQuickWindow::event(QEvent *e) break; #endif case QEvent::WindowDeactivate: - if (d->contentItem) - d->contentItem->windowDeactivateEvent(); + d->handleWindowDeactivate(); break; case QEvent::PlatformSurface: if ((static_cast(e))->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) { @@ -2296,6 +2295,41 @@ void QQuickWindowPrivate::deliverDelayedTouchEvent() deliverPointerEvent(e.data()); } +/*! \internal + The handler for the QEvent::WindowDeactivate event, and also when + Qt::ApplicationState tells us the application is no longer active. + It clears all exclusive grabs of items and handlers whose window is this one, + for all known pointing devices. + + The QEvent is not passed into this function because in the first case it's + just a plain QEvent with no extra data, and because the application state + change is delivered via a signal rather than an event. +*/ +void QQuickWindowPrivate::handleWindowDeactivate() +{ + Q_Q(QQuickWindow); + qCDebug(DBG_FOCUS) << "deactivated" << windowTitle; + const auto inputDevices = QInputDevice::devices(); + for (auto device : inputDevices) { + if (auto pointingDevice = qobject_cast(device)) { + auto devPriv = QPointingDevicePrivate::get(const_cast(pointingDevice)); + for (auto epd : devPriv->activePoints.values()) { + if (!epd.exclusiveGrabber.isNull()) { + bool relevant = false; + if (QQuickItem *item = qmlobject_cast(epd.exclusiveGrabber.data())) + relevant = (item->window() == q); + else if (QQuickPointerHandler *handler = qmlobject_cast(epd.exclusiveGrabber.data())) + relevant = (handler->parentItem()->window() == q); + if (relevant) + devPriv->setExclusiveGrabber(nullptr, epd.eventPoint, nullptr); + } + // For now, we don't clearPassiveGrabbers(), just in case passive grabs + // can be useful to keep monitoring the mouse even after window deactivation. + } + } + } +} + bool QQuickWindowPrivate::allUpdatedPointsAccepted(const QPointerEvent *ev) { for (auto &point : ev->points()) { diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 18a43487c1..6e4d24da85 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -187,6 +187,7 @@ public: bool compressTouchEvent(QTouchEvent *); void flushFrameSynchronousEvents(); void deliverDelayedTouchEvent(); + void handleWindowDeactivate(); // utility functions that used to be in QQuickPointerEvent et al. bool allUpdatedPointsAccepted(const QPointerEvent *ev); -- cgit v1.2.1