diff options
author | Jørgen Lind <jorgen.lind@nokia.com> | 2010-03-31 07:41:39 (GMT) |
---|---|---|
committer | Jørgen Lind <jorgen.lind@nokia.com> | 2010-03-31 09:32:07 (GMT) |
commit | a93f6b21f636df4840f86099c76d287afb978001 (patch) | |
tree | dc85d58ebc1ac7ee9d653157f42242cbc379a636 /src/plugins/platforms | |
parent | a31270b5fc88460d6923ac1f2b5b6e90da59c9c8 (diff) | |
download | Qt-a93f6b21f636df4840f86099c76d287afb978001.zip Qt-a93f6b21f636df4840f86099c76d287afb978001.tar.gz Qt-a93f6b21f636df4840f86099c76d287afb978001.tar.bz2 |
Refactoring GraphicsSystem to QPlatformIntegration
QPlatformIntegration is the "main" integration class which needs to be
subclassed.
This is done so that we don't pollute GraphicsSystem with functionality
that really does not belong there.
In lighthouse applications needs now to be started with
-platform some_platform
Diffstat (limited to 'src/plugins/platforms')
67 files changed, 11175 insertions, 0 deletions
diff --git a/src/plugins/platforms/fb_base/fb_base.cpp b/src/plugins/platforms/fb_base/fb_base.cpp new file mode 100644 index 0000000..d30746a --- /dev/null +++ b/src/plugins/platforms/fb_base/fb_base.cpp @@ -0,0 +1,364 @@ +#include "fb_base.h" + +#include <qpainter.h> +#include <qdebug.h> +#include <qbitmap.h> +#include <QGraphicsSystemCursor> +#include <QWindowSystemInterface> + +QGraphicsSystemSoftwareCursor::QGraphicsSystemSoftwareCursor(QGraphicsSystemScreen *scr) + : QGraphicsSystemCursor(scr), currentRect(QRect()), prevRect(QRect()) +{ + graphic = new QGraphicsSystemCursorImage(0, 0, 0, 0, 0, 0); + setCursor(Qt::ArrowCursor); +} + +QRect QGraphicsSystemSoftwareCursor::getCurrentRect() +{ + QRect rect = graphic->image()->rect().translated(-graphic->hotspot().x(), + -graphic->hotspot().y()); + rect.translate(QCursor::pos()); + return rect; +} + + +void QGraphicsSystemSoftwareCursor::pointerEvent(const QMouseEvent & e) +{ + Q_UNUSED(e); + currentRect = getCurrentRect(); + screen->setDirty(currentRect); +} + +QRect QGraphicsSystemSoftwareCursor::drawCursor(QPainter & painter) +{ + if (currentRect.isNull()) + return QRect(); + + prevRect = currentRect; + painter.drawImage(prevRect, *graphic->image()); + return prevRect; +} + +QRect QGraphicsSystemSoftwareCursor::dirtyRect() +{ + if (!prevRect.isNull()) { + QRect rect = prevRect; + prevRect = QRect(); + return rect; + } + return QRect(); +} + +void QGraphicsSystemSoftwareCursor::setCursor(Qt::CursorShape shape) +{ + graphic->set(shape); +} + +void QGraphicsSystemSoftwareCursor::setCursor(const QImage * image, int hotx, int hoty) +{ + graphic->set(image, hotx, hoty); +} + +void QGraphicsSystemSoftwareCursor::setCursor(const uchar *data, const uchar *mask, int width, int height, int hotX, int hotY) +{ + graphic->set(data, mask, width, height, hotX, hotY); +} + +void QGraphicsSystemSoftwareCursor::changeCursor(QCursor * widgetCursor, QWidget * widget) +{ + Q_UNUSED(widget); + Qt::CursorShape shape = widgetCursor->shape(); + + if (shape == Qt::BitmapCursor) { + // application supplied cursor + QPoint spot = widgetCursor->hotSpot(); + setCursor(&widgetCursor->pixmap().toImage(), spot.x(), spot.y()); + } else { + // system cursor + setCursor(shape); + } + currentRect = getCurrentRect(); + screen->setDirty(currentRect); +} + +QGraphicsSystemFbScreen::QGraphicsSystemFbScreen() : cursor(0), mGeometry(), mDepth(16), mFormat(QImage::Format_RGB16), mScreenImage(0), compositePainter(0), isUpToDate(false) +{ + mScreenImage = new QImage(mGeometry.size(), mFormat); + redrawTimer.setSingleShot(true); + redrawTimer.setInterval(0); + QObject::connect(&redrawTimer, SIGNAL(timeout()), this, SLOT(doRedraw())); +} + +void QGraphicsSystemFbScreen::setGeometry(QRect rect) +{ + delete mScreenImage; + mGeometry = rect; + mScreenImage = new QImage(mGeometry.size(), mFormat); + delete compositePainter; + compositePainter = 0; + invalidateRectCache(); +} + +void QGraphicsSystemFbScreen::setDepth(int depth) +{ + mDepth = depth; +} + +void QGraphicsSystemFbScreen::setPhysicalSize(QSize size) +{ + mPhysicalSize = size; +} + +void QGraphicsSystemFbScreen::setFormat(QImage::Format format) +{ + mFormat = format; + delete mScreenImage; + mScreenImage = new QImage(mGeometry.size(), mFormat); + delete compositePainter; + compositePainter = 0; +} + +QGraphicsSystemFbScreen::~QGraphicsSystemFbScreen() +{ + delete compositePainter; + delete mScreenImage; +} + +void QGraphicsSystemFbScreen::setDirty(const QRect &rect) +{ + repaintRegion += rect; + if (!redrawTimer.isActive()) { + redrawTimer.start(); + } +} + +void QGraphicsSystemFbScreen::generateRects() +{ + cachedRects.clear(); + QRegion remainingScreen(mGeometry); + + for (int i = 0; i < windowStack.length(); i++) { + if (remainingScreen.isEmpty()) + break; + if (!windowStack[i]->window()->testAttribute(Qt::WA_TranslucentBackground)) { + remainingScreen -= windowStack[i]->geometry(); + QRegion windowRegion(windowStack[i]->geometry()); + windowRegion -= remainingScreen; + foreach(QRect rect, windowRegion.rects()) { + cachedRects += QPair<QRect, int>(rect, i); + } + } + } + foreach (QRect rect, remainingScreen.rects()) + cachedRects += QPair<QRect, int>(rect, -1); + isUpToDate = true; + return; +} + + + +QRegion QGraphicsSystemFbScreen::doRedraw() +{ + QRegion touchedRegion; + if (cursor) + repaintRegion += cursor->dirtyRect(); + if (repaintRegion.isEmpty()) + return touchedRegion; + + QVector<QRect> rects = repaintRegion.rects(); + + if (!isUpToDate) + generateRects(); + + if (!compositePainter) + compositePainter = new QPainter(mScreenImage); + for (int rectIndex = 0; rectIndex < repaintRegion.numRects(); rectIndex++) { + QRegion rectRegion = rects[rectIndex]; + + for(int i = 0; i < cachedRects.length(); i++) { + QRect screenSubRect = cachedRects[i].first; + int layer = cachedRects[i].second; + QRegion intersect = rectRegion.intersected(screenSubRect); + + if (intersect.isEmpty()) + continue; + + rectRegion -= intersect; + + // we only expect one rectangle, but defensive coding... + foreach (QRect rect, intersect.rects()) { + bool firstLayer = true; + if (layer == -1) { + compositePainter->fillRect(rect, Qt::black); + firstLayer = false; + layer = windowStack.size() - 1; + } + + for (int layerIndex = layer; layerIndex != -1; layerIndex--) { + if (!windowStack[layerIndex]->visible()) + continue; + if (windowStack[layerIndex]->window()->isMinimized()) + continue; + QRect windowRect = windowStack[layerIndex]->geometry(); + QRect windowIntersect = rect.translated(-windowRect.left(), + -windowRect.top()); + compositePainter->drawImage(rect, windowStack[layerIndex]->image(), + windowIntersect); + if (firstLayer) { + firstLayer = false; + } + } + } + } + if (!rectRegion.isEmpty()) + qWarning() << "non-empty region!" << rectRegion; + // Everything on screen should be mapped to a sub-rectangle + // unless it's off the screen... + } + + QRect cursorRect; + if (cursor) { + cursorRect = cursor->drawCursor(*compositePainter); + touchedRegion += cursorRect; + } + touchedRegion += repaintRegion; + repaintRegion = QRegion(); + + return touchedRegion; +} + +void QGraphicsSystemFbScreen::removeWindowSurface(QGraphicsSystemFbWindowSurface * surface) +{ + windowStack.removeOne(surface); + invalidateRectCache(); + setDirty(surface->geometry()); +} + +void QGraphicsSystemFbWindowSurface::raise() +{ + mScreen->raise(this); +} + +void QGraphicsSystemFbScreen::raise(QWindowSurface * surface) +{ + QGraphicsSystemFbWindowSurface *s = static_cast<QGraphicsSystemFbWindowSurface *>(surface); + int index = windowStack.indexOf(s); + if (index <= 0) + return; + windowStack.move(index, 0); + invalidateRectCache(); + setDirty(s->geometry()); +} + +void QGraphicsSystemFbWindowSurface::lower() +{ + mScreen->lower(this); +} + +void QGraphicsSystemFbScreen::lower(QWindowSurface * surface) +{ + QGraphicsSystemFbWindowSurface *s = static_cast<QGraphicsSystemFbWindowSurface *>(surface); + int index = windowStack.indexOf(s); + if (index == -1 || index == (windowStack.size() - 1)) + return; + windowStack.move(index, windowStack.size() - 1); + invalidateRectCache(); + setDirty(s->geometry()); +} + +QWidget * QGraphicsSystemFbScreen::topLevelAt(const QPoint & p) const +{ + for(int i = 0; i < windowStack.size(); i++) { + if (windowStack[i]->geometry().contains(p, false) && + windowStack[i]->visible() && + !windowStack[i]->window()->isMinimized()) { + return windowStack[i]->window(); + } + } + return 0; +} + +QGraphicsSystemFbWindowSurface::QGraphicsSystemFbWindowSurface(QGraphicsSystemFbScreen *screen, QWidget *window) + : QWindowSurface(window), + mScreen(screen), + visibleFlag(false) +{ + static QAtomicInt winIdGenerator(1); + + mImage = QImage(window->size(), mScreen->format()); + windowId = winIdGenerator.fetchAndAddRelaxed(1); +} + +QGraphicsSystemFbWindowSurface::~QGraphicsSystemFbWindowSurface() +{ + mScreen->removeWindowSurface(this); +} + +void QGraphicsSystemFbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(widget); + Q_UNUSED(offset); + + QRect currentGeometry = geometry(); + // If this is a move, redraw the previous location + if (oldGeometry != currentGeometry) { + mScreen->setDirty(oldGeometry); + oldGeometry = currentGeometry; + } + + QRect dirtyClient = region.boundingRect(); + QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(), + currentGeometry.top() + dirtyClient.top(), + dirtyClient.width(), + dirtyClient.height()); + mScreen->setDirty(dirtyRegion); +} + +void QGraphicsSystemFbWindowSurface::setGeometry(const QRect &rect) +{ + // store previous geometry for screen update + oldGeometry = geometry(); + + // change the widget's QImage if this is a resize + if (mImage.size() != rect.size()) + mImage = QImage(rect.size(), mScreen->format()); + + mScreen->invalidateRectCache(); + QWindowSystemInterface::handleGeometryChange(window(), rect); + + QWindowSurface::setGeometry(rect); +} + +bool QGraphicsSystemFbWindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + return QWindowSurface::scroll(area, dx, dy); +} + +void QGraphicsSystemFbWindowSurface::beginPaint(const QRegion ®ion) +{ + Q_UNUSED(region); +} + +void QGraphicsSystemFbWindowSurface::endPaint(const QRegion ®ion) +{ + Q_UNUSED(region); +} + +void QGraphicsSystemFbWindowSurface::setVisible(bool visible) +{ + visibleFlag = visible; + mScreen->invalidateRectCache(); + mScreen->setDirty(geometry()); +} + +Qt::WindowFlags QGraphicsSystemFbWindowSurface::setWindowFlags(Qt::WindowFlags type) +{ + flags = type; + mScreen->invalidateRectCache(); + return flags; +} + +Qt::WindowFlags QGraphicsSystemFbWindowSurface::windowFlags() const +{ + return flags; +} diff --git a/src/plugins/platforms/fb_base/fb_base.h b/src/plugins/platforms/fb_base/fb_base.h new file mode 100644 index 0000000..7f9b005 --- /dev/null +++ b/src/plugins/platforms/fb_base/fb_base.h @@ -0,0 +1,132 @@ +#ifndef QLIGHTHOUSEGRAPHICSSCREEN_H +#define QLIGHTHOUSEGRAPHICSSCREEN_H + +#include <QtGui/private/qgraphicssystem_p.h> +#include <qrect.h> +#include <qimage.h> +#include <qtimer.h> +#include <qpainter.h> +#include <QGraphicsSystemCursor> + +class QMouseEvent; +class QSize; +class QPainter; + +class QGraphicsSystemFbScreen; + +class QGraphicsSystemSoftwareCursor : public QGraphicsSystemCursor +{ +public: + QGraphicsSystemSoftwareCursor(QGraphicsSystemScreen * scr); + + // output methods + QRect dirtyRect(); + virtual QRect drawCursor(QPainter & painter); + + // input methods + virtual void pointerEvent(const QMouseEvent & event); + virtual void changeCursor(QCursor * widgetCursor, QWidget * widget); + +protected: + QGraphicsSystemCursorImage * graphic; + +private: + void setCursor(const uchar *data, const uchar *mask, int width, int height, int hotX, int hotY); + void setCursor(Qt::CursorShape shape); + void setCursor(const QImage * image, int hotx, int hoty); + QRect currentRect; // next place to draw the cursor + QRect prevRect; // last place the cursor was drawn + QRect getCurrentRect(); +}; + +class QGraphicsSystemFbWindowSurface : public QWindowSurface +{ +public: + QGraphicsSystemFbWindowSurface(QGraphicsSystemFbScreen *screen, QWidget *window); + ~QGraphicsSystemFbWindowSurface(); + + virtual QPaintDevice *paintDevice() { return &mImage; } + virtual void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + virtual bool scroll(const QRegion &area, int dx, int dy); + + virtual void beginPaint(const QRegion ®ion); + virtual void endPaint(const QRegion ®ion); + virtual void setVisible(bool visible); + virtual bool visible() { return visibleFlag; } + + const QImage image() { return mImage; } + void setGeometry(const QRect &rect); + + virtual void raise(); + virtual void lower(); + + virtual Qt::WindowFlags setWindowFlags(Qt::WindowFlags type); + virtual Qt::WindowFlags windowFlags() const; + + WId winId() const { return windowId; } +protected: + QGraphicsSystemFbScreen *mScreen; + QRect oldGeometry; + QImage mImage; + bool visibleFlag; + Qt::WindowFlags flags; + + WId windowId; +}; + +class QGraphicsSystemFbScreen : public QGraphicsSystemScreen +{ + Q_OBJECT +public: + QGraphicsSystemFbScreen(); + ~QGraphicsSystemFbScreen(); + + virtual QRect geometry() const { return mGeometry; } + virtual int depth() const { return mDepth; } + virtual QImage::Format format() const { return mFormat; } + virtual QSize physicalSize() const { return mPhysicalSize; } + + virtual void setGeometry(QRect rect); + virtual void setDepth(int depth); + virtual void setFormat(QImage::Format format); + virtual void setPhysicalSize(QSize size); + + virtual void setDirty(const QRect &rect); + + virtual void removeWindowSurface(QGraphicsSystemFbWindowSurface * surface); + virtual void addWindowSurface(QGraphicsSystemFbWindowSurface * surface) { + windowStack.prepend(surface); invalidateRectCache(); } + virtual void raise(QWindowSurface * surface); + virtual void lower(QWindowSurface * surface); + virtual QWidget * topLevelAt(const QPoint & p) const; + + QImage * image() const { return mScreenImage; } + QPaintDevice * paintDevice() const { return mScreenImage; } + +protected: + QList<QGraphicsSystemFbWindowSurface *> windowStack; + QRegion repaintRegion; + QGraphicsSystemSoftwareCursor * cursor; + QTimer redrawTimer; + +protected slots: + virtual QRegion doRedraw(); + +protected: + QRect mGeometry; + int mDepth; + QImage::Format mFormat; + QSize mPhysicalSize; + QImage *mScreenImage; + +private: + QPainter * compositePainter; + void generateRects(); + QList<QPair<QRect, int> > cachedRects; + + void invalidateRectCache() { isUpToDate = false; } + friend class QGraphicsSystemFbWindowSurface; + bool isUpToDate; +}; + +#endif // QLIGHTHOUSEGRAPHICSSCREEN_H diff --git a/src/plugins/platforms/fb_base/fb_base.pri b/src/plugins/platforms/fb_base/fb_base.pri new file mode 100644 index 0000000..41bd87f --- /dev/null +++ b/src/plugins/platforms/fb_base/fb_base.pri @@ -0,0 +1,2 @@ +SOURCES += ../fb_base/fb_base.cpp +HEADERS += ../fb_base/fb_base.h diff --git a/src/plugins/platforms/fb_base/fb_base.pro b/src/plugins/platforms/fb_base/fb_base.pro new file mode 100644 index 0000000..e08c0c5 --- /dev/null +++ b/src/plugins/platforms/fb_base/fb_base.pro @@ -0,0 +1,23 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2009-11-05T13:22:31 +# +#------------------------------------------------- + +#QT -= core gui +TARGET = fb_base +#include(../../qpluginbase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems + +TEMPLATE = lib + +#DEFINES += STATIC_LIBRARY +CONFIG += staticlib + +SOURCES += fb_base.cpp + +HEADERS += fb_base.h + +target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems +INSTALLS += target diff --git a/src/plugins/platforms/linuxfb/linuxfb.pro b/src/plugins/platforms/linuxfb/linuxfb.pro new file mode 100644 index 0000000..031b843 --- /dev/null +++ b/src/plugins/platforms/linuxfb/linuxfb.pro @@ -0,0 +1,12 @@ +TARGET = qlinuxfbgraphicssystem +include(../../qpluginbase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems + +SOURCES = main.cpp qgraphicssystem_linuxfb.cpp +HEADERS = qgraphicssystem_linuxfb.h + +include(../fb_base/fb_base.pri) + +target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems +INSTALLS += target diff --git a/src/plugins/platforms/linuxfb/main.cpp b/src/plugins/platforms/linuxfb/main.cpp new file mode 100644 index 0000000..4d03fe5 --- /dev/null +++ b/src/plugins/platforms/linuxfb/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 <private/qgraphicssystemplugin_p.h> +#include "qgraphicssystem_linuxfb.h" + +QT_BEGIN_NAMESPACE + +class QLinuxFbGraphicsSystemPlugin : public QGraphicsSystemPlugin +{ +public: + QStringList keys() const; + QGraphicsSystem *create(const QString&); +}; + +QStringList QLinuxFbGraphicsSystemPlugin::keys() const +{ + QStringList list; + list << "LinuxFb"; + return list; +} + +QGraphicsSystem* QLinuxFbGraphicsSystemPlugin::create(const QString& system) +{ + if (system.toLower() == "linuxfb") + return new QLinuxFbGraphicsSystem; + + return 0; +} + +Q_EXPORT_PLUGIN2(linuxfb, QLinuxFbGraphicsSystemPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/linuxfb/qgraphicssystem_linuxfb.cpp b/src/plugins/platforms/linuxfb/qgraphicssystem_linuxfb.cpp new file mode 100644 index 0000000..44960bb --- /dev/null +++ b/src/plugins/platforms/linuxfb/qgraphicssystem_linuxfb.cpp @@ -0,0 +1,856 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 "qgraphicssystem_linuxfb.h" +#include "../fb_base/fb_base.h" +#include <QtGui/private/qpixmap_raster_p.h> +#include <private/qcore_unix_p.h> // overrides QT_OPEN +#include <qimage.h> +#include <qdebug.h> + +#include <unistd.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/kd.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <limits.h> +#include <signal.h> + +#if !defined(Q_OS_DARWIN) && !defined(Q_OS_FREEBSD) +#include <linux/fb.h> + +#ifdef __i386__ +#include <asm/mtrr.h> +#endif +#endif + +QT_BEGIN_NAMESPACE + +class QLinuxFbGraphicsSystemPrivate +{ +public: + QLinuxFbGraphicsSystemPrivate(); + ~QLinuxFbGraphicsSystemPrivate(); + + void openTty(); + void closeTty(); + + int fd; + int startupw; + int startuph; + int startupd; + bool blank; + + bool doGraphicsMode; +#ifdef QT_QWS_DEPTH_GENERIC + bool doGenericColors; +#endif + int ttyfd; + long oldKdMode; + QString ttyDevice; + QString displaySpec; +}; + +QLinuxFbGraphicsSystemPrivate::QLinuxFbGraphicsSystemPrivate() + : fd(-1), blank(true), doGraphicsMode(true), +#ifdef QT_QWS_DEPTH_GENERIC + doGenericColors(false), +#endif + ttyfd(-1), oldKdMode(KD_TEXT) +{ +} + +QLinuxFbGraphicsSystemPrivate::~QLinuxFbGraphicsSystemPrivate() +{ + closeTty(); +} + +void QLinuxFbGraphicsSystemPrivate::openTty() +{ + const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0}; + + if (ttyDevice.isEmpty()) { + for (const char * const *dev = devs; *dev; ++dev) { + ttyfd = QT_OPEN(*dev, O_RDWR); + if (ttyfd != -1) + break; + } + } else { + ttyfd = QT_OPEN(ttyDevice.toAscii().constData(), O_RDWR); + } + + if (ttyfd == -1) + return; + + 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"; + QT_WRITE(ttyfd, termctl, sizeof(termctl)); +} + +void QLinuxFbGraphicsSystemPrivate::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"; + QT_WRITE(ttyfd, termctl, sizeof(termctl)); + + QT_CLOSE(ttyfd); + ttyfd = -1; +} + +QLinuxFbGraphicsSystem::QLinuxFbGraphicsSystem() +{ + d_ptr = new QLinuxFbGraphicsSystemPrivate(); + + // XXX + QString displaySpec = QString::fromLatin1(qgetenv("QWS_DISPLAY")); + + if (!connect(displaySpec)) + qFatal("QLinuxFbGraphicsSystem: could not initialize screen"); + initDevice(); + + // Create a QImage directly on the screen's framebuffer. + // This is the blit target for copying windows to the screen. + mPrimaryScreen = new QLinuxFbGraphicsSystemScreen(data, w, h, lstep, + screenFormat); + mPrimaryScreen->setPhysicalSize(QSize(physWidth, physHeight)); + + mScreens.append(mPrimaryScreen); +} + +QLinuxFbGraphicsSystem::~QLinuxFbGraphicsSystem() +{ + delete mPrimaryScreen; + delete d_ptr; +} + +bool QLinuxFbGraphicsSystem::connect(const QString &displaySpec) +{ + const QStringList args = displaySpec.split(QLatin1Char(':')); + + if (args.contains(QLatin1String("nographicsmodeswitch"))) + d_ptr->doGraphicsMode = false; + +#ifdef QT_QWS_DEPTH_GENERIC + if (args.contains(QLatin1String("genericcolors"))) + d_ptr->doGenericColors = true; +#endif + + QRegExp ttyRegExp(QLatin1String("tty=(.*)")); + if (args.indexOf(ttyRegExp) != -1) + d_ptr->ttyDevice = ttyRegExp.cap(1); + +#if 0 +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +#ifndef QT_QWS_FRAMEBUFFER_LITTLE_ENDIAN + if (args.contains(QLatin1String("littleendian"))) +#endif + QScreen::setFrameBufferLittleEndian(true); +#endif +#endif + + // Check for explicitly specified device + const int len = 8; // "/dev/fbx" + int m = displaySpec.indexOf(QLatin1String("/dev/fb")); + + QString dev; + if (m > 0) + dev = displaySpec.mid(m, len); + else + dev = QLatin1String("/dev/fb0"); + + if (access(dev.toLatin1().constData(), R_OK|W_OK) == 0) + d_ptr->fd = QT_OPEN(dev.toLatin1().constData(), O_RDWR); + if (d_ptr->fd == -1) { + if (access(dev.toLatin1().constData(), R_OK) == 0) + d_ptr->fd = QT_OPEN(dev.toLatin1().constData(), O_RDONLY); + if (d_ptr->fd == 1) { + qWarning("Error opening framebuffer device %s", qPrintable(dev)); + return false; + } + } + + fb_fix_screeninfo finfo; + fb_var_screeninfo vinfo; + //####################### + // Shut up Valgrind + memset(&vinfo, 0, sizeof(vinfo)); + memset(&finfo, 0, sizeof(finfo)); + //####################### + + /* Get fixed screen information */ + if (d_ptr->fd != -1 && ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) { + perror("QLinuxFbGraphicsSystem::connect"); + qWarning("Error reading fixed information"); + return false; + } + + if (finfo.type == FB_TYPE_VGA_PLANES) { + qWarning("VGA16 video mode not supported"); + return false; + } + + /* Get variable screen information */ + if (d_ptr->fd != -1 && ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) { + perror("QLinuxFbGraphicsSystem::connect"); + qWarning("Error reading variable information"); + return false; + } + + grayscale = vinfo.grayscale; + d = vinfo.bits_per_pixel; + if (d == 24) { + d = vinfo.red.length + vinfo.green.length + vinfo.blue.length; + if (d <= 0) + d = 24; // reset if color component lengths are not reported + } else if (d == 16) { + d = vinfo.red.length + vinfo.green.length + vinfo.blue.length; + if (d <= 0) + d = 16; + } + lstep = finfo.line_length; + + int xoff = vinfo.xoffset; + int yoff = vinfo.yoffset; + const char* qwssize; + if((qwssize=::getenv("QWS_SIZE")) && sscanf(qwssize,"%dx%d",&w,&h)==2) { + if (d_ptr->fd != -1) { + if ((uint)w > vinfo.xres) w = vinfo.xres; + if ((uint)h > vinfo.yres) h = vinfo.yres; + } + dw=w; + dh=h; + int xxoff, yyoff; + if (sscanf(qwssize, "%*dx%*d+%d+%d", &xxoff, &yyoff) == 2) { + if (xxoff < 0 || xxoff + w > (int)(vinfo.xres)) + xxoff = vinfo.xres - w; + if (yyoff < 0 || yyoff + h > (int)(vinfo.yres)) + yyoff = vinfo.yres - h; + xoff += xxoff; + yoff += yyoff; + } else { + xoff += (vinfo.xres - w)/2; + yoff += (vinfo.yres - h)/2; + } + } else { + dw=w=vinfo.xres; + dh=h=vinfo.yres; + } + + if (w == 0 || h == 0) { + qWarning("QLinuxFbGraphicsSystem::connect(): Unable to find screen geometry, " + "will use 320x240."); + dw = w = 320; + dh = h = 240; + } + + setPixelFormat(vinfo); + + // 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) { + if (vinfo.width != 0 && vinfo.height != 0 + && vinfo.width != UINT_MAX && vinfo.height != UINT_MAX) { + physWidth = vinfo.width; + physHeight = vinfo.height; + } else { + const int dpi = 72; + physWidth = qRound(dw * 25.4 / dpi); + physHeight = qRound(dh * 25.4 / dpi); + } + } + + dataoffset = yoff * lstep + xoff * d / 8; + //qDebug("Using %dx%dx%d screen",w,h,d); + + /* Figure out the size of the screen in bytes */ + size = h * lstep; + + mapsize = finfo.smem_len; + + data = (unsigned char *)-1; + if (d_ptr->fd != -1) + data = (unsigned char *)mmap(0, mapsize, PROT_READ | PROT_WRITE, + MAP_SHARED, d_ptr->fd, 0); + + if ((long)data == -1) { + perror("QLinuxFbGraphicsSystem::connect"); + qWarning("Error: failed to map framebuffer device to memory."); + return false; + } else { + data += dataoffset; + } + +#if 0 + canaccel = useOffscreen(); + if(canaccel) + setupOffScreen(); +#endif + canaccel = false; + + // Now read in palette + if((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4)) { + screencols= (vinfo.bits_per_pixel==8) ? 256 : 16; + int loopc; + fb_cmap startcmap; + startcmap.start=0; + startcmap.len=screencols; + startcmap.red=(unsigned short int *) + malloc(sizeof(unsigned short int)*screencols); + startcmap.green=(unsigned short int *) + malloc(sizeof(unsigned short int)*screencols); + startcmap.blue=(unsigned short int *) + malloc(sizeof(unsigned short int)*screencols); + startcmap.transp=(unsigned short int *) + malloc(sizeof(unsigned short int)*screencols); + if (d_ptr->fd == -1 || ioctl(d_ptr->fd, FBIOGETCMAP, &startcmap)) { + perror("QLinuxFbGraphicsSystem::connect"); + qWarning("Error reading palette from framebuffer, using default palette"); + createPalette(startcmap, vinfo, finfo); + } + int bits_used = 0; + for(loopc=0;loopc<screencols;loopc++) { + screenclut[loopc]=qRgb(startcmap.red[loopc] >> 8, + startcmap.green[loopc] >> 8, + startcmap.blue[loopc] >> 8); + bits_used |= startcmap.red[loopc] + | startcmap.green[loopc] + | startcmap.blue[loopc]; + } + // WORKAROUND: Some framebuffer drivers only return 8 bit + // color values, so we need to not bit shift them.. + if ((bits_used & 0x00ff) && !(bits_used & 0xff00)) { + for(loopc=0;loopc<screencols;loopc++) { + screenclut[loopc] = qRgb(startcmap.red[loopc], + startcmap.green[loopc], + startcmap.blue[loopc]); + } + qWarning("8 bits cmap returned due to faulty FB driver, colors corrected"); + } + free(startcmap.red); + free(startcmap.green); + free(startcmap.blue); + free(startcmap.transp); + } else { + screencols=0; + } + + return true; +} + +bool QLinuxFbGraphicsSystem::initDevice() +{ + d_ptr->openTty(); + + // Grab current mode so we can reset it + fb_var_screeninfo vinfo; + fb_fix_screeninfo finfo; + //####################### + // Shut up Valgrind + memset(&vinfo, 0, sizeof(vinfo)); + memset(&finfo, 0, sizeof(finfo)); + //####################### + + if (ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) { + perror("QLinuxFbScreen::initDevice"); + qFatal("Error reading variable information in card init"); + return false; + } + +#ifdef DEBUG_VINFO + qDebug("Greyscale %d",vinfo.grayscale); + qDebug("Nonstd %d",vinfo.nonstd); + qDebug("Red %d %d %d",vinfo.red.offset,vinfo.red.length, + vinfo.red.msb_right); + qDebug("Green %d %d %d",vinfo.green.offset,vinfo.green.length, + vinfo.green.msb_right); + qDebug("Blue %d %d %d",vinfo.blue.offset,vinfo.blue.length, + vinfo.blue.msb_right); + qDebug("Transparent %d %d %d",vinfo.transp.offset,vinfo.transp.length, + vinfo.transp.msb_right); +#endif + + d_ptr->startupw=vinfo.xres; + d_ptr->startuph=vinfo.yres; + d_ptr->startupd=vinfo.bits_per_pixel; + grayscale = vinfo.grayscale; + + if (ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) { + perror("QLinuxFbScreen::initDevice"); + qCritical("Error reading fixed information in card init"); + // It's not an /error/ as such, though definitely a bad sign + // so we return true + return true; + } + +#ifdef __i386__ + // Now init mtrr + if(!::getenv("QWS_NOMTRR")) { + int mfd=QT_OPEN("/proc/mtrr",O_WRONLY,0); + // MTRR entry goes away when file is closed - i.e. + // hopefully when QWS is killed + if(mfd != -1) { + mtrr_sentry sentry; + sentry.base=(unsigned long int)finfo.smem_start; + //qDebug("Physical framebuffer address %p",(void*)finfo.smem_start); + // Size needs to be in 4k chunks, but that's not always + // what we get thanks to graphics card registers. Write combining + // these is Not Good, so we write combine what we can + // (which is not much - 4 megs on an 8 meg card, it seems) + unsigned int size=finfo.smem_len; + size=size >> 22; + size=size << 22; + sentry.size=size; + sentry.type=MTRR_TYPE_WRCOMB; + if(ioctl(mfd,MTRRIOC_ADD_ENTRY,&sentry)==-1) { + //printf("Couldn't add mtrr entry for %lx %lx, %s\n", + //sentry.base,sentry.size,strerror(errno)); + } + } + + // Should we close mfd here? + //QT_CLOSE(mfd); + } +#endif + if ((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4) || (finfo.visual==FB_VISUAL_DIRECTCOLOR)) + { + fb_cmap cmap; + createPalette(cmap, vinfo, finfo); + if (ioctl(d_ptr->fd, FBIOPUTCMAP, &cmap)) { + perror("QLinuxFbScreen::initDevice"); + qWarning("Error writing palette to framebuffer"); + } + free(cmap.red); + free(cmap.green); + free(cmap.blue); + free(cmap.transp); + } + +#if 0 + if (canaccel) { + *entryp=0; + *lowest = mapsize; + insert_entry(*entryp, *lowest, *lowest); // dummy entry to mark start + } + + shared->fifocount = 0; + shared->buffer_offset = 0xffffffff; // 0 would be a sensible offset (screen) + shared->linestep = 0; + shared->cliptop = 0xffffffff; + shared->clipleft = 0xffffffff; + shared->clipright = 0xffffffff; + shared->clipbottom = 0xffffffff; + shared->rop = 0xffffffff; +#endif + +#ifdef QT_QWS_DEPTH_GENERIC + if (pixelFormat() == QImage::Format_Invalid && screencols == 0 + && d_ptr->doGenericColors) + { + qt_set_generic_blit(this, vinfo.bits_per_pixel, + vinfo.red.length, vinfo.green.length, + vinfo.blue.length, vinfo.transp.length, + vinfo.red.offset, vinfo.green.offset, + vinfo.blue.offset, vinfo.transp.offset); + } +#endif + +#if 0 +#ifndef QT_NO_QWS_CURSOR + QScreenCursor::initSoftwareCursor(); +#endif +#endif + blank(false); + + return true; +} + +void QLinuxFbGraphicsSystem::setPixelFormat(struct fb_var_screeninfo info) +{ + const fb_bitfield rgba[4] = { info.red, info.green, + info.blue, info.transp }; + + QImage::Format format = QImage::Format_Invalid; + + switch (d) { + case 32: { + const fb_bitfield argb8888[4] = {{16, 8, 0}, {8, 8, 0}, + {0, 8, 0}, {24, 8, 0}}; + const fb_bitfield abgr8888[4] = {{0, 8, 0}, {8, 8, 0}, + {16, 8, 0}, {24, 8, 0}}; + if (memcmp(rgba, argb8888, 4 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_ARGB32; + } else if (memcmp(rgba, argb8888, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB32; + } else if (memcmp(rgba, abgr8888, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB32; + pixeltype = BGRPixel; + } + break; + } + case 24: { + const fb_bitfield rgb888[4] = {{16, 8, 0}, {8, 8, 0}, + {0, 8, 0}, {0, 0, 0}}; + const fb_bitfield bgr888[4] = {{0, 8, 0}, {8, 8, 0}, + {16, 8, 0}, {0, 0, 0}}; + if (memcmp(rgba, rgb888, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB888; + } else if (memcmp(rgba, bgr888, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB888; + pixeltype = BGRPixel; + } + break; + } + case 18: { + const fb_bitfield rgb666[4] = {{12, 6, 0}, {6, 6, 0}, + {0, 6, 0}, {0, 0, 0}}; + if (memcmp(rgba, rgb666, 3 * sizeof(fb_bitfield)) == 0) + format = QImage::Format_RGB666; + break; + } + case 16: { + const fb_bitfield rgb565[4] = {{11, 5, 0}, {5, 6, 0}, + {0, 5, 0}, {0, 0, 0}}; + const fb_bitfield bgr565[4] = {{0, 5, 0}, {5, 6, 0}, + {11, 5, 0}, {0, 0, 0}}; + if (memcmp(rgba, rgb565, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB16; + } else if (memcmp(rgba, bgr565, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB16; + pixeltype = BGRPixel; + } + break; + } + case 15: { + const fb_bitfield rgb1555[4] = {{10, 5, 0}, {5, 5, 0}, + {0, 5, 0}, {15, 1, 0}}; + const fb_bitfield bgr1555[4] = {{0, 5, 0}, {5, 5, 0}, + {10, 5, 0}, {15, 1, 0}}; + if (memcmp(rgba, rgb1555, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB555; + } else if (memcmp(rgba, bgr1555, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB555; + pixeltype = BGRPixel; + } + break; + } + case 12: { + const fb_bitfield rgb444[4] = {{8, 4, 0}, {4, 4, 0}, + {0, 4, 0}, {0, 0, 0}}; + if (memcmp(rgba, rgb444, 3 * sizeof(fb_bitfield)) == 0) + format = QImage::Format_RGB444; + break; + } + case 8: + break; + case 1: + format = QImage::Format_Mono; //###: LSB??? + break; + default: + break; + } + + screenFormat = format; +} + +void QLinuxFbGraphicsSystem::createPalette(fb_cmap &cmap, fb_var_screeninfo &vinfo, fb_fix_screeninfo &finfo) +{ + if((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4)) { + screencols= (vinfo.bits_per_pixel==8) ? 256 : 16; + cmap.start=0; + cmap.len=screencols; + cmap.red=(unsigned short int *) + malloc(sizeof(unsigned short int)*screencols); + cmap.green=(unsigned short int *) + malloc(sizeof(unsigned short int)*screencols); + cmap.blue=(unsigned short int *) + malloc(sizeof(unsigned short int)*screencols); + cmap.transp=(unsigned short int *) + malloc(sizeof(unsigned short int)*screencols); + + if (screencols==16) { + if (finfo.type == FB_TYPE_PACKED_PIXELS) { + // We'll setup a grayscale cmap for 4bpp linear + int val = 0; + for (int idx = 0; idx < 16; ++idx, val += 17) { + cmap.red[idx] = (val<<8)|val; + cmap.green[idx] = (val<<8)|val; + cmap.blue[idx] = (val<<8)|val; + screenclut[idx]=qRgb(val, val, val); + } + } else { + // Default 16 colour palette + // Green is now trolltech green so certain images look nicer + // black d_gray l_gray white red green blue cyan magenta yellow + unsigned char reds[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0xFF, 0xA2, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x82 }; + unsigned char greens[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0x00, 0xC5, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F }; + unsigned char blues[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0x00, 0x11, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0x7F, 0x7F, 0x00, 0x00 }; + + for (int idx = 0; idx < 16; ++idx) { + cmap.red[idx] = ((reds[idx]) << 8)|reds[idx]; + cmap.green[idx] = ((greens[idx]) << 8)|greens[idx]; + cmap.blue[idx] = ((blues[idx]) << 8)|blues[idx]; + cmap.transp[idx] = 0; + screenclut[idx]=qRgb(reds[idx], greens[idx], blues[idx]); + } + } + } else { + if (grayscale) { + // Build grayscale palette + int i; + for(i=0;i<screencols;++i) { + int bval = screencols == 256 ? i : (i << 4); + ushort val = (bval << 8) | bval; + cmap.red[i] = val; + cmap.green[i] = val; + cmap.blue[i] = val; + cmap.transp[i] = 0; + screenclut[i] = qRgb(bval,bval,bval); + } + } else { + // 6x6x6 216 color cube + int idx = 0; + for(int ir = 0x0; ir <= 0xff; ir+=0x33) { + for(int ig = 0x0; ig <= 0xff; ig+=0x33) { + for(int ib = 0x0; ib <= 0xff; ib+=0x33) { + cmap.red[idx] = (ir << 8)|ir; + cmap.green[idx] = (ig << 8)|ig; + cmap.blue[idx] = (ib << 8)|ib; + cmap.transp[idx] = 0; + screenclut[idx]=qRgb(ir, ig, ib); + ++idx; + } + } + } + // Fill in rest with 0 + for (int loopc=0; loopc<40; ++loopc) { + screenclut[idx]=0; + ++idx; + } + screencols=idx; + } + } + } else if(finfo.visual==FB_VISUAL_DIRECTCOLOR) { + cmap.start=0; + int rbits=0,gbits=0,bbits=0; + switch (vinfo.bits_per_pixel) { + case 8: + rbits=vinfo.red.length; + gbits=vinfo.green.length; + bbits=vinfo.blue.length; + if(rbits==0 && gbits==0 && bbits==0) { + // cyber2000 driver bug hack + rbits=3; + gbits=3; + bbits=2; + } + break; + case 15: + rbits=5; + gbits=5; + bbits=5; + break; + case 16: + rbits=5; + gbits=6; + bbits=5; + break; + case 18: + case 19: + rbits=6; + gbits=6; + bbits=6; + break; + case 24: case 32: + rbits=gbits=bbits=8; + break; + } + screencols=cmap.len=1<<qMax(rbits,qMax(gbits,bbits)); + cmap.red=(unsigned short int *) + malloc(sizeof(unsigned short int)*256); + cmap.green=(unsigned short int *) + malloc(sizeof(unsigned short int)*256); + cmap.blue=(unsigned short int *) + malloc(sizeof(unsigned short int)*256); + cmap.transp=(unsigned short int *) + malloc(sizeof(unsigned short int)*256); + for(unsigned int i = 0x0; i < cmap.len; i++) { + cmap.red[i] = i*65535/((1<<rbits)-1); + cmap.green[i] = i*65535/((1<<gbits)-1); + cmap.blue[i] = i*65535/((1<<bbits)-1); + cmap.transp[i] = 0; + } + } +} + +void QLinuxFbGraphicsSystem::blank(bool on) +{ + if (d_ptr->blank == on) + return; + +#if defined(QT_QWS_IPAQ) + if (on) + system("apm -suspend"); +#else + if (d_ptr->fd == -1) + return; +// Some old kernel versions don't have this. These defines should go +// away eventually +#if defined(FBIOBLANK) +#if defined(VESA_POWERDOWN) && defined(VESA_NO_BLANKING) + ioctl(d_ptr->fd, FBIOBLANK, on ? VESA_POWERDOWN : VESA_NO_BLANKING); +#else + ioctl(d_ptr->fd, FBIOBLANK, on ? 1 : 0); +#endif +#endif +#endif + + d_ptr->blank = on; +} + +QPixmapData *QLinuxFbGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +{ + return new QRasterPixmapData(type); +} + +QWindowSurface *QLinuxFbGraphicsSystem::createWindowSurface(QWidget *widget) const +{ + if (widget->windowType() == Qt::Desktop) + return 0; // Don't create an explicit window surface for the destkop. + QGraphicsSystemFbWindowSurface * surface = + new QGraphicsSystemFbWindowSurface(mPrimaryScreen, widget); + mPrimaryScreen->addWindowSurface(surface); + return surface; +} + +QLinuxFbGraphicsSystemScreen::QLinuxFbGraphicsSystemScreen(uchar * d, int w, + int h, int lstep, QImage::Format screenFormat) : compositePainter(0) +{ + data = d; + mGeometry = QRect(0,0,w,h); + bytesPerLine = lstep; + mFormat = screenFormat; + mDepth = 16; + mScreenImage = new QImage(mGeometry.width(), mGeometry.height(), + mFormat); + mFbScreenImage = new QImage(data, mGeometry.width(), mGeometry.height(), + bytesPerLine, mFormat); + cursor = new QGraphicsSystemSoftwareCursor(this); +} + +void QLinuxFbGraphicsSystemScreen::setGeometry(QRect rect) +{ + mGeometry = rect; + delete mFbScreenImage; + mFbScreenImage = new QImage(data, mGeometry.width(), mGeometry.height(), + bytesPerLine, mFormat); + delete compositePainter; + compositePainter = 0; + + delete mScreenImage; + mScreenImage = new QImage(mGeometry.width(), mGeometry.height(), + mFormat); +} + +void QLinuxFbGraphicsSystemScreen::setFormat(QImage::Format format) +{ + mFormat = format; + delete mFbScreenImage; + mFbScreenImage = new QImage(data, mGeometry.width(), mGeometry.height(), + bytesPerLine, mFormat); + delete compositePainter; + compositePainter = 0; + + delete mScreenImage; + mScreenImage = new QImage(mGeometry.width(), mGeometry.height(), + mFormat); +} + +QRegion QLinuxFbGraphicsSystemScreen::doRedraw() +{ + QRegion touched; + touched = QGraphicsSystemFbScreen::doRedraw(); + + if (!compositePainter) { + compositePainter = new QPainter(mFbScreenImage); + } + + QVector<QRect> rects = touched.rects(); + for (int i = 0; i < rects.size(); i++) + compositePainter->drawImage(rects[i], *mScreenImage, rects[i]); + return touched; +} +QT_END_NAMESPACE diff --git a/src/plugins/platforms/linuxfb/qgraphicssystem_linuxfb.h b/src/plugins/platforms/linuxfb/qgraphicssystem_linuxfb.h new file mode 100644 index 0000000..cc8ce7e --- /dev/null +++ b/src/plugins/platforms/linuxfb/qgraphicssystem_linuxfb.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 QGRAPHICSSYSTEM_LINUXFB_H +#define QGRAPHICSSYSTEM_LINUXFB_H + +#include <QtGui/private/qgraphicssystem_p.h> +#include "../fb_base/fb_base.h" + +QT_BEGIN_NAMESPACE + +class QLinuxFbGraphicsSystemScreen : public QGraphicsSystemFbScreen +{ +public: + QLinuxFbGraphicsSystemScreen(uchar * d, int w, int h, int lstep, QImage::Format screenFormat); + void setGeometry(QRect rect); + void setFormat(QImage::Format format); + +public slots: + QRegion doRedraw(); + +private: + QImage * mFbScreenImage; + uchar * data; + int bytesPerLine; + + QPainter *compositePainter; +}; + +class QLinuxFbGraphicsSystemPrivate; +struct fb_cmap; +struct fb_var_screeninfo; +struct fb_fix_screeninfo; + +class QLinuxFbGraphicsSystem : public QGraphicsSystem +{ +public: + QLinuxFbGraphicsSystem(); + ~QLinuxFbGraphicsSystem(); + + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QWindowSurface *createWindowSurface(QWidget *widget) const; + + QList<QGraphicsSystemScreen *> screens() const { return mScreens; } + +private: + QLinuxFbGraphicsSystemScreen *mPrimaryScreen; + QList<QGraphicsSystemScreen *> mScreens; + QLinuxFbGraphicsSystemPrivate *d_ptr; + + enum PixelType { NormalPixel, BGRPixel }; + + QRgb screenclut[256]; + int screencols; + + uchar * data; + + QImage::Format screenFormat; + int w; + int lstep; + int h; + int d; + PixelType pixeltype; + bool grayscale; + + int dw; + int dh; + + int size; // Screen size + int mapsize; // Total mapped memory + + int displayId; + + int physWidth; + int physHeight; + + bool canaccel; + int dataoffset; + int cacheStart; + + bool connect(const QString &displaySpec); + bool initDevice(); + void setPixelFormat(struct fb_var_screeninfo); + void createPalette(fb_cmap &cmap, fb_var_screeninfo &vinfo, fb_fix_screeninfo &finfo); + void blank(bool on); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/minimal/main.cpp b/src/plugins/platforms/minimal/main.cpp new file mode 100644 index 0000000..44c274b --- /dev/null +++ b/src/plugins/platforms/minimal/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 <QtGui/QPlatformIntegrationPlugin> +#include "qplatformintegration_minimal.h" + +QT_BEGIN_NAMESPACE + +class QMinimalIntegrationPlugin : public QPlatformIntegrationPlugin +{ +public: + QStringList keys() const; + QPlatformIntegration *create(const QString&); +}; + +QStringList QMinimalIntegrationPlugin::keys() const +{ + QStringList list; + list << "Minimal"; + return list; +} + +QPlatformIntegration *QMinimalIntegrationPlugin::create(const QString& system) +{ + if (system.toLower() == "minimal") + return new QMinimalIntegration; + + return 0; +} + +Q_EXPORT_PLUGIN2(minimal, QMinimalIntegrationPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/minimal/minimal.pro b/src/plugins/platforms/minimal/minimal.pro new file mode 100644 index 0000000..567b551 --- /dev/null +++ b/src/plugins/platforms/minimal/minimal.pro @@ -0,0 +1,13 @@ +TARGET = qminimalgraphicssystem +include(../../qpluginbase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms + +SOURCES = main.cpp \ + qplatformintegration_minimal.cpp \ + qwindowsurface_minimal.cpp +HEADERS = qplatformintegration_minimal.h \ + qwindowsurface_minimal.h + +target.path += $$[QT_INSTALL_PLUGINS]/platforms +INSTALLS += target diff --git a/src/plugins/platforms/minimal/qplatformintegration_minimal.cpp b/src/plugins/platforms/minimal/qplatformintegration_minimal.cpp new file mode 100644 index 0000000..693e0c3 --- /dev/null +++ b/src/plugins/platforms/minimal/qplatformintegration_minimal.cpp @@ -0,0 +1,25 @@ +#include "qplatformintegration_minimal.h" +#include "qwindowsurface_minimal.h" + +#include <QtGui/private/qpixmap_raster_p.h> + +QMinimalIntegration::QMinimalIntegration() +{ + QMinimalScreen *mPrimaryScreen = new QMinimalScreen(); + + mPrimaryScreen->mGeometry = QRect(0, 0, 240, 320); + mPrimaryScreen->mDepth = 16; + mPrimaryScreen->mFormat = QImage::Format_RGB16; + mPrimaryScreen->mPhysicalSize = QSize(40, 54); + + mScreens.append(mPrimaryScreen); +} + +QPixmapData *QMinimalIntegration::createPixmapData(QPixmapData::PixelType type) const +{ + return new QRasterPixmapData(type); +} +QWindowSurface *QMinimalIntegration::createWindowSurface(QWidget *widget) const +{ + return new QMinimalWindowSurface(widget); +} diff --git a/src/plugins/platforms/minimal/qplatformintegration_minimal.h b/src/plugins/platforms/minimal/qplatformintegration_minimal.h new file mode 100644 index 0000000..d4eb78b --- /dev/null +++ b/src/plugins/platforms/minimal/qplatformintegration_minimal.h @@ -0,0 +1,85 @@ + +/**************************************************************************** +** +** Copyright (C) 2009 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 QPLATFORMINTEGRATION_MINIMAL_H +#define QPLATFORMINTEGRATION_MINIMAL_H + +#include <QtGui/QPlatformIntegration> +#include <QtGui/QPlatformScreen> + +QT_BEGIN_NAMESPACE + +class QMinimalScreen : public QPlatformScreen +{ +public: + QMinimalScreen() + : mDepth(16), mFormat(QImage::Format_RGB16) {} + + QRect geometry() const { return mGeometry; } + int depth() const { return mDepth; } + QImage::Format format() const { return mFormat; } + QSize physicalSize() const { return mPhysicalSize; } + +public: + QRect mGeometry; + int mDepth; + QImage::Format mFormat; + QSize mPhysicalSize; +}; + +class QMinimalIntegration : public QPlatformIntegration +{ +public: + QMinimalIntegration(); + + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QWindowSurface *createWindowSurface(QWidget *widget) const; + + QList<QPlatformScreen *> screens() const { return mScreens; } + +private: + QList<QPlatformScreen *> mScreens; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/minimal/qwindowsurface_minimal.cpp b/src/plugins/platforms/minimal/qwindowsurface_minimal.cpp new file mode 100644 index 0000000..0b2bdd2 --- /dev/null +++ b/src/plugins/platforms/minimal/qwindowsurface_minimal.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 "qwindowsurface_minimal.h" +#include <QtCore/qdebug.h> +#include <QtGui/private/qapplication_p.h> + +QT_BEGIN_NAMESPACE + +QMinimalWindowSurface::QMinimalWindowSurface(QWidget *window) + : QWindowSurface(window) +{ + //qDebug() << "QMinimalWindowSurface::QMinimalWindowSurface:" << (long)this; +} + +QMinimalWindowSurface::~QMinimalWindowSurface() +{ +} + +QPaintDevice *QMinimalWindowSurface::paintDevice() +{ + //qDebug() << "QMinimalWindowSurface::paintDevice"; + return &mImage; +} + +void QMinimalWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(widget); + Q_UNUSED(region); + Q_UNUSED(offset); + + static int c = 0; + QString filename = QString("output%1.png").arg(c++, 4, 10, QLatin1Char('0')); + qDebug() << "QMinimalWindowSurface::flush() saving contents to" << filename.toLocal8Bit().constData(); + mImage.save(filename); +} + +void QMinimalWindowSurface::setGeometry(const QRect &rect) +{ + //qDebug() << "QMinimalWindowSurface::setGeometry:" << (long)this << rect; + QWindowSurface::setGeometry(rect); + QImage::Format format = QApplicationPrivate::platformIntegration()->screens().first()->format(); + if (mImage.size() != rect.size()) + mImage = QImage(rect.size(), format); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/minimal/qwindowsurface_minimal.h b/src/plugins/platforms/minimal/qwindowsurface_minimal.h new file mode 100644 index 0000000..959a731 --- /dev/null +++ b/src/plugins/platforms/minimal/qwindowsurface_minimal.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 QWINDOWSURFACE_MINIMAL_H +#define QWINDOWSURFACE_MINIMAL_H + +#include <QtGui/private/qwindowsurface_p.h> + +QT_BEGIN_NAMESPACE + +class QMinimalWindowSurface : public QWindowSurface +{ +public: + QMinimalWindowSurface(QWidget *window); + ~QMinimalWindowSurface(); + + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void setGeometry(const QRect &rect); + +private: + QImage mImage; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/minimaldfb/main.cpp b/src/plugins/platforms/minimaldfb/main.cpp new file mode 100644 index 0000000..fe9407c --- /dev/null +++ b/src/plugins/platforms/minimaldfb/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 <private/qgraphicssystemplugin_p.h> +#include "qgraphicssystem_minimaldfb.h" + +QT_BEGIN_NAMESPACE + +class QDirectFbGraphicsSystemPlugin : public QGraphicsSystemPlugin +{ +public: + QStringList keys() const; + QGraphicsSystem *create(const QString&); +}; + +QStringList QDirectFbGraphicsSystemPlugin::keys() const +{ + QStringList list; + list << "MinimalDfb"; + return list; +} + +QGraphicsSystem* QDirectFbGraphicsSystemPlugin::create(const QString& system) +{ + if (system.toLower() == "minimaldfb") + return new QDirectFbGraphicsSystem; + + return 0; +} + +Q_EXPORT_PLUGIN2(directfb, QDirectFbGraphicsSystemPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/minimaldfb/minimaldfb.pro b/src/plugins/platforms/minimaldfb/minimaldfb.pro new file mode 100644 index 0000000..b6c2ea8 --- /dev/null +++ b/src/plugins/platforms/minimaldfb/minimaldfb.pro @@ -0,0 +1,29 @@ +TARGET = qminimaldfb +include(../../qpluginbase.pri) +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems + +isEmpty(DIRECTFB_LIBS) { + DIRECTFB_LIBS = -ldirectfb -lfusion -ldirect -lpthread +} +isEmpty(DIRECTFB_INCLUDEPATH) { + DIRECTFB_INCLUDEPATH = /usr/include/directfb +} + +INCLUDEPATH += $$DIRECTFB_INCLUDEPATH +LIBS += $$DIRECTFB_LIBS + +SOURCES = main.cpp \ + qgraphicssystem_minimaldfb.cpp \ + qwindowsurface_minimaldfb.cpp \ + qblitter_directfb.cpp \ + qdirectfbconvenience.cpp \ + qdirectfbinput.cpp \ + qdirectfbcursor.cpp +HEADERS = qgraphicssystem_minimaldfb.h \ + qwindowsurface_minimaldfb.h \ + qblitter_directfb.h \ + qdirectfbconvenience.h \ + qdirectfbinput.h \ + qdirectfbcursor.h +target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems +INSTALLS += target diff --git a/src/plugins/platforms/minimaldfb/qblitter_directfb.cpp b/src/plugins/platforms/minimaldfb/qblitter_directfb.cpp new file mode 100644 index 0000000..070c563 --- /dev/null +++ b/src/plugins/platforms/minimaldfb/qblitter_directfb.cpp @@ -0,0 +1,110 @@ +#include "qblitter_directfb.h" +#include "qgraphicssystem_minimaldfb.h" +#include "qdirectfbconvenience.h" + +#include <QtGui/private/qpixmap_blitter_p.h> + +#include <QDebug> + +#include <directfb.h> + +QDirectFbBlitter::QDirectFbBlitter(const QSize &rect, IDirectFBSurface *surface) + : QBlittable(rect, QBlittable::Capabilities(QBlittable::SolidRectCapability + |QBlittable::SourcePixmapCapability + |QBlittable::SourceOverPixmapCapability + |QBlittable::SourceOverScaledPixmapCapability)) +{ + if (surface) { + m_surface = surface; + } else { + DFBSurfaceDescription surfaceDesc; + memset(&surfaceDesc,0,sizeof(DFBSurfaceDescription)); + surfaceDesc.width = rect.width(); + surfaceDesc.height = rect.height(); + surfaceDesc.caps = DSCAPS_PREMULTIPLIED; + surfaceDesc.pixelformat = DSPF_ARGB; + surfaceDesc.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_CAPS | DSDESC_PIXELFORMAT); + + IDirectFB *dfb = QDirectFbConvenience::dfbInterface(); + dfb->CreateSurface(dfb,&surfaceDesc, &m_surface); + m_surface->Clear(m_surface,0,0,0,0); + } +} + +QDirectFbBlitter::~QDirectFbBlitter() +{ + unlock(); + m_surface->Release(m_surface); +} + +void QDirectFbBlitter::fillRect(const QRectF &rect, const QColor &color) +{ + m_surface->SetColor(m_surface, color.red(), color.green(), color.blue(), color.alpha()); +// When the blitter api supports non opaque blits, also remember to change +// qpixmap_blitter.cpp::fill +// DFBSurfaceDrawingFlags drawingFlags = color.alpha() ? DSDRAW_BLEND : DSDRAW_NOFX; +// m_surface->SetDrawingFlags(m_surface, drawingFlags); + m_surface->SetDrawingFlags(m_surface, DSDRAW_NOFX); + m_surface->FillRectangle(m_surface, rect.x(), rect.y(), + rect.width(), rect.height()); +} + +void QDirectFbBlitter::drawPixmap(const QRectF &rect, const QPixmap &pixmap, const QRectF &srcRect) +{ + QPixmapData *data = pixmap.pixmapData(); + Q_ASSERT(data->width() && data->height()); + Q_ASSERT(data->classId() == QPixmapData::BlitterClass); + QBlittablePixmapData *blitPm = static_cast<QBlittablePixmapData*>(data); + QDirectFbBlitter *dfbBlitter = static_cast<QDirectFbBlitter *>(blitPm->blittable()); + dfbBlitter->unlock(); + + IDirectFBSurface *s = dfbBlitter->m_surface; + + quint32 blittingFlags = pixmap.hasAlpha()? DSBLIT_BLEND_ALPHACHANNEL : DSBLIT_NOFX; + + s->SetBlittingFlags(s, DFBSurfaceBlittingFlags(blittingFlags)); + m_surface->SetBlittingFlags(m_surface, DFBSurfaceBlittingFlags(blittingFlags)); + m_surface->SetPorterDuff(m_surface,DSPD_SRC_OVER); + m_surface->SetDstBlendFunction(m_surface,DSBF_INVSRCALPHA); + + const DFBRectangle sRect = { srcRect.x(), srcRect.y(), rect.width(), rect.height() }; + + DFBResult result; + if (rect.width() == srcRect.width() && rect.height() == srcRect.height()) + result = m_surface->Blit(m_surface, s, &sRect, rect.x(), rect.y()); + else { + const DFBRectangle dRect = { rect.x(), rect.y(), rect.width(), rect.height() }; + result = m_surface->StretchBlit(m_surface, s, &sRect, &dRect); + } + if (result != DFB_OK) + DirectFBError("QDirectFBBlitter::drawPixmap()", result); +} + +QImage *QDirectFbBlitter::doLock() +{ + Q_ASSERT(m_surface); + Q_ASSERT(size().isValid()); + + void *mem; + int bpl; + const DFBResult result = m_surface->Lock(m_surface, DFBSurfaceLockFlags(DSLF_WRITE|DSLF_READ), static_cast<void**>(&mem), &bpl); + if (result == DFB_OK) { + DFBSurfacePixelFormat dfbFormat; + DFBSurfaceCapabilities dfbCaps; + m_surface->GetPixelFormat(m_surface,&dfbFormat); + m_surface->GetCapabilities(m_surface,&dfbCaps); + QImage::Format format = QDirectFbConvenience::imageFormatFromSurfaceFormat(dfbFormat, dfbCaps); + int w, h; + m_surface->GetSize(m_surface,&w,&h); + m_image = QImage(static_cast<uchar *>(mem),w,h,bpl,format); + } else { + DirectFBError("Failed to lock image", result); + } + + return &m_image; +} + +void QDirectFbBlitter::doUnlock() +{ + m_surface->Unlock(m_surface); +} diff --git a/src/plugins/platforms/minimaldfb/qblitter_directfb.h b/src/plugins/platforms/minimaldfb/qblitter_directfb.h new file mode 100644 index 0000000..85a303a --- /dev/null +++ b/src/plugins/platforms/minimaldfb/qblitter_directfb.h @@ -0,0 +1,29 @@ +#ifndef QDIRECTFBBLITTER_H +#define QDIRECTFBBLITTER_H + +#include "qdirectfbconvenience.h" + +#include <private/qblittable_p.h> + +#include <directfb.h> + +class QDirectFbBlitter : public QBlittable +{ +public: + QDirectFbBlitter(const QSize &size, IDirectFBSurface *surface = 0); + virtual ~QDirectFbBlitter(); + + virtual void fillRect(const QRectF &rect, const QColor &color); + virtual void drawPixmap(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect); + +protected: + virtual QImage *doLock(); + virtual void doUnlock(); + + IDirectFBSurface *m_surface; + QImage m_image; + + friend class QDirectFbConvenience; +}; + +#endif // QDIRECTFBBLITTER_H diff --git a/src/plugins/platforms/minimaldfb/qdirectfbconvenience.cpp b/src/plugins/platforms/minimaldfb/qdirectfbconvenience.cpp new file mode 100644 index 0000000..8594c09 --- /dev/null +++ b/src/plugins/platforms/minimaldfb/qdirectfbconvenience.cpp @@ -0,0 +1,335 @@ +#include "qdirectfbconvenience.h" +#include "qblitter_directfb.h" + +#include <private/qpixmap_blitter_p.h> + +IDirectFB *QDirectFbConvenience::dfbInterface() +{ + static IDirectFB *dfb = 0; + if (!dfb) { + DFBResult result = DirectFBCreate(&dfb); + if (result != DFB_OK) { + DirectFBError("QDirectFBConvenience: error creating DirectFB interface",result); + return 0; + } + } + return dfb; +} + +IDirectFBDisplayLayer *QDirectFbConvenience::dfbDisplayLayer(int display) +{ + IDirectFBDisplayLayer *layer; + DFBResult result = QDirectFbConvenience::dfbInterface()->GetDisplayLayer(QDirectFbConvenience::dfbInterface(),display,&layer); + if (result != DFB_OK) { + DirectFBError("QDirectFbConvenience: " + "Unable to get primary display layer!", result); + } + return layer; +} + +QImage::Format QDirectFbConvenience::imageFormatFromSurfaceFormat(const DFBSurfacePixelFormat format, const DFBSurfaceCapabilities caps) +{ + switch (format) { + case DSPF_LUT8: + return QImage::Format_Indexed8; + case DSPF_RGB24: + return QImage::Format_RGB888; + case DSPF_ARGB4444: + return QImage::Format_ARGB4444_Premultiplied; + case DSPF_RGB444: + return QImage::Format_RGB444; + case DSPF_RGB555: + case DSPF_ARGB1555: + return QImage::Format_RGB555; + case DSPF_RGB16: + return QImage::Format_RGB16; + case DSPF_ARGB6666: + return QImage::Format_ARGB6666_Premultiplied; + case DSPF_RGB18: + return QImage::Format_RGB666; + case DSPF_RGB32: + return QImage::Format_RGB32; + case DSPF_ARGB: { + if (caps & DSCAPS_PREMULTIPLIED) + return QImage::Format_ARGB32_Premultiplied; + else return QImage::Format_ARGB32; } + default: + break; + } + return QImage::Format_Invalid; + +} + +int QDirectFbConvenience::colorDepthForSurface(const DFBSurfacePixelFormat format) +{ + return ((0x1f << 7) & format) >> 7; +} + +IDirectFBSurface *QDirectFbConvenience::dfbSurfaceForPixmapData(QPixmapData *pixmapData) +{ + QBlittablePixmapData *blittablePmData = static_cast<QBlittablePixmapData *>(pixmapData); + if (blittablePmData) { + QBlittable *blittable = blittablePmData->blittable(); + QDirectFbBlitter *dfbBlitter = static_cast<QDirectFbBlitter *>(blittable); + return dfbBlitter->m_surface; + } + return 0; +} + +Qt::MouseButton QDirectFbConvenience::mouseButton(DFBInputDeviceButtonIdentifier identifier) +{ + switch (identifier){ + case DIBI_LEFT: + return Qt::LeftButton; + case DIBI_MIDDLE: + return Qt::MidButton; + case DIBI_RIGHT: + return Qt::RightButton; + default: + return Qt::NoButton; + } +} + +Qt::MouseButtons QDirectFbConvenience::mouseButtons(DFBInputDeviceButtonMask mask) +{ + Qt::MouseButtons buttons = Qt::NoButton; + + if (mask & DIBM_LEFT) { + buttons |= Qt::LeftButton; + } + if (mask & DIBM_MIDDLE) { + buttons |= Qt::MidButton; + } + if (mask & DIBM_RIGHT) { + buttons |= Qt::RightButton; + } + return buttons; +} + +Qt::KeyboardModifiers QDirectFbConvenience::keyboardModifiers(DFBInputDeviceModifierMask mask) +{ + Qt::KeyboardModifiers modifiers = Qt::NoModifier; + + if (mask & DIMM_SHIFT) { + modifiers |= Qt::ShiftModifier; + } + if (mask & DIMM_ALT) { + modifiers |= Qt::AltModifier; + } + if (mask & DIMM_ALTGR) { + modifiers |= Qt::MetaModifier; + } + if (mask & DIMM_CONTROL) { + modifiers |= Qt::ControlModifier; + } + if (mask & DIMM_META) { + modifiers | Qt::MetaModifier; + } + return modifiers; +} + +QEvent::Type QDirectFbConvenience::eventType(DFBWindowEventType type) +{ + switch(type) { + case DWET_BUTTONDOWN: + return QEvent::MouseButtonPress; + case DWET_BUTTONUP: + return QEvent::MouseButtonRelease; + case DWET_MOTION: + return QEvent::MouseMove; + case DWET_WHEEL: + return QEvent::Wheel; + case DWET_KEYDOWN: + return QEvent::KeyPress; + case DWET_KEYUP: + return QEvent::KeyRelease; + default: + return QEvent::None; + } +} +QDirectFbKeyMap *QDirectFbConvenience::dfbKeymap = 0; +QDirectFbKeyMap *QDirectFbConvenience::keyMap() +{ + if (!dfbKeymap) + dfbKeymap = new QDirectFbKeyMap(); + return dfbKeymap; +} + +QDirectFbKeyMap::QDirectFbKeyMap() +{ + 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); +} diff --git a/src/plugins/platforms/minimaldfb/qdirectfbconvenience.h b/src/plugins/platforms/minimaldfb/qdirectfbconvenience.h new file mode 100644 index 0000000..0b1a24f --- /dev/null +++ b/src/plugins/platforms/minimaldfb/qdirectfbconvenience.h @@ -0,0 +1,43 @@ +#ifndef QDIRECTFBCONVENIENCE_H +#define QDIRECTFBCONVENIENCE_H + +#include <QtGui/qimage.h> +#include <QtCore/QHash> +#include <QtCore/QEvent> +#include <QtGui/QPixmap> + +#include <directfb.h> + +class QDirectFbKeyMap: public QHash<DFBInputDeviceKeySymbol, Qt::Key> +{ +public: + QDirectFbKeyMap(); +}; + + +class QDirectFbConvenience +{ +public: + static QImage::Format imageFormatFromSurfaceFormat(const DFBSurfacePixelFormat format, const DFBSurfaceCapabilities caps); + static bool pixelFomatHasAlpha(const DFBSurfacePixelFormat format) { return (1 << 16) & format; } + static int colorDepthForSurface(const DFBSurfacePixelFormat format); + + //This is set by the graphicssystem constructor + static IDirectFB *dfbInterface(); + static IDirectFBDisplayLayer *dfbDisplayLayer(int display = DLID_PRIMARY); + + static IDirectFBSurface *dfbSurfaceForPixmapData(QPixmapData *); + + static Qt::MouseButton mouseButton(DFBInputDeviceButtonIdentifier identifier); + static Qt::MouseButtons mouseButtons(DFBInputDeviceButtonMask mask); + static Qt::KeyboardModifiers keyboardModifiers(DFBInputDeviceModifierMask mask); + static QEvent::Type eventType(DFBWindowEventType type); + + static QDirectFbKeyMap *keyMap(); + +private: + static QDirectFbKeyMap *dfbKeymap; + friend class QDirectFbGraphicsSystem; +}; + +#endif // QDIRECTFBCONVENIENCE_H diff --git a/src/plugins/platforms/minimaldfb/qdirectfbcursor.cpp b/src/plugins/platforms/minimaldfb/qdirectfbcursor.cpp new file mode 100644 index 0000000..229a875 --- /dev/null +++ b/src/plugins/platforms/minimaldfb/qdirectfbcursor.cpp @@ -0,0 +1,42 @@ +#include "qdirectfbcursor.h" +#include "qblitter_directfb.h" +#include "qgraphicssystem_minimaldfb.h" +#include "qdirectfbconvenience.h" + +#include <private/qpixmap_blitter_p.h> + +QDirectFBCursor::QDirectFBCursor(QGraphicsSystemScreen * screen) : + QGraphicsSystemCursor(screen), surface(0) +{ + QDirectFbConvenience::dfbInterface()->GetDisplayLayer(QDirectFbConvenience::dfbInterface(),DLID_PRIMARY, &m_layer); + image = new QGraphicsSystemCursorImage(0, 0, 0, 0, 0, 0); +} + +void QDirectFBCursor::changeCursor(QCursor * cursor, QWidget * widget) +{ + Q_UNUSED(widget); + int xSpot; + int ySpot; + QPixmap map; + + if (cursor->shape() != Qt::BitmapCursor) { + image->set(cursor->shape()); + xSpot = image->hotspot().x(); + ySpot = image->hotspot().y(); + QImage *i = image->image(); + map = QPixmap::fromImage(*i); + } else { + QPoint point = cursor->hotSpot(); + xSpot = point.x(); + ySpot = point.y(); + map = cursor->pixmap(); + } + + IDirectFBSurface *surface = QDirectFbConvenience::dfbSurfaceForPixmapData(map.pixmapData()); + + if (m_layer->SetCooperativeLevel(m_layer, DLSCL_ADMINISTRATIVE) != DFB_OK) { + return; + } + m_layer->SetCursorShape( m_layer, surface, xSpot, ySpot); + m_layer->SetCooperativeLevel(m_layer, DLSCL_SHARED); +} diff --git a/src/plugins/platforms/minimaldfb/qdirectfbcursor.h b/src/plugins/platforms/minimaldfb/qdirectfbcursor.h new file mode 100644 index 0000000..064a336 --- /dev/null +++ b/src/plugins/platforms/minimaldfb/qdirectfbcursor.h @@ -0,0 +1,22 @@ +#ifndef QDIRECTFBCURSOR_H +#define QDIRECTFBCURSOR_H + +#include <QGraphicsSystemCursor> +#include <directfb.h> +class QDirectFbGraphicsSystemScreen; +class QDirectFbBlitter; + +class QDirectFBCursor : public QGraphicsSystemCursor +{ +public: + QDirectFBCursor(QGraphicsSystemScreen *screem); + void changeCursor(QCursor * cursor, QWidget * widget); + +private: + IDirectFBDisplayLayer * m_layer; + IDirectFBSurface * surface; + QGraphicsSystemCursorImage * image; + QDirectFbBlitter *blitter; +}; + +#endif // QDIRECTFBCURSOR_H diff --git a/src/plugins/platforms/minimaldfb/qdirectfbinput.cpp b/src/plugins/platforms/minimaldfb/qdirectfbinput.cpp new file mode 100644 index 0000000..74a38a4 --- /dev/null +++ b/src/plugins/platforms/minimaldfb/qdirectfbinput.cpp @@ -0,0 +1,205 @@ +#include "qdirectfbinput.h" +#include "qdirectfbconvenience.h" + +#include <QThread> +#include <QDebug> +#include <QWindowSystemInterface> +#include <QMouseEvent> +#include <QEvent> +#include <QApplication> + +#include <directfb.h> + +InputSocketWaiter::InputSocketWaiter(IDirectFBEventBuffer *eventBuffer, QObject *parent) + : QThread(parent), m_eventBuffer(eventBuffer),m_shouldStop(false) +{ + this->start(); +} + +InputSocketWaiter::~InputSocketWaiter() +{ + m_shouldStop = true; + m_eventBuffer->WakeUp(m_eventBuffer); + m_cleanupMutex.lock(); +} + +void InputSocketWaiter::continueWaitingForEvents() +{ + m_finishedProcessingEvents.wakeAll(); +} + +void InputSocketWaiter::run() +{ + m_cleanupMutex.lock(); + while (1) { + m_eventBuffer->WaitForEvent(m_eventBuffer); + if (m_shouldStop) + break; + emit newEvent(); + QMutex waitForProcessingMutex; + waitForProcessingMutex.lock(); + m_finishedProcessingEvents.wait(&waitForProcessingMutex); + } + m_cleanupMutex.unlock(); +} + +QDirectFbInput *QDirectFbInput::instance() +{ + static QDirectFbInput *input = 0; + if (!input) { + input = new QDirectFbInput(); + } + return input; +} + +QDirectFbInput::QDirectFbInput() + : QObject() +{ + dfbInterface = QDirectFbConvenience::dfbInterface(); + + DFBResult ok = dfbInterface->CreateEventBuffer(dfbInterface,&eventBuffer); + if (ok != DFB_OK) + DirectFBError("Failed to initialise eventbuffer", ok); + + dfbInterface->GetDisplayLayer(dfbInterface,DLID_PRIMARY, &dfbDisplayLayer); + + m_inputHandler = new InputSocketWaiter(eventBuffer,this); + connect(m_inputHandler,SIGNAL(newEvent()),this,SLOT(handleEvents())); + + connect(QApplication::instance(),SIGNAL(aboutToQuit()),SLOT(applicationEnd())); +} + +void QDirectFbInput::addWindow(DFBWindowID id, QWidget *tlw) +{ + tlwMap.insert(id,tlw); + IDirectFBWindow *window; + dfbDisplayLayer->GetWindow(dfbDisplayLayer,id,&window); + + window->AttachEventBuffer(window,eventBuffer); +} + +void QDirectFbInput::removeWindow(QWidget *tlw) +{ + DFBWindowID id = tlwMap.key(tlw,0); + if (id) { + IDirectFBWindow *window; + dfbDisplayLayer->GetWindow(dfbDisplayLayer,id, &window); + + window->DetachEventBuffer(window,eventBuffer); + tlwMap.remove(id); + } +} + +void QDirectFbInput::handleEvents() +{ + DFBResult hasEvent = eventBuffer->HasEvent(eventBuffer); + while(hasEvent == DFB_OK){ + DFBEvent event; + DFBResult ok = eventBuffer->GetEvent(eventBuffer,&event); + if (ok != DFB_OK) + DirectFBError("Failed to get event",ok); + if (event.clazz == DFEC_WINDOW) { + switch (event.window.type) { + case DWET_BUTTONDOWN: + case DWET_BUTTONUP: + case DWET_MOTION: + handleMouseEvents(event); + break; + case DWET_WHEEL: + handleWheelEvent(event); + break; + case DWET_KEYDOWN: + case DWET_KEYUP: + handleKeyEvents(event); + break; + case DWET_ENTER: + case DWET_LEAVE: + handleEnterLeaveEvents(event); + default: + break; + } + + } + + hasEvent = eventBuffer->HasEvent(eventBuffer); + } + m_inputHandler->continueWaitingForEvents(); +} + +void QDirectFbInput::handleMouseEvents(const DFBEvent &event) +{ + QPoint p(event.window.x, event.window.y); + QPoint globalPos = globalPoint(event); + Qt::MouseButtons buttons = QDirectFbConvenience::mouseButtons(event.window.buttons); + + IDirectFBDisplayLayer *layer = QDirectFbConvenience::dfbDisplayLayer(); + IDirectFBWindow *window; + layer->GetWindow(layer,event.window.window_id,&window); + + long timestamp = (event.window.timestamp.tv_sec*1000) + (event.window.timestamp.tv_usec/1000); + + if (event.window.type == DWET_BUTTONDOWN) { + window->GrabPointer(window); + } else if (event.window.type == DWET_BUTTONUP) { + window->UngrabPointer(window); + } + QWidget *tlw = tlwMap.value(event.window.window_id); + QWindowSystemInterface::handleMouseEvent(tlw, timestamp, p, globalPos, buttons); +} + +void QDirectFbInput::applicationEnd() +{ + delete m_inputHandler; + m_inputHandler = 0; +} + +void QDirectFbInput::handleWheelEvent(const DFBEvent &event) +{ + QPoint p(event.window.cx, event.window.cy); + QPoint globalPos = globalPoint(event); + long timestamp = (event.window.timestamp.tv_sec*1000) + (event.window.timestamp.tv_usec/1000); + QWidget *tlw = tlwMap.value(event.window.window_id); + QWindowSystemInterface::handleWheelEvent(tlw, timestamp, p, globalPos, + event.window.step*120, + Qt::Vertical); +} + +void QDirectFbInput::handleKeyEvents(const DFBEvent &event) +{ + QEvent::Type type = QDirectFbConvenience::eventType(event.window.type); + Qt::Key key = QDirectFbConvenience::keyMap()->value(event.window.key_symbol); + Qt::KeyboardModifiers modifiers = QDirectFbConvenience::keyboardModifiers(event.window.modifiers); + + long timestamp = (event.window.timestamp.tv_sec*1000) + (event.window.timestamp.tv_usec/1000); + + QChar character; + if (DFB_KEY_TYPE(event.window.key_symbol) == DIKT_UNICODE) + character = QChar(event.window.key_symbol); + QWidget *tlw = tlwMap.value(event.window.window_id); + QWindowSystemInterface::handleKeyEvent(tlw, timestamp, type, key, modifiers, character); +} + +void QDirectFbInput::handleEnterLeaveEvents(const DFBEvent &event) +{ + QWidget *tlw = tlwMap.value(event.window.window_id); + switch (event.window.type) { + case DWET_ENTER: + QWindowSystemInterface::handleEnterEvent(tlw); + break; + case DWET_LEAVE: + QWindowSystemInterface::handleLeaveEvent(tlw); + break; + default: + break; + } +} + +inline QPoint QDirectFbInput::globalPoint(const DFBEvent &event) const +{ + IDirectFBWindow *window; + dfbDisplayLayer->GetWindow(dfbDisplayLayer,event.window.window_id,&window); + int x,y; + window->GetPosition(window,&x,&y); + return QPoint(event.window.cx +x, event.window.cy + y); +} + diff --git a/src/plugins/platforms/minimaldfb/qdirectfbinput.h b/src/plugins/platforms/minimaldfb/qdirectfbinput.h new file mode 100644 index 0000000..31aa082 --- /dev/null +++ b/src/plugins/platforms/minimaldfb/qdirectfbinput.h @@ -0,0 +1,63 @@ +#ifndef QDIRECTFBINPUT_H +#define QDIRECTFBINPUT_H + +#include <QThread> +#include <QMutex> +#include <QWaitCondition> +#include <QObject> +#include <QHash> +#include <QPoint> +#include <QEvent> + +#include <directfb.h> + +class InputSocketWaiter : public QThread +{ + Q_OBJECT +public: + InputSocketWaiter(IDirectFBEventBuffer *eventBuffer, QObject *parent); + virtual ~InputSocketWaiter(); + void continueWaitingForEvents(); +protected: + void run(); +signals: + void newEvent(); +private: + IDirectFBEventBuffer *m_eventBuffer; + bool m_shouldStop; + QMutex m_cleanupMutex; + QWaitCondition m_finishedProcessingEvents; +}; + +class QDirectFbInput : public QObject +{ + Q_OBJECT +public: + static QDirectFbInput *instance(); + void addWindow(DFBWindowID id, QWidget *tlw); + void removeWindow(QWidget *tlw); + +public slots: + void handleEvents(); + void applicationEnd(); + +private: + QDirectFbInput(); + + void handleMouseEvents(const DFBEvent &event); + void handleWheelEvent(const DFBEvent &event); + void handleKeyEvents(const DFBEvent &event); + void handleEnterLeaveEvents(const DFBEvent &event); + IDirectFB *dfbInterface; + IDirectFBDisplayLayer *dfbDisplayLayer; + IDirectFBEventBuffer *eventBuffer; + + QHash<DFBWindowID,QWidget *>tlwMap; + + inline QPoint globalPoint(const DFBEvent &event) const; + + InputSocketWaiter *m_inputHandler; + +}; + +#endif // QDIRECTFBINPUT_H diff --git a/src/plugins/platforms/minimaldfb/qgraphicssystem_minimaldfb.cpp b/src/plugins/platforms/minimaldfb/qgraphicssystem_minimaldfb.cpp new file mode 100644 index 0000000..212f3a9 --- /dev/null +++ b/src/plugins/platforms/minimaldfb/qgraphicssystem_minimaldfb.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 "qgraphicssystem_minimaldfb.h" +#include "qwindowsurface_minimaldfb.h" +#include "qblitter_directfb.h" +#include "qdirectfbconvenience.h" +#include "qdirectfbcursor.h" + +#include <private/qwindowsurface_raster_p.h> +#include <private/qpixmap_raster_p.h> + +#include <private/qpixmap_blitter_p.h> +#include <private/qpixmapdata_p.h> +#include <QCoreApplication> + +QT_BEGIN_NAMESPACE + +QDirectFbGraphicsSystemScreen::QDirectFbGraphicsSystemScreen(int display) + :QGraphicsSystemScreen() +{ + m_layer = QDirectFbConvenience::dfbDisplayLayer(display); + m_layer->SetCooperativeLevel(m_layer,DLSCL_SHARED); + + DFBDisplayLayerConfig config; + m_layer->GetConfiguration(m_layer, &config); + + m_format = QDirectFbConvenience::imageFormatFromSurfaceFormat(config.pixelformat, config.surface_caps); + m_geometry = QRect(0,0,config.width,config.height); + const int dpi = 72; + const qreal inch = 25.4; + m_depth = 32; + m_physicalSize = QSize(qRound(config.width * inch / dpi), qRound(config.height *inch / dpi)); + + cursor = new QDirectFBCursor(this); +} + +QDirectFbGraphicsSystemScreen::~QDirectFbGraphicsSystemScreen() +{ +} + +QDirectFbGraphicsSystem::QDirectFbGraphicsSystem() +{ + 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()); + + DFBResult result = DirectFBInit(&argc, &argv); + if (result != DFB_OK) { + DirectFBError("QDirectFBScreen: error initializing DirectFB", + result); + } + delete[] argv; + + mPrimaryScreen = new QDirectFbGraphicsSystemScreen(0); + mScreens.append(mPrimaryScreen); +} + +QPixmapData *QDirectFbGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +{ + if (type == QPixmapData::BitmapType) + return new QRasterPixmapData(type); + else + return new QBlittablePixmapData(type); +} + +QWindowSurface *QDirectFbGraphicsSystem::createWindowSurface(QWidget *widget) const +{ + return new QDirectFbWindowSurface (widget); +} + +QBlittable *QDirectFbGraphicsSystem::createBlittable(const QSize &size) const +{ + return new QDirectFbBlitter(size); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/minimaldfb/qgraphicssystem_minimaldfb.h b/src/plugins/platforms/minimaldfb/qgraphicssystem_minimaldfb.h new file mode 100644 index 0000000..27bddfb --- /dev/null +++ b/src/plugins/platforms/minimaldfb/qgraphicssystem_minimaldfb.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 QGRAPHICSSYSTEM_MINIMAL_H +#define QGRAPHICSSYSTEM_MINIMAL_H + +#include "qdirectfbinput.h" + +#include <QtGui/private/qgraphicssystem_p.h> +#include <directfb.h> +#include <directfb_version.h> + +QT_BEGIN_NAMESPACE + +class QDirectFBCursor; + +class QDirectFbGraphicsSystemScreen : public QGraphicsSystemScreen +{ +public: + QDirectFbGraphicsSystemScreen(int display); + ~QDirectFbGraphicsSystemScreen(); + + QRect geometry() const { return m_geometry; } + int depth() const { return m_depth; } + QImage::Format format() const { return m_format; } + QSize physicalSize() const { return m_physicalSize; } + +public: + QRect m_geometry; + int m_depth; + QImage::Format m_format; + QSize m_physicalSize; + + IDirectFBDisplayLayer *m_layer; + +private: + QDirectFBCursor * cursor; + +}; + +class QDirectFbGraphicsSystem : public QGraphicsSystem +{ +public: + QDirectFbGraphicsSystem(); + + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QWindowSurface *createWindowSurface(QWidget *widget) const; + QBlittable *createBlittable(const QSize &size) const; + + QList<QGraphicsSystemScreen *> screens() const { return mScreens; } + + + +private: + QDirectFbGraphicsSystemScreen *mPrimaryScreen; + QList<QGraphicsSystemScreen *> mScreens; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/minimaldfb/qwindowsurface_minimaldfb.cpp b/src/plugins/platforms/minimaldfb/qwindowsurface_minimaldfb.cpp new file mode 100644 index 0000000..68d5aa0 --- /dev/null +++ b/src/plugins/platforms/minimaldfb/qwindowsurface_minimaldfb.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 "qwindowsurface_minimaldfb.h" +#include "qgraphicssystem_minimaldfb.h" +#include "qblitter_directfb.h" +#include "qdirectfbconvenience.h" +#include <private/qpixmap_blitter_p.h> + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +QDirectFbWindowSurface::QDirectFbWindowSurface(QWidget *window) + : QWindowSurface(window), m_pixmap(0), m_pmdata(0), + m_dfbWindow(0), m_dfbSurface(0) +{ + window->setWindowSurface(this); + + IDirectFBDisplayLayer *layer = QDirectFbConvenience::dfbDisplayLayer(); + DFBDisplayLayerConfig layerConfig; + layer->GetConfiguration(layer,&layerConfig); + + DFBWindowDescription description; + memset(&description,0,sizeof(DFBWindowDescription)); + description.flags = DFBWindowDescriptionFlags(DWDESC_WIDTH|DWDESC_HEIGHT|DWDESC_POSX|DWDESC_POSY|DWDESC_SURFACE_CAPS +#if DIRECTFB_MINOR_VERSION >= 1 + |DWDESC_OPTIONS +#endif + |DWDESC_CAPS); + description.width = window->rect().width(); + description.height = window->rect().height(); + description.posx = window->rect().x(); + description.posy = window->rect().y(); + + if (layerConfig.surface_caps & DSCAPS_PREMULTIPLIED) + description.surface_caps = DSCAPS_PREMULTIPLIED; + description.pixelformat = layerConfig.pixelformat; + +#if DIRECTFB_MINOR_VERSION >= 1 + description.options = DFBWindowOptions(DWOP_ALPHACHANNEL); +#endif + description.caps = DFBWindowCapabilities(DWCAPS_DOUBLEBUFFER|DWCAPS_ALPHACHANNEL); + description.surface_caps = DSCAPS_PREMULTIPLIED; + + DFBResult result = layer->CreateWindow(layer,&description,&m_dfbWindow); + if (result != DFB_OK) { + DirectFBError("QDirectFbGraphicsSystemScreen: failed to create window",result); + } + + DFBWindowID id; + m_dfbWindow->GetID(m_dfbWindow, &id); + QDirectFbInput::instance()->addWindow(id,window); + + m_dfbWindow->GetSurface(m_dfbWindow,&m_dfbSurface); + + QDirectFbBlitter *blitter = new QDirectFbBlitter(window->rect().size(), m_dfbSurface); + m_pmdata = new QBlittablePixmapData(QPixmapData::PixmapType); + m_pmdata->setBlittable(blitter); + m_pixmap = new QPixmap(m_pmdata); +} + +QDirectFbWindowSurface::~QDirectFbWindowSurface() +{ + QDirectFbInput::instance()->removeWindow(this->window()); + m_dfbWindow->Destroy(m_dfbWindow); +} + +QPaintDevice *QDirectFbWindowSurface::paintDevice() +{ + return m_pixmap; +} + +void QDirectFbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +{ + m_pmdata->blittable()->unlock(); + + const quint8 windowOpacity = quint8(widget->windowOpacity() * 0xff); + m_dfbWindow->SetOpacity(m_dfbWindow,windowOpacity); + + QVector<QRect> rects = region.rects(); + for (int i = 0 ; i < rects.size(); i++) { + const QRect rect = rects.at(i); + DFBRegion dfbReg = { rect.x() + offset.x(),rect.y() + offset.y(),rect.right() + offset.x(),rect.bottom() + offset.y()}; + m_dfbSurface->Flip(m_dfbSurface, &dfbReg, DFBSurfaceFlipFlags(DSFLIP_BLIT|DSFLIP_ONSYNC)); + } +} + +void QDirectFbWindowSurface::setGeometry(const QRect &rect) +{ + m_pmdata->blittable()->unlock(); + + QWindowSurface::setGeometry(rect); + m_dfbWindow->SetBounds(m_dfbWindow, rect.x(),rect.y(), + rect.width(), rect.height()); + + //Have to add 1 ref ass it will be removed by deleting the old blitter in setBlittable + m_dfbSurface->AddRef(m_dfbSurface); + QDirectFbBlitter *blitter = new QDirectFbBlitter(rect.size(),m_dfbSurface); + m_pmdata->setBlittable(blitter); +} + +static inline void scrollSurface(IDirectFBSurface *surface, const QRect &r, int dx, int dy) +{ + const DFBRectangle rect = { r.x(), r.y(), r.width(), r.height() }; + surface->Blit(surface, surface, &rect, r.x() + dx, r.y() + dy); + const DFBRegion region = { rect.x + dx, rect.y + dy, r.right() + dx, r.bottom() + dy }; + surface->Flip(surface, ®ion, DFBSurfaceFlipFlags(DSFLIP_BLIT)); +} + +bool QDirectFbWindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + m_pmdata->blittable()->unlock(); + + if (!m_dfbSurface || area.isEmpty()) + return false; + m_dfbSurface->SetBlittingFlags(m_dfbSurface, DSBLIT_NOFX); + if (area.rectCount() == 1) { + scrollSurface(m_dfbSurface, area.boundingRect(), dx, dy); + } else { + const QVector<QRect> rects = area.rects(); + const int n = rects.size(); + for (int i=0; i<n; ++i) { + scrollSurface(m_dfbSurface, rects.at(i), dx, dy); + } + } + return true; +} + +void QDirectFbWindowSurface::beginPaint(const QRegion ®ion) +{ + Q_UNUSED(region); +} + +void QDirectFbWindowSurface::endPaint(const QRegion ®ion) +{ + Q_UNUSED(region); +} + +void QDirectFbWindowSurface::setVisible(bool visible) +{ + m_pmdata->blittable()->unlock(); + + if (visible) { + int x = this->geometry().x(); + int y = this->geometry().y(); + m_dfbWindow->MoveTo(m_dfbWindow,x,y); + } else { + IDirectFBDisplayLayer *displayLayer; + QDirectFbConvenience::dfbInterface()->GetDisplayLayer(QDirectFbConvenience::dfbInterface(),DLID_PRIMARY,&displayLayer); + + DFBDisplayLayerConfig config; + displayLayer->GetConfiguration(displayLayer,&config); + m_dfbWindow->MoveTo(m_dfbWindow,config.width+1,config.height + 1); + } +} + +Qt::WindowFlags QDirectFbWindowSurface::setWindowFlags(Qt::WindowFlags flags) +{ + switch (flags & Qt::WindowType_Mask) { + case Qt::ToolTip: { + DFBWindowOptions options; + m_dfbWindow->GetOptions(m_dfbWindow,&options); + options = DFBWindowOptions(options | DWOP_GHOST); + m_dfbWindow->SetOptions(m_dfbWindow,options); + break; } + default: + break; + } + + m_dfbWindow->SetStackingClass(m_dfbWindow, flags & Qt::WindowStaysOnTopHint ? DWSC_UPPER : DWSC_MIDDLE); + return flags; +} + +void QDirectFbWindowSurface::raise() +{ + m_dfbWindow->RaiseToTop(m_dfbWindow); +} + +void QDirectFbWindowSurface::lower() +{ + m_dfbWindow->LowerToBottom(m_dfbWindow); +} + +WId QDirectFbWindowSurface::winId() const +{ + DFBWindowID id; + m_dfbWindow->GetID(m_dfbWindow, &id); + return WId(id); +} + + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/minimaldfb/qwindowsurface_minimaldfb.h b/src/plugins/platforms/minimaldfb/qwindowsurface_minimaldfb.h new file mode 100644 index 0000000..ca34cbf --- /dev/null +++ b/src/plugins/platforms/minimaldfb/qwindowsurface_minimaldfb.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 QWINDOWSURFACE_MINIMAL_H +#define QWINDOWSURFACE_MINIMAL_H + +#include <QtGui/private/qwindowsurface_p.h> +#include <private/qpixmap_blitter_p.h> + +#include <directfb.h> + +QT_BEGIN_NAMESPACE + +class QDirectFbGraphicsSystemScreen; + +class QDirectFbWindowSurface : public QWindowSurface +{ +public: + QDirectFbWindowSurface(QWidget *window); + ~QDirectFbWindowSurface(); + + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void setGeometry(const QRect &rect); + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion ®ion); + void endPaint(const QRegion ®ion); + + void setVisible(bool visible); + Qt::WindowFlags setWindowFlags(Qt::WindowFlags type); + + void raise(); + void lower(); + + WId winId() const; + +private: + void lockSurfaceToImage(); + + QPixmap *m_pixmap; + QBlittablePixmapData *m_pmdata; + + IDirectFBWindow *m_dfbWindow; + IDirectFBSurface *m_dfbSurface; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/openkode/frag.glslf b/src/plugins/platforms/openkode/frag.glslf new file mode 100644 index 0000000..a593434 --- /dev/null +++ b/src/plugins/platforms/openkode/frag.glslf @@ -0,0 +1,8 @@ +uniform sampler2D tex_samp; + +varying vec2 texcoord_var; + +void main() +{ + gl_FragColor = texture2D(tex_samp, texcoord_var); +} diff --git a/src/plugins/platforms/openkode/frag.h b/src/plugins/platforms/openkode/frag.h new file mode 100644 index 0000000..6575cb5 --- /dev/null +++ b/src/plugins/platforms/openkode/frag.h @@ -0,0 +1,37 @@ +0x4e,0x56,0x75,0x63,0x01,0x00,0x00,0x00,0x09,0x00,0x06,0x00,0x06,0x00,0x50,0x00, +0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x50,0x02,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x40,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x27,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x50,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0xe8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x90,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x11,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xb0,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x12,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0xc0,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x2b,0x00,0x00,0x00,0x7a,0x00,0x00,0x00,0xd0,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x2c,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x68,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, +0x00,0x00,0x00,0x80,0x04,0x00,0x00,0x90,0x00,0x02,0x01,0x82,0x04,0x02,0x02,0x82, +0x01,0x00,0x40,0xf6,0x85,0xc7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x02,0x00,0x00,0x00,0x00,0x00,0x00, +0x3a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x2a,0x00,0x06,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x3b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x02,0x00,0x00,0x00,0x00,0x00,0x00, +0x49,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x26,0x00,0x04,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x74,0x65,0x78,0x5f,0x73,0x61,0x6d,0x70,0x00,0x00,0x00,0x74,0x65,0x78,0x63, +0x6f,0x6f,0x72,0x64,0x5f,0x76,0x61,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 diff --git a/src/plugins/platforms/openkode/main.cpp b/src/plugins/platforms/openkode/main.cpp new file mode 100644 index 0000000..e9c1083 --- /dev/null +++ b/src/plugins/platforms/openkode/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qgraphicssystemplugin_p.h> +#include "qgraphicssystem_openkode.h" + +QT_BEGIN_NAMESPACE + +class QOpenKODEGraphicsSystemPlugin : public QGraphicsSystemPlugin +{ +public: + QStringList keys() const; + QGraphicsSystem *create(const QString&); +}; + +QStringList QOpenKODEGraphicsSystemPlugin::keys() const +{ + QStringList list; + list << "OpenKODE"; + return list; +} + +QGraphicsSystem* QOpenKODEGraphicsSystemPlugin::create(const QString& system) +{ + if (system.toLower() == "openkode") + return new QOpenKODEGraphicsSystem; + + return 0; +} + +Q_EXPORT_PLUGIN2(openkode, QOpenKODEGraphicsSystemPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/openkode/openkode.pro b/src/plugins/platforms/openkode/openkode.pro new file mode 100644 index 0000000..055048d --- /dev/null +++ b/src/plugins/platforms/openkode/openkode.pro @@ -0,0 +1,14 @@ +TARGET = qopenkodegraphicssystem +include(../../qpluginbase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems + +SOURCES = main.cpp qgraphicssystem_openkode.cpp qwindowsurface_openkode.cpp +HEADERS = qgraphicssystem_openkode.h qwindowsurface_openkode.h + +target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems +INSTALLS += target + +# openkode specific stuff +INCLUDEPATH += $(OPENKODE_DIR)/include +LIBS += $${QMAKE_RPATH}/$(OPENKODE_DIR)/lib-target -L$(OPENKODE_DIR)/lib-target -lKD -lEGL -lGLESv2 diff --git a/src/plugins/platforms/openkode/qgraphicssystem_openkode.cpp b/src/plugins/platforms/openkode/qgraphicssystem_openkode.cpp new file mode 100644 index 0000000..7a07776 --- /dev/null +++ b/src/plugins/platforms/openkode/qgraphicssystem_openkode.cpp @@ -0,0 +1,236 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgraphicssystem_openkode.h" +#include "qwindowsurface_openkode.h" +#include <QtGui/private/qpixmap_raster_p.h> + +#include <QtCore/qdebug.h> +#include <QtCore/qthread.h> + +#include <KD/kd.h> +#include <KD/NV_display.h> +#include <KD/NV_initialize.h> + +#include "GLES2/gl2ext.h" + + +QT_BEGIN_NAMESPACE + +QOpenKODEGraphicsSystemScreen::QOpenKODEGraphicsSystemScreen() +{ + KDDesktopNV *kdDesktop = KD_NULL; + KDDisplayNV *kdDisplay = KD_NULL; + + qDebug() << "QOpenKODEGraphicsSystemScreen::QOpenKODEGraphicsSystemScreen()"; + + // Get the default desktop and display + kdDesktop = kdGetDesktopNV(KD_DEFAULT_DESKTOP_NV, KD_NULL); + if (!kdDesktop || kdDesktop == (void*)-1) { + qErrnoWarning(kdGetError(), "Could not obtain KDDesktopNV pointer"); + return; + } + + kdDisplay = kdGetDisplayNV(KD_DEFAULT_DISPLAY_NV, KD_NULL); + if (!kdDisplay || kdDisplay == (void*)-1) { + qErrnoWarning(kdGetError(), "Could not obtain KDDisplayNV pointer"); + kdReleaseDesktopNV(kdDesktop); + return; + } + + KDDisplayModeNV mode; + if (kdGetDisplayModeNV(kdDisplay, &mode)) { + qErrnoWarning(kdGetError(), "Could not get display mode"); + return; + } + + qDebug() << " - display mode " << mode.width << "x" << mode.height << " refresh " << mode.refresh; + + KDint desktopSize[] = { mode.width, mode.height }; + + if (kdSetDesktopPropertyivNV(kdDesktop, KD_DESKTOPPROPERTY_SIZE_NV, desktopSize)) { + qErrnoWarning(kdGetError(), "Could not set desktop size"); + return; + } + + // Once we've set up the desktop and display we don't need them anymore + kdReleaseDisplayNV(kdDisplay); + kdReleaseDesktopNV(kdDesktop); + + const int defaultDpi = 72; + mGeometry = QRect(0, 0, mode.width, mode.height); + mPhysicalSize = QSize(mode.width * 25.4 / defaultDpi, mode.height * 25.4 / defaultDpi); + + mDepth = 24; + mFormat = QImage::Format_RGB888; + + + QEglProperties properties; + properties.setPixelFormat(QImage::Format_RGB888); + properties.setValue(EGL_BUFFER_SIZE, EGL_DONT_CARE); + properties.setRenderableType(QEgl::OpenGL); + + if (!mContext.chooseConfig(properties, QEgl::BestPixelFormat)) { + qWarning("qEglContext: Unable to choose config!"); + return; + } + + if (!mContext.display()) { + qWarning("qEglContext: Unable to open display!"); + return; + } + + qDebug() << " - QEglContext::openDisplay OK"; +} + +static GLuint NvKdTestLoadShaders(const char *vertex_shader_binary, + const char *fragment_shader_binary, + GLuint vertex_shader_binary_size, + GLuint fragment_shader_binary_size) +{ + GLuint prog; + GLuint vertShader; + GLuint fragShader; + + // Create the program + prog = glCreateProgram(); + + // Create the GL shader objects + vertShader = glCreateShader(GL_VERTEX_SHADER); + fragShader = glCreateShader(GL_FRAGMENT_SHADER); + + // Load the binary data into the shader objects + glShaderBinary(1, &vertShader, + GL_NVIDIA_PLATFORM_BINARY_NV, vertex_shader_binary, vertex_shader_binary_size); + glShaderBinary(1, &fragShader, + GL_NVIDIA_PLATFORM_BINARY_NV, fragment_shader_binary, fragment_shader_binary_size); + + // Attach the shaders to the program + glAttachShader(prog, vertShader); + glAttachShader(prog, fragShader); + + // Delete the shaders + glDeleteShader(vertShader); + glDeleteShader(fragShader); + + // Link and validate the shader program + glLinkProgram(prog); + glValidateProgram(prog); + + return prog; +} + +class QOpenKODEEventLoopHelper : public QThread +{ +public: + QOpenKODEEventLoopHelper(QSemaphore *m) + : eventMutex(m) + { + m->acquire(); + } + +protected: + void run() + { + qDebug() << "initializing KD"; + kdInitializeNV(); + qDebug() << "done initializing KD"; + eventMutex->release(); + + const KDEvent *event; + while ((event = kdWaitEvent(-1)) != 0) { + qDebug() << "!!! received event!"; + kdDefaultEvent(event); + } + + qDebug() << "exiting event loop"; + } + +private: + QSemaphore *eventMutex; +}; + +QOpenKODEGraphicsSystem::QOpenKODEGraphicsSystem() + : eventMutex(1) +{ + QOpenKODEEventLoopHelper *loop = new QOpenKODEEventLoopHelper(&eventMutex); + loop->start(); + eventMutex.acquire(); // block until initialization done + + mPrimaryScreen = new QOpenKODEGraphicsSystemScreen(); + + mScreens.append(mPrimaryScreen); + +} + +QPixmapData *QOpenKODEGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +{ + return new QRasterPixmapData(type); +} + +QWindowSurface *QOpenKODEGraphicsSystem::createWindowSurface(QWidget *widget) const +{ + return new QOpenKODEWindowSurface(mPrimaryScreen, widget); +} + +GLuint QOpenKODEGraphicsSystem::blitterProgram() +{ + static GLuint shaderProgram = 0; + if (!shaderProgram) { + + const char vertShaderBinary[] = { +# include "vert.h" + }; + const char fragShaderBinary[] = { +# include "frag.h" + }; + + shaderProgram = NvKdTestLoadShaders(vertShaderBinary, fragShaderBinary, + sizeof(vertShaderBinary), sizeof(fragShaderBinary)); + + if (!shaderProgram) + qFatal("QOpenKodeGraphicsSystem(): Cannot load shaders!"); + } + return shaderProgram; +} + + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/openkode/qgraphicssystem_openkode.h b/src/plugins/platforms/openkode/qgraphicssystem_openkode.h new file mode 100644 index 0000000..7d73ae0 --- /dev/null +++ b/src/plugins/platforms/openkode/qgraphicssystem_openkode.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGRAPHICSSYSTEM_OPENKODE_H +#define QGRAPHICSSYSTEM_OPENKODE_H + +#include <QtCore/qsemaphore.h> + +#include <QtGui/private/qgraphicssystem_p.h> +#include <QtGui/private/qeglcontext_p.h> + +# include <GLES2/gl2.h> + +QT_BEGIN_NAMESPACE + +struct KDDesktopNV; + +class QOpenKODEGraphicsSystemScreen : public QGraphicsSystemScreen +{ +public: + QOpenKODEGraphicsSystemScreen(); + ~QOpenKODEGraphicsSystemScreen() {} + + QRect geometry() const { return mGeometry; } + int depth() const { return mDepth; } + QImage::Format format() const { return mFormat; } + QSize physicalSize() const { return mPhysicalSize; } + +public: + QRect mGeometry; + int mDepth; + QImage::Format mFormat; + QSize mPhysicalSize; + QEglContext mContext; +}; + +class QOpenKODEGraphicsSystem : public QGraphicsSystem +{ +public: + QOpenKODEGraphicsSystem(); + + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QWindowSurface *createWindowSurface(QWidget *widget) const; + + QList<QGraphicsSystemScreen *> screens() const { return mScreens; } + + static GLuint blitterProgram(); + +private: + QOpenKODEGraphicsSystemScreen *mPrimaryScreen; + QList<QGraphicsSystemScreen *> mScreens; + QSemaphore eventMutex; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/openkode/qwindowsurface_openkode.cpp b/src/plugins/platforms/openkode/qwindowsurface_openkode.cpp new file mode 100644 index 0000000..b3f3965 --- /dev/null +++ b/src/plugins/platforms/openkode/qwindowsurface_openkode.cpp @@ -0,0 +1,265 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsurface_openkode.h" +#include "qgraphicssystem_openkode.h" +#include <QtCore/qdebug.h> + +#include "KD/kd.h" +#include "KD/NV_display.h" + +QT_BEGIN_NAMESPACE + +QOpenKODEWindowSurface::QOpenKODEWindowSurface + (QOpenKODEGraphicsSystemScreen *screen, QWidget *window) + : QWindowSurface(window), + mScreen(screen), + mSurface(0) +{ + qDebug() << "QOpenKODEWindowSurface::QOpenKODEWindowSurface:" << window << window->width() << "x" << window->height() + << "pos" << window->x() << "x" << window->y(); + + if (!mContext.display()) { + qWarning("qEglContext: Unable to open display!"); + return; + } + + QEglProperties properties; + properties.setPixelFormat(QImage::Format_RGB888); + properties.setValue(EGL_BUFFER_SIZE, EGL_DONT_CARE); + properties.setRenderableType(QEgl::OpenGL); + + if (!mContext.chooseConfig(properties, QEgl::BestPixelFormat)) { + qWarning("qEglContext: Unable to choose config!"); + return; + } + + createWindow(window); +} + +void QOpenKODEWindowSurface::createWindow(QWidget *window) +{ + qDebug() << "createWindow"; + kdWindow = kdCreateWindow(mContext.display(), mContext.config(), KD_NULL); + + if (!kdWindow) { + qErrnoWarning(kdGetError(), "Error creating native window"); + return; + } + + const KDint windowSize[2] = { window->width(), window->height() }; + if (kdSetWindowPropertyiv(kdWindow, KD_WINDOWPROPERTY_SIZE, windowSize)) { + qErrnoWarning(kdGetError(), "Could not set native window size"); + return; + } + + //const KDboolean windowExclusive[] = { false }; + //if (kdSetWindowPropertybv(kdWindow, KD_WINDOWPROPERTY_DESKTOP_EXCLUSIVE_NV, windowExclusive)) { + // qErrnoWarning(kdGetError(), "Could not set exclusive bit"); + // //return; + //} + + //const KDint windowPos[2] = { window->x(), window->y() }; + //if (kdSetWindowPropertyiv(kdWindow, KD_WINDOWPROPERTY_DESKTOP_OFFSET_NV, windowPos)) { + // qErrnoWarning(kdGetError(), "Could not set native window position"); + // //return; + //} + + EGLNativeWindowType nativeWindow; + + if (kdRealizeWindow(kdWindow, &nativeWindow)) { + qErrnoWarning(kdGetError(), "Could not realize native window"); + return; + } + qDebug() << "kdRealizeWindow" << nativeWindow; + + // Create an EGL window surface for the native window + EGLint windowAttrs[3] = { EGL_NONE }; + qDebug() << "doing createwindowsurface"; + *mSurface = eglCreateWindowSurface(mContext.display(), + mContext.config(), + nativeWindow, + windowAttrs); + qDebug() << "create windowsurface"; + if (!mSurface) { + qWarning("EGL couldn't create window surface: 0x%x", eglGetError()); + return; + } + + qDebug() << "making context"; + if (!mContext.createContext()) { + qDebug() << "Unable to create context!"; + return; + } + + qDebug() << "about to make current"; + mContext.makeCurrent(mSurface); +} + +QOpenKODEWindowSurface::~QOpenKODEWindowSurface() +{ +} + +QPaintDevice *QOpenKODEWindowSurface::paintDevice() +{ + qDebug() << "QOpenKODEWindowSurface::paintDevice"; + return &mImage; +} + +// ### TODO - this updates the entire toplevel, should only update the region +void QOpenKODEWindowSurface::flush(QWidget *, const QRegion ®ion, const QPoint &offset) +{ + qDebug() << "in flush"; + if (!offset.isNull()) { + qWarning("Offset flushing not supported yet"); + return; + } + + if (!mContext.makeCurrent(mSurface)) { + qWarning("EGL couldn't make context/surface current: 0x%x", eglGetError()); + return; + } + + QRect boundingRect = region.boundingRect(); + + int x, y, w, h; + QImage blitImage; + if (true || boundingRect == mImage.rect()) { // TODO - check optimization + blitImage = mImage; + x = y = 0; + w = mImage.width(); + h = mImage.height(); + } else { + blitImage = mImage.copy(boundingRect); + w = boundingRect.width(); + h = boundingRect.height(); + x = boundingRect.x(); + y = boundingRect.y(); + } + +// qDebug() << "flush" << widget << offset << region.boundingRect() << mImage.format() << blitImage.format(); + + GLuint shaderProgram = QOpenKODEGraphicsSystem::blitterProgram(); + + glUseProgram(shaderProgram); + + GLuint index = glGetUniformLocation(shaderProgram, "window"); + glUniform2f(index, GLfloat(mImage.width()), GLfloat(mImage.height())); + + // attributes + GLuint posId = glGetAttribLocation(shaderProgram, "pos_attr"); + GLuint texcoordId = glGetAttribLocation(shaderProgram, "texcoord_attr"); + + // sampler + index = glGetUniformLocation(shaderProgram, "tex_samp"); + + glUniform1i(index, 0); + + glDisable(GL_DEPTH_TEST); + glActiveTexture(GL_TEXTURE0); + + GLuint texId; + GLfloat coords[8] = {x, y, x, y + h, x + w, y + h, x + w, y }; + GLfloat texcoords[8] = { 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0 }; + + // Generate texture for checkered background + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glGenTextures(1, &texId); + glBindTexture(GL_TEXTURE_2D, texId); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, blitImage.bits()); + + // Enable vertex attribute associated with vertex position + glEnableVertexAttribArray(posId); + glEnableVertexAttribArray(texcoordId); + + // Set the quad vertices + glVertexAttribPointer(posId, 2, GL_FLOAT, 0, 0, coords); + glVertexAttribPointer(texcoordId, 2, GL_FLOAT, 0, 0, texcoords); + + // Draw the quad + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + // Cleanup + glDisableVertexAttribArray(posId); + glDisableVertexAttribArray(texcoordId); + + // Release all textures + glBindTexture(GL_TEXTURE_2D, 0); + if (texId) + glDeleteTextures(1, &texId); + + mContext.doneCurrent(); + mContext.swapBuffers(mSurface); +} + +void QOpenKODEWindowSurface::setGeometry(const QRect &rect) +{ + qDebug() << "QOpenKODEWindowSurface::setGeometry:" << rect; + QWindowSurface::setGeometry(rect); + if (mImage.size() != rect.size()) + mImage = QImage(rect.size(), mScreen->format()); + + mContext.destroySurface(mSurface); + kdDestroyWindow(kdWindow); + createWindow(window()); + qDebug() << "set geometry workded"; +} + +bool QOpenKODEWindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + return QWindowSurface::scroll(area, dx, dy); +} + +void QOpenKODEWindowSurface::beginPaint(const QRegion ®ion) +{ + Q_UNUSED(region); +} + +void QOpenKODEWindowSurface::endPaint(const QRegion ®ion) +{ + Q_UNUSED(region); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/openkode/qwindowsurface_openkode.h b/src/plugins/platforms/openkode/qwindowsurface_openkode.h new file mode 100644 index 0000000..bee94a5 --- /dev/null +++ b/src/plugins/platforms/openkode/qwindowsurface_openkode.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSURFACE_OPENKODE_H +#define QWINDOWSURFACE_OPENKODE_H + +#include <QtGui/private/qwindowsurface_p.h> +#include <QtGui/private/qeglcontext_p.h> + +QT_BEGIN_NAMESPACE + +class QOpenKODEGraphicsSystemScreen; + +class QOpenKODEWindowSurface : public QWindowSurface +{ +public: + QOpenKODEWindowSurface + (QOpenKODEGraphicsSystemScreen *screen, QWidget *window); + ~QOpenKODEWindowSurface(); + + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void setGeometry(const QRect &rect); + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion ®ion); + void endPaint(const QRegion ®ion); + +private: + QOpenKODEGraphicsSystemScreen *mScreen; + QImage mImage; + struct KDWindow *kdWindow; + EGLSurface *mSurface; + QEglContext mContext; + + void createWindow(QWidget *window); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/openkode/vert.glslv b/src/plugins/platforms/openkode/vert.glslv new file mode 100644 index 0000000..57b5866 --- /dev/null +++ b/src/plugins/platforms/openkode/vert.glslv @@ -0,0 +1,14 @@ +uniform vec2 window; // window size + +// Per-vertex attributes] +attribute vec2 pos_attr; +attribute vec2 texcoord_attr; + +// Output vertex color +varying vec2 texcoord_var; + +void main() +{ + gl_Position = vec4( (2.0 * pos_attr / window -1.0) * vec2(1.0, -1.0), 0.0, 1.0); + texcoord_var = texcoord_attr; +} diff --git a/src/plugins/platforms/openkode/vert.h b/src/plugins/platforms/openkode/vert.h new file mode 100644 index 0000000..bdf564d --- /dev/null +++ b/src/plugins/platforms/openkode/vert.h @@ -0,0 +1,63 @@ +0x4e,0x56,0x75,0x63,0x01,0x00,0x00,0x00,0x0a,0x00,0x06,0x00,0x06,0x00,0x50,0x00, +0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0xf0,0x03,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x60,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x24,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x70,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x26,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x90,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0xe8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x06,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0xb0,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x28,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, +0x05,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x10,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x20,0x02,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x30,0x02,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x2b,0x00,0x00,0x00,0x39,0x01,0x00,0x00,0xb0,0x02,0x00,0x00,0x00,0x00,0x00,0x00, +0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x04,0x05,0x08,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0f,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x01,0x02,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0x04,0x05,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x40,0x00,0x00,0x80,0xbf,0x00,0x00,0x00,0x00, +0x05,0x00,0x00,0x10,0x80,0xc7,0x00,0x24,0x05,0x02,0x00,0x10,0x80,0xc7,0x00,0x24, +0x01,0x02,0x81,0xc0,0x80,0x07,0x60,0x00,0x05,0x02,0x00,0x90,0x80,0x07,0x00,0x00, +0x09,0x00,0x01,0xe1,0x80,0x87,0x40,0x00,0x05,0x00,0x00,0x10,0x80,0xc7,0x00,0x24, +0x01,0x00,0x81,0xc0,0x80,0x07,0x60,0x00,0x09,0x04,0x00,0xa0,0x80,0x47,0x00,0xe4, +0x05,0x02,0x00,0x90,0x80,0x07,0x00,0x00,0x05,0x04,0x00,0x10,0x88,0xc7,0x03,0x04, +0x01,0x00,0x01,0xe1,0x88,0x87,0x40,0x00,0x09,0xf8,0x00,0x10,0x88,0xc7,0x03,0x04, +0x0d,0x00,0x00,0x10,0x88,0xc7,0x40,0x24,0x11,0x04,0x00,0x10,0x88,0xc7,0x23,0x04, +0x15,0x06,0x00,0x10,0x89,0xc7,0x23,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xa0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xa1,0x03,0x00,0x00,0x00,0x00,0x00,0x00, +0xad,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x28,0x00,0x02,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0xb6,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xb7,0x03,0x00,0x00,0x00,0x00,0x00,0x00, +0xbe,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x26,0x00,0x05,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xbf,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x03,0x00,0x00,0x00,0x00,0x00,0x00, +0xc9,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x26,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xca,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xcb,0x03,0x00,0x00,0x00,0x00,0x00,0x00, +0xd9,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x26,0x00,0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xda,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xdb,0x03,0x00,0x00,0x00,0x00,0x00,0x00, +0xe8,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x26,0x00,0x02,0x00,0x00,0x00, +0x04,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x50,0x4f,0x53, +0x49,0x54,0x49,0x4f,0x4e,0x00,0x00,0x77,0x69,0x6e,0x64,0x6f,0x77,0x00,0x00,0x00, +0x70,0x6f,0x73,0x5f,0x61,0x74,0x74,0x72,0x00,0x00,0x00,0x74,0x65,0x78,0x63,0x6f, +0x6f,0x72,0x64,0x5f,0x61,0x74,0x74,0x72,0x00,0x00,0x00,0x74,0x65,0x78,0x63,0x6f, +0x6f,0x72,0x64,0x5f,0x76,0x61,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 diff --git a/src/plugins/platforms/openvglite/main.cpp b/src/plugins/platforms/openvglite/main.cpp new file mode 100644 index 0000000..dc0b4a8 --- /dev/null +++ b/src/plugins/platforms/openvglite/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 <private/qgraphicssystemplugin_p.h> +#include "qgraphicssystem_vglite.h" + +QT_BEGIN_NAMESPACE + +class QVGGraphicsSystemPlugin : public QGraphicsSystemPlugin +{ +public: + QStringList keys() const; + QGraphicsSystem *create(const QString&); +}; + +QStringList QVGGraphicsSystemPlugin::keys() const +{ + QStringList list; + list << "OpenVG"; + return list; +} + +QGraphicsSystem* QVGGraphicsSystemPlugin::create(const QString& system) +{ + if (system.toLower() == "openvg") + return new QVGLiteGraphicsSystem; + + return 0; +} + +Q_EXPORT_PLUGIN2(openvg, QVGGraphicsSystemPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/openvglite/openvglite.pro b/src/plugins/platforms/openvglite/openvglite.pro new file mode 100644 index 0000000..9d7860a --- /dev/null +++ b/src/plugins/platforms/openvglite/openvglite.pro @@ -0,0 +1,12 @@ +TARGET = qvglitegraphicssystem +include(../../qpluginbase.pri) + +QT += openvg + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems + +SOURCES = main.cpp qgraphicssystem_vglite.cpp qwindowsurface_vglite.cpp +HEADERS = qgraphicssystem_vglite.h qwindowsurface_vglite.h + +target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems +INSTALLS += target diff --git a/src/plugins/platforms/openvglite/qgraphicssystem_vglite.cpp b/src/plugins/platforms/openvglite/qgraphicssystem_vglite.cpp new file mode 100644 index 0000000..41b2303 --- /dev/null +++ b/src/plugins/platforms/openvglite/qgraphicssystem_vglite.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 "qgraphicssystem_vglite.h" +#include "qwindowsurface_vglite.h" +#include <QtOpenVG/private/qpixmapdata_vg_p.h> +#include <QtGui/private/qegl_p.h> +#include <QtCore/qdebug.h> +#ifdef OPENVG_USBHP_INIT +extern "C" { +#include <linuxusbhp.h> +}; +#endif + +QT_BEGIN_NAMESPACE + +QVGLiteGraphicsSystem::QVGLiteGraphicsSystem() + : w(0), h(0), d(0), dw(0), dh(0), physWidth(0), physHeight(0), + surface(0), context(0), rootWindow(0), + screenFormat(QImage::Format_RGB16), preservedSwap(false) +{ +#ifdef OPENVG_USBHP_INIT + initLibrary(); +#endif + + // The graphics system is also the screen definition. + mScreens.append(this); + + QString displaySpec = QString::fromLatin1(qgetenv("QWS_DISPLAY")); + QStringList displayArgs = displaySpec.split(QLatin1Char(':')); + + // Initialize EGL and create the global EGL context. + context = qt_vg_create_context(0); + if (!context) { + qFatal("QVGLiteGraphicsSystem: could not initialize EGL"); + return; + } + + // Get the root window handle to use. Default to zero. + QRegExp winidRx(QLatin1String("winid=?(\\d+)")); + int winidIdx = displayArgs.indexOf(winidRx); + int handle = 0; + if (winidIdx >= 0) { + winidRx.exactMatch(displayArgs.at(winidIdx)); + handle = winidRx.cap(1).toInt(); + } + + // Create a full-screen window based on the native handle. + // If the context is premultiplied, the window should be too. + QEglProperties props; +#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT + EGLint surfaceType = 0; + if (context->configAttrib(EGL_SURFACE_TYPE, &surfaceType) && + (surfaceType & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0) + props.setValue(EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE); +#endif + rootWindow = eglCreateWindowSurface + (context->display(), context->config(), + (EGLNativeWindowType)handle, props.properties()); + if (rootWindow == EGL_NO_SURFACE) { + delete context; + context = 0; + qFatal("QVGLiteGraphicsSystem: could not create full-screen window"); + return; + } + + // Try to turn on preserved swap behaviour on the root window. + // This will allow us to optimize compositing to focus on just + // the screen region that has changed. Otherwise we must + // re-composite the entire screen every frame. +#if !defined(QVG_NO_PRESERVED_SWAP) + eglGetError(); // Clear error state first. + eglSurfaceAttrib(context->display(), rootWindow, + EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); + preservedSwap = (eglGetError() == EGL_SUCCESS); +#else + preservedSwap = false; +#endif + + // Fetch the root window properties. + eglQuerySurface(context->display(), rootWindow, EGL_WIDTH, &w); + eglQuerySurface(context->display(), rootWindow, EGL_HEIGHT, &h); + screenFormat = qt_vg_config_to_image_format(context); + switch (screenFormat) { + case QImage::Format_ARGB32_Premultiplied: + case QImage::Format_ARGB32: + case QImage::Format_RGB32: + default: + d = 32; + break; + case QImage::Format_RGB16: + case QImage::Format_ARGB4444_Premultiplied: + d = 16; + break; + } + dw = w; + dh = h; + qDebug("screen size: %dx%dx%d", w, h, d); + + // Handle display physical size spec. From qscreenlinuxfb_qws.cpp. + 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); + } +} + +QVGLiteGraphicsSystem::~QVGLiteGraphicsSystem() +{ +} + +QPixmapData *QVGLiteGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +{ +#if !defined(QVGLite_NO_SINGLE_CONTEXT) && !defined(QVGLite_NO_PIXMAP_DATA) + // Pixmaps can use QVGLitePixmapData; bitmaps must use raster. + if (type == QPixmapData::PixmapType) + return new QVGPixmapData(type); + else + return new QRasterPixmapData(type); +#else + return new QRasterPixmapData(type); +#endif +} + +QWindowSurface *QVGLiteGraphicsSystem::createWindowSurface(QWidget *widget) const +{ + if (widget->windowType() == Qt::Desktop) + return 0; // Don't create an explicit window surface for the destkop. + if (surface) { + qWarning() << "QVGLiteGraphicsSystem: only one window surface " + "is supported at a time"; + return 0; + } + surface = new QVGLiteWindowSurface + (const_cast<QVGLiteGraphicsSystem *>(this), widget); + return surface; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/openvglite/qgraphicssystem_vglite.h b/src/plugins/platforms/openvglite/qgraphicssystem_vglite.h new file mode 100644 index 0000000..512793d --- /dev/null +++ b/src/plugins/platforms/openvglite/qgraphicssystem_vglite.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 QGRAPHICSSYSTEM_VGLITE_H +#define QGRAPHICSSYSTEM_VGLITE_H + +#include <QtGui/private/qgraphicssystem_p.h> +#include <QtGui/private/qegl_p.h> +#include <QtGui/qimage.h> + +QT_BEGIN_NAMESPACE + +class QVGLiteWindowSurface; + +class QVGLiteGraphicsSystem : public QGraphicsSystem, + public QGraphicsSystemScreen +{ +public: + QVGLiteGraphicsSystem(); + ~QVGLiteGraphicsSystem(); + + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QWindowSurface *createWindowSurface(QWidget *widget) const; + QList<QGraphicsSystemScreen *> screens() const { return mScreens; } + + QRect geometry() const { return QRect(0, 0, w, h); } + int depth() const { return d; } + QImage::Format format() const { return screenFormat; } + QSize physicalSize() const { return QSize(physWidth, physHeight); } + +private: + friend class QVGLiteWindowSurface; + + int w; + int h; + int d; + + int dw; + int dh; + + int physWidth; + int physHeight; + + mutable QVGLiteWindowSurface *surface; + QEglContext *context; + EGLSurface rootWindow; + QImage::Format screenFormat; + bool preservedSwap; + + QList<QGraphicsSystemScreen *> mScreens; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/openvglite/qwindowsurface_vglite.cpp b/src/plugins/platforms/openvglite/qwindowsurface_vglite.cpp new file mode 100644 index 0000000..c73e35a --- /dev/null +++ b/src/plugins/platforms/openvglite/qwindowsurface_vglite.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 "qwindowsurface_vglite.h" +#include "qgraphicssystem_vglite.h" +#include <QtOpenVG/qvg.h> +#include <QtOpenVG/private/qvg_p.h> +#include <QtOpenVG/private/qpaintengine_vg_p.h> + +QT_BEGIN_NAMESPACE + +QVGLiteWindowSurface::QVGLiteWindowSurface + (QVGLiteGraphicsSystem *gs, QWidget *window) + : QWindowSurface(window), graphicsSystem(gs), + isPaintingActive(false), engine(0) +{ +} + +QVGLiteWindowSurface::~QVGLiteWindowSurface() +{ + graphicsSystem->surface = 0; + if (engine) + qt_vg_destroy_paint_engine(engine); +} + +QPaintDevice *QVGLiteWindowSurface::paintDevice() +{ + qt_vg_make_current(graphicsSystem->context, graphicsSystem->rootWindow); + isPaintingActive = true; + // TODO: clear the parts of the back buffer that are not + // covered by the window surface to black. + return this; +} + +void QVGLiteWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(widget); + Q_UNUSED(region); + Q_UNUSED(offset); + QEglContext *context = graphicsSystem->context; + if (context) { + if (!isPaintingActive) + qt_vg_make_current(context, graphicsSystem->rootWindow); + context->swapBuffers(); + qt_vg_done_current(context); + context->setSurface(EGL_NO_SURFACE); + isPaintingActive = false; + } +} + +void QVGLiteWindowSurface::setGeometry(const QRect &rect) +{ + QWindowSurface::setGeometry(rect); +} + +bool QVGLiteWindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + return QWindowSurface::scroll(area, dx, dy); +} + +void QVGLiteWindowSurface::beginPaint(const QRegion ®ion) +{ + Q_UNUSED(region); +} + +void QVGLiteWindowSurface::endPaint(const QRegion ®ion) +{ + Q_UNUSED(region); +} + +QPaintEngine *QVGLiteWindowSurface::paintEngine() const +{ + if (!engine) + engine = qt_vg_create_paint_engine(); + return engine; +} + +// We need to get access to QWidget::metric() from QVGLiteWindowSurface::metric, +// but it is not a friend of QWidget. To get around this, we create a +// fake QX11PaintEngine class, which is a friend. +class QX11PaintEngine +{ +public: + static int metric(const QWidget *widget, QPaintDevice::PaintDeviceMetric met) + { + return widget->metric(met); + } +}; + +int QVGLiteWindowSurface::metric(PaintDeviceMetric met) const +{ + return QX11PaintEngine::metric(window(), met); +} diff --git a/src/plugins/platforms/openvglite/qwindowsurface_vglite.h b/src/plugins/platforms/openvglite/qwindowsurface_vglite.h new file mode 100644 index 0000000..59faba8 --- /dev/null +++ b/src/plugins/platforms/openvglite/qwindowsurface_vglite.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 QWINDOWSURFACE_VGLITE_H +#define QWINDOWSURFACE_VGLITE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGui/private/qwindowsurface_p.h> +#include <QtGui/private/qegl_p.h> + +QT_BEGIN_NAMESPACE + +class QVGLiteGraphicsSystem; +class QVGPaintEngine; + +class Q_OPENVG_EXPORT QVGLiteWindowSurface : public QWindowSurface, public QPaintDevice +{ +public: + QVGLiteWindowSurface(QVGLiteGraphicsSystem *gs, QWidget *window); + ~QVGLiteWindowSurface(); + + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void setGeometry(const QRect &rect); + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion ®ion); + void endPaint(const QRegion ®ion); + + QPaintEngine *paintEngine() const; + +protected: + int metric(PaintDeviceMetric metric) const; + +private: + QVGLiteGraphicsSystem *graphicsSystem; + bool isPaintingActive; + mutable QVGPaintEngine *engine; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSURFACE_VGLITE_H diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro new file mode 100644 index 0000000..9688443 --- /dev/null +++ b/src/plugins/platforms/platforms.pro @@ -0,0 +1,14 @@ +TEMPLATE = subdirs +contains(QT_CONFIG, openvg):contains(QT_CONFIG, egl) { + embedded_lite { + SUBDIRS += openvglite + } +} + +embedded_lite { + SUBDIRS += minimal +} + +embedded_lite:x11 { + SUBDIRS += testlite +} diff --git a/src/plugins/platforms/qvfb/main.cpp b/src/plugins/platforms/qvfb/main.cpp new file mode 100644 index 0000000..b28dde8 --- /dev/null +++ b/src/plugins/platforms/qvfb/main.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 <private/qgraphicssystemplugin_p.h> +#include "qgraphicssystem_qvfb.h" +#include <qstringlist.h> + +QT_BEGIN_NAMESPACE + +class QVFbGraphicsSystemPlugin : public QGraphicsSystemPlugin +{ +public: + QStringList keys() const; + QGraphicsSystem *create(const QString&); +}; + +QStringList QVFbGraphicsSystemPlugin::keys() const +{ + QStringList list; + list << "QVFb"; + return list; +} + +QGraphicsSystem* QVFbGraphicsSystemPlugin::create(const QString& system) +{ + if (system.toLower() == "qvfb") + return new QVFbGraphicsSystem; + + return 0; +} + +Q_EXPORT_PLUGIN2(qvfb, QVFbGraphicsSystemPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qvfb/qgraphicssystem_qvfb.cpp b/src/plugins/platforms/qvfb/qgraphicssystem_qvfb.cpp new file mode 100644 index 0000000..19058a6 --- /dev/null +++ b/src/plugins/platforms/qvfb/qgraphicssystem_qvfb.cpp @@ -0,0 +1,434 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 <stdlib.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <private/qcore_unix_p.h> // overrides QT_OPEN + +#include <qvfbhdr.h> +#include <qsocketnotifier.h> + +#include "qgraphicssystem_qvfb.h" +#include "qwindowsurface_qvfb.h" +#include <QtGui/private/qpixmap_raster_p.h> +#include <QtCore/qdebug.h> +#include <QMouseEvent> + +#include <qsocketnotifier.h> +#include <QApplication> +#include <QWindowSystemInterface> + +QT_BEGIN_NAMESPACE + + +class QVFbGraphicsSystemScreenKeyboardHandler : public QObject +{ + Q_OBJECT +public: + QVFbGraphicsSystemScreenKeyboardHandler(); + ~QVFbGraphicsSystemScreenKeyboardHandler(); + +private slots: + void readKeyboardData(); + +private: + int kbdFD; + int kbdIdx; + int kbdBufferLen; + unsigned char *kbdBuffer; + QSocketNotifier *keyNotifier; +}; + +QVFbGraphicsSystemScreenKeyboardHandler::QVFbGraphicsSystemScreenKeyboardHandler() +{ + int displayId = 0; //TODO displayId + const QString keyboardDev = QT_VFB_KEYBOARD_PIPE(displayId); + + + kbdFD = -1; + kbdIdx = 0; + kbdBufferLen = sizeof(QVFbKeyData) * 5; + kbdBuffer = new unsigned char [kbdBufferLen]; + + kbdFD = QT_OPEN(keyboardDev.toLatin1().constData(), O_RDWR | O_NDELAY); + + if (kbdFD == -1) { + perror("QVFbGraphicsSystemScreenKeyboardHandler"); + qWarning("QVFbGraphicsSystemScreenKeyboardHandler: Unable to open device %s", + qPrintable(keyboardDev)); + return; + } + + // Clear pending input + char buf[2]; + while (QT_READ(kbdFD, buf, 1) > 0) { } + + keyNotifier = new QSocketNotifier(kbdFD, QSocketNotifier::Read, this); + connect(keyNotifier, SIGNAL(activated(int)),this, SLOT(readKeyboardData())); + +} + +QVFbGraphicsSystemScreenKeyboardHandler::~QVFbGraphicsSystemScreenKeyboardHandler() +{ + if (kbdFD >= 0) + QT_CLOSE(kbdFD); + delete [] kbdBuffer; +} + + +void QVFbGraphicsSystemScreenKeyboardHandler::readKeyboardData() +{ + int n; + do { + n = QT_READ(kbdFD, kbdBuffer+kbdIdx, kbdBufferLen - kbdIdx); + if (n > 0) + kbdIdx += n; + } while (n > 0); + + int idx = 0; + while (kbdIdx - idx >= (int)sizeof(QVFbKeyData)) { + QVFbKeyData *kd = (QVFbKeyData *)(kbdBuffer + idx); + if (kd->unicode == 0 && kd->keycode == 0 && kd->modifiers == 0 && kd->press) { + // magic exit key + qWarning("Instructed to quit by Virtual Keyboard"); + qApp->quit(); + } + + //QWSServer::processKeyEvent(kd->unicode ? kd->unicode : 0xffff, kd->keycode, kd->modifiers, kd->press, kd->repeat); + + QEvent::Type type = kd->press ? QEvent::KeyPress : QEvent::KeyRelease; + + QString text; + if (kd->unicode && kd->unicode != 0xffff) + text += QChar(kd->unicode); + +// qDebug() << "readKeyboardData" << type << hex << kd->keycode << kd->modifiers << text; + + QWindowSystemInterface::handleKeyEvent(0, type, kd->keycode, kd->modifiers, text, kd->repeat, int(text.length())); + idx += sizeof(QVFbKeyData); + } + + int surplus = kbdIdx - idx; + for (int i = 0; i < surplus; i++) + kbdBuffer[i] = kbdBuffer[idx+i]; + kbdIdx = surplus; +} + + + + +class QVFbGraphicsSystemScreenMouseHandler : public QObject +{ + Q_OBJECT +public: + QVFbGraphicsSystemScreenMouseHandler(); + ~QVFbGraphicsSystemScreenMouseHandler(); + +private slots: + void readMouseData(); + +private: + int mouseFD; + int mouseIdx; + enum {mouseBufSize = 128}; + uchar mouseBuf[mouseBufSize]; + QSocketNotifier *mouseNotifier; + + int oldButtonState; +}; + +QVFbGraphicsSystemScreenMouseHandler::QVFbGraphicsSystemScreenMouseHandler() +{ + int displayId = 0; //TODO: displayId + QString mouseDev = QT_VFB_MOUSE_PIPE(displayId); + + mouseFD = QT_OPEN(mouseDev.toLatin1().constData(), O_RDWR | O_NDELAY); + + if (mouseFD == -1) { + perror("QVFbMouseHandler::QVFbMouseHandler"); + qWarning("QVFbMouseHander: Unable to open device %s", + qPrintable(mouseDev)); + return; + } + + // Clear pending input + char buf[2]; + while (QT_READ(mouseFD, buf, 1) > 0) { } + + mouseIdx = 0; + oldButtonState = 0; + mouseNotifier = new QSocketNotifier(mouseFD, QSocketNotifier::Read, this); + connect(mouseNotifier, SIGNAL(activated(int)),this, SLOT(readMouseData())); +} + + +QVFbGraphicsSystemScreenMouseHandler::~QVFbGraphicsSystemScreenMouseHandler() +{ + if (mouseFD >= 0) + QT_CLOSE(mouseFD); +} + +void QVFbGraphicsSystemScreenMouseHandler::readMouseData() +{ + int n; + do { + n = QT_READ(mouseFD, mouseBuf+mouseIdx, mouseBufSize-mouseIdx); + if (n > 0) + mouseIdx += n; + } while (n > 0); + + int idx = 0; + static const int packetsize = sizeof(QPoint) + 2*sizeof(int); + while (mouseIdx-idx >= packetsize) { + uchar *mb = mouseBuf+idx; + QPoint mousePos = *reinterpret_cast<QPoint *>(mb); + mb += sizeof(QPoint); + int bstate = *reinterpret_cast<int *>(mb); + mb += sizeof(int); + int wheel = *reinterpret_cast<int *>(mb); + + int button = bstate ^ oldButtonState; + QEvent::Type type = QEvent::MouseMove; + + if (button) { + type = (button & bstate) ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease; + } + QWindowSystemInterface::handleMouseEvent(0, mousePos, mousePos, Qt::MouseButtons(bstate)); + +// qDebug() << "readMouseData" << mousePos << button << bstate << oldButtonState << type; + + oldButtonState = bstate; + + idx += packetsize; + } + + int surplus = mouseIdx - idx; + for (int i = 0; i < surplus; i++) + mouseBuf[i] = mouseBuf[idx+i]; + mouseIdx = surplus; + +} + + +class QVFbGraphicsSystemScreenPrivate +{ +public: + QVFbGraphicsSystemScreenPrivate(QVFbGraphicsSystemScreen *) + : shmrgn(0), hdr(0), data(0), mouseHandler(0), keyboardHandler(0) + { + connect(0); //for now we only handle one screen + } + + ~QVFbGraphicsSystemScreenPrivate() { disconnect(); } + void setDirty(const QRect &r); + + bool connect(int displayId); + void disconnect(); + + QImage *screenImage() { return &img; } + QSize screenSize() { return img.size(); } + + int depth() const { return img.depth(); } + QImage::Format format() const { return img.format(); } + +private: + unsigned char *shmrgn; + QVFbHeader *hdr; + uchar *data; + QVFbGraphicsSystemScreenMouseHandler *mouseHandler; + QVFbGraphicsSystemScreenKeyboardHandler *keyboardHandler; + + + QImage img; +}; + + +void QVFbGraphicsSystemScreenPrivate::setDirty(const QRect &r) +{ + hdr->dirty = true; + hdr->update = hdr->update.united(r); +} + + +bool QVFbGraphicsSystemScreenPrivate::connect(int displayId) +{ + + key_t key = ftok(QT_VFB_MOUSE_PIPE(displayId).toLatin1(), 'b'); + + if (key == -1) + return false; + + + int shmId = shmget(key, 0, 0); + if (shmId != -1) + shmrgn = (unsigned char *)shmat(shmId, 0, 0); + else + return false; + + if ((long)shmrgn == -1 || shmrgn == 0) { + qDebug("No shmrgn %ld", (long)shmrgn); + return false; + } + + hdr = (QVFbHeader *)shmrgn; + data = shmrgn + hdr->dataoffset; + + int w = hdr->width; + int h = hdr->height; + int d = hdr->depth; + int lstep = hdr->linestep; + + QImage::Format format = QImage::Format_Invalid; + if (d == 32) + format = QImage::Format_ARGB32_Premultiplied; + else if (d == 16) + format = QImage::Format_RGB16; + + + if (format == QImage::Format_Invalid) { + img = QImage(); + return false; + } + + img = QImage(data, w, h, lstep, format); + + qDebug("connected %dx%d %d bpp", w, h, d); + + + mouseHandler = new QVFbGraphicsSystemScreenMouseHandler; + keyboardHandler = new QVFbGraphicsSystemScreenKeyboardHandler; + return true; +} + +void QVFbGraphicsSystemScreenPrivate::disconnect() +{ + if ((long)shmrgn != -1 && shmrgn) { + shmdt((char*)shmrgn); + shmrgn = 0; + } + delete mouseHandler; + mouseHandler = 0; + delete keyboardHandler; + keyboardHandler = 0; +} + + +QVFbGraphicsSystemScreen::QVFbGraphicsSystemScreen() +{ + d_ptr = new QVFbGraphicsSystemScreenPrivate(this); +} + + +QVFbGraphicsSystemScreen::~QVFbGraphicsSystemScreen() +{ + delete d_ptr; +} + +void QVFbGraphicsSystemScreen::setDirty(const QRect &rect) +{ + d_ptr->setDirty(rect); +} + + + +QRect QVFbGraphicsSystemScreen::geometry() const { + return QRect(QPoint(), d_ptr->screenSize()); +} + + +int QVFbGraphicsSystemScreen::depth() const +{ + return d_ptr->depth(); +} + +QImage::Format QVFbGraphicsSystemScreen::format() const +{ + return d_ptr->format(); +} + +QSize QVFbGraphicsSystemScreen::physicalSize() const { + return (d_ptr->screenSize()*254)/720; +} + +#if 0 +int QVFbGraphicsSystemScreen::linestep() const { + return d_ptr->screenImage() ? d_ptr->screenImage()->bytesPerLine() : 0; +} + +uchar *QVFbGraphicsSystemScreen::base() const { + return d_ptr->screenImage() ? d_ptr->screenImage()->bits() : 0; +} +#endif + +QImage *QVFbGraphicsSystemScreen::screenImage() +{ + return d_ptr->screenImage(); +} + +QVFbGraphicsSystem::QVFbGraphicsSystem() +{ + mPrimaryScreen = new QVFbGraphicsSystemScreen(); + + mScreens.append(mPrimaryScreen); +} + +QPixmapData *QVFbGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +{ + return new QRasterPixmapData(type); +} + +QWindowSurface *QVFbGraphicsSystem::createWindowSurface(QWidget *widget) const +{ + if (widget->windowType() == Qt::Desktop) + return 0; // Don't create an explicit window surface for the destkop. + return new QVFbWindowSurface + (const_cast<QVFbGraphicsSystem *>(this), mPrimaryScreen, widget); +} + +QT_END_NAMESPACE + +#include "qgraphicssystem_qvfb.moc" diff --git a/src/plugins/platforms/qvfb/qgraphicssystem_qvfb.h b/src/plugins/platforms/qvfb/qgraphicssystem_qvfb.h new file mode 100644 index 0000000..b31869c --- /dev/null +++ b/src/plugins/platforms/qvfb/qgraphicssystem_qvfb.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 QGRAPHICSSYSTEM_QVFB_H +#define QGRAPHICSSYSTEM_QVFB_H + +#include <QtGui/private/qgraphicssystem_p.h> + +QT_BEGIN_NAMESPACE + + +class QVFbGraphicsSystemScreenPrivate; + +class QVFbGraphicsSystemScreen : public QGraphicsSystemScreen +{ +public: + QVFbGraphicsSystemScreen(); + ~QVFbGraphicsSystemScreen(); + + QRect geometry() const; + int depth() const; + QImage::Format format() const; + QSize physicalSize() const; + + QImage *screenImage(); + + void setDirty(const QRect &rect); + +public: + + QVFbGraphicsSystemScreenPrivate *d_ptr; +}; + +class QVFbGraphicsSystemPrivate; + + +class QVFbGraphicsSystem : public QGraphicsSystem +{ +public: + QVFbGraphicsSystem(); + + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QWindowSurface *createWindowSurface(QWidget *widget) const; + + QList<QGraphicsSystemScreen *> screens() const { return mScreens; } + +private: + QVFbGraphicsSystemScreen *mPrimaryScreen; + QList<QGraphicsSystemScreen *> mScreens; +}; + + + +QT_END_NAMESPACE + + +#endif diff --git a/src/plugins/platforms/qvfb/qvfb.pro b/src/plugins/platforms/qvfb/qvfb.pro new file mode 100644 index 0000000..b321725 --- /dev/null +++ b/src/plugins/platforms/qvfb/qvfb.pro @@ -0,0 +1,12 @@ +TARGET = qvfbgraphicssystem +include(../../qpluginbase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems + + + +SOURCES = main.cpp qgraphicssystem_qvfb.cpp qwindowsurface_qvfb.cpp +HEADERS = qgraphicssystem_qvfb.h qwindowsurface_qvfb.h + +target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems +INSTALLS += target diff --git a/src/plugins/platforms/qvfb/qwindowsurface_qvfb.cpp b/src/plugins/platforms/qvfb/qwindowsurface_qvfb.cpp new file mode 100644 index 0000000..0aafe28 --- /dev/null +++ b/src/plugins/platforms/qvfb/qwindowsurface_qvfb.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 "qwindowsurface_qvfb.h" +#include "qgraphicssystem_qvfb.h" +#include <QtCore/qdebug.h> +#include <QtGui/qpainter.h> +#include <private/qapplication_p.h> + +QT_BEGIN_NAMESPACE + +QVFbWindowSurface::QVFbWindowSurface(QVFbGraphicsSystem *graphicsSystem, + QVFbGraphicsSystemScreen *screen, QWidget *window) + : QWindowSurface(window), + mScreen(screen) +{ +} + +QVFbWindowSurface::~QVFbWindowSurface() +{ +} + +QPaintDevice *QVFbWindowSurface::paintDevice() +{ + return mScreen->screenImage(); +} + +void QVFbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(widget); + Q_UNUSED(offset); + + QRect rect = geometry(); + QPoint topLeft = rect.topLeft(); + + mScreen->setDirty(region.boundingRect()); +} + +void QVFbWindowSurface::setGeometry(const QRect &) +{ + +// any size you like as long as it's full-screen... + + QRect rect(mScreen->availableGeometry()); + QWindowSystemInterface::handleGeometryChange(this->window(), rect); + + QWindowSurface::setGeometry(rect); +} + +bool QVFbWindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + return QWindowSurface::scroll(area, dx, dy); +} + +void QVFbWindowSurface::beginPaint(const QRegion ®ion) +{ + Q_UNUSED(region); +} + +void QVFbWindowSurface::endPaint(const QRegion ®ion) +{ + Q_UNUSED(region); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qvfb/qwindowsurface_qvfb.h b/src/plugins/platforms/qvfb/qwindowsurface_qvfb.h new file mode 100644 index 0000000..1971caa --- /dev/null +++ b/src/plugins/platforms/qvfb/qwindowsurface_qvfb.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 QWINDOWSURFACE_QVFB_H +#define QWINDOWSURFACE_QVFB_H + +#include <QtGui/private/qwindowsurface_p.h> + +QT_BEGIN_NAMESPACE + +class QVFbGraphicsSystem; +class QVFbGraphicsSystemScreen; + +class QVFbWindowSurface : public QWindowSurface +{ +public: + QVFbWindowSurface(QVFbGraphicsSystem *graphicsSystem, + QVFbGraphicsSystemScreen *screen, QWidget *window); + ~QVFbWindowSurface(); + + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void setGeometry(const QRect &rect); + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion ®ion); + void endPaint(const QRegion ®ion); + +private: + QVFbGraphicsSystem *mGraphicsSystem; + QVFbGraphicsSystemScreen *mScreen; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/testlite/main.cpp b/src/plugins/platforms/testlite/main.cpp new file mode 100644 index 0000000..28caea7 --- /dev/null +++ b/src/plugins/platforms/testlite/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 <private/qgraphicssystemplugin_p.h> +#include "qgraphicssystem_testlite.h" + +QT_BEGIN_NAMESPACE + +class QTestLiteGraphicsSystemPlugin : public QGraphicsSystemPlugin +{ +public: + QStringList keys() const; + QGraphicsSystem *create(const QString&); +}; + +QStringList QTestLiteGraphicsSystemPlugin::keys() const +{ + QStringList list; + list << "TestLite"; + return list; +} + +QGraphicsSystem* QTestLiteGraphicsSystemPlugin::create(const QString& system) +{ + if (system.toLower() == "testlite") + return new QTestLiteGraphicsSystem; + + return 0; +} + +Q_EXPORT_PLUGIN2(testlite, QTestLiteGraphicsSystemPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/testlite/qgraphicssystem_testlite.cpp b/src/plugins/platforms/testlite/qgraphicssystem_testlite.cpp new file mode 100644 index 0000000..92e0ebc --- /dev/null +++ b/src/plugins/platforms/testlite/qgraphicssystem_testlite.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 "qgraphicssystem_testlite.h" +#include "qwindowsurface_testlite.h" +#include <QtGui/private/qpixmap_raster_p.h> +#include <QtCore/qdebug.h> + +#include <QGraphicsSystemCursor> + + +#include "x11util.h" + +QT_BEGIN_NAMESPACE + +class MyCursor : QGraphicsSystemCursor +{ +public: + MyCursor(QGraphicsSystemScreen *screen) : QGraphicsSystemCursor(screen) {} + + void changeCursor(QCursor * cursor, QWidget * widget) { + QTestLiteWindowSurface *ws = 0; + if (widget) { + QWidget *window = widget->window(); + ws = static_cast<QTestLiteWindowSurface*>(window->windowSurface()); + } else { + // No X11 cursor control when there is no widget under the cursor + return; + } + + //qDebug() << "changeCursor" << widget << ws; + if (!ws) + return; + + ws->setCursor(cursor); + } +}; + + +QTestLiteGraphicsSystem::QTestLiteGraphicsSystem() +{ + + xd = new MyDisplay; + + mPrimaryScreen = new QTestLiteGraphicsSystemScreen(); + + mPrimaryScreen->mGeometry = QRect + (0, 0, xd->width, xd->height); + mPrimaryScreen->mDepth = 32; + mPrimaryScreen->mFormat = QImage::Format_RGB32; + mPrimaryScreen->mPhysicalSize = + QSize(xd->physicalWidth, xd->physicalHeight); + + mScreens.append(mPrimaryScreen); + + + (void)new MyCursor(mPrimaryScreen); + +} + +QPixmapData *QTestLiteGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +{ + return new QRasterPixmapData(type); +} + +QWindowSurface *QTestLiteGraphicsSystem::createWindowSurface(QWidget *widget) const +{ + if (widget->windowType() == Qt::Desktop) + return 0; // Don't create an explicit window surface for the destkop. + return new QTestLiteWindowSurface + (const_cast<QTestLiteGraphicsSystem *>(this), mPrimaryScreen, widget); +} + + +QPixmap QTestLiteGraphicsSystem::grabWindow(WId window, int x, int y, int width, int height) const +{ + QImage img = xd->grabWindow(window, x, y, width, height); + return QPixmap::fromImage(img); +} + + + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/testlite/qgraphicssystem_testlite.h b/src/plugins/platforms/testlite/qgraphicssystem_testlite.h new file mode 100644 index 0000000..b2cd496 --- /dev/null +++ b/src/plugins/platforms/testlite/qgraphicssystem_testlite.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 QGRAPHICSSYSTEM_TESTLITE_H +#define QGRAPHICSSYSTEM_TESTLITE_H + +#include <QtGui/private/qgraphicssystem_p.h> + +QT_BEGIN_NAMESPACE + +class MyDisplay; + +class QTestLiteGraphicsSystemScreen : public QGraphicsSystemScreen +{ +public: + QTestLiteGraphicsSystemScreen() + : mDepth(16), mFormat(QImage::Format_RGB16) {} + ~QTestLiteGraphicsSystemScreen() {} + + QRect geometry() const { return mGeometry; } + int depth() const { return mDepth; } + QImage::Format format() const { return mFormat; } + QSize physicalSize() const { return mPhysicalSize; } + +public: + QRect mGeometry; + int mDepth; + QImage::Format mFormat; + QSize mPhysicalSize; +}; + +class QTestLiteGraphicsSystem : public QGraphicsSystem +{ +public: + QTestLiteGraphicsSystem(); + + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QWindowSurface *createWindowSurface(QWidget *widget) const; + + QPixmap grabWindow(WId window, int x, int y, int width, int height) const; + + QList<QGraphicsSystemScreen *> screens() const { return mScreens; } + + MyDisplay *xd; + +private: + QTestLiteGraphicsSystemScreen *mPrimaryScreen; + QList<QGraphicsSystemScreen *> mScreens; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/testlite/qwindowsurface_testlite.cpp b/src/plugins/platforms/testlite/qwindowsurface_testlite.cpp new file mode 100644 index 0000000..c54f6eb --- /dev/null +++ b/src/plugins/platforms/testlite/qwindowsurface_testlite.cpp @@ -0,0 +1,661 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 "qwindowsurface_testlite.h" +#include "qgraphicssystem_testlite.h" + +#include <QtCore/qdebug.h> +#include <QWindowSystemInterface> + +#include "x11util.h" + +QT_BEGIN_NAMESPACE + +QTestLiteWindowSurface::QTestLiteWindowSurface + (QTestLiteGraphicsSystem *graphicsSystem, + QTestLiteGraphicsSystemScreen *screen, QWidget *window) + : QWindowSurface(window), + mGraphicsSystem(graphicsSystem), + mScreen(screen), + xw(0) +{ + + + xw = new MyWindow(graphicsSystem->xd, 0,0,300,300); + xw->windowSurface = this; + +// qDebug() << "QTestLiteWindowSurface::QTestLiteWindowSurface:" << xw->window; + + setWindowFlags(window->windowFlags()); //##### This should not be the plugin's responsibility +} + +QTestLiteWindowSurface::~QTestLiteWindowSurface() +{ +// qDebug() << "~QTestLiteWindowSurface" << xw->window; + delete xw; +} + +QPaintDevice *QTestLiteWindowSurface::paintDevice() +{ + return xw->image(); +} + +void QTestLiteWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(widget); + Q_UNUSED(region); + Q_UNUSED(offset); + + // qDebug() << "QTestLiteWindowSurface::flush:" << (long)this; + + xw->paintEvent(); +} + + +void QTestLiteWindowSurface::setGeometry(const QRect &rect) +{ + QRect oldRect = geometry(); + if (rect == oldRect) + return; + + QWindowSurface::setGeometry(rect); + + //if unchanged ### +// xw->setSize(rect.width(), rect.height()); + xw->setGeometry(rect.x(), rect.y(), rect.width(), rect.height()); +} + +//### scroll logic copied from QRasterWindowSurface, we should make better API for this + +void copied_qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset) +{ + // make sure we don't detach + uchar *mem = const_cast<uchar*>(const_cast<const QImage &>(img).bits()); + + int lineskip = img.bytesPerLine(); + int depth = img.depth() >> 3; + + const QRect imageRect(0, 0, img.width(), img.height()); + const QRect r = rect & imageRect & imageRect.translated(-offset); + const QPoint p = rect.topLeft() + offset; + + if (r.isEmpty()) + return; + + const uchar *src; + uchar *dest; + + if (r.top() < p.y()) { + src = mem + r.bottom() * lineskip + r.left() * depth; + dest = mem + (p.y() + r.height() - 1) * lineskip + p.x() * depth; + lineskip = -lineskip; + } else { + src = mem + r.top() * lineskip + r.left() * depth; + dest = mem + p.y() * lineskip + p.x() * depth; + } + + const int w = r.width(); + int h = r.height(); + const int bytes = w * depth; + + // overlapping segments? + if (offset.y() == 0 && qAbs(offset.x()) < w) { + do { + ::memmove(dest, src, bytes); + dest += lineskip; + src += lineskip; + } while (--h); + } else { + do { + ::memcpy(dest, src, bytes); + dest += lineskip; + src += lineskip; + } while (--h); + } +} + +bool QTestLiteWindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + if (!xw->image() || xw->image()->isNull()) + return false; + + const QVector<QRect> rects = area.rects(); + for (int i = 0; i < rects.size(); ++i) + copied_qt_scrollRectInImage(*xw->image(), rects.at(i), QPoint(dx, dy)); + + return true; +} + + +void QTestLiteWindowSurface::beginPaint(const QRegion ®ion) +{ + Q_UNUSED(region); + xw->resizeBuffer(geometry().size()); +} + +void QTestLiteWindowSurface::endPaint(const QRegion ®ion) +{ + Q_UNUSED(region); + xw->painted = true; //there is content in the buffer +} + + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Mouse event stuff + + + + +static Qt::MouseButtons translateMouseButtons(int s) +{ + Qt::MouseButtons ret = 0; + if (s & Button1Mask) + ret |= Qt::LeftButton; + if (s & Button2Mask) + ret |= Qt::MidButton; + if (s & Button3Mask) + ret |= Qt::RightButton; + return ret; +} + + +static Qt::KeyboardModifiers translateModifiers(int s) +{ + const uchar qt_alt_mask = Mod1Mask; + const uchar qt_meta_mask = Mod4Mask; + + + Qt::KeyboardModifiers ret = 0; + if (s & ShiftMask) + ret |= Qt::ShiftModifier; + if (s & ControlMask) + ret |= Qt::ControlModifier; + if (s & qt_alt_mask) + ret |= Qt::AltModifier; + if (s & qt_meta_mask) + ret |= Qt::MetaModifier; +#if 0 + if (s & qt_mode_switch_mask) + ret |= Qt::GroupSwitchModifier; +#endif + return ret; +} + +void QTestLiteWindowSurface::handleMouseEvent(QEvent::Type type, void *ev) +{ + static QPoint mousePoint; + + XButtonEvent *e = static_cast<XButtonEvent*>(ev); + + Qt::MouseButton button = Qt::NoButton; + Qt::MouseButtons buttons = translateMouseButtons(e->state); + Qt::KeyboardModifiers modifiers = translateModifiers(e->state); + if (type != QEvent::MouseMove) { + switch (e->button) { + case Button1: button = Qt::LeftButton; break; + case Button2: button = Qt::MidButton; break; + case Button3: button = Qt::RightButton; break; + case Button4: + case Button5: + case 6: + case 7: { + //mouse wheel + if (type == QEvent::MouseButtonPress) { + //logic borrowed from qapplication_x11.cpp + int delta = 120 * ((e->button == Button4 || e->button == 6) ? 1 : -1); + bool hor = (((e->button == Button4 || e->button == Button5) + && (modifiers & Qt::AltModifier)) + || (e->button == 6 || e->button == 7)); + QWindowSystemInterface::handleWheelEvent(window(), e->time, + QPoint(e->x, e->y), + QPoint(e->x_root, e->y_root), + delta, hor ? Qt::Horizontal : Qt::Vertical); + } + return; + } + default: break; + } + } + + buttons ^= button; // X event uses state *before*, Qt uses state *after* + + QWindowSystemInterface::handleMouseEvent(window(), e->time, QPoint(e->x, e->y), + QPoint(e->x_root, e->y_root), + buttons); + + mousePoint = QPoint(e->x_root, e->y_root); +} + +void QTestLiteWindowSurface::handleGeometryChange(int x, int y, int w, int h) +{ + QWindowSystemInterface::handleGeometryChange(window(), QRect(x,y,w,h)); +} + + +void QTestLiteWindowSurface::handleCloseEvent() +{ + QWindowSystemInterface::handleCloseEvent(window()); +} + + +void QTestLiteWindowSurface::handleEnterEvent() +{ + QWindowSystemInterface::handleEnterEvent(window()); +} + +void QTestLiteWindowSurface::handleLeaveEvent() +{ + QWindowSystemInterface::handleLeaveEvent(window()); +} + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Key event stuff -- not pretty either +// +// What we want to do is to port Robert's keytable code properly + + + + + + + +// keyboard mapping table +static const unsigned int keyTbl[] = { + + // misc keys + + XK_Escape, Qt::Key_Escape, + XK_Tab, Qt::Key_Tab, + XK_ISO_Left_Tab, Qt::Key_Backtab, + XK_BackSpace, Qt::Key_Backspace, + XK_Return, Qt::Key_Return, + XK_Insert, Qt::Key_Insert, + XK_Delete, Qt::Key_Delete, + XK_Clear, Qt::Key_Delete, + XK_Pause, Qt::Key_Pause, + XK_Print, Qt::Key_Print, + 0x1005FF60, Qt::Key_SysReq, // hardcoded Sun SysReq + 0x1007ff00, Qt::Key_SysReq, // hardcoded X386 SysReq + + // cursor movement + + XK_Home, Qt::Key_Home, + XK_End, Qt::Key_End, + XK_Left, Qt::Key_Left, + XK_Up, Qt::Key_Up, + XK_Right, Qt::Key_Right, + XK_Down, Qt::Key_Down, + XK_Prior, Qt::Key_PageUp, + XK_Next, Qt::Key_PageDown, + + // modifiers + + XK_Shift_L, Qt::Key_Shift, + XK_Shift_R, Qt::Key_Shift, + XK_Shift_Lock, Qt::Key_Shift, + XK_Control_L, Qt::Key_Control, + XK_Control_R, Qt::Key_Control, + XK_Meta_L, Qt::Key_Meta, + XK_Meta_R, Qt::Key_Meta, + XK_Alt_L, Qt::Key_Alt, + XK_Alt_R, Qt::Key_Alt, + XK_Caps_Lock, Qt::Key_CapsLock, + XK_Num_Lock, Qt::Key_NumLock, + XK_Scroll_Lock, Qt::Key_ScrollLock, + XK_Super_L, Qt::Key_Super_L, + XK_Super_R, Qt::Key_Super_R, + XK_Menu, Qt::Key_Menu, + XK_Hyper_L, Qt::Key_Hyper_L, + XK_Hyper_R, Qt::Key_Hyper_R, + XK_Help, Qt::Key_Help, + 0x1000FF74, Qt::Key_Backtab, // hardcoded HP backtab + 0x1005FF10, Qt::Key_F11, // hardcoded Sun F36 (labeled F11) + 0x1005FF11, Qt::Key_F12, // hardcoded Sun F37 (labeled F12) + + // numeric and function keypad keys + + XK_KP_Space, Qt::Key_Space, + XK_KP_Tab, Qt::Key_Tab, + XK_KP_Enter, Qt::Key_Enter, + //XK_KP_F1, Qt::Key_F1, + //XK_KP_F2, Qt::Key_F2, + //XK_KP_F3, Qt::Key_F3, + //XK_KP_F4, Qt::Key_F4, + XK_KP_Home, Qt::Key_Home, + XK_KP_Left, Qt::Key_Left, + XK_KP_Up, Qt::Key_Up, + XK_KP_Right, Qt::Key_Right, + XK_KP_Down, Qt::Key_Down, + XK_KP_Prior, Qt::Key_PageUp, + XK_KP_Next, Qt::Key_PageDown, + XK_KP_End, Qt::Key_End, + XK_KP_Begin, Qt::Key_Clear, + XK_KP_Insert, Qt::Key_Insert, + XK_KP_Delete, Qt::Key_Delete, + XK_KP_Equal, Qt::Key_Equal, + XK_KP_Multiply, Qt::Key_Asterisk, + XK_KP_Add, Qt::Key_Plus, + XK_KP_Separator, Qt::Key_Comma, + XK_KP_Subtract, Qt::Key_Minus, + XK_KP_Decimal, Qt::Key_Period, + XK_KP_Divide, Qt::Key_Slash, + + // International input method support keys + + // International & multi-key character composition + XK_ISO_Level3_Shift, Qt::Key_AltGr, + XK_Multi_key, Qt::Key_Multi_key, + XK_Codeinput, Qt::Key_Codeinput, + XK_SingleCandidate, Qt::Key_SingleCandidate, + XK_MultipleCandidate, Qt::Key_MultipleCandidate, + XK_PreviousCandidate, Qt::Key_PreviousCandidate, + + // Misc Functions + XK_Mode_switch, Qt::Key_Mode_switch, + XK_script_switch, Qt::Key_Mode_switch, + + // Japanese keyboard support + XK_Kanji, Qt::Key_Kanji, + XK_Muhenkan, Qt::Key_Muhenkan, + //XK_Henkan_Mode, Qt::Key_Henkan_Mode, + XK_Henkan_Mode, Qt::Key_Henkan, + XK_Henkan, Qt::Key_Henkan, + XK_Romaji, Qt::Key_Romaji, + XK_Hiragana, Qt::Key_Hiragana, + XK_Katakana, Qt::Key_Katakana, + XK_Hiragana_Katakana, Qt::Key_Hiragana_Katakana, + XK_Zenkaku, Qt::Key_Zenkaku, + XK_Hankaku, Qt::Key_Hankaku, + XK_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku, + XK_Touroku, Qt::Key_Touroku, + XK_Massyo, Qt::Key_Massyo, + XK_Kana_Lock, Qt::Key_Kana_Lock, + XK_Kana_Shift, Qt::Key_Kana_Shift, + XK_Eisu_Shift, Qt::Key_Eisu_Shift, + XK_Eisu_toggle, Qt::Key_Eisu_toggle, + //XK_Kanji_Bangou, Qt::Key_Kanji_Bangou, + //XK_Zen_Koho, Qt::Key_Zen_Koho, + //XK_Mae_Koho, Qt::Key_Mae_Koho, + XK_Kanji_Bangou, Qt::Key_Codeinput, + XK_Zen_Koho, Qt::Key_MultipleCandidate, + XK_Mae_Koho, Qt::Key_PreviousCandidate, + +#ifdef XK_KOREAN + // Korean keyboard support + XK_Hangul, Qt::Key_Hangul, + XK_Hangul_Start, Qt::Key_Hangul_Start, + XK_Hangul_End, Qt::Key_Hangul_End, + XK_Hangul_Hanja, Qt::Key_Hangul_Hanja, + XK_Hangul_Jamo, Qt::Key_Hangul_Jamo, + XK_Hangul_Romaja, Qt::Key_Hangul_Romaja, + //XK_Hangul_Codeinput, Qt::Key_Hangul_Codeinput, + XK_Hangul_Codeinput, Qt::Key_Codeinput, + XK_Hangul_Jeonja, Qt::Key_Hangul_Jeonja, + XK_Hangul_Banja, Qt::Key_Hangul_Banja, + XK_Hangul_PreHanja, Qt::Key_Hangul_PreHanja, + XK_Hangul_PostHanja, Qt::Key_Hangul_PostHanja, + //XK_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate, + //XK_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate, + //XK_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate, + XK_Hangul_SingleCandidate, Qt::Key_SingleCandidate, + XK_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate, + XK_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate, + XK_Hangul_Special, Qt::Key_Hangul_Special, + //XK_Hangul_switch, Qt::Key_Hangul_switch, + XK_Hangul_switch, Qt::Key_Mode_switch, +#endif // XK_KOREAN + + // dead keys + XK_dead_grave, Qt::Key_Dead_Grave, + XK_dead_acute, Qt::Key_Dead_Acute, + XK_dead_circumflex, Qt::Key_Dead_Circumflex, + XK_dead_tilde, Qt::Key_Dead_Tilde, + XK_dead_macron, Qt::Key_Dead_Macron, + XK_dead_breve, Qt::Key_Dead_Breve, + XK_dead_abovedot, Qt::Key_Dead_Abovedot, + XK_dead_diaeresis, Qt::Key_Dead_Diaeresis, + XK_dead_abovering, Qt::Key_Dead_Abovering, + XK_dead_doubleacute, Qt::Key_Dead_Doubleacute, + XK_dead_caron, Qt::Key_Dead_Caron, + XK_dead_cedilla, Qt::Key_Dead_Cedilla, + XK_dead_ogonek, Qt::Key_Dead_Ogonek, + XK_dead_iota, Qt::Key_Dead_Iota, + XK_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound, + XK_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound, + XK_dead_belowdot, Qt::Key_Dead_Belowdot, + XK_dead_hook, Qt::Key_Dead_Hook, + XK_dead_horn, Qt::Key_Dead_Horn, + +#if 0 + // Special multimedia keys + // currently only tested with MS internet keyboard + + // browsing keys + XF86XK_Back, Qt::Key_Back, + XF86XK_Forward, Qt::Key_Forward, + XF86XK_Stop, Qt::Key_Stop, + XF86XK_Refresh, Qt::Key_Refresh, + XF86XK_Favorites, Qt::Key_Favorites, + XF86XK_AudioMedia, Qt::Key_LaunchMedia, + XF86XK_OpenURL, Qt::Key_OpenUrl, + XF86XK_HomePage, Qt::Key_HomePage, + XF86XK_Search, Qt::Key_Search, + + // media keys + XF86XK_AudioLowerVolume, Qt::Key_VolumeDown, + XF86XK_AudioMute, Qt::Key_VolumeMute, + XF86XK_AudioRaiseVolume, Qt::Key_VolumeUp, + XF86XK_AudioPlay, Qt::Key_MediaPlay, + XF86XK_AudioStop, Qt::Key_MediaStop, + XF86XK_AudioPrev, Qt::Key_MediaPrevious, + XF86XK_AudioNext, Qt::Key_MediaNext, + XF86XK_AudioRecord, Qt::Key_MediaRecord, + + // launch keys + XF86XK_Mail, Qt::Key_LaunchMail, + XF86XK_MyComputer, Qt::Key_Launch0, + XF86XK_Calculator, Qt::Key_Launch1, + XF86XK_Standby, Qt::Key_Standby, + + XF86XK_Launch0, Qt::Key_Launch2, + XF86XK_Launch1, Qt::Key_Launch3, + XF86XK_Launch2, Qt::Key_Launch4, + XF86XK_Launch3, Qt::Key_Launch5, + XF86XK_Launch4, Qt::Key_Launch6, + XF86XK_Launch5, Qt::Key_Launch7, + XF86XK_Launch6, Qt::Key_Launch8, + XF86XK_Launch7, Qt::Key_Launch9, + XF86XK_Launch8, Qt::Key_LaunchA, + XF86XK_Launch9, Qt::Key_LaunchB, + XF86XK_LaunchA, Qt::Key_LaunchC, + XF86XK_LaunchB, Qt::Key_LaunchD, + XF86XK_LaunchC, Qt::Key_LaunchE, + XF86XK_LaunchD, Qt::Key_LaunchF, +#endif + +#if 0 + // Qtopia keys + QTOPIAXK_Select, Qt::Key_Select, + QTOPIAXK_Yes, Qt::Key_Yes, + QTOPIAXK_No, Qt::Key_No, + QTOPIAXK_Cancel, Qt::Key_Cancel, + QTOPIAXK_Printer, Qt::Key_Printer, + QTOPIAXK_Execute, Qt::Key_Execute, + QTOPIAXK_Sleep, Qt::Key_Sleep, + QTOPIAXK_Play, Qt::Key_Play, + QTOPIAXK_Zoom, Qt::Key_Zoom, + QTOPIAXK_Context1, Qt::Key_Context1, + QTOPIAXK_Context2, Qt::Key_Context2, + QTOPIAXK_Context3, Qt::Key_Context3, + QTOPIAXK_Context4, Qt::Key_Context4, + QTOPIAXK_Call, Qt::Key_Call, + QTOPIAXK_Hangup, Qt::Key_Hangup, + QTOPIAXK_Flip, Qt::Key_Flip, +#endif + 0, 0 +}; + + +static int lookupCode(unsigned int xkeycode) +{ + if (xkeycode >= XK_F1 && xkeycode <= XK_F35) + return Qt::Key_F1 + (int(xkeycode) - XK_F1); + + const unsigned int *p = keyTbl; + while (*p) { + if (*p == xkeycode) + return *++p; + p += 2; + } + + return 0; +} + + +static Qt::KeyboardModifiers modifierFromKeyCode(int qtcode) +{ + switch (qtcode) { + case Qt::Key_Control: + return Qt::ControlModifier; + case Qt::Key_Alt: + return Qt::AltModifier; + case Qt::Key_Shift: + return Qt::ShiftModifier; + case Qt::Key_Meta: + return Qt::MetaModifier; + default: + return Qt::NoModifier; + } +} + +void QTestLiteWindowSurface::handleKeyEvent(QEvent::Type type, void *ev) +{ + XKeyEvent *e = static_cast<XKeyEvent*>(ev); + + KeySym keySym; + QByteArray chars; + chars.resize(513); + + int count = XLookupString(e, chars.data(), chars.size(), &keySym, 0); + +// qDebug() << "QTLWS::handleKeyEvent" << count << hex << "XKeysym:" << keySym; +// if (count) +// qDebug() << hex << int(chars[0]) << "String:" << chars; + + Qt::KeyboardModifiers modifiers = translateModifiers(e->state); + + int qtcode = lookupCode(keySym); +// qDebug() << "lookup: " << hex << keySym << qtcode << "mod" << modifiers; + + //X11 specifies state *before*, Qt expects state *after* the event + + modifiers ^= modifierFromKeyCode(qtcode); + + if (qtcode) { + QWindowSystemInterface::handleKeyEvent(window(), e->time, type, qtcode, modifiers); + } else if (chars[0]) { + int qtcode = chars.toUpper()[0]; //Not exactly right... + if (modifiers & Qt::ControlModifier && qtcode < ' ') + qtcode = chars[0] + '@'; + QWindowSystemInterface::handleKeyEvent(window(), e->time, type, qtcode, modifiers, QString::fromLatin1(chars)); + } else { + qWarning() << "unknown X keycode" << hex << e->keycode << keySym; + } +} + + + +Qt::WindowFlags QTestLiteWindowSurface::setWindowFlags(Qt::WindowFlags flags) +{ + Q_ASSERT(flags & Qt::Window); + + window_flags = flags; + + xw->setWindowFlags(flags); + + return window_flags; + +} + +Qt::WindowFlags QTestLiteWindowSurface::windowFlags() const +{ + return window_flags; +} + +void QTestLiteWindowSurface::setVisible(bool visible) +{ + //qDebug() << "QTestLiteWindowSurface::setVisible" << visible << xw->window; + xw->setVisible(visible); +} + + +WId QTestLiteWindowSurface::winId() const +{ + if (xw) + return (WId) xw->window; + else + return WId(0); +} + +void QTestLiteWindowSurface::raise() +{ + WId window = winId(); + XRaiseWindow(mGraphicsSystem->xd->display, window); +} + +void QTestLiteWindowSurface::lower() +{ + WId window = winId(); + XLowerWindow(mGraphicsSystem->xd->display, window); +} + +void QTestLiteWindowSurface::setWindowTitle(const QString &title) +{ + xw->setWindowTitle(title); +} + +void QTestLiteWindowSurface::setCursor(QCursor *cursor) +{ + xw->setCursor(cursor); +} +QT_END_NAMESPACE diff --git a/src/plugins/platforms/testlite/qwindowsurface_testlite.h b/src/plugins/platforms/testlite/qwindowsurface_testlite.h new file mode 100644 index 0000000..0c4df1a --- /dev/null +++ b/src/plugins/platforms/testlite/qwindowsurface_testlite.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 QWINDOWSURFACE_TESTLITE_H +#define QWINDOWSURFACE_TESTLITE_H + +#include <QtGui/private/qwindowsurface_p.h> +#include <qevent.h> + +QT_BEGIN_NAMESPACE + +class MyWindow; +class QTestLiteGraphicsSystem; +class QTestLiteGraphicsSystemScreen; + +class QTestLiteWindowSurface : public QWindowSurface +{ +public: + QTestLiteWindowSurface + (QTestLiteGraphicsSystem *graphicsSystem, + QTestLiteGraphicsSystemScreen *screen, QWidget *window); + ~QTestLiteWindowSurface(); + + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void setGeometry(const QRect &rect); + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion ®ion); + void endPaint(const QRegion ®ion); + + void handleMouseEvent(QEvent::Type, void *); //forwarding X types is apparently impossible :( + void handleKeyEvent(QEvent::Type, void *); + void handleGeometryChange(int x, int y, int w, int h); + void handleCloseEvent(); + void handleEnterEvent(); + void handleLeaveEvent(); + + Qt::WindowFlags setWindowFlags(Qt::WindowFlags type); + Qt::WindowFlags windowFlags() const; + void setVisible(bool visible); + WId winId() const; + void raise(); + void lower(); + void setWindowTitle(const QString &title); + + void setCursor(QCursor * cursor); + +private: + QTestLiteGraphicsSystem *mGraphicsSystem; + QTestLiteGraphicsSystemScreen *mScreen; + Qt::WindowFlags window_flags; + MyWindow *xw; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/testlite/testlite.pro b/src/plugins/platforms/testlite/testlite.pro new file mode 100644 index 0000000..d483f45 --- /dev/null +++ b/src/plugins/platforms/testlite/testlite.pro @@ -0,0 +1,17 @@ +TARGET = qtestlitegraphicssystem +include(../../qpluginbase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems + +SOURCES = main.cpp qgraphicssystem_testlite.cpp qwindowsurface_testlite.cpp +HEADERS = qgraphicssystem_testlite.h qwindowsurface_testlite.h + + +HEADERS += x11util.h +SOURCES += x11util.cpp + +LIBS += -lX11 -lXext + + +target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems +INSTALLS += target diff --git a/src/plugins/platforms/testlite/x11util.cpp b/src/plugins/platforms/testlite/x11util.cpp new file mode 100644 index 0000000..6d2966f --- /dev/null +++ b/src/plugins/platforms/testlite/x11util.cpp @@ -0,0 +1,1215 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 <QImage> +#include <QSocketNotifier> + +#include <qdebug.h> +#include <QTimer> +#include <QApplication> + +#include "x11util.h" +#include "qwindowsurface_testlite.h" + +#include <stdio.h> +#include <stdlib.h> + + +#include <X11/Xatom.h> + +#include <X11/cursorfont.h> + +# include <sys/ipc.h> +# include <sys/shm.h> +# include <X11/extensions/XShm.h> + + +#include <QBitmap> +#include <QCursor> +#include <QDateTime> +#include <QPixmap> + +//### remove stuff we don't want from qt_x11_p.h +#undef ATOM +#undef X11 + +//#define MYX11_DEBUG + +//#define DONT_USE_MIT_SHM + +static int (*original_x_errhandler)(Display *dpy, XErrorEvent *); +static bool seen_badwindow; + + +static Atom wmProtocolsAtom; +static Atom wmDeleteWindowAtom; + +//### copied from qapplication_x11.cpp + +static int qt_x_errhandler(Display *dpy, XErrorEvent *err) +{ + +qDebug() << "qt_x_errhandler" << err->error_code; + + switch (err->error_code) { + case BadAtom: +#if 0 + if (err->request_code == 20 /* X_GetProperty */ + && (err->resourceid == XA_RESOURCE_MANAGER + || err->resourceid == XA_RGB_DEFAULT_MAP + || err->resourceid == ATOM(_NET_SUPPORTED) + || err->resourceid == ATOM(_NET_SUPPORTING_WM_CHECK) + || err->resourceid == ATOM(KDE_FULL_SESSION) + || err->resourceid == ATOM(KWIN_RUNNING) + || err->resourceid == ATOM(XdndProxy) + || err->resourceid == ATOM(XdndAware)) + + + ) { + // Perhaps we're running under SECURITY reduction? :/ + return 0; + } +#endif + qDebug() << "BadAtom"; + break; + + case BadWindow: + if (err->request_code == 2 /* X_ChangeWindowAttributes */ + || err->request_code == 38 /* X_QueryPointer */) { + for (int i = 0; i < ScreenCount(dpy); ++i) { + if (err->resourceid == RootWindow(dpy, i)) { + // Perhaps we're running under SECURITY reduction? :/ + return 0; + } + } + } + seen_badwindow = true; + if (err->request_code == 25 /* X_SendEvent */) { + for (int i = 0; i < ScreenCount(dpy); ++i) { + if (err->resourceid == RootWindow(dpy, i)) { + // Perhaps we're running under SECURITY reduction? :/ + return 0; + } + } +#if 0 + if (X11->xdndHandleBadwindow()) { + qDebug("xdndHandleBadwindow returned true"); + return 0; + } +#endif + } +#if 0 + if (X11->ignore_badwindow) + return 0; +#endif + break; + + case BadMatch: + if (err->request_code == 42 /* X_SetInputFocus */) + return 0; + break; + + default: +#if 0 //!defined(QT_NO_XINPUT) + if (err->request_code == X11->xinput_major + && err->error_code == (X11->xinput_errorbase + XI_BadDevice) + && err->minor_code == 3 /* X_OpenDevice */) { + return 0; + } +#endif + break; + } + + char errstr[256]; + XGetErrorText( dpy, err->error_code, errstr, 256 ); + char buffer[256]; + char request_str[256]; + qsnprintf(buffer, 256, "%d", err->request_code); + XGetErrorDatabaseText(dpy, "XRequest", buffer, "", request_str, 256); + if (err->request_code < 128) { + // X error for a normal protocol request + qWarning( "X Error: %s %d\n" + " Major opcode: %d (%s)\n" + " Resource id: 0x%lx", + errstr, err->error_code, + err->request_code, + request_str, + err->resourceid ); + } else { + // X error for an extension request + const char *extensionName = 0; +#if 0 + if (err->request_code == X11->xrender_major) + extensionName = "RENDER"; + else if (err->request_code == X11->xrandr_major) + extensionName = "RANDR"; + else if (err->request_code == X11->xinput_major) + extensionName = "XInputExtension"; + else if (err->request_code == X11->mitshm_major) + extensionName = "MIT-SHM"; +#endif + char minor_str[256]; + if (extensionName) { + qsnprintf(buffer, 256, "%s.%d", extensionName, err->minor_code); + XGetErrorDatabaseText(dpy, "XRequest", buffer, "", minor_str, 256); + } else { + extensionName = "Uknown extension"; + qsnprintf(minor_str, 256, "Unknown request"); + } + qWarning( "X Error: %s %d\n" + " Extension: %d (%s)\n" + " Minor opcode: %d (%s)\n" + " Resource id: 0x%lx", + errstr, err->error_code, + err->request_code, + extensionName, + err->minor_code, + minor_str, + err->resourceid ); + } + + // ### we really should distinguish between severe, non-severe and + // ### application specific errors + + return 0; +} + + + + + + + + + +bool MyDisplay::handleEvent(XEvent *xe) +{ + //qDebug() << "handleEvent" << xe->xany.type << xe->xany.window; + int quit = false; + MyWindow *xw = 0; + foreach (MyWindow *w, windowList) { + if (w->window == xe->xany.window) { + xw = w; + break; + } + } + if (!xw) { +#ifdef MYX11_DEBUG + qWarning() << "Unknown window" << hex << xe->xany.window << "received event" << xe->type; +#endif + return quit; + } + + switch (xe->type) { + + case ClientMessage: + if (xe->xclient.format == 32 && xe->xclient.message_type == wmProtocolsAtom) { + Atom a = xe->xclient.data.l[0]; + if (a == wmDeleteWindowAtom) + xw->closeEvent(); +#ifdef MYX11_DEBUG + qDebug() << "ClientMessage WM_PROTOCOLS" << a; +#endif + } +#ifdef MYX11_DEBUG + else + qDebug() << "ClientMessage" << xe->xclient.format << xe->xclient.message_type; +#endif + break; + + case Expose: + if (xw) + if (xe->xexpose.count == 0) + xw->paintEvent(); + break; + case ConfigureNotify: + if (xw) + xw->resizeEvent(&xe->xconfigure); + break; + + case ButtonPress: + xw->mousePressEvent(&xe->xbutton); + break; + + case ButtonRelease: + xw->mouseReleaseEvent(&xe->xbutton); + break; + + case MotionNotify: + xw->mouseMoveEvent(&xe->xbutton); + break; + + case XKeyPress: + xw->keyPressEvent(&xe->xkey); + break; + + case XKeyRelease: + xw->keyReleaseEvent(&xe->xkey); + break; + + case EnterNotify: + xw->enterEvent(&xe->xcrossing); + break; + + case LeaveNotify: + xw->leaveEvent(&xe->xcrossing); + break; + + default: +#ifdef MYX11_DEBUG + qDebug() << hex << xe->xany.window << "Other X event" << xe->type; +#endif + break; + } + return quit; +}; + + + +MyDisplay::MyDisplay() +{ + char *display_name = getenv("DISPLAY"); + display = XOpenDisplay(display_name); + if (!display) { + fprintf(stderr, "Cannot connect to X server: %s\n", + display_name); + exit(1); + } + +#ifndef DONT_USE_MIT_SHM + Status MIT_SHM_extension_supported = XShmQueryExtension (display); + Q_ASSERT(MIT_SHM_extension_supported == True); +#endif + original_x_errhandler = XSetErrorHandler(qt_x_errhandler); + + if (qgetenv("DO_X_SYNCHRONIZE").toInt()) + XSynchronize(display, true); + + screen = DefaultScreen(display); + width = DisplayWidth(display, screen); + height = DisplayHeight(display, screen); + physicalWidth = DisplayWidthMM(display, screen); + physicalHeight = DisplayHeightMM(display, screen); + + int xSocketNumber = XConnectionNumber(display); +#ifdef MYX11_DEBUG + qDebug() << "X socket:"<< xSocketNumber; +#endif + QSocketNotifier *sock = new QSocketNotifier(xSocketNumber, QSocketNotifier::Read, this); + connect(sock, SIGNAL(activated(int)), this, SLOT(eventDispatcher())); + + wmProtocolsAtom = XInternAtom (display, "WM_PROTOCOLS", False); + wmDeleteWindowAtom = XInternAtom (display, "WM_DELETE_WINDOW", False); + + cursors = new MyX11Cursors(display); +} + + +MyDisplay::~MyDisplay() +{ + XCloseDisplay(display); +} + + +void MyDisplay::eventDispatcher() +{ +// qDebug() << "eventDispatcher"; + + + ulong marker = XNextRequest(display); +// int i = 0; + while (XPending(display)) { + XEvent event; + XNextEvent(display, &event); + /* done = */ + handleEvent(&event); + + if (event.xany.serial >= marker) { +#ifdef MYX11_DEBUG + qDebug() << "potential livelock averted"; +#endif +#if 0 + if (XEventsQueued(display, QueuedAfterFlush)) { + qDebug() << " with events queued"; + QTimer::singleShot(0, this, SLOT(eventDispatcher())); + } +#endif + break; + } + } +} + + +QImage MyDisplay::grabWindow(Window window, int x, int y, int w, int h) +{ + if (w == 0 || h ==0) + return QImage(); + + //WinId 0 means the desktop widget + if (!window) + window = rootWindow(); + + XWindowAttributes window_attr; + if (!XGetWindowAttributes(display, window, &window_attr)) + return QImage(); + + if (w < 0) + w = window_attr.width - x; + if (h < 0) + h = window_attr.height - y; + + // Ideally, we should also limit ourselves to the screen area, but the Qt docs say + // that it's "unsafe" to go outside the screen, so we can ignore that problem. + + //We're definitely not optimizing for speed... + XImage *xi = XGetImage(display, window, x, y, w, h, AllPlanes, ZPixmap); + + if (!xi) + return QImage(); + + //taking a copy to make sure we have ownership -- not fast + QImage result = QImage( (uchar*) xi->data, xi->width, xi->height, xi->bytes_per_line, QImage::Format_RGB32 ).copy(); + + XDestroyImage(xi); + + return result; +} + + + + +struct MyShmImageInfo { + MyShmImageInfo(Display *xdisplay) : image(0), display(xdisplay) {} + ~MyShmImageInfo() { destroy(); } + + void destroy(); + + XShmSegmentInfo shminfo; + XImage *image; + Display *display; +}; + +MyWindow::MyWindow(MyDisplay *display, int x, int y, int w, int h) +{ + xd = display; + + xd->windowList.append(this); + + window = XCreateSimpleWindow(xd->display, xd->rootWindow(), + x, y, w, h, 0 /*border_width*/, + xd->blackPixel(), xd->whitePixel()); + + +#ifdef MYX11_DEBUG + qDebug() << "MyWindow::MyWindow" << hex << window; +#endif + + + width = -1; + height = -1; + xpos = -1; + ypos = -1; + + XSetWindowBackgroundPixmap(xd->display, window, XNone); + + XSelectInput(xd->display, window, ExposureMask | KeyPressMask | KeyReleaseMask | + EnterWindowMask | LeaveWindowMask | FocusChangeMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | + StructureNotifyMask); + + gc = createGC(); + + XChangeProperty (xd->display, window, + wmProtocolsAtom, + XA_ATOM, 32, PropModeAppend, + (unsigned char *) &wmDeleteWindowAtom, 1); + + + setWindowTitle(QLatin1String("Qt Lighthouse")); + + currentCursor = -1; + + image_info = 0; + painted = false; +} + + +void MyWindow::setWindowTitle(const QString &title) + +{ + QByteArray ba = title.toLatin1(); //We're not making a general solution here... + XTextProperty windowName; + windowName.value = (unsigned char *)ba.constData(); + windowName.encoding = XA_STRING; + windowName.format = 8; + windowName.nitems = ba.length(); + + XSetWMName(xd->display, window, &windowName); +} + +MyWindow::~MyWindow() +{ +#ifdef MYX11_DEBUG + qDebug() << "~MyWindow" << hex << window; +#endif + XFreeGC(xd->display, gc); + XDestroyWindow(xd->display, window); + + xd->windowList.removeAll(this); + + delete image_info; +} + +GC MyWindow::createGC() +{ + GC gc; + + gc = XCreateGC(xd->display, window, 0, 0); + if (gc < 0) { + qWarning("MyWindow::createGC() could not create GC"); + } + return gc; +} + +void MyWindow::closeEvent() +{ + windowSurface->handleCloseEvent(); +} + +void MyWindow::paintEvent() +{ +#ifdef MYX11_DEBUG + qDebug() << "MyWindow::paintEvent" << shm_img.size() << painted; +#endif + if (!painted) + return; + +#ifdef DONT_USE_MIT_SHM + // just convert the image every time... + if (!shm_img.isNull()) { + Visual *visual = DefaultVisual(xd->display, xd->screen); + + QImage image = shm_img; + //img.convertToFormat( + XImage *xi = XCreateImage(xd->display, visual, 24, ZPixmap, + 0, (char *) image.scanLine(0), image.width(), image.height(), + 32, image.bytesPerLine()); + + int x = 0; + int y = 0; + + /*int r =*/ XPutImage(xd->display, window, gc, xi, 0, 0, x, y, image.width(), image.height()); + + xi->data = 0; // QImage owns these bits + XDestroyImage(xi); + } +#else + // Use MIT_SHM + if (image_info->image) { + //qDebug() << "Here we go" << image_info->image->width << image_info->image->height; + int x = 0; + int y = 0; + + // We could set send_event to true, and then use the ShmCompletion to synchronize, + // but let's do like Qt/11 and just use XSync + XShmPutImage (xd->display, window, gc, image_info->image, 0, 0, + x, y, image_info->image->width, image_info->image->height, + /*send_event*/ False); + + XSync(xd->display, False); + } +#endif +} + +#ifndef DONT_USE_MIT_SHM +void MyShmImageInfo::destroy() +{ + XShmDetach (display, &shminfo); + XDestroyImage (image); + shmdt (shminfo.shmaddr); + shmctl (shminfo.shmid, IPC_RMID, 0); +} +#endif + +void MyWindow::resizeShmImage(int width, int height) +{ +#ifdef DONT_USE_MIT_SHM + shm_img = QImage(width, height, QImage::Format_RGB32); +#else + if (image_info) + image_info->destroy(); + else + image_info = new MyShmImageInfo(xd->display); + + Visual *visual = DefaultVisual(xd->display, xd->screen); + + + XImage *image = XShmCreateImage (xd->display, visual, 24, ZPixmap, 0, + &image_info->shminfo, width, height); + + + image_info->shminfo.shmid = shmget (IPC_PRIVATE, + image->bytes_per_line * image->height, IPC_CREAT|0777); + + image_info->shminfo.shmaddr = image->data = (char*)shmat (image_info->shminfo.shmid, 0, 0); + image_info->shminfo.readOnly = False; + + image_info->image = image; + + Status shm_attach_status = XShmAttach(xd->display, &image_info->shminfo); + + Q_ASSERT(shm_attach_status == True); + + shm_img = QImage( (uchar*) image->data, image->width, image->height, image->bytes_per_line, QImage::Format_RGB32 ); +#endif + painted = false; +} + + +void MyWindow::resizeBuffer(QSize s) +{ + if (shm_img.size() != s) + resizeShmImage(s.width(), s.height()); +} + +QSize MyWindow::bufferSize() const +{ + return shm_img.size(); +} + + +void MyWindow::resizeEvent(XConfigureEvent *e) +{ + + if ((e->width != width || e->height != height) && e->x == 0 && e->y == 0) { + //qDebug() << "resize with bogus pos" << e->x << e->y << e->width << e->height << "window"<< hex << window; + } else { + //qDebug() << "geometry change" << e->x << e->y << e->width << e->height << "window"<< hex << window; + xpos = e->x; + ypos = e->y; + } + width = e->width; + height = e->height; + +#ifdef MYX11_DEBUG + qDebug() << hex << window << dec << "ConfigureNotify" << e->x << e->y << e->width << e->height << "geometry" << xpos << ypos << width << height << "img:" << shm_img.size(); +#endif + + windowSurface->handleGeometryChange(xpos, ypos, width, height); +} + +#if 0 +void MyWindow::setSize(int w, int h) +{ + XResizeWindow(xd->display, window, w, h); +} +#endif + +void MyWindow::setGeometry(int x, int y, int w, int h) +{ +#ifdef MYX11_DEBUG + qDebug() << "MyWindow::setGeometry" << hex << window << dec << x << y << w << h << "img:" << shm_img.size(); +#endif + XMoveResizeWindow(xd->display, window, x, y, w, h); +} + + +void MyWindow::enterEvent(XCrossingEvent *) +{ +#ifdef MYX11_DEBUG + qDebug() << "MyWindow::enterEvent" << hex << window; +#endif + windowSurface->handleEnterEvent(); +} + +void MyWindow::leaveEvent(XCrossingEvent *) +{ +#ifdef MYX11_DEBUG + qDebug() << "MyWindow::enterEvent" << hex << window; +#endif + windowSurface->handleLeaveEvent(); +} + +void MyWindow::mousePressEvent(XButtonEvent *e) +{ + static long prevTime = 0; + static Window prevWindow; + static int prevX = -999; + static int prevY = -999; + + QEvent::Type type = QEvent::MouseButtonPress; + + if (e->window == prevWindow && long(e->time) - prevTime < QApplication::doubleClickInterval() + && qAbs(e->x - prevX) < 5 && qAbs(e->y - prevY) < 5) { + type = QEvent::MouseButtonDblClick; + prevTime = e->time - QApplication::doubleClickInterval(); //no double click next time + } else { + prevTime = e->time; + } + prevWindow = e->window; + prevX = e->x; + prevY = e->y; + + windowSurface->handleMouseEvent(type, e); +} + +void MyWindow::mouseReleaseEvent(XButtonEvent *e) +{ + windowSurface->handleMouseEvent(QEvent::MouseButtonRelease, e); +} + +void MyWindow::mouseMoveEvent(XButtonEvent *e) +{ + windowSurface->handleMouseEvent(QEvent::MouseMove, e); +} + +#ifdef KeyPress +#undef KeyPress +#endif + +void MyWindow::keyPressEvent(XKeyEvent *e) +{ + windowSurface->handleKeyEvent(QEvent::KeyPress, e); +} + +#ifdef KeyRelease +#undef KeyRelease +#endif + +void MyWindow::keyReleaseEvent(XKeyEvent *e) +{ + windowSurface->handleKeyEvent(QEvent::KeyRelease, e); +} + + +// WindowFlag stuff, lots of copied code from qwidget_x11.cpp... + +//We're hacking here... + + +// MWM support +struct QtMWMHints { + ulong flags, functions, decorations; + long input_mode; + ulong status; +}; + +enum { + MWM_HINTS_FUNCTIONS = (1L << 0), + + MWM_FUNC_ALL = (1L << 0), + MWM_FUNC_RESIZE = (1L << 1), + MWM_FUNC_MOVE = (1L << 2), + MWM_FUNC_MINIMIZE = (1L << 3), + MWM_FUNC_MAXIMIZE = (1L << 4), + MWM_FUNC_CLOSE = (1L << 5), + + MWM_HINTS_DECORATIONS = (1L << 1), + + MWM_DECOR_ALL = (1L << 0), + MWM_DECOR_BORDER = (1L << 1), + MWM_DECOR_RESIZEH = (1L << 2), + MWM_DECOR_TITLE = (1L << 3), + MWM_DECOR_MENU = (1L << 4), + MWM_DECOR_MINIMIZE = (1L << 5), + MWM_DECOR_MAXIMIZE = (1L << 6), + + MWM_HINTS_INPUT_MODE = (1L << 2), + + MWM_INPUT_MODELESS = 0L, + MWM_INPUT_PRIMARY_APPLICATION_MODAL = 1L, + MWM_INPUT_FULL_APPLICATION_MODAL = 3L +}; + +static Atom mwm_hint_atom = XNone; + +static QtMWMHints GetMWMHints(Display *display, Window window) +{ + QtMWMHints mwmhints; + + Atom type; + int format; + ulong nitems, bytesLeft; + uchar *data = 0; + if ((XGetWindowProperty(display, window, mwm_hint_atom, 0, 5, false, + mwm_hint_atom, &type, &format, &nitems, &bytesLeft, + &data) == Success) + && (type == mwm_hint_atom + && format == 32 + && nitems >= 5)) { + mwmhints = *(reinterpret_cast<QtMWMHints *>(data)); + } else { + mwmhints.flags = 0L; + mwmhints.functions = MWM_FUNC_ALL; + mwmhints.decorations = MWM_DECOR_ALL; + mwmhints.input_mode = 0L; + mwmhints.status = 0L; + } + + if (data) + XFree(data); + + return mwmhints; +} + +static void SetMWMHints(Display *display, Window window, const QtMWMHints &mwmhints) +{ + if (mwmhints.flags != 0l) { + XChangeProperty(display, window, mwm_hint_atom, mwm_hint_atom, 32, + PropModeReplace, (unsigned char *) &mwmhints, 5); + } else { + XDeleteProperty(display, window, mwm_hint_atom); + } +} + +// Returns true if we should set WM_TRANSIENT_FOR on \a w +static inline bool isTransient(const QWidget *w) +{ + return ((w->windowType() == Qt::Dialog + || w->windowType() == Qt::Sheet + || w->windowType() == Qt::Tool + || w->windowType() == Qt::SplashScreen + || w->windowType() == Qt::ToolTip + || w->windowType() == Qt::Drawer + || w->windowType() == Qt::Popup) + && !w->testAttribute(Qt::WA_X11BypassTransientForHint)); +} + + + +Qt::WindowFlags MyWindow::setWindowFlags(Qt::WindowFlags flags) +{ + + if (mwm_hint_atom == XNone) { + mwm_hint_atom = XInternAtom(xd->display, "_MOTIF_WM_HINTS\0", False); + } + +#ifdef MYX11_DEBUG + qDebug() << "MyWindow::setWindowFlags" << hex << window << "flags" << flags; +#endif + Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); + + if (type == Qt::ToolTip) + flags |= Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint; + if (type == Qt::Popup) + flags |= Qt::X11BypassWindowManagerHint; + + bool topLevel = (flags & Qt::Window); + bool popup = (type == Qt::Popup); + bool dialog = (type == Qt::Dialog + || type == Qt::Sheet); + bool desktop = (type == Qt::Desktop); + bool tool = (type == Qt::Tool || type == Qt::SplashScreen + || type == Qt::ToolTip || type == Qt::Drawer); + + bool tooltip = (type == Qt::ToolTip); + + XSetWindowAttributes wsa; + + QtMWMHints mwmhints; + mwmhints.flags = 0L; + mwmhints.functions = 0L; + mwmhints.decorations = 0; + mwmhints.input_mode = 0L; + mwmhints.status = 0L; + + + ulong wsa_mask = 0; + if (type != Qt::SplashScreen) { // && customize) { + mwmhints.flags |= MWM_HINTS_DECORATIONS; + + bool customize = flags & Qt::CustomizeWindowHint; + if (!(flags & Qt::FramelessWindowHint) && !(customize && !(flags & Qt::WindowTitleHint))) { + mwmhints.decorations |= MWM_DECOR_BORDER; + mwmhints.decorations |= MWM_DECOR_RESIZEH; + + if (flags & Qt::WindowTitleHint) + mwmhints.decorations |= MWM_DECOR_TITLE; + + if (flags & Qt::WindowSystemMenuHint) + mwmhints.decorations |= MWM_DECOR_MENU; + + if (flags & Qt::WindowMinimizeButtonHint) { + mwmhints.decorations |= MWM_DECOR_MINIMIZE; + mwmhints.functions |= MWM_FUNC_MINIMIZE; + } + + if (flags & Qt::WindowMaximizeButtonHint) { + mwmhints.decorations |= MWM_DECOR_MAXIMIZE; + mwmhints.functions |= MWM_FUNC_MAXIMIZE; + } + + if (flags & Qt::WindowCloseButtonHint) + mwmhints.functions |= MWM_FUNC_CLOSE; + } + } else { + // if type == Qt::SplashScreen + mwmhints.decorations = MWM_DECOR_ALL; + } + + if (tool) { + wsa.save_under = True; + wsa_mask |= CWSaveUnder; + } + + if (flags & Qt::X11BypassWindowManagerHint) { + wsa.override_redirect = True; + wsa_mask |= CWOverrideRedirect; + } +#if 0 + if (wsa_mask && initializeWindow) { + Q_ASSERT(id); + XChangeWindowAttributes(dpy, id, wsa_mask, &wsa); + } +#endif + if (mwmhints.functions != 0) { + mwmhints.flags |= MWM_HINTS_FUNCTIONS; + mwmhints.functions |= MWM_FUNC_MOVE | MWM_FUNC_RESIZE; + } else { + mwmhints.functions = MWM_FUNC_ALL; + } + + if (!(flags & Qt::FramelessWindowHint) + && flags & Qt::CustomizeWindowHint + && flags & Qt::WindowTitleHint + && !(flags & + (Qt::WindowMinimizeButtonHint + | Qt::WindowMaximizeButtonHint + | Qt::WindowCloseButtonHint))) { + // a special case - only the titlebar without any button + mwmhints.flags = MWM_HINTS_FUNCTIONS; + mwmhints.functions = MWM_FUNC_MOVE | MWM_FUNC_RESIZE; + mwmhints.decorations = 0; + } + + SetMWMHints(xd->display, window, mwmhints); + +//##### only if initializeWindow??? + + if (popup || tooltip) { // popup widget +#ifdef MYX11_DEBUG + qDebug() << "Doing XChangeWindowAttributes for popup" << wsa.override_redirect; +#endif + // set EWMH window types + // setNetWmWindowTypes(); + + wsa.override_redirect = True; + wsa.save_under = True; + XChangeWindowAttributes(xd->display, window, CWOverrideRedirect | CWSaveUnder, + &wsa); + } else { +#ifdef MYX11_DEBUG + qDebug() << "Doing XChangeWindowAttributes for non-popup"; +#endif + } + + return flags; +} + +void MyWindow::setVisible(bool visible) +{ +#ifdef MYX11_DEBUG + qDebug() << "MyWindow::setVisible" << visible << hex << window; +#endif + if (visible) + XMapWindow(xd->display, window); + else + XUnmapWindow(xd->display, window); +} + +MyX11Cursors::MyX11Cursors(Display * d) : firstExpired(0), lastExpired(0), display(d), removalDelay(3) +{ + connect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); +} + +void MyX11Cursors::insertNode(MyX11CursorNode * node) +{ + QDateTime now = QDateTime::currentDateTime(); + QDateTime timeout = now.addSecs(removalDelay); + node->setExpiration(timeout); + node->setPost(0); + if (lastExpired) { + lastExpired->setPost(node); + node->setAnte(lastExpired); + } + lastExpired = node; + if (!firstExpired) { + firstExpired = node; + node->setAnte(0); + int interval = removalDelay * 1000; + timer.setInterval(interval); + timer.start(); + } +} + +void MyX11Cursors::removeNode(MyX11CursorNode * node) +{ + MyX11CursorNode *pre = node->ante(); + MyX11CursorNode *post = node->post(); + if (pre) + pre->setPost(post); + if (post) + post->setAnte(pre); + if (node == lastExpired) + lastExpired = pre; + if (node == firstExpired) { + firstExpired = post; + if (!firstExpired) { + timer.stop(); + return; + } + int interval = QDateTime::currentDateTime().secsTo(firstExpired->expiration()) * 1000; + timer.stop(); + timer.setInterval(interval); + timer.start(); + } +} + +void MyX11Cursors::incrementUseCount(int id) +{ + MyX11CursorNode * node = lookupMap.value(id); + Q_ASSERT(node); + if (!node->refCount) + removeNode(node); + node->refCount++; +} + +void MyX11Cursors::decrementUseCount(int id) +{ + MyX11CursorNode * node = lookupMap.value(id); + Q_ASSERT(node); + node->refCount--; + if (!node->refCount) + insertNode(node); +} + +void MyX11Cursors::createNode(int id, Cursor c) +{ + MyX11CursorNode * node = new MyX11CursorNode(id, c); + lookupMap.insert(id, node); +} + +void MyX11Cursors::timeout() +{ + MyX11CursorNode * node; + node = firstExpired; + QDateTime now = QDateTime::currentDateTime(); + while (node && now.secsTo(node->expiration()) < 1) { + Cursor c = node->cursor(); + int id = node->id(); + lookupMap.take(id); + MyX11CursorNode * tmp = node; + node = node->post(); + delete tmp; + XFreeCursor(display, c); + } + firstExpired = node; + if (node == 0) { + timer.stop(); + lastExpired = 0; + } + else { + int interval = QDateTime::currentDateTime().secsTo(firstExpired->expiration()) * 1000; + timer.setInterval(interval); + timer.start(); + } +} + +Cursor MyX11Cursors::cursor(int id) +{ + MyX11CursorNode * node = lookupMap.value(id); + Q_ASSERT(node); + return node->cursor(); +} + +void MyWindow::setCursor(QCursor * cursor) +{ + int id = cursor->handle(); + if (id == currentCursor) + return; + Cursor c; + if (!xd->cursors->exists(id)) { + if (cursor->shape() == Qt::BitmapCursor) + c = createCursorBitmap(cursor); + else + c = createCursorShape(cursor->shape()); + if (!c) { + return; + } + xd->cursors->createNode(id, c); + } else { + xd->cursors->incrementUseCount(id); + c = xd->cursors->cursor(id); + } + + if (currentCursor != -1) + xd->cursors->decrementUseCount(currentCursor); + currentCursor = id; + + XDefineCursor(xd->display, window, c); + XFlush(xd->display); +} + +Cursor MyWindow::createCursorBitmap(QCursor * cursor) +{ + XColor bg, fg; + bg.red = 255 << 8; + bg.green = 255 << 8; + bg.blue = 255 << 8; + fg.red = 0; + fg.green = 0; + fg.blue = 0; + QPoint spot = cursor->hotSpot(); + Window rootwin = window; + + QImage mapImage = cursor->bitmap()->toImage().convertToFormat(QImage::Format_MonoLSB); + QImage maskImage = cursor->mask()->toImage().convertToFormat(QImage::Format_MonoLSB); + + int width = cursor->bitmap()->width(); + int height = cursor->bitmap()->height(); + int bytesPerLine = mapImage.bytesPerLine(); + int destLineSize = width / 8; + if (width % 8) + destLineSize++; + + const uchar * map = mapImage.bits(); + const uchar * mask = maskImage.bits(); + + char * mapBits = new char[height * destLineSize]; + char * maskBits = new char[height * destLineSize]; + for (int i = 0; i < height; i++) { + memcpy(mapBits + (destLineSize * i),map + (bytesPerLine * i), destLineSize); + memcpy(maskBits + (destLineSize * i),mask + (bytesPerLine * i), destLineSize); + } + + Pixmap cp = XCreateBitmapFromData(xd->display, rootwin, mapBits, width, height); + Pixmap mp = XCreateBitmapFromData(xd->display, rootwin, maskBits, width, height); + Cursor c = XCreatePixmapCursor(xd->display, cp, mp, &fg, &bg, spot.x(), spot.y()); + XFreePixmap(xd->display, cp); + XFreePixmap(xd->display, mp); + delete[] mapBits; + delete[] maskBits; + + return c; +} + +Cursor MyWindow::createCursorShape(int cshape) +{ + Cursor cursor = 0; + + if (cshape < 0 || cshape > Qt::LastCursor) + return 0; + + switch (cshape) { + case Qt::ArrowCursor: + cursor = XCreateFontCursor(xd->display, XC_left_ptr); + break; + case Qt::UpArrowCursor: + cursor = XCreateFontCursor(xd->display, XC_center_ptr); + break; + case Qt::CrossCursor: + cursor = XCreateFontCursor(xd->display, XC_crosshair); + break; + case Qt::WaitCursor: + cursor = XCreateFontCursor(xd->display, XC_watch); + break; + case Qt::IBeamCursor: + cursor = XCreateFontCursor(xd->display, XC_xterm); + break; + case Qt::SizeAllCursor: + cursor = XCreateFontCursor(xd->display, XC_fleur); + break; + case Qt::PointingHandCursor: + cursor = XCreateFontCursor(xd->display, XC_hand2); + break; + case Qt::SizeBDiagCursor: + cursor = XCreateFontCursor(xd->display, XC_top_right_corner); + break; + case Qt::SizeFDiagCursor: + cursor = XCreateFontCursor(xd->display, XC_bottom_right_corner); + break; + case Qt::SizeVerCursor: + case Qt::SplitVCursor: + cursor = XCreateFontCursor(xd->display, XC_sb_v_double_arrow); + break; + case Qt::SizeHorCursor: + case Qt::SplitHCursor: + cursor = XCreateFontCursor(xd->display, XC_sb_h_double_arrow); + break; + case Qt::WhatsThisCursor: + cursor = XCreateFontCursor(xd->display, XC_question_arrow); + break; + case Qt::ForbiddenCursor: + cursor = XCreateFontCursor(xd->display, XC_circle); + break; + case Qt::BusyCursor: + cursor = XCreateFontCursor(xd->display, XC_watch); + break; + + default: //default cursor for all the rest + break; + } + return cursor; +} + + +#if 0 + + + switch (cshape) { // map Q cursor to X cursor + case Qt::BlankCursor: + XColor bg, fg; + bg.red = 255 << 8; + bg.green = 255 << 8; + bg.blue = 255 << 8; + fg.red = 0; + fg.green = 0; + fg.blue = 0; + pm = XCreateBitmapFromData(dpy, rootwin, cur_blank_bits, 16, 16); + pmm = XCreateBitmapFromData(dpy, rootwin, cur_blank_bits, 16, 16); + hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 8, 8); + return; + break; + default: + qWarning("QCursor::update: Invalid cursor shape %d", cshape); + return; + } +#endif diff --git a/src/plugins/platforms/testlite/x11util.h b/src/plugins/platforms/testlite/x11util.h new file mode 100644 index 0000000..79e7461 --- /dev/null +++ b/src/plugins/platforms/testlite/x11util.h @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 MYX11UTIL_H +#define MYX11UTIL_H + +#include <QObject> +#include <QImage> +#include <qtimer.h> +#include <QDateTime> + +#include <private/qt_x11_p.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + + +class MyWindow; +class MyX11Cursors; + +class MyDisplay : public QObject +{ + Q_OBJECT; +public: + MyDisplay(); + ~MyDisplay(); + + Window rootWindow() { return RootWindow(display, screen); } + unsigned long blackPixel() { return BlackPixel(display, screen); } + unsigned long whitePixel() { return WhitePixel(display, screen); } + + bool handleEvent(XEvent *xe); + QImage grabWindow(Window window, int x, int y, int w, int h); + +public slots: + void eventDispatcher(); + +public: //### + Display * display; + int screen; + int width, height; + int physicalWidth; + int physicalHeight; + + QList<MyWindow*> windowList; + + MyX11Cursors * cursors; +}; + +class QTestLiteWindowSurface; //### abstract callback interface, anyone? + +struct MyShmImageInfo; + +class MyWindow : public QObject +{ + Q_OBJECT; +public: + MyWindow(MyDisplay *xd, int x, int y, int w, int h); + ~MyWindow(); + + + void mousePressEvent(XButtonEvent*); + void mouseReleaseEvent(XButtonEvent*); + void mouseMoveEvent(XButtonEvent*); + + void keyPressEvent(XKeyEvent*); + void keyReleaseEvent(XKeyEvent*); + + void enterEvent(XCrossingEvent*); + void leaveEvent(XCrossingEvent*); + + void closeEvent(); + void paintEvent(); + void resizeEvent(XConfigureEvent *configure_event); +// void setSize(int w, int h); + void setGeometry(int x, int y, int w, int h); + + GC createGC(); + + Qt::WindowFlags setWindowFlags(Qt::WindowFlags flags); + void setVisible(bool visible); + void setCursor(QCursor * cursor); + Cursor createCursorShape(int cshape); + Cursor createCursorBitmap(QCursor * cursor); + + void setWindowTitle(const QString &title); + + QImage *image() { return &shm_img; } + +public: //### + + int xpos, ypos; + int width, height; + Window window; + MyDisplay *xd; + GC gc; + + QTestLiteWindowSurface *windowSurface; + + int currentCursor; + bool painted; + void resizeBuffer(QSize); + QSize bufferSize() const; + +private: + void resizeShmImage(int width, int height); + + QImage shm_img; + MyShmImageInfo *image_info; +}; + +class MyX11CursorNode +{ +public: + MyX11CursorNode(int id, Cursor c) { idValue = id; cursorValue = c; refCount = 1; } + QDateTime expiration() { return t; } + void setExpiration(QDateTime val) { t = val; } + MyX11CursorNode * ante() { return before; } + void setAnte(MyX11CursorNode *node) { before = node; } + MyX11CursorNode * post() { return after; } + void setPost(MyX11CursorNode *node) { after = node; } + Cursor cursor() { return cursorValue; } + int id() { return idValue; } + unsigned int refCount; + +private: + MyX11CursorNode *before; + MyX11CursorNode *after; + QDateTime t; + Cursor cursorValue; + int idValue; + + Display * display; +}; + +class MyX11Cursors : public QObject +{ + Q_OBJECT +public: + MyX11Cursors(Display * d); + ~MyX11Cursors() { timer.stop(); } + void incrementUseCount(int id); + void decrementUseCount(int id); + void createNode(int id, Cursor c); + bool exists(int id) { return lookupMap.contains(id); } + Cursor cursor(int id); +public slots: + void timeout(); + +private: + void removeNode(MyX11CursorNode *node); + void insertNode(MyX11CursorNode *node); + + // linked list of cursors currently not assigned to any window + MyX11CursorNode *firstExpired; + MyX11CursorNode *lastExpired; + + QHash<int, MyX11CursorNode *> lookupMap; + QTimer timer; + + Display *display; + + int removalDelay; +}; + +#endif // MYX11UTIL_H diff --git a/src/plugins/platforms/vnc/main.cpp b/src/plugins/platforms/vnc/main.cpp new file mode 100644 index 0000000..f10748a --- /dev/null +++ b/src/plugins/platforms/vnc/main.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 <private/qgraphicssystemplugin_p.h> +#include "qgraphicssystem_vnc.h" +#include <qstringlist.h> + +QT_BEGIN_NAMESPACE + +class QVNCGraphicsSystemPlugin : public QGraphicsSystemPlugin +{ +public: + QStringList keys() const; + QGraphicsSystem *create(const QString&); +}; + +QStringList QVNCGraphicsSystemPlugin::keys() const +{ + QStringList list; + list << "VNC"; + return list; +} + +QGraphicsSystem* QVNCGraphicsSystemPlugin::create(const QString& system) +{ + if (system.toLower() == "vnc") + return new QVNCGraphicsSystem; + + return 0; +} + +Q_EXPORT_PLUGIN2(vnc, QVNCGraphicsSystemPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/vnc/qgraphicssystem_vnc.cpp b/src/plugins/platforms/vnc/qgraphicssystem_vnc.cpp new file mode 100644 index 0000000..7815f24 --- /dev/null +++ b/src/plugins/platforms/vnc/qgraphicssystem_vnc.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 "qgraphicssystem_vnc.h" +#include "../fb_base/fb_base.h" +#include <private/qapplication_p.h> +#include <QtGui/private/qpixmap_raster_p.h> +#include <QtCore/qdebug.h> + +#include <qvncserver.h> +#include <QtGui/QPainter> + +#include <QtCore/QTimer> + + +QVNCGraphicsSystemScreen::QVNCGraphicsSystemScreen() + : QGraphicsSystemFbScreen::QGraphicsSystemFbScreen() +{ + int w = 800; + int h = 600; + int ew, eh; + const char *str; + if ((str=::getenv("QT_VNC_SIZE")) && sscanf(str,"%dx%d",&ew,&eh)==2) { + w = ew; + h = eh; + } + + setGeometry(QRect(0,0,w, h)); + setDepth(32); + setFormat(QImage::Format_RGB32); + setPhysicalSize((geometry().size()*254)/720); + + + d_ptr = new QVNCGraphicsSystemScreenPrivate(this); + + cursor = new QVNCCursor(d_ptr->vncServer, this); + d_ptr->vncServer->setCursor(static_cast<QVNCCursor *>(cursor)); +} + +QVNCDirtyMap *QVNCGraphicsSystemScreen::dirtyMap() +{ + return d_ptr->dirty; +} + +QRegion QVNCGraphicsSystemScreen::doRedraw() +{ + QRegion touched; + touched = QGraphicsSystemFbScreen::doRedraw(); + + QVector<QRect> rects = touched.rects(); + for (int i = 0; i < rects.size(); i++) + d_ptr->setDirty(rects[i]); + return touched; +} + + +QVNCGraphicsSystem::QVNCGraphicsSystem() +{ + mPrimaryScreen = new QVNCGraphicsSystemScreen(); + + mScreens.append(mPrimaryScreen); +} + +QPixmapData *QVNCGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +{ + return new QRasterPixmapData(type); +} + +QWindowSurface *QVNCGraphicsSystem::createWindowSurface(QWidget *widget) const +{ + if (widget->windowType() == Qt::Desktop) + return 0; // Don't create an explicit window surface for the destkop. + QGraphicsSystemFbWindowSurface * surface; + surface = new QGraphicsSystemFbWindowSurface(mPrimaryScreen, widget); + mPrimaryScreen->addWindowSurface(surface); + return surface; +} diff --git a/src/plugins/platforms/vnc/qgraphicssystem_vnc.h b/src/plugins/platforms/vnc/qgraphicssystem_vnc.h new file mode 100644 index 0000000..b3349b7 --- /dev/null +++ b/src/plugins/platforms/vnc/qgraphicssystem_vnc.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 QGRAPHICSSYSTEM_VNC_H +#define QGRAPHICSSYSTEM_VNC_H + +#include <QtGui/private/qgraphicssystem_p.h> +#include "qvnccursor.h" +#include "../fb_base/fb_base.h" + +QT_BEGIN_NAMESPACE + +class QVNCServer; +class QVNCDirtyMap; + +class QVNCGraphicsSystemScreenPrivate; + +class QVNCGraphicsSystemScreen : public QGraphicsSystemFbScreen +{ +public: + QVNCGraphicsSystemScreen(); + + int linestep() const { return image() ? image()->bytesPerLine() : 0; } + uchar *base() const { return image() ? image()->bits() : 0; } + QVNCDirtyMap *dirtyMap(); + +public: + QVNCGraphicsSystemScreenPrivate *d_ptr; + +private: + QVNCServer *server; + QRegion doRedraw(); +}; + +class QVNCGraphicsSystemPrivate; + + +class QVNCGraphicsSystem : public QGraphicsSystem +{ +public: + QVNCGraphicsSystem(); + + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QWindowSurface *createWindowSurface(QWidget *widget) const; + + QList<QGraphicsSystemScreen *> screens() const { return mScreens; } + + +private: + QVNCGraphicsSystemScreen *mPrimaryScreen; + QList<QGraphicsSystemScreen *> mScreens; +}; + + + +QT_END_NAMESPACE + +#endif //QGRAPHICSSYSTEM_VNC_H + diff --git a/src/plugins/platforms/vnc/qvnccursor.cpp b/src/plugins/platforms/vnc/qvnccursor.cpp new file mode 100644 index 0000000..fb214d8 --- /dev/null +++ b/src/plugins/platforms/vnc/qvnccursor.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 <QPainter> +#include <QTcpSocket> +#include <arpa/inet.h> +#include <QBitmap> +#include <QApplication> + +#include <QDebug> + +#include "qvnccursor.h" +#include "qvncserver.h" +#include "qgraphicssystem_vnc.h" + +QT_BEGIN_NAMESPACE + +QVNCCursor::QVNCCursor(QVNCServer * srvr, QVNCGraphicsSystemScreen *scr ) + :QGraphicsSystemSoftwareCursor(scr), useVncCursor(false), server(srvr) +{ +} + +void QVNCCursor::changeCursor(QCursor * widgetCursor, QWidget * widget) +{ + QGraphicsSystemSoftwareCursor::changeCursor(widgetCursor, widget); + if (useVncCursor) { + server->setDirtyCursor(); + } else { + screen->setDirty(QRect(0,0,1,1)); + } +} + +void QVNCCursor::setCursorMode(bool vnc) +{ + if (vnc) { + screen->setDirty(dirtyRect()); + server->setDirtyCursor(); + } else { + server->setDirtyCursor(); + } + useVncCursor = vnc; +} + +QRect QVNCCursor::drawCursor(QPainter & painter) +{ + if (useVncCursor) + return QRect(); + + return QGraphicsSystemSoftwareCursor::drawCursor(painter); +} + +void QVNCCursor::clearClientCursor() +{ + QTcpSocket *socket = server->clientSocket(); + if (!socket) { + return; + } + // FramebufferUpdate header + { + const quint16 tmp[6] = { htons(0), + htons(1), + htons(0), htons(0), + htons(0), + htons(0) }; + socket->write((char*)tmp, sizeof(tmp)); + + const quint32 encoding = htonl(-239); + socket->write((char*)(&encoding), sizeof(encoding)); + } +} + +void QVNCCursor::sendClientCursor() +{ + if (useVncCursor == false) { + clearClientCursor(); + return; + } + QImage *image = graphic->image(); + if (image->isNull()) + return; + QTcpSocket *socket = server->clientSocket(); + if (!socket) { + return; + } + // FramebufferUpdate header + { + const quint16 tmp[6] = { htons(0), + htons(1), + htons(graphic->hotspot().x()), htons(graphic->hotspot().y()), + htons(image->width()), + htons(image->height()) }; + socket->write((char*)tmp, sizeof(tmp)); + + const quint32 encoding = htonl(-239); + socket->write((char*)(&encoding), sizeof(encoding)); + } + + // write pixels + //Q_ASSERT(cursor->hasAlphaChannel()); + const QImage img = image->convertToFormat(QImage::Format_RGB32); + 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 = image->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); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/vnc/qvnccursor.h b/src/plugins/platforms/vnc/qvnccursor.h new file mode 100644 index 0000000..8ea0f45 --- /dev/null +++ b/src/plugins/platforms/vnc/qvnccursor.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module 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 QVNCCURSOR_H +#define QVNCCURSOR_H + +#include "../fb_base/fb_base.h" +#include <QList> +#include <QImage> +#include <QMouseEvent> + +QT_BEGIN_NAMESPACE + +class QVNCGraphicsSystemScreen; +class QVNCServer; + +class QVNCCursor : public QGraphicsSystemSoftwareCursor { +public: + QVNCCursor(QVNCServer *, QVNCGraphicsSystemScreen *); + + // input methods + void setCursorMode(bool vnc); + void changeCursor(QCursor * widgetCursor, QWidget * widget); + + // output methods + QRect drawCursor(QPainter &); + + // VNC client communication + void sendClientCursor(); + void clearClientCursor(); +private: + bool useVncCursor; // VNC or local + + QVNCServer * server; // VNC server to get events from +}; + +QT_END_NAMESPACE + +#endif // QVNCCURSOR_H diff --git a/src/plugins/platforms/vnc/qvncserver.cpp b/src/plugins/platforms/vnc/qvncserver.cpp new file mode 100644 index 0000000..ea576d4 --- /dev/null +++ b/src/plugins/platforms/vnc/qvncserver.cpp @@ -0,0 +1,1935 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 "qvncserver.h" + +#include <QtCore/qtimer.h> +#include <QtCore/qregexp.h> +#include <QtGui/qwidget.h> +#include <QtGui/qpolygon.h> +#include <QtGui/qpainter.h> + +#include <QtGui/qevent.h> +#include <QWindowSystemInterface> + +#include <qplatformdefs.h> + +#include <qdebug.h> + +#include <stdlib.h> + + +#define QT_QWS_VNC_DEBUG +#define QT_NO_QWS_CURSOR //### + + +QT_BEGIN_NAMESPACE + + + +//copied from qscreen_qws.h +#ifndef QT_QWS_DEPTH16_RGB +#define QT_QWS_DEPTH16_RGB 565 +#endif +static const int qt_rbits = (QT_QWS_DEPTH16_RGB/100); +static const int qt_gbits = (QT_QWS_DEPTH16_RGB/10%10); +static const int qt_bbits = (QT_QWS_DEPTH16_RGB%10); +static const int qt_red_shift = qt_bbits+qt_gbits-(8-qt_rbits); +static const int qt_green_shift = qt_bbits-(8-qt_gbits); +static const int qt_neg_blue_shift = 8-qt_bbits; +static const int qt_blue_mask = (1<<qt_bbits)-1; +static const int qt_green_mask = (1<<(qt_gbits+qt_bbits))-(1<<qt_bbits); +static const int qt_red_mask = (1<<(qt_rbits+qt_gbits+qt_bbits))-(1<<(qt_gbits+qt_bbits)); + +static const int qt_red_rounding_shift = qt_red_shift + qt_rbits; +static const int qt_green_rounding_shift = qt_green_shift + qt_gbits; +static const int qt_blue_rounding_shift = qt_bbits - qt_neg_blue_shift; + + +inline QRgb qt_conv16ToRgb(ushort c) +{ + const int r=(c & qt_red_mask); + const int g=(c & qt_green_mask); + const int b=(c & qt_blue_mask); + const int tr = r >> qt_red_shift | r >> qt_red_rounding_shift; + const int tg = g >> qt_green_shift | g >> qt_green_rounding_shift; + const int tb = b << qt_neg_blue_shift | b >> qt_blue_rounding_shift; + + return qRgb(tr,tg,tb); +} + + + +//=========================================================================== + +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 }, + { 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) { + 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 = Qt::NoButton; + wheelDirection = WheelNone; + if (buttonMask & 1) + buttons |= Qt::LeftButton; + if (buttonMask & 2) + buttons |= Qt::MidButton; + if (buttonMask & 4) + buttons |= Qt::RightButton; + if (buttonMask & 8) + wheelDirection = WheelUp; + if (buttonMask & 16) + wheelDirection = WheelDown; + if (buttonMask & 32) + wheelDirection = WheelLeft; + if (buttonMask & 64) + wheelDirection = WheelRight; + + 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(QVNCGraphicsSystemScreen *screen) + : qvnc_screen(screen), cursor(0) +{ + init(5900); +} + +QVNCServer::QVNCServer(QVNCGraphicsSystemScreen *screen, int id) + : qvnc_screen(screen), cursor(0) +{ + init(5900 + id); +} + +void QVNCServer::init(uint port) +{ + qDebug() << "QVNCServer::init" << 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()) +// 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->geometry().width(); + sim.height = qvnc_screen->geometry().height(); + 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 0//Q_BYTE_ORDER == Q_BIG_ENDIAN +bool QVNCGraphicsSystemScreen::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 + }; + + supportCursor = false; + + 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 + } + + if (cursor) + cursor->setCursorMode(supportCursor); +} + +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; + } +} + +static bool buttonChange(Qt::MouseButtons before, Qt::MouseButtons after, Qt::MouseButton *button, bool *isPress) +{ + if (before == after) + return false; + for (int b = Qt::LeftButton; b <= Qt::MidButton; b<<=1) { + if ((before & b) != (after & b)) { + *button = static_cast<Qt::MouseButton>(b); + *isPress = (after & b); + return true; + } + } + return 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); + + + //qDebug() << "pointerEvent" << ev.x << ev.y << hex << ev.buttons; + if (ev.wheelDirection == ev.WheelNone) { + QEvent::Type type = QEvent::MouseMove; + Qt::MouseButton button = Qt::NoButton; + bool isPress; + if (buttonChange(buttons, ev.buttons, &button, &isPress)) + type = isPress ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease; + QWindowSystemInterface::handleMouseEvent(0, QPoint(ev.x, ev.y), QPoint(ev.x, ev.y), ev.buttons); + } else { + // No buttons or motion reported at the same time as wheel events + Qt::Orientation orientation; + if (ev.wheelDirection == ev.WheelLeft || ev.wheelDirection == ev.WheelRight) + orientation = Qt::Horizontal; + else + orientation = Qt::Vertical; + int delta = 120 * ((ev.wheelDirection == ev.WheelLeft || ev.wheelDirection == ev.WheelUp) ? 1 : -1); + QWindowSystemInterface::handleWheelEvent(0, QPoint(ev.x, ev.y), QPoint(ev.x, ev.y), delta, orientation); + } + 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) { +// qDebug() << "keyEvent" << hex << ev.unicode << ev.keycode << keymod << ev.down; + QEvent::Type type = ev.down ? QEvent::KeyPress : QEvent::KeyRelease; + QString str; + if (ev.unicode && ev.unicode != 0xffff) + str = QString(ev.unicode); + QWindowSystemInterface::handleKeyEvent(0, type, ev.keycode, keymod, str); + } + handleMsg = false; + } +} + +void QVNCServer::clientCutText() +{ + QRfbClientCutText ev; + + if (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 = false; //### 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[count - 1] = 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 +#if 0 + case 8: { + QRgb rgb = qvnc_screen->clut()[int(*src)]; + r = qRed(rgb); + g = qGreen(rgb); + b = qBlue(rgb); + src++; + break; + } +#endif +#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(QVNCGraphicsSystemScreen *s) + : bytesPerPixel(0), numDirty(0), screen(s) +{ + bytesPerPixel = (screen->depth() + 7) / 8; + QSize screenSize = screen->geometry().size(); + bufferWidth = screenSize.width(); + bufferHeight = screenSize.height(); + 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); + + QSize screenSize = server->screen()->geometry().size(); + + for (int y = 0; y < map->mapHeight; ++y) { + if (rect.y + MAP_TILE_SIZE > screenSize.height()) + rect.h = screenSize.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 > screenSize.width()) //###deviceWidth ??? + rect.w = screenSize.width() - 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(); + QSize screenSize = server->screen()->geometry().size(); + + // 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, screenSize.width(), + screenSize.height()); + } + 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 qvnc_screen->image(); +} + +void QVNCServer::checkUpdate() +{ + if (!wantUpdate) + return; + + if (dirtyCursor) { +#ifndef QT_NO_QWS_CURSOR + Q_ASSERT(qvnc_cursor); + qvnc_cursor->write(); +#endif + cursor->sendClientCursor(); + 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()) +// QWSServer::instance()->enablePainting(false); +} + + + +QVNCGraphicsSystemScreenPrivate::QVNCGraphicsSystemScreenPrivate(QVNCGraphicsSystemScreen *parent) + : dpiX(72), dpiY(72), doOnScreenSurface(false), refreshRate(25), + vncServer(0), q_ptr(parent) +{ +#if 0//ndef QT_NO_QWS_SIGNALHANDLER + QWSSignalHandler::instance()->addObject(this); +#endif + + vncServer = new QVNCServer(q_ptr); + vncServer->setRefreshRate(refreshRate); + + + Q_ASSERT(q_ptr->depth() == 32); + + dirty = new QVNCDirtyMapOptimized<quint32>(q_ptr); +} + +QVNCGraphicsSystemScreenPrivate::~QVNCGraphicsSystemScreenPrivate() +{ +} + + +void QVNCGraphicsSystemScreenPrivate::setDirty(const QRect& rect, bool force) +{ + if (rect.isEmpty()) + return; + +// if (q_ptr->screen()) +// q_ptr->screen()->setDirty(rect); + + if (!vncServer || !vncServer->isConnected()) { +// qDebug() << "QVNCGraphicsSystemScreenPrivate::setDirty() - Not connected"; + 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(); +} + + + + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/vnc/qvncserver.h b/src/plugins/platforms/vnc/qvncserver.h new file mode 100644 index 0000000..4fcdbae --- /dev/null +++ b/src/plugins/platforms/vnc/qvncserver.h @@ -0,0 +1,534 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 "qgraphicssystem_vnc.h" +#include "qvnccursor.h" +#define QT_NO_QWS_CURSOR + +#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(QVNCGraphicsSystemScreen *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; + QVNCGraphicsSystemScreen *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(QVNCGraphicsSystemScreen *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; + QVNCGraphicsSystemScreen *screen; + uchar *buffer; + int bufferWidth; + int bufferHeight; + int bufferStride; + int numTiles; +}; + +template <class T> +class QVNCDirtyMapOptimized : public QVNCDirtyMap +{ +public: + QVNCDirtyMapOptimized(QVNCGraphicsSystemScreen *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); + + Qt::MouseButtons buttons; + enum { WheelNone, + WheelUp, + WheelDown, + WheelLeft, + WheelRight + } wheelDirection; + quint16 x; + quint16 y; +}; + +class QRfbClientCutText +{ +public: + bool read(QTcpSocket *s); + + quint32 length; +}; + +class QVNCGraphicsSystemScreenPrivate : public QObject +{ +public: + QVNCGraphicsSystemScreenPrivate(QVNCGraphicsSystemScreen *parent); + ~QVNCGraphicsSystemScreenPrivate(); + + 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 + + QVNCGraphicsSystemScreen *q_ptr; +}; + +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(QVNCGraphicsSystemScreen *screen); + QVNCServer(QVNCGraphicsSystemScreen *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 QVNCGraphicsSystemScreen* screen() const { return qvnc_screen; } + inline QVNCDirtyMap* dirtyMap() const { return qvnc_screen->dirtyMap(); } + 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 + + void setCursor(QVNCCursor * c) { cursor = c; } +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(); + void sendInputEvents(); + +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; + Qt::MouseButtons buttons; + 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; + QVNCGraphicsSystemScreen *qvnc_screen; +#ifndef QT_NO_QWS_CURSOR + QVNCClientCursor *qvnc_cursor; +#endif + + QRfbEncoder *encoder; + QVNCCursor *cursor; +}; + + +QT_END_NAMESPACE +#endif // QT_NO_QWS_VNC +#endif // QSCREENVNC_P_H diff --git a/src/plugins/platforms/vnc/vnc.pro b/src/plugins/platforms/vnc/vnc.pro new file mode 100644 index 0000000..0b73b5b --- /dev/null +++ b/src/plugins/platforms/vnc/vnc.pro @@ -0,0 +1,19 @@ +TARGET = qvncgraphicssystem +include(../../qpluginbase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems + +SOURCES = main.cpp qgraphicssystem_vnc.cpp +HEADERS = qgraphicssystem_vnc.h + +HEADERS += qvncserver.h +SOURCES += qvncserver.cpp + +HEADERS += qvnccursor.h +SOURCES += qvnccursor.cpp + +include(../fb_base/fb_base.pri) + +target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems + +INSTALLS += target |