1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qlinuxfbintegration.h"
43 #include "../fb_base/fb_base.h"
44 #include "qgenericunixfontdatabase.h"
45 #include <QtGui/private/qpixmap_raster_p.h>
46 #include <private/qcore_unix_p.h> // overrides QT_OPEN
47 #include <qimage.h>
48 #include <qdebug.h>
49
50 #include <unistd.h>
51 #include <stdlib.h>
52 #include <sys/ioctl.h>
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <sys/mman.h>
56 #include <sys/kd.h>
57 #include <fcntl.h>
58 #include <errno.h>
59 #include <stdio.h>
60 #include <limits.h>
61 #include <signal.h>
62
63 #if !defined(Q_OS_DARWIN) && !defined(Q_OS_FREEBSD)
64 #include <linux/fb.h>
65
66 #ifdef __i386__
67 #include <asm/mtrr.h>
68 #endif
69 #endif
70
71 QT_BEGIN_NAMESPACE
72
73 class QLinuxFbIntegrationPrivate
74 {
75 public:
76 QLinuxFbIntegrationPrivate();
77 ~QLinuxFbIntegrationPrivate();
78
79 void openTty();
80 void closeTty();
81
82 int fd;
83 int startupw;
84 int startuph;
85 int startupd;
86 bool blank;
87
88 bool doGraphicsMode;
89 #ifdef QT_QWS_DEPTH_GENERIC
90 bool doGenericColors;
91 #endif
92 int ttyfd;
93 long oldKdMode;
94 QString ttyDevice;
95 QString displaySpec;
96 };
97
QLinuxFbIntegrationPrivate()98 QLinuxFbIntegrationPrivate::QLinuxFbIntegrationPrivate()
99 : fd(-1), blank(true), doGraphicsMode(true),
100 #ifdef QT_QWS_DEPTH_GENERIC
101 doGenericColors(false),
102 #endif
103 ttyfd(-1), oldKdMode(KD_TEXT)
104 {
105 }
106
~QLinuxFbIntegrationPrivate()107 QLinuxFbIntegrationPrivate::~QLinuxFbIntegrationPrivate()
108 {
109 closeTty();
110 }
111
openTty()112 void QLinuxFbIntegrationPrivate::openTty()
113 {
114 const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0};
115
116 if (ttyDevice.isEmpty()) {
117 for (const char * const *dev = devs; *dev; ++dev) {
118 ttyfd = QT_OPEN(*dev, O_RDWR);
119 if (ttyfd != -1)
120 break;
121 }
122 } else {
123 ttyfd = QT_OPEN(ttyDevice.toAscii().constData(), O_RDWR);
124 }
125
126 if (ttyfd == -1)
127 return;
128
129 if (doGraphicsMode) {
130 ioctl(ttyfd, KDGETMODE, &oldKdMode);
131 if (oldKdMode != KD_GRAPHICS) {
132 int ret = ioctl(ttyfd, KDSETMODE, KD_GRAPHICS);
133 if (ret == -1)
134 doGraphicsMode = false;
135 }
136 }
137
138 // No blankin' screen, no blinkin' cursor!, no cursor!
139 const char termctl[] = "\033[9;0]\033[?33l\033[?25l\033[?1c";
140 QT_WRITE(ttyfd, termctl, sizeof(termctl));
141 }
142
closeTty()143 void QLinuxFbIntegrationPrivate::closeTty()
144 {
145 if (ttyfd == -1)
146 return;
147
148 if (doGraphicsMode)
149 ioctl(ttyfd, KDSETMODE, oldKdMode);
150
151 // Blankin' screen, blinkin' cursor!
152 const char termctl[] = "\033[9;15]\033[?33h\033[?25h\033[?0c";
153 QT_WRITE(ttyfd, termctl, sizeof(termctl));
154
155 QT_CLOSE(ttyfd);
156 ttyfd = -1;
157 }
158
QLinuxFbIntegration()159 QLinuxFbIntegration::QLinuxFbIntegration()
160 :fontDb(new QGenericUnixFontDatabase())
161 {
162 d_ptr = new QLinuxFbIntegrationPrivate();
163
164 // XXX
165 QString displaySpec = QString::fromLatin1(qgetenv("QWS_DISPLAY"));
166
167 if (!connect(displaySpec))
168 qFatal("QLinuxFbIntegration: could not initialize screen");
169 initDevice();
170
171 // Create a QImage directly on the screen's framebuffer.
172 // This is the blit target for copying windows to the screen.
173 mPrimaryScreen = new QLinuxFbScreen(data, w, h, lstep,
174 screenFormat);
175 mPrimaryScreen->setPhysicalSize(QSize(physWidth, physHeight));
176 mScreens.append(mPrimaryScreen);
177 }
178
~QLinuxFbIntegration()179 QLinuxFbIntegration::~QLinuxFbIntegration()
180 {
181 delete mPrimaryScreen;
182 delete d_ptr;
183 }
184
connect(const QString & displaySpec)185 bool QLinuxFbIntegration::connect(const QString &displaySpec)
186 {
187 const QStringList args = displaySpec.split(QLatin1Char(':'));
188
189 if (args.contains(QLatin1String("nographicsmodeswitch")))
190 d_ptr->doGraphicsMode = false;
191
192 #ifdef QT_QWS_DEPTH_GENERIC
193 if (args.contains(QLatin1String("genericcolors")))
194 d_ptr->doGenericColors = true;
195 #endif
196
197 QRegExp ttyRegExp(QLatin1String("tty=(.*)"));
198 if (args.indexOf(ttyRegExp) != -1)
199 d_ptr->ttyDevice = ttyRegExp.cap(1);
200
201 #if 0
202 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
203 #ifndef QT_QWS_FRAMEBUFFER_LITTLE_ENDIAN
204 if (args.contains(QLatin1String("littleendian")))
205 #endif
206 QScreen::setFrameBufferLittleEndian(true);
207 #endif
208 #endif
209
210 // Check for explicitly specified device
211 const int len = 8; // "/dev/fbx"
212 int m = displaySpec.indexOf(QLatin1String("/dev/fb"));
213
214 QString dev;
215 if (m > 0)
216 dev = displaySpec.mid(m, len);
217 else
218 dev = QLatin1String("/dev/fb0");
219
220 if (access(dev.toLatin1().constData(), R_OK|W_OK) == 0)
221 d_ptr->fd = QT_OPEN(dev.toLatin1().constData(), O_RDWR);
222 if (d_ptr->fd == -1) {
223 if (access(dev.toLatin1().constData(), R_OK) == 0)
224 d_ptr->fd = QT_OPEN(dev.toLatin1().constData(), O_RDONLY);
225 if (d_ptr->fd == 1) {
226 qWarning("Error opening framebuffer device %s", qPrintable(dev));
227 return false;
228 }
229 }
230
231 fb_fix_screeninfo finfo;
232 fb_var_screeninfo vinfo;
233 //#######################
234 // Shut up Valgrind
235 memset(&vinfo, 0, sizeof(vinfo));
236 memset(&finfo, 0, sizeof(finfo));
237 //#######################
238
239 /* Get fixed screen information */
240 if (d_ptr->fd != -1 && ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) {
241 perror("QLinuxFbIntegration::connect");
242 qWarning("Error reading fixed information");
243 return false;
244 }
245
246 if (finfo.type == FB_TYPE_VGA_PLANES) {
247 qWarning("VGA16 video mode not supported");
248 return false;
249 }
250
251 /* Get variable screen information */
252 if (d_ptr->fd != -1 && ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
253 perror("QLinuxFbIntegration::connect");
254 qWarning("Error reading variable information");
255 return false;
256 }
257
258 grayscale = vinfo.grayscale;
259 d = vinfo.bits_per_pixel;
260 if (d == 24) {
261 d = vinfo.red.length + vinfo.green.length + vinfo.blue.length;
262 if (d <= 0)
263 d = 24; // reset if color component lengths are not reported
264 } else if (d == 16) {
265 d = vinfo.red.length + vinfo.green.length + vinfo.blue.length;
266 if (d <= 0)
267 d = 16;
268 }
269 lstep = finfo.line_length;
270
271 int xoff = vinfo.xoffset;
272 int yoff = vinfo.yoffset;
273 const char* qwssize;
274 if((qwssize=::getenv("QWS_SIZE")) && sscanf(qwssize,"%dx%d",&w,&h)==2) {
275 if (d_ptr->fd != -1) {
276 if ((uint)w > vinfo.xres) w = vinfo.xres;
277 if ((uint)h > vinfo.yres) h = vinfo.yres;
278 }
279 dw=w;
280 dh=h;
281 int xxoff, yyoff;
282 if (sscanf(qwssize, "%*dx%*d+%d+%d", &xxoff, &yyoff) == 2) {
283 if (xxoff < 0 || xxoff + w > (int)(vinfo.xres))
284 xxoff = vinfo.xres - w;
285 if (yyoff < 0 || yyoff + h > (int)(vinfo.yres))
286 yyoff = vinfo.yres - h;
287 xoff += xxoff;
288 yoff += yyoff;
289 } else {
290 xoff += (vinfo.xres - w)/2;
291 yoff += (vinfo.yres - h)/2;
292 }
293 } else {
294 dw=w=vinfo.xres;
295 dh=h=vinfo.yres;
296 }
297
298 if (w == 0 || h == 0) {
299 qWarning("QLinuxFbIntegration::connect(): Unable to find screen geometry, "
300 "will use 320x240.");
301 dw = w = 320;
302 dh = h = 240;
303 }
304
305 setPixelFormat(vinfo);
306
307 // Handle display physical size spec.
308 QStringList displayArgs = displaySpec.split(QLatin1Char(':'));
309 QRegExp mmWidthRx(QLatin1String("mmWidth=?(\\d+)"));
310 int dimIdxW = displayArgs.indexOf(mmWidthRx);
311 QRegExp mmHeightRx(QLatin1String("mmHeight=?(\\d+)"));
312 int dimIdxH = displayArgs.indexOf(mmHeightRx);
313 if (dimIdxW >= 0) {
314 mmWidthRx.exactMatch(displayArgs.at(dimIdxW));
315 physWidth = mmWidthRx.cap(1).toInt();
316 if (dimIdxH < 0)
317 physHeight = dh*physWidth/dw;
318 }
319 if (dimIdxH >= 0) {
320 mmHeightRx.exactMatch(displayArgs.at(dimIdxH));
321 physHeight = mmHeightRx.cap(1).toInt();
322 if (dimIdxW < 0)
323 physWidth = dw*physHeight/dh;
324 }
325 if (dimIdxW < 0 && dimIdxH < 0) {
326 if (vinfo.width != 0 && vinfo.height != 0
327 && vinfo.width != UINT_MAX && vinfo.height != UINT_MAX) {
328 physWidth = vinfo.width;
329 physHeight = vinfo.height;
330 } else {
331 const int dpi = 72;
332 physWidth = qRound(dw * 25.4 / dpi);
333 physHeight = qRound(dh * 25.4 / dpi);
334 }
335 }
336
337 dataoffset = yoff * lstep + xoff * d / 8;
338 //qDebug("Using %dx%dx%d screen",w,h,d);
339
340 /* Figure out the size of the screen in bytes */
341 size = h * lstep;
342
343 mapsize = finfo.smem_len;
344
345 data = (unsigned char *)-1;
346 if (d_ptr->fd != -1)
347 data = (unsigned char *)mmap(0, mapsize, PROT_READ | PROT_WRITE,
348 MAP_SHARED, d_ptr->fd, 0);
349
350 if ((long)data == -1) {
351 perror("QLinuxFbIntegration::connect");
352 qWarning("Error: failed to map framebuffer device to memory.");
353 return false;
354 } else {
355 data += dataoffset;
356 }
357
358 #if 0
359 canaccel = useOffscreen();
360 if(canaccel)
361 setupOffScreen();
362 #endif
363 canaccel = false;
364
365 // Now read in palette
366 if((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4)) {
367 screencols= (vinfo.bits_per_pixel==8) ? 256 : 16;
368 int loopc;
369 fb_cmap startcmap;
370 startcmap.start=0;
371 startcmap.len=screencols;
372 startcmap.red=(unsigned short int *)
373 malloc(sizeof(unsigned short int)*screencols);
374 startcmap.green=(unsigned short int *)
375 malloc(sizeof(unsigned short int)*screencols);
376 startcmap.blue=(unsigned short int *)
377 malloc(sizeof(unsigned short int)*screencols);
378 startcmap.transp=(unsigned short int *)
379 malloc(sizeof(unsigned short int)*screencols);
380 if (d_ptr->fd == -1 || ioctl(d_ptr->fd, FBIOGETCMAP, &startcmap)) {
381 perror("QLinuxFbIntegration::connect");
382 qWarning("Error reading palette from framebuffer, using default palette");
383 createPalette(startcmap, vinfo, finfo);
384 }
385 int bits_used = 0;
386 for(loopc=0;loopc<screencols;loopc++) {
387 screenclut[loopc]=qRgb(startcmap.red[loopc] >> 8,
388 startcmap.green[loopc] >> 8,
389 startcmap.blue[loopc] >> 8);
390 bits_used |= startcmap.red[loopc]
391 | startcmap.green[loopc]
392 | startcmap.blue[loopc];
393 }
394 // WORKAROUND: Some framebuffer drivers only return 8 bit
395 // color values, so we need to not bit shift them..
396 if ((bits_used & 0x00ff) && !(bits_used & 0xff00)) {
397 for(loopc=0;loopc<screencols;loopc++) {
398 screenclut[loopc] = qRgb(startcmap.red[loopc],
399 startcmap.green[loopc],
400 startcmap.blue[loopc]);
401 }
402 qWarning("8 bits cmap returned due to faulty FB driver, colors corrected");
403 }
404 free(startcmap.red);
405 free(startcmap.green);
406 free(startcmap.blue);
407 free(startcmap.transp);
408 } else {
409 screencols=0;
410 }
411
412 return true;
413 }
414
initDevice()415 bool QLinuxFbIntegration::initDevice()
416 {
417 d_ptr->openTty();
418
419 // Grab current mode so we can reset it
420 fb_var_screeninfo vinfo;
421 fb_fix_screeninfo finfo;
422 //#######################
423 // Shut up Valgrind
424 memset(&vinfo, 0, sizeof(vinfo));
425 memset(&finfo, 0, sizeof(finfo));
426 //#######################
427
428 if (ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) {
429 perror("QLinuxFbScreen::initDevice");
430 qFatal("Error reading variable information in card init");
431 return false;
432 }
433
434 #ifdef DEBUG_VINFO
435 qDebug("Greyscale %d",vinfo.grayscale);
436 qDebug("Nonstd %d",vinfo.nonstd);
437 qDebug("Red %d %d %d",vinfo.red.offset,vinfo.red.length,
438 vinfo.red.msb_right);
439 qDebug("Green %d %d %d",vinfo.green.offset,vinfo.green.length,
440 vinfo.green.msb_right);
441 qDebug("Blue %d %d %d",vinfo.blue.offset,vinfo.blue.length,
442 vinfo.blue.msb_right);
443 qDebug("Transparent %d %d %d",vinfo.transp.offset,vinfo.transp.length,
444 vinfo.transp.msb_right);
445 #endif
446
447 d_ptr->startupw=vinfo.xres;
448 d_ptr->startuph=vinfo.yres;
449 d_ptr->startupd=vinfo.bits_per_pixel;
450 grayscale = vinfo.grayscale;
451
452 if (ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) {
453 perror("QLinuxFbScreen::initDevice");
454 qCritical("Error reading fixed information in card init");
455 // It's not an /error/ as such, though definitely a bad sign
456 // so we return true
457 return true;
458 }
459
460 #ifdef __i386__
461 // Now init mtrr
462 if(!::getenv("QWS_NOMTRR")) {
463 int mfd=QT_OPEN("/proc/mtrr",O_WRONLY,0);
464 // MTRR entry goes away when file is closed - i.e.
465 // hopefully when QWS is killed
466 if(mfd != -1) {
467 mtrr_sentry sentry;
468 sentry.base=(unsigned long int)finfo.smem_start;
469 //qDebug("Physical framebuffer address %p",(void*)finfo.smem_start);
470 // Size needs to be in 4k chunks, but that's not always
471 // what we get thanks to graphics card registers. Write combining
472 // these is Not Good, so we write combine what we can
473 // (which is not much - 4 megs on an 8 meg card, it seems)
474 unsigned int size=finfo.smem_len;
475 size=size >> 22;
476 size=size << 22;
477 sentry.size=size;
478 sentry.type=MTRR_TYPE_WRCOMB;
479 if(ioctl(mfd,MTRRIOC_ADD_ENTRY,&sentry)==-1) {
480 //printf("Couldn't add mtrr entry for %lx %lx, %s\n",
481 //sentry.base,sentry.size,strerror(errno));
482 }
483 }
484
485 // Should we close mfd here?
486 //QT_CLOSE(mfd);
487 }
488 #endif
489 if ((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4) || (finfo.visual==FB_VISUAL_DIRECTCOLOR))
490 {
491 fb_cmap cmap;
492 createPalette(cmap, vinfo, finfo);
493 if (ioctl(d_ptr->fd, FBIOPUTCMAP, &cmap)) {
494 perror("QLinuxFbScreen::initDevice");
495 qWarning("Error writing palette to framebuffer");
496 }
497 free(cmap.red);
498 free(cmap.green);
499 free(cmap.blue);
500 free(cmap.transp);
501 }
502
503 #if 0
504 if (canaccel) {
505 *entryp=0;
506 *lowest = mapsize;
507 insert_entry(*entryp, *lowest, *lowest); // dummy entry to mark start
508 }
509
510 shared->fifocount = 0;
511 shared->buffer_offset = 0xffffffff; // 0 would be a sensible offset (screen)
512 shared->linestep = 0;
513 shared->cliptop = 0xffffffff;
514 shared->clipleft = 0xffffffff;
515 shared->clipright = 0xffffffff;
516 shared->clipbottom = 0xffffffff;
517 shared->rop = 0xffffffff;
518 #endif
519
520 #ifdef QT_QWS_DEPTH_GENERIC
521 if (pixelFormat() == QImage::Format_Invalid && screencols == 0
522 && d_ptr->doGenericColors)
523 {
524 qt_set_generic_blit(this, vinfo.bits_per_pixel,
525 vinfo.red.length, vinfo.green.length,
526 vinfo.blue.length, vinfo.transp.length,
527 vinfo.red.offset, vinfo.green.offset,
528 vinfo.blue.offset, vinfo.transp.offset);
529 }
530 #endif
531
532 #if 0
533 #ifndef QT_NO_QWS_CURSOR
534 QScreenCursor::initSoftwareCursor();
535 #endif
536 #endif
537 blank(false);
538
539 return true;
540 }
541
setPixelFormat(struct fb_var_screeninfo info)542 void QLinuxFbIntegration::setPixelFormat(struct fb_var_screeninfo info)
543 {
544 const fb_bitfield rgba[4] = { info.red, info.green,
545 info.blue, info.transp };
546
547 QImage::Format format = QImage::Format_Invalid;
548
549 switch (d) {
550 case 32: {
551 const fb_bitfield argb8888[4] = {{16, 8, 0}, {8, 8, 0},
552 {0, 8, 0}, {24, 8, 0}};
553 const fb_bitfield abgr8888[4] = {{0, 8, 0}, {8, 8, 0},
554 {16, 8, 0}, {24, 8, 0}};
555 if (memcmp(rgba, argb8888, 4 * sizeof(fb_bitfield)) == 0) {
556 format = QImage::Format_ARGB32;
557 } else if (memcmp(rgba, argb8888, 3 * sizeof(fb_bitfield)) == 0) {
558 format = QImage::Format_RGB32;
559 } else if (memcmp(rgba, abgr8888, 3 * sizeof(fb_bitfield)) == 0) {
560 format = QImage::Format_RGB32;
561 pixeltype = BGRPixel;
562 }
563 break;
564 }
565 case 24: {
566 const fb_bitfield rgb888[4] = {{16, 8, 0}, {8, 8, 0},
567 {0, 8, 0}, {0, 0, 0}};
568 const fb_bitfield bgr888[4] = {{0, 8, 0}, {8, 8, 0},
569 {16, 8, 0}, {0, 0, 0}};
570 if (memcmp(rgba, rgb888, 3 * sizeof(fb_bitfield)) == 0) {
571 format = QImage::Format_RGB888;
572 } else if (memcmp(rgba, bgr888, 3 * sizeof(fb_bitfield)) == 0) {
573 format = QImage::Format_RGB888;
574 pixeltype = BGRPixel;
575 }
576 break;
577 }
578 case 18: {
579 const fb_bitfield rgb666[4] = {{12, 6, 0}, {6, 6, 0},
580 {0, 6, 0}, {0, 0, 0}};
581 if (memcmp(rgba, rgb666, 3 * sizeof(fb_bitfield)) == 0)
582 format = QImage::Format_RGB666;
583 break;
584 }
585 case 16: {
586 const fb_bitfield rgb565[4] = {{11, 5, 0}, {5, 6, 0},
587 {0, 5, 0}, {0, 0, 0}};
588 const fb_bitfield bgr565[4] = {{0, 5, 0}, {5, 6, 0},
589 {11, 5, 0}, {0, 0, 0}};
590 if (memcmp(rgba, rgb565, 3 * sizeof(fb_bitfield)) == 0) {
591 format = QImage::Format_RGB16;
592 } else if (memcmp(rgba, bgr565, 3 * sizeof(fb_bitfield)) == 0) {
593 format = QImage::Format_RGB16;
594 pixeltype = BGRPixel;
595 }
596 break;
597 }
598 case 15: {
599 const fb_bitfield rgb1555[4] = {{10, 5, 0}, {5, 5, 0},
600 {0, 5, 0}, {15, 1, 0}};
601 const fb_bitfield bgr1555[4] = {{0, 5, 0}, {5, 5, 0},
602 {10, 5, 0}, {15, 1, 0}};
603 if (memcmp(rgba, rgb1555, 3 * sizeof(fb_bitfield)) == 0) {
604 format = QImage::Format_RGB555;
605 } else if (memcmp(rgba, bgr1555, 3 * sizeof(fb_bitfield)) == 0) {
606 format = QImage::Format_RGB555;
607 pixeltype = BGRPixel;
608 }
609 break;
610 }
611 case 12: {
612 const fb_bitfield rgb444[4] = {{8, 4, 0}, {4, 4, 0},
613 {0, 4, 0}, {0, 0, 0}};
614 if (memcmp(rgba, rgb444, 3 * sizeof(fb_bitfield)) == 0)
615 format = QImage::Format_RGB444;
616 break;
617 }
618 case 8:
619 break;
620 case 1:
621 format = QImage::Format_Mono; //###: LSB???
622 break;
623 default:
624 break;
625 }
626
627 screenFormat = format;
628 }
629
createPalette(fb_cmap & cmap,fb_var_screeninfo & vinfo,fb_fix_screeninfo & finfo)630 void QLinuxFbIntegration::createPalette(fb_cmap &cmap, fb_var_screeninfo &vinfo, fb_fix_screeninfo &finfo)
631 {
632 if((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4)) {
633 screencols= (vinfo.bits_per_pixel==8) ? 256 : 16;
634 cmap.start=0;
635 cmap.len=screencols;
636 cmap.red=(unsigned short int *)
637 malloc(sizeof(unsigned short int)*screencols);
638 cmap.green=(unsigned short int *)
639 malloc(sizeof(unsigned short int)*screencols);
640 cmap.blue=(unsigned short int *)
641 malloc(sizeof(unsigned short int)*screencols);
642 cmap.transp=(unsigned short int *)
643 malloc(sizeof(unsigned short int)*screencols);
644
645 if (screencols==16) {
646 if (finfo.type == FB_TYPE_PACKED_PIXELS) {
647 // We'll setup a grayscale cmap for 4bpp linear
648 int val = 0;
649 for (int idx = 0; idx < 16; ++idx, val += 17) {
650 cmap.red[idx] = (val<<8)|val;
651 cmap.green[idx] = (val<<8)|val;
652 cmap.blue[idx] = (val<<8)|val;
653 screenclut[idx]=qRgb(val, val, val);
654 }
655 } else {
656 // Default 16 colour palette
657 // Green is now trolltech green so certain images look nicer
658 // black d_gray l_gray white red green blue cyan magenta yellow
659 unsigned char reds[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0xFF, 0xA2, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x82 };
660 unsigned char greens[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0x00, 0xC5, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F };
661 unsigned char blues[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0x00, 0x11, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0x7F, 0x7F, 0x00, 0x00 };
662
663 for (int idx = 0; idx < 16; ++idx) {
664 cmap.red[idx] = ((reds[idx]) << 8)|reds[idx];
665 cmap.green[idx] = ((greens[idx]) << 8)|greens[idx];
666 cmap.blue[idx] = ((blues[idx]) << 8)|blues[idx];
667 cmap.transp[idx] = 0;
668 screenclut[idx]=qRgb(reds[idx], greens[idx], blues[idx]);
669 }
670 }
671 } else {
672 if (grayscale) {
673 // Build grayscale palette
674 int i;
675 for(i=0;i<screencols;++i) {
676 int bval = screencols == 256 ? i : (i << 4);
677 ushort val = (bval << 8) | bval;
678 cmap.red[i] = val;
679 cmap.green[i] = val;
680 cmap.blue[i] = val;
681 cmap.transp[i] = 0;
682 screenclut[i] = qRgb(bval,bval,bval);
683 }
684 } else {
685 // 6x6x6 216 color cube
686 int idx = 0;
687 for(int ir = 0x0; ir <= 0xff; ir+=0x33) {
688 for(int ig = 0x0; ig <= 0xff; ig+=0x33) {
689 for(int ib = 0x0; ib <= 0xff; ib+=0x33) {
690 cmap.red[idx] = (ir << 8)|ir;
691 cmap.green[idx] = (ig << 8)|ig;
692 cmap.blue[idx] = (ib << 8)|ib;
693 cmap.transp[idx] = 0;
694 screenclut[idx]=qRgb(ir, ig, ib);
695 ++idx;
696 }
697 }
698 }
699 // Fill in rest with 0
700 for (int loopc=0; loopc<40; ++loopc) {
701 screenclut[idx]=0;
702 ++idx;
703 }
704 screencols=idx;
705 }
706 }
707 } else if(finfo.visual==FB_VISUAL_DIRECTCOLOR) {
708 cmap.start=0;
709 int rbits=0,gbits=0,bbits=0;
710 switch (vinfo.bits_per_pixel) {
711 case 8:
712 rbits=vinfo.red.length;
713 gbits=vinfo.green.length;
714 bbits=vinfo.blue.length;
715 if(rbits==0 && gbits==0 && bbits==0) {
716 // cyber2000 driver bug hack
717 rbits=3;
718 gbits=3;
719 bbits=2;
720 }
721 break;
722 case 15:
723 rbits=5;
724 gbits=5;
725 bbits=5;
726 break;
727 case 16:
728 rbits=5;
729 gbits=6;
730 bbits=5;
731 break;
732 case 18:
733 case 19:
734 rbits=6;
735 gbits=6;
736 bbits=6;
737 break;
738 case 24: case 32:
739 rbits=gbits=bbits=8;
740 break;
741 }
742 screencols=cmap.len=1<<qMax(rbits,qMax(gbits,bbits));
743 cmap.red=(unsigned short int *)
744 malloc(sizeof(unsigned short int)*256);
745 cmap.green=(unsigned short int *)
746 malloc(sizeof(unsigned short int)*256);
747 cmap.blue=(unsigned short int *)
748 malloc(sizeof(unsigned short int)*256);
749 cmap.transp=(unsigned short int *)
750 malloc(sizeof(unsigned short int)*256);
751 for(unsigned int i = 0x0; i < cmap.len; i++) {
752 cmap.red[i] = i*65535/((1<<rbits)-1);
753 cmap.green[i] = i*65535/((1<<gbits)-1);
754 cmap.blue[i] = i*65535/((1<<bbits)-1);
755 cmap.transp[i] = 0;
756 }
757 }
758 }
759
blank(bool on)760 void QLinuxFbIntegration::blank(bool on)
761 {
762 if (d_ptr->blank == on)
763 return;
764
765 #if defined(QT_QWS_IPAQ)
766 if (on)
767 system("apm -suspend");
768 #else
769 if (d_ptr->fd == -1)
770 return;
771 // Some old kernel versions don't have this. These defines should go
772 // away eventually
773 #if defined(FBIOBLANK)
774 #if defined(VESA_POWERDOWN) && defined(VESA_NO_BLANKING)
775 ioctl(d_ptr->fd, FBIOBLANK, on ? VESA_POWERDOWN : VESA_NO_BLANKING);
776 #else
777 ioctl(d_ptr->fd, FBIOBLANK, on ? 1 : 0);
778 #endif
779 #endif
780 #endif
781
782 d_ptr->blank = on;
783 }
784
hasCapability(QPlatformIntegration::Capability cap) const785 bool QLinuxFbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
786 {
787 switch (cap) {
788 case ThreadedPixmaps: return true;
789 default: return QPlatformIntegration::hasCapability(cap);
790 }
791 }
792
793
createPixmapData(QPixmapData::PixelType type) const794 QPixmapData *QLinuxFbIntegration::createPixmapData(QPixmapData::PixelType type) const
795 {
796 return new QRasterPixmapData(type);
797 }
798
createWindowSurface(QWidget * widget,WId) const799 QWindowSurface *QLinuxFbIntegration::createWindowSurface(QWidget *widget, WId) const
800 {
801 QFbWindowSurface * surface =
802 new QFbWindowSurface(mPrimaryScreen, widget);
803 return surface;
804 }
805
createPlatformWindow(QWidget * widget,WId) const806 QPlatformWindow *QLinuxFbIntegration::createPlatformWindow(QWidget *widget, WId /*winId*/) const
807 {
808 QFbWindow *w = new QFbWindow(widget);
809 mPrimaryScreen->addWindow(w);
810 return w;
811 }
812
fontDatabase() const813 QPlatformFontDatabase *QLinuxFbIntegration::fontDatabase() const
814 {
815 return fontDb;
816 }
817
QLinuxFbScreen(uchar * d,int w,int h,int lstep,QImage::Format screenFormat)818 QLinuxFbScreen::QLinuxFbScreen(uchar * d, int w,
819 int h, int lstep, QImage::Format screenFormat) : compositePainter(0)
820 {
821 data = d;
822 mGeometry = QRect(0,0,w,h);
823 bytesPerLine = lstep;
824 mFormat = screenFormat;
825 mDepth = 16;
826 mScreenImage = new QImage(mGeometry.width(), mGeometry.height(),
827 mFormat);
828 mFbScreenImage = new QImage(data, mGeometry.width(), mGeometry.height(),
829 bytesPerLine, mFormat);
830 #ifndef QT_NO_CURSOR
831 cursor = new QPlatformSoftwareCursor(this);
832 #endif
833 }
834
setGeometry(QRect rect)835 void QLinuxFbScreen::setGeometry(QRect rect)
836 {
837 mGeometry = rect;
838 delete mFbScreenImage;
839 mFbScreenImage = new QImage(data, mGeometry.width(), mGeometry.height(),
840 bytesPerLine, mFormat);
841 delete compositePainter;
842 compositePainter = 0;
843
844 delete mScreenImage;
845 mScreenImage = new QImage(mGeometry.width(), mGeometry.height(),
846 mFormat);
847 }
848
setFormat(QImage::Format format)849 void QLinuxFbScreen::setFormat(QImage::Format format)
850 {
851 mFormat = format;
852 delete mFbScreenImage;
853 mFbScreenImage = new QImage(data, mGeometry.width(), mGeometry.height(),
854 bytesPerLine, mFormat);
855 delete compositePainter;
856 compositePainter = 0;
857
858 delete mScreenImage;
859 mScreenImage = new QImage(mGeometry.width(), mGeometry.height(),
860 mFormat);
861 }
862
doRedraw()863 QRegion QLinuxFbScreen::doRedraw()
864 {
865 QRegion touched;
866 touched = QFbScreen::doRedraw();
867
868 if (!compositePainter) {
869 compositePainter = new QPainter(mFbScreenImage);
870 }
871
872 QVector<QRect> rects = touched.rects();
873 for (int i = 0; i < rects.size(); i++)
874 compositePainter->drawImage(rects[i], *mScreenImage, rects[i]);
875 return touched;
876 }
877 QT_END_NAMESPACE
878