From ccf61c34802ac46acb235cd737ae55b0c9a52636 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Fri, 10 Jan 2025 16:41:54 +0100 Subject: [PATCH] QWidget: don't re-polish when style did not change Don't call style->unpolish()/polish() when the old and new style did not change which might happen when setting a style sheet as this might create an infinite loop and the style (re)sets some window attribute. Bailing out early is not an option here as newStyle might be a nullptr so q->style() will fall back to the application default style. Fixes: QTBUG-133332 Change-Id: Ifa9ee4fdfa64b2768337e2d90b7bbaac5f3fcd70 Reviewed-by: Richard Moe Gustavsen (cherry picked from commit 3252e1808c12c21f27bb4844a1497d18587a64b5) Reviewed-by: Qt Cherry-pick Bot --- src/widgets/kernel/qwidget.cpp | 2 +- .../widgets/kernel/qwidget/tst_qwidget.cpp | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index a604cb1e439..d155eca3df1 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -2686,7 +2686,7 @@ void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate) extra->style = newStyle; // repolish - if (polished && q->windowType() != Qt::Desktop) { + if (polished && q->windowType() != Qt::Desktop && oldStyle != q->style()) { oldStyle->unpolish(q); q->style()->polish(q); } diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 41b29da0783..a49fa9c2137 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -291,6 +291,7 @@ private slots: void setLocale(); void propagateLocale(); void deleteStyle(); + void dontCrashOnSetStyle(); void multipleToplevelFocusCheck(); void setFocus(); #ifndef QT_NO_CURSOR @@ -6754,6 +6755,37 @@ void tst_QWidget::deleteStyle() QCoreApplication::processEvents(); } +class TestStyle : public QCommonStyle +{ + void polish(QWidget *w) override + { + w->setWindowFlag(Qt::NoDropShadowWindowHint, true); + } + void unpolish(QWidget *w) override + { + w->setWindowFlag(Qt::NoDropShadowWindowHint, false); + } +}; + +void tst_QWidget::dontCrashOnSetStyle() +{ + const auto oldStyleName = qApp->style()->name(); + const auto resetStyleHelper = qScopeGuard([&] { + qApp->setStyleSheet({}); + qApp->setStyle(QStyleFactory::create(oldStyleName)); + }); + { + qApp->setStyle(new TestStyle); + qApp->setStyleSheet("blub"); + 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); + } +} + class TopLevelFocusCheck: public QWidget { Q_OBJECT