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>
This commit is contained in:
Dyami Caliri 2014-08-27 09:27:50 -07:00
parent 3da75b0584
commit 9c3a58a913
4 changed files with 60 additions and 14 deletions

View File

@ -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);
}
/*!

View File

@ -132,6 +132,7 @@ public:
void _q_clearAlert();
void setScreen(QScreen *newScreen, bool recreate);
void create(bool recursive);
virtual void clearFocusObject();

View File

@ -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 {

View File

@ -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"