From 9c3a58a913a7e59359146264ee59d40d703d4db2 Mon Sep 17 00:00:00 2001 From: Dyami Caliri <dyami@dragonframe.com> Date: Wed, 27 Aug 2014 09:27:50 -0700 Subject: [PATCH] Recreate child windows when changing screens When setting a new screen, the code calls QWindow::destroy(), which recursively destroys all child windows. It then calls create() on the top-level window, leaving child windows destroyed. This causes crashes if you have embedded native widgets. Task-number: QTBUG-40817 Change-Id: Iaace2589f48bbfd5faaf5ff95357ff43b310504a Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com> Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com> --- src/gui/kernel/qwindow.cpp | 34 ++++++++++------- src/gui/kernel/qwindow_p.h | 1 + .../kernel/qwidget_window/qwidget_window.pro | 2 +- .../qwidget_window/tst_qwidget_window.cpp | 37 +++++++++++++++++++ 4 files changed, 60 insertions(+), 14 deletions(-) mode change 100644 => 100755 tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro mode change 100644 => 100755 tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index d6f9fad0707..6724d68c95b 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -367,12 +367,31 @@ void QWindowPrivate::setScreen(QScreen *newScreen, bool recreate) if (newScreen) { q->connect(screen, SIGNAL(destroyed(QObject*)), q, SLOT(screenDestroyed(QObject*))); if (shouldRecreate) - q->create(); + create(true); } emit q->screenChanged(newScreen); } } +void QWindowPrivate::create(bool recursive) +{ + Q_Q(QWindow); + if (!platformWindow) { + platformWindow = QGuiApplicationPrivate::platformIntegration()->createPlatformWindow(q); + QObjectList childObjects = q->children(); + for (int i = 0; i < childObjects.size(); i ++) { + QObject *object = childObjects.at(i); + if (object->isWindowType()) { + QWindow *window = static_cast<QWindow *>(object); + if (recursive) + window->d_func()->create(true); + if (window->d_func()->platformWindow) + window->d_func()->platformWindow->setParent(platformWindow); + } + } + } +} + void QWindowPrivate::clearFocusObject() { } @@ -490,18 +509,7 @@ bool QWindow::isVisible() const void QWindow::create() { Q_D(QWindow); - if (!d->platformWindow) { - d->platformWindow = QGuiApplicationPrivate::platformIntegration()->createPlatformWindow(this); - QObjectList childObjects = children(); - for (int i = 0; i < childObjects.size(); i ++) { - QObject *object = childObjects.at(i); - if(object->isWindowType()) { - QWindow *window = static_cast<QWindow *>(object); - if (window->d_func()->platformWindow) - window->d_func()->platformWindow->setParent(d->platformWindow); - } - } - } + d->create(false); } /*! diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 4305edea51f..51d78bb9cd1 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -132,6 +132,7 @@ public: void _q_clearAlert(); void setScreen(QScreen *newScreen, bool recreate); + void create(bool recursive); virtual void clearFocusObject(); diff --git a/tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro b/tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro old mode 100644 new mode 100755 index baa2823f9a4..d61681d5cb8 --- a/tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro +++ b/tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro @@ -1,7 +1,7 @@ CONFIG += testcase CONFIG += parallel_test TARGET = tst_qwidget_window -QT += widgets testlib +QT += widgets testlib core-private gui-private SOURCES += tst_qwidget_window.cpp x11 { diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp old mode 100644 new mode 100755 index d6b7fc20edc..87e1c7a4f3b --- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp @@ -52,6 +52,9 @@ #include <qlistwidget.h> #include <qpushbutton.h> #include <qboxlayout.h> +#include <qtabwidget.h> +#include <qlabel.h> +#include <private/qwindow_p.h> static inline void setFrameless(QWidget *w) { @@ -96,6 +99,8 @@ private slots: #endif void tst_qtbug35600(); + void tst_recreateWindow_QTBUG40817(); + }; void tst_QWidget_window::initTestCase() @@ -598,5 +603,37 @@ void tst_QWidget_window::tst_qtbug35600() // QTBUG-35600: program may crash here or on exit } +void tst_QWidget_window::tst_recreateWindow_QTBUG40817() +{ + QTabWidget tab; + + QWidget *w = new QWidget; + tab.addTab(w, "Tab1"); + QVBoxLayout *vl = new QVBoxLayout(w); + QLabel *lbl = new QLabel("HELLO1"); + lbl->setObjectName("label1"); + vl->addWidget(lbl); + w = new QWidget; + tab.addTab(w, "Tab2"); + vl = new QVBoxLayout(w); + lbl = new QLabel("HELLO2"); + lbl->setAttribute(Qt::WA_NativeWindow); + lbl->setObjectName("label2"); + vl->addWidget(lbl); + + tab.show(); + + QVERIFY(QTest::qWaitForWindowExposed(&tab)); + + QWindow *win = tab.windowHandle(); + win->destroy(); + QWindowPrivate *p = qt_window_private(win); + p->create(true); + win->show(); + + tab.setCurrentIndex(1); +} + + QTEST_MAIN(tst_QWidget_window) #include "tst_qwidget_window.moc" -- GitLab