From c6219ebfb5cd443abdbc466353979a9af3fe8d72 Mon Sep 17 00:00:00 2001 From: Axel Spoerl Date: Tue, 19 Dec 2023 11:20:41 +0100 Subject: [PATCH] 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. Fixes: QTBUG-119113 Change-Id: Id052a03be13adce05bbd025d86270d265dfb662e Reviewed-by: Paul Wicking Reviewed-by: Richard Moe Gustavsen (cherry picked from commit b9ee6d3b2e465eb70ba43ea62d2ada5327a138c8) Reviewed-by: Qt Cherry-pick Bot --- src/widgets/kernel/qwindowcontainer.cpp | 21 ++++++++++++ .../qwindowcontainer/tst_qwindowcontainer.cpp | 34 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/widgets/kernel/qwindowcontainer.cpp b/src/widgets/kernel/qwindowcontainer.cpp index 14286406dc5..7a7de660127 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 #include #include @@ -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(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 19c9606d79d..08c2f364df4 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 widgetWindow = widget->windowHandle(); + auto *container = QWidget::createWindowContainer(widgetWindow, &parent); + QCOMPARE(container, widget); + QCOMPARE(widget->parent(), &parent); + delete widget; + QTRY_VERIFY(widgetWindow.isNull()); + } + + QPointer widget = new QWidget; + QPointer 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"