/*
# 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));
}