#include "vncclientthread.h"
-#include <QCoreApplication>
#include <QMutexLocker>
#include <QTimer>
static QString outputErrorMessageString;
+#ifdef Q_WS_MAEMO_5
+//N900 display has 16bit depth (R/G/B with 5/6/5 bpp)
+const int MAX_COLOR_DEPTH = 16;
+#else
+const int MAX_COLOR_DEPTH = 32;
+#endif
+
+
rfbBool VncClientThread::newclient(rfbClient *cl)
{
- VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
+ VncClientThread *t = static_cast<VncClientThread*>(rfbClientGetClientData(cl, 0));
Q_ASSERT(t);
- const int width = cl->width, height = cl->height, depth = cl->format.bitsPerPixel;
- const int size = width * height * (depth / 8);
- if (t->frameBuffer)
- delete [] t->frameBuffer; // do not leak if we get a new framebuffer size
- t->frameBuffer = new uint8_t[size];
- cl->frameBuffer = t->frameBuffer;
- memset(cl->frameBuffer, '\0', size);
- cl->format.bitsPerPixel = 32;
- cl->format.redShift = 16;
- cl->format.greenShift = 8;
- cl->format.blueShift = 0;
- cl->format.redMax = 0xff;
- cl->format.greenMax = 0xff;
- cl->format.blueMax = 0xff;
-
switch (t->quality()) {
case RemoteView::High:
+ cl->format.bitsPerPixel = MAX_COLOR_DEPTH;
cl->appData.useBGR233 = 0;
cl->appData.encodingsString = "copyrect hextile raw";
cl->appData.compressLevel = 0;
cl->appData.qualityLevel = 9;
break;
case RemoteView::Medium:
+ cl->format.bitsPerPixel = 16;
cl->appData.useBGR233 = 0;
cl->appData.encodingsString = "tight zrle ultra copyrect hextile zlib corre rre raw";
cl->appData.compressLevel = 5;
case RemoteView::Low:
case RemoteView::Unknown:
default:
- cl->appData.useBGR233 = 1;
+ cl->format.bitsPerPixel = 16; //TODO: add support for 8bit (needs color map)
cl->appData.encodingsString = "tight zrle ultra copyrect hextile zlib corre rre raw";
cl->appData.compressLevel = 9;
cl->appData.qualityLevel = 1;
}
+ if(cl->format.bitsPerPixel == 16) {
+ cl->format.depth = 16; //number of useful bits in the pixel value
+ cl->format.redShift = 11;
+ cl->format.greenShift = 5;
+ cl->format.blueShift = 0;
+ cl->format.redMax = 0x1f;
+ cl->format.greenMax = 0x3f;
+ cl->format.blueMax = 0x1f;
+ } else {
+ cl->format.depth = 24; //number of useful bits in the pixel value
+ cl->format.redShift = 16;
+ cl->format.greenShift = 8;
+ cl->format.blueShift = 0;
+ cl->format.redMax = 0xff;
+ cl->format.greenMax = 0xff;
+ cl->format.blueMax = 0xff;
+ }
+
+ delete [] t->m_frameBuffer; // do not leak if we get a new framebuffer size
+ const int size = cl->width * cl->height * (cl->format.bitsPerPixel / 8);
+ t->m_frameBuffer = new uint8_t[size];
+ cl->frameBuffer = t->m_frameBuffer;
+ memset(cl->frameBuffer, '\0', size);
+
+
SetFormatAndEncodings(cl);
return true;
void VncClientThread::updatefb(rfbClient* cl, int x, int y, int w, int h)
{
- //kDebug(5011) << "updated client: x: " << x << ", y: " << y << ", w: " << w << ", h: " << h;
+ //kDebug(5011) << "updated client: x: " << x << ", y: " << y << ", w: " << w << ", h: " << h;
- const int width = cl->width, height = cl->height;
-
- const QImage img(cl->frameBuffer, width, height, QImage::Format_RGB32);
+ const QImage img(
+ cl->frameBuffer,
+ cl->width,
+ cl->height,
+ (cl->format.bitsPerPixel==16)?QImage::Format_RGB16:QImage::Format_RGB32
+ );
if (img.isNull()) {
kDebug(5011) << "image not loaded";
}
- VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
+ VncClientThread *t = static_cast<VncClientThread*>(rfbClientGetClientData(cl, 0));
Q_ASSERT(t);
t->setImage(img);
kDebug(5011) << "cuttext: " << cutText;
if (!cutText.isEmpty()) {
- VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
+ VncClientThread *t = static_cast<VncClientThread*>(rfbClientGetClientData(cl, 0));
Q_ASSERT(t);
t->emitGotCut(cutText);
{
kDebug(5011) << "password request" << kBacktrace();
- VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
+ VncClientThread *t = static_cast<VncClientThread*>(rfbClientGetClientData(cl, 0));
Q_ASSERT(t);
- t->passwordRequest();
t->m_passwordError = true;
+ t->passwordRequest();
return strdup(t->password().toLocal8Bit());
}
+void VncClientThread::setPassword(const QString &password)
+{
+ if(password.isNull()) //cancelled, don't retry
+ m_passwordError = false;
+
+ m_password = password;
+}
+
void VncClientThread::outputHandler(const char *format, ...)
{
va_list args;
if ((message.contains("Couldn't convert ")) ||
(message.contains("Unable to connect to VNC server")))
outputErrorMessageString = i18n("Server not found.");
-
- if ((message.contains("VNC connection failed: Authentication failed, too many tries")) ||
+ else if ((message.contains("VNC connection failed: Authentication failed, too many tries")) ||
(message.contains("VNC connection failed: Too many authentication failures")))
outputErrorMessageString = i18n("VNC authentication failed because of too many authentication tries.");
-
- if (message.contains("VNC connection failed: Authentication failed"))
+ else if (message.contains("VNC connection failed: Authentication failed"))
outputErrorMessageString = i18n("VNC authentication failed.");
-
- if (message.contains("VNC server closed connection"))
+ else if (message.contains("VNC server closed connection"))
outputErrorMessageString = i18n("VNC server closed connection.");
-
- // internal messages, not displayed to user
- if (message.contains("VNC server supports protocol version 3.889")) // see http://bugs.kde.org/162640
- outputErrorMessageString = "INTERNAL:APPLE_VNC_COMPATIBILTY";
+ else if (message.contains("VNC server supports protocol version 3.889")) // see http://bugs.kde.org/162640
+ outputErrorMessageString = "INTERNAL:APPLE_VNC_COMPATIBILTY"; // internal messages, not displayed to user
}
VncClientThread::VncClientThread(QObject *parent)
- : QThread(parent)
- , frameBuffer(0)
+ : QThread(parent)
+ , m_frameBuffer(0)
{
- QMutexLocker locker(&mutex);
+ QMutexLocker locker(&m_mutex);
m_stopped = false;
QTimer *outputErrorMessagesCheckTimer = new QTimer(this);
{
stop();
- const bool quitSuccess = wait(1000);
+ const bool quitSuccess = wait(4000);
- if(!quitSuccess)
- kDebug(5011) << "~VncClientThread(): Quit failed";
-
- delete [] frameBuffer;
- //cl is free()d when event loop exits.
+ if(!quitSuccess)
+ kDebug(5011) << "~VncClientThread(): Quit failed";
+
+ delete [] m_frameBuffer;
+ //m_cl is free()d when event loop exits.
}
void VncClientThread::checkOutputErrorMessage()
{
if (!outputErrorMessageString.isEmpty()) {
- kDebug(5011) << outputErrorMessageString;
QString errorMessage = outputErrorMessageString;
outputErrorMessageString.clear();
// show authentication failure error only after the 3rd unsuccessful try
if ((errorMessage != i18n("VNC authentication failed.")) || m_passwordError)
- outputErrorMessage(errorMessage);
+ emit outputErrorMessage(errorMessage);
}
}
void VncClientThread::setHost(const QString &host)
{
- QMutexLocker locker(&mutex);
+ QMutexLocker locker(&m_mutex);
m_host = host;
}
void VncClientThread::setPort(int port)
{
- QMutexLocker locker(&mutex);
+ QMutexLocker locker(&m_mutex);
m_port = port;
}
void VncClientThread::setImage(const QImage &img)
{
- QMutexLocker locker(&mutex);
+ QMutexLocker locker(&m_mutex);
m_image = img;
}
const QImage VncClientThread::image(int x, int y, int w, int h)
{
- QMutexLocker locker(&mutex);
+ QMutexLocker locker(&m_mutex);
if (w == 0) // full image requested
return m_image;
void VncClientThread::stop()
{
- QMutexLocker locker(&mutex);
+ if(m_stopped)
+ return;
+ //also abort listening for connections, should be safe without locking
+ if(m_listen_port)
+ m_cl->listenSpecified = false;
+
+ QMutexLocker locker(&m_mutex);
m_stopped = true;
}
void VncClientThread::run()
{
- QMutexLocker locker(&mutex);
- bool clean = false;
+ QMutexLocker locker(&m_mutex);
int passwd_failures = 0;
while (!m_stopped) { // try to connect as long as the server allows
m_passwordError = false;
+ outputErrorMessageString.clear(); //don't deliver error messages of old instances...
rfbClientLog = outputHandler;
rfbClientErr = outputHandler;
- cl = rfbGetClient(8, 3, 4);
- cl->MallocFrameBuffer = newclient;
- cl->canHandleNewFBSize = true;
- cl->GetPassword = passwdHandler;
- cl->GotFrameBufferUpdate = updatefb;
- cl->GotXCutText = cuttext;
- rfbClientSetClientData(cl, 0, this);
+ m_cl = rfbGetClient(8, 3, 4); // bitsPerSample, samplesPerPixel, bytesPerPixel
+ m_cl->MallocFrameBuffer = newclient;
+ m_cl->canHandleNewFBSize = true;
+ m_cl->GetPassword = passwdHandler;
+ m_cl->GotFrameBufferUpdate = updatefb;
+ m_cl->GotXCutText = cuttext;
+ rfbClientSetClientData(m_cl, 0, this);
- cl->serverHost = strdup(m_host.toUtf8().constData());
+ m_cl->serverHost = strdup(m_host.toUtf8().constData());
if (m_port < 0 || !m_port) // port is invalid or empty...
m_port = 5900; // fallback: try an often used VNC port
if (m_port >= 0 && m_port < 100) // the user most likely used the short form (e.g. :1)
m_port += 5900;
- cl->serverPort = m_port;
+ m_cl->serverPort = m_port;
+
+ m_cl->listenSpecified = rfbBool(m_listen_port > 0);
+ m_cl->listenPort = m_listen_port;
kDebug(5011) << "--------------------- trying init ---------------------";
- if(listen_port) { //listen for incoming connections
- int argc = 2;
- char* argv[2] = { "x", "-listen" }; //this isn't exactly elegant..
- cl->listenPort = listen_port;
- if (rfbInitClient(cl, &argc, argv))
- break;
- } else { //connect to host
- if (rfbInitClient(cl, 0, 0))
- break;
- }
+ if (rfbInitClient(m_cl, 0, 0))
+ break;
+ //init failed...
if (m_passwordError) {
- passwd_failures++;
- if(passwd_failures > 2) {
- m_stopped = true;
- clean = true; //rfbInitClient cleans up after itself upon failure
- }
- continue;
- }
+ passwd_failures++;
+ if(passwd_failures < 3)
+ continue; //that's ok, try again
+ }
- return;
+ //stop connecting
+ m_stopped = true;
+ return; //no cleanup necessary, m_cl was free()d by rfbInitClient()
}
locker.unlock();
// Main VNC event loop
while (!m_stopped) {
- const int i = WaitForMessage(cl, 500);
- if(m_stopped or i < 0)
- break;
+ const int i = WaitForMessage(m_cl, 500);
+ if(m_stopped or i < 0)
+ break;
if (i)
- if (!HandleRFBServerMessage(cl))
+ if (!HandleRFBServerMessage(m_cl))
break;
locker.relock();
while (!m_eventQueue.isEmpty()) {
ClientEvent* clientEvent = m_eventQueue.dequeue();
- clientEvent->fire(cl);
+ clientEvent->fire(m_cl);
delete clientEvent;
}
// Cleanup allocated resources
locker.relock();
- if(!clean)
- rfbClientCleanup(cl);
+ rfbClientCleanup(m_cl);
m_stopped = true;
}
void VncClientThread::mouseEvent(int x, int y, int buttonMask)
{
- QMutexLocker lock(&mutex);
+ QMutexLocker lock(&m_mutex);
if (m_stopped)
return;
void VncClientThread::keyEvent(int key, bool pressed)
{
- QMutexLocker lock(&mutex);
+ QMutexLocker lock(&m_mutex);
if (m_stopped)
return;
void VncClientThread::clientCut(const QString &text)
{
- QMutexLocker lock(&mutex);
+ QMutexLocker lock(&m_mutex);
if (m_stopped)
return;
m_eventQueue.enqueue(new ClientCutEvent(text));
}
-
-#include "moc_vncclientthread.cpp"