summaryrefslogtreecommitdiffstats
path: root/src/plugins/gfxdrivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/gfxdrivers')
-rw-r--r--src/plugins/gfxdrivers/ahi/ahi.pro14
-rw-r--r--src/plugins/gfxdrivers/ahi/qscreenahi_qws.cpp598
-rw-r--r--src/plugins/gfxdrivers/ahi/qscreenahi_qws.h84
-rw-r--r--src/plugins/gfxdrivers/ahi/qscreenahiplugin.cpp74
-rw-r--r--src/plugins/gfxdrivers/directfb/directfb.pro15
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp436
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.h74
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp294
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbmouse.h75
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp221
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h108
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp1430
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h123
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp588
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h105
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp1819
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbscreen.h303
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbscreenplugin.cpp78
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp506
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h129
-rw-r--r--src/plugins/gfxdrivers/eglnullws/README48
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullws.pro18
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.cpp181
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.h69
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.cpp66
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.h47
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.cpp84
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.h63
-rw-r--r--src/plugins/gfxdrivers/gfxdrivers.pro10
-rw-r--r--src/plugins/gfxdrivers/linuxfb/linuxfb.pro14
-rw-r--r--src/plugins/gfxdrivers/linuxfb/main.cpp79
-rw-r--r--src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro26
-rw-r--r--src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c830
-rw-r--r--src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h169
-rw-r--r--src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable_p.h132
-rw-r--r--src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwswsegl.c402
-rw-r--r--src/plugins/gfxdrivers/powervr/README66
-rw-r--r--src/plugins/gfxdrivers/powervr/powervr.pri2
-rw-r--r--src/plugins/gfxdrivers/powervr/powervr.pro3
-rw-r--r--src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp351
-rw-r--r--src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.h99
-rw-r--r--src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro27
-rw-r--r--src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp74
-rw-r--r--src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.cpp273
-rw-r--r--src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h85
-rw-r--r--src/plugins/gfxdrivers/qvfb/main.cpp82
-rw-r--r--src/plugins/gfxdrivers/qvfb/qvfb.pro19
-rw-r--r--src/plugins/gfxdrivers/transformed/main.cpp84
-rw-r--r--src/plugins/gfxdrivers/transformed/transformed.pro13
-rw-r--r--src/plugins/gfxdrivers/vnc/main.cpp86
-rw-r--r--src/plugins/gfxdrivers/vnc/qscreenvnc_p.h524
-rw-r--r--src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp2338
-rw-r--r--src/plugins/gfxdrivers/vnc/qscreenvnc_qws.h88
-rw-r--r--src/plugins/gfxdrivers/vnc/vnc.pro16
54 files changed, 13542 insertions, 0 deletions
diff --git a/src/plugins/gfxdrivers/ahi/ahi.pro b/src/plugins/gfxdrivers/ahi/ahi.pro
new file mode 100644
index 0000000000..6fc8a5cc8d
--- /dev/null
+++ b/src/plugins/gfxdrivers/ahi/ahi.pro
@@ -0,0 +1,14 @@
+TARGET = qahiscreen
+include(../../qpluginbase.pri)
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers
+
+target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers
+INSTALLS += target
+
+HEADERS = qscreenahi_qws.h
+
+SOURCES = qscreenahi_qws.cpp \
+ qscreenahiplugin.cpp
+
+LIBS += -lahi
diff --git a/src/plugins/gfxdrivers/ahi/qscreenahi_qws.cpp b/src/plugins/gfxdrivers/ahi/qscreenahi_qws.cpp
new file mode 100644
index 0000000000..aa28b0eeec
--- /dev/null
+++ b/src/plugins/gfxdrivers/ahi/qscreenahi_qws.cpp
@@ -0,0 +1,598 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qscreenahi_qws.h"
+
+#ifndef QT_NO_QWS_AHI
+
+#include <QtGui/qcolor.h>
+#include <QtGui/qapplication.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qvarlengtharray.h>
+#include <private/qwssignalhandler_p.h>
+
+#include <ahi.h>
+
+//#define QAHISCREEN_DEBUG
+
+static int depthForPixelFormat(const AhiPixelFormat_t format)
+{
+ switch (format) {
+ case AhiPix1bpp:
+ return 1;
+ case AhiPix2bpp:
+ return 2;
+ case AhiPix4bpp:
+ return 4;
+ case AhiPix8bpp_332RGB:
+ case AhiPix8bpp:
+ return 8;
+ case AhiPix16bpp_444RGB:
+ return 12;
+ case AhiPix16bpp_555RGB:
+ return 15;
+ case AhiPix16bpp_565RGB:
+ return 16;
+ case AhiPix32bpp_8888ARGB:
+ case AhiPix32bpp_8888BGRA:
+ return 32;
+ default:
+ return 0;
+ }
+}
+
+static AhiPixelFormat_t pixelFormatForImageFormat(const QImage::Format format)
+{
+ switch (format) {
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ return AhiPix1bpp;
+ case QImage::Format_Indexed8:
+ return AhiPix8bpp;
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ return AhiPix32bpp_8888ARGB;
+ case QImage::Format_RGB16:
+ return AhiPix16bpp_565RGB;
+ case QImage::Format_RGB555:
+ return AhiPix16bpp_555RGB;
+ case QImage::Format_ARGB4444_Premultiplied:
+ case QImage::Format_RGB444:
+ return AhiPix16bpp_444RGB;
+ default:
+ return AhiPixelFormatMax;
+ }
+}
+
+class QAhiScreenCursor : public QScreenCursor
+{
+public:
+ QAhiScreenCursor(QScreen *screen, AhiDevCtx_t context);
+
+ void set(const QImage &image, int hotx, int hoty);
+ void move(int x, int y);
+ void show();
+ void hide();
+
+private:
+ QScreen *screen;
+ AhiDevCtx_t context;
+};
+
+QAhiScreenCursor::QAhiScreenCursor(QScreen *s, AhiDevCtx_t c)
+ : QScreenCursor(), screen(s), context(c)
+{
+ hwaccel = true;
+ supportsAlpha = true;
+
+ if (enable)
+ show();
+ else
+ hide();
+}
+
+void QAhiScreenCursor::set(const QImage &image, int hotx, int hoty)
+{
+ if (image.isNull()) {
+ QScreenCursor::set(image, hotx, hoty);
+ return;
+ }
+
+ if (image.format() != QImage::Format_MonoLSB) {
+ set(image.convertToFormat(QImage::Format_MonoLSB), hotx, hoty);
+ return;
+ }
+
+ AhiPixelFormat_t pixFmt = pixelFormatForImageFormat(image.format());
+
+ if (pixFmt >= AhiPixelFormatMax) { // generic fallback
+ QImage::Format toFormat = screen->pixelFormat();
+ if (toFormat == QImage::Format_Invalid)
+ toFormat = QImage::Format_ARGB32;
+ set(image.convertToFormat(toFormat), hotx, hoty);
+ return;
+ }
+
+ AhiPoint_t hotSpot = { hotx, hoty };
+ AhiSize_t bitmapSize = { image.width(), image.height() };
+ AhiBitmap_t bitmap = { bitmapSize, (void*)(image.bits()),
+ image.bytesPerLine(), pixFmt };
+
+ AhiSts_t status;
+ status = AhiDispCursorSet(context, AhiCursor1, &bitmap, &hotSpot,
+ image.serialNumber(), 0);
+ if (status != AhiStsOk)
+ qWarning("QAhiScreenCursor::set(): AhiDispCursorSet failed: %x",
+ status);
+
+ QScreenCursor::set(image, hotx, hoty);
+}
+
+void QAhiScreenCursor::move(int x, int y)
+{
+ AhiPoint_t pos = { x, y };
+ AhiSts_t status = AhiDispCursorPos(context, AhiCursor1, &pos, 0);
+ if (status != AhiStsOk)
+ qWarning("QAhiScreenCursor::move(): error setting mouse position: %x",
+ status);
+ QScreenCursor::move(x, y);
+}
+
+void QAhiScreenCursor::show()
+{
+ AhiSts_t status;
+ status = AhiDispCursorState(context, AhiCursor1, AhiCursorStateOn, 0);
+ if (status != AhiStsOk)
+ qWarning("QAhiScreenCursor::show(): error setting state: %x", status);
+ QScreenCursor::show();
+}
+
+void QAhiScreenCursor::hide()
+{
+ AhiDispCursorState(context, AhiCursor1, AhiCursorStateOff, 0);
+ QScreenCursor::hide();
+}
+
+class QAhiScreenPrivate : public QObject
+{
+public:
+ QAhiScreenPrivate();
+ ~QAhiScreenPrivate();
+
+ bool setMode(AhiDispMode_t mode);
+
+ AhiDevCtx_t context;
+ AhiSurf_t surface;
+ QAhiScreenCursor *cursor;
+};
+
+QT_BEGIN_NAMESPACE
+
+QAhiScreenPrivate::QAhiScreenPrivate()
+ : context(0), surface(0), cursor(0)
+{
+#ifndef QT_NO_QWS_SIGNALHANDLER
+ QWSSignalHandler::instance()->addObject(this);
+#endif
+}
+
+QAhiScreenPrivate::~QAhiScreenPrivate()
+{
+ delete cursor;
+
+ if (surface) {
+ AhiSurfFree(context, surface);
+ surface = 0;
+ }
+ if (context) {
+ AhiDevClose(context);
+ context = 0;
+ }
+ AhiTerm();
+}
+
+bool QAhiScreenPrivate::setMode(AhiDispMode_t mode)
+{
+ AhiSts_t status;
+
+ status = AhiDispModeSet(context, &mode, 0);
+ if (status != AhiStsOk) {
+ qCritical("QAhiScreenPrivate::setMode(): AhiDispModeSet failed: %x",
+ status);
+ return false;
+ }
+
+ if (surface) {
+ AhiSurfFree(context, surface);
+ surface = 0;
+ }
+ status = AhiSurfAlloc(context, &surface, &mode.size, mode.pixFmt,
+ AHIFLAG_SURFFIXED);
+ if (status != AhiStsOk) {
+ qCritical("QAhiScreenPrivate::setMode(): AhisurfAlloc failed: %x",
+ status);
+ return false;
+ }
+
+ status = AhiDispSurfSet(context, surface, 0);
+ if (status != AhiStsOk) {
+ qCritical("QAhiScreenPrivate::setMode(): AhiDispSurfSet failed: %x",
+ status);
+ return false;
+ }
+
+ return true;
+}
+
+QAhiScreen::QAhiScreen(int displayId)
+ : QScreen(displayId), d_ptr(new QAhiScreenPrivate)
+{
+}
+
+QAhiScreen::~QAhiScreen()
+{
+ delete d_ptr;
+}
+
+bool QAhiScreen::configure()
+{
+ AhiSurfInfo_t surfaceInfo;
+ AhiSts_t status;
+
+ status = AhiSurfInfo(d_ptr->context, d_ptr->surface, &surfaceInfo);
+ if (status != AhiStsOk) {
+ qCritical("QAhiScreen::configure(): AhiSurfInfo failed: %x", status);
+ return false;
+ }
+
+ QScreen::data = 0;
+ QScreen::w = QScreen::dw = surfaceInfo.size.cx;
+ QScreen::h = QScreen::dh = surfaceInfo.size.cy;
+ QScreen::lstep = surfaceInfo.stride;
+ QScreen::size = surfaceInfo.sizeInBytes;
+
+ switch (surfaceInfo.pixFmt) {
+ case AhiPix1bpp:
+ setPixelFormat(QImage::Format_Mono);
+ QScreen::d = 1;
+ break;
+ case AhiPix4bpp:
+ QScreen::d = 4;
+ break;
+ case AhiPix8bpp_332RGB:
+ case AhiPix8bpp:
+ QScreen::d = 8;
+ break;
+ case AhiPix16bpp_444RGB:
+ setPixelFormat(QImage::Format_RGB444);
+ QScreen::d = 12;
+ break;
+ case AhiPix16bpp_555RGB:
+ setPixelFormat(QImage::Format_RGB555);
+ QScreen::d = 15;
+ break;
+ case AhiPix16bpp_565RGB:
+ setPixelFormat(QImage::Format_RGB16);
+ QScreen::d = 16;
+ break;
+ case AhiPix2bpp:
+ QScreen::d = 2;
+ break;
+ case AhiPix32bpp_8888ARGB:
+ setPixelFormat(QImage::Format_ARGB32);
+ // fallthrough
+ case AhiPix32bpp_8888BGRA:
+ QScreen::d = 32;
+ break;
+ default:
+ qCritical("QAhiScreen::configure(): Unknown pixel format: %x",
+ surfaceInfo.pixFmt);
+ return false;
+ }
+
+ const int dpi = 72;
+ QScreen::physWidth = qRound(QScreen::dw * 25.4 / dpi);
+ QScreen::physHeight = qRound(QScreen::dh * 25.4 / dpi);
+
+ return true;
+}
+
+bool QAhiScreen::connect(const QString &displaySpec)
+{
+ Q_UNUSED(displaySpec);
+
+ AhiSts_t status;
+
+ status = AhiInit(0);
+ if (status != AhiStsOk) {
+ qCritical("QAhiScreen::connect(): AhiInit failed: %x", status);
+ return false;
+ }
+
+ AhiDev_t device;
+ AhiDevInfo_t info;
+
+ status = AhiDevEnum(&device, &info, 0);
+ if (status != AhiStsOk) {
+ qCritical("QAhiScreen::connect(): AhiDevEnum failed: %x", status);
+ return false;
+ }
+#ifdef QAHISCREEN_DEBUG
+ {
+ int displayNo = 0;
+ AhiDevInfo_t dispInfo = info;
+ qDebug("AHI supported devices:");
+ do {
+ qDebug(" %2i: %s, sw version: %s (rev %u)\n"
+ " chip: 0x%x (rev %u), mem: %i (%i/%i), bus: 0x%x",
+ displayNo, dispInfo.name,
+ dispInfo.swVersion, uint(dispInfo.swRevision),
+ uint(dispInfo.chipId), uint(dispInfo.revisionId),
+ uint(dispInfo.totalMemory),
+ uint(dispInfo.internalMemSize),
+ uint(dispInfo.externalMemSize),
+ uint(dispInfo.cpuBusInterfaceMode));
+ status = AhiDevEnum(&device, &info, ++displayNo);
+ } while (status == AhiStsOk);
+ }
+#endif
+
+ status = AhiDevOpen(&d_ptr->context, device, "qscreenahi",
+ AHIFLAG_USERLEVEL);
+ if (status != AhiStsOk) {
+ qCritical("QAhiScreen::connect(): AhiDevOpen failed: %x", status);
+ return false;
+ }
+
+ AhiDispMode_t mode;
+
+ status = AhiDispModeEnum(d_ptr->context, &mode, 0);
+ if (status != AhiStsOk) {
+ qCritical("QAhiScreen::connect(): AhiDispModeEnum failed: %x", status);
+ return false;
+ }
+
+#ifdef QAHISCREEN_DEBUG
+ {
+ int modeNo = 0;
+ AhiDispMode_t modeInfo = mode;
+ qDebug("AHI supported modes:");
+ do {
+ qDebug(" %2i: %ux%u, fmt: %i, %u Hz, rot: %i, mirror: %i",
+ modeNo, uint(modeInfo.size.cx), uint(modeInfo.size.cy),
+ modeInfo.pixFmt, uint(modeInfo.frequency),
+ modeInfo.rotation, modeInfo.mirror);
+ status = AhiDispModeEnum(d_ptr->context, &modeInfo, ++modeNo);
+ } while (status == AhiStsOk);
+ }
+#endif
+
+ if (QApplication::type() == QApplication::GuiServer) {
+ if (!d_ptr->setMode(mode))
+ return false;
+ } else {
+ status = AhiDispSurfGet(d_ptr->context, &d_ptr->surface);
+ if (status != AhiStsOk) {
+ qCritical("QAhiScreen::connect(): AhiDispSurfGet failed: %x",
+ status);
+ return false;
+ }
+
+ status = AhiDispModeGet(d_ptr->context, &mode);
+ if (status != AhiStsOk) {
+ qCritical("QAhiScreen::context(): AhiDispModeGet failed: %x",
+ status);
+ return false;
+ }
+ }
+
+ return configure();
+}
+
+void QAhiScreen::disconnect()
+{
+ AhiSurfFree(d_ptr->context, d_ptr->surface);
+ d_ptr->surface = 0;
+ AhiDevClose(d_ptr->context);
+ d_ptr->context = 0;
+ AhiTerm();
+}
+
+bool QAhiScreen::initDevice()
+{
+ QScreenCursor::initSoftwareCursor();
+
+ AhiSts_t status = AhiDispState(d_ptr->context, AhiDispStateOn, 0);
+ if (status != AhiStsOk) {
+ qCritical("QAhiScreen::connect(): AhiDispState failed: %x", status);
+ return false;
+ }
+
+ return true;
+}
+
+void QAhiScreen::shutdownDevice()
+{
+ AhiDispState(d_ptr->context, AhiDispStateOff, 0);
+}
+
+void QAhiScreen::setMode(int width, int height, int depth)
+{
+ int modeNo = 0;
+ AhiDispMode_t mode;
+ AhiSts_t status = AhiStsOk;
+
+ while (status == AhiStsOk) {
+ status = AhiDispModeEnum(d_ptr->context, &mode, modeNo);
+ if (mode.size.cx == uint(width) &&
+ mode.size.cy == uint(height) &&
+ depthForPixelFormat(mode.pixFmt) == depth)
+ {
+ d_ptr->setMode(mode);
+ configure();
+ return;
+ }
+ }
+}
+
+void QAhiScreen::blit(const QImage &image, const QPoint &topLeft,
+ const QRegion &reg)
+{
+ AhiPixelFormat_t pixFmt = pixelFormatForImageFormat(image.format());
+
+ if (pixFmt >= AhiPixelFormatMax) { // generic fallback
+ QImage::Format toFormat = pixelFormat();
+ if (toFormat == QImage::Format_Invalid)
+ toFormat = QImage::Format_ARGB32;
+ blit(image.convertToFormat(toFormat), topLeft, reg);
+ return;
+ }
+
+ AhiSts_t status;
+
+ status = AhiDrawSurfDstSet(d_ptr->context, d_ptr->surface, 0);
+ if (status != AhiStsOk) {
+ qWarning("QAhiScreen::blit(): AhiDrawSurfDstSet failed: %x", status);
+ return;
+ }
+
+ const QVector<QRect> rects = (reg & region()).rects();
+ const int numRects = rects.size();
+ QVarLengthArray<AhiPoint_t, 8> src(numRects);
+ QVarLengthArray<AhiRect_t, 8> dest(numRects);
+
+ for (int i = 0; i < numRects; ++i) {
+ const QRect rect = rects.at(i);
+
+ src[i].x = rect.x() - topLeft.x();
+ src[i].y = rect.y() - topLeft.y();
+ dest[i].left = rect.left();
+ dest[i].top = rect.top();
+ dest[i].right = rect.x() + rect.width();
+ dest[i].bottom = rect.y() + rect.height();
+ }
+
+ AhiSize_t bitmapSize = { image.width(), image.height() };
+ AhiBitmap_t bitmap = { bitmapSize, (void*)(image.bits()),
+ image.bytesPerLine(), pixFmt };
+
+ status = AhiDrawRopSet(d_ptr->context, AHIMAKEROP3(AHIROPSRCCOPY));
+ if (status != AhiStsOk) {
+ qWarning("QAhiScreen::blit(): AhiDrawRopSet failed: %x", status);
+ return;
+ }
+
+ for (int i = 0; i < numRects; ++i) {
+ status = AhiDrawBitmapBlt(d_ptr->context, &dest[i], &src[i],
+ &bitmap, 0, 0);
+ if (status != AhiStsOk) {
+ qWarning("QAhiScreen::blit(): AhiDrawBitmapBlt failed: %x",
+ status);
+ break;
+ }
+ }
+}
+
+void QAhiScreen::solidFill(const QColor &color, const QRegion &reg)
+{
+ AhiSts_t status = AhiStsOk;
+
+ switch (pixelFormat()) {
+ case QImage::Format_ARGB32_Premultiplied:
+ case QImage::Format_ARGB32:
+ case QImage::Format_RGB32:
+ status = AhiDrawBrushFgColorSet(d_ptr->context, color.rgba());
+ break;
+ case QImage::Format_RGB16:
+ status = AhiDrawBrushFgColorSet(d_ptr->context, qt_convRgbTo16(color.rgb()));
+ break;
+ default:
+ qFatal("QAhiScreen::solidFill(): Not implemented for pixel format %d",
+ int(pixelFormat()));
+ break;
+ }
+
+ if (status != AhiStsOk) {
+ qWarning("QAhiScreen::solidFill(): AhiDrawBrushFgColorSet failed: %x",
+ status);
+ return;
+ }
+
+ status = AhiDrawBrushSet(d_ptr->context, 0, 0, 0, AHIFLAG_BRUSHSOLID);
+ if (status != AhiStsOk) {
+ qWarning("QAhiScreen::solidFill(): AhiDrawBrushSet failed: %x",
+ status);
+ return;
+ }
+
+ status = AhiDrawRopSet(d_ptr->context, AHIMAKEROP3(AHIROPPATCOPY));
+ if (status != AhiStsOk) {
+ qWarning("QAhiScreen::solidFill(): AhiDrawRopSet failed: %x", status);
+ return;
+ }
+
+ status = AhiDrawSurfDstSet(d_ptr->context, d_ptr->surface, 0);
+ if (status != AhiStsOk) {
+ qWarning("QAhiScreen::solidFill(): AhiDrawSurfDst failed: %x", status);
+ return;
+ }
+
+ const QVector<QRect> rects = (reg & region()).rects();
+ QVarLengthArray<AhiRect_t> ahiRects(rects.size());
+
+ for (int i = 0; i < rects.size(); ++i) {
+ const QRect rect = rects.at(i);
+ ahiRects[i].left = rect.left();
+ ahiRects[i].top = rect.top();
+ ahiRects[i].right = rect.x() + rect.width();
+ ahiRects[i].bottom = rect.y() + rect.height();
+ }
+
+ status = AhiDrawBitBltMulti(d_ptr->context, ahiRects.data(),
+ 0, ahiRects.size());
+ if (status != AhiStsOk)
+ qWarning("QAhiScreen::solidFill(): AhiDrawBitBlt failed: %x", status);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QWS_AHI
diff --git a/src/plugins/gfxdrivers/ahi/qscreenahi_qws.h b/src/plugins/gfxdrivers/ahi/qscreenahi_qws.h
new file mode 100644
index 0000000000..ec947f4dc6
--- /dev/null
+++ b/src/plugins/gfxdrivers/ahi/qscreenahi_qws.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QAHISCREEN_H
+#define QAHISCREEN_H
+
+#include <QtGui/qscreenlinuxfb_qws.h>
+
+#ifndef QT_NO_QWS_AHI
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QAhiScreenPrivate;
+
+class QAhiScreen : public QScreen
+{
+public:
+ QAhiScreen(int displayId);
+ ~QAhiScreen();
+
+ bool connect(const QString &displaySpec);
+ void disconnect();
+ bool initDevice();
+ void shutdownDevice();
+ void setMode(int width, int height, int depth);
+
+ void blit(const QImage &image, const QPoint &topLeft,
+ const QRegion &region);
+ void solidFill(const QColor &color, const QRegion &region);
+
+private:
+ bool configure();
+
+ QAhiScreenPrivate *d_ptr;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_QWS_AHI
+#endif // QAHISCREEN_H
diff --git a/src/plugins/gfxdrivers/ahi/qscreenahiplugin.cpp b/src/plugins/gfxdrivers/ahi/qscreenahiplugin.cpp
new file mode 100644
index 0000000000..7fdb7789b8
--- /dev/null
+++ b/src/plugins/gfxdrivers/ahi/qscreenahiplugin.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qscreenahi_qws.h"
+
+#include <QScreenDriverPlugin>
+#include <QStringList>
+
+class QAhiScreenPlugin : public QScreenDriverPlugin
+{
+public:
+ QAhiScreenPlugin();
+
+ QStringList keys() const;
+ QScreen *create(const QString&, int displayId);
+};
+
+QAhiScreenPlugin::QAhiScreenPlugin()
+ : QScreenDriverPlugin()
+{
+}
+
+QStringList QAhiScreenPlugin::keys() const
+{
+ return (QStringList() << "ahi");
+}
+
+QScreen* QAhiScreenPlugin::create(const QString& driver, int displayId)
+{
+ if (driver.toLower() != "ahi")
+ return 0;
+
+ return new QAhiScreen(displayId);
+}
+
+Q_EXPORT_PLUGIN2(qahiscreen, QAhiScreenPlugin)
diff --git a/src/plugins/gfxdrivers/directfb/directfb.pro b/src/plugins/gfxdrivers/directfb/directfb.pro
new file mode 100644
index 0000000000..d397050bdc
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/directfb.pro
@@ -0,0 +1,15 @@
+TARGET = qdirectfbscreen
+include(../../qpluginbase.pri)
+include($$QT_SOURCE_TREE/src/gui/embedded/directfb.pri)
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers
+
+target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers
+INSTALLS += target
+
+SOURCES += qdirectfbscreenplugin.cpp
+
+QMAKE_CXXFLAGS += $$QT_CFLAGS_DIRECTFB
+LIBS += $$QT_LIBS_DIRECTFB
+DEFINES += $$QT_DEFINES_DIRECTFB
+contains(gfx-plugins, directfb):DEFINES += QT_QWS_DIRECTFB
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp
new file mode 100644
index 0000000000..5c6842edca
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp
@@ -0,0 +1,436 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdirectfbkeyboard.h"
+
+#ifndef QT_NO_QWS_DIRECTFB
+
+#include "qdirectfbscreen.h"
+#include <qobject.h>
+#include <qsocketnotifier.h>
+#include <qhash.h>
+
+#include <directfb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+class KeyMap : public QHash<DFBInputDeviceKeySymbol, Qt::Key>
+{
+public:
+ KeyMap();
+};
+
+Q_GLOBAL_STATIC(KeyMap, keymap);
+
+class QDirectFBKeyboardHandlerPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QDirectFBKeyboardHandlerPrivate(QDirectFBKeyboardHandler *handler);
+ ~QDirectFBKeyboardHandlerPrivate();
+
+ void suspend();
+ void resume();
+
+private:
+ QDirectFBKeyboardHandler *handler;
+ IDirectFBEventBuffer *eventBuffer;
+ QSocketNotifier *keyboardNotifier;
+ DFBEvent event;
+ int bytesRead;
+ int lastUnicode, lastKeycode;
+ Qt::KeyboardModifiers lastModifiers;
+private Q_SLOTS:
+ void readKeyboardData();
+};
+
+QDirectFBKeyboardHandlerPrivate::QDirectFBKeyboardHandlerPrivate(QDirectFBKeyboardHandler *h)
+ : handler(h), eventBuffer(0), keyboardNotifier(0), bytesRead(0),
+ lastUnicode(0), lastKeycode(0), lastModifiers(0)
+{
+ Q_ASSERT(qt_screen);
+
+ IDirectFB *fb = QDirectFBScreen::instance()->dfb();
+ if (!fb) {
+ qCritical("QDirectFBKeyboardHandler: DirectFB not initialized");
+ return;
+ }
+
+ DFBResult result;
+ result = fb->CreateInputEventBuffer(fb, DICAPS_KEYS, DFB_TRUE,
+ &eventBuffer);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBKeyboardHandler: "
+ "Unable to create input event buffer", result);
+ return;
+ }
+
+ int fd;
+ result = eventBuffer->CreateFileDescriptor(eventBuffer, &fd);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBKeyboardHandler: "
+ "Unable to create file descriptor", result);
+ return;
+ }
+
+ int flags = ::fcntl(fd, F_GETFL, 0);
+ ::fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ memset(&event, 0, sizeof(event));
+
+ keyboardNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
+ connect(keyboardNotifier, SIGNAL(activated(int)),
+ this, SLOT(readKeyboardData()));
+ resume();
+}
+
+void QDirectFBKeyboardHandlerPrivate::suspend()
+{
+ keyboardNotifier->setEnabled(false);
+}
+
+void QDirectFBKeyboardHandlerPrivate::resume()
+{
+ eventBuffer->Reset(eventBuffer);
+ keyboardNotifier->setEnabled(true);
+}
+
+QDirectFBKeyboardHandlerPrivate::~QDirectFBKeyboardHandlerPrivate()
+{
+ if (eventBuffer)
+ eventBuffer->Release(eventBuffer);
+}
+
+void QDirectFBKeyboardHandlerPrivate::readKeyboardData()
+{
+ if(!qt_screen)
+ return;
+
+ for (;;) {
+ // GetEvent returns DFB_UNSUPPORTED after CreateFileDescriptor().
+ // This seems stupid and I really hope it's a bug which will be fixed.
+
+ // DFBResult ret = eventBuffer->GetEvent(eventBuffer, &event);
+
+ char *buf = reinterpret_cast<char*>(&event);
+ int ret = ::read(keyboardNotifier->socket(),
+ buf + bytesRead, sizeof(DFBEvent) - bytesRead);
+ if (ret == -1) {
+ if (errno != EAGAIN)
+ qWarning("QDirectFBKeyboardHandlerPrivate::readKeyboardData(): %s",
+ strerror(errno));
+ return;
+ }
+
+ Q_ASSERT(ret >= 0);
+ bytesRead += ret;
+ if (bytesRead < int(sizeof(DFBEvent)))
+ break;
+ bytesRead = 0;
+
+ Q_ASSERT(event.clazz == DFEC_INPUT);
+
+ const DFBInputEvent input = event.input;
+
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier;
+
+ // Not implemented:
+ // if (input.modifiers & DIMM_SUPER)
+ // if (input.modifiers & DIMM_HYPER)
+
+ if (!(input.flags & DIEF_KEYSYMBOL) ||
+ !(input.flags & DIEF_KEYID) ||
+ !(input.type & (DIET_KEYPRESS|DIET_KEYRELEASE)))
+ {
+ static bool first = true;
+ if (first) {
+ qWarning("QDirectFBKeyboardHandler - Getting unexpected non-keyboard related events");
+ first = false;
+ }
+ break;
+ }
+
+ if (input.flags & DIEF_MODIFIERS) {
+ if (input.modifiers & DIMM_SHIFT)
+ modifiers |= Qt::ShiftModifier;
+ if (input.modifiers & DIMM_CONTROL)
+ modifiers |= Qt::ControlModifier;
+ if (input.modifiers & DIMM_ALT)
+ modifiers |= Qt::AltModifier;
+ if (input.modifiers & DIMM_ALTGR)
+ modifiers |= Qt::AltModifier;
+ if (input.modifiers & DIMM_META)
+ modifiers |= Qt::MetaModifier;
+ }
+
+
+ const bool press = input.type & DIET_KEYPRESS;
+ DFBInputDeviceKeySymbol symbol = input.key_symbol;
+ int unicode = -1;
+ int keycode = 0;
+
+ keycode = keymap()->value(symbol);
+ if (DFB_KEY_TYPE(symbol) == DIKT_UNICODE)
+ unicode = symbol;
+
+ if (unicode != -1 || keycode != 0) {
+ bool autoRepeat = false;
+ if (press) {
+ if (unicode == lastUnicode && keycode == lastKeycode && modifiers == lastModifiers) {
+ autoRepeat = true;
+ } else {
+ lastUnicode = unicode;
+ lastKeycode = keycode;
+ lastModifiers = modifiers;
+ }
+ } else {
+ lastUnicode = lastKeycode = -1;
+ lastModifiers = 0;
+ }
+ if (autoRepeat) {
+ handler->processKeyEvent(unicode, keycode,
+ modifiers, false, autoRepeat);
+
+ }
+
+ handler->processKeyEvent(unicode, keycode,
+ modifiers, press, autoRepeat);
+ }
+ }
+}
+
+QDirectFBKeyboardHandler::QDirectFBKeyboardHandler(const QString &device)
+ : QWSKeyboardHandler()
+{
+ Q_UNUSED(device);
+ d = new QDirectFBKeyboardHandlerPrivate(this);
+}
+
+QDirectFBKeyboardHandler::~QDirectFBKeyboardHandler()
+{
+ delete d;
+}
+
+KeyMap::KeyMap()
+{
+ insert(DIKS_BACKSPACE , Qt::Key_Backspace);
+ insert(DIKS_TAB , Qt::Key_Tab);
+ insert(DIKS_RETURN , Qt::Key_Return);
+ insert(DIKS_ESCAPE , Qt::Key_Escape);
+ insert(DIKS_DELETE , Qt::Key_Delete);
+
+ insert(DIKS_CURSOR_LEFT , Qt::Key_Left);
+ insert(DIKS_CURSOR_RIGHT , Qt::Key_Right);
+ insert(DIKS_CURSOR_UP , Qt::Key_Up);
+ insert(DIKS_CURSOR_DOWN , Qt::Key_Down);
+ insert(DIKS_INSERT , Qt::Key_Insert);
+ insert(DIKS_HOME , Qt::Key_Home);
+ insert(DIKS_END , Qt::Key_End);
+ insert(DIKS_PAGE_UP , Qt::Key_PageUp);
+ insert(DIKS_PAGE_DOWN , Qt::Key_PageDown);
+ insert(DIKS_PRINT , Qt::Key_Print);
+ insert(DIKS_PAUSE , Qt::Key_Pause);
+ insert(DIKS_SELECT , Qt::Key_Select);
+ insert(DIKS_GOTO , Qt::Key_OpenUrl);
+ insert(DIKS_CLEAR , Qt::Key_Clear);
+ insert(DIKS_MENU , Qt::Key_Menu);
+ insert(DIKS_HELP , Qt::Key_Help);
+
+ insert(DIKS_INTERNET , Qt::Key_HomePage);
+ insert(DIKS_MAIL , Qt::Key_LaunchMail);
+ insert(DIKS_FAVORITES , Qt::Key_Favorites);
+
+ insert(DIKS_BACK , Qt::Key_Back);
+ insert(DIKS_FORWARD , Qt::Key_Forward);
+ insert(DIKS_VOLUME_UP , Qt::Key_VolumeUp);
+ insert(DIKS_VOLUME_DOWN , Qt::Key_VolumeDown);
+ insert(DIKS_MUTE , Qt::Key_VolumeMute);
+ insert(DIKS_PLAYPAUSE , Qt::Key_Pause);
+ insert(DIKS_PLAY , Qt::Key_MediaPlay);
+ insert(DIKS_STOP , Qt::Key_MediaStop);
+ insert(DIKS_RECORD , Qt::Key_MediaRecord);
+ insert(DIKS_PREVIOUS , Qt::Key_MediaPrevious);
+ insert(DIKS_NEXT , Qt::Key_MediaNext);
+
+ insert(DIKS_F1 , Qt::Key_F1);
+ insert(DIKS_F2 , Qt::Key_F2);
+ insert(DIKS_F3 , Qt::Key_F3);
+ insert(DIKS_F4 , Qt::Key_F4);
+ insert(DIKS_F5 , Qt::Key_F5);
+ insert(DIKS_F6 , Qt::Key_F6);
+ insert(DIKS_F7 , Qt::Key_F7);
+ insert(DIKS_F8 , Qt::Key_F8);
+ insert(DIKS_F9 , Qt::Key_F9);
+ insert(DIKS_F10 , Qt::Key_F10);
+ insert(DIKS_F11 , Qt::Key_F11);
+ insert(DIKS_F12 , Qt::Key_F12);
+
+ insert(DIKS_SHIFT , Qt::Key_Shift);
+ insert(DIKS_CONTROL , Qt::Key_Control);
+ insert(DIKS_ALT , Qt::Key_Alt);
+ insert(DIKS_ALTGR , Qt::Key_AltGr);
+
+ insert(DIKS_META , Qt::Key_Meta);
+ insert(DIKS_SUPER , Qt::Key_Super_L); // ???
+ insert(DIKS_HYPER , Qt::Key_Hyper_L); // ???
+
+ insert(DIKS_CAPS_LOCK , Qt::Key_CapsLock);
+ insert(DIKS_NUM_LOCK , Qt::Key_NumLock);
+ insert(DIKS_SCROLL_LOCK , Qt::Key_ScrollLock);
+
+ insert(DIKS_DEAD_ABOVEDOT , Qt::Key_Dead_Abovedot);
+ insert(DIKS_DEAD_ABOVERING , Qt::Key_Dead_Abovering);
+ insert(DIKS_DEAD_ACUTE , Qt::Key_Dead_Acute);
+ insert(DIKS_DEAD_BREVE , Qt::Key_Dead_Breve);
+ insert(DIKS_DEAD_CARON , Qt::Key_Dead_Caron);
+ insert(DIKS_DEAD_CEDILLA , Qt::Key_Dead_Cedilla);
+ insert(DIKS_DEAD_CIRCUMFLEX , Qt::Key_Dead_Circumflex);
+ insert(DIKS_DEAD_DIAERESIS , Qt::Key_Dead_Diaeresis);
+ insert(DIKS_DEAD_DOUBLEACUTE , Qt::Key_Dead_Doubleacute);
+ insert(DIKS_DEAD_GRAVE , Qt::Key_Dead_Grave);
+ insert(DIKS_DEAD_IOTA , Qt::Key_Dead_Iota);
+ insert(DIKS_DEAD_MACRON , Qt::Key_Dead_Macron);
+ insert(DIKS_DEAD_OGONEK , Qt::Key_Dead_Ogonek);
+ insert(DIKS_DEAD_SEMIVOICED_SOUND , Qt::Key_Dead_Semivoiced_Sound);
+ insert(DIKS_DEAD_TILDE , Qt::Key_Dead_Tilde);
+ insert(DIKS_DEAD_VOICED_SOUND , Qt::Key_Dead_Voiced_Sound);
+ insert(DIKS_SPACE , Qt::Key_Space);
+ insert(DIKS_EXCLAMATION_MARK , Qt::Key_Exclam);
+ insert(DIKS_QUOTATION , Qt::Key_QuoteDbl);
+ insert(DIKS_NUMBER_SIGN , Qt::Key_NumberSign);
+ insert(DIKS_DOLLAR_SIGN , Qt::Key_Dollar);
+ insert(DIKS_PERCENT_SIGN , Qt::Key_Percent);
+ insert(DIKS_AMPERSAND , Qt::Key_Ampersand);
+ insert(DIKS_APOSTROPHE , Qt::Key_Apostrophe);
+ insert(DIKS_PARENTHESIS_LEFT , Qt::Key_ParenLeft);
+ insert(DIKS_PARENTHESIS_RIGHT , Qt::Key_ParenRight);
+ insert(DIKS_ASTERISK , Qt::Key_Asterisk);
+ insert(DIKS_PLUS_SIGN , Qt::Key_Plus);
+ insert(DIKS_COMMA , Qt::Key_Comma);
+ insert(DIKS_MINUS_SIGN , Qt::Key_Minus);
+ insert(DIKS_PERIOD , Qt::Key_Period);
+ insert(DIKS_SLASH , Qt::Key_Slash);
+ insert(DIKS_0 , Qt::Key_0);
+ insert(DIKS_1 , Qt::Key_1);
+ insert(DIKS_2 , Qt::Key_2);
+ insert(DIKS_3 , Qt::Key_3);
+ insert(DIKS_4 , Qt::Key_4);
+ insert(DIKS_5 , Qt::Key_5);
+ insert(DIKS_6 , Qt::Key_6);
+ insert(DIKS_7 , Qt::Key_7);
+ insert(DIKS_8 , Qt::Key_8);
+ insert(DIKS_9 , Qt::Key_9);
+ insert(DIKS_COLON , Qt::Key_Colon);
+ insert(DIKS_SEMICOLON , Qt::Key_Semicolon);
+ insert(DIKS_LESS_THAN_SIGN , Qt::Key_Less);
+ insert(DIKS_EQUALS_SIGN , Qt::Key_Equal);
+ insert(DIKS_GREATER_THAN_SIGN , Qt::Key_Greater);
+ insert(DIKS_QUESTION_MARK , Qt::Key_Question);
+ insert(DIKS_AT , Qt::Key_At);
+ insert(DIKS_CAPITAL_A , Qt::Key_A);
+ insert(DIKS_CAPITAL_B , Qt::Key_B);
+ insert(DIKS_CAPITAL_C , Qt::Key_C);
+ insert(DIKS_CAPITAL_D , Qt::Key_D);
+ insert(DIKS_CAPITAL_E , Qt::Key_E);
+ insert(DIKS_CAPITAL_F , Qt::Key_F);
+ insert(DIKS_CAPITAL_G , Qt::Key_G);
+ insert(DIKS_CAPITAL_H , Qt::Key_H);
+ insert(DIKS_CAPITAL_I , Qt::Key_I);
+ insert(DIKS_CAPITAL_J , Qt::Key_J);
+ insert(DIKS_CAPITAL_K , Qt::Key_K);
+ insert(DIKS_CAPITAL_L , Qt::Key_L);
+ insert(DIKS_CAPITAL_M , Qt::Key_M);
+ insert(DIKS_CAPITAL_N , Qt::Key_N);
+ insert(DIKS_CAPITAL_O , Qt::Key_O);
+ insert(DIKS_CAPITAL_P , Qt::Key_P);
+ insert(DIKS_CAPITAL_Q , Qt::Key_Q);
+ insert(DIKS_CAPITAL_R , Qt::Key_R);
+ insert(DIKS_CAPITAL_S , Qt::Key_S);
+ insert(DIKS_CAPITAL_T , Qt::Key_T);
+ insert(DIKS_CAPITAL_U , Qt::Key_U);
+ insert(DIKS_CAPITAL_V , Qt::Key_V);
+ insert(DIKS_CAPITAL_W , Qt::Key_W);
+ insert(DIKS_CAPITAL_X , Qt::Key_X);
+ insert(DIKS_CAPITAL_Y , Qt::Key_Y);
+ insert(DIKS_CAPITAL_Z , Qt::Key_Z);
+ insert(DIKS_SQUARE_BRACKET_LEFT , Qt::Key_BracketLeft);
+ insert(DIKS_BACKSLASH , Qt::Key_Backslash);
+ insert(DIKS_SQUARE_BRACKET_RIGHT , Qt::Key_BracketRight);
+ insert(DIKS_CIRCUMFLEX_ACCENT , Qt::Key_AsciiCircum);
+ insert(DIKS_UNDERSCORE , Qt::Key_Underscore);
+ insert(DIKS_SMALL_A , Qt::Key_A);
+ insert(DIKS_SMALL_B , Qt::Key_B);
+ insert(DIKS_SMALL_C , Qt::Key_C);
+ insert(DIKS_SMALL_D , Qt::Key_D);
+ insert(DIKS_SMALL_E , Qt::Key_E);
+ insert(DIKS_SMALL_F , Qt::Key_F);
+ insert(DIKS_SMALL_G , Qt::Key_G);
+ insert(DIKS_SMALL_H , Qt::Key_H);
+ insert(DIKS_SMALL_I , Qt::Key_I);
+ insert(DIKS_SMALL_J , Qt::Key_J);
+ insert(DIKS_SMALL_K , Qt::Key_K);
+ insert(DIKS_SMALL_L , Qt::Key_L);
+ insert(DIKS_SMALL_M , Qt::Key_M);
+ insert(DIKS_SMALL_N , Qt::Key_N);
+ insert(DIKS_SMALL_O , Qt::Key_O);
+ insert(DIKS_SMALL_P , Qt::Key_P);
+ insert(DIKS_SMALL_Q , Qt::Key_Q);
+ insert(DIKS_SMALL_R , Qt::Key_R);
+ insert(DIKS_SMALL_S , Qt::Key_S);
+ insert(DIKS_SMALL_T , Qt::Key_T);
+ insert(DIKS_SMALL_U , Qt::Key_U);
+ insert(DIKS_SMALL_V , Qt::Key_V);
+ insert(DIKS_SMALL_W , Qt::Key_W);
+ insert(DIKS_SMALL_X , Qt::Key_X);
+ insert(DIKS_SMALL_Y , Qt::Key_Y);
+ insert(DIKS_SMALL_Z , Qt::Key_Z);
+ insert(DIKS_CURLY_BRACKET_LEFT , Qt::Key_BraceLeft);
+ insert(DIKS_VERTICAL_BAR , Qt::Key_Bar);
+ insert(DIKS_CURLY_BRACKET_RIGHT , Qt::Key_BraceRight);
+ insert(DIKS_TILDE , Qt::Key_AsciiTilde);
+}
+
+QT_END_NAMESPACE
+#include "qdirectfbkeyboard.moc"
+#endif // QT_NO_QWS_DIRECTFB
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.h b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.h
new file mode 100644
index 0000000000..49c1c18b22
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDIRECTFBKEYBOARD_H
+#define QDIRECTFBKEYBOARD_H
+
+#include <qglobal.h>
+#include <QtGui/qkbd_qws.h>
+
+#ifndef QT_NO_QWS_DIRECTFB
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QDirectFBKeyboardHandlerPrivate;
+
+class QDirectFBKeyboardHandler : public QWSKeyboardHandler
+{
+public:
+ QDirectFBKeyboardHandler(const QString &device);
+ ~QDirectFBKeyboardHandler();
+
+private:
+ QDirectFBKeyboardHandlerPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QWS_DIRECTFB
+
+QT_END_HEADER
+
+#endif // QDIRECTFBKEYBOARD_H
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp
new file mode 100644
index 0000000000..3999b85afb
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.cpp
@@ -0,0 +1,294 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdirectfbmouse.h"
+
+#ifndef QT_NO_QWS_DIRECTFB
+
+#include "qdirectfbscreen.h"
+#include <qsocketnotifier.h>
+
+#include <directfb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDirectFBMouseHandlerPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QDirectFBMouseHandlerPrivate(QDirectFBMouseHandler *h);
+ ~QDirectFBMouseHandlerPrivate();
+
+ void setEnabled(bool on);
+private:
+ QDirectFBMouseHandler *handler;
+ IDirectFBEventBuffer *eventBuffer;
+#ifndef QT_NO_DIRECTFB_LAYER
+ IDirectFBDisplayLayer *layer;
+#endif
+ QSocketNotifier *mouseNotifier;
+
+ QPoint prevPoint;
+ Qt::MouseButtons prevbuttons;
+
+ DFBEvent event;
+ uint bytesRead;
+
+private Q_SLOTS:
+ void readMouseData();
+};
+
+QDirectFBMouseHandlerPrivate::QDirectFBMouseHandlerPrivate(QDirectFBMouseHandler *h)
+ : handler(h), eventBuffer(0)
+{
+ DFBResult result;
+
+ QScreen *screen = QScreen::instance();
+ if (!screen) {
+ qCritical("QDirectFBMouseHandler: no screen instance found");
+ return;
+ }
+
+ IDirectFB *fb = QDirectFBScreen::instance()->dfb();
+ if (!fb) {
+ qCritical("QDirectFBMouseHandler: DirectFB not initialized");
+ return;
+ }
+
+#ifndef QT_NO_DIRECTFB_LAYER
+ layer = QDirectFBScreen::instance()->dfbDisplayLayer();
+ if (!layer) {
+ qCritical("QDirectFBMouseHandler: Unable to get primary display layer");
+ return;
+ }
+#endif
+
+ DFBInputDeviceCapabilities caps;
+ caps = DICAPS_BUTTONS | DICAPS_AXES;
+ result = fb->CreateInputEventBuffer(fb, caps, DFB_TRUE, &eventBuffer);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBMouseHandler: "
+ "Unable to create input event buffer", result);
+ return;
+ }
+
+ int fd;
+ result = eventBuffer->CreateFileDescriptor(eventBuffer, &fd);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBMouseHandler: "
+ "Unable to create file descriptor", result);
+ return;
+ }
+
+ int flags = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ // DirectFB seems to assume that the mouse always starts centered
+ prevPoint = QPoint(screen->deviceWidth() / 2, screen->deviceHeight() / 2);
+ prevbuttons = Qt::NoButton;
+ memset(&event, 0, sizeof(event));
+ bytesRead = 0;
+
+ mouseNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
+ connect(mouseNotifier, SIGNAL(activated(int)),this, SLOT(readMouseData()));
+ setEnabled(true);
+}
+
+QDirectFBMouseHandlerPrivate::~QDirectFBMouseHandlerPrivate()
+{
+ if (eventBuffer)
+ eventBuffer->Release(eventBuffer);
+}
+
+void QDirectFBMouseHandlerPrivate::setEnabled(bool on)
+{
+ if (mouseNotifier->isEnabled() != on) {
+#ifndef QT_NO_DIRECTFB_LAYER
+ DFBResult result;
+ result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::QDirectFBScreenCursor: "
+ "Unable to set cooperative level", result);
+ }
+ result = layer->EnableCursor(layer, on ? 1 : 0);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::QDirectFBScreenCursor: "
+ "Unable to enable cursor", result);
+ }
+
+ result = layer->SetCooperativeLevel(layer, DLSCL_SHARED);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::show: "
+ "Unable to set cooperative level", result);
+ }
+
+ layer->SetCooperativeLevel(layer, DLSCL_SHARED);
+#endif
+ mouseNotifier->setEnabled(on);
+ }
+}
+
+void QDirectFBMouseHandlerPrivate::readMouseData()
+{
+ if (!QScreen::instance())
+ return;
+
+ for (;;) {
+ // GetEvent returns DFB_UNSUPPORTED after CreateFileDescriptor().
+ // This seems stupid and I really hope it's a bug which will be fixed.
+
+ // DFBResult ret = eventBuffer->GetEvent(eventBuffer, &event);
+
+ char *buf = reinterpret_cast<char*>(&event);
+ int ret = ::read(mouseNotifier->socket(),
+ buf + bytesRead, sizeof(DFBEvent) - bytesRead);
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EAGAIN)
+ return;
+ qWarning("QDirectFBMouseHandlerPrivate::readMouseData(): %s",
+ strerror(errno));
+ return;
+ }
+
+ Q_ASSERT(ret >= 0);
+ bytesRead += ret;
+ if (bytesRead < sizeof(DFBEvent))
+ break;
+ bytesRead = 0;
+
+ Q_ASSERT(event.clazz == DFEC_INPUT);
+
+ const DFBInputEvent input = event.input;
+ int x = prevPoint.x();
+ int y = prevPoint.y();
+ int wheel = 0;
+
+ if (input.type == DIET_AXISMOTION) {
+#if defined(QT_NO_DIRECTFB_LAYER) || defined(QT_DIRECTFB_WINDOW_AS_CURSOR)
+ if (input.flags & DIEF_AXISABS) {
+ switch (input.axis) {
+ case DIAI_X: x = input.axisabs; break;
+ case DIAI_Y: y = input.axisabs; break;
+ default:
+ qWarning("QDirectFBMouseHandlerPrivate::readMouseData: "
+ "unknown axis (absolute) %d", input.axis);
+ break;
+ }
+ } else if (input.flags & DIEF_AXISREL) {
+ switch (input.axis) {
+ case DIAI_X: x += input.axisrel; break;
+ case DIAI_Y: y += input.axisrel; break;
+ case DIAI_Z: wheel = -120 * input.axisrel; break;
+ default:
+ qWarning("QDirectFBMouseHandlerPrivate::readMouseData: "
+ "unknown axis (releative) %d", input.axis);
+ }
+ }
+#else
+ if (input.axis == DIAI_X || input.axis == DIAI_Y) {
+ DFBResult result = layer->GetCursorPosition(layer, &x, &y);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBMouseHandler::readMouseData",
+ result);
+ }
+ } else if (input.axis == DIAI_Z) {
+ Q_ASSERT(input.flags & DIEF_AXISREL);
+ wheel = input.axisrel;
+ wheel *= -120;
+ }
+#endif
+ }
+
+ Qt::MouseButtons buttons = Qt::NoButton;
+ if (input.flags & DIEF_BUTTONS) {
+ if (input.buttons & DIBM_LEFT)
+ buttons |= Qt::LeftButton;
+ if (input.buttons & DIBM_MIDDLE)
+ buttons |= Qt::MidButton;
+ if (input.buttons & DIBM_RIGHT)
+ buttons |= Qt::RightButton;
+ }
+
+ QPoint p = QPoint(x, y);
+ handler->limitToScreen(p);
+
+ if (p == prevPoint && wheel == 0 && buttons == prevbuttons)
+ continue;
+
+ prevPoint = p;
+ prevbuttons = buttons;
+
+ handler->mouseChanged(p, buttons, wheel);
+ }
+}
+
+QDirectFBMouseHandler::QDirectFBMouseHandler(const QString &driver,
+ const QString &device)
+ : QWSMouseHandler(driver, device)
+{
+ d = new QDirectFBMouseHandlerPrivate(this);
+}
+
+QDirectFBMouseHandler::~QDirectFBMouseHandler()
+{
+ delete d;
+}
+
+void QDirectFBMouseHandler::suspend()
+{
+ d->setEnabled(false);
+}
+
+void QDirectFBMouseHandler::resume()
+{
+ d->setEnabled(true);
+}
+
+QT_END_NAMESPACE
+#include "qdirectfbmouse.moc"
+#endif // QT_NO_QWS_DIRECTFB
+
+
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbmouse.h b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.h
new file mode 100644
index 0000000000..ac0fcadfaa
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbmouse.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDIRECTFBMOUSE_H
+#define QDIRECTFBMOUSE_H
+
+#include <qglobal.h>
+#include <QtGui/qmouse_qws.h>
+
+#ifndef QT_NO_QWS_DIRECTFB
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QDirectFBMouseHandlerPrivate;
+
+class QDirectFBMouseHandler : public QWSMouseHandler
+{
+public:
+ explicit QDirectFBMouseHandler(const QString &driver = QString(),
+ const QString &device = QString());
+ ~QDirectFBMouseHandler();
+
+ void suspend();
+ void resume();
+protected:
+ QDirectFBMouseHandlerPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif // QT_NO_QWS_DIRECTFB
+#endif // QDIRECTFBMOUSE_H
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp
new file mode 100644
index 0000000000..10f1bb3f46
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdirectfbscreen.h"
+#include "qdirectfbpaintdevice.h"
+#include "qdirectfbpaintengine.h"
+
+#ifndef QT_NO_QWS_DIRECTFB
+
+QT_BEGIN_NAMESPACE
+
+QDirectFBPaintDevice::QDirectFBPaintDevice(QDirectFBScreen *scr)
+ : QCustomRasterPaintDevice(0), dfbSurface(0), screen(scr),
+ bpl(-1), lockFlgs(DFBSurfaceLockFlags(0)), mem(0), engine(0), imageFormat(QImage::Format_Invalid)
+{
+#ifdef QT_DIRECTFB_SUBSURFACE
+ subSurface = 0;
+ syncPending = false;
+#endif
+}
+
+QDirectFBPaintDevice::~QDirectFBPaintDevice()
+{
+ if (QDirectFBScreen::instance()) {
+ unlockSurface();
+#ifdef QT_DIRECTFB_SUBSURFACE
+ releaseSubSurface();
+#endif
+ if (dfbSurface) {
+ screen->releaseDFBSurface(dfbSurface);
+ }
+ }
+ delete engine;
+}
+
+IDirectFBSurface *QDirectFBPaintDevice::directFBSurface() const
+{
+ return dfbSurface;
+}
+
+bool QDirectFBPaintDevice::lockSurface(DFBSurfaceLockFlags lockFlags)
+{
+ if (lockFlgs && (lockFlags & ~lockFlgs))
+ unlockSurface();
+ if (!mem) {
+ Q_ASSERT(dfbSurface);
+#ifdef QT_DIRECTFB_SUBSURFACE
+ if (!subSurface) {
+ DFBResult result;
+ subSurface = screen->getSubSurface(dfbSurface, QRect(), QDirectFBScreen::TrackSurface, &result);
+ if (result != DFB_OK || !subSurface) {
+ DirectFBError("Couldn't create sub surface", result);
+ return false;
+ }
+ }
+ IDirectFBSurface *surface = subSurface;
+#else
+ IDirectFBSurface *surface = dfbSurface;
+#endif
+ Q_ASSERT(surface);
+ mem = QDirectFBScreen::lockSurface(surface, lockFlags, &bpl);
+ lockFlgs = lockFlags;
+ Q_ASSERT(mem);
+ Q_ASSERT(bpl > 0);
+ const QSize s = size();
+ lockedImage = QImage(mem, s.width(), s.height(), bpl,
+ QDirectFBScreen::getImageFormat(dfbSurface));
+ return true;
+ }
+#ifdef QT_DIRECTFB_SUBSURFACE
+ if (syncPending) {
+ syncPending = false;
+ screen->waitIdle();
+ }
+#endif
+ return false;
+}
+
+void QDirectFBPaintDevice::unlockSurface()
+{
+ if (QDirectFBScreen::instance() && lockFlgs) {
+#ifdef QT_DIRECTFB_SUBSURFACE
+ IDirectFBSurface *surface = subSurface;
+#else
+ IDirectFBSurface *surface = dfbSurface;
+#endif
+ if (surface) {
+ surface->Unlock(surface);
+ lockFlgs = static_cast<DFBSurfaceLockFlags>(0);
+ mem = 0;
+ }
+ }
+}
+
+void *QDirectFBPaintDevice::memory() const
+{
+ return mem;
+}
+
+QImage::Format QDirectFBPaintDevice::format() const
+{
+ return imageFormat;
+}
+
+int QDirectFBPaintDevice::bytesPerLine() const
+{
+ Q_ASSERT(!mem || bpl != -1);
+ return bpl;
+}
+
+QSize QDirectFBPaintDevice::size() const
+{
+ int w, h;
+ dfbSurface->GetSize(dfbSurface, &w, &h);
+ return QSize(w, h);
+}
+
+int QDirectFBPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const
+{
+ if (!dfbSurface)
+ return 0;
+
+ switch (metric) {
+ case QPaintDevice::PdmWidth:
+ case QPaintDevice::PdmHeight:
+ return (metric == PdmWidth ? size().width() : size().height());
+ case QPaintDevice::PdmWidthMM:
+ return (size().width() * 1000) / dotsPerMeterX();
+ case QPaintDevice::PdmHeightMM:
+ return (size().height() * 1000) / dotsPerMeterY();
+ case QPaintDevice::PdmPhysicalDpiX:
+ case QPaintDevice::PdmDpiX:
+ return (dotsPerMeterX() * 254) / 10000; // 0.0254 meters-per-inch
+ case QPaintDevice::PdmPhysicalDpiY:
+ case QPaintDevice::PdmDpiY:
+ return (dotsPerMeterY() * 254) / 10000; // 0.0254 meters-per-inch
+ case QPaintDevice::PdmDepth:
+ return QDirectFBScreen::depth(imageFormat);
+ case QPaintDevice::PdmNumColors: {
+ if (!lockedImage.isNull())
+ return lockedImage.colorCount();
+
+ DFBResult result;
+ IDirectFBPalette *palette = 0;
+ unsigned int numColors = 0;
+
+ result = dfbSurface->GetPalette(dfbSurface, &palette);
+ if ((result != DFB_OK) || !palette)
+ return 0;
+
+ result = palette->GetSize(palette, &numColors);
+ palette->Release(palette);
+ if (result != DFB_OK)
+ return 0;
+
+ return numColors;
+ }
+ default:
+ qCritical("QDirectFBPaintDevice::metric(): Unhandled metric!");
+ return 0;
+ }
+}
+
+QPaintEngine *QDirectFBPaintDevice::paintEngine() const
+{
+ return engine;
+}
+
+#ifdef QT_DIRECTFB_SUBSURFACE
+void QDirectFBPaintDevice::releaseSubSurface()
+{
+ Q_ASSERT(QDirectFBScreen::instance());
+ if (subSurface) {
+ unlockSurface();
+ screen->releaseDFBSurface(subSurface);
+ subSurface = 0;
+ }
+}
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QWS_DIRECTFB
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h
new file mode 100644
index 0000000000..71a7a8e104
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDIRECTFBPAINTDEVICE_H
+#define QDIRECTFBPAINTDEVICE_H
+
+#include <private/qpaintengine_raster_p.h>
+#include "qdirectfbscreen.h"
+
+#ifndef QT_NO_QWS_DIRECTFB
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+// Inherited by both window surface and pixmap
+class QDirectFBPaintEngine;
+class QDirectFBPaintDevice : public QCustomRasterPaintDevice
+{
+public:
+ ~QDirectFBPaintDevice();
+
+ virtual IDirectFBSurface *directFBSurface() const;
+
+ bool lockSurface(DFBSurfaceLockFlags lockFlags);
+ void unlockSurface();
+
+ // Reimplemented from QCustomRasterPaintDevice:
+ void *memory() const;
+ QImage::Format format() const;
+ int bytesPerLine() const;
+ QSize size() const;
+ int metric(QPaintDevice::PaintDeviceMetric metric) const;
+ DFBSurfaceLockFlags lockFlags() const { return lockFlgs; }
+ QPaintEngine *paintEngine() const;
+protected:
+ QDirectFBPaintDevice(QDirectFBScreen *scr);
+ inline int dotsPerMeterX() const
+ {
+ return (screen->deviceWidth() * 1000) / screen->physicalWidth();
+ }
+ inline int dotsPerMeterY() const
+ {
+ return (screen->deviceHeight() * 1000) / screen->physicalHeight();
+ }
+
+ IDirectFBSurface *dfbSurface;
+#ifdef QT_DIRECTFB_SUBSURFACE
+ void releaseSubSurface();
+ IDirectFBSurface *subSurface;
+ friend class QDirectFBPaintEnginePrivate;
+ bool syncPending;
+#endif
+ QImage lockedImage;
+ QDirectFBScreen *screen;
+ int bpl;
+ DFBSurfaceLockFlags lockFlgs;
+ uchar *mem;
+ QDirectFBPaintEngine *engine;
+ QImage::Format imageFormat;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_QWS_DIRECTFB
+#endif //QDIRECTFBPAINTDEVICE_H
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
new file mode 100644
index 0000000000..6d6fb02a68
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
@@ -0,0 +1,1430 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdirectfbpaintengine.h"
+
+#ifndef QT_NO_QWS_DIRECTFB
+
+#include "qdirectfbwindowsurface.h"
+#include "qdirectfbscreen.h"
+#include "qdirectfbpixmap.h"
+#include <directfb.h>
+#include <qtransform.h>
+#include <qvarlengtharray.h>
+#include <qcache.h>
+#include <qmath.h>
+#include <private/qpixmapdata_p.h>
+#include <private/qpixmap_raster_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class SurfaceCache;
+class QDirectFBPaintEnginePrivate : public QRasterPaintEnginePrivate
+{
+public:
+ enum TransformationTypeFlags {
+ Matrix_NegativeScale = 0x100,
+ Matrix_RectsUnsupported = (QTransform::TxRotate|QTransform::TxShear|QTransform::TxProject),
+ Matrix_BlitsUnsupported = (Matrix_NegativeScale|Matrix_RectsUnsupported)
+ };
+
+ inline static uint getTransformationType(const QTransform &transform)
+ {
+ int ret = transform.type();
+ if (qMin(transform.m11(), transform.m22()) < 0) {
+ ret |= QDirectFBPaintEnginePrivate::Matrix_NegativeScale;
+ }
+ return ret;
+ }
+
+ enum CompositionModeStatus {
+ PorterDuff_None = 0x0,
+ PorterDuff_Supported = 0x1,
+ PorterDuff_PremultiplyColors = 0x2,
+ PorterDuff_AlwaysBlend = 0x4
+ };
+
+ enum ClipType {
+ ClipUnset,
+ NoClip,
+ RectClip,
+ RegionClip,
+ ComplexClip
+ };
+
+ QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p);
+ ~QDirectFBPaintEnginePrivate();
+
+ inline void setTransform(const QTransform &transforma);
+ inline void setPen(const QPen &pen);
+ inline void setCompositionMode(QPainter::CompositionMode mode);
+ inline void setRenderHints(QPainter::RenderHints hints);
+
+ inline void setDFBColor(const QColor &color);
+
+ inline void lock();
+ inline void unlock();
+ static inline void unlock(QDirectFBPaintDevice *device);
+
+ inline bool isSimpleBrush(const QBrush &brush) const;
+
+ void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &pos, const QTransform &pixmapTransform);
+ void blit(const QRectF &dest, IDirectFBSurface *surface, const QRectF &src);
+
+ inline bool supportsStretchBlit() const;
+
+ inline void updateClip();
+ virtual void systemStateChanged();
+
+ static IDirectFBSurface *getSurface(const QImage &img, bool *release);
+
+#ifdef QT_DIRECTFB_IMAGECACHE
+ static inline int cacheCost(const QImage &img) { return img.width() * img.height() * img.depth() / 8; }
+#endif
+
+ enum BlitFlag {
+ HasAlpha = 0x1,
+ Premultiplied = 0x2
+ };
+ void prepareForBlit(uint blitFlags);
+
+ IDirectFBSurface *surface;
+
+ bool antialiased;
+ bool simplePen;
+
+ uint transformationType; // this is QTransform::type() + Matrix_NegativeScale if qMin(transform.m11(), transform.m22()) < 0
+
+ SurfaceCache *surfaceCache;
+ IDirectFB *fb;
+ quint8 opacity;
+
+ ClipType clipType;
+ QDirectFBPaintDevice *dfbDevice;
+ uint compositionModeStatus;
+ bool isPremultiplied;
+
+ bool inClip;
+ QRect currentClip;
+
+ QDirectFBPaintEngine *q;
+};
+
+class SurfaceCache
+{
+public:
+ SurfaceCache() : surface(0), buffer(0), bufsize(0) {}
+ ~SurfaceCache() { clear(); }
+ IDirectFBSurface *getSurface(const uint *buf, int size);
+ void clear();
+private:
+ IDirectFBSurface *surface;
+ uint *buffer;
+ int bufsize;
+};
+
+
+#ifdef QT_DIRECTFB_IMAGECACHE
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <private/qimage_p.h>
+QT_END_INCLUDE_NAMESPACE
+struct CachedImage
+{
+ IDirectFBSurface *surface;
+ ~CachedImage()
+ {
+ if (surface && QDirectFBScreen::instance()) {
+ QDirectFBScreen::instance()->releaseDFBSurface(surface);
+ }
+ }
+};
+static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB
+#endif
+
+#define VOID_ARG() static_cast<bool>(false)
+enum PaintOperation {
+ DRAW_RECTS = 0x0001, DRAW_LINES = 0x0002, DRAW_IMAGE = 0x0004,
+ DRAW_PIXMAP = 0x0008, DRAW_TILED_PIXMAP = 0x0010, STROKE_PATH = 0x0020,
+ DRAW_PATH = 0x0040, DRAW_POINTS = 0x0080, DRAW_ELLIPSE = 0x0100,
+ DRAW_POLYGON = 0x0200, DRAW_TEXT = 0x0400, FILL_PATH = 0x0800,
+ FILL_RECT = 0x1000, DRAW_COLORSPANS = 0x2000, DRAW_ROUNDED_RECT = 0x4000,
+ DRAW_STATICTEXT = 0x8000, ALL = 0xffff
+};
+
+enum { RasterWarn = 1, RasterDisable = 2 };
+static inline uint rasterFallbacksMask(PaintOperation op)
+{
+ uint ret = 0;
+#ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS
+ if (op & QT_DIRECTFB_WARN_ON_RASTERFALLBACKS)
+ ret |= RasterWarn;
+#endif
+#ifdef QT_DIRECTFB_DISABLE_RASTERFALLBACKS
+ if (op & QT_DIRECTFB_DISABLE_RASTERFALLBACKS)
+ ret |= RasterDisable;
+#endif
+ static int warningMask = -1;
+ static int disableMask = -1;
+ if (warningMask < 0) {
+ struct {
+ const char *name;
+ PaintOperation operation;
+ } const operations[] = {
+ { "DRAW_RECTS", DRAW_RECTS },
+ { "DRAW_LINES", DRAW_LINES },
+ { "DRAW_IMAGE", DRAW_IMAGE },
+ { "DRAW_PIXMAP", DRAW_PIXMAP },
+ { "DRAW_TILED_PIXMAP", DRAW_TILED_PIXMAP },
+ { "STROKE_PATH", STROKE_PATH },
+ { "DRAW_PATH", DRAW_PATH },
+ { "DRAW_POINTS", DRAW_POINTS },
+ { "DRAW_ELLIPSE", DRAW_ELLIPSE },
+ { "DRAW_POLYGON", DRAW_POLYGON },
+ { "DRAW_TEXT", DRAW_TEXT },
+ { "FILL_PATH", FILL_PATH },
+ { "FILL_RECT", FILL_RECT },
+ { "DRAW_COLORSPANS", DRAW_COLORSPANS },
+ { "DRAW_ROUNDED_RECT", DRAW_ROUNDED_RECT },
+ { "ALL", ALL },
+ { 0, ALL }
+ };
+
+ QStringList warning = QString::fromLatin1(qgetenv("QT_DIRECTFB_WARN_ON_RASTERFALLBACKS")).toUpper().split(QLatin1Char('|'),
+ QString::SkipEmptyParts);
+ QStringList disable = QString::fromLatin1(qgetenv("QT_DIRECTFB_DISABLE_RASTERFALLBACKS")).toUpper().split(QLatin1Char('|'),
+ QString::SkipEmptyParts);
+ warningMask = 0;
+ disableMask = 0;
+ if (!warning.isEmpty() || !disable.isEmpty()) {
+ for (int i=0; operations[i].name; ++i) {
+ const QString name = QString::fromLatin1(operations[i].name);
+ int idx = warning.indexOf(name);
+ if (idx != -1) {
+ warningMask |= operations[i].operation;
+ warning.erase(warning.begin() + idx);
+ }
+ idx = disable.indexOf(name);
+ if (idx != -1) {
+ disableMask |= operations[i].operation;
+ disable.erase(disable.begin() + idx);
+ }
+ }
+ }
+ if (!warning.isEmpty()) {
+ qWarning("QDirectFBPaintEngine QT_DIRECTFB_WARN_ON_RASTERFALLBACKS Unknown operation(s): %s",
+ qPrintable(warning.join(QLatin1String("|"))));
+ }
+ if (!disable.isEmpty()) {
+ qWarning("QDirectFBPaintEngine QT_DIRECTFB_DISABLE_RASTERFALLBACKS Unknown operation(s): %s",
+ qPrintable(disable.join(QLatin1String("|"))));
+ }
+ }
+ if (op & warningMask)
+ ret |= RasterWarn;
+ if (op & disableMask)
+ ret |= RasterDisable;
+ return ret;
+}
+
+template <typename device, typename T1, typename T2, typename T3>
+static void rasterFallbackWarn(const char *msg, const char *func, const device *dev,
+ uint transformationType, bool simplePen,
+ uint clipType, uint compositionModeStatus,
+ const char *nameOne, const T1 &one,
+ const char *nameTwo, const T2 &two,
+ const char *nameThree, const T3 &three);
+
+#define RASTERFALLBACK(op, one, two, three) \
+ { \
+ static const uint rasterFallbacks = rasterFallbacksMask(op); \
+ switch (rasterFallbacks) { \
+ case 0: break; \
+ case RasterWarn: \
+ rasterFallbackWarn("Falling back to raster engine for", \
+ __FUNCTION__, \
+ state()->painter->device(), \
+ d_func()->transformationType, \
+ d_func()->simplePen, \
+ d_func()->clipType, \
+ d_func()->compositionModeStatus, \
+ #one, one, #two, two, #three, three); \
+ break; \
+ case RasterDisable|RasterWarn: \
+ rasterFallbackWarn("Disabled raster engine operation", \
+ __FUNCTION__, \
+ state()->painter->device(), \
+ d_func()->transformationType, \
+ d_func()->simplePen, \
+ d_func()->clipType, \
+ d_func()->compositionModeStatus, \
+ #one, one, #two, two, #three, three); \
+ case RasterDisable: \
+ return; \
+ } \
+ }
+
+template <class T>
+static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface);
+template <class T>
+static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface);
+template <class T>
+static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface);
+
+#define CLIPPED_PAINT(operation) { \
+ d->unlock(); \
+ DFBRegion clipRegion; \
+ switch (d->clipType) { \
+ case QDirectFBPaintEnginePrivate::NoClip: \
+ case QDirectFBPaintEnginePrivate::RectClip: \
+ operation; \
+ break; \
+ case QDirectFBPaintEnginePrivate::RegionClip: { \
+ Q_ASSERT(d->clip()); \
+ const QVector<QRect> cr = d->clip()->clipRegion.rects(); \
+ const int size = cr.size(); \
+ for (int i=0; i<size; ++i) { \
+ d->currentClip = cr.at(i); \
+ clipRegion.x1 = d->currentClip.x(); \
+ clipRegion.y1 = d->currentClip.y(); \
+ clipRegion.x2 = d->currentClip.right(); \
+ clipRegion.y2 = d->currentClip.bottom(); \
+ d->surface->SetClip(d->surface, &clipRegion); \
+ operation; \
+ } \
+ d->updateClip(); \
+ break; } \
+ case QDirectFBPaintEnginePrivate::ComplexClip: \
+ case QDirectFBPaintEnginePrivate::ClipUnset: \
+ qFatal("CLIPPED_PAINT internal error %d", d->clipType); \
+ break; \
+ } \
+ }
+
+
+QDirectFBPaintEngine::QDirectFBPaintEngine(QPaintDevice *device)
+ : QRasterPaintEngine(*(new QDirectFBPaintEnginePrivate(this)), device)
+{
+}
+
+QDirectFBPaintEngine::~QDirectFBPaintEngine()
+{
+}
+
+bool QDirectFBPaintEngine::begin(QPaintDevice *device)
+{
+ Q_D(QDirectFBPaintEngine);
+ if (device->devType() == QInternal::CustomRaster) {
+ d->dfbDevice = static_cast<QDirectFBPaintDevice*>(device);
+ } else if (device->devType() == QInternal::Pixmap) {
+ QPixmapData *data = static_cast<QPixmap*>(device)->pixmapData();
+ Q_ASSERT(data->classId() == QPixmapData::DirectFBClass);
+ QDirectFBPixmapData *dfbPixmapData = static_cast<QDirectFBPixmapData*>(data);
+ QDirectFBPaintEnginePrivate::unlock(dfbPixmapData);
+ d->dfbDevice = static_cast<QDirectFBPaintDevice*>(dfbPixmapData);
+ }
+
+ if (d->dfbDevice)
+ d->surface = d->dfbDevice->directFBSurface();
+
+ if (!d->surface) {
+ qFatal("QDirectFBPaintEngine used on an invalid device: 0x%x",
+ device->devType());
+ }
+ d->isPremultiplied = QDirectFBScreen::isPremultiplied(d->dfbDevice->format());
+
+ d->prepare(d->dfbDevice);
+ gccaps = AllFeatures;
+ d->setCompositionMode(state()->composition_mode);
+
+ return QRasterPaintEngine::begin(device);
+}
+
+bool QDirectFBPaintEngine::end()
+{
+ Q_D(QDirectFBPaintEngine);
+ d->unlock();
+ d->dfbDevice = 0;
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ d->surface->ReleaseSource(d->surface);
+#endif
+ d->currentClip = QRect();
+ d->surface->SetClip(d->surface, NULL);
+ d->surface = 0;
+ return QRasterPaintEngine::end();
+}
+
+void QDirectFBPaintEngine::clipEnabledChanged()
+{
+ Q_D(QDirectFBPaintEngine);
+ QRasterPaintEngine::clipEnabledChanged();
+ d->updateClip();
+}
+
+void QDirectFBPaintEngine::penChanged()
+{
+ Q_D(QDirectFBPaintEngine);
+ d->setPen(state()->pen);
+
+ QRasterPaintEngine::penChanged();
+}
+
+void QDirectFBPaintEngine::opacityChanged()
+{
+ Q_D(QDirectFBPaintEngine);
+ d->opacity = quint8(state()->opacity * 255);
+ QRasterPaintEngine::opacityChanged();
+}
+
+void QDirectFBPaintEngine::compositionModeChanged()
+{
+ Q_D(QDirectFBPaintEngine);
+ d->setCompositionMode(state()->compositionMode());
+ QRasterPaintEngine::compositionModeChanged();
+}
+
+void QDirectFBPaintEngine::renderHintsChanged()
+{
+ Q_D(QDirectFBPaintEngine);
+ d->setRenderHints(state()->renderHints);
+ QRasterPaintEngine::renderHintsChanged();
+}
+
+void QDirectFBPaintEngine::transformChanged()
+{
+ Q_D(QDirectFBPaintEngine);
+ d->setTransform(state()->matrix);
+ QRasterPaintEngine::transformChanged();
+}
+
+void QDirectFBPaintEngine::setState(QPainterState *state)
+{
+ Q_D(QDirectFBPaintEngine);
+ QRasterPaintEngine::setState(state);
+ d->setPen(state->pen);
+ d->opacity = quint8(state->opacity * 255);
+ d->setCompositionMode(state->compositionMode());
+ d->setTransform(state->transform());
+ d->setRenderHints(state->renderHints);
+ if (d->surface)
+ d->updateClip();
+}
+
+void QDirectFBPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
+{
+ Q_D(QDirectFBPaintEngine);
+ const bool wasInClip = d->inClip;
+ d->inClip = true;
+ QRasterPaintEngine::clip(path, op);
+ if (!wasInClip) {
+ d->inClip = false;
+ d->updateClip();
+ }
+}
+
+void QDirectFBPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
+{
+ Q_D(QDirectFBPaintEngine);
+ const bool wasInClip = d->inClip;
+ d->inClip = true;
+ QRasterPaintEngine::clip(region, op);
+ if (!wasInClip) {
+ d->inClip = false;
+ d->updateClip();
+ }
+}
+
+void QDirectFBPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
+{
+ Q_D(QDirectFBPaintEngine);
+ const bool wasInClip = d->inClip;
+ d->inClip = true;
+ QRasterPaintEngine::clip(rect, op);
+ if (!wasInClip) {
+ d->inClip = false;
+ d->updateClip();
+ }
+}
+
+void QDirectFBPaintEngine::drawRects(const QRect *rects, int rectCount)
+{
+ Q_D(QDirectFBPaintEngine);
+ const QPen &pen = state()->pen;
+ const QBrush &brush = state()->brush;
+ if (brush.style() == Qt::NoBrush && pen.style() == Qt::NoPen)
+ return;
+
+ if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)
+ || !d->simplePen
+ || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
+ || !d->isSimpleBrush(brush)
+ || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) {
+ RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG());
+ d->lock();
+ QRasterPaintEngine::drawRects(rects, rectCount);
+ return;
+ }
+
+ if (brush.style() != Qt::NoBrush) {
+ d->setDFBColor(brush.color());
+ CLIPPED_PAINT(QT_PREPEND_NAMESPACE(fillRects<QRect>)(rects, rectCount, state()->matrix, d->surface));
+ }
+
+ if (pen.style() != Qt::NoPen) {
+ d->setDFBColor(pen.color());
+ CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawRects<QRect>)(rects, rectCount, state()->matrix, d->surface));
+ }
+}
+
+void QDirectFBPaintEngine::drawRects(const QRectF *rects, int rectCount)
+{
+ Q_D(QDirectFBPaintEngine);
+ const QPen &pen = state()->pen;
+ const QBrush &brush = state()->brush;
+ if (brush.style() == Qt::NoBrush && pen.style() == Qt::NoPen)
+ return;
+
+ if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)
+ || !d->simplePen
+ || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
+ || !d->isSimpleBrush(brush)
+ || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) {
+ RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG());
+ d->lock();
+ QRasterPaintEngine::drawRects(rects, rectCount);
+ return;
+ }
+
+ if (brush.style() != Qt::NoBrush) {
+ d->setDFBColor(brush.color());
+ CLIPPED_PAINT(fillRects<QRectF>(rects, rectCount, state()->matrix, d->surface));
+ }
+
+ if (pen.style() != Qt::NoPen) {
+ d->setDFBColor(pen.color());
+ CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawRects<QRectF>)(rects, rectCount, state()->matrix, d->surface));
+ }
+}
+
+void QDirectFBPaintEngine::drawLines(const QLine *lines, int lineCount)
+{
+ Q_D(QDirectFBPaintEngine);
+
+ const QPen &pen = state()->pen;
+ if (!d->simplePen
+ || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
+ || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) {
+ RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG());
+ d->lock();
+ QRasterPaintEngine::drawLines(lines, lineCount);
+ return;
+ }
+
+ if (pen.style() != Qt::NoPen) {
+ d->setDFBColor(pen.color());
+ CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawLines<QLine>)(lines, lineCount, state()->matrix, d->surface));
+ }
+}
+
+void QDirectFBPaintEngine::drawLines(const QLineF *lines, int lineCount)
+{
+ Q_D(QDirectFBPaintEngine);
+
+ const QPen &pen = state()->pen;
+ if (!d->simplePen
+ || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
+ || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) {
+ RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG());
+ d->lock();
+ QRasterPaintEngine::drawLines(lines, lineCount);
+ return;
+ }
+
+ if (pen.style() != Qt::NoPen) {
+ d->setDFBColor(pen.color());
+ CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawLines<QLineF>)(lines, lineCount, state()->matrix, d->surface));
+ }
+}
+
+void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image,
+ const QRectF &sr,
+ Qt::ImageConversionFlags flags)
+{
+ Q_D(QDirectFBPaintEngine);
+ Q_UNUSED(flags);
+
+ /* This is hard to read. The way it works is like this:
+
+ - If you do not have support for preallocated surfaces and do not use an
+ image cache we always fall back to raster engine.
+
+ - If it's rotated/sheared/mirrored (negative scale) or we can't
+ clip it we fall back to raster engine.
+
+ - If we don't cache the image, but we do have support for
+ preallocated surfaces we fall back to the raster engine if the
+ image is in a format DirectFB can't handle.
+
+ - If we do cache the image but don't have support for preallocated
+ images and the cost of caching the image (bytes used) is higher
+ than the max image cache size we fall back to raster engine.
+ */
+
+#if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE
+ if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)
+ || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
+ || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip)
+ || (!d->supportsStretchBlit() && state()->matrix.mapRect(r).size() != sr.size())
+#ifndef QT_DIRECTFB_IMAGECACHE
+ || (QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN)
+#elif defined QT_NO_DIRECTFB_PREALLOCATED
+ || (QDirectFBPaintEnginePrivate::cacheCost(image) > imageCache.maxCost())
+#endif
+ )
+#endif
+ {
+ RASTERFALLBACK(DRAW_IMAGE, r, image.size(), sr);
+ d->lock();
+ QRasterPaintEngine::drawImage(r, image, sr, flags);
+ return;
+ }
+#if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE
+ bool release;
+ IDirectFBSurface *imgSurface = d->getSurface(image, &release);
+ uint blitFlags = 0;
+ if (image.hasAlphaChannel())
+ blitFlags |= QDirectFBPaintEnginePrivate::HasAlpha;
+ if (QDirectFBScreen::isPremultiplied(image.format()))
+ blitFlags |= QDirectFBPaintEnginePrivate::Premultiplied;
+ d->prepareForBlit(blitFlags);
+ CLIPPED_PAINT(d->blit(r, imgSurface, sr));
+ if (release) {
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ d->surface->ReleaseSource(d->surface);
+#endif
+ imgSurface->Release(imgSurface);
+ }
+#endif
+}
+
+void QDirectFBPaintEngine::drawImage(const QPointF &p, const QImage &img)
+{
+ drawImage(QRectF(p, img.size()), img, img.rect());
+}
+
+void QDirectFBPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap,
+ const QRectF &sr)
+{
+ Q_D(QDirectFBPaintEngine);
+
+ if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) {
+ RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr);
+ d->lock();
+ QRasterPaintEngine::drawPixmap(r, pixmap, sr);
+ } else {
+ QPixmapData *data = pixmap.pixmapData();
+ Q_ASSERT(data->classId() == QPixmapData::DirectFBClass);
+ QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data);
+ if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)
+ || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
+ || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip)
+ || (!d->supportsStretchBlit() && state()->matrix.mapRect(r).size() != sr.size())) {
+ RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr);
+ const QImage *img = dfbData->buffer();
+ d->lock();
+ QRasterPaintEngine::drawImage(r, *img, sr);
+ } else {
+ QDirectFBPaintEnginePrivate::unlock(dfbData);
+ IDirectFBSurface *s = dfbData->directFBSurface();
+ uint blitFlags = 0;
+ if (pixmap.hasAlphaChannel())
+ blitFlags |= QDirectFBPaintEnginePrivate::HasAlpha;
+ if (QDirectFBScreen::isPremultiplied(dfbData->pixelFormat()))
+ blitFlags |= QDirectFBPaintEnginePrivate::Premultiplied;
+
+ d->prepareForBlit(blitFlags);
+ CLIPPED_PAINT(d->blit(r, s, sr));
+ }
+ }
+}
+
+void QDirectFBPaintEngine::drawPixmap(const QPointF &p, const QPixmap &pm)
+{
+ drawPixmap(QRectF(p, pm.size()), pm, pm.rect());
+}
+
+void QDirectFBPaintEngine::drawTiledPixmap(const QRectF &r,
+ const QPixmap &pixmap,
+ const QPointF &offset)
+{
+ Q_D(QDirectFBPaintEngine);
+ if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) {
+ RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset);
+ d->lock();
+ QRasterPaintEngine::drawTiledPixmap(r, pixmap, offset);
+ } else if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)
+ || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
+ || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip)
+ || (!d->supportsStretchBlit() && state()->matrix.isScaling())) {
+ RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset);
+ QPixmapData *pixmapData = pixmap.pixmapData();
+ Q_ASSERT(pixmapData->classId() == QPixmapData::DirectFBClass);
+ QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(pixmapData);
+ const QImage *img = dfbData->buffer();
+ d->lock();
+ QRasterPixmapData *data = new QRasterPixmapData(QPixmapData::PixmapType);
+ data->fromImage(*img, Qt::AutoColor);
+ const QPixmap pix(data);
+ QRasterPaintEngine::drawTiledPixmap(r, pix, offset);
+ } else {
+ QTransform transform(state()->matrix);
+ CLIPPED_PAINT(d->drawTiledPixmap(r, pixmap, offset, transform));
+ }
+}
+
+
+void QDirectFBPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
+{
+ RASTERFALLBACK(STROKE_PATH, path, VOID_ARG(), VOID_ARG());
+ Q_D(QDirectFBPaintEngine);
+ d->lock();
+ QRasterPaintEngine::stroke(path, pen);
+}
+
+void QDirectFBPaintEngine::drawPath(const QPainterPath &path)
+{
+ RASTERFALLBACK(DRAW_PATH, path, VOID_ARG(), VOID_ARG());
+ Q_D(QDirectFBPaintEngine);
+ d->lock();
+ QRasterPaintEngine::drawPath(path);
+}
+
+void QDirectFBPaintEngine::drawPoints(const QPointF *points, int pointCount)
+{
+ RASTERFALLBACK(DRAW_POINTS, pointCount, VOID_ARG(), VOID_ARG());
+ Q_D(QDirectFBPaintEngine);
+ d->lock();
+ QRasterPaintEngine::drawPoints(points, pointCount);
+}
+
+void QDirectFBPaintEngine::drawPoints(const QPoint *points, int pointCount)
+{
+ RASTERFALLBACK(DRAW_POINTS, pointCount, VOID_ARG(), VOID_ARG());
+ Q_D(QDirectFBPaintEngine);
+ d->lock();
+ QRasterPaintEngine::drawPoints(points, pointCount);
+}
+
+void QDirectFBPaintEngine::drawEllipse(const QRectF &rect)
+{
+ RASTERFALLBACK(DRAW_ELLIPSE, rect, VOID_ARG(), VOID_ARG());
+ Q_D(QDirectFBPaintEngine);
+ d->lock();
+ QRasterPaintEngine::drawEllipse(rect);
+}
+
+void QDirectFBPaintEngine::drawPolygon(const QPointF *points, int pointCount,
+ PolygonDrawMode mode)
+{
+ RASTERFALLBACK(DRAW_POLYGON, pointCount, mode, VOID_ARG());
+ Q_D(QDirectFBPaintEngine);
+ d->lock();
+ QRasterPaintEngine::drawPolygon(points, pointCount, mode);
+}
+
+void QDirectFBPaintEngine::drawPolygon(const QPoint *points, int pointCount,
+ PolygonDrawMode mode)
+{
+ RASTERFALLBACK(DRAW_POLYGON, pointCount, mode, VOID_ARG());
+ Q_D(QDirectFBPaintEngine);
+ d->lock();
+ QRasterPaintEngine::drawPolygon(points, pointCount, mode);
+}
+
+void QDirectFBPaintEngine::drawTextItem(const QPointF &p,
+ const QTextItem &textItem)
+{
+ RASTERFALLBACK(DRAW_TEXT, p, textItem.text(), VOID_ARG());
+ Q_D(QDirectFBPaintEngine);
+ d->lock();
+ QRasterPaintEngine::drawTextItem(p, textItem);
+}
+
+void QDirectFBPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
+{
+ if (brush.style() == Qt::NoBrush)
+ return;
+ RASTERFALLBACK(FILL_PATH, path, brush, VOID_ARG());
+ Q_D(QDirectFBPaintEngine);
+ d->lock();
+ QRasterPaintEngine::fill(path, brush);
+}
+
+void QDirectFBPaintEngine::drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode)
+{
+ RASTERFALLBACK(DRAW_ROUNDED_RECT, rect, xrad, yrad);
+ Q_D(QDirectFBPaintEngine);
+ d->lock();
+ QRasterPaintEngine::drawRoundedRect(rect, xrad, yrad, mode);
+}
+
+void QDirectFBPaintEngine::drawStaticTextItem(QStaticTextItem *item)
+{
+ RASTERFALLBACK(DRAW_STATICTEXT, item, VOID_ARG(), VOID_ARG());
+ Q_D(QDirectFBPaintEngine);
+ d->lock();
+ QRasterPaintEngine::drawStaticTextItem(item);
+}
+
+void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
+{
+ Q_D(QDirectFBPaintEngine);
+ if (brush.style() == Qt::NoBrush)
+ return;
+ if (d->clipType != QDirectFBPaintEnginePrivate::ComplexClip) {
+ switch (brush.style()) {
+ case Qt::SolidPattern: {
+ const QColor color = brush.color();
+ if (!color.isValid())
+ return;
+
+ if (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported
+ || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) {
+ break;
+ }
+ d->setDFBColor(color);
+ const QRect r = state()->matrix.mapRect(rect).toRect();
+ CLIPPED_PAINT(d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height()));
+ return; }
+
+ case Qt::TexturePattern: {
+ const QPointF &brushOrigin = state()->brushOrigin;
+ const QTransform stateTransform = state()->matrix;
+ QTransform transform(stateTransform);
+ transform.translate(brushOrigin.x(), brushOrigin.y());
+ transform = brush.transform() * transform;
+ if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)
+ || (QDirectFBPaintEnginePrivate::getTransformationType(transform) & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
+ || (!d->supportsStretchBlit() && transform.isScaling())) {
+ break;
+ }
+
+ const QPixmap texture = brush.texture();
+ if (texture.pixmapData()->classId() != QPixmapData::DirectFBClass)
+ break;
+
+ CLIPPED_PAINT(d->drawTiledPixmap(stateTransform.mapRect(rect), texture, rect.topLeft() - brushOrigin, transform));
+ return; }
+ default:
+ break;
+ }
+ }
+ RASTERFALLBACK(FILL_RECT, rect, brush, VOID_ARG());
+ d->lock();
+ QRasterPaintEngine::fillRect(rect, brush);
+}
+
+void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QColor &color)
+{
+ if (!color.isValid())
+ return;
+ Q_D(QDirectFBPaintEngine);
+ if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)
+ || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip)
+ || !(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_Supported)) {
+ RASTERFALLBACK(FILL_RECT, rect, color, VOID_ARG());
+ d->lock();
+ QRasterPaintEngine::fillRect(rect, color);
+ } else {
+ d->setDFBColor(color);
+ const QRect r = state()->matrix.mapRect(rect).toRect();
+ CLIPPED_PAINT(d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height()));
+ }
+}
+
+void QDirectFBPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
+ int x, int y, int length,
+ uint const_alpha)
+{
+ Q_D(QDirectFBPaintEngine);
+ IDirectFBSurface *src = d->surfaceCache->getSurface(buffer, bufsize);
+ // ### how does this play with setDFBColor
+ src->SetColor(src, 0, 0, 0, const_alpha);
+ const DFBRectangle rect = { 0, 0, length, 1 };
+ d->surface->Blit(d->surface, src, &rect, x, y);
+}
+
+#ifdef QT_DIRECTFB_IMAGECACHE
+static void cachedImageCleanupHook(qint64 key)
+{
+ delete imageCache.take(key);
+}
+void QDirectFBPaintEngine::initImageCache(int size)
+{
+ Q_ASSERT(size >= 0);
+ imageCache.setMaxCost(size);
+ QImagePixmapCleanupHooks::instance()->addImageHook(cachedImageCleanupHook);
+}
+
+#endif // QT_DIRECTFB_IMAGECACHE
+
+// ---- QDirectFBPaintEnginePrivate ----
+
+
+QDirectFBPaintEnginePrivate::QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p)
+ : surface(0), antialiased(false), simplePen(false),
+ transformationType(0), opacity(255),
+ clipType(ClipUnset), dfbDevice(0),
+ compositionModeStatus(0), isPremultiplied(false), inClip(false), q(p)
+{
+ fb = QDirectFBScreen::instance()->dfb();
+ surfaceCache = new SurfaceCache;
+}
+
+QDirectFBPaintEnginePrivate::~QDirectFBPaintEnginePrivate()
+{
+ delete surfaceCache;
+}
+
+bool QDirectFBPaintEnginePrivate::isSimpleBrush(const QBrush &brush) const
+{
+ return (brush.style() == Qt::NoBrush) || (brush.style() == Qt::SolidPattern && !antialiased);
+}
+
+void QDirectFBPaintEnginePrivate::lock()
+{
+ // We will potentially get a new pointer to the buffer after a
+ // lock so we need to call the base implementation of prepare so
+ // it updates its rasterBuffer to point to the new buffer address.
+ Q_ASSERT(dfbDevice);
+ if (dfbDevice->lockSurface(DSLF_READ|DSLF_WRITE)) {
+ prepare(dfbDevice);
+ }
+}
+
+void QDirectFBPaintEnginePrivate::unlock()
+{
+ Q_ASSERT(dfbDevice);
+#ifdef QT_DIRECTFB_SUBSURFACE
+ dfbDevice->syncPending = true;
+#else
+ QDirectFBPaintEnginePrivate::unlock(dfbDevice);
+#endif
+}
+
+void QDirectFBPaintEnginePrivate::unlock(QDirectFBPaintDevice *device)
+{
+#ifdef QT_NO_DIRECTFB_SUBSURFACE
+ Q_ASSERT(device);
+ device->unlockSurface();
+#else
+ Q_UNUSED(device);
+#endif
+}
+
+void QDirectFBPaintEnginePrivate::setTransform(const QTransform &transform)
+{
+ transformationType = getTransformationType(transform);
+ setPen(q->state()->pen);
+}
+
+void QDirectFBPaintEnginePrivate::setPen(const QPen &pen)
+{
+ if (pen.style() == Qt::NoPen) {
+ simplePen = true;
+ } else if (pen.style() == Qt::SolidLine
+ && !antialiased
+ && pen.brush().style() == Qt::SolidPattern
+ && pen.widthF() <= 1.0
+ && (transformationType < QTransform::TxScale || pen.isCosmetic())) {
+ simplePen = true;
+ } else {
+ simplePen = false;
+ }
+}
+
+void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode mode)
+{
+ if (!surface)
+ return;
+
+ static const bool forceRasterFallBack = qgetenv("QT_DIRECTFB_FORCE_RASTER").toInt() > 0;
+ if (forceRasterFallBack) {
+ compositionModeStatus = PorterDuff_None;
+ return;
+ }
+
+ compositionModeStatus = PorterDuff_Supported|PorterDuff_PremultiplyColors|PorterDuff_AlwaysBlend;
+ switch (mode) {
+ case QPainter::CompositionMode_Clear:
+ surface->SetPorterDuff(surface, DSPD_CLEAR);
+ break;
+ case QPainter::CompositionMode_Source:
+ surface->SetPorterDuff(surface, DSPD_SRC);
+ compositionModeStatus &= ~PorterDuff_AlwaysBlend;
+ if (!isPremultiplied)
+ compositionModeStatus &= ~PorterDuff_PremultiplyColors;
+ break;
+ case QPainter::CompositionMode_SourceOver:
+ compositionModeStatus &= ~PorterDuff_AlwaysBlend;
+ surface->SetPorterDuff(surface, DSPD_SRC_OVER);
+ break;
+ case QPainter::CompositionMode_DestinationOver:
+ surface->SetPorterDuff(surface, DSPD_DST_OVER);
+ break;
+ case QPainter::CompositionMode_SourceIn:
+ surface->SetPorterDuff(surface, DSPD_SRC_IN);
+ if (!isPremultiplied)
+ compositionModeStatus &= ~PorterDuff_PremultiplyColors;
+ break;
+ case QPainter::CompositionMode_DestinationIn:
+ surface->SetPorterDuff(surface, DSPD_DST_IN);
+ break;
+ case QPainter::CompositionMode_SourceOut:
+ surface->SetPorterDuff(surface, DSPD_SRC_OUT);
+ break;
+ case QPainter::CompositionMode_DestinationOut:
+ surface->SetPorterDuff(surface, DSPD_DST_OUT);
+ break;
+ case QPainter::CompositionMode_Destination:
+ surface->SetSrcBlendFunction(surface, DSBF_ZERO);
+ surface->SetDstBlendFunction(surface, DSBF_ONE);
+ break;
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ case QPainter::CompositionMode_SourceAtop:
+ surface->SetPorterDuff(surface, DSPD_SRC_ATOP);
+ break;
+ case QPainter::CompositionMode_DestinationAtop:
+ surface->SetPorterDuff(surface, DSPD_DST_ATOP);
+ break;
+ case QPainter::CompositionMode_Plus:
+ surface->SetPorterDuff(surface, DSPD_ADD);
+ break;
+ case QPainter::CompositionMode_Xor:
+ surface->SetPorterDuff(surface, DSPD_XOR);
+ break;
+#endif
+ default:
+ compositionModeStatus = PorterDuff_None;
+ break;
+ }
+}
+
+void QDirectFBPaintEnginePrivate::setRenderHints(QPainter::RenderHints hints)
+{
+ const bool old = antialiased;
+ antialiased = bool(hints & QPainter::Antialiasing);
+ if (old != antialiased) {
+ setPen(q->state()->pen);
+ }
+}
+
+void QDirectFBPaintEnginePrivate::prepareForBlit(uint flags)
+{
+ DFBSurfaceBlittingFlags blittingFlags = DSBLIT_NOFX;
+ if (flags & Premultiplied)
+ blittingFlags |= DSBLIT_SRC_PREMULTIPLY;
+ if (flags & HasAlpha)
+ blittingFlags |= DSBLIT_BLEND_ALPHACHANNEL;
+ if (opacity != 255) {
+ blittingFlags |= DSBLIT_BLEND_COLORALPHA;
+ surface->SetColor(surface, 0xff, 0xff, 0xff, opacity);
+ }
+
+ surface->SetBlittingFlags(surface, blittingFlags);
+}
+
+static inline uint ALPHA_MUL(uint x, uint a)
+{
+ uint t = x * a;
+ t = ((t + (t >> 8) + 0x80) >> 8) & 0xff;
+ return t;
+}
+
+void QDirectFBPaintEnginePrivate::setDFBColor(const QColor &color)
+{
+ Q_ASSERT(surface);
+ Q_ASSERT(compositionModeStatus & PorterDuff_Supported);
+ const quint8 alpha = (opacity == 255 ?
+ color.alpha() : ALPHA_MUL(color.alpha(), opacity));
+ QColor col;
+ if (compositionModeStatus & PorterDuff_PremultiplyColors) {
+ col = QColor(ALPHA_MUL(color.red(), alpha),
+ ALPHA_MUL(color.green(), alpha),
+ ALPHA_MUL(color.blue(), alpha),
+ alpha);
+ } else {
+ col = QColor(color.red(), color.green(), color.blue(), alpha);
+ }
+ surface->SetColor(surface, col.red(), col.green(), col.blue(), col.alpha());
+ surface->SetDrawingFlags(surface, alpha == 255 && !(compositionModeStatus & PorterDuff_AlwaysBlend) ? DSDRAW_NOFX : DSDRAW_BLEND);
+}
+
+IDirectFBSurface *QDirectFBPaintEnginePrivate::getSurface(const QImage &img, bool *release)
+{
+#ifdef QT_NO_DIRECTFB_IMAGECACHE
+ *release = true;
+ return QDirectFBScreen::instance()->createDFBSurface(img, img.format(), QDirectFBScreen::DontTrackSurface);
+#else
+ const qint64 key = img.cacheKey();
+ *release = false;
+ if (imageCache.contains(key)) {
+ return imageCache[key]->surface;
+ }
+
+ const int cost = cacheCost(img);
+ const bool cache = cost <= imageCache.maxCost();
+ QDirectFBScreen *screen = QDirectFBScreen::instance();
+ const QImage::Format format = (img.format() == screen->alphaPixmapFormat() || QDirectFBPixmapData::hasAlphaChannel(img)
+ ? screen->alphaPixmapFormat() : screen->pixelFormat());
+
+ IDirectFBSurface *surface = screen->createDFBSurface(img, format,
+ cache
+ ? QDirectFBScreen::TrackSurface
+ : QDirectFBScreen::DontTrackSurface);
+ if (cache) {
+ CachedImage *cachedImage = new CachedImage;
+ const_cast<QImage&>(img).data_ptr()->is_cached = true;
+ cachedImage->surface = surface;
+ imageCache.insert(key, cachedImage, cost);
+ } else {
+ *release = true;
+ }
+ return surface;
+#endif
+}
+
+
+void QDirectFBPaintEnginePrivate::blit(const QRectF &dest, IDirectFBSurface *s, const QRectF &src)
+{
+ const QRect sr = src.toRect();
+ const QRect dr = q->state()->matrix.mapRect(dest).toRect();
+ if (dr.isEmpty())
+ return;
+ const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() };
+ DFBResult result;
+
+ if (dr.size() == sr.size()) {
+ result = surface->Blit(surface, s, &sRect, dr.x(), dr.y());
+ } else {
+ Q_ASSERT(supportsStretchBlit());
+ const DFBRectangle dRect = { dr.x(), dr.y(), dr.width(), dr.height() };
+ result = surface->StretchBlit(surface, s, &sRect, &dRect);
+ }
+ if (result != DFB_OK)
+ DirectFBError("QDirectFBPaintEngine::drawPixmap()", result);
+}
+
+static inline qreal fixCoord(qreal rect_pos, qreal pixmapSize, qreal offset)
+{
+ qreal pos = rect_pos - offset;
+ while (pos > rect_pos)
+ pos -= pixmapSize;
+ while (pos + pixmapSize < rect_pos)
+ pos += pixmapSize;
+ return pos;
+}
+
+void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap,
+ const QPointF &off, const QTransform &pixmapTransform)
+{
+ const QTransform &transform = q->state()->matrix;
+ Q_ASSERT(!(getTransformationType(transform) & Matrix_BlitsUnsupported) &&
+ !(getTransformationType(pixmapTransform) & Matrix_BlitsUnsupported));
+ const QRect destinationRect = transform.mapRect(dest).toRect().normalized();
+ QRect newClip = destinationRect;
+ if (!currentClip.isEmpty())
+ newClip &= currentClip;
+
+ if (newClip.isNull())
+ return;
+
+ const DFBRegion clip = {
+ newClip.x(),
+ newClip.y(),
+ newClip.right(),
+ newClip.bottom()
+ };
+ surface->SetClip(surface, &clip);
+
+ QPointF offset = pixmapTransform.inverted().map(off);
+ Q_ASSERT(transform.type() <= QTransform::TxScale);
+ QPixmapData *data = pixmap.pixmapData();
+ Q_ASSERT(data->classId() == QPixmapData::DirectFBClass);
+ QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data);
+ IDirectFBSurface *sourceSurface = dfbData->directFBSurface();
+ uint blitFlags = 0;
+ if (dfbData->hasAlphaChannel())
+ blitFlags |= HasAlpha;
+ if (QDirectFBScreen::isPremultiplied(dfbData->pixelFormat()))
+ blitFlags |= Premultiplied;
+ prepareForBlit(blitFlags);
+ QDirectFBPaintEnginePrivate::unlock(dfbData);
+ const QSize pixmapSize = dfbData->size();
+ if (transform.isScaling() || pixmapTransform.isScaling()) {
+ Q_ASSERT(supportsStretchBlit());
+ Q_ASSERT(qMin(transform.m11(), transform.m22()) >= 0);
+ offset.rx() *= transform.m11();
+ offset.ry() *= transform.m22();
+
+ const QSizeF mappedSize(pixmapSize.width() * pixmapTransform.m11(), pixmapSize.height() * pixmapTransform.m22());
+ qreal y = fixCoord(destinationRect.y(), mappedSize.height(), offset.y());
+ const qreal startX = fixCoord(destinationRect.x(), mappedSize.width(), offset.x());
+ while (y <= destinationRect.bottom()) {
+ qreal x = startX;
+ while (x <= destinationRect.right()) {
+ const DFBRectangle destination = { qRound(x), qRound(y), mappedSize.width(), mappedSize.height() };
+ surface->StretchBlit(surface, sourceSurface, 0, &destination);
+ x += mappedSize.width();
+ }
+ y += mappedSize.height();
+ }
+ } else {
+ qreal y = fixCoord(destinationRect.y(), pixmapSize.height(), offset.y());
+ const qreal startX = fixCoord(destinationRect.x(), pixmapSize.width(), offset.x());
+ int horizontal = qMax(1, destinationRect.width() / pixmapSize.width()) + 1;
+ if (startX != destinationRect.x())
+ ++horizontal;
+ int vertical = qMax(1, destinationRect.height() / pixmapSize.height()) + 1;
+ if (y != destinationRect.y())
+ ++vertical;
+
+ const int maxCount = (vertical * horizontal);
+ QVarLengthArray<DFBRectangle, 16> sourceRects(maxCount);
+ QVarLengthArray<DFBPoint, 16> points(maxCount);
+
+ int i = 0;
+ while (y <= destinationRect.bottom()) {
+ Q_ASSERT(i < maxCount);
+ qreal x = startX;
+ while (x <= destinationRect.right()) {
+ points[i].x = qRound(x);
+ points[i].y = qRound(y);
+ sourceRects[i].x = 0;
+ sourceRects[i].y = 0;
+ sourceRects[i].w = int(pixmapSize.width());
+ sourceRects[i].h = int(pixmapSize.height());
+ x += pixmapSize.width();
+ ++i;
+ }
+ y += pixmapSize.height();
+ }
+ surface->BatchBlit(surface, sourceSurface, sourceRects.constData(), points.constData(), i);
+ }
+
+ if (currentClip.isEmpty()) {
+ surface->SetClip(surface, 0);
+ } else {
+ const DFBRegion clip = {
+ currentClip.x(),
+ currentClip.y(),
+ currentClip.right(),
+ currentClip.bottom()
+ };
+ surface->SetClip(surface, &clip);
+ }
+}
+
+void QDirectFBPaintEnginePrivate::updateClip()
+{
+ Q_ASSERT(surface);
+ currentClip = QRect();
+ const QClipData *clipData = clip();
+ if (!clipData || !clipData->enabled) {
+ surface->SetClip(surface, NULL);
+ clipType = NoClip;
+ } else if (clipData->hasRectClip) {
+ const DFBRegion r = {
+ clipData->clipRect.x(),
+ clipData->clipRect.y(),
+ clipData->clipRect.right(),
+ clipData->clipRect.bottom()
+ };
+ surface->SetClip(surface, &r);
+ currentClip = clipData->clipRect.normalized();
+ // ### is this guaranteed to always be normalized?
+ clipType = RectClip;
+ } else if (clipData->hasRegionClip) {
+ clipType = RegionClip;
+ } else {
+ clipType = ComplexClip;
+ }
+}
+
+bool QDirectFBPaintEnginePrivate::supportsStretchBlit() const
+{
+#ifdef QT_DIRECTFB_STRETCHBLIT
+ return !(q->state()->renderHints & QPainter::SmoothPixmapTransform);
+#else
+ return false;
+#endif
+}
+
+
+void QDirectFBPaintEnginePrivate::systemStateChanged()
+{
+ QRasterPaintEnginePrivate::systemStateChanged();
+ updateClip();
+}
+
+IDirectFBSurface *SurfaceCache::getSurface(const uint *buf, int size)
+{
+ if (buffer == buf && bufsize == size)
+ return surface;
+
+ clear();
+
+ const DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(buf, size);
+ surface = QDirectFBScreen::instance()->createDFBSurface(description, QDirectFBScreen::TrackSurface, 0);
+ if (!surface)
+ qWarning("QDirectFBPaintEngine: SurfaceCache: Unable to create surface");
+
+ buffer = const_cast<uint*>(buf);
+ bufsize = size;
+
+ return surface;
+}
+
+void SurfaceCache::clear()
+{
+ if (surface && QDirectFBScreen::instance())
+ QDirectFBScreen::instance()->releaseDFBSurface(surface);
+ surface = 0;
+ buffer = 0;
+ bufsize = 0;
+}
+
+
+static inline QRect mapRect(const QTransform &transform, const QRect &rect) { return transform.mapRect(rect); }
+static inline QRect mapRect(const QTransform &transform, const QRectF &rect) { return transform.mapRect(rect).toRect(); }
+static inline QLine map(const QTransform &transform, const QLine &line) { return transform.map(line); }
+static inline QLine map(const QTransform &transform, const QLineF &line) { return transform.map(line).toLine(); }
+template <class T>
+static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface)
+{
+ if (n == 1) {
+ const QLine l = map(transform, lines[0]);
+ surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2());
+ } else {
+ QVarLengthArray<DFBRegion, 32> lineArray(n);
+ for (int i=0; i<n; ++i) {
+ const QLine l = map(transform, lines[i]);
+ lineArray[i].x1 = l.x1();
+ lineArray[i].y1 = l.y1();
+ lineArray[i].x2 = l.x2();
+ lineArray[i].y2 = l.y2();
+ }
+ surface->DrawLines(surface, lineArray.constData(), n);
+ }
+}
+
+template <class T>
+static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface)
+{
+ if (n == 1) {
+ const QRect r = mapRect(transform, rects[0]);
+ surface->FillRectangle(surface, r.x(), r.y(), r.width(), r.height());
+ } else {
+ QVarLengthArray<DFBRectangle, 32> rectArray(n);
+ for (int i=0; i<n; ++i) {
+ const QRect r = mapRect(transform, rects[i]);
+ rectArray[i].x = r.x();
+ rectArray[i].y = r.y();
+ rectArray[i].w = r.width();
+ rectArray[i].h = r.height();
+ }
+ surface->FillRectangles(surface, rectArray.constData(), n);
+ }
+}
+
+template <class T>
+static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface)
+{
+ for (int i=0; i<n; ++i) {
+ const QRect r = mapRect(transform, rects[i]);
+ surface->DrawRectangle(surface, r.x(), r.y(), r.width(), r.height());
+ }
+}
+
+template <typename T> inline const T *ptr(const T &t) { return &t; }
+template <> inline const bool* ptr<bool>(const bool &) { return 0; }
+template <typename device, typename T1, typename T2, typename T3>
+static void rasterFallbackWarn(const char *msg, const char *func, const device *dev,
+ uint transformationType, bool simplePen,
+ uint clipType, uint compositionModeStatus,
+ const char *nameOne, const T1 &one,
+ const char *nameTwo, const T2 &two,
+ const char *nameThree, const T3 &three)
+{
+ QString out;
+ QDebug dbg(&out);
+ dbg << msg << (QByteArray(func) + "()") << "painting on";
+ if (dev->devType() == QInternal::Widget) {
+ dbg << static_cast<const QWidget*>(dev);
+ } else {
+ dbg << dev << "of type" << dev->devType();
+ }
+
+ dbg << QString::fromLatin1("transformationType 0x%1").arg(transformationType, 3, 16, QLatin1Char('0'))
+ << "simplePen" << simplePen
+ << "clipType" << clipType
+ << "compositionModeStatus" << compositionModeStatus;
+
+ const T1 *t1 = ptr(one);
+ const T2 *t2 = ptr(two);
+ const T3 *t3 = ptr(three);
+
+ if (t1) {
+ dbg << nameOne << *t1;
+ if (t2) {
+ dbg << nameTwo << *t2;
+ if (t3) {
+ dbg << nameThree << *t3;
+ }
+ }
+ }
+ qWarning("%s", qPrintable(out));
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QWS_DIRECTFB
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h
new file mode 100644
index 0000000000..1908f3ad32
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPAINTENGINE_DIRECTFB_P_H
+#define QPAINTENGINE_DIRECTFB_P_H
+
+#include <QtGui/qpaintengine.h>
+#include <private/qpaintengine_raster_p.h>
+
+#ifndef QT_NO_QWS_DIRECTFB
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QDirectFBPaintEnginePrivate;
+
+class QDirectFBPaintEngine : public QRasterPaintEngine
+{
+ Q_DECLARE_PRIVATE(QDirectFBPaintEngine)
+public:
+ QDirectFBPaintEngine(QPaintDevice *device);
+ virtual ~QDirectFBPaintEngine();
+
+ virtual bool begin(QPaintDevice *device);
+ virtual bool end();
+
+ virtual void drawRects(const QRect *rects, int rectCount);
+ virtual void drawRects(const QRectF *rects, int rectCount);
+
+ virtual void fillRect(const QRectF &r, const QBrush &brush);
+ virtual void fillRect(const QRectF &r, const QColor &color);
+
+ virtual void drawLines(const QLine *line, int lineCount);
+ virtual void drawLines(const QLineF *line, int lineCount);
+
+ virtual void drawImage(const QPointF &p, const QImage &img);
+ virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
+ Qt::ImageConversionFlags falgs = Qt::AutoColor);
+
+ virtual void drawPixmap(const QPointF &p, const QPixmap &pm);
+ virtual void drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr);
+ virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr);
+
+ virtual void drawBufferSpan(const uint *buffer, int bufsize,
+ int x, int y, int length, uint const_alpha);
+
+ virtual void stroke(const QVectorPath &path, const QPen &pen);
+ virtual void drawPath(const QPainterPath &path);
+ virtual void drawPoints(const QPointF *points, int pointCount);
+ virtual void drawPoints(const QPoint *points, int pointCount);
+ virtual void drawEllipse(const QRectF &rect);
+ virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode);
+ virtual void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode);
+ virtual void drawTextItem(const QPointF &p, const QTextItem &textItem);
+ virtual void fill(const QVectorPath &path, const QBrush &brush);
+ virtual void drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode);
+
+ virtual void clipEnabledChanged();
+ virtual void penChanged();
+ virtual void opacityChanged();
+ virtual void compositionModeChanged();
+ virtual void renderHintsChanged();
+ virtual void transformChanged();
+
+ virtual void setState(QPainterState *state);
+
+ virtual void clip(const QVectorPath &path, Qt::ClipOperation op);
+ virtual void clip(const QRegion &region, Qt::ClipOperation op);
+ virtual void clip(const QRect &rect, Qt::ClipOperation op);
+
+ virtual void drawStaticTextItem(QStaticTextItem *item);
+
+ static void initImageCache(int size);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_QWS_DIRECTFB
+
+#endif // QPAINTENGINE_DIRECTFB_P_H
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp
new file mode 100644
index 0000000000..eaff74a41c
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp
@@ -0,0 +1,588 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdirectfbpixmap.h"
+
+#ifndef QT_NO_QWS_DIRECTFB
+
+#include "qdirectfbscreen.h"
+#include "qdirectfbpaintengine.h"
+
+#include <QtGui/qbitmap.h>
+#include <QtCore/qfile.h>
+#include <directfb.h>
+
+
+QT_BEGIN_NAMESPACE
+
+static int global_ser_no = 0;
+
+QDirectFBPixmapData::QDirectFBPixmapData(QDirectFBScreen *screen, PixelType pixelType)
+ : QPixmapData(pixelType, DirectFBClass), QDirectFBPaintDevice(screen),
+ alpha(false)
+{
+ setSerialNumber(0);
+}
+
+QDirectFBPixmapData::~QDirectFBPixmapData()
+{
+}
+
+void QDirectFBPixmapData::resize(int width, int height)
+{
+ if (width <= 0 || height <= 0) {
+ invalidate();
+ return;
+ }
+
+ imageFormat = screen->pixelFormat();
+ dfbSurface = screen->createDFBSurface(QSize(width, height),
+ imageFormat,
+ QDirectFBScreen::TrackSurface);
+ d = QDirectFBScreen::depth(imageFormat);
+ alpha = false;
+ if (!dfbSurface) {
+ invalidate();
+ qWarning("QDirectFBPixmapData::resize(): Unable to allocate surface");
+ return;
+ }
+
+ w = width;
+ h = height;
+ is_null = (w <= 0 || h <= 0);
+ setSerialNumber(++global_ser_no);
+}
+
+#ifdef QT_DIRECTFB_OPAQUE_DETECTION
+// mostly duplicated from qimage.cpp (QImageData::checkForAlphaPixels)
+static bool checkForAlphaPixels(const QImage &img)
+{
+ const uchar *bits = img.bits();
+ const int bytes_per_line = img.bytesPerLine();
+ const uchar *end_bits = bits + bytes_per_line;
+ const int width = img.width();
+ const int height = img.height();
+ switch (img.format()) {
+ case QImage::Format_Indexed8:
+ return img.hasAlphaChannel();
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ for (int y=0; y<height; ++y) {
+ for (int x=0; x<width; ++x) {
+ if ((((uint *)bits)[x] & 0xff000000) != 0xff000000) {
+ return true;
+ }
+ }
+ bits += bytes_per_line;
+ }
+ break;
+
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_ARGB8565_Premultiplied:
+ for (int y=0; y<height; ++y) {
+ while (bits < end_bits) {
+ if (bits[0] != 0) {
+ return true;
+ }
+ bits += 3;
+ }
+ bits = end_bits;
+ end_bits += bytes_per_line;
+ }
+ break;
+
+ case QImage::Format_ARGB6666_Premultiplied:
+ for (int y=0; y<height; ++y) {
+ while (bits < end_bits) {
+ if ((bits[0] & 0xfc) != 0) {
+ return true;
+ }
+ bits += 3;
+ }
+ bits = end_bits;
+ end_bits += bytes_per_line;
+ }
+ break;
+
+ case QImage::Format_ARGB4444_Premultiplied:
+ for (int y=0; y<height; ++y) {
+ while (bits < end_bits) {
+ if ((bits[0] & 0xf0) != 0) {
+ return true;
+ }
+ bits += 2;
+ }
+ bits = end_bits;
+ end_bits += bytes_per_line;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+#endif // QT_DIRECTFB_OPAQUE_DETECTION
+
+bool QDirectFBPixmapData::hasAlphaChannel(const QImage &img, Qt::ImageConversionFlags flags)
+{
+ if (img.depth() == 1)
+ return true;
+#ifdef QT_DIRECTFB_OPAQUE_DETECTION
+ return ((flags & Qt::NoOpaqueDetection) ? img.hasAlphaChannel() : checkForAlphaPixels(img));
+#else
+ Q_UNUSED(flags);
+ return img.hasAlphaChannel();
+#endif
+}
+
+#ifdef QT_DIRECTFB_IMAGEPROVIDER
+bool QDirectFBPixmapData::fromFile(const QString &filename, const char *format,
+ Qt::ImageConversionFlags flags)
+{
+ if (!QFile::exists(filename))
+ return false;
+ if (flags == Qt::AutoColor) {
+ if (filename.startsWith(QLatin1Char(':'))) { // resource
+ QFile file(filename);
+ if (!file.open(QIODevice::ReadOnly))
+ return false;
+ const QByteArray data = file.readAll();
+ file.close();
+ return fromData(reinterpret_cast<const uchar*>(data.constData()), data.size(), format, flags);
+ } else {
+ DFBDataBufferDescription description;
+ description.flags = DBDESC_FILE;
+ const QByteArray fileNameData = filename.toLocal8Bit();
+ description.file = fileNameData.constData();
+ if (fromDataBufferDescription(description)) {
+ return true;
+ }
+ // fall back to Qt
+ }
+ }
+ return QPixmapData::fromFile(filename, format, flags);
+}
+
+bool QDirectFBPixmapData::fromData(const uchar *buffer, uint len, const char *format,
+ Qt::ImageConversionFlags flags)
+{
+ if (flags == Qt::AutoColor) {
+ DFBDataBufferDescription description;
+ description.flags = DBDESC_MEMORY;
+ description.memory.data = buffer;
+ description.memory.length = len;
+ if (fromDataBufferDescription(description))
+ return true;
+ // fall back to Qt
+ }
+ return QPixmapData::fromData(buffer, len, format, flags);
+}
+
+template <typename T> struct QDirectFBInterfaceCleanupHandler
+{
+ static void cleanup(T *t) { if (t) t->Release(t); }
+};
+
+template <typename T>
+class QDirectFBPointer : public QScopedPointer<T, QDirectFBInterfaceCleanupHandler<T> >
+{
+public:
+ QDirectFBPointer(T *t = 0)
+ : QScopedPointer<T, QDirectFBInterfaceCleanupHandler<T> >(t)
+ {}
+};
+
+bool QDirectFBPixmapData::fromDataBufferDescription(const DFBDataBufferDescription &dataBufferDescription)
+{
+ IDirectFB *dfb = screen->dfb();
+ Q_ASSERT(dfb);
+ DFBResult result = DFB_OK;
+ IDirectFBDataBuffer *dataBufferPtr;
+ if ((result = dfb->CreateDataBuffer(dfb, &dataBufferDescription, &dataBufferPtr)) != DFB_OK) {
+ DirectFBError("QDirectFBPixmapData::fromDataBufferDescription()", result);
+ return false;
+ }
+ QDirectFBPointer<IDirectFBDataBuffer> dataBuffer(dataBufferPtr);
+
+ IDirectFBImageProvider *providerPtr;
+ if ((result = dataBuffer->CreateImageProvider(dataBuffer.data(), &providerPtr)) != DFB_OK)
+ return false;
+
+ QDirectFBPointer<IDirectFBImageProvider> provider(providerPtr);
+
+ DFBImageDescription imageDescription;
+ result = provider->GetImageDescription(provider.data(), &imageDescription);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBPixmapData::fromSurfaceDescription(): Can't get image description", result);
+ return false;
+ }
+
+ if (imageDescription.caps & DICAPS_COLORKEY) {
+ return false;
+ }
+
+ DFBSurfaceDescription surfaceDescription;
+ if ((result = provider->GetSurfaceDescription(provider.data(), &surfaceDescription)) != DFB_OK) {
+ DirectFBError("QDirectFBPixmapData::fromDataBufferDescription(): Can't get surface description", result);
+ return false;
+ }
+
+ alpha = imageDescription.caps & DICAPS_ALPHACHANNEL;
+ imageFormat = alpha ? screen->alphaPixmapFormat() : screen->pixelFormat();
+
+ dfbSurface = screen->createDFBSurface(QSize(surfaceDescription.width, surfaceDescription.height),
+ imageFormat, QDirectFBScreen::TrackSurface);
+
+ result = provider->RenderTo(provider.data(), dfbSurface, 0);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBPixmapData::fromSurfaceDescription(): Can't render to surface", result);
+ return false;
+ }
+
+ w = surfaceDescription.width;
+ h = surfaceDescription.height;
+ is_null = (w <= 0 || h <= 0);
+ d = QDirectFBScreen::depth(imageFormat);
+ setSerialNumber(++global_ser_no);
+
+#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE
+ screen->setDirectFBImageProvider(providerPtr);
+ provider.take();
+#endif
+
+ return true;
+}
+
+#endif
+
+void QDirectFBPixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags)
+{
+ alpha = QDirectFBPixmapData::hasAlphaChannel(img, flags);
+ imageFormat = alpha ? screen->alphaPixmapFormat() : screen->pixelFormat();
+
+ QImage image;
+ if ((flags & ~Qt::NoOpaqueDetection) != Qt::AutoColor) {
+ image = img.convertToFormat(imageFormat, flags);
+ flags = Qt::AutoColor;
+ } else if (img.format() == QImage::Format_RGB32 || img.depth() == 1) {
+ image = img.convertToFormat(imageFormat, flags);
+ } else if (img.format() != imageFormat) {
+ image = img.convertToFormat(imageFormat, flags);
+ } else {
+ image = img;
+ }
+
+ dfbSurface = screen->createDFBSurface(image, image.format(), QDirectFBScreen::NoPreallocated | QDirectFBScreen::TrackSurface);
+ if (!dfbSurface) {
+ qWarning("QDirectFBPixmapData::fromImage()");
+ invalidate();
+ return;
+ }
+
+ w = image.width();
+ h = image.height();
+ is_null = (w <= 0 || h <= 0);
+ d = QDirectFBScreen::depth(imageFormat);
+ setSerialNumber(++global_ser_no);
+#ifdef QT_NO_DIRECTFB_OPAQUE_DETECTION
+ Q_UNUSED(flags);
+#endif
+}
+
+void QDirectFBPixmapData::copy(const QPixmapData *data, const QRect &rect)
+{
+ if (data->classId() != DirectFBClass) {
+ QPixmapData::copy(data, rect);
+ return;
+ }
+
+ const QDirectFBPixmapData *otherData = static_cast<const QDirectFBPixmapData*>(data);
+#ifdef QT_NO_DIRECTFB_SUBSURFACE
+ if (otherData->lockFlags()) {
+ const_cast<QDirectFBPixmapData*>(otherData)->unlockSurface();
+ }
+#endif
+ IDirectFBSurface *src = otherData->directFBSurface();
+ alpha = data->hasAlphaChannel();
+ imageFormat = (alpha
+ ? QDirectFBScreen::instance()->alphaPixmapFormat()
+ : QDirectFBScreen::instance()->pixelFormat());
+
+
+ dfbSurface = screen->createDFBSurface(rect.size(), imageFormat,
+ QDirectFBScreen::TrackSurface);
+ if (!dfbSurface) {
+ qWarning("QDirectFBPixmapData::copy()");
+ invalidate();
+ return;
+ }
+
+ if (alpha) {
+ dfbSurface->Clear(dfbSurface, 0, 0, 0, 0);
+ dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_BLEND_ALPHACHANNEL);
+ } else {
+ dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX);
+ }
+ const DFBRectangle blitRect = { rect.x(), rect.y(),
+ rect.width(), rect.height() };
+ w = rect.width();
+ h = rect.height();
+ d = otherData->d;
+ is_null = (w <= 0 || h <= 0);
+ unlockSurface();
+ DFBResult result = dfbSurface->Blit(dfbSurface, src, &blitRect, 0, 0);
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ dfbSurface->ReleaseSource(dfbSurface);
+#endif
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBPixmapData::copy()", result);
+ invalidate();
+ return;
+ }
+
+ setSerialNumber(++global_ser_no);
+}
+
+static inline bool isOpaqueFormat(QImage::Format format)
+{
+ switch (format) {
+ case QImage::Format_RGB32:
+ case QImage::Format_RGB16:
+ case QImage::Format_RGB666:
+ case QImage::Format_RGB555:
+ case QImage::Format_RGB888:
+ case QImage::Format_RGB444:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+void QDirectFBPixmapData::fill(const QColor &color)
+{
+ if (!serialNumber())
+ return;
+
+ Q_ASSERT(dfbSurface);
+
+ alpha |= (color.alpha() < 255);
+
+ if (alpha && isOpaqueFormat(imageFormat)) {
+ QSize size;
+ dfbSurface->GetSize(dfbSurface, &size.rwidth(), &size.rheight());
+ screen->releaseDFBSurface(dfbSurface);
+ imageFormat = screen->alphaPixmapFormat();
+ d = QDirectFBScreen::depth(imageFormat);
+ dfbSurface = screen->createDFBSurface(size, screen->alphaPixmapFormat(), QDirectFBScreen::TrackSurface);
+ setSerialNumber(++global_ser_no);
+ if (!dfbSurface) {
+ qWarning("QDirectFBPixmapData::fill()");
+ invalidate();
+ return;
+ }
+ }
+
+ dfbSurface->Clear(dfbSurface, color.red(), color.green(), color.blue(), color.alpha());
+}
+
+QPixmap QDirectFBPixmapData::transformed(const QTransform &transform,
+ Qt::TransformationMode mode) const
+{
+ QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this);
+#ifdef QT_NO_DIRECTFB_SUBSURFACE
+ if (lockFlags())
+ that->unlockSurface();
+#endif
+
+ if (!dfbSurface || transform.type() != QTransform::TxScale
+ || mode != Qt::FastTransformation)
+ {
+ const QImage *image = that->buffer();
+ Q_ASSERT(image);
+ const QImage transformed = image->transformed(transform, mode);
+ QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType);
+ data->fromImage(transformed, Qt::AutoColor);
+ return QPixmap(data);
+ }
+
+ const QSize size = transform.mapRect(QRect(0, 0, w, h)).size();
+ if (size.isEmpty())
+ return QPixmap();
+
+ QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType);
+ data->setSerialNumber(++global_ser_no);
+ DFBSurfaceBlittingFlags flags = DSBLIT_NOFX;
+ data->alpha = alpha;
+ if (alpha) {
+ flags = DSBLIT_BLEND_ALPHACHANNEL;
+ }
+ data->dfbSurface = screen->createDFBSurface(size,
+ imageFormat,
+ QDirectFBScreen::TrackSurface);
+ if (flags & DSBLIT_BLEND_ALPHACHANNEL) {
+ data->dfbSurface->Clear(data->dfbSurface, 0, 0, 0, 0);
+ }
+ data->dfbSurface->SetBlittingFlags(data->dfbSurface, flags);
+
+ const DFBRectangle destRect = { 0, 0, size.width(), size.height() };
+ data->dfbSurface->StretchBlit(data->dfbSurface, dfbSurface, 0, &destRect);
+ data->w = size.width();
+ data->h = size.height();
+ data->is_null = (data->w <= 0 || data->h <= 0);
+
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ data->dfbSurface->ReleaseSource(data->dfbSurface);
+#endif
+ return QPixmap(data);
+}
+
+QImage QDirectFBPixmapData::toImage() const
+{
+ if (!dfbSurface)
+ return QImage();
+
+#if 0
+ // In later versions of DirectFB one can set a flag to tell
+ // DirectFB not to move the surface to videomemory. When that
+ // happens we can use this (hopefully faster) codepath
+#ifndef QT_NO_DIRECTFB_PREALLOCATED
+ QImage ret(w, h, QDirectFBScreen::getImageFormat(dfbSurface));
+ if (IDirectFBSurface *imgSurface = screen->createDFBSurface(ret, QDirectFBScreen::DontTrackSurface)) {
+ if (hasAlphaChannel()) {
+ imgSurface->SetBlittingFlags(imgSurface, DSBLIT_BLEND_ALPHACHANNEL);
+ imgSurface->Clear(imgSurface, 0, 0, 0, 0);
+ } else {
+ imgSurface->SetBlittingFlags(imgSurface, DSBLIT_NOFX);
+ }
+ imgSurface->Blit(imgSurface, dfbSurface, 0, 0, 0);
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ imgSurface->ReleaseSource(imgSurface);
+#endif
+ imgSurface->Release(imgSurface);
+ return ret;
+ }
+#endif
+#endif
+
+ QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this);
+ const QImage *img = that->buffer();
+ return img->copy();
+}
+
+/* This is QPixmapData::paintEngine(), not QPaintDevice::paintEngine() */
+
+QPaintEngine *QDirectFBPixmapData::paintEngine() const
+{
+ if (!engine) {
+ // QDirectFBPixmapData is also a QCustomRasterPaintDevice, so pass
+ // that to the paint engine:
+ QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this);
+ that->engine = new QDirectFBPaintEngine(that);
+ }
+ return engine;
+}
+
+QImage *QDirectFBPixmapData::buffer()
+{
+ if (!lockFlgs) {
+ lockSurface(DSLF_READ|DSLF_WRITE);
+ }
+ Q_ASSERT(lockFlgs);
+ Q_ASSERT(!lockedImage.isNull());
+ return &lockedImage;
+}
+
+
+bool QDirectFBPixmapData::scroll(int dx, int dy, const QRect &rect)
+{
+ if (!dfbSurface) {
+ return false;
+ }
+ unlockSurface();
+ DFBResult result = dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBPixmapData::scroll", result);
+ return false;
+ }
+ result = dfbSurface->SetPorterDuff(dfbSurface, DSPD_NONE);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBPixmapData::scroll", result);
+ return false;
+ }
+
+ const DFBRectangle source = { rect.x(), rect.y(), rect.width(), rect.height() };
+ result = dfbSurface->Blit(dfbSurface, dfbSurface, &source, source.x + dx, source.y + dy);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBPixmapData::scroll", result);
+ return false;
+ }
+
+ return true;
+}
+
+void QDirectFBPixmapData::invalidate()
+{
+ if (dfbSurface) {
+ screen->releaseDFBSurface(dfbSurface);
+ dfbSurface = 0;
+ }
+ setSerialNumber(0);
+ alpha = false;
+ d = w = h = 0;
+ is_null = true;
+ imageFormat = QImage::Format_Invalid;
+}
+
+Q_GUI_EXPORT IDirectFBSurface *qt_directfb_surface_for_pixmap(const QPixmap &pixmap)
+{
+ const QPixmapData *data = pixmap.pixmapData();
+ if (!data || data->classId() != QPixmapData::DirectFBClass)
+ return 0;
+ const QDirectFBPixmapData *dfbData = static_cast<const QDirectFBPixmapData*>(data);
+ return dfbData->directFBSurface();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QWS_DIRECTFB
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h
new file mode 100644
index 0000000000..f8e3fa1d84
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDIRECTFBPIXMAP_H
+#define QDIRECTFBPIXMAP_H
+
+#include <qglobal.h>
+
+#ifndef QT_NO_QWS_DIRECTFB
+
+#include <QtGui/private/qpixmapdata_p.h>
+#include <QtGui/private/qpaintengine_raster_p.h>
+#include "qdirectfbpaintdevice.h"
+#include <directfb.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QDirectFBPaintEngine;
+
+class QDirectFBPixmapData : public QPixmapData, public QDirectFBPaintDevice
+{
+public:
+ QDirectFBPixmapData(QDirectFBScreen *screen, PixelType pixelType);
+ ~QDirectFBPixmapData();
+
+ // Re-implemented from QPixmapData:
+ virtual void resize(int width, int height);
+ virtual void fromImage(const QImage &image, Qt::ImageConversionFlags flags);
+#ifdef QT_DIRECTFB_IMAGEPROVIDER
+ virtual bool fromFile(const QString &filename, const char *format,
+ Qt::ImageConversionFlags flags);
+ virtual bool fromData(const uchar *buffer, uint len, const char *format,
+ Qt::ImageConversionFlags flags);
+#endif
+ virtual void copy(const QPixmapData *data, const QRect &rect);
+ virtual void fill(const QColor &color);
+ virtual QPixmap transformed(const QTransform &matrix,
+ Qt::TransformationMode mode) const;
+ virtual QImage toImage() const;
+ virtual QPaintEngine *paintEngine() const;
+ virtual QImage *buffer();
+ virtual bool scroll(int dx, int dy, const QRect &rect);
+ // Pure virtual in QPixmapData, so re-implement here and delegate to QDirectFBPaintDevice
+ virtual int metric(QPaintDevice::PaintDeviceMetric m) const { return QDirectFBPaintDevice::metric(m); }
+
+ inline QImage::Format pixelFormat() const { return imageFormat; }
+ inline bool hasAlphaChannel() const { return alpha; }
+ static bool hasAlphaChannel(const QImage &img, Qt::ImageConversionFlags flags = Qt::AutoColor);
+private:
+#ifdef QT_DIRECTFB_IMAGEPROVIDER
+ bool fromDataBufferDescription(const DFBDataBufferDescription &dataBuffer);
+#endif
+ void invalidate();
+ bool alpha;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_QWS_DIRECTFB
+
+#endif // QDIRECTFBPIXMAP_H
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp
new file mode 100644
index 0000000000..ff15078ee4
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp
@@ -0,0 +1,1819 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdirectfbscreen.h"
+#include "qdirectfbwindowsurface.h"
+#include "qdirectfbpixmap.h"
+#include "qdirectfbmouse.h"
+#include "qdirectfbkeyboard.h"
+#include <QtGui/qwsdisplay_qws.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qwindowsystem_qws.h>
+#include <QtGui/private/qgraphicssystem_qws_p.h>
+#include <QtGui/private/qwssignalhandler_p.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qrect.h>
+
+#ifndef QT_NO_QWS_DIRECTFB
+
+QT_BEGIN_NAMESPACE
+
+class QDirectFBScreenPrivate : public QObject, public QWSGraphicsSystem
+{
+ Q_OBJECT
+public:
+ QDirectFBScreenPrivate(QDirectFBScreen *qptr);
+ ~QDirectFBScreenPrivate();
+
+ void setFlipFlags(const QStringList &args);
+ QPixmapData *createPixmapData(QPixmapData::PixelType type) const;
+public slots:
+#ifdef QT_DIRECTFB_WM
+ void onWindowEvent(QWSWindow *window, QWSServer::WindowEvent event);
+#endif
+public:
+ IDirectFB *dfb;
+ DFBSurfaceFlipFlags flipFlags;
+ QDirectFBScreen::DirectFBFlags directFBFlags;
+ QImage::Format alphaPixmapFormat;
+ IDirectFBScreen *dfbScreen;
+#ifdef QT_NO_DIRECTFB_WM
+ IDirectFBSurface *primarySurface;
+ QColor backgroundColor;
+#endif
+#ifndef QT_NO_DIRECTFB_LAYER
+ IDirectFBDisplayLayer *dfbLayer;
+#endif
+ QSet<IDirectFBSurface*> allocatedSurfaces;
+
+#ifndef QT_NO_DIRECTFB_MOUSE
+ QDirectFBMouseHandler *mouse;
+#endif
+#ifndef QT_NO_DIRECTFB_KEYBOARD
+ QDirectFBKeyboardHandler *keyboard;
+#endif
+#if defined QT_DIRECTFB_IMAGEPROVIDER && defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE
+ IDirectFBImageProvider *imageProvider;
+#endif
+ IDirectFBSurface *cursorSurface;
+ qint64 cursorImageKey;
+
+ QDirectFBScreen *q;
+ static QDirectFBScreen *instance;
+};
+
+QDirectFBScreen *QDirectFBScreenPrivate::instance = 0;
+
+QDirectFBScreenPrivate::QDirectFBScreenPrivate(QDirectFBScreen *qptr)
+ : QWSGraphicsSystem(qptr), dfb(0), flipFlags(DSFLIP_NONE),
+ directFBFlags(QDirectFBScreen::NoFlags), alphaPixmapFormat(QImage::Format_Invalid),
+ dfbScreen(0)
+#ifdef QT_NO_DIRECTFB_WM
+ , primarySurface(0)
+#endif
+#ifndef QT_NO_DIRECTFB_LAYER
+ , dfbLayer(0)
+#endif
+#ifndef QT_NO_DIRECTFB_MOUSE
+ , mouse(0)
+#endif
+#ifndef QT_NO_DIRECTFB_KEYBOARD
+ , keyboard(0)
+#endif
+#if defined QT_DIRECTFB_IMAGEPROVIDER && defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE
+ , imageProvider(0)
+#endif
+ , cursorSurface(0)
+ , cursorImageKey(0)
+ , q(qptr)
+{
+#ifndef QT_NO_QWS_SIGNALHANDLER
+ QWSSignalHandler::instance()->addObject(this);
+#endif
+#ifdef QT_DIRECTFB_WM
+ connect(QWSServer::instance(), SIGNAL(windowEvent(QWSWindow*,QWSServer::WindowEvent)),
+ this, SLOT(onWindowEvent(QWSWindow*,QWSServer::WindowEvent)));
+#endif
+}
+
+QDirectFBScreenPrivate::~QDirectFBScreenPrivate()
+{
+#ifndef QT_NO_DIRECTFB_MOUSE
+ delete mouse;
+#endif
+#ifndef QT_NO_DIRECTFB_KEYBOARD
+ delete keyboard;
+#endif
+#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE
+ if (imageProvider)
+ imageProvider->Release(imageProvider);
+#endif
+
+ for (QSet<IDirectFBSurface*>::const_iterator it = allocatedSurfaces.begin(); it != allocatedSurfaces.end(); ++it) {
+ (*it)->Release(*it);
+ }
+
+#ifdef QT_NO_DIRECTFB_WM
+ if (primarySurface)
+ primarySurface->Release(primarySurface);
+#endif
+
+#ifndef QT_NO_DIRECTFB_LAYER
+ if (dfbLayer)
+ dfbLayer->Release(dfbLayer);
+#endif
+
+ if (dfbScreen)
+ dfbScreen->Release(dfbScreen);
+
+ if (dfb)
+ dfb->Release(dfb);
+}
+
+IDirectFBSurface *QDirectFBScreen::createDFBSurface(const QImage &image, QImage::Format format, SurfaceCreationOptions options, DFBResult *resultPtr)
+{
+ if (image.isNull()) // assert?
+ return 0;
+
+ if (QDirectFBScreen::getSurfacePixelFormat(format) == DSPF_UNKNOWN) {
+ format = QDirectFBPixmapData::hasAlphaChannel(image) ? d_ptr->alphaPixmapFormat : pixelFormat();
+ }
+ if (image.format() != format) {
+ return createDFBSurface(image.convertToFormat(format), format, options | NoPreallocated, resultPtr);
+ }
+
+ DFBSurfaceDescription description;
+ memset(&description, 0, sizeof(DFBSurfaceDescription));
+ description.width = image.width();
+ description.height = image.height();
+ description.flags = DSDESC_WIDTH|DSDESC_HEIGHT|DSDESC_PIXELFORMAT;
+ initSurfaceDescriptionPixelFormat(&description, format);
+ bool doMemCopy = true;
+#ifdef QT_DIRECTFB_PREALLOCATED
+ if (!(options & NoPreallocated)) {
+ doMemCopy = false;
+ description.flags |= DSDESC_PREALLOCATED;
+ description.preallocated[0].data = const_cast<uchar*>(image.bits());
+ description.preallocated[0].pitch = image.bytesPerLine();
+ description.preallocated[1].data = 0;
+ description.preallocated[1].pitch = 0;
+ }
+#endif
+ DFBResult result;
+ IDirectFBSurface *surface = createDFBSurface(description, options, &result);
+ if (resultPtr)
+ *resultPtr = result;
+ if (!surface) {
+ DirectFBError("Couldn't create surface createDFBSurface(QImage, QImage::Format, SurfaceCreationOptions)", result);
+ return 0;
+ }
+ if (doMemCopy) {
+ int bplDFB;
+ uchar *mem = QDirectFBScreen::lockSurface(surface, DSLF_WRITE, &bplDFB);
+ if (mem) {
+ const int height = image.height();
+ const int bplQt = image.bytesPerLine();
+ if (bplQt == bplDFB && bplQt == (image.width() * image.depth() / 8)) {
+ memcpy(mem, image.bits(), image.byteCount());
+ } else {
+ for (int i=0; i<height; ++i) {
+ memcpy(mem, image.scanLine(i), bplQt);
+ mem += bplDFB;
+ }
+ }
+ surface->Unlock(surface);
+ }
+ }
+#ifdef QT_DIRECTFB_PALETTE
+ if (image.colorCount() != 0 && surface)
+ QDirectFBScreen::setSurfaceColorTable(surface, image);
+#endif
+ return surface;
+}
+
+IDirectFBSurface *QDirectFBScreen::copyDFBSurface(IDirectFBSurface *src,
+ QImage::Format format,
+ SurfaceCreationOptions options,
+ DFBResult *result)
+{
+ Q_ASSERT(src);
+ QSize size;
+ src->GetSize(src, &size.rwidth(), &size.rheight());
+ IDirectFBSurface *surface = createDFBSurface(size, format, options, result);
+ DFBSurfaceBlittingFlags flags = QDirectFBScreen::hasAlphaChannel(surface)
+ ? DSBLIT_BLEND_ALPHACHANNEL
+ : DSBLIT_NOFX;
+ if (flags & DSBLIT_BLEND_ALPHACHANNEL)
+ surface->Clear(surface, 0, 0, 0, 0);
+
+ surface->SetBlittingFlags(surface, flags);
+ surface->Blit(surface, src, 0, 0, 0);
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ surface->ReleaseSource(surface);
+#endif
+ return surface;
+}
+
+IDirectFBSurface *QDirectFBScreen::createDFBSurface(const QSize &size,
+ QImage::Format format,
+ SurfaceCreationOptions options,
+ DFBResult *result)
+{
+ DFBSurfaceDescription desc;
+ memset(&desc, 0, sizeof(DFBSurfaceDescription));
+ desc.flags |= DSDESC_WIDTH|DSDESC_HEIGHT;
+ if (!QDirectFBScreen::initSurfaceDescriptionPixelFormat(&desc, format))
+ return 0;
+ desc.width = size.width();
+ desc.height = size.height();
+ return createDFBSurface(desc, options, result);
+}
+
+IDirectFBSurface *QDirectFBScreen::createDFBSurface(DFBSurfaceDescription desc, SurfaceCreationOptions options, DFBResult *resultPtr)
+{
+ DFBResult tmp;
+ DFBResult &result = (resultPtr ? *resultPtr : tmp);
+ result = DFB_OK;
+ IDirectFBSurface *newSurface = 0;
+
+ if (!d_ptr->dfb) {
+ qWarning("QDirectFBScreen::createDFBSurface() - not connected");
+ return 0;
+ }
+
+ if (d_ptr->directFBFlags & VideoOnly
+ && !(desc.flags & DSDESC_PREALLOCATED)
+ && (!(desc.flags & DSDESC_CAPS) || !(desc.caps & DSCAPS_SYSTEMONLY))) {
+ // Add the video only capability. This means the surface will be created in video ram
+ if (!(desc.flags & DSDESC_CAPS)) {
+ desc.caps = DSCAPS_VIDEOONLY;
+ desc.flags |= DSDESC_CAPS;
+ } else {
+ desc.caps |= DSCAPS_VIDEOONLY;
+ }
+ result = d_ptr->dfb->CreateSurface(d_ptr->dfb, &desc, &newSurface);
+ if (result != DFB_OK
+#ifdef QT_NO_DEBUG
+ && (desc.flags & DSDESC_CAPS) && (desc.caps & DSCAPS_PRIMARY)
+#endif
+ ) {
+ qWarning("QDirectFBScreen::createDFBSurface() Failed to create surface in video memory!\n"
+ " Flags %0x Caps %0x width %d height %d pixelformat %0x %d preallocated %p %d\n%s",
+ desc.flags, desc.caps, desc.width, desc.height,
+ desc.pixelformat, DFB_PIXELFORMAT_INDEX(desc.pixelformat),
+ desc.preallocated[0].data, desc.preallocated[0].pitch,
+ DirectFBErrorString(result));
+ }
+ desc.caps &= ~DSCAPS_VIDEOONLY;
+ }
+
+ if (d_ptr->directFBFlags & SystemOnly)
+ desc.caps |= DSCAPS_SYSTEMONLY;
+
+ if (!newSurface)
+ result = d_ptr->dfb->CreateSurface(d_ptr->dfb, &desc, &newSurface);
+
+ if (result != DFB_OK) {
+ qWarning("QDirectFBScreen::createDFBSurface() Failed!\n"
+ " Flags %0x Caps %0x width %d height %d pixelformat %0x %d preallocated %p %d\n%s",
+ desc.flags, desc.caps, desc.width, desc.height,
+ desc.pixelformat, DFB_PIXELFORMAT_INDEX(desc.pixelformat),
+ desc.preallocated[0].data, desc.preallocated[0].pitch,
+ DirectFBErrorString(result));
+ return 0;
+ }
+
+ Q_ASSERT(newSurface);
+
+ if (options & TrackSurface) {
+ d_ptr->allocatedSurfaces.insert(newSurface);
+ }
+
+ return newSurface;
+}
+
+#ifdef QT_DIRECTFB_SUBSURFACE
+IDirectFBSurface *QDirectFBScreen::getSubSurface(IDirectFBSurface *surface,
+ const QRect &rect,
+ SurfaceCreationOptions options,
+ DFBResult *resultPtr)
+{
+ Q_ASSERT(!(options & NoPreallocated));
+ Q_ASSERT(surface);
+ DFBResult res;
+ DFBResult &result = (resultPtr ? *resultPtr : res);
+ IDirectFBSurface *subSurface = 0;
+ if (rect.isNull()) {
+ result = surface->GetSubSurface(surface, 0, &subSurface);
+ } else {
+ const DFBRectangle subRect = { rect.x(), rect.y(), rect.width(), rect.height() };
+ result = surface->GetSubSurface(surface, &subRect, &subSurface);
+ }
+ if (result != DFB_OK) {
+ DirectFBError("Can't get sub surface", result);
+ } else if (options & TrackSurface) {
+ d_ptr->allocatedSurfaces.insert(subSurface);
+ }
+ return subSurface;
+}
+#endif
+
+
+void QDirectFBScreen::releaseDFBSurface(IDirectFBSurface *surface)
+{
+ Q_ASSERT(QDirectFBScreen::instance());
+ Q_ASSERT(surface);
+ surface->Release(surface);
+ if (!d_ptr->allocatedSurfaces.remove(surface))
+ qWarning("QDirectFBScreen::releaseDFBSurface() - %p not in list", surface);
+
+ //qDebug("Released surface at %p. New count = %d", surface, d_ptr->allocatedSurfaces.count());
+}
+
+QDirectFBScreen::DirectFBFlags QDirectFBScreen::directFBFlags() const
+{
+ return d_ptr->directFBFlags;
+}
+
+IDirectFB *QDirectFBScreen::dfb()
+{
+ return d_ptr->dfb;
+}
+
+#ifdef QT_NO_DIRECTFB_WM
+IDirectFBSurface *QDirectFBScreen::primarySurface()
+{
+ return d_ptr->primarySurface;
+}
+#endif
+
+#ifndef QT_NO_DIRECTFB_LAYER
+IDirectFBDisplayLayer *QDirectFBScreen::dfbDisplayLayer()
+{
+ return d_ptr->dfbLayer;
+}
+#endif
+
+DFBSurfacePixelFormat QDirectFBScreen::getSurfacePixelFormat(QImage::Format format)
+{
+ switch (format) {
+#ifndef QT_NO_DIRECTFB_PALETTE
+ case QImage::Format_Indexed8:
+ return DSPF_LUT8;
+#endif
+ case QImage::Format_RGB888:
+ return DSPF_RGB24;
+ case QImage::Format_ARGB4444_Premultiplied:
+ return DSPF_ARGB4444;
+#if (Q_DIRECTFB_VERSION >= 0x010100)
+ case QImage::Format_RGB444:
+ return DSPF_RGB444;
+ case QImage::Format_RGB555:
+ return DSPF_RGB555;
+#endif
+ case QImage::Format_RGB16:
+ return DSPF_RGB16;
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ case QImage::Format_ARGB6666_Premultiplied:
+ return DSPF_ARGB6666;
+ case QImage::Format_RGB666:
+ return DSPF_RGB18;
+#endif
+ case QImage::Format_RGB32:
+ return DSPF_RGB32;
+ case QImage::Format_ARGB32_Premultiplied:
+ case QImage::Format_ARGB32:
+ return DSPF_ARGB;
+ default:
+ return DSPF_UNKNOWN;
+ };
+}
+
+QImage::Format QDirectFBScreen::getImageFormat(IDirectFBSurface *surface)
+{
+ DFBSurfacePixelFormat format;
+ surface->GetPixelFormat(surface, &format);
+
+ switch (format) {
+ case DSPF_LUT8:
+ return QImage::Format_Indexed8;
+ case DSPF_RGB24:
+ return QImage::Format_RGB888;
+ case DSPF_ARGB4444:
+ return QImage::Format_ARGB4444_Premultiplied;
+#if (Q_DIRECTFB_VERSION >= 0x010100)
+ case DSPF_RGB444:
+ return QImage::Format_RGB444;
+ case DSPF_RGB555:
+#endif
+ case DSPF_ARGB1555:
+ return QImage::Format_RGB555;
+ case DSPF_RGB16:
+ return QImage::Format_RGB16;
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ case DSPF_ARGB6666:
+ return QImage::Format_ARGB6666_Premultiplied;
+ case DSPF_RGB18:
+ return QImage::Format_RGB666;
+#endif
+ case DSPF_RGB32:
+ return QImage::Format_RGB32;
+ case DSPF_ARGB: {
+ DFBSurfaceCapabilities caps;
+ const DFBResult result = surface->GetCapabilities(surface, &caps);
+ Q_ASSERT(result == DFB_OK);
+ Q_UNUSED(result);
+ return (caps & DSCAPS_PREMULTIPLIED
+ ? QImage::Format_ARGB32_Premultiplied
+ : QImage::Format_ARGB32); }
+ default:
+ break;
+ }
+ return QImage::Format_Invalid;
+}
+
+DFBSurfaceDescription QDirectFBScreen::getSurfaceDescription(const uint *buffer,
+ int length)
+{
+ DFBSurfaceDescription description;
+ memset(&description, 0, sizeof(DFBSurfaceDescription));
+
+ description.flags = DSDESC_CAPS|DSDESC_WIDTH|DSDESC_HEIGHT|DSDESC_PIXELFORMAT|DSDESC_PREALLOCATED;
+ description.caps = DSCAPS_PREMULTIPLIED;
+ description.width = length;
+ description.height = 1;
+ description.pixelformat = DSPF_ARGB;
+ description.preallocated[0].data = (void*)buffer;
+ description.preallocated[0].pitch = length * sizeof(uint);
+ description.preallocated[1].data = 0;
+ description.preallocated[1].pitch = 0;
+ return description;
+}
+
+#ifndef QT_NO_DIRECTFB_PALETTE
+void QDirectFBScreen::setSurfaceColorTable(IDirectFBSurface *surface,
+ const QImage &image)
+{
+ if (!surface)
+ return;
+
+ const int numColors = image.colorCount();
+ if (numColors == 0)
+ return;
+
+ QVarLengthArray<DFBColor, 256> colors(numColors);
+ for (int i = 0; i < numColors; ++i) {
+ QRgb c = image.color(i);
+ colors[i].a = qAlpha(c);
+ colors[i].r = qRed(c);
+ colors[i].g = qGreen(c);
+ colors[i].b = qBlue(c);
+ }
+
+ IDirectFBPalette *palette;
+ DFBResult result;
+ result = surface->GetPalette(surface, &palette);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreen::setSurfaceColorTable GetPalette",
+ result);
+ return;
+ }
+ result = palette->SetEntries(palette, colors.data(), numColors, 0);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreen::setSurfaceColorTable SetEntries",
+ result);
+ }
+ palette->Release(palette);
+}
+
+#endif // QT_NO_DIRECTFB_PALETTE
+
+#if defined QT_DIRECTFB_CURSOR
+class Q_GUI_EXPORT QDirectFBScreenCursor : public QScreenCursor
+{
+public:
+ QDirectFBScreenCursor();
+ virtual void set(const QImage &image, int hotx, int hoty);
+ virtual void move(int x, int y);
+ virtual void show();
+ virtual void hide();
+private:
+#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR
+ ~QDirectFBScreenCursor();
+ bool createWindow();
+ IDirectFBWindow *window;
+#endif
+ IDirectFBDisplayLayer *layer;
+};
+
+QDirectFBScreenCursor::QDirectFBScreenCursor()
+{
+ IDirectFB *fb = QDirectFBScreen::instance()->dfb();
+ if (!fb)
+ qFatal("QDirectFBScreenCursor: DirectFB not initialized");
+
+ layer = QDirectFBScreen::instance()->dfbDisplayLayer();
+ Q_ASSERT(layer);
+
+ enable = false;
+ hwaccel = true;
+ supportsAlpha = true;
+#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR
+ window = 0;
+ DFBResult result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::hide: "
+ "Unable to set cooperative level", result);
+ }
+ result = layer->SetCursorOpacity(layer, 0);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::hide: "
+ "Unable to set cursor opacity", result);
+ }
+
+ result = layer->SetCooperativeLevel(layer, DLSCL_SHARED);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::hide: "
+ "Unable to set cooperative level", result);
+ }
+#endif
+}
+
+#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR
+QDirectFBScreenCursor::~QDirectFBScreenCursor()
+{
+ if (window) {
+ window->Release(window);
+ window = 0;
+ }
+}
+
+bool QDirectFBScreenCursor::createWindow()
+{
+ Q_ASSERT(!window);
+ Q_ASSERT(!cursor.isNull());
+ DFBWindowDescription description;
+ memset(&description, 0, sizeof(DFBWindowDescription));
+ description.flags = DWDESC_POSX|DWDESC_POSY|DWDESC_WIDTH|DWDESC_HEIGHT|DWDESC_CAPS|DWDESC_PIXELFORMAT|DWDESC_SURFACE_CAPS;
+ description.width = cursor.width();
+ description.height = cursor.height();
+ description.posx = pos.x() - hotspot.x();
+ description.posy = pos.y() - hotspot.y();
+#if (Q_DIRECTFB_VERSION >= 0x010100)
+ description.flags |= DWDESC_OPTIONS;
+ description.options = DWOP_GHOST|DWOP_ALPHACHANNEL;
+#endif
+ description.caps = DWCAPS_NODECORATION|DWCAPS_DOUBLEBUFFER;
+ const QImage::Format format = QDirectFBScreen::instance()->alphaPixmapFormat();
+ description.pixelformat = QDirectFBScreen::getSurfacePixelFormat(format);
+ if (QDirectFBScreen::isPremultiplied(format))
+ description.surface_caps = DSCAPS_PREMULTIPLIED;
+
+ DFBResult result = layer->CreateWindow(layer, &description, &window);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::createWindow: Unable to create window", result);
+ return false;
+ }
+ result = window->SetOpacity(window, 255);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::createWindow: Unable to set opacity ", result);
+ return false;
+ }
+
+ result = window->SetStackingClass(window, DWSC_UPPER);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::createWindow: Unable to set stacking class ", result);
+ return false;
+ }
+
+ result = window->RaiseToTop(window);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::createWindow: Unable to raise window ", result);
+ return false;
+ }
+
+ return true;
+}
+#endif
+
+void QDirectFBScreenCursor::move(int x, int y)
+{
+ pos = QPoint(x, y);
+#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR
+ if (window) {
+ const QPoint p = pos - hotspot;
+ DFBResult result = window->MoveTo(window, p.x(), p.y());
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::move: Unable to move window", result);
+ }
+ }
+#else
+ layer->WarpCursor(layer, x, y);
+#endif
+}
+
+void QDirectFBScreenCursor::hide()
+{
+ if (enable) {
+ enable = false;
+ DFBResult result;
+#ifndef QT_DIRECTFB_WINDOW_AS_CURSOR
+ result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::hide: "
+ "Unable to set cooperative level", result);
+ }
+ result = layer->SetCursorOpacity(layer, 0);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::hide: "
+ "Unable to set cursor opacity", result);
+ }
+ result = layer->SetCooperativeLevel(layer, DLSCL_SHARED);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::hide: "
+ "Unable to set cooperative level", result);
+ }
+#else
+ if (window) {
+ result = window->SetOpacity(window, 0);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::hide: "
+ "Unable to set window opacity", result);
+ }
+ }
+#endif
+ }
+}
+
+void QDirectFBScreenCursor::show()
+{
+ if (!enable) {
+ enable = true;
+ DFBResult result;
+ result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::show: "
+ "Unable to set cooperative level", result);
+ }
+ result = layer->SetCursorOpacity(layer,
+#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR
+ 0
+#else
+ 255
+#endif
+ );
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::show: "
+ "Unable to set cursor shape", result);
+ }
+ result = layer->SetCooperativeLevel(layer, DLSCL_SHARED);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::show: "
+ "Unable to set cooperative level", result);
+ }
+#ifdef QT_DIRECTFB_WINDOW_AS_CURSOR
+ if (window) {
+ DFBResult result = window->SetOpacity(window, 255);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::show: "
+ "Unable to set window opacity", result);
+ }
+ }
+#endif
+ }
+}
+
+void QDirectFBScreenCursor::set(const QImage &image, int hotx, int hoty)
+{
+ QDirectFBScreen *screen = QDirectFBScreen::instance();
+ if (!screen)
+ return;
+
+ if (image.isNull()) {
+ cursor = QImage();
+ hide();
+ } else {
+ cursor = image.convertToFormat(screen->alphaPixmapFormat());
+ size = cursor.size();
+ hotspot = QPoint(hotx, hoty);
+ DFBResult result = DFB_OK;
+ IDirectFBSurface *surface = screen->createDFBSurface(cursor, screen->alphaPixmapFormat(),
+ QDirectFBScreen::DontTrackSurface, &result);
+ if (!surface) {
+ DirectFBError("QDirectFBScreenCursor::set: Unable to create surface", result);
+ return;
+ }
+#ifndef QT_DIRECTFB_WINDOW_AS_CURSOR
+ result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::show: "
+ "Unable to set cooperative level", result);
+ }
+ result = layer->SetCursorShape(layer, surface, hotx, hoty);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::show: "
+ "Unable to set cursor shape", result);
+ }
+ result = layer->SetCooperativeLevel(layer, DLSCL_SHARED);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::show: "
+ "Unable to set cooperative level", result);
+ }
+#else
+ if (window || createWindow()) {
+ QSize windowSize;
+ result = window->GetSize(window, &windowSize.rwidth(), &windowSize.rheight());
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::set: "
+ "Unable to get window size", result);
+ }
+ result = window->Resize(window, size.width(), size.height());
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::set: Unable to resize window", result);
+ }
+
+ IDirectFBSurface *windowSurface;
+ result = window->GetSurface(window, &windowSurface);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::set: Unable to get window surface", result);
+ } else {
+ result = windowSurface->Clear(windowSurface, 0, 0, 0, 0);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::set: Unable to clear surface", result);
+ }
+
+ result = windowSurface->Blit(windowSurface, surface, 0, 0, 0);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::set: Unable to blit to surface", result);
+ }
+ }
+ result = windowSurface->Flip(windowSurface, 0, DSFLIP_NONE);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::set: Unable to flip window", result);
+ }
+
+ windowSurface->Release(windowSurface);
+ }
+#endif
+ surface->Release(surface);
+ show();
+ }
+
+}
+#endif // QT_DIRECTFB_CURSOR
+
+QDirectFBScreen::QDirectFBScreen(int display_id)
+ : QScreen(display_id, DirectFBClass), d_ptr(new QDirectFBScreenPrivate(this))
+{
+ QDirectFBScreenPrivate::instance = this;
+}
+
+QDirectFBScreen::~QDirectFBScreen()
+{
+ if (QDirectFBScreenPrivate::instance == this)
+ QDirectFBScreenPrivate::instance = 0;
+ delete d_ptr;
+}
+
+QDirectFBScreen *QDirectFBScreen::instance()
+{
+ return QDirectFBScreenPrivate::instance;
+}
+
+int QDirectFBScreen::depth(DFBSurfacePixelFormat format)
+{
+ switch (format) {
+ case DSPF_A1:
+ return 1;
+ case DSPF_A8:
+ case DSPF_RGB332:
+ case DSPF_LUT8:
+ case DSPF_ALUT44:
+ return 8;
+ case DSPF_I420:
+ case DSPF_YV12:
+ case DSPF_NV12:
+ case DSPF_NV21:
+#if (Q_DIRECTFB_VERSION >= 0x010100)
+ case DSPF_RGB444:
+#endif
+ return 12;
+#if (Q_DIRECTFB_VERSION >= 0x010100)
+ case DSPF_RGB555:
+ return 15;
+#endif
+ case DSPF_ARGB1555:
+ case DSPF_RGB16:
+ case DSPF_YUY2:
+ case DSPF_UYVY:
+ case DSPF_NV16:
+ case DSPF_ARGB2554:
+ case DSPF_ARGB4444:
+ return 16;
+ case DSPF_RGB24:
+ return 24;
+ case DSPF_RGB32:
+ case DSPF_ARGB:
+ case DSPF_AiRGB:
+ return 32;
+ case DSPF_UNKNOWN:
+ default:
+ return 0;
+ };
+ return 0;
+}
+
+int QDirectFBScreen::depth(QImage::Format format)
+{
+ int depth = 0;
+ switch(format) {
+ case QImage::Format_Invalid:
+ case QImage::NImageFormats:
+ Q_ASSERT(false);
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ depth = 1;
+ break;
+ case QImage::Format_Indexed8:
+ depth = 8;
+ break;
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ depth = 32;
+ break;
+ case QImage::Format_RGB555:
+ case QImage::Format_RGB16:
+ case QImage::Format_RGB444:
+ case QImage::Format_ARGB4444_Premultiplied:
+ depth = 16;
+ break;
+ case QImage::Format_RGB666:
+ case QImage::Format_ARGB6666_Premultiplied:
+ case QImage::Format_ARGB8565_Premultiplied:
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_RGB888:
+ depth = 24;
+ break;
+ }
+ return depth;
+}
+
+void QDirectFBScreenPrivate::setFlipFlags(const QStringList &args)
+{
+ QRegExp flipRegexp(QLatin1String("^flip=([\\w,]*)$"));
+ int index = args.indexOf(flipRegexp);
+ if (index >= 0) {
+ const QStringList flips = flipRegexp.cap(1).split(QLatin1Char(','),
+ QString::SkipEmptyParts);
+ flipFlags = DSFLIP_NONE;
+ foreach(const QString &flip, flips) {
+ if (flip == QLatin1String("wait"))
+ flipFlags |= DSFLIP_WAIT;
+ else if (flip == QLatin1String("blit"))
+ flipFlags |= DSFLIP_BLIT;
+ else if (flip == QLatin1String("onsync"))
+ flipFlags |= DSFLIP_ONSYNC;
+ else if (flip == QLatin1String("pipeline"))
+ flipFlags |= DSFLIP_PIPELINE;
+ else
+ qWarning("QDirectFBScreen: Unknown flip argument: %s",
+ qPrintable(flip));
+ }
+ } else {
+ flipFlags = DSFLIP_BLIT|DSFLIP_ONSYNC;
+ }
+}
+
+#ifdef QT_DIRECTFB_WM
+void QDirectFBScreenPrivate::onWindowEvent(QWSWindow *window, QWSServer::WindowEvent event)
+{
+ if (event == QWSServer::Raise) {
+ QWSWindowSurface *windowSurface = window->windowSurface();
+ if (windowSurface && windowSurface->key() == QLatin1String("directfb")) {
+ static_cast<QDirectFBWindowSurface*>(windowSurface)->raise();
+ }
+ }
+}
+#endif
+
+QPixmapData *QDirectFBScreenPrivate::createPixmapData(QPixmapData::PixelType type) const
+{
+ if (type == QPixmapData::BitmapType)
+ return QWSGraphicsSystem::createPixmapData(type);
+
+ return new QDirectFBPixmapData(q, type);
+}
+
+#if (Q_DIRECTFB_VERSION >= 0x000923)
+#ifdef QT_NO_DEBUG
+struct FlagDescription;
+static const FlagDescription *accelerationDescriptions = 0;
+static const FlagDescription *blitDescriptions = 0;
+static const FlagDescription *drawDescriptions = 0;
+#else
+struct FlagDescription {
+ const char *name;
+ uint flag;
+};
+
+static const FlagDescription accelerationDescriptions[] = {
+ { "DFXL_NONE", DFXL_NONE },
+ { "DFXL_FILLRECTANGLE", DFXL_FILLRECTANGLE },
+ { "DFXL_DRAWRECTANGLE", DFXL_DRAWRECTANGLE },
+ { "DFXL_DRAWLINE", DFXL_DRAWLINE },
+ { "DFXL_FILLTRIANGLE", DFXL_FILLTRIANGLE },
+ { "DFXL_BLIT", DFXL_BLIT },
+ { "DFXL_STRETCHBLIT", DFXL_STRETCHBLIT },
+ { "DFXL_TEXTRIANGLES", DFXL_TEXTRIANGLES },
+ { "DFXL_DRAWSTRING", DFXL_DRAWSTRING },
+ { 0, 0 }
+};
+
+static const FlagDescription blitDescriptions[] = {
+ { "DSBLIT_NOFX", DSBLIT_NOFX },
+ { "DSBLIT_BLEND_ALPHACHANNEL", DSBLIT_BLEND_ALPHACHANNEL },
+ { "DSBLIT_BLEND_COLORALPHA", DSBLIT_BLEND_COLORALPHA },
+ { "DSBLIT_COLORIZE", DSBLIT_COLORIZE },
+ { "DSBLIT_SRC_COLORKEY", DSBLIT_SRC_COLORKEY },
+ { "DSBLIT_DST_COLORKEY", DSBLIT_DST_COLORKEY },
+ { "DSBLIT_SRC_PREMULTIPLY", DSBLIT_SRC_PREMULTIPLY },
+ { "DSBLIT_DST_PREMULTIPLY", DSBLIT_DST_PREMULTIPLY },
+ { "DSBLIT_DEMULTIPLY", DSBLIT_DEMULTIPLY },
+ { "DSBLIT_DEINTERLACE", DSBLIT_DEINTERLACE },
+#if (Q_DIRECTFB_VERSION >= 0x000923)
+ { "DSBLIT_SRC_PREMULTCOLOR", DSBLIT_SRC_PREMULTCOLOR },
+ { "DSBLIT_XOR", DSBLIT_XOR },
+#endif
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ { "DSBLIT_INDEX_TRANSLATION", DSBLIT_INDEX_TRANSLATION },
+#endif
+ { 0, 0 }
+};
+
+static const FlagDescription drawDescriptions[] = {
+ { "DSDRAW_NOFX", DSDRAW_NOFX },
+ { "DSDRAW_BLEND", DSDRAW_BLEND },
+ { "DSDRAW_DST_COLORKEY", DSDRAW_DST_COLORKEY },
+ { "DSDRAW_SRC_PREMULTIPLY", DSDRAW_SRC_PREMULTIPLY },
+ { "DSDRAW_DST_PREMULTIPLY", DSDRAW_DST_PREMULTIPLY },
+ { "DSDRAW_DEMULTIPLY", DSDRAW_DEMULTIPLY },
+ { "DSDRAW_XOR", DSDRAW_XOR },
+ { 0, 0 }
+};
+#endif
+
+static const QByteArray flagDescriptions(uint mask, const FlagDescription *flags)
+{
+#ifdef QT_NO_DEBUG
+ Q_UNUSED(mask);
+ Q_UNUSED(flags);
+ return QByteArray("");
+#else
+ if (!mask)
+ return flags[0].name;
+
+ QStringList list;
+ for (int i=1; flags[i].name; ++i) {
+ if (mask & flags[i].flag) {
+ list.append(QString::fromLatin1(flags[i].name));
+ }
+ }
+ Q_ASSERT(!list.isEmpty());
+ return (QLatin1Char(' ') + list.join(QLatin1String("|"))).toLatin1();
+#endif
+}
+static void printDirectFBInfo(IDirectFB *fb, IDirectFBSurface *primarySurface)
+{
+ DFBResult result;
+ DFBGraphicsDeviceDescription dev;
+
+ result = fb->GetDeviceDescription(fb, &dev);
+ if (result != DFB_OK) {
+ DirectFBError("Error reading graphics device description", result);
+ return;
+ }
+
+ DFBSurfacePixelFormat pixelFormat;
+ primarySurface->GetPixelFormat(primarySurface, &pixelFormat);
+
+ qDebug("Device: %s (%s), Driver: %s v%i.%i (%s) Pixelformat: %d (%d)\n"
+ "acceleration: 0x%x%s\nblit: 0x%x%s\ndraw: 0x%0x%s\nvideo: %iKB\n",
+ dev.name, dev.vendor, dev.driver.name, dev.driver.major,
+ dev.driver.minor, dev.driver.vendor, DFB_PIXELFORMAT_INDEX(pixelFormat),
+ QDirectFBScreen::getImageFormat(primarySurface), dev.acceleration_mask,
+ flagDescriptions(dev.acceleration_mask, accelerationDescriptions).constData(),
+ dev.blitting_flags, flagDescriptions(dev.blitting_flags, blitDescriptions).constData(),
+ dev.drawing_flags, flagDescriptions(dev.drawing_flags, drawDescriptions).constData(),
+ (dev.video_memory >> 10));
+}
+#endif
+
+static inline bool setIntOption(const QStringList &arguments, const QString &variable, int *value)
+{
+ Q_ASSERT(value);
+ QRegExp rx(QString::fromLatin1("%1=?(\\d+)").arg(variable));
+ rx.setCaseSensitivity(Qt::CaseInsensitive);
+ if (arguments.indexOf(rx) != -1) {
+ *value = rx.cap(1).toInt();
+ return true;
+ }
+ return false;
+}
+
+static inline QColor colorFromName(const QString &name)
+{
+ QRegExp rx(QLatin1String("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])"));
+ rx.setCaseSensitivity(Qt::CaseInsensitive);
+ if (rx.exactMatch(name)) {
+ Q_ASSERT(rx.captureCount() == 4);
+ int ints[4];
+ int i;
+ for (i=0; i<4; ++i) {
+ bool ok;
+ ints[i] = rx.cap(i + 1).toUInt(&ok, 16);
+ if (!ok || ints[i] > 255)
+ break;
+ }
+ if (i == 4)
+ return QColor(ints[0], ints[1], ints[2], ints[3]);
+ }
+ return QColor(name);
+}
+
+bool QDirectFBScreen::connect(const QString &displaySpec)
+{
+ DFBResult result = DFB_OK;
+
+ { // pass command line arguments to DirectFB
+ const QStringList args = QCoreApplication::arguments();
+ int argc = args.size();
+ char **argv = new char*[argc];
+
+ for (int i = 0; i < argc; ++i)
+ argv[i] = qstrdup(args.at(i).toLocal8Bit().constData());
+
+ result = DirectFBInit(&argc, &argv);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreen: error initializing DirectFB",
+ result);
+ }
+ delete[] argv;
+ }
+
+ const QStringList displayArgs = displaySpec.split(QLatin1Char(':'),
+ QString::SkipEmptyParts);
+
+ d_ptr->setFlipFlags(displayArgs);
+
+ result = DirectFBCreate(&d_ptr->dfb);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreen: error creating DirectFB interface",
+ result);
+ return false;
+ }
+
+ if (displayArgs.contains(QLatin1String("videoonly"), Qt::CaseInsensitive))
+ d_ptr->directFBFlags |= VideoOnly;
+
+ if (displayArgs.contains(QLatin1String("systemonly"), Qt::CaseInsensitive)) {
+ if (d_ptr->directFBFlags & VideoOnly) {
+ qWarning("QDirectFBScreen: error. videoonly and systemonly are mutually exclusive");
+ } else {
+ d_ptr->directFBFlags |= SystemOnly;
+ }
+ }
+
+ if (displayArgs.contains(QLatin1String("boundingrectflip"), Qt::CaseInsensitive)) {
+ d_ptr->directFBFlags |= BoundingRectFlip;
+ } else if (displayArgs.contains(QLatin1String("nopartialflip"), Qt::CaseInsensitive)) {
+ d_ptr->directFBFlags |= NoPartialFlip;
+ }
+
+#ifdef QT_DIRECTFB_IMAGECACHE
+ int imageCacheSize = 4 * 1024 * 1024; // 4 MB
+ setIntOption(displayArgs, QLatin1String("imagecachesize"), &imageCacheSize);
+ QDirectFBPaintEngine::initImageCache(imageCacheSize);
+#endif
+
+#ifndef QT_NO_DIRECTFB_WM
+ if (displayArgs.contains(QLatin1String("fullscreen")))
+#endif
+ d_ptr->dfb->SetCooperativeLevel(d_ptr->dfb, DFSCL_FULLSCREEN);
+
+ const bool forcePremultiplied = displayArgs.contains(QLatin1String("forcepremultiplied"), Qt::CaseInsensitive);
+
+ DFBSurfaceDescription description;
+ memset(&description, 0, sizeof(DFBSurfaceDescription));
+ IDirectFBSurface *surface;
+
+#ifdef QT_NO_DIRECTFB_WM
+ description.flags = DSDESC_CAPS;
+ if (::setIntOption(displayArgs, QLatin1String("width"), &description.width))
+ description.flags |= DSDESC_WIDTH;
+ if (::setIntOption(displayArgs, QLatin1String("height"), &description.height))
+ description.flags |= DSDESC_HEIGHT;
+
+ description.caps = DSCAPS_PRIMARY|DSCAPS_DOUBLE;
+ struct {
+ const char *name;
+ const DFBSurfaceCapabilities cap;
+ } const capabilities[] = {
+ { "static_alloc", DSCAPS_STATIC_ALLOC },
+ { "triplebuffer", DSCAPS_TRIPLE },
+ { "interlaced", DSCAPS_INTERLACED },
+ { "separated", DSCAPS_SEPARATED },
+// { "depthbuffer", DSCAPS_DEPTH }, // only makes sense with TextureTriangles which are not supported
+ { 0, DSCAPS_NONE }
+ };
+ for (int i=0; capabilities[i].name; ++i) {
+ if (displayArgs.contains(QString::fromLatin1(capabilities[i].name), Qt::CaseInsensitive))
+ description.caps |= capabilities[i].cap;
+ }
+
+ if (forcePremultiplied) {
+ description.caps |= DSCAPS_PREMULTIPLIED;
+ }
+
+ // We don't track the primary surface as it's released in disconnect
+ d_ptr->primarySurface = createDFBSurface(description, DontTrackSurface, &result);
+ if (!d_ptr->primarySurface) {
+ DirectFBError("QDirectFBScreen: error creating primary surface",
+ result);
+ return false;
+ }
+
+ surface = d_ptr->primarySurface;
+#else
+ description.flags = DSDESC_WIDTH|DSDESC_HEIGHT;
+ description.width = description.height = 1;
+ surface = createDFBSurface(description, DontTrackSurface, &result);
+ if (!surface) {
+ DirectFBError("QDirectFBScreen: error creating surface", result);
+ return false;
+ }
+#endif
+ // Work out what format we're going to use for surfaces with an alpha channel
+ QImage::Format pixelFormat = QDirectFBScreen::getImageFormat(surface);
+ d_ptr->alphaPixmapFormat = pixelFormat;
+
+ switch (pixelFormat) {
+ case QImage::Format_RGB666:
+ d_ptr->alphaPixmapFormat = QImage::Format_ARGB6666_Premultiplied;
+ break;
+ case QImage::Format_RGB444:
+ d_ptr->alphaPixmapFormat = QImage::Format_ARGB4444_Premultiplied;
+ break;
+ case QImage::Format_RGB32:
+ pixelFormat = d_ptr->alphaPixmapFormat = QImage::Format_ARGB32_Premultiplied;
+ // ### Format_RGB32 doesn't work so well with Qt. Force ARGB32 for windows/pixmaps
+ break;
+ case QImage::Format_Indexed8:
+ qWarning("QDirectFBScreen::connect(). Qt/DirectFB does not work with the LUT8 pixelformat.");
+ return false;
+ case QImage::NImageFormats:
+ case QImage::Format_Invalid:
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ case QImage::Format_RGB888:
+ case QImage::Format_RGB16:
+ case QImage::Format_RGB555:
+ d_ptr->alphaPixmapFormat = QImage::Format_ARGB32_Premultiplied;
+ break;
+ case QImage::Format_ARGB32:
+ if (forcePremultiplied)
+ d_ptr->alphaPixmapFormat = pixelFormat = QImage::Format_ARGB32_Premultiplied;
+ case QImage::Format_ARGB32_Premultiplied:
+ case QImage::Format_ARGB4444_Premultiplied:
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_ARGB8565_Premultiplied:
+ case QImage::Format_ARGB6666_Premultiplied:
+ // works already
+ break;
+ }
+ setPixelFormat(pixelFormat);
+ QScreen::d = QDirectFBScreen::depth(pixelFormat);
+ data = 0;
+ lstep = 0;
+ size = 0;
+
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreen::connect: "
+ "Unable to get screen!", result);
+ return false;
+ }
+ const QString qws_size = QString::fromLatin1(qgetenv("QWS_SIZE"));
+ if (!qws_size.isEmpty()) {
+ QRegExp rx(QLatin1String("(\\d+)x(\\d+)"));
+ if (!rx.exactMatch(qws_size)) {
+ qWarning("QDirectFBScreen::connect: Can't parse QWS_SIZE=\"%s\"", qPrintable(qws_size));
+ } else {
+ int *ints[2] = { &w, &h };
+ for (int i=0; i<2; ++i) {
+ *ints[i] = rx.cap(i + 1).toInt();
+ if (*ints[i] <= 0) {
+ qWarning("QDirectFBScreen::connect: %s is not a positive integer",
+ qPrintable(rx.cap(i + 1)));
+ w = h = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ setIntOption(displayArgs, QLatin1String("width"), &w);
+ setIntOption(displayArgs, QLatin1String("height"), &h);
+
+#ifndef QT_NO_DIRECTFB_LAYER
+ int layerId = DLID_PRIMARY;
+ setIntOption(displayArgs, QLatin1String("layerid"), &layerId);
+
+ result = d_ptr->dfb->GetDisplayLayer(d_ptr->dfb, static_cast<DFBDisplayLayerID>(layerId),
+ &d_ptr->dfbLayer);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreen::connect: "
+ "Unable to get display layer!", result);
+ return false;
+ }
+ result = d_ptr->dfbLayer->GetScreen(d_ptr->dfbLayer, &d_ptr->dfbScreen);
+#else
+ result = d_ptr->dfb->GetScreen(d_ptr->dfb, 0, &d_ptr->dfbScreen);
+#endif
+
+ if (w <= 0 || h <= 0) {
+#ifdef QT_NO_DIRECTFB_WM
+ result = d_ptr->primarySurface->GetSize(d_ptr->primarySurface, &w, &h);
+#elif (Q_DIRECTFB_VERSION >= 0x010000)
+ IDirectFBSurface *layerSurface;
+ if (d_ptr->dfbLayer->GetSurface(d_ptr->dfbLayer, &layerSurface) == DFB_OK) {
+ result = layerSurface->GetSize(layerSurface, &w, &h);
+ layerSurface->Release(layerSurface);
+ }
+ if (w <= 0 || h <= 0) {
+ result = d_ptr->dfbScreen->GetSize(d_ptr->dfbScreen, &w, &h);
+ }
+#else
+ qWarning("QDirectFBScreen::connect: DirectFB versions prior to 1.0 do not offer a way\n"
+ "query the size of the primary surface in windowed mode. You have to specify\n"
+ "the size of the display using QWS_SIZE=[0-9]x[0-9] or\n"
+ "QWS_DISPLAY=directfb:width=[0-9]:height=[0-9]");
+ return false;
+#endif
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreen::connect: "
+ "Unable to get screen size!", result);
+ return false;
+ }
+ }
+
+
+ dw = w;
+ dh = h;
+
+ Q_ASSERT(dw != 0 && dh != 0);
+
+ physWidth = physHeight = -1;
+ setIntOption(displayArgs, QLatin1String("mmWidth"), &physWidth);
+ setIntOption(displayArgs, QLatin1String("mmHeight"), &physHeight);
+ const int dpi = 72;
+ if (physWidth < 0)
+ physWidth = qRound(dw * 25.4 / dpi);
+ if (physHeight < 0)
+ physHeight = qRound(dh * 25.4 / dpi);
+
+ setGraphicsSystem(d_ptr);
+
+#if (Q_DIRECTFB_VERSION >= 0x000923)
+ if (displayArgs.contains(QLatin1String("debug"), Qt::CaseInsensitive))
+ printDirectFBInfo(d_ptr->dfb, surface);
+#endif
+#ifdef QT_DIRECTFB_WM
+ surface->Release(surface);
+ QColor backgroundColor;
+#else
+ QColor &backgroundColor = d_ptr->backgroundColor;
+#endif
+
+ QRegExp backgroundColorRegExp(QLatin1String("bgcolor=(.+)"));
+ backgroundColorRegExp.setCaseSensitivity(Qt::CaseInsensitive);
+ if (displayArgs.indexOf(backgroundColorRegExp) != -1) {
+ backgroundColor = colorFromName(backgroundColorRegExp.cap(1));
+ }
+#ifdef QT_NO_DIRECTFB_WM
+ if (!backgroundColor.isValid())
+ backgroundColor = Qt::green;
+ d_ptr->primarySurface->Clear(d_ptr->primarySurface, backgroundColor.red(),
+ backgroundColor.green(), backgroundColor.blue(),
+ backgroundColor.alpha());
+ d_ptr->primarySurface->Flip(d_ptr->primarySurface, 0, d_ptr->flipFlags);
+#else
+ if (backgroundColor.isValid()) {
+ DFBResult result = d_ptr->dfbLayer->SetCooperativeLevel(d_ptr->dfbLayer, DLSCL_ADMINISTRATIVE);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreen::connect "
+ "Unable to set cooperative level", result);
+ }
+ result = d_ptr->dfbLayer->SetBackgroundColor(d_ptr->dfbLayer, backgroundColor.red(), backgroundColor.green(),
+ backgroundColor.blue(), backgroundColor.alpha());
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::connect: "
+ "Unable to set background color", result);
+ }
+
+ result = d_ptr->dfbLayer->SetBackgroundMode(d_ptr->dfbLayer, DLBM_COLOR);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreenCursor::connect: "
+ "Unable to set background mode", result);
+ }
+
+ result = d_ptr->dfbLayer->SetCooperativeLevel(d_ptr->dfbLayer, DLSCL_SHARED);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreen::connect "
+ "Unable to set cooperative level", result);
+ }
+
+ }
+#endif
+
+ return true;
+}
+
+void QDirectFBScreen::disconnect()
+{
+#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE
+ if (d_ptr->imageProvider)
+ d_ptr->imageProvider->Release(d_ptr->imageProvider);
+#endif
+#ifdef QT_NO_DIRECTFB_WM
+ d_ptr->primarySurface->Release(d_ptr->primarySurface);
+ d_ptr->primarySurface = 0;
+#endif
+
+ foreach (IDirectFBSurface *surf, d_ptr->allocatedSurfaces)
+ surf->Release(surf);
+ d_ptr->allocatedSurfaces.clear();
+
+#ifndef QT_NO_DIRECTFB_LAYER
+ d_ptr->dfbLayer->Release(d_ptr->dfbLayer);
+ d_ptr->dfbLayer = 0;
+#endif
+
+ d_ptr->dfbScreen->Release(d_ptr->dfbScreen);
+ d_ptr->dfbScreen = 0;
+
+ d_ptr->dfb->Release(d_ptr->dfb);
+ d_ptr->dfb = 0;
+}
+
+bool QDirectFBScreen::initDevice()
+{
+#ifndef QT_NO_DIRECTFB_MOUSE
+ if (qgetenv("QWS_MOUSE_PROTO").isEmpty()) {
+ QWSServer::instance()->setDefaultMouse("None");
+ d_ptr->mouse = new QDirectFBMouseHandler;
+ }
+#endif
+#ifndef QT_NO_DIRECTFB_KEYBOARD
+ if (qgetenv("QWS_KEYBOARD").isEmpty()) {
+ QWSServer::instance()->setDefaultKeyboard("None");
+ d_ptr->keyboard = new QDirectFBKeyboardHandler(QString());
+ }
+#endif
+
+#ifdef QT_DIRECTFB_CURSOR
+ qt_screencursor = new QDirectFBScreenCursor;
+#elif !defined QT_NO_QWS_CURSOR
+ QScreenCursor::initSoftwareCursor();
+#endif
+ return true;
+}
+
+void QDirectFBScreen::shutdownDevice()
+{
+#ifndef QT_NO_DIRECTFB_MOUSE
+ delete d_ptr->mouse;
+ d_ptr->mouse = 0;
+#endif
+#ifndef QT_NO_DIRECTFB_KEYBOARD
+ delete d_ptr->keyboard;
+ d_ptr->keyboard = 0;
+#endif
+
+#ifndef QT_NO_QWS_CURSOR
+ delete qt_screencursor;
+ qt_screencursor = 0;
+#endif
+}
+
+void QDirectFBScreen::setMode(int width, int height, int depth)
+{
+ d_ptr->dfb->SetVideoMode(d_ptr->dfb, width, height, depth);
+}
+
+void QDirectFBScreen::blank(bool on)
+{
+ d_ptr->dfbScreen->SetPowerMode(d_ptr->dfbScreen,
+ (on ? DSPM_ON : DSPM_SUSPEND));
+}
+
+QWSWindowSurface *QDirectFBScreen::createSurface(QWidget *widget) const
+{
+#ifdef QT_NO_DIRECTFB_WM
+ if (QApplication::type() == QApplication::GuiServer) {
+ return new QDirectFBWindowSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this), widget);
+ } else {
+ return QScreen::createSurface(widget);
+ }
+#else
+ return new QDirectFBWindowSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this), widget);
+#endif
+}
+
+QWSWindowSurface *QDirectFBScreen::createSurface(const QString &key) const
+{
+ if (key == QLatin1String("directfb")) {
+ return new QDirectFBWindowSurface(d_ptr->flipFlags, const_cast<QDirectFBScreen*>(this));
+ }
+ return QScreen::createSurface(key);
+}
+
+#if defined QT_NO_DIRECTFB_WM
+struct PaintCommand {
+ PaintCommand() : dfbSurface(0), windowOpacity(255), blittingFlags(DSBLIT_NOFX) {}
+ IDirectFBSurface *dfbSurface;
+ QImage image;
+ QPoint windowPosition;
+ QRegion source;
+ quint8 windowOpacity;
+ DFBSurfaceBlittingFlags blittingFlags;
+};
+
+static inline void initParameters(DFBRectangle &source, const QRect &sourceGlobal, const QPoint &pos)
+{
+ source.x = sourceGlobal.x() - pos.x();
+ source.y = sourceGlobal.y() - pos.y();
+ source.w = sourceGlobal.width();
+ source.h = sourceGlobal.height();
+}
+#endif
+
+void QDirectFBScreen::exposeRegion(QRegion r, int)
+{
+ Q_UNUSED(r);
+#if defined QT_NO_DIRECTFB_WM
+
+ r &= region();
+ if (r.isEmpty()) {
+ return;
+ }
+ r = r.boundingRect();
+
+ IDirectFBSurface *primary = d_ptr->primarySurface;
+ const QList<QWSWindow*> windows = QWSServer::instance()->clientWindows();
+ QVarLengthArray<PaintCommand, 4> commands(windows.size());
+ QRegion region = r;
+ int idx = 0;
+ for (int i=0; i<windows.size(); ++i) {
+ QWSWindowSurface *surface = windows.at(i)->windowSurface();
+ if (!surface)
+ continue;
+
+ const QRect windowGeometry = surface->geometry();
+ const QRegion intersection = region & windowGeometry;
+ if (intersection.isEmpty()) {
+ continue;
+ }
+
+ PaintCommand &cmd = commands[idx];
+
+ if (surface->key() == QLatin1String("directfb")) {
+ const QDirectFBWindowSurface *ws = static_cast<QDirectFBWindowSurface*>(surface);
+ cmd.dfbSurface = ws->directFBSurface();
+
+ if (!cmd.dfbSurface) {
+ continue;
+ }
+ } else {
+ cmd.image = surface->image();
+ if (cmd.image.isNull()) {
+ continue;
+ }
+ }
+ ++idx;
+
+ cmd.windowPosition = windowGeometry.topLeft();
+ cmd.source = intersection;
+ if (windows.at(i)->isOpaque()) {
+ region -= intersection;
+ if (region.isEmpty())
+ break;
+ } else {
+ cmd.windowOpacity = windows.at(i)->opacity();
+ cmd.blittingFlags = cmd.windowOpacity == 255
+ ? DSBLIT_BLEND_ALPHACHANNEL
+ : (DSBLIT_BLEND_ALPHACHANNEL|DSBLIT_BLEND_COLORALPHA);
+ }
+ }
+
+ solidFill(d_ptr->backgroundColor, region);
+
+ while (idx > 0) {
+ const PaintCommand &cmd = commands[--idx];
+ Q_ASSERT(cmd.dfbSurface || !cmd.image.isNull());
+ IDirectFBSurface *surface;
+ if (cmd.dfbSurface) {
+ surface = cmd.dfbSurface;
+ } else {
+ Q_ASSERT(!cmd.image.isNull());
+ DFBResult result;
+ surface = createDFBSurface(cmd.image, cmd.image.format(), DontTrackSurface, &result);
+ Q_ASSERT((result != DFB_OK) == !surface);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreen::exposeRegion: Can't create surface from image", result);
+ continue;
+ }
+ }
+
+ primary->SetBlittingFlags(primary, cmd.blittingFlags);
+ if (cmd.blittingFlags & DSBLIT_BLEND_COLORALPHA) {
+ primary->SetColor(primary, 0xff, 0xff, 0xff, cmd.windowOpacity);
+ }
+ const QRegion &region = cmd.source;
+ const int rectCount = region.rectCount();
+ DFBRectangle source;
+ if (rectCount == 1) {
+ ::initParameters(source, region.boundingRect(), cmd.windowPosition);
+ primary->Blit(primary, surface, &source, cmd.windowPosition.x() + source.x, cmd.windowPosition.y() + source.y);
+ } else {
+ const QVector<QRect> rects = region.rects();
+ for (int i=0; i<rectCount; ++i) {
+ ::initParameters(source, rects.at(i), cmd.windowPosition);
+ primary->Blit(primary, surface, &source, cmd.windowPosition.x() + source.x, cmd.windowPosition.y() + source.y);
+ }
+ }
+ if (surface != cmd.dfbSurface) {
+ surface->Release(surface);
+ }
+ }
+
+ primary->SetColor(primary, 0xff, 0xff, 0xff, 0xff);
+
+#if defined QT_NO_DIRECTFB_CURSOR and !defined QT_NO_QWS_CURSOR
+ if (QScreenCursor *cursor = QScreenCursor::instance()) {
+ const QRect cursorRectangle = cursor->boundingRect();
+ if (cursor->isVisible() && !cursor->isAccelerated() && r.intersects(cursorRectangle)) {
+ const QImage image = cursor->image();
+ if (image.cacheKey() != d_ptr->cursorImageKey) {
+ if (d_ptr->cursorSurface) {
+ releaseDFBSurface(d_ptr->cursorSurface);
+ }
+ d_ptr->cursorSurface = createDFBSurface(image, image.format(), QDirectFBScreen::TrackSurface);
+ d_ptr->cursorImageKey = image.cacheKey();
+ }
+
+ Q_ASSERT(d_ptr->cursorSurface);
+ primary->SetBlittingFlags(primary, DSBLIT_BLEND_ALPHACHANNEL);
+ primary->Blit(primary, d_ptr->cursorSurface, 0, cursorRectangle.x(), cursorRectangle.y());
+ }
+ }
+#endif
+ flipSurface(primary, d_ptr->flipFlags, r, QPoint());
+ primary->SetBlittingFlags(primary, DSBLIT_NOFX);
+#endif
+}
+
+void QDirectFBScreen::solidFill(const QColor &color, const QRegion &region)
+{
+#ifdef QT_DIRECTFB_WM
+ Q_UNUSED(color);
+ Q_UNUSED(region);
+#else
+ QDirectFBScreen::solidFill(d_ptr->primarySurface, color, region);
+#endif
+}
+
+static inline void clearRect(IDirectFBSurface *surface, const QColor &color, const QRect &rect)
+{
+ Q_ASSERT(surface);
+ const DFBRegion region = { rect.left(), rect.top(), rect.right(), rect.bottom() };
+ // could just reinterpret_cast this to a DFBRegion
+ surface->SetClip(surface, &region);
+ surface->Clear(surface, color.red(), color.green(), color.blue(), color.alpha());
+}
+
+void QDirectFBScreen::solidFill(IDirectFBSurface *surface, const QColor &color, const QRegion &region)
+{
+ if (region.isEmpty())
+ return;
+
+ const int n = region.rectCount();
+ if (n == 1) {
+ clearRect(surface, color, region.boundingRect());
+ } else {
+ const QVector<QRect> rects = region.rects();
+ for (int i=0; i<n; ++i) {
+ clearRect(surface, color, rects.at(i));
+ }
+ }
+ surface->SetClip(surface, 0);
+}
+
+QImage::Format QDirectFBScreen::alphaPixmapFormat() const
+{
+ return d_ptr->alphaPixmapFormat;
+}
+
+bool QDirectFBScreen::initSurfaceDescriptionPixelFormat(DFBSurfaceDescription *description,
+ QImage::Format format)
+{
+ const DFBSurfacePixelFormat pixelformat = QDirectFBScreen::getSurfacePixelFormat(format);
+ if (pixelformat == DSPF_UNKNOWN)
+ return false;
+ description->flags |= DSDESC_PIXELFORMAT;
+ description->pixelformat = pixelformat;
+ if (QDirectFBScreen::isPremultiplied(format)) {
+ if (!(description->flags & DSDESC_CAPS)) {
+ description->caps = DSCAPS_PREMULTIPLIED;
+ description->flags |= DSDESC_CAPS;
+ } else {
+ description->caps |= DSCAPS_PREMULTIPLIED;
+ }
+ }
+ return true;
+}
+
+uchar *QDirectFBScreen::lockSurface(IDirectFBSurface *surface, DFBSurfaceLockFlags flags, int *bpl)
+{
+ void *mem = 0;
+ const DFBResult result = surface->Lock(surface, flags, &mem, bpl);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreen::lockSurface()", result);
+ }
+
+ return reinterpret_cast<uchar*>(mem);
+}
+
+static inline bool isFullUpdate(IDirectFBSurface *surface, const QRegion &region, const QPoint &offset)
+{
+ if (offset == QPoint(0, 0) && region.rectCount() == 1) {
+ QSize size;
+ surface->GetSize(surface, &size.rwidth(), &size.rheight());
+ if (region.boundingRect().size() == size)
+ return true;
+ }
+ return false;
+}
+
+void QDirectFBScreen::flipSurface(IDirectFBSurface *surface, DFBSurfaceFlipFlags flipFlags,
+ const QRegion &region, const QPoint &offset)
+{
+ if (d_ptr->directFBFlags & NoPartialFlip
+ || (!(flipFlags & DSFLIP_BLIT) && QT_PREPEND_NAMESPACE(isFullUpdate(surface, region, offset)))) {
+ surface->Flip(surface, 0, flipFlags);
+ } else {
+ if (!(d_ptr->directFBFlags & BoundingRectFlip) && region.rectCount() > 1) {
+ const QVector<QRect> rects = region.rects();
+ const DFBSurfaceFlipFlags nonWaitFlags = flipFlags & ~DSFLIP_WAIT;
+ for (int i=0; i<rects.size(); ++i) {
+ const QRect &r = rects.at(i);
+ const DFBRegion dfbReg = { r.x() + offset.x(), r.y() + offset.y(),
+ r.right() + offset.x(),
+ r.bottom() + offset.y() };
+ surface->Flip(surface, &dfbReg, i + 1 < rects.size() ? nonWaitFlags : flipFlags);
+ }
+ } else {
+ const QRect r = region.boundingRect();
+ const DFBRegion dfbReg = { r.x() + offset.x(), r.y() + offset.y(),
+ r.right() + offset.x(),
+ r.bottom() + offset.y() };
+ surface->Flip(surface, &dfbReg, flipFlags);
+ }
+ }
+}
+
+#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE
+void QDirectFBScreen::setDirectFBImageProvider(IDirectFBImageProvider *provider)
+{
+ Q_ASSERT(provider);
+ if (d_ptr->imageProvider)
+ d_ptr->imageProvider->Release(d_ptr->imageProvider);
+ d_ptr->imageProvider = provider;
+}
+#endif
+
+void QDirectFBScreen::waitIdle()
+{
+ d_ptr->dfb->WaitIdle(d_ptr->dfb);
+}
+
+#ifdef QT_DIRECTFB_WM
+IDirectFBWindow *QDirectFBScreen::windowForWidget(const QWidget *widget) const
+{
+ if (widget) {
+ const QWSWindowSurface *surface = static_cast<const QWSWindowSurface*>(widget->windowSurface());
+ if (surface && surface->key() == QLatin1String("directfb")) {
+ return static_cast<const QDirectFBWindowSurface*>(surface)->directFBWindow();
+ }
+ }
+ return 0;
+}
+#endif
+
+IDirectFBSurface * QDirectFBScreen::surfaceForWidget(const QWidget *widget, QRect *rect) const
+{
+ Q_ASSERT(widget);
+ if (!widget->isVisible() || widget->size().isNull())
+ return 0;
+
+ const QWSWindowSurface *surface = static_cast<const QWSWindowSurface*>(widget->windowSurface());
+ if (surface && surface->key() == QLatin1String("directfb")) {
+ return static_cast<const QDirectFBWindowSurface*>(surface)->surfaceForWidget(widget, rect);
+ }
+ return 0;
+}
+
+#ifdef QT_DIRECTFB_SUBSURFACE
+IDirectFBSurface *QDirectFBScreen::subSurfaceForWidget(const QWidget *widget, const QRect &area) const
+{
+ Q_ASSERT(widget);
+ QRect rect;
+ IDirectFBSurface *surface = surfaceForWidget(widget, &rect);
+ IDirectFBSurface *subSurface = 0;
+ if (surface) {
+ if (!area.isNull())
+ rect &= area.translated(widget->mapTo(widget->window(), QPoint(0, 0)));
+ if (!rect.isNull()) {
+ const DFBRectangle subRect = { rect.x(), rect.y(), rect.width(), rect.height() };
+ const DFBResult result = surface->GetSubSurface(surface, &subRect, &subSurface);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBScreen::subSurface(): Can't get sub surface", result);
+ }
+ }
+ }
+ return subSurface;
+}
+#endif
+
+Q_GUI_EXPORT IDirectFBSurface *qt_directfb_surface_for_widget(const QWidget *widget, QRect *rect)
+{
+ return QDirectFBScreen::instance() ? QDirectFBScreen::instance()->surfaceForWidget(widget, rect) : 0;
+}
+#ifdef QT_DIRECTFB_SUBSURFACE
+Q_GUI_EXPORT IDirectFBSurface *qt_directfb_subsurface_for_widget(const QWidget *widget, const QRect &area)
+{
+ return QDirectFBScreen::instance() ? QDirectFBScreen::instance()->subSurfaceForWidget(widget, area) : 0;
+}
+#endif
+#ifdef QT_DIRECTFB_WM
+Q_GUI_EXPORT IDirectFBWindow *qt_directfb_window_for_widget(const QWidget *widget)
+{
+ return QDirectFBScreen::instance() ? QDirectFBScreen::instance()->windowForWidget(widget) : 0;
+}
+
+#endif
+
+QT_END_NAMESPACE
+
+#include "qdirectfbscreen.moc"
+#endif // QT_NO_QWS_DIRECTFB
+
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h
new file mode 100644
index 0000000000..0e9098df3b
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h
@@ -0,0 +1,303 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDIRECTFBSCREEN_H
+#define QDIRECTFBSCREEN_H
+
+#include <qglobal.h>
+#ifndef QT_NO_QWS_DIRECTFB
+#include <QtGui/qscreen_qws.h>
+#include <directfb.h>
+#include <directfb_version.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined QT_DIRECTFB_SUBSURFACE && !defined QT_NO_DIRECTFB_SUBSURFACE
+#define QT_NO_DIRECTFB_SUBSURFACE
+#endif
+#if !defined QT_NO_DIRECTFB_LAYER && !defined QT_DIRECTFB_LAYER
+#define QT_DIRECTFB_LAYER
+#endif
+#if !defined QT_NO_DIRECTFB_WM && !defined QT_DIRECTFB_WM
+#define QT_DIRECTFB_WM
+#endif
+#if !defined QT_DIRECTFB_IMAGECACHE && !defined QT_NO_DIRECTFB_IMAGECACHE
+#define QT_NO_DIRECTFB_IMAGECACHE
+#endif
+#if !defined QT_NO_DIRECTFB_IMAGEPROVIDER && !defined QT_DIRECTFB_IMAGEPROVIDER
+#define QT_DIRECTFB_IMAGEPROVIDER
+#endif
+#if !defined QT_NO_DIRECTFB_STRETCHBLIT && !defined QT_DIRECTFB_STRETCHBLIT
+#define QT_DIRECTFB_STRETCHBLIT
+#endif
+#if !defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE && !defined QT_NO_DIRECTFB_IMAGEPROVIDER_KEEPALIVE
+#define QT_NO_DIRECTFB_IMAGEPROVIDER_KEEPALIVE
+#endif
+#if !defined QT_DIRECTFB_WINDOW_AS_CURSOR && !defined QT_NO_DIRECTFB_WINDOW_AS_CURSOR
+#define QT_NO_DIRECTFB_WINDOW_AS_CURSOR
+#endif
+#if !defined QT_DIRECTFB_PALETTE && !defined QT_NO_DIRECTFB_PALETTE
+#define QT_NO_DIRECTFB_PALETTE
+#endif
+#if !defined QT_NO_DIRECTFB_PREALLOCATED && !defined QT_DIRECTFB_PREALLOCATED
+#define QT_DIRECTFB_PREALLOCATED
+#endif
+#if !defined QT_NO_DIRECTFB_MOUSE && !defined QT_DIRECTFB_MOUSE
+#define QT_DIRECTFB_MOUSE
+#endif
+#if !defined QT_NO_DIRECTFB_KEYBOARD && !defined QT_DIRECTFB_KEYBOARD
+#define QT_DIRECTFB_KEYBOARD
+#endif
+#if !defined QT_NO_DIRECTFB_OPAQUE_DETECTION && !defined QT_DIRECTFB_OPAQUE_DETECTION
+#define QT_DIRECTFB_OPAQUE_DETECTION
+#endif
+#ifndef QT_NO_QWS_CURSOR
+#if defined QT_DIRECTFB_WM && defined QT_DIRECTFB_WINDOW_AS_CURSOR
+#define QT_DIRECTFB_CURSOR
+#elif defined QT_DIRECTFB_LAYER
+#define QT_DIRECTFB_CURSOR
+#endif
+#endif
+#ifndef QT_DIRECTFB_CURSOR
+#define QT_NO_DIRECTFB_CURSOR
+#endif
+#if defined QT_NO_DIRECTFB_LAYER && defined QT_DIRECTFB_WM
+#error QT_NO_DIRECTFB_LAYER requires QT_NO_DIRECTFB_WM
+#endif
+#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE && defined QT_NO_DIRECTFB_IMAGEPROVIDER
+#error QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE requires QT_DIRECTFB_IMAGEPROVIDER to be defined
+#endif
+#if defined QT_DIRECTFB_WINDOW_AS_CURSOR && defined QT_NO_DIRECTFB_WM
+#error QT_DIRECTFB_WINDOW_AS_CURSOR requires QT_DIRECTFB_WM to be defined
+#endif
+
+#define Q_DIRECTFB_VERSION ((DIRECTFB_MAJOR_VERSION << 16) | (DIRECTFB_MINOR_VERSION << 8) | DIRECTFB_MICRO_VERSION)
+
+#define DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(F) \
+ static inline F operator~(F f) { return F(~int(f)); } \
+ static inline F operator&(F left, F right) { return F(int(left) & int(right)); } \
+ static inline F operator|(F left, F right) { return F(int(left) | int(right)); } \
+ static inline F &operator|=(F &left, F right) { left = (left | right); return left; } \
+ static inline F &operator&=(F &left, F right) { left = (left & right); return left; }
+
+DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBInputDeviceCapabilities);
+DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBWindowDescriptionFlags);
+DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBWindowCapabilities);
+DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBWindowOptions);
+DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceDescriptionFlags);
+DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceCapabilities);
+DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceLockFlags);
+DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceBlittingFlags);
+DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceDrawingFlags);
+DIRECTFB_DECLARE_OPERATORS_FOR_FLAGS(DFBSurfaceFlipFlags);
+
+class QDirectFBScreenPrivate;
+class Q_GUI_EXPORT QDirectFBScreen : public QScreen
+{
+public:
+ QDirectFBScreen(int display_id);
+ ~QDirectFBScreen();
+
+ enum DirectFBFlag {
+ NoFlags = 0x00,
+ VideoOnly = 0x01,
+ SystemOnly = 0x02,
+ BoundingRectFlip = 0x04,
+ NoPartialFlip = 0x08
+ };
+
+ Q_DECLARE_FLAGS(DirectFBFlags, DirectFBFlag);
+
+ DirectFBFlags directFBFlags() const;
+
+ bool connect(const QString &displaySpec);
+ void disconnect();
+ bool initDevice();
+ void shutdownDevice();
+
+ void exposeRegion(QRegion r, int changing);
+ void solidFill(const QColor &color, const QRegion &region);
+ static void solidFill(IDirectFBSurface *surface, const QColor &color, const QRegion &region);
+
+ void setMode(int width, int height, int depth);
+ void blank(bool on);
+
+ QWSWindowSurface *createSurface(QWidget *widget) const;
+ QWSWindowSurface *createSurface(const QString &key) const;
+
+ static QDirectFBScreen *instance();
+ void waitIdle();
+ IDirectFBSurface *surfaceForWidget(const QWidget *widget, QRect *rect) const;
+#ifdef QT_DIRECTFB_SUBSURFACE
+ IDirectFBSurface *subSurfaceForWidget(const QWidget *widget, const QRect &area = QRect()) const;
+#endif
+ IDirectFB *dfb();
+#ifdef QT_DIRECTFB_WM
+ IDirectFBWindow *windowForWidget(const QWidget *widget) const;
+#else
+ IDirectFBSurface *primarySurface();
+#endif
+#ifndef QT_NO_DIRECTFB_LAYER
+ IDirectFBDisplayLayer *dfbDisplayLayer();
+#endif
+
+ // Track surface creation/release so we can release all on exit
+ enum SurfaceCreationOption {
+ DontTrackSurface = 0x1,
+ TrackSurface = 0x2,
+ NoPreallocated = 0x4
+ };
+ Q_DECLARE_FLAGS(SurfaceCreationOptions, SurfaceCreationOption);
+ IDirectFBSurface *createDFBSurface(const QImage &image,
+ QImage::Format format,
+ SurfaceCreationOptions options,
+ DFBResult *result = 0);
+ IDirectFBSurface *createDFBSurface(const QSize &size,
+ QImage::Format format,
+ SurfaceCreationOptions options,
+ DFBResult *result = 0);
+ IDirectFBSurface *copyDFBSurface(IDirectFBSurface *src,
+ QImage::Format format,
+ SurfaceCreationOptions options,
+ DFBResult *result = 0);
+ IDirectFBSurface *createDFBSurface(DFBSurfaceDescription desc,
+ SurfaceCreationOptions options,
+ DFBResult *result);
+#ifdef QT_DIRECTFB_SUBSURFACE
+ IDirectFBSurface *getSubSurface(IDirectFBSurface *surface,
+ const QRect &rect,
+ SurfaceCreationOptions options,
+ DFBResult *result);
+#endif
+
+ void flipSurface(IDirectFBSurface *surface, DFBSurfaceFlipFlags flipFlags,
+ const QRegion &region, const QPoint &offset);
+ void releaseDFBSurface(IDirectFBSurface *surface);
+
+ using QScreen::depth;
+ static int depth(DFBSurfacePixelFormat format);
+ static int depth(QImage::Format format);
+
+ static DFBSurfacePixelFormat getSurfacePixelFormat(QImage::Format format);
+ static DFBSurfaceDescription getSurfaceDescription(const uint *buffer,
+ int length);
+ static QImage::Format getImageFormat(IDirectFBSurface *surface);
+ static bool initSurfaceDescriptionPixelFormat(DFBSurfaceDescription *description, QImage::Format format);
+ static inline bool isPremultiplied(QImage::Format format);
+ static inline bool hasAlphaChannel(DFBSurfacePixelFormat format);
+ static inline bool hasAlphaChannel(IDirectFBSurface *surface);
+ QImage::Format alphaPixmapFormat() const;
+
+#ifndef QT_NO_DIRECTFB_PALETTE
+ static void setSurfaceColorTable(IDirectFBSurface *surface,
+ const QImage &image);
+#endif
+
+ static uchar *lockSurface(IDirectFBSurface *surface, DFBSurfaceLockFlags flags, int *bpl = 0);
+#if defined QT_DIRECTFB_IMAGEPROVIDER && defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE
+ void setDirectFBImageProvider(IDirectFBImageProvider *provider);
+#endif
+private:
+ QDirectFBScreenPrivate *d_ptr;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDirectFBScreen::SurfaceCreationOptions);
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDirectFBScreen::DirectFBFlags);
+
+inline bool QDirectFBScreen::isPremultiplied(QImage::Format format)
+{
+ switch (format) {
+ case QImage::Format_ARGB32_Premultiplied:
+ case QImage::Format_ARGB8565_Premultiplied:
+ case QImage::Format_ARGB6666_Premultiplied:
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_ARGB4444_Premultiplied:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+inline bool QDirectFBScreen::hasAlphaChannel(DFBSurfacePixelFormat format)
+{
+ switch (format) {
+ case DSPF_ARGB1555:
+ case DSPF_ARGB:
+ case DSPF_LUT8:
+ case DSPF_AiRGB:
+ case DSPF_A1:
+ case DSPF_ARGB2554:
+ case DSPF_ARGB4444:
+#if (Q_DIRECTFB_VERSION >= 0x000923)
+ case DSPF_AYUV:
+#endif
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ case DSPF_A4:
+ case DSPF_ARGB1666:
+ case DSPF_ARGB6666:
+ case DSPF_LUT2:
+#endif
+ return true;
+ default:
+ return false;
+ }
+}
+
+inline bool QDirectFBScreen::hasAlphaChannel(IDirectFBSurface *surface)
+{
+ Q_ASSERT(surface);
+ DFBSurfacePixelFormat format;
+ surface->GetPixelFormat(surface, &format);
+ return QDirectFBScreen::hasAlphaChannel(format);
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_QWS_DIRECTFB
+#endif // QDIRECTFBSCREEN_H
+
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreenplugin.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreenplugin.cpp
new file mode 100644
index 0000000000..742c857e9e
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreenplugin.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdirectfbscreen.h"
+
+#include <QtGui/qscreendriverplugin_qws.h>
+#include <QtCore/qstringlist.h>
+#ifndef QT_NO_QWS_DIRECTFB
+
+class DirectFBScreenDriverPlugin : public QScreenDriverPlugin
+{
+public:
+ DirectFBScreenDriverPlugin();
+
+ QStringList keys() const;
+ QScreen *create(const QString&, int displayId);
+};
+
+DirectFBScreenDriverPlugin::DirectFBScreenDriverPlugin()
+ : QScreenDriverPlugin()
+{
+}
+
+QStringList DirectFBScreenDriverPlugin::keys() const
+{
+ return (QStringList() << "directfb");
+}
+
+QScreen* DirectFBScreenDriverPlugin::create(const QString& driver,
+ int displayId)
+{
+ if (driver.toLower() != "directfb")
+ return 0;
+
+ return new QDirectFBScreen(displayId);
+}
+
+Q_EXPORT_PLUGIN2(qdirectfbscreen, DirectFBScreenDriverPlugin)
+
+#endif
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp
new file mode 100644
index 0000000000..9a94c30d8c
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp
@@ -0,0 +1,506 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdirectfbwindowsurface.h"
+#include "qdirectfbscreen.h"
+#include "qdirectfbpaintengine.h"
+
+#include <private/qwidget_p.h>
+#include <qwidget.h>
+#include <qwindowsystem_qws.h>
+#include <qpaintdevice.h>
+#include <qvarlengtharray.h>
+
+#ifndef QT_NO_QWS_DIRECTFB
+
+QT_BEGIN_NAMESPACE
+
+QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr)
+ : QDirectFBPaintDevice(scr)
+#ifndef QT_NO_DIRECTFB_WM
+ , dfbWindow(0)
+#endif
+ , flipFlags(flip)
+ , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip)
+ , flushPending(false)
+{
+#ifdef QT_NO_DIRECTFB_WM
+ mode = Offscreen;
+#endif
+ setSurfaceFlags(Opaque | Buffered);
+#ifdef QT_DIRECTFB_TIMING
+ frames = 0;
+ timer.start();
+#endif
+}
+
+QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr, QWidget *widget)
+ : QWSWindowSurface(widget), QDirectFBPaintDevice(scr)
+#ifndef QT_NO_DIRECTFB_WM
+ , dfbWindow(0)
+#endif
+ , flipFlags(flip)
+ , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip)
+ , flushPending(false)
+{
+ SurfaceFlags flags = 0;
+ if (!widget || widget->window()->windowOpacity() == 0xff)
+ flags |= Opaque;
+#ifdef QT_NO_DIRECTFB_WM
+ if (widget && widget->testAttribute(Qt::WA_PaintOnScreen)) {
+ flags = RegionReserved;
+ mode = Primary;
+ } else {
+ mode = Offscreen;
+ flags = Buffered;
+ }
+#endif
+ setSurfaceFlags(flags);
+#ifdef QT_DIRECTFB_TIMING
+ frames = 0;
+ timer.start();
+#endif
+}
+
+QDirectFBWindowSurface::~QDirectFBWindowSurface()
+{
+ releaseSurface();
+ // these are not tracked by QDirectFBScreen so we don't want QDirectFBPaintDevice to release it
+}
+
+bool QDirectFBWindowSurface::isValid() const
+{
+ return true;
+}
+
+#ifdef QT_DIRECTFB_WM
+void QDirectFBWindowSurface::raise()
+{
+ if (IDirectFBWindow *window = directFBWindow()) {
+ window->RaiseToTop(window);
+ }
+}
+
+IDirectFBWindow *QDirectFBWindowSurface::directFBWindow() const
+{
+ return dfbWindow;
+}
+
+void QDirectFBWindowSurface::createWindow(const QRect &rect)
+{
+ IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer();
+ if (!layer)
+ qFatal("QDirectFBWindowSurface: Unable to get primary display layer!");
+
+ updateIsOpaque();
+
+ DFBWindowDescription description;
+ memset(&description, 0, sizeof(DFBWindowDescription));
+
+ description.flags = DWDESC_CAPS|DWDESC_HEIGHT|DWDESC_WIDTH|DWDESC_POSX|DWDESC_POSY|DWDESC_SURFACE_CAPS|DWDESC_PIXELFORMAT;
+ description.caps = DWCAPS_NODECORATION;
+ description.surface_caps = DSCAPS_NONE;
+ imageFormat = screen->pixelFormat();
+
+ if (!(surfaceFlags() & Opaque)) {
+ imageFormat = screen->alphaPixmapFormat();
+ description.caps |= DWCAPS_ALPHACHANNEL;
+#if (Q_DIRECTFB_VERSION >= 0x010200)
+ description.flags |= DWDESC_OPTIONS;
+ description.options |= DWOP_ALPHACHANNEL;
+#endif
+ }
+ description.pixelformat = QDirectFBScreen::getSurfacePixelFormat(imageFormat);
+ description.posx = rect.x();
+ description.posy = rect.y();
+ description.width = rect.width();
+ description.height = rect.height();
+
+ if (QDirectFBScreen::isPremultiplied(imageFormat))
+ description.surface_caps = DSCAPS_PREMULTIPLIED;
+
+ if (screen->directFBFlags() & QDirectFBScreen::VideoOnly)
+ description.surface_caps |= DSCAPS_VIDEOONLY;
+
+ DFBResult result = layer->CreateWindow(layer, &description, &dfbWindow);
+
+ if (result != DFB_OK)
+ DirectFBErrorFatal("QDirectFBWindowSurface::createWindow", result);
+
+ if (window()) {
+ if (window()->windowFlags() & Qt::WindowStaysOnTopHint) {
+ dfbWindow->SetStackingClass(dfbWindow, DWSC_UPPER);
+ }
+ DFBWindowID winid;
+ result = dfbWindow->GetID(dfbWindow, &winid);
+ if (result != DFB_OK) {
+ DirectFBError("QDirectFBWindowSurface::createWindow. Can't get ID", result);
+ } else {
+ window()->setProperty("_q_DirectFBWindowID", winid);
+ }
+ }
+
+ Q_ASSERT(!dfbSurface);
+ dfbWindow->GetSurface(dfbWindow, &dfbSurface);
+}
+
+static DFBResult setWindowGeometry(IDirectFBWindow *dfbWindow, const QRect &old, const QRect &rect)
+{
+ DFBResult result = DFB_OK;
+ const bool isMove = old.isEmpty() || rect.topLeft() != old.topLeft();
+ const bool isResize = rect.size() != old.size();
+
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ if (isResize && isMove) {
+ result = dfbWindow->SetBounds(dfbWindow, rect.x(), rect.y(),
+ rect.width(), rect.height());
+ } else if (isResize) {
+ result = dfbWindow->Resize(dfbWindow,
+ rect.width(), rect.height());
+ } else if (isMove) {
+ result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y());
+ }
+#else
+ if (isResize) {
+ result = dfbWindow->Resize(dfbWindow,
+ rect.width(), rect.height());
+ }
+ if (isMove) {
+ result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y());
+ }
+#endif
+ return result;
+}
+#endif // QT_NO_DIRECTFB_WM
+
+void QDirectFBWindowSurface::setGeometry(const QRect &rect)
+{
+ const QRect oldRect = geometry();
+ if (oldRect == rect)
+ return;
+
+ IDirectFBSurface *oldSurface = dfbSurface;
+ const bool sizeChanged = oldRect.size() != rect.size();
+ if (sizeChanged) {
+ delete engine;
+ engine = 0;
+ releaseSurface();
+ Q_ASSERT(!dfbSurface);
+ }
+
+ if (rect.isNull()) {
+#ifndef QT_NO_DIRECTFB_WM
+ if (dfbWindow) {
+ if (window())
+ window()->setProperty("_q_DirectFBWindowID", QVariant());
+
+ dfbWindow->Release(dfbWindow);
+ dfbWindow = 0;
+ }
+#endif
+ Q_ASSERT(!dfbSurface);
+#ifdef QT_DIRECTFB_SUBSURFACE
+ Q_ASSERT(!subSurface);
+#endif
+ } else {
+#ifdef QT_DIRECTFB_WM
+ if (!dfbWindow) {
+ createWindow(rect);
+ } else {
+ setWindowGeometry(dfbWindow, oldRect, rect);
+ Q_ASSERT(!sizeChanged || !dfbSurface);
+ if (sizeChanged)
+ dfbWindow->GetSurface(dfbWindow, &dfbSurface);
+ }
+#else
+ IDirectFBSurface *primarySurface = screen->primarySurface();
+ DFBResult result = DFB_OK;
+ if (mode == Primary) {
+ Q_ASSERT(primarySurface);
+ if (rect == screen->region().boundingRect()) {
+ dfbSurface = primarySurface;
+ } else {
+ const DFBRectangle r = { rect.x(), rect.y(),
+ rect.width(), rect.height() };
+ result = primarySurface->GetSubSurface(primarySurface, &r, &dfbSurface);
+ }
+ } else { // mode == Offscreen
+ if (!dfbSurface) {
+ dfbSurface = screen->createDFBSurface(rect.size(), surfaceFlags() & Opaque ? screen->pixelFormat() : screen->alphaPixmapFormat(),
+ QDirectFBScreen::DontTrackSurface);
+ }
+ }
+ if (result != DFB_OK)
+ DirectFBErrorFatal("QDirectFBWindowSurface::setGeometry()", result);
+#endif
+ }
+ if (oldSurface != dfbSurface) {
+ imageFormat = dfbSurface ? QDirectFBScreen::getImageFormat(dfbSurface) : QImage::Format_Invalid;
+ }
+
+ if (oldRect.size() != rect.size()) {
+ QWSWindowSurface::setGeometry(rect);
+ } else {
+ QWindowSurface::setGeometry(rect);
+ }
+}
+
+QByteArray QDirectFBWindowSurface::permanentState() const
+{
+ QByteArray state(sizeof(SurfaceFlags) + sizeof(DFBWindowID), 0);
+ char *ptr = state.data();
+ SurfaceFlags flags = surfaceFlags();
+ memcpy(ptr, &flags, sizeof(SurfaceFlags));
+ ptr += sizeof(SurfaceFlags);
+ DFBWindowID did = (DFBWindowID)(-1);
+ if (dfbWindow)
+ dfbWindow->GetID(dfbWindow, &did);
+ memcpy(ptr, &did, sizeof(DFBWindowID));
+ return state;
+}
+
+void QDirectFBWindowSurface::setPermanentState(const QByteArray &state)
+{
+ const char *ptr = state.constData();
+ IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer();
+ SurfaceFlags flags;
+ memcpy(&flags, ptr, sizeof(SurfaceFlags));
+
+ setSurfaceFlags(flags);
+ ptr += sizeof(SurfaceFlags);
+ DFBWindowID id;
+ memcpy(&id, ptr, sizeof(DFBWindowID));
+ if (dfbSurface)
+ dfbSurface->Release(dfbSurface);
+ if (id != (DFBWindowID)-1) {
+ IDirectFBWindow *dw;
+ layer->GetWindow(layer, id, &dw);
+ if (dw->GetSurface(dw, &dfbSurface) != DFB_OK)
+ dfbSurface = 0;
+ dw->Release(dw);
+ }
+ else {
+ dfbSurface = 0;
+ }
+}
+
+bool QDirectFBWindowSurface::scroll(const QRegion &region, int dx, int dy)
+{
+ if (!dfbSurface || !(flipFlags & DSFLIP_BLIT) || region.rectCount() != 1)
+ return false;
+ if (flushPending) {
+ dfbSurface->Flip(dfbSurface, 0, DSFLIP_BLIT);
+ } else {
+ flushPending = true;
+ }
+ dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX);
+ const QRect r = region.boundingRect();
+ const DFBRectangle rect = { r.x(), r.y(), r.width(), r.height() };
+ dfbSurface->Blit(dfbSurface, dfbSurface, &rect, r.x() + dx, r.y() + dy);
+ return true;
+}
+
+bool QDirectFBWindowSurface::move(const QPoint &moveBy)
+{
+ setGeometry(geometry().translated(moveBy));
+ return true;
+}
+
+void QDirectFBWindowSurface::setOpaque(bool opaque)
+{
+ SurfaceFlags flags = surfaceFlags();
+ if (opaque != (flags & Opaque)) {
+ if (opaque) {
+ flags |= Opaque;
+ } else {
+ flags &= ~Opaque;
+ }
+ setSurfaceFlags(flags);
+ }
+}
+
+
+void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion &region,
+ const QPoint &offset)
+{
+ QWidget *win = window();
+ if (!win)
+ return;
+
+#if !defined(QT_NO_QWS_PROXYSCREEN) && !defined(QT_NO_GRAPHICSVIEW)
+ QWExtra *extra = qt_widget_private(widget)->extraData();
+ if (extra && extra->proxyWidget)
+ return;
+#else
+ Q_UNUSED(widget);
+#endif
+
+ const quint8 windowOpacity = quint8(win->windowOpacity() * 0xff);
+ const QRect windowGeometry = geometry();
+#ifdef QT_DIRECTFB_WM
+ quint8 currentOpacity;
+ Q_ASSERT(dfbWindow);
+ dfbWindow->GetOpacity(dfbWindow, &currentOpacity);
+ if (currentOpacity != windowOpacity) {
+ dfbWindow->SetOpacity(dfbWindow, windowOpacity);
+ }
+
+ screen->flipSurface(dfbSurface, flipFlags, region, offset);
+#else
+ setOpaque(windowOpacity == 0xff);
+ if (mode == Offscreen) {
+ screen->exposeRegion(region.translated(offset + geometry().topLeft()), 0);
+ } else {
+ screen->flipSurface(dfbSurface, flipFlags, region, offset);
+ }
+#endif
+
+#ifdef QT_DIRECTFB_TIMING
+ enum { Secs = 3 };
+ ++frames;
+ if (timer.elapsed() >= Secs * 1000) {
+ qDebug("%d fps", int(double(frames) / double(Secs)));
+ frames = 0;
+ timer.restart();
+ }
+#endif
+ flushPending = false;
+}
+
+void QDirectFBWindowSurface::beginPaint(const QRegion &region)
+{
+ if (!engine) {
+ engine = new QDirectFBPaintEngine(this);
+ }
+
+ if (dfbSurface) {
+ const QWidget *win = window();
+ if (win && win->testAttribute(Qt::WA_NoSystemBackground)) {
+ QDirectFBScreen::solidFill(dfbSurface, Qt::transparent, region);
+ }
+ }
+ flushPending = true;
+}
+
+void QDirectFBWindowSurface::endPaint(const QRegion &)
+{
+#ifdef QT_NO_DIRECTFB_SUBSURFACE
+ unlockSurface();
+#endif
+}
+
+IDirectFBSurface *QDirectFBWindowSurface::directFBSurface() const
+{
+ return dfbSurface;
+}
+
+
+IDirectFBSurface *QDirectFBWindowSurface::surfaceForWidget(const QWidget *widget, QRect *rect) const
+{
+ Q_ASSERT(widget);
+ if (!dfbSurface)
+ return 0;
+ QWidget *win = window();
+ Q_ASSERT(win);
+ if (rect) {
+ if (win == widget) {
+ *rect = widget->rect();
+ } else {
+ *rect = QRect(widget->mapTo(win, QPoint(0, 0)), widget->size());
+ }
+ }
+
+ Q_ASSERT(win == widget || win->isAncestorOf(widget));
+ return dfbSurface;
+}
+
+void QDirectFBWindowSurface::releaseSurface()
+{
+ if (dfbSurface) {
+#ifdef QT_DIRECTFB_SUBSURFACE
+ releaseSubSurface();
+#else
+ unlockSurface();
+#endif
+#ifdef QT_NO_DIRECTFB_WM
+ Q_ASSERT(screen->primarySurface());
+ if (dfbSurface != screen->primarySurface())
+#endif
+
+ dfbSurface->Release(dfbSurface);
+ dfbSurface = 0;
+ }
+}
+
+void QDirectFBWindowSurface::updateIsOpaque()
+{
+ const QWidget *win = window();
+ Q_ASSERT(win);
+ if (win->testAttribute(Qt::WA_OpaquePaintEvent) || win->testAttribute(Qt::WA_PaintOnScreen)) {
+ setOpaque(true);
+ return;
+ }
+
+ if (qFuzzyCompare(static_cast<float>(win->windowOpacity()), 1.0f)) {
+ const QPalette &pal = win->palette();
+
+ if (win->autoFillBackground()) {
+ const QBrush &autoFillBrush = pal.brush(win->backgroundRole());
+ if (autoFillBrush.style() != Qt::NoBrush && autoFillBrush.isOpaque()) {
+ setOpaque(true);
+ return;
+ }
+ }
+
+ if (win->isWindow() && !win->testAttribute(Qt::WA_NoSystemBackground)) {
+ const QBrush &windowBrush = win->palette().brush(QPalette::Window);
+ if (windowBrush.style() != Qt::NoBrush && windowBrush.isOpaque()) {
+ setOpaque(true);
+ return;
+ }
+ }
+ }
+ setOpaque(false);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QWS_DIRECTFB
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h
new file mode 100644
index 0000000000..75d462b523
--- /dev/null
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDIRECFBWINDOWSURFACE_H
+#define QDIRECFBWINDOWSURFACE_H
+
+#include "qdirectfbpaintengine.h"
+#include "qdirectfbpaintdevice.h"
+#include "qdirectfbscreen.h"
+
+#ifndef QT_NO_QWS_DIRECTFB
+
+#include <private/qpaintengine_raster_p.h>
+#include <private/qwindowsurface_qws_p.h>
+
+#ifdef QT_DIRECTFB_TIMING
+#include <qdatetime.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QDirectFBWindowSurface : public QWSWindowSurface, public QDirectFBPaintDevice
+{
+public:
+ QDirectFBWindowSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen *scr);
+ QDirectFBWindowSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen *scr, QWidget *widget);
+ ~QDirectFBWindowSurface();
+
+#ifdef QT_DIRECTFB_WM
+ void raise();
+#endif
+ bool isValid() const;
+
+ void setGeometry(const QRect &rect);
+
+ QString key() const { return QLatin1String("directfb"); }
+ QByteArray permanentState() const;
+ void setPermanentState(const QByteArray &state);
+
+ bool scroll(const QRegion &area, int dx, int dy);
+
+ bool move(const QPoint &offset);
+
+ QImage image() const { return QImage(); }
+ QPaintDevice *paintDevice() { return this; }
+
+ void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
+
+ void beginPaint(const QRegion &);
+ void endPaint(const QRegion &);
+
+ IDirectFBSurface *surfaceForWidget(const QWidget *widget, QRect *rect) const;
+ IDirectFBSurface *directFBSurface() const;
+#ifdef QT_DIRECTFB_WM
+ IDirectFBWindow *directFBWindow() const;
+#endif
+private:
+ void updateIsOpaque();
+ void setOpaque(bool opaque);
+ void releaseSurface();
+
+#ifdef QT_DIRECTFB_WM
+ void createWindow(const QRect &rect);
+ IDirectFBWindow *dfbWindow;
+#else
+ enum Mode {
+ Primary,
+ Offscreen
+ } mode;
+#endif
+
+ DFBSurfaceFlipFlags flipFlags;
+ bool boundingRectFlip;
+ bool flushPending;
+#ifdef QT_DIRECTFB_TIMING
+ int frames;
+ QTime timer;
+#endif
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_QWS_DIRECTFB
+
+#endif // QDIRECFBWINDOWSURFACE_H
diff --git a/src/plugins/gfxdrivers/eglnullws/README b/src/plugins/gfxdrivers/eglnullws/README
new file mode 100644
index 0000000000..80b88c7e01
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/README
@@ -0,0 +1,48 @@
+EGL NullWS QScreen Driver
+=========================
+
+If your application draws everything within a single full-screen QGLWidget then
+you may wish to use this QScreen plugin driver. This driver simply returns 0
+(as a EGLNativeWindowType value) when asked by the QtOpenGl module to create a
+native window. Some OpenGL ES implementations (including PowerVR) interpret this
+to mean that a full-screen OpenGL context is desired without any windowing
+support (NullWS).
+
+To tell a Qt/Embedded application to use this driver use the -display command
+line option or the QWS_DISPLAY environment variable. The following driver
+options are supported:
+
+size=WIDTHxHEIGHT Screen size reported by the driver
+format=FORMAT Screen format
+
+Run with '-display eglnullws:help' to get a full list of options (including a
+list of supported format strings).
+
+If you choose a screen format that is not supported by the hardware then the
+QtOpenGl module will write out a list of supported EGL configurations. Use
+one of the supported screen formats from this list.
+
+Using this driver with PowerVR hardware
+---------------------------------------
+
+Using this plugin with PowerVR hardware should give a significant speedup
+compared to running with the Qt powervr driver (with a full-screen QGLWidget).
+This is because sacrificing the window system allows less work to be done in
+order to get graphics on the screen. Using this driver also avoids the memory
+fragmentation issues present in the powervr driver and avoids any direct
+dependencies on the deprecated PVR2D API from Imagination Technologies.
+
+To use this driver ensure you have /etc/powervr.ini with contents similar to
+this:
+
+[default]
+WindowSystem=libpvrPVR2D_FLIPWSEGL.so
+
+This driver will also function with libpvrPVR2D_FRONTWSEGL.so, but that draws
+straight into the framebuffer and will therefore cause flickering (it can be
+useful for performance testing though). The flip plugin uses triple buffering,
+so you will need to set the virtual vertical resolution of your framebuffer to
+be three times the physical vertical resolution of your screen. This can be
+done with 'fbset -vyres'. Failure to do this can cause system crashes. You
+should also ensure that the plugin you choose in powervr.ini is in your library
+path (it may just silently default to the flip plugin if not).
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullws.pro b/src/plugins/gfxdrivers/eglnullws/eglnullws.pro
new file mode 100644
index 0000000000..242ab07ecd
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullws.pro
@@ -0,0 +1,18 @@
+TARGET = qeglnullws
+include(../../qpluginbase.pri)
+
+CONFIG += warn_on
+QT += opengl
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers
+
+target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers
+INSTALLS += target
+
+HEADERS = eglnullwsscreen.h \
+ eglnullwsscreenplugin.h \
+ eglnullwswindowsurface.h
+
+SOURCES = eglnullwsscreen.cpp \
+ eglnullwsscreenplugin.cpp \
+ eglnullwswindowsurface.cpp
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.cpp b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.cpp
new file mode 100644
index 0000000000..d090e857ad
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "eglnullwsscreen.h"
+#include "eglnullwswindowsurface.h"
+#include "eglnullwsscreenplugin.h"
+
+#include <QHash>
+#include <QDebug>
+
+namespace
+{
+ class EGLNullWSScreenSurfaceFunctions : public QGLScreenSurfaceFunctions
+ {
+ public:
+ virtual bool createNativeWindow(QWidget *, EGLNativeWindowType *native)
+ { *native = 0; return true; }
+ };
+}
+
+EGLNullWSScreen::EGLNullWSScreen(int displayId) : QGLScreen(displayId) {}
+
+EGLNullWSScreen::~EGLNullWSScreen() {}
+
+bool EGLNullWSScreen::initDevice()
+{
+ setSurfaceFunctions(new EGLNullWSScreenSurfaceFunctions);
+ return true;
+}
+
+static const QHash<QString, QImage::Format> formatDictionary()
+{
+ QHash<QString, QImage::Format> dictionary;
+ dictionary["rgb32"] = QImage::Format_RGB32;
+ dictionary["argb32"] = QImage::Format_ARGB32;
+ dictionary["rgb16"] = QImage::Format_RGB16;
+ dictionary["rgb666"] = QImage::Format_RGB666;
+ dictionary["rgb555"] = QImage::Format_RGB555;
+ dictionary["rgb888"] = QImage::Format_RGB888;
+ dictionary["rgb444"] = QImage::Format_RGB444;
+ return dictionary;
+}
+
+static int depthForFormat(QImage::Format format)
+{
+ switch (format) {
+ case QImage::Format_RGB32: return 32;
+ case QImage::Format_ARGB32: return 32;
+ case QImage::Format_RGB16: return 16;
+ case QImage::Format_RGB666: return 24;
+ case QImage::Format_RGB555: return 16;
+ case QImage::Format_RGB888: return 24;
+ case QImage::Format_RGB444: return 16;
+ default:
+ Q_ASSERT_X(false, "EGLNullWSScreen", "Unknown format");
+ return -1;
+ }
+}
+
+static void printHelp(const QHash<QString, QImage::Format> &formatDictionary)
+{
+ QByteArray formatsBuf;
+ QTextStream(&formatsBuf) << QStringList(formatDictionary.keys()).join(", ");
+ qWarning(
+ "%s: Valid options are:\n"
+ "size=WIDTHxHEIGHT Screen size reported by this driver\n"
+ "format=FORMAT Screen format, where FORMAT is one of the following:\n"
+ " %s\n",
+ PluginName,
+ formatsBuf.constData());
+}
+
+bool EGLNullWSScreen::connect(const QString &displaySpec)
+{
+ const QStringList args = displaySpec.section(':', 1).split(':', QString::SkipEmptyParts);
+ const QHash<QString, QImage::Format> formatDict = formatDictionary();
+ Q_FOREACH(const QString arg, args) {
+ const QString optionName = arg.section('=', 0, 0);
+ const QString optionArg = arg.section('=', 1);
+ if (optionName == QLatin1String("size")) {
+ w = optionArg.section('x', 0, 0).toInt();
+ h = optionArg.section('x', 1, 1).toInt();
+ } else if (optionName == QLatin1String("format")) {
+ if (formatDict.contains(optionArg))
+ setPixelFormat(formatDict.value(optionArg));
+ else
+ printHelp(formatDict);
+ } else {
+ printHelp(formatDict);
+ }
+ }
+
+ if (w == 0 || h == 0) {
+ w = 640;
+ h = 480;
+ qWarning("%s: Using default screen size %dx%d", PluginName, w, h);
+ }
+ dw = w;
+ dh = h;
+
+ if (pixelFormat() == QImage::Format_Invalid) {
+ qWarning("%s: Using default screen format argb32", PluginName);
+ setPixelFormat(QImage::Format_ARGB32);
+ }
+ d = depthForFormat(pixelFormat());
+
+ static const int Dpi = 120;
+ static const qreal ScalingFactor = static_cast<qreal>(25.4) / Dpi;
+ physWidth = qRound(dw * ScalingFactor);
+ physHeight = qRound(dh * ScalingFactor);
+
+ return true;
+}
+
+void EGLNullWSScreen::disconnect() {}
+
+void EGLNullWSScreen::shutdownDevice() {}
+
+void EGLNullWSScreen::setMode(int /*width*/, int /*height*/, int /*depth*/) {}
+
+void EGLNullWSScreen::blank(bool /*on*/) {}
+
+void EGLNullWSScreen::exposeRegion(QRegion /*r*/, int /*changing*/) {}
+
+QWSWindowSurface* EGLNullWSScreen::createSurface(QWidget *widget) const
+{
+ if (qobject_cast<QGLWidget*>(widget)) {
+ return new EGLNullWSWindowSurface(widget);
+ } else {
+ qWarning("%s: Creating non-GL surface", PluginName);
+ return QScreen::createSurface(widget);
+ }
+}
+
+QWSWindowSurface* EGLNullWSScreen::createSurface(const QString &key) const
+{
+ if (key == QLatin1String("eglnullws")) {
+ return new EGLNullWSWindowSurface;
+ } else {
+ qWarning("%s: Creating non-GL surface", PluginName);
+ return QScreen::createSurface(key);
+ }
+}
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.h b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.h
new file mode 100644
index 0000000000..08ba2fa0cc
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef EGLNULLWSSCREEN
+#define EGLNULLWSSCREEN
+
+#include <QGLScreen>
+
+class EGLNullWSScreen : public QGLScreen
+{
+public:
+ EGLNullWSScreen(int displayId);
+ ~EGLNullWSScreen();
+
+ bool initDevice();
+ bool connect(const QString &displaySpec);
+ void disconnect();
+ void shutdownDevice();
+
+ void setMode(int width, int height, int depth);
+ void blank(bool on);
+
+ void exposeRegion(QRegion r, int changing);
+
+ QWSWindowSurface* createSurface(QWidget *widget) const;
+ QWSWindowSurface* createSurface(const QString &key) const;
+
+ bool hasOpenGL() { return true; }
+};
+
+#endif // EGLNULLWSSCREEN
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.cpp b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.cpp
new file mode 100644
index 0000000000..f7080333f8
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "eglnullwsscreenplugin.h"
+#include "eglnullwsscreen.h"
+
+#include <QScreenDriverPlugin>
+#include <QStringList>
+
+class EGLNullWSScreenPlugin : public QScreenDriverPlugin
+{
+public:
+ virtual QStringList keys() const;
+ virtual QScreen *create(const QString& driver, int displayId);
+};
+
+QStringList EGLNullWSScreenPlugin::keys() const
+{
+ return QStringList() << QLatin1String(PluginName);
+}
+
+QScreen *EGLNullWSScreenPlugin::create(const QString& driver, int displayId)
+{
+ return (driver.toLower() == QLatin1String(PluginName) ?
+ new EGLNullWSScreen(displayId) : 0);
+}
+
+Q_EXPORT_PLUGIN2(qeglnullws, EGLNullWSScreenPlugin)
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.h b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.h
new file mode 100644
index 0000000000..64a362374d
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef EGLNULLWSSCREENPLUGIN_H
+#define EGLNULLWSSCREENPLUGIN_H
+
+const char *const PluginName = "eglnullws";
+
+#endif // EGLNULLWSSCREENPLUGIN_H
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.cpp b/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.cpp
new file mode 100644
index 0000000000..8af4d406a5
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "eglnullwswindowsurface.h"
+#include "eglnullwsscreenplugin.h"
+
+#include <QGLWidget>
+
+static const QWSWindowSurface::SurfaceFlags Flags
+ = QWSWindowSurface::RegionReserved | QWSWindowSurface::RegionReserved;
+
+EGLNullWSWindowSurface::EGLNullWSWindowSurface(QWidget *w)
+ :
+ QWSGLWindowSurface(w),
+ widget(w)
+{
+ setSurfaceFlags(Flags);
+}
+
+EGLNullWSWindowSurface::EGLNullWSWindowSurface()
+ : widget(0)
+{
+ setSurfaceFlags(Flags);
+}
+
+EGLNullWSWindowSurface::~EGLNullWSWindowSurface() {}
+
+QString EGLNullWSWindowSurface::key() const
+{
+ return QLatin1String(PluginName);
+}
+
+QPaintDevice *EGLNullWSWindowSurface::paintDevice()
+{
+ return widget;
+}
+
+bool EGLNullWSWindowSurface::isValid() const
+{
+ return qobject_cast<QGLWidget *>(window());
+}
+
+QImage EGLNullWSWindowSurface::image() const
+{
+ return QImage();
+}
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.h b/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.h
new file mode 100644
index 0000000000..793d3256d6
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef EGLNULLWSWINDOWSURFACE_H
+#define EGLNULLWSWINDOWSURFACE_H
+
+#include <private/qglwindowsurface_qws_p.h>
+
+class EGLNullWSWindowSurface : public QWSGLWindowSurface
+{
+public:
+ EGLNullWSWindowSurface(QWidget *widget);
+ EGLNullWSWindowSurface();
+ virtual ~EGLNullWSWindowSurface();
+
+ virtual QString key() const;
+ virtual QPaintDevice *paintDevice();
+ virtual bool isValid() const;
+ virtual QImage image() const;
+
+private:
+ QWidget *widget;
+};
+
+#endif // EGLNULLWSWINDOWSURFACE_H
diff --git a/src/plugins/gfxdrivers/gfxdrivers.pro b/src/plugins/gfxdrivers/gfxdrivers.pro
new file mode 100644
index 0000000000..1f38942a50
--- /dev/null
+++ b/src/plugins/gfxdrivers/gfxdrivers.pro
@@ -0,0 +1,10 @@
+TEMPLATE = subdirs
+contains(gfx-plugins, ahi) :SUBDIRS += ahi
+contains(gfx-plugins, directfb) :SUBDIRS += directfb
+contains(gfx-plugins, linuxfb) :SUBDIRS += linuxfb
+contains(gfx-plugins, qvfb) :SUBDIRS += qvfb
+contains(gfx-plugins, vnc) :SUBDIRS += vnc
+contains(gfx-plugins, transformed) :SUBDIRS += transformed
+contains(gfx-plugins, svgalib) :SUBDIRS += svgalib
+contains(gfx-plugins, powervr) :SUBDIRS += powervr
+contains(gfx-plugins, eglnullws) :SUBDIRS += eglnullws
diff --git a/src/plugins/gfxdrivers/linuxfb/linuxfb.pro b/src/plugins/gfxdrivers/linuxfb/linuxfb.pro
new file mode 100644
index 0000000000..2a376e4158
--- /dev/null
+++ b/src/plugins/gfxdrivers/linuxfb/linuxfb.pro
@@ -0,0 +1,14 @@
+TARGET = qscreenlinuxfb
+include(../../qpluginbase.pri)
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers
+
+target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers
+INSTALLS += target
+
+DEFINES += QT_QWS_LINUXFB
+
+HEADERS = $$QT_SOURCE_TREE/src/gui/embedded/qscreenlinuxfb_qws.h
+
+SOURCES = main.cpp \
+ $$QT_SOURCE_TREE/src/gui/embedded/qscreenlinuxfb_qws.cpp
diff --git a/src/plugins/gfxdrivers/linuxfb/main.cpp b/src/plugins/gfxdrivers/linuxfb/main.cpp
new file mode 100644
index 0000000000..6ea7b9ca24
--- /dev/null
+++ b/src/plugins/gfxdrivers/linuxfb/main.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qscreendriverplugin_qws.h>
+#include <qscreenlinuxfb_qws.h>
+#include <qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QScreenLinuxFbPlugin : public QScreenDriverPlugin
+{
+public:
+ QScreenLinuxFbPlugin();
+
+ QStringList keys() const;
+ QScreen *create(const QString&, int displayId);
+};
+
+QScreenLinuxFbPlugin::QScreenLinuxFbPlugin()
+ : QScreenDriverPlugin()
+{
+}
+
+QStringList QScreenLinuxFbPlugin::keys() const
+{
+ QStringList list;
+ list << QLatin1String("LinuxFb");
+ return list;
+}
+
+QScreen* QScreenLinuxFbPlugin::create(const QString& driver, int displayId)
+{
+ if (driver.toLower() == QLatin1String("linuxfb"))
+ return new QLinuxFbScreen(displayId);
+
+ return 0;
+}
+
+Q_EXPORT_PLUGIN2(qscreenlinuxfb, QScreenLinuxFbPlugin)
+
+QT_END_NAMESPACE
diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro b/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro
new file mode 100644
index 0000000000..595cf45301
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro
@@ -0,0 +1,26 @@
+TEMPLATE = lib
+TARGET = pvrQWSWSEGL
+CONFIG += dll warn_on
+CONFIG -= qt
+
+HEADERS+=\
+ pvrqwsdrawable.h \
+ pvrqwsdrawable_p.h
+
+SOURCES+=\
+ pvrqwsdrawable.c \
+ pvrqwswsegl.c
+
+INCLUDEPATH += $$QMAKE_INCDIR_EGL
+
+for(p, QMAKE_LIBDIR_EGL) {
+ exists($$p):LIBS += -L$$p
+}
+
+LIBS += -lpvr2d
+
+DESTDIR = $$QMAKE_LIBDIR_QT
+target.path = $$[QT_INSTALL_LIBS]
+INSTALLS += target
+
+include(../powervr.pri) \ No newline at end of file
diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c
new file mode 100644
index 0000000000..8dc0120fe1
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c
@@ -0,0 +1,830 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pvrqwsdrawable_p.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <linux/fb.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+PvrQwsDisplay pvrQwsDisplay;
+
+static void pvrQwsDestroyDrawableForced(PvrQwsDrawable *drawable);
+
+/* Initialize the /dev/fbN device for a specific screen */
+static int pvrQwsInitFbScreen(int screen)
+{
+ struct fb_var_screeninfo var;
+ struct fb_fix_screeninfo fix;
+ unsigned long start;
+ unsigned long length;
+ int width, height, stride;
+ PVR2DFORMAT format;
+ void *mapped;
+ int fd, bytesPerPixel;
+ char name[64];
+ PVR2DMEMINFO *memInfo;
+ unsigned long pageAddresses[2];
+
+ /* Bail out if already initialized, or the number is incorrect */
+ if (screen < 0 || screen >= PVRQWS_MAX_SCREENS)
+ return 0;
+ if (pvrQwsDisplay.screens[screen].initialized)
+ return 1;
+
+ /* Open the framebuffer and fetch its properties */
+ sprintf(name, "/dev/fb%d", screen);
+ fd = open(name, O_RDWR, 0);
+ if (fd < 0) {
+ perror(name);
+ return 0;
+ }
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &var) < 0) {
+ perror("FBIOGET_VSCREENINFO");
+ close(fd);
+ return 0;
+ }
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &fix) < 0) {
+ perror("FBIOGET_FSCREENINFO");
+ close(fd);
+ return 0;
+ }
+ width = var.xres;
+ height = var.yres;
+ bytesPerPixel = var.bits_per_pixel / 8;
+ stride = fix.line_length;
+ format = PVR2D_1BPP;
+ if (var.bits_per_pixel == 16) {
+ if (var.red.length == 5 && var.green.length == 6 &&
+ var.blue.length == 5 && var.red.offset == 11 &&
+ var.green.offset == 5 && var.blue.offset == 0) {
+ format = PVR2D_RGB565;
+ }
+ if (var.red.length == 4 && var.green.length == 4 &&
+ var.blue.length == 4 && var.transp.length == 4 &&
+ var.red.offset == 8 && var.green.offset == 4 &&
+ var.blue.offset == 0 && var.transp.offset == 12) {
+ format = PVR2D_ARGB4444;
+ }
+ } else if (var.bits_per_pixel == 32) {
+ if (var.red.length == 8 && var.green.length == 8 &&
+ var.blue.length == 8 && var.transp.length == 8 &&
+ var.red.offset == 16 && var.green.offset == 8 &&
+ var.blue.offset == 0 && var.transp.offset == 24) {
+ format = PVR2D_ARGB8888;
+ }
+ }
+ if (format == PVR2D_1BPP) {
+ fprintf(stderr, "%s: could not find a suitable PVR2D pixel format\n", name);
+ close(fd);
+ return 0;
+ }
+ start = fix.smem_start;
+ length = var.xres_virtual * var.yres_virtual * bytesPerPixel;
+
+ if (screen == 0) {
+ /* We use PVR2DGetFrameBuffer to map the first screen.
+ On some chipsets it is more reliable than using PVR2DMemWrap */
+ mapped = 0;
+ memInfo = 0;
+ } else {
+ /* Other screens: map the framebuffer region into memory */
+ mapped = mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (!mapped || mapped == (void *)(-1)) {
+ perror("mmap");
+ close(fd);
+ return 0;
+ }
+
+ /* Allocate a PVR2D memory region for the framebuffer */
+ memInfo = 0;
+ if (pvrQwsDisplay.context) {
+ pageAddresses[0] = start & 0xFFFFF000;
+ pageAddresses[1] = 0;
+ if (PVR2DMemWrap
+ (pvrQwsDisplay.context, mapped, PVR2D_WRAPFLAG_CONTIGUOUS,
+ length, pageAddresses, &memInfo) != PVR2D_OK) {
+ munmap(mapped, length);
+ close(fd);
+ return 0;
+ }
+ }
+ }
+
+ /* We don't need the file descriptor any more */
+ close(fd);
+
+ /* The framebuffer is ready, so initialize the PvrQwsScreenInfo */
+ pvrQwsDisplay.screens[screen].screenRect.x = 0;
+ pvrQwsDisplay.screens[screen].screenRect.y = 0;
+ pvrQwsDisplay.screens[screen].screenRect.width = width;
+ pvrQwsDisplay.screens[screen].screenRect.height = height;
+ pvrQwsDisplay.screens[screen].screenStride = stride;
+ pvrQwsDisplay.screens[screen].pixelFormat = format;
+ pvrQwsDisplay.screens[screen].bytesPerPixel = bytesPerPixel;
+ pvrQwsDisplay.screens[screen].screenDrawable = 0;
+ if (mapped) {
+ /* Don't set these fields if mapped is 0, because PVR2DGetFrameBuffer
+ may have already been called and set them */
+ pvrQwsDisplay.screens[screen].frameBuffer = memInfo;
+ pvrQwsDisplay.screens[screen].mapped = mapped;
+ }
+ pvrQwsDisplay.screens[screen].mappedLength = length;
+ pvrQwsDisplay.screens[screen].screenStart = start;
+ pvrQwsDisplay.screens[screen].needsUnmap = (mapped != 0);
+ pvrQwsDisplay.screens[screen].initialized = 1;
+ return 1;
+}
+
+/* Called when a new drawable is added to ensure that we have a
+ PVR2D context and framebuffer PVR2DMEMINFO blocks */
+static int pvrQwsAddDrawable(void)
+{
+ int numDevs, screen;
+ PVR2DDEVICEINFO *devs;
+ unsigned long devId;
+ unsigned long pageAddresses[2];
+ PVR2DMEMINFO *memInfo;
+ PVR2DDISPLAYINFO displayInfo;
+
+ /* Bail out early if this is not the first drawable */
+ if (pvrQwsDisplay.numDrawables > 0) {
+ ++(pvrQwsDisplay.numDrawables);
+ return 1;
+ }
+
+ /* Find the first PVR2D device in the system and open it */
+ numDevs = PVR2DEnumerateDevices(0);
+ if (numDevs <= 0)
+ return 0;
+ devs = (PVR2DDEVICEINFO *)malloc(sizeof(PVR2DDEVICEINFO) * numDevs);
+ if (!devs)
+ return 0;
+ if (PVR2DEnumerateDevices(devs) != PVR2D_OK) {
+ free(devs);
+ return 0;
+ }
+ devId = devs[0].ulDevID;
+ free(devs);
+ if (PVR2DCreateDeviceContext(devId, &pvrQwsDisplay.context, 0) != PVR2D_OK)
+ return 0;
+ pvrQwsDisplay.numFlipBuffers = 0;
+ pvrQwsDisplay.flipChain = 0;
+ if (PVR2DGetDeviceInfo(pvrQwsDisplay.context, &displayInfo) == PVR2D_OK) {
+ if (displayInfo.ulMaxFlipChains > 0 && displayInfo.ulMaxBuffersInChain > 0)
+ pvrQwsDisplay.numFlipBuffers = displayInfo.ulMaxBuffersInChain;
+ if (pvrQwsDisplay.numFlipBuffers > PVRQWS_MAX_FLIP_BUFFERS)
+ pvrQwsDisplay.numFlipBuffers = PVRQWS_MAX_FLIP_BUFFERS;
+ }
+
+ /* Create the PVR2DMEMINFO blocks for the active framebuffers */
+ for (screen = 0; screen < PVRQWS_MAX_SCREENS; ++screen) {
+ if (screen != 0 && pvrQwsDisplay.screens[screen].mapped) {
+ pageAddresses[0]
+ = pvrQwsDisplay.screens[screen].screenStart & 0xFFFFF000;
+ pageAddresses[1] = 0;
+ if (PVR2DMemWrap
+ (pvrQwsDisplay.context,
+ pvrQwsDisplay.screens[screen].mapped,
+ PVR2D_WRAPFLAG_CONTIGUOUS,
+ pvrQwsDisplay.screens[screen].mappedLength,
+ pageAddresses, &memInfo) != PVR2D_OK) {
+ PVR2DDestroyDeviceContext(pvrQwsDisplay.context);
+ pvrQwsDisplay.context = 0;
+ return 0;
+ }
+ pvrQwsDisplay.screens[screen].frameBuffer = memInfo;
+ } else if (screen == 0) {
+ if (PVR2DGetFrameBuffer
+ (pvrQwsDisplay.context,
+ PVR2D_FB_PRIMARY_SURFACE, &memInfo) != PVR2D_OK) {
+ fprintf(stderr, "QWSWSEGL: could not get the primary framebuffer surface\n");
+ PVR2DDestroyDeviceContext(pvrQwsDisplay.context);
+ pvrQwsDisplay.context = 0;
+ return 0;
+ }
+ pvrQwsDisplay.screens[screen].frameBuffer = memInfo;
+ pvrQwsDisplay.screens[screen].mapped = memInfo->pBase;
+ }
+ }
+
+ /* Create a flip chain for the screen if supported by the hardware */
+ pvrQwsDisplay.usePresentBlit = 0;
+ if (pvrQwsDisplay.numFlipBuffers > 0) {
+ long stride = 0;
+ unsigned long flipId = 0;
+ unsigned long numBuffers;
+ if (PVR2DCreateFlipChain(pvrQwsDisplay.context, 0,
+ //PVR2D_CREATE_FLIPCHAIN_SHARED |
+ //PVR2D_CREATE_FLIPCHAIN_QUERY,
+ pvrQwsDisplay.numFlipBuffers,
+ pvrQwsDisplay.screens[0].screenRect.width,
+ pvrQwsDisplay.screens[0].screenRect.height,
+ pvrQwsDisplay.screens[0].pixelFormat,
+ &stride, &flipId, &(pvrQwsDisplay.flipChain))
+ == PVR2D_OK) {
+ pvrQwsDisplay.screens[0].screenStride = stride;
+ PVR2DGetFlipChainBuffers(pvrQwsDisplay.context,
+ pvrQwsDisplay.flipChain,
+ &numBuffers,
+ pvrQwsDisplay.flipBuffers);
+ } else {
+ pvrQwsDisplay.flipChain = 0;
+ pvrQwsDisplay.numFlipBuffers = 0;
+ }
+
+ /* PVR2DPresentBlt is a little more reliable than PVR2DBlt
+ when flip chains are present, even if we cannot create a
+ flip chain at the moment */
+ pvrQwsDisplay.usePresentBlit = 1;
+ }
+
+ /* The context is ready to go */
+ ++(pvrQwsDisplay.numDrawables);
+ return 1;
+}
+
+/* Called when the last drawable is destroyed. The PVR2D context
+ will be destroyed but the raw framebuffer memory will stay mapped */
+static void pvrQwsDestroyContext(void)
+{
+ int screen;
+ for (screen = 0; screen < PVRQWS_MAX_SCREENS; ++screen) {
+ if (pvrQwsDisplay.screens[screen].frameBuffer) {
+ PVR2DMemFree
+ (pvrQwsDisplay.context,
+ pvrQwsDisplay.screens[screen].frameBuffer);
+ pvrQwsDisplay.screens[screen].frameBuffer = 0;
+ }
+ }
+
+ if (pvrQwsDisplay.numFlipBuffers > 0)
+ PVR2DDestroyFlipChain(pvrQwsDisplay.context, pvrQwsDisplay.flipChain);
+ PVR2DDestroyDeviceContext(pvrQwsDisplay.context);
+ pvrQwsDisplay.context = 0;
+ pvrQwsDisplay.flipChain = 0;
+ pvrQwsDisplay.numFlipBuffers = 0;
+ pvrQwsDisplay.usePresentBlit = 0;
+}
+
+int pvrQwsDisplayOpen(void)
+{
+ int screen;
+
+ /* If the display is already open, increase reference count and return */
+ if (pvrQwsDisplay.refCount > 0) {
+ ++(pvrQwsDisplay.refCount);
+ return 1;
+ }
+
+ /* Open the framebuffer and map it directly */
+ if (!pvrQwsInitFbScreen(0)) {
+ --(pvrQwsDisplay.refCount);
+ return 0;
+ }
+
+ /* Clear the other screens. We will create them if they are referenced */
+ for (screen = 1; screen < PVRQWS_MAX_SCREENS; ++screen)
+ memset(&(pvrQwsDisplay.screens[screen]), 0, sizeof(PvrQwsScreenInfo));
+
+ /* The display is open and ready */
+ ++(pvrQwsDisplay.refCount);
+ return 1;
+}
+
+void pvrQwsDisplayClose(void)
+{
+ int screen;
+
+ if (pvrQwsDisplay.refCount == 0)
+ return;
+ if (--(pvrQwsDisplay.refCount) > 0)
+ return;
+
+ /* Prevent pvrQwsDestroyContext from being called for the time being */
+ ++pvrQwsDisplay.numDrawables;
+
+ /* Free the screens */
+ for (screen = 0; screen < PVRQWS_MAX_SCREENS; ++screen) {
+ PvrQwsScreenInfo *info = &(pvrQwsDisplay.screens[screen]);
+ if (info->screenDrawable)
+ pvrQwsDestroyDrawableForced(info->screenDrawable);
+ if (info->frameBuffer)
+ PVR2DMemFree(pvrQwsDisplay.context, info->frameBuffer);
+ if (info->mapped && info->needsUnmap)
+ munmap(info->mapped, info->mappedLength);
+ }
+
+ /* Now it is safe to destroy the PVR2D context */
+ --pvrQwsDisplay.numDrawables;
+ if (pvrQwsDisplay.context)
+ PVR2DDestroyDeviceContext(pvrQwsDisplay.context);
+
+ memset(&pvrQwsDisplay, 0, sizeof(pvrQwsDisplay));
+}
+
+int pvrQwsDisplayIsOpen(void)
+{
+ return (pvrQwsDisplay.refCount > 0);
+}
+
+/* Ensure that a specific screen has been initialized */
+static int pvrQwsEnsureScreen(int screen)
+{
+ if (screen < 0 || screen >= PVRQWS_MAX_SCREENS)
+ return 0;
+ if (!screen)
+ return 1;
+ return pvrQwsInitFbScreen(screen);
+}
+
+PvrQwsDrawable *pvrQwsScreenWindow(int screen)
+{
+ PvrQwsDrawable *drawable;
+
+ if (!pvrQwsEnsureScreen(screen))
+ return 0;
+
+ drawable = pvrQwsDisplay.screens[screen].screenDrawable;
+ if (drawable)
+ return drawable;
+
+ drawable = (PvrQwsDrawable *)calloc(1, sizeof(PvrQwsDrawable));
+ if (!drawable)
+ return 0;
+
+ drawable->type = PvrQwsScreen;
+ drawable->screen = screen;
+ drawable->pixelFormat = pvrQwsDisplay.screens[screen].pixelFormat;
+ drawable->rect = pvrQwsDisplay.screens[screen].screenRect;
+ drawable->visibleRects[0] = drawable->rect;
+ drawable->numVisibleRects = 1;
+ drawable->isFullScreen = 1;
+
+ if (!pvrQwsAddDrawable()) {
+ free(drawable);
+ return 0;
+ }
+
+ pvrQwsDisplay.screens[screen].screenDrawable = drawable;
+
+ return drawable;
+}
+
+PvrQwsDrawable *pvrQwsCreateWindow(int screen, long winId, const PvrQwsRect *rect)
+{
+ PvrQwsDrawable *drawable;
+
+ if (!pvrQwsEnsureScreen(screen))
+ return 0;
+
+ drawable = (PvrQwsDrawable *)calloc(1, sizeof(PvrQwsDrawable));
+ if (!drawable)
+ return 0;
+
+ drawable->type = PvrQwsWindow;
+ drawable->winId = winId;
+ drawable->refCount = 1;
+ drawable->screen = screen;
+ drawable->pixelFormat = pvrQwsDisplay.screens[screen].pixelFormat;
+ drawable->rect = *rect;
+
+ if (!pvrQwsAddDrawable()) {
+ free(drawable);
+ return 0;
+ }
+
+ drawable->nextWinId = pvrQwsDisplay.firstWinId;
+ pvrQwsDisplay.firstWinId = drawable;
+
+ return drawable;
+}
+
+PvrQwsDrawable *pvrQwsFetchWindow(long winId)
+{
+ PvrQwsDrawable *drawable = pvrQwsDisplay.firstWinId;
+ while (drawable != 0 && drawable->winId != winId)
+ drawable = drawable->nextWinId;
+
+ if (drawable)
+ ++(drawable->refCount);
+ return drawable;
+}
+
+int pvrQwsReleaseWindow(PvrQwsDrawable *drawable)
+{
+ if (drawable->type == PvrQwsWindow)
+ return (--(drawable->refCount) <= 0);
+ else
+ return 0;
+}
+
+PvrQwsDrawable *pvrQwsCreatePixmap(int width, int height, int screen)
+{
+ PvrQwsDrawable *drawable;
+
+ if (!pvrQwsEnsureScreen(screen))
+ return 0;
+
+ drawable = (PvrQwsDrawable *)calloc(1, sizeof(PvrQwsDrawable));
+ if (!drawable)
+ return 0;
+
+ drawable->type = PvrQwsPixmap;
+ drawable->screen = screen;
+ drawable->pixelFormat = pvrQwsDisplay.screens[screen].pixelFormat;
+ drawable->rect.x = 0;
+ drawable->rect.y = 0;
+ drawable->rect.width = width;
+ drawable->rect.height = height;
+
+ if (!pvrQwsAddDrawable()) {
+ free(drawable);
+ return 0;
+ }
+
+ return drawable;
+}
+
+static void pvrQwsDestroyDrawableForced(PvrQwsDrawable *drawable)
+{
+ /* Remove the drawable from the display's winId list */
+ PvrQwsDrawable *current = pvrQwsDisplay.firstWinId;
+ PvrQwsDrawable *prev = 0;
+ while (current != 0 && current != drawable) {
+ prev = current;
+ current = current->nextWinId;
+ }
+ if (current != 0) {
+ if (prev)
+ prev->nextWinId = current->nextWinId;
+ else
+ pvrQwsDisplay.firstWinId = current->nextWinId;
+ }
+
+ pvrQwsFreeBuffers(drawable);
+ free(drawable);
+
+ --pvrQwsDisplay.numDrawables;
+ if (pvrQwsDisplay.numDrawables == 0)
+ pvrQwsDestroyContext();
+}
+
+void pvrQwsDestroyDrawable(PvrQwsDrawable *drawable)
+{
+ if (drawable && drawable->type != PvrQwsScreen)
+ pvrQwsDestroyDrawableForced(drawable);
+}
+
+PvrQwsDrawableType pvrQwsGetDrawableType(PvrQwsDrawable *drawable)
+{
+ return drawable->type;
+}
+
+void pvrQwsSetVisibleRegion
+ (PvrQwsDrawable *drawable, const PvrQwsRect *rects, int numRects)
+{
+ int index, indexOut;
+ PvrQwsRect *rect;
+ PvrQwsRect *screenRect;
+
+ /* Visible regions don't make sense for pixmaps */
+ if (drawable->type == PvrQwsPixmap)
+ return;
+
+ /* Restrict the number of rectangles to prevent buffer overflow */
+ if (numRects > PVRQWS_MAX_VISIBLE_RECTS)
+ numRects = PVRQWS_MAX_VISIBLE_RECTS;
+ if (numRects > 0)
+ memcpy(drawable->visibleRects, rects, numRects * sizeof(PvrQwsRect));
+
+ /* Convert the rectangles into screen-relative co-ordinates and
+ then clamp them to the screen boundaries. If any of the
+ clamped rectangles are empty, remove them from the list */
+ screenRect = &(pvrQwsDisplay.screens[drawable->screen].screenRect);
+ indexOut = 0;
+ for (index = 0, rect = drawable->visibleRects; index < numRects; ++index, ++rect) {
+ if (rect->x < 0) {
+ rect->width += rect->x;
+ rect->x = 0;
+ if (rect->width < 0)
+ rect->width = 0;
+ } else if (rect->x >= screenRect->width) {
+ rect->x = screenRect->width;
+ rect->width = 0;
+ }
+ if ((rect->x + rect->width) > screenRect->width) {
+ rect->width = screenRect->width - rect->x;
+ }
+ if (rect->y < 0) {
+ rect->height += rect->y;
+ rect->y = 0;
+ if (rect->height < 0)
+ rect->height = 0;
+ } else if (rect->y >= screenRect->height) {
+ rect->y = screenRect->height;
+ rect->height = 0;
+ }
+ if ((rect->y + rect->height) > screenRect->height) {
+ rect->height = screenRect->height - rect->y;
+ }
+ if (rect->width > 0 && rect->height > 0) {
+ if (index != indexOut)
+ drawable->visibleRects[indexOut] = *rect;
+ ++indexOut;
+ }
+ }
+ drawable->numVisibleRects = indexOut;
+}
+
+void pvrQwsClearVisibleRegion(PvrQwsDrawable *drawable)
+{
+ if (drawable->type != PvrQwsPixmap)
+ drawable->numVisibleRects = 0;
+}
+
+void pvrQwsSetGeometry(PvrQwsDrawable *drawable, const PvrQwsRect *rect)
+{
+ /* We can only change the geometry of window drawables */
+ if (drawable->type != PvrQwsWindow)
+ return;
+
+ /* If the position has changed, then clear the visible region */
+ if (drawable->rect.x != rect->x || drawable->rect.y != rect->y) {
+ drawable->rect.x = rect->x;
+ drawable->rect.y = rect->y;
+ drawable->numVisibleRects = 0;
+ }
+
+ /* If the size has changed, then clear the visible region and
+ invalidate the drawable's buffers. Invalidating the buffers
+ will force EGL to recreate the drawable, which will then
+ allocate new buffers for the new size */
+ if (drawable->rect.width != rect->width ||
+ drawable->rect.height != rect->height) {
+ drawable->rect.width = rect->width;
+ drawable->rect.height = rect->height;
+ drawable->numVisibleRects = 0;
+ pvrQwsInvalidateBuffers(drawable);
+ }
+}
+
+void pvrQwsGetGeometry(PvrQwsDrawable *drawable, PvrQwsRect *rect)
+{
+ *rect = drawable->rect;
+}
+
+void pvrQwsSetRotation(PvrQwsDrawable *drawable, int angle)
+{
+ if (drawable->rotationAngle != angle) {
+ drawable->rotationAngle = angle;
+
+ /* Force the buffers to be recreated if the rotation angle changes */
+ pvrQwsInvalidateBuffers(drawable);
+ }
+}
+
+int pvrQwsGetStride(PvrQwsDrawable *drawable)
+{
+ if (drawable->backBuffersValid)
+ return drawable->strideBytes;
+ else
+ return 0;
+}
+
+PvrQwsPixelFormat pvrQwsGetPixelFormat(PvrQwsDrawable *drawable)
+{
+ return (PvrQwsPixelFormat)(drawable->pixelFormat);
+}
+
+void *pvrQwsGetRenderBuffer(PvrQwsDrawable *drawable)
+{
+ if (drawable->backBuffersValid)
+ return drawable->backBuffers[drawable->currentBackBuffer]->pBase;
+ else
+ return 0;
+}
+
+int pvrQwsAllocBuffers(PvrQwsDrawable *drawable)
+{
+ int index;
+ int numBuffers = PVRQWS_MAX_BACK_BUFFERS;
+ if (drawable->type == PvrQwsPixmap)
+ numBuffers = 1;
+ if (drawable->backBuffers[0]) {
+ if (drawable->backBuffersValid)
+ return 1;
+ if (!drawable->usingFlipBuffers) {
+ for (index = 0; index < numBuffers; ++index)
+ PVR2DMemFree(pvrQwsDisplay.context, drawable->backBuffers[index]);
+ }
+ }
+ drawable->stridePixels = (drawable->rect.width + 31) & ~31;
+ drawable->strideBytes =
+ drawable->stridePixels *
+ pvrQwsDisplay.screens[drawable->screen].bytesPerPixel;
+ drawable->usingFlipBuffers =
+ (pvrQwsDisplay.numFlipBuffers > 0 && drawable->isFullScreen);
+ if (drawable->usingFlipBuffers) {
+ if (numBuffers > (int)(pvrQwsDisplay.numFlipBuffers))
+ numBuffers = pvrQwsDisplay.numFlipBuffers;
+ for (index = 0; index < numBuffers; ++index)
+ drawable->backBuffers[index] = pvrQwsDisplay.flipBuffers[index];
+ } else {
+ for (index = 0; index < numBuffers; ++index) {
+ if (PVR2DMemAlloc(pvrQwsDisplay.context,
+ drawable->strideBytes * drawable->rect.height,
+ 128, 0,
+ &(drawable->backBuffers[index])) != PVR2D_OK) {
+ while (--index >= 0)
+ PVR2DMemFree(pvrQwsDisplay.context, drawable->backBuffers[index]);
+ memset(drawable->backBuffers, 0, sizeof(drawable->backBuffers));
+ drawable->backBuffersValid = 0;
+ return 0;
+ }
+ }
+ }
+ for (index = numBuffers; index < PVRQWS_MAX_BACK_BUFFERS; ++index) {
+ drawable->backBuffers[index] = drawable->backBuffers[0];
+ }
+ drawable->backBuffersValid = 1;
+ drawable->currentBackBuffer = 0;
+ return 1;
+}
+
+void pvrQwsFreeBuffers(PvrQwsDrawable *drawable)
+{
+ int index;
+ int numBuffers = PVRQWS_MAX_BACK_BUFFERS;
+ if (drawable->type == PvrQwsPixmap)
+ numBuffers = 1;
+ if (!drawable->usingFlipBuffers) {
+ for (index = 0; index < numBuffers; ++index) {
+ if (drawable->backBuffers[index])
+ PVR2DMemFree(pvrQwsDisplay.context, drawable->backBuffers[index]);
+ }
+ }
+ memset(drawable->backBuffers, 0, sizeof(drawable->backBuffers));
+ drawable->backBuffersValid = 0;
+ drawable->usingFlipBuffers = 0;
+}
+
+void pvrQwsInvalidateBuffers(PvrQwsDrawable *drawable)
+{
+ drawable->backBuffersValid = 0;
+}
+
+int pvrQwsGetBuffers
+ (PvrQwsDrawable *drawable, PVR2DMEMINFO **source, PVR2DMEMINFO **render)
+{
+ if (!drawable->backBuffersValid)
+ return 0;
+ *render = drawable->backBuffers[drawable->currentBackBuffer];
+ *source = drawable->backBuffers
+ [(drawable->currentBackBuffer + PVRQWS_MAX_BACK_BUFFERS - 1) %
+ PVRQWS_MAX_BACK_BUFFERS];
+ return 1;
+}
+
+int pvrQwsSwapBuffers(PvrQwsDrawable *drawable, int repaintOnly)
+{
+ PVR2DMEMINFO *buffer;
+ PvrQwsRect *rect;
+ int index;
+
+ /* Bail out if the back buffers have been invalidated */
+ if (!drawable->backBuffersValid)
+ return 0;
+
+ /* If there is a swap function, then use that instead */
+ if (drawable->swapFunction) {
+ (*(drawable->swapFunction))(drawable, drawable->userData, repaintOnly);
+ if (!repaintOnly) {
+ drawable->currentBackBuffer
+ = (drawable->currentBackBuffer + 1) % PVRQWS_MAX_BACK_BUFFERS;
+ }
+ return 1;
+ }
+
+ /* Iterate through the visible rectangles and blit them to the screen */
+ if (!repaintOnly) {
+ index = drawable->currentBackBuffer;
+ } else {
+ index = (drawable->currentBackBuffer + PVRQWS_MAX_BACK_BUFFERS - 1)
+ % PVRQWS_MAX_BACK_BUFFERS;
+ }
+ buffer = drawable->backBuffers[index];
+ rect = drawable->visibleRects;
+ if (drawable->usingFlipBuffers) {
+ PVR2DPresentFlip(pvrQwsDisplay.context, pvrQwsDisplay.flipChain, buffer, 0);
+ } else if (pvrQwsDisplay.usePresentBlit && drawable->numVisibleRects > 0) {
+ PVR2DRECT pvrRects[PVRQWS_MAX_VISIBLE_RECTS];
+ for (index = 0; index < drawable->numVisibleRects; ++index, ++rect) {
+ pvrRects[index].left = rect->x;
+ pvrRects[index].top = rect->y;
+ pvrRects[index].right = rect->x + rect->width;
+ pvrRects[index].bottom = rect->y + rect->height;
+ }
+ for (index = 0; index < drawable->numVisibleRects; index += 4) {
+ int numClip = drawable->numVisibleRects - index;
+ if (numClip > 4) /* No more than 4 clip rects at a time */
+ numClip = 4;
+ PVR2DSetPresentBltProperties
+ (pvrQwsDisplay.context,
+ PVR2D_PRESENT_PROPERTY_SRCSTRIDE |
+ PVR2D_PRESENT_PROPERTY_DSTSIZE |
+ PVR2D_PRESENT_PROPERTY_DSTPOS |
+ PVR2D_PRESENT_PROPERTY_CLIPRECTS,
+ drawable->strideBytes,
+ drawable->rect.width, drawable->rect.height,
+ drawable->rect.x, drawable->rect.y,
+ numClip, pvrRects + index, 0);
+ PVR2DPresentBlt(pvrQwsDisplay.context, buffer, 0);
+ }
+ PVR2DQueryBlitsComplete(pvrQwsDisplay.context, buffer, 1);
+ } else {
+ /* TODO: use PVR2DBltClipped for faster transfers of clipped windows */
+ PVR2DBLTINFO blit;
+ for (index = 0; index < drawable->numVisibleRects; ++index, ++rect) {
+ memset(&blit, 0, sizeof(blit));
+
+ blit.CopyCode = PVR2DROPcopy;
+ blit.BlitFlags = PVR2D_BLIT_DISABLE_ALL;
+
+ blit.pSrcMemInfo = buffer;
+ blit.SrcStride = drawable->strideBytes;
+ blit.SrcX = rect->x - drawable->rect.x;
+ blit.SrcY = rect->y - drawable->rect.y;
+ blit.SizeX = rect->width;
+ blit.SizeY = rect->height;
+ blit.SrcFormat = drawable->pixelFormat;
+
+ blit.pDstMemInfo = pvrQwsDisplay.screens[drawable->screen].frameBuffer;
+ blit.DstStride = pvrQwsDisplay.screens[drawable->screen].screenStride;
+ blit.DstX = rect->x;
+ blit.DstY = rect->y;
+ blit.DSizeX = rect->width;
+ blit.DSizeY = rect->height;
+ blit.DstFormat = pvrQwsDisplay.screens[drawable->screen].pixelFormat;
+
+ PVR2DBlt(pvrQwsDisplay.context, &blit);
+ }
+ }
+
+ /* Swap the buffers */
+ if (!repaintOnly) {
+ drawable->currentBackBuffer
+ = (drawable->currentBackBuffer + 1) % PVRQWS_MAX_BACK_BUFFERS;
+ }
+ return 1;
+}
+
+void pvrQwsSetSwapFunction
+ (PvrQwsDrawable *drawable, PvrQwsSwapFunction func, void *userData)
+{
+ drawable->swapFunction = func;
+ drawable->userData = userData;
+}
diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h
new file mode 100644
index 0000000000..8c8cc27018
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PVRQWSDRAWABLE_H
+#define PVRQWSDRAWABLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ int x, y, width, height;
+} PvrQwsRect;
+
+typedef enum
+{
+ PvrQwsScreen,
+ PvrQwsWindow,
+ PvrQwsPixmap
+
+} PvrQwsDrawableType;
+
+typedef enum
+{
+ PvrQws_1BPP = 0,
+ PvrQws_RGB565,
+ PvrQws_ARGB4444,
+ PvrQws_RGB888,
+ PvrQws_ARGB8888,
+ PvrQws_VGAEMU
+
+} PvrQwsPixelFormat;
+
+typedef struct _PvrQwsDrawable PvrQwsDrawable;
+
+typedef void (*PvrQwsSwapFunction)
+ (PvrQwsDrawable *drawable, void *userData, int repaintOnly);
+
+/* Open the display and prepare for window operations. The display
+ can be opened multiple times and each time is reference counted.
+ The display will be finally closed when the same number of
+ calls to pvrQwsDisplayClose() have been encountered */
+int pvrQwsDisplayOpen(void);
+
+/* Close the display */
+void pvrQwsDisplayClose(void);
+
+/* Determine if the display is already open */
+int pvrQwsDisplayIsOpen(void);
+
+/* Create a window that represents a particular framebuffer screen.
+ Initially the visible region will be the whole screen. If the screen
+ window has already been created, then will return the same value */
+PvrQwsDrawable *pvrQwsScreenWindow(int screen);
+
+/* Create a top-level window on a particular framebuffer screen.
+ Initially the window will not have a visible region */
+PvrQwsDrawable *pvrQwsCreateWindow(int screen, long winId, const PvrQwsRect *rect);
+
+/* Fetch an existing window for a window id and increase its refcount */
+PvrQwsDrawable *pvrQwsFetchWindow(long winId);
+
+/* Release the refcount on a window. Returns 1 if refcount is zero */
+int pvrQwsReleaseWindow(PvrQwsDrawable *drawable);
+
+/* Create an off-screen pixmap */
+PvrQwsDrawable *pvrQwsCreatePixmap(int width, int height, int screen);
+
+/* Destroy a previously-created drawable. Will not destroy screens. */
+void pvrQwsDestroyDrawable(PvrQwsDrawable *drawable);
+
+/* Get a drawable's type */
+PvrQwsDrawableType pvrQwsGetDrawableType(PvrQwsDrawable *drawable);
+
+/* Sets the visible region for a window or screen drawable. Pixels within
+ the specified rectangles will be copied to the framebuffer when the window
+ or screen is swapped. The rectangles should be in global co-ordinates */
+void pvrQwsSetVisibleRegion
+ (PvrQwsDrawable *drawable, const PvrQwsRect *rects, int numRects);
+
+/* Clear the visible region for a window or screen drawable,
+ effectively removing it from the screen */
+void pvrQwsClearVisibleRegion(PvrQwsDrawable *drawable);
+
+/* Set the geometry for a drawable. This can only be used on windows */
+void pvrQwsSetGeometry(PvrQwsDrawable *drawable, const PvrQwsRect *rect);
+
+/* Get the current geometry for a drawable */
+void pvrQwsGetGeometry(PvrQwsDrawable *drawable, PvrQwsRect *rect);
+
+/* Set the rotation angle in degrees */
+void pvrQwsSetRotation(PvrQwsDrawable *drawable, int angle);
+
+/* Get the line stride for a drawable. Returns zero if the buffers
+ are not allocated or have been invalidated */
+int pvrQwsGetStride(PvrQwsDrawable *drawable);
+
+/* Get the pixel format for a drawable */
+PvrQwsPixelFormat pvrQwsGetPixelFormat(PvrQwsDrawable *drawable);
+
+/* Get a pointer to the beginning of a drawable's current render buffer.
+ Returns null if the buffers are not allocated or have been invalidated */
+void *pvrQwsGetRenderBuffer(PvrQwsDrawable *drawable);
+
+/* Allocate the buffers associated with a drawable. We allocate one buffer
+ for pixmaps, and several for windows and screens */
+int pvrQwsAllocBuffers(PvrQwsDrawable *drawable);
+
+/* Free the buffers associated with a drawable */
+void pvrQwsFreeBuffers(PvrQwsDrawable *drawable);
+
+/* Invalidate the buffers associated with a drawable. The buffers will
+ still be allocated but the next attempt to swap the buffers will fail */
+void pvrQwsInvalidateBuffers(PvrQwsDrawable *drawable);
+
+/* Swap the back buffers for a window or screen and copy to the framebuffer */
+int pvrQwsSwapBuffers(PvrQwsDrawable *drawable, int repaintOnly);
+
+/* Set the swap function for a drawable. When pvrQwsSwapBuffers()
+ is called on the drawable, the supplied function will be called
+ instead of copying the drawable contents to the screen. This allows
+ higher-level compositors to know when a drawable has changed.
+ The swap function can be set to null to return to normal processing */
+void pvrQwsSetSwapFunction
+ (PvrQwsDrawable *drawable, PvrQwsSwapFunction func, void *userData);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable_p.h b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable_p.h
new file mode 100644
index 0000000000..3ad0693e02
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable_p.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PVRQWSDRAWABLE_P_H
+#define PVRQWSDRAWABLE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// reasons. This header file may change from version to version
+// without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <pvr2d.h>
+#include "pvrqwsdrawable.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PVRQWS_MAX_VISIBLE_RECTS 32
+#define PVRQWS_MAX_SCREENS 1
+#define PVRQWS_MAX_BACK_BUFFERS 2
+#define PVRQWS_MAX_FLIP_BUFFERS 2
+
+typedef struct {
+
+ PvrQwsRect screenRect;
+ int screenStride;
+ PVR2DFORMAT pixelFormat;
+ int bytesPerPixel;
+ PVR2DMEMINFO *frameBuffer;
+ PvrQwsDrawable *screenDrawable;
+ void *mapped;
+ int mappedLength;
+ unsigned long screenStart;
+ int needsUnmap;
+ int initialized;
+
+} PvrQwsScreenInfo;
+
+typedef struct {
+
+ int refCount;
+ PvrQwsScreenInfo screens[PVRQWS_MAX_SCREENS];
+ PVR2DCONTEXTHANDLE context;
+ int numDrawables;
+ unsigned long numFlipBuffers;
+ PVR2DFLIPCHAINHANDLE flipChain;
+ PVR2DMEMINFO *flipBuffers[PVRQWS_MAX_FLIP_BUFFERS];
+ int usePresentBlit;
+ PvrQwsDrawable *firstWinId;
+
+} PvrQwsDisplay;
+
+extern PvrQwsDisplay pvrQwsDisplay;
+
+struct _PvrQwsDrawable
+{
+ PvrQwsDrawableType type;
+ long winId;
+ int refCount;
+ PvrQwsRect rect;
+ int screen;
+ PVR2DFORMAT pixelFormat;
+ PvrQwsRect visibleRects[PVRQWS_MAX_VISIBLE_RECTS];
+ int numVisibleRects;
+ PVR2DMEMINFO *backBuffers[PVRQWS_MAX_BACK_BUFFERS];
+ int currentBackBuffer;
+ int backBuffersValid;
+ int usingFlipBuffers;
+ int isFullScreen;
+ int strideBytes;
+ int stridePixels;
+ int rotationAngle;
+ PvrQwsSwapFunction swapFunction;
+ void *userData;
+ PvrQwsDrawable *nextWinId;
+
+};
+
+/* Get the current source and render buffers for a drawable */
+int pvrQwsGetBuffers
+ (PvrQwsDrawable *drawable, PVR2DMEMINFO **source, PVR2DMEMINFO **render);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwswsegl.c b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwswsegl.c
new file mode 100644
index 0000000000..f861838e90
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwswsegl.c
@@ -0,0 +1,402 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <GLES/eglplatform.h>
+#include <wsegl.h>
+#include <pvr2d.h>
+#include <string.h>
+#include <sys/mman.h>
+#include "pvrqwsdrawable_p.h"
+
+#define WSEGL_UNUSED(x) (void)x;
+
+// If the PVR2D version is not specified, then assume MBX-style headers.
+// If the version is defined, then we assume that we have SGX-style headers.
+#if !defined(PVR2D_REV_MAJOR)
+#define WSEGL_CAP_WINDOWS_USE_HW_SYNC WSEGL_CAP_WINDOWS_USE_MBX_SYNC
+#define WSEGL_CAP_PIXMAPS_USE_HW_SYNC WSEGL_CAP_PIXMAPS_USE_MBX_SYNC
+#endif
+
+/* Capability information for the display */
+static WSEGLCaps const wseglDisplayCaps[] = {
+ {WSEGL_CAP_WINDOWS_USE_HW_SYNC, 1},
+ {WSEGL_CAP_PIXMAPS_USE_HW_SYNC, 1},
+ {WSEGL_NO_CAPS, 0}
+};
+
+/* Configuration information for the display */
+static WSEGLConfig wseglDisplayConfigs[] = {
+ {WSEGL_DRAWABLE_WINDOW, WSEGL_PIXELFORMAT_565, WSEGL_FALSE,
+ 0, 0, 0, WSEGL_OPAQUE, 0},
+ {WSEGL_DRAWABLE_PIXMAP, WSEGL_PIXELFORMAT_565, WSEGL_FALSE,
+ 0, 0, 0, WSEGL_OPAQUE, 0},
+ {WSEGL_NO_DRAWABLE, 0, 0, 0, 0, 0, 0, 0}
+};
+
+/* Determine if nativeDisplay is a valid display handle */
+static WSEGLError wseglIsDisplayValid(NativeDisplayType nativeDisplay)
+{
+ /* We only have the default display in this system */
+ if (nativeDisplay == WSEGL_DEFAULT_DISPLAY)
+ return WSEGL_SUCCESS;
+ else
+ return WSEGL_BAD_NATIVE_DISPLAY;
+}
+
+/* Initialize a native display for use with WSEGL */
+static WSEGLError wseglInitializeDisplay
+ (NativeDisplayType nativeDisplay, WSEGLDisplayHandle *display,
+ const WSEGLCaps **caps, WSEGLConfig **configs)
+{
+ WSEGLPixelFormat pixelFormat;
+
+ /* Bail out if the native display is incorrect */
+ if (nativeDisplay != WSEGL_DEFAULT_DISPLAY)
+ return WSEGL_CANNOT_INITIALISE;
+
+ /* Open the PVR/QWS display, which will initialize the framebuffer */
+ if (!pvrQwsDisplayOpen())
+ return WSEGL_CANNOT_INITIALISE;
+
+ /* Convert the PVR2D pixel format into a WSEGL pixel format */
+ switch (pvrQwsDisplay.screens[0].pixelFormat) {
+ case PVR2D_RGB565:
+ pixelFormat = WSEGL_PIXELFORMAT_565;
+ break;
+
+ case PVR2D_ARGB4444:
+ pixelFormat = WSEGL_PIXELFORMAT_4444;
+ break;
+
+ case PVR2D_ARGB8888:
+ pixelFormat = WSEGL_PIXELFORMAT_8888;
+ break;
+
+ default:
+ pvrQwsDisplayClose();
+ return WSEGL_CANNOT_INITIALISE;
+ }
+ wseglDisplayConfigs[0].ePixelFormat = pixelFormat;
+ wseglDisplayConfigs[1].ePixelFormat = pixelFormat;
+
+ /* The display has been initialized */
+ *display = (WSEGLDisplayHandle)&pvrQwsDisplay;
+ *caps = wseglDisplayCaps;
+ *configs = wseglDisplayConfigs;
+ return WSEGL_SUCCESS;
+}
+
+/* Close the WSEGL display */
+static WSEGLError wseglCloseDisplay(WSEGLDisplayHandle display)
+{
+ if (display == (WSEGLDisplayHandle)&pvrQwsDisplay)
+ pvrQwsDisplayClose();
+ return WSEGL_SUCCESS;
+}
+
+static WSEGLRotationAngle wseglRotationValue(int degrees)
+{
+ switch (degrees) {
+ case 90: return WSEGL_ROTATE_90;
+ case 180: return WSEGL_ROTATE_180;
+ case 270: return WSEGL_ROTATE_270;
+ default: return WSEGL_ROTATE_0;
+ }
+}
+
+/* Create the WSEGL drawable version of a native window */
+static WSEGLError wseglCreateWindowDrawable
+ (WSEGLDisplayHandle display, WSEGLConfig *config,
+ WSEGLDrawableHandle *drawable, NativeWindowType nativeWindow,
+ WSEGLRotationAngle *rotationAngle)
+{
+ PvrQwsDrawable *draw;
+
+ WSEGL_UNUSED(display);
+ WSEGL_UNUSED(config);
+
+ /* Check for special handles that indicate framebuffer screens */
+ if (nativeWindow >= (NativeWindowType)0 &&
+ nativeWindow < (NativeWindowType)PVRQWS_MAX_SCREENS) {
+ PvrQwsDrawable *screen = pvrQwsScreenWindow((int)nativeWindow);
+ if (!screen)
+ return WSEGL_OUT_OF_MEMORY;
+ *drawable = (WSEGLDrawableHandle)screen;
+ if (!pvrQwsAllocBuffers(screen))
+ return WSEGL_OUT_OF_MEMORY;
+ *rotationAngle = wseglRotationValue(screen->rotationAngle);
+ return WSEGL_SUCCESS;
+ }
+
+ /* The native window is the winId - fetch the underlying drawable */
+ draw = pvrQwsFetchWindow((long)nativeWindow);
+ if (!draw)
+ return WSEGL_BAD_DRAWABLE;
+
+ /* The drawable is ready to go */
+ *drawable = (WSEGLDrawableHandle)draw;
+ *rotationAngle = wseglRotationValue(draw->rotationAngle);
+ if (!pvrQwsAllocBuffers(draw))
+ return WSEGL_OUT_OF_MEMORY;
+ return WSEGL_SUCCESS;
+}
+
+/* Create the WSEGL drawable version of a native pixmap */
+static WSEGLError wseglCreatePixmapDrawable
+ (WSEGLDisplayHandle display, WSEGLConfig *config,
+ WSEGLDrawableHandle *drawable, NativePixmapType nativePixmap,
+ WSEGLRotationAngle *rotationAngle)
+{
+ WSEGL_UNUSED(display);
+ WSEGL_UNUSED(config);
+ if (!nativePixmap)
+ return WSEGL_BAD_NATIVE_PIXMAP;
+ if (!pvrQwsAllocBuffers((PvrQwsDrawable *)nativePixmap))
+ return WSEGL_OUT_OF_MEMORY;
+ *drawable = (WSEGLDrawableHandle)nativePixmap;
+ *rotationAngle = WSEGL_ROTATE_0;
+ return WSEGL_SUCCESS;
+}
+
+/* Delete a specific drawable */
+static WSEGLError wseglDeleteDrawable(WSEGLDrawableHandle _drawable)
+{
+ PvrQwsDrawable *drawable = (PvrQwsDrawable *)_drawable;
+ if (!drawable || drawable->type == PvrQwsScreen)
+ return WSEGL_SUCCESS;
+ if (pvrQwsDisplay.numFlipBuffers == 0)
+ pvrQwsFreeBuffers(drawable);
+ if (pvrQwsReleaseWindow(drawable))
+ pvrQwsDestroyDrawable(drawable);
+ return WSEGL_SUCCESS;
+}
+
+/* Swap the contents of a drawable to the screen */
+static WSEGLError wseglSwapDrawable
+ (WSEGLDrawableHandle _drawable, unsigned long data)
+{
+ WSEGL_UNUSED(data);
+ PvrQwsDrawable *drawable = (PvrQwsDrawable *)_drawable;
+ if (drawable->type != PvrQwsPixmap && !pvrQwsSwapBuffers(drawable, 0))
+ return WSEGL_BAD_DRAWABLE;
+ else
+ return WSEGL_SUCCESS;
+}
+
+/* Set the swap interval of a window drawable */
+static WSEGLError wseglSwapControlInterval
+ (WSEGLDrawableHandle drawable, unsigned long interval)
+{
+ WSEGL_UNUSED(drawable);
+ if (pvrQwsDisplay.flipChain) {
+ PVR2DSetPresentFlipProperties
+ (pvrQwsDisplay.context, pvrQwsDisplay.flipChain,
+ PVR2D_PRESENT_PROPERTY_INTERVAL, 0, 0, 0, NULL, interval);
+ }
+ return WSEGL_SUCCESS;
+}
+
+/* Flush native rendering requests on a drawable */
+static WSEGLError wseglWaitNative
+ (WSEGLDrawableHandle drawable, unsigned long engine)
+{
+ WSEGL_UNUSED(drawable);
+ if (engine == WSEGL_DEFAULT_NATIVE_ENGINE)
+ return WSEGL_SUCCESS;
+ else
+ return WSEGL_BAD_NATIVE_ENGINE;
+}
+
+/* Copy color data from a drawable to a native pixmap */
+static WSEGLError wseglCopyFromDrawable
+ (WSEGLDrawableHandle _drawable, NativePixmapType nativePixmap)
+{
+ PvrQwsDrawable *drawable = (PvrQwsDrawable *)_drawable;
+ PvrQwsDrawable *pixmap = (PvrQwsDrawable *)nativePixmap;
+ PVR2DBLTINFO blit;
+
+ if (!drawable || !drawable->backBuffersValid)
+ return WSEGL_BAD_NATIVE_WINDOW;
+ if (!pixmap || !pixmap->backBuffersValid)
+ return WSEGL_BAD_NATIVE_PIXMAP;
+
+ memset(&blit, 0, sizeof(blit));
+
+ blit.CopyCode = PVR2DROPcopy;
+ blit.BlitFlags = PVR2D_BLIT_DISABLE_ALL;
+
+ blit.pSrcMemInfo = drawable->backBuffers[drawable->currentBackBuffer];
+ blit.SrcStride = drawable->strideBytes;
+ blit.SrcX = 0;
+ blit.SrcY = 0;
+ blit.SizeX = drawable->rect.width;
+ blit.SizeY = drawable->rect.height;
+ blit.SrcFormat = drawable->pixelFormat;
+
+ blit.pDstMemInfo = pixmap->backBuffers[pixmap->currentBackBuffer];
+ blit.DstStride = pixmap->strideBytes;
+ blit.DstX = 0;
+ blit.DstY = 0;
+ blit.DSizeX = pixmap->rect.width;
+ blit.DSizeY = pixmap->rect.height;
+ blit.DstFormat = pixmap->pixelFormat;
+
+ PVR2DBlt(pvrQwsDisplay.context, &blit);
+ PVR2DQueryBlitsComplete
+ (pvrQwsDisplay.context, pixmap->backBuffers[pixmap->currentBackBuffer], 1);
+
+ return WSEGL_SUCCESS;
+}
+
+/* Copy color data from a PBuffer to a native pixmap */
+static WSEGLError wseglCopyFromPBuffer
+ (void *address, unsigned long width, unsigned long height,
+ unsigned long stride, WSEGLPixelFormat format,
+ NativePixmapType nativePixmap)
+{
+ PvrQwsDrawable *pixmap = (PvrQwsDrawable *)nativePixmap;
+ PVR2DFORMAT pixelFormat;
+
+ if (!pixmap)
+ return WSEGL_BAD_NATIVE_PIXMAP;
+
+ /* We can only copy under certain conditions */
+ switch (format) {
+ case WSEGL_PIXELFORMAT_565:
+ pixelFormat = PVR2D_RGB565; break;
+ case WSEGL_PIXELFORMAT_4444:
+ pixelFormat = PVR2D_ARGB4444; break;
+ case WSEGL_PIXELFORMAT_8888:
+ pixelFormat = PVR2D_ARGB8888; break;
+ default:
+ return WSEGL_BAD_CONFIG;
+ }
+ if (width > (unsigned long)(pixmap->rect.width) ||
+ height > (unsigned long)(pixmap->rect.height) ||
+ pixelFormat != pixmap->pixelFormat) {
+ return WSEGL_BAD_CONFIG;
+ }
+
+ /* We'd like to use PVR2DBlt to do this, but there is no easy way
+ to map the virtual "address" into physical space to be able
+ to use the hardware assist. Use memcpy to do the work instead.
+ Note: PBuffer's are upside down, so we copy from the bottom up */
+ char *srcaddr = (char *)address;
+ char *dstaddr = (char *)(pixmap->backBuffers[pixmap->currentBackBuffer]->pBase);
+ int dststride = pixmap->strideBytes;
+ int srcwidth = ((int)width) * pvrQwsDisplay.screens[0].bytesPerPixel;
+ srcaddr += height * stride;
+ while (height > 0) {
+ srcaddr -= (int)stride;
+ memcpy(dstaddr, srcaddr, srcwidth);
+ dstaddr += dststride;
+ --height;
+ }
+ return WSEGL_SUCCESS;
+}
+
+/* Return the parameters of a drawable that are needed by the EGL layer */
+static WSEGLError wseglGetDrawableParameters
+ (WSEGLDrawableHandle _drawable, WSEGLDrawableParams *sourceParams,
+ WSEGLDrawableParams *renderParams)
+{
+ PvrQwsDrawable *drawable = (PvrQwsDrawable *)_drawable;
+ PVR2DMEMINFO *source, *render;
+ WSEGLPixelFormat pixelFormat;
+
+ if (!pvrQwsGetBuffers(drawable, &source, &render))
+ return WSEGL_BAD_DRAWABLE;
+
+ switch (drawable->pixelFormat) {
+ case PVR2D_RGB565:
+ default:
+ pixelFormat = WSEGL_PIXELFORMAT_565;
+ break;
+
+ case PVR2D_ARGB4444:
+ pixelFormat = WSEGL_PIXELFORMAT_4444;
+ break;
+
+ case PVR2D_ARGB8888:
+ pixelFormat = WSEGL_PIXELFORMAT_8888;
+ break;
+ }
+
+ sourceParams->ui32Width = drawable->rect.width;
+ sourceParams->ui32Height = drawable->rect.height;
+ sourceParams->ui32Stride = drawable->stridePixels;
+ sourceParams->ePixelFormat = pixelFormat;
+ sourceParams->pvLinearAddress = source->pBase;
+ sourceParams->ui32HWAddress = source->ui32DevAddr;
+ sourceParams->hPrivateData = source->hPrivateData;
+
+ renderParams->ui32Width = drawable->rect.width;
+ renderParams->ui32Height = drawable->rect.height;
+ renderParams->ui32Stride = drawable->stridePixels;
+ renderParams->ePixelFormat = pixelFormat;
+ renderParams->pvLinearAddress = render->pBase;
+ renderParams->ui32HWAddress = render->ui32DevAddr;
+ renderParams->hPrivateData = render->hPrivateData;
+
+ return WSEGL_SUCCESS;
+}
+
+static WSEGL_FunctionTable const wseglFunctions = {
+ WSEGL_VERSION,
+ wseglIsDisplayValid,
+ wseglInitializeDisplay,
+ wseglCloseDisplay,
+ wseglCreateWindowDrawable,
+ wseglCreatePixmapDrawable,
+ wseglDeleteDrawable,
+ wseglSwapDrawable,
+ wseglSwapControlInterval,
+ wseglWaitNative,
+ wseglCopyFromDrawable,
+ wseglCopyFromPBuffer,
+ wseglGetDrawableParameters
+};
+
+/* Return the table of WSEGL functions to the EGL implementation */
+const WSEGL_FunctionTable *WSEGL_GetFunctionTablePointer(void)
+{
+ return &wseglFunctions;
+}
diff --git a/src/plugins/gfxdrivers/powervr/README b/src/plugins/gfxdrivers/powervr/README
new file mode 100644
index 0000000000..513e7f5e9e
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/README
@@ -0,0 +1,66 @@
+PowerVR QScreen Driver
+======================
+
+This QScreen plugin driver allows the QtOpenGl module to integrate with PowerVR
+hardware from Imagination Technologies. Using this plugin, applications may use
+QGLWidget & QGLPixelBuffer with OpenGL ES. The integration with PowerVR drivers
+is built as two libraries: The actual QScreen plugin used by Qt (in the
+pvreglscreen directory) and a WSEGL plugin for the PowerVR drivers (in the
+QWSWSEGL directory).
+
+Qt/Embedded needs to be configured with the QT_QWS_CLIENTBLIT and
+QT_NO_QWS_CURSOR defines.
+
+The PowerVR drivers provide the WSEGL plugin API to allow window systems such as
+QWS to integrate correctly. In order to use the integration, the WSEGL plugin
+(libpvrQWSWSEGL.so, usually installed into the Qt library directory) must be in
+the LD library path. The PowerVR driver also needs to be told which WSEGL library
+to use. This is done by creating/modifying /etc/powervr.ini:
+
+[default]
+WindowSystem=libpvrQWSWSEGL.so
+
+Note: It is important that the /etc/powervr.ini file not contain ^M (Ctrl-M) DOS
+end of line markers at the end of its lines. If ^M markers are present, then the
+libpvrQWSWSEGL.so driver will not be loaded and the default null Linux driver
+will be loaded silently instead. Make sure that the end of line markers are
+strictly Unix-style markers.
+
+
+***************************************************************************
+* IMPORTANT: To build the QScreen plugin and the WSEGL library it depends *
+* on, the pvr2d.h, wsegl.h headers for your platform are required. You *
+* can find a copy of these headers in src/3rdparty/powervr for SGX based *
+* platforms like the TI OMAP3xxx. They probably will not work on MBX *
+* because of differences in the layout of certain PVR2D structures. *
+* You can tell Qt where to find the actual headers for your system by *
+* setting QMAKE_INCDIR_POWERVR in the mkspec. *
+***************************************************************************
+
+When you start a Qt/Embedded application, you should modify the QWS_DISPLAY
+environment variable to use the "powervr" driver instead of "LinuxFb". For
+example, if your original QWS_DISPLAY variable was:
+
+ LinuxFb:mmWidth40:mmHeight54:0
+
+then it should be changed to:
+
+ powervr:mmWidth40:mmHeight54:0
+
+To test the OpenGL ES integration, you can use the hellogl_es example and run it
+on the device with:
+
+ hellogl_es -qws
+
+The driver also supports screen rotation if Qt is configured with the
+-qt-gfx-transformed option and the QWS_DISPLAY variable is wrapped in a
+"Transformed" declaration:
+
+ Transformed:powervr:mmWidth40:mmHeight54:Rot90:0
+
+Know Issues:
+ * A QGLWidget may not have window decorations if it is a top-level window.
+ * On some platforms, starting a QWS application after the system has been up
+ for a long time may cause the driver to fail. This is due to fragmentation
+ of main memory prevening older PowerVR drivers from allocating a contiguous
+ region of phyical RAM for the GL surface.
diff --git a/src/plugins/gfxdrivers/powervr/powervr.pri b/src/plugins/gfxdrivers/powervr/powervr.pri
new file mode 100644
index 0000000000..9df8c0ed5b
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/powervr.pri
@@ -0,0 +1,2 @@
+
+INCLUDEPATH += $$QMAKE_INCDIR_POWERVR
diff --git a/src/plugins/gfxdrivers/powervr/powervr.pro b/src/plugins/gfxdrivers/powervr/powervr.pro
new file mode 100644
index 0000000000..f31ad042d8
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/powervr.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = QWSWSEGL pvreglscreen
+CONFIG += ordered
diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp
new file mode 100644
index 0000000000..c981e0d300
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp
@@ -0,0 +1,351 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pvreglscreen.h"
+#include "pvreglwindowsurface.h"
+#include "pvrqwsdrawable_p.h"
+#include <QRegExp>
+#include <qwindowsystem_qws.h>
+#ifndef QT_NO_QWS_TRANSFORMED
+#include <qscreentransformed_qws.h>
+#endif
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/kd.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+//![0]
+PvrEglScreen::PvrEglScreen(int displayId)
+ : QGLScreen(displayId)
+{
+ setOptions(NativeWindows);
+ setSupportsBlitInClients(true);
+ setSurfaceFunctions(new PvrEglScreenSurfaceFunctions(this, displayId));
+//![0]
+ fd = -1;
+ ttyfd = -1;
+ doGraphicsMode = true;
+ oldKdMode = KD_TEXT;
+ parent = 0;
+
+ // Make sure that the EGL layer is initialized and the drivers loaded.
+ EGLDisplay dpy = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);
+ if (!eglInitialize(dpy, 0, 0))
+ qWarning("Could not initialize EGL display - are the drivers loaded?");
+
+ // Make sure that screen 0 is initialized.
+ pvrQwsScreenWindow(0);
+}
+
+PvrEglScreen::~PvrEglScreen()
+{
+ if (fd >= 0)
+ ::close(fd);
+}
+
+bool PvrEglScreen::initDevice()
+{
+ openTty();
+ return true;
+}
+
+bool PvrEglScreen::connect(const QString &displaySpec)
+{
+ if (!pvrQwsDisplayOpen())
+ return false;
+
+ // Initialize the QScreen properties.
+ data = (uchar *)(pvrQwsDisplay.screens[0].mapped);
+ w = pvrQwsDisplay.screens[0].screenRect.width;
+ h = pvrQwsDisplay.screens[0].screenRect.height;
+ lstep = pvrQwsDisplay.screens[0].screenStride;
+ dw = w;
+ dh = h;
+ size = h * lstep;
+ mapsize = size;
+ switch (pvrQwsDisplay.screens[0].pixelFormat) {
+ case PVR2D_RGB565:
+ d = 16;
+ setPixelFormat(QImage::Format_RGB16);
+ break;
+ case PVR2D_ARGB4444:
+ d = 16;
+ setPixelFormat(QImage::Format_ARGB4444_Premultiplied);
+ break;
+ case PVR2D_ARGB8888:
+ d = 32;
+ setPixelFormat(QImage::Format_ARGB32_Premultiplied);
+ break;
+ default:
+ pvrQwsDisplayClose();
+ qWarning("PvrEglScreen::connect: unsupported pixel format %d", (int)(pvrQwsDisplay.screens[0].pixelFormat));
+ return false;
+ }
+
+ // Handle display physical size spec.
+ QStringList displayArgs = displaySpec.split(QLatin1Char(':'));
+ QRegExp mmWidthRx(QLatin1String("mmWidth=?(\\d+)"));
+ int dimIdxW = displayArgs.indexOf(mmWidthRx);
+ QRegExp mmHeightRx(QLatin1String("mmHeight=?(\\d+)"));
+ int dimIdxH = displayArgs.indexOf(mmHeightRx);
+ if (dimIdxW >= 0) {
+ mmWidthRx.exactMatch(displayArgs.at(dimIdxW));
+ physWidth = mmWidthRx.cap(1).toInt();
+ if (dimIdxH < 0)
+ physHeight = dh*physWidth/dw;
+ }
+ if (dimIdxH >= 0) {
+ mmHeightRx.exactMatch(displayArgs.at(dimIdxH));
+ physHeight = mmHeightRx.cap(1).toInt();
+ if (dimIdxW < 0)
+ physWidth = dw*physHeight/dh;
+ }
+ if (dimIdxW < 0 && dimIdxH < 0) {
+ const int dpi = 72;
+ physWidth = qRound(dw * 25.4 / dpi);
+ physHeight = qRound(dh * 25.4 / dpi);
+ }
+
+ // Find the name of the tty device to use.
+ QRegExp ttyRegExp(QLatin1String("tty=(.*)"));
+ if (displayArgs.indexOf(ttyRegExp) != -1)
+ ttyDevice = ttyRegExp.cap(1);
+ if (displayArgs.contains(QLatin1String("nographicsmodeswitch")))
+ doGraphicsMode = false;
+
+ // The screen is ready.
+ return true;
+}
+
+void PvrEglScreen::disconnect()
+{
+ pvrQwsDisplayClose();
+}
+
+void PvrEglScreen::shutdownDevice()
+{
+ closeTty();
+}
+
+void PvrEglScreen::blit(const QImage &img, const QPoint &topLeft, const QRegion &region)
+{
+ QGLScreen::blit(img, topLeft, region);
+ sync();
+}
+
+void PvrEglScreen::solidFill(const QColor &color, const QRegion &region)
+{
+ QGLScreen::solidFill(color, region);
+ sync();
+}
+
+bool PvrEglScreen::chooseContext
+ (QGLContext *context, const QGLContext *shareContext)
+{
+ // We use PvrEglScreenSurfaceFunctions instead.
+ Q_UNUSED(context);
+ Q_UNUSED(shareContext);
+ return false;
+}
+
+bool PvrEglScreen::hasOpenGL()
+{
+ return true;
+}
+
+//![1]
+QWSWindowSurface* PvrEglScreen::createSurface(QWidget *widget) const
+{
+ if (qobject_cast<QGLWidget*>(widget))
+ return new PvrEglWindowSurface(widget, (PvrEglScreen *)this, displayId);
+
+ return QScreen::createSurface(widget);
+}
+
+QWSWindowSurface* PvrEglScreen::createSurface(const QString &key) const
+{
+ if (key == QLatin1String("PvrEgl"))
+ return new PvrEglWindowSurface();
+
+ return QScreen::createSurface(key);
+}
+//![1]
+
+#ifndef QT_NO_QWS_TRANSFORMED
+
+static const QScreen *parentScreen
+ (const QScreen *current, const QScreen *lookingFor)
+{
+ if (!current)
+ return 0;
+ switch (current->classId()) {
+ case QScreen::ProxyClass:
+ case QScreen::TransformedClass: {
+ const QScreen *child =
+ static_cast<const QProxyScreen *>(current)->screen();
+ if (child == lookingFor)
+ return current;
+ else
+ return parentScreen(child, lookingFor);
+ }
+ // Not reached.
+
+ case QScreen::MultiClass: {
+ QList<QScreen *> screens = current->subScreens();
+ foreach (QScreen *screen, screens) {
+ if (screen == lookingFor)
+ return current;
+ const QScreen *parent = parentScreen(screen, lookingFor);
+ if (parent)
+ return parent;
+ }
+ }
+ break;
+
+ default: break;
+ }
+ return 0;
+}
+
+int PvrEglScreen::transformation() const
+{
+ // We need to search for our parent screen, which is assumed to be
+ // "Transformed". If it isn't, then there is no transformation.
+ // There is no direct method to get the parent screen so we need
+ // to search every screen until we find ourselves.
+ if (!parent && qt_screen != this)
+ parent = parentScreen(qt_screen, this);
+ if (!parent)
+ return 0;
+ if (parent->classId() != QScreen::TransformedClass)
+ return 0;
+ return 90 * static_cast<const QTransformedScreen *>(parent)
+ ->transformOrientation();
+}
+
+#else
+
+int PvrEglScreen::transformation() const
+{
+ return 0;
+}
+
+#endif
+
+void PvrEglScreen::sync()
+{
+ // Put code here to synchronize 2D and 3D operations if necessary.
+}
+
+void PvrEglScreen::openTty()
+{
+ const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0};
+
+ if (ttyDevice.isEmpty()) {
+ for (const char * const *dev = devs; *dev; ++dev) {
+ ttyfd = ::open(*dev, O_RDWR);
+ if (ttyfd != -1)
+ break;
+ }
+ } else {
+ ttyfd = ::open(ttyDevice.toAscii().constData(), O_RDWR);
+ }
+
+ if (ttyfd == -1)
+ return;
+
+ ::fcntl(ttyfd, F_SETFD, FD_CLOEXEC);
+
+ if (doGraphicsMode) {
+ ioctl(ttyfd, KDGETMODE, &oldKdMode);
+ if (oldKdMode != KD_GRAPHICS) {
+ int ret = ioctl(ttyfd, KDSETMODE, KD_GRAPHICS);
+ if (ret == -1)
+ doGraphicsMode = false;
+ }
+ }
+
+ // No blankin' screen, no blinkin' cursor!, no cursor!
+ const char termctl[] = "\033[9;0]\033[?33l\033[?25l\033[?1c";
+ ::write(ttyfd, termctl, sizeof(termctl));
+}
+
+void PvrEglScreen::closeTty()
+{
+ if (ttyfd == -1)
+ return;
+
+ if (doGraphicsMode)
+ ioctl(ttyfd, KDSETMODE, oldKdMode);
+
+ // Blankin' screen, blinkin' cursor!
+ const char termctl[] = "\033[9;15]\033[?33h\033[?25h\033[?0c";
+ ::write(ttyfd, termctl, sizeof(termctl));
+
+ ::close(ttyfd);
+ ttyfd = -1;
+}
+
+//![2]
+bool PvrEglScreenSurfaceFunctions::createNativeWindow(QWidget *widget, EGLNativeWindowType *native)
+{
+//![2]
+ QWSWindowSurface *surface =
+ static_cast<QWSWindowSurface *>(widget->windowSurface());
+ if (!surface) {
+ // The widget does not have a surface yet, so give it one.
+ surface = new PvrEglWindowSurface(widget, screen, displayId);
+ widget->setWindowSurface(surface);
+ } else if (surface->key() != QLatin1String("PvrEgl")) {
+ // The application has attached a QGLContext to an ordinary QWidget.
+ // Replace the widget's window surface with a new one that can do GL.
+ QRect geometry = widget->frameGeometry();
+ geometry.moveTo(widget->mapToGlobal(QPoint(0, 0)));
+ surface = new PvrEglWindowSurface(widget, screen, displayId);
+ surface->setGeometry(geometry);
+ widget->setWindowSurface(surface);
+ widget->setAttribute(Qt::WA_NoSystemBackground, true);
+ }
+ PvrEglWindowSurface *nsurface = static_cast<PvrEglWindowSurface*>(surface);
+ *native = (EGLNativeWindowType)(nsurface->nativeDrawable());
+ return true;
+}
diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.h b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.h
new file mode 100644
index 0000000000..efb2406771
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PVREGLSCREEN_H
+#define PVREGLSCREEN_H
+
+#include <QScreen>
+#include <QGLScreen>
+#include "pvrqwsdrawable.h"
+
+class PvrEglScreen;
+
+class PvrEglScreenSurfaceFunctions : public QGLScreenSurfaceFunctions
+{
+public:
+ PvrEglScreenSurfaceFunctions(PvrEglScreen *s, int screenNum)
+ : screen(s), displayId(screenNum) {}
+
+ bool createNativeWindow(QWidget *widget, EGLNativeWindowType *native);
+
+private:
+ PvrEglScreen *screen;
+ int displayId;
+};
+
+class PvrEglScreen : public QGLScreen
+{
+public:
+ PvrEglScreen(int displayId);
+ ~PvrEglScreen();
+
+ bool initDevice();
+ bool connect(const QString &displaySpec);
+ void disconnect();
+ void shutdownDevice();
+ void setMode(int, int, int) {}
+
+ void blit(const QImage &img, const QPoint &topLeft, const QRegion &region);
+ void solidFill(const QColor &color, const QRegion &region);
+
+ bool chooseContext(QGLContext *context, const QGLContext *shareContext);
+ bool hasOpenGL();
+
+ QWSWindowSurface* createSurface(QWidget *widget) const;
+ QWSWindowSurface* createSurface(const QString &key) const;
+
+ int transformation() const;
+
+private:
+ void sync();
+ void openTty();
+ void closeTty();
+
+ int fd;
+ int ttyfd, oldKdMode;
+ QString ttyDevice;
+ bool doGraphicsMode;
+ mutable const QScreen *parent;
+};
+
+#endif
diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro
new file mode 100644
index 0000000000..675be85460
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro
@@ -0,0 +1,27 @@
+TEMPLATE = lib
+TARGET = qgfxpvregl
+CONFIG += qt plugin warn_on
+QT += opengl
+
+LIBS += -lpvrQWSWSEGL
+
+DEFINES += QT_QWS_CLIENTBLIT
+
+INCLUDEPATH += ../QWSWSEGL
+
+
+HEADERS = \
+ pvreglscreen.h \
+ pvreglwindowsurface.h
+
+SOURCES = \
+ pvreglscreenplugin.cpp \
+ pvreglscreen.cpp \
+ pvreglwindowsurface.cpp
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers
+
+target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers
+INSTALLS += target
+
+include(../powervr.pri) \ No newline at end of file
diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp
new file mode 100644
index 0000000000..872285e818
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pvreglscreen.h"
+
+#include <QScreenDriverPlugin>
+#include <QStringList>
+
+class PvrEglScreenPlugin : public QScreenDriverPlugin
+{
+public:
+ PvrEglScreenPlugin();
+
+ QStringList keys() const;
+ QScreen *create(const QString&, int displayId);
+};
+
+PvrEglScreenPlugin::PvrEglScreenPlugin()
+ : QScreenDriverPlugin()
+{
+}
+
+QStringList PvrEglScreenPlugin::keys() const
+{
+ return (QStringList() << "powervr");
+}
+
+QScreen* PvrEglScreenPlugin::create(const QString& driver, int displayId)
+{
+ if (driver.toLower() != "powervr")
+ return 0;
+
+ return new PvrEglScreen(displayId);
+}
+
+Q_EXPORT_PLUGIN2(qgfxpvregl, PvrEglScreenPlugin)
diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.cpp b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.cpp
new file mode 100644
index 0000000000..43648159c8
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.cpp
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pvreglwindowsurface.h"
+#include "pvreglscreen.h"
+#include <QScreen>
+#include <QDebug>
+#include <QWSDisplay>
+
+PvrEglWindowSurface::PvrEglWindowSurface
+ (QWidget *widget, PvrEglScreen *screen, int screenNum)
+ : QWSGLWindowSurface(widget)
+{
+ setSurfaceFlags(QWSWindowSurface::Opaque);
+
+ this->widget = widget;
+ this->screen = screen;
+ this->pdevice = 0;
+
+ QPoint pos = offset(widget);
+ QSize size = widget->size();
+
+ PvrQwsRect pvrRect;
+ pvrRect.x = pos.x();
+ pvrRect.y = pos.y();
+ pvrRect.width = size.width();
+ pvrRect.height = size.height();
+ transformRects(&pvrRect, 1);
+
+ // Try to recover a previous PvrQwsDrawable object for the widget
+ // if there is one. This can happen when a PvrEglWindowSurface
+ // is created for a widget, bound to a EGLSurface, and then destroyed.
+ // When a new PvrEglWindowSurface is created for the widget, it will
+ // pick up the previous PvrQwsDrawable if the EGLSurface has not been
+ // destroyed in the meantime.
+ drawable = pvrQwsFetchWindow((long)widget);
+ if (drawable)
+ pvrQwsSetGeometry(drawable, &pvrRect);
+ else
+ drawable = pvrQwsCreateWindow(screenNum, (long)widget, &pvrRect);
+ pvrQwsSetRotation(drawable, screen->transformation());
+}
+
+PvrEglWindowSurface::PvrEglWindowSurface()
+ : QWSGLWindowSurface()
+{
+ setSurfaceFlags(QWSWindowSurface::Opaque);
+ drawable = 0;
+ widget = 0;
+ screen = 0;
+ pdevice = 0;
+}
+
+PvrEglWindowSurface::~PvrEglWindowSurface()
+{
+ // Release the PvrQwsDrawable. If it is bound to an EGLSurface,
+ // then it will stay around until a new PvrEglWindowSurface is
+ // created for the widget. If it is not bound to an EGLSurface,
+ // it will be destroyed immediately.
+ if (drawable && pvrQwsReleaseWindow(drawable))
+ pvrQwsDestroyDrawable(drawable);
+
+ delete pdevice;
+}
+
+bool PvrEglWindowSurface::isValid() const
+{
+ return (widget != 0);
+}
+
+void PvrEglWindowSurface::setGeometry(const QRect &rect)
+{
+ if (drawable) {
+ // XXX: adjust for the screen offset.
+ PvrQwsRect pvrRect;
+ pvrRect.x = rect.x();
+ pvrRect.y = rect.y();
+ pvrRect.width = rect.width();
+ pvrRect.height = rect.height();
+ transformRects(&pvrRect, 1);
+ pvrQwsSetGeometry(drawable, &pvrRect);
+ pvrQwsSetRotation(drawable, screen->transformation());
+ }
+ QWSGLWindowSurface::setGeometry(rect);
+}
+
+bool PvrEglWindowSurface::move(const QPoint &offset)
+{
+ QRect rect = geometry().translated(offset);
+ if (drawable) {
+ PvrQwsRect pvrRect;
+ pvrRect.x = rect.x();
+ pvrRect.y = rect.y();
+ pvrRect.width = rect.width();
+ pvrRect.height = rect.height();
+ transformRects(&pvrRect, 1);
+ pvrQwsSetGeometry(drawable, &pvrRect);
+ pvrQwsSetRotation(drawable, screen->transformation());
+ }
+ return QWSGLWindowSurface::move(offset);
+}
+
+QByteArray PvrEglWindowSurface::permanentState() const
+{
+ // Nothing interesting to pass to the server just yet.
+ return QByteArray();
+}
+
+void PvrEglWindowSurface::setPermanentState(const QByteArray &state)
+{
+ Q_UNUSED(state);
+}
+
+void PvrEglWindowSurface::flush
+ (QWidget *widget, const QRegion &region, const QPoint &offset)
+{
+ // The GL paint engine is responsible for the swapBuffers() call.
+ // If we were to call the base class's implementation of flush()
+ // then it would fetch the image() and manually blit it to the
+ // screeen instead of using the fast PVR2D blit.
+ Q_UNUSED(widget);
+ Q_UNUSED(region);
+ Q_UNUSED(offset);
+}
+
+QImage PvrEglWindowSurface::image() const
+{
+ if (drawable) {
+ PvrQwsRect pvrRect;
+ pvrQwsGetGeometry(drawable, &pvrRect);
+ void *data = pvrQwsGetRenderBuffer(drawable);
+ if (data) {
+ return QImage((uchar *)data, pvrRect.width, pvrRect.height,
+ pvrQwsGetStride(drawable), screen->pixelFormat());
+ }
+ }
+ return QImage(16, 16, screen->pixelFormat());
+}
+
+QPaintDevice *PvrEglWindowSurface::paintDevice()
+{
+ return widget;
+}
+
+void PvrEglWindowSurface::setDirectRegion(const QRegion &r, int id)
+{
+ QWSGLWindowSurface::setDirectRegion(r, id);
+
+ if (!drawable)
+ return;
+
+ // Clip the region to the window boundaries in case the child
+ // is partially outside the geometry of the parent.
+ QWidget *window = widget->window();
+ QRegion region = r;
+ if (widget != window) {
+ QRect rect = window->geometry();
+ rect.moveTo(window->mapToGlobal(QPoint(0, 0)));
+ region = region.intersect(rect);
+ }
+
+ if (region.isEmpty()) {
+ pvrQwsClearVisibleRegion(drawable);
+ } else if (region.rectCount() == 1) {
+ QRect rect = region.boundingRect();
+ PvrQwsRect pvrRect;
+ pvrRect.x = rect.x();
+ pvrRect.y = rect.y();
+ pvrRect.width = rect.width();
+ pvrRect.height = rect.height();
+ transformRects(&pvrRect, 1);
+ pvrQwsSetVisibleRegion(drawable, &pvrRect, 1);
+ pvrQwsSetRotation(drawable, screen->transformation());
+ if (!pvrQwsSwapBuffers(drawable, 1))
+ screen->solidFill(QColor(0, 0, 0), region);
+ } else {
+ QVector<QRect> rects = region.rects();
+ PvrQwsRect *pvrRects = new PvrQwsRect [rects.size()];
+ for (int index = 0; index < rects.size(); ++index) {
+ QRect rect = rects[index];
+ pvrRects[index].x = rect.x();
+ pvrRects[index].y = rect.y();
+ pvrRects[index].width = rect.width();
+ pvrRects[index].height = rect.height();
+ }
+ transformRects(pvrRects, rects.size());
+ pvrQwsSetVisibleRegion(drawable, pvrRects, rects.size());
+ pvrQwsSetRotation(drawable, screen->transformation());
+ if (!pvrQwsSwapBuffers(drawable, 1))
+ screen->solidFill(QColor(0, 0, 0), region);
+ delete [] pvrRects;
+ }
+}
+
+void PvrEglWindowSurface::transformRects(PvrQwsRect *rects, int count) const
+{
+ switch (screen->transformation()) {
+ case 0: break;
+
+ case 90:
+ {
+ for (int index = 0; index < count; ++index) {
+ int x = rects[index].y;
+ int y = screen->height() - (rects[index].x + rects[index].width);
+ rects[index].x = x;
+ rects[index].y = y;
+ qSwap(rects[index].width, rects[index].height);
+ }
+ }
+ break;
+
+ case 180:
+ {
+ for (int index = 0; index < count; ++index) {
+ int x = screen->width() - (rects[index].x + rects[index].width);
+ int y = screen->height() - (rects[index].y + rects[index].height);
+ rects[index].x = x;
+ rects[index].y = y;
+ }
+ }
+ break;
+
+ case 270:
+ {
+ for (int index = 0; index < count; ++index) {
+ int x = screen->width() - (rects[index].y + rects[index].height);
+ int y = rects[index].x;
+ rects[index].x = x;
+ rects[index].y = y;
+ qSwap(rects[index].width, rects[index].height);
+ }
+ }
+ break;
+ }
+}
diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h
new file mode 100644
index 0000000000..9f5600c136
--- /dev/null
+++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PVREGLWINDOWSURFACE_H
+#define PVREGLWINDOWSURFACE_H
+
+#include <private/qglwindowsurface_qws_p.h>
+#include "pvrqwsdrawable.h"
+
+class PvrEglScreen;
+
+class PvrEglWindowSurface : public QWSGLWindowSurface
+{
+public:
+ PvrEglWindowSurface(QWidget *widget, PvrEglScreen *screen, int screenNum);
+ PvrEglWindowSurface();
+ ~PvrEglWindowSurface();
+
+ QString key() const { return QLatin1String("PvrEgl"); }
+
+ bool isValid() const;
+
+ void setGeometry(const QRect &rect);
+ bool move(const QPoint &offset);
+
+ QByteArray permanentState() const;
+ void setPermanentState(const QByteArray &state);
+
+ void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
+
+ QImage image() const;
+ QPaintDevice *paintDevice();
+
+ void setDirectRegion(const QRegion &region, int id);
+
+ long nativeDrawable() const { return (long)widget; }
+
+private:
+ QWidget *widget;
+ PvrQwsDrawable *drawable;
+ PvrEglScreen *screen;
+ QPaintDevice *pdevice;
+
+ void transformRects(PvrQwsRect *rects, int count) const;
+};
+
+#endif
diff --git a/src/plugins/gfxdrivers/qvfb/main.cpp b/src/plugins/gfxdrivers/qvfb/main.cpp
new file mode 100644
index 0000000000..fb275818b9
--- /dev/null
+++ b/src/plugins/gfxdrivers/qvfb/main.cpp
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qscreendriverplugin_qws.h>
+#include <qscreenvfb_qws.h>
+#include <qstringlist.h>
+
+#ifndef QT_NO_LIBRARY
+QT_BEGIN_NAMESPACE
+
+class ScreenVfbDriver : public QScreenDriverPlugin
+{
+public:
+ ScreenVfbDriver();
+
+ QStringList keys() const;
+ QScreen *create(const QString&, int displayId);
+};
+
+ScreenVfbDriver::ScreenVfbDriver()
+: QScreenDriverPlugin()
+{
+}
+
+QStringList ScreenVfbDriver::keys() const
+{
+ QStringList list;
+ list << "QVFb";
+ return list;
+}
+
+QScreen* ScreenVfbDriver::create(const QString& driver, int displayId)
+{
+ if (driver.toLower() == "qvfb")
+ return new QVFbScreen(displayId);
+
+ return 0;
+}
+
+Q_EXPORT_STATIC_PLUGIN(ScreenVfbDriver)
+Q_EXPORT_PLUGIN2(qscreenvfb, ScreenVfbDriver)
+
+QT_END_NAMESPACE
+#endif //QT_NO_LIBRARY
diff --git a/src/plugins/gfxdrivers/qvfb/qvfb.pro b/src/plugins/gfxdrivers/qvfb/qvfb.pro
new file mode 100644
index 0000000000..a0996e77dc
--- /dev/null
+++ b/src/plugins/gfxdrivers/qvfb/qvfb.pro
@@ -0,0 +1,19 @@
+TARGET = qscreenvfb
+include(../../qpluginbase.pri)
+
+DEFINES += QT_QWS_QVFB QT_QWS_MOUSE_QVFB QT_QWS_KBD_QVFB
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers
+
+HEADERS = \
+ $$QT_SOURCE_TREE/src/gui/embedded/qscreenvfb_qws.h \
+ $$QT_SOURCE_TREE/src/gui/embedded/qkbdvfb_qws.h \
+ $$QT_SOURCE_TREE/src/gui/embedded/qmousevfb_qws.h
+
+SOURCES = main.cpp \
+ $$QT_SOURCE_TREE/src/gui/embedded/qscreenvfb_qws.cpp \
+ $$QT_SOURCE_TREE/src/gui/embedded/qkbdvfb_qws.cpp \
+ $$QT_SOURCE_TREE/src/gui/embedded/qmousevfb_qws.cpp
+
+target.path += $$[QT_INSTALL_PLUGINS]/gfxdrivers
+INSTALLS += target
diff --git a/src/plugins/gfxdrivers/transformed/main.cpp b/src/plugins/gfxdrivers/transformed/main.cpp
new file mode 100644
index 0000000000..da619bb3e5
--- /dev/null
+++ b/src/plugins/gfxdrivers/transformed/main.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qscreendriverplugin_qws.h>
+#include <qscreentransformed_qws.h>
+#include <qstringlist.h>
+#ifndef QT_NO_LIBRARY
+QT_BEGIN_NAMESPACE
+
+class GfxTransformedDriver : public QScreenDriverPlugin
+{
+public:
+ GfxTransformedDriver();
+
+ QStringList keys() const;
+ QScreen *create(const QString&, int displayId);
+};
+
+GfxTransformedDriver::GfxTransformedDriver()
+: QScreenDriverPlugin()
+{
+}
+
+QStringList GfxTransformedDriver::keys() const
+{
+ QStringList list;
+ list << "Transformed";
+ return list;
+}
+
+QScreen* GfxTransformedDriver::create(const QString& driver, int displayId)
+{
+#ifndef QT_NO_QWS_TRANSFORMED
+ if (driver.toLower() == "transformed")
+ return new QTransformedScreen(displayId);
+#else //QT_NO_QWS_TRANSFORMED
+ printf("QT buildt with QT_NO_QWS_TRANSFORMED. No screen driver returned\n");
+#endif //QT_NO_QWS_TRANSFORMED
+ return 0;
+}
+
+Q_EXPORT_STATIC_PLUGIN(GfxTransformedDriver)
+Q_EXPORT_PLUGIN2(qgfxtransformed, GfxTransformedDriver)
+
+QT_END_NAMESPACE
+#endif //QT_NO_LIBRARY
diff --git a/src/plugins/gfxdrivers/transformed/transformed.pro b/src/plugins/gfxdrivers/transformed/transformed.pro
new file mode 100644
index 0000000000..173f7e99d4
--- /dev/null
+++ b/src/plugins/gfxdrivers/transformed/transformed.pro
@@ -0,0 +1,13 @@
+TARGET = qgfxtransformed
+include(../../qpluginbase.pri)
+
+DEFINES += QT_QWS_TRANSFORMED
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers
+
+HEADERS = $$QT_SOURCE_TREE/src/gui/embedded/qscreentransformed_qws.h
+SOURCES = main.cpp \
+ $$QT_SOURCE_TREE/src/gui/embedded/qscreentransformed_qws.cpp
+
+target.path=$$[QT_INSTALL_PLUGINS]/gfxdrivers
+INSTALLS += target
diff --git a/src/plugins/gfxdrivers/vnc/main.cpp b/src/plugins/gfxdrivers/vnc/main.cpp
new file mode 100644
index 0000000000..65c6cf25c6
--- /dev/null
+++ b/src/plugins/gfxdrivers/vnc/main.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qscreendriverplugin_qws.h>
+#include <qscreenvnc_qws.h>
+#include <qstringlist.h>
+
+#ifndef QT_NO_LIBRARY
+QT_BEGIN_NAMESPACE
+
+class GfxVncDriver : public QScreenDriverPlugin
+{
+public:
+ GfxVncDriver();
+
+ QStringList keys() const;
+ QScreen *create(const QString&, int displayId);
+};
+
+GfxVncDriver::GfxVncDriver()
+: QScreenDriverPlugin()
+{
+}
+
+QStringList GfxVncDriver::keys() const
+{
+ QStringList list;
+ list << "VNC";
+ return list;
+}
+
+QScreen* GfxVncDriver::create(const QString& driver, int displayId)
+{
+#ifndef QT_NO_QWS_VNC
+ if (driver.toLower() == "vnc")
+ return new QVNCScreen(displayId);
+#else //QT_NO_QWS_VNC
+ printf("QT buildt with QT_NO_QWS_VNC. No screen driver returned\n");
+#endif //QT_NO_QWS_VNC
+ return 0;
+}
+
+Q_EXPORT_STATIC_PLUGIN(GfxVncDriver)
+Q_EXPORT_PLUGIN2(qgfxvnc, GfxVncDriver)
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_LIBRARY
diff --git a/src/plugins/gfxdrivers/vnc/qscreenvnc_p.h b/src/plugins/gfxdrivers/vnc/qscreenvnc_p.h
new file mode 100644
index 0000000000..9a02072815
--- /dev/null
+++ b/src/plugins/gfxdrivers/vnc/qscreenvnc_p.h
@@ -0,0 +1,524 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCREENVNC_P_H
+#define QSCREENVNC_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from version to version
+// without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qscreenvnc_qws.h"
+
+#ifndef QT_NO_QWS_VNC
+
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qsharedmemory.h>
+#include <QtNetwork/qtcpsocket.h>
+#include <QtNetwork/qtcpserver.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVNCServer;
+
+#ifndef QT_NO_QWS_CURSOR
+class QVNCCursor : public QProxyScreenCursor
+{
+public:
+ QVNCCursor(QVNCScreen *s);
+ ~QVNCCursor();
+
+ void hide();
+ void show();
+ void set(const QImage &image, int hotx, int hoty);
+ void move(int x, int y);
+
+private:
+ void setDirty(const QRect &r) const;
+ QVNCScreen *screen;
+};
+
+class QVNCClientCursor : public QProxyScreenCursor
+{
+public:
+ QVNCClientCursor(QVNCServer *s);
+ ~QVNCClientCursor();
+
+ void set(const QImage &image, int hotx, int hoty);
+ void write() const;
+
+private:
+ QVNCServer *server;
+};
+#endif // QT_NO_QWS_CURSOR
+
+#define MAP_TILE_SIZE 16
+#define MAP_WIDTH 1280 / MAP_TILE_SIZE
+#define MAP_HEIGHT 1024 / MAP_TILE_SIZE
+
+class QVNCDirtyMap
+{
+public:
+ QVNCDirtyMap(QScreen *screen);
+ virtual ~QVNCDirtyMap();
+
+ void reset();
+ bool dirty(int x, int y) const;
+ virtual void setDirty(int x, int y, bool force = false) = 0;
+ void setClean(int x, int y);
+
+ int bytesPerPixel;
+
+ int numDirty;
+ int mapWidth;
+ int mapHeight;
+
+protected:
+ uchar *map;
+ QScreen *screen;
+ uchar *buffer;
+ int bufferWidth;
+ int bufferHeight;
+ int bufferStride;
+ int numTiles;
+};
+
+template <class T>
+class QVNCDirtyMapOptimized : public QVNCDirtyMap
+{
+public:
+ QVNCDirtyMapOptimized(QScreen *screen) : QVNCDirtyMap(screen) {}
+ ~QVNCDirtyMapOptimized() {}
+
+ void setDirty(int x, int y, bool force = false);
+};
+
+class QRfbRect
+{
+public:
+ QRfbRect() {}
+ QRfbRect(quint16 _x, quint16 _y, quint16 _w, quint16 _h) {
+ x = _x; y = _y; w = _w; h = _h;
+ }
+
+ void read(QTcpSocket *s);
+ void write(QTcpSocket *s) const;
+
+ quint16 x;
+ quint16 y;
+ quint16 w;
+ quint16 h;
+};
+
+class QRfbPixelFormat
+{
+public:
+ static int size() { return 16; }
+
+ void read(QTcpSocket *s);
+ void write(QTcpSocket *s);
+
+ int bitsPerPixel;
+ int depth;
+ bool bigEndian;
+ bool trueColor;
+ int redBits;
+ int greenBits;
+ int blueBits;
+ int redShift;
+ int greenShift;
+ int blueShift;
+};
+
+class QRfbServerInit
+{
+public:
+ QRfbServerInit() { name = 0; }
+ ~QRfbServerInit() { delete[] name; }
+
+ int size() const { return QRfbPixelFormat::size() + 8 + strlen(name); }
+ void setName(const char *n);
+
+ void read(QTcpSocket *s);
+ void write(QTcpSocket *s);
+
+ quint16 width;
+ quint16 height;
+ QRfbPixelFormat format;
+ char *name;
+};
+
+class QRfbSetEncodings
+{
+public:
+ bool read(QTcpSocket *s);
+
+ quint16 count;
+};
+
+class QRfbFrameBufferUpdateRequest
+{
+public:
+ bool read(QTcpSocket *s);
+
+ char incremental;
+ QRfbRect rect;
+};
+
+class QRfbKeyEvent
+{
+public:
+ bool read(QTcpSocket *s);
+
+ char down;
+ int keycode;
+ int unicode;
+};
+
+class QRfbPointerEvent
+{
+public:
+ bool read(QTcpSocket *s);
+
+ uint buttons;
+ quint16 x;
+ quint16 y;
+};
+
+class QRfbClientCutText
+{
+public:
+ bool read(QTcpSocket *s);
+
+ quint32 length;
+};
+
+class QVNCScreenPrivate : public QObject
+{
+public:
+ QVNCScreenPrivate(QVNCScreen *parent);
+ ~QVNCScreenPrivate();
+
+ void setDirty(const QRect &rect, bool force = false);
+ void configure();
+
+ qreal dpiX;
+ qreal dpiY;
+ bool doOnScreenSurface;
+ QVNCDirtyMap *dirty;
+ int refreshRate;
+ QVNCServer *vncServer;
+
+#if !defined(QT_NO_QWS_MULTIPROCESS) && !defined(QT_NO_SHAREDMEMORY)
+ QSharedMemory shm;
+#endif
+
+ QVNCScreen *q_ptr;
+
+ bool noDisablePainting;
+};
+
+class QRfbEncoder
+{
+public:
+ QRfbEncoder(QVNCServer *s) : server(s) {}
+ virtual ~QRfbEncoder() {}
+
+ virtual void write() = 0;
+
+protected:
+ QVNCServer *server;
+};
+
+class QRfbRawEncoder : public QRfbEncoder
+{
+public:
+ QRfbRawEncoder(QVNCServer *s) : QRfbEncoder(s) {}
+
+ void write();
+
+private:
+ QByteArray buffer;
+};
+
+template <class SRC> class QRfbHextileEncoder;
+
+template <class SRC>
+class QRfbSingleColorHextile
+{
+public:
+ QRfbSingleColorHextile(QRfbHextileEncoder<SRC> *e) : encoder(e) {}
+ bool read(const uchar *data, int width, int height, int stride);
+ void write(QTcpSocket *socket) const;
+
+private:
+ QRfbHextileEncoder<SRC> *encoder;
+};
+
+template <class SRC>
+class QRfbDualColorHextile
+{
+public:
+ QRfbDualColorHextile(QRfbHextileEncoder<SRC> *e) : encoder(e) {}
+ bool read(const uchar *data, int width, int height, int stride);
+ void write(QTcpSocket *socket) const;
+
+private:
+ struct Rect {
+ quint8 xy;
+ quint8 wh;
+ } Q_PACKED rects[8 * 16];
+
+ quint8 numRects;
+ QRfbHextileEncoder<SRC> *encoder;
+
+private:
+ inline int lastx() const { return rectx(numRects); }
+ inline int lasty() const { return recty(numRects); }
+ inline int rectx(int r) const { return rects[r].xy >> 4; }
+ inline int recty(int r) const { return rects[r].xy & 0x0f; }
+ inline int width(int r) const { return (rects[r].wh >> 4) + 1; }
+ inline int height(int r) const { return (rects[r].wh & 0x0f) + 1; }
+
+ inline void setX(int r, int x) {
+ rects[r].xy = (x << 4) | (rects[r].xy & 0x0f);
+ }
+ inline void setY(int r, int y) {
+ rects[r].xy = (rects[r].xy & 0xf0) | y;
+ }
+ inline void setWidth(int r, int width) {
+ rects[r].wh = ((width - 1) << 4) | (rects[r].wh & 0x0f);
+ }
+ inline void setHeight(int r, int height) {
+ rects[r].wh = (rects[r].wh & 0xf0) | (height - 1);
+ }
+
+ inline void setWidth(int width) { setWidth(numRects, width); }
+ inline void setHeight(int height) { setHeight(numRects, height); }
+ inline void setX(int x) { setX(numRects, x); }
+ inline void setY(int y) { setY(numRects, y); }
+ void next();
+};
+
+template <class SRC>
+class QRfbMultiColorHextile
+{
+public:
+ QRfbMultiColorHextile(QRfbHextileEncoder<SRC> *e) : encoder(e) {}
+ bool read(const uchar *data, int width, int height, int stride);
+ void write(QTcpSocket *socket) const;
+
+private:
+ inline quint8* rect(int r) {
+ return rects.data() + r * (bpp + 2);
+ }
+ inline const quint8* rect(int r) const {
+ return rects.constData() + r * (bpp + 2);
+ }
+ inline void setX(int r, int x) {
+ quint8 *ptr = rect(r) + bpp;
+ *ptr = (x << 4) | (*ptr & 0x0f);
+ }
+ inline void setY(int r, int y) {
+ quint8 *ptr = rect(r) + bpp;
+ *ptr = (*ptr & 0xf0) | y;
+ }
+ void setColor(SRC color);
+ inline int rectx(int r) const {
+ const quint8 *ptr = rect(r) + bpp;
+ return *ptr >> 4;
+ }
+ inline int recty(int r) const {
+ const quint8 *ptr = rect(r) + bpp;
+ return *ptr & 0x0f;
+ }
+ inline void setWidth(int r, int width) {
+ quint8 *ptr = rect(r) + bpp + 1;
+ *ptr = ((width - 1) << 4) | (*ptr & 0x0f);
+ }
+ inline void setHeight(int r, int height) {
+ quint8 *ptr = rect(r) + bpp + 1;
+ *ptr = (*ptr & 0xf0) | (height - 1);
+ }
+
+ bool beginRect();
+ void endRect();
+
+ static const int maxRectsSize = 16 * 16;
+ QVarLengthArray<quint8, maxRectsSize> rects;
+
+ quint8 bpp;
+ quint8 numRects;
+ QRfbHextileEncoder<SRC> *encoder;
+};
+
+template <class SRC>
+class QRfbHextileEncoder : public QRfbEncoder
+{
+public:
+ QRfbHextileEncoder(QVNCServer *s);
+ void write();
+
+private:
+ enum SubEncoding {
+ Raw = 1,
+ BackgroundSpecified = 2,
+ ForegroundSpecified = 4,
+ AnySubrects = 8,
+ SubrectsColoured = 16
+ };
+
+ QByteArray buffer;
+ QRfbSingleColorHextile<SRC> singleColorHextile;
+ QRfbDualColorHextile<SRC> dualColorHextile;
+ QRfbMultiColorHextile<SRC> multiColorHextile;
+
+ SRC bg;
+ SRC fg;
+ bool newBg;
+ bool newFg;
+
+ friend class QRfbSingleColorHextile<SRC>;
+ friend class QRfbDualColorHextile<SRC>;
+ friend class QRfbMultiColorHextile<SRC>;
+};
+
+class QVNCServer : public QObject
+{
+ Q_OBJECT
+public:
+ QVNCServer(QVNCScreen *screen);
+ QVNCServer(QVNCScreen *screen, int id);
+ ~QVNCServer();
+
+ void setDirty();
+ void setDirtyCursor() { dirtyCursor = true; setDirty(); }
+ inline bool isConnected() const { return state == Connected; }
+ inline void setRefreshRate(int rate) { refreshRate = rate; }
+
+ enum ClientMsg { SetPixelFormat = 0,
+ FixColourMapEntries = 1,
+ SetEncodings = 2,
+ FramebufferUpdateRequest = 3,
+ KeyEvent = 4,
+ PointerEvent = 5,
+ ClientCutText = 6 };
+
+ enum ServerMsg { FramebufferUpdate = 0,
+ SetColourMapEntries = 1 };
+
+ void convertPixels(char *dst, const char *src, int count) const;
+
+ inline int clientBytesPerPixel() const {
+ return pixelFormat.bitsPerPixel / 8;
+ }
+
+ inline QVNCScreen* screen() const { return qvnc_screen; }
+ inline QVNCDirtyMap* dirtyMap() const { return qvnc_screen->d_ptr->dirty; }
+ inline QTcpSocket* clientSocket() const { return client; }
+ QImage screenImage() const;
+ inline bool doPixelConversion() const { return needConversion; }
+#ifndef QT_NO_QWS_CURSOR
+ inline bool hasClientCursor() const { return qvnc_cursor != 0; }
+#endif
+
+private:
+ void setPixelFormat();
+ void setEncodings();
+ void frameBufferUpdateRequest();
+ void pointerEvent();
+ void keyEvent();
+ void clientCutText();
+ bool pixelConversionNeeded() const;
+
+private slots:
+ void newConnection();
+ void readClient();
+ void checkUpdate();
+ void discardClient();
+
+private:
+ void init(uint port);
+ enum ClientState { Unconnected, Protocol, Init, Connected };
+ QTimer *timer;
+ QTcpServer *serverSocket;
+ QTcpSocket *client;
+ ClientState state;
+ quint8 msgType;
+ bool handleMsg;
+ QRfbPixelFormat pixelFormat;
+ Qt::KeyboardModifiers keymod;
+ int encodingsPending;
+ int cutTextPending;
+ uint supportCopyRect : 1;
+ uint supportRRE : 1;
+ uint supportCoRRE : 1;
+ uint supportHextile : 1;
+ uint supportZRLE : 1;
+ uint supportCursor : 1;
+ uint supportDesktopSize : 1;
+ bool wantUpdate;
+ bool sameEndian;
+ bool needConversion;
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ bool swapBytes;
+#endif
+ bool dirtyCursor;
+ int refreshRate;
+ QVNCScreen *qvnc_screen;
+#ifndef QT_NO_QWS_CURSOR
+ QVNCClientCursor *qvnc_cursor;
+#endif
+
+ QRfbEncoder *encoder;
+};
+
+
+QT_END_NAMESPACE
+#endif // QT_NO_QWS_VNC
+#endif // QSCREENVNC_P_H
diff --git a/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp b/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp
new file mode 100644
index 0000000000..63e06659aa
--- /dev/null
+++ b/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp
@@ -0,0 +1,2338 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qscreenvnc_qws.h"
+
+#ifndef QT_NO_QWS_VNC
+
+#include "qscreenvnc_p.h"
+#include "qwindowsystem_qws.h"
+#include "qwsdisplay_qws.h"
+#include "qscreendriverfactory_qws.h"
+#include <QtCore/qtimer.h>
+#include <QtCore/qregexp.h>
+#include <QtGui/qwidget.h>
+#include <QtGui/qpolygon.h>
+#include <QtGui/qpainter.h>
+#include <qdebug.h>
+#include <private/qwindowsurface_qws_p.h>
+#include <private/qwssignalhandler_p.h>
+#include <private/qwidget_p.h>
+#include <private/qdrawhelper_p.h>
+
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+//#define QT_QWS_VNC_DEBUG
+
+extern QString qws_qtePipeFilename();
+
+#ifndef QT_NO_QWS_CURSOR
+
+QVNCCursor::QVNCCursor(QVNCScreen *s)
+ : screen(s)
+{
+ if (qt_screencursor)
+ setScreenCursor(qt_screencursor);
+ else
+ hwaccel = true;
+}
+
+QVNCCursor::~QVNCCursor()
+{
+ if (screenCursor())
+ qt_screencursor = screenCursor();
+}
+
+void QVNCCursor::setDirty(const QRect &r) const
+{
+ screen->d_ptr->setDirty(r, true);
+}
+
+void QVNCCursor::hide()
+{
+ QProxyScreenCursor::hide();
+ if (enable)
+ setDirty(boundingRect());
+}
+
+void QVNCCursor::show()
+{
+ QProxyScreenCursor::show();
+ if (enable)
+ setDirty(boundingRect());
+}
+
+void QVNCCursor::set(const QImage &image, int hotx, int hoty)
+{
+ QRegion dirty = boundingRect();
+ QProxyScreenCursor::set(image, hotx, hoty);
+ dirty |= boundingRect();
+ if (enable && hwaccel && !screen->d_ptr->vncServer->hasClientCursor()) {
+ const QVector<QRect> rects = dirty.rects();
+ for (int i = 0; i < rects.size(); ++i)
+ setDirty(rects.at(i));
+ }
+}
+
+void QVNCCursor::move(int x, int y)
+{
+ if (enable && hwaccel && !screen->d_ptr->vncServer->hasClientCursor()) {
+ QRegion dirty = boundingRect();
+ QProxyScreenCursor::move(x, y);
+ dirty |= boundingRect();
+ if (enable) {
+ const QVector<QRect> rects = dirty.rects();
+ for (int i = 0; i < rects.size(); ++i)
+ setDirty(rects.at(i));
+ }
+ } else {
+ QProxyScreenCursor::move(x, y);
+ }
+}
+
+QVNCClientCursor::QVNCClientCursor(QVNCServer *s)
+ : server(s)
+{
+ setScreenCursor(qt_screencursor);
+ Q_ASSERT(hwaccel);
+ qt_screencursor = this; // hw: XXX
+
+ set(image(), hotspot.x(), hotspot.y());
+}
+
+QVNCClientCursor::~QVNCClientCursor()
+{
+ qt_screencursor = screenCursor();
+}
+
+void QVNCClientCursor::set(const QImage &image, int hotx, int hoty)
+{
+ QScreenCursor::set(image, hotx, hoty);
+ server->setDirtyCursor();
+}
+
+void QVNCClientCursor::write() const
+{
+ QTcpSocket *socket = server->clientSocket();
+
+ // FramebufferUpdate header
+ {
+ const quint16 tmp[6] = { htons(0),
+ htons(1),
+ htons(hotspot.x()), htons(hotspot.y()),
+ htons(cursor.width()),
+ htons(cursor.height()) };
+ socket->write((char*)tmp, sizeof(tmp));
+
+ const quint32 encoding = htonl(-239);
+ socket->write((char*)(&encoding), sizeof(encoding));
+ }
+
+ if (cursor.isNull())
+ return;
+
+ // write pixels
+ Q_ASSERT(cursor.hasAlphaChannel());
+ const QImage img = cursor.convertToFormat(server->screen()->pixelFormat());
+ const int n = server->clientBytesPerPixel() * img.width();
+ char *buffer = new char[n];
+ for (int i = 0; i < img.height(); ++i) {
+ server->convertPixels(buffer, (const char*)img.scanLine(i), img.width());
+ socket->write(buffer, n);
+ }
+ delete[] buffer;
+
+ // write mask
+ const QImage bitmap = cursor.createAlphaMask().convertToFormat(QImage::Format_Mono);
+ Q_ASSERT(bitmap.depth() == 1);
+ Q_ASSERT(bitmap.size() == img.size());
+ const int width = (bitmap.width() + 7) / 8;
+ for (int i = 0; i < bitmap.height(); ++i)
+ socket->write((const char*)bitmap.scanLine(i), width);
+}
+
+#endif // QT_NO_QWS_CURSOR
+
+QVNCScreenPrivate::QVNCScreenPrivate(QVNCScreen *parent)
+ : dpiX(72), dpiY(72), doOnScreenSurface(false), refreshRate(25),
+ vncServer(0), q_ptr(parent), noDisablePainting(false)
+{
+#ifdef QT_BUILD_INTERNAL
+ noDisablePainting = (qgetenv("QT_VNC_NO_DISABLEPAINTING").toInt() > 0);
+#endif
+#ifndef QT_NO_QWS_SIGNALHANDLER
+ QWSSignalHandler::instance()->addObject(this);
+#endif
+}
+
+QVNCScreenPrivate::~QVNCScreenPrivate()
+{
+#if defined(QT_NO_QWS_MULTIPROCESS) || defined(QT_NO_SHAREDMEMORY)
+ if (q_ptr->screen())
+ return;
+
+ delete[] q_ptr->data;
+ q_ptr->data = 0;
+#else
+ shm.detach();
+#endif
+}
+
+void QVNCScreenPrivate::configure()
+{
+ if (q_ptr->screen())
+ return;
+
+ q_ptr->lstep = q_ptr->dw * ((q_ptr->d + 7) / 8);
+ q_ptr->size = q_ptr->h * q_ptr->lstep;
+ q_ptr->mapsize = q_ptr->size;
+ q_ptr->physWidth = qRound(q_ptr->dw * qreal(25.4) / dpiX);
+ q_ptr->physHeight = qRound(q_ptr->dh * qreal(25.4) / dpiY);
+
+ switch (q_ptr->d) {
+ case 1:
+ q_ptr->setPixelFormat(QImage::Format_Mono); //### LSB???
+ break;
+ case 8:
+ q_ptr->setPixelFormat(QImage::Format_Indexed8);
+ break;
+ case 12:
+ q_ptr->setPixelFormat(QImage::Format_RGB444);
+ break;
+ case 15:
+ q_ptr->setPixelFormat(QImage::Format_RGB555);
+ break;
+ case 16:
+ q_ptr->setPixelFormat(QImage::Format_RGB16);
+ break;
+ case 18:
+ q_ptr->setPixelFormat(QImage::Format_RGB666);
+ break;
+ case 24:
+ q_ptr->setPixelFormat(QImage::Format_RGB888);
+ break;
+ case 32:
+ q_ptr->setPixelFormat(QImage::Format_ARGB32_Premultiplied);
+ break;
+ }
+
+#if !defined(QT_NO_QWS_MULTIPROCESS) && !defined(QT_NO_SHAREDMEMORY)
+ if (q_ptr->size != shm.size()) {
+ shm.detach();
+ const QString key = qws_qtePipeFilename() +
+ QString().sprintf("_vnc_%d_%d",
+ q_ptr->displayId, q_ptr->size);
+ shm.setKey(key);
+ if (QApplication::type() == QApplication::GuiServer) {
+ if (!shm.create(q_ptr->size)) {
+ qWarning() << "QVNCScreen could not create shared memory:"
+ << shm.errorString();
+ if (!shm.attach()) {
+ qWarning() << "QVNCScreen could not attach to shared memory:"
+ << shm.errorString();
+ }
+ }
+ } else if (!shm.attach()) {
+ qWarning() << "QVNCScreen could not attach to shared memory:"
+ << shm.errorString();
+ }
+ q_ptr->data = reinterpret_cast<uchar*>(shm.data());
+ }
+#else
+ if (q_ptr->data)
+ delete[] q_ptr->data;
+ q_ptr->data = new uchar[q_ptr->size];
+#endif
+}
+
+//===========================================================================
+
+static const struct {
+ int keysym;
+ int keycode;
+} keyMap[] = {
+ { 0xff08, Qt::Key_Backspace },
+ { 0xff09, Qt::Key_Tab },
+ { 0xff0d, Qt::Key_Return },
+ { 0xff1b, Qt::Key_Escape },
+ { 0xff63, Qt::Key_Insert },
+ { 0xffff, Qt::Key_Delete },
+ { 0xff50, Qt::Key_Home },
+ { 0xff57, Qt::Key_End },
+ { 0xff55, Qt::Key_PageUp },
+ { 0xff56, Qt::Key_PageDown },
+ { 0xff51, Qt::Key_Left },
+ { 0xff52, Qt::Key_Up },
+ { 0xff53, Qt::Key_Right },
+ { 0xff54, Qt::Key_Down },
+ { 0xffbe, Qt::Key_F1 },
+ { 0xffbf, Qt::Key_F2 },
+ { 0xffc0, Qt::Key_F3 },
+ { 0xffc1, Qt::Key_F4 },
+ { 0xffc2, Qt::Key_F5 },
+ { 0xffc3, Qt::Key_F6 },
+ { 0xffc4, Qt::Key_F7 },
+ { 0xffc5, Qt::Key_F8 },
+ { 0xffc6, Qt::Key_F9 },
+ { 0xffc7, Qt::Key_F10 },
+ { 0xffc8, Qt::Key_F11 },
+ { 0xffc9, Qt::Key_F12 },
+ { 0xffe1, Qt::Key_Shift },
+ { 0xffe2, Qt::Key_Shift },
+ { 0xffe3, Qt::Key_Control },
+ { 0xffe4, Qt::Key_Control },
+ { 0xffe7, Qt::Key_Meta },
+ { 0xffe8, Qt::Key_Meta },
+ { 0xffe9, Qt::Key_Alt },
+ { 0xffea, Qt::Key_Alt },
+
+ { 0xffb0, Qt::Key_0 },
+ { 0xffb1, Qt::Key_1 },
+ { 0xffb2, Qt::Key_2 },
+ { 0xffb3, Qt::Key_3 },
+ { 0xffb4, Qt::Key_4 },
+ { 0xffb5, Qt::Key_5 },
+ { 0xffb6, Qt::Key_6 },
+ { 0xffb7, Qt::Key_7 },
+ { 0xffb8, Qt::Key_8 },
+ { 0xffb9, Qt::Key_9 },
+
+ { 0xff8d, Qt::Key_Return },
+ { 0xffaa, Qt::Key_Asterisk },
+ { 0xffab, Qt::Key_Plus },
+ { 0xffad, Qt::Key_Minus },
+ { 0xffae, Qt::Key_Period },
+ { 0xffaf, Qt::Key_Slash },
+
+ { 0xff95, Qt::Key_Home },
+ { 0xff96, Qt::Key_Left },
+ { 0xff97, Qt::Key_Up },
+ { 0xff98, Qt::Key_Right },
+ { 0xff99, Qt::Key_Down },
+ { 0xff9a, Qt::Key_PageUp },
+ { 0xff9b, Qt::Key_PageDown },
+ { 0xff9c, Qt::Key_End },
+ { 0xff9e, Qt::Key_Insert },
+ { 0xff9f, Qt::Key_Delete },
+
+ { 0, 0 }
+};
+
+void QRfbRect::read(QTcpSocket *s)
+{
+ quint16 buf[4];
+ s->read((char*)buf, 8);
+ x = ntohs(buf[0]);
+ y = ntohs(buf[1]);
+ w = ntohs(buf[2]);
+ h = ntohs(buf[3]);
+}
+
+void QRfbRect::write(QTcpSocket *s) const
+{
+ quint16 buf[4];
+ buf[0] = htons(x);
+ buf[1] = htons(y);
+ buf[2] = htons(w);
+ buf[3] = htons(h);
+ s->write((char*)buf, 8);
+}
+
+void QRfbPixelFormat::read(QTcpSocket *s)
+{
+ char buf[16];
+ s->read(buf, 16);
+ bitsPerPixel = buf[0];
+ depth = buf[1];
+ bigEndian = buf[2];
+ trueColor = buf[3];
+
+ quint16 a = ntohs(*(quint16 *)(buf + 4));
+ redBits = 0;
+ while (a) { a >>= 1; redBits++; }
+
+ a = ntohs(*(quint16 *)(buf + 6));
+ greenBits = 0;
+ while (a) { a >>= 1; greenBits++; }
+
+ a = ntohs(*(quint16 *)(buf + 8));
+ blueBits = 0;
+ while (a) { a >>= 1; blueBits++; }
+
+ redShift = buf[10];
+ greenShift = buf[11];
+ blueShift = buf[12];
+}
+
+void QRfbPixelFormat::write(QTcpSocket *s)
+{
+ char buf[16];
+ buf[0] = bitsPerPixel;
+ buf[1] = depth;
+ buf[2] = bigEndian;
+ buf[3] = trueColor;
+
+ quint16 a = 0;
+ for (int i = 0; i < redBits; i++) a = (a << 1) | 1;
+ *(quint16 *)(buf + 4) = htons(a);
+
+ a = 0;
+ for (int i = 0; i < greenBits; i++) a = (a << 1) | 1;
+ *(quint16 *)(buf + 6) = htons(a);
+
+ a = 0;
+ for (int i = 0; i < blueBits; i++) a = (a << 1) | 1;
+ *(quint16 *)(buf + 8) = htons(a);
+
+ buf[10] = redShift;
+ buf[11] = greenShift;
+ buf[12] = blueShift;
+ s->write(buf, 16);
+}
+
+
+void QRfbServerInit::setName(const char *n)
+{
+ delete[] name;
+ name = new char [strlen(n) + 1];
+ strcpy(name, n);
+}
+
+void QRfbServerInit::read(QTcpSocket *s)
+{
+ s->read((char *)&width, 2);
+ width = ntohs(width);
+ s->read((char *)&height, 2);
+ height = ntohs(height);
+ format.read(s);
+
+ quint32 len;
+ s->read((char *)&len, 4);
+ len = ntohl(len);
+
+ name = new char [len + 1];
+ s->read(name, len);
+ name[len] = '\0';
+}
+
+void QRfbServerInit::write(QTcpSocket *s)
+{
+ quint16 t = htons(width);
+ s->write((char *)&t, 2);
+ t = htons(height);
+ s->write((char *)&t, 2);
+ format.write(s);
+ quint32 len = strlen(name);
+ len = htonl(len);
+ s->write((char *)&len, 4);
+ s->write(name, strlen(name));
+}
+
+bool QRfbSetEncodings::read(QTcpSocket *s)
+{
+ if (s->bytesAvailable() < 3)
+ return false;
+
+ char tmp;
+ s->read(&tmp, 1); // padding
+ s->read((char *)&count, 2);
+ count = ntohs(count);
+
+ return true;
+}
+
+bool QRfbFrameBufferUpdateRequest::read(QTcpSocket *s)
+{
+ if (s->bytesAvailable() < 9)
+ return false;
+
+ s->read(&incremental, 1);
+ rect.read(s);
+
+ return true;
+}
+
+bool QRfbKeyEvent::read(QTcpSocket *s)
+{
+ if (s->bytesAvailable() < 7)
+ return false;
+
+ s->read(&down, 1);
+ quint16 tmp;
+ s->read((char *)&tmp, 2); // padding
+
+ quint32 key;
+ s->read((char *)&key, 4);
+ key = ntohl(key);
+
+ unicode = 0;
+ keycode = 0;
+ int i = 0;
+ while (keyMap[i].keysym && !keycode) {
+ if (keyMap[i].keysym == (int)key)
+ keycode = keyMap[i].keycode;
+ i++;
+ }
+
+ if (keycode >= ' ' && keycode <= '~')
+ unicode = keycode;
+
+ if (!keycode) {
+ if (key <= 0xff) {
+ unicode = key;
+ if (key >= 'a' && key <= 'z')
+ keycode = Qt::Key_A + key - 'a';
+ else if (key >= ' ' && key <= '~')
+ keycode = Qt::Key_Space + key - ' ';
+ }
+ }
+
+ return true;
+}
+
+bool QRfbPointerEvent::read(QTcpSocket *s)
+{
+ if (s->bytesAvailable() < 5)
+ return false;
+
+ char buttonMask;
+ s->read(&buttonMask, 1);
+ buttons = 0;
+ if (buttonMask & 1)
+ buttons |= Qt::LeftButton;
+ if (buttonMask & 2)
+ buttons |= Qt::MidButton;
+ if (buttonMask & 4)
+ buttons |= Qt::RightButton;
+
+ quint16 tmp;
+ s->read((char *)&tmp, 2);
+ x = ntohs(tmp);
+ s->read((char *)&tmp, 2);
+ y = ntohs(tmp);
+
+ return true;
+}
+
+bool QRfbClientCutText::read(QTcpSocket *s)
+{
+ if (s->bytesAvailable() < 7)
+ return false;
+
+ char tmp[3];
+ s->read(tmp, 3); // padding
+ s->read((char *)&length, 4);
+ length = ntohl(length);
+
+ return true;
+}
+
+//===========================================================================
+
+QVNCServer::QVNCServer(QVNCScreen *screen)
+ : qvnc_screen(screen)
+{
+ init(5900);
+}
+
+QVNCServer::QVNCServer(QVNCScreen *screen, int id)
+ : qvnc_screen(screen)
+{
+ init(5900 + id);
+}
+
+void QVNCServer::init(uint port)
+{
+ handleMsg = false;
+ client = 0;
+ encodingsPending = 0;
+ cutTextPending = 0;
+ keymod = 0;
+ state = Unconnected;
+ dirtyCursor = false;
+
+ refreshRate = 25;
+ timer = new QTimer(this);
+ timer->setSingleShot(true);
+ connect(timer, SIGNAL(timeout()), this, SLOT(checkUpdate()));
+
+ serverSocket = new QTcpServer(this);
+ if (!serverSocket->listen(QHostAddress::Any, port))
+ qDebug() << "QVNCServer could not connect:" << serverSocket->errorString();
+ else
+ qDebug("QVNCServer created on port %d", port);
+
+ connect(serverSocket, SIGNAL(newConnection()), this, SLOT(newConnection()));
+
+#ifndef QT_NO_QWS_CURSOR
+ qvnc_cursor = 0;
+#endif
+ encoder = 0;
+}
+
+QVNCServer::~QVNCServer()
+{
+ delete encoder;
+ encoder = 0;
+ delete client;
+ client = 0;
+#ifndef QT_NO_QWS_CURSOR
+ delete qvnc_cursor;
+ qvnc_cursor = 0;
+#endif
+}
+
+void QVNCServer::setDirty()
+{
+ if (state == Connected && !timer->isActive() &&
+ ((dirtyMap()->numDirty > 0) || dirtyCursor)) {
+ timer->start();
+ }
+}
+
+void QVNCServer::newConnection()
+{
+ if (client)
+ delete client;
+
+ client = serverSocket->nextPendingConnection();
+ connect(client,SIGNAL(readyRead()),this,SLOT(readClient()));
+ connect(client,SIGNAL(disconnected()),this,SLOT(discardClient()));
+ handleMsg = false;
+ encodingsPending = 0;
+ cutTextPending = 0;
+ supportHextile = false;
+ wantUpdate = false;
+
+ timer->start(1000 / refreshRate);
+ dirtyMap()->reset();
+
+ // send protocol version
+ const char *proto = "RFB 003.003\n";
+ client->write(proto, 12);
+ state = Protocol;
+
+ if (!qvnc_screen->screen() && !qvnc_screen->d_ptr->noDisablePainting)
+ QWSServer::instance()->enablePainting(true);
+}
+
+void QVNCServer::readClient()
+{
+ switch (state) {
+ case Protocol:
+ if (client->bytesAvailable() >= 12) {
+ char proto[13];
+ client->read(proto, 12);
+ proto[12] = '\0';
+ qDebug("Client protocol version %s", proto);
+ // No authentication
+ quint32 auth = htonl(1);
+ client->write((char *) &auth, sizeof(auth));
+ state = Init;
+ }
+ break;
+
+ case Init:
+ if (client->bytesAvailable() >= 1) {
+ quint8 shared;
+ client->read((char *) &shared, 1);
+
+ // Server Init msg
+ QRfbServerInit sim;
+ QRfbPixelFormat &format = sim.format;
+ switch (qvnc_screen->depth()) {
+ case 32:
+ format.bitsPerPixel = 32;
+ format.depth = 32;
+ format.bigEndian = 0;
+ format.trueColor = true;
+ format.redBits = 8;
+ format.greenBits = 8;
+ format.blueBits = 8;
+ format.redShift = 16;
+ format.greenShift = 8;
+ format.blueShift = 0;
+ break;
+
+ case 24:
+ format.bitsPerPixel = 24;
+ format.depth = 24;
+ format.bigEndian = 0;
+ format.trueColor = true;
+ format.redBits = 8;
+ format.greenBits = 8;
+ format.blueBits = 8;
+ format.redShift = 16;
+ format.greenShift = 8;
+ format.blueShift = 0;
+ break;
+
+ case 18:
+ format.bitsPerPixel = 24;
+ format.depth = 18;
+ format.bigEndian = 0;
+ format.trueColor = true;
+ format.redBits = 6;
+ format.greenBits = 6;
+ format.blueBits = 6;
+ format.redShift = 12;
+ format.greenShift = 6;
+ format.blueShift = 0;
+ break;
+
+ case 16:
+ format.bitsPerPixel = 16;
+ format.depth = 16;
+ format.bigEndian = 0;
+ format.trueColor = true;
+ format.redBits = 5;
+ format.greenBits = 6;
+ format.blueBits = 5;
+ format.redShift = 11;
+ format.greenShift = 5;
+ format.blueShift = 0;
+ break;
+
+ case 15:
+ format.bitsPerPixel = 16;
+ format.depth = 15;
+ format.bigEndian = 0;
+ format.trueColor = true;
+ format.redBits = 5;
+ format.greenBits = 5;
+ format.blueBits = 5;
+ format.redShift = 10;
+ format.greenShift = 5;
+ format.blueShift = 0;
+ break;
+
+ case 12:
+ format.bitsPerPixel = 16;
+ format.depth = 12;
+ format.bigEndian = 0;
+ format.trueColor = true;
+ format.redBits = 4;
+ format.greenBits = 4;
+ format.blueBits = 4;
+ format.redShift = 8;
+ format.greenShift = 4;
+ format.blueShift = 0;
+ break;
+
+ case 8:
+ case 4:
+ format.bitsPerPixel = 8;
+ format.depth = 8;
+ format.bigEndian = 0;
+ format.trueColor = false;
+ format.redBits = 0;
+ format.greenBits = 0;
+ format.blueBits = 0;
+ format.redShift = 0;
+ format.greenShift = 0;
+ format.blueShift = 0;
+ break;
+
+ default:
+ qDebug("QVNC cannot drive depth %d", qvnc_screen->depth());
+ discardClient();
+ return;
+ }
+ sim.width = qvnc_screen->deviceWidth();
+ sim.height = qvnc_screen->deviceHeight();
+ sim.setName("Qt for Embedded Linux VNC Server");
+ sim.write(client);
+ state = Connected;
+ }
+ break;
+
+ case Connected:
+ do {
+ if (!handleMsg) {
+ client->read((char *)&msgType, 1);
+ handleMsg = true;
+ }
+ if (handleMsg) {
+ switch (msgType ) {
+ case SetPixelFormat:
+ setPixelFormat();
+ break;
+ case FixColourMapEntries:
+ qDebug("Not supported: FixColourMapEntries");
+ handleMsg = false;
+ break;
+ case SetEncodings:
+ setEncodings();
+ break;
+ case FramebufferUpdateRequest:
+ frameBufferUpdateRequest();
+ break;
+ case KeyEvent:
+ keyEvent();
+ break;
+ case PointerEvent:
+ pointerEvent();
+ break;
+ case ClientCutText:
+ clientCutText();
+ break;
+ default:
+ qDebug("Unknown message type: %d", (int)msgType);
+ handleMsg = false;
+ }
+ }
+ } while (!handleMsg && client->bytesAvailable());
+ break;
+ default:
+ break;
+ }
+}
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+bool QVNCScreen::swapBytes() const
+{
+ if (depth() != 16)
+ return false;
+
+ if (screen())
+ return screen()->frameBufferLittleEndian();
+ return frameBufferLittleEndian();
+}
+#endif
+
+void QVNCServer::setPixelFormat()
+{
+ if (client->bytesAvailable() >= 19) {
+ char buf[3];
+ client->read(buf, 3); // just padding
+ pixelFormat.read(client);
+#ifdef QT_QWS_VNC_DEBUG
+ qDebug("Want format: %d %d %d %d %d %d %d %d %d %d",
+ int(pixelFormat.bitsPerPixel),
+ int(pixelFormat.depth),
+ int(pixelFormat.bigEndian),
+ int(pixelFormat.trueColor),
+ int(pixelFormat.redBits),
+ int(pixelFormat.greenBits),
+ int(pixelFormat.blueBits),
+ int(pixelFormat.redShift),
+ int(pixelFormat.greenShift),
+ int(pixelFormat.blueShift));
+#endif
+ if (!pixelFormat.trueColor) {
+ qDebug("Can only handle true color clients");
+ discardClient();
+ }
+ handleMsg = false;
+ sameEndian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) == !!pixelFormat.bigEndian;
+ needConversion = pixelConversionNeeded();
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ swapBytes = qvnc_screen->swapBytes();
+#endif
+ }
+}
+
+void QVNCServer::setEncodings()
+{
+ QRfbSetEncodings enc;
+
+ if (!encodingsPending && enc.read(client)) {
+ encodingsPending = enc.count;
+ if (!encodingsPending)
+ handleMsg = false;
+ }
+
+ if (encoder) {
+ delete encoder;
+ encoder = 0;
+ }
+
+ enum Encodings {
+ Raw = 0,
+ CopyRect = 1,
+ RRE = 2,
+ CoRRE = 4,
+ Hextile = 5,
+ ZRLE = 16,
+ Cursor = -239,
+ DesktopSize = -223
+ };
+
+ if (encodingsPending && (unsigned)client->bytesAvailable() >=
+ encodingsPending * sizeof(quint32)) {
+ for (int i = 0; i < encodingsPending; ++i) {
+ qint32 enc;
+ client->read((char *)&enc, sizeof(qint32));
+ enc = ntohl(enc);
+#ifdef QT_QWS_VNC_DEBUG
+ qDebug("QVNCServer::setEncodings: %d", enc);
+#endif
+ switch (enc) {
+ case Raw:
+ if (!encoder) {
+ encoder = new QRfbRawEncoder(this);
+#ifdef QT_QWS_VNC_DEBUG
+ qDebug("QVNCServer::setEncodings: using raw");
+#endif
+ }
+ break;
+ case CopyRect:
+ supportCopyRect = true;
+ break;
+ case RRE:
+ supportRRE = true;
+ break;
+ case CoRRE:
+ supportCoRRE = true;
+ break;
+ case Hextile:
+ supportHextile = true;
+ if (encoder)
+ break;
+ switch (qvnc_screen->depth()) {
+#ifdef QT_QWS_DEPTH_8
+ case 8:
+ encoder = new QRfbHextileEncoder<quint8>(this);
+ break;
+#endif
+#ifdef QT_QWS_DEPTH_12
+ case 12:
+ encoder = new QRfbHextileEncoder<qrgb444>(this);
+ break;
+#endif
+#ifdef QT_QWS_DEPTH_15
+ case 15:
+ encoder = new QRfbHextileEncoder<qrgb555>(this);
+ break;
+#endif
+#ifdef QT_QWS_DEPTH_16
+ case 16:
+ encoder = new QRfbHextileEncoder<quint16>(this);
+ break;
+#endif
+#ifdef QT_QWS_DEPTH_18
+ case 18:
+ encoder = new QRfbHextileEncoder<qrgb666>(this);
+ break;
+#endif
+#ifdef QT_QWS_DEPTH_24
+ case 24:
+ encoder = new QRfbHextileEncoder<qrgb888>(this);
+ break;
+#endif
+#ifdef QT_QWS_DEPTH_32
+ case 32:
+ encoder = new QRfbHextileEncoder<quint32>(this);
+ break;
+#endif
+ default:
+ break;
+ }
+#ifdef QT_QWS_VNC_DEBUG
+ qDebug("QVNCServer::setEncodings: using hextile");
+#endif
+ break;
+ case ZRLE:
+ supportZRLE = true;
+ break;
+ case Cursor:
+ supportCursor = true;
+#ifndef QT_NO_QWS_CURSOR
+ if (!qvnc_screen->screen() || qt_screencursor->isAccelerated()) {
+ delete qvnc_cursor;
+ qvnc_cursor = new QVNCClientCursor(this);
+ }
+#endif
+ break;
+ case DesktopSize:
+ supportDesktopSize = true;
+ break;
+ default:
+ break;
+ }
+ }
+ handleMsg = false;
+ encodingsPending = 0;
+ }
+
+ if (!encoder) {
+ encoder = new QRfbRawEncoder(this);
+#ifdef QT_QWS_VNC_DEBUG
+ qDebug("QVNCServer::setEncodings: fallback using raw");
+#endif
+ }
+}
+
+void QVNCServer::frameBufferUpdateRequest()
+{
+ QRfbFrameBufferUpdateRequest ev;
+
+ if (ev.read(client)) {
+ if (!ev.incremental) {
+ QRect r(ev.rect.x, ev.rect.y, ev.rect.w, ev.rect.h);
+ r.translate(qvnc_screen->offset());
+ qvnc_screen->d_ptr->setDirty(r, true);
+ }
+ wantUpdate = true;
+ checkUpdate();
+ handleMsg = false;
+ }
+}
+
+void QVNCServer::pointerEvent()
+{
+ QRfbPointerEvent ev;
+ if (ev.read(client)) {
+ const QPoint offset = qvnc_screen->offset();
+ QWSServer::sendMouseEvent(offset + QPoint(ev.x, ev.y), ev.buttons);
+ handleMsg = false;
+ }
+}
+
+void QVNCServer::keyEvent()
+{
+ QRfbKeyEvent ev;
+
+ if (ev.read(client)) {
+ if (ev.keycode == Qt::Key_Shift)
+ keymod = ev.down ? keymod | Qt::ShiftModifier :
+ keymod & ~Qt::ShiftModifier;
+ else if (ev.keycode == Qt::Key_Control)
+ keymod = ev.down ? keymod | Qt::ControlModifier :
+ keymod & ~Qt::ControlModifier;
+ else if (ev.keycode == Qt::Key_Alt)
+ keymod = ev.down ? keymod | Qt::AltModifier :
+ keymod & ~Qt::AltModifier;
+ if (ev.unicode || ev.keycode)
+ QWSServer::sendKeyEvent(ev.unicode, ev.keycode, keymod, ev.down, false);
+ handleMsg = false;
+ }
+}
+
+void QVNCServer::clientCutText()
+{
+ QRfbClientCutText ev;
+
+ if (cutTextPending == 0 && ev.read(client)) {
+ cutTextPending = ev.length;
+ if (!cutTextPending)
+ handleMsg = false;
+ }
+
+ if (cutTextPending && client->bytesAvailable() >= cutTextPending) {
+ char *text = new char [cutTextPending+1];
+ client->read(text, cutTextPending);
+ delete [] text;
+ cutTextPending = 0;
+ handleMsg = false;
+ }
+}
+
+// stride in bytes
+template <class SRC>
+bool QRfbSingleColorHextile<SRC>::read(const uchar *data,
+ int width, int height, int stride)
+{
+ const int depth = encoder->server->screen()->depth();
+ if (width % (depth / 8)) // hw: should rather fallback to simple loop
+ return false;
+
+ static int alwaysFalse = qgetenv("QT_VNC_NOCHECKFILL").toInt();
+ if (alwaysFalse)
+ return false;
+
+ switch (depth) {
+ case 4: {
+ const quint8 *data8 = reinterpret_cast<const quint8*>(data);
+ if ((data8[0] & 0xf) != (data8[0] >> 4))
+ return false;
+ width /= 2;
+ } // fallthrough
+ case 8: {
+ const quint8 *data8 = reinterpret_cast<const quint8*>(data);
+ if (data8[0] != data8[1])
+ return false;
+ width /= 2;
+ } // fallthrough
+ case 12:
+ case 15:
+ case 16: {
+ const quint16 *data16 = reinterpret_cast<const quint16*>(data);
+ if (data16[0] != data16[1])
+ return false;
+ width /= 2;
+ } // fallthrough
+ case 18:
+ case 24:
+ case 32: {
+ const quint32 *data32 = reinterpret_cast<const quint32*>(data);
+ const quint32 first = data32[0];
+ const int linestep = (stride / sizeof(quint32)) - width;
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width; ++x) {
+ if (*(data32++) != first)
+ return false;
+ }
+ data32 += linestep;
+ }
+ break;
+ }
+ default:
+ return false;
+ }
+
+ SRC color = reinterpret_cast<const SRC*>(data)[0];
+ encoder->newBg |= (color != encoder->bg);
+ encoder->bg = color;
+ return true;
+}
+
+template <class SRC>
+void QRfbSingleColorHextile<SRC>::write(QTcpSocket *socket) const
+{
+ if (true || encoder->newBg) {
+ const int bpp = encoder->server->clientBytesPerPixel();
+ const int padding = 3;
+ QVarLengthArray<char> buffer(padding + 1 + bpp);
+ buffer[padding] = 2; // BackgroundSpecified
+ encoder->server->convertPixels(buffer.data() + padding + 1,
+ reinterpret_cast<char*>(&encoder->bg),
+ 1);
+ socket->write(buffer.data() + padding, bpp + 1);
+// encoder->newBg = false;
+ } else {
+ char subenc = 0;
+ socket->write(&subenc, 1);
+ }
+}
+
+template <class SRC>
+bool QRfbDualColorHextile<SRC>::read(const uchar *data,
+ int width, int height, int stride)
+{
+ const SRC *ptr = reinterpret_cast<const SRC*>(data);
+ const int linestep = (stride / sizeof(SRC)) - width;
+
+ SRC c1;
+ SRC c2 = 0;
+ int n1 = 0;
+ int n2 = 0;
+ int x = 0;
+ int y = 0;
+
+ c1 = *ptr;
+
+ // find second color
+ while (y < height) {
+ while (x < width) {
+ if (*ptr == c1) {
+ ++n1;
+ } else {
+ c2 = *ptr;
+ goto found_second_color;
+ }
+ ++ptr;
+ ++x;
+ }
+ x = 0;
+ ptr += linestep;
+ ++y;
+ }
+
+found_second_color:
+ // finish counting
+ while (y < height) {
+ while (x < width) {
+ if (*ptr == c1) {
+ ++n1;
+ } else if (*ptr == c2) {
+ ++n2;
+ } else {
+ return false;
+ }
+ ++ptr;
+ ++x;
+ }
+ x = 0;
+ ptr += linestep;
+ ++y;
+ }
+
+ if (n2 > n1) {
+ const quint32 tmpC = c1;
+ c1 = c2;
+ c2 = tmpC;
+ }
+
+ encoder->newBg |= (c1 != encoder->bg);
+ encoder->newFg |= (c2 != encoder->fg);
+
+ encoder->bg = c1;
+ encoder->fg = c2;
+
+ // create map
+ bool inRect = false;
+ numRects = 0;
+ ptr = reinterpret_cast<const SRC*>(data);
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ if (inRect && *ptr == encoder->bg) {
+ // rect finished
+ setWidth(x - lastx());
+ next();
+ inRect = false;
+ } else if (!inRect && *ptr == encoder->fg) {
+ // rect start
+ setX(x);
+ setY(y);
+ setHeight(1);
+ inRect = true;
+ }
+ ++ptr;
+ }
+ if (inRect) {
+ // finish rect
+ setWidth(width - lastx());
+ next();
+ inRect = false;
+ }
+ ptr += linestep;
+ }
+
+ return true;
+}
+
+template <class SRC>
+void QRfbDualColorHextile<SRC>::write(QTcpSocket *socket) const
+{
+ const int bpp = encoder->server->clientBytesPerPixel();
+ const int padding = 3;
+ QVarLengthArray<char> buffer(padding + 2 * bpp + sizeof(char) + sizeof(numRects));
+ char &subenc = buffer[padding];
+ int n = padding + sizeof(subenc);
+
+ subenc = 0x8; // AnySubrects
+
+ if (encoder->newBg) {
+ subenc |= 0x2; // Background
+ encoder->server->convertPixels(buffer.data() + n, (char*)&encoder->bg, 1);
+ n += bpp;
+// encoder->newBg = false;
+ }
+
+ if (encoder->newFg) {
+ subenc |= 0x4; // Foreground
+ encoder->server->convertPixels(buffer.data() + n, (char*)&encoder->fg, 1);
+ n += bpp;
+// encoder->newFg = false;
+ }
+ buffer[n] = numRects;
+ n += sizeof(numRects);
+
+ socket->write(buffer.data() + padding, n - padding);
+ socket->write((char*)rects, numRects * sizeof(Rect));
+}
+
+template <class SRC>
+void QRfbDualColorHextile<SRC>::next()
+{
+ for (int r = numRects - 1; r >= 0; --r) {
+ if (recty(r) == lasty())
+ continue;
+ if (recty(r) < lasty() - 1) // only search previous scanline
+ break;
+ if (rectx(r) == lastx() && width(r) == width(numRects)) {
+ ++rects[r].wh;
+ return;
+ }
+ }
+ ++numRects;
+}
+
+template <class SRC>
+inline void QRfbMultiColorHextile<SRC>::setColor(SRC color)
+{
+ encoder->server->convertPixels(reinterpret_cast<char*>(rect(numRects)),
+ (const char*)&color, 1);
+}
+
+template <class SRC>
+inline bool QRfbMultiColorHextile<SRC>::beginRect()
+{
+ if ((rects.size() + bpp + 2) > maxRectsSize)
+ return false;
+ rects.resize(rects.size() + bpp + 2);
+ return true;
+}
+
+template <class SRC>
+inline void QRfbMultiColorHextile<SRC>::endRect()
+{
+ setHeight(numRects, 1);
+ ++numRects;
+}
+
+template <class SRC>
+bool QRfbMultiColorHextile<SRC>::read(const uchar *data,
+ int width, int height, int stride)
+{
+ const SRC *ptr = reinterpret_cast<const SRC*>(data);
+ const int linestep = (stride / sizeof(SRC)) - width;
+
+ bpp = encoder->server->clientBytesPerPixel();
+
+ if (encoder->newBg)
+ encoder->bg = ptr[0];
+
+ const SRC bg = encoder->bg;
+ SRC color = bg;
+ bool inRect = false;
+
+ numRects = 0;
+ rects.clear();
+
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width; ++x) {
+ if (inRect && *ptr != color) { // end rect
+ setWidth(numRects, x - rectx(numRects));
+ endRect();
+ inRect = false;
+ }
+
+ if (!inRect && *ptr != bg) { // begin rect
+ if (!beginRect())
+ return false;
+ inRect = true;
+ color = *ptr;
+ setColor(color);
+ setX(numRects, x);
+ setY(numRects, y);
+ }
+ ++ptr;
+ }
+ if (inRect) { // end rect
+ setWidth(numRects, width - rectx(numRects));
+ endRect();
+ inRect = false;
+ }
+ ptr += linestep;
+ }
+
+ return true;
+}
+
+template <class SRC>
+void QRfbMultiColorHextile<SRC>::write(QTcpSocket *socket) const
+{
+ const int padding = 3;
+ QVarLengthArray<quint8> buffer(bpp + padding + sizeof(quint8) + sizeof(numRects));
+
+ quint8 &subenc = buffer[padding];
+ int n = padding + sizeof(quint8);
+
+ subenc = 8 | 16; // AnySubrects | SubrectsColoured
+
+ if (encoder->newBg) {
+ subenc |= 0x2; // Background
+ encoder->server->convertPixels(reinterpret_cast<char*>(buffer.data() + n),
+ reinterpret_cast<const char*>(&encoder->bg),
+ 1);
+ n += bpp;
+// encoder->newBg = false;
+ }
+
+ buffer[n] = numRects;
+ n += sizeof(numRects);
+
+ socket->write(reinterpret_cast<const char*>(buffer.data() + padding),
+ n - padding);
+ socket->write(reinterpret_cast<const char*>(rects.constData()),
+ rects.size());
+}
+
+bool QVNCServer::pixelConversionNeeded() const
+{
+ if (!sameEndian)
+ return true;
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ if (qvnc_screen->swapBytes())
+ return true;
+#endif
+
+ const int screendepth = qvnc_screen->depth();
+ if (screendepth != pixelFormat.bitsPerPixel)
+ return true;
+
+ switch (screendepth) {
+ case 32:
+ case 24:
+ return false;
+ case 18:
+ return (pixelFormat.redBits == 6
+ && pixelFormat.greenBits == 6
+ && pixelFormat.blueBits == 6);
+ case 16:
+ return (pixelFormat.redBits == 5
+ && pixelFormat.greenBits == 6
+ && pixelFormat.blueBits == 5);
+ case 15:
+ return (pixelFormat.redBits == 5
+ && pixelFormat.greenBits == 5
+ && pixelFormat.blueBits == 5);
+ case 12:
+ return (pixelFormat.redBits == 4
+ && pixelFormat.greenBits == 4
+ && pixelFormat.blueBits == 4);
+ }
+ return true;
+}
+
+// count: number of pixels
+void QVNCServer::convertPixels(char *dst, const char *src, int count) const
+{
+ const int screendepth = qvnc_screen->depth();
+ const bool isBgr = qvnc_screen->pixelType() == QScreen::BGRPixel;
+
+ // cutoffs
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ if (!swapBytes)
+#endif
+ if (sameEndian) {
+ if (screendepth == pixelFormat.bitsPerPixel) { // memcpy cutoffs
+
+ switch (screendepth) {
+ case 32:
+ memcpy(dst, src, count * sizeof(quint32));
+ return;
+ case 16:
+ if (pixelFormat.redBits == 5
+ && pixelFormat.greenBits == 6
+ && pixelFormat.blueBits == 5)
+ {
+ memcpy(dst, src, count * sizeof(quint16));
+ return;
+ }
+ }
+ } else if (screendepth == 16 && pixelFormat.bitsPerPixel == 32) {
+#if defined(__i386__) // Currently fails on ARM if dst is not 4 byte aligned
+ const quint32 *src32 = reinterpret_cast<const quint32*>(src);
+ quint32 *dst32 = reinterpret_cast<quint32*>(dst);
+ int count32 = count * sizeof(quint16) / sizeof(quint32);
+ while (count32--) {
+ const quint32 s = *src32++;
+ quint32 result1;
+ quint32 result2;
+
+ // red
+ result1 = ((s & 0xf8000000) | ((s & 0xe0000000) >> 5)) >> 8;
+ result2 = ((s & 0x0000f800) | ((s & 0x0000e000) >> 5)) << 8;
+
+ // green
+ result1 |= ((s & 0x07e00000) | ((s & 0x06000000) >> 6)) >> 11;
+ result2 |= ((s & 0x000007e0) | ((s & 0x00000600) >> 6)) << 5;
+
+ // blue
+ result1 |= ((s & 0x001f0000) | ((s & 0x001c0000) >> 5)) >> 13;
+ result2 |= ((s & 0x0000001f) | ((s & 0x0000001c) >> 5)) << 3;
+
+ *dst32++ = result2;
+ *dst32++ = result1;
+ }
+ if (count & 0x1) {
+ const quint16 *src16 = reinterpret_cast<const quint16*>(src);
+ *dst32 = qt_conv16ToRgb(src16[count - 1]);
+ }
+ return;
+#endif
+ }
+ }
+
+ const int bytesPerPixel = (pixelFormat.bitsPerPixel + 7) / 8;
+
+// nibble = 0;
+
+ for (int i = 0; i < count; ++i) {
+ int r, g, b;
+
+ switch (screendepth) {
+#if 0
+ case 4: {
+ if (!nibble) {
+ r = ((*src) & 0x0f) << 4;
+ } else {
+ r = (*src) & 0xf0;
+ src++;
+ }
+ nibble = !nibble;
+ g = b = r;
+ break;
+ }
+#endif
+ case 8: {
+ QRgb rgb = qvnc_screen->clut()[int(*src)];
+ r = qRed(rgb);
+ g = qGreen(rgb);
+ b = qBlue(rgb);
+ src++;
+ break;
+ }
+#ifdef QT_QWS_DEPTH_12
+ case 12: {
+ quint32 p = quint32(*reinterpret_cast<const qrgb444*>(src));
+ r = qRed(p);
+ g = qGreen(p);
+ b = qBlue(p);
+ src += sizeof(qrgb444);
+ break;
+ }
+#endif
+#ifdef QT_QWS_DEPTH_15
+ case 15: {
+ quint32 p = quint32(*reinterpret_cast<const qrgb555*>(src));
+ r = qRed(p);
+ g = qGreen(p);
+ b = qBlue(p);
+ src += sizeof(qrgb555);
+ break;
+ }
+#endif
+ case 16: {
+ quint16 p = *reinterpret_cast<const quint16*>(src);
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ if (swapBytes)
+ p = ((p & 0xff) << 8) | ((p & 0xff00) >> 8);
+#endif
+ r = (p >> 11) & 0x1f;
+ g = (p >> 5) & 0x3f;
+ b = p & 0x1f;
+ r <<= 3;
+ g <<= 2;
+ b <<= 3;
+ src += sizeof(quint16);
+ break;
+ }
+#ifdef QT_QWS_DEPTH_18
+ case 18: {
+ quint32 p = quint32(*reinterpret_cast<const qrgb666*>(src));
+ r = qRed(p);
+ g = qGreen(p);
+ b = qBlue(p);
+ src += sizeof(qrgb666);
+ break;
+ }
+#endif
+#ifdef QT_QWS_DEPTH_24
+ case 24: {
+ quint32 p = quint32(*reinterpret_cast<const qrgb888*>(src));
+ r = qRed(p);
+ g = qGreen(p);
+ b = qBlue(p);
+ src += sizeof(qrgb888);
+ break;
+ }
+#endif
+ case 32: {
+ quint32 p = *reinterpret_cast<const quint32*>(src);
+ r = (p >> 16) & 0xff;
+ g = (p >> 8) & 0xff;
+ b = p & 0xff;
+ src += sizeof(quint32);
+ break;
+ }
+ default: {
+ r = g = b = 0;
+ qDebug("QVNCServer: don't support %dbpp display", screendepth);
+ return;
+ }
+ }
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ if (swapBytes ^ isBgr)
+#else
+ if (isBgr)
+#endif
+ qSwap(r, b);
+
+ r >>= (8 - pixelFormat.redBits);
+ g >>= (8 - pixelFormat.greenBits);
+ b >>= (8 - pixelFormat.blueBits);
+
+ int pixel = (r << pixelFormat.redShift) |
+ (g << pixelFormat.greenShift) |
+ (b << pixelFormat.blueShift);
+
+ if (sameEndian || pixelFormat.bitsPerPixel == 8) {
+ memcpy(dst, &pixel, bytesPerPixel); // XXX: do a simple for-loop instead?
+ dst += bytesPerPixel;
+ continue;
+ }
+
+
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ switch (pixelFormat.bitsPerPixel) {
+ case 16:
+ pixel = (((pixel & 0x0000ff00) << 8) |
+ ((pixel & 0x000000ff) << 24));
+ break;
+ case 32:
+ pixel = (((pixel & 0xff000000) >> 24) |
+ ((pixel & 0x00ff0000) >> 8) |
+ ((pixel & 0x0000ff00) << 8) |
+ ((pixel & 0x000000ff) << 24));
+ break;
+ default:
+ qDebug("Cannot handle %d bpp client", pixelFormat.bitsPerPixel);
+ }
+ } else { // QSysInfo::ByteOrder == QSysInfo::LittleEndian
+ switch (pixelFormat.bitsPerPixel) {
+ case 16:
+ pixel = (((pixel & 0xff000000) >> 8) |
+ ((pixel & 0x00ff0000) << 8));
+ break;
+ case 32:
+ pixel = (((pixel & 0xff000000) >> 24) |
+ ((pixel & 0x00ff0000) >> 8) |
+ ((pixel & 0x0000ff00) << 8) |
+ ((pixel & 0x000000ff) << 24));
+ break;
+ default:
+ qDebug("Cannot handle %d bpp client",
+ pixelFormat.bitsPerPixel);
+ break;
+ }
+ }
+ memcpy(dst, &pixel, bytesPerPixel); // XXX: simple for-loop instead?
+ dst += bytesPerPixel;
+ }
+}
+
+#ifndef QT_NO_QWS_CURSOR
+static void blendCursor(QImage &image, const QRect &imageRect)
+{
+ const QRect cursorRect = qt_screencursor->boundingRect();
+ const QRect intersection = (cursorRect & imageRect);
+ const QRect destRect = intersection.translated(-imageRect.topLeft());
+ const QRect srcRect = intersection.translated(-cursorRect.topLeft());
+
+ QPainter painter(&image);
+ painter.drawImage(destRect, qt_screencursor->image(), srcRect);
+ painter.end();
+}
+#endif // QT_NO_QWS_CURSOR
+
+QVNCDirtyMap::QVNCDirtyMap(QScreen *s)
+ : bytesPerPixel(0), numDirty(0), screen(s)
+{
+ bytesPerPixel = (screen->depth() + 7) / 8;
+ bufferWidth = screen->deviceWidth();
+ bufferHeight = screen->deviceHeight();
+ bufferStride = bufferWidth * bytesPerPixel;
+ buffer = new uchar[bufferHeight * bufferStride];
+
+ mapWidth = (bufferWidth + MAP_TILE_SIZE - 1) / MAP_TILE_SIZE;
+ mapHeight = (bufferHeight + MAP_TILE_SIZE - 1) / MAP_TILE_SIZE;
+ numTiles = mapWidth * mapHeight;
+ map = new uchar[numTiles];
+}
+
+QVNCDirtyMap::~QVNCDirtyMap()
+{
+ delete[] map;
+ delete[] buffer;
+}
+
+void QVNCDirtyMap::reset()
+{
+ memset(map, 1, numTiles);
+ memset(buffer, 0, bufferHeight * bufferStride);
+ numDirty = numTiles;
+}
+
+inline bool QVNCDirtyMap::dirty(int x, int y) const
+{
+ return map[y * mapWidth + x];
+}
+
+inline void QVNCDirtyMap::setClean(int x, int y)
+{
+ map[y * mapWidth + x] = 0;
+ --numDirty;
+}
+
+template <class T>
+void QVNCDirtyMapOptimized<T>::setDirty(int tileX, int tileY, bool force)
+{
+ static bool alwaysForce = qgetenv("QT_VNC_NO_COMPAREBUFFER").toInt();
+ if (alwaysForce)
+ force = true;
+
+ bool changed = false;
+
+ if (!force) {
+ const int lstep = screen->linestep();
+ const int startX = tileX * MAP_TILE_SIZE;
+ const int startY = tileY * MAP_TILE_SIZE;
+ const uchar *scrn = screen->base()
+ + startY * lstep + startX * bytesPerPixel;
+ uchar *old = buffer + startY * bufferStride + startX * sizeof(T);
+
+ const int tileHeight = (startY + MAP_TILE_SIZE > bufferHeight ?
+ bufferHeight - startY : MAP_TILE_SIZE);
+ const int tileWidth = (startX + MAP_TILE_SIZE > bufferWidth ?
+ bufferWidth - startX : MAP_TILE_SIZE);
+ const bool doInlines = (tileWidth == MAP_TILE_SIZE);
+
+ int y = tileHeight;
+
+ if (doInlines) { // hw: memcmp/memcpy is inlined when using constants
+ while (y) {
+ if (memcmp(old, scrn, sizeof(T) * MAP_TILE_SIZE)) {
+ changed = true;
+ break;
+ }
+ scrn += lstep;
+ old += bufferStride;
+ --y;
+ }
+
+ while (y) {
+ memcpy(old, scrn, sizeof(T) * MAP_TILE_SIZE);
+ scrn += lstep;
+ old += bufferStride;
+ --y;
+ }
+ } else {
+ while (y) {
+ if (memcmp(old, scrn, sizeof(T) * tileWidth)) {
+ changed = true;
+ break;
+ }
+ scrn += lstep;
+ old += bufferStride;
+ --y;
+ }
+
+ while (y) {
+ memcpy(old, scrn, sizeof(T) * tileWidth);
+ scrn += lstep;
+ old += bufferStride;
+ --y;
+ }
+ }
+ }
+
+ const int mapIndex = tileY * mapWidth + tileX;
+ if ((force || changed) && !map[mapIndex]) {
+ map[mapIndex] = 1;
+ ++numDirty;
+ }
+}
+
+template <class SRC>
+QRfbHextileEncoder<SRC>::QRfbHextileEncoder(QVNCServer *s)
+ : QRfbEncoder(s),
+ singleColorHextile(this), dualColorHextile(this), multiColorHextile(this)
+{
+}
+
+/*
+ \internal
+ Send dirty rects using hextile encoding.
+*/
+template <class SRC>
+void QRfbHextileEncoder<SRC>::write()
+{
+ QWSDisplay::grab(true);
+
+ QVNCDirtyMap *map = server->dirtyMap();
+ QTcpSocket *socket = server->clientSocket();
+
+ const quint32 encoding = htonl(5); // hextile encoding
+ const int bytesPerPixel = server->clientBytesPerPixel();
+
+ {
+ const char tmp[2] = { 0, 0 }; // msg type, padding
+ socket->write(tmp, sizeof(tmp));
+ }
+ {
+ const quint16 count = htons(map->numDirty);
+ socket->write((char *)&count, sizeof(count));
+ }
+
+ if (map->numDirty <= 0) {
+ QWSDisplay::ungrab();
+ return;
+ }
+
+ newBg = true;
+ newFg = true;
+
+ const QImage screenImage = server->screenImage();
+ QRfbRect rect(0, 0, MAP_TILE_SIZE, MAP_TILE_SIZE);
+
+ for (int y = 0; y < map->mapHeight; ++y) {
+ if (rect.y + MAP_TILE_SIZE > server->screen()->height())
+ rect.h = server->screen()->height() - rect.y;
+ rect.w = MAP_TILE_SIZE;
+ for (int x = 0; x < map->mapWidth; ++x) {
+ if (!map->dirty(x, y))
+ continue;
+ map->setClean(x, y);
+
+ rect.x = x * MAP_TILE_SIZE;
+ if (rect.x + MAP_TILE_SIZE > server->screen()->deviceWidth())
+ rect.w = server->screen()->deviceWidth() - rect.x;
+ rect.write(socket);
+
+ socket->write((char *)&encoding, sizeof(encoding));
+
+ const uchar *screendata = screenImage.scanLine(rect.y)
+ + rect.x * screenImage.depth() / 8;
+ int linestep = screenImage.bytesPerLine();
+
+#ifndef QT_NO_QWS_CURSOR
+ // hardware cursors must be blended with the screen memory
+ const bool doBlendCursor = qt_screencursor
+ && !server->hasClientCursor()
+ && qt_screencursor->isAccelerated();
+ QImage tileImage;
+ if (doBlendCursor) {
+ const QRect tileRect(rect.x, rect.y, rect.w, rect.h);
+ const QRect cursorRect = qt_screencursor->boundingRect()
+ .translated(-server->screen()->offset());
+ if (tileRect.intersects(cursorRect)) {
+ tileImage = screenImage.copy(tileRect);
+ blendCursor(tileImage,
+ tileRect.translated(server->screen()->offset()));
+ screendata = tileImage.bits();
+ linestep = tileImage.bytesPerLine();
+ }
+ }
+#endif // QT_NO_QWS_CURSOR
+
+ if (singleColorHextile.read(screendata, rect.w, rect.h, linestep)) {
+ singleColorHextile.write(socket);
+ } else if (dualColorHextile.read(screendata, rect.w, rect.h, linestep)) {
+ dualColorHextile.write(socket);
+ } else if (multiColorHextile.read(screendata, rect.w, rect.h, linestep)) {
+ multiColorHextile.write(socket);
+ } else if (server->doPixelConversion()) {
+ const int bufferSize = rect.w * rect.h * bytesPerPixel + 1;
+ const int padding = sizeof(quint32) - sizeof(char);
+ buffer.resize(bufferSize + padding);
+
+ buffer[padding] = 1; // Raw subencoding
+
+ // convert pixels
+ char *b = buffer.data() + padding + 1;
+ const int bstep = rect.w * bytesPerPixel;
+ for (int i = 0; i < rect.h; ++i) {
+ server->convertPixels(b, (const char*)screendata, rect.w);
+ screendata += linestep;
+ b += bstep;
+ }
+ socket->write(buffer.constData() + padding, bufferSize);
+ } else {
+ quint8 subenc = 1; // Raw subencoding
+ socket->write((char *)&subenc, 1);
+
+ // send pixels
+ for (int i = 0; i < rect.h; ++i) {
+ socket->write((const char*)screendata,
+ rect.w * bytesPerPixel);
+ screendata += linestep;
+ }
+ }
+ }
+ if (socket->state() == QAbstractSocket::UnconnectedState)
+ break;
+ rect.y += MAP_TILE_SIZE;
+ }
+ socket->flush();
+ Q_ASSERT(map->numDirty == 0);
+
+ QWSDisplay::ungrab();
+}
+
+void QRfbRawEncoder::write()
+{
+ QWSDisplay::grab(false);
+
+ QVNCDirtyMap *map = server->dirtyMap();
+ QTcpSocket *socket = server->clientSocket();
+
+ const int bytesPerPixel = server->clientBytesPerPixel();
+
+ // create a region from the dirty rects and send the region's merged rects.
+ QRegion rgn;
+ if (map) {
+ for (int y = 0; y < map->mapHeight; ++y) {
+ for (int x = 0; x < map->mapWidth; ++x) {
+ if (!map->dirty(x, y))
+ continue;
+ rgn += QRect(x * MAP_TILE_SIZE, y * MAP_TILE_SIZE,
+ MAP_TILE_SIZE, MAP_TILE_SIZE);
+ map->setClean(x, y);
+ }
+ }
+
+ rgn &= QRect(0, 0, server->screen()->deviceWidth(),
+ server->screen()->deviceHeight());
+ }
+ const QVector<QRect> rects = rgn.rects();
+
+ {
+ const char tmp[2] = { 0, 0 }; // msg type, padding
+ socket->write(tmp, sizeof(tmp));
+ }
+
+ {
+ const quint16 count = htons(rects.size());
+ socket->write((char *)&count, sizeof(count));
+ }
+
+ if (rects.size() <= 0) {
+ QWSDisplay::ungrab();
+ return;
+ }
+
+ const QImage screenImage = server->screenImage();
+
+ for (int i = 0; i < rects.size(); ++i) {
+ const QRect tileRect = rects.at(i);
+ const QRfbRect rect(tileRect.x(), tileRect.y(),
+ tileRect.width(), tileRect.height());
+ rect.write(socket);
+
+ const quint32 encoding = htonl(0); // raw encoding
+ socket->write((char *)&encoding, sizeof(encoding));
+
+ int linestep = screenImage.bytesPerLine();
+ const uchar *screendata = screenImage.scanLine(rect.y)
+ + rect.x * screenImage.depth() / 8;
+
+#ifndef QT_NO_QWS_CURSOR
+ // hardware cursors must be blended with the screen memory
+ const bool doBlendCursor = qt_screencursor
+ && !server->hasClientCursor()
+ && qt_screencursor->isAccelerated();
+ QImage tileImage;
+ if (doBlendCursor) {
+ const QRect cursorRect = qt_screencursor->boundingRect()
+ .translated(-server->screen()->offset());
+ if (tileRect.intersects(cursorRect)) {
+ tileImage = screenImage.copy(tileRect);
+ blendCursor(tileImage,
+ tileRect.translated(server->screen()->offset()));
+ screendata = tileImage.bits();
+ linestep = tileImage.bytesPerLine();
+ }
+ }
+#endif // QT_NO_QWS_CURSOR
+
+ if (server->doPixelConversion()) {
+ const int bufferSize = rect.w * rect.h * bytesPerPixel;
+ if (bufferSize > buffer.size())
+ buffer.resize(bufferSize);
+
+ // convert pixels
+ char *b = buffer.data();
+ const int bstep = rect.w * bytesPerPixel;
+ for (int i = 0; i < rect.h; ++i) {
+ server->convertPixels(b, (const char*)screendata, rect.w);
+ screendata += linestep;
+ b += bstep;
+ }
+ socket->write(buffer.constData(), bufferSize);
+ } else {
+ for (int i = 0; i < rect.h; ++i) {
+ socket->write((const char*)screendata, rect.w * bytesPerPixel);
+ screendata += linestep;
+ }
+ }
+ if (socket->state() == QAbstractSocket::UnconnectedState)
+ break;
+ }
+ socket->flush();
+
+ QWSDisplay::ungrab();
+}
+
+inline QImage QVNCServer::screenImage() const
+{
+ return QImage(qvnc_screen->base(), qvnc_screen->deviceWidth(),
+ qvnc_screen->deviceHeight(), qvnc_screen->linestep(),
+ qvnc_screen->pixelFormat());
+}
+
+void QVNCServer::checkUpdate()
+{
+ if (!wantUpdate)
+ return;
+
+ if (dirtyCursor) {
+#ifndef QT_NO_QWS_CURSOR
+ Q_ASSERT(qvnc_cursor);
+ qvnc_cursor->write();
+#endif
+ dirtyCursor = false;
+ wantUpdate = false;
+ return;
+ }
+
+ if (dirtyMap()->numDirty > 0) {
+ if (encoder)
+ encoder->write();
+ wantUpdate = false;
+ }
+}
+
+void QVNCServer::discardClient()
+{
+ timer->stop();
+ state = Unconnected;
+ delete encoder;
+ encoder = 0;
+#ifndef QT_NO_QWS_CURSOR
+ delete qvnc_cursor;
+ qvnc_cursor = 0;
+#endif
+ if (!qvnc_screen->screen() && !qvnc_screen->d_ptr->noDisablePainting && QWSServer::instance())
+ QWSServer::instance()->enablePainting(false);
+}
+
+
+//===========================================================================
+
+/*!
+ \class QVNCScreen
+ \internal
+ \ingroup qws
+
+ \brief The QVNCScreen class implements a screen driver for VNC
+ servers.
+
+ Note that this class is only available in \l{Qt for Embedded Linux}.
+ Custom screen drivers can be added by subclassing the QScreen
+ class, using the QScreenDriverFactory class to dynamically load
+ the driver into the application.
+
+ The VNC protocol allows you to view and interact with the
+ computer's display from anywhere on the network. See the
+ \l{The VNC Protocol and Qt for Embedded Linux}{VNC protocol}
+ documentation for more details.
+
+ The default implementation of QVNCScreen inherits QLinuxFbScreen,
+ but any QScreen subclass, or QScreen itself, can serve as its base
+ class. This is easily achieved by manipulating the \c
+ VNCSCREEN_BASE definition in the header file.
+
+ \sa QScreen, {Running Applications}
+*/
+
+/*!
+ \fn QVNCScreen::QVNCScreen(int displayId)
+
+ Constructs a QVNCScreen object. The \a displayId argument
+ identifies the Qt for Embedded Linux server to connect to.
+*/
+QVNCScreen::QVNCScreen(int display_id)
+ : QProxyScreen(display_id, VNCClass)
+{
+ d_ptr = new QVNCScreenPrivate(this);
+}
+
+/*!
+ Destroys this QVNCScreen object.
+*/
+QVNCScreen::~QVNCScreen()
+{
+ delete d_ptr;
+}
+
+/*!
+ \reimp
+*/
+void QVNCScreen::setDirty(const QRect &rect)
+{
+ d_ptr->setDirty(rect);
+}
+
+void QVNCScreenPrivate::setDirty(const QRect& rect, bool force)
+{
+ if (rect.isEmpty())
+ return;
+
+ if (q_ptr->screen())
+ q_ptr->screen()->setDirty(rect);
+
+ if (!vncServer || !vncServer->isConnected())
+ return;
+
+ const QRect r = rect.translated(-q_ptr->offset());
+ const int x1 = r.x() / MAP_TILE_SIZE;
+ int y = r.y() / MAP_TILE_SIZE;
+ for (; (y <= r.bottom() / MAP_TILE_SIZE) && y < dirty->mapHeight; y++)
+ for (int x = x1; (x <= r.right() / MAP_TILE_SIZE) && x < dirty->mapWidth; x++)
+ dirty->setDirty(x, y, force);
+
+ vncServer->setDirty();
+}
+
+static int getDisplayId(const QString &spec)
+{
+ QRegExp regexp(QLatin1String(":(\\d+)\\b"));
+ if (regexp.lastIndexIn(spec) != -1) {
+ const QString capture = regexp.cap(1);
+ return capture.toInt();
+ }
+ return 0;
+}
+
+/*!
+ \reimp
+*/
+bool QVNCScreen::connect(const QString &displaySpec)
+{
+ QString dspec = displaySpec;
+ if (dspec.startsWith(QLatin1String("vnc:"), Qt::CaseInsensitive))
+ dspec = dspec.mid(QString::fromLatin1("vnc:").size());
+ else if (dspec.compare(QLatin1String("vnc"), Qt::CaseInsensitive) == 0)
+ dspec = QString();
+
+ const QString displayIdSpec = QString::fromLatin1(" :%1").arg(displayId);
+ if (dspec.endsWith(displayIdSpec))
+ dspec = dspec.left(dspec.size() - displayIdSpec.size());
+
+ QStringList args = dspec.split(QLatin1Char(':'),
+ QString::SkipEmptyParts);
+ QRegExp refreshRegexp(QLatin1String("^refreshrate=(\\d+)$"));
+ int index = args.indexOf(refreshRegexp);
+ if (index >= 0) {
+ d_ptr->refreshRate = refreshRegexp.cap(1).toInt();
+ args.removeAt(index);
+ dspec = args.join(QLatin1String(":"));
+ }
+
+ QString driver = dspec;
+ int colon = driver.indexOf(QLatin1Char(':'));
+ if (colon >= 0)
+ driver.truncate(colon);
+
+ if (QScreenDriverFactory::keys().contains(driver, Qt::CaseInsensitive)) {
+ const int id = getDisplayId(dspec);
+ QScreen *s = qt_get_screen(id, dspec.toLatin1().constData());
+ if (s->pixelFormat() == QImage::Format_Indexed8
+ || s->pixelFormat() == QImage::Format_Invalid && s->depth() == 8)
+ qFatal("QVNCScreen: unsupported screen format");
+ setScreen(s);
+ } else { // create virtual screen
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ QScreen::setFrameBufferLittleEndian(false);
+#endif
+
+ d = qgetenv("QWS_DEPTH").toInt();
+ if (!d)
+ d = 16;
+
+ QByteArray str = qgetenv("QWS_SIZE");
+ if(!str.isEmpty()) {
+ sscanf(str.constData(), "%dx%d", &w, &h);
+ dw = w;
+ dh = h;
+ } else {
+ dw = w = 640;
+ dh = h = 480;
+ }
+
+ const QStringList args = displaySpec.split(QLatin1Char(':'),
+ QString::SkipEmptyParts);
+
+ if (args.contains(QLatin1String("paintonscreen"), Qt::CaseInsensitive))
+ d_ptr->doOnScreenSurface = true;
+
+ QRegExp depthRegexp(QLatin1String("^depth=(\\d+)$"));
+ if (args.indexOf(depthRegexp) != -1)
+ d = depthRegexp.cap(1).toInt();
+
+ QRegExp sizeRegexp(QLatin1String("^size=(\\d+)x(\\d+)$"));
+ if (args.indexOf(sizeRegexp) != -1) {
+ dw = w = sizeRegexp.cap(1).toInt();
+ dh = h = sizeRegexp.cap(2).toInt();
+ }
+
+ // Handle display physical size spec.
+ QRegExp mmWidthRegexp(QLatin1String("^mmWidth=?(\\d+)$"));
+ if (args.indexOf(mmWidthRegexp) != -1) {
+ const int mmWidth = mmWidthRegexp.cap(1).toInt();
+ if (mmWidth > 0)
+ d_ptr->dpiX = dw * 25.4 / mmWidth;
+ }
+ QRegExp mmHeightRegexp(QLatin1String("^mmHeight=?(\\d+)$"));
+ if (args.indexOf(mmHeightRegexp) != -1) {
+ const int mmHeight = mmHeightRegexp.cap(1).toInt();
+ if (mmHeight > 0)
+ d_ptr->dpiY = dh * 25.4 / mmHeight;
+ }
+ QRegExp dpiRegexp(QLatin1String("^dpi=(\\d+)(?:,(\\d+))?$"));
+ if (args.indexOf(dpiRegexp) != -1) {
+ const qreal dpiX = dpiRegexp.cap(1).toFloat();
+ const qreal dpiY = dpiRegexp.cap(2).toFloat();
+ if (dpiX > 0)
+ d_ptr->dpiX = dpiX;
+ d_ptr->dpiY = (dpiY > 0 ? dpiY : dpiX);
+ }
+
+ if (args.contains(QLatin1String("noDisablePainting")))
+ d_ptr->noDisablePainting = true;
+
+ QWSServer::setDefaultMouse("None");
+ QWSServer::setDefaultKeyboard("None");
+
+ d_ptr->configure();
+ }
+
+ // XXX
+ qt_screen = this;
+
+ return true;
+}
+
+/*!
+ \reimp
+*/
+void QVNCScreen::disconnect()
+{
+ QProxyScreen::disconnect();
+#if !defined(QT_NO_QWS_MULTIPROCESS) && !defined(QT_NO_SHAREDMEMORY)
+ d_ptr->shm.detach();
+#endif
+}
+
+/*!
+ \reimp
+*/
+bool QVNCScreen::initDevice()
+{
+ if (!QProxyScreen::screen() && d == 4) {
+ screencols = 16;
+ int val = 0;
+ for (int idx = 0; idx < 16; idx++, val += 17) {
+ screenclut[idx] = qRgb(val, val, val);
+ }
+ }
+ d_ptr->vncServer = new QVNCServer(this, displayId);
+ d_ptr->vncServer->setRefreshRate(d_ptr->refreshRate);
+
+ switch (depth()) {
+#ifdef QT_QWS_DEPTH_32
+ case 32:
+ d_ptr->dirty = new QVNCDirtyMapOptimized<quint32>(this);
+ break;
+#endif
+#ifdef QT_QWS_DEPTH_24
+ case 24:
+ d_ptr->dirty = new QVNCDirtyMapOptimized<qrgb888>(this);
+ break;
+#endif
+#ifdef QT_QWS_DEPTH_18
+ case 18:
+ d_ptr->dirty = new QVNCDirtyMapOptimized<qrgb666>(this);
+ break;
+#endif
+#ifdef QT_QWS_DEPTH_16
+ case 16:
+ d_ptr->dirty = new QVNCDirtyMapOptimized<quint16>(this);
+ break;
+#endif
+#ifdef QT_QWS_DEPTH_15
+ case 15:
+ d_ptr->dirty = new QVNCDirtyMapOptimized<qrgb555>(this);
+ break;
+#endif
+#ifdef QT_QWS_DEPTH_12
+ case 12:
+ d_ptr->dirty = new QVNCDirtyMapOptimized<qrgb444>(this);
+ break;
+#endif
+#ifdef QT_QWS_DEPTH_8
+ case 8:
+ d_ptr->dirty = new QVNCDirtyMapOptimized<quint8>(this);
+ break;
+#endif
+ default:
+ qWarning("QVNCScreen::initDevice: No support for screen depth %d",
+ depth());
+ d_ptr->dirty = 0;
+ return false;
+ }
+
+
+ const bool ok = QProxyScreen::initDevice();
+#ifndef QT_NO_QWS_CURSOR
+ qt_screencursor = new QVNCCursor(this);
+#endif
+ if (QProxyScreen::screen())
+ return ok;
+
+ // Disable painting if there is only 1 display and nothing is attached to the VNC server
+ if (!d_ptr->noDisablePainting)
+ QWSServer::instance()->enablePainting(false);
+
+ return true;
+}
+
+/*!
+ \reimp
+*/
+void QVNCScreen::shutdownDevice()
+{
+ QProxyScreen::shutdownDevice();
+ delete d_ptr->vncServer;
+ delete d_ptr->dirty;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QWS_VNC
diff --git a/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.h b/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.h
new file mode 100644
index 0000000000..646109f5ef
--- /dev/null
+++ b/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCREENVNC_QWS_H
+#define QSCREENVNC_QWS_H
+
+#include <QtGui/qscreenproxy_qws.h>
+
+#ifndef QT_NO_QWS_VNC
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QVNCScreenPrivate;
+
+class QVNCScreen : public QProxyScreen
+{
+public:
+ explicit QVNCScreen(int display_id);
+ virtual ~QVNCScreen();
+
+ bool initDevice();
+ bool connect(const QString &displaySpec);
+ void disconnect();
+ void shutdownDevice();
+
+ void setDirty(const QRect&);
+
+private:
+ friend class QVNCCursor;
+ friend class QVNCClientCursor;
+ friend class QVNCServer;
+ friend class QVNCScreenPrivate;
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ bool swapBytes() const;
+#endif
+
+ QVNCScreenPrivate *d_ptr;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_QWS_VNC
+#endif // QSCREENVNC_QWS_H
diff --git a/src/plugins/gfxdrivers/vnc/vnc.pro b/src/plugins/gfxdrivers/vnc/vnc.pro
new file mode 100644
index 0000000000..31da2f404e
--- /dev/null
+++ b/src/plugins/gfxdrivers/vnc/vnc.pro
@@ -0,0 +1,16 @@
+TARGET = qgfxvnc
+include(../../qpluginbase.pri)
+
+DEFINES += QT_QWS_VNC
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers
+
+HEADERS = \
+ qscreenvnc_qws.h \
+ qscreenvnc_p.h
+
+SOURCES = main.cpp \
+ qscreenvnc_qws.cpp
+
+target.path += $$[QT_INSTALL_PLUGINS]/gfxdrivers
+INSTALLS += target