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:
parent
0be4073708
commit
f0922c9baf
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 ¶mList)
|
||||
: 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
|
||||
|
@ -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 ¶mList);
|
||||
~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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user