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