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 QtGui module 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 #ifndef QT_NO_QWS_QVFB
43
44 #define QTOPIA_QVFB_BRIGHTNESS
45
46 #include <stdlib.h>
47 #include <sys/types.h>
48 #include <sys/ipc.h>
49 #include <sys/shm.h>
50 #include <sys/stat.h>
51 #include <unistd.h>
52 #include <fcntl.h>
53 #include <errno.h>
54
55 #include <qvfbhdr.h>
56 #include <qscreenvfb_qws.h>
57 #include <qkbdvfb_qws.h>
58 #include <qmousevfb_qws.h>
59 #include <qwindowsystem_qws.h>
60 #include <qsocketnotifier.h>
61 #include <qapplication.h>
62 #include <qscreen_qws.h>
63 #include <qmousedriverfactory_qws.h>
64 #include <qkbddriverfactory_qws.h>
65 #include <qdebug.h>
66
67 QT_BEGIN_NAMESPACE
68
69 class QVFbScreenPrivate
70 {
71 public:
72 QVFbScreenPrivate();
73 ~QVFbScreenPrivate();
74
75 bool success;
76 unsigned char *shmrgn;
77 int brightness;
78 bool blank;
79 QVFbHeader *hdr;
80 QWSMouseHandler *mouse;
81 #ifndef QT_NO_QWS_KEYBOARD
82 QWSKeyboardHandler *keyboard;
83 #endif
84 };
85
QVFbScreenPrivate()86 QVFbScreenPrivate::QVFbScreenPrivate()
87 : mouse(0)
88
89 {
90 #ifndef QT_NO_QWS_KEYBOARD
91 keyboard = 0;
92 #endif
93 brightness = 255;
94 blank = false;
95 }
96
~QVFbScreenPrivate()97 QVFbScreenPrivate::~QVFbScreenPrivate()
98 {
99 delete mouse;
100 #ifndef QT_NO_QWS_KEYBOARD
101 delete keyboard;
102 #endif
103 }
104
105 /*!
106 \internal
107
108 \class QVFbScreen
109 \ingroup qws
110
111 \brief The QVFbScreen class implements a screen driver for the
112 virtual framebuffer.
113
114 Note that this class is only available in \l{Qt for Embedded Linux}.
115 Custom screen drivers can be added by subclassing the
116 QScreenDriverPlugin class, using the QScreenDriverFactory class to
117 dynamically load the driver into the application, but there should
118 only be one screen object per application.
119
120 The Qt for Embedded Linux platform provides a \l{The Virtual
121 Framebuffer}{virtual framebuffer} for development and debugging;
122 the virtual framebuffer allows Qt for Embedded Linux applications to be
123 developed on a desktop machine, without switching between consoles
124 and X11.
125
126 \sa QScreen, QScreenDriverPlugin, {Running Applications}
127 */
128
129 /*!
130 \fn bool QVFbScreen::connect(const QString & displaySpec)
131 \reimp
132 */
133
134 /*!
135 \fn void QVFbScreen::disconnect()
136 \reimp
137 */
138
139 /*!
140 \fn bool QVFbScreen::initDevice()
141 \reimp
142 */
143
144 /*!
145 \fn void QVFbScreen::restore()
146 \reimp
147 */
148
149 /*!
150 \fn void QVFbScreen::save()
151 \reimp
152 */
153
154 /*!
155 \fn void QVFbScreen::setDirty(const QRect & r)
156 \reimp
157 */
158
159 /*!
160 \fn void QVFbScreen::setMode(int nw, int nh, int nd)
161 \reimp
162 */
163
164 /*!
165 \fn void QVFbScreen::shutdownDevice()
166 \reimp
167 */
168
169 /*!
170 \fn QVFbScreen::QVFbScreen(int displayId)
171
172 Constructs a QVNCScreen object. The \a displayId argument
173 identifies the Qt for Embedded Linux server to connect to.
174 */
QVFbScreen(int display_id)175 QVFbScreen::QVFbScreen(int display_id)
176 : QScreen(display_id, VFbClass), d_ptr(new QVFbScreenPrivate)
177 {
178 d_ptr->shmrgn = 0;
179 d_ptr->hdr = 0;
180 data = 0;
181 }
182
183 /*!
184 Destroys this QVFbScreen object.
185 */
~QVFbScreen()186 QVFbScreen::~QVFbScreen()
187 {
188 delete d_ptr;
189 }
190
191 static QVFbScreen *connected = 0;
192
connect(const QString & displaySpec)193 bool QVFbScreen::connect(const QString &displaySpec)
194 {
195 QStringList displayArgs = displaySpec.split(QLatin1Char(':'));
196 if (displayArgs.contains(QLatin1String("Gray")))
197 grayscale = true;
198
199 key_t key = ftok(QT_VFB_MOUSE_PIPE(displayId).toLocal8Bit(), 'b');
200
201 if (key == -1)
202 return false;
203
204 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
205 #ifndef QT_QWS_FRAMEBUFFER_LITTLE_ENDIAN
206 if (displayArgs.contains(QLatin1String("littleendian")))
207 #endif
208 QScreen::setFrameBufferLittleEndian(true);
209 #endif
210
211 int shmId = shmget(key, 0, 0);
212 if (shmId != -1)
213 d_ptr->shmrgn = (unsigned char *)shmat(shmId, 0, 0);
214 else
215 return false;
216
217 if ((long)d_ptr->shmrgn == -1 || d_ptr->shmrgn == 0) {
218 qDebug("No shmrgn %ld", (long)d_ptr->shmrgn);
219 return false;
220 }
221
222 d_ptr->hdr = (QVFbHeader *)d_ptr->shmrgn;
223 data = d_ptr->shmrgn + d_ptr->hdr->dataoffset;
224
225 dw = w = d_ptr->hdr->width;
226 dh = h = d_ptr->hdr->height;
227 d = d_ptr->hdr->depth;
228
229 switch (d) {
230 case 1:
231 setPixelFormat(QImage::Format_Mono);
232 break;
233 case 8:
234 setPixelFormat(QImage::Format_Indexed8);
235 break;
236 case 12:
237 setPixelFormat(QImage::Format_RGB444);
238 break;
239 case 15:
240 setPixelFormat(QImage::Format_RGB555);
241 break;
242 case 16:
243 setPixelFormat(QImage::Format_RGB16);
244 break;
245 case 18:
246 setPixelFormat(QImage::Format_RGB666);
247 break;
248 case 24:
249 setPixelFormat(QImage::Format_RGB888);
250 break;
251 case 32:
252 setPixelFormat(QImage::Format_ARGB32_Premultiplied);
253 break;
254 }
255
256 lstep = d_ptr->hdr->linestep;
257
258 // Handle display physical size spec.
259 int dimIdxW = -1;
260 int dimIdxH = -1;
261 for (int i = 0; i < displayArgs.size(); ++i) {
262 if (displayArgs.at(i).startsWith(QLatin1String("mmWidth"))) {
263 dimIdxW = i;
264 break;
265 }
266 }
267 for (int i = 0; i < displayArgs.size(); ++i) {
268 if (displayArgs.at(i).startsWith(QLatin1String("mmHeight"))) {
269 dimIdxH = i;
270 break;
271 }
272 }
273 if (dimIdxW >= 0) {
274 bool ok;
275 int pos = 7;
276 if (displayArgs.at(dimIdxW).at(pos) == QLatin1Char('='))
277 ++pos;
278 int pw = displayArgs.at(dimIdxW).mid(pos).toInt(&ok);
279 if (ok) {
280 physWidth = pw;
281 if (dimIdxH < 0)
282 physHeight = dh*physWidth/dw;
283 }
284 }
285 if (dimIdxH >= 0) {
286 bool ok;
287 int pos = 8;
288 if (displayArgs.at(dimIdxH).at(pos) == QLatin1Char('='))
289 ++pos;
290 int ph = displayArgs.at(dimIdxH).mid(pos).toInt(&ok);
291 if (ok) {
292 physHeight = ph;
293 if (dimIdxW < 0)
294 physWidth = dw*physHeight/dh;
295 }
296 }
297 if (dimIdxW < 0 && dimIdxH < 0) {
298 const int dpi = 72;
299 physWidth = qRound(dw * 25.4 / dpi);
300 physHeight = qRound(dh * 25.4 / dpi);
301 }
302
303 qDebug("Connected to VFB server %s: %d x %d x %d %dx%dmm (%dx%ddpi)", displaySpec.toLatin1().data(),
304 w, h, d, physWidth, physHeight, qRound(dw*25.4/physWidth), qRound(dh*25.4/physHeight) );
305
306 size = lstep * h;
307 mapsize = size;
308 screencols = d_ptr->hdr->numcols;
309 memcpy(screenclut, d_ptr->hdr->clut, sizeof(QRgb) * screencols);
310
311 connected = this;
312
313 if (qgetenv("QT_QVFB_BGR").toInt())
314 pixeltype = BGRPixel;
315
316 return true;
317 }
318
disconnect()319 void QVFbScreen::disconnect()
320 {
321 connected = 0;
322 if ((long)d_ptr->shmrgn != -1 && d_ptr->shmrgn) {
323 if (qApp->type() == QApplication::GuiServer && d_ptr->hdr->dataoffset >= (int)sizeof(QVFbHeader)) {
324 d_ptr->hdr->serverVersion = 0;
325 }
326 shmdt((char*)d_ptr->shmrgn);
327 }
328 }
329
initDevice()330 bool QVFbScreen::initDevice()
331 {
332 #ifndef QT_NO_QWS_MOUSE_QVFB
333 const QString mouseDev = QT_VFB_MOUSE_PIPE(displayId);
334 d_ptr->mouse = new QVFbMouseHandler(QLatin1String("QVFbMouse"), mouseDev);
335 qwsServer->setDefaultMouse("None");
336 if (d_ptr->mouse)
337 d_ptr->mouse->setScreen(this);
338 #endif
339
340 #if !defined(QT_NO_QWS_KBD_QVFB) && !defined(QT_NO_QWS_KEYBOARD)
341 const QString keyboardDev = QT_VFB_KEYBOARD_PIPE(displayId);
342 d_ptr->keyboard = new QVFbKeyboardHandler(keyboardDev);
343 qwsServer->setDefaultKeyboard("None");
344 #endif
345
346 if (d_ptr->hdr->dataoffset >= (int)sizeof(QVFbHeader))
347 d_ptr->hdr->serverVersion = QT_VERSION;
348
349 if(d==8) {
350 screencols=256;
351 if (grayscale) {
352 // Build grayscale palette
353 for(int loopc=0;loopc<256;loopc++) {
354 screenclut[loopc]=qRgb(loopc,loopc,loopc);
355 }
356 } else {
357 // 6x6x6 216 color cube
358 int idx = 0;
359 for(int ir = 0x0; ir <= 0xff; ir+=0x33) {
360 for(int ig = 0x0; ig <= 0xff; ig+=0x33) {
361 for(int ib = 0x0; ib <= 0xff; ib+=0x33) {
362 screenclut[idx]=qRgb(ir, ig, ib);
363 idx++;
364 }
365 }
366 }
367 screencols=idx;
368 }
369 memcpy(d_ptr->hdr->clut, screenclut, sizeof(QRgb) * screencols);
370 d_ptr->hdr->numcols = screencols;
371 } else if (d == 4) {
372 int val = 0;
373 for (int idx = 0; idx < 16; idx++, val += 17) {
374 screenclut[idx] = qRgb(val, val, val);
375 }
376 screencols = 16;
377 memcpy(d_ptr->hdr->clut, screenclut, sizeof(QRgb) * screencols);
378 d_ptr->hdr->numcols = screencols;
379 } else if (d == 1) {
380 screencols = 2;
381 screenclut[1] = qRgb(0xff, 0xff, 0xff);
382 screenclut[0] = qRgb(0, 0, 0);
383 memcpy(d_ptr->hdr->clut, screenclut, sizeof(QRgb) * screencols);
384 d_ptr->hdr->numcols = screencols;
385 }
386
387 #ifndef QT_NO_QWS_CURSOR
388 QScreenCursor::initSoftwareCursor();
389 #endif
390 return true;
391 }
392
shutdownDevice()393 void QVFbScreen::shutdownDevice()
394 {
395 }
396
setMode(int,int,int)397 void QVFbScreen::setMode(int ,int ,int)
398 {
399 }
400
401 // save the state of the graphics card
402 // This is needed so that e.g. we can restore the palette when switching
403 // between linux virtual consoles.
save()404 void QVFbScreen::save()
405 {
406 // nothing to do.
407 }
408
409 // restore the state of the graphics card.
restore()410 void QVFbScreen::restore()
411 {
412 }
setDirty(const QRect & rect)413 void QVFbScreen::setDirty(const QRect& rect)
414 {
415 const QRect r = rect.translated(-offset());
416 d_ptr->hdr->dirty = true;
417 d_ptr->hdr->update = d_ptr->hdr->update.united(r);
418 }
419
setBrightness(int b)420 void QVFbScreen::setBrightness(int b)
421 {
422 if (connected) {
423 connected->d_ptr->brightness = b;
424
425 QVFbHeader *hdr = connected->d_ptr->hdr;
426 if (hdr->viewerVersion < 0x040400) // brightness not supported
427 return;
428
429 const int br = connected->d_ptr->blank ? 0 : b;
430 if (hdr->brightness != br) {
431 hdr->brightness = br;
432 connected->setDirty(connected->region().boundingRect());
433 }
434 }
435 }
436
blank(bool on)437 void QVFbScreen::blank(bool on)
438 {
439 d_ptr->blank = on;
440 setBrightness(connected->d_ptr->brightness);
441 }
442
443 #endif // QT_NO_QWS_QVFB
444
445 QT_END_NAMESPACE
446