From 4469de4ce7a72ab6824629bfe8483131aaf22137 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 7 Jun 2011 15:38:45 +0200 Subject: Cursor support in xcb plug-in. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Custom cursor pixmaps with depth greater than 1 are not yet supported and will be converted to monochrome always. Reviewed-by: Samuel Rødal --- src/plugins/platforms/xcb/qxcbconnection.cpp | 34 +- src/plugins/platforms/xcb/qxcbconnection.h | 1 + src/plugins/platforms/xcb/qxcbcursor.cpp | 550 ++++++++++++++++++++++++++ src/plugins/platforms/xcb/qxcbcursor.h | 71 ++++ src/plugins/platforms/xcb/qxcbimage.cpp | 180 +++++++++ src/plugins/platforms/xcb/qxcbimage.h | 62 +++ src/plugins/platforms/xcb/qxcbintegration.cpp | 100 +---- src/plugins/platforms/xcb/qxcbscreen.cpp | 4 + src/plugins/platforms/xcb/qxcbscreen.h | 2 + src/plugins/platforms/xcb/qxcbwindow.cpp | 6 + src/plugins/platforms/xcb/qxcbwindow.h | 2 + src/plugins/platforms/xcb/xcb.pro | 19 +- 12 files changed, 912 insertions(+), 119 deletions(-) create mode 100644 src/plugins/platforms/xcb/qxcbcursor.cpp create mode 100644 src/plugins/platforms/xcb/qxcbcursor.h create mode 100644 src/plugins/platforms/xcb/qxcbimage.cpp create mode 100644 src/plugins/platforms/xcb/qxcbimage.h (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 94c30a989f..1f966b1bd8 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -56,6 +56,7 @@ #include #include +#include #ifdef XCB_USE_XLIB #include @@ -68,7 +69,6 @@ #ifdef XCB_USE_DRI2 #include -#include extern "C" { #include } @@ -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) { diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index aa54229779..b148b56eb4 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -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 diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp new file mode 100644 index 0000000000..cf1e5279a0 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +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(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(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(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(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(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(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(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(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(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(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 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 +#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 m_shapeCursorMap; + QMap m_bitmapCursorMap; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp new file mode 100644 index 0000000000..6c8c4e32c8 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbimage.cpp @@ -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 +#include + +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(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 diff --git a/src/plugins/platforms/xcb/qxcbimage.h b/src/plugins/platforms/xcb/qxcbimage.h new file mode 100644 index 0000000000..39a7abd315 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbimage.h @@ -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 +#include +#include +#include + +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 diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index a7d88e7741..aa11ba5cb0 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -47,6 +47,7 @@ #include "qxcbnativeinterface.h" #include "qxcbclipboard.h" #include "qxcbdrag.h" +#include "qxcbimage.h" #include @@ -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,85 +235,12 @@ 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); + QPixmap result = qt_xcb_pixmapFromXPixmap(m_connection, pixmap, width, height, reply->depth, visual); + free(reply); xcb_free_gc(connection, gc); xcb_free_pixmap(connection, pixmap); - uint8_t depth = reply->depth; - - 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(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); - return result; } diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 0d0c4a5138..6c3d1813b0 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -41,6 +41,7 @@ #include "qxcbscreen.h" #include "qxcbwindow.h" +#include "qxcbcursor.h" #include @@ -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 diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index cb84e55ccc..5b8492faa5 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 { @@ -83,6 +84,7 @@ private: bool m_syncRequestSupported; xcb_window_t m_clientLeader; QMap m_visuals; + QXcbCursor *m_cursor; }; #endif diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 09b92b2fbf..de48c83cd1 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -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()); +} diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 0412f4a75e..f6869c7937 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -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; } diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro index 2f70b659c9..0d9e969ddc 100644 --- a/src/plugins/platforms/xcb/xcb.pro +++ b/src/plugins/platforms/xcb/xcb.pro @@ -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 -- cgit v1.2.3