tools/qvfb/qvfbview.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the tools applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qvfbview.h"
       
    43 #include "qvfbshmem.h"
       
    44 #include "qvfbmmap.h"
       
    45 
       
    46 #include "qanimationwriter.h"
       
    47 #include <QApplication>
       
    48 #include <QPainter>
       
    49 #include <QImage>
       
    50 #include <QBitmap>
       
    51 #include <QMatrix>
       
    52 #include <QPaintEvent>
       
    53 #include <QScrollArea>
       
    54 #include <QFile>
       
    55 #include <QDebug>
       
    56 
       
    57 #ifdef Q_WS_X11
       
    58 #include <QX11EmbedContainer>
       
    59 #include <QHBoxLayout>
       
    60 #endif
       
    61 
       
    62 #include <stdlib.h>
       
    63 #include <unistd.h>
       
    64 #include <sys/ipc.h>
       
    65 #include <sys/types.h>
       
    66 #include <sys/shm.h>
       
    67 #include <sys/stat.h>
       
    68 #include <sys/sem.h>
       
    69 #include <fcntl.h>
       
    70 #include <errno.h>
       
    71 #include <math.h>
       
    72 
       
    73 QT_BEGIN_NAMESPACE
       
    74 
       
    75 extern int qvfb_protocol;
       
    76 
       
    77 QVFbAbstractView::QVFbAbstractView( QWidget *parent )
       
    78 #ifdef QVFB_USE_GLWIDGET
       
    79     : QGLWidget( parent )
       
    80 #else
       
    81     : QWidget( parent )
       
    82 #endif
       
    83 {
       
    84 }
       
    85 
       
    86 QVFbAbstractView::~QVFbAbstractView()
       
    87 {
       
    88 }
       
    89 
       
    90 QVFbView::QVFbView(int id, int w, int h, int d, Rotation r, QWidget *parent)
       
    91         : QVFbAbstractView(parent),
       
    92           viewdepth(d), viewFormat(DefaultFormat), rgb_swapped(0), rsh(0), gsh(0), bsh(0), rmax(15), gmax(15), bmax(15),
       
    93         contentsWidth(w), contentsHeight(h), gred(1.0), ggreen(1.0), gblue(1.0),
       
    94         gammatable(0), refreshRate(30), animation(0),
       
    95         hzm(0.0), vzm(0.0), mView(0),
       
    96         emulateTouchscreen(false), emulateLcdScreen(false), rotation(r)
       
    97 #ifdef Q_WS_X11
       
    98         , embedContainer(0)
       
    99 #endif
       
   100 {
       
   101     switch(qvfb_protocol) {
       
   102     default:
       
   103     case 0:
       
   104         mView = new QShMemViewProtocol(id, QSize(w, h), d, this);
       
   105         break;
       
   106     case 1:
       
   107         mView = new QMMapViewProtocol(id, QSize(w, h), d, this);
       
   108         break;
       
   109     }
       
   110 
       
   111     connect(mView, SIGNAL(displayDataChanged(const QRect &)),
       
   112             SLOT(refreshDisplay(const QRect &)));
       
   113 #ifdef Q_WS_X11
       
   114     connect(mView, SIGNAL(displayEmbedRequested(WId)),
       
   115             this, SLOT(embedDisplay(WId)));
       
   116 #endif
       
   117 
       
   118     setAttribute(Qt::WA_PaintOnScreen, viewFormat != ARGBFormat);
       
   119     setMouseTracking(true);
       
   120     setFocusPolicy(Qt::StrongFocus);
       
   121     setAttribute(Qt::WA_NoSystemBackground);
       
   122 
       
   123     setZoom(1.0,1.0);
       
   124 
       
   125     setGamma(1.0,1.0,1.0);
       
   126     mView->setRate(30);
       
   127 }
       
   128 
       
   129 QVFbView::~QVFbView()
       
   130 {
       
   131     stopAnimation();
       
   132     sendKeyboardData(0, 0, 0, true, false); // magic die key
       
   133 #ifdef Q_WS_X11
       
   134     delete embedContainer;
       
   135 #endif
       
   136 }
       
   137 
       
   138 QSize QVFbView::sizeHint() const
       
   139 {
       
   140     return QSize(contentsWidth, contentsHeight);
       
   141 }
       
   142 
       
   143 void QVFbView::setRate(int i)
       
   144 {
       
   145     mView->setRate(i);
       
   146 }
       
   147 
       
   148 void QVFbView::setGamma(double gr, double gg, double gb)
       
   149 {
       
   150     gred = gr; ggreen = gg; gblue = gb;
       
   151 
       
   152     switch (viewdepth) {
       
   153     case 12:
       
   154 	rsh = 12;
       
   155 	gsh = 7;
       
   156 	bsh = 1;
       
   157 	rmax = 15;
       
   158 	gmax = 15;
       
   159 	bmax = 15;
       
   160 	break;
       
   161     case 15:
       
   162         rsh = 10;
       
   163         gsh = 5;
       
   164         bsh = 0;
       
   165         rmax = 31;
       
   166         gmax = 31;
       
   167         bmax = 31;
       
   168         break;
       
   169     case 16:
       
   170 	rsh = 11;
       
   171 	gsh = 5;
       
   172 	bsh = 0;
       
   173 	rmax = 31;
       
   174 	gmax = 63;
       
   175 	bmax = 31;
       
   176 	break;
       
   177     case 18:
       
   178         rsh = 12;
       
   179         gsh = 6;
       
   180         bsh = 0;
       
   181         rmax = 63;
       
   182         gmax = 63;
       
   183         bmax = 63;
       
   184         break;
       
   185     case 24:
       
   186     case 32:
       
   187 	rsh = 16;
       
   188 	gsh = 8;
       
   189 	bsh = 0;
       
   190 	rmax = 255;
       
   191 	gmax = 255;
       
   192 	bmax = 255;
       
   193     }
       
   194     int mm = qMax(rmax,qMax(gmax,bmax))+1;
       
   195     if (gammatable)
       
   196 	delete [] gammatable;
       
   197     gammatable = new QRgb[mm];
       
   198     for (int i=0; i<mm; i++) {
       
   199 	int r = int(pow(i,gr)*255/rmax);
       
   200 	int g = int(pow(i,gg)*255/gmax);
       
   201 	int b = int(pow(i,gb)*255/bmax);
       
   202 	if (r > 255) r = 255;
       
   203 	if (g > 255) g = 255;
       
   204 	if (b > 255) b = 255;
       
   205 	gammatable[i] = qRgb(r,g,b);
       
   206 //qDebug("%d: %d,%d,%d",i,r,g,b);
       
   207     }
       
   208 
       
   209     mView->flushChanges();
       
   210 }
       
   211 
       
   212 void QVFbView::getGamma(int i, QRgb& rgb)
       
   213 {
       
   214     if (i > 255) i = 255;
       
   215     if (i < 0) i = 0;
       
   216     rgb = qRgb(qRed(gammatable[i*rmax/255]),
       
   217                qGreen(gammatable[i*rmax/255]),
       
   218                qBlue(gammatable[i*rmax/255]));
       
   219 }
       
   220 
       
   221 int QVFbView::displayId() const
       
   222 {
       
   223     return mView->id();
       
   224 }
       
   225 
       
   226 int QVFbView::displayWidth() const
       
   227 {
       
   228     return mView->width();
       
   229 }
       
   230 
       
   231 int QVFbView::displayHeight() const
       
   232 {
       
   233     return mView->height();
       
   234 }
       
   235 
       
   236 int QVFbView::displayDepth() const
       
   237 {
       
   238     return viewdepth;
       
   239 }
       
   240 
       
   241 QVFbView::PixelFormat QVFbView::displayFormat() const
       
   242 {
       
   243     return viewFormat;
       
   244 }
       
   245 
       
   246 QVFbView::Rotation QVFbView::displayRotation() const
       
   247 {
       
   248     return rotation;
       
   249 }
       
   250 
       
   251 void QVFbView::setZoom(double hz, double vz)
       
   252 {
       
   253     if (hzm != hz || vzm != vz) {
       
   254 	hzm = hz;
       
   255 	vzm = vz;
       
   256         mView->flushChanges();
       
   257 
       
   258         contentsWidth = int(displayWidth()*hz);
       
   259         contentsHeight = int(displayHeight()*vz);
       
   260         if (rotation & 1)
       
   261             qSwap(contentsWidth,contentsHeight);
       
   262         resize(contentsWidth, contentsHeight);
       
   263 
       
   264         if (isVisible()) {
       
   265             updateGeometry();
       
   266             qApp->sendPostedEvents();
       
   267             topLevelWidget()->adjustSize();
       
   268             update();
       
   269         }
       
   270     }
       
   271 }
       
   272 
       
   273 void QVFbView::setRotation(QVFbView::Rotation r)
       
   274 {
       
   275     rotation = r;
       
   276     // Force update...
       
   277     double ohzm = hzm;
       
   278     hzm=0.0;
       
   279     setZoom(ohzm,vzm);
       
   280 }
       
   281 
       
   282 static QRect mapToDevice(const QRect &r, const QSize &s, QVFbView::Rotation rotation)
       
   283 {
       
   284     int x1 = r.x();
       
   285     int y1 = r.y();
       
   286     int x2 = r.right();
       
   287     int y2 = r.bottom();
       
   288     int w = s.width();
       
   289     int h = s.height();
       
   290     switch (rotation) {
       
   291     case QVFbView::Rot90:
       
   292         return QRect(
       
   293             QPoint(y1, w - x1),
       
   294             QPoint(y2, w - x2)).normalized();
       
   295     case QVFbView::Rot180:
       
   296         return QRect(
       
   297             QPoint(w - x1, h - y1),
       
   298             QPoint(w - x2, h - y2)).normalized();
       
   299     case QVFbView::Rot270:
       
   300         return QRect(
       
   301             QPoint(h - y1, x1),
       
   302             QPoint(h - y2, x2)).normalized();
       
   303     default:
       
   304         break;
       
   305     }
       
   306     return r;
       
   307 }
       
   308 
       
   309 static QRect mapFromDevice(const QRect &r, const QSize &s, QVFbView::Rotation rotation)
       
   310 {
       
   311     return mapToDevice(r,s,QVFbView::Rotation(4-(int)rotation));
       
   312 }
       
   313 
       
   314 void QVFbView::sendMouseData(const QPoint &pos, int buttons, int wheel)
       
   315 {
       
   316     QPoint p = mapToDevice(QRect(pos,QSize(1,1)), QSize(int(width()/hzm), int(height()/vzm)), rotation).topLeft();
       
   317     mView->sendMouseData(p, buttons, wheel);
       
   318 }
       
   319 
       
   320 void QVFbView::sendKeyboardData(QString unicode, int keycode, int modifiers,
       
   321 				 bool press, bool repeat)
       
   322 {
       
   323     mView->sendKeyboardData(unicode, keycode, modifiers, press, repeat);
       
   324 }
       
   325 
       
   326 void QVFbView::refreshDisplay(const QRect &r)
       
   327 {
       
   328     if (animation) {
       
   329         if (r.isEmpty()) {
       
   330             animation->appendBlankFrame();
       
   331         } else {
       
   332             int l;
       
   333             QImage img = getBuffer(r, l);
       
   334             animation->appendFrame(img,QPoint(r.x(),r.y()));
       
   335         }
       
   336     }
       
   337     if (!r.isNull()) {
       
   338         if (hzm == 1.0 && vzm == 1.0) // hw: workaround for 4.3.1
       
   339             update(mapFromDevice(r, QSize(displayWidth(), displayHeight()), rotation));
       
   340         else
       
   341             update();
       
   342     }
       
   343 }
       
   344 
       
   345 static void dim(QRgb* rgb, int n, int brightness)
       
   346 {
       
   347     uchar* b = (uchar*)rgb;
       
   348 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
       
   349     b++;
       
   350 #endif
       
   351     while (n--) {
       
   352         b[0] = (uint)b[0] * brightness / 255;
       
   353         b[1] = (uint)b[1] * brightness / 255;
       
   354         b[2] = (uint)b[2] * brightness / 255;
       
   355         b += 4;
       
   356     }
       
   357 }
       
   358 
       
   359 QImage QVFbView::getBuffer(const QRect &r, int &leading) const
       
   360 {
       
   361     const int brightness = mView->brightness();
       
   362     if ( brightness == 0 ) {
       
   363         QImage img(r.size(),QImage::Format_RGB32);
       
   364         img.fill(0);
       
   365         leading = 0;
       
   366         return img;
       
   367     }
       
   368 
       
   369     static QByteArray buffer;
       
   370 
       
   371     const int requiredSize = r.width() * r.height() * 4;
       
   372 
       
   373     QImage img;
       
   374     leading = 0;
       
   375 
       
   376     switch (viewdepth) {
       
   377     case 1: {
       
   378         if (requiredSize > buffer.size())
       
   379             buffer.resize(requiredSize);
       
   380 
       
   381         // XXX: hw: replace by drawhelper functionality
       
   382 
       
   383         const int pixelsPerByte = 8;
       
   384         quint8 *src = reinterpret_cast<quint8*>(mView->data())
       
   385                       + r.y() * mView->linestep() + r.x() / pixelsPerByte;
       
   386         const int align = qMin(r.width(), (8 - (r.x() & 7)) & 7);
       
   387         const int doAlign = (align > 0 ? 1 : 0);
       
   388         const int tail = qMin(r.width(), (r.width() - align) & 7);
       
   389         const int doTail = (tail > 0 ? 1 : 0);
       
   390         const int width8 = (r.width() - align) / pixelsPerByte;
       
   391         const int stride = mView->linestep() - (width8 + doAlign);
       
   392 
       
   393         uchar *b = reinterpret_cast<uchar*>(buffer.data());
       
   394 	img = QImage(b, r.width(), r.height(), QImage::Format_RGB32);
       
   395 	for (int y = 0; y < r.height(); ++y) {
       
   396             quint32 *dest = reinterpret_cast<quint32*>(img.scanLine(y));
       
   397             quint8 c;
       
   398 
       
   399             if (doAlign) {
       
   400                 switch (align) {
       
   401                 case 7: c = ((*src & 0x40) >> 6) * 0xff;
       
   402                         *dest++ = qRgb(c, c, c);
       
   403                 case 6: c = ((*src & 0x20) >> 5) * 0xff;
       
   404                         *dest++ = qRgb(c, c, c);
       
   405                 case 5: c = ((*src & 0x10) >> 4) * 0xff;
       
   406                         *dest++ = qRgb(c, c, c);
       
   407                 case 4: c = ((*src & 0x08) >> 3) * 0xff;
       
   408                         *dest++ = qRgb(c, c, c);
       
   409                 case 3: c = ((*src & 0x04) >> 2) * 0xff;
       
   410                         *dest++ = qRgb(c, c, c);
       
   411                 case 2: c = ((*src & 0x02) >> 1) * 0xff;
       
   412                         *dest++ = qRgb(c, c, c);
       
   413                 case 1: c = ((*src & 0x01)) * 0xff;
       
   414                         *dest++ = qRgb(c, c, c);
       
   415                 }
       
   416                 ++src;
       
   417             }
       
   418             for (int i = 0; i < width8; ++i) {
       
   419                 c = ((*src & 0x80) >> 7) * 0xff;
       
   420                 *dest++ = qRgb(c, c, c);
       
   421                 c = ((*src & 0x40) >> 6) * 0xff;
       
   422                 *dest++ = qRgb(c, c, c);
       
   423                 c = ((*src & 0x20) >> 5) * 0xff;
       
   424                 *dest++ = qRgb(c, c, c);
       
   425                 c = ((*src & 0x10) >> 4) * 0xff;
       
   426                 *dest++ = qRgb(c, c, c);
       
   427                 c = ((*src & 0x08) >> 3) * 0xff;
       
   428                 *dest++ = qRgb(c, c, c);
       
   429                 c = ((*src & 0x04) >> 2) * 0xff;
       
   430                 *dest++ = qRgb(c, c, c);
       
   431                 c = ((*src & 0x02) >> 1) * 0xff;
       
   432                 *dest++ = qRgb(c, c, c);
       
   433                 c = ((*src & 0x01)) * 0xff;
       
   434                 *dest++ = qRgb(c, c, c);
       
   435 
       
   436                 ++src;
       
   437             }
       
   438             if (doTail) {
       
   439                 switch (tail) {
       
   440                 case 7: c = ((*src & 0x02) >> 1) * 0xff;
       
   441                         dest[6] = qRgb(c, c, c);
       
   442                 case 6: c = ((*src & 0x04) >> 2) * 0xff;
       
   443                         dest[5] = qRgb(c, c, c);
       
   444                 case 5: c = ((*src & 0x08) >> 3) * 0xff;
       
   445                         dest[4] = qRgb(c, c, c);
       
   446                 case 4: c = ((*src & 0x10) >> 4) * 0xff;
       
   447                         dest[3] = qRgb(c, c, c);
       
   448                 case 3: c = ((*src & 0x20) >> 5) * 0xff;
       
   449                         dest[2] = qRgb(c, c, c);
       
   450                 case 2: c = ((*src & 0x40) >> 6) * 0xff;
       
   451                         dest[1] = qRgb(c, c, c);
       
   452                 case 1: c = ((*src & 0x80) >> 7) * 0xff;
       
   453                         dest[0] = qRgb(c, c, c);
       
   454                 }
       
   455             }
       
   456             src += stride;
       
   457         }
       
   458         break;
       
   459     }
       
   460 
       
   461     case 2: {
       
   462         if (requiredSize > buffer.size())
       
   463             buffer.resize(requiredSize);
       
   464 
       
   465         // XXX: hw: replace by drawhelper functionality
       
   466 
       
   467         const int pixelsPerByte = 4;
       
   468         quint8 *src = reinterpret_cast<quint8*>(mView->data())
       
   469                       + r.y() * mView->linestep() + r.x() / pixelsPerByte;
       
   470         const int align = qMin(r.width(), (4 - (r.x() & 3)) & 3);
       
   471         const int doAlign = (align > 0 ? 1 : 0);
       
   472         const int tail = qMin(r.width(), (r.width() - align) & 3);
       
   473         const int doTail = (tail > 0 ? 1 : 0);
       
   474         const int width8 = (r.width() - align) / pixelsPerByte;
       
   475         const int stride = mView->linestep() - (width8 + doAlign);
       
   476 
       
   477         uchar *b = reinterpret_cast<uchar*>(buffer.data());
       
   478 	img = QImage(b, r.width(), r.height(), QImage::Format_RGB32);
       
   479 	for (int y = 0; y < r.height(); ++y) {
       
   480             quint32 *dest = reinterpret_cast<quint32*>(img.scanLine(y));
       
   481             quint8 c;
       
   482 
       
   483             if (doAlign) {
       
   484                 switch (align) {
       
   485                 case 3: c = ((*src & 0x30) >> 4) * 0x55;
       
   486                         *dest++ = qRgb(c, c, c);
       
   487                 case 2: c = ((*src & 0x0c) >> 2) * 0x55;
       
   488                         *dest++ = qRgb(c, c, c);
       
   489                 case 1: c = ((*src & 0x03)) * 0x55;
       
   490                         *dest++ = qRgb(c, c, c);
       
   491                 }
       
   492                 ++src;
       
   493             }
       
   494             for (int i = 0; i < width8; ++i) {
       
   495                 c = ((*src & 0xc0) >> 6) * 0x55;
       
   496                 *dest++ = qRgb(c, c, c);
       
   497                 c = ((*src & 0x30) >> 4) * 0x55;
       
   498                 *dest++ = qRgb(c, c, c);
       
   499                 c = ((*src & 0x0c) >> 2) * 0x55;
       
   500                 *dest++ = qRgb(c, c, c);
       
   501                 c = ((*src & 0x03)) * 0x55;
       
   502                 *dest++ = qRgb(c, c, c);
       
   503 
       
   504                 ++src;
       
   505             }
       
   506             if (doTail) {
       
   507                 switch (tail) {
       
   508                 case 3: c = ((*src & 0x0c) >> 2) * 0x55;
       
   509                         dest[2] = qRgb(c, c, c);
       
   510                 case 2: c = ((*src & 0x30) >> 4) * 0x55;
       
   511                         dest[1] = qRgb(c, c, c);
       
   512                 case 1: c = ((*src & 0xc0) >> 6) * 0x55;
       
   513                         dest[0] = qRgb(c, c, c);
       
   514                 }
       
   515             }
       
   516             src += stride;
       
   517         }
       
   518         break;
       
   519     }
       
   520 
       
   521     case 4: {
       
   522         if (requiredSize > buffer.size())
       
   523             buffer.resize(requiredSize);
       
   524 
       
   525         // XXX: hw: replace by drawhelper functionality
       
   526 
       
   527         const int pixelsPerByte = 2;
       
   528         const int doAlign = r.x() & 1;
       
   529         const int doTail = (r.width() - doAlign) & 1;
       
   530         const int width8 = (r.width() - doAlign) / pixelsPerByte;
       
   531 
       
   532         uchar *b = reinterpret_cast<uchar*>(buffer.data());
       
   533 	img = QImage(b, r.width(), r.height(), QImage::Format_RGB32);
       
   534 	for (int y = 0; y < r.height(); ++y) {
       
   535             const quint8 *sptr = mView->data()
       
   536                                  + (r.y() + y) * mView->linestep()
       
   537                                  + r.x() / pixelsPerByte;
       
   538             quint32 *dptr = reinterpret_cast<quint32*>(img.scanLine(y));
       
   539 
       
   540             if (doAlign) {
       
   541                 quint8 c = (*sptr++ & 0x0f);
       
   542                 c |= (c << 4);
       
   543                 *dptr++ = qRgb(c, c, c);
       
   544             }
       
   545 
       
   546             for (int i = 0; i < width8; ++i) {
       
   547                 quint8 c1 = (*sptr >> 4);
       
   548                 quint8 c2 = (*sptr & 0x0f);
       
   549                 c1 |= (c1 << 4);
       
   550                 c2 |= (c2 << 4);
       
   551 		*dptr++ = qRgb(c1, c1, c1);
       
   552 		*dptr++ = qRgb(c2, c2, c2);
       
   553                 ++sptr;
       
   554 	    }
       
   555 
       
   556             if (doTail) {
       
   557                 quint8 c = *sptr >> 4;
       
   558                 c |= (c << 4);
       
   559                 *dptr = qRgb(c, c, c);
       
   560             }
       
   561 	}
       
   562         break;
       
   563     }
       
   564     case 12:
       
   565 	img = QImage((const uchar*)(mView->data() + r.y() * mView->linestep() + r.x() * 2),
       
   566                      r.width(), r.height(), mView->linestep(),
       
   567                      QImage::Format_RGB444);
       
   568         break;
       
   569     case 15:
       
   570 	img = QImage((const uchar*)(mView->data() + r.y() * mView->linestep() + r.x() * 2),
       
   571                      r.width(), r.height(), mView->linestep(),
       
   572                      QImage::Format_RGB555);
       
   573         break;
       
   574     case 16:
       
   575 	img = QImage((const uchar*)(mView->data() + r.y() * mView->linestep() + r.x() * 2),
       
   576                      r.width(), r.height(), mView->linestep(),
       
   577                      QImage::Format_RGB16);
       
   578         break;
       
   579     case 18:
       
   580 	img = QImage((const uchar*)(mView->data() + r.y() * mView->linestep() + r.x() * 3),
       
   581                      r.width(), r.height(), mView->linestep(),
       
   582                      QImage::Format_RGB666);
       
   583         break;
       
   584     case 24:
       
   585 	img = QImage((const uchar*)(mView->data() + r.y() * mView->linestep() + r.x() * 3),
       
   586                       r.width(), r.height(), mView->linestep(),
       
   587                      QImage::Format_RGB888);
       
   588         break;
       
   589     case 32:
       
   590 	img = QImage((const uchar*)(mView->data() + r.y() * mView->linestep() + r.x() * 4),
       
   591                      r.width(), r.height(), mView->linestep(),
       
   592                      viewFormat == ARGBFormat ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
       
   593         break;
       
   594     case 8:
       
   595         img = QImage(mView->data() + r.y() * mView->linestep() + r.x(),
       
   596                    r.width(), r.height(), mView->linestep(),
       
   597                    QImage::Format_Indexed8);
       
   598         img.setColorTable(mView->clut());
       
   599         if (img.numColors() <= 0)
       
   600             img = QImage();
       
   601         break;
       
   602     }
       
   603 
       
   604     if (rgb_swapped)
       
   605         img = img.rgbSwapped();
       
   606 
       
   607     if ( brightness != 255 ) {
       
   608         if (img.format() == QImage::Format_Indexed8) {
       
   609             QVector<QRgb> c = img.colorTable();
       
   610             dim(c.data(),c.count(),brightness);
       
   611             img.setColorTable(c);
       
   612         } else {
       
   613             if ( img.format() != QImage::Format_ARGB32_Premultiplied )
       
   614                 img = img.convertToFormat(QImage::Format_RGB32);
       
   615 
       
   616             // NOTE: calling bits() may change numBytes(), so do not
       
   617             // pass them as parameters (which are evaluated right-to-left).
       
   618             QRgb *b = (QRgb*)img.bits();
       
   619             int n = img.numBytes()/4;
       
   620             dim(b,n,brightness);
       
   621         }
       
   622     }
       
   623 
       
   624     return img;
       
   625 }
       
   626 
       
   627 static int findMultiple(int start, double m, int limit, int step)
       
   628 {
       
   629     int r = start;
       
   630     while (r != limit) {
       
   631 	if (int(int(r * m)/m) == r)
       
   632 	    break;
       
   633 	r += step;
       
   634     }
       
   635     return r;
       
   636 }
       
   637 
       
   638 void QVFbView::drawScreen(const QRect &rect)
       
   639 {
       
   640     QRect r = QRect(0, 0, mView->width(), mView->height());
       
   641 
       
   642     if (hzm == 1.0 && vzm == 1.0) // hw: workaround for 4.3.1
       
   643         r &= rect;
       
   644 
       
   645     if (int(hzm) != hzm || int(vzm) != vzm) {
       
   646         r.setLeft(findMultiple(r.left(),hzm,0,-1));
       
   647         r.setTop(findMultiple(r.top(),vzm,0,-1));
       
   648         int w = findMultiple(r.width(),hzm,mView->width(),1);
       
   649         int h = findMultiple(r.height(),vzm,mView->height(),1);
       
   650         r.setRight(r.left()+w-1);
       
   651         r.setBottom(r.top()+h-1);
       
   652     }
       
   653 
       
   654     int leading;
       
   655     const QImage img = getBuffer(r, leading);
       
   656 
       
   657     QPixmap pm;
       
   658     if (hzm == 1.0 && vzm == 1.0) {
       
   659         pm = QPixmap::fromImage(img);
       
   660     } else if (emulateLcdScreen && hzm == 3.0 && vzm == 3.0) {
       
   661         QImage img2(img.width()*3, img.height(), QImage::Format_RGB32);
       
   662         for (int row = 0; row < img2.height(); row++) {
       
   663             QRgb *dptr = (QRgb*)img2.scanLine(row);
       
   664             QRgb *sptr = (QRgb*)img.scanLine(row);
       
   665             for (int col = 0; col < img.width(); col++) {
       
   666                 QRgb s = *sptr++;
       
   667                 *dptr++ = qRgb(qRed(s),0,0);
       
   668                 *dptr++ = qRgb(0,qGreen(s),0);
       
   669                 *dptr++ = qRgb(0,0,qBlue(s));
       
   670             }
       
   671         }
       
   672         QMatrix m;
       
   673         m.scale(1.0, 3.0);
       
   674         pm = QPixmap::fromImage(img2);
       
   675         pm = pm.transformed(m);
       
   676     } else if (int(hzm) == hzm && int(vzm) == vzm) {
       
   677         QMatrix m;
       
   678         m.scale(hzm,vzm);
       
   679         pm = QPixmap::fromImage(img);
       
   680         pm = pm.transformed(m);
       
   681     } else {
       
   682         pm = QPixmap::fromImage(img.scaled(int(img.width()*hzm),int(img.height()*vzm), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
       
   683     }
       
   684 
       
   685     int x1 = r.x();
       
   686     int y1 = r.y();
       
   687     int leadingX = leading;
       
   688     int leadingY = 0;
       
   689 
       
   690     // Do the rotation thing
       
   691     int rotX1 = mView->width() - x1 - img.width();
       
   692     int rotY1 = mView->height() - y1 - img.height();
       
   693     int rotLeadingX = (leading) ? mView->width() - leadingX - img.width() : 0;
       
   694     int rotLeadingY = 0;
       
   695     switch (rotation) {
       
   696     case Rot0:
       
   697         break;
       
   698     case Rot90:
       
   699         leadingY = leadingX;
       
   700         leadingX = rotLeadingY;
       
   701         y1 = x1;
       
   702         x1 = rotY1;
       
   703         break;
       
   704     case Rot180:
       
   705         leadingX = rotLeadingX;
       
   706         leadingY = leadingY;
       
   707         x1 = rotX1;
       
   708         y1 = rotY1;
       
   709         break;
       
   710     case Rot270:
       
   711         leadingX = leadingY;
       
   712         leadingY = rotLeadingX;
       
   713         x1 = y1;
       
   714         y1 = rotX1;
       
   715         break;
       
   716     default:
       
   717         break;
       
   718     }
       
   719     x1 = int(x1*hzm);
       
   720     y1 = int(y1*vzm);
       
   721     leadingX = int(leadingX*hzm);
       
   722     leadingY = int(leadingY*vzm);
       
   723     if (rotation != 0) {
       
   724         QMatrix m;
       
   725         m.rotate(rotation * 90.0);
       
   726         pm = pm.transformed(m);
       
   727     }
       
   728 
       
   729     QPainter p(this);
       
   730     if (viewFormat == ARGBFormat) {
       
   731         QPixmap bg(":/res/images/logo-nt.png");
       
   732         p.fillRect(x1,y1,pm.width(), pm.height(), QBrush(bg));
       
   733     }
       
   734     p.drawPixmap(x1, y1, pm, leadingX, leadingY, pm.width(), pm.height());
       
   735 }
       
   736 
       
   737 //bool QVFbView::eventFilter(QObject *obj, QEvent *e)
       
   738 //{
       
   739 //    if (obj == this &&
       
   740 //	 (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut))
       
   741 //	return true;
       
   742 //
       
   743 //    return QWidgetView::eventFilter(obj, e);
       
   744 //}
       
   745 
       
   746 void QVFbView::paintEvent(QPaintEvent *e)
       
   747 {
       
   748     drawScreen(mapToDevice(e->rect(),QSize(int(width()/hzm), int(height()/vzm)),rotation));
       
   749 }
       
   750 
       
   751 void QVFbView::mousePressEvent(QMouseEvent *e)
       
   752 {
       
   753     sendMouseData(QPoint(int(e->x()/hzm),int(e->y()/vzm)), e->buttons(), 0);
       
   754 }
       
   755 
       
   756 void QVFbView::contextMenuEvent(QContextMenuEvent*)
       
   757 {
       
   758 
       
   759 }
       
   760 
       
   761 void QVFbView::mouseDoubleClickEvent(QMouseEvent *e)
       
   762 {
       
   763     sendMouseData(QPoint(int(e->x()/hzm),int(e->y()/vzm)), e->buttons(), 0);
       
   764 }
       
   765 
       
   766 void QVFbView::mouseReleaseEvent(QMouseEvent *e)
       
   767 {
       
   768     sendMouseData(QPoint(int(e->x()/hzm),int(e->y()/vzm)), e->buttons(), 0);
       
   769 }
       
   770 
       
   771 void QVFbView::skinMouseEvent(QMouseEvent *e)
       
   772 {
       
   773     sendMouseData(QPoint(int(e->x()/hzm),int(e->y()/vzm)), e->buttons(), 0);
       
   774 }
       
   775 
       
   776 void QVFbView::mouseMoveEvent(QMouseEvent *e)
       
   777 {
       
   778     if (!emulateTouchscreen || (e->buttons() & Qt::MouseButtonMask))
       
   779 	sendMouseData(QPoint(int(e->x()/hzm),int(e->y()/vzm)), e->buttons(), 0);
       
   780 }
       
   781 
       
   782 void QVFbView::wheelEvent(QWheelEvent *e)
       
   783 {
       
   784     if (!e)
       
   785         return;
       
   786     sendMouseData(QPoint(int(e->x()/hzm),int(e->y()/vzm)), e->buttons(), e->delta());
       
   787 }
       
   788 
       
   789 void QVFbView::setTouchscreenEmulation(bool b)
       
   790 {
       
   791     emulateTouchscreen = b;
       
   792 }
       
   793 
       
   794 void QVFbView::setLcdScreenEmulation(bool b)
       
   795 {
       
   796     emulateLcdScreen = b;
       
   797 }
       
   798 
       
   799 void QVFbView::setViewFormat(PixelFormat f)
       
   800 {
       
   801     if (viewFormat == f)
       
   802         return;
       
   803     viewFormat = f;
       
   804     setAttribute(Qt::WA_PaintOnScreen, viewFormat != ARGBFormat);
       
   805 }
       
   806 
       
   807 #ifdef Q_WS_X11
       
   808 void QVFbView::embedDisplay(WId windowId)
       
   809 {
       
   810     if (windowId == 0) {
       
   811         delete embedContainer;
       
   812         embedContainer = 0;
       
   813         return;
       
   814     }
       
   815 
       
   816     if (!embedContainer) {
       
   817         embedContainer = new QX11EmbedContainer(this);
       
   818         embedContainer->setGeometry(rect());
       
   819         embedContainer->show();
       
   820     }
       
   821     embedContainer->embedClient(windowId);
       
   822 }
       
   823 #endif
       
   824 
       
   825 bool QVFbView::event(QEvent *e)
       
   826 {
       
   827     if (e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease) {
       
   828         QKeyEvent *ke = static_cast<QKeyEvent*>(e);
       
   829         sendKeyboardData(ke->text(), ke->key(),
       
   830 		     ke->modifiers()&(Qt::ShiftModifier|Qt::ControlModifier|Qt::AltModifier),
       
   831                          ke->type() == QEvent::KeyPress, ke->isAutoRepeat());
       
   832         ke->accept();
       
   833         return true;
       
   834     }
       
   835     return QVFbAbstractView::event(e);
       
   836 }
       
   837 
       
   838 void QVFbView::keyPressEvent(QKeyEvent *e)
       
   839 {
       
   840     sendKeyboardData(e->text(), e->key(),
       
   841 		     e->modifiers()&(Qt::ShiftModifier|Qt::ControlModifier|Qt::AltModifier),
       
   842 		     true, e->isAutoRepeat());
       
   843 }
       
   844 
       
   845 void QVFbView::keyReleaseEvent(QKeyEvent *e)
       
   846 {
       
   847     sendKeyboardData(e->text(), e->key(),
       
   848 		     e->modifiers()&(Qt::ShiftModifier|Qt::ControlModifier|Qt::AltModifier),
       
   849 		     false, e->isAutoRepeat());
       
   850 }
       
   851 
       
   852 
       
   853 QImage QVFbView::image() const
       
   854 {
       
   855     int l;
       
   856     QImage r = getBuffer(QRect(0, 0, mView->width(), mView->height()), l).copy();
       
   857     return r;
       
   858 }
       
   859 
       
   860 void QVFbView::startAnimation(const QString& filename)
       
   861 {
       
   862     delete animation;
       
   863     animation = new QAnimationWriter(filename,"MNG");
       
   864     animation->setFrameRate(refreshRate);
       
   865     animation->appendFrame(QImage(mView->data(),
       
   866                                   mView->width(), mView->height(), QImage::Format_RGB32));
       
   867 }
       
   868 
       
   869 void QVFbView::stopAnimation()
       
   870 {
       
   871     delete animation;
       
   872     animation = 0;
       
   873 }
       
   874 
       
   875 
       
   876 void QVFbView::skinKeyPressEvent(int code, const QString& text, bool autorep)
       
   877 {
       
   878     QKeyEvent e(QEvent::KeyPress,code,0,text,autorep);
       
   879     keyPressEvent(&e);
       
   880 }
       
   881 
       
   882 void QVFbView::skinKeyReleaseEvent(int code, const QString& text, bool autorep)
       
   883 {
       
   884     QKeyEvent e(QEvent::KeyRelease,code,0,text,autorep);
       
   885     keyReleaseEvent(&e);
       
   886 }
       
   887 
       
   888 QT_END_NAMESPACE