diff options
Diffstat (limited to 'krdc/vnc/threads.cpp')
-rw-r--r-- | krdc/vnc/threads.cpp | 584 |
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 ®ion) { - 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 |