📄 qscreenvnc_qws.cpp
字号:
case 16: pixel = (((pixel & 0xff000000) >> 8) | ((pixel & 0x00ff0000) << 8)); break; case 32: pixel = (((pixel & 0xff000000) >> 24) | ((pixel & 0x00ff0000) >> 8) | ((pixel & 0x0000ff00) << 8) | ((pixel & 0x000000ff) << 24)); break; default: qDebug("Cannot handle %d bpp client", pixelFormat.bitsPerPixel); break; } } memcpy(dst, &pixel, bytesPerPixel); // XXX: simple for-loop instead? dst += bytesPerPixel; }}// XXXstatic inline QImage::Format formatForDepth(int depth){ switch (depth) { case 8: return QImage::Format_Indexed8; case 16: return QImage::Format_RGB16; case 32: return QImage::Format_RGB32; default: return QImage::Format_Invalid; }}#ifndef QT_NO_QWS_CURSORstatic void blendCursor(QImage &image, const QRect &imageRect){ const QRect cursorRect = qt_screencursor->boundingRect(); const QRect intersection = (cursorRect & imageRect); const QRect destRect = intersection.translated(-imageRect.topLeft()); const QRect srcRect = intersection.translated(-cursorRect.topLeft()); QPainter painter(&image); painter.drawImage(destRect, qt_screencursor->image(), srcRect); painter.end();}#endif // QT_NO_QWS_CURSORQVNCDirtyMap::QVNCDirtyMap(QScreen *s) : bytesPerPixel(0), numDirty(0), screen(s){ bytesPerPixel = screen->depth() / 8; bufferWidth = screen->deviceWidth(); bufferHeight = screen->deviceHeight(); bufferStride = bufferWidth * bytesPerPixel; buffer = new uchar[bufferHeight * bufferStride]; mapWidth = (bufferWidth + MAP_TILE_SIZE - 1) / MAP_TILE_SIZE; mapHeight = (bufferHeight + MAP_TILE_SIZE - 1) / MAP_TILE_SIZE; map = new uchar[mapWidth * mapHeight]; numTiles = mapWidth * mapHeight;}QVNCDirtyMap::~QVNCDirtyMap(){ delete[] map; delete[] buffer;}void QVNCDirtyMap::reset(){ memset(map, 1, numTiles); memset(buffer, 0, bufferHeight * bufferStride); numDirty = numTiles;}inline bool QVNCDirtyMap::dirty(int x, int y) const{ return map[y * mapWidth + x];}inline void QVNCDirtyMap::setClean(int x, int y){ map[y * mapWidth + x] = 0; --numDirty;}template <class T>void QVNCDirtyMapOptimized<T>::setDirty(int tileX, int tileY, bool force){ static bool alwaysForce = qgetenv("QT_VNC_NO_COMPAREBUFFER").toInt(); if (alwaysForce) force = true; bool changed = false; if (!force) { const int lstep = screen->linestep(); const int startX = tileX * MAP_TILE_SIZE; const int startY = tileY * MAP_TILE_SIZE; const uchar *scrn = screen->base() + startY * lstep + startX * bytesPerPixel; uchar *old = buffer + startY * bufferStride + startX * sizeof(T); const int tileHeight = (startY + MAP_TILE_SIZE > bufferHeight ? bufferHeight - startY : MAP_TILE_SIZE); const int tileWidth = (startX + MAP_TILE_SIZE > bufferWidth ? bufferWidth - startX : MAP_TILE_SIZE); const bool doInlines = (tileWidth == MAP_TILE_SIZE); int y = tileHeight; if (doInlines) { // hw: memcmp/memcpy is inlined when using constants while (y) { if (memcmp(old, scrn, sizeof(T) * MAP_TILE_SIZE)) { changed = true; break; } scrn += lstep; old += bufferStride; --y; } while (y) { memcpy(old, scrn, sizeof(T) * MAP_TILE_SIZE); scrn += lstep; old += bufferStride; --y; } } else { while (y) { if (memcmp(old, scrn, sizeof(T) * tileWidth)) { changed = true; break; } scrn += lstep; old += bufferStride; --y; } while (y) { memcpy(old, scrn, sizeof(T) * tileWidth); scrn += lstep; old += bufferStride; --y; } } } const int mapIndex = tileY * mapWidth + tileX; if ((force || changed) && !map[mapIndex]) { map[mapIndex] = 1; ++numDirty; }}template <class SRC>QRfbHextileEncoder<SRC>::QRfbHextileEncoder(QVNCServer *s) : QRfbEncoder(s), singleColorHextile(this), dualColorHextile(this), multiColorHextile(this){}/* \internal Send dirty rects using hextile encoding.*/template <class SRC>void QRfbHextileEncoder<SRC>::write(){ QWSDisplay::grab(true); QVNCDirtyMap *map = server->dirtyMap(); QTcpSocket *socket = server->clientSocket(); const quint32 encoding = htonl(5); // hextile encoding const int bytesPerPixel = server->clientBytesPerPixel(); { const char tmp[2] = { 0, 0 }; // msg type, padding socket->write(tmp, sizeof(tmp)); } { const quint16 count = htons(map->numDirty); socket->write((char *)&count, sizeof(count)); } if (map->numDirty <= 0) { QWSDisplay::ungrab(); return; } newBg = true; newFg = true; const QImage screenImage = server->screenImage(); QRfbRect rect(0, 0, MAP_TILE_SIZE, MAP_TILE_SIZE); for (int y = 0; y < map->mapHeight; ++y) { if (rect.y + MAP_TILE_SIZE > server->screen()->height()) rect.h = server->screen()->height() - rect.y; rect.w = MAP_TILE_SIZE; for (int x = 0; x < map->mapWidth; ++x) { if (!map->dirty(x, y)) continue; map->setClean(x, y); rect.x = x * MAP_TILE_SIZE; if (rect.x + MAP_TILE_SIZE > server->screen()->deviceWidth()) rect.w = server->screen()->deviceWidth() - rect.x; rect.write(socket); socket->write((char *)&encoding, sizeof(encoding)); const uchar *screendata = screenImage.scanLine(rect.y) + rect.x * screenImage.depth() / 8; int linestep = screenImage.bytesPerLine();#ifndef QT_NO_QWS_CURSOR // hardware cursors must be blended with the screen memory QImage tileImage; if (qt_screencursor->isAccelerated()) { const QRect tileRect(rect.x, rect.y, rect.w, rect.h); const QRect cursorRect = qt_screencursor->boundingRect() .translated(-server->screen()->offset()); if (tileRect.intersects(cursorRect)) { tileImage = screenImage.copy(tileRect); blendCursor(tileImage, tileRect.translated(server->screen()->offset())); screendata = tileImage.bits(); linestep = tileImage.bytesPerLine(); } }#endif // QT_NO_QWS_CURSOR if (singleColorHextile.read(screendata, rect.w, rect.h, linestep)) { singleColorHextile.write(socket); } else if (dualColorHextile.read(screendata, rect.w, rect.h, linestep)) { dualColorHextile.write(socket); } else if (multiColorHextile.read(screendata, rect.w, rect.h, linestep)) { multiColorHextile.write(socket); } else if (server->doPixelConversion()) { const int bufferSize = rect.w * rect.h * bytesPerPixel + 1; const int padding = sizeof(quint32) - sizeof(char); buffer.resize(bufferSize + padding); buffer[padding] = 1; // Raw subencoding // convert pixels char *b = buffer.data() + padding + 1; const int bstep = rect.w * bytesPerPixel; for (int i = 0; i < rect.h; ++i) { server->convertPixels(b, (const char*)screendata, rect.w); screendata += linestep; b += bstep; } socket->write(buffer.constData() + padding, bufferSize); } else { quint8 subenc = 1; // Raw subencoding socket->write((char *)&subenc, 1); // send pixels for (int i = 0; i < rect.h; ++i) { socket->write((const char*)screendata, rect.w * bytesPerPixel); screendata += linestep; } } } if (socket->state() == QAbstractSocket::UnconnectedState) break; rect.y += MAP_TILE_SIZE; } socket->flush(); Q_ASSERT(map->numDirty == 0); QWSDisplay::ungrab();}void QRfbRawEncoder::write(){ QWSDisplay::grab(false); QVNCDirtyMap *map = server->dirtyMap(); QTcpSocket *socket = server->clientSocket(); const int bytesPerPixel = server->clientBytesPerPixel(); // create a region from the dirty rects and send the region's merged rects. QRegion rgn; if (map) { for (int y = 0; y < map->mapHeight; ++y) { for (int x = 0; x < map->mapWidth; ++x) { if (!map->dirty(x, y)) continue; rgn += QRect(x * MAP_TILE_SIZE, y * MAP_TILE_SIZE, MAP_TILE_SIZE, MAP_TILE_SIZE); map->setClean(x, y); } } rgn &= QRect(0, 0, server->screen()->deviceWidth(), server->screen()->deviceHeight()); } const QVector<QRect> rects = rgn.rects(); { const char tmp[2] = { 0, 0 }; // msg type, padding socket->write(tmp, sizeof(tmp)); } { const quint16 count = htons(rects.size()); socket->write((char *)&count, sizeof(count)); } if (rects.size() <= 0) { QWSDisplay::ungrab(); return; } const QImage screenImage = server->screenImage(); for (int i = 0; i < rects.size(); ++i) { const QRect tileRect = rects.at(i); const QRfbRect rect(tileRect.x(), tileRect.y(), tileRect.width(), tileRect.height()); rect.write(socket); const quint32 encoding = htonl(0); // raw encoding socket->write((char *)&encoding, sizeof(encoding)); int linestep = screenImage.bytesPerLine(); const uchar *screendata = screenImage.scanLine(rect.y) + rect.x * screenImage.depth() / 8;#ifndef QT_NO_QWS_CURSOR // hardware cursors must be blended with the screen memory QImage tileImage; if (qt_screencursor->isAccelerated()) { const QRect cursorRect = qt_screencursor->boundingRect() .translated(-server->screen()->offset()); if (tileRect.intersects(cursorRect)) { tileImage = screenImage.copy(tileRect); blendCursor(tileImage, tileRect.translated(server->screen()->offset())); screendata = tileImage.bits(); linestep = tileImage.bytesPerLine(); } }#endif // QT_NO_QWS_CURSOR if (server->doPixelConversion()) { const int bufferSize = rect.w * rect.h * bytesPerPixel; if (bufferSize > buffer.size()) buffer.resize(bufferSize); // convert pixels char *b = buffer.data(); const int bstep = rect.w * bytesPerPixel; for (int i = 0; i < rect.h; ++i) { server->convertPixels(b, (const char*)screendata, rect.w); screendata += linestep; b += bstep; } socket->write(buffer.constData(), bufferSize); } else { for (int i = 0; i < rect.h; ++i) { socket->write((const char*)screendata, rect.w * bytesPerPixel); screendata += linestep; } } if (socket->state() == QAbstractSocket::UnconnectedState) break; } socket->flush(); QWSDisplay::ungrab();}inline QImage QVNCServer::screenImage() const{ return QImage(qvnc_screen->base(), qvnc_screen->deviceWidth(), qvnc_screen->deviceHeight(), formatForDepth(qvnc_screen->depth()));}void QVNCServer::checkUpdate(){ if (wantUpdate && dirtyMap()->numDirty > 0) { if (encoder) encoder->write(); wantUpdate = false; }}void QVNCServer::discardClient(){ timer->stop(); state = Unconnected; delete encoder; encoder = 0; if (!qvnc_screen->d_ptr->subscreen) QWSServer::instance()->enablePainting(false);}//===========================================================================/*! \class QVNCScreen \internal \ingroup qws \brief The QVNCScreen class implements a screen driver for VNC servers. Note that this class is only available in \l {Qtopia Core}. Custom screen drivers can be added by subclassing the QScreen class, using the QScreenDriverFactory class to dynamically load the driver into the application. The VNC protocol allows you to view and interact with the computer's display from anywhere on the network. See the \l {The VNC Protocol and Qtopia Core}{VNC protocol} documentation for more details. The default implementation of QVNCScreen inherits QLinuxFbScreen, but any QScreen subclass, or QScreen itself, can serve as its base class. This is easily achieved by manipulating the \c VNCSCREEN_BASE definition in the header file. \sa QScreen, {Running Applications}*//*! \fn QVNCScreen::QVNCScreen(int displayId) Constructs a QVNCScreen object. The \a displayId argument identifies the Qtopia Core server to connect to.*/QVNCScreen::QVNCScreen(int display_id) : QScreen(display_id){ d_ptr = new QVNCScreenPrivate(this);}/*!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -