linuxfb: Rework screen code
authorGirish Ramakrishnan <girish.1.ramakrishnan@nokia.com>
Fri, 6 Jul 2012 00:10:57 +0000 (05:40 +0530)
committerQt by Nokia <qt-info@nokia.com>
Wed, 11 Jul 2012 10:44:05 +0000 (12:44 +0200)
Move the screen code from integration. The design philosophy
is that QFbScreen takes care of generic framebuffer composition.
QLinuxFbScreen is just an linux framebuffer adaptation layer.

Change-Id: I8456c13826f06621037dd77fe0d0bd8873806c96
Reviewed-by: Thomas Senyk <thomas.senyk@nokia.com>
Reviewed-by: Girish Ramakrishnan <girish.1.ramakrishnan@nokia.com>
src/platformsupport/fbconvenience/qfbscreen.cpp
src/platformsupport/fbconvenience/qfbscreen_p.h
src/plugins/platforms/linuxfb/main.cpp
src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
src/plugins/platforms/linuxfb/qlinuxfbintegration.h
src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
src/plugins/platforms/linuxfb/qlinuxfbscreen.h

index cd45e5c..5d2208a 100644 (file)
 
 QT_BEGIN_NAMESPACE
 
-QFbScreen::QFbScreen() : cursor(0), mGeometry(), mDepth(16), mFormat(QImage::Format_RGB16), mScreenImage(0), compositePainter(0), isUpToDate(false)
+QFbScreen::QFbScreen() : mCursor(0), mGeometry(), mDepth(16), mFormat(QImage::Format_RGB16), mScreenImage(0), mCompositePainter(0), isUpToDate(false)
+{
+}
+
+QFbScreen::~QFbScreen()
+{
+    delete mCompositePainter;
+    delete mScreenImage;
+}
+
+void QFbScreen::initializeCompositor()
 {
     mScreenImage = new QImage(mGeometry.size(), mFormat);
+
     redrawTimer.setSingleShot(true);
     redrawTimer.setInterval(0);
     connect(&redrawTimer, SIGNAL(timeout()), this, SLOT(doRedraw()));
@@ -93,42 +104,6 @@ QWindow *QFbScreen::topLevelAt(const QPoint & p) const
     return 0;
 }
 
-
-void QFbScreen::setGeometry(QRect rect)
-{
-    delete mScreenImage;
-    mGeometry = rect;
-    mScreenImage = new QImage(mGeometry.size(), mFormat);
-    delete compositePainter;
-    compositePainter = 0;
-    invalidateRectCache();
-}
-
-void QFbScreen::setDepth(int depth)
-{
-    mDepth = depth;
-}
-
-void QFbScreen::setPhysicalSize(QSize size)
-{
-    mPhysicalSize = size;
-}
-
-void QFbScreen::setFormat(QImage::Format format)
-{
-    mFormat = format;
-    delete mScreenImage;
-    mScreenImage = new QImage(mGeometry.size(), mFormat);
-    delete compositePainter;
-    compositePainter = 0;
-}
-
-QFbScreen::~QFbScreen()
-{
-    delete compositePainter;
-    delete mScreenImage;
-}
-
 void QFbScreen::setDirty(const QRect &rect)
 {
     QRect intersection = rect.intersected(mGeometry);
@@ -171,18 +146,16 @@ void QFbScreen::generateRects()
     return;
 }
 
-
-
 QRegion QFbScreen::doRedraw()
 {
     QPoint screenOffset = mGeometry.topLeft();
 
     QRegion touchedRegion;
-    if (cursor && cursor->isDirty() && cursor->isOnScreen()) {
-        QRect lastCursor = cursor->dirtyRect();
+    if (mCursor && mCursor->isDirty() && mCursor->isOnScreen()) {
+        QRect lastCursor = mCursor->dirtyRect();
         repaintRegion += lastCursor;
     }
-    if (repaintRegion.isEmpty() && (!cursor || !cursor->isDirty())) {
+    if (repaintRegion.isEmpty() && (!mCursor || !mCursor->isDirty())) {
         return touchedRegion;
     }
 
@@ -191,8 +164,8 @@ QRegion QFbScreen::doRedraw()
     if (!isUpToDate)
         generateRects();
 
-    if (!compositePainter)
-        compositePainter = new QPainter(mScreenImage);
+    if (!mCompositePainter)
+        mCompositePainter = new QPainter(mScreenImage);
     for (int rectIndex = 0; rectIndex < repaintRegion.rectCount(); rectIndex++) {
         QRegion rectRegion = rects[rectIndex];
 
@@ -210,7 +183,7 @@ QRegion QFbScreen::doRedraw()
             foreach (QRect rect, intersect.rects()) {
                 bool firstLayer = true;
                 if (layer == -1) {
-                    compositePainter->fillRect(rect, Qt::black);
+                    mCompositePainter->fillRect(rect, Qt::black);
                     firstLayer = false;
                     layer = windowStack.size() - 1;
                 }
@@ -223,7 +196,7 @@ QRegion QFbScreen::doRedraw()
                     QRect windowRect = windowStack[layerIndex]->geometry().translated(-screenOffset);
                     QRect windowIntersect = rect.translated(-windowRect.left(),
                                                             -windowRect.top());
-                    compositePainter->drawImage(rect, windowStack[layerIndex]->backingStore()->image(),
+                    mCompositePainter->drawImage(rect, windowStack[layerIndex]->backingStore()->image(),
                                                 windowIntersect);
                     if (firstLayer) {
                         firstLayer = false;
@@ -234,8 +207,8 @@ QRegion QFbScreen::doRedraw()
     }
 
     QRect cursorRect;
-    if (cursor && (cursor->isDirty() || repaintRegion.intersects(cursor->lastPainted()))) {
-        cursorRect = cursor->drawCursor(*compositePainter);
+    if (mCursor && (mCursor->isDirty() || repaintRegion.intersects(mCursor->lastPainted()))) {
+        cursorRect = mCursor->drawCursor(*mCompositePainter);
         touchedRegion += cursorRect;
     }
     touchedRegion += repaintRegion;
index 71d8d45..b37d3ad 100644 (file)
@@ -64,32 +64,26 @@ public:
     virtual QImage::Format format() const { return mFormat; }
     virtual QSizeF 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 QWindow *topLevelAt(const QPoint & p) const;
 
+    // compositor api
+    virtual void addWindow(QFbWindow *window);
+    virtual void removeWindow(QFbWindow *window);
+    virtual void raise(QPlatformWindow *window);
+    virtual void lower(QPlatformWindow *window);
     virtual void setDirty(const QRect &rect);
 
-    virtual void removeWindow(QFbWindow * surface);
-    virtual void addWindow(QFbWindow * surface);
-    virtual void raise(QPlatformWindow * surface);
-    virtual void lower(QPlatformWindow * surface);
-    virtual QWindow *topLevelAt(const QPoint & p) const;
-
-    QImage * image() const { return mScreenImage; }
-    QPaintDevice * paintDevice() const { return mScreenImage; }
+protected slots:
+    virtual QRegion doRedraw();
 
 protected:
+    void initializeCompositor();
+
     QList<QFbWindow *> windowStack;
     QRegion repaintRegion;
-    QFbCursor * cursor;
     QTimer redrawTimer;
 
-protected slots:
-    virtual QRegion doRedraw();
-
-protected:
+    QFbCursor *mCursor;
     QRect mGeometry;
     int mDepth;
     QImage::Format mFormat;
@@ -97,11 +91,12 @@ protected:
     QImage *mScreenImage;
 
 private:
-    QPainter *compositePainter;
+    void invalidateRectCache() { isUpToDate = false; }
     void generateRects();
+
+    QPainter *mCompositePainter;
     QList<QPair<QRect, int> > cachedRects;
 
-    void invalidateRectCache() { isUpToDate = false; }
     friend class QFbWindow;
     bool isUpToDate;
 };
index e0348ab..12b68a6 100644 (file)
@@ -56,7 +56,7 @@ QPlatformIntegration* QLinuxFbIntegrationPlugin::create(const QString& system, c
 {
     Q_UNUSED(paramList);
     if (system.toLower() == "linuxfb")
-        return new QLinuxFbIntegration;
+        return new QLinuxFbIntegration(paramList);
 
     return 0;
 }
index cdec49b..057839a 100644 (file)
 #include <QtPlatformSupport/private/qfbwindow_p.h>
 #include <QtPlatformSupport/private/qfbcursor_p.h>
 
+#include <QtGui/private/qguiapplication_p.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.toLatin1().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()
+QLinuxFbIntegration::QLinuxFbIntegration(const QStringList &paramList)
+    : m_fontDb(new QGenericUnixFontDatabase()),
+      m_eventDispatcher(createUnixEventDispatcher())
 {
-    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"));
+    QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher);
 
-    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);
+    m_primaryScreen = new QLinuxFbScreen;
+    if (m_primaryScreen->initialize(paramList))
+        screenAdded(m_primaryScreen);
 }
 
 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;
+    delete m_primaryScreen;
 }
 
 bool QLinuxFbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
@@ -796,7 +77,6 @@ bool QLinuxFbIntegration::hasCapability(QPlatformIntegration::Capability cap) co
     }
 }
 
-
 QPlatformPixmap *QLinuxFbIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const
 {
     return new QRasterPlatformPixmap(type);
@@ -810,18 +90,25 @@ QPlatformBackingStore *QLinuxFbIntegration::createPlatformBackingStore(QWindow *
 QPlatformWindow *QLinuxFbIntegration::createPlatformWindow(QWindow *window) const
 {
     QFbWindow *w = new QFbWindow(window);
-    mPrimaryScreen->addWindow(w);
+    m_primaryScreen->addWindow(w);
     return w;
 }
 
 QAbstractEventDispatcher *QLinuxFbIntegration::guiThreadEventDispatcher() const
 {
-    return createUnixEventDispatcher();
+    return m_eventDispatcher;
+}
+
+QList<QPlatformScreen *> QLinuxFbIntegration::screens() const
+{
+    QList<QPlatformScreen *> list;
+    list.append(m_primaryScreen);
+    return list;
 }
 
 QPlatformFontDatabase *QLinuxFbIntegration::fontDatabase() const
 {
-    return fontDb;
+    return m_fontDb;
 }
 
 QT_END_NAMESPACE
index 430375d..7c67431 100644 (file)
 
 #include <qpa/qplatformintegration.h>
 
-#include <QtPlatformSupport/private/qfbscreen_p.h>
-
 QT_BEGIN_NAMESPACE
 
 class QLinuxFbIntegrationPrivate;
-struct fb_cmap;
-struct fb_var_screeninfo;
-struct fb_fix_screeninfo;
 class QAbstractEventDispatcher;
 class QLinuxFbScreen;
 
 class QLinuxFbIntegration : public QPlatformIntegration
 {
 public:
-    QLinuxFbIntegration();
+    QLinuxFbIntegration(const QStringList &paramList);
     ~QLinuxFbIntegration();
 
     bool hasCapability(QPlatformIntegration::Capability cap) const;
@@ -67,52 +62,13 @@ public:
     QPlatformWindow *createPlatformWindow(QWindow *window) const;
     QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
     QAbstractEventDispatcher *guiThreadEventDispatcher() const;
-
-    QList<QPlatformScreen *> screens() const { return mScreens; }
-
+    QList<QPlatformScreen *> screens() const;
     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;
+    QLinuxFbScreen *m_primaryScreen;
+    QPlatformFontDatabase *m_fontDb;
+    QAbstractEventDispatcher *m_eventDispatcher;
 };
 
 QT_END_NAMESPACE
index 729fd87..7b9eacf 100644 (file)
 #include <QtPlatformSupport/private/qfbcursor_p.h>
 #include <QtGui/QPainter>
 
+#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>
+
+#include <linux/fb.h>
+
 QT_BEGIN_NAMESPACE
 
-QLinuxFbScreen::QLinuxFbScreen(uchar * d, int w,
-    int h, int lstep, QImage::Format screenFormat) : compositePainter(0)
+static int openFramebufferDevice(const QString &dev)
 {
-    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 QFbCursor(this);
+    int fd = -1;
+
+    if (access(dev.toLatin1().constData(), R_OK|W_OK) == 0)
+        fd = QT_OPEN(dev.toLatin1().constData(), O_RDWR);
+
+    if (fd == -1) {
+        if (access(dev.toLatin1().constData(), R_OK) == 0)
+            fd = QT_OPEN(dev.toLatin1().constData(), O_RDONLY);
+    }
+
+    return fd;
 }
 
-void QLinuxFbScreen::setGeometry(QRect rect)
+static int determineDepth(const fb_var_screeninfo &vinfo)
 {
-    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);
+    int depth = vinfo.bits_per_pixel;
+    if (depth== 24) {
+        depth = vinfo.red.length + vinfo.green.length + vinfo.blue.length;
+        if (depth <= 0)
+            depth = 24; // reset if color component lengths are not reported
+    } else if (depth == 16) {
+        depth = vinfo.red.length + vinfo.green.length + vinfo.blue.length;
+        if (depth <= 0)
+            depth = 16;
+    }
+    return depth;
 }
 
-void QLinuxFbScreen::setFormat(QImage::Format format)
+static QRect determineGeometry(const fb_var_screeninfo &vinfo, const QRect &userGeometry)
 {
-    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);
+    int xoff = vinfo.xoffset;
+    int yoff = vinfo.yoffset;
+    int w, h;
+    if (userGeometry.isValid()) {
+        w = userGeometry.width();
+        h = userGeometry.height();
+        if ((uint)w > vinfo.xres)
+            w = vinfo.xres;
+        if ((uint)h > vinfo.yres)
+            h = vinfo.yres;
+
+        int xxoff = userGeometry.x(), yyoff = userGeometry.y();
+        if (xxoff != 0 || yyoff != 0) {
+            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 {
+        w = vinfo.xres;
+        h = vinfo.yres;
+    }
+
+    if (w == 0 || h == 0) {
+        qWarning("Unable to find screen geometry, using 320x240");
+        w = 320;
+        h = 240;
+    }
+
+    return QRect(xoff, yoff, w, h);
 }
 
-QRegion QLinuxFbScreen::doRedraw()
+static QSizeF determinePhysicalSize(const fb_var_screeninfo &vinfo, const QSize &mmSize, const QSize &res)
 {
-    QRegion touched;
-    touched = QFbScreen::doRedraw();
+    int mmWidth = mmSize.width(), mmHeight = mmSize.height();
+
+    if (mmWidth <= 0 && mmHeight <= 0) {
+        if (vinfo.width != 0 && vinfo.height != 0
+            && vinfo.width != UINT_MAX && vinfo.height != UINT_MAX) {
+            mmWidth = vinfo.width;
+            mmHeight = vinfo.height;
+        } else {
+            const int dpi = 72;
+            mmWidth = qRound(res.width() * 25.4 / dpi);
+            mmHeight = qRound(res.height() * 25.4 / dpi);
+        }
+    } else if (mmWidth > 0 && mmHeight <= 0) {
+        mmHeight = res.height() * mmWidth/res.width();
+    } else if (mmHeight > 0 && mmWidth <= 0) {
+        mmWidth = res.width() * mmHeight/res.height();
+    }
+
+    return QSize(mmWidth, mmHeight);
+}
 
-    if (!compositePainter) {
-        compositePainter = new QPainter(mFbScreenImage);
+static QImage::Format determineFormat(const fb_var_screeninfo &info, int depth)
+{
+    const fb_bitfield rgba[4] = { info.red, info.green,
+                                  info.blue, info.transp };
+
+    QImage::Format format = QImage::Format_Invalid;
+
+    switch (depth) {
+    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;
+    }
+
+    return format;
+}
+
+static void debug(const fb_var_screeninfo &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);
+}
+
+static int openTtyDevice(const QString &device)
+{
+    const char *const devs[] = { "/dev/tty0", "/dev/tty", "/dev/console", 0 };
+
+    int fd = -1;
+    if (device.isEmpty()) {
+        for (const char * const *dev = devs; *dev; ++dev) {
+            fd = QT_OPEN(*dev, O_RDWR);
+            if (fd != -1)
+                break;
+        }
+    } else {
+        fd = QT_OPEN(QFile::encodeName(device).constData(), O_RDWR);
+    }
+
+    return fd;
+}
+
+static bool switchToGraphicsMode(int ttyfd, int *oldMode)
+{
+    ioctl(ttyfd, KDGETMODE, &oldMode);
+    if (*oldMode != KD_GRAPHICS) {
+       if (ioctl(ttyfd, KDSETMODE, KD_GRAPHICS) != 0)
+            return 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));
+    return true;
+}
+
+static void resetTty(int ttyfd, int oldMode)
+{
+    ioctl(ttyfd, KDSETMODE, oldMode);
+
+    // 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);
+}
+
+static void blankScreen(int fd, bool on)
+{
+    ioctl(fd, FBIOBLANK, on ? VESA_POWERDOWN : VESA_NO_BLANKING);
+}
+
+QLinuxFbScreen::QLinuxFbScreen()
+    : mFbFd(-1), mBlitter(0)
+{
+}
+
+QLinuxFbScreen::~QLinuxFbScreen()
+{
+    if (mFbFd != -1) {
+        munmap(mMmap.data - mMmap.offset, mMmap.size);
+        close(mFbFd);
+    }
+
+    if (mTtyFd != -1) {
+        resetTty(mTtyFd, mOldTtyMode);
+        close(mTtyFd);
+    }
+
+    delete mBlitter;
+}
+
+bool QLinuxFbScreen::initialize(const QStringList &args)
+{
+    QRegExp ttyRx(QLatin1String("tty=(.*)"));
+    QRegExp fbRx(QLatin1String("fb=(.*)"));
+    QRegExp mmSizeRx(QLatin1String("mmsize=(\\d+)x(\\d+)"));
+    QRegExp sizeRx(QLatin1String("size=(\\d+)x(\\d+)"));
+    QRegExp offsetRx(QLatin1String("offset=(\\d+)x(\\d+)"));
+
+    QString fbDevice, ttyDevice;
+    QSize userMmSize;
+    QRect userGeometry;
+
+    // Parse arguments
+    foreach (const QString &arg, args) {
+        if (sizeRx.indexIn(arg) != -1)
+            userGeometry.setSize(QSize(sizeRx.cap(1).toInt(), sizeRx.cap(2).toInt()));
+        else if (offsetRx.indexIn(arg) != -1)
+            userGeometry.setTopLeft(QPoint(offsetRx.cap(1).toInt(), offsetRx.cap(2).toInt()));
+        else if (ttyRx.indexIn(arg) != -1)
+            ttyDevice = ttyRx.cap(1);
+        else if (fbRx.indexIn(arg) != -1)
+            fbDevice = fbRx.cap(1);
+        else if (mmSizeRx.indexIn(arg) != -1)
+            userMmSize = QSize(mmSizeRx.cap(1).toInt(), mmSizeRx.cap(2).toInt());
+    }
+
+    if (fbDevice.isEmpty())
+        fbDevice = QLatin1String("/dev/fb0"); // ## auto-detect
+
+    // Open the device
+    mFbFd = openFramebufferDevice(fbDevice);
+    if (mFbFd == -1) {
+        qWarning("Failed to open framebuffer %s : %s", qPrintable(fbDevice), strerror(errno));
+        return false;
+    }
+
+    // Read the fixed and variable screen information
+    fb_fix_screeninfo finfo;
+    fb_var_screeninfo vinfo;
+    memset(&vinfo, 0, sizeof(vinfo));
+    memset(&finfo, 0, sizeof(finfo));
+
+    if (ioctl(mFbFd, FBIOGET_FSCREENINFO, &finfo) != 0) {
+        qWarning("Error reading fixed information: %s", strerror(errno));
+        return false;
+    }
+
+    if (ioctl(mFbFd, FBIOGET_VSCREENINFO, &vinfo)) {
+        qWarning("Error reading variable information: %s", strerror(errno));
+        return false;
+    }
+
+    mDepth = determineDepth(vinfo);
+    mBytesPerLine = finfo.line_length;
+    mGeometry = determineGeometry(vinfo, userGeometry);
+    mFormat = determineFormat(vinfo, mDepth);
+    mPhysicalSize = determinePhysicalSize(vinfo, userMmSize, mGeometry.size());
+
+    // mmap the framebuffer
+    mMmap.size = finfo.smem_len;
+    uchar *data = (unsigned char *)mmap(0, mMmap.size, PROT_READ | PROT_WRITE, MAP_SHARED, mFbFd, 0);
+    if ((long)data == -1) {
+        qWarning("Failed to mmap framebuffer: %s", strerror(errno));
+        return false;
+    }
+
+    mMmap.offset = mGeometry.y() * mBytesPerLine + mGeometry.x() * mDepth / 8;
+    mMmap.data = data + mMmap.offset;
+
+    QFbScreen::initializeCompositor();
+    mFbScreenImage = QImage(data, mGeometry.width(), mGeometry.height(), mBytesPerLine, mFormat);
+    mCursor = new QFbCursor(this);
+
+    mTtyFd = openTtyDevice(ttyDevice);
+    if (mTtyFd == -1)
+        qWarning() << "Failed to open tty" << strerror(errno);
+
+    if (!switchToGraphicsMode(mTtyFd, &mOldTtyMode))
+        qWarning() << "Failed to set graphics mode" << strerror(errno);
+
+    blankScreen(mFbFd, false);
+
+    return true;
+}
+
+QRegion QLinuxFbScreen::doRedraw()
+{
+    QRegion touched = QFbScreen::doRedraw();
+
+    if (touched.isEmpty())
+        return touched;
+
+    if (!mBlitter)
+        mBlitter = new QPainter(&mFbScreenImage);
 
     QVector<QRect> rects = touched.rects();
     for (int i = 0; i < rects.size(); i++)
-        compositePainter->drawImage(rects[i], *mScreenImage, rects[i]);
+        mBlitter->drawImage(rects[i], *mScreenImage, rects[i]);
     return touched;
 }
 
index 6181ee9..69b8d5c 100644 (file)
 QT_BEGIN_NAMESPACE
 
 class QPainter;
+class QFbCursor;
 
 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);
+    QLinuxFbScreen();
+    ~QLinuxFbScreen();
+
+    bool initialize(const QStringList &args);
 
 public slots:
     QRegion doRedraw();
 
 private:
-    QImage *mFbScreenImage;
-    uchar *data;
-    int bytesPerLine;
+    int mFbFd;
+    int mTtyFd;
+
+    QImage mFbScreenImage;
+    int mBytesPerLine;
+    int mOldTtyMode;
+
+    struct {
+        uchar *data;
+        int offset, size;
+    } mMmap;
 
-    QPainter *compositePainter;
+    QPainter *mBlitter;
 };
 
 QT_END_NAMESPACE