From 2ac622fae920ac038e6d5afb4db9df2e3b896514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 29 Mar 2011 18:25:11 +0200 Subject: Threaded event handling and improved error reporting in XCB plugin. --- src/plugins/platforms/xcb/qxcbconnection.cpp | 233 +++++++++++++++++++++++- src/plugins/platforms/xcb/qxcbconnection.h | 20 +- src/plugins/platforms/xcb/qxcbscreen.cpp | 3 +- src/plugins/platforms/xcb/qxcbwindow.cpp | 44 ++--- src/plugins/platforms/xcb/qxcbwindowsurface.cpp | 18 ++ src/plugins/platforms/xcb/qxcbwindowsurface.h | 1 + 6 files changed, 284 insertions(+), 35 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 2bdd6d4..1ac73c9 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_enabled(true) #ifdef XCB_USE_DRI2 , m_dri2_major(0) , m_dri2_minor(0) @@ -112,8 +113,11 @@ QXcbConnection::QXcbConnection(const char *displayName) xcb_screen_next(&it); } - QSocketNotifier *socket = new QSocketNotifier(xcb_get_file_descriptor(xcb_connection()), QSocketNotifier::Read, this); - connect(socket, SIGNAL(activated(int)), this, SLOT(eventDispatcher())); + 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); @@ -122,10 +126,47 @@ QXcbConnection::QXcbConnection(const char *displayName) #ifdef XCB_USE_DRI2 initializeDri2(); #endif + + start(); +} + +void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom atom) +{ + 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; + + 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) { + m_connectionLock.lock(); + sendConnectionEvent(QXcbAtom::_QT_PAUSE_CONNECTION); + } else { + m_connectionLock.unlock(); + } + + m_enabled = enabled; } QXcbConnection::~QXcbConnection() { + sendConnectionEvent(QXcbAtom::_QT_CLOSE_CONNECTION); + wait(); + + xcb_destroy_window(xcb_connection(), m_connectionEventListener); qDeleteAll(m_screens); #ifdef XCB_USE_XLIB @@ -168,7 +209,7 @@ void printXcbEvent(const char *message, xcb_generic_event_t *event) #ifdef XCB_EVENT_DEBUG #define PRINT_XCB_EVENT(event) \ case event: \ - printf("%s: %d - %s\n", message, event, #event); \ + printf("%s: %d - %s\n", message, int(event), #event); \ break; switch (event->response_type & ~0x80) { @@ -205,7 +246,7 @@ void printXcbEvent(const char *message, xcb_generic_event_t *event) PRINT_XCB_EVENT(XCB_CLIENT_MESSAGE); PRINT_XCB_EVENT(XCB_MAPPING_NOTIFY); default: - printf("%s: %d - %s\n", message, event->response_type, "unknown"); + printf("%s: unknown event - response_type: %d - sequence: %d\n", message, int(event->response_type & ~0x80), int(event->sequence)); } #else Q_UNUSED(message); @@ -213,11 +254,185 @@ void printXcbEvent(const char *message, xcb_generic_event_t *event) #endif } -void QXcbConnection::eventDispatcher() +const char *xcb_errors[] = { - while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection())) { + "Success", + "BadRequest", + "BadValue", + "BadWindow", + "BadPixmap", + "BadAtom", + "BadCursor", + "BadFont", + "BadMatch", + "BadDrawable", + "BadAccess", + "BadAlloc", + "BadColor", + "BadGC", + "BadIDChoice", + "BadName", + "BadLength", + "BadImplementation", + "Unknown" +}; + +const char *xcb_protocol_request_codes[] = +{ + "CreateWindow", + "ChangeWindowAttributes", + "GetWindowAttributes", + "DestroyWindow", + "DestroySubwindows", + "ChangeSaveSet", + "ReparentWindow", + "MapWindow", + "MapSubwindows", + "UnmapWindow", + "UnmapSubwindows", + "ConfigureWindow", + "CirculateWindow", + "GetGeometry", + "QueryTree", + "InternAtom", + "GetAtomName", + "ChangeProperty", + "DeleteProperty", + "GetProperty", + "ListProperties", + "SetSelectionOwner", + "GetSelectionOwner", + "ConvertSelection", + "SendEvent", + "GrabPointer", + "UngrabPointer", + "GrabButton", + "UngrabButton", + "ChangeActivePointerGrab", + "GrabKeyboard", + "UngrabKeyboard", + "GrabKey", + "UngrabKey", + "AllowEvents", + "GrabServer", + "UngrabServer", + "QueryPointer", + "GetMotionEvents", + "TranslateCoords", + "WarpPointer", + "SetInputFocus", + "GetInputFocus", + "QueryKeymap", + "OpenFont", + "CloseFont", + "QueryFont", + "QueryTextExtents", + "ListFonts", + "ListFontsWithInfo", + "SetFontPath", + "GetFontPath", + "CreatePixmap", + "FreePixmap", + "CreateGC", + "ChangeGC", + "CopyGC", + "SetDashes", + "SetClipRectangles", + "FreeGC", + "ClearArea", + "CopyArea", + "CopyPlane", + "PolyPoint", + "PolyLine", + "PolySegment", + "PolyRectangle", + "PolyArc", + "FillPoly", + "PolyFillRectangle", + "PolyFillArc", + "PutImage", + "GetImage", + "PolyText8", + "PolyText16", + "ImageText8", + "ImageText16", + "CreateColormap", + "FreeColormap", + "CopyColormapAndFree", + "InstallColormap", + "UninstallColormap", + "ListInstalledColormaps", + "AllocColor", + "AllocNamedColor", + "AllocColorCells", + "AllocColorPlanes", + "FreeColors", + "StoreColors", + "StoreNamedColor", + "QueryColors", + "LookupColor", + "CreateCursor", + "CreateGlyphCursor", + "FreeCursor", + "RecolorCursor", + "QueryBestSize", + "QueryExtension", + "ListExtensions", + "ChangeKeyboardMapping", + "GetKeyboardMapping", + "ChangeKeyboardControl", + "GetKeyboardControl", + "Bell", + "ChangePointerControl", + "GetPointerControl", + "SetScreenSaver", + "GetScreenSaver", + "ChangeHosts", + "ListHosts", + "SetAccessControl", + "SetCloseDownMode", + "KillClient", + "RotateProperties", + "ForceScreenSaver", + "SetPointerMapping", + "GetPointerMapping", + "SetModifierMapping", + "GetModifierMapping", + "NoOperation", + "Unknown" +}; + +void QXcbConnection::run() +{ + while (xcb_generic_event_t *event = xcb_wait_for_event(xcb_connection())) { bool handled = true; - switch (event->response_type & ~0x80) { + + 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), resource id: %d, major code: %d (%s), minor code: %d\n", + int(error->error_code), xcb_errors[clamped_error_code], int(error->resource_id), + int(error->major_code), xcb_protocol_request_codes[clamped_major_code], + int(error->minor_code)); + continue; + } + + if (response_type == XCB_CLIENT_MESSAGE + && ((xcb_client_message_event_t *)event)->type == QXcbAtom::_QT_CLOSE_CONNECTION) + return; + + if (response_type == XCB_CLIENT_MESSAGE + && ((xcb_client_message_event_t *)event)->type == QXcbAtom::_QT_PAUSE_CONNECTION) + { + QMutexLocker locker(&m_connectionLock); + } + + switch (response_type) { case XCB_EXPOSE: HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent); case XCB_BUTTON_PRESS: @@ -254,6 +469,7 @@ void QXcbConnection::eventDispatcher() else printXcbEvent("Unhandled XCB event", event); } + fprintf(stderr, "I/O error in xcb_wait_for_event\n"); } static const char * xcb_atomnames = { @@ -295,6 +511,9 @@ 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" diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index e00fbb1..a36694d 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -45,7 +45,8 @@ #include #include -#include +#include +#include class QXcbScreen; @@ -89,6 +90,10 @@ namespace QXcbAtom { _QT_SCROLL_DONE, _QT_INPUT_ENCODING, + // Qt/XCB specific + _QT_CLOSE_CONNECTION, + _QT_PAUSE_CONNECTION, + _MOTIF_WM_HINTS, DTWM_IS_RUNNING, @@ -214,7 +219,7 @@ namespace QXcbAtom { class QXcbKeyboard; -class QXcbConnection : public QObject +class QXcbConnection : public QThread { Q_OBJECT public: @@ -232,6 +237,8 @@ public: QXcbKeyboard *keyboard() const { return m_keyboard; } + void setEventProcessingEnabled(bool enabled); + #ifdef XCB_USE_XLIB void *xlib_display() const { return m_xlib_display; } #endif @@ -247,11 +254,12 @@ public: void *egl_display() const { return m_egl_display; } #endif -private slots: - void eventDispatcher(); +protected: + void run(); private: void initializeAllAtoms(); + void sendConnectionEvent(QXcbAtom::Atom atom); #ifdef XCB_USE_DRI2 void initializeDri2(); #endif @@ -266,6 +274,10 @@ private: QByteArray m_displayName; + xcb_window_t m_connectionEventListener; + QMutex m_connectionLock; + bool m_enabled; + QXcbKeyboard *m_keyboard; #if defined(XCB_USE_XLIB) diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index fffeb2e..49ed44c 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -60,8 +60,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num const quint32 mask = XCB_CW_EVENT_MASK; const quint32 values[] = { // XCB_CW_EVENT_MASK - XCB_EVENT_MASK_KEYMAP_STATE - | XCB_EVENT_MASK_ENTER_WINDOW + XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_PROPERTY_CHANGE }; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index b6c133f..54a4d7f 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -111,9 +111,11 @@ QXcbWindow::QXcbWindow(QWidget *tlw) #if defined(XCB_USE_GLX) || defined(XCB_USE_EGL) if (tlw->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL - && QApplicationPrivate::platformIntegration()->hasOpenGL() ) { + && 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()); + XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), tlw->platformWindowFormat()); #elif defined(XCB_USE_EGL) EGLDisplay eglDisplay = connection()->egl_display(); EGLConfig eglConfig = q_configFromQPlatformWindowFormat(eglDisplay,tlw->platformWindowFormat(),true); @@ -127,19 +129,20 @@ QXcbWindow::QXcbWindow(QWidget *tlw) int matchingCount = 0; visualInfo = XGetVisualInfo(DISPLAY_FROM_XCB(this), VisualIDMask, &visualInfoTemplate, &matchingCount); #endif //XCB_USE_GLX - if (visualInfo) { - Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), m_screen->root(), visualInfo->visual, AllocNone); - - XSetWindowAttributes a; - a.colormap = cmap; - m_window = XCreateWindow(DISPLAY_FROM_XCB(this), m_screen->root(), tlw->x(), tlw->y(), tlw->width(), tlw->height(), - 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWColormap, &a); - - printf("created GL window: %d\n", m_window); - } else { - qFatal("no window!"); - } + if (visualInfo) { + Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), m_screen->root(), visualInfo->visual, AllocNone); + + XSetWindowAttributes a; + a.colormap = cmap; + m_window = XCreateWindow(DISPLAY_FROM_XCB(this), m_screen->root(), tlw->x(), tlw->y(), tlw->width(), tlw->height(), + 0, visualInfo->depth, InputOutput, visualInfo->visual, + CWColormap, &a); + + printf("created GL window: %d\n", m_window); + } else { + qFatal("no window!"); + } + connection()->setEventProcessingEnabled(true); } else #endif //defined(XCB_USE_GLX) || defined(XCB_USE_EGL) { @@ -428,13 +431,12 @@ QPlatformGLContext *QXcbWindow::glContext() const printf("no opengl\n"); return 0; } -#if defined(XCB_USE_GLX) 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()); - } #elif defined(XCB_USE_EGL) - if (!m_context) { EGLDisplay display = connection()->egl_display(); EGLConfig config = q_configFromQPlatformWindowFormat(display,widget()->platformWindowFormat(),true); QVector eglContextAttrs; @@ -445,14 +447,12 @@ QPlatformGLContext *QXcbWindow::glContext() const EGLSurface eglSurface = eglCreateWindowSurface(display,config,(EGLNativeWindowType)m_window,0); QXcbWindow *that = const_cast(this); that->m_context = new QEGLPlatformContext(display, config, eglContextAttrs.data(), eglSurface, EGL_OPENGL_ES_API); - } #elif defined(XCB_USE_DRI2) - if (!m_context) { 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 7fed230..6bacf3d 100644 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp +++ b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp @@ -44,6 +44,7 @@ #include "qxcbconnection.h" #include "qxcbscreen.h" #include "qxcbwindow.h" +#include "qmutex.h" #include #include @@ -64,6 +65,9 @@ public: void put(xcb_window_t window, const QPoint &dst, const QRect &source); void preparePaint(const QRegion ®ion); + void lock() { m_surfaceLock.lock(); } + void unlock() { m_surfaceLock.unlock(); } + private: void destroy(); @@ -77,6 +81,7 @@ private: xcb_window_t m_gc_window; QRegion m_dirty; + QMutex m_surfaceLock; }; QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size) @@ -174,9 +179,15 @@ QPaintDevice *QXcbWindowSurface::paintDevice() void QXcbWindowSurface::beginPaint(const QRegion ®ion) { + m_image->lock(); m_image->preparePaint(region); } +void QXcbWindowSurface::endPaint(const QRegion &) +{ + m_image->unlock(); +} + void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) { Q_UNUSED(region); @@ -187,9 +198,13 @@ void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoi extern QWidgetData* qt_widget_data(QWidget *); QPoint widgetOffset = qt_qwidget_data(widget)->wrect.topLeft(); + m_image->lock(); + 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)); + + m_image->unlock(); } void QXcbWindowSurface::resize(const QSize &size) @@ -198,6 +213,9 @@ void QXcbWindowSurface::resize(const QSize &size) QXcbScreen *screen = static_cast(QPlatformScreen::platformScreenForWidget(window())); + if (m_image) + m_image->lock(); + delete m_image; m_image = new QXcbShmImage(screen, size); } diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.h b/src/plugins/platforms/xcb/qxcbwindowsurface.h index 61689b1..f87e122 100644 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.h +++ b/src/plugins/platforms/xcb/qxcbwindowsurface.h @@ -62,6 +62,7 @@ public: bool scroll(const QRegion &area, int dx, int dy); void beginPaint(const QRegion &); + void endPaint(const QRegion &); private: QXcbShmImage *m_image; -- cgit v0.12