Ability to build a Qt-only version of the KRDC VNC backend.
[kdenetwork.git] / krdc / vnc / vncclientthread.cpp
blobed053dfe40394a80be7bb59f2b2325e0482a8e5f
1 /****************************************************************************
2 **
3 ** Copyright (C) 2007-2008 Urs Wolfer <uwolfer @ kde.org>
4 **
5 ** This file is part of KDE.
6 **
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation; either version 2 of the License, or
10 ** (at your option) any later version.
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; see the file COPYING. If not, write to
19 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 ** Boston, MA 02110-1301, USA.
22 ****************************************************************************/
24 #include "vncclientthread.h"
26 #include <QMutexLocker>
27 #include <QTimer>
29 static QString outputErrorMessageString;
31 static uint8_t *buf = 0;
33 static rfbBool newclient(rfbClient *cl)
35 int width = cl->width, height = cl->height, depth = cl->format.bitsPerPixel;
36 int size = width * height * (depth / 8);
37 if (cl->frameBuffer)
38 delete [] buf; // do not leak if we get a new framebuffer size
39 buf = new uint8_t[size];
40 memset(buf, '\0', size);
41 cl->frameBuffer = buf;
42 cl->format.bitsPerPixel = 32;
43 cl->format.redShift = 16;
44 cl->format.greenShift = 8;
45 cl->format.blueShift = 0;
46 cl->format.redMax = 0xff;
47 cl->format.greenMax = 0xff;
48 cl->format.blueMax = 0xff;
50 VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
52 switch (t->quality()) {
53 case RemoteView::High:
54 cl->appData.useBGR233 = 0;
55 cl->appData.encodingsString = "copyrect hextile raw";
56 cl->appData.compressLevel = 0;
57 cl->appData.qualityLevel = 9;
58 break;
59 case RemoteView::Medium:
60 cl->appData.useBGR233 = 0;
61 cl->appData.encodingsString = "tight zrle ultra copyrect hextile zlib corre rre raw";
62 cl->appData.compressLevel = 5;
63 cl->appData.qualityLevel = 7;
64 break;
65 case RemoteView::Low:
66 case RemoteView::Unknown:
67 default:
68 cl->appData.useBGR233 = 1;
69 cl->appData.encodingsString = "tight zrle ultra copyrect hextile zlib corre rre raw";
70 cl->appData.compressLevel = 9;
71 cl->appData.qualityLevel = 1;
74 SetFormatAndEncodings(cl);
76 return true;
79 extern void updatefb(rfbClient* cl, int x, int y, int w, int h)
81 // kDebug(5011) << "updated client: x: " << x << ", y: " << y << ", w: " << w << ", h: " << h;
83 int width = cl->width, height = cl->height;
85 QImage img(cl->frameBuffer, width, height, QImage::Format_RGB32);
87 if (img.isNull())
88 kDebug(5011) << "image not loaded";
91 VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
93 if (!t)
94 return;
96 t->setImage(img);
98 t->emitUpdated(x, y, w, h);
101 extern void cuttext(rfbClient* cl, const char *text, int textlen)
103 QString cutText = QString::fromUtf8(text, textlen);
104 kDebug(5011) << cutText;
106 if (!cutText.isEmpty()) {
107 VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
109 if (!t)
110 return;
112 t->emitGotCut(cutText);
116 char *VncClientThread::passwdHandler(rfbClient *cl)
118 kDebug(5011) << "password request" << kBacktrace();
120 VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
122 if (!t)
123 return 0;
125 t->passwordRequest();
126 t->m_passwordError = true;
128 return strdup(t->password().toLocal8Bit());
131 void VncClientThread::outputHandler(const char *format, ...)
133 va_list args;
134 va_start(args, format);
136 QString message;
137 message.vsprintf(format, args);
139 va_end(args);
141 message = message.trimmed();
143 kDebug(5011) << message;
145 if ((message.contains("Couldn't convert ")) ||
146 (message.contains("Unable to connect to VNC server")))
147 outputErrorMessageString = i18n("Server not found.");
149 if ((message.contains("VNC connection failed: Authentication failed, too many tries")) ||
150 (message.contains("VNC connection failed: Too many authentication failures")))
151 outputErrorMessageString = i18n("VNC authentication failed because of too many authentication tries.");
153 if (message.contains("VNC connection failed: Authentication failed"))
154 outputErrorMessageString = i18n("VNC authentication failed.");
156 if (message.contains("VNC server closed connection"))
157 outputErrorMessageString = i18n("VNC server closed connection.");
160 VncClientThread::VncClientThread()
162 QMutexLocker locker(&mutex);
163 m_stopped = false;
165 QTimer *outputErrorMessagesCheckTimer = new QTimer(this);
166 outputErrorMessagesCheckTimer->setInterval(500);
167 connect(outputErrorMessagesCheckTimer, SIGNAL(timeout()), this, SLOT(checkOutputErrorMessage()));
168 outputErrorMessagesCheckTimer->start();
171 VncClientThread::~VncClientThread()
173 stop();
174 wait(500);
177 void VncClientThread::checkOutputErrorMessage()
179 if (!outputErrorMessageString.isEmpty()) {
180 kDebug(5011) << outputErrorMessageString;
181 QString errorMessage = outputErrorMessageString;
182 outputErrorMessageString.clear();
183 // show authentication failure error only after the 3rd unsuccessful try
184 if ((errorMessage != i18n("VNC authentication failed.")) || m_passwordError)
185 outputErrorMessage(errorMessage);
189 void VncClientThread::setHost(const QString &host)
191 QMutexLocker locker(&mutex);
192 m_host = host;
195 void VncClientThread::setPort(int port)
197 QMutexLocker locker(&mutex);
198 m_port = port;
201 void VncClientThread::setQuality(RemoteView::Quality quality)
203 m_quality = quality;
206 RemoteView::Quality VncClientThread::quality() const
208 return m_quality;
211 void VncClientThread::setImage(const QImage &img)
213 QMutexLocker locker(&mutex);
214 m_image = img;
217 const QImage VncClientThread::image(int x, int y, int w, int h)
219 QMutexLocker locker(&mutex);
221 if (w == 0) // full image requested
222 return m_image;
223 else
224 return m_image.copy(x, y, w, h);
227 void VncClientThread::emitUpdated(int x, int y, int w, int h)
229 emit imageUpdated(x, y, w, h);
232 void VncClientThread::emitGotCut(const QString &text)
234 emit gotCut(text);
237 void VncClientThread::stop()
239 QMutexLocker locker(&mutex);
240 m_stopped = true;
243 void VncClientThread::run()
245 QMutexLocker locker(&mutex);
247 while (!m_stopped) { // try to connect as long as the server allows
248 m_passwordError = false;
250 rfbClientLog = outputHandler;
251 rfbClientErr = outputHandler;
252 cl = rfbGetClient(8, 3, 4);
253 cl->MallocFrameBuffer = newclient;
254 cl->canHandleNewFBSize = true;
255 cl->GetPassword = passwdHandler;
256 cl->GotFrameBufferUpdate = updatefb;
257 cl->GotXCutText = cuttext;
258 rfbClientSetClientData(cl, 0, this);
260 cl->serverHost = strdup(m_host.toUtf8().constData());
262 if (m_port < 0 || !m_port) // port is invalid or empty...
263 m_port = 5900; // fallback: try an often used VNC port
265 if (m_port >= 0 && m_port < 100) // the user most likely used the short form (e.g. :1)
266 m_port += 5900;
267 cl->serverPort = m_port;
269 kDebug(5011) << "--------------------- trying init ---------------------";
271 if (rfbInitClient(cl, 0, 0))
272 break;
274 if (m_passwordError)
275 continue;
277 return;
280 locker.unlock();
282 // Main VNC event loop
283 while (!m_stopped) {
284 int i = WaitForMessage(cl, 500);
285 if (i < 0)
286 break;
287 if (i)
288 if (!HandleRFBServerMessage(cl))
289 break;
291 locker.relock();
293 while (!m_eventQueue.isEmpty()) {
294 ClientEvent* clientEvent = m_eventQueue.dequeue();
295 clientEvent->fire(cl);
296 delete clientEvent;
299 locker.unlock();
302 // Cleanup allocated resources
303 locker.relock();
304 delete [] cl->frameBuffer;
305 cl->frameBuffer = 0;
306 rfbClientCleanup(cl);
307 buf = 0;
308 m_stopped = true;
311 ClientEvent::~ClientEvent()
315 void PointerClientEvent::fire(rfbClient* cl)
317 SendPointerEvent(cl, m_x, m_y, m_buttonMask);
320 void KeyClientEvent::fire(rfbClient* cl)
322 SendKeyEvent(cl, m_key, m_pressed);
325 void ClientCutEvent::fire(rfbClient* cl)
327 SendClientCutText(cl, text, qstrlen(text));
330 void VncClientThread::mouseEvent(int x, int y, int buttonMask)
332 QMutexLocker lock(&mutex);
333 if (m_stopped)
334 return;
336 m_eventQueue.enqueue(new PointerClientEvent(x, y, buttonMask));
339 void VncClientThread::keyEvent(int key, bool pressed)
341 QMutexLocker lock(&mutex);
342 if (m_stopped)
343 return;
345 m_eventQueue.enqueue(new KeyClientEvent(key, pressed));
348 void VncClientThread::clientCut(const QString &text)
350 QMutexLocker lock(&mutex);
351 if (m_stopped)
352 return;
354 m_eventQueue.enqueue(new ClientCutEvent(strdup(text.toUtf8())));
357 #include "moc_vncclientthread.cpp"