diff options
author | Axel Spoerl <axel.spoerl@qt.io> | 2023-12-19 11:20:41 +0100 |
---|---|---|
committer | Axel Spoerl <axel.spoerl@qt.io> | 2023-12-21 18:49:29 +0000 |
commit | b9ee6d3b2e465eb70ba43ea62d2ada5327a138c8 (patch) | |
tree | 2c7e8db4b5bfcac6a68e0ea94dda03bf65ed63d7 | |
parent | 29a4323974a1877faf389637be40688e3bc1790d (diff) |
QWindowContainer: Don't embed a QWidget
Embedding a QWidget in a window container (via its windowHandle())
may cause crashes, e.g. during drag & drop and when the application
goes out of scope.
If a QWidget->windowHandle() is attempted to be embedded in a window
container, return the pointer to the widget instead of creating a
container.
Add an autotest.
Update documentation.
[ChangeLog][QtWidgets][QWindowContainer] If createWindowContainer()
is called with a QWidgetWindow argument, return pointer to the
widget instead of new container.
Pick-to: 6.7
Fixes: QTBUG-119113
Change-Id: Id052a03be13adce05bbd025d86270d265dfb662e
Reviewed-by: Paul Wicking <paul.wicking@qt.io>
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
-rw-r--r-- | src/widgets/kernel/qwindowcontainer.cpp | 21 | ||||
-rw-r--r-- | tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp | 34 |
2 files changed, 55 insertions, 0 deletions
diff --git a/src/widgets/kernel/qwindowcontainer.cpp b/src/widgets/kernel/qwindowcontainer.cpp index 14286406dc..7a7de66012 100644 --- a/src/widgets/kernel/qwindowcontainer.cpp +++ b/src/widgets/kernel/qwindowcontainer.cpp @@ -3,6 +3,7 @@ #include "qwindowcontainer_p.h" #include "qwidget_p.h" +#include "qwidgetwindow_p.h" #include <QtGui/qwindow.h> #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformintegration.h> @@ -164,11 +165,31 @@ public: application can greatly hurt the overall performance of the application. + \li Since 6.7, if \a window belongs to a widget (that is, \a window + was received from calling \l windowHandle()), no container will be + created. Instead, this function will return the widget itself, after + being reparented to \l parent. Since no container will be created, + \a flags will be ignored. In other words, if \a window belongs to + a widget, consider just reparenting that widget to \a parent instead + of using this function. + \endlist */ QWidget *QWidget::createWindowContainer(QWindow *window, QWidget *parent, Qt::WindowFlags flags) { + // Embedding a QWidget in a window container doesn't make sense, + // and has various issues in practice, so just return the widget + // itself. + if (auto *widgetWindow = qobject_cast<QWidgetWindow *>(window)) { + QWidget *widget = widgetWindow->widget(); + if (flags != Qt::WindowFlags()) { + qWarning() << window << "refers to a widget:" << widget + << "WindowFlags" << flags << "will be ignored."; + } + widget->setParent(parent); + return widget; + } return new QWindowContainer(window, parent, flags); } diff --git a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp index 19c9606d79..08c2f364df 100644 --- a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp +++ b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp @@ -57,6 +57,7 @@ private slots: void testDockWidget(); void testNativeContainerParent(); void testPlatformSurfaceEvent(); + void embedWidgetWindow(); void cleanup(); private: @@ -410,6 +411,39 @@ void tst_QWindowContainer::testPlatformSurfaceEvent() QVERIFY(ok); } +void tst_QWindowContainer::embedWidgetWindow() +{ + { + QWidget parent; + QWidget *widget = new QWidget; + widget->show(); + QVERIFY(QTest::qWaitForWindowExposed(widget)); + QVERIFY(widget->windowHandle()); + QPointer<QWindow> widgetWindow = widget->windowHandle(); + auto *container = QWidget::createWindowContainer(widgetWindow, &parent); + QCOMPARE(container, widget); + QCOMPARE(widget->parent(), &parent); + delete widget; + QTRY_VERIFY(widgetWindow.isNull()); + } + + QPointer<QWidget> widget = new QWidget; + QPointer<QWindow> widgetWindow; + { + QWidget parent; + widget->show(); + QVERIFY(QTest::qWaitForWindowExposed(widget)); + QVERIFY(widget->windowHandle()); + widgetWindow = widget->windowHandle(); + auto *container = QWidget::createWindowContainer(widgetWindow, &parent); + QCOMPARE(container, widget); + QCOMPARE(widget->parent(), &parent); + } + QTRY_VERIFY(widget.isNull()); + QTRY_VERIFY(widgetWindow.isNull()); + +} + QTEST_MAIN(tst_QWindowContainer) #include "tst_qwindowcontainer.moc" |