You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/krdc/vnc/threads.cpp

384 lines
9.2 KiB

/***************************************************************************
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"