1 /****************************************************************************
3 ** Copyright (C) 2007 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"
29 #include <QMutexLocker>
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);
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;
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;
69 case RemoteView::Unknown
:
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
);
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
);
91 kDebug(5011) << "image not loaded";
94 VncClientThread
*t
= (VncClientThread
*)rfbClientGetClientData(cl
, 0);
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);
115 t
->emitGotCut(cutText
);
119 char *VncClientThread::passwdHandler(rfbClient
*cl
)
121 kDebug(5011) << "password request" << kBacktrace();
123 VncClientThread
*t
= (VncClientThread
*)rfbClientGetClientData(cl
, 0);
128 t
->passwordRequest();
129 t
->m_passwordError
= true;
131 return strdup(t
->password().toLocal8Bit());
134 void VncClientThread::outputHandler(const char *format
, ...)
137 va_start(args
, format
);
140 message
.vsprintf(format
, 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
);
168 QTimer
*outputErrorMessagesCheckTimer
= new QTimer(this);
169 outputErrorMessagesCheckTimer
->setInterval(500);
170 connect(outputErrorMessagesCheckTimer
, SIGNAL(timeout()), this, SLOT(checkOutputErrorMessage()));
171 outputErrorMessagesCheckTimer
->start();
174 VncClientThread::~VncClientThread()
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
);
198 void VncClientThread::setPort(int port
)
200 QMutexLocker
locker(&mutex
);
204 void VncClientThread::setQuality(RemoteView::Quality quality
)
209 RemoteView::Quality
VncClientThread::quality() const
214 void VncClientThread::setImage(const QImage
&img
)
216 QMutexLocker
locker(&mutex
);
220 const QImage
VncClientThread::image(int x
, int y
, int w
, int h
)
222 QMutexLocker
locker(&mutex
);
224 if (w
== 0) // full image requested
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
)
240 void VncClientThread::stop()
242 QMutexLocker
locker(&mutex
);
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)
270 cl
->serverPort
= m_port
;
272 kDebug(5011) << "--------------------- trying init ---------------------";
274 if (rfbInitClient(cl
, 0, 0))
285 // Main VNC event loop
287 int i
= WaitForMessage(cl
, 500);
291 if (!HandleRFBServerMessage(cl
))
296 while (!m_eventQueue
.isEmpty()) {
297 ClientEvent
* clientEvent
= m_eventQueue
.dequeue();
298 clientEvent
->fire(cl
);
305 // Cleanup allocated resources
307 delete [] cl
->frameBuffer
;
309 rfbClientCleanup(cl
);
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
);
339 m_eventQueue
.enqueue(new PointerClientEvent(x
, y
, buttonMask
));
342 void VncClientThread::keyEvent(int key
, bool pressed
)
344 QMutexLocker
lock(&mutex
);
348 m_eventQueue
.enqueue(new KeyClientEvent(key
, pressed
));
351 void VncClientThread::clientCut(const QString
&text
)
353 QMutexLocker
lock(&mutex
);
357 m_eventQueue
.enqueue(new ClientCutEvent(strdup(text
.toUtf8())));
360 #include "vncclientthread.moc"