summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/linuxfb
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/linuxfb')
-rw-r--r--src/plugins/platforms/linuxfb/linuxfb.pro13
-rw-r--r--src/plugins/platforms/linuxfb/main.cpp72
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp875
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbintegration.h135
4 files changed, 1095 insertions, 0 deletions
diff --git a/src/plugins/platforms/linuxfb/linuxfb.pro b/src/plugins/platforms/linuxfb/linuxfb.pro
new file mode 100644
index 0000000000..216b899fdb
--- /dev/null
+++ b/src/plugins/platforms/linuxfb/linuxfb.pro
@@ -0,0 +1,13 @@
+TARGET = qlinuxfbgraphicssystem
+include(../../qpluginbase.pri)
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms
+
+SOURCES = main.cpp qlinuxfbintegration.cpp
+HEADERS = qlinuxfbintegration.h
+
+include(../fb_base/fb_base.pri)
+include(../fontdatabases/genericunix/genericunix.pri)
+
+target.path += $$[QT_INSTALL_PLUGINS]/platforms
+INSTALLS += target
diff --git a/src/plugins/platforms/linuxfb/main.cpp b/src/plugins/platforms/linuxfb/main.cpp
new file mode 100644
index 0000000000..fb14ef4d13
--- /dev/null
+++ b/src/plugins/platforms/linuxfb/main.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QPlatformIntegrationPlugin>
+#include "qlinuxfbintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QLinuxFbIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+public:
+ QStringList keys() const;
+ QPlatformIntegration *create(const QString&, const QStringList&);
+};
+
+QStringList QLinuxFbIntegrationPlugin::keys() const
+{
+ QStringList list;
+ list << "LinuxFb";
+ return list;
+}
+
+QPlatformIntegration* QLinuxFbIntegrationPlugin::create(const QString& system, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ if (system.toLower() == "linuxfb")
+ return new QLinuxFbIntegration;
+
+ return 0;
+}
+
+Q_EXPORT_PLUGIN2(linuxfb, QLinuxFbIntegrationPlugin)
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
new file mode 100644
index 0000000000..a088a31d6d
--- /dev/null
+++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
@@ -0,0 +1,875 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlinuxfbintegration.h"
+#include "../fb_base/fb_base.h"
+#include "qgenericunixfontdatabase.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 QLinuxFbIntegrationPrivate
+{
+public:
+ QLinuxFbIntegrationPrivate();
+ ~QLinuxFbIntegrationPrivate();
+
+ 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;
+};
+
+QLinuxFbIntegrationPrivate::QLinuxFbIntegrationPrivate()
+ : fd(-1), blank(true), doGraphicsMode(true),
+#ifdef QT_QWS_DEPTH_GENERIC
+ doGenericColors(false),
+#endif
+ ttyfd(-1), oldKdMode(KD_TEXT)
+{
+}
+
+QLinuxFbIntegrationPrivate::~QLinuxFbIntegrationPrivate()
+{
+ closeTty();
+}
+
+void QLinuxFbIntegrationPrivate::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 QLinuxFbIntegrationPrivate::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;
+}
+
+QLinuxFbIntegration::QLinuxFbIntegration()
+ :fontDb(new QGenericUnixFontDatabase())
+{
+ d_ptr = new QLinuxFbIntegrationPrivate();
+
+ // XXX
+ QString displaySpec = QString::fromLatin1(qgetenv("QWS_DISPLAY"));
+
+ if (!connect(displaySpec))
+ qFatal("QLinuxFbIntegration: 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 QLinuxFbScreen(data, w, h, lstep,
+ screenFormat);
+ mPrimaryScreen->setPhysicalSize(QSize(physWidth, physHeight));
+ mScreens.append(mPrimaryScreen);
+}
+
+QLinuxFbIntegration::~QLinuxFbIntegration()
+{
+ delete mPrimaryScreen;
+ delete d_ptr;
+}
+
+bool QLinuxFbIntegration::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("QLinuxFbIntegration::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("QLinuxFbIntegration::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("QLinuxFbIntegration::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("QLinuxFbIntegration::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("QLinuxFbIntegration::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 QLinuxFbIntegration::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 QLinuxFbIntegration::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 QLinuxFbIntegration::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 QLinuxFbIntegration::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;
+}
+
+bool QLinuxFbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case ThreadedPixmaps: return true;
+ default: return QPlatformIntegration::hasCapability(cap);
+ }
+}
+
+
+QPixmapData *QLinuxFbIntegration::createPixmapData(QPixmapData::PixelType type) const
+{
+ return new QRasterPixmapData(type);
+}
+
+QWindowSurface *QLinuxFbIntegration::createWindowSurface(QWidget *widget, WId) const
+{
+ QFbWindowSurface * surface =
+ new QFbWindowSurface(mPrimaryScreen, widget);
+ return surface;
+}
+
+QPlatformWindow *QLinuxFbIntegration::createPlatformWindow(QWidget *widget, WId /*winId*/) const
+{
+ QFbWindow *w = new QFbWindow(widget);
+ mPrimaryScreen->addWindow(w);
+ return w;
+}
+
+QPlatformFontDatabase *QLinuxFbIntegration::fontDatabase() const
+{
+ return fontDb;
+}
+
+QLinuxFbScreen::QLinuxFbScreen(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 QPlatformSoftwareCursor(this);
+}
+
+void QLinuxFbScreen::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 QLinuxFbScreen::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 QLinuxFbScreen::doRedraw()
+{
+ QRegion touched;
+ touched = QFbScreen::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/qlinuxfbintegration.h b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h
new file mode 100644
index 0000000000..f361843c6f
--- /dev/null
+++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSSYSTEM_LINUXFB_H
+#define QGRAPHICSSYSTEM_LINUXFB_H
+
+#include <QPlatformIntegration>
+#include "../fb_base/fb_base.h"
+
+QT_BEGIN_NAMESPACE
+
+class QLinuxFbScreen : public QFbScreen
+{
+ Q_OBJECT
+public:
+ QLinuxFbScreen(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 QLinuxFbIntegrationPrivate;
+struct fb_cmap;
+struct fb_var_screeninfo;
+struct fb_fix_screeninfo;
+
+class QLinuxFbIntegration : public QPlatformIntegration
+{
+public:
+ QLinuxFbIntegration();
+ ~QLinuxFbIntegration();
+
+ bool hasCapability(QPlatformIntegration::Capability cap) const;
+
+ QPixmapData *createPixmapData(QPixmapData::PixelType type) const;
+ QPlatformWindow *createPlatformWindow(QWidget *widget, WId WinId) const;
+ QWindowSurface *createWindowSurface(QWidget *widget, WId WinId) const;
+
+ QList<QPlatformScreen *> screens() const { return mScreens; }
+
+ QPlatformFontDatabase *fontDatabase() const;
+
+private:
+ QLinuxFbScreen *mPrimaryScreen;
+ QList<QPlatformScreen *> mScreens;
+ QLinuxFbIntegrationPrivate *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);
+ QPlatformFontDatabase *fontDb;
+};
+
+QT_END_NAMESPACE
+
+#endif