From 16836da1ae44c11317b9861764ea55cce39eac02 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 19 Feb 2019 14:22:27 +0100 Subject: Page: fix binding loop When Dialog (which derives from Page) has only its title set, there'd be a binding loop. A simplified version of the call stack: - QQuickPopup::componentComplete - QQuickPopupPrivate::prepareEnterTransition - QQuickItem::setVisible - QQuickPagePrivate::itemVisibilityChanged - QQuickDialog::implicitHeaderWidthChanged - QQmlBinding::expressionChanged <== Dialog.qml's implicitWidth binding - QQmlPropertyData::readProperty - QQuickDialog::implicitHeaderWidth - QQuickPage::implicitHeaderWidth - QQuickItem::implicitWidth <== QQuickPagePrivate::header, aka Label - QQuickTextPrivate::getImplicitWidth - QQuickTextPrivate::updateSize - QQuickTextPrivate::setupTextLayout - QQuickItem::setImplicitSize - QQuickItemPrivate::implicitWidthChanged - QQuickPagePrivate::itemImplicitWidthChanged - QQuickDialog::implicitHeaderWidthChanged - QQmlBinding::expressionChanged - QQmlAbstractBinding::printBindingLoopError Fix the issue by not emitting change signals if we're already in the process of doing so. Change-Id: I37d6fa35b1e70420e436c0e001f55035d7630542 Fixes: QTBUG-66494 Reviewed-by: Frederik Gladhorn --- src/quicktemplates2/qquickpage.cpp | 12 ++++++++++++ src/quicktemplates2/qquickpage_p_p.h | 1 + 2 files changed, 13 insertions(+) diff --git a/src/quicktemplates2/qquickpage.cpp b/src/quicktemplates2/qquickpage.cpp index 56034297..cb90ac48 100644 --- a/src/quicktemplates2/qquickpage.cpp +++ b/src/quicktemplates2/qquickpage.cpp @@ -149,10 +149,12 @@ void QQuickPagePrivate::itemVisibilityChanged(QQuickItem *item) Q_Q(QQuickPage); QQuickPanePrivate::itemVisibilityChanged(item); if (item == header) { + QBoolBlocker signalGuard(emittingImplicitSizeChangedSignals); emit q->implicitHeaderWidthChanged(); emit q->implicitHeaderHeightChanged(); relayout(); } else if (item == footer) { + QBoolBlocker signalGuard(emittingImplicitSizeChangedSignals); emit q->implicitFooterWidthChanged(); emit q->implicitFooterHeightChanged(); relayout(); @@ -163,6 +165,11 @@ void QQuickPagePrivate::itemImplicitWidthChanged(QQuickItem *item) { Q_Q(QQuickPage); QQuickPanePrivate::itemImplicitWidthChanged(item); + + // Avoid binding loops by skipping signal emission if we're already doing it. + if (emittingImplicitSizeChangedSignals) + return; + if (item == header) emit q->implicitHeaderWidthChanged(); else if (item == footer) @@ -173,6 +180,11 @@ void QQuickPagePrivate::itemImplicitHeightChanged(QQuickItem *item) { Q_Q(QQuickPage); QQuickPanePrivate::itemImplicitHeightChanged(item); + + // Avoid binding loops by skipping signal emission if we're already doing it. + if (emittingImplicitSizeChangedSignals) + return; + if (item == header) emit q->implicitHeaderHeightChanged(); else if (item == footer) diff --git a/src/quicktemplates2/qquickpage_p_p.h b/src/quicktemplates2/qquickpage_p_p.h index b7d89ac4..6c8b0371 100644 --- a/src/quicktemplates2/qquickpage_p_p.h +++ b/src/quicktemplates2/qquickpage_p_p.h @@ -71,6 +71,7 @@ public: QString title; QQuickItem *header = nullptr; QQuickItem *footer = nullptr; + bool emittingImplicitSizeChangedSignals = false; }; QT_END_NAMESPACE -- cgit v1.2.3