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>
This commit is contained in:
Girish Ramakrishnan 2012-07-06 05:40:57 +05:30 committed by Qt by Nokia
parent 0be4073708
commit f0922c9baf
7 changed files with 438 additions and 897 deletions

View File

@ -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;

View 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 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:
QList<QFbWindow *> windowStack;
QRegion repaintRegion;
QFbCursor * cursor;
QTimer redrawTimer;
// 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);
protected slots:
virtual QRegion doRedraw();
protected:
void initializeCompositor();
QList<QFbWindow *> windowStack;
QRegion repaintRegion;
QTimer redrawTimer;
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;
};

View 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;
}

View File

@ -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
QLinuxFbIntegration::QLinuxFbIntegration(const QStringList &paramList)
: m_fontDb(new QGenericUnixFontDatabase()),
m_eventDispatcher(createUnixEventDispatcher())
{
public:
QLinuxFbIntegrationPrivate();
~QLinuxFbIntegrationPrivate();
QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher);
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()
{
if (ttyfd == -1)
return;
if (doGraphicsMode)
ioctl(ttyfd, KDSETMODE, oldKdMode);
// Blankin' screen, blinkin' cursor!
const char termctl[] = "\033[9;15]\033[?33h\033[?25h\033[?0c";
QT_WRITE(ttyfd, termctl, sizeof(termctl));
QT_CLOSE(ttyfd);
ttyfd = -1;
}
QLinuxFbIntegration::QLinuxFbIntegration()
:fontDb(new QGenericUnixFontDatabase())
{
d_ptr = new QLinuxFbIntegrationPrivate();
// XXX
QString displaySpec = QString::fromLatin1(qgetenv("QWS_DISPLAY"));
if (!connect(displaySpec))
qFatal("QLinuxFbIntegration: could not initialize screen");
initDevice();
// Create a QImage directly on the screen's framebuffer.
// This is the blit target for copying windows to the screen.
mPrimaryScreen = new QLinuxFbScreen(data, w, h, lstep,
screenFormat);
mPrimaryScreen->setPhysicalSize(QSize(physWidth, physHeight));
mScreens.append(mPrimaryScreen);
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

View File

@ -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

View File

@ -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;
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;
delete mScreenImage;
mScreenImage = new QImage(mGeometry.width(), mGeometry.height(),
mFormat);
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);
}
static QSizeF determinePhysicalSize(const fb_var_screeninfo &vinfo, const QSize &mmSize, const QSize &res)
{
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);
}
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;
touched = QFbScreen::doRedraw();
QRegion touched = QFbScreen::doRedraw();
if (!compositePainter) {
compositePainter = new QPainter(mFbScreenImage);
}
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;
}

View File

@ -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;
QPainter *compositePainter;
QImage mFbScreenImage;
int mBytesPerLine;
int mOldTtyMode;
struct {
uchar *data;
int offset, size;
} mMmap;
QPainter *mBlitter;
};
QT_END_NAMESPACE