00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "qvfbview.h"
00025 #include "qvfbshmem.h"
00026 #include "qvfbmmap.h"
00027
00028 #include "qanimationwriter.h"
00029 #include <QApplication>
00030 #include <QPainter>
00031 #include <QImage>
00032 #include <QBitmap>
00033 #include <QTimer>
00034 #include <QMatrix>
00035 #include <QPaintEvent>
00036 #include <QScrollArea>
00037 #include <QFile>
00038 #include <QDebug>
00039
00040 #include <stdlib.h>
00041 #include <unistd.h>
00042 #include <sys/ipc.h>
00043 #include <sys/types.h>
00044 #include <sys/shm.h>
00045 #include <sys/stat.h>
00046 #include <sys/sem.h>
00047 #include <fcntl.h>
00048 #include <errno.h>
00049 #include <math.h>
00050
00051 extern int qvfb_protocol;
00052
00053 QVFbView::QVFbView( int id, int w, int h, int d, Rotation r, QWidget *parent )
00054 #ifdef QVFB_USE_GLWIDGET
00055 : QGLWidget( parent ),
00056 #else
00057 : QWidget( parent ),
00058 #endif
00059 viewdepth(d), rsh(0), gsh(0), bsh(0), rmax(15), gmax(15), bmax(15),
00060 contentsWidth(w), contentsHeight(h), gred(1.0), ggreen(1.0), gblue(1.0),
00061 gammatable(0), refreshRate(30), animation(0),
00062 hzm(1.0), vzm(1.0), mView(0),
00063 emulateTouchscreen(false), emulateLcdScreen(false), rotation(r)
00064 {
00065 int _w = ( rotation & 0x1 ) ? h : w;
00066 int _h = ( rotation & 0x1 ) ? w : h;
00067
00068 switch(qvfb_protocol) {
00069 default:
00070 case 0:
00071 mView = new QShMemViewProtocol(id, QSize(_w, _h), d, this);
00072 break;
00073 case 1:
00074 mView = new QMMapViewProtocol(id, QSize(_w, _h), d, this);
00075 break;
00076 }
00077
00078 connect(mView, SIGNAL(displayDataChanged(const QRect &)),
00079 SLOT(refreshDisplay(const QRect &)));
00080
00081 setAttribute(Qt::WA_PaintOnScreen, true);
00082 setMouseTracking( true );
00083 setFocusPolicy( Qt::StrongFocus );
00084 setAttribute( Qt::WA_NoSystemBackground );
00085
00086 resize( contentsWidth, contentsHeight );
00087
00088 setGamma(1.0,1.0,1.0);
00089 mView->setRate( 30 );
00090 }
00091
00092 QVFbView::~QVFbView()
00093 {
00094 stopAnimation();
00095 sendKeyboardData( 0, 0, 0, true, false );
00096 }
00097
00098 QSize QVFbView::sizeHint() const
00099 {
00100 return QSize(contentsWidth, contentsHeight);
00101 }
00102
00103 void QVFbView::setRate(int i)
00104 {
00105 mView->setRate(i);
00106 }
00107
00108 void QVFbView::setGamma(double gr, double gg, double gb)
00109 {
00110 if ( viewdepth < 12 )
00111 return;
00112
00113 gred=gr; ggreen=gg; gblue=gb;
00114
00115 switch ( viewdepth ) {
00116 case 12:
00117 rsh = 12;
00118 gsh = 7;
00119 bsh = 1;
00120 rmax = 15;
00121 gmax = 15;
00122 bmax = 15;
00123 break;
00124 case 16:
00125 rsh = 11;
00126 gsh = 5;
00127 bsh = 0;
00128 rmax = 31;
00129 gmax = 63;
00130 bmax = 31;
00131 break;
00132 case 18:
00133 rsh = 12;
00134 gsh = 6;
00135 bsh = 0;
00136 rmax = 63;
00137 gmax = 63;
00138 bmax = 63;
00139 break;
00140 case 24:
00141 case 32:
00142 rsh = 16;
00143 gsh = 8;
00144 bsh = 0;
00145 rmax = 255;
00146 gmax = 255;
00147 bmax = 255;
00148 }
00149 int mm = qMax(rmax,qMax(gmax,bmax))+1;
00150 if ( gammatable )
00151 delete [] gammatable;
00152 gammatable = new QRgb[mm];
00153 for (int i=0; i<mm; i++) {
00154 int r = int(pow(i,gr)*255/rmax);
00155 int g = int(pow(i,gg)*255/gmax);
00156 int b = int(pow(i,gb)*255/bmax);
00157 if ( r > 255 ) r = 255;
00158 if ( g > 255 ) g = 255;
00159 if ( b > 255 ) b = 255;
00160 gammatable[i] = qRgb(r,g,b);
00161
00162 }
00163
00164 mView->flushChanges();
00165 }
00166
00167 void QVFbView::getGamma(int i, QRgb& rgb)
00168 {
00169 if ( i > 255 ) i = 255;
00170 if ( i < 0 ) i = 0;
00171 rgb = qRgb(qRed(gammatable[i*rmax/255]),
00172 qGreen(gammatable[i*rmax/255]),
00173 qBlue(gammatable[i*rmax/255]));
00174 }
00175
00176 int QVFbView::displayId() const
00177 {
00178 return mView->id();
00179 }
00180
00181 int QVFbView::displayWidth() const
00182 {
00183 return ( (int)rotation & 0x01 ) ? mView->height() : mView->width();
00184 }
00185
00186 int QVFbView::displayHeight() const
00187 {
00188 return ( (int)rotation & 0x01 ) ? mView->width(): mView->height();
00189 }
00190
00191 int QVFbView::displayDepth() const
00192 {
00193 return viewdepth;
00194 }
00195
00196 QVFbView::Rotation QVFbView::displayRotation() const
00197 {
00198 return rotation;
00199 }
00200
00201 void QVFbView::setZoom( double hz, double vz )
00202 {
00203 if ( hzm != hz || vzm != vz ) {
00204 hzm = hz;
00205 vzm = vz;
00206 mView->flushChanges();
00207
00208 contentsWidth = int(displayWidth()*hz);
00209 contentsHeight = int(displayHeight()*vz);
00210 resize(contentsWidth, contentsHeight);
00211
00212 updateGeometry();
00213 qApp->sendPostedEvents();
00214 topLevelWidget()->adjustSize();
00215 update();
00216 }
00217 }
00218
00219 static QRect mapToDevice( const QRect &r, const QSize &s, QVFbView::Rotation rotation )
00220 {
00221 int x1 = r.x();
00222 int y1 = r.y();
00223 int x2 = r.right();
00224 int y2 = r.bottom();
00225 int w = s.width();
00226 int h = s.height();
00227 switch ( rotation ) {
00228 case QVFbView::Rot90:
00229 return QRect(
00230 QPoint(y1, w - x1 - 1),
00231 QPoint(y2, w - x2 - 1) );
00232 case QVFbView::Rot180:
00233 return QRect(
00234 QPoint(w - x1 - 1, h - y1 - 1),
00235 QPoint(w - x2 - 1, h - y2 - 1) );
00236 case QVFbView::Rot270:
00237 return QRect(
00238 QPoint(h - y1 - 1, x1),
00239 QPoint(h - y2 - 1, x2) );
00240 default:
00241 break;
00242 }
00243 return r;
00244 }
00245
00246 void QVFbView::sendMouseData( const QPoint &pos, int buttons, int wheel )
00247 {
00248 QPoint p = mapToDevice( QRect(pos,QSize(1,1)), QSize(displayWidth(), displayHeight()), rotation ).topLeft();
00249 mView->sendMouseData(p, buttons, wheel);
00250 }
00251
00252 void QVFbView::sendKeyboardData( QString unicode, int keycode, int modifiers,
00253 bool press, bool repeat )
00254 {
00255 mView->sendKeyboardData(unicode, keycode, modifiers, press, repeat);
00256 }
00257
00258 void QVFbView::refreshDisplay(const QRect &r)
00259 {
00260 if ( animation ) {
00261 if ( r.isEmpty() ) {
00262 animation->appendBlankFrame();
00263 } else {
00264 int l;
00265 QImage img = getBuffer( r, l );
00266 animation->appendFrame(img,QPoint(r.x(),r.y()));
00267 }
00268 }
00269 if ( !r.isNull() )
00270 repaint();
00271 }
00272
00273 QImage QVFbView::getBuffer( const QRect &r, int &leading ) const
00274 {
00275 static QByteArray buffer;
00276
00277 const int requiredSize = r.width() * r.height() * 4;
00278
00279 switch ( viewdepth ) {
00280 case 12:
00281 case 16: {
00282 if (requiredSize > buffer.size())
00283 buffer.resize(requiredSize);
00284 uchar *b = reinterpret_cast<uchar*>(buffer.data());
00285 QImage img(b, r.width(), r.height(), QImage::Format_RGB32);
00286 const int rsh = viewdepth == 12 ? 12 : 11;
00287 const int gsh = viewdepth == 12 ? 7 : 5;
00288 const int bsh = viewdepth == 12 ? 1 : 0;
00289 const int rmax = viewdepth == 12 ? 15 : 31;
00290 const int gmax = viewdepth == 12 ? 15 : 63;
00291 const int bmax = viewdepth == 12 ? 15 : 31;
00292 for ( int row = 0; row < r.height(); row++ ) {
00293 QRgb *dptr = (QRgb*)img.scanLine( row );
00294 ushort *sptr = (ushort*)(mView->data() + (r.y()+row)*mView->linestep());
00295 sptr += r.x();
00296 for ( int col=0; col < r.width(); col++ ) {
00297 ushort s = *sptr++;
00298 *dptr++ = qRgb(qRed(gammatable[(s>>rsh)&rmax]),qGreen(gammatable[(s>>gsh)&gmax]),qBlue(gammatable[(s>>bsh)&bmax]));
00299
00300 }
00301 }
00302 leading = 0;
00303 return img;
00304 }
00305 case 4: {
00306 if (requiredSize > buffer.size())
00307 buffer.resize(requiredSize);
00308 uchar *b = reinterpret_cast<uchar*>(buffer.data());
00309 QImage img(b, r.width(), r.height(), QImage::Format_Indexed8);
00310
00311 for ( int row = 0; row < r.height(); row++ ) {
00312 unsigned char *dptr = img.scanLine( row );
00313 const unsigned char *sptr = mView->data() + (r.y()+row)*mView->linestep();
00314 sptr += r.x()/2;
00315 int col = 0;
00316 if ( r.x() & 1 ) {
00317 *dptr++ = *sptr++ >> 4;
00318 col++;
00319 }
00320 for ( ; col < r.width()-1; col+=2 ) {
00321 unsigned char s = *sptr++;
00322 *dptr++ = s & 0x0f;
00323 *dptr++ = s >> 4;
00324 }
00325 if ( !(r.right() & 1) )
00326 *dptr = *sptr & 0x0f;
00327 }
00328 leading = 0;
00329 return img;
00330 }
00331 case 18: {
00332
00333 if (requiredSize > buffer.size())
00334 buffer.resize(requiredSize);
00335 uchar *b = reinterpret_cast<uchar*>(buffer.data());
00336 QImage img(b, r.width(), r.height(), QImage::Format_RGB32);
00337 const int rsh = 12;
00338 const int gsh = 6;
00339 const int bsh = 0;
00340 const int rmax = 63;
00341 const int gmax = 63;
00342 const int bmax = 63;
00343 for ( int row = 0; row < r.height(); row++ ) {
00344 QRgb *dptr = (QRgb*)img.scanLine( row );
00345 uchar *sptr = (uchar*)(mView->data() + (r.y()+row)*mView->linestep());
00346 sptr += r.x()*3;
00347 for ( int col=0; col < r.width(); col++ ) {
00348 uint s = *(reinterpret_cast<uint*>(sptr));
00349 s &= 0x00ffffff;
00350 sptr += 3;
00351 *dptr++ = qRgb(qRed(gammatable[(s>>rsh)&rmax]),qGreen(gammatable[(s>>gsh)&gmax]),qBlue(gammatable[(s>>bsh)&bmax]));
00352 }
00353 }
00354 leading = 0;
00355 return img;
00356 }
00357 case 24: {
00358 static unsigned char *imgData = 0;
00359 if (!imgData) {
00360 int bpl = mView->width() *4;
00361 imgData = new unsigned char[bpl * mView->height()];
00362 }
00363 QImage img(imgData, r.width(), r.height(), QImage::Format_RGB32);
00364 for (int row = 0; row < r.height(); ++row) {
00365 uchar *dptr = img.scanLine(row);
00366 const uchar *sptr = mView->data() + (r.y() + row) * mView->linestep();
00367 sptr += r.x() * 3;
00368 for (int col = 0; col < r.width(); ++col) {
00369 *dptr++ = *sptr++;
00370 *dptr++ = *sptr++;
00371 *dptr++ = *sptr++;
00372 dptr++;
00373 }
00374 }
00375 leading = 0;
00376 return img;
00377 }
00378 case 32: {
00379 leading = r.x();
00380 return QImage( mView->data() + r.y() * mView->linestep(),
00381 mView->width(), r.height(), QImage::Format_RGB32 );
00382 }
00383 case 8: {
00384 leading = r.x();
00385 QImage img( mView->data() + r.y() * mView->linestep(),
00386 mView->width(), r.height(), QImage::Format_Indexed8 );
00387 img.setColorTable(mView->clut());
00388 return img;
00389 }
00390 case 1: {
00391 leading = r.x();
00392 return QImage( mView->data() + r.y() * mView->linestep(),
00393 mView->width(), r.height(), QImage::Format_MonoLSB );
00394 }
00395 }
00396 return QImage();
00397 }
00398
00399 static int findMultiple(int start, double m, int limit, int step)
00400 {
00401 int r = start;
00402 while (r != limit) {
00403 if ( int(int(r * m)/m) == r )
00404 break;
00405 r += step;
00406 }
00407 return r;
00408 }
00409
00410 void QVFbView::drawScreen()
00411 {
00412 QPainter p( this );
00413
00414
00415 QRect r(0, 0, mView->width(), mView->height() );
00416
00417 if ( int(hzm) != hzm || int(vzm) != vzm ) {
00418 r.setLeft( findMultiple(r.left(),hzm,0,-1) );
00419 r.setTop( findMultiple(r.top(),vzm,0,-1) );
00420 int w = findMultiple(r.width(),hzm,mView->width(),1);
00421 int h = findMultiple(r.height(),vzm,mView->height(),1);
00422 r.setRight( r.left()+w-1 );
00423 r.setBottom( r.top()+h-1 );
00424 }
00425 int leading;
00426 QImage img( getBuffer( r, leading ) );
00427 QPixmap pm;
00428 if ( hzm == 1.0 && vzm == 1.0 ) {
00429 pm = QPixmap::fromImage( img );
00430 } else if ( emulateLcdScreen && hzm == 3.0 && vzm == 3.0 ) {
00431 QImage img2( img.width()*3, img.height(), QImage::Format_RGB32 );
00432 for ( int row = 0; row < img2.height(); row++ ) {
00433 QRgb *dptr = (QRgb*)img2.scanLine( row );
00434 QRgb *sptr = (QRgb*)img.scanLine( row );
00435 for ( int col = 0; col < img.width(); col++ ) {
00436 QRgb s = *sptr++;
00437 *dptr++ = qRgb(qRed(s),0,0);
00438 *dptr++ = qRgb(0,qGreen(s),0);
00439 *dptr++ = qRgb(0,0,qBlue(s));
00440 }
00441 }
00442 QMatrix m;
00443 m.scale(1.0, 3.0);
00444 pm = QPixmap::fromImage( img2 );
00445 pm = pm.transformed(m);
00446 } else if ( int(hzm) == hzm && int(vzm) == vzm ) {
00447 QMatrix m;
00448 m.scale(hzm,vzm);
00449 pm = QPixmap::fromImage( img );
00450 pm = pm.transformed(m);
00451 } else {
00452 pm = QPixmap::fromImage( img.scaled(int(img.width()*hzm),int(img.height()*vzm), Qt::IgnoreAspectRatio, Qt::SmoothTransformation) );
00453 }
00454
00455 int x1 = r.x();
00456 int y1 = r.y();
00457 int leadingX = leading;
00458 int leadingY = 0;
00459
00460
00461 int rotX1 = mView->width() - x1 - img.width();
00462 int rotY1 = mView->height() - y1 - img.height();
00463 int rotLeadingX = (leading) ? mView->width() - leadingX - img.width() : 0;
00464 int rotLeadingY = 0;
00465 switch ( rotation ) {
00466 case Rot0:
00467 break;
00468 case Rot90:
00469 leadingY = leadingX;
00470 leadingX = rotLeadingY;
00471 y1 = x1;
00472 x1 = rotY1;
00473 break;
00474 case Rot180:
00475 leadingX = rotLeadingX;
00476 leadingY = leadingY;
00477 x1 = rotX1;
00478 y1 = rotY1;
00479 break;
00480 case Rot270:
00481 leadingX = leadingY;
00482 leadingY = rotLeadingX;
00483 x1 = y1;
00484 y1 = rotX1;
00485 break;
00486 default:
00487 break;
00488 }
00489 x1 = int(x1*hzm);
00490 y1 = int(y1*vzm);
00491 leadingX = int(leadingX*hzm);
00492 leadingY = int(leadingY*vzm);
00493 if ( rotation != 0 ) {
00494 QMatrix m;
00495 m.rotate(rotation * 90.0);
00496 pm = pm.transformed(m);
00497 }
00498 p.setPen( Qt::black );
00499 p.setBrush( Qt::white );
00500 p.drawPixmap( x1, y1, pm, leadingX, leadingY, pm.width(), pm.height() );
00501 }
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512 void QVFbView::paintEvent( QPaintEvent * )
00513 {
00514
00515
00516
00517
00518
00519
00520
00521 drawScreen();
00522 }
00523
00524 void QVFbView::mousePressEvent( QMouseEvent *e )
00525 {
00526 sendMouseData( QPoint(int(e->x()/hzm),int(e->y()/vzm)), e->buttons(), 0 );
00527 }
00528
00529 void QVFbView::contextMenuEvent( QContextMenuEvent* )
00530 {
00531
00532 }
00533
00534 void QVFbView::mouseDoubleClickEvent( QMouseEvent *e )
00535 {
00536 sendMouseData( QPoint(int(e->x()/hzm),int(e->y()/vzm)), e->buttons(), 0 );
00537 }
00538
00539 void QVFbView::mouseReleaseEvent( QMouseEvent *e )
00540 {
00541 sendMouseData( QPoint(int(e->x()/hzm),int(e->y()/vzm)), e->buttons(), 0 );
00542 }
00543
00544 void QVFbView::skinMouseEvent( QMouseEvent *e )
00545 {
00546 sendMouseData( QPoint(int(e->x()/hzm),int(e->y()/vzm)), e->buttons(), 0 );
00547 }
00548
00549 void QVFbView::mouseMoveEvent( QMouseEvent *e )
00550 {
00551 if ( !emulateTouchscreen || (e->buttons() & Qt::MouseButtonMask ) )
00552 sendMouseData( QPoint(int(e->x()/hzm),int(e->y()/vzm)), e->buttons(), 0 );
00553 }
00554
00555 void QVFbView::wheelEvent( QWheelEvent *e )
00556 {
00557 if (!e)
00558 return;
00559 sendMouseData( QPoint(int(e->x()/hzm),int(e->y()/vzm)), e->buttons(), e->delta());
00560 }
00561
00562 void QVFbView::setTouchscreenEmulation( bool b )
00563 {
00564 emulateTouchscreen = b;
00565 }
00566
00567 void QVFbView::setLcdScreenEmulation( bool b )
00568 {
00569 emulateLcdScreen = b;
00570 }
00571
00572 void QVFbView::keyPressEvent( QKeyEvent *e )
00573 {
00574 sendKeyboardData(e->text(), e->key(),
00575 e->modifiers()&(Qt::ShiftModifier|Qt::ControlModifier|Qt::AltModifier),
00576 true, e->isAutoRepeat());
00577 }
00578
00579 void QVFbView::keyReleaseEvent( QKeyEvent *e )
00580 {
00581 sendKeyboardData(e->text(), e->key(),
00582 e->modifiers()&(Qt::ShiftModifier|Qt::ControlModifier|Qt::AltModifier),
00583 false, e->isAutoRepeat());
00584 }
00585
00586
00587 QImage QVFbView::image() const
00588 {
00589 int l;
00590 QImage r = getBuffer( QRect(0, 0, mView->width(), mView->height()), l ).copy();
00591 return r;
00592 }
00593
00594 void QVFbView::startAnimation( const QString& filename )
00595 {
00596 delete animation;
00597 animation = new QAnimationWriter(filename,"MNG");
00598 animation->setFrameRate(refreshRate);
00599 animation->appendFrame(QImage(mView->data(),
00600 mView->width(), mView->height(), QImage::Format_RGB32));
00601 }
00602
00603 void QVFbView::stopAnimation()
00604 {
00605 delete animation;
00606 animation = 0;
00607 }
00608
00609
00610 void QVFbView::skinKeyPressEvent( int code, const QString& text, bool autorep )
00611 {
00612 QKeyEvent e(QEvent::KeyPress,code,0,text,autorep);
00613 keyPressEvent(&e);
00614 }
00615
00616 void QVFbView::skinKeyReleaseEvent( int code, const QString& text, bool autorep )
00617 {
00618 QKeyEvent e(QEvent::KeyRelease,code,0,text,autorep);
00619 keyReleaseEvent(&e);
00620 }