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 ParentChange The widget parent has changed.
|
||||
\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 PolishRequest The widget should be polished.
|
||||
\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
|
||||
ScreenChangeInternal = 216,
|
||||
|
||||
PlatformSurface = 217, // Platform surface created or about to be destroyed
|
||||
|
||||
// 512 reserved for Qt Jambi's MetaCall 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
|
||||
|
||||
|
|
|
@ -410,6 +410,23 @@ protected:
|
|||
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
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -180,6 +180,9 @@ void QOffscreenSurface::create()
|
|||
d->offscreenWindow->setGeometry(0, 0, d->size.width(), d->size.height());
|
||||
d->offscreenWindow->create();
|
||||
}
|
||||
|
||||
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated);
|
||||
QGuiApplication::sendEvent(this, &e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,6 +194,10 @@ void QOffscreenSurface::create()
|
|||
void QOffscreenSurface::destroy()
|
||||
{
|
||||
Q_D(QOffscreenSurface);
|
||||
|
||||
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed);
|
||||
QGuiApplication::sendEvent(this, &e);
|
||||
|
||||
delete d->platformOffscreenSurface;
|
||||
d->platformOffscreenSurface = 0;
|
||||
if (d->offscreenWindow) {
|
||||
|
|
|
@ -404,6 +404,11 @@ void QWindowPrivate::create(bool recursive)
|
|||
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();
|
||||
|
||||
setVisible(false);
|
||||
|
||||
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed);
|
||||
QGuiApplication::sendEvent(this, &e);
|
||||
|
||||
delete d->platformWindow;
|
||||
d->resizeEventPending = true;
|
||||
d->receivedExpose = false;
|
||||
|
|
|
@ -63,6 +63,7 @@ private slots:
|
|||
void positioning_data();
|
||||
void positioning();
|
||||
void positioningDuringMinimized();
|
||||
void platformSurface();
|
||||
void isExposed();
|
||||
void isActive();
|
||||
void testInputEvents();
|
||||
|
@ -160,8 +161,18 @@ public:
|
|||
{
|
||||
m_received[event->type()]++;
|
||||
m_order << event->type();
|
||||
if (event->type() == QEvent::Expose)
|
||||
switch (event->type()) {
|
||||
case QEvent::Expose:
|
||||
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);
|
||||
}
|
||||
|
@ -181,10 +192,16 @@ public:
|
|||
return m_exposeRegion;
|
||||
}
|
||||
|
||||
QPlatformSurfaceEvent::SurfaceEventType surfaceEventType() const
|
||||
{
|
||||
return m_surfaceventType;
|
||||
}
|
||||
|
||||
private:
|
||||
QHash<QEvent::Type, int> m_received;
|
||||
QVector<QEvent::Type> m_order;
|
||||
QRegion m_exposeRegion;
|
||||
QPlatformSurfaceEvent::SurfaceEventType m_surfaceventType;
|
||||
};
|
||||
|
||||
void tst_QWindow::eventOrderOnShow()
|
||||
|
@ -352,6 +369,63 @@ void tst_QWindow::positioningDuringMinimized()
|
|||
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()
|
||||
{
|
||||
QRect geometry(m_availableTopLeft + QPoint(80, 80), m_testWindowSize);
|
||||
|
|
Loading…
Reference in New Issue