summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r--src/plugins/platforms/xcb/README2
-rw-r--r--src/plugins/platforms/xcb/main.cpp5
-rw-r--r--src/plugins/platforms/xcb/qdri2context.cpp8
-rw-r--r--src/plugins/platforms/xcb/qdri2context.h4
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.cpp61
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.h26
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp (renamed from src/plugins/platforms/xcb/qxcbwindowsurface.cpp)121
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.h (renamed from src/plugins/platforms/xcb/qxcbwindowsurface.h)16
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.cpp848
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.h108
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp474
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h109
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp546
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.h71
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp1332
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.h158
-rw-r--r--src/plugins/platforms/xcb/qxcbeglsurface.h68
-rw-r--r--src/plugins/platforms/xcb/qxcbimage.cpp266
-rw-r--r--src/plugins/platforms/xcb/qxcbimage.h64
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp177
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.h28
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp219
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h13
-rw-r--r--src/plugins/platforms/xcb/qxcbmime.cpp288
-rw-r--r--src/plugins/platforms/xcb/qxcbmime.h68
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp95
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.h18
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp220
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h14
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp950
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h62
-rw-r--r--src/plugins/platforms/xcb/qxcbwmsupport.cpp136
-rw-r--r--src/plugins/platforms/xcb/qxcbwmsupport.h67
-rw-r--r--src/plugins/platforms/xcb/xcb.pro103
34 files changed, 6187 insertions, 558 deletions
diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README
index 17a86e6d08..d2884f109c 100644
--- a/src/plugins/platforms/xcb/README
+++ b/src/plugins/platforms/xcb/README
@@ -1,3 +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 libxcb-sync0 libxcb-sync0-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 libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev
diff --git a/src/plugins/platforms/xcb/main.cpp b/src/plugins/platforms/xcb/main.cpp
index 7fee7455be..c544f7073d 100644
--- a/src/plugins/platforms/xcb/main.cpp
+++ b/src/plugins/platforms/xcb/main.cpp
@@ -58,11 +58,10 @@ QStringList QXcbIntegrationPlugin::keys() const
return list;
}
-QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& paramList)
+QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& parameters)
{
- Q_UNUSED(paramList);
if (system.toLower() == "xcb")
- return new QXcbIntegration;
+ return new QXcbIntegration(parameters);
return 0;
}
diff --git a/src/plugins/platforms/xcb/qdri2context.cpp b/src/plugins/platforms/xcb/qdri2context.cpp
index 8bcdacb92b..5f4aff5455 100644
--- a/src/plugins/platforms/xcb/qdri2context.cpp
+++ b/src/plugins/platforms/xcb/qdri2context.cpp
@@ -45,7 +45,7 @@
#include "qxcbconnection.h"
#include <QtCore/QDebug>
-#include <QtGui/QWidget>
+#include <QtWidgets/QWidget>
#include <xcb/dri2.h>
#include <xcb/xfixes.h>
@@ -134,9 +134,9 @@ QDri2Context::QDri2Context(QXcbWindow *window)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERER,d->depth);
//restore the old current context
- const QPlatformGLContext *currentContext = QPlatformGLContext::currentContext();
+ const QPlatformOpenGLContext *currentContext = QPlatformOpenGLContext::currentContext();
if (currentContext)
- const_cast<QPlatformGLContext*>(currentContext)->makeCurrent();
+ const_cast<QPlatformOpenGLContext*>(currentContext)->makeCurrent();
}
QDri2Context::~QDri2Context()
@@ -146,7 +146,6 @@ QDri2Context::~QDri2Context()
void QDri2Context::makeCurrent()
{
- QPlatformGLContext::makeCurrent();
Q_D(QDri2Context);
eglMakeCurrent(EGL_DISPLAY_FROM_XCB(d->qXcbWindow),EGL_NO_SURFACE,EGL_NO_SURFACE,d->eglContext);
@@ -156,7 +155,6 @@ void QDri2Context::makeCurrent()
void QDri2Context::doneCurrent()
{
- QPlatformGLContext::doneCurrent();
Q_D(QDri2Context);
eglMakeCurrent(EGL_DISPLAY_FROM_XCB(d->qXcbWindow),EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT);
}
diff --git a/src/plugins/platforms/xcb/qdri2context.h b/src/plugins/platforms/xcb/qdri2context.h
index be7d637643..ec8b251c3f 100644
--- a/src/plugins/platforms/xcb/qdri2context.h
+++ b/src/plugins/platforms/xcb/qdri2context.h
@@ -42,14 +42,14 @@
#ifndef QDRI2CONTEXT_H
#define QDRI2CONTEXT_H
-#include <QtGui/QPlatformGLContext>
+#include <QtGui/QPlatformOpenGLContext>
class QXcbWindow;
class QDri2ContextPrivate;
struct xcb_dri2_dri2_buffer_t;
-class QDri2Context : public QPlatformGLContext
+class QDri2Context : public QPlatformOpenGLContext
{
Q_DECLARE_PRIVATE(QDri2Context);
public:
diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp
index 8e04cbcb71..41bceaf406 100644
--- a/src/plugins/platforms/xcb/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/qglxintegration.cpp
@@ -41,7 +41,6 @@
#include <QDebug>
#include <QLibrary>
-#include <QGLFormat>
#include "qxcbwindow.h"
#include "qxcbscreen.h"
@@ -50,72 +49,56 @@
#include <X11/Xutil.h>
#include <GL/glx.h>
+#include <QtGui/QOpenGLContext>
+
#include "qglxintegration.h"
-#include "qglxconvenience.h"
+#include <QtPlatformSupport/private/qglxconvenience_p.h>
#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
#include <dlfcn.h>
#endif
-QGLXContext::QGLXContext(Window window, QXcbScreen *screen, const QPlatformWindowFormat &format)
- : QPlatformGLContext()
+QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share)
+ : QPlatformOpenGLContext()
, m_screen(screen)
- , m_drawable((Drawable)window)
, m_context(0)
{
- Q_XCB_NOOP(m_screen->connection());
- const QPlatformGLContext *sharePlatformContext;
- sharePlatformContext = format.sharedGLContext();
GLXContext shareGlxContext = 0;
- if (sharePlatformContext)
- shareGlxContext = static_cast<const QGLXContext*>(sharePlatformContext)->glxContext();
+ if (share)
+ shareGlxContext = static_cast<const QGLXContext*>(share)->glxContext();
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 = qglx_platformWindowFromGLXFBConfig(DISPLAY_FROM_XCB(screen), config, m_context);
- Q_XCB_NOOP(m_screen->connection());
-}
-
-QGLXContext::QGLXContext(QXcbScreen *screen, Drawable drawable, GLXContext context)
- : QPlatformGLContext(), m_screen(screen), m_drawable(drawable), m_context(context)
-{
-
+ m_format = qglx_surfaceFormatFromGLXFBConfig(DISPLAY_FROM_XCB(screen), config, m_context);
}
QGLXContext::~QGLXContext()
{
- Q_XCB_NOOP(m_screen->connection());
- if (m_context)
- glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context);
- Q_XCB_NOOP(m_screen->connection());
+ glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context);
}
-void QGLXContext::makeCurrent()
+bool QGLXContext::makeCurrent(QPlatformSurface *surface)
{
- Q_XCB_NOOP(m_screen->connection());
- QPlatformGLContext::makeCurrent();
- glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), m_drawable, m_context);
- Q_XCB_NOOP(m_screen->connection());
+ Q_ASSERT(surface);
+
+ GLXDrawable glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
+
+ return glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), glxDrawable, m_context);
}
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()
+void QGLXContext::swapBuffers(QPlatformSurface *surface)
{
- Q_XCB_NOOP(m_screen->connection());
- glXSwapBuffers(DISPLAY_FROM_XCB(m_screen), m_drawable);
- Q_XCB_NOOP(m_screen->connection());
+ GLXDrawable glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
+ glXSwapBuffers(DISPLAY_FROM_XCB(m_screen), glxDrawable);
}
-void* QGLXContext::getProcAddress(const QString& procName)
+void (*QGLXContext::getProcAddress(const QByteArray &procName)) ()
{
- Q_XCB_NOOP(m_screen->connection());
typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *);
static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
static bool resolved = false;
@@ -144,10 +127,10 @@ void* QGLXContext::getProcAddress(const QString& procName)
}
if (!glXGetProcAddressARB)
return 0;
- return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.toLatin1().data()));
+ return (void (*)())glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.constData()));
}
-QPlatformWindowFormat QGLXContext::platformWindowFormat() const
+QSurfaceFormat QGLXContext::format() const
{
- return m_windowFormat;
+ return m_format;
}
diff --git a/src/plugins/platforms/xcb/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h
index 84de7b7143..bbe67b653a 100644
--- a/src/plugins/platforms/xcb/qglxintegration.h
+++ b/src/plugins/platforms/xcb/qglxintegration.h
@@ -43,36 +43,34 @@
#define QGLXINTEGRATION_H
#include "qxcbwindow.h"
+#include "qxcbscreen.h"
-#include <QtGui/QPlatformGLContext>
-#include <QtGui/QPlatformWindowFormat>
+#include <QtGui/QPlatformOpenGLContext>
+#include <QtGui/QSurfaceFormat>
#include <QtCore/QMutex>
#include <GL/glx.h>
-class QGLXContext : public QPlatformGLContext
+class QGLXContext : public QPlatformOpenGLContext
{
public:
- QGLXContext(Window window, QXcbScreen *xd, const QPlatformWindowFormat &format);
+ QGLXContext(QXcbScreen *xd, const QSurfaceFormat &format, QPlatformOpenGLContext *share);
~QGLXContext();
- virtual void makeCurrent();
- virtual void doneCurrent();
- virtual void swapBuffers();
- virtual void* getProcAddress(const QString& procName);
+ bool makeCurrent(QPlatformSurface *surface);
+ void doneCurrent();
+ void swapBuffers(QPlatformSurface *surface);
+ void (*getProcAddress(const QByteArray &procName)) ();
- GLXContext glxContext() const { return m_context; }
+ QSurfaceFormat format() const;
- QPlatformWindowFormat platformWindowFormat() const;
+ GLXContext glxContext() const { return m_context; }
private:
QXcbScreen *m_screen;
- Drawable m_drawable;
GLXContext m_context;
- QPlatformWindowFormat m_windowFormat;
-
- QGLXContext (QXcbScreen *screen, Drawable drawable, GLXContext context);
+ QSurfaceFormat m_format;
};
#endif
diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index 4fcd207df3..fadcb4d5b8 100644
--- a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -39,7 +39,7 @@
**
****************************************************************************/
-#include "qxcbwindowsurface.h"
+#include "qxcbbackingstore.h"
#include "qxcbconnection.h"
#include "qxcbscreen.h"
@@ -52,9 +52,11 @@
#include <sys/shm.h>
#include <stdio.h>
+#include <errno.h>
#include <qdebug.h>
#include <qpainter.h>
+#include <qscreen.h>
class QXcbShmImage : public QXcbObject
{
@@ -63,6 +65,7 @@ public:
~QXcbShmImage() { destroy(); }
QImage *image() { return &m_qimage; }
+ QSize size() const { return m_qimage.size(); }
void put(xcb_window_t window, const QPoint &dst, const QRect &source);
void preparePaint(const QRegion &region);
@@ -97,30 +100,54 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI
~0,
0);
- m_shm_info.shmid = shmget (IPC_PRIVATE,
- m_xcb_image->stride * m_xcb_image->height, IPC_CREAT|0777);
+ const int segmentSize = m_xcb_image->stride * m_xcb_image->height;
+ if (!segmentSize)
+ return;
+ int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0777);
+ if (id == -1)
+ qWarning("QXcbShmImage: shmget() failed (%d) for size %d (%dx%d)",
+ errno, segmentSize, size.width(), size.height());
+ else
+ m_shm_info.shmid = id;
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_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";
+ shmdt(m_shm_info.shmaddr);
+ shmctl(m_shm_info.shmid, IPC_RMID, 0);
+
+ m_shm_info.shmaddr = 0;
+
+ m_xcb_image->data = (uint8_t *)qMalloc(segmentSize);
+ } else {
+ if (shmctl(m_shm_info.shmid, IPC_RMID, 0) == -1)
+ qWarning() << "QXcbBackingStore: 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, format);
}
void QXcbShmImage::destroy()
{
- Q_XCB_CALL(xcb_shm_detach(xcb_connection(), m_shm_info.shmseg));
+ const int segmentSize = m_xcb_image ? (m_xcb_image->stride * m_xcb_image->height) : 0;
+ if (segmentSize && m_shm_info.shmaddr)
+ 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);
+
+ if (segmentSize) {
+ if (m_shm_info.shmaddr) {
+ shmdt(m_shm_info.shmaddr);
+ shmctl(m_shm_info.shmid, IPC_RMID, 0);
+ } else {
+ qFree(m_xcb_image->data);
+ }
+ }
+
if (m_gc)
Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc));
}
@@ -139,18 +166,32 @@ void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &s
}
Q_XCB_NOOP(connection());
- xcb_image_shm_put(xcb_connection(),
+ if (m_shm_info.shmaddr) {
+ xcb_image_shm_put(xcb_connection(),
+ window,
+ m_gc,
+ m_xcb_image,
+ m_shm_info,
+ source.x(),
+ source.y(),
+ target.x(),
+ target.y(),
+ source.width(),
+ source.height(),
+ false);
+ } else {
+ xcb_image_t *subimage = xcb_image_subimage(m_xcb_image, source.x(), source.y(), source.width(), source.height(),
+ 0, 0, 0);
+ xcb_image_put(xcb_connection(),
window,
m_gc,
- m_xcb_image,
- m_shm_info,
- source.x(),
- source.y(),
+ subimage,
target.x(),
target.y(),
- source.width(),
- source.height(),
- false);
+ 0);
+
+ xcb_image_destroy(subimage);
+ }
Q_XCB_NOOP(connection());
m_dirty = m_dirty | source;
@@ -168,29 +209,30 @@ void QXcbShmImage::preparePaint(const QRegion &region)
}
}
-QXcbWindowSurface::QXcbWindowSurface(QWidget *widget, bool setDefaultSurface)
- : QWindowSurface(widget, setDefaultSurface)
+QXcbBackingStore::QXcbBackingStore(QWindow *window)
+ : QPlatformBackingStore(window)
, m_image(0)
, m_syncingResize(false)
{
- QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(widget));
+ QXcbScreen *screen = static_cast<QXcbScreen *>(window->screen()->handle());
setConnection(screen->connection());
}
-QXcbWindowSurface::~QXcbWindowSurface()
+QXcbBackingStore::~QXcbBackingStore()
{
delete m_image;
}
-QPaintDevice *QXcbWindowSurface::paintDevice()
+QPaintDevice *QXcbBackingStore::paintDevice()
{
return m_image->image();
}
-void QXcbWindowSurface::beginPaint(const QRegion &region)
+void QXcbBackingStore::beginPaint(const QRegion &region)
{
m_image->preparePaint(region);
+#if 0
if (m_image->image()->hasAlphaChannel()) {
QPainter p(m_image->image());
p.setCompositionMode(QPainter::CompositionMode_Source);
@@ -200,29 +242,27 @@ void QXcbWindowSurface::beginPaint(const QRegion &region)
p.fillRect(*it, blank);
}
}
+#endif
}
-void QXcbWindowSurface::endPaint(const QRegion &)
+void QXcbBackingStore::endPaint(const QRegion &)
{
}
-void QXcbWindowSurface::flush(QWidget *widget, const QRegion &region, const QPoint &offset)
+void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
QRect bounds = region.boundingRect();
- if (size().isEmpty() || !geometry().contains(bounds))
+ if (!m_image || m_image->size().isEmpty())
return;
Q_XCB_NOOP(connection());
- QXcbWindow *window = static_cast<QXcbWindow *>(widget->window()->platformWindow());
-
- extern QWidgetData* qt_widget_data(QWidget *);
- QPoint widgetOffset = qt_qwidget_data(widget)->wrect.topLeft();
+ QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle());
QVector<QRect> rects = region.rects();
for (int i = 0; i < rects.size(); ++i)
- m_image->put(window->window(), rects.at(i).topLeft() - widgetOffset, rects.at(i).translated(offset));
+ m_image->put(platformWindow->xcb_window(), rects.at(i).topLeft(), rects.at(i).translated(offset));
Q_XCB_NOOP(connection());
@@ -230,23 +270,22 @@ void QXcbWindowSurface::flush(QWidget *widget, const QRegion &region, const QPoi
xcb_flush(xcb_connection());
connection()->sync();
m_syncingResize = false;
- window->updateSyncRequestCounter();
+ platformWindow->updateSyncRequestCounter();
}
}
-void QXcbWindowSurface::resize(const QSize &size)
+void QXcbBackingStore::resize(const QSize &size, const QRegion &)
{
- if (size == QWindowSurface::size())
+ if (m_image && size == m_image->size())
return;
Q_XCB_NOOP(connection());
- QWindowSurface::resize(size);
- QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(window()));
- QXcbWindow* win = static_cast<QXcbWindow *>(window()->platformWindow());
+ QXcbScreen *screen = static_cast<QXcbScreen *>(window()->screen()->handle());
+ QXcbWindow* win = static_cast<QXcbWindow *>(window()->handle());
delete m_image;
- m_image = new QXcbShmImage(screen, size, win->depth(), win->format());
+ m_image = new QXcbShmImage(screen, size, win->depth(), win->imageFormat());
Q_XCB_NOOP(connection());
m_syncingResize = true;
@@ -254,9 +293,9 @@ void QXcbWindowSurface::resize(const QSize &size)
extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
-bool QXcbWindowSurface::scroll(const QRegion &area, int dx, int dy)
+bool QXcbBackingStore::scroll(const QRegion &area, int dx, int dy)
{
- if (m_image->image()->isNull())
+ if (!m_image || m_image->image()->isNull())
return false;
m_image->preparePaint(area);
diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.h b/src/plugins/platforms/xcb/qxcbbackingstore.h
index 5f61815b65..db94d26b09 100644
--- a/src/plugins/platforms/xcb/qxcbwindowsurface.h
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.h
@@ -39,10 +39,10 @@
**
****************************************************************************/
-#ifndef QXCBWINDOWSURFACE_H
-#define QXCBWINDOWSURFACE_H
+#ifndef QXCBBACKINGSTORE_H
+#define QXCBBACKINGSTORE_H
-#include <private/qwindowsurface_p.h>
+#include <qplatformbackingstore_qpa.h>
#include <xcb/xcb.h>
@@ -50,15 +50,15 @@
class QXcbShmImage;
-class QXcbWindowSurface : public QXcbObject, public QWindowSurface
+class QXcbBackingStore : public QXcbObject, public QPlatformBackingStore
{
public:
- QXcbWindowSurface(QWidget *widget, bool setDefaultSurface = true);
- ~QXcbWindowSurface();
+ QXcbBackingStore(QWindow *widget);
+ ~QXcbBackingStore();
QPaintDevice *paintDevice();
- void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
- void resize(const QSize &size);
+ void flush(QWindow *window, const QRegion &region, const QPoint &offset);
+ void resize(const QSize &size, const QRegion &staticContents);
bool scroll(const QRegion &area, int dx, int dy);
void beginPaint(const QRegion &);
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
new file mode 100644
index 0000000000..550b8cbd73
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -0,0 +1,848 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qxcbclipboard.h"
+
+#include "qxcbconnection.h"
+#include "qxcbscreen.h"
+#include "qxcbmime.h"
+
+#include <private/qguiapplication_p.h>
+#include <QElapsedTimer>
+
+#include <QtCore/QDebug>
+
+#include <xcb/xcb_icccm.h>
+
+class QXcbClipboardMime : public QXcbMime
+{
+ Q_OBJECT
+public:
+ QXcbClipboardMime(QClipboard::Mode mode, QXcbClipboard *clipboard)
+ : QXcbMime()
+ , m_clipboard(clipboard)
+ {
+ switch (mode) {
+ case QClipboard::Selection:
+ modeAtom = XCB_ATOM_PRIMARY;
+ break;
+
+ case QClipboard::Clipboard:
+ modeAtom = m_clipboard->atom(QXcbAtom::CLIPBOARD);
+ break;
+
+ default:
+ qWarning("QTestLiteMime: Internal error: Unsupported clipboard mode");
+ break;
+ }
+ }
+
+protected:
+ QStringList formats_sys() const
+ {
+ if (empty())
+ return QStringList();
+
+ if (!formatList.count()) {
+ QXcbClipboardMime *that = const_cast<QXcbClipboardMime *>(this);
+ // get the list of targets from the current clipboard owner - we do this
+ // once so that multiple calls to this function don't require multiple
+ // server round trips...
+ that->format_atoms = m_clipboard->getDataInFormat(modeAtom, m_clipboard->atom(QXcbAtom::TARGETS));
+
+ if (format_atoms.size() > 0) {
+ xcb_atom_t *targets = (xcb_atom_t *) format_atoms.data();
+ int size = format_atoms.size() / sizeof(xcb_atom_t);
+
+ for (int i = 0; i < size; ++i) {
+ if (targets[i] == 0)
+ continue;
+
+ QString format = mimeAtomToString(m_clipboard->connection(), targets[i]);
+ if (!formatList.contains(format))
+ that->formatList.append(format);
+ }
+ }
+ }
+
+ return formatList;
+ }
+
+ bool hasFormat_sys(const QString &format) const
+ {
+ QStringList list = formats();
+ return list.contains(format);
+ }
+
+ QVariant retrieveData_sys(const QString &fmt, QVariant::Type requestedType) const
+ {
+ if (fmt.isEmpty() || empty())
+ return QByteArray();
+
+ (void)formats(); // trigger update of format list
+
+ QList<xcb_atom_t> atoms;
+ xcb_atom_t *targets = (xcb_atom_t *) format_atoms.data();
+ int size = format_atoms.size() / sizeof(xcb_atom_t);
+ for (int i = 0; i < size; ++i)
+ atoms.append(targets[i]);
+
+ QByteArray encoding;
+ xcb_atom_t fmtatom = mimeAtomForFormat(m_clipboard->connection(), fmt, requestedType, atoms, &encoding);
+
+ if (fmtatom == 0)
+ return QVariant();
+
+ return mimeConvertToFormat(m_clipboard->connection(), fmtatom, m_clipboard->getDataInFormat(modeAtom, fmtatom), fmt, requestedType, encoding);
+ }
+private:
+ bool empty() const
+ {
+ return m_clipboard->getSelectionOwner(modeAtom) == XCB_NONE;
+ }
+
+
+ xcb_atom_t modeAtom;
+ QXcbClipboard *m_clipboard;
+ QStringList formatList;
+ QByteArray format_atoms;
+};
+
+const int QXcbClipboard::clipboard_timeout = 5000;
+
+QXcbClipboard::QXcbClipboard(QXcbConnection *c)
+ : QXcbObject(c), QPlatformClipboard()
+ , m_requestor(XCB_NONE)
+ , m_owner(XCB_NONE)
+{
+ Q_ASSERT(QClipboard::Clipboard == 0);
+ Q_ASSERT(QClipboard::Selection == 1);
+ m_xClipboard[QClipboard::Clipboard] = 0;
+ m_xClipboard[QClipboard::Selection] = 0;
+ m_clientClipboard[QClipboard::Clipboard] = 0;
+ m_clientClipboard[QClipboard::Selection] = 0;
+ m_timestamp[QClipboard::Clipboard] = XCB_CURRENT_TIME;
+ m_timestamp[QClipboard::Selection] = XCB_CURRENT_TIME;
+
+ m_screen = connection()->screens().at(connection()->primaryScreen());
+
+ int x = 0, y = 0, w = 3, h = 3;
+
+ m_owner = xcb_generate_id(xcb_connection());
+ Q_XCB_CALL(xcb_create_window(xcb_connection(),
+ XCB_COPY_FROM_PARENT, // depth -- same as root
+ m_owner, // window id
+ m_screen->screen()->root, // parent window id
+ x, y, w, h,
+ 0, // border width
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class
+ m_screen->screen()->root_visual, // visual
+ 0, // value mask
+ 0)); // value list
+
+ if (connection()->hasXFixes()) {
+ const uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
+ XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
+ XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
+ Q_XCB_CALL(xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, XCB_ATOM_PRIMARY, mask));
+ Q_XCB_CALL(xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD), mask));
+ }
+}
+
+QXcbClipboard::~QXcbClipboard()
+{
+ // Transfer the clipboard content to the clipboard manager if we own a selection
+ if (m_timestamp[QClipboard::Clipboard] != XCB_CURRENT_TIME ||
+ m_timestamp[QClipboard::Selection] != XCB_CURRENT_TIME) {
+
+ // First we check if there is a clipboard manager.
+ xcb_get_selection_owner_cookie_t cookie = xcb_get_selection_owner(xcb_connection(), atom(QXcbAtom::CLIPBOARD_MANAGER));
+ xcb_get_selection_owner_reply_t *reply = xcb_get_selection_owner_reply(xcb_connection(), cookie, 0);
+ if (reply && reply->owner != XCB_NONE) {
+ // we delete the property so the manager saves all TARGETS.
+ xcb_delete_property(xcb_connection(), m_owner, atom(QXcbAtom::_QT_SELECTION));
+ xcb_convert_selection(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD_MANAGER), atom(QXcbAtom::SAVE_TARGETS),
+ atom(QXcbAtom::_QT_SELECTION), connection()->time());
+ connection()->sync();
+
+ // waiting until the clipboard manager fetches the content.
+ if (!waitForClipboardEvent(m_owner, XCB_SELECTION_NOTIFY, 5000)) {
+ qWarning("QClipboard: Unable to receive an event from the "
+ "clipboard manager in a reasonable time");
+ }
+ }
+ }
+}
+
+
+xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const
+{
+ xcb_connection_t *c = xcb_connection();
+ xcb_get_selection_owner_cookie_t cookie = xcb_get_selection_owner(c, atom);
+ xcb_get_selection_owner_reply_t *reply;
+ reply = xcb_get_selection_owner_reply(c, cookie, 0);
+ xcb_window_t win = reply->owner;
+ free(reply);
+ return win;
+}
+
+xcb_atom_t QXcbClipboard::atomForMode(QClipboard::Mode mode) const
+{
+ if (mode == QClipboard::Clipboard)
+ return atom(QXcbAtom::CLIPBOARD);
+ if (mode == QClipboard::Selection)
+ return XCB_ATOM_PRIMARY;
+ return XCB_NONE;
+}
+
+QClipboard::Mode QXcbClipboard::modeForAtom(xcb_atom_t a) const
+{
+ if (a == XCB_ATOM_PRIMARY)
+ return QClipboard::Selection;
+ if (a == atom(QXcbAtom::CLIPBOARD))
+ return QClipboard::Clipboard;
+ // not supported enum value, used to detect errors
+ return QClipboard::FindBuffer;
+}
+
+
+QMimeData * QXcbClipboard::mimeData(QClipboard::Mode mode)
+{
+ if (mode > QClipboard::Selection)
+ return 0;
+
+ xcb_window_t clipboardOwner = getSelectionOwner(atomForMode(mode));
+ if (clipboardOwner == owner()) {
+ return m_clientClipboard[mode];
+ } else {
+ if (!m_xClipboard[mode])
+ m_xClipboard[mode] = new QXcbClipboardMime(mode, this);
+
+ return m_xClipboard[mode];
+ }
+}
+
+void QXcbClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
+{
+ if (mode > QClipboard::Selection)
+ return;
+
+ xcb_atom_t modeAtom = atomForMode(mode);
+
+ if (m_clientClipboard[mode] == data)
+ return;
+
+ xcb_window_t newOwner = XCB_NONE;
+
+ if (m_clientClipboard[QClipboard::Clipboard] != m_clientClipboard[QClipboard::Selection])
+ delete m_clientClipboard[mode];
+ m_clientClipboard[mode] = 0;
+ m_timestamp[mode] = XCB_CURRENT_TIME;
+
+ if (data) {
+ newOwner = owner();
+
+ m_clientClipboard[mode] = data;
+ m_timestamp[mode] = connection()->time();
+ }
+
+ xcb_set_selection_owner(xcb_connection(), newOwner, modeAtom, connection()->time());
+
+ if (getSelectionOwner(modeAtom) != newOwner) {
+ qWarning("QClipboard::setData: Cannot set X11 selection owner");
+ }
+
+}
+
+bool QXcbClipboard::supportsMode(QClipboard::Mode mode) const
+{
+ if (mode <= QClipboard::Selection)
+ return true;
+ return false;
+}
+
+bool QXcbClipboard::ownsMode(QClipboard::Mode mode) const
+{
+ if (m_owner == XCB_NONE || mode > QClipboard::Selection)
+ return false;
+
+ Q_ASSERT(m_timestamp[mode] == XCB_CURRENT_TIME || getSelectionOwner(atomForMode(mode)) == m_owner);
+
+ return m_timestamp[mode] != XCB_CURRENT_TIME;
+}
+
+xcb_window_t QXcbClipboard::requestor() const
+{
+ if (!m_requestor) {
+ const int x = 0, y = 0, w = 3, h = 3;
+ QXcbClipboard *that = const_cast<QXcbClipboard *>(this);
+
+ xcb_window_t window = xcb_generate_id(xcb_connection());
+ Q_XCB_CALL(xcb_create_window(xcb_connection(),
+ XCB_COPY_FROM_PARENT, // depth -- same as root
+ window, // window id
+ m_screen->screen()->root, // parent window id
+ x, y, w, h,
+ 0, // border width
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class
+ m_screen->screen()->root_visual, // visual
+ 0, // value mask
+ 0)); // value list
+
+ uint32_t mask = XCB_EVENT_MASK_PROPERTY_CHANGE;
+ xcb_change_window_attributes(xcb_connection(), window, XCB_CW_EVENT_MASK, &mask);
+
+ that->setRequestor(window);
+ }
+ return m_requestor;
+}
+
+void QXcbClipboard::setRequestor(xcb_window_t window)
+{
+ if (m_requestor != XCB_NONE) {
+ xcb_destroy_window(xcb_connection(), m_requestor);
+ }
+ m_requestor = window;
+}
+
+xcb_window_t QXcbClipboard::owner() const
+{
+ return m_owner;
+}
+
+xcb_atom_t QXcbClipboard::sendTargetsSelection(QMimeData *d, xcb_window_t window, xcb_atom_t property)
+{
+ QVector<xcb_atom_t> types;
+ QStringList formats = QInternalMimeData::formatsHelper(d);
+ for (int i = 0; i < formats.size(); ++i) {
+ QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), formats.at(i));
+ for (int j = 0; j < atoms.size(); ++j) {
+ if (!types.contains(atoms.at(j)))
+ types.append(atoms.at(j));
+ }
+ }
+ types.append(atom(QXcbAtom::TARGETS));
+ types.append(atom(QXcbAtom::MULTIPLE));
+ types.append(atom(QXcbAtom::TIMESTAMP));
+ types.append(atom(QXcbAtom::SAVE_TARGETS));
+
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, XCB_ATOM_ATOM,
+ 32, types.size(), (const void *)types.constData());
+ return property;
+}
+
+xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_window_t window, xcb_atom_t property)
+{
+ xcb_atom_t atomFormat = target;
+ int dataFormat = 0;
+ QByteArray data;
+
+ QString fmt = QXcbMime::mimeAtomToString(connection(), target);
+ if (fmt.isEmpty()) { // Not a MIME type we have
+// qDebug() << "QClipboard: send_selection(): converting to type" << connection()->atomName(target) << "is not supported";
+ return XCB_NONE;
+ }
+// qDebug() << "QClipboard: send_selection(): converting to type" << fmt;
+
+ if (QXcbMime::mimeDataForAtom(connection(), target, d, &data, &atomFormat, &dataFormat)) {
+
+ // don't allow INCR transfers when using MULTIPLE or to
+ // Motif clients (since Motif doesn't support INCR)
+ static xcb_atom_t motif_clip_temporary = atom(QXcbAtom::CLIP_TEMPORARY);
+ bool allow_incr = property != motif_clip_temporary;
+
+ // X_ChangeProperty protocol request is 24 bytes
+ const int increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24;
+ if (data.size() > increment && allow_incr) {
+ long bytes = data.size();
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property,
+ atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes);
+
+// (void)new QClipboardINCRTransaction(window, property, atomFormat, dataFormat, data, increment);
+ qWarning() << "not implemented INCR just YET!";
+ return property;
+ }
+
+ // make sure we can perform the XChangeProperty in a single request
+ if (data.size() > increment)
+ return XCB_NONE; // ### perhaps use several XChangeProperty calls w/ PropModeAppend?
+ int dataSize = data.size() / (dataFormat / 8);
+ // use a single request to transfer data
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, atomFormat,
+ dataFormat, dataSize, (const void *)data.constData());
+ }
+ return property;
+}
+
+void QXcbClipboard::handleSelectionClearRequest(xcb_selection_clear_event_t *event)
+{
+ QClipboard::Mode mode = modeForAtom(event->selection);
+ if (mode > QClipboard::Selection)
+ return;
+
+ // ignore the event if it was generated before we gained selection ownership
+ if (m_timestamp[mode] != XCB_CURRENT_TIME && event->time <= m_timestamp[mode])
+ return;
+
+// DEBUG("QClipboard: new selection owner 0x%lx at time %lx (ours %lx)",
+// XGetSelectionOwner(dpy, XA_PRIMARY),
+// xevent->xselectionclear.time, d->timestamp);
+
+// if (!waiting_for_data) {
+ setMimeData(0, mode);
+ emitChanged(mode);
+// } else {
+// pending_selection_changed = true;
+// if (! pending_timer_id)
+// pending_timer_id = QApplication::clipboard()->startTimer(0);
+// }
+}
+
+void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req)
+{
+ if (requestor() && req->requestor == requestor()) {
+ qDebug() << "This should be caught before";
+ return;
+ }
+
+ xcb_selection_notify_event_t event;
+ event.response_type = XCB_SELECTION_NOTIFY;
+ event.requestor = req->requestor;
+ event.selection = req->selection;
+ event.target = req->target;
+ event.property = XCB_NONE;
+ event.time = req->time;
+
+ QMimeData *d;
+ QClipboard::Mode mode = modeForAtom(req->selection);
+ if (mode > QClipboard::Selection) {
+ qWarning() << "QClipboard: Unknown selection" << connection()->atomName(req->selection);
+ xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
+ return;
+ }
+
+ d = m_clientClipboard[mode];
+
+ if (!d) {
+ qWarning("QClipboard: Cannot transfer data, no data available");
+ xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
+ return;
+ }
+
+ if (m_timestamp[mode] == XCB_CURRENT_TIME // we don't own the selection anymore
+ || (req->time != XCB_CURRENT_TIME && req->time < m_timestamp[mode])) {
+ qDebug("QClipboard: SelectionRequest too old");
+ xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
+ return;
+ }
+
+ xcb_atom_t xa_targets = atom(QXcbAtom::TARGETS);
+ xcb_atom_t xa_multiple = atom(QXcbAtom::MULTIPLE);
+ xcb_atom_t xa_timestamp = atom(QXcbAtom::TIMESTAMP);
+
+ struct AtomPair { xcb_atom_t target; xcb_atom_t property; } *multi = 0;
+ xcb_atom_t multi_type = XCB_NONE;
+ int multi_format = 0;
+ int nmulti = 0;
+ int imulti = -1;
+ bool multi_writeback = false;
+
+ if (req->target == xa_multiple) {
+ QByteArray multi_data;
+ if (req->property == XCB_NONE
+ || !clipboardReadProperty(req->requestor, req->property, false, &multi_data,
+ 0, &multi_type, &multi_format)
+ || multi_format != 32) {
+ // MULTIPLE property not formatted correctly
+ xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
+ return;
+ }
+ nmulti = multi_data.size()/sizeof(*multi);
+ multi = new AtomPair[nmulti];
+ memcpy(multi,multi_data.data(),multi_data.size());
+ imulti = 0;
+ }
+
+ for (; imulti < nmulti; ++imulti) {
+ xcb_atom_t target;
+ xcb_atom_t property;
+
+ if (multi) {
+ target = multi[imulti].target;
+ property = multi[imulti].property;
+ } else {
+ target = req->target;
+ property = req->property;
+ if (property == XCB_NONE) // obsolete client
+ property = target;
+ }
+
+ xcb_atom_t ret = XCB_NONE;
+ if (target == XCB_NONE || property == XCB_NONE) {
+ ;
+ } else if (target == xa_timestamp) {
+ if (m_timestamp[mode] != XCB_CURRENT_TIME) {
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, req->requestor,
+ property, XCB_ATOM_INTEGER, 32, 1, &m_timestamp[mode]);
+ ret = property;
+ } else {
+ qWarning("QClipboard: Invalid data timestamp");
+ }
+ } else if (target == xa_targets) {
+ ret = sendTargetsSelection(d, req->requestor, property);
+ } else {
+ ret = sendSelection(d, target, req->requestor, property);
+ }
+
+ if (nmulti > 0) {
+ if (ret == XCB_NONE) {
+ multi[imulti].property = XCB_NONE;
+ multi_writeback = true;
+ }
+ } else {
+ event.property = ret;
+ break;
+ }
+ }
+
+ if (nmulti > 0) {
+ if (multi_writeback) {
+ // according to ICCCM 2.6.2 says to put None back
+ // into the original property on the requestor window
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, req->requestor, req->property,
+ multi_type, 32, nmulti*2, (const void *)multi);
+ }
+
+ delete [] multi;
+ event.property = req->property;
+ }
+
+ // send selection notify to requestor
+ xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
+}
+
+void QXcbClipboard::handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event)
+{
+ QClipboard::Mode mode = modeForAtom(event->selection);
+ if (event->owner != owner() && m_clientClipboard[mode] && m_timestamp[mode] < event->selection_timestamp) {
+ setMimeData(0, mode);
+ emitChanged(mode);
+ }
+}
+
+
+static inline int maxSelectionIncr(xcb_connection_t *c)
+{
+ int l = xcb_get_maximum_request_length(c);
+ return (l > 65536 ? 65536*4 : l*4) - 100;
+}
+
+bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) const
+{
+ int maxsize = maxSelectionIncr(xcb_connection());
+ ulong bytes_left; // bytes_after
+ xcb_atom_t dummy_type;
+ int dummy_format;
+
+ if (!type) // allow null args
+ type = &dummy_type;
+ if (!format)
+ format = &dummy_format;
+
+ // Don't read anything, just get the size of the property data
+ xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(xcb_connection(), false, win, property, XCB_GET_PROPERTY_TYPE_ANY, 0, 0));
+ xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0);
+ if (!reply || reply->type == XCB_NONE) {
+ buffer->resize(0);
+ return false;
+ }
+ *type = reply->type;
+ *format = reply->format;
+ bytes_left = reply->bytes_after;
+ free(reply);
+
+ int offset = 0, buffer_offset = 0, format_inc = 1, proplen = bytes_left;
+
+ switch (*format) {
+ case 8:
+ default:
+ format_inc = sizeof(char) / 1;
+ break;
+
+ case 16:
+ format_inc = sizeof(short) / 2;
+ proplen *= sizeof(short) / 2;
+ break;
+
+ case 32:
+ format_inc = sizeof(long) / 4;
+ proplen *= sizeof(long) / 4;
+ break;
+ }
+
+ int newSize = proplen;
+ buffer->resize(newSize);
+
+ bool ok = (buffer->size() == newSize);
+
+ if (ok && newSize) {
+ // could allocate buffer
+
+ while (bytes_left) {
+ // more to read...
+
+ xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(xcb_connection(), false, win, property, XCB_GET_PROPERTY_TYPE_ANY, offset, maxsize/4));
+ reply = xcb_get_property_reply(xcb_connection(), cookie, 0);
+ if (!reply || reply->type == XCB_NONE) {
+ free(reply);
+ break;
+ }
+ *type = reply->type;
+ *format = reply->format;
+ bytes_left = reply->bytes_after;
+ char *data = (char *)xcb_get_property_value(reply);
+ int length = xcb_get_property_value_length(reply);
+
+ offset += length / (32 / *format);
+ length *= format_inc * (*format) / 8;
+
+ // Here we check if we get a buffer overflow and tries to
+ // recover -- this shouldn't normally happen, but it doesn't
+ // hurt to be defensive
+ if ((int)(buffer_offset + length) > buffer->size()) {
+ length = buffer->size() - buffer_offset;
+
+ // escape loop
+ bytes_left = 0;
+ }
+
+ memcpy(buffer->data() + buffer_offset, data, length);
+ buffer_offset += length;
+
+ free(reply);
+ }
+ }
+
+
+ // correct size, not 0-term.
+ if (size)
+ *size = buffer_offset;
+
+ if (deleteProperty)
+ xcb_delete_property(xcb_connection(), win, property);
+
+ connection()->flush();
+
+ return ok;
+}
+
+
+namespace
+{
+ class Notify {
+ public:
+ Notify(xcb_window_t win, int t)
+ : window(win), type(t) {}
+ xcb_window_t window;
+ int type;
+ bool check(xcb_generic_event_t *event) const {
+ if (!event)
+ return false;
+ int t = event->response_type & 0x7f;
+ if (t != type)
+ return false;
+ if (t == XCB_PROPERTY_NOTIFY) {
+ xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event;
+ if (pn->window == window)
+ return true;
+ } else if (t == XCB_SELECTION_NOTIFY) {
+ xcb_selection_notify_event_t *sn = (xcb_selection_notify_event_t *)event;
+ if (sn->requestor == window)
+ return true;
+ }
+ return false;
+ }
+ };
+ class ClipboardEvent {
+ public:
+ ClipboardEvent(QXcbConnection *c)
+ { clipboard = c->internAtom("CLIPBOARD"); }
+ xcb_atom_t clipboard;
+ bool check(xcb_generic_event_t *e) const {
+ if (!e)
+ return false;
+ int type = e->response_type & 0x7f;
+ if (type == XCB_SELECTION_REQUEST) {
+ xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)e;
+ return sr->selection == XCB_ATOM_PRIMARY || sr->selection == clipboard;
+ } else if (type == XCB_SELECTION_CLEAR) {
+ xcb_selection_clear_event_t *sc = (xcb_selection_clear_event_t *)e;
+ return sc->selection == XCB_ATOM_PRIMARY || sc->selection == clipboard;
+ }
+ return false;
+ }
+ };
+}
+
+xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t win, int type, int timeout)
+{
+ QElapsedTimer timer;
+ timer.start();
+ do {
+ Notify notify(win, type);
+ xcb_generic_event_t *e = connection()->checkEvent(notify);
+ if (e)
+ return e;
+
+ // process other clipboard events, since someone is probably requesting data from us
+ ClipboardEvent clipboard(connection());
+ e = connection()->checkEvent(clipboard);
+ if (e) {
+ connection()->handleXcbEvent(e);
+ free(e);
+ }
+
+ connection()->flush();
+
+ // sleep 50 ms, so we don't use up CPU cycles all the time.
+ struct timeval usleep_tv;
+ usleep_tv.tv_sec = 0;
+ usleep_tv.tv_usec = 50000;
+ select(0, 0, 0, 0, &usleep_tv);
+ } while (timer.elapsed() < timeout);
+
+ return 0;
+}
+
+QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm)
+{
+ QByteArray buf;
+ QByteArray tmp_buf;
+ bool alloc_error = false;
+ int length;
+ int offset = 0;
+
+ if (nbytes > 0) {
+ // Reserve buffer + zero-terminator (for text data)
+ // We want to complete the INCR transfer even if we cannot
+ // allocate more memory
+ buf.resize(nbytes+1);
+ alloc_error = buf.size() != nbytes+1;
+ }
+
+ for (;;) {
+ connection()->flush();
+ xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY, clipboard_timeout);
+ if (!ge)
+ break;
+
+ xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge;
+ if (event->atom != property || event->state != XCB_PROPERTY_NEW_VALUE)
+ continue;
+ if (clipboardReadProperty(win, property, true, &tmp_buf, &length, 0, 0)) {
+ if (length == 0) { // no more data, we're done
+ if (nullterm) {
+ buf.resize(offset+1);
+ buf[offset] = '\0';
+ } else {
+ buf.resize(offset);
+ }
+ return buf;
+ } else if (!alloc_error) {
+ if (offset+length > (int)buf.size()) {
+ buf.resize(offset+length+65535);
+ if (buf.size() != offset+length+65535) {
+ alloc_error = true;
+ length = buf.size() - offset;
+ }
+ }
+ memcpy(buf.data()+offset, tmp_buf.constData(), length);
+ tmp_buf.resize(0);
+ offset += length;
+ }
+ } else {
+ break;
+ }
+
+ free(ge);
+ }
+
+ // timed out ... create a new requestor window, otherwise the requestor
+ // could consider next request to be still part of this timed out request
+ setRequestor(0);
+
+ return QByteArray();
+}
+
+QByteArray QXcbClipboard::getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtAtom)
+{
+ return getSelection(modeAtom, fmtAtom, atom(QXcbAtom::_QT_SELECTION));
+}
+
+QByteArray QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property)
+{
+ QByteArray buf;
+ xcb_window_t win = requestor();
+
+ xcb_delete_property(xcb_connection(), win, property);
+ xcb_convert_selection(xcb_connection(), win, selection, target, property, connection()->time());
+
+ connection()->sync();
+
+ xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_SELECTION_NOTIFY, clipboard_timeout);
+ bool no_selection = !ge || ((xcb_selection_notify_event_t *)ge)->property == XCB_NONE;
+ free(ge);
+
+ if (no_selection)
+ return buf;
+
+ xcb_atom_t type;
+ if (clipboardReadProperty(win, property, true, &buf, 0, &type, 0)) {
+ if (type == atom(QXcbAtom::INCR)) {
+ int nbytes = buf.size() >= 4 ? *((int*)buf.data()) : 0;
+ buf = clipboardReadIncrementalProperty(win, property, nbytes, false);
+ }
+ }
+
+ return buf;
+}
+
+#include "qxcbclipboard.moc"
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h
new file mode 100644
index 0000000000..d23f93529b
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbclipboard.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QXCBCLIPBOARD_H
+#define QXCBCLIPBOARD_H
+
+#include <QPlatformClipboard>
+#include <qxcbobject.h>
+#include <xcb/xcb.h>
+#include <xcb/xfixes.h>
+
+class QXcbConnection;
+class QXcbScreen;
+class QXcbClipboardMime;
+
+class QXcbClipboard : public QXcbObject, public QPlatformClipboard
+{
+public:
+ QXcbClipboard(QXcbConnection *connection);
+ ~QXcbClipboard();
+
+ QMimeData *mimeData(QClipboard::Mode mode);
+ void setMimeData(QMimeData *data, QClipboard::Mode mode);
+
+ bool supportsMode(QClipboard::Mode mode) const;
+ bool ownsMode(QClipboard::Mode mode) const;
+
+ QXcbScreen *screen() const { return m_screen; }
+
+ xcb_window_t requestor() const;
+ void setRequestor(xcb_window_t window);
+
+ xcb_window_t owner() const;
+
+ void handleSelectionRequest(xcb_selection_request_event_t *event);
+ void handleSelectionClearRequest(xcb_selection_clear_event_t *event);
+ void handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event);
+
+ bool clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) const;
+ QByteArray clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm);
+
+ QByteArray getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom);
+
+ xcb_window_t getSelectionOwner(xcb_atom_t atom) const;
+ QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property);
+
+private:
+ xcb_generic_event_t *waitForClipboardEvent(xcb_window_t win, int type, int timeout);
+
+ xcb_atom_t sendTargetsSelection(QMimeData *d, xcb_window_t window, xcb_atom_t property);
+ xcb_atom_t sendSelection(QMimeData *d, xcb_atom_t target, xcb_window_t window, xcb_atom_t property);
+
+ xcb_atom_t atomForMode(QClipboard::Mode mode) const;
+ QClipboard::Mode modeForAtom(xcb_atom_t atom) const;
+
+ QXcbScreen *m_screen;
+
+ // Selection and Clipboard
+ QXcbClipboardMime *m_xClipboard[2];
+ QMimeData *m_clientClipboard[2];
+ xcb_timestamp_t m_timestamp[2];
+
+ xcb_window_t m_requestor;
+ xcb_window_t m_owner;
+
+ static const int clipboard_timeout;
+
+};
+
+#endif // QXCBCLIPBOARD_H
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 80a1624380..a0b894602d 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -39,33 +39,41 @@
**
****************************************************************************/
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtCore/QDebug>
+
#include "qxcbconnection.h"
#include "qxcbkeyboard.h"
#include "qxcbscreen.h"
#include "qxcbwindow.h"
+#include "qxcbclipboard.h"
+#include "qxcbdrag.h"
+#include "qxcbwmsupport.h"
#include <QtAlgorithms>
#include <QSocketNotifier>
-#include <QtGui/private/qapplication_p.h>
#include <QAbstractEventDispatcher>
-
-#include <QtCore/QDebug>
+#include <QTimer>
#include <stdio.h>
#include <errno.h>
+#include <xcb/xfixes.h>
#ifdef XCB_USE_XLIB
#include <X11/Xlib.h>
#include <X11/Xlib-xcb.h>
#endif
+#ifdef XCB_USE_RENDER
+#include <xcb/render.h>
+#endif
+
#ifdef XCB_USE_EGL //dont pull in eglext prototypes
#include <EGL/egl.h>
#endif
#ifdef XCB_USE_DRI2
#include <xcb/dri2.h>
-#include <xcb/xfixes.h>
extern "C" {
#include <xf86drm.h>
}
@@ -83,12 +91,13 @@ QXcbConnection::QXcbConnection(const char *displayName)
, m_dri2_support_probed(false)
, m_has_support_for_dri2(false)
#endif
+ , xfixes_first_event(0)
{
- int primaryScreen = 0;
+ m_primaryScreen = 0;
#ifdef XCB_USE_XLIB
Display *dpy = XOpenDisplay(m_displayName.constData());
- primaryScreen = DefaultScreen(dpy);
+ m_primaryScreen = DefaultScreen(dpy);
m_connection = XGetXCBConnection(dpy);
XSetEventQueueOwner(dpy, XCBOwnsEventQueue);
m_xlib_display = dpy;
@@ -100,13 +109,33 @@ QXcbConnection::QXcbConnection(const char *displayName)
m_has_egl = eglInitialize(eglDisplay,&major,&minor);
#endif //XCB_USE_EGL
#else
- m_connection = xcb_connect(m_displayName.constData(), &primaryScreen);
-
+ m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreen);
#endif //XCB_USE_XLIB
+
+ if (m_connection)
+ printf("Successfully connected to display %s\n", m_displayName.constData());
+
+ m_reader = new QXcbEventReader(m_connection);
+#ifdef XCB_POLL_FOR_QUEUED_EVENT
+ connect(m_reader, SIGNAL(eventPending()), this, SLOT(processXcbEvents()), Qt::QueuedConnection);
+ m_reader->start();
+#else
+ QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(xcb_connection()), QSocketNotifier::Read, this);
+ connect(notifier, SIGNAL(activated(int)), this, SLOT(processXcbEvents()));
+
+ QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
+ connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processXcbEvents()));
+ connect(dispatcher, SIGNAL(awake()), this, SLOT(processXcbEvents()));
+#endif
+
+ xcb_prefetch_extension_data (m_connection, &xcb_xfixes_id);
+
m_setup = xcb_get_setup(xcb_connection());
initializeAllAtoms();
+ m_time = XCB_CURRENT_TIME;
+
xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
int screenNumber = 0;
@@ -115,25 +144,38 @@ QXcbConnection::QXcbConnection(const char *displayName)
xcb_screen_next(&it);
}
+ m_connectionEventListener = xcb_generate_id(m_connection);
+ xcb_create_window(m_connection, XCB_COPY_FROM_PARENT,
+ m_connectionEventListener, m_screens.at(0)->root(),
+ 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
+ m_screens.at(0)->screen()->root_visual, 0, 0);
+
+ initializeXFixes();
+ initializeXRender();
+
+ m_wmSupport = new QXcbWMSupport(this);
m_keyboard = new QXcbKeyboard(this);
+ m_clipboard = new QXcbClipboard(this);
+ m_drag = new QXcbDrag(this);
#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()
{
+ delete m_clipboard;
+
qDeleteAll(m_screens);
+#ifdef XCB_POLL_FOR_QUEUED_EVENT
+ sendConnectionEvent(QXcbAtom::_QT_CLOSE_CONNECTION);
+ m_reader->wait();
+#endif
+ delete m_reader;
+
#ifdef XCB_USE_XLIB
XCloseDisplay((Display *)m_xlib_display);
#else
@@ -143,22 +185,26 @@ QXcbConnection::~QXcbConnection()
delete m_keyboard;
}
-QXcbWindow *platformWindowFromId(xcb_window_t id)
+void QXcbConnection::addWindow(xcb_window_t id, QXcbWindow *window)
{
- QWidget *widget = QWidget::find(id);
- if (widget)
- return static_cast<QXcbWindow *>(widget->platformWindow());
- return 0;
+ m_mapper.insert(id, window);
+}
+
+void QXcbConnection::removeWindow(xcb_window_t id)
+{
+ m_mapper.remove(id);
+}
+
+QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id)
+{
+ return m_mapper.value(id, 0);
}
-#define HANDLE_PLATFORM_WINDOW_EVENT(event_t, window, handler) \
+#define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \
{ \
event_t *e = (event_t *)event; \
- if (QXcbWindow *platformWindow = platformWindowFromId(e->window)) { \
- QObjectPrivate *d = QObjectPrivate::get(platformWindow->widget()); \
- if (!d->wasDeleted) \
- platformWindow->handler(e); \
- } \
+ if (QXcbWindow *platformWindow = platformWindowFromId(e->windowMember)) \
+ platformWindow->handler(e); \
} \
break;
@@ -166,7 +212,7 @@ break;
{ \
event_t *e = (event_t *)event; \
if (QXcbWindow *platformWindow = platformWindowFromId(e->event)) \
- m_keyboard->handler(platformWindow->widget(), e); \
+ m_keyboard->handler(platformWindow, e); \
} \
break;
@@ -373,6 +419,7 @@ const char *xcb_protocol_request_codes[] =
#ifdef Q_XCB_DEBUG
void QXcbConnection::log(const char *file, int line, int sequence)
{
+ QMutexLocker locker(&m_callLogMutex);
CallInfo info;
info.sequence = sequence;
info.file = file;
@@ -392,6 +439,7 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error)
int(error->major_code), xcb_protocol_request_codes[clamped_major_code],
int(error->minor_code));
#ifdef Q_XCB_DEBUG
+ QMutexLocker locker(&m_callLogMutex);
int i = 0;
for (; i < m_callLog.size(); ++i) {
if (m_callLog.at(i).sequence == error->sequence) {
@@ -409,67 +457,236 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error)
#endif
}
+void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
+{
+#ifdef Q_XCB_DEBUG
+ {
+ QMutexLocker locker(&m_callLogMutex);
+ int i = 0;
+ for (; i < m_callLog.size(); ++i)
+ if (m_callLog.at(i).sequence >= event->sequence)
+ break;
+ m_callLog.remove(0, i);
+ }
+#endif
+ bool handled = true;
+
+ uint response_type = event->response_type & ~0x80;
+
+ switch (response_type) {
+ case XCB_EXPOSE:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
+ case XCB_BUTTON_PRESS:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
+ case XCB_BUTTON_RELEASE:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
+ case XCB_MOTION_NOTIFY:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent);
+ case XCB_CONFIGURE_NOTIFY:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent);
+ case XCB_MAP_NOTIFY:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent);
+ case XCB_UNMAP_NOTIFY:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent);
+ case XCB_CLIENT_MESSAGE:
+ handleClientMessageEvent((xcb_client_message_event_t *)event);
+ case XCB_ENTER_NOTIFY:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
+ case XCB_LEAVE_NOTIFY:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent);
+ case XCB_FOCUS_IN:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent);
+ case XCB_FOCUS_OUT:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent);
+ case XCB_KEY_PRESS:
+ HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
+ case XCB_KEY_RELEASE:
+ HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
+ case XCB_MAPPING_NOTIFY:
+ m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event);
+ break;
+ case XCB_SELECTION_REQUEST:
+ {
+ xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event;
+ if (sr->selection == atom(QXcbAtom::XdndSelection))
+ m_drag->handleSelectionRequest(sr);
+ else
+ m_clipboard->handleSelectionRequest(sr);
+ break;
+ }
+ case XCB_SELECTION_CLEAR:
+ setTime(((xcb_selection_clear_event_t *)event)->time);
+ m_clipboard->handleSelectionClearRequest((xcb_selection_clear_event_t *)event);
+ handled = true;
+ break;
+ case XCB_SELECTION_NOTIFY:
+ setTime(((xcb_selection_notify_event_t *)event)->time);
+ qDebug() << "XCB_SELECTION_NOTIFY";
+ handled = false;
+ break;
+ case XCB_PROPERTY_NOTIFY:
+ setTime(((xcb_property_notify_event_t *)event)->time);
+// qDebug() << "XCB_PROPERTY_NOTIFY";
+ handled = false;
+ break;
+ default:
+ handled = false;
+ break;
+ }
+
+ if (!handled) {
+ if (response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) {
+ setTime(((xcb_xfixes_selection_notify_event_t *)event)->timestamp);
+ m_clipboard->handleXFixesSelectionRequest((xcb_xfixes_selection_notify_event_t *)event);
+ handled = true;
+ }
+ }
+
+ if (handled)
+ printXcbEvent("Handled XCB event", event);
+ else
+ printXcbEvent("Unhandled XCB event", event);
+}
+
+void QXcbConnection::addPeekFunc(PeekFunc f)
+{
+ m_peekFuncs.append(f);
+}
+
+#ifdef XCB_POLL_FOR_QUEUED_EVENT
+void QXcbEventReader::run()
+{
+ xcb_generic_event_t *event;
+ while (m_connection && (event = xcb_wait_for_event(m_connection))) {
+ m_mutex.lock();
+ addEvent(event);
+ while (m_connection && (event = xcb_poll_for_queued_event(m_connection)))
+ addEvent(event);
+ m_mutex.unlock();
+ emit eventPending();
+ }
+
+ for (int i = 0; i < m_events.size(); ++i)
+ free(m_events.at(i));
+}
+#endif
+
+void QXcbEventReader::addEvent(xcb_generic_event_t *event)
+{
+ if ((event->response_type & ~0x80) == XCB_CLIENT_MESSAGE
+ && ((xcb_client_message_event_t *)event)->type == QXcbAtom::_QT_CLOSE_CONNECTION)
+ m_connection = 0;
+ m_events << event;
+}
+
+QList<xcb_generic_event_t *> *QXcbEventReader::lock()
+{
+ m_mutex.lock();
+#ifndef XCB_POLL_FOR_QUEUED_EVENT
+ while (xcb_generic_event_t *event = xcb_poll_for_event(m_connection))
+ m_events << event;
+#endif
+ return &m_events;
+}
+
+void QXcbEventReader::unlock()
+{
+ m_mutex.unlock();
+}
+
+void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom atom, uint id)
+{
+ xcb_client_message_event_t event;
+ memset(&event, 0, sizeof(event));
+
+ event.response_type = XCB_CLIENT_MESSAGE;
+ event.format = 32;
+ event.sequence = 0;
+ event.window = m_connectionEventListener;
+ event.type = atom;
+ event.data.data32[0] = id;
+
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_connectionEventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event));
+ xcb_flush(xcb_connection());
+}
+
void QXcbConnection::processXcbEvents()
{
- while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection())) {
- bool handled = true;
+ QList<xcb_generic_event_t *> *eventqueue = m_reader->lock();
+
+ for(int i = 0; i < eventqueue->size(); ++i) {
+ xcb_generic_event_t *event = eventqueue->at(i);
+ if (!event)
+ continue;
+ (*eventqueue)[i] = 0;
uint response_type = event->response_type & ~0x80;
if (!response_type) {
handleXcbError((xcb_generic_error_t *)event);
- continue;
+ } else {
+ QVector<PeekFunc>::iterator it = m_peekFuncs.begin();
+ while (it != m_peekFuncs.end()) {
+ // These callbacks return true if the event is what they were
+ // waiting for, remove them from the list in that case.
+ if ((*it)(event))
+ it = m_peekFuncs.erase(it);
+ else
+ ++it;
+ }
+ handleXcbEvent(event);
}
-#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
+ free(event);
+ }
- switch (response_type) {
- case XCB_EXPOSE:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
- case XCB_BUTTON_PRESS:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
- case XCB_BUTTON_RELEASE:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
- case XCB_MOTION_NOTIFY:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent);
- case XCB_CONFIGURE_NOTIFY:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent);
- case XCB_CLIENT_MESSAGE:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_client_message_event_t, window, handleClientMessageEvent);
- case XCB_ENTER_NOTIFY:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
- case XCB_LEAVE_NOTIFY:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent);
- case XCB_FOCUS_IN:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent);
- case XCB_FOCUS_OUT:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent);
- case XCB_KEY_PRESS:
- HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
- case XCB_KEY_RELEASE:
- HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
- case XCB_MAPPING_NOTIFY:
- m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event);
- break;
- default:
- handled = false;
- break;
+ eventqueue->clear();
+
+ m_reader->unlock();
+
+ // Indicate with a null event that the event the callbacks are waiting for
+ // is not in the queue currently.
+ Q_FOREACH (PeekFunc f, m_peekFuncs)
+ f(0);
+ m_peekFuncs.clear();
+
+ xcb_flush(xcb_connection());
+}
+
+void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t *event)
+{
+ if (event->format != 32)
+ return;
+
+ if (event->type == atom(QXcbAtom::XdndStatus)) {
+ drag()->handleStatus(event, false);
+ } else if (event->type == atom(QXcbAtom::XdndFinished)) {
+ drag()->handleFinished(event, false);
+ }
+
+ QXcbWindow *window = platformWindowFromId(event->window);
+ if (!window)
+ return;
+
+ window->handleClientMessageEvent(event);
+}
+
+xcb_generic_event_t *QXcbConnection::checkEvent(int type)
+{
+ QList<xcb_generic_event_t *> *eventqueue = m_reader->lock();
+
+ for (int i = 0; i < eventqueue->size(); ++i) {
+ xcb_generic_event_t *event = eventqueue->at(i);
+ if (event->response_type == type) {
+ (*eventqueue)[i] = 0;
+ m_reader->unlock();
+ return event;
}
- if (handled)
- printXcbEvent("Handled XCB event", event);
- else
- printXcbEvent("Unhandled XCB event", event);
}
- xcb_flush(xcb_connection());
+ m_reader->unlock();
+
+ return 0;
}
static const char * xcb_atomnames = {
@@ -511,6 +728,8 @@ static const char * xcb_atomnames = {
"_QT_SCROLL_DONE\0"
"_QT_INPUT_ENCODING\0"
+ "_QT_CLOSE_CONNECTION\0"
+
"_MOTIF_WM_HINTS\0"
"DTWM_IS_RUNNING\0"
@@ -579,7 +798,6 @@ static const char * xcb_atomnames = {
"_NET_ACTIVE_WINDOW\0"
// Property formats
- "COMPOUND_TEXT\0"
"TEXT\0"
"UTF8_STRING\0"
@@ -659,8 +877,57 @@ void QXcbConnection::initializeAllAtoms() {
for (i = 0; i < QXcbAtom::NAtoms; ++i)
cookies[i] = xcb_intern_atom(xcb_connection(), false, strlen(names[i]), names[i]);
- for (i = 0; i < QXcbAtom::NAtoms; ++i)
- m_allAtoms[i] = xcb_intern_atom_reply(xcb_connection(), cookies[i], 0)->atom;
+ for (i = 0; i < QXcbAtom::NAtoms; ++i) {
+ xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookies[i], 0);
+ m_allAtoms[i] = reply->atom;
+ free(reply);
+ }
+}
+
+xcb_atom_t QXcbConnection::internAtom(const char *name)
+{
+ if (!name || *name == 0)
+ return XCB_NONE;
+
+ xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xcb_connection(), false, strlen(name), name);
+ xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookie, 0);
+ int atom = reply->atom;
+ free(reply);
+ return atom;
+}
+
+QByteArray QXcbConnection::atomName(xcb_atom_t atom)
+{
+ if (!atom)
+ return QByteArray();
+
+ xcb_generic_error_t *error = 0;
+ xcb_get_atom_name_cookie_t cookie = Q_XCB_CALL(xcb_get_atom_name(xcb_connection(), atom));
+ xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(xcb_connection(), cookie, &error);
+ if (error) {
+ qWarning() << "QXcbConnection::atomName: bad Atom" << atom;
+ }
+ if (reply) {
+ QByteArray result(xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply));
+ free(reply);
+ return result;
+ }
+ return QByteArray();
+}
+
+const xcb_format_t *QXcbConnection::formatForDepth(uint8_t depth) const
+{
+ xcb_format_iterator_t iterator =
+ xcb_setup_pixmap_formats_iterator(m_setup);
+
+ while (iterator.rem) {
+ xcb_format_t *format = iterator.data;
+ if (format->depth == depth)
+ return format;
+ xcb_format_next(&iterator);
+ }
+
+ return 0;
}
void QXcbConnection::sync()
@@ -670,6 +937,43 @@ void QXcbConnection::sync()
free(xcb_get_input_focus_reply(xcb_connection(), cookie, 0));
}
+void QXcbConnection::initializeXFixes()
+{
+ xcb_generic_error_t *error = 0;
+ const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xfixes_id);
+ xfixes_first_event = reply->first_event;
+
+ xcb_xfixes_query_version_cookie_t xfixes_query_cookie = xcb_xfixes_query_version(m_connection,
+ XCB_XFIXES_MAJOR_VERSION,
+ XCB_XFIXES_MINOR_VERSION);
+ xcb_xfixes_query_version_reply_t *xfixes_query = xcb_xfixes_query_version_reply (m_connection,
+ xfixes_query_cookie, &error);
+ if (!xfixes_query || error || xfixes_query->major_version < 2) {
+ qWarning("Failed to initialize XFixes");
+ free(error);
+ xfixes_first_event = 0;
+ }
+ free(xfixes_query);
+
+}
+
+void QXcbConnection::initializeXRender()
+{
+#ifdef XCB_USE_RENDER
+ xcb_generic_error_t *error = 0;
+ xcb_render_query_version_cookie_t xrender_query_cookie = xcb_render_query_version(m_connection,
+ XCB_RENDER_MAJOR_VERSION,
+ XCB_RENDER_MINOR_VERSION);
+ xcb_render_query_version_reply_t *xrender_query = xcb_render_query_version_reply(m_connection,
+ xrender_query_cookie, &error);
+ if (!xrender_query || error || (xrender_query->major_version == 0 && xrender_query->minor_version < 5)) {
+ qWarning("Failed to initialize XRender");
+ free(error);
+ }
+ free(xrender_query);
+#endif
+}
+
#if defined(XCB_USE_EGL)
bool QXcbConnection::hasEgl() const
{
@@ -740,26 +1044,12 @@ bool QXcbConnection::hasSupportForDri2() const
if (!m_dri2_support_probed) {
xcb_generic_error_t *error = 0;
- xcb_prefetch_extension_data (m_connection, &xcb_xfixes_id);
xcb_prefetch_extension_data (m_connection, &xcb_dri2_id);
- xcb_xfixes_query_version_cookie_t xfixes_query_cookie = xcb_xfixes_query_version(m_connection,
- XCB_XFIXES_MAJOR_VERSION,
- XCB_XFIXES_MINOR_VERSION);
-
xcb_dri2_query_version_cookie_t dri2_query_cookie = xcb_dri2_query_version (m_connection,
XCB_DRI2_MAJOR_VERSION,
XCB_DRI2_MINOR_VERSION);
- xcb_xfixes_query_version_reply_t *xfixes_query = xcb_xfixes_query_version_reply (m_connection,
- xfixes_query_cookie, &error);
- if (!xfixes_query || error || xfixes_query->major_version < 2) {
- delete error;
- delete xfixes_query;
- return false;
- }
- delete xfixes_query;
-
xcb_dri2_query_version_reply_t *dri2_query = xcb_dri2_query_version_reply (m_connection,
dri2_query_cookie, &error);
if (!dri2_query || error) {
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 01bc719546..6d93093072 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -44,13 +44,23 @@
#include <xcb/xcb.h>
+#include <QHash>
#include <QList>
+#include <QMutex>
#include <QObject>
+#include <QThread>
#include <QVector>
#define Q_XCB_DEBUG
class QXcbScreen;
+class QXcbWindow;
+class QXcbDrag;
+class QXcbKeyboard;
+class QXcbClipboard;
+class QXcbWMSupport;
+
+typedef QHash<xcb_window_t, QXcbWindow *> WindowMapper;
namespace QXcbAtom {
enum Atom {
@@ -92,6 +102,9 @@ namespace QXcbAtom {
_QT_SCROLL_DONE,
_QT_INPUT_ENCODING,
+ // Qt/XCB specific
+ _QT_CLOSE_CONNECTION,
+
_MOTIF_WM_HINTS,
DTWM_IS_RUNNING,
@@ -160,7 +173,6 @@ namespace QXcbAtom {
_NET_ACTIVE_WINDOW,
// Property formats
- COMPOUND_TEXT,
TEXT,
UTF8_STRING,
@@ -215,8 +227,34 @@ namespace QXcbAtom {
};
}
-class QXcbKeyboard;
+class QXcbEventReader : public QThread
+{
+ Q_OBJECT
+public:
+ QXcbEventReader(xcb_connection_t *connection)
+ : m_connection(connection)
+ {
+ }
+
+#ifdef XCB_POLL_FOR_QUEUED_EVENT
+ void run();
+#endif
+ QList<xcb_generic_event_t *> *lock();
+ void unlock();
+
+signals:
+ void eventPending();
+
+private:
+ void addEvent(xcb_generic_event_t *event);
+
+ QMutex m_mutex;
+ QList<xcb_generic_event_t *> m_events;
+ xcb_connection_t *m_connection;
+};
+
+class QAbstractEventDispatcher;
class QXcbConnection : public QObject
{
Q_OBJECT
@@ -226,17 +264,26 @@ public:
QXcbConnection *connection() const { return const_cast<QXcbConnection *>(this); }
- QList<QXcbScreen *> screens() const { return m_screens; }
+ const QList<QXcbScreen *> &screens() const { return m_screens; }
int primaryScreen() const { return m_primaryScreen; }
xcb_atom_t atom(QXcbAtom::Atom atom);
+ xcb_atom_t internAtom(const char *name);
+ QByteArray atomName(xcb_atom_t atom);
const char *displayName() const { return m_displayName.constData(); }
xcb_connection_t *xcb_connection() const { return m_connection; }
+ const xcb_setup_t *setup() const { return m_setup; }
+ const xcb_format_t *formatForDepth(uint8_t depth) const;
QXcbKeyboard *keyboard() const { return m_keyboard; }
+ QXcbClipboard *clipboard() const { return m_clipboard; }
+ QXcbDrag *drag() const { return m_drag; }
+
+ QXcbWMSupport *wmSupport() const { return m_wmSupport; }
+
#ifdef XCB_USE_XLIB
void *xlib_display() const { return m_xlib_display; }
#endif
@@ -253,7 +300,26 @@ public:
#endif
void sync();
+ void flush() { xcb_flush(m_connection); }
+
void handleXcbError(xcb_generic_error_t *error);
+ void handleXcbEvent(xcb_generic_event_t *event);
+
+ void addWindow(xcb_window_t id, QXcbWindow *window);
+ void removeWindow(xcb_window_t id);
+ QXcbWindow *platformWindowFromId(xcb_window_t id);
+
+ xcb_generic_event_t *checkEvent(int type);
+ template<typename T>
+ inline xcb_generic_event_t *checkEvent(const T &checker);
+
+ typedef bool (*PeekFunc)(xcb_generic_event_t *);
+ void addPeekFunc(PeekFunc f);
+
+ inline xcb_timestamp_t time() const { return m_time; }
+ inline void setTime(xcb_timestamp_t t) { if (t > m_time) m_time = t; }
+
+ bool hasXFixes() const { return xfixes_first_event > 0; }
private slots:
void processXcbEvents();
@@ -261,9 +327,12 @@ private slots:
private:
void initializeAllAtoms();
void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0);
+ void initializeXFixes();
+ void initializeXRender();
#ifdef XCB_USE_DRI2
void initializeDri2();
#endif
+ void handleClientMessageEvent(const xcb_client_message_event_t *event);
xcb_connection_t *m_connection;
const xcb_setup_t *m_setup;
@@ -273,14 +342,21 @@ private:
xcb_atom_t m_allAtoms[QXcbAtom::NAtoms];
+ xcb_timestamp_t m_time;
+
QByteArray m_displayName;
+ xcb_window_t m_connectionEventListener;
+
QXcbKeyboard *m_keyboard;
+ QXcbClipboard *m_clipboard;
+ QXcbDrag *m_drag;
+ QXcbWMSupport *m_wmSupport;
#if defined(XCB_USE_XLIB)
void *m_xlib_display;
#endif
-
+ QXcbEventReader *m_reader;
#ifdef XCB_USE_DRI2
uint32_t m_dri2_major;
uint32_t m_dri2_minor;
@@ -299,14 +375,39 @@ private:
int line;
};
QVector<CallInfo> m_callLog;
+ QMutex m_callLogMutex;
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
+
+ WindowMapper m_mapper;
+
+ QVector<PeekFunc> m_peekFuncs;
+
+ uint32_t xfixes_first_event;
};
#define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display()))
+template<typename T>
+xcb_generic_event_t *QXcbConnection::checkEvent(const T &checker)
+{
+ QList<xcb_generic_event_t *> *eventqueue = m_reader->lock();
+
+ for (int i = 0; i < eventqueue->size(); ++i) {
+ xcb_generic_event_t *event = eventqueue->at(i);
+ if (checker.check(event)) {
+ (*eventqueue)[i] = 0;
+ m_reader->unlock();
+ return event;
+ }
+ }
+ m_reader->unlock();
+ return 0;
+}
+
+
#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)
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
new file mode 100644
index 0000000000..f6856d5694
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -0,0 +1,546 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qxcbcursor.h"
+#include "qxcbconnection.h"
+#include "qxcbwindow.h"
+#include "qxcbimage.h"
+#include <QtCore/QLibrary>
+#include <QtGui/QWindow>
+#include <QtGui/QBitmap>
+#include <QtGui/private/qguiapplication_p.h>
+#include <X11/cursorfont.h>
+#include <xcb/xfixes.h>
+#include <xcb/xcb_image.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef int (*PtrXcursorLibraryLoadCursor)(void *, const char *);
+static PtrXcursorLibraryLoadCursor ptrXcursorLibraryLoadCursor = 0;
+static xcb_font_t cursorFont = 0;
+static int cursorCount = 0;
+
+static uint8_t cur_blank_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const uint8_t cur_ver_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xf0, 0x0f,
+ 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00 };
+static const uint8_t mcur_ver_bits[] = {
+ 0x00, 0x00, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f,
+ 0xfc, 0x7f, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xfc, 0x7f, 0xf8, 0x3f,
+ 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03 };
+static const uint8_t cur_hor_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x30, 0x18,
+ 0x38, 0x38, 0xfc, 0x7f, 0xfc, 0x7f, 0x38, 0x38, 0x30, 0x18, 0x20, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const uint8_t mcur_hor_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x60, 0x0c, 0x70, 0x1c, 0x78, 0x3c,
+ 0xfc, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0x7f, 0x78, 0x3c,
+ 0x70, 0x1c, 0x60, 0x0c, 0x40, 0x04, 0x00, 0x00 };
+static const uint8_t cur_bdiag_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x3e,
+ 0x00, 0x37, 0x88, 0x23, 0xd8, 0x01, 0xf8, 0x00, 0x78, 0x00, 0xf8, 0x00,
+ 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const uint8_t mcur_bdiag_bits[] = {
+ 0x00, 0x00, 0xc0, 0x7f, 0x80, 0x7f, 0x00, 0x7f, 0x00, 0x7e, 0x04, 0x7f,
+ 0x8c, 0x7f, 0xdc, 0x77, 0xfc, 0x63, 0xfc, 0x41, 0xfc, 0x00, 0xfc, 0x01,
+ 0xfc, 0x03, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00 };
+static const uint8_t cur_fdiag_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0xf8, 0x00, 0x78, 0x00,
+ 0xf8, 0x00, 0xd8, 0x01, 0x88, 0x23, 0x00, 0x37, 0x00, 0x3e, 0x00, 0x3c,
+ 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00 };
+static const uint8_t mcur_fdiag_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xfc, 0x03, 0xfc, 0x01, 0xfc, 0x00,
+ 0xfc, 0x41, 0xfc, 0x63, 0xdc, 0x77, 0x8c, 0x7f, 0x04, 0x7f, 0x00, 0x7e,
+ 0x00, 0x7f, 0x80, 0x7f, 0xc0, 0x7f, 0x00, 0x00 };
+static const uint8_t *cursor_bits16[] = {
+ cur_ver_bits, mcur_ver_bits, cur_hor_bits, mcur_hor_bits,
+ cur_bdiag_bits, mcur_bdiag_bits, cur_fdiag_bits, mcur_fdiag_bits,
+ 0, 0, cur_blank_bits, cur_blank_bits };
+
+static const uint8_t vsplit_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const uint8_t vsplitm_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00,
+ 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
+ 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
+ 0x80, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00,
+ 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const uint8_t hsplit_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x41, 0x82, 0x00, 0x80, 0x41, 0x82, 0x01, 0xc0, 0x7f, 0xfe, 0x03,
+ 0x80, 0x41, 0x82, 0x01, 0x00, 0x41, 0x82, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const uint8_t hsplitm_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe3, 0xc7, 0x00,
+ 0x80, 0xe3, 0xc7, 0x01, 0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07,
+ 0xc0, 0xff, 0xff, 0x03, 0x80, 0xe3, 0xc7, 0x01, 0x00, 0xe3, 0xc7, 0x00,
+ 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const uint8_t whatsthis_bits[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0xf0, 0x07, 0x00,
+ 0x09, 0x18, 0x0e, 0x00, 0x11, 0x1c, 0x0e, 0x00, 0x21, 0x1c, 0x0e, 0x00,
+ 0x41, 0x1c, 0x0e, 0x00, 0x81, 0x1c, 0x0e, 0x00, 0x01, 0x01, 0x07, 0x00,
+ 0x01, 0x82, 0x03, 0x00, 0xc1, 0xc7, 0x01, 0x00, 0x49, 0xc0, 0x01, 0x00,
+ 0x95, 0xc0, 0x01, 0x00, 0x93, 0xc0, 0x01, 0x00, 0x21, 0x01, 0x00, 0x00,
+ 0x20, 0xc1, 0x01, 0x00, 0x40, 0xc2, 0x01, 0x00, 0x40, 0x02, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+static const uint8_t whatsthism_bits[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x07, 0x00, 0x07, 0xf8, 0x0f, 0x00,
+ 0x0f, 0xfc, 0x1f, 0x00, 0x1f, 0x3e, 0x1f, 0x00, 0x3f, 0x3e, 0x1f, 0x00,
+ 0x7f, 0x3e, 0x1f, 0x00, 0xff, 0x3e, 0x1f, 0x00, 0xff, 0x9d, 0x0f, 0x00,
+ 0xff, 0xc3, 0x07, 0x00, 0xff, 0xe7, 0x03, 0x00, 0x7f, 0xe0, 0x03, 0x00,
+ 0xf7, 0xe0, 0x03, 0x00, 0xf3, 0xe0, 0x03, 0x00, 0xe1, 0xe1, 0x03, 0x00,
+ 0xe0, 0xe1, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+static const uint8_t busy_bits[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
+ 0x41, 0xe0, 0xff, 0x00, 0x81, 0x20, 0x80, 0x00, 0x01, 0xe1, 0xff, 0x00,
+ 0x01, 0x42, 0x40, 0x00, 0xc1, 0x47, 0x40, 0x00, 0x49, 0x40, 0x55, 0x00,
+ 0x95, 0x80, 0x2a, 0x00, 0x93, 0x00, 0x15, 0x00, 0x21, 0x01, 0x0a, 0x00,
+ 0x20, 0x01, 0x11, 0x00, 0x40, 0x82, 0x20, 0x00, 0x40, 0x42, 0x44, 0x00,
+ 0x80, 0x41, 0x4a, 0x00, 0x00, 0x40, 0x55, 0x00, 0x00, 0xe0, 0xff, 0x00,
+ 0x00, 0x20, 0x80, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static const uint8_t busym_bits[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
+ 0x7f, 0xe0, 0xff, 0x00, 0xff, 0xe0, 0xff, 0x00, 0xff, 0xe1, 0xff, 0x00,
+ 0xff, 0xc3, 0x7f, 0x00, 0xff, 0xc7, 0x7f, 0x00, 0x7f, 0xc0, 0x7f, 0x00,
+ 0xf7, 0x80, 0x3f, 0x00, 0xf3, 0x00, 0x1f, 0x00, 0xe1, 0x01, 0x0e, 0x00,
+ 0xe0, 0x01, 0x1f, 0x00, 0xc0, 0x83, 0x3f, 0x00, 0xc0, 0xc3, 0x7f, 0x00,
+ 0x80, 0xc1, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0xff, 0x00,
+ 0x00, 0xe0, 0xff, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const uint8_t * const cursor_bits32[] = {
+ vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits,
+ 0, 0, 0, 0, whatsthis_bits, whatsthism_bits, busy_bits, busym_bits
+};
+
+static const uint8_t forbidden_bits[] = {
+ 0x00,0x00,0x00,0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xf0,0x00,0x38,0xc0,0x01,
+ 0x7c,0x80,0x03,0xec,0x00,0x03,0xce,0x01,0x07,0x86,0x03,0x06,0x06,0x07,0x06,
+ 0x06,0x0e,0x06,0x06,0x1c,0x06,0x0e,0x38,0x07,0x0c,0x70,0x03,0x1c,0xe0,0x03,
+ 0x38,0xc0,0x01,0xf0,0xe0,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00,0x00,0x00,0x00 };
+
+static const uint8_t forbiddenm_bits[] = {
+ 0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xff,0x00,0xf8,0xff,0x01,0xfc,0xf0,0x03,
+ 0xfe,0xc0,0x07,0xfe,0x81,0x07,0xff,0x83,0x0f,0xcf,0x07,0x0f,0x8f,0x0f,0x0f,
+ 0x0f,0x1f,0x0f,0x0f,0x3e,0x0f,0x1f,0xfc,0x0f,0x1e,0xf8,0x07,0x3e,0xf0,0x07,
+ 0xfc,0xe0,0x03,0xf8,0xff,0x01,0xf0,0xff,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00};
+
+static const uint8_t openhand_bits[] = {
+ 0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92,
+ 0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20,
+ 0x08,0x20,0x10,0x10,0x20,0x10,0x00,0x00};
+static const uint8_t openhandm_bits[] = {
+ 0x80,0x01,0xd8,0x0f,0xfc,0x1f,0xfc,0x5f,0xf8,0xff,0xf8,0xff,
+ 0xf6,0xff,0xff,0xff,0xff,0x7f,0xfe,0x7f,0xfc,0x7f,0xfc,0x3f,
+ 0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0x00,0x00};
+static const uint8_t closedhand_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0x48,0x32,0x08,0x50,
+ 0x10,0x40,0x18,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10,
+ 0x20,0x10,0x20,0x10,0x00,0x00,0x00,0x00};
+static const uint8_t closedhandm_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0xf8,0x3f,0xf8,0x7f,
+ 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f,
+ 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00};
+
+static const uint8_t * const cursor_bits20[] = {
+ forbidden_bits, forbiddenm_bits
+};
+
+static const char * const cursorNames[] = {
+ "left_ptr",
+ "up_arrow",
+ "cross",
+ "wait",
+ "ibeam",
+ "size_ver",
+ "size_hor",
+ "size_bdiag",
+ "size_fdiag",
+ "size_all",
+ "blank",
+ "split_v",
+ "split_h",
+ "pointing_hand",
+ "forbidden",
+ "whats_this",
+ "left_ptr_watch",
+ "openhand",
+ "closedhand",
+ "copy",
+ "move",
+ "link"
+};
+
+QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen)
+ : QXcbObject(conn), QPlatformCursor(screen), m_screen(screen)
+{
+ if (cursorCount++)
+ return;
+
+ cursorFont = xcb_generate_id(xcb_connection());
+ const char *cursorStr = "cursor";
+ xcb_open_font(xcb_connection(), cursorFont, strlen(cursorStr), cursorStr);
+
+#ifdef XCB_USE_XLIB
+ QLibrary xcursorLib(QLatin1String("Xcursor"), 1);
+ bool xcursorFound = xcursorLib.load();
+ if (!xcursorFound) { // try without the version number
+ xcursorLib.setFileName(QLatin1String("Xcursor"));
+ xcursorFound = xcursorLib.load();
+ }
+ if (xcursorFound)
+ ptrXcursorLibraryLoadCursor =
+ (PtrXcursorLibraryLoadCursor) xcursorLib.resolve("XcursorLibraryLoadCursor");
+#endif
+}
+
+QXcbCursor::~QXcbCursor()
+{
+ if (!--cursorCount)
+ xcb_close_font(xcb_connection(), cursorFont);
+}
+
+void QXcbCursor::changeCursor(QCursor *cursor, QWindow *widget)
+{
+ QXcbWindow *w = 0;
+ if (widget && widget->handle())
+ w = static_cast<QXcbWindow *>(widget->handle());
+ else
+ // No X11 cursor control when there is no widget under the cursor
+ return;
+
+ xcb_cursor_t c;
+ if (cursor->shape() == Qt::BitmapCursor) {
+ qint64 id = cursor->pixmap().cacheKey();
+ if (!m_bitmapCursorMap.contains(id))
+ m_bitmapCursorMap.insert(id, createBitmapCursor(cursor));
+ c = m_bitmapCursorMap.value(id);
+ } else {
+ int id = cursor->handle();
+ if (!m_shapeCursorMap.contains(id))
+ m_shapeCursorMap.insert(id, createFontCursor(cursor->shape()));
+ c = m_shapeCursorMap.value(id);
+ }
+
+ w->setCursor(c);
+}
+
+static int cursorIdForShape(int cshape)
+{
+ int cursorId = 0;
+ switch (cshape) {
+ case Qt::ArrowCursor:
+ cursorId = XC_left_ptr;
+ break;
+ case Qt::UpArrowCursor:
+ cursorId = XC_center_ptr;
+ break;
+ case Qt::CrossCursor:
+ cursorId = XC_crosshair;
+ break;
+ case Qt::WaitCursor:
+ cursorId = XC_watch;
+ break;
+ case Qt::IBeamCursor:
+ cursorId = XC_xterm;
+ break;
+ case Qt::SizeAllCursor:
+ cursorId = XC_fleur;
+ break;
+ case Qt::PointingHandCursor:
+ cursorId = XC_hand2;
+ break;
+ case Qt::SizeBDiagCursor:
+ cursorId = XC_top_right_corner;
+ break;
+ case Qt::SizeFDiagCursor:
+ cursorId = XC_bottom_right_corner;
+ break;
+ case Qt::SizeVerCursor:
+ case Qt::SplitVCursor:
+ cursorId = XC_sb_v_double_arrow;
+ break;
+ case Qt::SizeHorCursor:
+ case Qt::SplitHCursor:
+ cursorId = XC_sb_h_double_arrow;
+ break;
+ case Qt::WhatsThisCursor:
+ cursorId = XC_question_arrow;
+ break;
+ case Qt::ForbiddenCursor:
+ cursorId = XC_circle;
+ break;
+ case Qt::BusyCursor:
+ cursorId = XC_watch;
+ break;
+ default:
+ break;
+ }
+ return cursorId;
+}
+
+xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape)
+{
+ xcb_cursor_t cursor = 0;
+ xcb_connection_t *conn = xcb_connection();
+
+ if (cshape == Qt::BlankCursor) {
+ xcb_pixmap_t cp = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits, 16, 16,
+ 1, 0, 0, 0);
+ xcb_pixmap_t mp = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits, 16, 16,
+ 1, 0, 0, 0);
+ cursor = xcb_generate_id(conn);
+ xcb_create_cursor(conn, cursor, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8);
+ } else if (cshape >= Qt::SizeVerCursor && cshape < Qt::SizeAllCursor) {
+ int i = (cshape - Qt::SizeVerCursor) * 2;
+ xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
+ const_cast<uint8_t*>(cursor_bits16[i]),
+ 16, 16, 1, 0, 0, 0);
+ xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
+ const_cast<uint8_t*>(cursor_bits16[i + 1]),
+ 16, 16, 1, 0, 0, 0);
+ cursor = xcb_generate_id(conn);
+ xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8);
+ } else if ((cshape >= Qt::SplitVCursor && cshape <= Qt::SplitHCursor)
+ || cshape == Qt::WhatsThisCursor || cshape == Qt::BusyCursor) {
+ int i = (cshape - Qt::SplitVCursor) * 2;
+ xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
+ const_cast<uint8_t*>(cursor_bits32[i]),
+ 32, 32, 1, 0, 0, 0);
+ xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
+ const_cast<uint8_t*>(cursor_bits32[i + 1]),
+ 32, 32, 1, 0, 0, 0);
+ int hs = (cshape == Qt::PointingHandCursor || cshape == Qt::WhatsThisCursor
+ || cshape == Qt::BusyCursor) ? 0 : 16;
+ cursor = xcb_generate_id(conn);
+ xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, hs, hs);
+ } else if (cshape == Qt::ForbiddenCursor) {
+ int i = (cshape - Qt::ForbiddenCursor) * 2;
+ xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
+ const_cast<uint8_t*>(cursor_bits20[i]),
+ 20, 20, 1, 0, 0, 0);
+ xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
+ const_cast<uint8_t*>(cursor_bits20[i + 1]),
+ 20, 20, 1, 0, 0, 0);
+ cursor = xcb_generate_id(conn);
+ xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 10, 10);
+ } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) {
+ bool open = cshape == Qt::OpenHandCursor;
+ xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
+ const_cast<uint8_t*>(open ? openhand_bits : closedhand_bits),
+ 16, 16, 1, 0, 0, 0);
+ xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
+ const_cast<uint8_t*>(open ? openhandm_bits : closedhandm_bits),
+ 16, 16, 1, 0, 0, 0);
+ cursor = xcb_generate_id(conn);
+ xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8);
+ } else if (cshape == Qt::DragCopyCursor || cshape == Qt::DragMoveCursor
+ || cshape == Qt::DragLinkCursor) {
+ QImage image = QGuiApplicationPrivate::instance()->getPixmapCursor(static_cast<Qt::CursorShape>(cshape)).toImage();
+ xcb_pixmap_t pm = qt_xcb_XPixmapFromBitmap(m_screen, image);
+ xcb_pixmap_t pmm = qt_xcb_XPixmapFromBitmap(m_screen, image.createAlphaMask());
+ cursor = xcb_generate_id(conn);
+ xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8);
+ }
+
+ return cursor;
+}
+
+xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
+{
+ xcb_connection_t *conn = xcb_connection();
+ int cursorId = cursorIdForShape(cshape);
+ xcb_cursor_t cursor = XCB_NONE;
+
+ // Try Xcursor first
+#ifdef XCB_USE_XLIB
+ if (ptrXcursorLibraryLoadCursor && cshape >= 0 && cshape < Qt::LastCursor) {
+ void *dpy = connection()->xlib_display();
+ // special case for non-standard dnd-* cursors
+ switch (cshape) {
+ case Qt::DragCopyCursor:
+ cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-copy");
+ break;
+ case Qt::DragMoveCursor:
+ cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-move");
+ break;
+ case Qt::DragLinkCursor:
+ cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-link");
+ break;
+ default:
+ break;
+ }
+ if (!cursor)
+ cursor = ptrXcursorLibraryLoadCursor(dpy, cursorNames[cshape]);
+ }
+ if (cursor)
+ return cursor;
+#endif
+
+ // Non-standard X11 cursors are created from bitmaps
+ cursor = createNonStandardCursor(cshape);
+
+ // Create a glpyh cursor if everything else failed
+ if (!cursor && cursorId) {
+ cursor = xcb_generate_id(conn);
+ xcb_create_glyph_cursor(conn, cursor, cursorFont, cursorFont,
+ cursorId, cursorId + 1,
+ 0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0);
+ }
+
+ if (cursor && cshape >= 0 && cshape < Qt::LastCursor) {
+ const char *name = cursorNames[cshape];
+ xcb_xfixes_set_cursor_name(conn, cursor, strlen(name), name);
+ }
+
+ return cursor;
+}
+
+xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor)
+{
+ xcb_connection_t *conn = xcb_connection();
+ QPoint spot = cursor->hotSpot();
+ xcb_cursor_t c = XCB_NONE;
+ if (cursor->pixmap().depth() > 1)
+ c = qt_xcb_createCursorXRender(m_screen, cursor->pixmap().toImage(), spot);
+ if (!c) {
+ xcb_pixmap_t cp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap()->toImage());
+ xcb_pixmap_t mp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask()->toImage());
+ c = xcb_generate_id(conn);
+ xcb_create_cursor(conn, c, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF,
+ spot.x(), spot.y());
+ xcb_free_pixmap(conn, cp);
+ xcb_free_pixmap(conn, mp);
+ }
+ return c;
+}
+
+static void getPosAndRoot(xcb_connection_t *conn, xcb_window_t *rootWin, QPoint *pos)
+{
+ if (pos)
+ *pos = QPoint();
+ xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(conn));
+ while (it.rem) {
+ xcb_window_t root = it.data->root;
+ xcb_query_pointer_cookie_t cookie = xcb_query_pointer(conn, root);
+ xcb_generic_error_t *err = 0;
+ xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(conn, cookie, &err);
+ if (!err && reply) {
+ if (pos)
+ *pos = QPoint(reply->root_x, reply->root_y);
+ if (rootWin)
+ *rootWin = root;
+ free(reply);
+ return;
+ }
+ free(err);
+ free(reply);
+ xcb_screen_next(&it);
+ }
+}
+
+QPoint QXcbCursor::pos() const
+{
+ QPoint p;
+ getPosAndRoot(xcb_connection(), 0, &p);
+ return p;
+}
+
+void QXcbCursor::setPos(const QPoint &pos)
+{
+ xcb_connection_t *conn = xcb_connection();
+ xcb_window_t root;
+ getPosAndRoot(conn, &root, 0);
+ xcb_warp_pointer(conn, XCB_NONE, root, 0, 0, 0, 0, pos.x(), pos.y());
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbcursor.h b/src/plugins/platforms/xcb/qxcbcursor.h
new file mode 100644
index 0000000000..4bbb9a928b
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbcursor.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QXCBCURSOR_H
+#define QXCBCURSOR_H
+
+#include <QtGui/QPlatformCursor>
+#include "qxcbscreen.h"
+
+QT_BEGIN_NAMESPACE
+
+class QXcbCursor : public QXcbObject, public QPlatformCursor
+{
+public:
+ QXcbCursor(QXcbConnection *conn, QXcbScreen *screen);
+ ~QXcbCursor();
+ void changeCursor(QCursor *cursor, QWindow *widget);
+ QPoint pos() const;
+ void setPos(const QPoint &pos);
+
+private:
+ xcb_cursor_t createFontCursor(int cshape);
+ xcb_cursor_t createBitmapCursor(QCursor *cursor);
+ xcb_cursor_t createNonStandardCursor(int cshape);
+
+ QXcbScreen *m_screen;
+ QMap<int, xcb_cursor_t> m_shapeCursorMap;
+ QMap<qint64, xcb_cursor_t> m_bitmapCursorMap;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
new file mode 100644
index 0000000000..8a6fd29986
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -0,0 +1,1332 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qxcbdrag.h"
+#include <xcb/xcb.h>
+#include "qxcbconnection.h"
+#include "qxcbclipboard.h"
+#include "qxcbmime.h"
+#include "qxcbwindow.h"
+#include "qxcbscreen.h"
+#include "qwindow.h"
+#include <private/qdnd_p.h>
+#include <qdebug.h>
+#include <qevent.h>
+#include <qguiapplication.h>
+#include <qrect.h>
+
+QT_BEGIN_NAMESPACE
+
+//#define DND_DEBUG
+#ifdef DND_DEBUG
+#define DEBUG qDebug
+#else
+#define DEBUG if(0) qDebug
+#endif
+
+#ifdef DND_DEBUG
+#define DNDDEBUG qDebug()
+#else
+#define DNDDEBUG if(0) qDebug()
+#endif
+
+const int xdnd_version = 5;
+
+static inline xcb_window_t xcb_window(QWindow *w)
+{
+ return static_cast<QXcbWindow *>(w->handle())->xcb_window();
+}
+
+
+static xcb_window_t xdndProxy(QXcbConnection *c, xcb_window_t w)
+{
+ xcb_window_t proxy = XCB_NONE;
+
+ xcb_get_property_cookie_t cookie = Q_XCB_CALL2(xcb_get_property(c->xcb_connection(), false, w, c->atom(QXcbAtom::XdndProxy),
+ XCB_ATOM_WINDOW, 0, 1), c);
+ xcb_get_property_reply_t *reply = xcb_get_property_reply(c->xcb_connection(), cookie, 0);
+
+ if (reply && reply->type == XCB_ATOM_WINDOW)
+ proxy = *((xcb_window_t *)xcb_get_property_value(reply));
+ free(reply);
+
+ if (proxy == XCB_NONE)
+ return proxy;
+
+ // exists and is real?
+ cookie = Q_XCB_CALL2(xcb_get_property(c->xcb_connection(), false, proxy, c->atom(QXcbAtom::XdndProxy),
+ XCB_ATOM_WINDOW, 0, 1), c);
+ reply = xcb_get_property_reply(c->xcb_connection(), cookie, 0);
+
+ if (reply && reply->type == XCB_ATOM_WINDOW) {
+ xcb_window_t p = *((xcb_window_t *)xcb_get_property_value(reply));
+ if (proxy != p)
+ proxy = 0;
+ } else {
+ proxy = 0;
+ }
+
+ free(reply);
+
+ return proxy;
+}
+
+
+class QDropData : public QXcbMime
+{
+public:
+ QDropData(QXcbDrag *d);
+ ~QDropData();
+
+protected:
+ bool hasFormat_sys(const QString &mimeType) const;
+ QStringList formats_sys() const;
+ QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const;
+
+ QVariant xdndObtainData(const QByteArray &format, QVariant::Type requestedType) const;
+
+ QXcbDrag *drag;
+};
+
+
+QXcbDrag::QXcbDrag(QXcbConnection *c)
+ : QXcbObject(c)
+{
+ dropData = new QDropData(this);
+
+ init();
+ heartbeat = -1;
+
+ transaction_expiry_timer = -1;
+}
+
+QXcbDrag::~QXcbDrag()
+{
+ delete dropData;
+}
+
+void QXcbDrag::init()
+{
+ currentWindow.clear();
+
+ xdnd_dragsource = XCB_NONE;
+ last_target_accepted_action = Qt::IgnoreAction;
+
+ waiting_for_status = false;
+ current_target = XCB_NONE;
+ current_proxy_target = XCB_NONE;
+ xdnd_dragging = false;
+
+ source_time = XCB_CURRENT_TIME;
+ target_time = XCB_CURRENT_TIME;
+
+ current_screen = 0;
+ drag_types.clear();
+}
+
+QMimeData *QXcbDrag::platformDropData()
+{
+ return dropData;
+}
+
+void QXcbDrag::startDrag()
+{
+ init();
+
+ heartbeat = startTimer(200);
+ xdnd_dragging = true;
+
+ xcb_set_selection_owner(xcb_connection(), connection()->clipboard()->owner(),
+ atom(QXcbAtom::XdndSelection), connection()->time());
+
+ QDragManager *manager = QDragManager::self();
+ QStringList fmts = QXcbMime::formatsHelper(manager->dropData());
+ for (int i = 0; i < fmts.size(); ++i) {
+ QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), fmts.at(i));
+ for (int j = 0; j < atoms.size(); ++j) {
+ if (!drag_types.contains(atoms.at(j)))
+ drag_types.append(atoms.at(j));
+ }
+ }
+ if (drag_types.size() > 3)
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, connection()->clipboard()->owner(),
+ atom(QXcbAtom::XdndTypelist),
+ XCB_ATOM_ATOM, 32, drag_types.size(), (const void *)drag_types.constData());
+
+ QPointF pos = QCursor::pos();
+ QMouseEvent me(QEvent::MouseMove, pos, pos, pos, Qt::LeftButton,
+ QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+ move(&me);
+
+// if (!QWidget::mouseGrabber())
+// manager->shapedPixmapWindow->grabMouse();
+}
+
+void QXcbDrag::endDrag()
+{
+ Q_ASSERT(heartbeat != -1);
+ killTimer(heartbeat);
+ heartbeat = -1;
+
+ xdnd_dragging = false;
+}
+
+static xcb_translate_coordinates_reply_t *
+translateCoordinates(QXcbConnection *c, xcb_window_t from, xcb_window_t to, int x, int y)
+{
+ xcb_translate_coordinates_cookie_t cookie =
+ xcb_translate_coordinates(c->xcb_connection(), from, to, x, y);
+ return xcb_translate_coordinates_reply(c->xcb_connection(), cookie, 0);
+}
+
+void QXcbDrag::move(const QMouseEvent *me)
+{
+ DEBUG() << "QDragManager::move enter";
+
+ // ###
+ QPoint globalPos = me->globalPos();
+
+ if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid())
+ return;
+
+ const QList<QXcbScreen *> &screens = connection()->screens();
+ QXcbScreen *screen = screens.at(connection()->primaryScreen());
+ for (int i = 0; i < screens.size(); ++i) {
+ if (screens.at(i)->geometry().contains(globalPos)) {
+ screen = screens.at(i);
+ break;
+ }
+ }
+ if (screen != current_screen) {
+ // ### need to recreate the shaped pixmap window?
+// int screen = QCursor::x11Screen();
+// if ((qt_xdnd_current_screen == -1 && screen != X11->defaultScreen) || (screen != qt_xdnd_current_screen)) {
+// // recreate the pixmap on the new screen...
+// delete xdnd_data.deco;
+// QWidget* parent = object->source()->window()->x11Info().screen() == screen
+// ? object->source()->window() : QApplication::desktop()->screen(screen);
+// xdnd_data.deco = new QShapedPixmapWidget(parent);
+// if (!QWidget::mouseGrabber()) {
+// updatePixmap();
+// xdnd_data.deco->grabMouse();
+// }
+// }
+// xdnd_data.deco->move(QCursor::pos() - xdnd_data.deco->pm_hot);
+ current_screen = screen;
+ }
+
+
+// qt_xdnd_current_screen = screen;
+ xcb_window_t rootwin = current_screen->root();
+ xcb_translate_coordinates_reply_t *translate =
+ ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x(), globalPos.y());
+ if (!translate)
+ return;
+ xcb_window_t target = translate->child;
+ int lx = translate->dst_x;
+ int ly = translate->dst_y;
+ free (translate);
+
+ if (target == rootwin) {
+ // Ok.
+ } else if (target) {
+ //me
+ xcb_window_t src = rootwin;
+ while (target != 0) {
+ DNDDEBUG << "checking target for XdndAware" << target;
+
+ // translate coordinates
+ translate = ::translateCoordinates(connection(), src, target, lx, ly);
+ if (!translate) {
+ target = 0;
+ break;
+ }
+ lx = translate->dst_x;
+ ly = translate->dst_y;
+ src = translate->child;
+ free(translate);
+
+ // check if it has XdndAware
+ xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(xcb_connection(), false, target,
+ atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0));
+ xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0);
+ bool aware = reply && reply->type != XCB_NONE;
+ free(reply);
+ if (aware) {
+ DNDDEBUG << "Found XdndAware on " << target;
+ break;
+ }
+
+ // find child at the coordinates
+ translate = ::translateCoordinates(connection(), src, src, lx, ly);
+ if (!translate) {
+ target = 0;
+ break;
+ }
+ target = translate->child;
+ free(translate);
+ }
+ // ####
+// if (xdnd_data.deco && (!target || target == xdnd_data.deco->effectiveWinId())) {
+// DNDDEBUG << "need to find real window";
+// target = findRealWindow(globalPos, rootwin, 6);
+// DNDDEBUG << "real window found" << QWidget::find(target) << target;
+// }
+ }
+
+ QXcbWindow *w = 0;
+ if (target) {
+ w = connection()->platformWindowFromId(target);
+ if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/)
+ w = 0;
+ } else {
+ w = 0;
+ target = rootwin;
+ }
+
+ DNDDEBUG << "and the final target is " << target;
+ DNDDEBUG << "the widget w is" << (w ? w->window() : 0);
+
+ xcb_window_t proxy_target = xdndProxy(connection(), target);
+ if (!proxy_target)
+ proxy_target = target;
+ int target_version = 1;
+
+ if (proxy_target) {
+ xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, target,
+ atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 1);
+ xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0);
+ if (!reply || reply->type == XCB_NONE)
+ target = 0;
+ target_version = xcb_get_property_value_length(reply) == 1 ? *(uint32_t *)xcb_get_property_value(reply) : 1;
+ if (target_version > xdnd_version)
+ target_version = xdnd_version;
+
+ free(reply);
+ }
+
+ DEBUG() << "target=" << target << "current_target=" << current_target;
+ if (target != current_target) {
+ if (current_target)
+ send_leave();
+
+ current_target = target;
+ current_proxy_target = proxy_target;
+ if (target) {
+ int flags = target_version << 24;
+ if (drag_types.size() > 3)
+ flags |= 0x0001;
+
+ xcb_client_message_event_t enter;
+ enter.response_type = XCB_CLIENT_MESSAGE;
+ enter.window = target;
+ enter.format = 32;
+ enter.type = atom(QXcbAtom::XdndEnter);
+ enter.data.data32[0] = connection()->clipboard()->owner();
+ enter.data.data32[1] = flags;
+ enter.data.data32[2] = drag_types.size()>0 ? drag_types.at(0) : 0;
+ enter.data.data32[3] = drag_types.size()>1 ? drag_types.at(1) : 0;
+ enter.data.data32[4] = drag_types.size()>2 ? drag_types.at(2) : 0;
+ // provisionally set the rectangle to 5x5 pixels...
+ source_sameanswer = QRect(globalPos.x() - 2, globalPos.y() -2 , 5, 5);
+
+ DEBUG() << "sending Xdnd enter source=" << enter.data.data32[0];
+ if (w)
+ handleEnter(w->window(), &enter);
+ else if (target)
+ xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&enter);
+ waiting_for_status = false;
+ }
+ }
+ if (waiting_for_status)
+ return;
+
+ QDragManager *m = QDragManager::self();
+
+ if (target) {
+ waiting_for_status = true;
+
+ xcb_client_message_event_t move;
+ move.response_type = XCB_CLIENT_MESSAGE;
+ move.window = target;
+ move.format = 32;
+ move.type = atom(QXcbAtom::XdndPosition);
+ move.window = target;
+ move.data.data32[0] = connection()->clipboard()->owner();
+ move.data.data32[1] = 0; // flags
+ move.data.data32[2] = (globalPos.x() << 16) + globalPos.y();
+ move.data.data32[3] = connection()->time();
+ move.data.data32[4] = toXdndAction(m->defaultAction(m->dragPrivate()->possible_actions, QGuiApplication::keyboardModifiers()));
+ DEBUG() << "sending Xdnd position source=" << move.data.data32[0] << "target=" << move.window;
+
+ source_time = connection()->time();
+
+ if (w)
+ handle_xdnd_position(w->window(), &move, false);
+ else
+ xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move);
+ } else {
+ if (m->willDrop) {
+ m->willDrop = false;
+ m->updateCursor();
+ }
+ }
+ DEBUG() << "QDragManager::move leave";
+}
+
+void QXcbDrag::drop(const QMouseEvent *)
+{
+ endDrag();
+
+ if (!current_target)
+ return;
+
+ xcb_client_message_event_t drop;
+ drop.response_type = XCB_CLIENT_MESSAGE;
+ drop.window = current_target;
+ drop.format = 32;
+ drop.type = atom(QXcbAtom::XdndDrop);
+ drop.data.data32[0] = connection()->clipboard()->owner();
+ drop.data.data32[1] = 0; // flags
+ drop.data.data32[2] = connection()->time();
+
+ drop.data.data32[3] = 0;
+ drop.data.data32[4] = 0;
+
+ QXcbWindow *w = connection()->platformWindowFromId(current_proxy_target);
+
+ if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/)
+ w = 0;
+
+ QDragManager *manager = QDragManager::self();
+
+ Transaction t = {
+ connection()->time(),
+ current_target,
+ current_proxy_target,
+ (w ? w->window() : 0),
+// current_embedding_widget,
+ manager->object
+ };
+ transactions.append(t);
+ restartDropExpiryTimer();
+
+ if (w)
+ handleDrop(w->window(), &drop, false);
+ else
+ xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&drop);
+
+ current_target = 0;
+ current_proxy_target = 0;
+ source_time = 0;
+// current_embedding_widget = 0;
+ manager->object = 0;
+}
+
+Qt::DropAction QXcbDrag::toDropAction(xcb_atom_t a) const
+{
+ if (a == atom(QXcbAtom::XdndActionCopy) || a == 0)
+ return Qt::CopyAction;
+ if (a == atom(QXcbAtom::XdndActionLink))
+ return Qt::LinkAction;
+ if (a == atom(QXcbAtom::XdndActionMove))
+ return Qt::MoveAction;
+ return Qt::CopyAction;
+}
+
+xcb_atom_t QXcbDrag::toXdndAction(Qt::DropAction a) const
+{
+ switch (a) {
+ case Qt::CopyAction:
+ return atom(QXcbAtom::XdndActionCopy);
+ case Qt::LinkAction:
+ return atom(QXcbAtom::XdndActionLink);
+ case Qt::MoveAction:
+ case Qt::TargetMoveAction:
+ return atom(QXcbAtom::XdndActionMove);
+ case Qt::IgnoreAction:
+ return XCB_NONE;
+ default:
+ return atom(QXcbAtom::XdndActionCopy);
+ }
+}
+
+// timer used to discard old XdndDrop transactions
+enum { XdndDropTransactionTimeout = 5000 }; // 5 seconds
+
+void QXcbDrag::restartDropExpiryTimer()
+{
+ if (transaction_expiry_timer != -1)
+ killTimer(transaction_expiry_timer);
+ transaction_expiry_timer = startTimer(XdndDropTransactionTimeout);
+}
+
+int QXcbDrag::findTransactionByWindow(xcb_window_t window)
+{
+ int at = -1;
+ for (int i = 0; i < transactions.count(); ++i) {
+ const Transaction &t = transactions.at(i);
+ if (t.target == window || t.proxy_target == window) {
+ at = i;
+ break;
+ }
+ }
+ return at;
+}
+
+int QXcbDrag::findTransactionByTime(xcb_timestamp_t timestamp)
+{
+ int at = -1;
+ for (int i = 0; i < transactions.count(); ++i) {
+ const Transaction &t = transactions.at(i);
+ if (t.timestamp == timestamp) {
+ at = i;
+ break;
+ }
+ }
+ return at;
+}
+
+#if 0
+
+// find an ancestor with XdndAware on it
+static Window findXdndAwareParent(Window window)
+{
+ Window target = 0;
+ forever {
+ // check if window has XdndAware
+ Atom type = 0;
+ int f;
+ unsigned long n, a;
+ unsigned char *data = 0;
+ if (XGetWindowProperty(X11->display, window, ATOM(XdndAware), 0, 0, False,
+ AnyPropertyType, &type, &f,&n,&a,&data) == Success) {
+ if (data)
+ XFree(data);
+ if (type) {
+ target = window;
+ break;
+ }
+ }
+
+ // try window's parent
+ Window root;
+ Window parent;
+ Window *children;
+ uint unused;
+ if (!XQueryTree(X11->display, window, &root, &parent, &children, &unused))
+ break;
+ if (children)
+ XFree(children);
+ if (window == root)
+ break;
+ window = parent;
+ }
+ return target;
+}
+
+
+// for embedding only
+static QWidget* current_embedding_widget = 0;
+static xcb_client_message_event_t last_enter_event;
+
+
+static bool checkEmbedded(QWidget* w, const XEvent* xe)
+{
+ if (!w)
+ return false;
+
+ if (current_embedding_widget != 0 && current_embedding_widget != w) {
+ current_target = ((QExtraWidget*)current_embedding_widget)->extraData()->xDndProxy;
+ current_proxy_target = current_target;
+ qt_xdnd_send_leave();
+ current_target = 0;
+ current_proxy_target = 0;
+ current_embedding_widget = 0;
+ }
+
+ QWExtra* extra = ((QExtraWidget*)w)->extraData();
+ if (extra && extra->xDndProxy != 0) {
+
+ if (current_embedding_widget != w) {
+
+ last_enter_event.xany.window = extra->xDndProxy;
+ XSendEvent(X11->display, extra->xDndProxy, False, NoEventMask, &last_enter_event);
+ current_embedding_widget = w;
+ }
+
+ ((XEvent*)xe)->xany.window = extra->xDndProxy;
+ XSendEvent(X11->display, extra->xDndProxy, False, NoEventMask, (XEvent*)xe);
+ if (currentWindow != w) {
+ currentWindow = w;
+ }
+ return true;
+ }
+ current_embedding_widget = 0;
+ return false;
+}
+#endif
+
+
+void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *event)
+{
+ Q_UNUSED(window);
+ DEBUG() << "handleEnter" << window;
+
+ xdnd_types.clear();
+// motifdnd_active = false;
+// last_enter_event.xclient = xe->xclient;
+
+ int version = (int)(event->data.data32[1] >> 24);
+ if (version > xdnd_version)
+ return;
+
+ xdnd_dragsource = event->data.data32[0];
+
+ if (event->data.data32[1] & 1) {
+ // get the types from XdndTypeList
+ xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, xdnd_dragsource,
+ atom(QXcbAtom::XdndTypelist), XCB_ATOM_ATOM,
+ 0, xdnd_max_type);
+ xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0);
+ if (reply && reply->type != XCB_NONE && reply->format == 32) {
+ int length = xcb_get_property_value_length(reply) / 4;
+ if (length > xdnd_max_type)
+ length = xdnd_max_type;
+
+ xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply);
+ for (int i = 0; i < length; ++i)
+ xdnd_types.append(atoms[i]);
+ }
+ free(reply);
+ } else {
+ // get the types from the message
+ for(int i = 2; i < 5; i++) {
+ if (event->data.data32[i])
+ xdnd_types.append(event->data.data32[i]);
+ }
+ }
+ for(int i = 0; i < xdnd_types.length(); ++i)
+ DEBUG() << " " << connection()->atomName(xdnd_types.at(i));
+}
+
+void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *e, bool passive)
+{
+ QPoint p((e->data.data32[2] & 0xffff0000) >> 16, e->data.data32[2] & 0x0000ffff);
+ Q_ASSERT(w);
+ QRect geometry = w->geometry();
+
+ p -= geometry.topLeft();
+
+ // ####
+// if (!passive && checkEmbedded(w, e))
+// return;
+
+ if (!w || (/*!w->acceptDrops() &&*/ (w->windowType() == Qt::Desktop)))
+ return;
+
+ if (e->data.data32[0] != xdnd_dragsource) {
+ DEBUG("xdnd drag position from unexpected source (%x not %x)", e->data.data32[0], xdnd_dragsource);
+ return;
+ }
+
+ // timestamp from the source
+ if (e->data.data32[3] != XCB_NONE)
+ target_time /*= X11->userTime*/ = e->data.data32[3];
+
+ QDragManager *manager = QDragManager::self();
+ QMimeData *dropData = manager->dropData();
+
+ xcb_client_message_event_t response;
+ response.response_type = XCB_CLIENT_MESSAGE;
+ response.window = xdnd_dragsource;
+ response.format = 32;
+ response.type = atom(QXcbAtom::XdndStatus);
+ response.data.data32[0] = xcb_window(w);
+ response.data.data32[1] = 0; // flags
+ response.data.data32[2] = 0; // x, y
+ response.data.data32[3] = 0; // w, h
+ response.data.data32[4] = 0; // action
+
+ if (!passive) { // otherwise just reject
+ QRect answerRect(p + geometry.topLeft(), QSize(1,1));
+
+ if (manager->object) {
+ manager->possible_actions = manager->dragPrivate()->possible_actions;
+ } else {
+ manager->possible_actions = Qt::DropActions(toDropAction(e->data.data32[4]));
+ }
+ QDragMoveEvent me(p, manager->possible_actions, dropData,
+ QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+
+ Qt::DropAction accepted_action = Qt::IgnoreAction;
+
+ currentPosition = p;
+
+ if (w != currentWindow.data()) {
+ if (currentWindow) {
+ QDragLeaveEvent e;
+ QGuiApplication::sendEvent(currentWindow.data(), &e);
+ }
+ currentWindow = w;
+
+ last_target_accepted_action = Qt::IgnoreAction;
+ QDragEnterEvent de(p, manager->possible_actions, dropData,
+ QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+ QGuiApplication::sendEvent(w, &de);
+ if (de.isAccepted() && de.dropAction() != Qt::IgnoreAction)
+ last_target_accepted_action = de.dropAction();
+ }
+
+ DEBUG() << "qt_handle_xdnd_position action=" << connection()->atomName(e->data.data32[4]);
+
+ if (last_target_accepted_action != Qt::IgnoreAction) {
+ me.setDropAction(last_target_accepted_action);
+ me.accept();
+ }
+ QGuiApplication::sendEvent(w, &me);
+ if (me.isAccepted()) {
+ response.data.data32[1] = 1; // yes
+ accepted_action = me.dropAction();
+ last_target_accepted_action = accepted_action;
+ } else {
+ response.data.data32[0] = 0;
+ last_target_accepted_action = Qt::IgnoreAction;
+ }
+ answerRect = me.answerRect().translated(geometry.topLeft()).intersected(geometry);
+
+ if (answerRect.left() < 0)
+ answerRect.setLeft(0);
+ if (answerRect.right() > 4096)
+ answerRect.setRight(4096);
+ if (answerRect.top() < 0)
+ answerRect.setTop(0);
+ if (answerRect.bottom() > 4096)
+ answerRect.setBottom(4096);
+ if (answerRect.width() < 0)
+ answerRect.setWidth(0);
+ if (answerRect.height() < 0)
+ answerRect.setHeight(0);
+
+// response.data.data32[2] = (answerRect.x() << 16) + answerRect.y();
+// response.data.data32[3] = (answerRect.width() << 16) + answerRect.height();
+ response.data.data32[4] = toXdndAction(accepted_action);
+ }
+
+ // reset
+ target_time = XCB_CURRENT_TIME;
+
+ DEBUG() << "sending XdndStatus" << (xdnd_dragsource == connection()->clipboard()->owner()) << xdnd_dragsource
+ << response.data.data32[1] << connection()->atomName(response.data.data32[4]);
+ if (xdnd_dragsource == connection()->clipboard()->owner())
+ handle_xdnd_status(&response, passive);
+ else
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&response));
+}
+
+namespace
+{
+ class ClientMessageScanner {
+ public:
+ ClientMessageScanner(xcb_atom_t a) : atom(a) {}
+ xcb_atom_t atom;
+ bool check(xcb_generic_event_t *event) const {
+ if (!event)
+ return false;
+ if ((event->response_type & 0x7f) != XCB_CLIENT_MESSAGE)
+ return false;
+ return ((xcb_client_message_event_t *)event)->type == atom;
+ }
+ };
+}
+
+void QXcbDrag::handlePosition(QWindow * w, const xcb_client_message_event_t *event, bool passive)
+{
+ xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event);
+ xcb_generic_event_t *nextEvent;
+ ClientMessageScanner scanner(atom(QXcbAtom::XdndPosition));
+ while ((nextEvent = connection()->checkEvent(scanner))) {
+ if (lastEvent != event)
+ free(lastEvent);
+ lastEvent = (xcb_client_message_event_t *)nextEvent;
+ }
+
+ handle_xdnd_position(w, lastEvent, passive);
+ if (lastEvent != event)
+ free(lastEvent);
+}
+
+void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event, bool)
+{
+ DEBUG("xdndHandleStatus");
+ // ignore late status messages
+ if (event->data.data32[0] && event->data.data32[0] != current_proxy_target)
+ return;
+
+ Qt::DropAction newAction = (event->data.data32[1] & 0x1) ? toDropAction(event->data.data32[4]) : Qt::IgnoreAction;
+
+ if ((event->data.data32[1] & 2) == 0) {
+ QPoint p((event->data.data32[2] & 0xffff0000) >> 16, event->data.data32[2] & 0x0000ffff);
+ QSize s((event->data.data32[3] & 0xffff0000) >> 16, event->data.data32[3] & 0x0000ffff);
+ source_sameanswer = QRect(p, s);
+ } else {
+ source_sameanswer = QRect();
+ }
+ QDragManager *manager = QDragManager::self();
+ manager->willDrop = (event->data.data32[1] & 0x1);
+ if (manager->global_accepted_action != newAction) {
+ manager->global_accepted_action = newAction;
+ manager->emitActionChanged(newAction);
+ }
+ DEBUG() << "willDrop=" << manager->willDrop << "action=" << newAction;
+ manager->updateCursor();
+ waiting_for_status = false;
+}
+
+void QXcbDrag::handleStatus(const xcb_client_message_event_t *event, bool passive)
+{
+ if (event->window != connection()->clipboard()->owner())
+ return;
+
+ xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event);
+ qDebug() << "handleStatus" << lastEvent->window << lastEvent->data.data32[0];
+ xcb_generic_event_t *nextEvent;
+ ClientMessageScanner scanner(atom(QXcbAtom::XdndStatus));
+ while ((nextEvent = connection()->checkEvent(scanner))) {
+ if (lastEvent != event)
+ free(lastEvent);
+ lastEvent = (xcb_client_message_event_t *)nextEvent;
+ }
+
+ handle_xdnd_status(lastEvent, passive);
+ if (lastEvent != event)
+ free(lastEvent);
+ DEBUG("xdndHandleStatus end");
+}
+
+void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event, bool /*passive*/)
+{
+ DEBUG("xdnd leave");
+ if (!currentWindow || w != currentWindow.data())
+ return; // sanity
+
+ // ###
+// if (checkEmbedded(current_embedding_widget, event)) {
+// current_embedding_widget = 0;
+// currentWindow.clear();
+// return;
+// }
+
+ if (event->data.data32[0] != xdnd_dragsource) {
+ // This often happens - leave other-process window quickly
+ DEBUG("xdnd drag leave from unexpected source (%x not %x", event->data.data32[0], xdnd_dragsource);
+ }
+
+ QDragLeaveEvent e;
+ QGuiApplication::sendEvent(currentWindow.data(), &e);
+
+ xdnd_dragsource = 0;
+ xdnd_types.clear();
+ currentWindow.clear();
+}
+
+void QXcbDrag::send_leave()
+{
+ if (!current_target)
+ return;
+
+ QDragManager *manager = QDragManager::self();
+
+ xcb_client_message_event_t leave;
+ leave.response_type = XCB_CLIENT_MESSAGE;
+ leave.window = current_target;
+ leave.format = 32;
+ leave.type = atom(QXcbAtom::XdndLeave);
+ leave.data.data32[0] = connection()->clipboard()->owner();
+ leave.data.data32[1] = 0; // flags
+ leave.data.data32[2] = 0; // x, y
+ leave.data.data32[3] = 0; // w, h
+ leave.data.data32[4] = 0; // just null
+
+ QXcbWindow *w = connection()->platformWindowFromId(current_proxy_target);
+
+ if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/)
+ w = 0;
+
+ if (w)
+ handleLeave(w->window(), (const xcb_client_message_event_t *)&leave, false);
+ else
+ xcb_send_event(xcb_connection(), false,current_proxy_target,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&leave);
+
+ // reset the drag manager state
+ manager->willDrop = false;
+ if (manager->global_accepted_action != Qt::IgnoreAction)
+ manager->emitActionChanged(Qt::IgnoreAction);
+ manager->global_accepted_action = Qt::IgnoreAction;
+ manager->updateCursor();
+ current_target = 0;
+ current_proxy_target = 0;
+ source_time = XCB_CURRENT_TIME;
+ waiting_for_status = false;
+}
+
+void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event, bool passive)
+{
+ DEBUG("xdndHandleDrop");
+ if (!currentWindow) {
+ xdnd_dragsource = 0;
+ return; // sanity
+ }
+
+ // ###
+// if (!passive && checkEmbedded(currentWindow, xe)){
+// current_embedding_widget = 0;
+// xdnd_dragsource = 0;
+// currentWindow = 0;
+// return;
+// }
+ const uint32_t *l = event->data.data32;
+
+ QDragManager *manager = QDragManager::self();
+ DEBUG("xdnd drop");
+
+ if (l[0] != xdnd_dragsource) {
+ DEBUG("xdnd drop from unexpected source (%x not %x", l[0], xdnd_dragsource);
+ return;
+ }
+
+ // update the "user time" from the timestamp in the event.
+ if (l[2] != 0)
+ target_time = /*X11->userTime =*/ l[2];
+
+ if (!passive) {
+ // this could be a same-application drop, just proxied due to
+ // some XEMBEDding, so try to find the real QMimeData used
+ // based on the timestamp for this drop.
+ QMimeData *dropData = 0;
+ // ###
+// int at = findXdndDropTransactionByTime(target_time);
+// if (at != -1)
+// dropData = QDragManager::dragPrivate(X11->dndDropTransactions.at(at).object)->data;
+ // if we can't find it, then use the data in the drag manager
+ if (!dropData)
+ dropData = manager->dropData();
+
+ // Drop coming from another app? Update keyboard modifiers.
+// if (!qt_xdnd_dragging) {
+// QApplicationPrivate::modifier_buttons = currentKeyboardModifiers();
+// }
+
+ QDropEvent de(currentPosition, manager->possible_actions, dropData,
+ QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+ QGuiApplication::sendEvent(currentWindow.data(), &de);
+ if (!de.isAccepted()) {
+ // Ignore a failed drag
+ manager->global_accepted_action = Qt::IgnoreAction;
+ } else {
+ manager->global_accepted_action = de.dropAction();
+ }
+ xcb_client_message_event_t finished;
+ finished.response_type = XCB_CLIENT_MESSAGE;
+ finished.window = xdnd_dragsource;
+ finished.format = 32;
+ finished.type = atom(QXcbAtom::XdndFinished);
+ DNDDEBUG << "xdndHandleDrop"
+ << "currentWindow" << currentWindow.data()
+ << (currentWindow ? xcb_window(currentWindow.data()) : 0);
+ finished.data.data32[0] = currentWindow ? xcb_window(currentWindow.data()) : XCB_NONE;
+ finished.data.data32[1] = de.isAccepted() ? 1 : 0; // flags
+ finished.data.data32[2] = toXdndAction(manager->global_accepted_action);
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource,
+ XCB_EVENT_MASK_NO_EVENT, (char *)&finished));
+ } else {
+ QDragLeaveEvent e;
+ QGuiApplication::sendEvent(currentWindow.data(), &e);
+ }
+ xdnd_dragsource = 0;
+ currentWindow.clear();
+ waiting_for_status = false;
+
+ // reset
+ target_time = XCB_CURRENT_TIME;
+}
+
+
+void QXcbDrag::handleFinished(const xcb_client_message_event_t *event, bool)
+{
+ DEBUG("xdndHandleFinished");
+ if (event->window != connection()->clipboard()->owner())
+ return;
+
+ const unsigned long *l = (const unsigned long *)event->data.data32;
+
+ DNDDEBUG << "xdndHandleFinished, l[0]" << l[0]
+ << "current_target" << current_target
+ << "qt_xdnd_current_proxy_targe" << current_proxy_target;
+
+ if (l[0]) {
+ int at = findTransactionByWindow(l[0]);
+ if (at != -1) {
+ restartDropExpiryTimer();
+
+ Transaction t = transactions.takeAt(at);
+// QDragManager *manager = QDragManager::self();
+
+// Window target = current_target;
+// Window proxy_target = current_proxy_target;
+// QWidget *embedding_widget = current_embedding_widget;
+// QDrag *currentObject = manager->object;
+
+// current_target = t.target;
+// current_proxy_target = t.proxy_target;
+// current_embedding_widget = t.embedding_widget;
+// manager->object = t.object;
+
+// if (!passive)
+// (void) checkEmbedded(currentWindow, xe);
+
+// current_embedding_widget = 0;
+// current_target = 0;
+// current_proxy_target = 0;
+
+ if (t.object)
+ t.object->deleteLater();
+
+// current_target = target;
+// current_proxy_target = proxy_target;
+// current_embedding_widget = embedding_widget;
+// manager->object = currentObject;
+ }
+ }
+ waiting_for_status = false;
+}
+
+
+void QXcbDrag::timerEvent(QTimerEvent* e)
+{
+ if (e->timerId() == heartbeat && source_sameanswer.isNull()) {
+ QPointF pos = QCursor::pos();
+ QMouseEvent me(QEvent::MouseMove, pos, pos, pos, Qt::LeftButton,
+ QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+ move(&me);
+ } else if (e->timerId() == transaction_expiry_timer) {
+ for (int i = 0; i < transactions.count(); ++i) {
+ const Transaction &t = transactions.at(i);
+ if (t.targetWindow) {
+ // dnd within the same process, don't delete these
+ continue;
+ }
+ t.object->deleteLater();
+ transactions.removeAt(i--);
+ }
+
+ killTimer(transaction_expiry_timer);
+ transaction_expiry_timer = -1;
+ }
+}
+
+void QXcbDrag::cancel()
+{
+ DEBUG("QXcbDrag::cancel");
+ endDrag();
+
+ if (current_target)
+ send_leave();
+
+ current_target = 0;
+}
+
+#if 0
+
+static
+Window findRealWindow(const QPoint & pos, Window w, int md)
+{
+ if (xdnd_data.deco && w == xdnd_data.deco->effectiveWinId())
+ return 0;
+
+ if (md) {
+ X11->ignoreBadwindow();
+ XWindowAttributes attr;
+ XGetWindowAttributes(X11->display, w, &attr);
+ if (X11->badwindow())
+ return 0;
+
+ if (attr.map_state == IsViewable
+ && QRect(attr.x,attr.y,attr.width,attr.height).contains(pos)) {
+ {
+ Atom type = XNone;
+ int f;
+ unsigned long n, a;
+ unsigned char *data;
+
+ XGetWindowProperty(X11->display, w, ATOM(XdndAware), 0, 0, False,
+ AnyPropertyType, &type, &f,&n,&a,&data);
+ if (data) XFree(data);
+ if (type)
+ return w;
+ }
+
+ Window r, p;
+ Window* c;
+ uint nc;
+ if (XQueryTree(X11->display, w, &r, &p, &c, &nc)) {
+ r=0;
+ for (uint i=nc; !r && i--;) {
+ r = findRealWindow(pos-QPoint(attr.x,attr.y),
+ c[i], md-1);
+ }
+ XFree(c);
+ if (r)
+ return r;
+
+ // We didn't find a client window! Just use the
+ // innermost window.
+ }
+
+ // No children!
+ return w;
+ }
+ }
+ return 0;
+}
+#endif
+
+void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event)
+{
+ xcb_selection_notify_event_t notify;
+ notify.response_type = XCB_SELECTION_NOTIFY;
+ notify.requestor = event->requestor;
+ notify.selection = event->selection;
+ notify.target = XCB_NONE;
+ notify.property = XCB_NONE;
+ notify.time = event->time;
+
+ QDragManager *manager = QDragManager::self();
+ QDrag *currentObject = manager->object;
+
+ // which transaction do we use? (note: -2 means use current manager->object)
+ int at = -1;
+
+ // figure out which data the requestor is really interested in
+ if (manager->object && event->time == source_time) {
+ // requestor wants the current drag data
+ at = -2;
+ } else {
+ // if someone has requested data in response to XdndDrop, find the corresponding transaction. the
+ // spec says to call XConvertSelection() using the timestamp from the XdndDrop
+ at = findTransactionByTime(event->time);
+ if (at == -1) {
+ // no dice, perhaps the client was nice enough to use the same window id in XConvertSelection()
+ // that we sent the XdndDrop event to.
+ at = findTransactionByWindow(event->requestor);
+ }
+// if (at == -1 && event->time == XCB_CURRENT_TIME) {
+// // previous Qt versions always requested the data on a child of the target window
+// // using CurrentTime... but it could be asking for either drop data or the current drag's data
+// Window target = findXdndAwareParent(event->requestor);
+// if (target) {
+// if (current_target && current_target == target)
+// at = -2;
+// else
+// at = findXdndDropTransactionByWindow(target);
+// }
+// }
+ }
+ if (at >= 0) {
+ restartDropExpiryTimer();
+
+ // use the drag object from an XdndDrop tansaction
+ manager->object = transactions.at(at).object;
+ } else if (at != -2) {
+ // no transaction found, we'll have to reject the request
+ manager->object = 0;
+ }
+ if (manager->object) {
+ xcb_atom_t atomFormat = event->target;
+ int dataFormat = 0;
+ QByteArray data;
+ if (QXcbMime::mimeDataForAtom(connection(), event->target, manager->dragPrivate()->data,
+ &data, &atomFormat, &dataFormat)) {
+ int dataSize = data.size() / (dataFormat / 8);
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, event->requestor, event->property,
+ atomFormat, dataFormat, dataSize, (const void *)data.constData());
+ notify.property = event->property;
+ notify.target = atomFormat;
+ }
+ }
+
+ // reset manager->object in case we modified it above
+ manager->object = currentObject;
+
+ xcb_send_event(xcb_connection(), false, event->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&notify);
+}
+
+
+bool QXcbDrag::dndEnable(QXcbWindow *w, bool on)
+{
+ DNDDEBUG << "xdndEnable" << w << on;
+ if (on) {
+ QXcbWindow *xdnd_widget = 0;
+ if ((w->window()->windowType() == Qt::Desktop)) {
+ if (desktop_proxy) // *WE* already have one.
+ return false;
+
+ xcb_grab_server(xcb_connection());
+
+ // As per Xdnd4, use XdndProxy
+ xcb_window_t proxy_id = xdndProxy(connection(), w->xcb_window());
+
+ if (!proxy_id) {
+ desktop_proxy = new QWindow;
+ xdnd_widget = static_cast<QXcbWindow *>(desktop_proxy->handle());
+ proxy_id = xdnd_widget->xcb_window();
+ xcb_atom_t xdnd_proxy = atom(QXcbAtom::XdndProxy);
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, w->xcb_window(), xdnd_proxy,
+ XCB_ATOM_WINDOW, 32, 1, &proxy_id);
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, proxy_id, xdnd_proxy,
+ XCB_ATOM_WINDOW, 32, 1, &proxy_id);
+ }
+
+ xcb_ungrab_server(xcb_connection());
+ } else {
+ xdnd_widget = w;
+ }
+ if (xdnd_widget) {
+ DNDDEBUG << "setting XdndAware for" << xdnd_widget << xdnd_widget->xcb_window();
+ xcb_atom_t atm = xdnd_version;
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, xdnd_widget->xcb_window(),
+ atom(QXcbAtom::XdndAware), XCB_ATOM_ATOM, 32, 1, &atm);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ if ((w->window()->windowType() == Qt::Desktop)) {
+ xcb_delete_property(xcb_connection(), w->xcb_window(), atom(QXcbAtom::XdndProxy));
+ delete desktop_proxy;
+ desktop_proxy = 0;
+ } else {
+ DNDDEBUG << "not deleting XDndAware";
+ }
+ return true;
+ }
+}
+
+
+
+
+QDropData::QDropData(QXcbDrag *d)
+ : QXcbMime(),
+ drag(d)
+{
+}
+
+QDropData::~QDropData()
+{
+}
+
+QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type requestedType) const
+{
+ QByteArray mime = mimetype.toLatin1();
+ QVariant data = /*X11->motifdnd_active
+ ? X11->motifdndObtainData(mime)
+ :*/ xdndObtainData(mime, requestedType);
+ return data;
+}
+
+QVariant QDropData::xdndObtainData(const QByteArray &format, QVariant::Type requestedType) const
+{
+ QByteArray result;
+
+ QDragManager *manager = QDragManager::self();
+ QXcbConnection *c = drag->connection();
+ QXcbWindow *xcb_window = c->platformWindowFromId(drag->xdnd_dragsource);
+ if (xcb_window && manager->object && xcb_window->window()->windowType() != Qt::Desktop) {
+ QDragPrivate *o = manager->dragPrivate();
+ if (o->data->hasFormat(QLatin1String(format)))
+ result = o->data->data(QLatin1String(format));
+ return result;
+ }
+
+ QList<xcb_atom_t> atoms = drag->xdnd_types;
+ QByteArray encoding;
+ xcb_atom_t a = mimeAtomForFormat(c, QLatin1String(format), requestedType, atoms, &encoding);
+ if (a == XCB_NONE)
+ return result;
+
+ if (c->clipboard()->getSelectionOwner(drag->atom(QXcbAtom::XdndSelection)) == XCB_NONE)
+ return result; // should never happen?
+
+ xcb_atom_t xdnd_selection = c->atom(QXcbAtom::XdndSelection);
+ result = c->clipboard()->getSelection(xdnd_selection, a, xdnd_selection);
+
+ return mimeConvertToFormat(c, a, result, QLatin1String(format), requestedType, encoding);
+}
+
+
+bool QDropData::hasFormat_sys(const QString &format) const
+{
+ return formats().contains(format);
+}
+
+QStringList QDropData::formats_sys() const
+{
+ QStringList formats;
+// if (X11->motifdnd_active) {
+// int i = 0;
+// QByteArray fmt;
+// while (!(fmt = X11->motifdndFormat(i)).isEmpty()) {
+// formats.append(QLatin1String(fmt));
+// ++i;
+// }
+// } else {
+ for (int i = 0; i < drag->xdnd_types.size(); ++i) {
+ QString f = mimeAtomToString(drag->connection(), drag->xdnd_types.at(i));
+ if (!formats.contains(f))
+ formats.append(f);
+ }
+// }
+ return formats;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h
new file mode 100644
index 0000000000..ce0f8faa54
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbdrag.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QXCBDRAG_H
+#define QXCBDRAG_H
+
+#include <qplatformdrag_qpa.h>
+#include <qxcbobject.h>
+#include <xcb/xcb.h>
+#include <qlist.h>
+#include <qpoint.h>
+#include <qrect.h>
+#include <qsharedpointer.h>
+#include <qvector.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMouseEvent;
+class QWindow;
+class QXcbConnection;
+class QXcbWindow;
+class QDropData;
+class QXcbScreen;
+class QDrag;
+
+class QXcbDrag : public QObject, public QXcbObject, public QPlatformDrag
+{
+public:
+ QXcbDrag(QXcbConnection *c);
+ ~QXcbDrag();
+
+ virtual QMimeData *platformDropData();
+
+// virtual Qt::DropAction drag(QDrag *);
+
+ virtual void startDrag();
+ virtual void cancel();
+ virtual void move(const QMouseEvent *me);
+ virtual void drop(const QMouseEvent *me);
+ void endDrag();
+
+ void handleEnter(QWindow *window, const xcb_client_message_event_t *event);
+ void handlePosition(QWindow *w, const xcb_client_message_event_t *event, bool passive);
+ void handleLeave(QWindow *w, const xcb_client_message_event_t *event, bool /*passive*/);
+ void handleDrop(QWindow *, const xcb_client_message_event_t *event, bool passive);
+
+ void handleStatus(const xcb_client_message_event_t *event, bool passive);
+ void handleSelectionRequest(const xcb_selection_request_event_t *event);
+ void handleFinished(const xcb_client_message_event_t *event, bool passive);
+
+ bool dndEnable(QXcbWindow *win, bool on);
+
+protected:
+ void timerEvent(QTimerEvent* e);
+
+private:
+ friend class QDropData;
+
+ void init();
+
+ void handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *event, bool passive);
+ void handle_xdnd_status(const xcb_client_message_event_t *event, bool);
+ void send_leave();
+
+ Qt::DropAction toDropAction(xcb_atom_t atom) const;
+ xcb_atom_t toXdndAction(Qt::DropAction a) const;
+
+ QWeakPointer<QWindow> currentWindow;
+ QPoint currentPosition;
+
+ QDropData *dropData;
+
+ QWindow *desktop_proxy;
+
+ xcb_atom_t xdnd_dragsource;
+
+ // the types in this drop. 100 is no good, but at least it's big.
+ enum { xdnd_max_type = 100 };
+ QList<xcb_atom_t> xdnd_types;
+
+ xcb_timestamp_t target_time;
+ xcb_timestamp_t source_time;
+ Qt::DropAction last_target_accepted_action;
+
+ // rectangle in which the answer will be the same
+ QRect source_sameanswer;
+ bool waiting_for_status;
+
+ // top-level window we sent position to last.
+ xcb_window_t current_target;
+ // window to send events to (always valid if current_target)
+ xcb_window_t current_proxy_target;
+
+ QXcbScreen *current_screen;
+
+ int heartbeat;
+ bool xdnd_dragging;
+
+ QVector<xcb_atom_t> drag_types;
+
+ struct Transaction
+ {
+ xcb_timestamp_t timestamp;
+ xcb_window_t target;
+ xcb_window_t proxy_target;
+ QWindow *targetWindow;
+// QWidget *embedding_widget;
+ QDrag *object;
+ };
+ QList<Transaction> transactions;
+
+ int transaction_expiry_timer;
+ void restartDropExpiryTimer();
+ int findTransactionByWindow(xcb_window_t window);
+ int findTransactionByTime(xcb_timestamp_t timestamp);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/xcb/qxcbeglsurface.h b/src/plugins/platforms/xcb/qxcbeglsurface.h
new file mode 100644
index 0000000000..a1e6c148a2
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbeglsurface.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QXCBEGLSURFACE_H
+#define QXCBEGLSURFACE_H
+
+#include <EGL/egl.h>
+
+class QXcbEGLSurface
+{
+public:
+ QXcbEGLSurface(EGLDisplay display, EGLSurface surface)
+ : m_display(display)
+ , m_surface(surface)
+ {
+ }
+
+ ~QXcbEGLSurface()
+ {
+ eglDestroySurface(m_display, m_surface);
+ }
+
+ EGLSurface surface() const { return m_surface; }
+
+private:
+ EGLDisplay m_display;
+ EGLSurface m_surface;
+};
+
+#endif
diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp
new file mode 100644
index 0000000000..569e4fc4e4
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbimage.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qxcbimage.h"
+#include <QtGui/QColor>
+#include <QtGui/private/qimage_p.h>
+#include <QtGui/private/qdrawhelper_p.h>
+#ifdef XCB_USE_RENDER
+#include <xcb/render.h>
+// 'template' is used as a function argument name in xcb_renderutil.h
+#define template template_param
+// extern "C" is missing too
+extern "C" {
+#include <xcb/xcb_renderutil.h>
+}
+#undef template
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QImage::Format qt_xcb_imageFormatForVisual(QXcbConnection *connection, uint8_t depth,
+ const xcb_visualtype_t *visual)
+{
+ const xcb_format_t *format = connection->formatForDepth(depth);
+
+ if (!visual || !format)
+ return QImage::Format_Invalid;
+
+ if (depth == 32 && format->bits_per_pixel == 32 && visual->red_mask == 0xff0000
+ && visual->green_mask == 0xff00 && visual->blue_mask == 0xff)
+ return QImage::Format_ARGB32_Premultiplied;
+
+ if (depth == 24 && format->bits_per_pixel == 32 && visual->red_mask == 0xff0000
+ && visual->green_mask == 0xff00 && visual->blue_mask == 0xff)
+ return QImage::Format_RGB32;
+
+ if (depth == 16 && format->bits_per_pixel == 16 && visual->red_mask == 0xf800
+ && visual->green_mask == 0x7e0 && visual->blue_mask == 0x1f)
+ return QImage::Format_RGB16;
+
+ return QImage::Format_Invalid;
+}
+
+QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap,
+ int width, int height, int depth,
+ const xcb_visualtype_t *visual)
+{
+ xcb_connection_t *conn = connection->xcb_connection();
+ xcb_generic_error_t *error = 0;
+
+ xcb_get_image_cookie_t get_image_cookie =
+ xcb_get_image(conn, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap,
+ 0, 0, width, height, 0xffffffff);
+
+ xcb_get_image_reply_t *image_reply =
+ xcb_get_image_reply(conn, get_image_cookie, &error);
+
+ if (!image_reply) {
+ if (error) {
+ connection->handleXcbError(error);
+ free(error);
+ }
+ return QPixmap();
+ }
+
+ uint8_t *data = xcb_get_image_data(image_reply);
+ uint32_t length = xcb_get_image_data_length(image_reply);
+
+ QPixmap result;
+
+ QImage::Format format = qt_xcb_imageFormatForVisual(connection, depth, visual);
+ if (format != QImage::Format_Invalid) {
+ uint32_t bytes_per_line = length / height;
+ QImage image(const_cast<uint8_t *>(data), width, height, bytes_per_line, format);
+ uint8_t image_byte_order = connection->setup()->image_byte_order;
+
+ // we may have to swap the byte order
+ if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && image_byte_order == XCB_IMAGE_ORDER_MSB_FIRST)
+ || (QSysInfo::ByteOrder == QSysInfo::BigEndian && image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST))
+ {
+ for (int i=0; i < image.height(); i++) {
+ switch (format) {
+ case QImage::Format_RGB16: {
+ ushort *p = (ushort*)image.scanLine(i);
+ ushort *end = p + image.width();
+ while (p < end) {
+ *p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff);
+ p++;
+ }
+ break;
+ }
+ case QImage::Format_RGB32: // fall-through
+ case QImage::Format_ARGB32_Premultiplied: {
+ uint *p = (uint*)image.scanLine(i);
+ uint *end = p + image.width();
+ while (p < end) {
+ *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
+ | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
+ p++;
+ }
+ break;
+ }
+ default:
+ Q_ASSERT(false);
+ }
+ }
+ }
+
+ // fix-up alpha channel
+ if (format == QImage::Format_RGB32) {
+ QRgb *p = (QRgb *)image.bits();
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width; ++x)
+ p[x] |= 0xff000000;
+ p += bytes_per_line / 4;
+ }
+ }
+
+ result = QPixmap::fromImage(image.copy());
+ }
+
+ free(image_reply);
+ return result;
+}
+
+xcb_pixmap_t qt_xcb_XPixmapFromBitmap(QXcbScreen *screen, const QImage &image)
+{
+ xcb_connection_t *conn = screen->xcb_connection();
+ QImage bitmap = image.convertToFormat(QImage::Format_MonoLSB);
+ const QRgb c0 = QColor(Qt::black).rgb();
+ const QRgb c1 = QColor(Qt::white).rgb();
+ if (bitmap.color(0) == c0 && bitmap.color(1) == c1) {
+ bitmap.invertPixels();
+ bitmap.setColor(0, c1);
+ bitmap.setColor(1, c0);
+ }
+ const int width = bitmap.width();
+ const int height = bitmap.height();
+ const int bytesPerLine = bitmap.bytesPerLine();
+ int destLineSize = width / 8;
+ if (width % 8)
+ ++destLineSize;
+ const uchar *map = bitmap.bits();
+ uint8_t *buf = new uint8_t[height * destLineSize];
+ for (int i = 0; i < height; i++)
+ memcpy(buf + (destLineSize * i), map + (bytesPerLine * i), destLineSize);
+ xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, screen->root(), buf,
+ width, height, 1, 0, 0, 0);
+ delete[] buf;
+ return pm;
+}
+
+xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image,
+ const QPoint &spot)
+{
+#ifdef XCB_USE_RENDER
+ xcb_connection_t *conn = screen->xcb_connection();
+ const int w = image.width();
+ const int h = image.height();
+ xcb_generic_error_t *error = 0;
+ xcb_render_query_pict_formats_cookie_t formatsCookie = xcb_render_query_pict_formats(conn);
+ xcb_render_query_pict_formats_reply_t *formatsReply = xcb_render_query_pict_formats_reply(conn,
+ formatsCookie,
+ &error);
+ if (!formatsReply || error) {
+ qWarning("createCursorXRender: query_pict_formats failed");
+ free(formatsReply);
+ free(error);
+ return XCB_NONE;
+ }
+ xcb_render_pictforminfo_t *fmt = xcb_render_util_find_standard_format(formatsReply,
+ XCB_PICT_STANDARD_ARGB_32);
+ if (!fmt) {
+ qWarning("createCursorXRender: Failed to find format PICT_STANDARD_ARGB_32");
+ free(formatsReply);
+ return XCB_NONE;
+ }
+
+ QImage img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ xcb_image_t *xi = xcb_image_create(w, h, XCB_IMAGE_FORMAT_Z_PIXMAP,
+ 32, 32, 32, 32,
+ QSysInfo::ByteOrder == QSysInfo::BigEndian ? XCB_IMAGE_ORDER_MSB_FIRST : XCB_IMAGE_ORDER_LSB_FIRST,
+ XCB_IMAGE_ORDER_MSB_FIRST,
+ 0, 0, 0);
+ if (!xi) {
+ qWarning("createCursorXRender: xcb_image_create failed");
+ free(formatsReply);
+ return XCB_NONE;
+ }
+ xi->data = (uint8_t *) malloc(xi->stride * h);
+ if (!xi->data) {
+ qWarning("createCursorXRender: Failed to malloc() image data");
+ xcb_image_destroy(xi);
+ free(formatsReply);
+ return XCB_NONE;
+ }
+ memcpy(xi->data, img.constBits(), img.byteCount());
+
+ xcb_pixmap_t pix = xcb_generate_id(conn);
+ xcb_create_pixmap(conn, 32, pix, screen->root(), w, h);
+
+ xcb_render_picture_t pic = xcb_generate_id(conn);
+ xcb_render_create_picture(conn, pic, pix, fmt->id, 0, 0);
+
+ xcb_gcontext_t gc = xcb_generate_id(conn);
+ xcb_create_gc(conn, gc, pix, 0, 0);
+ xcb_image_put(conn, pix, gc, xi, 0, 0, 0);
+ xcb_free_gc(conn, gc);
+
+ xcb_cursor_t cursor = xcb_generate_id(conn);
+ xcb_render_create_cursor(conn, cursor, pic, spot.x(), spot.y());
+
+ free(xi->data);
+ xcb_image_destroy(xi);
+ xcb_render_free_picture(conn, pic);
+ xcb_free_pixmap(conn, pix);
+ free(formatsReply);
+ return cursor;
+
+#else
+ Q_UNUSED(screen);
+ Q_UNUSED(image);
+ Q_UNUSED(spot);
+ return XCB_NONE;
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbimage.h b/src/plugins/platforms/xcb/qxcbimage.h
new file mode 100644
index 0000000000..1e7f104084
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbimage.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QXCBIMAGE_H
+#define QXCBIMAGE_H
+
+#include "qxcbscreen.h"
+#include <QtCore/QPair>
+#include <QtGui/QImage>
+#include <QtGui/QPixmap>
+#include <xcb/xcb_image.h>
+
+QT_BEGIN_NAMESPACE
+
+QImage::Format qt_xcb_imageFormatForVisual(QXcbConnection *connection,
+ uint8_t depth, const xcb_visualtype_t *visual);
+QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap,
+ int width, int height, int depth,
+ const xcb_visualtype_t *visual);
+xcb_pixmap_t qt_xcb_XPixmapFromBitmap(QXcbScreen *screen, const QImage &image);
+xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image,
+ const QPoint &spot);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index 12b63f36ea..b0d377bcac 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -43,76 +43,161 @@
#include "qxcbconnection.h"
#include "qxcbscreen.h"
#include "qxcbwindow.h"
-#include "qxcbwindowsurface.h"
+#include "qxcbbackingstore.h"
#include "qxcbnativeinterface.h"
+#include "qxcbclipboard.h"
+#include "qxcbdrag.h"
#include <xcb/xcb.h>
-#include <private/qpixmap_raster_p.h>
-
-#include "qgenericunixfontdatabase.h"
+#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
+#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
#include <stdio.h>
+//this has to be included before egl, since egl pulls in X headers
+#include <QtGui/private/qguiapplication_p.h>
+
#ifdef XCB_USE_EGL
#include <EGL/egl.h>
#endif
-QXcbIntegration::QXcbIntegration()
- : m_connection(new QXcbConnection)
+#include <private/qplatforminputcontextfactory_qpa_p.h>
+#include <qplatforminputcontext_qpa.h>
+
+#if defined(XCB_USE_GLX)
+#include "qglxintegration.h"
+#elif defined(XCB_USE_EGL)
+#include "qxcbeglsurface.h"
+#include <QtPlatformSupport/private/qeglplatformcontext_p.h>
+#endif
+
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QScreen>
+
+QXcbIntegration::QXcbIntegration(const QStringList &parameters)
+ : m_eventDispatcher(createUnixEventDispatcher())
{
- foreach (QXcbScreen *screen, m_connection->screens())
- m_screens << screen;
+ QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher);
+
+#ifdef XCB_USE_XLIB
+ XInitThreads();
+#endif
+
+ m_connections << new QXcbConnection;
+
+ for (int i = 0; i < parameters.size() - 1; i += 2) {
+ qDebug() << parameters.at(i) << parameters.at(i+1);
+ QString display = parameters.at(i) + ':' + parameters.at(i+1);
+ m_connections << new QXcbConnection(display.toAscii().constData());
+ }
+
+ foreach (QXcbConnection *connection, m_connections)
+ foreach (QXcbScreen *screen, connection->screens())
+ screenAdded(screen);
m_fontDatabase = new QGenericUnixFontDatabase();
m_nativeInterface = new QXcbNativeInterface;
+
+ m_inputContext = QPlatformInputContextFactory::create();
}
QXcbIntegration::~QXcbIntegration()
{
- delete m_connection;
+ qDeleteAll(m_connections);
}
-bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const
{
- switch (cap) {
- case ThreadedPixmaps: return true;
- case OpenGL: return hasOpenGL();
- default: return QPlatformIntegration::hasCapability(cap);
- }
+ return new QXcbWindow(window);
}
-QPixmapData *QXcbIntegration::createPixmapData(QPixmapData::PixelType type) const
+#if defined(XCB_USE_EGL)
+class QEGLXcbPlatformContext : public QEGLPlatformContext
{
- return new QRasterPixmapData(type);
-}
+public:
+ QEGLXcbPlatformContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share,
+ EGLDisplay display, QXcbConnection *c)
+ : QEGLPlatformContext(glFormat, share, display)
+ , m_connection(c)
+ {
+ Q_XCB_NOOP(m_connection);
+ }
+
+ void swapBuffers(QPlatformSurface *surface)
+ {
+ Q_XCB_NOOP(m_connection);
+ QEGLPlatformContext::swapBuffers(surface);
+ Q_XCB_NOOP(m_connection);
+ }
+
+ bool makeCurrent(QPlatformSurface *surface)
+ {
+ Q_XCB_NOOP(m_connection);
+ bool ret = QEGLPlatformContext::makeCurrent(surface);
+ Q_XCB_NOOP(m_connection);
+ return ret;
+ }
+
+ void doneCurrent()
+ {
+ Q_XCB_NOOP(m_connection);
+ QEGLPlatformContext::doneCurrent();
+ Q_XCB_NOOP(m_connection);
+ }
+
+ EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface)
+ {
+ return static_cast<QXcbWindow *>(surface)->eglSurface()->surface();
+ }
-QPlatformWindow *QXcbIntegration::createPlatformWindow(QWidget *widget, WId winId) const
+private:
+ QXcbConnection *m_connection;
+};
+#endif
+
+QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
- Q_UNUSED(winId);
- return new QXcbWindow(widget);
+ QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle());
+#if defined(XCB_USE_GLX)
+ return new QGLXContext(screen, context->format(), context->shareHandle());
+#elif defined(XCB_USE_EGL)
+ return new QEGLXcbPlatformContext(context->format(), context->shareHandle(),
+ screen->connection()->egl_display(), screen->connection());
+#elif defined(XCB_USE_DRI2)
+ return new QDri2Context(context->format(), context->shareHandle());
+#endif
}
-QWindowSurface *QXcbIntegration::createWindowSurface(QWidget *widget, WId winId) const
+QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *window) const
{
- Q_UNUSED(winId);
- return new QXcbWindowSurface(widget);
+ return new QXcbBackingStore(window);
}
-QList<QPlatformScreen *> QXcbIntegration::screens() const
+bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
- return m_screens;
+ switch (cap) {
+ case ThreadedPixmaps: return true;
+ case OpenGL: return true;
+ case ThreadedOpenGL:
+#ifdef XCB_POLL_FOR_QUEUED_EVENT
+ return true;
+#else
+ return false;
+#endif
+ default: return QPlatformIntegration::hasCapability(cap);
+ }
}
-void QXcbIntegration::moveToScreen(QWidget *window, int screen)
+QAbstractEventDispatcher *QXcbIntegration::guiThreadEventDispatcher() const
{
- Q_UNUSED(window);
- Q_UNUSED(screen);
+ return m_eventDispatcher;
}
-bool QXcbIntegration::isVirtualDesktop()
+void QXcbIntegration::moveToScreen(QWindow *window, int screen)
{
- return false;
+ Q_UNUSED(window);
+ Q_UNUSED(screen);
}
QPlatformFontDatabase *QXcbIntegration::fontDatabase() const
@@ -120,32 +205,22 @@ QPlatformFontDatabase *QXcbIntegration::fontDatabase() const
return m_fontDatabase;
}
-QPixmap QXcbIntegration::grabWindow(WId window, int x, int y, int width, int height) const
+QPlatformNativeInterface * QXcbIntegration::nativeInterface() const
{
- Q_UNUSED(window);
- Q_UNUSED(x);
- Q_UNUSED(y);
- Q_UNUSED(width);
- Q_UNUSED(height);
- return QPixmap();
+ return m_nativeInterface;
}
+QPlatformClipboard *QXcbIntegration::clipboard() const
+{
+ return m_connections.at(0)->clipboard();
+}
-bool QXcbIntegration::hasOpenGL() const
+QPlatformDrag *QXcbIntegration::drag() const
{
-#if defined(XCB_USE_GLX)
- return true;
-#elif defined(XCB_USE_EGL)
- return m_connection->hasEgl();
-#elif defined(XCB_USE_DRI2)
- if (m_connection->hasSupportForDri2()) {
- return true;
- }
-#endif
- return false;
+ return m_connections.at(0)->drag();
}
-QPlatformNativeInterface * QXcbIntegration::nativeInterface() const
+QPlatformInputContext *QXcbIntegration::inputContext() const
{
- return m_nativeInterface;
+ return m_inputContext;
}
diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h
index cd68919b54..cad127c28e 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.h
+++ b/src/plugins/platforms/xcb/qxcbintegration.h
@@ -48,34 +48,40 @@
QT_BEGIN_NAMESPACE
class QXcbConnection;
+class QAbstractEventDispatcher;
class QXcbIntegration : public QPlatformIntegration
{
public:
- QXcbIntegration();
+ QXcbIntegration(const QStringList &parameters);
~QXcbIntegration();
+ QPlatformWindow *createPlatformWindow(QWindow *window) const;
+ QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
+
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;
+ QAbstractEventDispatcher *guiThreadEventDispatcher() const;
- QList<QPlatformScreen *> screens() const;
- void moveToScreen(QWidget *window, int screen);
- bool isVirtualDesktop();
- QPixmap grabWindow(WId window, int x, int y, int width, int height) const;
+ void moveToScreen(QWindow *window, int screen);
QPlatformFontDatabase *fontDatabase() const;
QPlatformNativeInterface *nativeInterface()const;
+ QPlatformClipboard *clipboard() const;
+ QPlatformDrag *drag() const;
+
+ QPlatformInputContext *inputContext() const;
+
private:
- bool hasOpenGL() const;
- QList<QPlatformScreen *> m_screens;
- QXcbConnection *m_connection;
+ QList<QXcbConnection *> m_connections;
QPlatformFontDatabase *m_fontDatabase;
QPlatformNativeInterface *m_nativeInterface;
+
+ QPlatformInputContext *m_inputContext;
+ QAbstractEventDispatcher *m_eventDispatcher;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index 6bbc3c18ca..907dd0f1b6 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -40,16 +40,17 @@
****************************************************************************/
#include "qxcbkeyboard.h"
-
+#include "qxcbwindow.h"
+#include "qxcbscreen.h"
#include <xcb/xcb_keysyms.h>
-
#include <X11/keysym.h>
-
#include <QtGui/QWindowSystemInterface>
#include <QtCore/QTextCodec>
-
+#include <private/qguiapplication_p.h>
#include <stdio.h>
+#include <qplatforminputcontext_qpa.h>
+
#ifndef XK_ISO_Left_Tab
#define XK_ISO_Left_Tab 0xFE20
#endif
@@ -898,12 +899,9 @@ QString QXcbKeyboard::translateKeySym(xcb_keysym_t keysym, uint xmodifiers,
QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
: QXcbObject(connection)
- , m_alt_mask(0)
- , m_super_mask(0)
- , m_hyper_mask(0)
- , m_meta_mask(0)
{
m_key_symbols = xcb_key_symbols_alloc(xcb_connection());
+ setupModifiers();
}
QXcbKeyboard::~QXcbKeyboard()
@@ -911,18 +909,113 @@ QXcbKeyboard::~QXcbKeyboard()
xcb_key_symbols_free(m_key_symbols);
}
-// #define XCB_KEYBOARD_DEBUG
+void QXcbKeyboard::setupModifiers()
+{
+ m_alt_mask = 0;
+ m_super_mask = 0;
+ m_hyper_mask = 0;
+ m_meta_mask = 0;
+ m_mode_switch_mask = 0;
+ m_num_lock_mask = 0;
+ m_caps_lock_mask = 0;
+
+ xcb_generic_error_t *error = 0;
+ xcb_connection_t *conn = xcb_connection();
+ xcb_get_modifier_mapping_cookie_t modMapCookie = xcb_get_modifier_mapping(conn);
+ xcb_get_modifier_mapping_reply_t *modMapReply =
+ xcb_get_modifier_mapping_reply(conn, modMapCookie, &error);
+ if (error) {
+ qWarning("xcb keyboard: failed to get modifier mapping");
+ free(error);
+ return;
+ }
+
+ // Figure out the modifier mapping, ICCCM 6.6
+ typedef QPair<uint, xcb_keycode_t *> SymCodes;
+ QList<SymCodes> modKeyCodes;
+
+ // for Alt and Meta L and R are the same
+ modKeyCodes << SymCodes(XK_Alt_L, xcb_key_symbols_get_keycode(m_key_symbols, XK_Alt_L));
+ modKeyCodes << SymCodes(XK_Meta_L, xcb_key_symbols_get_keycode(m_key_symbols, XK_Meta_L));
+ modKeyCodes << SymCodes(XK_Super_L, xcb_key_symbols_get_keycode(m_key_symbols, XK_Super_L));
+ modKeyCodes << SymCodes(XK_Super_R, xcb_key_symbols_get_keycode(m_key_symbols, XK_Super_R));
+ modKeyCodes << SymCodes(XK_Hyper_L, xcb_key_symbols_get_keycode(m_key_symbols, XK_Hyper_L));
+ modKeyCodes << SymCodes(XK_Hyper_R, xcb_key_symbols_get_keycode(m_key_symbols, XK_Hyper_R));
+ modKeyCodes << SymCodes(XK_Num_Lock, xcb_key_symbols_get_keycode(m_key_symbols, XK_Num_Lock));
+ modKeyCodes << SymCodes(XK_Mode_switch, xcb_key_symbols_get_keycode(m_key_symbols, XK_Mode_switch));
+ modKeyCodes << SymCodes(XK_Caps_Lock, xcb_key_symbols_get_keycode(m_key_symbols, XK_Caps_Lock));
+
+ xcb_keycode_t *modMap = xcb_get_modifier_mapping_keycodes(modMapReply);
+ const int w = modMapReply->keycodes_per_modifier;
+ for (int i = 0; i < modKeyCodes.count(); ++i) {
+ for (int bit = 0; bit < 8; ++bit) {
+ uint mask = 1 << bit;
+ for (int x = 0; x < w; ++x) {
+ xcb_keycode_t keyCode = modMap[x + bit * w];
+ xcb_keycode_t *itk = modKeyCodes.at(i).second;
+ while (itk && *itk != XCB_NO_SYMBOL)
+ if (*itk++ == keyCode)
+ setMask(modKeyCodes.at(i).first, mask);
+ }
+ }
+ }
-void QXcbKeyboard::handleKeyEvent(QWidget *widget, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time)
+ for (int i = 0; i < modKeyCodes.count(); ++i)
+ free(modKeyCodes.at(i).second);
+ free(modMapReply);
+}
+
+void QXcbKeyboard::setMask(uint sym, uint mask)
{
- int col = state & XCB_MOD_MASK_SHIFT ? 1 : 0;
+ if (m_alt_mask == 0
+ && m_meta_mask != mask
+ && m_super_mask != mask
+ && m_hyper_mask != mask
+ && (sym == XK_Alt_L || sym == XK_Alt_R))
+ m_alt_mask = mask;
+
+ if (m_meta_mask == 0
+ && m_alt_mask != mask
+ && m_super_mask != mask
+ && m_hyper_mask != mask
+ && (sym == XK_Meta_L || sym == XK_Meta_R))
+ m_meta_mask = mask;
+
+ if (m_super_mask == 0
+ && m_alt_mask != mask
+ && m_meta_mask != mask
+ && m_hyper_mask != mask
+ && (sym == XK_Super_L || sym == XK_Super_R))
+ m_super_mask = mask;
+
+ if (m_hyper_mask == 0
+ && m_alt_mask != mask
+ && m_meta_mask != mask
+ && m_super_mask != mask
+ && (sym == XK_Hyper_L || sym == XK_Hyper_R))
+ m_hyper_mask = mask;
+
+ if (m_mode_switch_mask == 0
+ && m_alt_mask != mask
+ && m_meta_mask != mask
+ && m_super_mask != mask
+ && m_hyper_mask != mask
+ && sym == XK_Mode_switch)
+ m_mode_switch_mask = mask;
+
+ if (m_num_lock_mask == 0 && sym == XK_Num_Lock)
+ m_num_lock_mask = mask;
+
+ if (m_caps_lock_mask == 0 && sym == XK_Caps_Lock)
+ m_caps_lock_mask = mask;
+}
- const int altGrOffset = 4;
- if (state & 128)
- col += altGrOffset;
+// #define XCB_KEYBOARD_DEBUG
+void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code,
+ quint16 state, xcb_timestamp_t time)
+{
Q_XCB_NOOP(connection());
-
#ifdef XCB_KEYBOARD_DEBUG
printf("key code: %d, state: %d, syms: ", code, state);
for (int i = 0; i <= 5; ++i) {
@@ -931,43 +1024,105 @@ void QXcbKeyboard::handleKeyEvent(QWidget *widget, QEvent::Type type, xcb_keycod
printf("\n");
#endif
- Q_XCB_NOOP(connection());
+ QByteArray chars;
+ xcb_keysym_t sym = lookupString(window, state, code, type, &chars);
+
+
+ if (QObject* inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext()) {
+ bool retval;
+ QMetaObject::invokeMethod(inputContext, "x11FilterEvent", Qt::DirectConnection,
+ Q_RETURN_ARG(bool, retval),
+ Q_ARG(uint, sym),
+ Q_ARG(uint, code),
+ Q_ARG(uint, state),
+ Q_ARG(bool, type == QEvent::KeyPress));
+ if (retval)
+ return;
+ }
+ Qt::KeyboardModifiers modifiers;
+ int qtcode = 0;
+ int count = chars.count();
+ QString string = translateKeySym(sym, state, qtcode, modifiers, chars, count);
+ QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers,
+ code, 0, state, string.left(count));
+}
+
+#ifdef XCB_USE_XLIB
+extern "C" {
+ int XLookupString(void *event, char *buf, int count, void *keysym, void *comp);
+}
+typedef struct { // must match XKeyEvent in Xlib.h
+ int type;
+ unsigned long serial;
+ int send_event;
+ void *display;
+ unsigned long window;
+ unsigned long root;
+ unsigned long subwindow;
+ unsigned long time;
+ int x, y;
+ int x_root, y_root;
+ unsigned int state;
+ unsigned int keycode;
+ int same_screen;
+} FakeXKeyEvent;
+#endif
+
+xcb_keysym_t QXcbKeyboard::lookupString(QWindow *window, uint state, xcb_keycode_t code,
+ QEvent::Type type, QByteArray *chars)
+{
+#ifdef XCB_USE_XLIB
+
+ xcb_keysym_t sym = XCB_NO_SYMBOL;
+ chars->resize(512);
+ FakeXKeyEvent event;
+ memset(&event, 0, sizeof(event));
+ event.type = (type == QEvent::KeyRelease ? 3 : 2);
+ event.display = connection()->xlib_display();
+ event.window = static_cast<QXcbWindow *>(window->handle())->xcb_window();
+ event.root = connection()->screens().at(0)->root();
+ event.state = state;
+ event.keycode = code;
+ int count = XLookupString(&event, chars->data(), chars->size(), &sym, 0);
+ chars->resize(count);
+ return sym;
+
+#else
+
+ // No XLookupString available. The following is really incomplete...
+
+ int col = state & XCB_MOD_MASK_SHIFT ? 1 : 0;
+ const int altGrOffset = 4;
+ if (state & 128)
+ col += altGrOffset;
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);
-
if (state & XCB_MOD_MASK_LOCK && sym <= 0x7f && isprint(sym)) {
if (isupper(sym))
sym = tolower(sym);
else
sym = toupper(sym);
}
+ return sym;
- Q_XCB_NOOP(connection());
-
- QByteArray chars;
-
- Qt::KeyboardModifiers modifiers;
- int qtcode = 0;
- int count = 0;
-
- QString string = translateKeySym(sym, state, qtcode, modifiers, chars, count);
-
- QWindowSystemInterface::handleExtendedKeyEvent(widget, time, type, qtcode, modifiers, code, 0, state, string.left(count));
+#endif
}
-void QXcbKeyboard::handleKeyPressEvent(QWidget *widget, const xcb_key_press_event_t *event)
+void QXcbKeyboard::handleKeyPressEvent(QXcbWindow *window, const xcb_key_press_event_t *event)
{
- handleKeyEvent(widget, QEvent::KeyPress, event->detail, event->state, event->time);
+ window->updateNetWmUserTime(event->time);
+ handleKeyEvent(window->window(), QEvent::KeyPress, event->detail, event->state, event->time);
}
-void QXcbKeyboard::handleKeyReleaseEvent(QWidget *widget, const xcb_key_release_event_t *event)
+void QXcbKeyboard::handleKeyReleaseEvent(QXcbWindow *window, const xcb_key_release_event_t *event)
{
- handleKeyEvent(widget, QEvent::KeyRelease, event->detail, event->state, event->time);
+ handleKeyEvent(window->window(), QEvent::KeyRelease, event->detail, event->state, event->time);
}
void QXcbKeyboard::handleMappingNotifyEvent(const xcb_mapping_notify_event_t *event)
{
xcb_refresh_keyboard_mapping(m_key_symbols, const_cast<xcb_mapping_notify_event_t *>(event));
+ setupModifiers();
}
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index 095c3e4efb..ea5f84e8c2 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -48,26 +48,32 @@
#include <QEvent>
+class QWindow;
+
class QXcbKeyboard : public QXcbObject
{
public:
QXcbKeyboard(QXcbConnection *connection);
~QXcbKeyboard();
- void handleKeyPressEvent(QWidget *widget, const xcb_key_press_event_t *event);
- void handleKeyReleaseEvent(QWidget *widget, const xcb_key_release_event_t *event);
+ void handleKeyPressEvent(QXcbWindow *window, const xcb_key_press_event_t *event);
+ void handleKeyReleaseEvent(QXcbWindow *window, const xcb_key_release_event_t *event);
void handleMappingNotifyEvent(const xcb_mapping_notify_event_t *event);
Qt::KeyboardModifiers translateModifiers(int s);
private:
- void handleKeyEvent(QWidget *widget, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time);
+ void handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time);
int translateKeySym(uint key) const;
QString translateKeySym(xcb_keysym_t keysym, uint xmodifiers,
int &code, Qt::KeyboardModifiers &modifiers,
QByteArray &chars, int &count);
+ void setupModifiers();
+ void setMask(uint sym, uint mask);
+ xcb_keysym_t lookupString(QWindow *window, uint state, xcb_keycode_t code,
+ QEvent::Type type, QByteArray *chars);
uint m_alt_mask;
uint m_super_mask;
@@ -75,6 +81,7 @@ private:
uint m_meta_mask;
uint m_mode_switch_mask;
uint m_num_lock_mask;
+ uint m_caps_lock_mask;
xcb_key_symbols_t *m_key_symbols;
};
diff --git a/src/plugins/platforms/xcb/qxcbmime.cpp b/src/plugins/platforms/xcb/qxcbmime.cpp
new file mode 100644
index 0000000000..d4f80ca09d
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbmime.cpp
@@ -0,0 +1,288 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qxcbmime.h"
+
+#include <QtCore/QTextCodec>
+#include <QtGui/QImageWriter>
+#include <QtCore/QBuffer>
+#include <qdebug.h>
+
+#include <X11/Xutil.h>
+
+#undef XCB_ATOM_STRING
+#undef XCB_ATOM_PIXMAP
+#undef XCB_ATOM_BITMAP
+
+QXcbMime::QXcbMime()
+ : QInternalMimeData()
+{ }
+
+QXcbMime::~QXcbMime()
+{}
+
+
+
+QString QXcbMime::mimeAtomToString(QXcbConnection *connection, xcb_atom_t a)
+{
+ if (a == XCB_NONE)
+ return QString();
+
+ // special cases for string type
+ if (a == XCB_ATOM_STRING
+ || a == connection->atom(QXcbAtom::UTF8_STRING)
+ || a == connection->atom(QXcbAtom::TEXT))
+ return QLatin1String("text/plain");
+
+ // special case for images
+ if (a == XCB_ATOM_PIXMAP)
+ return QLatin1String("image/ppm");
+
+ QByteArray atomName = connection->atomName(a);
+
+ // special cases for uris
+ if (atomName == "text/x-moz-url")
+ atomName = "text/uri-list";
+
+ return QString::fromLatin1(atomName.constData());
+}
+
+bool QXcbMime::mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeData *mimeData, QByteArray *data,
+ xcb_atom_t *atomFormat, int *dataFormat)
+{
+ if (!data)
+ return false;
+
+ bool ret = false;
+ *atomFormat = a;
+ *dataFormat = 8;
+
+ if ((a == connection->atom(QXcbAtom::UTF8_STRING)
+ || a == XCB_ATOM_STRING
+ || a == connection->atom(QXcbAtom::TEXT))
+ && QInternalMimeData::hasFormatHelper(QLatin1String("text/plain"), mimeData)) {
+ if (a == connection->atom(QXcbAtom::UTF8_STRING)) {
+ *data = QInternalMimeData::renderDataHelper(QLatin1String("text/plain"), mimeData);
+ ret = true;
+ } else if (a == XCB_ATOM_STRING ||
+ a == connection->atom(QXcbAtom::TEXT)) {
+ // ICCCM says STRING is latin1
+ *data = QString::fromUtf8(QInternalMimeData::renderDataHelper(
+ QLatin1String("text/plain"), mimeData)).toLatin1();
+ ret = true;
+ }
+ return ret;
+ }
+
+ QString atomName = mimeAtomToString(connection, a);
+ if (QInternalMimeData::hasFormatHelper(atomName, mimeData)) {
+ *data = QInternalMimeData::renderDataHelper(atomName, mimeData);
+ if (atomName == QLatin1String("application/x-color"))
+ *dataFormat = 16;
+ ret = true;
+ } else if (atomName == QLatin1String("text/x-moz-url") &&
+ QInternalMimeData::hasFormatHelper(QLatin1String("text/uri-list"), mimeData)) {
+ QByteArray uri = QInternalMimeData::renderDataHelper(
+ QLatin1String("text/uri-list"), mimeData).split('\n').first();
+ QString mozUri = QString::fromLatin1(uri, uri.size());
+ mozUri += QLatin1Char('\n');
+ *data = QByteArray(reinterpret_cast<const char *>(mozUri.utf16()), mozUri.length() * 2);
+ ret = true;
+ } else if ((a == XCB_ATOM_PIXMAP || a == XCB_ATOM_BITMAP) && mimeData->hasImage()) {
+ ret = true;
+ }
+ return ret;
+}
+
+QList<xcb_atom_t> QXcbMime::mimeAtomsForFormat(QXcbConnection *connection, const QString &format)
+{
+ QList<xcb_atom_t> atoms;
+ atoms.append(connection->internAtom(format.toLatin1()));
+
+ // special cases for strings
+ if (format == QLatin1String("text/plain")) {
+ atoms.append(connection->atom(QXcbAtom::UTF8_STRING));
+ atoms.append(XCB_ATOM_STRING);
+ atoms.append(connection->atom(QXcbAtom::TEXT));
+ }
+
+ // special cases for uris
+ if (format == QLatin1String("text/uri-list"))
+ atoms.append(connection->internAtom("text/x-moz-url"));
+
+ //special cases for images
+ if (format == QLatin1String("image/ppm"))
+ atoms.append(XCB_ATOM_PIXMAP);
+ if (format == QLatin1String("image/pbm"))
+ atoms.append(XCB_ATOM_BITMAP);
+
+ return atoms;
+}
+
+QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &data, const QString &format,
+ QVariant::Type requestedType, const QByteArray &encoding)
+{
+ QString atomName = mimeAtomToString(connection, a);
+// qDebug() << "mimeConvertDataToFormat" << format << atomName << data;
+
+ if (!encoding.isEmpty()
+ && atomName == format + QLatin1String(";charset=") + QString::fromLatin1(encoding)) {
+
+ if (requestedType == QVariant::String) {
+ QTextCodec *codec = QTextCodec::codecForName(encoding);
+ if (codec)
+ return codec->toUnicode(data);
+ }
+
+ return data;
+ }
+
+ // special cases for string types
+ if (format == QLatin1String("text/plain")) {
+ if (a == connection->atom(QXcbAtom::UTF8_STRING))
+ return QString::fromUtf8(data);
+ if (a == XCB_ATOM_STRING ||
+ a == connection->atom(QXcbAtom::TEXT))
+ return QString::fromLatin1(data);
+ }
+
+ // special case for uri types
+ if (format == QLatin1String("text/uri-list")) {
+ if (atomName == QLatin1String("text/x-moz-url")) {
+ // we expect this as utf16 <url><space><title>
+ // the first part is a url that should only contain ascci char
+ // so it should be safe to check that the second char is 0
+ // to verify that it is utf16
+ if (data.size() > 1 && data.at(1) == 0)
+ return QString::fromRawData((const QChar *)data.constData(),
+ data.size() / 2).split(QLatin1Char('\n')).first().toLatin1();
+ }
+ }
+
+ if (atomName == format)
+ return data;
+
+#if 0 // ###
+ // special case for images
+ if (format == QLatin1String("image/ppm")) {
+ if (a == XCB_ATOM_PIXMAP && data.size() == sizeof(Pixmap)) {
+ Pixmap xpm = *((Pixmap*)data.data());
+ if (!xpm)
+ return QByteArray();
+ Window root;
+ int x;
+ int y;
+ uint width;
+ uint height;
+ uint border_width;
+ uint depth;
+
+ XGetGeometry(display, xpm, &root, &x, &y, &width, &height, &border_width, &depth);
+ XImage *ximg = XGetImage(display,xpm,x,y,width,height,AllPlanes,depth==1 ? XYPixmap : ZPixmap);
+ QImage qimg = QXlibStatic::qimageFromXImage(ximg);
+ XDestroyImage(ximg);
+
+ QImageWriter imageWriter;
+ imageWriter.setFormat("PPMRAW");
+ QBuffer buf;
+ buf.open(QIODevice::WriteOnly);
+ imageWriter.setDevice(&buf);
+ imageWriter.write(qimg);
+ return buf.buffer();
+ }
+ }
+#endif
+ return QVariant();
+}
+
+xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString &format, QVariant::Type requestedType,
+ const QList<xcb_atom_t> &atoms, QByteArray *requestedEncoding)
+{
+ requestedEncoding->clear();
+
+ // find matches for string types
+ if (format == QLatin1String("text/plain")) {
+ if (atoms.contains(connection->atom(QXcbAtom::UTF8_STRING)))
+ return connection->atom(QXcbAtom::UTF8_STRING);
+ if (atoms.contains(XCB_ATOM_STRING))
+ return XCB_ATOM_STRING;
+ if (atoms.contains(connection->atom(QXcbAtom::TEXT)))
+ return connection->atom(QXcbAtom::TEXT);
+ }
+
+ // find matches for uri types
+ if (format == QLatin1String("text/uri-list")) {
+ xcb_atom_t a = connection->internAtom(format.toLatin1());
+ if (a && atoms.contains(a))
+ return a;
+ a = connection->internAtom("text/x-moz-url");
+ if (a && atoms.contains(a))
+ return a;
+ }
+
+ // find match for image
+ if (format == QLatin1String("image/ppm")) {
+ if (atoms.contains(XCB_ATOM_PIXMAP))
+ return XCB_ATOM_PIXMAP;
+ }
+
+ // for string/text requests try to use a format with a well-defined charset
+ // first to avoid encoding problems
+ if (requestedType == QVariant::String
+ && format.startsWith(QLatin1String("text/"))
+ && !format.contains(QLatin1String("charset="))) {
+
+ QString formatWithCharset = format;
+ formatWithCharset.append(QLatin1String(";charset=utf-8"));
+
+ xcb_atom_t a = connection->internAtom(formatWithCharset.toLatin1());
+ if (a && atoms.contains(a)) {
+ *requestedEncoding = "utf-8";
+ return a;
+ }
+ }
+
+ xcb_atom_t a = connection->internAtom(format.toLatin1());
+ if (a && atoms.contains(a))
+ return a;
+
+ return 0;
+}
diff --git a/src/plugins/platforms/xcb/qxcbmime.h b/src/plugins/platforms/xcb/qxcbmime.h
new file mode 100644
index 0000000000..4ab38ed803
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbmime.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QXCBMIME_H
+#define QXCBMIME_H
+
+#include <private/qdnd_p.h>
+
+#include <QtGui/QClipboard>
+
+#include "qxcbintegration.h"
+#include "qxcbconnection.h"
+
+class QXcbMime : public QInternalMimeData {
+ Q_OBJECT
+public:
+ QXcbMime();
+ ~QXcbMime();
+
+ static QList<xcb_atom_t> mimeAtomsForFormat(QXcbConnection *connection, const QString &format);
+ static QString mimeAtomToString(QXcbConnection *connection, xcb_atom_t a);
+ static bool mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeData *mimeData, QByteArray *data,
+ xcb_atom_t *atomFormat, int *dataFormat);
+ static QVariant mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &data, const QString &format,
+ QVariant::Type requestedType, const QByteArray &encoding);
+ static xcb_atom_t mimeAtomForFormat(QXcbConnection *connection, const QString &format, QVariant::Type requestedType,
+ const QList<xcb_atom_t> &atoms, QByteArray *requestedEncoding);
+};
+
+#endif // QXCBMIME_H
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index 6423f1b798..3c9cdfd257 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -43,13 +43,16 @@
#include "qxcbscreen.h"
-#include <QtGui/private/qapplication_p.h>
+#include <private/qguiapplication_p.h>
#include <QtCore/QMap>
#include <QtCore/QDebug>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qscreen.h>
+
#if defined(XCB_USE_EGL)
-#include "../eglconvenience/qeglplatformcontext.h"
+#include "QtPlatformSupport/private/qeglplatformcontext_p.h"
#elif defined (XCB_USE_DRI2)
#include "qdri2context.h"
#endif
@@ -71,29 +74,41 @@ public:
Q_GLOBAL_STATIC(QXcbResourceMap, qXcbResourceMap)
-void *QXcbNativeInterface::nativeResourceForWidget(const QByteArray &resourceString, QWidget *widget)
+void *QXcbNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context)
+{
+ QByteArray lowerCaseResource = resourceString.toLower();
+ ResourceType resource = qXcbResourceMap()->value(lowerCaseResource);
+ void *result = 0;
+ switch(resource) {
+ case EglContext:
+ result = eglContextForContext(context);
+ break;
+ default:
+ result = 0;
+ }
+ return result;
+}
+
+void *QXcbNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window)
{
QByteArray lowerCaseResource = resourceString.toLower();
ResourceType resource = qXcbResourceMap()->value(lowerCaseResource);
void *result = 0;
switch(resource) {
case Display:
- result = displayForWidget(widget);
+ result = displayForWindow(window);
break;
case EglDisplay:
- result = eglDisplayForWidget(widget);
+ result = eglDisplayForWindow(window);
break;
case Connection:
- result = connectionForWidget(widget);
+ result = connectionForWindow(window);
break;
case Screen:
- result = qPlatformScreenForWidget(widget);
+ result = qPlatformScreenForWindow(window);
break;
case GraphicsDevice:
- result = graphicsDeviceForWidget(widget);
- break;
- case EglContext:
- result = eglContextForWidget(widget);
+ result = graphicsDeviceForWindow(window);
break;
default:
result = 0;
@@ -101,75 +116,76 @@ void *QXcbNativeInterface::nativeResourceForWidget(const QByteArray &resourceStr
return result;
}
-QXcbScreen *QXcbNativeInterface::qPlatformScreenForWidget(QWidget *widget)
+QXcbScreen *QXcbNativeInterface::qPlatformScreenForWindow(QWindow *window)
{
QXcbScreen *screen;
- if (widget) {
- screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(widget));
- }else {
- screen = static_cast<QXcbScreen *>(QApplicationPrivate::platformIntegration()->screens()[0]);
+ if (window) {
+ screen = static_cast<QXcbScreen *>(window->screen()->handle());
+ } else {
+ screen = static_cast<QXcbScreen *>(QGuiApplication::primaryScreen()->handle());
}
return screen;
}
-void *QXcbNativeInterface::displayForWidget(QWidget *widget)
+void *QXcbNativeInterface::displayForWindow(QWindow *window)
{
#if defined(XCB_USE_XLIB)
- QXcbScreen *screen = qPlatformScreenForWidget(widget);
+ QXcbScreen *screen = qPlatformScreenForWindow(window);
return screen->connection()->xlib_display();
#else
- Q_UNUSED(widget);
+ Q_UNUSED(window);
return 0;
#endif
}
-void *QXcbNativeInterface::eglDisplayForWidget(QWidget *widget)
+void *QXcbNativeInterface::eglDisplayForWindow(QWindow *window)
{
#if defined(XCB_USE_DRI2) || defined(XCB_USE_EGL)
- QXcbScreen *screen = qPlatformScreenForWidget(widget);
+ QXcbScreen *screen = qPlatformScreenForWindow(window);
return screen->connection()->egl_display();
#else
- Q_UNUSED(widget)
+ Q_UNUSED(window)
return 0;
#endif
}
-void *QXcbNativeInterface::connectionForWidget(QWidget *widget)
+void *QXcbNativeInterface::connectionForWindow(QWindow *window)
{
- QXcbScreen *screen = qPlatformScreenForWidget(widget);
+ QXcbScreen *screen = qPlatformScreenForWindow(window);
return screen->xcb_connection();
}
-void *QXcbNativeInterface::screenForWidget(QWidget *widget)
+void *QXcbNativeInterface::screenForWindow(QWindow *window)
{
- QXcbScreen *screen = qPlatformScreenForWidget(widget);
+ QXcbScreen *screen = qPlatformScreenForWindow(window);
return screen->screen();
}
-void *QXcbNativeInterface::graphicsDeviceForWidget(QWidget *widget)
+void *QXcbNativeInterface::graphicsDeviceForWindow(QWindow *window)
{
#if defined(XCB_USE_DRI2)
- QXcbScreen *screen = qPlatformScreenForWidget(widget);
+ QXcbScreen *screen = qPlatformScreenForWindow(window);
QByteArray deviceName = screen->connection()->dri2DeviceName();
return deviceName.data();
#else
- Q_UNUSED(widget);
+ Q_UNUSED(window);
return 0;
#endif
}
-void * QXcbNativeInterface::eglContextForWidget(QWidget *widget)
+void * QXcbNativeInterface::eglContextForContext(QOpenGLContext *context)
{
- Q_ASSERT(widget);
- if (!widget->platformWindow()) {
- qDebug() << "QPlatformWindow does not exist for widget" << widget
- << "cannot return EGLContext";
- return 0;
- }
- QPlatformGLContext *platformContext = widget->platformWindow()->glContext();
+ Q_ASSERT(context);
+#if defined(XCB_USE_EGL)
+ QEGLPlatformContext *eglPlatformContext = static_cast<QEGLPlatformContext *>(context->handle());
+ return eglPlatformContext->eglContext();
+#endif
+#if 0
+ Q_ASSERT(window);
+ QPlatformOpenGLContext *platformContext = window->glContext()->handle();
if (!platformContext) {
- qDebug() << "QPlatformWindow" << widget->platformWindow() << "does not have a glContext"
+ qDebug() << "QWindow" << window << "does not have a glContext"
<< "cannot return EGLContext";
return 0;
}
@@ -182,4 +198,7 @@ void * QXcbNativeInterface::eglContextForWidget(QWidget *widget)
#else
return 0;
#endif
+#else
+ return 0;
+#endif
}
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h
index 3fb0fa5e2d..8dec83267a 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.h
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h
@@ -59,17 +59,19 @@ public:
EglContext
};
- void *nativeResourceForWidget(const QByteArray &resourceString, QWidget *widget);
+ void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context);
+ void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window);
- void *displayForWidget(QWidget *widget);
- void *eglDisplayForWidget(QWidget *widget);
- void *connectionForWidget(QWidget *widget);
- void *screenForWidget(QWidget *widget);
- void *graphicsDeviceForWidget(QWidget *widget);
- void *eglContextForWidget(QWidget *widget);
+ void *displayForWindow(QWindow *window);
+ void *eglDisplayForWindow(QWindow *window);
+ void *connectionForWindow(QWindow *window);
+ void *screenForWindow(QWindow *window);
+ void *graphicsDeviceForWindow(QWindow *window);
+
+ void *eglContextForContext(QOpenGLContext *context);
private:
- static QXcbScreen *qPlatformScreenForWidget(QWidget *widget);
+ static QXcbScreen *qPlatformScreenForWindow(QWindow *window);
};
#endif // QXCBNATIVEINTERFACE_H
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 9a4858123b..42259feda8 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -40,6 +40,9 @@
****************************************************************************/
#include "qxcbscreen.h"
+#include "qxcbwindow.h"
+#include "qxcbcursor.h"
+#include "qxcbimage.h"
#include <stdio.h>
@@ -102,10 +105,104 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num
free(reply);
m_syncRequestSupported = m_windowManagerName != QLatin1String("KWin");
+
+ m_clientLeader = xcb_generate_id(xcb_connection());
+ Q_XCB_CALL2(xcb_create_window(xcb_connection(),
+ XCB_COPY_FROM_PARENT,
+ m_clientLeader,
+ m_screen->root,
+ 0, 0, 1, 1,
+ 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ m_screen->root_visual,
+ 0, 0), connection);
+
+ Q_XCB_CALL2(xcb_change_property(xcb_connection(),
+ XCB_PROP_MODE_REPLACE,
+ m_clientLeader,
+ atom(QXcbAtom::WM_CLIENT_LEADER),
+ XCB_ATOM_WINDOW,
+ 32,
+ 1,
+ &m_clientLeader), connection);
+
+ xcb_depth_iterator_t depth_iterator =
+ xcb_screen_allowed_depths_iterator(screen);
+
+ while (depth_iterator.rem) {
+ xcb_depth_t *depth = depth_iterator.data;
+ xcb_visualtype_iterator_t visualtype_iterator =
+ xcb_depth_visuals_iterator(depth);
+
+ while (visualtype_iterator.rem) {
+ xcb_visualtype_t *visualtype = visualtype_iterator.data;
+ m_visuals.insert(visualtype->visual_id, *visualtype);
+ xcb_visualtype_next(&visualtype_iterator);
+ }
+
+ xcb_depth_next(&depth_iterator);
+ }
+
+ m_cursor = new QXcbCursor(connection, this);
}
QXcbScreen::~QXcbScreen()
{
+ delete m_cursor;
+}
+
+
+QWindow *QXcbScreen::topLevelAt(const QPoint &p) const
+{
+ xcb_window_t root = m_screen->root;
+
+ int x = p.x();
+ int y = p.y();
+
+ xcb_generic_error_t *error;
+
+ xcb_window_t parent = root;
+ xcb_window_t child = root;
+
+ do {
+ xcb_translate_coordinates_cookie_t translate_cookie =
+ xcb_translate_coordinates(xcb_connection(), parent, child, x, y);
+
+ xcb_translate_coordinates_reply_t *translate_reply =
+ xcb_translate_coordinates_reply(xcb_connection(), translate_cookie, &error);
+
+ if (!translate_reply) {
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+ return 0;
+ }
+
+ parent = child;
+ child = translate_reply->child;
+ x = translate_reply->dst_x;
+ y = translate_reply->dst_y;
+
+ free(translate_reply);
+
+ if (!child || child == root)
+ return 0;
+
+ QPlatformWindow *platformWindow = connection()->platformWindowFromId(child);
+ if (platformWindow)
+ return platformWindow->window();
+ } while (parent != child);
+
+ return 0;
+}
+
+const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid) const
+{
+ QMap<xcb_visualid_t, xcb_visualtype_t>::const_iterator it = m_visuals.find(visualid);
+ if (it == m_visuals.constEnd())
+ return 0;
+ return &*it;
}
QRect QXcbScreen::geometry() const
@@ -132,3 +229,126 @@ int QXcbScreen::screenNumber() const
{
return m_number;
}
+
+QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height) const
+{
+ if (width == 0 || height == 0)
+ return QPixmap();
+
+ xcb_get_geometry_cookie_t geometry_cookie = xcb_get_geometry(xcb_connection(), window);
+
+ xcb_generic_error_t *error;
+ xcb_get_geometry_reply_t *reply =
+ xcb_get_geometry_reply(xcb_connection(), geometry_cookie, &error);
+
+ if (!reply) {
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+ return QPixmap();
+ }
+
+ if (width < 0)
+ width = reply->width - x;
+ if (height < 0)
+ height = reply->height - y;
+
+ // TODO: handle multiple screens
+ QXcbScreen *screen = const_cast<QXcbScreen *>(this);
+ xcb_window_t root = screen->root();
+ geometry_cookie = xcb_get_geometry(xcb_connection(), root);
+ xcb_get_geometry_reply_t *root_reply =
+ xcb_get_geometry_reply(xcb_connection(), geometry_cookie, &error);
+
+ if (!root_reply) {
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+ free(reply);
+ return QPixmap();
+ }
+
+ if (reply->depth == root_reply->depth) {
+ // if the depth of the specified window and the root window are the
+ // same, grab pixels from the root window (so that we get the any
+ // overlapping windows and window manager frames)
+
+ // map x and y to the root window
+ xcb_translate_coordinates_cookie_t translate_cookie =
+ xcb_translate_coordinates(xcb_connection(), window, root, x, y);
+
+ xcb_translate_coordinates_reply_t *translate_reply =
+ xcb_translate_coordinates_reply(xcb_connection(), translate_cookie, &error);
+
+ if (!translate_reply) {
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+ free(reply);
+ free(root_reply);
+ return QPixmap();
+ }
+
+ x = translate_reply->dst_x;
+ y = translate_reply->dst_y;
+
+ window = root;
+
+ free(translate_reply);
+ free(reply);
+ reply = root_reply;
+ } else {
+ free(root_reply);
+ root_reply = 0;
+ }
+
+ xcb_get_window_attributes_reply_t *attributes_reply =
+ xcb_get_window_attributes_reply(xcb_connection(), xcb_get_window_attributes(xcb_connection(), window), &error);
+
+ if (!attributes_reply) {
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+ free(reply);
+ return QPixmap();
+ }
+
+ const xcb_visualtype_t *visual = screen->visualForId(attributes_reply->visual);
+ free(attributes_reply);
+
+ xcb_pixmap_t pixmap = xcb_generate_id(xcb_connection());
+ error = xcb_request_check(xcb_connection(), xcb_create_pixmap_checked(xcb_connection(), reply->depth, pixmap, window, width, height));
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+
+ uint32_t gc_value_mask = XCB_GC_SUBWINDOW_MODE;
+ uint32_t gc_value_list[] = { XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS };
+
+ xcb_gcontext_t gc = xcb_generate_id(xcb_connection());
+ xcb_create_gc(xcb_connection(), gc, pixmap, gc_value_mask, gc_value_list);
+
+ error = xcb_request_check(xcb_connection(), xcb_copy_area_checked(xcb_connection(), window, pixmap, gc, x, y, 0, 0, width, height));
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+
+ QPixmap result = qt_xcb_pixmapFromXPixmap(connection(), pixmap, width, height, reply->depth, visual);
+
+ free(reply);
+ xcb_free_gc(xcb_connection(), gc);
+ xcb_free_pixmap(xcb_connection(), pixmap);
+
+ return result;
+}
+
+QString QXcbScreen::name() const
+{
+ return connection()->displayName() + QLatin1String(".") + QString::number(screenNumber());
+}
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index a78ee822f4..07d855b398 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -50,6 +50,7 @@
#include "qxcbobject.h"
class QXcbConnection;
+class QXcbCursor;
class QXcbScreen : public QXcbObject, public QPlatformScreen
{
@@ -57,6 +58,10 @@ public:
QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int number);
~QXcbScreen();
+ QPixmap grabWindow(WId window, int x, int y, int width, int height) const;
+
+ QWindow *topLevelAt(const QPoint &point) const;
+
QRect geometry() const;
int depth() const;
QImage::Format format() const;
@@ -67,14 +72,23 @@ public:
xcb_screen_t *screen() const { return m_screen; }
xcb_window_t root() const { return m_screen->root; }
+ xcb_window_t clientLeader() const { return m_clientLeader; }
+
QString windowManagerName() const { return m_windowManagerName; }
bool syncRequestSupported() const { return m_syncRequestSupported; }
+ const xcb_visualtype_t *visualForId(xcb_visualid_t) const;
+
+ QString name() const;
+
private:
xcb_screen_t *m_screen;
int m_number;
QString m_windowManagerName;
bool m_syncRequestSupported;
+ xcb_window_t m_clientLeader;
+ QMap<xcb_visualid_t, xcb_visualtype_t> m_visuals;
+ QXcbCursor *m_cursor;
};
#endif
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 20e4187541..db8d37e817 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -42,9 +42,13 @@
#include "qxcbwindow.h"
#include <QtDebug>
+#include <QScreen>
#include "qxcbconnection.h"
#include "qxcbscreen.h"
+#include "qxcbdrag.h"
+#include "qxcbwmsupport.h"
+
#ifdef XCB_USE_DRI2
#include "qdri2context.h"
#endif
@@ -61,9 +65,10 @@
#define xcb_set_wm_hints xcb_icccm_set_wm_hints
#endif
-#include <private/qapplication_p.h>
-#include <private/qwindowsurface_p.h>
+#include <private/qguiapplication_p.h>
+#include <private/qwindow_p.h>
+#include <QtGui/QPlatformBackingStore>
#include <QtGui/QWindowSystemInterface>
#include <stdio.h>
@@ -75,38 +80,71 @@
#if defined(XCB_USE_GLX)
#include "qglxintegration.h"
-#include "qglxconvenience.h"
+#include <QtPlatformSupport/private/qglxconvenience_p.h>
#elif defined(XCB_USE_EGL)
-#include "../eglconvenience/qeglplatformcontext.h"
-#include "../eglconvenience/qeglconvenience.h"
-#include "../eglconvenience/qxlibeglintegration.h"
+#include "qxcbeglsurface.h"
+#include <QtPlatformSupport/private/qeglconvenience_p.h>
+#include <QtPlatformSupport/private/qxlibeglintegration_p.h>
#endif
+#define XCOORD_MAX 16383
+
+//#ifdef NET_WM_STATE_DEBUG
+
// Returns true if we should set WM_TRANSIENT_FOR on \a w
-static inline bool isTransient(const QWidget *w)
+static inline bool isTransient(const QWindow *w)
{
- return ((w->windowType() == Qt::Dialog
- || w->windowType() == Qt::Sheet
- || w->windowType() == Qt::Tool
- || w->windowType() == Qt::SplashScreen
- || w->windowType() == Qt::ToolTip
- || w->windowType() == Qt::Drawer
- || w->windowType() == Qt::Popup)
- && !w->testAttribute(Qt::WA_X11BypassTransientForHint));
+ return w->windowType() == Qt::Dialog
+ || w->windowType() == Qt::Sheet
+ || w->windowType() == Qt::Tool
+ || w->windowType() == Qt::SplashScreen
+ || w->windowType() == Qt::ToolTip
+ || w->windowType() == Qt::Drawer
+ || w->windowType() == Qt::Popup;
}
-QXcbWindow::QXcbWindow(QWidget *tlw)
- : QPlatformWindow(tlw)
- , m_context(0)
+QXcbWindow::QXcbWindow(QWindow *window)
+ : QPlatformWindow(window)
+ , m_window(0)
+ , m_syncCounter(0)
+ , m_mapped(false)
+ , m_netWmUserTimeWindow(XCB_NONE)
+#if defined(XCB_USE_EGL)
+ , m_eglSurface(0)
+#endif
{
- m_screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(tlw));
+ m_screen = static_cast<QXcbScreen *>(window->screen()->handle());
setConnection(m_screen->connection());
- const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_EVENT_MASK;
+ create();
+}
+
+void QXcbWindow::create()
+{
+ destroy();
+
+ m_windowState = Qt::WindowNoState;
+ m_dirtyFrameMargins = true;
+
+ Qt::WindowType type = window()->windowType();
+
+ if (type == Qt::Desktop) {
+ m_window = m_screen->root();
+ m_depth = m_screen->screen()->root_depth;
+ m_imageFormat = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
+ connection()->addWindow(m_window, this);
+ return;
+ }
+
+ const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK;
const quint32 values[] = {
// XCB_CW_BACK_PIXMAP
XCB_NONE,
+ // XCB_CW_OVERRIDE_REDIRECT
+ type == Qt::Popup || type == Qt::ToolTip,
+ // XCB_CW_SAVE_UNDER
+ type == Qt::Popup || type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip || type == Qt::Drawer,
// XCB_CW_EVENT_MASK
XCB_EVENT_MASK_EXPOSURE
| XCB_EVENT_MASK_STRUCTURE_NOTIFY
@@ -117,20 +155,33 @@ QXcbWindow::QXcbWindow(QWidget *tlw)
| XCB_EVENT_MASK_BUTTON_MOTION
| XCB_EVENT_MASK_ENTER_WINDOW
| XCB_EVENT_MASK_LEAVE_WINDOW
+ | XCB_EVENT_MASK_POINTER_MOTION
| XCB_EVENT_MASK_PROPERTY_CHANGE
| XCB_EVENT_MASK_FOCUS_CHANGE
};
-#if defined(XCB_USE_GLX) || defined(XCB_USE_EGL)
- if (tlw->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL
- && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)
- || tlw->platformWindowFormat().alpha())
+ QRect rect = window()->geometry();
+ QPlatformWindow::setGeometry(rect);
+
+ rect.setWidth(qBound(1, rect.width(), XCOORD_MAX));
+ rect.setHeight(qBound(1, rect.height(), XCOORD_MAX));
+
+ xcb_window_t xcb_parent_id = m_screen->root();
+ if (parent())
+ xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
+
+ m_requestedFormat = window()->format();
+
+#if (defined(XCB_USE_GLX) || defined(XCB_USE_EGL)) && defined(XCB_USE_XLIB)
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)
+ || window()->format().hasAlpha())
{
#if defined(XCB_USE_GLX)
- XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), tlw->platformWindowFormat());
+ XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), window()->format());
+
#elif defined(XCB_USE_EGL)
EGLDisplay eglDisplay = connection()->egl_display();
- EGLConfig eglConfig = q_configFromQPlatformWindowFormat(eglDisplay,tlw->platformWindowFormat(),true);
+ EGLConfig eglConfig = q_configFromGLFormat(eglDisplay, window()->format(), true);
VisualID id = QXlibEglIntegration::getCompatibleVisualId(DISPLAY_FROM_XCB(this), eglDisplay, eglConfig);
XVisualInfo visualInfoTemplate;
@@ -143,18 +194,16 @@ QXcbWindow::QXcbWindow(QWidget *tlw)
#endif //XCB_USE_GLX
if (visualInfo) {
m_depth = visualInfo->depth;
- m_format = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
- Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), m_screen->root(), visualInfo->visual, AllocNone);
+ m_imageFormat = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
+ Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), xcb_parent_id, visualInfo->visual, AllocNone);
XSetWindowAttributes a;
a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber());
a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber());
a.colormap = cmap;
- m_window = XCreateWindow(DISPLAY_FROM_XCB(this), m_screen->root(), tlw->x(), tlw->y(), tlw->width(), tlw->height(),
+ m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, rect.x(), rect.y(), rect.width(), rect.height(),
0, visualInfo->depth, InputOutput, visualInfo->visual,
CWBackPixel|CWBorderPixel|CWColormap, &a);
-
- printf("created GL window: %d\n", m_window);
} else {
qFatal("no window!");
}
@@ -163,25 +212,25 @@ QXcbWindow::QXcbWindow(QWidget *tlw)
{
m_window = xcb_generate_id(xcb_connection());
m_depth = m_screen->screen()->root_depth;
- m_format = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
+ m_imageFormat = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
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(),
+ xcb_parent_id, // parent window id
+ rect.x(),
+ rect.y(),
+ rect.width(),
+ rect.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);
}
+ connection()->addWindow(m_window, this);
+
Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values));
xcb_atom_t properties[4];
@@ -193,7 +242,7 @@ QXcbWindow::QXcbWindow(QWidget *tlw)
if (m_screen->syncRequestSupported())
properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST);
- if (tlw->windowFlags() & Qt::WindowContextHelpButtonHint)
+ if (window()->windowFlags() & Qt::WindowContextHelpButtonHint)
properties[propertyCount++] = atom(QXcbAtom::_NET_WM_CONTEXT_HELP);
Q_XCB_CALL(xcb_change_property(xcb_connection(),
@@ -221,29 +270,49 @@ QXcbWindow::QXcbWindow(QWidget *tlw)
&m_syncCounter));
}
- if (isTransient(tlw) && tlw->parentWidget()) {
- // ICCCM 4.1.2.6
- QWidget *p = tlw->parentWidget()->window();
- xcb_window_t parentWindow = p->winId();
- 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));
+
+ xcb_wm_hints_t hints;
+ memset(&hints, 0, sizeof(hints));
+ xcb_wm_hints_set_normal(&hints);
+
+ xcb_set_wm_hints(xcb_connection(), m_window, &hints);
+
+ xcb_window_t leader = m_screen->clientLeader();
+ Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
+ atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32,
+ 1, &leader));
+
+ setWindowFlags(window()->windowFlags());
+ setWindowTitle(window()->windowTitle());
+ setWindowState(window()->windowState());
+
+ connection()->drag()->dndEnable(this, true);
}
QXcbWindow::~QXcbWindow()
{
- delete m_context;
- if (m_screen->syncRequestSupported())
+ destroy();
+}
+
+void QXcbWindow::destroy()
+{
+ if (m_syncCounter && m_screen->syncRequestSupported())
Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter));
- Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window));
+ if (m_window) {
+ connection()->removeWindow(m_window);
+ Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window));
+ }
+ m_mapped = false;
+
+#if defined(XCB_USE_EGL)
+ delete m_eglSurface;
+ m_eglSurface = 0;
+#endif
}
void QXcbWindow::setGeometry(const QRect &rect)
@@ -251,40 +320,182 @@ void QXcbWindow::setGeometry(const QRect &rect)
QPlatformWindow::setGeometry(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() };
+ const quint32 values[] = { rect.x(),
+ rect.y(),
+ qBound(1, rect.width(), XCOORD_MAX),
+ qBound(1, rect.height(), XCOORD_MAX) };
Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values));
}
+QMargins QXcbWindow::frameMargins() const
+{
+ if (m_dirtyFrameMargins) {
+ xcb_window_t window = m_window;
+ xcb_window_t parent = m_window;
+
+ bool foundRoot = false;
+
+ const QVector<xcb_window_t> &virtualRoots =
+ connection()->wmSupport()->virtualRoots();
+
+ while (!foundRoot) {
+ xcb_query_tree_cookie_t cookie = xcb_query_tree(xcb_connection(), parent);
+
+ xcb_generic_error_t *error;
+ xcb_query_tree_reply_t *reply = xcb_query_tree_reply(xcb_connection(), cookie, &error);
+ if (reply) {
+ if (reply->root == reply->parent || virtualRoots.indexOf(reply->parent) != -1) {
+ foundRoot = true;
+ } else {
+ window = parent;
+ parent = reply->parent;
+ }
+
+ free(reply);
+ } else {
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+
+ m_dirtyFrameMargins = false;
+ m_frameMargins = QMargins();
+ return m_frameMargins;
+ }
+ }
+
+ QPoint offset;
+
+ xcb_generic_error_t *error;
+ xcb_translate_coordinates_reply_t *reply =
+ xcb_translate_coordinates_reply(
+ xcb_connection(),
+ xcb_translate_coordinates(xcb_connection(), window, parent, 0, 0),
+ &error);
+
+ if (reply) {
+ offset = QPoint(reply->dst_x, reply->dst_y);
+ free(reply);
+ } else if (error) {
+ free(error);
+ }
+
+ xcb_get_geometry_reply_t *geom =
+ xcb_get_geometry_reply(
+ xcb_connection(),
+ xcb_get_geometry(xcb_connection(), parent),
+ &error);
+
+ if (geom) {
+ // --
+ // add the border_width for the window managers frame... some window managers
+ // do not use a border_width of zero for their frames, and if we the left and
+ // top strut, we ensure that pos() is absolutely correct. frameGeometry()
+ // will still be incorrect though... perhaps i should have foffset as well, to
+ // indicate the frame offset (equal to the border_width on X).
+ // - Brad
+ // -- copied from qwidget_x11.cpp
+
+ int left = offset.x() + geom->border_width;
+ int top = offset.y() + geom->border_width;
+ int right = geom->width + geom->border_width - geometry().width() - offset.x();
+ int bottom = geom->height + geom->border_width - geometry().height() - offset.y();
+
+ m_frameMargins = QMargins(left, top, right, bottom);
+
+ free(geom);
+ } else if (error) {
+ free(error);
+ }
+
+ m_dirtyFrameMargins = false;
+ }
+
+ return m_frameMargins;
+}
+
void QXcbWindow::setVisible(bool visible)
{
- xcb_wm_hints_t hints;
- if (visible) {
- if (widget()->isMinimized())
+ if (visible)
+ show();
+ else
+ hide();
+}
+
+void QXcbWindow::show()
+{
+ if (window()->isTopLevel()) {
+ xcb_get_property_cookie_t cookie = xcb_get_wm_hints(xcb_connection(), m_window);
+
+ xcb_generic_error_t *error;
+
+ xcb_wm_hints_t hints;
+ xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, &error);
+
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+
+ m_dirtyFrameMargins = true;
+
+ if (window()->windowState() & Qt::WindowMinimized)
xcb_wm_hints_set_iconic(&hints);
else
xcb_wm_hints_set_normal(&hints);
+
xcb_set_wm_hints(xcb_connection(), m_window, &hints);
- Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
- connection()->sync();
- } else {
- 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;
- event.response_type = XCB_UNMAP_NOTIFY;
- event.sequence = 0; // does this matter?
- event.event = m_screen->root();
- event.window = m_window;
- event.from_configure = false;
- 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());
+ // update WM_NORMAL_HINTS
+ propagateSizeHints();
+
+ // update WM_TRANSIENT_FOR
+ if (window()->transientParent() && isTransient(window())) {
+ QXcbWindow *transientXcbParent = static_cast<QXcbWindow *>(window()->transientParent()->handle());
+ if (transientXcbParent) {
+ // ICCCM 4.1.2.6
+ xcb_window_t parentWindow = transientXcbParent->xcb_window();
+
+ // todo: set transient for group (wm_client_leader) if no parent, a la qwidget_x11.cpp
+ 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));
+ }
+ }
+
+ // update _MOTIF_WM_HINTS
+ updateMotifWmHintsBeforeMap();
+
+ // update _NET_WM_STATE
+ updateNetWmStateBeforeMap();
}
+
+ Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
+ xcb_flush(xcb_connection());
+
+ connection()->sync();
+}
+
+void QXcbWindow::hide()
+{
+ 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;
+ event.response_type = XCB_UNMAP_NOTIFY;
+ event.event = m_screen->root();
+ event.window = m_window;
+ event.from_configure = false;
+ 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());
+
+ m_mapped = false;
}
-struct QtMWMHints {
+struct QtMotifWmHints {
quint32 flags, functions, decorations;
qint32 input_mode;
quint32 status;
@@ -317,33 +528,142 @@ enum {
MWM_INPUT_FULL_APPLICATION_MODAL = 3L
};
+static QtMotifWmHints getMotifWmHints(QXcbConnection *c, xcb_window_t window)
+{
+ QtMotifWmHints hints;
+
+ xcb_get_property_cookie_t get_cookie =
+ xcb_get_property(c->xcb_connection(), 0, window, c->atom(QXcbAtom::_MOTIF_WM_HINTS),
+ c->atom(QXcbAtom::_MOTIF_WM_HINTS), 0, 20);
+
+ xcb_generic_error_t *error;
+
+ xcb_get_property_reply_t *reply =
+ xcb_get_property_reply(c->xcb_connection(), get_cookie, &error);
+
+ if (reply && reply->format == 32 && reply->type == c->atom(QXcbAtom::_MOTIF_WM_HINTS)) {
+ hints = *((QtMotifWmHints *)xcb_get_property_value(reply));
+ } else if (error) {
+ c->handleXcbError(error);
+ free(error);
+
+ hints.flags = 0L;
+ hints.functions = MWM_FUNC_ALL;
+ hints.decorations = MWM_DECOR_ALL;
+ hints.input_mode = 0L;
+ hints.status = 0L;
+ }
+
+ free(reply);
+
+ return hints;
+}
+
+static void setMotifWmHints(QXcbConnection *c, xcb_window_t window, const QtMotifWmHints &hints)
+{
+ if (hints.flags != 0l) {
+ Q_XCB_CALL2(xcb_change_property(c->xcb_connection(),
+ XCB_PROP_MODE_REPLACE,
+ window,
+ c->atom(QXcbAtom::_MOTIF_WM_HINTS),
+ c->atom(QXcbAtom::_MOTIF_WM_HINTS),
+ 32,
+ 5,
+ &hints), c);
+ } else {
+ Q_XCB_CALL2(xcb_delete_property(c->xcb_connection(), window, c->atom(QXcbAtom::_MOTIF_WM_HINTS)), c);
+ }
+}
+
+void QXcbWindow::printNetWmState(const QVector<xcb_atom_t> &state)
+{
+ printf("_NET_WM_STATE (%d): ", state.size());
+ for (int i = 0; i < state.size(); ++i) {
+#define CHECK_WM_STATE(state_atom) \
+ if (state.at(i) == atom(QXcbAtom::state_atom))\
+ printf(#state_atom " ");
+ CHECK_WM_STATE(_NET_WM_STATE_ABOVE)
+ CHECK_WM_STATE(_NET_WM_STATE_BELOW)
+ CHECK_WM_STATE(_NET_WM_STATE_FULLSCREEN)
+ CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_HORZ)
+ CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_VERT)
+ CHECK_WM_STATE(_NET_WM_STATE_MODAL)
+ CHECK_WM_STATE(_NET_WM_STATE_STAYS_ON_TOP)
+ CHECK_WM_STATE(_NET_WM_STATE_DEMANDS_ATTENTION)
+#undef CHECK_WM_STATE
+ }
+ printf("\n");
+}
+
+QVector<xcb_atom_t> QXcbWindow::getNetWmState()
+{
+ QVector<xcb_atom_t> result;
+
+ xcb_get_property_cookie_t get_cookie =
+ xcb_get_property(xcb_connection(), 0, m_window, atom(QXcbAtom::_NET_WM_STATE),
+ XCB_ATOM_ATOM, 0, 1024);
+
+ xcb_generic_error_t *error;
+
+ xcb_get_property_reply_t *reply =
+ xcb_get_property_reply(xcb_connection(), get_cookie, &error);
+
+ if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) {
+ result.resize(reply->length);
+
+ memcpy(result.data(), xcb_get_property_value(reply), reply->length * sizeof(xcb_atom_t));
+
+#ifdef NET_WM_STATE_DEBUG
+ printf("getting net wm state (%x)\n", m_window);
+ printNetWmState(result);
+#endif
+
+ free(reply);
+ } else if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ } else {
+#ifdef NET_WM_STATE_DEBUG
+ printf("getting net wm state (%x), empty\n", m_window);
+#endif
+ }
+
+ return result;
+}
+
+void QXcbWindow::setNetWmState(const QVector<xcb_atom_t> &atoms)
+{
+ if (atoms.isEmpty()) {
+ Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_STATE)));
+ } else {
+ Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
+ atom(QXcbAtom::_NET_WM_STATE), XCB_ATOM_ATOM, 32,
+ atoms.count(), atoms.constData()));
+ }
+ xcb_flush(xcb_connection());
+}
+
+
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)
flags |= Qt::X11BypassWindowManagerHint;
- bool topLevel = (flags & Qt::Window);
- bool popup = (type == Qt::Popup);
- bool dialog = (type == Qt::Dialog
- || type == Qt::Sheet);
- bool desktop = (type == Qt::Desktop);
- bool tool = (type == Qt::Tool || type == Qt::SplashScreen
- || type == Qt::ToolTip || type == Qt::Drawer);
+ setNetWmWindowFlags(flags);
+ setMotifWindowFlags(flags);
- Q_UNUSED(topLevel);
- Q_UNUSED(dialog);
- Q_UNUSED(desktop);
- Q_UNUSED(tool);
+ return flags;
+}
- bool tooltip = (type == Qt::ToolTip);
+void QXcbWindow::setMotifWindowFlags(Qt::WindowFlags flags)
+{
+ Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
- QtMWMHints mwmhints;
+ QtMotifWmHints mwmhints;
mwmhints.flags = 0L;
mwmhints.functions = 0L;
mwmhints.decorations = 0;
@@ -403,30 +723,90 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
mwmhints.decorations = 0;
}
- if (mwmhints.flags != 0l) {
- 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 {
- Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_MOTIF_WM_HINTS)));
- }
+ setMotifWmHints(connection(), m_window, mwmhints);
+}
+
+void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two)
+{
+ xcb_client_message_event_t event;
+
+ event.response_type = XCB_CLIENT_MESSAGE;
+ event.format = 32;
+ event.window = m_window;
+ event.type = atom(QXcbAtom::_NET_WM_STATE);
+ event.data.data32[0] = set ? 1 : 0;
+ event.data.data32[1] = one;
+ event.data.data32[2] = two;
+ event.data.data32[3] = 0;
+ event.data.data32[4] = 0;
+
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
+}
- if (popup || tooltip) {
- const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER;
- const quint32 values[] = { true, true };
+Qt::WindowState QXcbWindow::setWindowState(Qt::WindowState state)
+{
+ if (state == m_windowState)
+ return state;
+
+ m_dirtyFrameMargins = true;
+
+ // unset old state
+ switch (m_windowState) {
+ case Qt::WindowMinimized:
+ Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
+ break;
+ case Qt::WindowMaximized:
+ changeNetWmState(false,
+ atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ),
+ atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
+ break;
+ case Qt::WindowFullScreen:
+ changeNetWmState(false, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
+ break;
+ default:
+ break;
+ }
- Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values));
+ // set new state
+ switch (state) {
+ case Qt::WindowMinimized:
+ {
+ xcb_client_message_event_t event;
+
+ event.response_type = XCB_CLIENT_MESSAGE;
+ event.format = 32;
+ event.window = m_window;
+ event.type = atom(QXcbAtom::WM_CHANGE_STATE);
+ event.data.data32[0] = XCB_WM_STATE_ICONIC;
+ event.data.data32[1] = 0;
+ event.data.data32[2] = 0;
+ event.data.data32[3] = 0;
+ event.data.data32[4] = 0;
+
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
+ }
+ break;
+ case Qt::WindowMaximized:
+ changeNetWmState(true,
+ atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ),
+ atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
+ break;
+ case Qt::WindowFullScreen:
+ changeNetWmState(true, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
+ break;
+ case Qt::WindowNoState:
+ break;
+ default:
+ break;
}
- return QPlatformWindow::setWindowFlags(flags);
+ connection()->sync();
+
+ m_windowState = state;
+ return m_windowState;
}
-void QXcbWindow::setNetWmWindowTypes(Qt::WindowFlags flags)
+void QXcbWindow::setNetWmWindowFlags(Qt::WindowFlags flags)
{
// in order of decreasing priority
QVector<uint> windowTypes;
@@ -462,6 +842,127 @@ void QXcbWindow::setNetWmWindowTypes(Qt::WindowFlags flags)
windowTypes.count(), windowTypes.constData()));
}
+void QXcbWindow::updateMotifWmHintsBeforeMap()
+{
+ QtMotifWmHints mwmhints = getMotifWmHints(connection(), m_window);
+
+ if (window()->windowModality() != Qt::NonModal) {
+ switch (window()->windowModality()) {
+ case Qt::WindowModal:
+ mwmhints.input_mode = MWM_INPUT_PRIMARY_APPLICATION_MODAL;
+ break;
+ case Qt::ApplicationModal:
+ default:
+ mwmhints.input_mode = MWM_INPUT_FULL_APPLICATION_MODAL;
+ break;
+ }
+ mwmhints.flags |= MWM_HINTS_INPUT_MODE;
+ } else {
+ mwmhints.input_mode = MWM_INPUT_MODELESS;
+ mwmhints.flags &= ~MWM_HINTS_INPUT_MODE;
+ }
+
+ if (window()->minimumSize() == window()->maximumSize()) {
+ // fixed size, remove the resize handle (since mwm/dtwm
+ // isn't smart enough to do it itself)
+ mwmhints.flags |= MWM_HINTS_FUNCTIONS;
+ if (mwmhints.functions == MWM_FUNC_ALL) {
+ mwmhints.functions = MWM_FUNC_MOVE;
+ } else {
+ mwmhints.functions &= ~MWM_FUNC_RESIZE;
+ }
+
+ if (mwmhints.decorations == MWM_DECOR_ALL) {
+ mwmhints.flags |= MWM_HINTS_DECORATIONS;
+ mwmhints.decorations = (MWM_DECOR_BORDER
+ | MWM_DECOR_TITLE
+ | MWM_DECOR_MENU);
+ } else {
+ mwmhints.decorations &= ~MWM_DECOR_RESIZEH;
+ }
+ }
+
+ if (window()->windowFlags() & Qt::WindowMinimizeButtonHint) {
+ mwmhints.flags |= MWM_HINTS_DECORATIONS;
+ mwmhints.decorations |= MWM_DECOR_MINIMIZE;
+ mwmhints.functions |= MWM_FUNC_MINIMIZE;
+ }
+ if (window()->windowFlags() & Qt::WindowMaximizeButtonHint) {
+ mwmhints.flags |= MWM_HINTS_DECORATIONS;
+ mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
+ mwmhints.functions |= MWM_FUNC_MAXIMIZE;
+ }
+ if (window()->windowFlags() & Qt::WindowCloseButtonHint)
+ mwmhints.functions |= MWM_FUNC_CLOSE;
+
+ setMotifWmHints(connection(), m_window, mwmhints);
+}
+
+void QXcbWindow::updateNetWmStateBeforeMap()
+{
+ QVector<xcb_atom_t> netWmState;
+
+ Qt::WindowFlags flags = window()->windowFlags();
+ if (flags & Qt::WindowStaysOnTopHint) {
+ netWmState.append(atom(QXcbAtom::_NET_WM_STATE_ABOVE));
+ netWmState.append(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP));
+ } else if (flags & Qt::WindowStaysOnBottomHint) {
+ netWmState.append(atom(QXcbAtom::_NET_WM_STATE_BELOW));
+ }
+
+ if (window()->windowState() & Qt::WindowFullScreen) {
+ netWmState.append(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
+ }
+
+ if (window()->windowState() & Qt::WindowMaximized) {
+ netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ));
+ netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
+ }
+
+ if (window()->windowModality() != Qt::NonModal) {
+ netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MODAL));
+ }
+
+ setNetWmState(netWmState);
+}
+
+void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp)
+{
+ xcb_window_t wid = m_window;
+
+ const bool isSupportedByWM = connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW));
+ if (m_netWmUserTimeWindow || isSupportedByWM) {
+ if (!m_netWmUserTimeWindow) {
+ m_netWmUserTimeWindow = xcb_generate_id(xcb_connection());
+ Q_XCB_CALL(xcb_create_window(xcb_connection(),
+ XCB_COPY_FROM_PARENT, // depth -- same as root
+ m_netWmUserTimeWindow, // window id
+ m_window, // parent window id
+ -1, -1, 1, 1,
+ 0, // border width
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class
+ m_screen->screen()->root_visual, // visual
+ 0, // value mask
+ 0)); // value list
+ wid = m_netWmUserTimeWindow;
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW),
+ XCB_ATOM_WINDOW, 32, 1, &m_netWmUserTimeWindow);
+ xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME));
+ } else if (!isSupportedByWM) {
+ // WM no longer supports it, then we should remove the
+ // _NET_WM_USER_TIME_WINDOW atom.
+ xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW));
+ xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow);
+ m_netWmUserTimeWindow = XCB_NONE;
+ } else {
+ wid = m_netWmUserTimeWindow;
+ }
+ }
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, wid, atom(QXcbAtom::_NET_WM_USER_TIME),
+ XCB_ATOM_CARDINAL, 32, 1, &timestamp);
+}
+
+
WId QXcbWindow::winId() const
{
return m_window;
@@ -469,8 +970,13 @@ WId QXcbWindow::winId() const
void QXcbWindow::setParent(const QPlatformWindow *parent)
{
+ // re-create for compatibility
+ create();
+
QPoint topLeft = geometry().topLeft();
- Q_XCB_CALL(xcb_reparent_window(xcb_connection(), window(), static_cast<const QXcbWindow *>(parent)->window(), topLeft.x(), topLeft.y()));
+
+ xcb_window_t xcb_parent_id = parent ? static_cast<const QXcbWindow *>(parent)->xcb_window() : m_screen->root();
+ Q_XCB_CALL(xcb_reparent_window(xcb_connection(), xcb_window(), xcb_parent_id, topLeft.x(), topLeft.y()));
}
void QXcbWindow::setWindowTitle(const QString &title)
@@ -500,56 +1006,87 @@ void QXcbWindow::lower()
Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values));
}
+void QXcbWindow::propagateSizeHints()
+{
+ // update WM_NORMAL_HINTS
+ xcb_size_hints_t hints;
+ memset(&hints, 0, sizeof(hints));
+
+ QRect rect = geometry();
+
+ xcb_size_hints_set_position(&hints, true, rect.x(), rect.y());
+ xcb_size_hints_set_size(&hints, true, rect.width(), rect.height());
+ xcb_size_hints_set_win_gravity(&hints, XCB_GRAVITY_STATIC);
+
+ QWindow *win = window();
+
+ QSize minimumSize = win->minimumSize();
+ QSize maximumSize = win->maximumSize();
+ QSize baseSize = win->baseSize();
+ QSize sizeIncrement = win->sizeIncrement();
+
+ if (minimumSize.width() > 0 || minimumSize.height() > 0)
+ xcb_size_hints_set_min_size(&hints, minimumSize.width(), minimumSize.height());
+
+ if (maximumSize.width() < QWINDOWSIZE_MAX || maximumSize.height() < QWINDOWSIZE_MAX)
+ xcb_size_hints_set_max_size(&hints,
+ qMin(XCOORD_MAX, maximumSize.width()),
+ qMin(XCOORD_MAX, maximumSize.height()));
+
+ if (sizeIncrement.width() > 0 || sizeIncrement.height() > 0) {
+ xcb_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height());
+ xcb_size_hints_set_resize_inc(&hints, sizeIncrement.width(), sizeIncrement.height());
+ }
+
+ xcb_set_wm_normal_hints(xcb_connection(), m_window, &hints);
+}
+
void QXcbWindow::requestActivateWindow()
{
- Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, XCB_TIME_CURRENT_TIME));
+ if (m_mapped){
+ updateNetWmUserTime(connection()->time());
+ Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, connection()->time()));
+ }
connection()->sync();
}
-QPlatformGLContext *QXcbWindow::glContext() const
+QSurfaceFormat QXcbWindow::format() const
{
- if (!QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) {
- printf("no opengl\n");
- return 0;
- }
- 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)
+ // ### return actual format
+ return m_requestedFormat;
+}
+
+#if defined(XCB_USE_EGL)
+QXcbEGLSurface *QXcbWindow::eglSurface() const
+{
+ if (!m_eglSurface) {
EGLDisplay display = connection()->egl_display();
- EGLConfig config = q_configFromQPlatformWindowFormat(display,widget()->platformWindowFormat(),true);
- QVector<EGLint> eglContextAttrs;
- eglContextAttrs.append(EGL_CONTEXT_CLIENT_VERSION);
- eglContextAttrs.append(2);
- eglContextAttrs.append(EGL_NONE);
-
- 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)
- QXcbWindow *that = const_cast<QXcbWindow *>(this);
- that->m_context = new QDri2Context(that);
-#endif
+ EGLConfig config = q_configFromGLFormat(display, window()->format(), true);
+ EGLSurface surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)m_window, 0);
+
+ m_eglSurface = new QXcbEGLSurface(display, surface);
}
- return m_context;
+
+ return m_eglSurface;
}
+#endif
void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event)
{
- QWindowSurface *surface = widget()->windowSurface();
- if (surface) {
- QRect rect(event->x, event->y, event->width, event->height);
-
- surface->flush(widget(), rect, QPoint());
- }
+ QRect rect(event->x, event->y, event->width, event->height);
+ QWindowSystemInterface::handleSynchronousExposeEvent(window(), rect);
}
void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *event)
{
- if (event->format == 32 && event->type == atom(QXcbAtom::WM_PROTOCOLS)) {
+ if (event->format != 32)
+ return;
+
+ if (event->type == atom(QXcbAtom::WM_PROTOCOLS)) {
if (event->data.data32[0] == atom(QXcbAtom::WM_DELETE_WINDOW)) {
- QWindowSystemInterface::handleCloseEvent(widget());
+ QWindowSystemInterface::handleCloseEvent(window());
+ } else if (event->data.data32[0] == atom(QXcbAtom::WM_TAKE_FOCUS)) {
+ connection()->setTime(event->data.data32[1]);
} else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) {
xcb_client_message_event_t reply = *event;
@@ -559,13 +1096,22 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
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");
- }
+ connection()->setTime(event->data.data32[1]);
m_syncValue.lo = event->data.data32[2];
m_syncValue.hi = event->data.data32[3];
+ } else {
+ qWarning() << "unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]);
}
+ } else if (event->type == atom(QXcbAtom::XdndEnter)) {
+ connection()->drag()->handleEnter(window(), event);
+ } else if (event->type == atom(QXcbAtom::XdndPosition)) {
+ connection()->drag()->handlePosition(window(), event, false);
+ } else if (event->type == atom(QXcbAtom::XdndLeave)) {
+ connection()->drag()->handleLeave(window(), event, false);
+ } else if (event->type == atom(QXcbAtom::XdndDrop)) {
+ connection()->drag()->handleDrop(window(), event, false);
+ } else {
+ qWarning() << "unhandled client message:" << connection()->atomName(event->type);
}
}
@@ -581,11 +1127,8 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
QRect rect(xpos, ypos, event->width, event->height);
- if (rect == geometry())
- return;
-
QPlatformWindow::setGeometry(rect);
- QWindowSystemInterface::handleGeometryChange(widget(), rect);
+ QWindowSystemInterface::handleGeometryChange(window(), rect);
#if XCB_USE_DRI2
if (m_context)
@@ -593,6 +1136,22 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
#endif
}
+void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event)
+{
+ if (event->window == m_window) {
+ m_mapped = true;
+ QWindowSystemInterface::handleMapEvent(window());
+ }
+}
+
+void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event)
+{
+ if (event->window == m_window) {
+ m_mapped = false;
+ QWindowSystemInterface::handleUnmapEvent(window());
+ }
+}
+
static Qt::MouseButtons translateMouseButtons(int s)
{
Qt::MouseButtons ret = 0;
@@ -621,6 +1180,8 @@ static Qt::MouseButton translateMouseButton(xcb_button_t s)
void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
{
+ updateNetWmUserTime(event->time);
+
QPoint local(event->event_x, event->event_y);
QPoint global(event->root_x, event->root_y);
@@ -633,7 +1194,7 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
&& (modifiers & Qt::AltModifier))
|| (event->detail == 6 || event->detail == 7));
- QWindowSystemInterface::handleWheelEvent(widget(), event->time,
+ QWindowSystemInterface::handleWheelEvent(window(), event->time,
local, global, delta, hor ? Qt::Horizontal : Qt::Vertical);
return;
}
@@ -659,32 +1220,65 @@ void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
void QXcbWindow::handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_timestamp_t time, const QPoint &local, const QPoint &global)
{
+ connection()->setTime(time);
+
Qt::MouseButtons buttons = translateMouseButtons(state);
Qt::MouseButton button = translateMouseButton(detail);
buttons ^= button; // X event uses state *before*, Qt uses state *after*
- QWindowSystemInterface::handleMouseEvent(widget(), time, local, global, buttons);
+ QWindowSystemInterface::handleMouseEvent(window(), time, local, global, buttons);
}
-void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *)
+void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event)
{
- QWindowSystemInterface::handleEnterEvent(widget());
+ connection()->setTime(event->time);
+
+ if ((event->mode != XCB_NOTIFY_MODE_NORMAL && event->mode != XCB_NOTIFY_MODE_UNGRAB)
+ || event->detail == XCB_NOTIFY_DETAIL_VIRTUAL
+ || event->detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL)
+ {
+ return;
+ }
+
+ QWindowSystemInterface::handleEnterEvent(window());
}
-void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *)
+void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event)
{
- QWindowSystemInterface::handleLeaveEvent(widget());
+ connection()->setTime(event->time);
+
+ if ((event->mode != XCB_NOTIFY_MODE_NORMAL && event->mode != XCB_NOTIFY_MODE_UNGRAB)
+ || event->detail == XCB_NOTIFY_DETAIL_INFERIOR)
+ {
+ return;
+ }
+
+ QWindowSystemInterface::handleLeaveEvent(window());
}
void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *)
{
- QWindowSystemInterface::handleWindowActivated(widget());
+ QWindowSystemInterface::handleWindowActivated(window());
+}
+
+static bool focusInPeeker(xcb_generic_event_t *event)
+{
+ if (!event) {
+ // FocusIn event is not in the queue, proceed with FocusOut normally.
+ QWindowSystemInterface::handleWindowActivated(0);
+ return true;
+ }
+ uint response_type = event->response_type & ~0x80;
+ return response_type == XCB_FOCUS_IN;
}
void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *)
{
- QWindowSystemInterface::handleWindowActivated(0);
+ // Do not set the active window to 0 if there is a FocusIn coming.
+ // There is however no equivalent for XPutBackEvent so register a
+ // callback for QXcbConnection instead.
+ connection()->addPeekFunc(focusInPeeker);
}
void QXcbWindow::updateSyncRequestCounter()
@@ -698,3 +1292,47 @@ void QXcbWindow::updateSyncRequestCounter()
m_syncValue.hi = 0;
}
}
+
+bool QXcbWindow::setKeyboardGrabEnabled(bool grab)
+{
+ if (!grab) {
+ xcb_ungrab_keyboard(xcb_connection(), XCB_TIME_CURRENT_TIME);
+ return true;
+ }
+ xcb_grab_keyboard_cookie_t cookie = xcb_grab_keyboard(xcb_connection(), false,
+ m_window, XCB_TIME_CURRENT_TIME,
+ XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+ xcb_generic_error_t *err;
+ xcb_grab_keyboard_reply_t *reply = xcb_grab_keyboard_reply(xcb_connection(), cookie, &err);
+ bool result = !(err || !reply || reply->status != XCB_GRAB_STATUS_SUCCESS);
+ free(reply);
+ free(err);
+ return result;
+}
+
+bool QXcbWindow::setMouseGrabEnabled(bool grab)
+{
+ if (!grab) {
+ xcb_ungrab_pointer(xcb_connection(), XCB_TIME_CURRENT_TIME);
+ return true;
+ }
+ xcb_grab_pointer_cookie_t cookie = xcb_grab_pointer(xcb_connection(), false, m_window,
+ (XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE
+ | XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_ENTER_WINDOW
+ | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_POINTER_MOTION),
+ XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
+ XCB_WINDOW_NONE, XCB_CURSOR_NONE,
+ XCB_TIME_CURRENT_TIME);
+ xcb_generic_error_t *err;
+ xcb_grab_pointer_reply_t *reply = xcb_grab_pointer_reply(xcb_connection(), cookie, &err);
+ bool result = !(err || !reply || reply->status != XCB_GRAB_STATUS_SUCCESS);
+ free(reply);
+ free(err);
+ return result;
+}
+
+void QXcbWindow::setCursor(xcb_cursor_t cursor)
+{
+ xcb_change_window_attributes(xcb_connection(), m_window, XCB_CW_CURSOR, &cursor);
+ xcb_flush(xcb_connection());
+}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 69d0bc2f1d..a85760ea8d 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -43,7 +43,7 @@
#define QXCBWINDOW_H
#include <QtGui/QPlatformWindow>
-#include <QtGui/QPlatformWindowFormat>
+#include <QtGui/QSurfaceFormat>
#include <QtGui/QImage>
#include <xcb/xcb.h>
@@ -52,35 +52,47 @@
#include "qxcbobject.h"
class QXcbScreen;
+class QXcbEGLSurface;
class QXcbWindow : public QXcbObject, public QPlatformWindow
{
public:
- QXcbWindow(QWidget *tlw);
+ QXcbWindow(QWindow *window);
~QXcbWindow();
void setGeometry(const QRect &rect);
+ QMargins frameMargins() const;
+
void setVisible(bool visible);
Qt::WindowFlags setWindowFlags(Qt::WindowFlags flags);
+ Qt::WindowState setWindowState(Qt::WindowState state);
WId winId() const;
void setParent(const QPlatformWindow *window);
void setWindowTitle(const QString &title);
void raise();
void lower();
+ void propagateSizeHints();
void requestActivateWindow();
- QPlatformGLContext *glContext() const;
+ bool setKeyboardGrabEnabled(bool grab);
+ bool setMouseGrabEnabled(bool grab);
+
+ void setCursor(xcb_cursor_t cursor);
- xcb_window_t window() const { return m_window; }
+ QSurfaceFormat format() const;
+
+ xcb_window_t xcb_window() const { return m_window; }
uint depth() const { return m_depth; }
- QImage::Format format() const { return m_format; }
+ QImage::Format imageFormat() const { return m_imageFormat; }
void handleExposeEvent(const xcb_expose_event_t *event);
void handleClientMessageEvent(const xcb_client_message_event_t *event);
void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event);
+ void handleMapNotifyEvent(const xcb_map_notify_event_t *event);
+ void handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event);
void handleButtonPressEvent(const xcb_button_press_event_t *event);
void handleButtonReleaseEvent(const xcb_button_release_event_t *event);
void handleMotionNotifyEvent(const xcb_motion_notify_event_t *event);
@@ -93,22 +105,54 @@ public:
void handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_timestamp_t time, const QPoint &local, const QPoint &global);
void updateSyncRequestCounter();
+ void updateNetWmUserTime(xcb_timestamp_t timestamp);
+ void netWmUserTime() const;
+
+#if defined(XCB_USE_EGL)
+ QXcbEGLSurface *eglSurface() const;
+#endif
private:
- void setNetWmWindowTypes(Qt::WindowFlags flags);
+ void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0);
+ QVector<xcb_atom_t> getNetWmState();
+ void setNetWmState(const QVector<xcb_atom_t> &atoms);
+ void printNetWmState(const QVector<xcb_atom_t> &state);
+
+ void setNetWmWindowFlags(Qt::WindowFlags flags);
+ void setMotifWindowFlags(Qt::WindowFlags flags);
+
+ void updateMotifWmHintsBeforeMap();
+ void updateNetWmStateBeforeMap();
+
+ void create();
+ void destroy();
+
+ void show();
+ void hide();
QXcbScreen *m_screen;
xcb_window_t m_window;
- QPlatformGLContext *m_context;
uint m_depth;
- QImage::Format m_format;
+ QImage::Format m_imageFormat;
xcb_sync_int64_t m_syncValue;
xcb_sync_counter_t m_syncCounter;
- bool m_hasReceivedSyncRequest;
+ Qt::WindowState m_windowState;
+
+ bool m_mapped;
+ xcb_window_t m_netWmUserTimeWindow;
+
+ QSurfaceFormat m_requestedFormat;
+
+ mutable bool m_dirtyFrameMargins;
+ mutable QMargins m_frameMargins;
+
+#if defined(XCB_USE_EGL)
+ mutable QXcbEGLSurface *m_eglSurface;
+#endif
};
#endif
diff --git a/src/plugins/platforms/xcb/qxcbwmsupport.cpp b/src/plugins/platforms/xcb/qxcbwmsupport.cpp
new file mode 100644
index 0000000000..5fb67b6377
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbwmsupport.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qxcbwmsupport.h"
+#include "qxcbscreen.h"
+
+#include <qdebug.h>
+
+QXcbWMSupport::QXcbWMSupport(QXcbConnection *c)
+ : QXcbObject(c)
+{
+ updateNetWMAtoms();
+ updateVirtualRoots();
+}
+
+bool QXcbWMSupport::isSupportedByWM(xcb_atom_t atom) const
+{
+ return net_wm_atoms.contains(atom);
+}
+
+
+
+void QXcbWMSupport::updateNetWMAtoms()
+{
+ net_wm_atoms.clear();
+
+ xcb_window_t root = connection()->screens().at(connection()->primaryScreen())->root();
+ int offset = 0;
+ int remaining = 0;
+ do {
+ xcb_generic_error_t *error = 0;
+ xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, root, atom(QXcbAtom::_NET_SUPPORTED), XCB_ATOM_ATOM, offset, 1024);
+ xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, &error);
+ if (!reply || error)
+ break;
+
+ remaining = 0;
+
+ if (reply->type == XCB_ATOM_ATOM && reply->format == 32) {
+ int len = xcb_get_property_value_length(reply)/4;
+ xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply);
+ int s = net_wm_atoms.size();
+ net_wm_atoms.resize(s + len);
+ memcpy(net_wm_atoms.data() + s, atoms, len*sizeof(xcb_atom_t));
+
+ remaining = reply->bytes_after;
+ offset += len;
+ }
+
+ free(reply);
+ } while (remaining > 0);
+
+// qDebug() << "======== updateNetWMAtoms";
+// for (int i = 0; i < net_wm_atoms.size(); ++i)
+// qDebug() << atomName(net_wm_atoms.at(i));
+// qDebug() << "======== updateNetWMAtoms";
+}
+
+// update the virtual roots array
+void QXcbWMSupport::updateVirtualRoots()
+{
+ net_virtual_roots.clear();
+
+ if (!isSupportedByWM(atom(QXcbAtom::_NET_VIRTUAL_ROOTS)))
+ return;
+
+ xcb_window_t root = connection()->screens().at(connection()->primaryScreen())->root();
+ int offset = 0;
+ int remaining = 0;
+ do {
+ xcb_generic_error_t *error = 0;
+ xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, root, atom(QXcbAtom::_NET_VIRTUAL_ROOTS), XCB_ATOM_ATOM, offset, 1024);
+ xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, &error);
+ if (!reply || error)
+ break;
+
+ remaining = 0;
+
+ if (reply->type == XCB_ATOM_ATOM && reply->format == 32) {
+ int len = xcb_get_property_value_length(reply)/4;
+ xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply);
+ int s = net_wm_atoms.size();
+ net_wm_atoms.resize(s + len);
+ memcpy(net_wm_atoms.data() + s, atoms, len*sizeof(xcb_atom_t));
+
+ remaining = reply->bytes_after;
+ offset += len;
+ }
+
+ free(reply);
+ } while (remaining > 0);
+
+ qDebug() << "======== updateVirtualRoots";
+ for (int i = 0; i < net_virtual_roots.size(); ++i)
+ qDebug() << connection()->atomName(net_virtual_roots.at(i));
+ qDebug() << "======== updateVirtualRoots";
+}
+
diff --git a/src/plugins/platforms/xcb/qxcbwmsupport.h b/src/plugins/platforms/xcb/qxcbwmsupport.h
new file mode 100644
index 0000000000..3b02ef3e7e
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbwmsupport.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QXCBWMSUPPORT_H
+#define QXCBWMSUPPORT_H
+
+#include "qxcbobject.h"
+#include "qxcbconnection.h"
+#include <qvector.h>
+
+class QXcbWMSupport : public QXcbObject
+{
+public:
+ QXcbWMSupport(QXcbConnection *c);
+
+
+ bool isSupportedByWM(xcb_atom_t atom) const;
+ const QVector<xcb_window_t> &virtualRoots() const { return net_virtual_roots; }
+
+private:
+ friend class QXcbConnection;
+ void updateNetWMAtoms();
+ void updateVirtualRoots();
+
+ QVector<xcb_atom_t> net_wm_atoms;
+ QVector<xcb_window_t> net_virtual_roots;
+};
+
+
+#endif
diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro
index 27d10b6756..143a671047 100644
--- a/src/plugins/platforms/xcb/xcb.pro
+++ b/src/plugins/platforms/xcb/xcb.pro
@@ -3,70 +3,91 @@ TARGET = xcb
load(qt_plugin)
QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms
-QT += core-private gui-private
+QT += core-private gui-private platformsupport-private
SOURCES = \
+ qxcbclipboard.cpp \
qxcbconnection.cpp \
qxcbintegration.cpp \
qxcbkeyboard.cpp \
+ qxcbmime.cpp \
+ qxcbdrag.cpp \
qxcbscreen.cpp \
qxcbwindow.cpp \
- qxcbwindowsurface.cpp \
+ qxcbbackingstore.cpp \
+ qxcbwmsupport.cpp \
main.cpp \
- qxcbnativeinterface.cpp
+ qxcbnativeinterface.cpp \
+ qxcbcursor.cpp \
+ qxcbimage.cpp
HEADERS = \
+ qxcbclipboard.h \
qxcbconnection.h \
qxcbintegration.h \
qxcbkeyboard.h \
+ qxcbdrag.h \
+ qxcbmime.h \
qxcbobject.h \
qxcbscreen.h \
qxcbwindow.h \
- qxcbwindowsurface.h \
- qxcbnativeinterface.h
+ qxcbbackingstore.h \
+ qxcbwmsupport.h \
+ qxcbnativeinterface.h \
+ qxcbcursor.h \
+ qxcbimage.h
-contains(QT_CONFIG, opengl) {
- QT += opengl
+contains(QT_CONFIG, xcb-poll-for-queued-event) {
+ DEFINES += XCB_POLL_FOR_QUEUED_EVENT
+}
+
+# needed by GLX, Xcursor, XLookupString, ...
+contains(QT_CONFIG, xcb-xlib) {
+ DEFINES += XCB_USE_XLIB
+ LIBS += -lX11 -lX11-xcb
+}
+
+# to support custom cursors with depth > 1
+contains(QT_CONFIG, xcb-render) {
+ DEFINES += XCB_USE_RENDER
+ LIBS += -lxcb-render -lxcb-render-util -lXrender
+}
# DEFINES += XCB_USE_DRI2
- contains(DEFINES, XCB_USE_DRI2) {
- LIBS += -lxcb-dri2 -lxcb-xfixes -lEGL
-
- CONFIG += link_pkgconfig
- PKGCONFIG += libdrm
-
- HEADERS += qdri2context.h
- SOURCES += qdri2context.cpp
-
- } else {
- DEFINES += XCB_USE_XLIB
- LIBS += -lX11 -lX11-xcb
-
- contains(QT_CONFIG, opengles2) {
- DEFINES += XCB_USE_EGL
- HEADERS += \
- ../eglconvenience/qeglplatformcontext.h \
- ../eglconvenience/qeglconvenience.h \
- ../eglconvenience/qxlibeglintegration.h
-
- SOURCES += \
- ../eglconvenience/qeglplatformcontext.cpp \
- ../eglconvenience/qeglconvenience.cpp \
- ../eglconvenience/qxlibeglintegration.cpp
-
- LIBS += -lEGL
- } else {
- DEFINES += XCB_USE_GLX
- include (../glxconvenience/glxconvenience.pri)
- HEADERS += qglxintegration.h
- SOURCES += qglxintegration.cpp
- }
+contains(DEFINES, XCB_USE_DRI2) {
+ LIBS += -lxcb-dri2 -lEGL
+
+ CONFIG += link_pkgconfig
+ PKGCONFIG += libdrm
+
+ HEADERS += qdri2context.h
+ SOURCES += qdri2context.cpp
+
+} else {
+ contains(QT_CONFIG, opengles2) {
+ DEFINES += XCB_USE_EGL
+ LIBS += -lEGL
+ HEADERS += qxcbeglsurface.h
+ } else:contains(QT_CONFIG, xcb-xlib) {
+ DEFINES += XCB_USE_GLX
+ HEADERS += qglxintegration.h
+ SOURCES += qglxintegration.cpp
}
}
-LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync
+LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync -lxcb-xfixes
+
+DEFINES += $$QMAKE_DEFINES_XCB
+LIBS += $$QMAKE_LIBS_XCB
+QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XCB
-include (../fontdatabases/genericunix/genericunix.pri)
+CONFIG += qpa/genericunixfontdatabase
+
+contains(QT_CONFIG, dbus) {
+DEFINES += XCB_USE_IBUS
+QT += dbus
+LIBS += -ldbus-1
+}
target.path += $$[QT_INSTALL_PLUGINS]/platforms
INSTALLS += target