类似于 加速图形驱动程序范例 , there are three steps to writing and implementing this graphics driver:
After compiling the example code, install the graphics driver plugin with the command
make install
. To start an application using the graphics driver, you can either set the environment variable
QWS_DISPLAY
and then run the application, or you can just run the application using the
-display
switch.
Note that this is a minimal example and this driver will not work well with widgets painting themself directly to the screen (e.g. widgets with the Qt::WA_PaintOnScreen window attribute set). Also, the example requires the Linux framebuffer to be set up correctly and with the correct device permissions. For further information, refer to Testing the Linux Framebuffer .
Usually, a custom graphics driver is created by subclassing the QScreen class, the base class for implementing screen or graphics drivers in Qt for Embedded Linux. In this example, however, we subclass the QLinuxFbScreen class instead, to ensure that our driver uses the Linux framebuffer.
For our graphics driver, the
DBScreen
class, we reimplement five functions belonging to
QScreen
:
class DBScreen : public QLinuxFbScreen { public: DBScreen(int displayId) : QLinuxFbScreen(displayId) {}; ~DBScreen() {} bool initDevice(); void shutdownDevice(); void blit(const QImage &image, const QPoint &topLeft, const QRegion ®ion); void solidFill(const QColor &color, const QRegion ®ion); void exposeRegion(QRegion region, int changing); private: QPainter *painter; QImage *image; };
In addition to the abovementioned functions, there is a private instance of
QPainter
and
QImage
-
painter
, used for drawing operations on the back buffer, and
image
, the back buffer itself.
The graphics driver must carry out three main functions:
We first reimplement
initDevice()
and
shutdownDevice()
.
The
initDevice()
function initializes the framebuffer. We reimplement this function to enable accelerated drivers to set up the graphic card. For this example, we first call the super class' implementation to set up the Linux framebuffer. If this call returns
false
, we return
false
. Otherwise, we initialize the screen cursor with
QScreenCursor::initSoftwareCursor
() as well as instantiate
image
and
painter
. Then, we return
true
.
bool DBScreen::initDevice() { if (!QLinuxFbScreen::initDevice()) return false; QScreenCursor::initSoftwareCursor(); image = new QImage(deviceWidth(), deviceHeight(), pixelFormat()); painter = new QPainter(image); return true; }
The
shutdownDevice()
function's default implementation only hides the mouse cursor. Hence, we reimplement it to carry out the necessary cleanup before the Qt for Embedded Linux server exits.
void DBScreen::shutdownDevice() { QLinuxFbScreen::shutdownDevice(); delete painter; delete image; }
Again, we call the super class implementation to shutdown the Linux framebuffer prior to deleting
image
and
painter
.
We move on to the drawing functions -
solidFill()
and
blit()
. In QLinuxFbScreen, these functions draw directly to the Linux framebuffer; but in our driver we reimplement them to draw to the back buffer instead.
void DBScreen::solidFill(const QColor &color, const QRegion ®ion) { QVector<QRect> rects = region.rects(); for (int i = 0; i < rects.size(); i++) painter->fillRect(rects.at(i), color); }
The
solidFill()
function is called from
exposeRegion()
to fill the given
region
of the screen with the specified
color
. In this example, we use
painter
to fill rectangles in
image
, the back buffer, according to the given region.
void DBScreen::blit(const QImage &image, const QPoint &topLeft, const QRegion ®ion) { QVector<QRect> rects = region.rects(); for (int i = 0; i < rects.size(); i++) { QRect destRect = rects.at(i); QRect srcRect(destRect.x()-topLeft.x(), destRect.y()-topLeft.y(), destRect.width(), destRect.height()); painter->drawImage(destRect.topLeft(), image, srcRect); } }
The
blit()
function is also called from
exposeRegion()
to copy the given
QRegion
对象,
region
,在给定
QImage
对象,
image
,到
QPoint
object specified by
topLeft
. Once again we use
painter
to draw in the back buffer,
image
.
The
exposeRegion()
function is called by the Qt for Embedded Linux server whenever a screen update is required. The given
region
is the screen region that needs to be updated and
changing
is is the index into
QWSServer::clientWindows
() of the window that caused the update.
void DBScreen::exposeRegion(QRegion region, int changing) { QLinuxFbScreen::exposeRegion(region, changing); QLinuxFbScreen::blit(*image, QPoint(0, 0), region); }
In our implementation, we first call the super class implementation to ensure that
solidFill()
and
blit()
will be called correctly. This causes the changed areas to be updated in the back buffer. We then call the super class' implementation of
blit()
to copy the updated region from the back buffer into the Linux framebuffer.
Qt provides a high level API for writing Qt extentions. One of the plugin base classes provided is QScreenDriverPlugin , which we use in this example to create our screen driver plugin.
class DBScreenDriverPlugin : public QScreenDriverPlugin { public: DBScreenDriverPlugin(); QScreen* create(const QString& key, int displayId); QStringList keys () const; };
There are only two functions to reimplement:
QScreen* DBScreenDriverPlugin::create(const QString& key, int displayId) { if (key.toLower() != "dbscreen") return 0; return new DBScreen(displayId); } QStringList DBScreenDriverPlugin::keys() const { return QStringList() << "dbscreen"; }
Our plugin will only support one driver,
dbscreen
.
Lastly, we export the plugin.
Q_EXPORT_PLUGIN2(dbscreen, DBScreenDriverPlugin)
For detailed information about the Qt plugin system see How to Create Qt Plugins.
文件: