SVN_SILENT
[kdenetwork.git] / krdc / vnc / vncclientthread.cpp
blob98edf5fc65314529a86a53287b7c3fae1bbd116f
1 /****************************************************************************
2 **
3 ** Copyright (C) 2007 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 <KDebug>
27 #include <KLocale>
29 #include <QMutexLocker>
30 #include <QTimer>
32 static QString outputErrorMessageString;
34 static uint8_t *buf = 0;
36 static rfbBool newclient(rfbClient *cl)
38 int width = cl->width, height = cl->height, depth = cl->format.bitsPerPixel;
39 int size = width * height * (depth / 8);
40 if (cl->frameBuffer)
41 delete [] buf; // do not leak if we get a new framebuffer size
42 buf = new uint8_t[size];
43 memset(buf, '\0', size);
44 cl->frameBuffer = buf;
45 cl->format.bitsPerPixel = 32;
46 cl->format.redShift = 16;
47 cl->format.greenShift = 8;
48 cl->format.blueShift = 0;
49 cl->format.redMax = 0xff;
50 cl->format.greenMax = 0xff;
51 cl->format.blueMax = 0xff;
53 VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
55 switch (t->quality()) {
56 case RemoteView::High:
57 cl->appData.useBGR233 = 0;
58 cl->appData.encodingsString = "copyrect hextile raw";
59 cl->appData.compressLevel = 0;
60 cl->appData.qualityLevel = 9;
61 break;
62 case RemoteView::Medium:
63 cl->appData.useBGR233 = 0;
64 cl->appData.encodingsString = "tight zrle ultra copyrect hextile zlib corre rre raw";
65 cl->appData.compressLevel = 5;
66 cl->appData.qualityLevel = 7;
67 break;
68 case RemoteView::Low:
69 case RemoteView::Unknown:
70 default:
71 cl->appData.useBGR233 = 1;
72 cl->appData.encodingsString = "tight zrle ultra copyrect hextile zlib corre rre raw";
73 cl->appData.compressLevel = 9;
74 cl->appData.qualityLevel = 1;
77 SetFormatAndEncodings(cl);
79 return true;
82 extern void updatefb(rfbClient* cl, int x, int y, int w, int h)
84 // kDebug(5011) << "updated client: x: " << x << ", y: " << y << ", w: " << w << ", h: " << h;
86 int width = cl->width, height = cl->height;
88 QImage img(cl->frameBuffer, width, height, QImage::Format_RGB32);
90 if (img.isNull())
91 kDebug(5011) << "image not loaded";
94 VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
96 if (!t)
97 return;
99 t->setImage(img);
101 t->emitUpdated(x, y, w, h);
104 extern void cuttext(rfbClient* cl, const char *text, int textlen)
106 QString cutText = QString::fromUtf8(text, textlen);
107 kDebug(5011) << cutText;
109 if (!cutText.isEmpty()) {
110 VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
112 if (!t)
113 return;
115 t->emitGotCut(cutText);
119 char *VncClientThread::passwdHandler(rfbClient *cl)
121 kDebug(5011) << "password request" << kBacktrace();
123 VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
125 if (!t)
126 return 0;
128 t->passwordRequest();
129 t->m_passwordError = true;
131 return strdup(t->password().toLocal8Bit());
134 void VncClientThread::outputHandler(const char *format, ...)
136 va_list args;
137 va_start(args, format);
139 QString message;
140 message.vsprintf(format, args);
142 va_end(args);
144 message = message.trimmed();
146 kDebug(5011) << message;
148 if ((message.contains("Couldn't convert ")) ||
149 (message.contains("Unable to connect to VNC server")))
150 outputErrorMessageString = i18n("Server not found.");
152 if ((message.contains("VNC connection failed: Authentication failed, too many tries")) ||
153 (message.contains("VNC connection failed: Too many authentication failures")))
154 outputErrorMessageString = i18n("VNC authentication failed because of too many authentication tries.");
156 if (message.contains("VNC connection failed: Authentication failed"))
157 outputErrorMessageString = i18n("VNC authentication failed.");
159 if (message.contains("VNC server closed connection"))
160 outputErrorMessageString = i18n("VNC server closed connection.");
163 VncClientThread::VncClientThread()
165 QMutexLocker locker(&mutex);
166 m_stopped = false;
168 QTimer *outputErrorMessagesCheckTimer = new QTimer(this);
169 outputErrorMessagesCheckTimer->setInterval(500);
170 connect(outputErrorMessagesCheckTimer, SIGNAL(timeout()), this, SLOT(checkOutputErrorMessage()));
171 outputErrorMessagesCheckTimer->start();
174 VncClientThread::~VncClientThread()
176 stop();
177 wait(500);
180 void VncClientThread::checkOutputErrorMessage()
182 if (!outputErrorMessageString.isEmpty()) {
183 kDebug(5011) << outputErrorMessageString;
184 QString errorMessage = outputErrorMessageString;
185 outputErrorMessageString.clear();
186 // show authentication failure error only after the 3rd unsuccessful try
187 if ((errorMessage != i18n("VNC authentication failed.")) || m_passwordError)
188 outputErrorMessage(errorMessage);
192 void VncClientThread::setHost(const QString &host)
194 QMutexLocker locker(&mutex);
195 m_host = host;
198 void VncClientThread::setPort(int port)
200 QMutexLocker locker(&mutex);
201 m_port = port;
204 void VncClientThread::setQuality(RemoteView::Quality quality)
206 m_quality = quality;
209 RemoteView::Quality VncClientThread::quality() const
211 return m_quality;
214 void VncClientThread::setImage(const QImage &img)
216 QMutexLocker locker(&mutex);
217 m_image = img;
220 const QImage VncClientThread::image(int x, int y, int w, int h)
222 QMutexLocker locker(&mutex);
224 if (w == 0) // full image requested
225 return m_image;
226 else
227 return m_image.copy(x, y, w, h);
230 void VncClientThread::emitUpdated(int x, int y, int w, int h)
232 emit imageUpdated(x, y, w, h);
235 void VncClientThread::emitGotCut(const QString &text)
237 emit gotCut(text);
240 void VncClientThread::stop()
242 QMutexLocker locker(&mutex);
243 m_stopped = true;
246 void VncClientThread::run()
248 QMutexLocker locker(&mutex);
250 while (!m_stopped) { // try to connect as long as the server allows
251 m_passwordError = false;
253 rfbClientLog = outputHandler;
254 rfbClientErr = outputHandler;
255 cl = rfbGetClient(8, 3, 4);
256 cl->MallocFrameBuffer = newclient;
257 cl->canHandleNewFBSize = true;
258 cl->GetPassword = passwdHandler;
259 cl->GotFrameBufferUpdate = updatefb;
260 cl->GotXCutText = cuttext;
261 rfbClientSetClientData(cl, 0, this);
263 cl->serverHost = strdup(m_host.toUtf8().constData());
265 if (m_port < 0 || !m_port) // port is invalid or empty...
266 m_port = 5900; // fallback: try an often used VNC port
268 if (m_port >= 0 && m_port < 100) // the user most likely used the short form (e.g. :1)
269 m_port += 5900;
270 cl->serverPort = m_port;
272 kDebug(5011) << "--------------------- trying init ---------------------";
274 if (rfbInitClient(cl, 0, 0))
275 break;
277 if (m_passwordError)
278 continue;
280 return;
283 locker.unlock();
285 // Main VNC event loop
286 while (!m_stopped) {
287 int i = WaitForMessage(cl, 500);
288 if (i < 0)
289 break;
290 if (i)
291 if (!HandleRFBServerMessage(cl))
292 break;
294 locker.relock();
296 while (!m_eventQueue.isEmpty()) {
297 ClientEvent* clientEvent = m_eventQueue.dequeue();
298 clientEvent->fire(cl);
299 delete clientEvent;
302 locker.unlock();
305 // Cleanup allocated resources
306 locker.relock();
307 delete [] cl->frameBuffer;
308 cl->frameBuffer = 0;
309 rfbClientCleanup(cl);
310 buf = 0;
311 m_stopped = true;
314 ClientEvent::~ClientEvent()
318 void PointerClientEvent::fire(rfbClient* cl)
320 SendPointerEvent(cl, m_x, m_y, m_buttonMask);
323 void KeyClientEvent::fire(rfbClient* cl)
325 SendKeyEvent(cl, m_key, m_pressed);
328 void ClientCutEvent::fire(rfbClient* cl)
330 SendClientCutText(cl, text, qstrlen(text));
333 void VncClientThread::mouseEvent(int x, int y, int buttonMask)
335 QMutexLocker lock(&mutex);
336 if (m_stopped)
337 return;
339 m_eventQueue.enqueue(new PointerClientEvent(x, y, buttonMask));
342 void VncClientThread::keyEvent(int key, bool pressed)
344 QMutexLocker lock(&mutex);
345 if (m_stopped)
346 return;
348 m_eventQueue.enqueue(new KeyClientEvent(key, pressed));
351 void VncClientThread::clientCut(const QString &text)
353 QMutexLocker lock(&mutex);
354 if (m_stopped)
355 return;
357 m_eventQueue.enqueue(new ClientCutEvent(strdup(text.toUtf8())));
360 #include "vncclientthread.moc"