Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Added guest GDT and IDT printing
[palacios.git] / linux_usr / gui / palacios / vnc_module / vncclientthread.cpp
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.
11 **
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.
16 **
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.
21 **
22 ****************************************************************************/
23
24 #include "vncclientthread.h"
25
26 #include <QMutexLocker>
27 #include <QTimer>
28
29 //for detecting intel AMT KVM vnc server
30 static const QString INTEL_AMT_KVM_STRING= "Intel(r) AMT KVM";
31 static QString outputErrorMessageString;
32
33 QVector<QRgb> VncClientThread::m_colorTable;
34
35 void VncClientThread::setClientColorDepth(rfbClient* cl, VncClientThread::ColorDepth cd)
36 {
37     switch(cd) {
38     case bpp8:
39         if (m_colorTable.isEmpty()) {
40             m_colorTable.resize(256);
41             int r,g,b;
42             for (int i = 0; i < 256; ++i) {
43                 //pick out the red (3 bits), green (3 bits) and blue (2 bits) bits and make them maximum significant in 8bits
44                 //this gives a colortable for 8bit true colors
45                 r= (i & 0x07) << 5;
46                 g= (i & 0x38) << 2;
47                 b= i & 0xc0;
48                 m_colorTable[i] = qRgb(r, g, b);
49             }
50         }
51         cl->format.depth = 8;
52         cl->format.bitsPerPixel = 8;
53         cl->format.redShift = 0;
54         cl->format.greenShift = 3;
55         cl->format.blueShift = 6;
56         cl->format.redMax = 7;
57         cl->format.greenMax = 7;
58         cl->format.blueMax = 3;
59         break;
60     case bpp16:
61         cl->format.depth = 16;
62         cl->format.bitsPerPixel = 16;
63         cl->format.redShift = 11;
64         cl->format.greenShift = 5;
65         cl->format.blueShift = 0;
66         cl->format.redMax = 0x1f;
67         cl->format.greenMax = 0x3f;
68         cl->format.blueMax = 0x1f;
69         break;
70     case bpp32:
71     default:
72         cl->format.depth = 24;
73         cl->format.bitsPerPixel = 32;
74         cl->format.redShift = 16;
75         cl->format.greenShift = 8;
76         cl->format.blueShift = 0;
77         cl->format.redMax = 0xff;
78         cl->format.greenMax = 0xff;
79         cl->format.blueMax = 0xff;
80     }
81 }
82
83 rfbBool VncClientThread::newclient(rfbClient *cl)
84 {
85     VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
86     Q_ASSERT(t);
87
88     //8bit color hack for Intel(r) AMT KVM "classic vnc" = vnc server built in in Intel Vpro chipsets.
89     if (INTEL_AMT_KVM_STRING == cl->desktopName) {
90         kDebug(5011) << "Intel(R) AMT KVM: switching to 8 bit color depth (workaround, recent libvncserver needed)";
91         t->setColorDepth(bpp8);
92     }
93     setClientColorDepth(cl, t->colorDepth());
94
95     const int width = cl->width, height = cl->height, depth = cl->format.bitsPerPixel;
96     const int size = width * height * (depth / 8);
97     if (t->frameBuffer)
98         delete [] t->frameBuffer; // do not leak if we get a new framebuffer size
99     t->frameBuffer = new uint8_t[size];
100     cl->frameBuffer = t->frameBuffer;
101     memset(cl->frameBuffer, '\0', size);
102
103     switch (t->quality()) {
104     case RemoteView::High:
105         cl->appData.encodingsString = "copyrect zlib hextile raw";
106         cl->appData.compressLevel = 0;
107         cl->appData.qualityLevel = 9;
108         break;
109     case RemoteView::Medium:
110         cl->appData.encodingsString = "copyrect tight zrle ultra zlib hextile corre rre raw";
111         cl->appData.compressLevel = 5;
112         cl->appData.qualityLevel = 7;
113         break;
114     case RemoteView::Low:
115     case RemoteView::Unknown:
116     default:
117         cl->appData.encodingsString = "copyrect tight zrle ultra zlib hextile corre rre raw";
118         cl->appData.compressLevel = 9;
119         cl->appData.qualityLevel = 1;
120     }
121
122     SetFormatAndEncodings(cl);
123     kDebug(5011) << "Client created";
124     return true;
125 }
126
127 void VncClientThread::updatefb(rfbClient* cl, int x, int y, int w, int h)
128 {
129 //     kDebug(5011) << "updated client: x: " << x << ", y: " << y << ", w: " << w << ", h: " << h;
130     VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
131     Q_ASSERT(t);
132
133     const int width = cl->width, height = cl->height;
134     QImage img;
135     switch(t->colorDepth()) {
136     case bpp8:
137         img = QImage(cl->frameBuffer, width, height, QImage::Format_Indexed8);
138         img.setColorTable(m_colorTable);
139         break;
140     case bpp16:
141         img = QImage(cl->frameBuffer, width, height, QImage::Format_RGB16);
142         break;
143     case bpp32:
144         img = QImage(cl->frameBuffer, width, height, QImage::Format_RGB32);
145         break;
146     }
147
148     if (img.isNull()) {
149         kDebug(5011) << "image not loaded";
150     }
151
152     t->setImage(img);
153
154     t->emitUpdated(x, y, w, h);
155 }
156
157 void VncClientThread::cuttext(rfbClient* cl, const char *text, int textlen)
158 {
159     const QString cutText = QString::fromUtf8(text, textlen);
160     kDebug(5011) << cutText;
161
162     if (!cutText.isEmpty()) {
163         VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
164         Q_ASSERT(t);
165
166         t->emitGotCut(cutText);
167     }
168 }
169
170 char *VncClientThread::passwdHandler(rfbClient *cl)
171 {
172     kDebug(5011) << "password request" << kBacktrace();
173
174     VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
175     Q_ASSERT(t);
176
177     t->passwordRequest();
178     t->m_passwordError = true;
179
180     return strdup(t->password().toLocal8Bit());
181 }
182
183 void VncClientThread::outputHandler(const char *format, ...)
184 {
185     va_list args;
186     va_start(args, format);
187
188     QString message;
189     message.vsprintf(format, args);
190
191     va_end(args);
192
193     message = message.trimmed();
194
195     kDebug(5011) << message;
196
197     if ((message.contains("Couldn't convert ")) ||
198             (message.contains("Unable to connect to VNC server")))
199         outputErrorMessageString = i18n("Server not found.");
200
201     if ((message.contains("VNC connection failed: Authentication failed, too many tries")) ||
202             (message.contains("VNC connection failed: Too many authentication failures")))
203         outputErrorMessageString = i18n("VNC authentication failed because of too many authentication tries.");
204
205     if (message.contains("VNC connection failed: Authentication failed"))
206         outputErrorMessageString = i18n("VNC authentication failed.");
207
208     if (message.contains("VNC server closed connection"))
209         outputErrorMessageString = i18n("VNC server closed connection.");
210
211     // internal messages, not displayed to user
212     if (message.contains("VNC server supports protocol version 3.889")) // see http://bugs.kde.org/162640
213         outputErrorMessageString = "INTERNAL:APPLE_VNC_COMPATIBILTY";
214 }
215
216 VncClientThread::VncClientThread(QObject *parent)
217         : QThread(parent)
218         , frameBuffer(0)
219         , cl(0)
220         , m_stopped(false)
221 {
222     QMutexLocker locker(&mutex);
223
224     QTimer *outputErrorMessagesCheckTimer = new QTimer(this);
225     outputErrorMessagesCheckTimer->setInterval(500);
226     connect(outputErrorMessagesCheckTimer, SIGNAL(timeout()), this, SLOT(checkOutputErrorMessage()));
227     outputErrorMessagesCheckTimer->start();
228 }
229
230 VncClientThread::~VncClientThread()
231 {
232     if(isRunning()) {
233         stop();
234         terminate();
235         const bool quitSuccess = wait(1000);
236         kDebug(5011) << "Attempting to stop in deconstructor, will crash if this fails:" << quitSuccess;
237     }
238
239     if (cl) {
240         // Disconnect from vnc server & cleanup allocated resources
241         rfbClientCleanup(cl);
242     }
243
244     delete [] frameBuffer;
245 }
246
247 void VncClientThread::checkOutputErrorMessage()
248 {
249     if (!outputErrorMessageString.isEmpty()) {
250         kDebug(5011) << outputErrorMessageString;
251         QString errorMessage = outputErrorMessageString;
252         outputErrorMessageString.clear();
253         // show authentication failure error only after the 3rd unsuccessful try
254         if ((errorMessage != i18n("VNC authentication failed.")) || m_passwordError)
255             outputErrorMessage(errorMessage);
256     }
257 }
258
259 void VncClientThread::setHost(const QString &host)
260 {
261     QMutexLocker locker(&mutex);
262     m_host = host;
263 }
264
265 void VncClientThread::setPort(int port)
266 {
267     QMutexLocker locker(&mutex);
268     m_port = port;
269 }
270
271 void VncClientThread::setQuality(RemoteView::Quality quality)
272 {
273     m_quality = quality;
274     //set color depth dependent on quality
275     switch(quality) {
276     case RemoteView::Low:
277         setColorDepth(bpp8);
278         break;
279     case RemoteView::High:
280         setColorDepth(bpp32);
281         break;
282     case RemoteView::Medium:
283     default:
284         setColorDepth(bpp16);
285     }
286 }
287
288 void VncClientThread::setColorDepth(ColorDepth colorDepth)
289 {
290     m_colorDepth= colorDepth;
291 }
292
293 RemoteView::Quality VncClientThread::quality() const
294 {
295     return m_quality;
296 }
297
298 VncClientThread::ColorDepth VncClientThread::colorDepth() const
299 {
300     return m_colorDepth;
301 }
302
303 void VncClientThread::setImage(const QImage &img)
304 {
305     QMutexLocker locker(&mutex);
306     m_image = img;
307 }
308
309 const QImage VncClientThread::image(int x, int y, int w, int h)
310 {
311     QMutexLocker locker(&mutex);
312
313     if (w == 0) // full image requested
314         return m_image;
315     else
316         return m_image.copy(x, y, w, h);
317 }
318
319 void VncClientThread::emitUpdated(int x, int y, int w, int h)
320 {
321     emit imageUpdated(x, y, w, h);
322 }
323
324 void VncClientThread::emitGotCut(const QString &text)
325 {
326     emit gotCut(text);
327 }
328
329 void VncClientThread::stop()
330 {
331     QMutexLocker locker(&mutex);
332     m_stopped = true;
333 }
334
335 void VncClientThread::run()
336 {
337     QMutexLocker locker(&mutex);
338
339     while (!m_stopped) { // try to connect as long as the server allows
340         locker.relock();
341         m_passwordError = false;
342         locker.unlock();
343
344         rfbClientLog = outputHandler;
345         rfbClientErr = outputHandler;
346         //24bit color dept in 32 bits per pixel = default. Will change colordepth and bpp later if needed
347         cl = rfbGetClient(8, 3, 4);
348         setClientColorDepth(cl, this->colorDepth());
349         cl->MallocFrameBuffer = newclient;
350         cl->canHandleNewFBSize = true;
351         cl->GetPassword = passwdHandler;
352         cl->GotFrameBufferUpdate = updatefb;
353         cl->GotXCutText = cuttext;
354         rfbClientSetClientData(cl, 0, this);
355
356         locker.relock();
357         cl->serverHost = strdup(m_host.toUtf8().constData());
358
359         if (m_port < 0 || !m_port) // port is invalid or empty...
360             m_port = 5900; // fallback: try an often used VNC port
361
362         if (m_port >= 0 && m_port < 100) // the user most likely used the short form (e.g. :1)
363             m_port += 5900;
364         cl->serverPort = m_port;
365         locker.unlock();
366
367         kDebug(5011) << "--------------------- trying init ---------------------";
368
369         if (rfbInitClient(cl, 0, 0))
370             break;
371         else
372             cl = 0;
373
374         locker.relock();
375         if (m_passwordError)
376             continue;
377
378         return;
379     }
380
381     locker.relock();
382     kDebug(5011) << "--------------------- Starting main VNC event loop ---------------------";
383     while (!m_stopped) {
384         locker.unlock();
385         const int i = WaitForMessage(cl, 500);
386         if (i < 0) {
387             break;
388         }
389         if (i) {
390             if (!HandleRFBServerMessage(cl)) {
391                 break;
392             }
393         }
394
395         locker.relock();
396         while (!m_eventQueue.isEmpty()) {
397             ClientEvent* clientEvent = m_eventQueue.dequeue();
398             locker.unlock();
399             clientEvent->fire(cl);
400             delete clientEvent;
401             locker.relock();
402         }
403     }
404
405     m_stopped = true;
406 }
407
408 ClientEvent::~ClientEvent()
409 {
410 }
411
412 void PointerClientEvent::fire(rfbClient* cl)
413 {
414     SendPointerEvent(cl, m_x, m_y, m_buttonMask);
415 }
416
417 void KeyClientEvent::fire(rfbClient* cl)
418 {
419     SendKeyEvent(cl, m_key, m_pressed);
420 }
421
422 void ClientCutEvent::fire(rfbClient* cl)
423 {
424     SendClientCutText(cl, text.toUtf8().data(), text.size());
425 }
426
427 void VncClientThread::mouseEvent(int x, int y, int buttonMask)
428 {
429     QMutexLocker lock(&mutex);
430     if (m_stopped)
431         return;
432
433     m_eventQueue.enqueue(new PointerClientEvent(x, y, buttonMask));
434 }
435
436 void VncClientThread::keyEvent(int key, bool pressed)
437 {
438     QMutexLocker lock(&mutex);
439     if (m_stopped)
440         return;
441
442     m_eventQueue.enqueue(new KeyClientEvent(key, pressed));
443 }
444
445 void VncClientThread::clientCut(const QString &text)
446 {
447     QMutexLocker lock(&mutex);
448     if (m_stopped)
449         return;
450
451     m_eventQueue.enqueue(new ClientCutEvent(text));
452 }
453
454 #include "moc_vncclientthread.cpp"