📄 qscreenlinuxfb_qws.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qscreenlinuxfb_qws.h"#ifndef QT_NO_QWS_LINUXFB//#include "qmemorymanager_qws.h"#include "qwsdisplay_qws.h"#include "qpixmap.h"#include <private/qwssignalhandler_p.h>#include <unistd.h>#include <stdlib.h>#include <sys/ioctl.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/mman.h>#include <sys/kd.h>#include <fcntl.h>#include <errno.h>#include <stdio.h>#include <limits.h>#include <signal.h>#include <qdebug.h>#include "qwindowsystem_qws.h"#if !defined(Q_OS_DARWIN) && !defined(Q_OS_FREEBSD)#include <linux/fb.h>#ifdef __i386__#include <asm/mtrr.h>#endif#endifextern int qws_client_id;//#define DEBUG_CACHEclass QLinuxFbScreenPrivate : public QObject{public: QLinuxFbScreenPrivate(); ~QLinuxFbScreenPrivate(); void openTty(); void closeTty(); int fd; int startupw; int startuph; int startupd; bool doGraphicsMode;#ifdef QT_QWS_DEPTH_GENERIC bool doGenericColors;#endif int ttyfd; long oldKdMode; QString ttyDevice; QString displaySpec;};QLinuxFbScreenPrivate::QLinuxFbScreenPrivate() : fd(-1), doGraphicsMode(true),#ifdef QT_QWS_DEPTH_GENERIC doGenericColors(false),#endif ttyfd(-1), oldKdMode(KD_TEXT){ QWSSignalHandler::instance()->addObject(this);}QLinuxFbScreenPrivate::~QLinuxFbScreenPrivate(){ closeTty();}void QLinuxFbScreenPrivate::openTty(){ const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0}; if (ttyDevice.isEmpty()) { for (const char * const *dev = devs; *dev; ++dev) { ttyfd = ::open(*dev, O_RDWR); if (ttyfd != -1) break; } } else { ttyfd = ::open(ttyDevice.toAscii().constData(), O_RDWR); } if (ttyfd == -1) return; if (doGraphicsMode) { ioctl(ttyfd, KDGETMODE, &oldKdMode); if (oldKdMode != KD_GRAPHICS) { int ret = ioctl(ttyfd, KDSETMODE, KD_GRAPHICS); if (ret == -1) doGraphicsMode = false; } } if (!doGraphicsMode) { // No blankin' screen, no blinkin' cursor!, no cursor! const char termctl[] = "\033[9;0]\033[?33l\033[?25l\033[?1c"; ::write(ttyfd, termctl, sizeof(termctl)); }}void QLinuxFbScreenPrivate::closeTty(){ if (ttyfd == -1) return; if (doGraphicsMode) { ioctl(ttyfd, KDSETMODE, oldKdMode); } else { // Blankin' screen, blinkin' cursor! const char termctl[] = "\033[9;15]\033[?33h\033[?25h\033[?0c"; ::write(ttyfd, termctl, sizeof(termctl)); } ::close(ttyfd); ttyfd = -1;}/*! \internal \class QLinuxFbScreen \ingroup qws \brief The QLinuxFbScreen class implements a screen driver for the Linux framebuffer. Note that this class is only available in \l {Qtopia Core}. Custom screen drivers can be added by subclassing the QScreenDriverPlugin class, using the QScreenDriverFactory class to dynamically load the driver into the application, but there should only be one screen object per application. The QLinuxFbScreen class provides the cache() function allocating off-screen graphics memory, and the complementary uncache() function releasing the allocated memory. The latter function will first sync the graphics card to ensure the memory isn't still being used by a command in the graphics card FIFO queue. The deleteEntry() function deletes the given memory block without such synchronization. Given the screen instance and client id, the memory can also be released using the clearCache() function, but this should only be necessary if a client exits abnormally. In addition, when in paletted graphics modes, the set() function provides the possibility of setting a specified color index to a given RGB value. The QLinuxFbScreen class also acts as a factory for the unaccelerated screen cursor and the unaccelerated raster-based implementation of QPaintEngine (\c QRasterPaintEngine); accelerated drivers for Linux should derive from this class. \sa QScreen, QScreenDriverPlugin, {Running Applications}*//*! \fn bool QLinuxFbScreen::useOffscreen() \internal*/// Unaccelerated screen/driver setup. Can be overridden by accelerated// drivers/*! \fn QLinuxFbScreen::QLinuxFbScreen(int displayId) Constructs a QLinuxFbScreen object. The \a displayId argument identifies the Qtopia Core server to connect to.*/QLinuxFbScreen::QLinuxFbScreen(int display_id) : QScreen(display_id), d_ptr(new QLinuxFbScreenPrivate){ canaccel=false; clearCacheFunc = &clearCache;}/*! Destroys this QLinuxFbScreen object.*/QLinuxFbScreen::~QLinuxFbScreen(){}/*! \reimp This is called by \l {Qtopia Core} clients to map in the framebuffer. It should be reimplemented by accelerated drivers to map in graphics card registers; those drivers should then call this function in order to set up offscreen memory management. The device is specified in \a displaySpec, e.g. "/dev/fb". \sa disconnect()*/bool QLinuxFbScreen::connect(const QString &displaySpec){ d_ptr->displaySpec = displaySpec; const QStringList args = displaySpec.split(QLatin1Char(':')); if (args.contains(QLatin1String("nographicsmodeswitch"))) d_ptr->doGraphicsMode = false;#ifdef QT_QWS_DEPTH_GENERIC if (args.contains(QLatin1String("genericcolors"))) d_ptr->doGenericColors = true;#endif QRegExp ttyRegExp(QLatin1String("tty=(.*)")); if (args.indexOf(ttyRegExp) != -1) d_ptr->ttyDevice = ttyRegExp.cap(1);#if Q_BYTE_ORDER == Q_BIG_ENDIAN#ifndef QT_QWS_FRAMEBUFFER_LITTLE_ENDIAN if (args.contains(QLatin1String("littleendian")))#endif QScreen::setFrameBufferLittleEndian(true);#endif // Check for explicitly specified device const int len = 8; // "/dev/fbx" int m = displaySpec.indexOf(QLatin1String("/dev/fb")); QString dev; if (m > 0) dev = displaySpec.mid(m, len); else dev = QLatin1String("/dev/fb0"); if (access(dev.toLatin1().constData(), R_OK|W_OK) == 0) d_ptr->fd = open(dev.toLatin1().constData(), O_RDWR); if (d_ptr->fd == -1) { if (QApplication::type() == QApplication::GuiServer) { perror("QScreenLinuxFb::connect"); qCritical("Error opening framebuffer device %s", qPrintable(dev)); return false; } if (access(dev.toLatin1().constData(), R_OK) == 0) d_ptr->fd = open(dev.toLatin1().constData(), O_RDONLY); } fb_fix_screeninfo finfo; fb_var_screeninfo vinfo; //####################### // Shut up Valgrind memset(&vinfo, 0, sizeof(vinfo)); memset(&finfo, 0, sizeof(finfo)); //####################### /* Get fixed screen information */ if (d_ptr->fd != -1 && ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) { perror("QLinuxFbScreen::connect"); qWarning("Error reading fixed information"); return false; } /* Get variable screen information */ if (d_ptr->fd != -1 && ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) { perror("QLinuxFbScreen::connect"); qWarning("Error reading variable information"); return false; } grayscale = vinfo.grayscale; d = vinfo.bits_per_pixel; if (d == 24) d = vinfo.red.length + vinfo.green.length + vinfo.blue.length; lstep=finfo.line_length; int xoff = vinfo.xoffset; int yoff = vinfo.yoffset; const char* qwssize; if((qwssize=::getenv("QWS_SIZE")) && sscanf(qwssize,"%dx%d",&w,&h)==2) { if (d_ptr->fd != -1) { if ((uint)w > vinfo.xres) w = vinfo.xres; if ((uint)h > vinfo.yres) h = vinfo.yres; } dw=w; dh=h; xoff += (vinfo.xres - w)/2; yoff += (vinfo.yres - h)/2; } else { dw=w=vinfo.xres; dh=h=vinfo.yres; } if (w == 0 || h == 0) { qWarning("QScreenLinuxFb::connect(): Unable to find screen geometry, " "will use 320x240."); dw = w = 320; dh = h = 240; } setPixelFormat(vinfo); // Handle display physical size spec. QStringList displayArgs = displaySpec.split(QLatin1Char(':')); QRegExp mmWidthRx(QLatin1String("mmWidth=?(\\d+)")); int dimIdxW = displayArgs.indexOf(mmWidthRx); QRegExp mmHeightRx(QLatin1String("mmHeight=?(\\d+)")); int dimIdxH = displayArgs.indexOf(mmHeightRx); if (dimIdxW >= 0) { mmWidthRx.exactMatch(displayArgs.at(dimIdxW)); physWidth = mmWidthRx.cap(1).toInt(); if (dimIdxH < 0) physHeight = dh*physWidth/dw; } if (dimIdxH >= 0) { mmHeightRx.exactMatch(displayArgs.at(dimIdxH)); physHeight = mmHeightRx.cap(1).toInt(); if (dimIdxW < 0) physWidth = dw*physHeight/dh; } if (dimIdxW < 0 && dimIdxH < 0) { if (vinfo.width != 0 && vinfo.height != 0 && vinfo.width != UINT_MAX && vinfo.height != UINT_MAX) { physWidth = vinfo.width; physHeight = vinfo.height; } else { const int dpi = 72; physWidth = qRound(dw * 25.4 / dpi); physHeight = qRound(dh * 25.4 / dpi); } } dataoffset = yoff * lstep + xoff * d / 8; //qDebug("Using %dx%dx%d screen",w,h,d); /* Figure out the size of the screen in bytes */ size = h * lstep; // qDebug("Framebuffer base at %lx",finfo.smem_start); // qDebug("Registers base %lx",finfo.mmio_start); mapsize=finfo.smem_len; data = (unsigned char *)-1; if (d_ptr->fd != -1) data = (unsigned char *)mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, d_ptr->fd, 0); if ((long)data == -1) { if (QApplication::type() == QApplication::GuiServer) { perror("QLinuxFbScreen::connect"); qWarning("Error: failed to map framebuffer device to memory."); return false; } data = 0; } else { data += dataoffset; } canaccel=useOffscreen(); if(mapsize-size<16384) { canaccel=false; } if(canaccel) { setupOffScreen(); } // Now read in palette if((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4)) { screencols= (vinfo.bits_per_pixel==8) ? 256 : 16; int loopc; fb_cmap startcmap; startcmap.start=0; startcmap.len=screencols; startcmap.red=(unsigned short int *)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -