summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@digia.com>2014-07-31 16:20:49 +0200
committerLaszlo Agocs <laszlo.agocs@digia.com>2014-08-01 20:42:31 +0200
commit61179c1447eb2b3fd43ca12d8b436cd73a0872a6 (patch)
tree3337eeadf8206ba4e1af22daaebf5a72d46432b9 /src
parent751a74c339586d86bc5df0586e1cdcb886e381bb (diff)
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>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.cpp8
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp21
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h16
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp13
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h7
5 files changed, 58 insertions, 7 deletions
diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp
index 45ccd9929e..3ce0041aeb 100644
--- a/src/plugins/platforms/xcb/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/qglxintegration.cpp
@@ -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();
}
}
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 7f23c84cb9..a2ce392151 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -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)
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 354ba54e70..9e9865a2e9 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -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:
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 787fdb6641..a127ac0293 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -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
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 72b5c7bcc9..a8cadd8e6c 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -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