Make QPlatformSurface events work with QWindowContainer
Embeddeding a QWindow via QWidget::createWindowContainer() fails to deliver the SurfaceAboutToBeDestroyed event. This breaks any OpenGL or Vulkan based QWindow that releases resources upon this event, and is particularly critical with Vulkan where the only way to do properly ordered swapchain - surface cleanup is via this event. In the non-embedded case close() eventually ends up in an explicit destroy() in QWindow. In the embedded case destroy() only gets called from ~QWindow. This then silently breaks since the subclass' reimplemented event() virtual is not getting called anymore. To remedy the problem, simply add an explicit destroy() to QWindowContainer. Task-number: QTBUG-55166 Change-Id: I1671e8f4d39f6c44e19eca7b9387f55fe3788294 Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
This commit is contained in:
parent
e39e4bfc0f
commit
dfc338613e
@ -1814,6 +1814,15 @@ void QWindowPrivate::destroy()
|
||||
|
||||
q->setVisible(false);
|
||||
|
||||
// Let subclasses act, typically by doing graphics resource cleaup, when
|
||||
// the window, to which graphics resource may be tied, is going away.
|
||||
//
|
||||
// NB! This is disfunctional when destroy() is invoked from the dtor since
|
||||
// a reimplemented event() will not get called in the subclasses at that
|
||||
// stage. However, the typical QWindow cleanup involves either close() or
|
||||
// going through QWindowContainer, both of which will do an explicit, early
|
||||
// destroy(), which is good here.
|
||||
|
||||
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed);
|
||||
QGuiApplication::sendEvent(q, &e);
|
||||
|
||||
|
@ -241,6 +241,14 @@ QWindow *QWindowContainer::containedWindow() const
|
||||
QWindowContainer::~QWindowContainer()
|
||||
{
|
||||
Q_D(QWindowContainer);
|
||||
|
||||
// Call destroy() explicitly first. The dtor would do this too, but
|
||||
// QEvent::PlatformSurface delivery relies on virtuals. Getting
|
||||
// SurfaceAboutToBeDestroyed can be essential for OpenGL, Vulkan, etc.
|
||||
// QWindow subclasses in particular. Keep these working.
|
||||
if (d->window)
|
||||
d->window->destroy();
|
||||
|
||||
delete d->window;
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <qmainwindow.h>
|
||||
#include <qscreen.h>
|
||||
#include <qscopedpointer.h>
|
||||
#include <qevent.h>
|
||||
|
||||
|
||||
class Window : public QWindow
|
||||
@ -77,6 +78,7 @@ private slots:
|
||||
void testAncestorChange();
|
||||
void testDockWidget();
|
||||
void testNativeContainerParent();
|
||||
void testPlatformSurfaceEvent();
|
||||
void cleanup();
|
||||
|
||||
private:
|
||||
@ -343,6 +345,41 @@ void tst_QWindowContainer::testNativeContainerParent()
|
||||
QTRY_COMPARE(window->parent(), container->windowHandle());
|
||||
}
|
||||
|
||||
class EventWindow : public QWindow
|
||||
{
|
||||
public:
|
||||
EventWindow(bool *surfaceDestroyFlag) : m_surfaceDestroyFlag(surfaceDestroyFlag) { }
|
||||
bool event(QEvent *e) override;
|
||||
|
||||
private:
|
||||
bool *m_surfaceDestroyFlag;
|
||||
};
|
||||
|
||||
bool EventWindow::event(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::PlatformSurface) {
|
||||
if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
|
||||
*m_surfaceDestroyFlag = true;
|
||||
}
|
||||
return QWindow::event(e);
|
||||
}
|
||||
|
||||
void tst_QWindowContainer::testPlatformSurfaceEvent()
|
||||
{
|
||||
// Verify that SurfaceAboutToBeDestroyed is delivered and the
|
||||
// window subclass still gets a chance to process it.
|
||||
|
||||
bool ok = false;
|
||||
QPointer<EventWindow> window(new EventWindow(&ok));
|
||||
window->create();
|
||||
QWidget *container = QWidget::createWindowContainer(window);
|
||||
|
||||
delete container;
|
||||
|
||||
QCOMPARE(window.data(), nullptr);
|
||||
QVERIFY(ok);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QWindowContainer)
|
||||
|
||||
#include "tst_qwindowcontainer.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user