Avoid calling syncWindow with already destroyed platform windows

Issuing a metacall from swapBuffers is dangerous since the window
may get destroyed by the time the slot is invoked.

This patch changes it to use an event, which is more efficient anyway,
that can be invalidated in case the QXcbWindow is destroy()'ed before
the event is delivered.

Change-Id: I44618ac1cb8b221aecce001ea39702164dcab6a5
Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
Reviewed-by: Uli Schlachter <psychon@znc.in>
bb10
Laszlo Agocs 2014-07-31 16:20:49 +02:00
parent 751a74c339
commit 61179c1447
5 changed files with 58 additions and 7 deletions

View File

@ -523,11 +523,11 @@ void QGLXContext::swapBuffers(QPlatformSurface *surface)
if (surface->surface()->surfaceClass() == QSurface::Window) {
QXcbWindow *platformWindow = static_cast<QXcbWindow *>(surface);
// OpenGL context might be bound to a non-gui thread
// use QueuedConnection to sync the window from the platformWindow's thread
// as QXcbWindow is no QObject, a wrapper slot in QXcbConnection is used.
// OpenGL context might be bound to a non-gui thread use QueuedConnection to sync
// the window from the platformWindow's thread as QXcbWindow is no QObject, an
// event is sent to QXcbConnection. (this is faster than a metacall)
if (platformWindow->needsSync())
QMetaObject::invokeMethod(m_screen->connection(), "syncWindow", Qt::QueuedConnection, Q_ARG(QXcbWindow*, platformWindow));
platformWindow->postSyncWindowRequest();
}
}

View File

@ -1842,9 +1842,26 @@ QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker()
return m_systemTrayTracker;
}
void QXcbConnection::syncWindow(QXcbWindow *window)
bool QXcbConnection::event(QEvent *e)
{
window->updateSyncRequestCounter();
if (e->type() == QEvent::User + 1) {
QXcbSyncWindowRequest *ev = static_cast<QXcbSyncWindowRequest *>(e);
QXcbWindow *w = ev->window();
if (w) {
w->updateSyncRequestCounter();
ev->invalidate();
}
return true;
}
return QObject::event(e);
}
void QXcbSyncWindowRequest::invalidate()
{
if (m_window) {
m_window->clearSyncWindowRequest();
m_window = 0;
}
}
QXcbConnectionGrabber::QXcbConnectionGrabber(QXcbConnection *connection)

View File

@ -355,6 +355,18 @@ public:
typedef QHash<xcb_window_t, QXcbWindowEventListener *> WindowMapper;
class QXcbSyncWindowRequest : public QEvent
{
public:
QXcbSyncWindowRequest(QXcbWindow *w) : QEvent(QEvent::Type(QEvent::User + 1)), m_window(w) { }
QXcbWindow *window() const { return m_window; }
void invalidate();
private:
QXcbWindow *m_window;
};
class QAbstractEventDispatcher;
class QXcbConnection : public QObject
{
@ -468,8 +480,10 @@ public:
QXcbEventReader *eventReader() const { return m_reader; }
protected:
bool event(QEvent *e) Q_DECL_OVERRIDE;
public slots:
void syncWindow(QXcbWindow *window);
void flush() { xcb_flush(m_connection); }
private slots:

View File

@ -223,6 +223,7 @@ QXcbWindow::QXcbWindow(QWindow *window)
#endif
, m_lastWindowStateEvent(-1)
, m_syncState(NoSyncNeeded)
, m_pendingSyncRequest(0)
{
m_screen = static_cast<QXcbScreen *>(window->screen()->handle());
@ -565,6 +566,9 @@ void QXcbWindow::destroy()
delete m_eglSurface;
m_eglSurface = 0;
#endif
if (m_pendingSyncRequest)
m_pendingSyncRequest->invalidate();
}
void QXcbWindow::setGeometry(const QRect &rect)
@ -2371,4 +2375,13 @@ bool QXcbWindow::needsSync() const
return m_syncState == SyncAndConfigureReceived;
}
void QXcbWindow::postSyncWindowRequest()
{
if (!m_pendingSyncRequest) {
QXcbSyncWindowRequest *e = new QXcbSyncWindowRequest(this);
m_pendingSyncRequest = e;
QCoreApplication::postEvent(m_screen->connection(), e);
}
}
QT_END_NAMESPACE

View File

@ -57,7 +57,9 @@ QT_BEGIN_NAMESPACE
class QXcbScreen;
class QXcbEGLSurface;
class QXcbSyncWindowRequest;
class QIcon;
class QXcbWindow : public QXcbObject, public QXcbWindowEventListener, public QPlatformWindow
{
public:
@ -159,6 +161,9 @@ public:
bool needsSync() const;
void postSyncWindowRequest();
void clearSyncWindowRequest() { m_pendingSyncRequest = 0; }
public Q_SLOTS:
void updateSyncRequestCounter();
@ -235,6 +240,8 @@ private:
SyncAndConfigureReceived
};
SyncState m_syncState;
QXcbSyncWindowRequest *m_pendingSyncRequest;
};
QT_END_NAMESPACE