summaryrefslogtreecommitdiffstats
path: root/krdc/vnc/threads.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'krdc/vnc/threads.cpp')
-rw-r--r--krdc/vnc/threads.cpp584
1 files changed, 288 insertions, 296 deletions
diff --git a/krdc/vnc/threads.cpp b/krdc/vnc/threads.cpp
index cf32d081..860511e9 100644
--- a/krdc/vnc/threads.cpp
+++ b/krdc/vnc/threads.cpp
@@ -2,7 +2,8 @@
threads.cpp - threads
-------------------
begin : Thu May 09 17:01:44 CET 2002
- copyright : (C) 2002 by Tim Jansen
+ copyright : (C) 2015 Timothy Pearson <kb9vqf@pearsoncomputing.net>
+ (C) 2002 by Tim Jansen
email : tim@tjansen.de
***************************************************************************/
@@ -24,369 +25,360 @@
#include "threads.h"
#include <tqcstring.h>
+#include <tqpainter.h>
-// Maximum idle time for writer thread in ms. When it timeouts, it will request
-// another incremental update. Must be smaller than the timeout of the server
-// (krfb's is 20s).
-static const int MAXIMUM_WAIT_PERIOD = 8000;
+#include <math.h>
-// time to postpone incremental updates that have not been requested explicitly
-static const int POSTPONED_INCRRQ_WAIT_PERIOD = 110;
+extern void pnmscale_fractional(const TQImage& src, TQImage& dst, int x, int y, int w, int h);
-static const int MOUSEPRESS_QUEUE_SIZE = 5;
-static const int MOUSEMOVE_QUEUE_SIZE = 3;
-static const int KEY_QUEUE_SIZE = 8192;
+int getPassword(char * &passwd);
-
-ControllerThread::ControllerThread(KVncView *v, WriterThread &wt, volatile bool &quitFlag) :
- m_view(v),
- m_status(REMOTE_VIEW_CONNECTING),
- m_wthread(wt),
- m_quitFlag(quitFlag),
- m_desktopInitialized(false)
+extern rfbBool newclient(rfbClient *cl)
{
+ int width = cl->width, height = cl->height, depth = cl->format.bitsPerPixel;
+ int size = width * height * (depth / 8);
+ uint8_t *buf = new uint8_t[size];
+ memset(buf, '\0', size);
+ cl->frameBuffer = buf;
+ 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;
+
+ SetFormatAndEncodings(cl);
+
+ return true;
}
-void ControllerThread::changeStatus(RemoteViewStatus s) {
- m_status = s;
- TQApplication::postEvent(m_view, new StatusChangeEvent(s));
+extern void updatefb(rfbClient* cl, int x, int y, int w, int h)
+{
+// kdDebug(5011) << "updated client: x: " << x << ", y: " << y << ", w: " << w << ", h: " << h << endl;
+
+ int width = cl->width, height = cl->height;
+
+ TQImage img(cl->frameBuffer, width, height, 32, NULL, 256, TQImage::IgnoreEndian);
+
+ if (img.isNull())
+ kdDebug(5011) << "image not loaded" << endl;
+
+
+ ControllerThreadObject *t = (ControllerThreadObject*)rfbClientGetClientData(cl, 0);
+
+ t->setImage(img);
+ t->queueDrawRegion(x, y, w, h);
}
-void ControllerThread::sendFatalError(ErrorCode s) {
- m_quitFlag = true;
- TQApplication::postEvent(m_view, new FatalErrorEvent(s));
- m_wthread.kick();
+extern char *passwd(rfbClient *cl)
+{
+ Q_UNUSED(cl)
+
+ kdDebug(5011) << "password request" << endl;
+
+ char *passwd;
+ if (getPassword(passwd)) {
+ return passwd;
+ }
+ else {
+ return NULL;
+ }
}
-/*
- * Calls this from the X11 thread
- */
-void ControllerThread::desktopInit() {
- SetVisualAndCmap();
- ToplevelInit();
- DesktopInit(m_view->winId());
- m_desktopInitialized = true;
- m_waiter.wakeAll();
+extern void authresults(rfbClient *cl, uint32_t authResult)
+{
+ kdDebug(5011) << "authentication result: " << authResult << endl;
+
+ ControllerThreadObject *t = (ControllerThreadObject*)rfbClientGetClientData(cl, 0);
+
+ t->authenticationResults(authResult);
}
-void ControllerThread::kick() {
- m_waiter.wakeAll();
+extern void networkstat(rfbClient *cl, uint32_t statuscode)
+{
+ kdDebug(5011) << "network status: " << statuscode << endl;
+
+ ControllerThreadObject *t = (ControllerThreadObject*)rfbClientGetClientData(cl, 0);
+
+ t->networkStatus(statuscode);
}
-void ControllerThread::run() {
- int fd;
- fd = ConnectToRFBServer(m_view->host().latin1(), m_view->port());
- if (fd < 0) {
- if (fd == -(int)INIT_NO_SERVER)
- sendFatalError(ERROR_NO_SERVER);
- else if (fd == -(int)INIT_NAME_RESOLUTION_FAILURE)
- sendFatalError(ERROR_NAME);
- else
- sendFatalError(ERROR_CONNECTION);
- return;
+extern void output(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ TQString message;
+ message.vsprintf(format, args);
+
+ va_end(args);
+
+ kdDebug(5011) << message.local8Bit();
+
+ if (message.contains("Could not open")) {
+ kdDebug(5011) << "Server not found!" << endl;
}
- if (m_quitFlag) {
- changeStatus(REMOTE_VIEW_DISCONNECTED);
- return;
+
+ if (message.contains("VNC authentication succeeded")) {
+ kdDebug(5011) << "Password OK" << endl;
}
+}
- changeStatus(REMOTE_VIEW_AUTHENTICATING);
+ControllerThreadObject::ControllerThreadObject(KVncView *v, volatile bool &quitFlag) :
+ cl(0L),
+ m_view(v),
+ m_status(REMOTE_VIEW_CONNECTING),
+ m_quitFlag(quitFlag),
+ m_scaling(false),
+ m_scalingWidth(-1),
+ m_scalingHeight(-1),
+ m_resizeEntireFrame(false)
+{
+ TQMutexLocker locker(&mutex);
- enum InitStatus s = InitialiseRFBConnection();
- if (s != INIT_OK) {
- if (s == INIT_CONNECTION_FAILED)
- sendFatalError(ERROR_IO);
- else if (s == INIT_SERVER_BLOCKED)
- sendFatalError(ERROR_SERVER_BLOCKED);
- else if (s == INIT_PROTOCOL_FAILURE)
- sendFatalError(ERROR_PROTOCOL);
- else if (s == INIT_AUTHENTICATION_FAILED)
- sendFatalError(ERROR_AUTHENTICATION);
- else if (s == INIT_ABORTED)
- changeStatus(REMOTE_VIEW_DISCONNECTED);
- else
- sendFatalError(ERROR_INTERNAL);
- return;
- }
+ cl = rfbGetClient(8, 3, 4);
+}
- TQApplication::postEvent(m_view,
- new ScreenResizeEvent(si.framebufferWidth,
- si.framebufferHeight));
- m_wthread.queueUpdateRequest(TQRegion(TQRect(0,0,si.framebufferWidth,
- si.framebufferHeight)));
+ControllerThreadObject::~ControllerThreadObject() {
+ TQMutexLocker locker(&mutex);
- TQApplication::postEvent(m_view, new DesktopInitEvent());
- while ((!m_quitFlag) && (!m_desktopInitialized))
- m_waiter.wait(1000);
+ rfbClientCleanup(cl);
+}
- if (m_quitFlag) {
- changeStatus(REMOTE_VIEW_DISCONNECTED);
- return;
- }
+void ControllerThreadObject::changeStatus(RemoteViewStatus s) {
+ m_status = s;
+ TQApplication::postEvent(m_view, new StatusChangeEvent(s));
+}
- changeStatus(REMOTE_VIEW_PREPARING);
+void ControllerThreadObject::sendFatalError(ErrorCode s) {
+ m_quitFlag = true;
+ TQApplication::postEvent(m_view, new FatalErrorEvent(s));
+}
- if (!SetFormatAndEncodings()) {
- sendFatalError(ERROR_INTERNAL);
- return;
- }
+void ControllerThreadObject::queueDrawRegion(int x, int y, int w, int h) {
+ if (m_scaling) {
+ // Rescale desktop
- changeStatus(REMOTE_VIEW_CONNECTED);
+ int new_x;
+ int new_y;
+ int new_w;
+ int new_h;
- m_wthread.start();
+ mutex.lock();
- while (!m_quitFlag) {
- if ((!HandleRFBServerMessage()) && (!m_quitFlag)) {
- sendFatalError(ERROR_IO);
- return;
- }
- }
+ if (m_resizeEntireFrame) {
+ m_scaledImage.create(m_scalingWidth, m_scalingHeight, 32);
- m_quitFlag = true;
- changeStatus(REMOTE_VIEW_DISCONNECTED);
- m_wthread.kick();
-}
+ new_x = 0;
+ new_y = 0;
+ new_w = m_scalingWidth;
+ new_h = m_scalingHeight;
-enum RemoteViewStatus ControllerThread::status() {
- return m_status;
-}
+ TQImage scaledBlock = m_image.smoothScale(new_w, new_h);
+ bitBlt(&m_scaledImage, new_x, new_y, &scaledBlock, 0, 0, new_w, new_h);
+ m_resizeEntireFrame = false;
+ }
+ else {
+ // Extend redraw boundaries to avoid pixelation artifacts due to rounding errors
+ x = x - round((2.0 * m_image.width()) / m_scalingWidth);
+ y = y - round((2.0 * m_image.height()) / m_scalingHeight);
+ w = w + round((4.0 * m_image.width()) / m_scalingWidth);
+ h = h + round((4.0 * m_image.height()) / m_scalingHeight);
+
+ if (x < 0) {
+ x = 0;
+ }
+ if (y < 0) {
+ y = 0;
+ }
+ if (w > m_image.width()) {
+ w = m_image.width();
+ }
+ if (h > m_image.height()) {
+ h = m_image.height();
+ }
+ new_x = round((x * m_scalingWidth) / m_image.width());
+ new_y = round((y * m_scalingHeight) / m_image.height());
+ new_w = round((w * m_scalingWidth) / m_image.width());
+ new_h = round((h * m_scalingHeight) / m_image.height());
+ TQImage scaledBlock(m_scalingWidth, m_scalingHeight, 32);
+ pnmscale_fractional(m_image, scaledBlock, new_x, new_y, new_w, new_h);
+ bitBlt(&m_scaledImage, new_x, new_y, &scaledBlock, new_x, new_y, new_w, new_h);
+ }
+ mutex.unlock();
-static WriterThread *writerThread;
-void queueIncrementalUpdateRequest() {
- writerThread->queueIncrementalUpdateRequest();
+ DrawScreenRegion(new_x, new_y, new_w, new_h);
+ }
+ else {
+ DrawScreenRegion(x, y, w, h);
+ }
}
-void announceIncrementalUpdateRequest() {
- writerThread->announceIncrementalUpdateRequest();
+void ControllerThreadObject::setImage(const TQImage &img) {
+ TQMutexLocker locker(&mutex);
+
+ m_image = img;
}
+const TQImage ControllerThreadObject::image(int x, int y, int w, int h) {
+ TQMutexLocker locker(&mutex);
-WriterThread::WriterThread(KVncView *v, volatile bool &quitFlag) :
- m_quitFlag(quitFlag),
- m_view(v),
- m_lastIncrUpdatePostponed(false),
- m_incrementalUpdateRQ(false),
- m_incrementalUpdateAnnounced(false),
- m_mouseEventNum(0),
- m_keyEventNum(0),
- m_clientCut(TQString())
-{
- writerThread = this;
- m_lastIncrUpdate.start();
+ if (m_scaling) {
+ return m_scaledImage.copy(x, y, w, h);
+ }
+ else {
+ return m_image.copy(x, y, w, h);
+ }
}
-bool WriterThread::sendIncrementalUpdateRequest() {
- m_lastIncrUpdate.restart();
- return SendIncrementalFramebufferUpdateRequest();
-}
+void ControllerThreadObject::setScaling(int w, int h) {
+ bool scale;
-bool WriterThread::sendUpdateRequest(const TQRegion &region) {
- TQMemArray<TQRect> r = region.rects();
- for (unsigned int i = 0; i < r.size(); i++)
- if (!SendFramebufferUpdateRequest(r[i].x(),
- r[i].y(),
- r[i].width(),
- r[i].height(), False))
- return false;
- return true;
-}
+ if (w <= 0) {
+ scale = false;
+ }
+ else {
+ scale = true;
+ }
-bool WriterThread::sendInputEvents(const TQValueList<InputEvent> &events) {
- TQValueList<InputEvent>::const_iterator it = events.begin();
- while (it != events.end()) {
- if ((*it).type == KeyEventType) {
- if (!SendKeyEvent((*it).e.k.k, (*it).e.k.down ? True : False))
- return false;
- }
- else
- if (!SendPointerEvent((*it).e.m.x, (*it).e.m.y, (*it).e.m.buttons))
- return false;
- it++;
+ if ((m_scalingWidth != w) || (m_scalingHeight = h) || (m_scaling != scale)) {
+ m_resizeEntireFrame = true;
}
- return true;
-}
-void WriterThread::queueIncrementalUpdateRequest() {
- m_lock.lock();
- m_incrementalUpdateRQ = true;
- m_waiter.wakeAll();
- m_lock.unlock();
+ m_scaling = scale;
+ m_scalingWidth = w;
+ m_scalingHeight = h;
}
-void WriterThread::announceIncrementalUpdateRequest() {
- m_lock.lock();
- m_incrementalUpdateAnnounced = true;
- m_lock.unlock();
-}
+void ControllerThreadObject::run() {
+ mutex.lock();
+ rfbClientLog = output;
+ rfbClientErr = output;
+ cl->MallocFrameBuffer = newclient;
+ cl->canHandleNewFBSize = true;
+ cl->GetPassword = passwd;
+ cl->AuthenticationResults = authresults;
+ cl->NetworkStatus = networkstat;
+ cl->GotFrameBufferUpdate = updatefb;
+ rfbClientSetClientData(cl, 0, this);
-void WriterThread::queueUpdateRequest(const TQRegion &r) {
- m_lock.lock();
- m_updateRegionRQ += r;
- m_waiter.wakeAll();
- m_lock.unlock();
-}
+ // make a copy of the host string...
+ char *host = (char*) malloc(m_view->host().length());
+ strcpy(host, m_view->host().ascii());
-void WriterThread::queueMouseEvent(int x, int y, int buttonMask) {
- InputEvent e;
- e.type = MouseEventType;
- e.e.m.x = x;
- e.e.m.y = y;
- e.e.m.buttons = buttonMask;
-
- m_lock.lock();
- if (m_mouseEventNum > 0) {
- if ((e.e.m.x == m_lastMouseEvent.x) &&
- (e.e.m.y == m_lastMouseEvent.y) &&
- (e.e.m.buttons == m_lastMouseEvent.buttons)) {
- m_lock.unlock();
- return;
- }
- if (m_mouseEventNum >= MOUSEPRESS_QUEUE_SIZE) {
- m_lock.unlock();
+ cl->serverHost = host;
+
+ int port = m_view->port();
+ if(port >= 0 && port < 100) // the user most likely used the short form (e.g. :1)
+ port += 5900;
+ cl->serverPort = port;
+
+ mutex.unlock();
+
+ if(!rfbInitClient(cl, 0, 0)) {
+ sendFatalError(ERROR_INTERNAL);
+ // Terminate thread
+ TQThread::exit();
+ return;
+ }
+
+ TQApplication::postEvent(m_view,
+ new ScreenResizeEvent(cl->width,
+ cl->height));
+
+ changeStatus(REMOTE_VIEW_CONNECTED);
+
+ while (!m_quitFlag) {
+ int i = WaitForMessage(cl, 500);
+ if (i < 0) {
+ m_quitFlag = true;
+ changeStatus(REMOTE_VIEW_DISCONNECTED);
+
+ // Terminate thread
+ TQThread::exit();
return;
}
- if ((m_lastMouseEvent.buttons == buttonMask) &&
- (m_mouseEventNum >= MOUSEMOVE_QUEUE_SIZE)) {
- m_lock.unlock();
- return;
+ if (i) {
+ if(!HandleRFBServerMessage(cl)) {
+ m_quitFlag = true;
+ changeStatus(REMOTE_VIEW_DISCONNECTED);
+
+ // Terminate thread
+ TQThread::exit();
+ return;
+ }
}
}
- m_mouseEventNum++;
- m_lastMouseEvent = e.e.m;
+ m_quitFlag = true;
+ changeStatus(REMOTE_VIEW_DISCONNECTED);
- m_inputEvents.push_back(e);
- m_waiter.wakeAll();
- m_lock.unlock();
+ // Terminate thread
+ TQThread::exit();
}
-void WriterThread::queueKeyEvent(unsigned int k, bool down) {
- InputEvent e;
- e.type = KeyEventType;
- e.e.k.k = k;
- e.e.k.down = down;
-
- m_lock.lock();
- if (m_keyEventNum >= KEY_QUEUE_SIZE) {
- m_lock.unlock();
- return;
+void ControllerThreadObject::authenticationResults(int resultCode) {
+ if (resultCode == rfbVncAuthOK) {
+ changeStatus(REMOTE_VIEW_PREPARING);
}
+ else {
+ sendFatalError(ERROR_AUTHENTICATION);
- m_keyEventNum++;
- m_inputEvents.push_back(e);
- m_waiter.wakeAll();
- m_lock.unlock();
+ // Terminate thread
+ TQThread::exit();
+ }
}
-void WriterThread::queueClientCut(const TQString &text) {
- m_lock.lock();
-
- m_clientCut = text;
+void ControllerThreadObject::networkStatus(int statusCode) {
+ if (statusCode == rfbNetworkConnectionSuccess) {
+ // Stage 1 OK...
+ changeStatus(REMOTE_VIEW_AUTHENTICATING);
+ }
+ else if (statusCode == rfbNetworkRFBConnectionSuccess) {
+ // Stage 2 OK!
+ }
+ else {
+ if (statusCode == rfbNetworkConnectionClosed) {
+ sendFatalError(ERROR_CONNECTION);
+ }
+ else if (statusCode == rfbNetworkConnectionFailed) {
+ sendFatalError(ERROR_CONNECTION);
+ }
+ else if (statusCode == rfbNetworkNameResolutionFailed) {
+ sendFatalError(ERROR_NAME);
+ }
+ else if (statusCode == rfbNetworkRFBServerNotValid) {
+ sendFatalError(ERROR_IO);
+ }
+ else if (statusCode == rfbNetworkRFBProtocolFailure) {
+ sendFatalError(ERROR_PROTOCOL);
+ }
+
+ // Terminate thread
+ TQThread::exit();
+ }
+}
- m_waiter.wakeAll();
- m_lock.unlock();
+enum RemoteViewStatus ControllerThreadObject::status() {
+ return m_status;
}
-void WriterThread::kick() {
- m_waiter.wakeAll();
+void ControllerThreadObject::queueMouseEvent(int x, int y, int buttonMask) {
+ SendPointerEvent(cl, x, y, buttonMask);
}
-void WriterThread::run() {
- bool incrementalUpdateRQ = false;
- bool incrementalUpdateAnnounced = false;
- TQRegion updateRegionRQ;
- TQValueList<InputEvent> inputEvents;
- TQString clientCut;
-
- while (!m_quitFlag) {
- m_lock.lock();
- incrementalUpdateRQ = m_incrementalUpdateRQ;
- incrementalUpdateAnnounced = m_incrementalUpdateAnnounced;
- updateRegionRQ = m_updateRegionRQ;
- inputEvents = m_inputEvents;
- clientCut = m_clientCut;
-
- if ((!incrementalUpdateRQ) &&
- (updateRegionRQ.isNull()) &&
- (inputEvents.size() == 0) &&
- (clientCut.isNull())) {
- if (!m_waiter.wait(&m_lock,
- m_lastIncrUpdatePostponed ?
- POSTPONED_INCRRQ_WAIT_PERIOD : MAXIMUM_WAIT_PERIOD))
- m_incrementalUpdateRQ = true;
- m_lock.unlock();
- }
- else {
- m_incrementalUpdateRQ = false;
- m_incrementalUpdateAnnounced = false;
- m_updateRegionRQ = TQRegion();
- m_inputEvents.clear();
- m_keyEventNum = 0;
- m_mouseEventNum = 0;
- m_clientCut = TQString();
- m_lock.unlock();
-
- // always send incremental update, unless
- // a) a framebuffer update is done ATM and will do the request later, or
- // b) the last unrequested update has been done less than 0.1s ago
- //
- // if the update has not been done because of b, postpone it.
- if (incrementalUpdateRQ || !incrementalUpdateAnnounced) {
- bool sendUpdate;
- if (incrementalUpdateRQ) {
- sendUpdate = true;
- m_lastIncrUpdatePostponed = false;
- }
- else {
- if (m_lastIncrUpdate.elapsed() < 100) {
- sendUpdate = false;
- m_lastIncrUpdatePostponed = true;
- }
- else {
- sendUpdate = true;
- m_lastIncrUpdatePostponed = false;
- }
- }
-
- if (sendUpdate)
- if (!sendIncrementalUpdateRequest()) {
- sendFatalError(ERROR_IO);
- break;
- }
- }
- else
- m_lastIncrUpdatePostponed = false;
-
- if (!updateRegionRQ.isNull())
- if (!sendUpdateRequest(updateRegionRQ)) {
- sendFatalError(ERROR_IO);
- break;
- }
- if (inputEvents.size() != 0)
- if (!sendInputEvents(inputEvents)) {
- sendFatalError(ERROR_IO);
- break;
- }
- if (!clientCut.isNull()) {
- TQCString cutTextUtf8(clientCut.utf8());
- if (!SendClientCutText(cutTextUtf8.data(),
- (int)cutTextUtf8.length())) {
- sendFatalError(ERROR_IO);
- break;
- }
- }
- }
- }
- m_quitFlag = true;
+void ControllerThreadObject::queueKeyEvent(unsigned int k, bool down) {
+ SendKeyEvent(cl, k, down);
}
-void WriterThread::sendFatalError(ErrorCode s) {
- m_quitFlag = true;
- TQApplication::postEvent(m_view, new FatalErrorEvent(s));
+void ControllerThreadObject::queueClientCut(const TQString &text) {
+ SendClientCutText(cl, (char*)text.ascii(), text.length());
}
+#include "threads.moc" \ No newline at end of file