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.

Pick-to: 6.9
Fixes: QTBUG-133332
Change-Id: Ifa9ee4fdfa64b2768337e2d90b7bbaac5f3fcd70
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
Christian Ehrlicher 2025-01-10 16:41:54 +01:00
parent 263f06ae8b
commit 3252e1808c
2 changed files with 33 additions and 1 deletions

View File

@ -2676,7 +2676,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);
}

View File

@ -292,6 +292,7 @@ private slots:
void setLocale();
void propagateLocale();
void deleteStyle();
void dontCrashOnSetStyle();
void multipleToplevelFocusCheck();
void setFocus();
#ifndef QT_NO_CURSOR
@ -6795,6 +6796,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