diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 3f707bb936a..162268fad3c 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -1652,10 +1652,9 @@ void QWidgetPrivate::deleteExtra() if (QStyleSheetStyle *proxy = qt_styleSheet(extra->style)) proxy->deref(); #endif - if (extra->topextra) { + if (extra->topextra) deleteTLSysExtra(); - // extra->topextra->backingStore destroyed in QWidgetPrivate::deleteTLSysExtra() - } + // extra->xic destroyed in QWidget::destroy() extra.reset(); } @@ -1665,34 +1664,11 @@ void QWidgetPrivate::deleteSysExtra() { } -static void deleteBackingStore(QWidgetPrivate *d) -{ - QTLWExtra *topData = d->topData(); - - delete topData->backingStore; - topData->backingStore = nullptr; -} - void QWidgetPrivate::deleteTLSysExtra() { if (extra && extra->topextra) { - //the qplatformbackingstore may hold a reference to the window, so the backingstore - //needs to be deleted first. - - extra->topextra->repaintManager.reset(nullptr); - deleteBackingStore(this); - extra->topextra->widgetTextures.clear(); - - //the toplevel might have a context with a "qglcontext associated with it. We need to - //delete the qglcontext before we delete the qplatformopenglcontext. - //One unfortunate thing about this is that we potentially create a glContext just to - //delete it straight afterwards. - if (extra->topextra->window) { - extra->topextra->window->destroy(); - } delete extra->topextra->window; extra->topextra->window = nullptr; - } } @@ -12256,7 +12232,7 @@ void QWidget::setBackingStore(QBackingStore *store) return; QBackingStore *oldStore = topData->backingStore; - deleteBackingStore(d); + delete topData->backingStore; topData->backingStore = store; QWidgetRepaintManager *repaintManager = d->maybeRepaintManager(); diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 99c54b9d987..ff666a7e499 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -145,6 +145,21 @@ QWidgetWindow::QWidgetWindow(QWidget *widget) QWidgetWindow::~QWidgetWindow() { + if (!m_widget) + return; + + QTLWExtra *topData = QWidgetPrivate::get(m_widget)->topData(); + Q_ASSERT(topData); + + // The QPlaformBackingStore may hold a reference to the window, + // so the backingstore needs to be deleted first. + topData->repaintManager.reset(nullptr); + delete topData->backingStore; + topData->backingStore = nullptr; + topData->widgetTextures.clear(); + + // Too late to do anything beyond this point + topData->window = nullptr; } #if QT_CONFIG(accessibility) diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp index addcc7d321f..83e6415569f 100644 --- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp @@ -113,6 +113,8 @@ private slots: void resetFocusObjectOnDestruction(); + void cleanupOnDestruction(); + private: QSize m_testWidgetSize; const int m_fuzz; @@ -1672,5 +1674,30 @@ void tst_QWidget_window::resetFocusObjectOnDestruction() QCOMPARE(focusObjectChangedSpy.last().last().value(), nullptr); } +class CreateDestroyWidget : public QWidget +{ +public: + using QWidget::create; + using QWidget::destroy; +}; + +void tst_QWidget_window::cleanupOnDestruction() +{ + CreateDestroyWidget widget; + QWidget child(&widget); + + QWidget grandChild(&child); + // Ensure there's not a 1:1 native window hierarhcy that we could + // recurse during QWidget::destroy(), triggering the issue that + // we were failing to clean up when not destroyed via QWidget. + grandChild.setAttribute(Qt::WA_DontCreateNativeAncestors); + grandChild.winId(); + + widget.destroy(); + widget.create(); + + widget.show(); +} + QTEST_MAIN(tst_QWidget_window) #include "tst_qwidget_window.moc"