Fix crash when windowcontainer is used in a dockwidget

The dockwidget's toplevel window would be a parent of the container's
window when floating. When plugged back into the mainwindow the
dockwidget's window is destroyed and the container's window along
with it. Added a function toplevelAboutToBeDestroyed to unparent
the containers window before this happens so parentWasChanged will
work correctly.

Change-Id: I06679cfb3a8fa3834c0db0be5973c012b8277275
Reviewed-by: Ulf Hermann <ulf.hermann@digia.com>
Reviewed-by: Jørgen Lind <jorgen.lind@digia.com>
This commit is contained in:
Gunnar Sletta 2013-11-15 11:26:38 +01:00 committed by The Qt Project
parent 16ad93af49
commit 54b8c27e03
4 changed files with 51 additions and 4 deletions

View File

@ -53,6 +53,7 @@
#include <qpa/qplatformintegration.h>
#include "QtGui/private/qwindow_p.h"
#include "QtGui/private/qguiapplication_p.h"
#include <private/qwindowcontainer_p.h>
#include <qpa/qplatformcursor.h>
#include <QtGui/QGuiApplication>
@ -267,8 +268,11 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
// Reparenting toplevel to child
if (wasCreated && !(f & Qt::Window) && (oldFlags & Qt::Window) && !q->testAttribute(Qt::WA_NativeWindow))
if (wasCreated && !(f & Qt::Window) && (oldFlags & Qt::Window) && !q->testAttribute(Qt::WA_NativeWindow)) {
if (extra && extra->hasWindowContainer)
QWindowContainer::toplevelAboutToBeDestroyed(q);
q->destroy();
}
adjustFlags(f, q);
data.window_flags = f;

View File

@ -300,15 +300,28 @@ static void qwindowcontainer_traverse(QWidget *parent, qwindowcontainer_traverse
}
}
void QWindowContainer::toplevelAboutToBeDestroyed(QWidget *parent)
{
if (QWindowContainerPrivate *d = QWindowContainerPrivate::get(parent)) {
d->window->setParent(&d->fakeParent);
}
qwindowcontainer_traverse(parent, toplevelAboutToBeDestroyed);
}
void QWindowContainer::parentWasChanged(QWidget *parent)
{
if (QWindowContainerPrivate *d = QWindowContainerPrivate::get(parent)) {
if (d->window->parent()) {
d->updateUsesNativeWidgets();
d->markParentChain();
d->window->setParent(d->usesNativeWidgets
? parent->windowHandle()
: parent->window()->windowHandle());
QWidget *toplevel = d->usesNativeWidgets ? parent : parent->window();
if (!toplevel->windowHandle()) {
QWidgetPrivate *tld = static_cast<QWidgetPrivate *>(QWidgetPrivate::get(toplevel));
tld->createTLExtra();
tld->createTLSysExtra();
Q_ASSERT(toplevel->windowHandle());
}
d->window->setParent(toplevel->windowHandle());
d->updateGeometry();
}
}

View File

@ -57,6 +57,7 @@ public:
explicit QWindowContainer(QWindow *embeddedWindow, QWidget *parent = 0, Qt::WindowFlags f = 0);
~QWindowContainer();
static void toplevelAboutToBeDestroyed(QWidget *parent);
static void parentWasChanged(QWidget *parent);
static void parentWasMoved(QWidget *parent);
static void parentWasRaised(QWidget *parent);

View File

@ -46,6 +46,8 @@
#include <qwindow.h>
#include <qwidget.h>
#include <qdockwidget.h>
#include <qmainwindow.h>
class Window : public QWindow
@ -80,6 +82,7 @@ private slots:
void testUnparenting();
void testActivation();
void testAncestorChange();
void testDockWidget();
};
@ -278,6 +281,7 @@ void tst_QWindowContainer::testAncestorChange()
newRoot->setGeometry(100, 100, 200, 200);
newRoot->show();
QVERIFY(QTest::qWaitForWindowExposed(newRoot));
QCOMPARE(newRoot->windowHandle(), window->parent());
// newRoot
// + right
// + container
@ -285,6 +289,31 @@ void tst_QWindowContainer::testAncestorChange()
QCOMPARE(window->geometry(), QRect(100, 0, 100, 100));
}
void tst_QWindowContainer::testDockWidget()
{
QMainWindow mainWindow;
mainWindow.resize(200, 200);
QDockWidget *dock = new QDockWidget();
QWindow *window = new QWindow();
QWidget *container = QWidget::createWindowContainer(window);
dock->setWidget(container);
mainWindow.addDockWidget(Qt::RightDockWidgetArea, dock);
mainWindow.show();
QVERIFY(QTest::qWaitForWindowExposed(&mainWindow));
QVERIFY(window->parent() == mainWindow.window()->windowHandle());
QTest::qWait(1000);
dock->setFloating(true);
QTRY_VERIFY(window->parent() != mainWindow.window()->windowHandle());
QTest::qWait(1000);
dock->setFloating(false);
QTRY_VERIFY(window->parent() == mainWindow.window()->windowHandle());
}
QTEST_MAIN(tst_QWindowContainer)
#include "tst_qwindowcontainer.moc"