/****************************************************************************
**
** Copyright (C) 2010 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 <private/qdrawhelper_p.h>
#include <private/qpaintengine_raster_p.h>
#include <private/qpixmap_raster_p.h>
#include <private/qwindowsurface_qws_p.h>
#include <private/qpainter_p.h>
#include <private/qwidget_p.h>
#include <private/qgraphicssystem_qws_p.h>
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<QScreen*> 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 <typename T>
static void solidFill_template(QScreen *screen, const QColor &color,
const QRegion ®ion)
{
T *dest = reinterpret_cast<T*>(screen->base());
const T c = qt_colorConvert<T, quint32>(color.rgba(), 0);
const int stride = screen->linestep();
const QVector<QRect> 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<quint32*>(screen->base());
const quint32 c = qt_convertToRgb<quint32>(color.rgba());
const int stride = screen->linestep();
const QVector<QRect> 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<quint16*>(screen->base());
const quint16 c = qt_convertToRgb<quint32>(color.rgba());
const int stride = screen->linestep();
const QVector<QRect> 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<quint8>(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<quint8*>(screen->base());
const quint8 c = qGray(color.rgba()) >> 4;
const quint8 c8 = (c << 4) | c;
const int stride = screen->linestep();
const QVector<QRect> 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<quint8>(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<quint8*>(screen->base());
const quint8 c8 = (qGray(color.rgba()) >> 7) * 0xff;
const int stride = screen->linestep();
const QVector<QRect> 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<quint32>;
else
screen->d_ptr->solidFill = solidFill_template<qabgr8888>;
break;
#endif
#ifdef QT_QWS_DEPTH_24
case 24:
if (screen->pixelType() == QScreen::NormalPixel)
screen->d_ptr->solidFill = solidFill_template<qrgb888>;
else
screen->d_ptr->solidFill = solidFill_template<quint24>;
break;
#endif
#ifdef QT_QWS_DEPTH_18
case 18:
screen->d_ptr->solidFill = solidFill_template<quint18>;
break;
#endif
#ifdef QT_QWS_DEPTH_16
case 16:
if (screen->pixelType() == QScreen::NormalPixel)
screen->d_ptr->solidFill = solidFill_template<quint16>;
else
screen->d_ptr->solidFill = solidFill_template<qbgr565>;
break;
#endif
#ifdef QT_QWS_DEPTH_15
case 15:
if (screen->pixelType() == QScreen::NormalPixel)
screen->d_ptr->solidFill = solidFill_template<qrgb555>;
else
screen->d_ptr->solidFill = solidFill_template<qbgr555>;
break;
#endif
#ifdef QT_QWS_DEPTH_12
case 12:
screen->d_ptr->solidFill = solidFill_template<qrgb444>;
break;
#endif
#ifdef QT_QWS_DEPTH_8
case 8:
screen->d_ptr->solidFill = solidFill_template<quint8>;
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 <typename DST, typename SRC>
static void blit_template(QScreen *screen, const QImage &image,
const QPoint &topLeft, const QRegion ®ion)
{
DST *dest = reinterpret_cast<DST*>(screen->base());
const int screenStride = screen->linestep();
const int imageStride = image.bytesPerLine();
if (region.rectCount() == 1) {
const QRect r = region.boundingRect();
const SRC *src = reinterpret_cast<const SRC*>(image.scanLine(r.y()))
+ r.x();
qt_rectconvert<DST, SRC>(dest, src,
r.x() + topLeft.x(), r.y() + topLeft.y(),
r.width(), r.height(),
screenStride, imageStride);
} else {
const QVector<QRect> rects = region.rects();
for (int i = 0; i < rects.size(); ++i) {
const QRect r = rects.at(i);
const SRC *src = reinterpret_cast<const SRC*>(image.scanLine(r.y()))
+ r.x();
qt_rectconvert<DST, SRC>(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<quint32, quint32>(screen, image, topLeft, region);
return;
#ifdef QT_QWS_DEPTH_16
case QImage::Format_RGB16:
blit_template<quint32, quint16>(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<quint24, quint32>(screen, image, topLeft, region);
return;
case QImage::Format_RGB888:
blit_template<quint24, qrgb888>(screen, image, topLeft, region);
return;
#ifdef QT_QWS_DEPTH_16
case QImage::Format_RGB16:
blit_template<quint24, quint16>(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<qrgb888, quint32>(screen, image, topLeft, region);
return;
case QImage::Format_RGB888:
blit_template<qrgb888, qrgb888>(screen, image, topLeft, region);
return;
#ifdef QT_QWS_DEPTH_16
case QImage::Format_RGB16:
blit_template<qrgb888, quint16>(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<qrgb666, quint32>(screen, image, topLeft, region);
return;
case QImage::Format_RGB666:
blit_template<qrgb666, qrgb666>(screen, image, topLeft, region);
return;
#ifdef QT_QWS_DEPTH_16
case QImage::Format_RGB16:
blit_template<qrgb666, quint16>(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<quint16, quint32>(screen, image, topLeft, region);
return;
case QImage::Format_RGB16:
blit_template<quint16, quint16>(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<quint16LE, quint32>(screen, image, topLeft, region);
return;
case QImage::Format_RGB16:
blit_template<quint16LE, quint16>(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<qrgb555, quint32>(screen, image, topLeft, region);
return;
case QImage::Format_RGB555:
blit_template<qrgb555, qrgb555>(screen, image, topLeft, region);
return;
case QImage::Format_RGB16:
blit_template<qrgb555, quint16>(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<quint16LE, qrgb555>(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<qrgb444, qargb4444>(screen, image, topLeft, region);
return;
case QImage::Format_RGB444:
blit_template<qrgb444, qrgb444>(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<quint8, quint32>(screen, image, topLeft, region);
return;
case QImage::Format_RGB16:
blit_template<quint8, quint16>(screen, image, topLeft, region);
return;
case QImage::Format_ARGB4444_Premultiplied:
blit_template<quint8, qargb4444>(screen, image, topLeft, region);
return;
case QImage::Format_RGB444:
blit_template<quint8, qrgb444>(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 <typename SRC>
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 <typename SRC>
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<quint8*>(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>(*src++);
++dest8;
}
if (count8) {
int n = count8;
switch (width8 & 0x03) // duff's device
{
case 0: do { *dest8++ = qt_convertToGray4<SRC>(src[0]) << 4
| qt_convertToGray4<SRC>(src[1]);
src += 2;
case 3: *dest8++ = qt_convertToGray4<SRC>(src[0]) << 4
| qt_convertToGray4<SRC>(src[1]);
src += 2;
case 2: *dest8++ = qt_convertToGray4<SRC>(src[0]) << 4
| qt_convertToGray4<SRC>(src[1]);
src += 2;
case 1: *dest8++ = qt_convertToGray4<SRC>(src[0]) << 4
| qt_convertToGray4<SRC>(src[1]);
src += 2;
} while (--n > 0);
}
}
if (doTail)
*dest8 = qt_convertToGray4<SRC>(*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<quint32>(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<quint16>(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<qrgb444>(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<qargb4444>(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<qgray4, quint32>(screen, image, topLeft, region);
return;
case QImage::Format_RGB16:
blit_template<qgray4, quint16>(screen, image, topLeft, region);
return;
case QImage::Format_RGB444:
blit_template<qgray4, qrgb444>(screen, image, topLeft, region);
return;
case QImage::Format_ARGB4444_Premultiplied:
blit_template<qgray4, qargb4444>(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 <typename SRC>
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<quint32, quint16>(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 <typename SRC>
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<quint8*>(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>(*src++) << i;
*dest8++ = d;
}
for (int i = 0; i < width8; ++i) {
*dest8 = (qt_convertToMono<SRC>(src[0]) << 7)
| (qt_convertToMono<SRC>(src[1]) << 6)
| (qt_convertToMono<SRC>(src[2]) << 5)
| (qt_convertToMono<SRC>(src[3]) << 4)
| (qt_convertToMono<SRC>(src[4]) << 3)
| (qt_convertToMono<SRC>(src[5]) << 2)
| (qt_convertToMono<SRC>(src[6]) << 1)
| (qt_convertToMono<SRC>(src[7]));
src += 8;
++dest8;
}
if (doTail) {
quint8 d = *dest8 & tailMask;
switch (tailWidth) {
case 7: d |= qt_convertToMono<SRC>(src[6]) << 1;
case 6: d |= qt_convertToMono<SRC>(src[5]) << 2;
case 5: d |= qt_convertToMono<SRC>(src[4]) << 3;
case 4: d |= qt_convertToMono<SRC>(src[3]) << 4;
case 3: d |= qt_convertToMono<SRC>(src[2]) << 5;
case 2: d |= qt_convertToMono<SRC>(src[1]) << 6;
case 1: d |= qt_convertToMono<SRC>(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<quint32>(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<quint16>(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<qrgb444>(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<qargb4444>(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<qmono, quint32>(screen, image, topLeft, region);
return;
case QImage::Format_RGB16:
blit_template<qmono, quint16>(screen, image, topLeft, region);
return;
case QImage::Format_RGB444:
blit_template<qmono, qrgb444>(screen, image, topLeft, region);
return;
case QImage::Format_ARGB4444_Premultiplied:
blit_template<qmono, qargb4444>(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<qrgb, quint32>(screen, image, topLeft, region);
return;
case QImage::Format_RGB16:
blit_template<qrgb, quint16>(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<qabgr8888, quint32>;
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<qbgr565, quint16>;
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<qbgr555, qrgb555>;
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 colorCount()
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*> 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(), colorCount()
*/
/*!
\obsolete
\fn int QScreen::numCols()
\sa colorCount()
*/
/*!
\since 4.6
\fn int QScreen::colorCount()
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(), colorCount()
*/
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<QT_FT_Span, 32> 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.rectCount() == 1) {
setDirty(r.boundingRect());
} else {
const QVector<QRect> 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<QRect> 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<QRect> 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<QScreen*> 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
#include <dlfcn.h>
// ### 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<ClassId>(d_ptr->classId);
}
QT_END_NAMESPACE