aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/util')
-rw-r--r--src/quick/util/qminimalflatset_p.h12
-rw-r--r--src/quick/util/qquickdeliveryagent.cpp53
-rw-r--r--src/quick/util/qquickprofiler_p.h12
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);