From 991f59a295e7678165b1db7befc9beac8bdbe503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 1 Apr 2011 17:36:26 +0200 Subject: Moved all XCB event handling back into the main thread. There are to many synchronization problems if any GL call can lead the event processing thread to stall. --- src/plugins/platforms/xcb/qglxintegration.cpp | 2 - src/plugins/platforms/xcb/qxcbconnection.cpp | 241 ++++++++---------------- src/plugins/platforms/xcb/qxcbconnection.h | 23 +-- src/plugins/platforms/xcb/qxcbwindow.cpp | 4 - src/plugins/platforms/xcb/qxcbwindowsurface.cpp | 23 +-- src/plugins/platforms/xcb/qxcbwindowsurface.h | 3 - 6 files changed, 86 insertions(+), 210 deletions(-) diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp index d1171b8..19a9503 100644 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/qglxintegration.cpp @@ -137,7 +137,6 @@ void QGLXContext::createDefaultSharedContext(QXcbScreen *screen) 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()); @@ -148,7 +147,6 @@ 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()); } diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 05d3440..ec1fc1b 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -76,8 +77,6 @@ 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) , m_dri2_minor(0) @@ -114,12 +113,6 @@ QXcbConnection::QXcbConnection(const char *displayName) xcb_screen_next(&it); } - m_connectionEventListener = xcb_generate_id(xcb_connection()); - xcb_create_window(xcb_connection(), XCB_COPY_FROM_PARENT, - m_connectionEventListener, m_screens.at(0)->root(), - 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, - m_screens.at(0)->screen()->root_visual, 0, 0); - m_keyboard = new QXcbKeyboard(this); initializeAllAtoms(); @@ -128,50 +121,15 @@ QXcbConnection::QXcbConnection(const char *displayName) initializeDri2(); #endif - start(); -} + QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(xcb_connection()), QSocketNotifier::Read, this); + connect(notifier, SIGNAL(activated(int)), this, SLOT(processXcbEvents())); -void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom atom, uint id) -{ - xcb_client_message_event_t event; - memset(&event, 0, sizeof(event)); - - event.response_type = XCB_CLIENT_MESSAGE; - event.format = 32; - event.sequence = 0; - event.window = m_connectionEventListener; - event.type = atom; - event.data.data32[0] = id; - - Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_connectionEventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event)); - xcb_flush(xcb_connection()); -} - -void QXcbConnection::setEventProcessingEnabled(bool enabled) -{ - if (enabled == m_enabled) - return; - - if (!enabled) { - sendConnectionEvent(QXcbAtom::_QT_PAUSE_CONNECTION, uint(m_pauseId)); - m_connectionLock.lock(); - m_pauseId.fetchAndAddOrdered(1); - } else { - m_connectionLock.unlock(); - m_connectionWaitCondition.wakeAll(); - } - - m_enabled = enabled; + QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance(qApp->thread()); + connect(dispatcher, SIGNAL(awake()), this, SLOT(processXcbEvents())); } QXcbConnection::~QXcbConnection() { - setEventProcessingEnabled(true); - - sendConnectionEvent(QXcbAtom::_QT_CLOSE_CONNECTION); - wait(); - - xcb_destroy_window(xcb_connection(), m_connectionEventListener); qDeleteAll(m_screens); #ifdef XCB_USE_XLIB @@ -417,128 +375,93 @@ void QXcbConnection::log(const char *file, int line, int sequence) info.sequence = sequence; info.file = file; info.line = line; - - QMutexLocker locker(&m_callLogMutex); - m_callLog << info; } #endif -void QXcbConnection::run() +void QXcbConnection::processXcbEvents() { - 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(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1); - uint clamped_major_code = qMin(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; - } + while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection())) { + bool handled = true; -#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 + uint response_type = event->response_type & ~0x80; - if (response_type == XCB_CLIENT_MESSAGE) { - xcb_client_message_event_t *ev = (xcb_client_message_event_t *)event; + if (!response_type) { + xcb_generic_error_t *error = (xcb_generic_error_t *)event; - if (ev->type == QXcbAtom::_QT_CLOSE_CONNECTION) - return; + uint clamped_error_code = qMin(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1); + uint clamped_major_code = qMin(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1); - if (ev->type == QXcbAtom::_QT_PAUSE_CONNECTION) { - if (ev->data.data32[0] == uint(m_pauseId)) - m_connectionWaitCondition.wait(&m_connectionLock); - continue; + 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 + 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; } } - - 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); + 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; } - do { - result = select(xcb_fd + 1, &readset, 0, 0, 0); - } while (result == -1 && errno == EINTR); - - if (result <= 0 || !FD_ISSET(xcb_fd, &readset)) - continue; +#ifdef Q_XCB_DEBUG + { + int i = 0; + for (; i < m_callLog.size(); ++i) + if (m_callLog.at(i).sequence >= event->sequence) + break; + m_callLog.remove(0, i); + } +#endif + 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"); } static const char * xcb_atomnames = { @@ -580,9 +503,6 @@ static const char * xcb_atomnames = { "_QT_SCROLL_DONE\0" "_QT_INPUT_ENCODING\0" - "_QT_CLOSE_CONNECTION\0" - "_QT_PAUSE_CONNECTION\0" - "_MOTIF_WM_HINTS\0" "DTWM_IS_RUNNING\0" @@ -738,13 +658,8 @@ 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 7088184..53846f1 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -44,10 +44,8 @@ #include #include -#include +#include #include -#include -#include #define Q_XCB_DEBUG @@ -93,10 +91,6 @@ namespace QXcbAtom { _QT_SCROLL_DONE, _QT_INPUT_ENCODING, - // Qt/XCB specific - _QT_CLOSE_CONNECTION, - _QT_PAUSE_CONNECTION, - _MOTIF_WM_HINTS, DTWM_IS_RUNNING, @@ -222,7 +216,7 @@ namespace QXcbAtom { class QXcbKeyboard; -class QXcbConnection : public QThread +class QXcbConnection : public QObject { Q_OBJECT public: @@ -242,8 +236,6 @@ public: QXcbKeyboard *keyboard() const { return m_keyboard; } - void setEventProcessingEnabled(bool enabled); - #ifdef XCB_USE_XLIB void *xlib_display() const { return m_xlib_display; } #endif @@ -261,8 +253,8 @@ public: void sync(); -protected: - void run(); +private slots: + void processXcbEvents(); private: void initializeAllAtoms(); @@ -281,12 +273,6 @@ private: QByteArray m_displayName; - xcb_window_t m_connectionEventListener; - QMutex m_connectionLock; - QWaitCondition m_connectionWaitCondition; - QAtomicInt m_pauseId; - bool m_enabled; - QXcbKeyboard *m_keyboard; #if defined(XCB_USE_XLIB) @@ -311,7 +297,6 @@ private: int line; }; QVector m_callLog; - QMutex m_callLogMutex; void log(const char *file, int line, int sequence); template friend cookie_t q_xcb_call_template(const cookie_t &cookie, QXcbConnection *connection, const char *file, int line); diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 7aeb557..1f4a13c 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -113,7 +113,6 @@ QXcbWindow::QXcbWindow(QWidget *tlw) if (tlw->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL && QApplicationPrivate::platformIntegration()->hasOpenGL()) { - connection()->setEventProcessingEnabled(false); #if defined(XCB_USE_GLX) XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), tlw->platformWindowFormat()); #elif defined(XCB_USE_EGL) @@ -142,7 +141,6 @@ QXcbWindow::QXcbWindow(QWidget *tlw) } else { qFatal("no window!"); } - connection()->setEventProcessingEnabled(true); } else #endif //defined(XCB_USE_GLX) || defined(XCB_USE_EGL) { @@ -431,7 +429,6 @@ QPlatformGLContext *QXcbWindow::glContext() const return 0; } if (!m_context) { - connection()->setEventProcessingEnabled(false); #if defined(XCB_USE_GLX) QXcbWindow *that = const_cast(this); that->m_context = new QGLXContext(m_window, m_screen, widget()->platformWindowFormat()); @@ -450,7 +447,6 @@ QPlatformGLContext *QXcbWindow::glContext() const QXcbWindow *that = const_cast(this); that->m_context = new QDri2Context(that); #endif - connection()->setEventProcessingEnabled(true); } return m_context; } diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp index 4c0d862..a4607dc 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 ®ion, QMutex *mutex); + void preparePaint(const QRegion ®ion); private: void destroy(); @@ -148,15 +148,12 @@ void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &s Q_XCB_NOOP(connection()); } -void QXcbShmImage::preparePaint(const QRegion ®ion, QMutex *mutex) +void QXcbShmImage::preparePaint(const QRegion ®ion) { // 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(); } } @@ -170,7 +167,6 @@ QXcbWindowSurface::QXcbWindowSurface(QWidget *widget, bool setDefaultSurface) QXcbWindowSurface::~QXcbWindowSurface() { - QMutexLocker locker(&m_surfaceLock); delete m_image; } @@ -181,12 +177,11 @@ QPaintDevice *QXcbWindowSurface::paintDevice() void QXcbWindowSurface::beginPaint(const QRegion ®ion) { - m_image->preparePaint(region, &m_surfaceLock); + m_image->preparePaint(region); } void QXcbWindowSurface::endPaint(const QRegion &) { - m_surfaceLock.unlock(); } void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) @@ -201,8 +196,6 @@ void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoi extern QWidgetData* qt_widget_data(QWidget *); QPoint widgetOffset = qt_qwidget_data(widget)->wrect.topLeft(); - QMutexLocker locker(&m_surfaceLock); - QVector 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)); @@ -217,15 +210,9 @@ void QXcbWindowSurface::resize(const QSize &size) QXcbScreen *screen = static_cast(QPlatformScreen::platformScreenForWidget(window())); - 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); @@ -235,14 +222,12 @@ bool QXcbWindowSurface::scroll(const QRegion &area, int dx, int dy) if (m_image->image()->isNull()) return false; - m_image->preparePaint(area, &m_surfaceLock); + m_image->preparePaint(area); const QVector 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; } diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.h b/src/plugins/platforms/xcb/qxcbwindowsurface.h index e508fe6..f87e122 100644 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.h +++ b/src/plugins/platforms/xcb/qxcbwindowsurface.h @@ -48,8 +48,6 @@ #include "qxcbobject.h" -#include - class QXcbShmImage; class QXcbWindowSurface : public QXcbObject, public QWindowSurface @@ -68,7 +66,6 @@ public: private: QXcbShmImage *m_image; - QMutex m_surfaceLock; }; #endif -- cgit v0.12