summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb
diff options
context:
space:
mode:
authoraavit <qt-info@nokia.com>2011-04-26 08:28:04 (GMT)
committeraavit <qt-info@nokia.com>2011-04-26 08:28:04 (GMT)
commitff8c99eb54f33108709f9f3107b35780a80f3f17 (patch)
tree11d4c08809bf90fd8b25b175b4903ab00d36e3d6 /src/plugins/platforms/xcb
parent28c7e17d9eeb8264ad9e26a5b93e5ff744add9a6 (diff)
parent7ef9f99301a7c71fdb835f9e1f27d3111557aa2e (diff)
downloadQt-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/README3
-rw-r--r--src/plugins/platforms/xcb/qdri2context.cpp2
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.cpp238
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.h9
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp251
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h39
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp9
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp39
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h6
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp257
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h10
-rw-r--r--src/plugins/platforms/xcb/qxcbwindowsurface.cpp64
-rw-r--r--src/plugins/platforms/xcb/qxcbwindowsurface.h2
-rw-r--r--src/plugins/platforms/xcb/xcb.pro3
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 &region)
{
// 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 &region)
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 &region)
m_image->preparePaint(region);
}
+void QXcbWindowSurface::endPaint(const QRegion &)
+{
+}
+
void QXcbWindowSurface::flush(QWidget *widget, const QRegion &region, 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 &region, const QPoi
QVector<QRect> rects = region.rects();
for (int i = 0; i < rects.size(); ++i)
m_image->put(window->window(), rects.at(i).topLeft() - widgetOffset, rects.at(i).translated(offset));
+
+ Q_XCB_NOOP(connection());
+
+ 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)