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 <paul.wicking@qt.io>
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
(cherry picked from commit b9ee6d3b2e465eb70ba43ea62d2ada5327a138c8)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Axel Spoerl 2023-12-19 11:20:41 +01:00 committed by Qt Cherry-pick Bot
parent eb9252526e
commit c6219ebfb5
2 changed files with 55 additions and 0 deletions

View File

@ -3,6 +3,7 @@
#include "qwindowcontainer_p.h" #include "qwindowcontainer_p.h"
#include "qwidget_p.h" #include "qwidget_p.h"
#include "qwidgetwindow_p.h"
#include <QtGui/qwindow.h> #include <QtGui/qwindow.h>
#include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h> #include <qpa/qplatformintegration.h>
@ -164,11 +165,31 @@ public:
application can greatly hurt the overall performance of the application can greatly hurt the overall performance of the
application. 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 \endlist
*/ */
QWidget *QWidget::createWindowContainer(QWindow *window, QWidget *parent, Qt::WindowFlags flags) 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); return new QWindowContainer(window, parent, flags);
} }

View File

@ -57,6 +57,7 @@ private slots:
void testDockWidget(); void testDockWidget();
void testNativeContainerParent(); void testNativeContainerParent();
void testPlatformSurfaceEvent(); void testPlatformSurfaceEvent();
void embedWidgetWindow();
void cleanup(); void cleanup();
private: private:
@ -410,6 +411,39 @@ void tst_QWindowContainer::testPlatformSurfaceEvent()
QVERIFY(ok); 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) QTEST_MAIN(tst_QWindowContainer)
#include "tst_qwindowcontainer.moc" #include "tst_qwindowcontainer.moc"