/* # Copyright (c) 2009, 2010 - OpenSLX Project, Computer Center University of # Freiburg # # This program is free software distributed under the GPL version 2. # See http://openslx.org/COPYING # # If you have any feedback please consult http://openslx.org/feedback and # send your suggestions, praise, or complaints to feedback@openslx.org # # General information about OpenSLX can be found at http://openslx.org/ # ----------------------------------------------------------------------------- # vncClientThread.cpp # - Connection to remove vnc server # - Emits Qt signal on framebuffer updates # ----------------------------------------------------------------------------- */ #include "vncClientThread.h" VNCClientThread::VNCClientThread(QString host, int port, QString passwd, int quality, int updatefreq) : QThread(), _frameBuffer(0) { _host = host; _port = port; _passwd = passwd; _quality = quality; _updatefreq = updatefreq; terminate = false; _client = NULL; _connected = false; } VNCClientThread::~VNCClientThread() { if (this->isRunning()) this->wait(2000); if (_frameBuffer) delete[] _frameBuffer; _frameBuffer = NULL; if (_client != NULL) { ::close(_client->sock); _client->frameBuffer = NULL; rfbClientCleanup(_client); _client = NULL; } } //////////////////////////////////////////////////////////////////////////////// // Public void VNCClientThread::run() { qDebug("[%s] VNC client started.", metaObject()->className()); qDebug("[%s] Host: '%s' Port: %i Passwd: '%s' Quality: %i", metaObject()->className(), qPrintable(_host), _port, qPrintable(_passwd), _quality); // setup network _client = rfbGetClient(8, 3, 4); _client->MallocFrameBuffer = frameBufferHandler; _client->canHandleNewFBSize = true; _client->serverHost = strdup(_host.toUtf8().constData()); _client->desktopName = NULL; _client->serverPort = _port; _client->GetPassword = passwdHandler; _client->GotFrameBufferUpdate = updateImage; _client->frameBuffer = NULL; // save this instance in vnc-struct for callbacks rfbClientSetClientData(_client, 0, this); // start client if (!rfbInitClient(_client, NULL, NULL)) { _client = NULL; // !!! <- if you don't do this you will get a segfault return; // later when you try to clean up _client, as rfbInitClient already did so } qDebug("[%s] Connection successful!", metaObject()->className()); // Main VNC event loop while (!terminate) { _connected = true; const int i = WaitForMessage(_client, 500); // its usec, not msec if (i < 0) break; if (i) if (!HandleRFBServerMessage(_client)) break; /* //work yourself through event queue and fire every event... while (!_eventQueue.isEmpty()) { SomeEvent* event = _eventQueue.dequeue(); event->fire(_client); delete event; }*/ this->msleep(_updatefreq); } // cleanup ::close(_client->sock); qDebug("[%s] VNC client stopped.", metaObject()->className()); _connected = false; } QImage VNCClientThread::getImage() { return _img; } QSize VNCClientThread::getSize() { return _clientSize; } int VNCClientThread::getUpdatefreq() { if (_updatefreq > 0) return _updatefreq; return 500; } void VNCClientThread::setUpdatefreq(int updatefreq) { _updatefreq = updatefreq; } QString VNCClientThread::getDesktopName() { if (_client == NULL || _client->desktopName == NULL) return QString(); return QString(_client->desktopName); } char* VNCClientThread::passwdHandler(rfbClient *client) { VNCClientThread* t = (VNCClientThread*) rfbClientGetClientData(client, 0); return strdup(t->_passwd.toLocal8Bit()); } rfbBool VNCClientThread::frameBufferHandler(rfbClient *client) { VNCClientThread *t = (VNCClientThread*) rfbClientGetClientData(client, 0); const int width = client->width, height = client->height, depth = client->format.bitsPerPixel; const int size = width * height * (depth / 8); qDebug("[%s] Remote desktop: %ix%ix%i", t->metaObject()->className(), width, height, depth); if (t->_frameBuffer) delete[] t->_frameBuffer; t->_frameBuffer = new uint8_t[size]; client->frameBuffer = t->_frameBuffer; memset(client->frameBuffer, '\0', size); client->format.bitsPerPixel = 32; client->format.redShift = 16; client->format.greenShift = 8; client->format.blueShift = 0; client->format.redMax = 0xff; client->format.greenMax = 0xff; client->format.blueMax = 0xff; const int quality = t->_quality; switch (quality) { case VNCClientThread::HIGH: client->appData.useBGR233 = 0; client->appData.encodingsString = "copyrect hextile raw"; client->appData.compressLevel = 0; client->appData.qualityLevel = 9; client->appData.scaleSetting = 10; // FIXME: Doesn't work break; case VNCClientThread::MEDIUM: client->appData.useBGR233 = 0; client->appData.encodingsString = "tight zrle ultra copyrect hextile zlib corre rre raw"; client->appData.compressLevel = 5; client->appData.qualityLevel = 7; client->appData.scaleSetting = 10; break; case VNCClientThread::LOW: default: client->appData.useBGR233 = 1; client->appData.encodingsString = "tight zrle ultra copyrect hextile zlib corre rre raw"; client->appData.compressLevel = 9; client->appData.qualityLevel = 1; client->appData.scaleSetting = 10; break; } SetFormatAndEncodings(client); t->_clientSize = QSize(width, height); // If something stops working with VNC images/updates, move these two // commands back tp updateImage const QImage img = QImage(client->frameBuffer, client->width, client->height, QImage::Format_RGB32); t->_img = img; // <> return true; } void VNCClientThread::updateImage(rfbClient* client, int x, int y, int w, int h) { VNCClientThread* t = (VNCClientThread*) rfbClientGetClientData(client, 0); emit t->imageUpdated(x, y, w, h); } /* rfbClient* VNCClientThread::getRfbClient(){ return _client; }*/ SomeEvent::~SomeEvent() { } void PointerEvent::fire(rfbClient* cl) { SendPointerEvent(cl, _x, _y, _buttonMask); } void KeyEvent::fire(rfbClient* cl) { SendKeyEvent(cl, _key, _pressed); } void VNCClientThread::mouseEvent(int x, int y, int buttonMask) { //QMutexLocker lock(&mutex); if (terminate) return; _eventQueue.enqueue(new PointerEvent(x, y, buttonMask)); } void VNCClientThread::keyEvent(int key, bool pressed) { //QMutexLocker lock(&mutex); if (terminate) return; _eventQueue.enqueue(new KeyEvent(key, pressed)); }