|
|
|
/***************************************************************************
|
|
|
|
threads.cpp - threads
|
|
|
|
-------------------
|
|
|
|
begin : Thu May 09 17:01:44 CET 2002
|
|
|
|
copyright : (C) 2015 Timothy Pearson <kb9vqf@pearsoncomputing.net>
|
|
|
|
(C) 2002 by Tim Jansen
|
|
|
|
email : tim@tjansen.de
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "kvncview.h"
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <tdeapplication.h>
|
|
|
|
|
|
|
|
#include "vncviewer.h"
|
|
|
|
#include "threads.h"
|
|
|
|
|
|
|
|
#include <tqcstring.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
extern void pnmscale_fractional(const TQImage& src, TQImage& dst, int x, int y, int w, int h);
|
|
|
|
|
|
|
|
int getPassword(char * &passwd);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern char *passwd(rfbClient *cl)
|
|
|
|
{
|
|
|
|
Q_UNUSED(cl)
|
|
|
|
|
|
|
|
kdDebug(5011) << "password request" << endl;
|
|
|
|
|
|
|
|
char *passwd;
|
|
|
|
if (getPassword(passwd)) {
|
|
|
|
return passwd;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern void authresults(rfbClient *cl, uint32_t authResult)
|
|
|
|
{
|
|
|
|
kdDebug(5011) << "authentication result: " << authResult << endl;
|
|
|
|
|
|
|
|
ControllerThreadObject *t = (ControllerThreadObject*)rfbClientGetClientData(cl, 0);
|
|
|
|
|
|
|
|
t->authenticationResults(authResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern void networkstat(rfbClient *cl, uint32_t statuscode)
|
|
|
|
{
|
|
|
|
kdDebug(5011) << "network status: " << statuscode << endl;
|
|
|
|
|
|
|
|
ControllerThreadObject *t = (ControllerThreadObject*)rfbClientGetClientData(cl, 0);
|
|
|
|
|
|
|
|
t->networkStatus(statuscode);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 (message.contains("VNC authentication succeeded")) {
|
|
|
|
kdDebug(5011) << "Password OK" << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
cl = rfbGetClient(8, 3, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
ControllerThreadObject::~ControllerThreadObject() {
|
|
|
|
TQMutexLocker locker(&mutex);
|
|
|
|
|
|
|
|
rfbClientCleanup(cl);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ControllerThreadObject::changeStatus(RemoteViewStatus s) {
|
|
|
|
m_status = s;
|
|
|
|
TQApplication::postEvent(m_view, new StatusChangeEvent(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ControllerThreadObject::sendFatalError(ErrorCode s) {
|
|
|
|
m_quitFlag = true;
|
|
|
|
TQApplication::postEvent(m_view, new FatalErrorEvent(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ControllerThreadObject::queueDrawRegion(int x, int y, int w, int h) {
|
|
|
|
if (m_scaling) {
|
|
|
|
// Rescale desktop
|
|
|
|
|
|
|
|
int new_x;
|
|
|
|
int new_y;
|
|
|
|
int new_w;
|
|
|
|
int new_h;
|
|
|
|
|
|
|
|
mutex.lock();
|
|
|
|
|
|
|
|
if (m_resizeEntireFrame) {
|
|
|
|
m_scaledImage.create(m_scalingWidth, m_scalingHeight, 32);
|
|
|
|
|
|
|
|
new_x = 0;
|
|
|
|
new_y = 0;
|
|
|
|
new_w = m_scalingWidth;
|
|
|
|
new_h = m_scalingHeight;
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
DrawScreenRegion(new_x, new_y, new_w, new_h);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DrawScreenRegion(x, y, w, h);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (m_scaling) {
|
|
|
|
return m_scaledImage.copy(x, y, w, h);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return m_image.copy(x, y, w, h);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ControllerThreadObject::setScaling(int w, int h) {
|
|
|
|
bool scale;
|
|
|
|
|
|
|
|
if (w <= 0) {
|
|
|
|
scale = false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
scale = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((m_scalingWidth != w) || (m_scalingHeight = h) || (m_scaling != scale)) {
|
|
|
|
m_resizeEntireFrame = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_scaling = scale;
|
|
|
|
m_scalingWidth = w;
|
|
|
|
m_scalingHeight = h;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
// make a copy of the host string...
|
|
|
|
char *host = (char*) malloc(m_view->host().length());
|
|
|
|
strcpy(host, m_view->host().ascii());
|
|
|
|
|
|
|
|
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 (i) {
|
|
|
|
if(!HandleRFBServerMessage(cl)) {
|
|
|
|
m_quitFlag = true;
|
|
|
|
changeStatus(REMOTE_VIEW_DISCONNECTED);
|
|
|
|
|
|
|
|
// Terminate thread
|
|
|
|
TQThread::exit();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_quitFlag = true;
|
|
|
|
changeStatus(REMOTE_VIEW_DISCONNECTED);
|
|
|
|
|
|
|
|
// Terminate thread
|
|
|
|
TQThread::exit();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ControllerThreadObject::authenticationResults(int resultCode) {
|
|
|
|
if (resultCode == rfbVncAuthOK) {
|
|
|
|
changeStatus(REMOTE_VIEW_PREPARING);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sendFatalError(ERROR_AUTHENTICATION);
|
|
|
|
|
|
|
|
// Terminate thread
|
|
|
|
TQThread::exit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum RemoteViewStatus ControllerThreadObject::status() {
|
|
|
|
return m_status;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ControllerThreadObject::queueMouseEvent(int x, int y, int buttonMask) {
|
|
|
|
SendPointerEvent(cl, x, y, buttonMask);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ControllerThreadObject::queueKeyEvent(unsigned int k, bool down) {
|
|
|
|
SendKeyEvent(cl, k, down);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ControllerThreadObject::queueClientCut(const TQString &text) {
|
|
|
|
SendClientCutText(cl, (char*)text.ascii(), text.length());
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "threads.moc"
|