diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index d81632cfbe2..cddf5833fa0 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -161,6 +161,7 @@ QWidgetPrivate::QWidgetPrivate(decltype(QObjectPrivateVersion) version) , childrenHiddenByWState(0) , childrenShownByExpose(0) , dontSetExplicitShowHide(0) + , inheritStyleRecursionGuard(0) #if defined(Q_OS_WIN) , noPaintOnScreen(0) #endif @@ -2692,7 +2693,7 @@ void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate) extra->style = newStyle; // repolish - if (polished && q->windowType() != Qt::Desktop && oldStyle != q->style()) { + if (polished && q->windowType() != Qt::Desktop) { oldStyle->unpolish(q); q->style()->polish(q); } @@ -2740,6 +2741,12 @@ void QWidgetPrivate::inheritStyle() proxy->repolish(q); return; } + if (inheritStyleRecursionGuard) + return; + inheritStyleRecursionGuard = true; + const auto resetGuard = qScopeGuard([&]() { + inheritStyleRecursionGuard = false; + }); QStyle *origStyle = proxy ? proxy->base : extraStyle; QWidget *parent = q->parentWidget(); diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index ac417178813..87601d2cc42 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -742,6 +742,7 @@ public: uint childrenHiddenByWState : 1; uint childrenShownByExpose : 1; uint dontSetExplicitShowHide : 1; + uint inheritStyleRecursionGuard : 1; // *************************** Focus abstraction ************************************ enum class FocusDirection { diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index dcde8c19c75..0d31ff77a73 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -11,7 +11,9 @@ #include #include #include -#include +#if QT_CONFIG(listwidget) +#include +#endif #include #include #include @@ -22,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -6806,7 +6809,32 @@ void tst_QWidget::deleteStyle() QCoreApplication::processEvents(); } -class TestStyle : public QCommonStyle + +#if QT_CONFIG(listwidget) +class DontCrashOnSetStyleWidget : public QWidget +{ + Q_OBJECT +public: + DontCrashOnSetStyleWidget() + { + lw = new QListWidget; + lwi = new QListWidgetItem; + lw->addItem(lwi); + lw->setItemWidget(lwi, new QLabel(u"test"_s)); + auto l = new QVBoxLayout(this); + l->addWidget(lw); + } + bool testStyleSheetTarget() const + { + return lw->itemWidget(lwi)->testAttribute(Qt::WA_StyleSheetTarget); + } +private: + QListWidget *lw = nullptr; + QListWidgetItem *lwi = nullptr; +}; +#endif + +class TestStyle : public QWindowsStyle { void polish(QWidget *w) override { @@ -6827,13 +6855,17 @@ void tst_QWidget::dontCrashOnSetStyle() }); { qApp->setStyle(new TestStyle); - qApp->setStyleSheet("blub"); + qApp->setStyleSheet(u"DontCrashOnSetStyleWidget QLabel {color:red;}"_s); QComboBox w; w.show(); QVERIFY(QTest::qWaitForWindowExposed(&w)); // this created an infinite loop / stack overflow inside setStyle_helper() // directly call polish instead waiting for the polish event qApp->style()->polish(&w); +#if QT_CONFIG(listwidget) + DontCrashOnSetStyleWidget widget; + QVERIFY(widget.testStyleSheetTarget()); +#endif } }