mirror of https://github.com/qt/qtbase.git
Send events when platform surfaces are created/about to be destroyed
These synchronously delivered events allow applications to correctly and conveniently handle native platform surfaces being destroyed. This is particularly useful when doing rendering on a non-gui thread as it allows to shutdown rendering before the native surface gets destroyed from under us. Task-number: QTBUG-42476 Task-number: QTBUG-42483 Change-Id: I63f41bbdb32f281d0f3b8ec2537eb2b0361f3bb3 Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
This commit is contained in:
parent
3d575d4845
commit
c5ecabb70c
|
@ -183,6 +183,7 @@ QT_BEGIN_NAMESPACE
|
||||||
\value ParentAboutToChange The widget parent is about to change.
|
\value ParentAboutToChange The widget parent is about to change.
|
||||||
\value ParentChange The widget parent has changed.
|
\value ParentChange The widget parent has changed.
|
||||||
\value PlatformPanel A platform specific panel has been requested.
|
\value PlatformPanel A platform specific panel has been requested.
|
||||||
|
\value PlatformSurface A native platform surface has been created or is about to be destroyed.
|
||||||
\value Polish The widget is polished.
|
\value Polish The widget is polished.
|
||||||
\value PolishRequest The widget should be polished.
|
\value PolishRequest The widget should be polished.
|
||||||
\value QueryWhatsThis The widget should accept the event if it has "What's This?" help.
|
\value QueryWhatsThis The widget should accept the event if it has "What's This?" help.
|
||||||
|
|
|
@ -275,6 +275,8 @@ public:
|
||||||
WindowChangeInternal = 215, // internal for QQuickWidget
|
WindowChangeInternal = 215, // internal for QQuickWidget
|
||||||
ScreenChangeInternal = 216,
|
ScreenChangeInternal = 216,
|
||||||
|
|
||||||
|
PlatformSurface = 217, // Platform surface created or about to be destroyed
|
||||||
|
|
||||||
// 512 reserved for Qt Jambi's MetaCall event
|
// 512 reserved for Qt Jambi's MetaCall event
|
||||||
// 513 reserved for Qt Jambi's DeleteOnMainThread event
|
// 513 reserved for Qt Jambi's DeleteOnMainThread event
|
||||||
|
|
||||||
|
|
|
@ -1323,6 +1323,55 @@ QExposeEvent::~QExposeEvent()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class QPlatformSurfaceEvent
|
||||||
|
\since 5.5
|
||||||
|
\brief The QPlatformSurfaceEvent class is used to notify about native platform surface events.
|
||||||
|
\inmodule QtGui
|
||||||
|
|
||||||
|
\ingroup events
|
||||||
|
|
||||||
|
Platform window events are synchronously sent to windows and offscreen surfaces when their
|
||||||
|
underlying native surfaces are created or are about to be destroyed.
|
||||||
|
|
||||||
|
Applications can respond to these events to know when the underlying platform
|
||||||
|
surface exists.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\enum QPlatformSurfaceEvent::SurfaceEventType
|
||||||
|
|
||||||
|
This enum describes the type of platform surface event. The possible types are:
|
||||||
|
|
||||||
|
\value SurfaceCreated The underlying native surface has been created
|
||||||
|
\value SurfaceAboutToBeDestroyed The underlying native surface will be destroyed immediately after this event
|
||||||
|
|
||||||
|
The \c SurfaceAboutToBeDestroyed event type is useful as a means of stopping rendering to
|
||||||
|
a platform window before it is destroyed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn QPlatformSurfaceEvent::SurfaceEventType QPlatformSurfaceEvent::surfaceEventType() const
|
||||||
|
|
||||||
|
Returns the specific type of platform surface event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructs a platform surface event for the given \a surfaceEventType.
|
||||||
|
*/
|
||||||
|
QPlatformSurfaceEvent::QPlatformSurfaceEvent(SurfaceEventType surfaceEventType)
|
||||||
|
: QEvent(PlatformSurface)
|
||||||
|
, m_surfaceEventType(surfaceEventType)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
QPlatformSurfaceEvent::~QPlatformSurfaceEvent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn const QRegion &QExposeEvent::region() const
|
\fn const QRegion &QExposeEvent::region() const
|
||||||
|
|
||||||
|
|
|
@ -410,6 +410,23 @@ protected:
|
||||||
QRegion rgn;
|
QRegion rgn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Q_GUI_EXPORT QPlatformSurfaceEvent : public QEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum SurfaceEventType {
|
||||||
|
SurfaceCreated,
|
||||||
|
SurfaceAboutToBeDestroyed
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit QPlatformSurfaceEvent(SurfaceEventType surfaceEventType);
|
||||||
|
~QPlatformSurfaceEvent();
|
||||||
|
|
||||||
|
inline SurfaceEventType surfaceEventType() const { return m_surfaceEventType; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SurfaceEventType m_surfaceEventType;
|
||||||
|
};
|
||||||
|
|
||||||
class Q_GUI_EXPORT QResizeEvent : public QEvent
|
class Q_GUI_EXPORT QResizeEvent : public QEvent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -180,6 +180,9 @@ void QOffscreenSurface::create()
|
||||||
d->offscreenWindow->setGeometry(0, 0, d->size.width(), d->size.height());
|
d->offscreenWindow->setGeometry(0, 0, d->size.width(), d->size.height());
|
||||||
d->offscreenWindow->create();
|
d->offscreenWindow->create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated);
|
||||||
|
QGuiApplication::sendEvent(this, &e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,6 +194,10 @@ void QOffscreenSurface::create()
|
||||||
void QOffscreenSurface::destroy()
|
void QOffscreenSurface::destroy()
|
||||||
{
|
{
|
||||||
Q_D(QOffscreenSurface);
|
Q_D(QOffscreenSurface);
|
||||||
|
|
||||||
|
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed);
|
||||||
|
QGuiApplication::sendEvent(this, &e);
|
||||||
|
|
||||||
delete d->platformOffscreenSurface;
|
delete d->platformOffscreenSurface;
|
||||||
d->platformOffscreenSurface = 0;
|
d->platformOffscreenSurface = 0;
|
||||||
if (d->offscreenWindow) {
|
if (d->offscreenWindow) {
|
||||||
|
|
|
@ -404,6 +404,11 @@ void QWindowPrivate::create(bool recursive)
|
||||||
window->d_func()->platformWindow->setParent(platformWindow);
|
window->d_func()->platformWindow->setParent(platformWindow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (platformWindow) {
|
||||||
|
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated);
|
||||||
|
QGuiApplication::sendEvent(q, &e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1590,6 +1595,10 @@ void QWindow::destroy()
|
||||||
bool wasVisible = isVisible();
|
bool wasVisible = isVisible();
|
||||||
|
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
|
|
||||||
|
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed);
|
||||||
|
QGuiApplication::sendEvent(this, &e);
|
||||||
|
|
||||||
delete d->platformWindow;
|
delete d->platformWindow;
|
||||||
d->resizeEventPending = true;
|
d->resizeEventPending = true;
|
||||||
d->receivedExpose = false;
|
d->receivedExpose = false;
|
||||||
|
|
|
@ -63,6 +63,7 @@ private slots:
|
||||||
void positioning_data();
|
void positioning_data();
|
||||||
void positioning();
|
void positioning();
|
||||||
void positioningDuringMinimized();
|
void positioningDuringMinimized();
|
||||||
|
void platformSurface();
|
||||||
void isExposed();
|
void isExposed();
|
||||||
void isActive();
|
void isActive();
|
||||||
void testInputEvents();
|
void testInputEvents();
|
||||||
|
@ -160,8 +161,18 @@ public:
|
||||||
{
|
{
|
||||||
m_received[event->type()]++;
|
m_received[event->type()]++;
|
||||||
m_order << event->type();
|
m_order << event->type();
|
||||||
if (event->type() == QEvent::Expose)
|
switch (event->type()) {
|
||||||
|
case QEvent::Expose:
|
||||||
m_exposeRegion = static_cast<QExposeEvent *>(event)->region();
|
m_exposeRegion = static_cast<QExposeEvent *>(event)->region();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QEvent::PlatformSurface:
|
||||||
|
m_surfaceventType = static_cast<QPlatformSurfaceEvent *>(event)->surfaceEventType();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return QWindow::event(event);
|
return QWindow::event(event);
|
||||||
}
|
}
|
||||||
|
@ -181,10 +192,16 @@ public:
|
||||||
return m_exposeRegion;
|
return m_exposeRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPlatformSurfaceEvent::SurfaceEventType surfaceEventType() const
|
||||||
|
{
|
||||||
|
return m_surfaceventType;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<QEvent::Type, int> m_received;
|
QHash<QEvent::Type, int> m_received;
|
||||||
QVector<QEvent::Type> m_order;
|
QVector<QEvent::Type> m_order;
|
||||||
QRegion m_exposeRegion;
|
QRegion m_exposeRegion;
|
||||||
|
QPlatformSurfaceEvent::SurfaceEventType m_surfaceventType;
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_QWindow::eventOrderOnShow()
|
void tst_QWindow::eventOrderOnShow()
|
||||||
|
@ -352,6 +369,63 @@ void tst_QWindow::positioningDuringMinimized()
|
||||||
QTRY_COMPARE(window.geometry(), newGeometry);
|
QTRY_COMPARE(window.geometry(), newGeometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PlatformWindowFilter : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
PlatformWindowFilter(QObject *parent = 0)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_window(Q_NULLPTR)
|
||||||
|
, m_alwaysExisted(true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void setWindow(Window *window) { m_window = window; }
|
||||||
|
|
||||||
|
bool eventFilter(QObject *o, QEvent *e)
|
||||||
|
{
|
||||||
|
// Check that the platform surface events are delivered synchronously.
|
||||||
|
// If they are, the native platform surface should always exist when we
|
||||||
|
// receive a QPlatformSurfaceEvent
|
||||||
|
if (e->type() == QEvent::PlatformSurface && o == m_window) {
|
||||||
|
m_alwaysExisted &= (m_window->handle() != Q_NULLPTR);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool surfaceExisted() const { return m_alwaysExisted; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Window *m_window;
|
||||||
|
bool m_alwaysExisted;
|
||||||
|
};
|
||||||
|
|
||||||
|
void tst_QWindow::platformSurface()
|
||||||
|
{
|
||||||
|
QRect geometry(m_availableTopLeft + QPoint(80, 80), m_testWindowSize);
|
||||||
|
|
||||||
|
Window window;
|
||||||
|
PlatformWindowFilter filter;
|
||||||
|
filter.setWindow(&window);
|
||||||
|
window.installEventFilter(&filter);
|
||||||
|
|
||||||
|
window.setGeometry(geometry);
|
||||||
|
QCOMPARE(window.geometry(), geometry);
|
||||||
|
window.create();
|
||||||
|
|
||||||
|
QTRY_VERIFY(window.received(QEvent::PlatformSurface) == 1);
|
||||||
|
QTRY_VERIFY(window.surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated);
|
||||||
|
QTRY_VERIFY(window.handle() != Q_NULLPTR);
|
||||||
|
|
||||||
|
window.destroy();
|
||||||
|
QTRY_VERIFY(window.received(QEvent::PlatformSurface) == 2);
|
||||||
|
QTRY_VERIFY(window.surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed);
|
||||||
|
QTRY_VERIFY(window.handle() == Q_NULLPTR);
|
||||||
|
|
||||||
|
// Check for synchronous delivery of platform surface events and that the platform
|
||||||
|
// surface always existed upon event delivery
|
||||||
|
QTRY_VERIFY(filter.surfaceExisted());
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QWindow::isExposed()
|
void tst_QWindow::isExposed()
|
||||||
{
|
{
|
||||||
QRect geometry(m_availableTopLeft + QPoint(80, 80), m_testWindowSize);
|
QRect geometry(m_availableTopLeft + QPoint(80, 80), m_testWindowSize);
|
||||||
|
|
Loading…
Reference in New Issue