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:
parent
3da75b0584
commit
9c3a58a913
@ -367,12 +367,31 @@ void QWindowPrivate::setScreen(QScreen *newScreen, bool recreate)
|
|||||||
if (newScreen) {
|
if (newScreen) {
|
||||||
q->connect(screen, SIGNAL(destroyed(QObject*)), q, SLOT(screenDestroyed(QObject*)));
|
q->connect(screen, SIGNAL(destroyed(QObject*)), q, SLOT(screenDestroyed(QObject*)));
|
||||||
if (shouldRecreate)
|
if (shouldRecreate)
|
||||||
q->create();
|
create(true);
|
||||||
}
|
}
|
||||||
emit q->screenChanged(newScreen);
|
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()
|
void QWindowPrivate::clearFocusObject()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -490,18 +509,7 @@ bool QWindow::isVisible() const
|
|||||||
void QWindow::create()
|
void QWindow::create()
|
||||||
{
|
{
|
||||||
Q_D(QWindow);
|
Q_D(QWindow);
|
||||||
if (!d->platformWindow) {
|
d->create(false);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -132,6 +132,7 @@ public:
|
|||||||
void _q_clearAlert();
|
void _q_clearAlert();
|
||||||
|
|
||||||
void setScreen(QScreen *newScreen, bool recreate);
|
void setScreen(QScreen *newScreen, bool recreate);
|
||||||
|
void create(bool recursive);
|
||||||
|
|
||||||
virtual void clearFocusObject();
|
virtual void clearFocusObject();
|
||||||
|
|
||||||
|
2
tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro
Normal file → Executable file
2
tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro
Normal file → Executable file
@ -1,7 +1,7 @@
|
|||||||
CONFIG += testcase
|
CONFIG += testcase
|
||||||
CONFIG += parallel_test
|
CONFIG += parallel_test
|
||||||
TARGET = tst_qwidget_window
|
TARGET = tst_qwidget_window
|
||||||
QT += widgets testlib
|
QT += widgets testlib core-private gui-private
|
||||||
SOURCES += tst_qwidget_window.cpp
|
SOURCES += tst_qwidget_window.cpp
|
||||||
|
|
||||||
x11 {
|
x11 {
|
||||||
|
37
tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp
Normal file → Executable file
37
tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp
Normal file → Executable file
@ -52,6 +52,9 @@
|
|||||||
#include <qlistwidget.h>
|
#include <qlistwidget.h>
|
||||||
#include <qpushbutton.h>
|
#include <qpushbutton.h>
|
||||||
#include <qboxlayout.h>
|
#include <qboxlayout.h>
|
||||||
|
#include <qtabwidget.h>
|
||||||
|
#include <qlabel.h>
|
||||||
|
#include <private/qwindow_p.h>
|
||||||
|
|
||||||
static inline void setFrameless(QWidget *w)
|
static inline void setFrameless(QWidget *w)
|
||||||
{
|
{
|
||||||
@ -96,6 +99,8 @@ private slots:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void tst_qtbug35600();
|
void tst_qtbug35600();
|
||||||
|
void tst_recreateWindow_QTBUG40817();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_QWidget_window::initTestCase()
|
void tst_QWidget_window::initTestCase()
|
||||||
@ -598,5 +603,37 @@ void tst_QWidget_window::tst_qtbug35600()
|
|||||||
// QTBUG-35600: program may crash here or on exit
|
// 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)
|
QTEST_MAIN(tst_QWidget_window)
|
||||||
#include "tst_qwidget_window.moc"
|
#include "tst_qwidget_window.moc"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user