| /**************************************************************************** |
| ** |
| ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). |
| ** All rights reserved. |
| ** Contact: Nokia Corporation (qt-info@nokia.com) |
| ** |
| ** This file is part of the QtGui module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** GNU Lesser General Public License Usage |
| ** This file may be used under the terms of the GNU Lesser General Public |
| ** License version 2.1 as published by the Free Software Foundation and |
| ** appearing in the file LICENSE.LGPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU Lesser |
| ** General Public License version 2.1 requirements will be met: |
| ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| ** |
| ** In addition, as a special exception, Nokia gives you certain additional |
| ** rights. These rights are described in the Nokia Qt LGPL Exception |
| ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU General |
| ** Public License version 3.0 as published by the Free Software Foundation |
| ** and appearing in the file LICENSE.GPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU General |
| ** Public License version 3.0 requirements will be met: |
| ** http://www.gnu.org/copyleft/gpl.html. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #ifndef QT_NO_QWS_QVFB |
| |
| #define QTOPIA_QVFB_BRIGHTNESS |
| |
| #include <stdlib.h> |
| #include <sys/types.h> |
| #include <sys/ipc.h> |
| #include <sys/shm.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| |
| #include <qvfbhdr.h> |
| #include <qscreenvfb_qws.h> |
| #include <qkbdvfb_qws.h> |
| #include <qmousevfb_qws.h> |
| #include <qwindowsystem_qws.h> |
| #include <qsocketnotifier.h> |
| #include <qapplication.h> |
| #include <qscreen_qws.h> |
| #include <qmousedriverfactory_qws.h> |
| #include <qkbddriverfactory_qws.h> |
| #include <qdebug.h> |
| |
| QT_BEGIN_NAMESPACE |
| |
| class QVFbScreenPrivate |
| { |
| public: |
| QVFbScreenPrivate(); |
| ~QVFbScreenPrivate(); |
| |
| bool success; |
| unsigned char *shmrgn; |
| int brightness; |
| bool blank; |
| QVFbHeader *hdr; |
| QWSMouseHandler *mouse; |
| #ifndef QT_NO_QWS_KEYBOARD |
| QWSKeyboardHandler *keyboard; |
| #endif |
| }; |
| |
| QVFbScreenPrivate::QVFbScreenPrivate() |
| : mouse(0) |
| |
| { |
| #ifndef QT_NO_QWS_KEYBOARD |
| keyboard = 0; |
| #endif |
| brightness = 255; |
| blank = false; |
| } |
| |
| QVFbScreenPrivate::~QVFbScreenPrivate() |
| { |
| delete mouse; |
| #ifndef QT_NO_QWS_KEYBOARD |
| delete keyboard; |
| #endif |
| } |
| |
| /*! |
| \internal |
| |
| \class QVFbScreen |
| \ingroup qws |
| |
| \brief The QVFbScreen class implements a screen driver for the |
| virtual framebuffer. |
| |
| Note that this class is only available in \l{Qt for Embedded Linux}. |
| Custom screen drivers can be added by subclassing the |
| QScreenDriverPlugin class, using the QScreenDriverFactory class to |
| dynamically load the driver into the application, but there should |
| only be one screen object per application. |
| |
| The Qt for Embedded Linux platform provides a \l{The Virtual |
| Framebuffer}{virtual framebuffer} for development and debugging; |
| the virtual framebuffer allows Qt for Embedded Linux applications to be |
| developed on a desktop machine, without switching between consoles |
| and X11. |
| |
| \sa QScreen, QScreenDriverPlugin, {Running Applications} |
| */ |
| |
| /*! |
| \fn bool QVFbScreen::connect(const QString & displaySpec) |
| \reimp |
| */ |
| |
| /*! |
| \fn void QVFbScreen::disconnect() |
| \reimp |
| */ |
| |
| /*! |
| \fn bool QVFbScreen::initDevice() |
| \reimp |
| */ |
| |
| /*! |
| \fn void QVFbScreen::restore() |
| \reimp |
| */ |
| |
| /*! |
| \fn void QVFbScreen::save() |
| \reimp |
| */ |
| |
| /*! |
| \fn void QVFbScreen::setDirty(const QRect & r) |
| \reimp |
| */ |
| |
| /*! |
| \fn void QVFbScreen::setMode(int nw, int nh, int nd) |
| \reimp |
| */ |
| |
| /*! |
| \fn void QVFbScreen::shutdownDevice() |
| \reimp |
| */ |
| |
| /*! |
| \fn QVFbScreen::QVFbScreen(int displayId) |
| |
| Constructs a QVNCScreen object. The \a displayId argument |
| identifies the Qt for Embedded Linux server to connect to. |
| */ |
| QVFbScreen::QVFbScreen(int display_id) |
| : QScreen(display_id, VFbClass), d_ptr(new QVFbScreenPrivate) |
| { |
| d_ptr->shmrgn = 0; |
| d_ptr->hdr = 0; |
| data = 0; |
| } |
| |
| /*! |
| Destroys this QVFbScreen object. |
| */ |
| QVFbScreen::~QVFbScreen() |
| { |
| delete d_ptr; |
| } |
| |
| static QVFbScreen *connected = 0; |
| |
| bool QVFbScreen::connect(const QString &displaySpec) |
| { |
| QStringList displayArgs = displaySpec.split(QLatin1Char(':')); |
| if (displayArgs.contains(QLatin1String("Gray"))) |
| grayscale = true; |
| |
| key_t key = ftok(QT_VFB_MOUSE_PIPE(displayId).toLocal8Bit(), 'b'); |
| |
| if (key == -1) |
| return false; |
| |
| #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
| #ifndef QT_QWS_FRAMEBUFFER_LITTLE_ENDIAN |
| if (displayArgs.contains(QLatin1String("littleendian"))) |
| #endif |
| QScreen::setFrameBufferLittleEndian(true); |
| #endif |
| |
| int shmId = shmget(key, 0, 0); |
| if (shmId != -1) |
| d_ptr->shmrgn = (unsigned char *)shmat(shmId, 0, 0); |
| else |
| return false; |
| |
| if ((long)d_ptr->shmrgn == -1 || d_ptr->shmrgn == 0) { |
| qDebug("No shmrgn %ld", (long)d_ptr->shmrgn); |
| return false; |
| } |
| |
| d_ptr->hdr = (QVFbHeader *)d_ptr->shmrgn; |
| data = d_ptr->shmrgn + d_ptr->hdr->dataoffset; |
| |
| dw = w = d_ptr->hdr->width; |
| dh = h = d_ptr->hdr->height; |
| d = d_ptr->hdr->depth; |
| |
| switch (d) { |
| case 1: |
| setPixelFormat(QImage::Format_Mono); |
| break; |
| case 8: |
| setPixelFormat(QImage::Format_Indexed8); |
| break; |
| case 12: |
| setPixelFormat(QImage::Format_RGB444); |
| break; |
| case 15: |
| setPixelFormat(QImage::Format_RGB555); |
| break; |
| case 16: |
| setPixelFormat(QImage::Format_RGB16); |
| break; |
| case 18: |
| setPixelFormat(QImage::Format_RGB666); |
| break; |
| case 24: |
| setPixelFormat(QImage::Format_RGB888); |
| break; |
| case 32: |
| setPixelFormat(QImage::Format_ARGB32_Premultiplied); |
| break; |
| } |
| |
| lstep = d_ptr->hdr->linestep; |
| |
| // Handle display physical size spec. |
| int dimIdxW = -1; |
| int dimIdxH = -1; |
| for (int i = 0; i < displayArgs.size(); ++i) { |
| if (displayArgs.at(i).startsWith(QLatin1String("mmWidth"))) { |
| dimIdxW = i; |
| break; |
| } |
| } |
| for (int i = 0; i < displayArgs.size(); ++i) { |
| if (displayArgs.at(i).startsWith(QLatin1String("mmHeight"))) { |
| dimIdxH = i; |
| break; |
| } |
| } |
| if (dimIdxW >= 0) { |
| bool ok; |
| int pos = 7; |
| if (displayArgs.at(dimIdxW).at(pos) == QLatin1Char('=')) |
| ++pos; |
| int pw = displayArgs.at(dimIdxW).mid(pos).toInt(&ok); |
| if (ok) { |
| physWidth = pw; |
| if (dimIdxH < 0) |
| physHeight = dh*physWidth/dw; |
| } |
| } |
| if (dimIdxH >= 0) { |
| bool ok; |
| int pos = 8; |
| if (displayArgs.at(dimIdxH).at(pos) == QLatin1Char('=')) |
| ++pos; |
| int ph = displayArgs.at(dimIdxH).mid(pos).toInt(&ok); |
| if (ok) { |
| physHeight = ph; |
| if (dimIdxW < 0) |
| physWidth = dw*physHeight/dh; |
| } |
| } |
| if (dimIdxW < 0 && dimIdxH < 0) { |
| const int dpi = 72; |
| physWidth = qRound(dw * 25.4 / dpi); |
| physHeight = qRound(dh * 25.4 / dpi); |
| } |
| |
| qDebug("Connected to VFB server %s: %d x %d x %d %dx%dmm (%dx%ddpi)", displaySpec.toLatin1().data(), |
| w, h, d, physWidth, physHeight, qRound(dw*25.4/physWidth), qRound(dh*25.4/physHeight) ); |
| |
| size = lstep * h; |
| mapsize = size; |
| screencols = d_ptr->hdr->numcols; |
| memcpy(screenclut, d_ptr->hdr->clut, sizeof(QRgb) * screencols); |
| |
| connected = this; |
| |
| if (qgetenv("QT_QVFB_BGR").toInt()) |
| pixeltype = BGRPixel; |
| |
| return true; |
| } |
| |
| void QVFbScreen::disconnect() |
| { |
| connected = 0; |
| if ((long)d_ptr->shmrgn != -1 && d_ptr->shmrgn) { |
| if (qApp->type() == QApplication::GuiServer && d_ptr->hdr->dataoffset >= (int)sizeof(QVFbHeader)) { |
| d_ptr->hdr->serverVersion = 0; |
| } |
| shmdt((char*)d_ptr->shmrgn); |
| } |
| } |
| |
| bool QVFbScreen::initDevice() |
| { |
| #ifndef QT_NO_QWS_MOUSE_QVFB |
| const QString mouseDev = QT_VFB_MOUSE_PIPE(displayId); |
| d_ptr->mouse = new QVFbMouseHandler(QLatin1String("QVFbMouse"), mouseDev); |
| qwsServer->setDefaultMouse("None"); |
| if (d_ptr->mouse) |
| d_ptr->mouse->setScreen(this); |
| #endif |
| |
| #if !defined(QT_NO_QWS_KBD_QVFB) && !defined(QT_NO_QWS_KEYBOARD) |
| const QString keyboardDev = QT_VFB_KEYBOARD_PIPE(displayId); |
| d_ptr->keyboard = new QVFbKeyboardHandler(keyboardDev); |
| qwsServer->setDefaultKeyboard("None"); |
| #endif |
| |
| if (d_ptr->hdr->dataoffset >= (int)sizeof(QVFbHeader)) |
| d_ptr->hdr->serverVersion = QT_VERSION; |
| |
| if(d==8) { |
| screencols=256; |
| if (grayscale) { |
| // Build grayscale palette |
| for(int loopc=0;loopc<256;loopc++) { |
| screenclut[loopc]=qRgb(loopc,loopc,loopc); |
| } |
| } else { |
| // 6x6x6 216 color cube |
| int idx = 0; |
| for(int ir = 0x0; ir <= 0xff; ir+=0x33) { |
| for(int ig = 0x0; ig <= 0xff; ig+=0x33) { |
| for(int ib = 0x0; ib <= 0xff; ib+=0x33) { |
| screenclut[idx]=qRgb(ir, ig, ib); |
| idx++; |
| } |
| } |
| } |
| screencols=idx; |
| } |
| memcpy(d_ptr->hdr->clut, screenclut, sizeof(QRgb) * screencols); |
| d_ptr->hdr->numcols = screencols; |
| } else if (d == 4) { |
| int val = 0; |
| for (int idx = 0; idx < 16; idx++, val += 17) { |
| screenclut[idx] = qRgb(val, val, val); |
| } |
| screencols = 16; |
| memcpy(d_ptr->hdr->clut, screenclut, sizeof(QRgb) * screencols); |
| d_ptr->hdr->numcols = screencols; |
| } else if (d == 1) { |
| screencols = 2; |
| screenclut[1] = qRgb(0xff, 0xff, 0xff); |
| screenclut[0] = qRgb(0, 0, 0); |
| memcpy(d_ptr->hdr->clut, screenclut, sizeof(QRgb) * screencols); |
| d_ptr->hdr->numcols = screencols; |
| } |
| |
| #ifndef QT_NO_QWS_CURSOR |
| QScreenCursor::initSoftwareCursor(); |
| #endif |
| return true; |
| } |
| |
| void QVFbScreen::shutdownDevice() |
| { |
| } |
| |
| void QVFbScreen::setMode(int ,int ,int) |
| { |
| } |
| |
| // save the state of the graphics card |
| // This is needed so that e.g. we can restore the palette when switching |
| // between linux virtual consoles. |
| void QVFbScreen::save() |
| { |
| // nothing to do. |
| } |
| |
| // restore the state of the graphics card. |
| void QVFbScreen::restore() |
| { |
| } |
| void QVFbScreen::setDirty(const QRect& rect) |
| { |
| const QRect r = rect.translated(-offset()); |
| d_ptr->hdr->dirty = true; |
| d_ptr->hdr->update = d_ptr->hdr->update.united(r); |
| } |
| |
| void QVFbScreen::setBrightness(int b) |
| { |
| if (connected) { |
| connected->d_ptr->brightness = b; |
| |
| QVFbHeader *hdr = connected->d_ptr->hdr; |
| if (hdr->viewerVersion < 0x040400) // brightness not supported |
| return; |
| |
| const int br = connected->d_ptr->blank ? 0 : b; |
| if (hdr->brightness != br) { |
| hdr->brightness = br; |
| connected->setDirty(connected->region().boundingRect()); |
| } |
| } |
| } |
| |
| void QVFbScreen::blank(bool on) |
| { |
| d_ptr->blank = on; |
| setBrightness(connected->d_ptr->brightness); |
| } |
| |
| #endif // QT_NO_QWS_QVFB |
| |
| QT_END_NAMESPACE |