Cursor support in xcb plug-in.

Custom cursor pixmaps with depth greater than 1 are not yet supported
and will be converted to monochrome always.

Reviewed-by: Samuel Rødal
bb10
Laszlo Agocs 2011-06-07 15:38:45 +02:00
parent 88f3b059a9
commit 4469de4ce7
19 changed files with 1003 additions and 179 deletions

View File

@ -41,6 +41,7 @@
#include <qcursor.h>
#include <private/qcursor_p.h>
#include <qplatformcursor_qpa.h>
#include <qbitmap.h>
QT_BEGIN_NAMESPACE
@ -107,21 +108,39 @@ void QCursorData::update()
#endif //QT_NO_CURSOR
extern int qt_last_x,qt_last_y;
extern int qt_last_x;
extern int qt_last_y;
QPoint QCursor::pos()
{
QList<QWeakPointer<QPlatformCursor> > cursors = QPlatformCursorPrivate::getInstances();
int cursorCount = cursors.count();
for (int i = 0; i < cursorCount; ++i) {
const QWeakPointer<QPlatformCursor> &cursor(cursors.at(i));
if (cursor)
return cursor.data()->pos();
}
return QPoint(qt_last_x, qt_last_y);
}
void QCursor::setPos(int x, int y)
{
QPoint target(x, y);
// Need to check, since some X servers generate null mouse move
// events, causing looping in applications which call setPos() on
// every mouse move event.
//
if (pos() == QPoint(x, y))
if (pos() == target)
return;
QList<QWeakPointer<QPlatformCursor> > cursors = QPlatformCursorPrivate::getInstances();
int cursorCount = cursors.count();
for (int i = 0; i < cursorCount; ++i) {
const QWeakPointer<QPlatformCursor> &cursor(cursors.at(i));
if (cursor)
cursor.data()->setPos(target);
}
}
QT_END_NAMESPACE

View File

@ -212,7 +212,7 @@ static void init_platform(const QString &name, const QString &platformPluginPath
QStringList keys = QPlatformIntegrationFactory::keys(platformPluginPath);
QString fatalMessage =
QString::fromLatin1("Failed to load platform plugin \"%1\". Available platforms are: \n").arg(name);
foreach(QString key, keys) {
foreach(const QString &key, keys) {
fatalMessage.append(key + QString::fromLatin1("\n"));
}
qFatal("%s", fatalMessage.toLocal8Bit().constData());
@ -221,7 +221,7 @@ static void init_platform(const QString &name, const QString &platformPluginPath
}
static void init_plugins(const QList<QByteArray> pluginList)
static void init_plugins(const QList<QByteArray> &pluginList)
{
for (int i = 0; i < pluginList.count(); ++i) {
QByteArray pluginSpec = pluginList.at(i);

View File

@ -98,6 +98,21 @@ QPlatformCursor::QPlatformCursor(QPlatformScreen *scr )
QPlatformCursorPrivate::instances.append(this);
}
extern int qt_last_x;
extern int qt_last_y;
QPoint QPlatformCursor::pos() const
{
// As a fallback return the last mouse position seen by QGuiApplication.
return QPoint(qt_last_x, qt_last_y);
}
void QPlatformCursor::setPos(const QPoint &pos)
{
Q_UNUSED(pos);
qWarning("This plugin does not support QCursor::setPos()");
}
// End of display and pointer event handling code
// Beginning of built-in cursor graphics
// from src/gui/embedded/QGraphicsSystemCursorImage_qws.cpp

View File

@ -86,6 +86,8 @@ public:
// input methods
virtual void pointerEvent(const QMouseEvent & event) { Q_UNUSED(event); }
virtual void changeCursor(QCursor * widgetCursor, QWindow * widget) = 0;
virtual QPoint pos() const;
virtual void setPos(const QPoint &pos);
protected:
QPlatformScreen* screen; // Where to request an update

View File

@ -56,6 +56,7 @@
#include <stdio.h>
#include <errno.h>
#include <xcb/xfixes.h>
#ifdef XCB_USE_XLIB
#include <X11/Xlib.h>
@ -68,7 +69,6 @@
#ifdef XCB_USE_DRI2
#include <xcb/dri2.h>
#include <xcb/xfixes.h>
extern "C" {
#include <xf86drm.h>
}
@ -125,6 +125,8 @@ QXcbConnection::QXcbConnection(const char *displayName)
m_clipboard = new QXcbClipboard(this);
m_drag = new QXcbDrag(this);
initializeXFixes();
#ifdef XCB_USE_DRI2
initializeDri2();
#endif
@ -830,6 +832,22 @@ void QXcbConnection::sync()
free(xcb_get_input_focus_reply(xcb_connection(), cookie, 0));
}
void QXcbConnection::initializeXFixes()
{
xcb_generic_error_t *error = 0;
xcb_prefetch_extension_data (m_connection, &xcb_xfixes_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_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);
}
free(xfixes_query);
}
#if defined(XCB_USE_EGL)
bool QXcbConnection::hasEgl() const
{
@ -900,26 +918,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) {

View File

@ -292,6 +292,7 @@ private slots:
private:
void initializeAllAtoms();
void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0);
void initializeXFixes();
#ifdef XCB_USE_DRI2
void initializeDri2();
#endif

View File

@ -0,0 +1,550 @@
/****************************************************************************
**
** 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_pixmap_t cp;
xcb_pixmap_t mp;
if (cursor->pixmap().depth() > 1) {
// ### this will result in monochrome cursors
cp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap()->toImage());
mp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask()->toImage());
} else {
cp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap()->toImage());
mp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask()->toImage());
}
xcb_cursor_t 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);
if (mp)
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

View File

@ -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

View File

@ -0,0 +1,180 @@
/****************************************************************************
**
** 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>
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;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,62 @@
/****************************************************************************
**
** 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);
QT_END_NAMESPACE
#endif

View File

@ -47,6 +47,7 @@
#include "qxcbnativeinterface.h"
#include "qxcbclipboard.h"
#include "qxcbdrag.h"
#include "qxcbimage.h"
#include <qgenericunixprintersupport.h>
@ -123,28 +124,6 @@ QPlatformFontDatabase *QXcbIntegration::fontDatabase() const
return m_fontDatabase;
}
static QImage::Format 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 QXcbIntegration::grabWindow(WId window, int x, int y, int width, int height) const
{
if (width == 0 || height == 0)
@ -256,84 +235,11 @@ QPixmap QXcbIntegration::grabWindow(WId window, int x, int y, int width, int hei
free(error);
}
xcb_get_image_cookie_t get_image_cookie =
xcb_get_image(connection, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, 0, 0, width, height, 0xffffffff);
xcb_get_image_reply_t *image_reply =
xcb_get_image_reply(connection, get_image_cookie, &error);
xcb_free_gc(connection, gc);
xcb_free_pixmap(connection, pixmap);
uint8_t depth = reply->depth;
QPixmap result = qt_xcb_pixmapFromXPixmap(m_connection, pixmap, width, height, reply->depth, visual);
free(reply);
if (!image_reply) {
if (error) {
m_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 = imageFormatForVisual(m_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 = m_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);
xcb_free_gc(connection, gc);
xcb_free_pixmap(connection, pixmap);
return result;
}

View File

@ -41,6 +41,7 @@
#include "qxcbscreen.h"
#include "qxcbwindow.h"
#include "qxcbcursor.h"
#include <stdio.h>
@ -140,10 +141,13 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num
xcb_depth_next(&depth_iterator);
}
m_cursor = new QXcbCursor(connection, this);
}
QXcbScreen::~QXcbScreen()
{
delete m_cursor;
}
QWindow *QXcbScreen::topLevelAt(const QPoint &p) const

View File

@ -50,6 +50,7 @@
#include "qxcbobject.h"
class QXcbConnection;
class QXcbCursor;
class QXcbScreen : public QXcbObject, public QPlatformScreen
{
@ -83,6 +84,7 @@ private:
bool m_syncRequestSupported;
xcb_window_t m_clientLeader;
QMap<xcb_visualid_t, xcb_visualtype_t> m_visuals;
QXcbCursor *m_cursor;
};
#endif

View File

@ -1234,3 +1234,9 @@ bool QXcbWindow::setMouseGrabEnabled(bool grab)
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());
}

View File

@ -79,6 +79,8 @@ public:
bool setKeyboardGrabEnabled(bool grab);
bool setMouseGrabEnabled(bool grab);
void setCursor(xcb_cursor_t cursor);
xcb_window_t xcb_window() const { return m_window; }
uint depth() const { return m_depth; }
QImage::Format format() const { return m_format; }

View File

@ -17,7 +17,9 @@ SOURCES = \
qxcbwindowsurface.cpp \
qxcbwmsupport.cpp \
main.cpp \
qxcbnativeinterface.cpp
qxcbnativeinterface.cpp \
qxcbcursor.cpp \
qxcbimage.cpp
HEADERS = \
qxcbclipboard.h \
@ -31,16 +33,21 @@ HEADERS = \
qxcbwindow.h \
qxcbwindowsurface.h \
qxcbwmsupport.h \
qxcbnativeinterface.h
qxcbnativeinterface.h \
qxcbcursor.h \
qxcbimage.h
QT += gui-private core-private
# needed by GLX, Xcursor, ...
DEFINES += XCB_USE_XLIB
contains(QT_CONFIG, opengl) {
QT += opengl
# DEFINES += XCB_USE_DRI2
contains(DEFINES, XCB_USE_DRI2) {
LIBS += -lxcb-dri2 -lxcb-xfixes -lEGL
LIBS += -lxcb-dri2 -lEGL
CONFIG += link_pkgconfig
PKGCONFIG += libdrm
@ -49,9 +56,6 @@ contains(QT_CONFIG, opengl) {
SOURCES += qdri2context.cpp
} else {
DEFINES += XCB_USE_XLIB
LIBS += -lX11 -lX11-xcb
contains(QT_CONFIG, opengles2) {
DEFINES += XCB_USE_EGL
load(qpa/egl/convenience)
@ -68,7 +72,8 @@ contains(QT_CONFIG, opengl) {
}
}
LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync
LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync -lxcb-xfixes
contains(DEFINES, XCB_USE_XLIB): LIBS += -lX11 -lX11-xcb
DEFINES += $$QMAKE_DEFINES_XCB
LIBS += $$QMAKE_LIBS_XCB

View File

@ -3348,6 +3348,12 @@ void QWidgetPrivate::setEnabled_helper(bool enable)
// disabled widgets
qt_x11_enforce_cursor(q);
}
#elif defined(Q_WS_QPA)
if (q->testAttribute(Qt::WA_SetCursor) || q->isWindow()) {
// enforce the windows behavior of clearing the cursor on
// disabled widgets
qt_qpa_set_cursor(q, false);
}
#endif
#if defined(Q_WS_MAC)
setEnabled_helper_sys(enable);

View File

@ -903,9 +903,6 @@ public:
void setFullScreenSize_helper();
bool stealKeyboardGrab(bool grab);
bool stealMouseGrab(bool grab);
#ifndef QT_NO_CURSOR
void updateCursor() const;
#endif
#elif defined(Q_OS_SYMBIAN) // <--------------------------------------------------------- SYMBIAN
static QWidget *mouseGrabber;
static QWidget *keyboardGrabber;

View File

@ -299,20 +299,13 @@ void QWidgetPrivate::setCursor_sys(const QCursor &cursor)
{
Q_UNUSED(cursor);
Q_Q(QWidget);
if (q->isVisible())
qt_qpa_set_cursor(q, false);
qt_qpa_set_cursor(q, false);
}
void QWidgetPrivate::unsetCursor_sys()
{
Q_Q(QWidget);
if (q->isVisible())
qt_qpa_set_cursor(q, false);
}
void QWidgetPrivate::updateCursor() const
{
// XXX
qt_qpa_set_cursor(q, false);
}
#endif //QT_NO_CURSOR
@ -858,56 +851,55 @@ void QWidgetPrivate::setModal_sys()
}
#ifndef QT_NO_CURSOR
void qt_qpa_set_cursor(QWidget * w, bool force)
static void applyCursor(QWidget *w, const QCursor &c)
{
static QCursor arrowCursor(Qt::ArrowCursor);
static QPointer<QWidget> lastUnderMouse = 0;
QCursor cc = c;
QList<QWeakPointer<QPlatformCursor> > cursors = QPlatformCursorPrivate::getInstances();
int cursorCount = cursors.count();
for (int i = 0; i < cursorCount; ++i) {
const QWeakPointer<QPlatformCursor> &cursor(cursors.at(i));
if (cursor)
cursor.data()->changeCursor(&cc, w->window()->windowHandle());
}
}
QCursor * override = QApplication::overrideCursor();
if (override && w != 0)
void qt_qpa_set_cursor(QWidget *w, bool force)
{
if (!w->testAttribute(Qt::WA_WState_Created))
return;
QWidget *cursorWidget;
QCursor cursorCursor;
static QPointer<QWidget> lastUnderMouse = 0;
if (force) {
lastUnderMouse = w;
} else if (lastUnderMouse && lastUnderMouse->effectiveWinId() == w->effectiveWinId()) {
w = lastUnderMouse;
} else if (!w->internalWinId()) {
return; // The mouse is not under this widget, and it's not native, so don't change it.
}
do {
if (w == 0) {
if (override) {
cursorCursor = *override;
cursorWidget = QApplication::topLevelAt(QCursor::pos());
break;
}
w = QApplication::widgetAt(QCursor::pos());
if (w == 0) // clear the override cursor while over empty space
w = QApplication::desktop();
} else if (force) {
lastUnderMouse = w;
} else if (w->testAttribute(Qt::WA_WState_Created) && lastUnderMouse
&& lastUnderMouse->effectiveWinId() == w->effectiveWinId()) {
w = lastUnderMouse;
}
if (w == QApplication::desktop() && !override) {
cursorCursor = arrowCursor;
cursorWidget = w;
break;
}
while (!w->internalWinId() && w->parentWidget() && !w->isWindow()
&& !w->testAttribute(Qt::WA_SetCursor))
w = w->parentWidget();
QWidget * curWin = QApplication::activeWindow();
if (!curWin && w && w->internalWinId())
return;
QWidget* cW = w && !w->internalWinId() ? w : curWin;
QWidget *nativeParent = w;
if (!w->internalWinId())
nativeParent = w->nativeParentWidget();
if (!nativeParent || !nativeParent->internalWinId())
return;
if (!cW || cW->window() != w->window() ||
!cW->isVisible() || !cW->underMouse() || override)
return;
cursorCursor = w->cursor();
cursorWidget = w;
} while (0);
foreach (QWeakPointer<QPlatformCursor> cursor, QPlatformCursorPrivate::getInstances())
if (cursor)
cursor.data()->changeCursor(&cursorCursor, cursorWidget->windowHandle());
if (w->isWindow() || w->testAttribute(Qt::WA_SetCursor)) {
QCursor *oc = QApplication::overrideCursor();
if (oc)
applyCursor(nativeParent, *oc);
else if (w->isEnabled())
applyCursor(nativeParent, w->cursor());
else
// Enforce the windows behavior of clearing the cursor on
// disabled widgets.
applyCursor(nativeParent, Qt::ArrowCursor);
} else {
applyCursor(nativeParent, Qt::ArrowCursor);
}
}
#endif //QT_NO_CURSOR