diff -r 000000000000 -r 1918ee327afb src/gui/embedded/qscreen_qws.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gui/embedded/qscreen_qws.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,3340 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qscreen_qws.h" + +#include "qcolormap.h" +#include "qscreendriverfactory_qws.h" +#include "qwindowsystem_qws.h" +#include "qwidget.h" +#include "qcolor.h" +#include "qpixmap.h" +#include "qvarlengtharray.h" +#include "qwsdisplay_qws.h" +#include "qpainter.h" +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// #define QT_USE_MEMCPY_DUFF + +#ifndef QT_NO_QWS_CURSOR +bool qt_sw_cursor=false; +Q_GUI_EXPORT QScreenCursor * qt_screencursor = 0; +#endif +Q_GUI_EXPORT QScreen * qt_screen = 0; + +ClearCacheFunc QScreen::clearCacheFunc = 0; + +#ifndef QT_NO_QWS_CURSOR +/*! + \class QScreenCursor + \ingroup qws + + \brief The QScreenCursor class is a base class for screen cursors + in Qt for Embedded Linux. + + Note that this class is non-portable, and that it is only + available in \l{Qt for Embedded Linux}. + + QScreenCursor implements a software cursor, but can be subclassed + to support hardware cursors as well. When deriving from the + QScreenCursor class it is important to maintain the cursor's + image, position, hot spot (the point within the cursor's image + that will be the position of the associated mouse events) and + visibility as well as informing whether it is hardware accelerated + or not. + + Note that there may only be one screen cursor at a time. Use the + static instance() function to retrieve a pointer to the current + screen cursor. Typically, the cursor is constructed by the QScreen + class or one of its descendants when it is initializing the + device; the QScreenCursor class should never be instantiated + explicitly. + + Use the move() function to change the position of the cursor, and + the set() function to alter its image or its hot spot. In + addition, you can find out whether the cursor is accelerated or + not, using the isAccelerated() function, and the boundingRect() + function returns the cursor's bounding rectangle. + + The cursor's appearance can be controlled using the isVisible(), + hide() and show() functions; alternatively the QWSServer class + provides some means of controlling the cursor's appearance using + the QWSServer::isCursorVisible() and QWSServer::setCursorVisible() + functions. + + \sa QScreen, QWSServer +*/ + +/*! + \fn static QScreenCursor* QScreenCursor::instance() + \since 4.2 + + Returns a pointer to the application's unique screen cursor. +*/ + +extern bool qws_sw_cursor; + +/*! + Constructs a screen cursor +*/ +QScreenCursor::QScreenCursor() +{ + pos = QPoint(qt_screen->deviceWidth()/2, qt_screen->deviceHeight()/2); + size = QSize(0,0); + enable = true; + hwaccel = false; + supportsAlpha = true; +} + +/*! + Destroys the screen cursor. +*/ +QScreenCursor::~QScreenCursor() +{ +} + +/*! + Hides the cursor from the screen. + + \sa show() +*/ +void QScreenCursor::hide() +{ + if (enable) { + enable = false; + if (!hwaccel) + qt_screen->exposeRegion(boundingRect(), 0); + } +} + +/*! + Shows the mouse cursor. + + \sa hide() +*/ +void QScreenCursor::show() +{ + if (!enable) { + enable = true; + if (!hwaccel) + qt_screen->exposeRegion(boundingRect(), 0); + } +} + +/*! + Sets the cursor's image to be the given \a image. + + The \a hotx and \a hoty parameters define the cursor's hot spot, + i.e., the point within the cursor's image that will be the + position of the associated mouse events. + + \sa move() +*/ +void QScreenCursor::set(const QImage &image, int hotx, int hoty) +{ + const QRect r = boundingRect(); + + hotspot = QPoint(hotx, hoty); + // These are in almost all cases the fastest formats to blend + QImage::Format f; + switch (qt_screen->depth()) { + case 12: + f = QImage::Format_ARGB4444_Premultiplied; + break; + case 15: + f = QImage::Format_ARGB8555_Premultiplied; + break; + case 16: + f = QImage::Format_ARGB8565_Premultiplied; + break; + case 18: + f = QImage::Format_ARGB6666_Premultiplied; + break; + default: + f = QImage::Format_ARGB32_Premultiplied; + } + + cursor = image.convertToFormat(f); + + size = image.size(); + + if (enable && !hwaccel) + qt_screen->exposeRegion(r | boundingRect(), 0); +} + +/*! + Moves the mouse cursor to the given position, i.e., (\a x, \a y). + + Note that the given position defines the top-left corner of the + cursor's image, i.e., not the cursor's hot spot (the position of + the associated mouse events). + + \sa set() +*/ +void QScreenCursor::move(int x, int y) +{ + QRegion r = boundingRect(); + pos = QPoint(x,y); + if (enable && !hwaccel) { + r |= boundingRect(); + qt_screen->exposeRegion(r, 0); + } +} + + +/*! + \fn void QScreenCursor::initSoftwareCursor () + + Initializes the screen cursor. + + This function is typically called from the screen driver when + initializing the device. Alternatively, the cursor can be set + directly using the pointer returned by the static instance() + function. + + \sa QScreen::initDevice() +*/ +void QScreenCursor::initSoftwareCursor() +{ + qt_screencursor = new QScreenCursor; +} + + +#endif // QT_NO_QWS_CURSOR + + +/*! + \fn QRect QScreenCursor::boundingRect () const + + Returns the cursor's bounding rectangle. +*/ + +/*! + \internal + \fn bool QScreenCursor::enabled () +*/ + +/*! + \fn QImage QScreenCursor::image () const + + Returns the cursor's image. +*/ + + +/*! + \fn bool QScreenCursor::isAccelerated () const + + Returns true if the cursor is accelerated; otherwise false. +*/ + +/*! + \fn bool QScreenCursor::isVisible () const + + Returns true if the cursor is visible; otherwise false. +*/ + +/*! + \internal + \fn bool QScreenCursor::supportsAlphaCursor () const +*/ + +/* + \variable QScreenCursor::cursor + + \brief the cursor's image. + + \sa image() +*/ + +/* + \variable QScreenCursor::size + + \brief the cursor's size +*/ + +/* + \variable QScreenCursor::pos + + \brief the cursor's position, i.e., the position of the top-left + corner of the crsor's image + + \sa set(), move() +*/ + +/* + \variable QScreenCursor::hotspot + + \brief the cursor's hotspot, i.e., the point within the cursor's + image that will be the position of the associated mouse events. + + \sa set(), move() +*/ + +/* + \variable QScreenCursor::enable + + \brief whether the cursor is visible or not + + \sa isVisible() +*/ + +/* + \variable QScreenCursor::hwaccel + + \brief holds whether the cursor is accelerated or not + + If the cursor is not accelerated, its image will be included by + the screen when it composites the window surfaces. + + \sa isAccelerated() + +*/ + +/* + \variable QScreenCursor::supportsAlpha +*/ + +/*! + \internal + \macro qt_screencursor + \relates QScreenCursor + + A global pointer referring to the unique screen cursor. It is + equivalent to the pointer returned by the + QScreenCursor::instance() function. +*/ + + + +class QScreenPrivate +{ +public: + QScreenPrivate(QScreen *parent, QScreen::ClassId id = QScreen::CustomClass); + ~QScreenPrivate(); + + inline QImage::Format preferredImageFormat() const; + + typedef void (*SolidFillFunc)(QScreen*, const QColor&, const QRegion&); + typedef void (*BlitFunc)(QScreen*, const QImage&, const QPoint&, const QRegion&); + + SolidFillFunc solidFill; + BlitFunc blit; + + QPoint offset; + QList subScreens; + QPixmapDataFactory* pixmapFactory; + QGraphicsSystem* graphicsSystem; + QWSGraphicsSystem defaultGraphicsSystem; //### + QImage::Format pixelFormat; +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + bool fb_is_littleEndian; +#endif +#ifdef QT_QWS_CLIENTBLIT + bool supportsBlitInClients; +#endif + int classId; + QScreen *q_ptr; +}; + +template +static void solidFill_template(QScreen *screen, const QColor &color, + const QRegion ®ion) +{ + T *dest = reinterpret_cast(screen->base()); + const T c = qt_colorConvert(color.rgba(), 0); + const int stride = screen->linestep(); + const QVector rects = region.rects(); + + for (int i = 0; i < rects.size(); ++i) { + const QRect r = rects.at(i); + qt_rectfill(dest, c, r.x(), r.y(), r.width(), r.height(), stride); + } +} + +#ifdef QT_QWS_DEPTH_GENERIC +static void solidFill_rgb_32bpp(QScreen *screen, const QColor &color, + const QRegion ®ion) +{ + quint32 *dest = reinterpret_cast(screen->base()); + const quint32 c = qt_convertToRgb(color.rgba()); + + const int stride = screen->linestep(); + const QVector rects = region.rects(); + + for (int i = 0; i < rects.size(); ++i) { + const QRect r = rects.at(i); + qt_rectfill(dest, c, r.x(), r.y(), r.width(), r.height(), stride); + } +} + +static void solidFill_rgb_16bpp(QScreen *screen, const QColor &color, + const QRegion ®ion) +{ + quint16 *dest = reinterpret_cast(screen->base()); + const quint16 c = qt_convertToRgb(color.rgba()); + + const int stride = screen->linestep(); + const QVector rects = region.rects(); + + for (int i = 0; i < rects.size(); ++i) { + const QRect r = rects.at(i); + qt_rectfill(dest, c, r.x(), r.y(), r.width(), r.height(), stride); + } +} +#endif // QT_QWS_DEPTH_GENERIC + +#ifdef QT_QWS_DEPTH_4 +static inline void qt_rectfill_gray4(quint8 *dest, quint8 value, + int x, int y, int width, int height, + int stride) +{ + const int pixelsPerByte = 2; + dest += y * stride + x / pixelsPerByte; + const int doAlign = x & 1; + const int doTail = (width - doAlign) & 1; + const int width8 = (width - doAlign) / pixelsPerByte; + + for (int j = 0; j < height; ++j) { + if (doAlign) + *dest = (*dest & 0xf0) | (value & 0x0f); + if (width8) + qt_memfill(dest + doAlign, value, width8); + if (doTail) { + quint8 *d = dest + doAlign + width8; + *d = (*d & 0x0f) | (value & 0xf0); + } + dest += stride; + } +} + +static void solidFill_gray4(QScreen *screen, const QColor &color, + const QRegion ®ion) +{ + quint8 *dest = reinterpret_cast(screen->base()); + const quint8 c = qGray(color.rgba()) >> 4; + const quint8 c8 = (c << 4) | c; + + const int stride = screen->linestep(); + const QVector rects = region.rects(); + + for (int i = 0; i < rects.size(); ++i) { + const QRect r = rects.at(i); + qt_rectfill_gray4(dest, c8, r.x(), r.y(), r.width(), r.height(), + stride); + } +} +#endif // QT_QWS_DEPTH_4 + +#ifdef QT_QWS_DEPTH_1 +static inline void qt_rectfill_mono(quint8 *dest, quint8 value, + int x, int y, int width, int height, + int stride) +{ + const int pixelsPerByte = 8; + const int alignWidth = qMin(width, (8 - (x & 7)) & 7); + const int doAlign = (alignWidth > 0 ? 1 : 0); + const int alignStart = pixelsPerByte - 1 - (x & 7); + const int alignStop = alignStart - (alignWidth - 1); + const quint8 alignMask = ((1 << alignWidth) - 1) << alignStop; + const int tailWidth = (width - alignWidth) & 7; + const int doTail = (tailWidth > 0 ? 1 : 0); + const quint8 tailMask = (1 << (pixelsPerByte - tailWidth)) - 1; + const int width8 = (width - alignWidth) / pixelsPerByte; + + dest += y * stride + x / pixelsPerByte; + stride -= (doAlign + width8); + + for (int j = 0; j < height; ++j) { + if (doAlign) { + *dest = (*dest & ~alignMask) | (value & alignMask); + ++dest; + } + if (width8) { + qt_memfill(dest, value, width8); + dest += width8; + } + if (doTail) + *dest = (*dest & tailMask) | (value & ~tailMask); + dest += stride; + } +} + +static void solidFill_mono(QScreen *screen, const QColor &color, + const QRegion ®ion) +{ + quint8 *dest = reinterpret_cast(screen->base()); + const quint8 c8 = (qGray(color.rgba()) >> 7) * 0xff; + + const int stride = screen->linestep(); + const QVector rects = region.rects(); + + for (int i = 0; i < rects.size(); ++i) { + const QRect r = rects.at(i); + qt_rectfill_mono(dest, c8, r.x(), r.y(), r.width(), r.height(), + stride); + } +} +#endif // QT_QWS_DEPTH_1 + +void qt_solidFill_setup(QScreen *screen, const QColor &color, + const QRegion ®ion) +{ + switch (screen->depth()) { +#ifdef QT_QWS_DEPTH_32 + case 32: + if (screen->pixelType() == QScreen::NormalPixel) + screen->d_ptr->solidFill = solidFill_template; + else + screen->d_ptr->solidFill = solidFill_template; + break; +#endif +#ifdef QT_QWS_DEPTH_24 + case 24: + if (screen->pixelType() == QScreen::NormalPixel) + screen->d_ptr->solidFill = solidFill_template; + else + screen->d_ptr->solidFill = solidFill_template; + break; +#endif +#ifdef QT_QWS_DEPTH_18 + case 18: + screen->d_ptr->solidFill = solidFill_template; + break; +#endif +#ifdef QT_QWS_DEPTH_16 + case 16: + if (screen->pixelType() == QScreen::NormalPixel) + screen->d_ptr->solidFill = solidFill_template; + else + screen->d_ptr->solidFill = solidFill_template; + break; +#endif +#ifdef QT_QWS_DEPTH_15 + case 15: + if (screen->pixelType() == QScreen::NormalPixel) + screen->d_ptr->solidFill = solidFill_template; + else + screen->d_ptr->solidFill = solidFill_template; + break; +#endif +#ifdef QT_QWS_DEPTH_12 + case 12: + screen->d_ptr->solidFill = solidFill_template; + break; +#endif +#ifdef QT_QWS_DEPTH_8 + case 8: + screen->d_ptr->solidFill = solidFill_template; + break; +#endif +#ifdef QT_QWS_DEPTH_4 + case 4: + screen->d_ptr->solidFill = solidFill_gray4; + break; +#endif +#ifdef QT_QWS_DEPTH_1 + case 1: + screen->d_ptr->solidFill = solidFill_mono; + break; +#endif + default: + qFatal("solidFill_setup(): Screen depth %d not supported!", + screen->depth()); + screen->d_ptr->solidFill = 0; + break; + } + screen->d_ptr->solidFill(screen, color, region); +} + +template +static void blit_template(QScreen *screen, const QImage &image, + const QPoint &topLeft, const QRegion ®ion) +{ + DST *dest = reinterpret_cast(screen->base()); + const int screenStride = screen->linestep(); + const int imageStride = image.bytesPerLine(); + + if (region.numRects() == 1) { + const QRect r = region.boundingRect(); + const SRC *src = reinterpret_cast(image.scanLine(r.y())) + + r.x(); + qt_rectconvert(dest, src, + r.x() + topLeft.x(), r.y() + topLeft.y(), + r.width(), r.height(), + screenStride, imageStride); + } else { + const QVector rects = region.rects(); + + for (int i = 0; i < rects.size(); ++i) { + const QRect r = rects.at(i); + const SRC *src = reinterpret_cast(image.scanLine(r.y())) + + r.x(); + qt_rectconvert(dest, src, + r.x() + topLeft.x(), r.y() + topLeft.y(), + r.width(), r.height(), + screenStride, imageStride); + } + } +} + +#ifdef QT_QWS_DEPTH_32 +static void blit_32(QScreen *screen, const QImage &image, + const QPoint &topLeft, const QRegion ®ion) +{ + switch (image.format()) { + case QImage::Format_RGB32: + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + blit_template(screen, image, topLeft, region); + return; +#ifdef QT_QWS_DEPTH_16 + case QImage::Format_RGB16: + blit_template(screen, image, topLeft, region); + return; +#endif + default: + qCritical("blit_32(): Image format %d not supported!", image.format()); + } +} +#endif // QT_QWS_DEPTH_32 + +#ifdef QT_QWS_DEPTH_24 +static void blit_24(QScreen *screen, const QImage &image, + const QPoint &topLeft, const QRegion ®ion) +{ + switch (image.format()) { + case QImage::Format_RGB32: + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB888: + blit_template(screen, image, topLeft, region); + return; +#ifdef QT_QWS_DEPTH_16 + case QImage::Format_RGB16: + blit_template(screen, image, topLeft, region); + return; +#endif + default: + qCritical("blit_24(): Image format %d not supported!", image.format()); + } +} + +static void blit_qrgb888(QScreen *screen, const QImage &image, + const QPoint &topLeft, const QRegion ®ion) +{ + switch (image.format()) { + case QImage::Format_RGB32: + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB888: + blit_template(screen, image, topLeft, region); + return; +#ifdef QT_QWS_DEPTH_16 + case QImage::Format_RGB16: + blit_template(screen, image, topLeft, region); + return; +#endif + default: + qCritical("blit_24(): Image format %d not supported!", image.format()); + break; + } +} +#endif // QT_QWS_DEPTH_24 + +#ifdef QT_QWS_DEPTH_18 +static void blit_18(QScreen *screen, const QImage &image, + const QPoint &topLeft, const QRegion ®ion) +{ + switch (image.format()) { + case QImage::Format_RGB32: + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB666: + blit_template(screen, image, topLeft, region); + return; +#ifdef QT_QWS_DEPTH_16 + case QImage::Format_RGB16: + blit_template(screen, image, topLeft, region); + return; +#endif + default: + qCritical("blit_18(): Image format %d not supported!", image.format()); + } +} +#endif // QT_QWS_DEPTH_18 + +#if (Q_BYTE_ORDER == Q_BIG_ENDIAN) && (defined(QT_QWS_DEPTH_16) || defined(QT_QWS_DEPTH_15)) +class quint16LE +{ +public: + inline quint16LE(quint32 v) { + data = ((v & 0xff00) >> 8) | ((v & 0x00ff) << 8); + } + + inline quint16LE(int v) { + data = ((v & 0xff00) >> 8) | ((v & 0x00ff) << 8); + } + + inline quint16LE(quint16 v) { + data = ((v & 0xff00) >> 8) | ((v & 0x00ff) << 8); + } + + inline quint16LE(qrgb555 v) { + data = (( (quint16)v & 0xff00) >> 8) | + (( (quint16)v & 0x00ff) << 8); + } + + inline bool operator==(const quint16LE &v) const + { + return data == v.data; + } + +private: + quint16 data; +}; +#endif + +#ifdef QT_QWS_DEPTH_16 +static void blit_16(QScreen *screen, const QImage &image, + const QPoint &topLeft, const QRegion ®ion) +{ + switch (image.format()) { + case QImage::Format_RGB32: + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + // ### This probably doesn't work but it's a case which should never happen + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB16: + blit_template(screen, image, topLeft, region); + return; + default: + qCritical("blit_16(): Image format %d not supported!", image.format()); + } +} + +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +static void blit_16_bigToLittleEndian(QScreen *screen, const QImage &image, + const QPoint &topLeft, + const QRegion ®ion) +{ + switch (image.format()) { + case QImage::Format_RGB32: + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB16: + blit_template(screen, image, topLeft, region); + return; + default: + qCritical("blit_16_bigToLittleEndian(): Image format %d not supported!", image.format()); + } +} + +#endif // Q_BIG_ENDIAN +#endif // QT_QWS_DEPTH_16 + +#ifdef QT_QWS_DEPTH_15 +static void blit_15(QScreen *screen, const QImage &image, + const QPoint &topLeft, const QRegion ®ion) +{ + switch (image.format()) { + case QImage::Format_RGB32: + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB555: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB16: + blit_template(screen, image, topLeft, region); + return; + default: + qCritical("blit_15(): Image format %d not supported!", image.format()); + } +} + +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +static void blit_15_bigToLittleEndian(QScreen *screen, const QImage &image, + const QPoint &topLeft, + const QRegion ®ion) +{ + switch (image.format()) { + case QImage::Format_RGB555: + blit_template(screen, image, topLeft, region); + return; + default: + qCritical("blit_15_bigToLittleEndian(): Image format %d not supported!", image.format()); + } +} +#endif // Q_BIG_ENDIAN +#endif // QT_QWS_DEPTH_15 + + +#ifdef QT_QWS_DEPTH_12 +static void blit_12(QScreen *screen, const QImage &image, + const QPoint &topLeft, const QRegion ®ion) +{ + switch (image.format()) { + case QImage::Format_ARGB4444_Premultiplied: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB444: + blit_template(screen, image, topLeft, region); + return; + default: + qCritical("blit_12(): Image format %d not supported!", image.format()); + } +} +#endif // QT_QWS_DEPTH_12 + +#ifdef QT_QWS_DEPTH_8 +static void blit_8(QScreen *screen, const QImage &image, + const QPoint &topLeft, const QRegion ®ion) +{ + switch (image.format()) { + case QImage::Format_RGB32: + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB16: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_ARGB4444_Premultiplied: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB444: + blit_template(screen, image, topLeft, region); + return; + default: + qCritical("blit_8(): Image format %d not supported!", image.format()); + } +} +#endif // QT_QWS_DEPTH_8 + +#ifdef QT_QWS_DEPTH_4 + +struct qgray4 { quint8 dummy; } Q_PACKED; + +template +Q_STATIC_TEMPLATE_FUNCTION inline quint8 qt_convertToGray4(SRC color); + +template <> +inline quint8 qt_convertToGray4(quint32 color) +{ + return qGray(color) >> 4; +} + +template <> +inline quint8 qt_convertToGray4(quint16 color) +{ + const int r = (color & 0xf800) >> 11; + const int g = (color & 0x07e0) >> 6; // only keep 5 bit + const int b = (color & 0x001f); + return (r * 11 + g * 16 + b * 5) >> 6; +} + +template <> +inline quint8 qt_convertToGray4(qrgb444 color) +{ + return qt_convertToGray4(quint32(color)); +} + +template <> +inline quint8 qt_convertToGray4(qargb4444 color) +{ + return qt_convertToGray4(quint32(color)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void qt_rectconvert_gray4(qgray4 *dest4, const SRC *src, + int x, int y, int width, int height, + int dstStride, int srcStride) +{ + const int pixelsPerByte = 2; + quint8 *dest8 = reinterpret_cast(dest4) + + y * dstStride + x / pixelsPerByte; + const int doAlign = x & 1; + const int doTail = (width - doAlign) & 1; + const int width8 = (width - doAlign) / pixelsPerByte; + const int count8 = (width8 + 3) / 4; + + srcStride = srcStride / sizeof(SRC) - width; + dstStride -= (width8 + doAlign); + + for (int i = 0; i < height; ++i) { + if (doAlign) { + *dest8 = (*dest8 & 0xf0) | qt_convertToGray4(*src++); + ++dest8; + } + if (count8) { + int n = count8; + switch (width8 & 0x03) // duff's device + { + case 0: do { *dest8++ = qt_convertToGray4(src[0]) << 4 + | qt_convertToGray4(src[1]); + src += 2; + case 3: *dest8++ = qt_convertToGray4(src[0]) << 4 + | qt_convertToGray4(src[1]); + src += 2; + case 2: *dest8++ = qt_convertToGray4(src[0]) << 4 + | qt_convertToGray4(src[1]); + src += 2; + case 1: *dest8++ = qt_convertToGray4(src[0]) << 4 + | qt_convertToGray4(src[1]); + src += 2; + } while (--n > 0); + } + } + + if (doTail) + *dest8 = qt_convertToGray4(*src++) << 4 | (*dest8 & 0x0f); + + dest8 += dstStride; + src += srcStride; + } +} + +template <> +void qt_rectconvert(qgray4 *dest, const quint32 *src, + int x, int y, int width, int height, + int dstStride, int srcStride) +{ + qt_rectconvert_gray4(dest, src, x, y, width, height, + dstStride, srcStride); +} + +template <> +void qt_rectconvert(qgray4 *dest, const quint16 *src, + int x, int y, int width, int height, + int dstStride, int srcStride) +{ + qt_rectconvert_gray4(dest, src, x, y, width, height, + dstStride, srcStride); +} + +template <> +void qt_rectconvert(qgray4 *dest, const qrgb444 *src, + int x, int y, int width, int height, + int dstStride, int srcStride) +{ + qt_rectconvert_gray4(dest, src, x, y, width, height, + dstStride, srcStride); +} + +template <> +void qt_rectconvert(qgray4 *dest, const qargb4444 *src, + int x, int y, int width, int height, + int dstStride, int srcStride) +{ + qt_rectconvert_gray4(dest, src, x, y, width, height, + dstStride, srcStride); +} + +static void blit_4(QScreen *screen, const QImage &image, + const QPoint &topLeft, const QRegion ®ion) +{ + switch (image.format()) { + case QImage::Format_ARGB32_Premultiplied: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB16: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB444: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_ARGB4444_Premultiplied: + blit_template(screen, image, topLeft, region); + return; + default: + qCritical("blit_4(): Image format %d not supported!", image.format()); + } +} +#endif // QT_QWS_DEPTH_4 + +#ifdef QT_QWS_DEPTH_1 + +struct qmono { quint8 dummy; } Q_PACKED; + +template +Q_STATIC_TEMPLATE_FUNCTION inline quint8 qt_convertToMono(SRC color); + +template <> +inline quint8 qt_convertToMono(quint32 color) +{ + return qGray(color) >> 7; +} + +template <> +inline quint8 qt_convertToMono(quint16 color) +{ + return (qGray(qt_colorConvert(color, 0)) >> 7); +} + +template <> +inline quint8 qt_convertToMono(qargb4444 color) +{ + return (qGray(quint32(color)) >> 7); +} + +template <> +inline quint8 qt_convertToMono(qrgb444 color) +{ + return (qGray(quint32(color)) >> 7); +} + +template +inline void qt_rectconvert_mono(qmono *dest, const SRC *src, + int x, int y, int width, int height, + int dstStride, int srcStride) +{ + const int pixelsPerByte = 8; + quint8 *dest8 = reinterpret_cast(dest) + + y * dstStride + x / pixelsPerByte; + const int alignWidth = qMin(width, (8 - (x & 7)) & 7); + const int doAlign = (alignWidth > 0 ? 1 : 0); + const int alignStart = pixelsPerByte - 1 - (x & 7); + const int alignStop = alignStart - (alignWidth - 1); + const quint8 alignMask = ((1 << alignWidth) - 1) << alignStop; + const int tailWidth = (width - alignWidth) & 7; + const int doTail = (tailWidth > 0 ? 1 : 0); + const quint8 tailMask = (1 << (pixelsPerByte - tailWidth)) - 1; + const int width8 = (width - alignWidth) / pixelsPerByte; + + srcStride = srcStride / sizeof(SRC) - (width8 * 8 + alignWidth); + dstStride -= (width8 + doAlign); + + for (int j = 0; j < height; ++j) { + if (doAlign) { + quint8 d = *dest8 & ~alignMask; + for (int i = alignStart; i >= alignStop; --i) + d |= qt_convertToMono(*src++) << i; + *dest8++ = d; + } + for (int i = 0; i < width8; ++i) { + *dest8 = (qt_convertToMono(src[0]) << 7) + | (qt_convertToMono(src[1]) << 6) + | (qt_convertToMono(src[2]) << 5) + | (qt_convertToMono(src[3]) << 4) + | (qt_convertToMono(src[4]) << 3) + | (qt_convertToMono(src[5]) << 2) + | (qt_convertToMono(src[6]) << 1) + | (qt_convertToMono(src[7])); + src += 8; + ++dest8; + } + if (doTail) { + quint8 d = *dest8 & tailMask; + switch (tailWidth) { + case 7: d |= qt_convertToMono(src[6]) << 1; + case 6: d |= qt_convertToMono(src[5]) << 2; + case 5: d |= qt_convertToMono(src[4]) << 3; + case 4: d |= qt_convertToMono(src[3]) << 4; + case 3: d |= qt_convertToMono(src[2]) << 5; + case 2: d |= qt_convertToMono(src[1]) << 6; + case 1: d |= qt_convertToMono(src[0]) << 7; + } + *dest8 = d; + } + + dest8 += dstStride; + src += srcStride; + } +} + +template <> +void qt_rectconvert(qmono *dest, const quint32 *src, + int x, int y, int width, int height, + int dstStride, int srcStride) +{ + qt_rectconvert_mono(dest, src, x, y, width, height, + dstStride, srcStride); +} + +template <> +void qt_rectconvert(qmono *dest, const quint16 *src, + int x, int y, int width, int height, + int dstStride, int srcStride) +{ + qt_rectconvert_mono(dest, src, x, y, width, height, + dstStride, srcStride); +} + +template <> +void qt_rectconvert(qmono *dest, const qrgb444 *src, + int x, int y, int width, int height, + int dstStride, int srcStride) +{ + qt_rectconvert_mono(dest, src, x, y, width, height, + dstStride, srcStride); +} + +template <> +void qt_rectconvert(qmono *dest, const qargb4444 *src, + int x, int y, int width, int height, + int dstStride, int srcStride) +{ + qt_rectconvert_mono(dest, src, x, y, width, height, + dstStride, srcStride); +} + +static void blit_1(QScreen *screen, const QImage &image, + const QPoint &topLeft, const QRegion ®ion) +{ + switch (image.format()) { + case QImage::Format_ARGB32_Premultiplied: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB16: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB444: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_ARGB4444_Premultiplied: + blit_template(screen, image, topLeft, region); + return; + default: + qCritical("blit_1(): Image format %d not supported!", image.format()); + } +} +#endif // QT_QWS_DEPTH_1 + +#ifdef QT_QWS_DEPTH_GENERIC + +static void blit_rgb(QScreen *screen, const QImage &image, + const QPoint &topLeft, const QRegion ®ion) +{ + switch (image.format()) { + case QImage::Format_ARGB32_Premultiplied: + blit_template(screen, image, topLeft, region); + return; + case QImage::Format_RGB16: + blit_template(screen, image, topLeft, region); + return; + default: + qCritical("blit_rgb(): Image format %d not supported!", image.format()); + } +} + +void qt_set_generic_blit(QScreen *screen, int bpp, + int len_red, int len_green, int len_blue, int len_alpha, + int off_red, int off_green, int off_blue, int off_alpha) +{ + qrgb::bpp = bpp / 8; + qrgb::len_red = len_red; + qrgb::len_green = len_green; + qrgb::len_blue = len_blue; + qrgb::len_alpha = len_alpha; + qrgb::off_red = off_red; + qrgb::off_green = off_green; + qrgb::off_blue = off_blue; + qrgb::off_alpha = off_alpha; + screen->d_ptr->blit = blit_rgb; + if (bpp == 16) + screen->d_ptr->solidFill = solidFill_rgb_16bpp; + else if (bpp == 32) + screen->d_ptr->solidFill = solidFill_rgb_32bpp; +} + +#endif // QT_QWS_DEPTH_GENERIC + +void qt_blit_setup(QScreen *screen, const QImage &image, + const QPoint &topLeft, const QRegion ®ion) +{ + switch (screen->depth()) { +#ifdef QT_QWS_DEPTH_32 + case 32: + if (screen->pixelType() == QScreen::NormalPixel) + screen->d_ptr->blit = blit_32; + else + screen->d_ptr->blit = blit_template; + break; +#endif +#ifdef QT_QWS_DEPTH_24 + case 24: + if (screen->pixelType() == QScreen::NormalPixel) + screen->d_ptr->blit = blit_qrgb888; + else + screen->d_ptr->blit = blit_24; + break; +#endif +#ifdef QT_QWS_DEPTH_18 + case 18: + screen->d_ptr->blit = blit_18; + break; +#endif +#ifdef QT_QWS_DEPTH_16 + case 16: +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + if (screen->d_ptr->fb_is_littleEndian) + screen->d_ptr->blit = blit_16_bigToLittleEndian; + else +#endif + if (screen->pixelType() == QScreen::NormalPixel) + screen->d_ptr->blit = blit_16; + else + screen->d_ptr->blit = blit_template; + break; +#endif +#ifdef QT_QWS_DEPTH_15 + case 15: +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + if (screen->d_ptr->fb_is_littleEndian) + screen->d_ptr->blit = blit_15_bigToLittleEndian; + else +#endif // Q_BIG_ENDIAN + if (screen->pixelType() == QScreen::NormalPixel) + screen->d_ptr->blit = blit_15; + else + screen->d_ptr->blit = blit_template; + break; +#endif +#ifdef QT_QWS_DEPTH_12 + case 12: + screen->d_ptr->blit = blit_12; + break; +#endif +#ifdef QT_QWS_DEPTH_8 + case 8: + screen->d_ptr->blit = blit_8; + break; +#endif +#ifdef QT_QWS_DEPTH_4 + case 4: + screen->d_ptr->blit = blit_4; + break; +#endif +#ifdef QT_QWS_DEPTH_1 + case 1: + screen->d_ptr->blit = blit_1; + break; +#endif + default: + qFatal("blit_setup(): Screen depth %d not supported!", + screen->depth()); + screen->d_ptr->blit = 0; + break; + } + screen->d_ptr->blit(screen, image, topLeft, region); +} + +QScreenPrivate::QScreenPrivate(QScreen *parent, QScreen::ClassId id) + : defaultGraphicsSystem(QWSGraphicsSystem(parent)), + pixelFormat(QImage::Format_Invalid), +#ifdef QT_QWS_CLIENTBLIT + supportsBlitInClients(false), +#endif + classId(id), q_ptr(parent) +{ + solidFill = qt_solidFill_setup; + blit = qt_blit_setup; +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + fb_is_littleEndian = false; +#endif + pixmapFactory = 0; + graphicsSystem = &defaultGraphicsSystem; +} + +QScreenPrivate::~QScreenPrivate() +{ +} + +QImage::Format QScreenPrivate::preferredImageFormat() const +{ + if (pixelFormat > QImage::Format_Indexed8) + return pixelFormat; + + if (q_ptr->depth() <= 16) + return QImage::Format_RGB16; + else + return QImage::Format_ARGB32_Premultiplied; +} + +/*! + \class QScreen + \ingroup qws + + \brief The QScreen class is a base class for screen drivers in + Qt for Embedded Linux. + + Note that this class is only available in \l{Qt for Embedded Linux}. + + \l{Qt for Embedded Linux} provides ready-made drivers for several screen + protocols, see the \l{Qt for Embedded Linux Display Management}{display + management} documentation for details. Custom screen drivers can + be implemented by subclassing the QScreen class and creating a + screen driver plugin (derived from QScreenDriverPlugin). The + default implementation of the QScreenDriverFactory class + will automatically detect the plugin, and load the driver into the + server application at run-time using Qt's \l {How to Create Qt + Plugins}{plugin system}. + + When rendering, the default behavior is for each + client to render its widgets as well as its decorations into + memory, while the server copies the memory content to the device's + framebuffer using the screen driver. See the \l{Qt for Embedded Linux + Architecture} overview for details (note that it is possible for + the clients to manipulate and control the underlying hardware + directly as well). + + Starting with Qt 4.2, it is also possible to add an + accelerated graphics driver to take advantage of available + hardware resources. See the \l{Adding an Accelerated Graphics + Driver to Qt for Embedded Linux} documentation for details. + + \tableofcontents + + \section1 Framebuffer Management + + When a \l{Qt for Embedded Linux} application starts running, it + calls the screen driver's connect() function to map the + framebuffer and the accelerated drivers that the graphics card + control registers. The connect() function should then read out the + parameters of the framebuffer and use them as required to set this + class's protected variables. + + The initDevice() function can be reimplemented to initialize the + graphics card. Note, however, that connect() is called \e before + the initDevice() function, so, for some hardware configurations, + some of the initialization that would normally be done in the + initDevice() function might have to be done in the connect() + function. + + Likewise, just before a \l{Qt for Embedded Linux} application + exits, it calls the screen driver's disconnect() function. The + server application will in addition call the shutdownDevice() + function before it calls disconnect(). Note that the default + implementation of the shutdownDevice() function only hides the + mouse cursor. + + QScreen also provides the save() and restore() functions, making + it possible to save and restore the state of the graphics + card. Note that the default implementations do nothing. Hardware + screen drivers should reimplement these functions to save (and + restore) its registers, enabling switching between virtual + consoles. + + In addition, you can use the base() function to retrieve a pointer + to the beginning of the framebuffer, and the region() function to + retrieve the framebuffer's region. Use the onCard() function to + determine whether the framebuffer is within the graphics card's + memory, and the totalSize() function to determine the size of the + available graphics card memory (including the screen). Finally, + you can use the offset() function to retrieve the offset between + the framebuffer's coordinates and the application's coordinate + system. + + \section1 Palette Management + + QScreen provides several functions to retrieve information about + the color palette: The clut() function returns a pointer to the + color lookup table (i.e. its color palette). Use the numCols() + function to determine the number of entries in this table, and the + alloc() function to retrieve the palette index of the color that + is the closest match to a given RGB value. + + To determine if the screen driver supports a given color depth, + use the supportsDepth() function that returns true of the + specified depth is supported. + + \section1 Drawing on Screen + + When a screen update is required, the \l{Qt for Embedded Linux} server runs + through all the top-level windows that intersect with the region + that is about to be updated, and ensures that the associated + clients have updated their memory buffer. Then the server calls + the exposeRegion() function that composes the window surfaces and + copies the content of memory to screen by calling the blit() and + solidFill() functions. + + The blit() function copies a given region in a given image to a + specified point using device coordinates, while the solidFill() + function fills the given region of the screen with the specified + color. Note that normally there is no need to call either of these + functions explicitly. + + In addition, QScreen provides the blank() function that can be + reimplemented to prevent any contents from being displayed on the + screen, and the setDirty() function that can be reimplemented to + indicate that a given rectangle of the screen has been + altered. Note that the default implementations of these functions + do nothing. + + Reimplement the mapFromDevice() and mapToDevice() functions to + map objects from the framebuffer coordinate system to the + coordinate space used by the application, and vice versa. Be aware + that the default implementations simply return the given objects + as they are. + + \section1 Properties + + \table + \header \o Property \o Functions + \row + \o Size + \o + + The size of the screen can be retrieved using the screenSize() + function. The size is returned in bytes. + + The framebuffer's logical width and height can be retrieved using + width() and height(), respectively. These functions return values + are given in pixels. Alternatively, the physicalWidth() and + physicalHeight() function returns the same metrics in + millimeters. QScreen also provides the deviceWidth() and + deviceHeight() functions returning the physical width and height + of the device in pixels. Note that the latter metrics can differ + from the ones used if the display is centered within the + framebuffer. + + \row + \o Resolution + \o + + Reimplement the setMode() function to be able to set the + framebuffer to a new resolution (width and height) and bit depth. + + The current depth of the framebuffer can be always be retrieved + using the depth() function. Use the pixmapDepth() function to + obtain the preferred depth for pixmaps. + + \row + \o Pixmap Alignment + \o + + Use the pixmapOffsetAlignment() function to retrieve the value to + which the start address of pixmaps held in the graphics card's + memory, should be aligned. + + Use the pixmapLinestepAlignment() to retrieve the value to which + the \e {individual scanlines} of pixmaps should be aligned. + + \row + \o Image Display + \o + + The isInterlaced() function tells whether the screen is displaying + images progressively, and the isTransformed() function whether it + is rotated. The transformOrientation() function can be + reimplemented to return the current rotation. + + \row + \o Scanlines + \o + + Use the linestep() function to retrieve the length of each + scanline of the framebuffer. + + \row + \o Pixel Type + \o + + The pixelType() function returns the screen's pixel storage format as + described by the PixelType enum. + + \endtable + + \section1 Subclassing and Initial Values + + You need to set the following members when implementing a subclass of QScreen: + + \table + \header \o Member \o Initial Value + \row \o \l{QScreen::}{data} \o A pointer to the framebuffer if possible; + 0 otherwise. + \row \o \l{QScreen::}{lstep} \o The number of bytes between each scanline + in the framebuffer. + \row \o \l{QScreen::}{w} \o The logical screen width in pixels. + \row \o \l{QScreen::}{h} \o The logical screen height in pixels. + \row \o \l{QScreen::}{dw} \o The real screen width in pixels. + \row \o \l{QScreen::}{dh} \o The real screen height in pixels. + \row \o \l{QScreen::}{d} \o The number of bits per pixel. + \row \o \l{QScreen::}{physWidth} \o The screen width in millimeters. + \row \o \l{QScreen::}{physHeight} \o The screen height in millimeters. + \endtable + + The logical screen values are the same as the real screen values unless the + screen is transformed in some way; e.g., rotated. + + See also the \l{Accelerated Graphics Driver Example} for an example that + shows how to initialize these values. + + \sa QScreenDriverPlugin, QScreenDriverFactory, {Qt for Embedded Linux Display + Management} +*/ + +/*! + \enum QScreen::PixelType + + This enum describes the pixel storage format of the screen, + i.e. the order of the red (R), green (G) and blue (B) components + of a pixel. + + \value NormalPixel Red-green-blue (RGB) + \value BGRPixel Blue-green-red (BGR) + + \sa pixelType() +*/ + +/*! + \enum QScreen::ClassId + + This enum defines the class identifiers for the known screen subclasses. + + \value LinuxFBClass QLinuxFBScreen + \value TransformedClass QTransformedScreen + \value VNCClass QVNCScreen + \value MultiClass QMultiScreen + \value VFbClass QVFbScreen + \value DirectFBClass QDirectFBScreen + \value SvgalibClass QSvgalibScreen + \value ProxyClass QProxyScreen + \value GLClass QGLScreen + \value CustomClass Unknown QScreen subclass + + \sa classId() +*/ + +/*! + \variable QScreen::screenclut + \brief the color table + + Initialize this variable in a subclass using a paletted screen mode, + and initialize its partner, QScreen::screencols. + + \sa screencols +*/ + +/*! + \variable QScreen::screencols + \brief the number of entries in the color table + + Initialize this variable in a subclass using a paletted screen mode, + and initialize its partner, QScreen::screenclut. + + \sa screenclut +*/ + +/*! + \variable QScreen::data + \brief points to the first visible pixel in the frame buffer. + + You must initialize this variable if you are using the default + implementation of non-buffered painting Qt::WA_PaintOnScreen, + QPixmap::grabWindow() or QDirectPainter::frameBuffer(). If you + initialize this variable, you must also initialize QScreen::size and + QScreen::mapsize. + + \sa QScreen::size, QScreen::mapsize +*/ + +/*! + \variable QScreen::w + \brief the logical width of the screen. + + This variable \e{must} be initialized by a subclass. +*/ + +/*! + \variable QScreen::lstep + \brief the number of bytes representing a line in the frame buffer. + + i.e., \e{line step}. \c {data[lstep * 2]} is the address of the + first visible pixel in the third line of the frame buffer. + + \sa data +*/ + +/*! + \variable QScreen::h + \brief the logical height of the screen. + + This variable \e{must} be initialized by a subclass. +*/ + +/*! + \variable QScreen::d + \brief the pixel depth + + This is the number of significant bits used to set a pixel + color. This variable \e{must} be initialized by a subclass. +*/ + +/*! + \variable QScreen::pixeltype + \brief set to BGRPixel + + Set this variable to BGRPixel in a subclass, if the screen pixel + format is a BGR type and you have used setPixelFormat() to set the + pixel format to the corresponding RGB format. e.g., you have set the + pixel format to QImage::Format_RGB555, but your screen really uses + BGR, not RGB. +*/ + +/*! + \variable QScreen::grayscale + \brief the gray scale screen mode flag + + Set this variable to true in a subclass, if you are using a + grayscale screen mode. e.g., in an 8-bit mode where you don't want + to use the palette, but you want to use the grayscales. +*/ + +/*! + \variable QScreen::dw + \brief the device width + + This is the number of pixels in a row of the physical screen. It + \e{must} be initialized by a subclass. Normally, it should be set to + the logical width QScreen::w, but it might be different, e.g., if + you are doing rotations in software. + + \sa QScreen::w +*/ + +/*! + \variable QScreen::dh + \brief the device height + + This is the number of pixels in a column of the physical screen. It + \e{must} be initialized by a subclass. Normally, it should be set to + the logical height QScreen::h, but it might be different, e.g., if + you are doing rotations in software. + + \sa QScreen::h +*/ + +/*! + \variable QScreen::size + \brief the number of bytes in the visible region of the frame buffer + + This is the number of bytes in the visible part of the block pointed + to by the QScreen::data pointer. You must initialize this variable + if you initialize the QScreen::data pointer. + + \sa QScreen::data, QScreen::mapsize +*/ + +/*! + \variable QScreen::mapsize + \brief the total number of bytes in the frame buffer + + This is the total number of bytes in the block pointed to by the + QScreen::data pointer. You must initialize this variable if you + initialize the QScreen::data pointer. + + \sa QScreen::data, QScreen::size +*/ + +/*! + \variable QScreen::physWidth + \brief the physical width of the screen in millimeters. + + Currently, this variable is used when calculating the screen DPI, + which in turn is used when deciding the actual font size Qt is + using. +*/ + +/*! + \variable QScreen::physHeight + \brief the physical height of the screen in millimeters. + + Currently, this variable is used when calculating the screen DPI, + which in turn is used when deciding the actual font size Qt is + using. +*/ + +/*! + \fn static QScreen* QScreen::instance() + + Returns a pointer to the application's QScreen instance. + + If this screen consists of several subscreens, operations to the + returned instance will affect all its subscreens. Use the + subscreens() function to retrieve access to a particular + subscreen. + + \sa subScreens(), subScreenIndexAt() +*/ + +/*! + \fn QList QScreen::subScreens() const + \since 4.2 + + Returns a list of this screen's subscreens. Use the + subScreenIndexAt() function to retrieve the index of a screen at a + given position. + + Note that if \e this screen consists of several subscreens, + operations to \e this instance will affect all subscreens by + default. + + \sa instance(), subScreenIndexAt() +*/ + +/*! + \fn int QScreen::physicalWidth() const + \since 4.2 + + Returns the physical width of the screen in millimeters. + + \sa width(), deviceWidth(), physicalHeight() +*/ + +/*! + \fn int QScreen::physicalHeight() const + \since 4.2 + + Returns the physical height of the screen in millimeters. + + \sa height(), deviceHeight(), physicalWidth() +*/ + +/*! + \fn virtual bool QScreen::initDevice() = 0 + + This function is called by the \l{Qt for Embedded Linux} server to + initialize the framebuffer. Note that a server application will call the + connect() function prior to this function. + + Implement this function to make accelerated drivers set up the + graphics card. Return true to indicate success and false to indicate + failure. + + \sa shutdownDevice(), connect() +*/ + +/*! + \fn virtual bool QScreen::connect(const QString &displaySpec) = 0 + + This function is called by every \l{Qt for Embedded Linux} + application on startup, and must be implemented to map in the + framebuffer and the accelerated drivers that the graphics card + control registers. Note that coonnect must be called \e before + the initDevice() function. + + Ensure that true is returned if a connection to the screen device + is made. Otherwise, return false. Upon making the connection, the + function should read out the parameters of the framebuffer and use + them as required to set this class's protected variables. + + The \a displaySpec argument is passed by the QWS_DISPLAY + environment variable or the -display command line parameter, and + has the following syntax: + + \snippet doc/src/snippets/code/src_gui_embedded_qscreen_qws.cpp 0 + + For example, to use the mach64 driver on fb1 as display 2: + + \snippet doc/src/snippets/code/src_gui_embedded_qscreen_qws.cpp 1 + + See \l{Qt for Embedded Linux Display Management} for more details. + + \sa disconnect(), initDevice(), {Running Qt for Embedded Linux Applications} +*/ + +/*! + \fn QScreen::disconnect() + + This function is called by every \l{Qt for Embedded Linux} application + before exiting, and must be implemented to unmap the + framebuffer. Note that a server application will call the + shutdownDevice() function prior to this function. + + \sa connect(), shutdownDevice(), {Running Qt for Embedded Linux + Applications} +*/ + +/*! + \fn QScreen::setMode(int width, int height, int depth) + + Implement this function to reset the framebuffer's resolution (\a + width and \a height) and bit \a depth. + + After the resolution has been set, existing paint engines will be + invalid and the framebuffer should be completely redrawn. In a + multiple-process situation, all other applications must be + notified to reset their mode and update themselves accordingly. +*/ + +/*! + \fn QScreen::blank(bool on) + + Prevents the screen driver form displaying any content on the + screen. + + Note that the default implementation does nothing. + + Reimplement this function to prevent the screen driver from + displaying any contents on the screen if \a on is true; otherwise + the contents is expected to be shown. + + \sa blit() +*/ + +/*! + \fn int QScreen::pixmapOffsetAlignment() + + Returns the value (in bits) to which the start address of pixmaps + held in the graphics card's memory, should be aligned. + + Note that the default implementation returns 64; reimplement this + function to override the return value, e.g., when implementing an + accelerated driver (see the \l {Adding an Accelerated Graphics + Driver to Qt for Embedded Linux}{Adding an Accelerated Graphics Driver} + documentation for details). + + \sa pixmapLinestepAlignment() +*/ + +/*! + \fn int QScreen::pixmapLinestepAlignment() + + Returns the value (in bits) to which individual scanlines of + pixmaps held in the graphics card's memory, should be + aligned. + + Note that the default implementation returns 64; reimplement this + function to override the return value, e.g., when implementing an + accelerated driver (see the \l {Adding an Accelerated Graphics + Driver to Qt for Embedded Linux}{Adding an Accelerated Graphics Driver} + documentation for details). + + \sa pixmapOffsetAlignment() +*/ + +/*! + \fn QScreen::width() const + + Returns the logical width of the framebuffer in pixels. + + \sa deviceWidth(), physicalWidth(), height() +*/ + +/*! + \fn int QScreen::height() const + + Returns the logical height of the framebuffer in pixels. + + \sa deviceHeight(), physicalHeight(), width() +*/ + +/*! + \fn QScreen::depth() const + + Returns the depth of the framebuffer, in bits per pixel. + + Note that the returned depth is the number of bits each pixel + fills rather than the number of significant bits, so 24bpp and + 32bpp express the same range of colors (8 bits of red, green and + blue). + + \sa clut(), pixmapDepth() +*/ + +/*! + \fn int QScreen::pixmapDepth() const + + Returns the preferred depth for pixmaps, in bits per pixel. + + \sa depth() +*/ + +/*! + \fn QScreen::linestep() const + + Returns the length of each scanline of the framebuffer in bytes. + + \sa isInterlaced() +*/ + +/*! + \fn QScreen::deviceWidth() const + + Returns the physical width of the framebuffer device in pixels. + + Note that the returned width can differ from the width which + \l{Qt for Embedded Linux} will actually use, that is if the display is + centered within the framebuffer. + + \sa width(), physicalWidth(), deviceHeight() +*/ + +/*! + \fn QScreen::deviceHeight() const + + Returns the full height of the framebuffer device in pixels. + + Note that the returned height can differ from the height which + \l{Qt for Embedded Linux} will actually use, that is if the display is + centered within the framebuffer. + + \sa height(), physicalHeight(), deviceWidth() +*/ + +/*! + \fn uchar *QScreen::base() const + + Returns a pointer to the beginning of the framebuffer. + + \sa onCard(), region(), totalSize() +*/ + +/*! + \fn uchar *QScreen::cache(int) + + \internal + + This function is used to store pixmaps in graphics memory for the + use of the accelerated drivers. See QLinuxFbScreen (where the + caching is implemented) for more information. +*/ + +/*! + \fn QScreen::uncache(uchar *) + + \internal + + This function is called on pixmap destruction to remove them from + graphics card memory. +*/ + +/*! + \fn QScreen::screenSize() const + + Returns the size of the screen in bytes. + + The screen size is always located at the beginning of framebuffer + memory, i.e. it can also be retrieved using the base() function. + + \sa base(), region() +*/ + +/*! + \fn QScreen::totalSize() const + + Returns the size of the available graphics card memory (including + the screen) in bytes. + + \sa onCard() +*/ + +// Unaccelerated screen/driver setup. Can be overridden by accelerated +// drivers + +/*! + \fn QScreen::QScreen(int displayId) + + Constructs a new screen driver. + + The \a displayId identifies the \l{Qt for Embedded Linux} server to connect + to. +*/ + +/*! + \fn QScreen::clut() + + Returns a pointer to the screen's color lookup table (i.e. its + color palette). + + Note that this function only apply in paletted modes like 8-bit, + i.e. in modes where only the palette indexes (and not the actual + color values) are stored in memory. + + \sa alloc(), depth(), numCols() +*/ + +/*! + \fn int QScreen::numCols() + + Returns the number of entries in the screen's color lookup table + (i.e. its color palette). A pointer to the color table can be + retrieved using the clut() function. + + \sa clut(), alloc() +*/ + +/*! + \since 4.4 + + Constructs a new screen driver. + + The \a display_id identifies the \l{Qt for Embedded Linux} + server to connect to. The \a classId specifies the class + identifier. +*/ +QScreen::QScreen(int display_id, ClassId classId) + : screencols(0), data(0), entries(0), entryp(0), lowest(0), + w(0), lstep(0), h(0), d(1), pixeltype(NormalPixel), grayscale(false), + dw(0), dh(0), size(0), mapsize(0), displayId(display_id), + physWidth(0), physHeight(0), d_ptr(new QScreenPrivate(this, classId)) +{ + clearCacheFunc = 0; +} + +QScreen::QScreen(int display_id) + : screencols(0), data(0), entries(0), entryp(0), lowest(0), + w(0), lstep(0), h(0), d(1), pixeltype(NormalPixel), grayscale(false), + dw(0), dh(0), size(0), mapsize(0), displayId(display_id), + physWidth(0), physHeight(0), d_ptr(new QScreenPrivate(this)) +{ + clearCacheFunc = 0; +} + +/*! + Destroys this screen driver. +*/ + +QScreen::~QScreen() +{ + delete d_ptr; +} + +/*! + This function is called by the \l{Qt for Embedded Linux} server before it + calls the disconnect() function when exiting. + + Note that the default implementation only hides the mouse cursor; + reimplement this function to do the necessary graphics card + specific cleanup. + + \sa initDevice(), disconnect() +*/ + +void QScreen::shutdownDevice() +{ +#ifndef QT_NO_QWS_CURSOR + if (qt_screencursor) + qt_screencursor->hide(); +#endif +} + +extern bool qws_accel; //in qapplication_qws.cpp + +/*! + \fn PixelType QScreen::pixelType() const + + Returns the pixel storage format of the screen. +*/ + +/*! + Returns the pixel format of the screen, or \c QImage::Format_Invalid + if the pixel format is not a supported image format. + +*/ +QImage::Format QScreen::pixelFormat() const +{ + return d_ptr->pixelFormat; +} + +/*! + Sets the screen's pixel format to \a format. + */ +void QScreen::setPixelFormat(QImage::Format format) +{ + d_ptr->pixelFormat = format; +} + + +/*! + \fn int QScreen::alloc(unsigned int red, unsigned int green, unsigned int blue) + + Returns the index in the screen's palette which is the closest + match to the given RGB value (\a red, \a green, \a blue). + + Note that this function only apply in paletted modes like 8-bit, + i.e. in modes where only the palette indexes (and not the actual + color values) are stored in memory. + + \sa clut(), numCols() +*/ + +int QScreen::alloc(unsigned int r,unsigned int g,unsigned int b) +{ + int ret = 0; + if (d == 8) { + if (grayscale) + return qGray(r, g, b); + + // First we look to see if we match a default color + const int pos = (r + 25) / 51 * 36 + (g + 25) / 51 * 6 + (b + 25) / 51; + if (pos < screencols && screenclut[pos] == qRgb(r, g, b)) { + return pos; + } + + // search for nearest color + unsigned int mindiff = 0xffffffff; + unsigned int diff; + int dr,dg,db; + + for (int loopc = 0; loopc < screencols; ++loopc) { + dr = qRed(screenclut[loopc]) - r; + dg = qGreen(screenclut[loopc]) - g; + db = qBlue(screenclut[loopc]) - b; + diff = dr*dr + dg*dg + db*db; + + if (diff < mindiff) { + ret = loopc; + if (!diff) + break; + mindiff = diff; + } + } + } else if (d == 4) { + ret = qGray(r, g, b) >> 4; + } else if (d == 1) { + ret = qGray(r, g, b) >= 128; + } else { + qFatal("cannot alloc %dbpp color", d); + } + + return ret; +} + +/*! + Saves the current state of the graphics card. + + For example, hardware screen drivers should reimplement the save() + and restore() functions to save and restore its registers, + enabling swintching between virtual consoles. + + Note that the default implementation does nothing. + + \sa restore() +*/ + +void QScreen::save() +{ +} + +/*! + Restores the previously saved state of the graphics card. + + For example, hardware screen drivers should reimplement the save() + and restore() functions to save and restore its registers, + enabling swintching between virtual consoles. + + Note that the default implementation does nothing. + + \sa save() +*/ + +void QScreen::restore() +{ +} + +void QScreen::blank(bool) +{ +} + +/*! + \internal +*/ + +void QScreen::set(unsigned int, unsigned int, unsigned int, unsigned int) +{ +} + +/*! + \fn bool QScreen::supportsDepth(int depth) const + + Returns true if the screen supports the specified color \a depth; + otherwise returns false. + + \sa clut() +*/ + +bool QScreen::supportsDepth(int d) const +{ + if (false) { + //Just to simplify the ifdeffery +#ifdef QT_QWS_DEPTH_1 + } else if(d==1) { + return true; +#endif +#ifdef QT_QWS_DEPTH_4 + } else if(d==4) { + return true; +#endif +#ifdef QT_QWS_DEPTH_8 + } else if(d==8) { + return true; +#endif +#ifdef QT_QWS_DEPTH_16 + } else if(d==16) { + return true; +#endif +#ifdef QT_QWS_DEPTH_15 + } else if (d == 15) { + return true; +#endif +#ifdef QT_QWS_DEPTH_18 + } else if(d==18 || d==19) { + return true; +#endif +#ifdef QT_QWS_DEPTH_24 + } else if(d==24) { + return true; +#endif +#ifdef QT_QWS_DEPTH_32 + } else if(d==32) { + return true; +#endif + } + return false; +} + +/*! + \fn bool QScreen::onCard(const unsigned char *buffer) const + + Returns true if the specified \a buffer is within the graphics + card's memory; otherwise returns false (i.e. if it's in main RAM). + + \sa base(), totalSize() +*/ + +bool QScreen::onCard(const unsigned char * p) const +{ + long t=(unsigned long)p; + long bmin=(unsigned long)data; + if (t < bmin) + return false; + if(t >= bmin+mapsize) + return false; + return true; +} + +/*! + \fn bool QScreen::onCard(const unsigned char * buffer, ulong& offset) const + \overload + + If the specified \a buffer is within the graphics card's memory, + this function stores the offset from the start of graphics card + memory (in bytes), in the location specified by the \a offset + parameter. +*/ + +bool QScreen::onCard(const unsigned char * p, ulong& offset) const +{ + long t=(unsigned long)p; + long bmin=(unsigned long)data; + if (t < bmin) + return false; + long o = t - bmin; + if (o >= mapsize) + return false; + offset = o; + return true; +} + +/* +#if !defined(QT_NO_QWS_REPEATER) + { "Repeater", qt_get_screen_repeater, 0 }, +#endif +#if defined(QT_QWS_EE) + { "EE", qt_get_screen_ee, 0 }, +#endif + +*/ + +/* +Given a display_id (number of the \l{Qt for Embedded Linux} server to connect to) +and a spec (e.g. Mach64:/dev/fb0) return a QScreen-descendant. +The QScreenDriverFactory is queried for a suitable driver and, if found, +asked to create a driver. +People writing new graphics drivers should either hook their own +QScreen-descendant into QScreenDriverFactory or use the QScreenDriverPlugin +to make a dynamically loadable driver. +*/ + +Q_GUI_EXPORT QScreen* qt_get_screen(int display_id, const char *spec) +{ + QString displaySpec = QString::fromAscii(spec); + QString driver = displaySpec; + int colon = displaySpec.indexOf(QLatin1Char(':')); + if (colon >= 0) + driver.truncate(colon); + driver = driver.trimmed(); + + bool foundDriver = false; + QString driverName = driver; + + QStringList driverList; + if (!driver.isEmpty()) + driverList << driver; + else + driverList = QScreenDriverFactory::keys(); + + for (int i = 0; i < driverList.size(); ++i) { + const QString driverName = driverList.at(i); + qt_screen = QScreenDriverFactory::create(driverName, display_id); + if (qt_screen) { + foundDriver = true; + if (qt_screen->connect(displaySpec)) { + return qt_screen; + } else { + delete qt_screen; + qt_screen = 0; + } + } + } + + if (driver.isNull()) + qFatal("No suitable driver found"); + else if (foundDriver) + qFatal("%s: driver cannot connect", driver.toLatin1().constData()); + else + qFatal("%s: driver not found", driver.toLatin1().constData()); + + return 0; +} + +#ifndef QT_NO_QWS_CURSOR +static void blendCursor(QImage *dest, const QImage &cursor, const QPoint &offset) +{ + QRasterBuffer rb; + rb.prepare(dest); + + QSpanData spanData; + spanData.init(&rb, 0); + spanData.type = QSpanData::Texture; + spanData.initTexture(&cursor, 256); + spanData.dx = -offset.x(); + spanData.dy = -offset.y(); + if (!spanData.blend) + return; + + const QRect rect = QRect(offset, cursor.size()) + & QRect(QPoint(0, 0), dest->size()); + const int w = rect.width(); + const int h = rect.height(); + + QVarLengthArray spans(h); + for (int i = 0; i < h; ++i) { + spans[i].x = rect.x(); + spans[i].len = w; + spans[i].y = rect.y() + i; + spans[i].coverage = 255; + } + spanData.blend(h, spans.constData(), &spanData); +} +#endif // QT_NO_QWS_CURSOR + +/*! + \fn void QScreen::exposeRegion(QRegion region, int windowIndex) + + This function is called by the \l{Qt for Embedded Linux} server whenever a + screen update is required. \a region is the area on the screen + that must be updated, and \a windowIndex is the index into + QWSServer::clientWindows() of the window that required the + update. QWSWindow::state() gives more information about the cause. + + The default implementation composes the + affected windows and paints the given \a region on screen by + calling the blit() and solidFill() functions + + This function can be reimplemented to perform composition in + hardware, or to perform transition effects. + For simpler hardware acceleration, or to interface with + this is typically done by reimplementing the blit() and + solidFill() functions instead. + + Note that there is no need to call this function explicitly. + + \sa blit(), solidFill(), blank() +*/ +void QScreen::exposeRegion(QRegion r, int windowIndex) +{ + r &= region(); + if (r.isEmpty()) + return; + + int changing = windowIndex; + // when we have just lowered a window, we have to expose all the windows below where the + // window used to be. + if (changing && qwsServer->clientWindows().at(changing)->state() == QWSWindow::Lowering) + changing = 0; +#ifdef QTOPIA_PERFTEST + static enum { PerfTestUnknown, PerfTestOn, PerfTestOff } perfTestState = PerfTestUnknown; + if(PerfTestUnknown == perfTestState) { + if(::getenv("QTOPIA_PERFTEST")) + perfTestState = PerfTestOn; + else + perfTestState = PerfTestOff; + } + if(PerfTestOn == perfTestState) { + QWSWindow *changed = qwsServer->clientWindows().at(changing); + if(!changed->client()->identity().isEmpty()) + qDebug() << "Performance : expose_region :" + << changed->client()->identity() + << r.boundingRect() << ": " + << qPrintable( QTime::currentTime().toString( "h:mm:ss.zzz" ) ); + } +#endif + + const QRect bounds = r.boundingRect(); + QRegion blendRegion; + QImage *blendBuffer = 0; + +#ifndef QT_NO_QWS_CURSOR + if (qt_screencursor && !qt_screencursor->isAccelerated()) { + blendRegion = r & qt_screencursor->boundingRect(); + } +#endif + compose(0, r, blendRegion, &blendBuffer, changing); + + if (blendBuffer && !blendBuffer->isNull()) { + const QPoint offset = blendRegion.boundingRect().topLeft(); +#ifndef QT_NO_QWS_CURSOR + if (qt_screencursor && !qt_screencursor->isAccelerated()) { + const QRect cursorRect = qt_screencursor->boundingRect(); + if (blendRegion.intersects(cursorRect)) { + blendCursor(blendBuffer, qt_screencursor->image(), + cursorRect.topLeft() - offset); + } + } +#endif // QT_NO_QWS_CURSOR + blit(*blendBuffer, offset, blendRegion); + delete blendBuffer; + } + + if (r.numRects() == 1) { + setDirty(r.boundingRect()); + } else { + const QVector rects = r.rects(); + for (int i = 0; i < rects.size(); ++i) + setDirty(rects.at(i)); + } +} + +/*! + \fn void QScreen::blit(const QImage &image, const QPoint &topLeft, const QRegion ®ion) + + Copies the given \a region in the given \a image to the point + specified by \a topLeft using device coordinates. + + This function is called from the exposeRegion() function; it is + not intended to be called explicitly. + + Reimplement this function to make use of \l{Adding an Accelerated + Graphics Driver to Qt for Embedded Linux}{accelerated hardware}. Note that + this function must be reimplemented if the framebuffer format is + not supported by \l{Qt for Embedded Linux} (See the + \l{Qt for Embedded Linux Display Management}{Display Management} + documentation for more details). + + \sa exposeRegion(), solidFill(), blank() +*/ +void QScreen::blit(const QImage &img, const QPoint &topLeft, const QRegion ®) +{ + const QRect bound = (region() & QRect(topLeft, img.size())).boundingRect(); + QWSDisplay::grab(); + d_ptr->blit(this, img, topLeft - offset(), + (reg & bound).translated(-topLeft)); + QWSDisplay::ungrab(); +} + +#ifdef QT_QWS_CLIENTBLIT +/*! + Returns true if this screen driver supports calling QScreen::blit() and + QScreen::setDirty() directly from non-server applications, otherwise returns + false. + + If available, this is used to optimize the performance of non-occluded, opaque + client windows by removing the server round trip when they are updated. + + \sa setSupportsBlitInClients() + */ +bool QScreen::supportsBlitInClients() const +{ + return d_ptr->supportsBlitInClients; +} + +/*! + If \a supported, the screen driver is marked as supporting blitting directly + from non-server applications. + + \sa supportsBlitInClients() + */ +void QScreen::setSupportsBlitInClients(bool supported) +{ + d_ptr->supportsBlitInClients = supported; +} +#endif + +/*! + \internal +*/ + +void QScreen::blit(QWSWindow *win, const QRegion &clip) +{ + QWSWindowSurface *surface = win->windowSurface(); + if (!surface) + return; + + const QImage &img = surface->image(); + if (img.isNull()) + return; + + const QRegion rgn = clip & win->paintedRegion(); + if (rgn.isEmpty()) + return; + + surface->lock(); + blit(img, win->requestedRegion().boundingRect().topLeft(), rgn); + surface->unlock(); +} + +struct fill_data { + quint32 color; + uchar *data; + int lineStep; + int x; + int y; + int w; + int h; +}; + +/*! + Fills the given \a region of the screen with the specified \a + color. + + This function is called from the exposeRegion() function; it is + not intended to be called explicitly. + + Reimplement this function to make use of \l{Adding an Accelerated + Graphics Driver to Qt for Embedded Linux}{accelerated hardware}. Note that + this function must be reimplemented if the framebuffer format is + not supported by \l{Qt for Embedded Linux} (See the + \l{Qt for Embedded Linux Display Management}{Display Management} + documentation for more details). + + \sa exposeRegion(), blit(), blank() +*/ +// the base class implementation works in device coordinates, so that transformed drivers can use it +void QScreen::solidFill(const QColor &color, const QRegion ®ion) +{ + QWSDisplay::grab(); + d_ptr->solidFill(this, color, + region.translated(-offset()) & QRect(0, 0, dw, dh)); + QWSDisplay::ungrab(); +} + +/*! + \since 4.2 + + Creates and returns a new window surface matching the given \a + key. + + The server application will call this function whenever it needs + to create a server side representation of a window, e.g. when + copying the content of memory to the screen using the screen + driver. + + Note that this function must be reimplemented when adding an + accelerated graphics driver. See the + \l{Adding an Accelerated Graphics Driver to Qt for Embedded Linux} + {Adding an Accelerated Graphics Driver} documentation for details. + + \sa {Qt for Embedded Linux Architecture} +*/ +QWSWindowSurface* QScreen::createSurface(const QString &key) const +{ +#ifndef QT_NO_PAINTONSCREEN + if (key == QLatin1String("OnScreen")) + return new QWSOnScreenSurface; + else +#endif + if (key == QLatin1String("mem")) + return new QWSLocalMemSurface; +#ifndef QT_NO_QWS_MULTIPROCESS + else if (key == QLatin1String("shm")) + return new QWSSharedMemSurface; +#endif +#ifndef QT_NO_PAINT_DEBUG + else if (key == QLatin1String("Yellow")) + return new QWSYellowSurface; +#endif +#ifndef QT_NO_DIRECTPAINTER + else if (key == QLatin1String("DirectPainter")) + return new QWSDirectPainterSurface; +#endif + + return 0; +} + +#ifndef QT_NO_PAINTONSCREEN +bool QScreen::isWidgetPaintOnScreen(const QWidget *w) +{ + static int doOnScreen = -1; + if (doOnScreen == -1) { + const QByteArray env = qgetenv("QT_ONSCREEN_PAINT"); + if (env == "force") + doOnScreen = 2; + else + doOnScreen = (env.toInt() > 0 ? 1 : 0); + } + + if (doOnScreen == 2) // force + return true; + + if (doOnScreen == 0 && !w->testAttribute(Qt::WA_PaintOnScreen)) + return false; + + return w->d_func()->isOpaque; +} +#endif + +/*! + \overload + + Creates and returns a new window surface for the given \a widget. +*/ +QWSWindowSurface* QScreen::createSurface(QWidget *widget) const +{ +#ifndef QT_NO_PAINTONSCREEN + if (isWidgetPaintOnScreen(widget) && base()) + return new QWSOnScreenSurface(widget); + else +#endif + if (QApplication::type() == QApplication::GuiServer) + return new QWSLocalMemSurface(widget); +#ifndef QT_NO_QWS_MULTIPROCESS + else + return new QWSSharedMemSurface(widget); +#endif + + return 0; +} + +void QScreen::compose(int level, const QRegion &exposed, QRegion &blend, + QImage **blendbuffer, int changing_level) +{ + QRect exposed_bounds = exposed.boundingRect(); + QWSWindow *win = 0; + do { + win = qwsServer->clientWindows().value(level); // null is background + ++level; + } while (win && !win->paintedRegion().boundingRect().intersects(exposed_bounds)); + + QWSWindowSurface *surface = (win ? win->windowSurface() : 0); + bool above_changing = level <= changing_level; // 0 is topmost + + QRegion exposedBelow = exposed; + bool opaque = true; + + if (win) { + opaque = win->isOpaque() || !surface->isBuffered(); + if (opaque) { + exposedBelow -= win->paintedRegion(); + if (above_changing || !surface->isBuffered()) + blend -= exposed & win->paintedRegion(); + } else { + blend += exposed & win->paintedRegion(); + } + } + if (win && !exposedBelow.isEmpty()) { + compose(level, exposedBelow, blend, blendbuffer, changing_level); + } else { + QSize blendSize = blend.boundingRect().size(); + if (!blendSize.isNull()) { + *blendbuffer = new QImage(blendSize, d_ptr->preferredImageFormat()); + } + } + + const QRegion blitRegion = exposed - blend; + if (!win) + paintBackground(blitRegion); + else if (!above_changing && surface->isBuffered()) + blit(win, blitRegion); + + QRegion blendRegion = exposed & blend; + + if (win) + blendRegion &= win->paintedRegion(); + if (!blendRegion.isEmpty()) { + + QPoint off = blend.boundingRect().topLeft(); + + QRasterBuffer rb; + rb.prepare(*blendbuffer); + QSpanData spanData; + spanData.init(&rb, 0); + if (!win) { + const QImage::Format format = (*blendbuffer)->format(); + switch (format) { + case QImage::Format_ARGB32_Premultiplied: + case QImage::Format_ARGB32: + case QImage::Format_ARGB8565_Premultiplied: + case QImage::Format_ARGB8555_Premultiplied: + case QImage::Format_ARGB6666_Premultiplied: + case QImage::Format_ARGB4444_Premultiplied: + spanData.rasterBuffer->compositionMode = QPainter::CompositionMode_Source; + break; + default: + break; + } + spanData.setup(qwsServer->backgroundBrush(), 256, QPainter::CompositionMode_SourceOver); + spanData.dx = off.x(); + spanData.dy = off.y(); + } else if (!surface->isBuffered()) { + return; + } else { + const QImage &img = surface->image(); + QPoint winoff = off - win->requestedRegion().boundingRect().topLeft(); + // convert win->opacity() from scale [0..255] to [0..256] + int const_alpha = win->opacity(); + const_alpha += (const_alpha >> 7); + spanData.type = QSpanData::Texture; + spanData.initTexture(&img, const_alpha); + spanData.dx = winoff.x(); + spanData.dy = winoff.y(); + } + if (!spanData.blend) + return; + + if (surface) + surface->lock(); + const QVector rects = blendRegion.rects(); + const int nspans = 256; + QT_FT_Span spans[nspans]; + for (int i = 0; i < rects.size(); ++i) { + int y = rects.at(i).y() - off.y(); + int ye = y + rects.at(i).height(); + int x = rects.at(i).x() - off.x(); + int len = rects.at(i).width(); + while (y < ye) { + int n = qMin(nspans, ye - y); + int i = 0; + while (i < n) { + spans[i].x = x; + spans[i].len = len; + spans[i].y = y + i; + spans[i].coverage = 255; + ++i; + } + spanData.blend(n, spans, &spanData); + y += n; + } + } + if (surface) + surface->unlock(); + } +} + +void QScreen::paintBackground(const QRegion &r) +{ + const QBrush &bg = qwsServer->backgroundBrush(); + Qt::BrushStyle bs = bg.style(); + if (bs == Qt::NoBrush || r.isEmpty()) + return; + + if (bs == Qt::SolidPattern) { + solidFill(bg.color(), r); + } else { + const QRect br = r.boundingRect(); + QImage img(br.size(), d_ptr->preferredImageFormat()); + QPoint off = br.topLeft(); + QRasterBuffer rb; + rb.prepare(&img); + QSpanData spanData; + spanData.init(&rb, 0); + spanData.setup(bg, 256, QPainter::CompositionMode_Source); + spanData.dx = off.x(); + spanData.dy = off.y(); + Q_ASSERT(spanData.blend); + + const QVector rects = r.rects(); + const int nspans = 256; + QT_FT_Span spans[nspans]; + for (int i = 0; i < rects.size(); ++i) { + int y = rects.at(i).y() - off.y(); + int ye = y + rects.at(i).height(); + int x = rects.at(i).x() - off.x(); + int len = rects.at(i).width(); + while (y < ye) { + int n = qMin(nspans, ye - y); + int i = 0; + while (i < n) { + spans[i].x = x; + spans[i].len = len; + spans[i].y = y + i; + spans[i].coverage = 255; + ++i; + } + spanData.blend(n, spans, &spanData); + y += n; + } + } + blit(img, br.topLeft(), r); + } +} + +/*! + \fn virtual int QScreen::sharedRamSize(void *) + + \internal +*/ + +/*! + \fn QScreen::setDirty(const QRect& rectangle) + + Marks the given \a rectangle as dirty. + + Note that the default implementation does nothing; reimplement + this function to indicate that the given \a rectangle has been + altered. +*/ + +void QScreen::setDirty(const QRect&) +{ +} + +/*! + \fn QScreen::isTransformed() const + + Returns true if the screen is transformed (for instance, rotated + 90 degrees); otherwise returns false. + + \sa transformOrientation(), isInterlaced() +*/ + +bool QScreen::isTransformed() const +{ + return false; +} + +/*! + \fn QScreen::isInterlaced() const + + Returns true if the display is interlaced (i.e. is displaying + images progressively like a television screen); otherwise returns + false. + + If the display is interlaced, the drawing is altered to look + better. + + \sa isTransformed(), linestep() +*/ + +bool QScreen::isInterlaced() const +{ + return false;//qws_screen_is_interlaced;; +} + +/*! + \fn QScreen::mapToDevice(const QSize &size) const + + Maps the given \a size from the coordinate space used by the + application to the framebuffer coordinate system. Note that the + default implementation simply returns the given \a size as it is. + + Reimplement this function to use the given device's coordinate + system when mapping. + + \sa mapFromDevice() +*/ + +QSize QScreen::mapToDevice(const QSize &s) const +{ + return s; +} + +/*! + \fn QScreen::mapFromDevice(const QSize &size) const + + Maps the given \a size from the framebuffer coordinate system to + the coordinate space used by the application. Note that the + default implementation simply returns the given \a size as it is. + + Reimplement this function to use the given device's coordinate + system when mapping. + + \sa mapToDevice() +*/ + +QSize QScreen::mapFromDevice(const QSize &s) const +{ + return s; +} + +/*! + \fn QScreen::mapToDevice(const QPoint &point, const QSize &screenSize) const + \overload + + Maps the given \a point from the coordinate space used by the + application to the framebuffer coordinate system, passing the + device's \a screenSize as argument. Note that the default + implementation returns the given \a point as it is. +*/ + +QPoint QScreen::mapToDevice(const QPoint &p, const QSize &) const +{ + return p; +} + +/*! + \fn QScreen::mapFromDevice(const QPoint &point, const QSize &screenSize) const + \overload + + Maps the given \a point from the framebuffer coordinate system to + the coordinate space used by the application, passing the device's + \a screenSize as argument. Note that the default implementation + simply returns the given \a point as it is. +*/ + +QPoint QScreen::mapFromDevice(const QPoint &p, const QSize &) const +{ + return p; +} + +/*! + \fn QScreen::mapToDevice(const QRect &rectangle, const QSize &screenSize) const + \overload + + Maps the given \a rectangle from the coordinate space used by the + application to the framebuffer coordinate system, passing the + device's \a screenSize as argument. Note that the default + implementation returns the given \a rectangle as it is. +*/ + +QRect QScreen::mapToDevice(const QRect &r, const QSize &) const +{ + return r; +} + +/*! + \fn QScreen::mapFromDevice(const QRect &rectangle, const QSize &screenSize) const + \overload + + Maps the given \a rectangle from the framebuffer coordinate system to + the coordinate space used by the application, passing the device's + \a screenSize as argument. Note that the default implementation + simply returns the given \a rectangle as it is. +*/ + +QRect QScreen::mapFromDevice(const QRect &r, const QSize &) const +{ + return r; +} + +/*! + \fn QScreen::mapToDevice(const QImage &image) const + \overload + + Maps the given \a image from the coordinate space used by the + application to the framebuffer coordinate system. Note that the + default implementation returns the given \a image as it is. +*/ + +QImage QScreen::mapToDevice(const QImage &i) const +{ + return i; +} + +/*! + \fn QScreen::mapFromDevice(const QImage &image) const + \overload + + Maps the given \a image from the framebuffer coordinate system to + the coordinate space used by the application. Note that the + default implementation simply returns the given \a image as it is. +*/ + +QImage QScreen::mapFromDevice(const QImage &i) const +{ + return i; +} + +/*! + \fn QScreen::mapToDevice(const QRegion ®ion, const QSize &screenSize) const + \overload + + Maps the given \a region from the coordinate space used by the + application to the framebuffer coordinate system, passing the + device's \a screenSize as argument. Note that the default + implementation returns the given \a region as it is. +*/ + +QRegion QScreen::mapToDevice(const QRegion &r, const QSize &) const +{ + return r; +} + +/*! + \fn QScreen::mapFromDevice(const QRegion ®ion, const QSize &screenSize) const + \overload + + Maps the given \a region from the framebuffer coordinate system to + the coordinate space used by the application, passing the device's + \a screenSize as argument. Note that the default implementation + simply returns the given \a region as it is. +*/ + +QRegion QScreen::mapFromDevice(const QRegion &r, const QSize &) const +{ + return r; +} + +/*! + \fn QScreen::transformOrientation() const + + Returns the current rotation as an integer value. + + Note that the default implementation returns 0; reimplement this + function to override this value. + + \sa isTransformed() +*/ + +int QScreen::transformOrientation() const +{ + return 0; +} + +int QScreen::pixmapDepth() const +{ + return depth(); +} + +/*! + \internal +*/ +int QScreen::memoryNeeded(const QString&) +{ + return 0; +} + +/*! + \internal +*/ +void QScreen::haltUpdates() +{ +} + +/*! + \internal +*/ +void QScreen::resumeUpdates() +{ +} + +/*! + \fn QRegion QScreen::region() const + \since 4.2 + + Returns the region covered by this screen driver. + + \sa base(), screenSize() +*/ + +/*! + \internal +*/ +void QScreen::setOffset(const QPoint &p) +{ + d_ptr->offset = p; +} + +/*! + \since 4.2 + + Returns the logical offset of the screen, i.e., the offset between + (0,0) in screen coordinates and the application coordinate system. +*/ +QPoint QScreen::offset() const +{ + return d_ptr->offset; +} + +#if Q_BYTE_ORDER == Q_BIG_ENDIAN +void QScreen::setFrameBufferLittleEndian(bool littleEndian) +{ + d_ptr->fb_is_littleEndian = littleEndian; +} + +bool QScreen::frameBufferLittleEndian() const +{ + return d_ptr->fb_is_littleEndian; +} +#endif + +/*! + \fn int QScreen::subScreenIndexAt(const QPoint &position) const + \since 4.2 + + Returns the index of the subscreen at the given \a position; + returns -1 if no screen is found. + + The index identifies the subscreen in the list of pointers + returned by the subScreens() function. + + \sa instance(), subScreens() +*/ +int QScreen::subScreenIndexAt(const QPoint &p) const +{ + const QList screens = subScreens(); + const int n = screens.count(); + for (int i = 0; i < n; ++i) { + if (screens.at(i)->region().contains(p)) + return i; + } + + return -1; +} + +#if 0 +#ifdef QT_LOADABLE_MODULES + +// ### needs update after driver init changes + +static QScreen * qt_dodriver(char * driver,char * a,unsigned char * b) + +{ + char buf[200]; + strcpy(buf,"/etc/qws/drivers/"); + qstrcpy(buf+17,driver); + qDebug("Attempting driver %s",driver); + + void * handle; + handle=dlopen(buf,RTLD_LAZY); + if(handle==0) { + qFatal("Module load error"); + } + QScreen *(*qt_get_screen_func)(char *,unsigned char *); + qt_get_screen_func=dlsym(handle,"qt_get_screen"); + if(qt_get_screen_func==0) { + qFatal("Couldn't get symbol"); + } + QScreen * ret=qt_get_screen_func(a,b); + return ret; +} + +static QScreen * qt_do_entry(char * entry) +{ + unsigned char config[256]; + + FILE * f=fopen(entry,"r"); + if(!f) { + return 0; + } + + int r=fread(config,256,1,f); + if(r<1) + return 0; + + fclose(f); + + unsigned short vendorid=*((unsigned short int *)config); + unsigned short deviceid=*(((unsigned short int *)config)+1); + if(config[0xb]!=3) + return 0; + + if(vendorid==0x1002) { + if(deviceid==0x4c4d) { + qDebug("Compaq Armada/IBM Thinkpad's Mach64 card"); + return qt_dodriver("mach64.so",entry,config); + } else if(deviceid==0x4742) { + qDebug("Desktop Rage Pro Mach64 card"); + return qt_dodriver("mach64.so",entry,config); + } else { + qDebug("Unrecognised ATI card id %x",deviceid); + return 0; + } + } else { + qDebug("Unrecognised vendor"); + } + return 0; +} + +extern bool qws_accel; + +/// ** NOT SUPPPORTED ** + +QScreen * qt_probe_bus() +{ + if(!qws_accel) { + return qt_dodriver("unaccel.so",0,0); + } + + DIR * dirptr=opendir("/proc/bus/pci"); + if(!dirptr) + return qt_dodriver("unaccel.so",0,0); + DIR * dirptr2; + dirent * cards; + + dirent * busses=readdir(dirptr); + + while(busses) { + if(busses->d_name[0]!='.') { + char buf[100]; + strcpy(buf,"/proc/bus/pci/"); + qstrcpy(buf+14,busses->d_name); + int p=strlen(buf); + dirptr2=opendir(buf); + if(dirptr2) { + cards=readdir(dirptr2); + while(cards) { + if(cards->d_name[0]!='.') { + buf[p]='/'; + qstrcpy(buf+p+1,cards->d_name); + QScreen * ret=qt_do_entry(buf); + if(ret) + return ret; + } + cards=readdir(dirptr2); + } + closedir(dirptr2); + } + } + busses=readdir(dirptr); + } + closedir(dirptr); + + return qt_dodriver("unaccel.so",0,0); +} + +#else + +char *qt_qws_hardcoded_slot = "/proc/bus/pci/01/00.0"; + +const unsigned char* qt_probe_bus() +{ + const char * slot; + slot=::getenv("QWS_CARD_SLOT"); + if(!slot) + slot=qt_qws_hardcoded_slot; + if (slot) { + static unsigned char config[256]; + FILE * f=fopen(slot,"r"); + if(!f) { + qDebug("Open failure for %s",slot); + slot=0; + } else { + int r=fread((char*)config,256,1,f); + fclose(f); + if(r<1) { + qDebug("Read failure"); + return 0; + } else { + return config; + } + } + } + return 0; +} + +#endif + +#endif // 0 + +/*! + \internal + \since 4.4 +*/ +void QScreen::setPixmapDataFactory(QPixmapDataFactory *factory) +{ + static bool shownWarning = false; + if (!shownWarning) { + qWarning("QScreen::setPixmapDataFactory() is deprecated - use setGraphicsSystem() instead"); + shownWarning = true; + } + + d_ptr->pixmapFactory = factory; +} + +/*! + \internal + \since 4.4 +*/ +QPixmapDataFactory* QScreen::pixmapDataFactory() const +{ + return d_ptr->pixmapFactory; +} + +/*! + \internal + \since 4.5 +*/ +void QScreen::setGraphicsSystem(QGraphicsSystem* system) +{ + d_ptr->graphicsSystem = system; +} + +/*! + \internal + \since 4.5 +*/ +QGraphicsSystem* QScreen::graphicsSystem() const +{ + return d_ptr->graphicsSystem; +} + +/*! + \since 4.4 + + Returns the class identifier for the screen object. +*/ +QScreen::ClassId QScreen::classId() const +{ + return static_cast(d_ptr->classId); +} + +QT_END_NAMESPACE