1 /****************************************************************************
3 ** Copyright (C) 2007-2008 Urs Wolfer <uwolfer @ kde.org>
5 ** This file is part of KDE.
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>
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);
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;
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;
66 case RemoteView::Unknown
:
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
);
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
);
88 kDebug(5011) << "image not loaded";
91 VncClientThread
*t
= (VncClientThread
*)rfbClientGetClientData(cl
, 0);
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);
112 t
->emitGotCut(cutText
);
116 char *VncClientThread::passwdHandler(rfbClient
*cl
)
118 kDebug(5011) << "password request" << kBacktrace();
120 VncClientThread
*t
= (VncClientThread
*)rfbClientGetClientData(cl
, 0);
125 t
->passwordRequest();
126 t
->m_passwordError
= true;
128 return strdup(t
->password().toLocal8Bit());
131 void VncClientThread::outputHandler(const char *format
, ...)
134 va_start(args
, format
);
137 message
.vsprintf(format
, 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
);
165 QTimer
*outputErrorMessagesCheckTimer
= new QTimer(this);
166 outputErrorMessagesCheckTimer
->setInterval(500);
167 connect(outputErrorMessagesCheckTimer
, SIGNAL(timeout()), this, SLOT(checkOutputErrorMessage()));
168 outputErrorMessagesCheckTimer
->start();
171 VncClientThread::~VncClientThread()
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
);
195 void VncClientThread::setPort(int port
)
197 QMutexLocker
locker(&mutex
);
201 void VncClientThread::setQuality(RemoteView::Quality quality
)
206 RemoteView::Quality
VncClientThread::quality() const
211 void VncClientThread::setImage(const QImage
&img
)
213 QMutexLocker
locker(&mutex
);
217 const QImage
VncClientThread::image(int x
, int y
, int w
, int h
)
219 QMutexLocker
locker(&mutex
);
221 if (w
== 0) // full image requested
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
)
237 void VncClientThread::stop()
239 QMutexLocker
locker(&mutex
);
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)
267 cl
->serverPort
= m_port
;
269 kDebug(5011) << "--------------------- trying init ---------------------";
271 if (rfbInitClient(cl
, 0, 0))
282 // Main VNC event loop
284 int i
= WaitForMessage(cl
, 500);
288 if (!HandleRFBServerMessage(cl
))
293 while (!m_eventQueue
.isEmpty()) {
294 ClientEvent
* clientEvent
= m_eventQueue
.dequeue();
295 clientEvent
->fire(cl
);
302 // Cleanup allocated resources
304 delete [] cl
->frameBuffer
;
306 rfbClientCleanup(cl
);
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
);
336 m_eventQueue
.enqueue(new PointerClientEvent(x
, y
, buttonMask
));
339 void VncClientThread::keyEvent(int key
, bool pressed
)
341 QMutexLocker
lock(&mutex
);
345 m_eventQueue
.enqueue(new KeyClientEvent(key
, pressed
));
348 void VncClientThread::clientCut(const QString
&text
)
350 QMutexLocker
lock(&mutex
);
354 m_eventQueue
.enqueue(new ClientCutEvent(strdup(text
.toUtf8())));
357 #include "moc_vncclientthread.cpp"