summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGirish Ramakrishnan <girish.1.ramakrishnan@nokia.com>2012-07-06 05:40:57 +0530
committerQt by Nokia <qt-info@nokia.com>2012-07-11 12:44:05 +0200
commitf0922c9bafce6a565af020851012dd3cbb609888 (patch)
tree73db8e1a9632118dbd8140998550a9b7655b6f6b /src
parent0be40737081110238f326e3644287b3dca18a824 (diff)
linuxfb: Rework screen code
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>
Diffstat (limited to 'src')
-rw-r--r--src/platformsupport/fbconvenience/qfbscreen.cpp69
-rw-r--r--src/platformsupport/fbconvenience/qfbscreen_p.h33
-rw-r--r--src/plugins/platforms/linuxfb/main.cpp2
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp751
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbintegration.h54
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp400
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbscreen.h24
7 files changed, 437 insertions, 896 deletions
diff --git a/src/platformsupport/fbconvenience/qfbscreen.cpp b/src/platformsupport/fbconvenience/qfbscreen.cpp
index cd45e5ce08..5d2208a3a1 100644
--- a/src/platformsupport/fbconvenience/qfbscreen.cpp
+++ b/src/platformsupport/fbconvenience/qfbscreen.cpp
@@ -48,9 +48,20 @@
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;
diff --git a/src/platformsupport/fbconvenience/qfbscreen_p.h b/src/platformsupport/fbconvenience/qfbscreen_p.h
index 71d8d455f6..b37d3ad907 100644
--- a/src/platformsupport/fbconvenience/qfbscreen_p.h
+++ b/src/platformsupport/fbconvenience/qfbscreen_p.h
@@ -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;
};
diff --git a/src/plugins/platforms/linuxfb/main.cpp b/src/plugins/platforms/linuxfb/main.cpp
index e0348abac4..12b68a6f2b 100644
--- a/src/plugins/platforms/linuxfb/main.cpp
+++ b/src/plugins/platforms/linuxfb/main.cpp
@@ -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;
}
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
index cdec49b55f..057839a96d 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
@@ -48,744 +48,25 @@
#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
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h
index 430375dbb6..7c67431fdb 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h
+++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h
@@ -44,21 +44,16 @@
#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
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
index 729fd87a31..7b9eacf59f 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
@@ -43,63 +43,383 @@
#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;
}
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.h b/src/plugins/platforms/linuxfb/qlinuxfbscreen.h
index 6181ee964b..69b8d5c79a 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.h
+++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.h
@@ -47,24 +47,34 @@
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