diff options
Diffstat (limited to 'src/quick/util')
-rw-r--r-- | src/quick/util/qminimalflatset_p.h | 12 | ||||
-rw-r--r-- | src/quick/util/qquickdeliveryagent.cpp | 53 | ||||
-rw-r--r-- | src/quick/util/qquickprofiler_p.h | 12 |
3 files changed, 63 insertions, 14 deletions
diff --git a/src/quick/util/qminimalflatset_p.h b/src/quick/util/qminimalflatset_p.h index a7aed41305..0a882205ef 100644 --- a/src/quick/util/qminimalflatset_p.h +++ b/src/quick/util/qminimalflatset_p.h @@ -1,8 +1,12 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -#ifndef QMINIMALFLATSET_P_H -#define QMINIMALFLATSET_P_H +#ifndef QTDECLARATIVE_QMINIMALFLATSET_P_H +#define QTDECLARATIVE_QMINIMALFLATSET_P_H + +#if __has_include(<QtCore/private/qminimalflatset_p.h>) +# include <QtCore/private/qminimalflatset_p.h> +#else // // W A R N I N G @@ -140,4 +144,6 @@ private: QT_END_NAMESPACE -#endif // QMINIMALFLATSET_P_H +#endif // !__has_include(<QtCore/private/qminimalflatset_p.h>) + +#endif // QTDECLARATIVE_QMINIMALFLATSET_P_H diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp index 07506e68b7..2ae2bd1a02 100644 --- a/src/quick/util/qquickdeliveryagent.cpp +++ b/src/quick/util/qquickdeliveryagent.cpp @@ -305,6 +305,16 @@ static inline bool windowHasFocus(QQuickWindow *win) return win == focusWindow || QQuickRenderControlPrivate::isRenderWindowFor(win, focusWindow) || !focusWindow; } +static QQuickItem *findFurthestFocusScopeAncestor(QQuickItem *item) +{ + QQuickItem *parentItem = item->parentItem(); + + if (parentItem && parentItem->flags() & QQuickItem::ItemIsFocusScope) + return findFurthestFocusScopeAncestor(parentItem); + + return item; +} + #ifdef Q_OS_WEBOS // Temporary fix for webOS until multi-seat is implemented see QTBUG-85272 static inline bool singleWindowOnScreen(QQuickWindow *win) @@ -447,6 +457,16 @@ void QQuickDeliveryAgentPrivate::setFocusInScope(QQuickItem *scope, QQuickItem * if (isSubsceneAgent) { auto da = QQuickWindowPrivate::get(rootItem->window())->deliveryAgent; qCDebug(lcFocus) << " delegating setFocusInScope to" << da; + + // When setting subFocusItem, hierarchy is important. Each focus ancestor's + // subFocusItem must be its nearest descendant with focus. Changing the rootItem's + // subFocusItem to 'item' here would make 'item' the subFocusItem of all ancestor + // focus scopes up until root item. + // That is why we should avoid altering subFocusItem until having traversed + // all the focus hierarchy. + QQuickItem *ancestorFS = findFurthestFocusScopeAncestor(item); + if (ancestorFS != item) + options |= QQuickDeliveryAgentPrivate::DontChangeSubFocusItem; QQuickWindowPrivate::get(rootItem->window())->deliveryAgentPrivate()->setFocusInScope(da->rootItem(), item, reason, options); } if (oldActiveFocusItem == activeFocusItem) @@ -1017,7 +1037,8 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEvent( } // Prune the list for items that are no longer hovered - for (auto it = hoverItems.begin(); it != hoverItems.end();) { + auto hoverItemsCopy = hoverItems; + for (auto it = hoverItemsCopy.begin(); it != hoverItemsCopy.end();) { auto item = (*it).first.data(); auto hoverId = (*it).second; if (hoverId == currentHoverId) { @@ -1031,9 +1052,12 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEvent( const bool clearHover = true; deliverHoverEventToItem(item, scenePos, lastScenePos, modifiers, timestamp, clearHover); } - it = hoverItems.erase(it); + it = hoverItemsCopy.erase(it); } } + // delivery of the events might have cleared hoverItems, so don't overwrite if empty + if (!hoverItems.isEmpty()) + hoverItems = hoverItemsCopy; const bool itemsAreHovered = !hoverItems.isEmpty(); return itemsWasHovered || itemsAreHovered; @@ -1112,9 +1136,6 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive( // All decendants have been visited. // Now deliver the event to the item return deliverHoverEventToItem(item, scenePos, lastScenePos, modifiers, timestamp, false); - - // Continue propagation / recursion - return false; } /*! \internal @@ -1133,7 +1154,8 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem( const QPointF localPos = item->mapFromScene(scenePos); const QPointF globalPos = item->mapToGlobal(localPos); const bool isHovering = item->contains(localPos); - const bool wasHovering = hoverItems.contains(item); + const auto hoverItemIterator = hoverItems.find(item); + const bool wasHovering = hoverItemIterator != hoverItems.end() && hoverItemIterator.value() != 0; qCDebug(lcHoverTrace) << "item:" << item << "scene pos:" << scenePos << "localPos:" << localPos << "wasHovering:" << wasHovering << "isHovering:" << isHovering; @@ -1149,14 +1171,18 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem( // Also set hoveredLeafItemFound, so that only propagate in a straight // line towards the root from now on. hoveredLeafItemFound = true; - hoverItems[item] = currentHoverId; + if (hoverItemIterator != hoverItems.end()) + hoverItemIterator.value() = currentHoverId; + else + hoverItems[item] = currentHoverId; + if (wasHovering) accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, timestamp); else accepted = sendHoverEvent(QEvent::HoverEnter, item, scenePos, lastScenePos, modifiers, timestamp); } else if (wasHovering) { // A leave should never stop propagation - hoverItems[item] = 0; + hoverItemIterator.value() = 0; sendHoverEvent(QEvent::HoverLeave, item, scenePos, lastScenePos, modifiers, timestamp); } @@ -1197,7 +1223,10 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem( // Mark the whole item as updated, even if only the handler is // actually in a hovered state (because of HoverHandler.margins) hoveredLeafItemFound = true; - hoverItems[item] = currentHoverId; + if (hoverItemIterator != hoverItems.end()) + hoverItemIterator.value() = currentHoverId; + else + hoverItems[item] = currentHoverId; if (hh->isBlocking()) { qCDebug(lcHoverTrace) << "skipping rest of hover delivery due to blocking" << hh; accepted = true; @@ -2103,7 +2132,11 @@ bool QQuickDeliveryAgentPrivate::deliverPressOrReleaseEvent(QPointerEvent *event } } - for (QQuickItem *item : targetItems) { + QVector<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end()); + + for (auto &item : safeTargetItems) { + if (item.isNull()) + continue; // failsafe: when items get into a subscene somehow, ensure that QQuickItemPrivate::deliveryAgent() can find it if (isSubsceneAgent) QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent = true; diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h index 276172a2da..7768351b70 100644 --- a/src/quick/util/qquickprofiler_p.h +++ b/src/quick/util/qquickprofiler_p.h @@ -316,7 +316,17 @@ protected: void processMessage(const QQuickProfilerData &message) { QMutexLocker lock(&m_dataMutex); - m_data.append(message); + if (Q_LIKELY(m_data.isEmpty() || m_data.last().time <= message.time)) { + m_data.append(message); + return; + } + + // Since the scenegraph data is recorded from different threads, contention for the lock + // can cause it to be processed out of order here. Insert the message at the right place. + const auto it = std::find_if( + m_data.rbegin(), m_data.rend(), + [t = message.time](const QQuickProfilerData &i) { return i.time <= t; }); + m_data.insert(it.base(), message); } void startProfilingImpl(quint64 features); |