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 rfbBool
VncClientThread::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 void VncClientThread::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 void VncClientThread::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.");
159 // internal messages, not displayed to user
160 if (message
.contains("VNC server supports protocol version 3.889")) // see http://bugs.kde.org/162640
161 outputErrorMessageString
= "INTERNAL:APPLE_VNC_COMPATIBILTY";
164 VncClientThread::VncClientThread(QObject
*parent
)
167 QMutexLocker
locker(&mutex
);
170 QTimer
*outputErrorMessagesCheckTimer
= new QTimer(this);
171 outputErrorMessagesCheckTimer
->setInterval(500);
172 connect(outputErrorMessagesCheckTimer
, SIGNAL(timeout()), this, SLOT(checkOutputErrorMessage()));
173 outputErrorMessagesCheckTimer
->start();
176 VncClientThread::~VncClientThread()
182 void VncClientThread::checkOutputErrorMessage()
184 if (!outputErrorMessageString
.isEmpty()) {
185 kDebug(5011) << outputErrorMessageString
;
186 QString errorMessage
= outputErrorMessageString
;
187 outputErrorMessageString
.clear();
188 // show authentication failure error only after the 3rd unsuccessful try
189 if ((errorMessage
!= i18n("VNC authentication failed.")) || m_passwordError
)
190 outputErrorMessage(errorMessage
);
194 void VncClientThread::setHost(const QString
&host
)
196 QMutexLocker
locker(&mutex
);
200 void VncClientThread::setPort(int port
)
202 QMutexLocker
locker(&mutex
);
206 void VncClientThread::setQuality(RemoteView::Quality quality
)
211 RemoteView::Quality
VncClientThread::quality() const
216 void VncClientThread::setImage(const QImage
&img
)
218 QMutexLocker
locker(&mutex
);
222 const QImage
VncClientThread::image(int x
, int y
, int w
, int h
)
224 QMutexLocker
locker(&mutex
);
226 if (w
== 0) // full image requested
229 return m_image
.copy(x
, y
, w
, h
);
232 void VncClientThread::emitUpdated(int x
, int y
, int w
, int h
)
234 emit
imageUpdated(x
, y
, w
, h
);
237 void VncClientThread::emitGotCut(const QString
&text
)
242 void VncClientThread::stop()
244 QMutexLocker
locker(&mutex
);
248 void VncClientThread::run()
250 QMutexLocker
locker(&mutex
);
252 while (!m_stopped
) { // try to connect as long as the server allows
253 m_passwordError
= false;
255 rfbClientLog
= outputHandler
;
256 rfbClientErr
= outputHandler
;
257 cl
= rfbGetClient(8, 3, 4);
258 cl
->MallocFrameBuffer
= newclient
;
259 cl
->canHandleNewFBSize
= true;
260 cl
->GetPassword
= passwdHandler
;
261 cl
->GotFrameBufferUpdate
= updatefb
;
262 cl
->GotXCutText
= cuttext
;
263 rfbClientSetClientData(cl
, 0, this);
265 cl
->serverHost
= strdup(m_host
.toUtf8().constData());
267 if (m_port
< 0 || !m_port
) // port is invalid or empty...
268 m_port
= 5900; // fallback: try an often used VNC port
270 if (m_port
>= 0 && m_port
< 100) // the user most likely used the short form (e.g. :1)
272 cl
->serverPort
= m_port
;
274 kDebug(5011) << "--------------------- trying init ---------------------";
276 if (rfbInitClient(cl
, 0, 0))
287 // Main VNC event loop
289 int i
= WaitForMessage(cl
, 500);
293 if (!HandleRFBServerMessage(cl
))
298 while (!m_eventQueue
.isEmpty()) {
299 ClientEvent
* clientEvent
= m_eventQueue
.dequeue();
300 clientEvent
->fire(cl
);
307 // Cleanup allocated resources
309 delete [] cl
->frameBuffer
;
311 rfbClientCleanup(cl
);
316 ClientEvent::~ClientEvent()
320 void PointerClientEvent::fire(rfbClient
* cl
)
322 SendPointerEvent(cl
, m_x
, m_y
, m_buttonMask
);
325 void KeyClientEvent::fire(rfbClient
* cl
)
327 SendKeyEvent(cl
, m_key
, m_pressed
);
330 void ClientCutEvent::fire(rfbClient
* cl
)
332 SendClientCutText(cl
, text
, qstrlen(text
));
335 void VncClientThread::mouseEvent(int x
, int y
, int buttonMask
)
337 QMutexLocker
lock(&mutex
);
341 m_eventQueue
.enqueue(new PointerClientEvent(x
, y
, buttonMask
));
344 void VncClientThread::keyEvent(int key
, bool pressed
)
346 QMutexLocker
lock(&mutex
);
350 m_eventQueue
.enqueue(new KeyClientEvent(key
, pressed
));
353 void VncClientThread::clientCut(const QString
&text
)
355 QMutexLocker
lock(&mutex
);
359 m_eventQueue
.enqueue(new ClientCutEvent(strdup(text
.toUtf8())));
362 #include "moc_vncclientthread.cpp"