summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Rødal <samuel.rodal@nokia.com>2011-03-29 16:25:11 (GMT)
committerSamuel Rødal <samuel.rodal@nokia.com>2011-03-29 19:27:26 (GMT)
commit2ac622fae920ac038e6d5afb4db9df2e3b896514 (patch)
tree200e78f6fafdbe66ebd1b4186d6a5c5718555808
parent26012845b8b12b2e4d3b6138124f8647a6144d3b (diff)
downloadQt-2ac622fae920ac038e6d5afb4db9df2e3b896514.zip
Qt-2ac622fae920ac038e6d5afb4db9df2e3b896514.tar.gz
Qt-2ac622fae920ac038e6d5afb4db9df2e3b896514.tar.bz2
Threaded event handling and improved error reporting in XCB plugin.
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp233
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h20
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp3
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp44
-rw-r--r--src/plugins/platforms/xcb/qxcbwindowsurface.cpp18
-rw-r--r--src/plugins/platforms/xcb/qxcbwindowsurface.h1
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<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), 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 <xcb/xcb.h>
#include <QList>
-#include <QObject>
+#include <QMutex>
+#include <QThread>
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<QXcbWindow *>(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<EGLint> eglContextAttrs;
@@ -445,14 +447,12 @@ QPlatformGLContext *QXcbWindow::glContext() const
EGLSurface eglSurface = eglCreateWindowSurface(display,config,(EGLNativeWindowType)m_window,0);
QXcbWindow *that = const_cast<QXcbWindow *>(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<QXcbWindow *>(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 <xcb/shm.h>
#include <xcb/xcb_image.h>
@@ -64,6 +65,9 @@ public:
void put(xcb_window_t window, const QPoint &dst, const QRect &source);
void preparePaint(const QRegion &region);
+ 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 &region)
{
+ m_image->lock();
m_image->preparePaint(region);
}
+void QXcbWindowSurface::endPaint(const QRegion &)
+{
+ m_image->unlock();
+}
+
void QXcbWindowSurface::flush(QWidget *widget, const QRegion &region, const QPoint &offset)
{
Q_UNUSED(region);
@@ -187,9 +198,13 @@ void QXcbWindowSurface::flush(QWidget *widget, const QRegion &region, const QPoi
extern QWidgetData* qt_widget_data(QWidget *);
QPoint widgetOffset = qt_qwidget_data(widget)->wrect.topLeft();
+ m_image->lock();
+
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));
+
+ m_image->unlock();
}
void QXcbWindowSurface::resize(const QSize &size)
@@ -198,6 +213,9 @@ void QXcbWindowSurface::resize(const QSize &size)
QXcbScreen *screen = static_cast<QXcbScreen *>(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;