diff options
author | aavit <qt-info@nokia.com> | 2011-04-26 08:28:04 (GMT) |
---|---|---|
committer | aavit <qt-info@nokia.com> | 2011-04-26 08:28:04 (GMT) |
commit | ff8c99eb54f33108709f9f3107b35780a80f3f17 (patch) | |
tree | 11d4c08809bf90fd8b25b175b4903ab00d36e3d6 /src/plugins/platforms/xcb | |
parent | 28c7e17d9eeb8264ad9e26a5b93e5ff744add9a6 (diff) | |
parent | 7ef9f99301a7c71fdb835f9e1f27d3111557aa2e (diff) | |
download | Qt-ff8c99eb54f33108709f9f3107b35780a80f3f17.zip Qt-ff8c99eb54f33108709f9f3107b35780a80f3f17.tar.gz Qt-ff8c99eb54f33108709f9f3107b35780a80f3f17.tar.bz2 |
Merge remote branch 'qt-mainline/master'
Conflicts:
configure
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r-- | src/plugins/platforms/xcb/README | 3 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qdri2context.cpp | 2 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qglxintegration.cpp | 238 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qglxintegration.h | 9 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 251 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.h | 39 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbintegration.cpp | 9 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbintegration.h | 3 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbkeyboard.cpp | 6 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbscreen.cpp | 39 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbscreen.h | 6 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 257 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.h | 10 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindowsurface.cpp | 64 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindowsurface.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/xcb.pro | 3 |
16 files changed, 595 insertions, 346 deletions
diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README index e88596b..17a86e6 100644 --- a/src/plugins/platforms/xcb/README +++ b/src/plugins/platforms/xcb/README @@ -1,2 +1,3 @@ Required packages: -libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev +libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev + diff --git a/src/plugins/platforms/xcb/qdri2context.cpp b/src/plugins/platforms/xcb/qdri2context.cpp index 0079f91..dbbfa67 100644 --- a/src/plugins/platforms/xcb/qdri2context.cpp +++ b/src/plugins/platforms/xcb/qdri2context.cpp @@ -266,6 +266,6 @@ xcb_dri2_dri2_buffer_t * QDri2Context::backBuffer() void * QDri2Context::eglContext() const { - Q_D(QDri2Context); + Q_D(const QDri2Context); return d->eglContext; } diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp index e94b6a6..190221c 100644 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/qglxintegration.cpp @@ -51,218 +51,29 @@ #include <GL/glx.h> #include "qglxintegration.h" +#include "qglxconvenience.h" #if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) #include <dlfcn.h> #endif -QMutex QGLXContext::m_defaultSharedContextMutex(QMutex::Recursive); - -QVector<int> QGLXContext::buildSpec(const QPlatformWindowFormat &format) -{ - QVector<int> spec(48); - int i = 0; - - spec[i++] = GLX_LEVEL; - spec[i++] = 0; - spec[i++] = GLX_DRAWABLE_TYPE; spec[i++] = GLX_WINDOW_BIT; - - if (format.rgba()) { - spec[i++] = GLX_RENDER_TYPE; spec[i++] = GLX_RGBA_BIT; - spec[i++] = GLX_RED_SIZE; spec[i++] = (format.redBufferSize() == -1) ? 1 : format.redBufferSize(); - spec[i++] = GLX_GREEN_SIZE; spec[i++] = (format.greenBufferSize() == -1) ? 1 : format.greenBufferSize(); - spec[i++] = GLX_BLUE_SIZE; spec[i++] = (format.blueBufferSize() == -1) ? 1 : format.blueBufferSize(); - if (format.alpha()) { - spec[i++] = GLX_ALPHA_SIZE; spec[i++] = (format.alphaBufferSize() == -1) ? 1 : format.alphaBufferSize(); - } - - spec[i++] = GLX_ACCUM_RED_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); - spec[i++] = GLX_ACCUM_GREEN_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); - spec[i++] = GLX_ACCUM_BLUE_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); - - if (format.alpha()) { - spec[i++] = GLX_ACCUM_ALPHA_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); - } - - } else { - spec[i++] = GLX_RENDER_TYPE; spec[i++] = GLX_COLOR_INDEX_BIT; //I'm really not sure if this works.... - spec[i++] = GLX_BUFFER_SIZE; spec[i++] = 8; - } - - spec[i++] = GLX_DOUBLEBUFFER; spec[i++] = format.doubleBuffer() ? True : False; - spec[i++] = GLX_STEREO; spec[i++] = format.stereo() ? True : False; - - if (format.depth()) { - spec[i++] = GLX_DEPTH_SIZE; spec[i++] = (format.depthBufferSize() == -1) ? 1 : format.depthBufferSize(); - } - - if (format.stencil()) { - spec[i++] = GLX_STENCIL_SIZE; spec[i++] = (format.stencilBufferSize() == -1) ? 1 : format.stencilBufferSize(); - } - if (format.sampleBuffers()) { - spec[i++] = GLX_SAMPLE_BUFFERS_ARB; - spec[i++] = 1; - spec[i++] = GLX_SAMPLES_ARB; - spec[i++] = format.samples() == -1 ? 4 : format.samples(); - } - - spec[i++] = None; - return spec; -} - -GLXFBConfig QGLXContext::findConfig(const QXcbScreen *screen, const QPlatformWindowFormat &format) -{ - bool reduced = true; - GLXFBConfig chosenConfig = 0; - QPlatformWindowFormat reducedFormat = format; - while (!chosenConfig && reduced) { - QVector<int> spec = buildSpec(reducedFormat); - int confcount = 0; - GLXFBConfig *configs; - configs = glXChooseFBConfig(DISPLAY_FROM_XCB(screen), screen->screenNumber(), spec.constData(), &confcount); - if (confcount) - { - for (int i = 0; i < confcount; i++) { - chosenConfig = configs[i]; - // Make sure we try to get an ARGB visual if the format asked for an alpha: - if (reducedFormat.alpha()) { - int alphaSize; - glXGetFBConfigAttrib(DISPLAY_FROM_XCB(screen), configs[i], GLX_ALPHA_SIZE, &alphaSize); - if (alphaSize > 0) - break; - } else { - break; // Just choose the first in the list if there's no alpha requested - } - } - - XFree(configs); - } - reducedFormat = reducePlatformWindowFormat(reducedFormat,&reduced); - } - - if (!chosenConfig) - qWarning("Warning no context created"); - - return chosenConfig; -} - -XVisualInfo *QGLXContext::findVisualInfo(const QXcbScreen *screen, const QPlatformWindowFormat &format) -{ - GLXFBConfig config = QGLXContext::findConfig(screen,format); - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(DISPLAY_FROM_XCB(screen), config); - return visualInfo; -} - -QPlatformWindowFormat QGLXContext::platformWindowFromGLXFBConfig(Display *display, GLXFBConfig config, GLXContext ctx) -{ - QPlatformWindowFormat format; - int redSize = 0; - int greenSize = 0; - int blueSize = 0; - int alphaSize = 0; - int depthSize = 0; - int stencilSize = 0; - int sampleBuffers = 0; - int sampleCount = 0; - int level = 0; - int rgba = 0; - int stereo = 0; - int accumSizeA = 0; - int accumSizeR = 0; - int accumSizeG = 0; - int accumSizeB = 0; - - XVisualInfo *vi = glXGetVisualFromFBConfig(display,config); - glXGetConfig(display,vi,GLX_RGBA,&rgba); - XFree(vi); - glXGetFBConfigAttrib(display, config, GLX_RED_SIZE, &redSize); - glXGetFBConfigAttrib(display, config, GLX_GREEN_SIZE, &greenSize); - glXGetFBConfigAttrib(display, config, GLX_BLUE_SIZE, &blueSize); - glXGetFBConfigAttrib(display, config, GLX_ALPHA_SIZE, &alphaSize); - glXGetFBConfigAttrib(display, config, GLX_DEPTH_SIZE, &depthSize); - glXGetFBConfigAttrib(display, config, GLX_STENCIL_SIZE, &stencilSize); - glXGetFBConfigAttrib(display, config, GLX_SAMPLES, &sampleBuffers); - glXGetFBConfigAttrib(display, config, GLX_LEVEL, &level); - glXGetFBConfigAttrib(display, config, GLX_STEREO, &stereo); - glXGetFBConfigAttrib(display, config, GLX_ACCUM_ALPHA_SIZE, &accumSizeA); - glXGetFBConfigAttrib(display, config, GLX_ACCUM_RED_SIZE, &accumSizeR); - glXGetFBConfigAttrib(display, config, GLX_ACCUM_GREEN_SIZE, &accumSizeG); - glXGetFBConfigAttrib(display, config, GLX_ACCUM_BLUE_SIZE, &accumSizeB); - - format.setRedBufferSize(redSize); - format.setGreenBufferSize(greenSize); - format.setBlueBufferSize(blueSize); - format.setAlphaBufferSize(alphaSize); - format.setDepthBufferSize(depthSize); - format.setStencilBufferSize(stencilSize); - format.setSampleBuffers(sampleBuffers); - if (format.sampleBuffers()) { - glXGetFBConfigAttrib(display, config, GLX_SAMPLES_ARB, &sampleCount); - format.setSamples(sampleCount); - } - - format.setDirectRendering(glXIsDirect(display, ctx)); - format.setRgba(rgba); - format.setStereo(stereo); - format.setAccumBufferSize(accumSizeB); - - return format; -} - -QPlatformWindowFormat QGLXContext::reducePlatformWindowFormat(const QPlatformWindowFormat &format, bool *reduced) -{ - QPlatformWindowFormat retFormat = format; - *reduced = true; - - if (retFormat.sampleBuffers()) { - retFormat.setSampleBuffers(false); - } else if (retFormat.stereo()) { - retFormat.setStereo(false); - } else if (retFormat.accum()) { - retFormat.setAccum(false); - }else if (retFormat.stencil()) { - retFormat.setStencil(false); - }else if (retFormat.alpha()) { - retFormat.setAlpha(false); - }else if (retFormat.depth()) { - retFormat.setDepth(false); - }else if (retFormat.doubleBuffer()) { - retFormat.setDoubleBuffer(false); - }else{ - *reduced = false; - } - return retFormat; -} - QGLXContext::QGLXContext(Window window, QXcbScreen *screen, const QPlatformWindowFormat &format) : QPlatformGLContext() , m_screen(screen) , m_drawable((Drawable)window) , m_context(0) { - + Q_XCB_NOOP(m_screen->connection()); const QPlatformGLContext *sharePlatformContext; - if (format.useDefaultSharedContext()) { - if (!QPlatformGLContext::defaultSharedContext()) { - if (m_defaultSharedContextMutex.tryLock()){ - createDefaultSharedContex(screen); - m_defaultSharedContextMutex.unlock(); - } else { - m_defaultSharedContextMutex.lock(); //wait to the the shared context is created - m_defaultSharedContextMutex.unlock(); - } - } - sharePlatformContext = QPlatformGLContext::defaultSharedContext(); - } else { - sharePlatformContext = format.sharedGLContext(); - } + sharePlatformContext = format.sharedGLContext(); GLXContext shareGlxContext = 0; if (sharePlatformContext) shareGlxContext = static_cast<const QGLXContext*>(sharePlatformContext)->glxContext(); - GLXFBConfig config = findConfig(screen,format); + 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 = QGLXContext::platformWindowFromGLXFBConfig(DISPLAY_FROM_XCB(screen), config, m_context); + 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) @@ -273,56 +84,39 @@ 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); -} - -void QGLXContext::createDefaultSharedContex(QXcbScreen *screen) -{ - int x = 0; - int y = 0; - int w = 3; - int h = 3; - - QPlatformWindowFormat format = QPlatformWindowFormat::defaultFormat(); - GLXContext context; - GLXFBConfig config = findConfig(screen,format); - if (config) { - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(DISPLAY_FROM_XCB(screen), config); - Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(screen), screen->root(), visualInfo->visual, AllocNone); - XSetWindowAttributes a; - a.colormap = cmap; - Window sharedWindow = XCreateWindow(DISPLAY_FROM_XCB(screen), screen->root(), x, y, w, h, - 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWColormap, &a); - - context = glXCreateNewContext(DISPLAY_FROM_XCB(screen), config, GLX_RGBA_TYPE, 0, TRUE); - QPlatformGLContext *sharedContext = new QGLXContext(screen, sharedWindow, context); - QPlatformGLContext::setDefaultSharedContext(sharedContext); - } else { - qWarning("Warning no shared context created"); - } + Q_XCB_NOOP(m_screen->connection()); } void QGLXContext::makeCurrent() { + Q_XCB_NOOP(m_screen->connection()); 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); + 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/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h index f2e20c4..99b72a0 100644 --- a/src/plugins/platforms/xcb/qglxintegration.h +++ b/src/plugins/platforms/xcb/qglxintegration.h @@ -66,22 +66,13 @@ public: QPlatformWindowFormat platformWindowFormat() const; - static XVisualInfo *findVisualInfo(const QXcbScreen *xd, const QPlatformWindowFormat &format); - private: - static GLXFBConfig findConfig(const QXcbScreen *xd,const QPlatformWindowFormat &format); - static QVector<int> buildSpec(const QPlatformWindowFormat &format); - static QPlatformWindowFormat platformWindowFromGLXFBConfig(Display *display, GLXFBConfig config, GLXContext context); - static QPlatformWindowFormat reducePlatformWindowFormat(const QPlatformWindowFormat &format, bool *reduced); - QXcbScreen *m_screen; Drawable m_drawable; GLXContext m_context; QPlatformWindowFormat m_windowFormat; QGLXContext (QXcbScreen *screen, Drawable drawable, GLXContext context); - static QMutex m_defaultSharedContextMutex; - static void createDefaultSharedContex(QXcbScreen *xd); }; #endif diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 191699b..7ad12fe 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -47,6 +47,7 @@ #include <QtAlgorithms> #include <QSocketNotifier> #include <QtGui/private/qapplication_p.h> +#include <QAbstractEventDispatcher> #include <QtCore/QDebug> @@ -104,6 +105,8 @@ QXcbConnection::QXcbConnection(const char *displayName) #endif //XCB_USE_XLIB m_setup = xcb_get_setup(xcb_connection()); + initializeAllAtoms(); + xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup); int screenNumber = 0; @@ -112,16 +115,19 @@ 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_keyboard = new QXcbKeyboard(this); - initializeAllAtoms(); - #ifdef XCB_USE_DRI2 initializeDri2(); #endif + + QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(xcb_connection()), QSocketNotifier::Read, this); + connect(notifier, SIGNAL(activated(int)), this, SLOT(processXcbEvents())); + + QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance(qApp->thread()); + connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processXcbEvents())); + + sync(); } QXcbConnection::~QXcbConnection() @@ -148,8 +154,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; @@ -166,9 +175,9 @@ break; 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); \ +#define PRINT_XCB_EVENT(ev) \ + case ev: \ + printf("%s: %d - %s - sequence: %d\n", message, int(ev), #ev, event->sequence); \ break; switch (event->response_type & ~0x80) { @@ -205,7 +214,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 +222,216 @@ void printXcbEvent(const char *message, xcb_generic_event_t *event) #endif } -void QXcbConnection::eventDispatcher() +const char *xcb_errors[] = +{ + "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[] = +{ + "Null", + "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", + "Unknown" +}; + +#ifdef Q_XCB_DEBUG +void QXcbConnection::log(const char *file, int line, int sequence) +{ + CallInfo info; + info.sequence = sequence; + info.file = file; + info.line = line; + m_callLog << info; +} +#endif + +void QXcbConnection::handleXcbError(xcb_generic_error_t *error) +{ + 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 + 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 +} + +void QXcbConnection::processXcbEvents() { while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection())) { bool handled = true; - switch (event->response_type & ~0x80) { + + uint response_type = event->response_type & ~0x80; + + if (!response_type) { + handleXcbError((xcb_generic_error_t *)event); + 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: @@ -247,13 +461,15 @@ void QXcbConnection::eventDispatcher() break; default: handled = false; - return; + break; } if (handled) printXcbEvent("Handled XCB event", event); else printXcbEvent("Unhandled XCB event", event); } + + xcb_flush(xcb_connection()); } static const char * xcb_atomnames = { @@ -447,6 +663,13 @@ void QXcbConnection::initializeAllAtoms() { m_allAtoms[i] = xcb_intern_atom_reply(xcb_connection(), cookies[i], 0)->atom; } +void QXcbConnection::sync() +{ + // from xcb_aux_sync + 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 defined(XCB_USE_EGL) bool QXcbConnection::hasEgl() const { diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index e00fbb1..6b5f810 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -46,6 +46,9 @@ #include <QList> #include <QObject> +#include <QVector> + +#define Q_XCB_DEBUG class QXcbScreen; @@ -221,6 +224,8 @@ public: QXcbConnection(const char *displayName = 0); ~QXcbConnection(); + QXcbConnection *connection() const { return const_cast<QXcbConnection *>(this); } + QList<QXcbScreen *> screens() const { return m_screens; } int primaryScreen() const { return m_primaryScreen; } @@ -247,11 +252,15 @@ public: void *egl_display() const { return m_egl_display; } #endif + void sync(); + void handleXcbError(xcb_generic_error_t *error); + private slots: - void eventDispatcher(); + void processXcbEvents(); private: void initializeAllAtoms(); + void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0); #ifdef XCB_USE_DRI2 void initializeDri2(); #endif @@ -283,10 +292,38 @@ private: void *m_egl_display; bool m_has_egl; #endif +#ifdef Q_XCB_DEBUG + struct CallInfo { + int sequence; + QByteArray file; + int line; + }; + QVector<CallInfo> m_callLog; + void log(const char *file, int line, int sequence); + template <typename cookie_t> + friend cookie_t q_xcb_call_template(const cookie_t &cookie, QXcbConnection *connection, const char *file, int line); +#endif }; #define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display())) +#ifdef Q_XCB_DEBUG +template <typename cookie_t> +cookie_t q_xcb_call_template(const cookie_t &cookie, QXcbConnection *connection, const char *file, int line) +{ + connection->log(file, line, cookie.sequence); + return cookie; +} +#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 + + #if defined(XCB_USE_DRI2) || defined(XCB_USE_EGL) #define EGL_DISPLAY_FROM_XCB(object) ((EGLDisplay)(object->connection()->egl_display())) #endif //endifXCB_USE_DRI2 diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 63c26a1..9df5f14 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -73,6 +73,15 @@ QXcbIntegration::~QXcbIntegration() delete m_connection; } +bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const +{ + switch (cap) { + case ThreadedPixmaps: return true; + case OpenGL: return hasOpenGL(); + default: return QPlatformIntegration::hasCapability(cap); + } +} + QPixmapData *QXcbIntegration::createPixmapData(QPixmapData::PixelType type) const { return new QRasterPixmapData(type); diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index 6c9634e..d27fd71 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -55,6 +55,7 @@ public: QXcbIntegration(); ~QXcbIntegration(); + bool hasCapability(Capability cap) const; QPixmapData *createPixmapData(QPixmapData::PixelType type) const; QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const; QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; @@ -65,11 +66,11 @@ public: QPixmap grabWindow(WId window, int x, int y, int width, int height) const; QPlatformFontDatabase *fontDatabase() const; - bool hasOpenGL() const; QPlatformNativeInterface *nativeInterface()const; private: + bool hasOpenGL() const; QList<QPlatformScreen *> m_screens; QXcbConnection *m_connection; 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/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index fffeb2e..1c12ee3 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -60,13 +60,48 @@ 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 }; xcb_change_window_attributes(xcb_connection(), screen->root, mask, values); + + xcb_generic_error_t *error; + + xcb_get_property_reply_t *reply = + xcb_get_property_reply(xcb_connection(), + xcb_get_property(xcb_connection(), false, screen->root, + atom(QXcbAtom::_NET_SUPPORTING_WM_CHECK), + XCB_ATOM_WINDOW, 0, 1024), &error); + + if (reply && reply->format == 32 && reply->type == XCB_ATOM_WINDOW) { + xcb_window_t windowManager = *((xcb_window_t *)xcb_get_property_value(reply)); + + if (windowManager != XCB_WINDOW_NONE) { + xcb_get_property_reply_t *windowManagerReply = + xcb_get_property_reply(xcb_connection(), + xcb_get_property(xcb_connection(), false, windowManager, + atom(QXcbAtom::_NET_WM_NAME), + atom(QXcbAtom::UTF8_STRING), 0, 1024), &error); + if (windowManagerReply && windowManagerReply->format == 8 && windowManagerReply->type == atom(QXcbAtom::UTF8_STRING)) { + m_windowManagerName = QString::fromUtf8((const char *)xcb_get_property_value(windowManagerReply), xcb_get_property_value_length(windowManagerReply)); + printf("Running window manager: %s\n", qPrintable(m_windowManagerName)); + } else if (error) { + connection->handleXcbError(error); + free(error); + } + + free(windowManagerReply); + } + } else if (error) { + connection->handleXcbError(error); + free(error); + } + + free(reply); + + m_syncRequestSupported = m_windowManagerName != QLatin1String("KWin"); } QXcbScreen::~QXcbScreen() diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index 6f69fc7..9547d01 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -43,6 +43,7 @@ #define QXCBSCREEN_H #include <QtGui/QPlatformScreen> +#include <QtCore/QString> #include <xcb/xcb.h> @@ -66,9 +67,14 @@ public: xcb_screen_t *screen() const { return m_screen; } xcb_window_t root() const { return m_screen->root; } + QString windowManagerName() const { return m_windowManagerName; } + bool syncRequestSupported() const { return m_syncRequestSupported; } + private: xcb_screen_t *m_screen; int m_number; + QString m_windowManagerName; + bool m_syncRequestSupported; }; #endif diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index cbf50f7..0456638 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -41,6 +41,8 @@ #include "qxcbwindow.h" +#include <QtDebug> + #include "qxcbconnection.h" #include "qxcbscreen.h" #ifdef XCB_USE_DRI2 @@ -63,6 +65,7 @@ #if defined(XCB_USE_GLX) #include "qglxintegration.h" +#include "qglxconvenience.h" #elif defined(XCB_USE_EGL) #include "../eglconvenience/qeglplatformcontext.h" #include "../eglconvenience/qeglconvenience.h" @@ -110,13 +113,14 @@ QXcbWindow::QXcbWindow(QWidget *tlw) #if defined(XCB_USE_GLX) || defined(XCB_USE_EGL) if (tlw->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL - && QApplicationPrivate::platformIntegration()->hasOpenGL() ) { + && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) + { #if defined(XCB_USE_GLX) - XVisualInfo *visualInfo = QGLXContext::findVisualInfo(m_screen, tlw->platformWindowFormat()); + XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), tlw->platformWindowFormat()); #elif defined(XCB_USE_EGL) - EGLDisplay eglDisplay = eglGetDisplay(DISPLAY_FROM_XCB(this)); + EGLDisplay eglDisplay = connection()->egl_display(); EGLConfig eglConfig = q_configFromQPlatformWindowFormat(eglDisplay,tlw->platformWindowFormat(),true); - VisualID id = QXlibEglIntegration::getCompatibleVisualId(DISPLAY_FROM_XCB(this),eglConfig); + VisualID id = QXlibEglIntegration::getCompatibleVisualId(DISPLAY_FROM_XCB(this), eglDisplay, eglConfig); XVisualInfo visualInfoTemplate; memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); @@ -126,42 +130,42 @@ 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!"); + } } else #endif //defined(XCB_USE_GLX) || defined(XCB_USE_EGL) { m_window = xcb_generate_id(xcb_connection()); - xcb_create_window(xcb_connection(), - XCB_COPY_FROM_PARENT, // depth -- same as root - m_window, // window id - m_screen->root(), // parent window id - tlw->x(), - tlw->y(), - tlw->width(), - tlw->height(), - 0, // border width - XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class - m_screen->screen()->root_visual, // visual - 0, // value mask - 0); // value list + Q_XCB_CALL(xcb_create_window(xcb_connection(), + XCB_COPY_FROM_PARENT, // depth -- same as root + m_window, // window id + m_screen->root(), // parent window id + tlw->x(), + tlw->y(), + tlw->width(), + tlw->height(), + 0, // border width + XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class + m_screen->screen()->root_visual, // visual + 0, // value mask + 0)); // value list printf("created regular window: %d\n", m_window); } - xcb_change_window_attributes(xcb_connection(), m_window, mask, values); + Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values)); xcb_atom_t properties[4]; int propertyCount = 0; @@ -169,32 +173,60 @@ QXcbWindow::QXcbWindow(QWidget *tlw) properties[propertyCount++] = atom(QXcbAtom::WM_TAKE_FOCUS); properties[propertyCount++] = atom(QXcbAtom::_NET_WM_PING); + if (m_screen->syncRequestSupported()) + properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST); + if (tlw->windowFlags() & Qt::WindowContextHelpButtonHint) properties[propertyCount++] = atom(QXcbAtom::_NET_WM_CONTEXT_HELP); - xcb_change_property(xcb_connection(), - XCB_PROP_MODE_REPLACE, - m_window, - atom(QXcbAtom::WM_PROTOCOLS), - 4, - 32, - propertyCount, - properties); + Q_XCB_CALL(xcb_change_property(xcb_connection(), + XCB_PROP_MODE_REPLACE, + m_window, + atom(QXcbAtom::WM_PROTOCOLS), + XCB_ATOM_ATOM, + 32, + propertyCount, + properties)); + m_syncValue.hi = 0; + m_syncValue.lo = 0; + + if (m_screen->syncRequestSupported()) { + m_syncCounter = xcb_generate_id(xcb_connection()); + Q_XCB_CALL(xcb_sync_create_counter(xcb_connection(), m_syncCounter, m_syncValue)); + + Q_XCB_CALL(xcb_change_property(xcb_connection(), + XCB_PROP_MODE_REPLACE, + m_window, + atom(QXcbAtom::_NET_WM_SYNC_REQUEST_COUNTER), + XCB_ATOM_CARDINAL, + 32, + 1, + &m_syncCounter)); + } if (isTransient(tlw) && tlw->parentWidget()) { // ICCCM 4.1.2.6 QWidget *p = tlw->parentWidget()->window(); xcb_window_t parentWindow = p->winId(); - xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, - 1, &parentWindow); + Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, + 1, &parentWindow)); } + + // set the PID to let the WM kill the application if unresponsive + long pid = getpid(); + Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + atom(QXcbAtom::_NET_WM_PID), XCB_ATOM_CARDINAL, 32, + 1, &pid)); } QXcbWindow::~QXcbWindow() { - xcb_destroy_window(xcb_connection(), m_window); + delete m_context; + if (m_screen->syncRequestSupported()) + Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter)); + Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window)); } void QXcbWindow::setGeometry(const QRect &rect) @@ -204,7 +236,7 @@ void QXcbWindow::setGeometry(const QRect &rect) const quint32 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; const quint32 values[] = { rect.x(), rect.y(), rect.width(), rect.height() }; - xcb_configure_window(xcb_connection(), m_window, mask, values); + Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values)); } void QXcbWindow::setVisible(bool visible) @@ -216,9 +248,10 @@ void QXcbWindow::setVisible(bool visible) else xcb_wm_hints_set_normal(&hints); xcb_set_wm_hints(xcb_connection(), m_window, &hints); - xcb_map_window(xcb_connection(), m_window); + Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window)); + connection()->sync(); } else { - xcb_unmap_window(xcb_connection(), m_window); + Q_XCB_CALL(xcb_unmap_window(xcb_connection(), m_window)); // send synthetic UnmapNotify event according to icccm 4.1.4 xcb_unmap_notify_event_t event; @@ -227,8 +260,8 @@ void QXcbWindow::setVisible(bool visible) event.event = m_screen->root(); event.window = m_window; event.from_configure = false; - xcb_send_event(xcb_connection(), false, m_screen->root(), - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event); + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_screen->root(), + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); xcb_flush(xcb_connection()); } @@ -271,6 +304,8 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) { Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); + setNetWmWindowTypes(flags); + if (type == Qt::ToolTip) flags |= Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint; if (type == Qt::Popup) @@ -352,28 +387,64 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) } if (mwmhints.flags != 0l) { - xcb_change_property(xcb_connection(), - XCB_PROP_MODE_REPLACE, - m_window, - atom(QXcbAtom::_MOTIF_WM_HINTS), - atom(QXcbAtom::_MOTIF_WM_HINTS), - 32, - 5, - &mwmhints); + Q_XCB_CALL(xcb_change_property(xcb_connection(), + XCB_PROP_MODE_REPLACE, + m_window, + atom(QXcbAtom::_MOTIF_WM_HINTS), + atom(QXcbAtom::_MOTIF_WM_HINTS), + 32, + 5, + &mwmhints)); } else { - xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_MOTIF_WM_HINTS)); + Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_MOTIF_WM_HINTS))); } if (popup || tooltip) { const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER; const quint32 values[] = { true, true }; - xcb_change_window_attributes(xcb_connection(), m_window, mask, values); + Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values)); } return QPlatformWindow::setWindowFlags(flags); } +void QXcbWindow::setNetWmWindowTypes(Qt::WindowFlags flags) +{ + // in order of decreasing priority + QVector<uint> windowTypes; + + Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); + + switch (type) { + case Qt::Dialog: + case Qt::Sheet: + windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DIALOG)); + break; + case Qt::Tool: + case Qt::Drawer: + windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_UTILITY)); + break; + case Qt::ToolTip: + windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLTIP)); + break; + case Qt::SplashScreen: + windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_SPLASH)); + break; + default: + break; + } + + if (flags & Qt::FramelessWindowHint) + windowTypes.append(atom(QXcbAtom::_KDE_NET_WM_WINDOW_TYPE_OVERRIDE)); + + windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL)); + + Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + atom(QXcbAtom::_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32, + windowTypes.count(), windowTypes.constData())); +} + WId QXcbWindow::winId() const { return m_window; @@ -382,56 +453,54 @@ WId QXcbWindow::winId() const void QXcbWindow::setParent(const QPlatformWindow *parent) { QPoint topLeft = geometry().topLeft(); - xcb_reparent_window(xcb_connection(), window(), static_cast<const QXcbWindow *>(parent)->window(), topLeft.x(), topLeft.y()); + Q_XCB_CALL(xcb_reparent_window(xcb_connection(), window(), static_cast<const QXcbWindow *>(parent)->window(), topLeft.x(), topLeft.y())); } void QXcbWindow::setWindowTitle(const QString &title) { QByteArray ba = title.toUtf8(); - xcb_change_property (xcb_connection(), - XCB_PROP_MODE_REPLACE, - m_window, - atom(QXcbAtom::_NET_WM_NAME), - atom(QXcbAtom::UTF8_STRING), - 8, - ba.length(), - ba.constData()); + Q_XCB_CALL(xcb_change_property(xcb_connection(), + XCB_PROP_MODE_REPLACE, + m_window, + atom(QXcbAtom::_NET_WM_NAME), + atom(QXcbAtom::UTF8_STRING), + 8, + ba.length(), + ba.constData())); } void QXcbWindow::raise() { const quint32 mask = XCB_CONFIG_WINDOW_STACK_MODE; const quint32 values[] = { XCB_STACK_MODE_ABOVE }; - xcb_configure_window(xcb_connection(), m_window, mask, values); + Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values)); } void QXcbWindow::lower() { const quint32 mask = XCB_CONFIG_WINDOW_STACK_MODE; const quint32 values[] = { XCB_STACK_MODE_BELOW }; - xcb_configure_window(xcb_connection(), m_window, mask, values); + Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values)); } void QXcbWindow::requestActivateWindow() { - xcb_set_input_focus(xcb_connection(), m_window, XCB_INPUT_FOCUS_PARENT, XCB_TIME_CURRENT_TIME); + Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, XCB_TIME_CURRENT_TIME)); + connection()->sync(); } QPlatformGLContext *QXcbWindow::glContext() const { - if (!QApplicationPrivate::platformIntegration()->hasOpenGL()) { + if (!QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) { printf("no opengl\n"); return 0; } -#if defined(XCB_USE_GLX) if (!m_context) { +#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 = eglGetDisplay(DISPLAY_FROM_XCB(this)); - + EGLDisplay display = connection()->egl_display(); EGLConfig config = q_configFromQPlatformWindowFormat(display,widget()->platformWindowFormat(),true); QVector<EGLint> eglContextAttrs; eglContextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); @@ -441,14 +510,11 @@ 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 + } return m_context; } @@ -467,6 +533,21 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even if (event->format == 32 && event->type == atom(QXcbAtom::WM_PROTOCOLS)) { if (event->data.data32[0] == atom(QXcbAtom::WM_DELETE_WINDOW)) { QWindowSystemInterface::handleCloseEvent(widget()); + } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) { + xcb_client_message_event_t reply = *event; + + reply.response_type = XCB_CLIENT_MESSAGE; + reply.window = m_screen->root(); + + xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&reply); + xcb_flush(xcb_connection()); + } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_SYNC_REQUEST)) { + if (!m_hasReceivedSyncRequest) { + m_hasReceivedSyncRequest = true; + printf("Window manager supports _NET_WM_SYNC_REQUEST, syncing resizes\n"); + } + m_syncValue.lo = event->data.data32[2]; + m_syncValue.hi = event->data.data32[3]; } } } @@ -482,8 +563,11 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * } QRect rect(xpos, ypos, event->width, event->height); - QPlatformWindow::setGeometry(rect); + if (rect == geometry()) + return; + + QPlatformWindow::setGeometry(rect); QWindowSystemInterface::handleGeometryChange(widget(), rect); #if XCB_USE_DRI2 @@ -586,3 +670,14 @@ void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *) QWindowSystemInterface::handleWindowActivated(0); } +void QXcbWindow::updateSyncRequestCounter() +{ + if (m_screen->syncRequestSupported() && (m_syncValue.lo != 0 || m_syncValue.hi != 0)) { + Q_XCB_CALL(xcb_sync_set_counter(xcb_connection(), m_syncCounter, m_syncValue)); + xcb_flush(xcb_connection()); + connection()->sync(); + + m_syncValue.lo = 0; + m_syncValue.hi = 0; + } +} diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 1e9930d..e049837 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -46,6 +46,7 @@ #include <QtGui/QPlatformWindowFormat> #include <xcb/xcb.h> +#include <xcb/sync.h> #include "qxcbobject.h" @@ -88,11 +89,20 @@ public: void handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_timestamp_t time, const QPoint &local, const QPoint &global); + void updateSyncRequestCounter(); + private: + void setNetWmWindowTypes(Qt::WindowFlags flags); + QXcbScreen *m_screen; xcb_window_t m_window; QPlatformGLContext *m_context; + + xcb_sync_int64_t m_syncValue; + xcb_sync_counter_t m_syncCounter; + + bool m_hasReceivedSyncRequest; }; #endif diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp index 7fed230..718f093 100644 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp +++ b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp @@ -53,6 +53,8 @@ #include <stdio.h> +#include <qdebug.h> + class QXcbShmImage : public QXcbObject { public: @@ -84,6 +86,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(), @@ -92,38 +95,49 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size) 0, ~0, 0); + m_shm_info.shmid = shmget (IPC_PRIVATE, m_xcb_image->stride * m_xcb_image->height, IPC_CREAT|0777); m_shm_info.shmaddr = m_xcb_image->data = (quint8 *)shmat (m_shm_info.shmid, 0, 0); m_shm_info.shmseg = xcb_generate_id(xcb_connection()); - xcb_shm_attach(xcb_connection(), m_shm_info.shmseg, m_shm_info.shmid, false); + xcb_generic_error_t *error = xcb_request_check(xcb_connection(), xcb_shm_attach_checked(xcb_connection(), m_shm_info.shmseg, m_shm_info.shmid, false)); + if (error) { + qWarning() << "QXcbWindowSurface: Unable to attach to shared memory segment"; + free(error); + } + + if (shmctl(m_shm_info.shmid, IPC_RMID, 0) == -1) + qWarning() << "QXcbWindowSurface: Error while marking the shared memory segment to be destroyed"; m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, screen->format()); } void QXcbShmImage::destroy() { - xcb_shm_detach(xcb_connection(), m_shm_info.shmseg); + Q_XCB_CALL(xcb_shm_detach(xcb_connection(), m_shm_info.shmseg)); xcb_image_destroy(m_xcb_image); shmdt(m_shm_info.shmaddr); shmctl(m_shm_info.shmid, IPC_RMID, 0); - - xcb_free_gc(xcb_connection(), m_gc); + if (m_gc) + Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc)); } void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &source) { + Q_XCB_NOOP(connection()); if (m_gc_window != window) { - xcb_free_gc(xcb_connection(), m_gc); + if (m_gc) + Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc)); m_gc = xcb_generate_id(xcb_connection()); - xcb_create_gc(xcb_connection(), m_gc, window, 0, 0); + Q_XCB_CALL(xcb_create_gc(xcb_connection(), m_gc, window, 0, 0)); m_gc_window = window; } + Q_XCB_NOOP(connection()); xcb_image_shm_put(xcb_connection(), window, m_gc, @@ -136,18 +150,19 @@ 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 ®ion) { // to prevent X from reading from the image region while we're writing to it if (m_dirty.intersects(region)) { - // from xcb_aux_sync - free(xcb_get_input_focus_reply(xcb_connection(), xcb_get_input_focus(xcb_connection()), 0)); + connection()->sync(); m_dirty = QRegion(); } } @@ -155,16 +170,15 @@ void QXcbShmImage::preparePaint(const QRegion ®ion) QXcbWindowSurface::QXcbWindowSurface(QWidget *widget, bool setDefaultSurface) : QWindowSurface(widget, setDefaultSurface) , m_image(0) + , m_syncingResize(false) { - setStaticContentsSupport(false); - setPartialUpdateSupport(true); - QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(widget)); setConnection(screen->connection()); } QXcbWindowSurface::~QXcbWindowSurface() { + delete m_image; } QPaintDevice *QXcbWindowSurface::paintDevice() @@ -177,10 +191,18 @@ void QXcbWindowSurface::beginPaint(const QRegion ®ion) m_image->preparePaint(region); } +void QXcbWindowSurface::endPaint(const QRegion &) +{ +} + void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) { - Q_UNUSED(region); - Q_UNUSED(offset); + QRect bounds = region.boundingRect(); + + if (size().isEmpty() || !geometry().contains(bounds)) + return; + + Q_XCB_NOOP(connection()); QXcbWindow *window = static_cast<QXcbWindow *>(widget->window()->platformWindow()); @@ -190,16 +212,32 @@ void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, 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()); + + if (m_syncingResize) { + xcb_flush(xcb_connection()); + connection()->sync(); + m_syncingResize = false; + window->updateSyncRequestCounter(); + } } void QXcbWindowSurface::resize(const QSize &size) { + if (size == QWindowSurface::size()) + return; + + Q_XCB_NOOP(connection()); QWindowSurface::resize(size); QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(window())); delete m_image; m_image = new QXcbShmImage(screen, size); + Q_XCB_NOOP(connection()); + + m_syncingResize = true; } extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.h b/src/plugins/platforms/xcb/qxcbwindowsurface.h index 61689b1..23d32ef 100644 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.h +++ b/src/plugins/platforms/xcb/qxcbwindowsurface.h @@ -62,9 +62,11 @@ public: bool scroll(const QRegion &area, int dx, int dy); void beginPaint(const QRegion &); + void endPaint(const QRegion &); private: QXcbShmImage *m_image; + bool m_syncingResize; }; #endif diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro index fdbe2cd..101bdcd 100644 --- a/src/plugins/platforms/xcb/xcb.pro +++ b/src/plugins/platforms/xcb/xcb.pro @@ -55,13 +55,14 @@ contains(QT_CONFIG, opengl) { LIBS += -lEGL } else { DEFINES += XCB_USE_GLX + include (../glxconvenience/glxconvenience.pri) HEADERS += qglxintegration.h SOURCES += qglxintegration.cpp } } } -LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm +LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync include (../fontdatabases/genericunix/genericunix.pri) |