summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorSamuel Rødal <samuel.rodal@nokia.com>2011-03-31 10:08:14 (GMT)
committerSamuel Rødal <samuel.rodal@nokia.com>2011-03-31 10:08:14 (GMT)
commitfaeabd9d202b1af002cd73da148ca4c27715470d (patch)
treec75e13a68ffe8cbce256a8eaa24d30f5f8eeb9f7 /src/plugins
parentee481481bbd1d910c8a0191aa517f96186130d8b (diff)
downloadQt-faeabd9d202b1af002cd73da148ca4c27715470d.zip
Qt-faeabd9d202b1af002cd73da148ca4c27715470d.tar.gz
Qt-faeabd9d202b1af002cd73da148ca4c27715470d.tar.bz2
Fixed synchronizations issues in XCB platform plugin.
Use select() and xcb_poll_for_event() instead of xcb_wait_for_event(), ad xcb_wait_for_event() will lock the XCB connection mutex, preventing the other thread from posting events etc.
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.cpp13
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp205
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h7
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbwindowsurface.cpp33
6 files changed, 170 insertions, 98 deletions
diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp
index d42cfeb..d1171b8 100644
--- a/src/plugins/platforms/xcb/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/qglxintegration.cpp
@@ -65,6 +65,7 @@ QGLXContext::QGLXContext(Window window, QXcbScreen *screen, const QPlatformWindo
, m_drawable((Drawable)window)
, m_context(0)
{
+ Q_XCB_NOOP(m_screen->connection());
const QPlatformGLContext *sharePlatformContext;
if (format.useDefaultSharedContext()) {
if (!QPlatformGLContext::defaultSharedContext()) {
@@ -87,6 +88,7 @@ QGLXContext::QGLXContext(Window window, QXcbScreen *screen, const QPlatformWindo
GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen),screen->screenNumber(),format);
m_context = glXCreateNewContext(DISPLAY_FROM_XCB(screen), config, GLX_RGBA_TYPE, shareGlxContext, TRUE);
m_windowFormat = qglx_platformWindowFromGLXFBConfig(DISPLAY_FROM_XCB(screen), config, m_context);
+ Q_XCB_NOOP(m_screen->connection());
}
QGLXContext::QGLXContext(QXcbScreen *screen, Drawable drawable, GLXContext context)
@@ -97,12 +99,15 @@ QGLXContext::QGLXContext(QXcbScreen *screen, Drawable drawable, GLXContext conte
QGLXContext::~QGLXContext()
{
+ Q_XCB_NOOP(m_screen->connection());
if (m_context)
glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context);
+ Q_XCB_NOOP(m_screen->connection());
}
void QGLXContext::createDefaultSharedContext(QXcbScreen *screen)
{
+ Q_XCB_NOOP(screen->connection());
int x = 0;
int y = 0;
int w = 3;
@@ -126,30 +131,38 @@ void QGLXContext::createDefaultSharedContext(QXcbScreen *screen)
} else {
qWarning("Warning no shared context created");
}
+ Q_XCB_NOOP(screen->connection());
}
void QGLXContext::makeCurrent()
{
+ Q_XCB_NOOP(m_screen->connection());
m_screen->connection()->setEventProcessingEnabled(false);
QPlatformGLContext::makeCurrent();
glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), m_drawable, m_context);
+ Q_XCB_NOOP(m_screen->connection());
}
void QGLXContext::doneCurrent()
{
+ Q_XCB_NOOP(m_screen->connection());
QPlatformGLContext::doneCurrent();
glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), 0, 0);
m_screen->connection()->setEventProcessingEnabled(true);
+ Q_XCB_NOOP(m_screen->connection());
}
void QGLXContext::swapBuffers()
{
+ Q_XCB_NOOP(m_screen->connection());
glXSwapBuffers(DISPLAY_FROM_XCB(m_screen), m_drawable);
doneCurrent();
+ Q_XCB_NOOP(m_screen->connection());
}
void* QGLXContext::getProcAddress(const QString& procName)
{
+ Q_XCB_NOOP(m_screen->connection());
typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *);
static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
static bool resolved = false;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index f1d3d2b..05d3440 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -76,6 +76,7 @@ extern "C" {
QXcbConnection::QXcbConnection(const char *displayName)
: m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY"))
+ , m_pauseId(0)
, m_enabled(true)
#ifdef XCB_USE_DRI2
, m_dri2_major(0)
@@ -130,7 +131,7 @@ QXcbConnection::QXcbConnection(const char *displayName)
start();
}
-void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom atom)
+void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom atom, uint id)
{
xcb_client_message_event_t event;
memset(&event, 0, sizeof(event));
@@ -140,9 +141,9 @@ void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom atom)
event.sequence = 0;
event.window = m_connectionEventListener;
event.type = atom;
+ event.data.data32[0] = id;
- xcb_send_event(xcb_connection(), false, m_connectionEventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
-
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_connectionEventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event));
xcb_flush(xcb_connection());
}
@@ -152,10 +153,12 @@ void QXcbConnection::setEventProcessingEnabled(bool enabled)
return;
if (!enabled) {
+ sendConnectionEvent(QXcbAtom::_QT_PAUSE_CONNECTION, uint(m_pauseId));
m_connectionLock.lock();
- sendConnectionEvent(QXcbAtom::_QT_PAUSE_CONNECTION);
+ m_pauseId.fetchAndAddOrdered(1);
} else {
m_connectionLock.unlock();
+ m_connectionWaitCondition.wakeAll();
}
m_enabled = enabled;
@@ -191,8 +194,11 @@ QXcbWindow *platformWindowFromId(xcb_window_t id)
#define HANDLE_PLATFORM_WINDOW_EVENT(event_t, window, handler) \
{ \
event_t *e = (event_t *)event; \
- if (QXcbWindow *platformWindow = platformWindowFromId(e->window)) \
- platformWindow->handler(e); \
+ if (QXcbWindow *platformWindow = platformWindowFromId(e->window)) { \
+ QObjectPrivate *d = QObjectPrivate::get(platformWindow->widget()); \
+ if (!d->wasDeleted) \
+ platformWindow->handler(e); \
+ } \
} \
break;
@@ -419,100 +425,118 @@ void QXcbConnection::log(const char *file, int line, int sequence)
void QXcbConnection::run()
{
- while (xcb_generic_event_t *event = xcb_wait_for_event(xcb_connection())) {
- bool handled = true;
+ QMutexLocker locker(&m_connectionLock);
+ fd_set readset;
+ int xcb_fd = xcb_get_file_descriptor(xcb_connection());
+ FD_ZERO(&readset);
+ FD_SET(xcb_fd, &readset);
+ int result;
+ while (true) {
+ while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection())) {
+ bool handled = true;
+
+ uint response_type = event->response_type & ~0x80;
+
+ if (!response_type) {
+ xcb_generic_error_t *error = (xcb_generic_error_t *)event;
+
+ uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1);
+ uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1);
+
+ printf("XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d\n",
+ int(error->error_code), xcb_errors[clamped_error_code],
+ int(error->sequence), int(error->resource_id),
+ int(error->major_code), xcb_protocol_request_codes[clamped_major_code],
+ int(error->minor_code));
+#ifdef Q_XCB_DEBUG
+ QMutexLocker locker(&m_callLogMutex);
+ int i = 0;
+ for (; i < m_callLog.size(); ++i) {
+ if (m_callLog.at(i).sequence == error->sequence) {
+ printf("Caused by: %s:%d\n", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
+ break;
+ } else if (m_callLog.at(i).sequence > error->sequence) {
+ printf("Caused some time before: %s:%d\n", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
+ if (i > 0)
+ printf("and after: %s:%d\n", qPrintable(m_callLog.at(i-1).file), m_callLog.at(i-1).line);
+ break;
+ }
+ }
+ if (i == m_callLog.size() && !m_callLog.isEmpty())
+ printf("Caused some time after: %s:%d\n", qPrintable(m_callLog.first().file), m_callLog.first().line);
+#endif
+ continue;
+ }
- uint response_type = event->response_type & ~0x80;
+#ifdef Q_XCB_DEBUG
+ {
+ QMutexLocker locker(&m_callLogMutex);
+ int i = 0;
+ for (; i < m_callLog.size(); ++i)
+ if (m_callLog.at(i).sequence >= event->sequence)
+ break;
+ m_callLog.remove(0, i);
+ }
+#endif
- if (!response_type) {
- xcb_generic_error_t *error = (xcb_generic_error_t *)event;
+ if (response_type == XCB_CLIENT_MESSAGE) {
+ xcb_client_message_event_t *ev = (xcb_client_message_event_t *)event;
- uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1);
- uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1);
+ if (ev->type == QXcbAtom::_QT_CLOSE_CONNECTION)
+ return;
- printf("XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d\n",
- int(error->error_code), xcb_errors[clamped_error_code],
- int(error->sequence), int(error->resource_id),
- int(error->major_code), xcb_protocol_request_codes[clamped_major_code],
- int(error->minor_code));
-#ifdef Q_XCB_DEBUG
- QMutexLocker locker(&m_callLogMutex);
- int i = 0;
- for (; i < m_callLog.size(); ++i) {
- if (m_callLog.at(i).sequence == error->sequence) {
- printf("Caused by: %s:%d\n", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
- break;
- } else if (m_callLog.at(i).sequence > error->sequence) {
- printf("Caused some time before: %s:%d\n", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
- if (i > 0)
- printf("and after: %s:%d\n", qPrintable(m_callLog.at(i-1).file), m_callLog.at(i-1).line);
- break;
+ if (ev->type == QXcbAtom::_QT_PAUSE_CONNECTION) {
+ if (ev->data.data32[0] == uint(m_pauseId))
+ m_connectionWaitCondition.wait(&m_connectionLock);
+ continue;
}
}
- if (i == m_callLog.size() && !m_callLog.isEmpty())
- printf("Caused some time after: %s:%d\n", qPrintable(m_callLog.first().file), m_callLog.first().line);
-#endif
- continue;
- }
-#ifdef Q_XCB_DEBUG
- {
- QMutexLocker locker(&m_callLogMutex);
- int i = 0;
- for (; i < m_callLog.size(); ++i)
- if (m_callLog.at(i).sequence >= event->sequence)
- break;
- m_callLog.remove(0, i);
+ switch (response_type) {
+ case XCB_EXPOSE:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
+ case XCB_BUTTON_PRESS:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
+ case XCB_BUTTON_RELEASE:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
+ case XCB_MOTION_NOTIFY:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent);
+ case XCB_CONFIGURE_NOTIFY:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent);
+ case XCB_CLIENT_MESSAGE:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_client_message_event_t, window, handleClientMessageEvent);
+ case XCB_ENTER_NOTIFY:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
+ case XCB_LEAVE_NOTIFY:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent);
+ case XCB_FOCUS_IN:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent);
+ case XCB_FOCUS_OUT:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent);
+ case XCB_KEY_PRESS:
+ HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
+ case XCB_KEY_RELEASE:
+ HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
+ case XCB_MAPPING_NOTIFY:
+ m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event);
+ break;
+ default:
+ handled = false;
+ break;
+ }
+ if (handled)
+ printXcbEvent("Handled XCB event", event);
+ else
+ printXcbEvent("Unhandled XCB event", event);
}
-#endif
- if (response_type == XCB_CLIENT_MESSAGE
- && ((xcb_client_message_event_t *)event)->type == QXcbAtom::_QT_CLOSE_CONNECTION)
- return;
+ do {
+ result = select(xcb_fd + 1, &readset, 0, 0, 0);
+ } while (result == -1 && errno == EINTR);
- if (response_type == XCB_CLIENT_MESSAGE
- && ((xcb_client_message_event_t *)event)->type == QXcbAtom::_QT_PAUSE_CONNECTION)
- {
- QMutexLocker locker(&m_connectionLock);
+ if (result <= 0 || !FD_ISSET(xcb_fd, &readset))
continue;
- }
- switch (response_type) {
- case XCB_EXPOSE:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
- case XCB_BUTTON_PRESS:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
- case XCB_BUTTON_RELEASE:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
- case XCB_MOTION_NOTIFY:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent);
- case XCB_CONFIGURE_NOTIFY:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent);
- case XCB_CLIENT_MESSAGE:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_client_message_event_t, window, handleClientMessageEvent);
- case XCB_ENTER_NOTIFY:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
- case XCB_LEAVE_NOTIFY:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent);
- case XCB_FOCUS_IN:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent);
- case XCB_FOCUS_OUT:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent);
- case XCB_KEY_PRESS:
- HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
- case XCB_KEY_RELEASE:
- HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
- case XCB_MAPPING_NOTIFY:
- m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event);
- break;
- default:
- handled = false;
- break;
- }
- if (handled)
- printXcbEvent("Handled XCB event", event);
- else
- printXcbEvent("Unhandled XCB event", event);
}
fprintf(stderr, "I/O error in xcb_wait_for_event\n");
}
@@ -714,8 +738,13 @@ void QXcbConnection::initializeAllAtoms() {
void QXcbConnection::sync()
{
// from xcb_aux_sync
+ bool wasEnabled = m_enabled;
+ setEventProcessingEnabled(false);
xcb_get_input_focus_cookie_t cookie = Q_XCB_CALL(xcb_get_input_focus(xcb_connection()));
free(xcb_get_input_focus_reply(xcb_connection(), cookie, 0));
+
+ if (wasEnabled)
+ setEventProcessingEnabled(true);
}
#if defined(XCB_USE_EGL)
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 2723f26..7088184 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -46,6 +46,7 @@
#include <QList>
#include <QMutex>
#include <QVector>
+#include <QWaitCondition>
#include <QThread>
#define Q_XCB_DEBUG
@@ -265,7 +266,7 @@ protected:
private:
void initializeAllAtoms();
- void sendConnectionEvent(QXcbAtom::Atom atom);
+ void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0);
#ifdef XCB_USE_DRI2
void initializeDri2();
#endif
@@ -282,6 +283,8 @@ private:
xcb_window_t m_connectionEventListener;
QMutex m_connectionLock;
+ QWaitCondition m_connectionWaitCondition;
+ QAtomicInt m_pauseId;
bool m_enabled;
QXcbKeyboard *m_keyboard;
@@ -326,9 +329,11 @@ cookie_t q_xcb_call_template(const cookie_t &cookie, QXcbConnection *connection,
}
#define Q_XCB_CALL(x) q_xcb_call_template(x, connection(), __FILE__, __LINE__)
#define Q_XCB_CALL2(x, connection) q_xcb_call_template(x, connection, __FILE__, __LINE__)
+#define Q_XCB_NOOP(c) q_xcb_call_template(xcb_no_operation(c->xcb_connection()), c, __FILE__, __LINE__);
#else
#define Q_XCB_CALL(x) x
#define Q_XCB_CALL2(x, connection) x
+#define Q_XCB_NOOP(c)
#endif
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index ec9a009..f501c00 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -921,6 +921,8 @@ void QXcbKeyboard::handleKeyEvent(QWidget *widget, QEvent::Type type, xcb_keycod
if (state & 128)
col += altGrOffset;
+ Q_XCB_NOOP(connection());
+
#ifdef XCB_KEYBOARD_DEBUG
printf("key code: %d, state: %d, syms: ", code, state);
for (int i = 0; i <= 5; ++i) {
@@ -929,6 +931,8 @@ void QXcbKeyboard::handleKeyEvent(QWidget *widget, QEvent::Type type, xcb_keycod
printf("\n");
#endif
+ Q_XCB_NOOP(connection());
+
xcb_keysym_t sym = xcb_key_symbols_get_keysym(m_key_symbols, code, col);
if (sym == XCB_NO_SYMBOL)
sym = xcb_key_symbols_get_keysym(m_key_symbols, code, col ^ 0x1);
@@ -940,6 +944,8 @@ void QXcbKeyboard::handleKeyEvent(QWidget *widget, QEvent::Type type, xcb_keycod
sym = toupper(sym);
}
+ Q_XCB_NOOP(connection());
+
QByteArray chars;
Qt::KeyboardModifiers modifiers;
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index e997824..7aeb557 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -222,9 +222,7 @@ void QXcbWindow::setVisible(bool visible)
xcb_wm_hints_set_normal(&hints);
xcb_set_wm_hints(xcb_connection(), m_window, &hints);
Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
-#if defined(XCB_USE_GLX)
- glXWaitX();
-#endif
+ connection()->sync();
} else {
Q_XCB_CALL(xcb_unmap_window(xcb_connection(), m_window));
diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp
index dd28c31..4c0d862 100644
--- a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp
@@ -62,7 +62,7 @@ public:
QImage *image() { return &m_qimage; }
void put(xcb_window_t window, const QPoint &dst, const QRect &source);
- void preparePaint(const QRegion &region);
+ void preparePaint(const QRegion &region, QMutex *mutex);
private:
void destroy();
@@ -84,6 +84,7 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size)
, m_gc(0)
, m_gc_window(0)
{
+ Q_XCB_NOOP(connection());
m_xcb_image = xcb_image_create_native(xcb_connection(),
size.width(),
size.height(),
@@ -115,6 +116,7 @@ void QXcbShmImage::destroy()
void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &source)
{
+ Q_XCB_NOOP(connection());
if (m_gc_window != window) {
if (m_gc)
Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc));
@@ -125,6 +127,7 @@ void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &s
m_gc_window = window;
}
+ Q_XCB_NOOP(connection());
xcb_image_shm_put(xcb_connection(),
window,
m_gc,
@@ -137,18 +140,23 @@ void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &s
source.width(),
source.height(),
false);
+ Q_XCB_NOOP(connection());
m_dirty = m_dirty | source;
xcb_flush(xcb_connection());
+ Q_XCB_NOOP(connection());
}
-void QXcbShmImage::preparePaint(const QRegion &region)
+void QXcbShmImage::preparePaint(const QRegion &region, QMutex *mutex)
{
// to prevent X from reading from the image region while we're writing to it
if (m_dirty.intersects(region)) {
connection()->sync();
+ mutex->lock();
m_dirty = QRegion();
+ } else {
+ mutex->lock();
}
}
@@ -162,6 +170,8 @@ QXcbWindowSurface::QXcbWindowSurface(QWidget *widget, bool setDefaultSurface)
QXcbWindowSurface::~QXcbWindowSurface()
{
+ QMutexLocker locker(&m_surfaceLock);
+ delete m_image;
}
QPaintDevice *QXcbWindowSurface::paintDevice()
@@ -171,8 +181,7 @@ QPaintDevice *QXcbWindowSurface::paintDevice()
void QXcbWindowSurface::beginPaint(const QRegion &region)
{
- m_surfaceLock.lock();
- m_image->preparePaint(region);
+ m_image->preparePaint(region, &m_surfaceLock);
}
void QXcbWindowSurface::endPaint(const QRegion &)
@@ -185,6 +194,8 @@ void QXcbWindowSurface::flush(QWidget *widget, const QRegion &region, const QPoi
Q_UNUSED(region);
Q_UNUSED(offset);
+ Q_XCB_NOOP(connection());
+
QXcbWindow *window = static_cast<QXcbWindow *>(widget->window()->platformWindow());
extern QWidgetData* qt_widget_data(QWidget *);
@@ -195,18 +206,26 @@ void QXcbWindowSurface::flush(QWidget *widget, const QRegion &region, const QPoi
QVector<QRect> rects = region.rects();
for (int i = 0; i < rects.size(); ++i)
m_image->put(window->window(), rects.at(i).topLeft() - widgetOffset, rects.at(i).translated(offset));
+
+ Q_XCB_NOOP(connection());
}
void QXcbWindowSurface::resize(const QSize &size)
{
+ Q_XCB_NOOP(connection());
QWindowSurface::resize(size);
QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(window()));
- QMutexLocker locker(&m_surfaceLock);
+ connection()->setEventProcessingEnabled(false);
+ m_surfaceLock.lock();
delete m_image;
m_image = new QXcbShmImage(screen, size);
+ Q_XCB_NOOP(connection());
+
+ m_surfaceLock.unlock();
+ connection()->setEventProcessingEnabled(true);
}
extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
@@ -216,12 +235,14 @@ bool QXcbWindowSurface::scroll(const QRegion &area, int dx, int dy)
if (m_image->image()->isNull())
return false;
- m_image->preparePaint(area);
+ m_image->preparePaint(area, &m_surfaceLock);
const QVector<QRect> rects = area.rects();
for (int i = 0; i < rects.size(); ++i)
qt_scrollRectInImage(*m_image->image(), rects.at(i), QPoint(dx, dy));
+ m_surfaceLock.unlock();
+
return true;
}