source: trunk/src/plugins/gfxdrivers/vnc/qscreenvnc_qws.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 66.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the plugins of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qscreenvnc_qws.h"
43
44#ifndef QT_NO_QWS_VNC
45
46#include "qscreenvnc_p.h"
47#include "qwindowsystem_qws.h"
48#include "qwsdisplay_qws.h"
49#include "qscreendriverfactory_qws.h"
50#include <QtCore/qtimer.h>
51#include <QtCore/qregexp.h>
52#include <QtGui/qwidget.h>
53#include <QtGui/qpolygon.h>
54#include <QtGui/qpainter.h>
55#include <qdebug.h>
56#include <private/qwindowsurface_qws_p.h>
57#include <private/qwssignalhandler_p.h>
58#include <private/qwidget_p.h>
59#include <private/qdrawhelper_p.h>
60
61#include <stdlib.h>
62
63QT_BEGIN_NAMESPACE
64
65//#define QT_QWS_VNC_DEBUG
66
67extern QString qws_qtePipeFilename();
68
69#ifndef QT_NO_QWS_CURSOR
70
71QVNCCursor::QVNCCursor(QVNCScreen *s)
72 : screen(s)
73{
74 if (qt_screencursor)
75 setScreenCursor(qt_screencursor);
76 else
77 hwaccel = true;
78}
79
80QVNCCursor::~QVNCCursor()
81{
82 if (screenCursor())
83 qt_screencursor = screenCursor();
84}
85
86void QVNCCursor::setDirty(const QRect &r) const
87{
88 screen->d_ptr->setDirty(r, true);
89}
90
91void QVNCCursor::hide()
92{
93 QProxyScreenCursor::hide();
94 if (enable)
95 setDirty(boundingRect());
96}
97
98void QVNCCursor::show()
99{
100 QProxyScreenCursor::show();
101 if (enable)
102 setDirty(boundingRect());
103}
104
105void QVNCCursor::set(const QImage &image, int hotx, int hoty)
106{
107 QRegion dirty = boundingRect();
108 QProxyScreenCursor::set(image, hotx, hoty);
109 dirty |= boundingRect();
110 if (enable && hwaccel && !screen->d_ptr->vncServer->hasClientCursor()) {
111 const QVector<QRect> rects = dirty.rects();
112 for (int i = 0; i < rects.size(); ++i)
113 setDirty(rects.at(i));
114 }
115}
116
117void QVNCCursor::move(int x, int y)
118{
119 if (enable && hwaccel && !screen->d_ptr->vncServer->hasClientCursor()) {
120 QRegion dirty = boundingRect();
121 QProxyScreenCursor::move(x, y);
122 dirty |= boundingRect();
123 if (enable) {
124 const QVector<QRect> rects = dirty.rects();
125 for (int i = 0; i < rects.size(); ++i)
126 setDirty(rects.at(i));
127 }
128 } else {
129 QProxyScreenCursor::move(x, y);
130 }
131}
132
133QVNCClientCursor::QVNCClientCursor(QVNCServer *s)
134 : server(s)
135{
136 setScreenCursor(qt_screencursor);
137 Q_ASSERT(hwaccel);
138 qt_screencursor = this; // hw: XXX
139
140 set(image(), hotspot.x(), hotspot.y());
141}
142
143QVNCClientCursor::~QVNCClientCursor()
144{
145 qt_screencursor = screenCursor();
146}
147
148void QVNCClientCursor::set(const QImage &image, int hotx, int hoty)
149{
150 QScreenCursor::set(image, hotx, hoty);
151 server->setDirtyCursor();
152}
153
154void QVNCClientCursor::write() const
155{
156 QTcpSocket *socket = server->clientSocket();
157
158 // FramebufferUpdate header
159 {
160 const quint16 tmp[6] = { htons(0),
161 htons(1),
162 htons(hotspot.x()), htons(hotspot.y()),
163 htons(cursor.width()),
164 htons(cursor.height()) };
165 socket->write((char*)tmp, sizeof(tmp));
166
167 const quint32 encoding = htonl(-239);
168 socket->write((char*)(&encoding), sizeof(encoding));
169 }
170
171 if (cursor.isNull())
172 return;
173
174 // write pixels
175 Q_ASSERT(cursor.hasAlphaChannel());
176 const QImage img = cursor.convertToFormat(server->screen()->pixelFormat());
177 const int n = server->clientBytesPerPixel() * img.width();
178 char *buffer = new char[n];
179 for (int i = 0; i < img.height(); ++i) {
180 server->convertPixels(buffer, (const char*)img.scanLine(i), img.width());
181 socket->write(buffer, n);
182 }
183 delete[] buffer;
184
185 // write mask
186 const QImage bitmap = cursor.createAlphaMask().convertToFormat(QImage::Format_Mono);
187 Q_ASSERT(bitmap.depth() == 1);
188 Q_ASSERT(bitmap.size() == img.size());
189 const int width = (bitmap.width() + 7) / 8;
190 for (int i = 0; i < bitmap.height(); ++i)
191 socket->write((const char*)bitmap.scanLine(i), width);
192}
193
194#endif // QT_NO_QWS_CURSOR
195
196QVNCScreenPrivate::QVNCScreenPrivate(QVNCScreen *parent)
197 : dpiX(72), dpiY(72), doOnScreenSurface(false), refreshRate(25),
198 vncServer(0), q_ptr(parent), noDisablePainting(false)
199{
200#ifdef QT_BUILD_INTERNAL
201 noDisablePainting = (qgetenv("QT_VNC_NO_DISABLEPAINTING").toInt() > 0);
202#endif
203#ifndef QT_NO_QWS_SIGNALHANDLER
204 QWSSignalHandler::instance()->addObject(this);
205#endif
206}
207
208QVNCScreenPrivate::~QVNCScreenPrivate()
209{
210#if defined(QT_NO_QWS_MULTIPROCESS) || defined(QT_NO_SHAREDMEMORY)
211 if (q_ptr->screen())
212 return;
213
214 delete[] q_ptr->data;
215 q_ptr->data = 0;
216#else
217 shm.detach();
218#endif
219}
220
221void QVNCScreenPrivate::configure()
222{
223 if (q_ptr->screen())
224 return;
225
226 q_ptr->lstep = q_ptr->dw * ((q_ptr->d + 7) / 8);
227 q_ptr->size = q_ptr->h * q_ptr->lstep;
228 q_ptr->mapsize = q_ptr->size;
229 q_ptr->physWidth = qRound(q_ptr->dw * qreal(25.4) / dpiX);
230 q_ptr->physHeight = qRound(q_ptr->dh * qreal(25.4) / dpiY);
231
232 switch (q_ptr->d) {
233 case 1:
234 q_ptr->setPixelFormat(QImage::Format_Mono); //### LSB???
235 break;
236 case 8:
237 q_ptr->setPixelFormat(QImage::Format_Indexed8);
238 break;
239 case 12:
240 q_ptr->setPixelFormat(QImage::Format_RGB444);
241 break;
242 case 15:
243 q_ptr->setPixelFormat(QImage::Format_RGB555);
244 break;
245 case 16:
246 q_ptr->setPixelFormat(QImage::Format_RGB16);
247 break;
248 case 18:
249 q_ptr->setPixelFormat(QImage::Format_RGB666);
250 break;
251 case 24:
252 q_ptr->setPixelFormat(QImage::Format_RGB888);
253 break;
254 case 32:
255 q_ptr->setPixelFormat(QImage::Format_ARGB32_Premultiplied);
256 break;
257 }
258
259#if !defined(QT_NO_QWS_MULTIPROCESS) && !defined(QT_NO_SHAREDMEMORY)
260 if (q_ptr->size != shm.size()) {
261 shm.detach();
262 const QString key = qws_qtePipeFilename() +
263 QString().sprintf("_vnc_%d_%d",
264 q_ptr->displayId, q_ptr->size);
265 shm.setKey(key);
266 if (QApplication::type() == QApplication::GuiServer) {
267 if (!shm.create(q_ptr->size)) {
268 qWarning() << "QVNCScreen could not create shared memory:"
269 << shm.errorString();
270 if (!shm.attach()) {
271 qWarning() << "QVNCScreen could not attach to shared memory:"
272 << shm.errorString();
273 }
274 }
275 } else if (!shm.attach()) {
276 qWarning() << "QVNCScreen could not attach to shared memory:"
277 << shm.errorString();
278 }
279 q_ptr->data = reinterpret_cast<uchar*>(shm.data());
280 }
281#else
282 if (q_ptr->data)
283 delete[] q_ptr->data;
284 q_ptr->data = new uchar[q_ptr->size];
285#endif
286}
287
288//===========================================================================
289
290static const struct {
291 int keysym;
292 int keycode;
293} keyMap[] = {
294 { 0xff08, Qt::Key_Backspace },
295 { 0xff09, Qt::Key_Tab },
296 { 0xff0d, Qt::Key_Return },
297 { 0xff1b, Qt::Key_Escape },
298 { 0xff63, Qt::Key_Insert },
299 { 0xffff, Qt::Key_Delete },
300 { 0xff50, Qt::Key_Home },
301 { 0xff57, Qt::Key_End },
302 { 0xff55, Qt::Key_PageUp },
303 { 0xff56, Qt::Key_PageDown },
304 { 0xff51, Qt::Key_Left },
305 { 0xff52, Qt::Key_Up },
306 { 0xff53, Qt::Key_Right },
307 { 0xff54, Qt::Key_Down },
308 { 0xffbe, Qt::Key_F1 },
309 { 0xffbf, Qt::Key_F2 },
310 { 0xffc0, Qt::Key_F3 },
311 { 0xffc1, Qt::Key_F4 },
312 { 0xffc2, Qt::Key_F5 },
313 { 0xffc3, Qt::Key_F6 },
314 { 0xffc4, Qt::Key_F7 },
315 { 0xffc5, Qt::Key_F8 },
316 { 0xffc6, Qt::Key_F9 },
317 { 0xffc7, Qt::Key_F10 },
318 { 0xffc8, Qt::Key_F11 },
319 { 0xffc9, Qt::Key_F12 },
320 { 0xffe1, Qt::Key_Shift },
321 { 0xffe2, Qt::Key_Shift },
322 { 0xffe3, Qt::Key_Control },
323 { 0xffe4, Qt::Key_Control },
324 { 0xffe7, Qt::Key_Meta },
325 { 0xffe8, Qt::Key_Meta },
326 { 0xffe9, Qt::Key_Alt },
327 { 0xffea, Qt::Key_Alt },
328
329 { 0xffb0, Qt::Key_0 },
330 { 0xffb1, Qt::Key_1 },
331 { 0xffb2, Qt::Key_2 },
332 { 0xffb3, Qt::Key_3 },
333 { 0xffb4, Qt::Key_4 },
334 { 0xffb5, Qt::Key_5 },
335 { 0xffb6, Qt::Key_6 },
336 { 0xffb7, Qt::Key_7 },
337 { 0xffb8, Qt::Key_8 },
338 { 0xffb9, Qt::Key_9 },
339
340 { 0xff8d, Qt::Key_Return },
341 { 0xffaa, Qt::Key_Asterisk },
342 { 0xffab, Qt::Key_Plus },
343 { 0xffad, Qt::Key_Minus },
344 { 0xffae, Qt::Key_Period },
345 { 0xffaf, Qt::Key_Slash },
346
347 { 0xff95, Qt::Key_Home },
348 { 0xff96, Qt::Key_Left },
349 { 0xff97, Qt::Key_Up },
350 { 0xff98, Qt::Key_Right },
351 { 0xff99, Qt::Key_Down },
352 { 0xff9a, Qt::Key_PageUp },
353 { 0xff9b, Qt::Key_PageDown },
354 { 0xff9c, Qt::Key_End },
355 { 0xff9e, Qt::Key_Insert },
356 { 0xff9f, Qt::Key_Delete },
357
358 { 0, 0 }
359};
360
361void QRfbRect::read(QTcpSocket *s)
362{
363 quint16 buf[4];
364 s->read((char*)buf, 8);
365 x = ntohs(buf[0]);
366 y = ntohs(buf[1]);
367 w = ntohs(buf[2]);
368 h = ntohs(buf[3]);
369}
370
371void QRfbRect::write(QTcpSocket *s) const
372{
373 quint16 buf[4];
374 buf[0] = htons(x);
375 buf[1] = htons(y);
376 buf[2] = htons(w);
377 buf[3] = htons(h);
378 s->write((char*)buf, 8);
379}
380
381void QRfbPixelFormat::read(QTcpSocket *s)
382{
383 char buf[16];
384 s->read(buf, 16);
385 bitsPerPixel = buf[0];
386 depth = buf[1];
387 bigEndian = buf[2];
388 trueColor = buf[3];
389
390 quint16 a = ntohs(*(quint16 *)(buf + 4));
391 redBits = 0;
392 while (a) { a >>= 1; redBits++; }
393
394 a = ntohs(*(quint16 *)(buf + 6));
395 greenBits = 0;
396 while (a) { a >>= 1; greenBits++; }
397
398 a = ntohs(*(quint16 *)(buf + 8));
399 blueBits = 0;
400 while (a) { a >>= 1; blueBits++; }
401
402 redShift = buf[10];
403 greenShift = buf[11];
404 blueShift = buf[12];
405}
406
407void QRfbPixelFormat::write(QTcpSocket *s)
408{
409 char buf[16];
410 buf[0] = bitsPerPixel;
411 buf[1] = depth;
412 buf[2] = bigEndian;
413 buf[3] = trueColor;
414
415 quint16 a = 0;
416 for (int i = 0; i < redBits; i++) a = (a << 1) | 1;
417 *(quint16 *)(buf + 4) = htons(a);
418
419 a = 0;
420 for (int i = 0; i < greenBits; i++) a = (a << 1) | 1;
421 *(quint16 *)(buf + 6) = htons(a);
422
423 a = 0;
424 for (int i = 0; i < blueBits; i++) a = (a << 1) | 1;
425 *(quint16 *)(buf + 8) = htons(a);
426
427 buf[10] = redShift;
428 buf[11] = greenShift;
429 buf[12] = blueShift;
430 s->write(buf, 16);
431}
432
433
434void QRfbServerInit::setName(const char *n)
435{
436 delete[] name;
437 name = new char [strlen(n) + 1];
438 strcpy(name, n);
439}
440
441void QRfbServerInit::read(QTcpSocket *s)
442{
443 s->read((char *)&width, 2);
444 width = ntohs(width);
445 s->read((char *)&height, 2);
446 height = ntohs(height);
447 format.read(s);
448
449 quint32 len;
450 s->read((char *)&len, 4);
451 len = ntohl(len);
452
453 name = new char [len + 1];
454 s->read(name, len);
455 name[len] = '\0';
456}
457
458void QRfbServerInit::write(QTcpSocket *s)
459{
460 quint16 t = htons(width);
461 s->write((char *)&t, 2);
462 t = htons(height);
463 s->write((char *)&t, 2);
464 format.write(s);
465 quint32 len = strlen(name);
466 len = htonl(len);
467 s->write((char *)&len, 4);
468 s->write(name, strlen(name));
469}
470
471bool QRfbSetEncodings::read(QTcpSocket *s)
472{
473 if (s->bytesAvailable() < 3)
474 return false;
475
476 char tmp;
477 s->read(&tmp, 1); // padding
478 s->read((char *)&count, 2);
479 count = ntohs(count);
480
481 return true;
482}
483
484bool QRfbFrameBufferUpdateRequest::read(QTcpSocket *s)
485{
486 if (s->bytesAvailable() < 9)
487 return false;
488
489 s->read(&incremental, 1);
490 rect.read(s);
491
492 return true;
493}
494
495bool QRfbKeyEvent::read(QTcpSocket *s)
496{
497 if (s->bytesAvailable() < 7)
498 return false;
499
500 s->read(&down, 1);
501 quint16 tmp;
502 s->read((char *)&tmp, 2); // padding
503
504 quint32 key;
505 s->read((char *)&key, 4);
506 key = ntohl(key);
507
508 unicode = 0;
509 keycode = 0;
510 int i = 0;
511 while (keyMap[i].keysym && !keycode) {
512 if (keyMap[i].keysym == (int)key)
513 keycode = keyMap[i].keycode;
514 i++;
515 }
516
517 if (keycode >= ' ' && keycode <= '~')
518 unicode = keycode;
519
520 if (!keycode) {
521 if (key <= 0xff) {
522 unicode = key;
523 if (key >= 'a' && key <= 'z')
524 keycode = Qt::Key_A + key - 'a';
525 else if (key >= ' ' && key <= '~')
526 keycode = Qt::Key_Space + key - ' ';
527 }
528 }
529
530 return true;
531}
532
533bool QRfbPointerEvent::read(QTcpSocket *s)
534{
535 if (s->bytesAvailable() < 5)
536 return false;
537
538 char buttonMask;
539 s->read(&buttonMask, 1);
540 buttons = 0;
541 if (buttonMask & 1)
542 buttons |= Qt::LeftButton;
543 if (buttonMask & 2)
544 buttons |= Qt::MidButton;
545 if (buttonMask & 4)
546 buttons |= Qt::RightButton;
547
548 quint16 tmp;
549 s->read((char *)&tmp, 2);
550 x = ntohs(tmp);
551 s->read((char *)&tmp, 2);
552 y = ntohs(tmp);
553
554 return true;
555}
556
557bool QRfbClientCutText::read(QTcpSocket *s)
558{
559 if (s->bytesAvailable() < 7)
560 return false;
561
562 char tmp[3];
563 s->read(tmp, 3); // padding
564 s->read((char *)&length, 4);
565 length = ntohl(length);
566
567 return true;
568}
569
570//===========================================================================
571
572QVNCServer::QVNCServer(QVNCScreen *screen)
573 : qvnc_screen(screen)
574{
575 init(5900);
576}
577
578QVNCServer::QVNCServer(QVNCScreen *screen, int id)
579 : qvnc_screen(screen)
580{
581 init(5900 + id);
582}
583
584void QVNCServer::init(uint port)
585{
586 handleMsg = false;
587 client = 0;
588 encodingsPending = 0;
589 cutTextPending = 0;
590 keymod = 0;
591 state = Unconnected;
592 dirtyCursor = false;
593
594 refreshRate = 25;
595 timer = new QTimer(this);
596 timer->setSingleShot(true);
597 connect(timer, SIGNAL(timeout()), this, SLOT(checkUpdate()));
598
599 serverSocket = new QTcpServer(this);
600 if (!serverSocket->listen(QHostAddress::Any, port))
601 qDebug() << "QVNCServer could not connect:" << serverSocket->errorString();
602 else
603 qDebug("QVNCServer created on port %d", port);
604
605 connect(serverSocket, SIGNAL(newConnection()), this, SLOT(newConnection()));
606
607#ifndef QT_NO_QWS_CURSOR
608 qvnc_cursor = 0;
609#endif
610 encoder = 0;
611}
612
613QVNCServer::~QVNCServer()
614{
615 delete encoder;
616 encoder = 0;
617 delete client;
618 client = 0;
619#ifndef QT_NO_QWS_CURSOR
620 delete qvnc_cursor;
621 qvnc_cursor = 0;
622#endif
623}
624
625void QVNCServer::setDirty()
626{
627 if (state == Connected && !timer->isActive() &&
628 ((dirtyMap()->numDirty > 0) || dirtyCursor)) {
629 timer->start();
630 }
631}
632
633void QVNCServer::newConnection()
634{
635 if (client)
636 delete client;
637
638 client = serverSocket->nextPendingConnection();
639 connect(client,SIGNAL(readyRead()),this,SLOT(readClient()));
640 connect(client,SIGNAL(disconnected()),this,SLOT(discardClient()));
641 handleMsg = false;
642 encodingsPending = 0;
643 cutTextPending = 0;
644 supportHextile = false;
645 wantUpdate = false;
646
647 timer->start(1000 / refreshRate);
648 dirtyMap()->reset();
649
650 // send protocol version
651 const char *proto = "RFB 003.003\n";
652 client->write(proto, 12);
653 state = Protocol;
654
655 if (!qvnc_screen->screen() && !qvnc_screen->d_ptr->noDisablePainting)
656 QWSServer::instance()->enablePainting(true);
657}
658
659void QVNCServer::readClient()
660{
661 switch (state) {
662 case Protocol:
663 if (client->bytesAvailable() >= 12) {
664 char proto[13];
665 client->read(proto, 12);
666 proto[12] = '\0';
667 qDebug("Client protocol version %s", proto);
668 // No authentication
669 quint32 auth = htonl(1);
670 client->write((char *) &auth, sizeof(auth));
671 state = Init;
672 }
673 break;
674
675 case Init:
676 if (client->bytesAvailable() >= 1) {
677 quint8 shared;
678 client->read((char *) &shared, 1);
679
680 // Server Init msg
681 QRfbServerInit sim;
682 QRfbPixelFormat &format = sim.format;
683 switch (qvnc_screen->depth()) {
684 case 32:
685 format.bitsPerPixel = 32;
686 format.depth = 32;
687 format.bigEndian = 0;
688 format.trueColor = true;
689 format.redBits = 8;
690 format.greenBits = 8;
691 format.blueBits = 8;
692 format.redShift = 16;
693 format.greenShift = 8;
694 format.blueShift = 0;
695 break;
696
697 case 24:
698 format.bitsPerPixel = 24;
699 format.depth = 24;
700 format.bigEndian = 0;
701 format.trueColor = true;
702 format.redBits = 8;
703 format.greenBits = 8;
704 format.blueBits = 8;
705 format.redShift = 16;
706 format.greenShift = 8;
707 format.blueShift = 0;
708 break;
709
710 case 18:
711 format.bitsPerPixel = 24;
712 format.depth = 18;
713 format.bigEndian = 0;
714 format.trueColor = true;
715 format.redBits = 6;
716 format.greenBits = 6;
717 format.blueBits = 6;
718 format.redShift = 12;
719 format.greenShift = 6;
720 format.blueShift = 0;
721 break;
722
723 case 16:
724 format.bitsPerPixel = 16;
725 format.depth = 16;
726 format.bigEndian = 0;
727 format.trueColor = true;
728 format.redBits = 5;
729 format.greenBits = 6;
730 format.blueBits = 5;
731 format.redShift = 11;
732 format.greenShift = 5;
733 format.blueShift = 0;
734 break;
735
736 case 15:
737 format.bitsPerPixel = 16;
738 format.depth = 15;
739 format.bigEndian = 0;
740 format.trueColor = true;
741 format.redBits = 5;
742 format.greenBits = 5;
743 format.blueBits = 5;
744 format.redShift = 10;
745 format.greenShift = 5;
746 format.blueShift = 0;
747 break;
748
749 case 12:
750 format.bitsPerPixel = 16;
751 format.depth = 12;
752 format.bigEndian = 0;
753 format.trueColor = true;
754 format.redBits = 4;
755 format.greenBits = 4;
756 format.blueBits = 4;
757 format.redShift = 8;
758 format.greenShift = 4;
759 format.blueShift = 0;
760 break;
761
762 case 8:
763 case 4:
764 format.bitsPerPixel = 8;
765 format.depth = 8;
766 format.bigEndian = 0;
767 format.trueColor = false;
768 format.redBits = 0;
769 format.greenBits = 0;
770 format.blueBits = 0;
771 format.redShift = 0;
772 format.greenShift = 0;
773 format.blueShift = 0;
774 break;
775
776 default:
777 qDebug("QVNC cannot drive depth %d", qvnc_screen->depth());
778 discardClient();
779 return;
780 }
781 sim.width = qvnc_screen->deviceWidth();
782 sim.height = qvnc_screen->deviceHeight();
783 sim.setName("Qt for Embedded Linux VNC Server");
784 sim.write(client);
785 state = Connected;
786 }
787 break;
788
789 case Connected:
790 do {
791 if (!handleMsg) {
792 client->read((char *)&msgType, 1);
793 handleMsg = true;
794 }
795 if (handleMsg) {
796 switch (msgType ) {
797 case SetPixelFormat:
798 setPixelFormat();
799 break;
800 case FixColourMapEntries:
801 qDebug("Not supported: FixColourMapEntries");
802 handleMsg = false;
803 break;
804 case SetEncodings:
805 setEncodings();
806 break;
807 case FramebufferUpdateRequest:
808 frameBufferUpdateRequest();
809 break;
810 case KeyEvent:
811 keyEvent();
812 break;
813 case PointerEvent:
814 pointerEvent();
815 break;
816 case ClientCutText:
817 clientCutText();
818 break;
819 default:
820 qDebug("Unknown message type: %d", (int)msgType);
821 handleMsg = false;
822 }
823 }
824 } while (!handleMsg && client->bytesAvailable());
825 break;
826 default:
827 break;
828 }
829}
830
831#if Q_BYTE_ORDER == Q_BIG_ENDIAN
832bool QVNCScreen::swapBytes() const
833{
834 if (depth() != 16)
835 return false;
836
837 if (screen())
838 return screen()->frameBufferLittleEndian();
839 return frameBufferLittleEndian();
840}
841#endif
842
843void QVNCServer::setPixelFormat()
844{
845 if (client->bytesAvailable() >= 19) {
846 char buf[3];
847 client->read(buf, 3); // just padding
848 pixelFormat.read(client);
849#ifdef QT_QWS_VNC_DEBUG
850 qDebug("Want format: %d %d %d %d %d %d %d %d %d %d",
851 int(pixelFormat.bitsPerPixel),
852 int(pixelFormat.depth),
853 int(pixelFormat.bigEndian),
854 int(pixelFormat.trueColor),
855 int(pixelFormat.redBits),
856 int(pixelFormat.greenBits),
857 int(pixelFormat.blueBits),
858 int(pixelFormat.redShift),
859 int(pixelFormat.greenShift),
860 int(pixelFormat.blueShift));
861#endif
862 if (!pixelFormat.trueColor) {
863 qDebug("Can only handle true color clients");
864 discardClient();
865 }
866 handleMsg = false;
867 sameEndian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) == !!pixelFormat.bigEndian;
868 needConversion = pixelConversionNeeded();
869#if Q_BYTE_ORDER == Q_BIG_ENDIAN
870 swapBytes = qvnc_screen->swapBytes();
871#endif
872 }
873}
874
875void QVNCServer::setEncodings()
876{
877 QRfbSetEncodings enc;
878
879 if (!encodingsPending && enc.read(client)) {
880 encodingsPending = enc.count;
881 if (!encodingsPending)
882 handleMsg = false;
883 }
884
885 if (encoder) {
886 delete encoder;
887 encoder = 0;
888 }
889
890 enum Encodings {
891 Raw = 0,
892 CopyRect = 1,
893 RRE = 2,
894 CoRRE = 4,
895 Hextile = 5,
896 ZRLE = 16,
897 Cursor = -239,
898 DesktopSize = -223
899 };
900
901 if (encodingsPending && (unsigned)client->bytesAvailable() >=
902 encodingsPending * sizeof(quint32)) {
903 for (int i = 0; i < encodingsPending; ++i) {
904 qint32 enc;
905 client->read((char *)&enc, sizeof(qint32));
906 enc = ntohl(enc);
907#ifdef QT_QWS_VNC_DEBUG
908 qDebug("QVNCServer::setEncodings: %d", enc);
909#endif
910 switch (enc) {
911 case Raw:
912 if (!encoder) {
913 encoder = new QRfbRawEncoder(this);
914#ifdef QT_QWS_VNC_DEBUG
915 qDebug("QVNCServer::setEncodings: using raw");
916#endif
917 }
918 break;
919 case CopyRect:
920 supportCopyRect = true;
921 break;
922 case RRE:
923 supportRRE = true;
924 break;
925 case CoRRE:
926 supportCoRRE = true;
927 break;
928 case Hextile:
929 supportHextile = true;
930 if (encoder)
931 break;
932 switch (qvnc_screen->depth()) {
933#ifdef QT_QWS_DEPTH_8
934 case 8:
935 encoder = new QRfbHextileEncoder<quint8>(this);
936 break;
937#endif
938#ifdef QT_QWS_DEPTH_12
939 case 12:
940 encoder = new QRfbHextileEncoder<qrgb444>(this);
941 break;
942#endif
943#ifdef QT_QWS_DEPTH_15
944 case 15:
945 encoder = new QRfbHextileEncoder<qrgb555>(this);
946 break;
947#endif
948#ifdef QT_QWS_DEPTH_16
949 case 16:
950 encoder = new QRfbHextileEncoder<quint16>(this);
951 break;
952#endif
953#ifdef QT_QWS_DEPTH_18
954 case 18:
955 encoder = new QRfbHextileEncoder<qrgb666>(this);
956 break;
957#endif
958#ifdef QT_QWS_DEPTH_24
959 case 24:
960 encoder = new QRfbHextileEncoder<qrgb888>(this);
961 break;
962#endif
963#ifdef QT_QWS_DEPTH_32
964 case 32:
965 encoder = new QRfbHextileEncoder<quint32>(this);
966 break;
967#endif
968 default:
969 break;
970 }
971#ifdef QT_QWS_VNC_DEBUG
972 qDebug("QVNCServer::setEncodings: using hextile");
973#endif
974 break;
975 case ZRLE:
976 supportZRLE = true;
977 break;
978 case Cursor:
979 supportCursor = true;
980#ifndef QT_NO_QWS_CURSOR
981 if (!qvnc_screen->screen() || qt_screencursor->isAccelerated()) {
982 delete qvnc_cursor;
983 qvnc_cursor = new QVNCClientCursor(this);
984 }
985#endif
986 break;
987 case DesktopSize:
988 supportDesktopSize = true;
989 break;
990 default:
991 break;
992 }
993 }
994 handleMsg = false;
995 encodingsPending = 0;
996 }
997
998 if (!encoder) {
999 encoder = new QRfbRawEncoder(this);
1000#ifdef QT_QWS_VNC_DEBUG
1001 qDebug("QVNCServer::setEncodings: fallback using raw");
1002#endif
1003 }
1004}
1005
1006void QVNCServer::frameBufferUpdateRequest()
1007{
1008 QRfbFrameBufferUpdateRequest ev;
1009
1010 if (ev.read(client)) {
1011 if (!ev.incremental) {
1012 QRect r(ev.rect.x, ev.rect.y, ev.rect.w, ev.rect.h);
1013 r.translate(qvnc_screen->offset());
1014 qvnc_screen->d_ptr->setDirty(r, true);
1015 }
1016 wantUpdate = true;
1017 checkUpdate();
1018 handleMsg = false;
1019 }
1020}
1021
1022void QVNCServer::pointerEvent()
1023{
1024 QRfbPointerEvent ev;
1025 if (ev.read(client)) {
1026 const QPoint offset = qvnc_screen->offset();
1027 QWSServer::sendMouseEvent(offset + QPoint(ev.x, ev.y), ev.buttons);
1028 handleMsg = false;
1029 }
1030}
1031
1032void QVNCServer::keyEvent()
1033{
1034 QRfbKeyEvent ev;
1035
1036 if (ev.read(client)) {
1037 if (ev.keycode == Qt::Key_Shift)
1038 keymod = ev.down ? keymod | Qt::ShiftModifier :
1039 keymod & ~Qt::ShiftModifier;
1040 else if (ev.keycode == Qt::Key_Control)
1041 keymod = ev.down ? keymod | Qt::ControlModifier :
1042 keymod & ~Qt::ControlModifier;
1043 else if (ev.keycode == Qt::Key_Alt)
1044 keymod = ev.down ? keymod | Qt::AltModifier :
1045 keymod & ~Qt::AltModifier;
1046 if (ev.unicode || ev.keycode)
1047 QWSServer::sendKeyEvent(ev.unicode, ev.keycode, keymod, ev.down, false);
1048 handleMsg = false;
1049 }
1050}
1051
1052void QVNCServer::clientCutText()
1053{
1054 QRfbClientCutText ev;
1055
1056 if (cutTextPending == 0 && ev.read(client)) {
1057 cutTextPending = ev.length;
1058 if (!cutTextPending)
1059 handleMsg = false;
1060 }
1061
1062 if (cutTextPending && client->bytesAvailable() >= cutTextPending) {
1063 char *text = new char [cutTextPending+1];
1064 client->read(text, cutTextPending);
1065 delete [] text;
1066 cutTextPending = 0;
1067 handleMsg = false;
1068 }
1069}
1070
1071// stride in bytes
1072template <class SRC>
1073bool QRfbSingleColorHextile<SRC>::read(const uchar *data,
1074 int width, int height, int stride)
1075{
1076 const int depth = encoder->server->screen()->depth();
1077 if (width % (depth / 8)) // hw: should rather fallback to simple loop
1078 return false;
1079
1080 static int alwaysFalse = qgetenv("QT_VNC_NOCHECKFILL").toInt();
1081 if (alwaysFalse)
1082 return false;
1083
1084 switch (depth) {
1085 case 4: {
1086 const quint8 *data8 = reinterpret_cast<const quint8*>(data);
1087 if ((data8[0] & 0xf) != (data8[0] >> 4))
1088 return false;
1089 width /= 2;
1090 } // fallthrough
1091 case 8: {
1092 const quint8 *data8 = reinterpret_cast<const quint8*>(data);
1093 if (data8[0] != data8[1])
1094 return false;
1095 width /= 2;
1096 } // fallthrough
1097 case 12:
1098 case 15:
1099 case 16: {
1100 const quint16 *data16 = reinterpret_cast<const quint16*>(data);
1101 if (data16[0] != data16[1])
1102 return false;
1103 width /= 2;
1104 } // fallthrough
1105 case 18:
1106 case 24:
1107 case 32: {
1108 const quint32 *data32 = reinterpret_cast<const quint32*>(data);
1109 const quint32 first = data32[0];
1110 const int linestep = (stride / sizeof(quint32)) - width;
1111 for (int y = 0; y < height; ++y) {
1112 for (int x = 0; x < width; ++x) {
1113 if (*(data32++) != first)
1114 return false;
1115 }
1116 data32 += linestep;
1117 }
1118 break;
1119 }
1120 default:
1121 return false;
1122 }
1123
1124 SRC color = reinterpret_cast<const SRC*>(data)[0];
1125 encoder->newBg |= (color != encoder->bg);
1126 encoder->bg = color;
1127 return true;
1128}
1129
1130template <class SRC>
1131void QRfbSingleColorHextile<SRC>::write(QTcpSocket *socket) const
1132{
1133 if (true || encoder->newBg) {
1134 const int bpp = encoder->server->clientBytesPerPixel();
1135 const int padding = 3;
1136 QVarLengthArray<char> buffer(padding + 1 + bpp);
1137 buffer[padding] = 2; // BackgroundSpecified
1138 encoder->server->convertPixels(buffer.data() + padding + 1,
1139 reinterpret_cast<char*>(&encoder->bg),
1140 1);
1141 socket->write(buffer.data() + padding, bpp + 1);
1142// encoder->newBg = false;
1143 } else {
1144 char subenc = 0;
1145 socket->write(&subenc, 1);
1146 }
1147}
1148
1149template <class SRC>
1150bool QRfbDualColorHextile<SRC>::read(const uchar *data,
1151 int width, int height, int stride)
1152{
1153 const SRC *ptr = reinterpret_cast<const SRC*>(data);
1154 const int linestep = (stride / sizeof(SRC)) - width;
1155
1156 SRC c1;
1157 SRC c2 = 0;
1158 int n1 = 0;
1159 int n2 = 0;
1160 int x = 0;
1161 int y = 0;
1162
1163 c1 = *ptr;
1164
1165 // find second color
1166 while (y < height) {
1167 while (x < width) {
1168 if (*ptr == c1) {
1169 ++n1;
1170 } else {
1171 c2 = *ptr;
1172 goto found_second_color;
1173 }
1174 ++ptr;
1175 ++x;
1176 }
1177 x = 0;
1178 ptr += linestep;
1179 ++y;
1180 }
1181
1182found_second_color:
1183 // finish counting
1184 while (y < height) {
1185 while (x < width) {
1186 if (*ptr == c1) {
1187 ++n1;
1188 } else if (*ptr == c2) {
1189 ++n2;
1190 } else {
1191 return false;
1192 }
1193 ++ptr;
1194 ++x;
1195 }
1196 x = 0;
1197 ptr += linestep;
1198 ++y;
1199 }
1200
1201 if (n2 > n1) {
1202 const quint32 tmpC = c1;
1203 c1 = c2;
1204 c2 = tmpC;
1205 }
1206
1207 encoder->newBg |= (c1 != encoder->bg);
1208 encoder->newFg |= (c2 != encoder->fg);
1209
1210 encoder->bg = c1;
1211 encoder->fg = c2;
1212
1213 // create map
1214 bool inRect = false;
1215 numRects = 0;
1216 ptr = reinterpret_cast<const SRC*>(data);
1217 for (y = 0; y < height; ++y) {
1218 for (x = 0; x < width; ++x) {
1219 if (inRect && *ptr == encoder->bg) {
1220 // rect finished
1221 setWidth(x - lastx());
1222 next();
1223 inRect = false;
1224 } else if (!inRect && *ptr == encoder->fg) {
1225 // rect start
1226 setX(x);
1227 setY(y);
1228 setHeight(1);
1229 inRect = true;
1230 }
1231 ++ptr;
1232 }
1233 if (inRect) {
1234 // finish rect
1235 setWidth(width - lastx());
1236 next();
1237 inRect = false;
1238 }
1239 ptr += linestep;
1240 }
1241
1242 return true;
1243}
1244
1245template <class SRC>
1246void QRfbDualColorHextile<SRC>::write(QTcpSocket *socket) const
1247{
1248 const int bpp = encoder->server->clientBytesPerPixel();
1249 const int padding = 3;
1250 QVarLengthArray<char> buffer(padding + 2 * bpp + sizeof(char) + sizeof(numRects));
1251 char &subenc = buffer[padding];
1252 int n = padding + sizeof(subenc);
1253
1254 subenc = 0x8; // AnySubrects
1255
1256 if (encoder->newBg) {
1257 subenc |= 0x2; // Background
1258 encoder->server->convertPixels(buffer.data() + n, (char*)&encoder->bg, 1);
1259 n += bpp;
1260// encoder->newBg = false;
1261 }
1262
1263 if (encoder->newFg) {
1264 subenc |= 0x4; // Foreground
1265 encoder->server->convertPixels(buffer.data() + n, (char*)&encoder->fg, 1);
1266 n += bpp;
1267// encoder->newFg = false;
1268 }
1269 buffer[n] = numRects;
1270 n += sizeof(numRects);
1271
1272 socket->write(buffer.data() + padding, n - padding);
1273 socket->write((char*)rects, numRects * sizeof(Rect));
1274}
1275
1276template <class SRC>
1277void QRfbDualColorHextile<SRC>::next()
1278{
1279 for (int r = numRects - 1; r >= 0; --r) {
1280 if (recty(r) == lasty())
1281 continue;
1282 if (recty(r) < lasty() - 1) // only search previous scanline
1283 break;
1284 if (rectx(r) == lastx() && width(r) == width(numRects)) {
1285 ++rects[r].wh;
1286 return;
1287 }
1288 }
1289 ++numRects;
1290}
1291
1292template <class SRC>
1293inline void QRfbMultiColorHextile<SRC>::setColor(SRC color)
1294{
1295 encoder->server->convertPixels(reinterpret_cast<char*>(rect(numRects)),
1296 (const char*)&color, 1);
1297}
1298
1299template <class SRC>
1300inline bool QRfbMultiColorHextile<SRC>::beginRect()
1301{
1302 if ((rects.size() + bpp + 2) > maxRectsSize)
1303 return false;
1304 rects.resize(rects.size() + bpp + 2);
1305 return true;
1306}
1307
1308template <class SRC>
1309inline void QRfbMultiColorHextile<SRC>::endRect()
1310{
1311 setHeight(numRects, 1);
1312 ++numRects;
1313}
1314
1315template <class SRC>
1316bool QRfbMultiColorHextile<SRC>::read(const uchar *data,
1317 int width, int height, int stride)
1318{
1319 const SRC *ptr = reinterpret_cast<const SRC*>(data);
1320 const int linestep = (stride / sizeof(SRC)) - width;
1321
1322 bpp = encoder->server->clientBytesPerPixel();
1323
1324 if (encoder->newBg)
1325 encoder->bg = ptr[0];
1326
1327 const SRC bg = encoder->bg;
1328 SRC color = bg;
1329 bool inRect = false;
1330
1331 numRects = 0;
1332 rects.clear();
1333
1334 for (int y = 0; y < height; ++y) {
1335 for (int x = 0; x < width; ++x) {
1336 if (inRect && *ptr != color) { // end rect
1337 setWidth(numRects, x - rectx(numRects));
1338 endRect();
1339 inRect = false;
1340 }
1341
1342 if (!inRect && *ptr != bg) { // begin rect
1343 if (!beginRect())
1344 return false;
1345 inRect = true;
1346 color = *ptr;
1347 setColor(color);
1348 setX(numRects, x);
1349 setY(numRects, y);
1350 }
1351 ++ptr;
1352 }
1353 if (inRect) { // end rect
1354 setWidth(numRects, width - rectx(numRects));
1355 endRect();
1356 inRect = false;
1357 }
1358 ptr += linestep;
1359 }
1360
1361 return true;
1362}
1363
1364template <class SRC>
1365void QRfbMultiColorHextile<SRC>::write(QTcpSocket *socket) const
1366{
1367 const int padding = 3;
1368 QVarLengthArray<quint8> buffer(bpp + padding + sizeof(quint8) + sizeof(numRects));
1369
1370 quint8 &subenc = buffer[padding];
1371 int n = padding + sizeof(quint8);
1372
1373 subenc = 8 | 16; // AnySubrects | SubrectsColoured
1374
1375 if (encoder->newBg) {
1376 subenc |= 0x2; // Background
1377 encoder->server->convertPixels(reinterpret_cast<char*>(buffer.data() + n),
1378 reinterpret_cast<const char*>(&encoder->bg),
1379 1);
1380 n += bpp;
1381// encoder->newBg = false;
1382 }
1383
1384 buffer[n] = numRects;
1385 n += sizeof(numRects);
1386
1387 socket->write(reinterpret_cast<const char*>(buffer.data() + padding),
1388 n - padding);
1389 socket->write(reinterpret_cast<const char*>(rects.constData()),
1390 rects.size());
1391}
1392
1393bool QVNCServer::pixelConversionNeeded() const
1394{
1395 if (!sameEndian)
1396 return true;
1397
1398#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1399 if (qvnc_screen->swapBytes())
1400 return true;
1401#endif
1402
1403 const int screendepth = qvnc_screen->depth();
1404 if (screendepth != pixelFormat.bitsPerPixel)
1405 return true;
1406
1407 switch (screendepth) {
1408 case 32:
1409 case 24:
1410 return false;
1411 case 18:
1412 return (pixelFormat.redBits == 6
1413 && pixelFormat.greenBits == 6
1414 && pixelFormat.blueBits == 6);
1415 case 16:
1416 return (pixelFormat.redBits == 5
1417 && pixelFormat.greenBits == 6
1418 && pixelFormat.blueBits == 5);
1419 case 15:
1420 return (pixelFormat.redBits == 5
1421 && pixelFormat.greenBits == 5
1422 && pixelFormat.blueBits == 5);
1423 case 12:
1424 return (pixelFormat.redBits == 4
1425 && pixelFormat.greenBits == 4
1426 && pixelFormat.blueBits == 4);
1427 }
1428 return true;
1429}
1430
1431// count: number of pixels
1432void QVNCServer::convertPixels(char *dst, const char *src, int count) const
1433{
1434 const int screendepth = qvnc_screen->depth();
1435 const bool isBgr = qvnc_screen->pixelType() == QScreen::BGRPixel;
1436
1437 // cutoffs
1438#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1439 if (!swapBytes)
1440#endif
1441 if (sameEndian) {
1442 if (screendepth == pixelFormat.bitsPerPixel) { // memcpy cutoffs
1443
1444 switch (screendepth) {
1445 case 32:
1446 memcpy(dst, src, count * sizeof(quint32));
1447 return;
1448 case 16:
1449 if (pixelFormat.redBits == 5
1450 && pixelFormat.greenBits == 6
1451 && pixelFormat.blueBits == 5)
1452 {
1453 memcpy(dst, src, count * sizeof(quint16));
1454 return;
1455 }
1456 }
1457 } else if (screendepth == 16 && pixelFormat.bitsPerPixel == 32) {
1458#if defined(__i386__) // Currently fails on ARM if dst is not 4 byte aligned
1459 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
1460 quint32 *dst32 = reinterpret_cast<quint32*>(dst);
1461 int count32 = count * sizeof(quint16) / sizeof(quint32);
1462 while (count32--) {
1463 const quint32 s = *src32++;
1464 quint32 result1;
1465 quint32 result2;
1466
1467 // red
1468 result1 = ((s & 0xf8000000) | ((s & 0xe0000000) >> 5)) >> 8;
1469 result2 = ((s & 0x0000f800) | ((s & 0x0000e000) >> 5)) << 8;
1470
1471 // green
1472 result1 |= ((s & 0x07e00000) | ((s & 0x06000000) >> 6)) >> 11;
1473 result2 |= ((s & 0x000007e0) | ((s & 0x00000600) >> 6)) << 5;
1474
1475 // blue
1476 result1 |= ((s & 0x001f0000) | ((s & 0x001c0000) >> 5)) >> 13;
1477 result2 |= ((s & 0x0000001f) | ((s & 0x0000001c) >> 5)) << 3;
1478
1479 *dst32++ = result2;
1480 *dst32++ = result1;
1481 }
1482 if (count & 0x1) {
1483 const quint16 *src16 = reinterpret_cast<const quint16*>(src);
1484 *dst32 = qt_conv16ToRgb(src16[count - 1]);
1485 }
1486 return;
1487#endif
1488 }
1489 }
1490
1491 const int bytesPerPixel = (pixelFormat.bitsPerPixel + 7) / 8;
1492
1493// nibble = 0;
1494
1495 for (int i = 0; i < count; ++i) {
1496 int r, g, b;
1497
1498 switch (screendepth) {
1499#if 0
1500 case 4: {
1501 if (!nibble) {
1502 r = ((*src) & 0x0f) << 4;
1503 } else {
1504 r = (*src) & 0xf0;
1505 src++;
1506 }
1507 nibble = !nibble;
1508 g = b = r;
1509 break;
1510 }
1511#endif
1512 case 8: {
1513 QRgb rgb = qvnc_screen->clut()[int(*src)];
1514 r = qRed(rgb);
1515 g = qGreen(rgb);
1516 b = qBlue(rgb);
1517 src++;
1518 break;
1519 }
1520#ifdef QT_QWS_DEPTH_12
1521 case 12: {
1522 quint32 p = quint32(*reinterpret_cast<const qrgb444*>(src));
1523 r = qRed(p);
1524 g = qGreen(p);
1525 b = qBlue(p);
1526 src += sizeof(qrgb444);
1527 break;
1528 }
1529#endif
1530#ifdef QT_QWS_DEPTH_15
1531 case 15: {
1532 quint32 p = quint32(*reinterpret_cast<const qrgb555*>(src));
1533 r = qRed(p);
1534 g = qGreen(p);
1535 b = qBlue(p);
1536 src += sizeof(qrgb555);
1537 break;
1538 }
1539#endif
1540 case 16: {
1541 quint16 p = *reinterpret_cast<const quint16*>(src);
1542#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1543 if (swapBytes)
1544 p = ((p & 0xff) << 8) | ((p & 0xff00) >> 8);
1545#endif
1546 r = (p >> 11) & 0x1f;
1547 g = (p >> 5) & 0x3f;
1548 b = p & 0x1f;
1549 r <<= 3;
1550 g <<= 2;
1551 b <<= 3;
1552 src += sizeof(quint16);
1553 break;
1554 }
1555#ifdef QT_QWS_DEPTH_18
1556 case 18: {
1557 quint32 p = quint32(*reinterpret_cast<const qrgb666*>(src));
1558 r = qRed(p);
1559 g = qGreen(p);
1560 b = qBlue(p);
1561 src += sizeof(qrgb666);
1562 break;
1563 }
1564#endif
1565#ifdef QT_QWS_DEPTH_24
1566 case 24: {
1567 quint32 p = quint32(*reinterpret_cast<const qrgb888*>(src));
1568 r = qRed(p);
1569 g = qGreen(p);
1570 b = qBlue(p);
1571 src += sizeof(qrgb888);
1572 break;
1573 }
1574#endif
1575 case 32: {
1576 quint32 p = *reinterpret_cast<const quint32*>(src);
1577 r = (p >> 16) & 0xff;
1578 g = (p >> 8) & 0xff;
1579 b = p & 0xff;
1580 src += sizeof(quint32);
1581 break;
1582 }
1583 default: {
1584 r = g = b = 0;
1585 qDebug("QVNCServer: don't support %dbpp display", screendepth);
1586 return;
1587 }
1588 }
1589
1590#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1591 if (swapBytes ^ isBgr)
1592#else
1593 if (isBgr)
1594#endif
1595 qSwap(r, b);
1596
1597 r >>= (8 - pixelFormat.redBits);
1598 g >>= (8 - pixelFormat.greenBits);
1599 b >>= (8 - pixelFormat.blueBits);
1600
1601 int pixel = (r << pixelFormat.redShift) |
1602 (g << pixelFormat.greenShift) |
1603 (b << pixelFormat.blueShift);
1604
1605 if (sameEndian || pixelFormat.bitsPerPixel == 8) {
1606 memcpy(dst, &pixel, bytesPerPixel); // XXX: do a simple for-loop instead?
1607 dst += bytesPerPixel;
1608 continue;
1609 }
1610
1611
1612 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
1613 switch (pixelFormat.bitsPerPixel) {
1614 case 16:
1615 pixel = (((pixel & 0x0000ff00) << 8) |
1616 ((pixel & 0x000000ff) << 24));
1617 break;
1618 case 32:
1619 pixel = (((pixel & 0xff000000) >> 24) |
1620 ((pixel & 0x00ff0000) >> 8) |
1621 ((pixel & 0x0000ff00) << 8) |
1622 ((pixel & 0x000000ff) << 24));
1623 break;
1624 default:
1625 qDebug("Cannot handle %d bpp client", pixelFormat.bitsPerPixel);
1626 }
1627 } else { // QSysInfo::ByteOrder == QSysInfo::LittleEndian
1628 switch (pixelFormat.bitsPerPixel) {
1629 case 16:
1630 pixel = (((pixel & 0xff000000) >> 8) |
1631 ((pixel & 0x00ff0000) << 8));
1632 break;
1633 case 32:
1634 pixel = (((pixel & 0xff000000) >> 24) |
1635 ((pixel & 0x00ff0000) >> 8) |
1636 ((pixel & 0x0000ff00) << 8) |
1637 ((pixel & 0x000000ff) << 24));
1638 break;
1639 default:
1640 qDebug("Cannot handle %d bpp client",
1641 pixelFormat.bitsPerPixel);
1642 break;
1643 }
1644 }
1645 memcpy(dst, &pixel, bytesPerPixel); // XXX: simple for-loop instead?
1646 dst += bytesPerPixel;
1647 }
1648}
1649
1650#ifndef QT_NO_QWS_CURSOR
1651static void blendCursor(QImage &image, const QRect &imageRect)
1652{
1653 const QRect cursorRect = qt_screencursor->boundingRect();
1654 const QRect intersection = (cursorRect & imageRect);
1655 const QRect destRect = intersection.translated(-imageRect.topLeft());
1656 const QRect srcRect = intersection.translated(-cursorRect.topLeft());
1657
1658 QPainter painter(&image);
1659 painter.drawImage(destRect, qt_screencursor->image(), srcRect);
1660 painter.end();
1661}
1662#endif // QT_NO_QWS_CURSOR
1663
1664QVNCDirtyMap::QVNCDirtyMap(QScreen *s)
1665 : bytesPerPixel(0), numDirty(0), screen(s)
1666{
1667 bytesPerPixel = (screen->depth() + 7) / 8;
1668 bufferWidth = screen->deviceWidth();
1669 bufferHeight = screen->deviceHeight();
1670 bufferStride = bufferWidth * bytesPerPixel;
1671 buffer = new uchar[bufferHeight * bufferStride];
1672
1673 mapWidth = (bufferWidth + MAP_TILE_SIZE - 1) / MAP_TILE_SIZE;
1674 mapHeight = (bufferHeight + MAP_TILE_SIZE - 1) / MAP_TILE_SIZE;
1675 numTiles = mapWidth * mapHeight;
1676 map = new uchar[numTiles];
1677}
1678
1679QVNCDirtyMap::~QVNCDirtyMap()
1680{
1681 delete[] map;
1682 delete[] buffer;
1683}
1684
1685void QVNCDirtyMap::reset()
1686{
1687 memset(map, 1, numTiles);
1688 memset(buffer, 0, bufferHeight * bufferStride);
1689 numDirty = numTiles;
1690}
1691
1692inline bool QVNCDirtyMap::dirty(int x, int y) const
1693{
1694 return map[y * mapWidth + x];
1695}
1696
1697inline void QVNCDirtyMap::setClean(int x, int y)
1698{
1699 map[y * mapWidth + x] = 0;
1700 --numDirty;
1701}
1702
1703template <class T>
1704void QVNCDirtyMapOptimized<T>::setDirty(int tileX, int tileY, bool force)
1705{
1706 static bool alwaysForce = qgetenv("QT_VNC_NO_COMPAREBUFFER").toInt();
1707 if (alwaysForce)
1708 force = true;
1709
1710 bool changed = false;
1711
1712 if (!force) {
1713 const int lstep = screen->linestep();
1714 const int startX = tileX * MAP_TILE_SIZE;
1715 const int startY = tileY * MAP_TILE_SIZE;
1716 const uchar *scrn = screen->base()
1717 + startY * lstep + startX * bytesPerPixel;
1718 uchar *old = buffer + startY * bufferStride + startX * sizeof(T);
1719
1720 const int tileHeight = (startY + MAP_TILE_SIZE > bufferHeight ?
1721 bufferHeight - startY : MAP_TILE_SIZE);
1722 const int tileWidth = (startX + MAP_TILE_SIZE > bufferWidth ?
1723 bufferWidth - startX : MAP_TILE_SIZE);
1724 const bool doInlines = (tileWidth == MAP_TILE_SIZE);
1725
1726 int y = tileHeight;
1727
1728 if (doInlines) { // hw: memcmp/memcpy is inlined when using constants
1729 while (y) {
1730 if (memcmp(old, scrn, sizeof(T) * MAP_TILE_SIZE)) {
1731 changed = true;
1732 break;
1733 }
1734 scrn += lstep;
1735 old += bufferStride;
1736 --y;
1737 }
1738
1739 while (y) {
1740 memcpy(old, scrn, sizeof(T) * MAP_TILE_SIZE);
1741 scrn += lstep;
1742 old += bufferStride;
1743 --y;
1744 }
1745 } else {
1746 while (y) {
1747 if (memcmp(old, scrn, sizeof(T) * tileWidth)) {
1748 changed = true;
1749 break;
1750 }
1751 scrn += lstep;
1752 old += bufferStride;
1753 --y;
1754 }
1755
1756 while (y) {
1757 memcpy(old, scrn, sizeof(T) * tileWidth);
1758 scrn += lstep;
1759 old += bufferStride;
1760 --y;
1761 }
1762 }
1763 }
1764
1765 const int mapIndex = tileY * mapWidth + tileX;
1766 if ((force || changed) && !map[mapIndex]) {
1767 map[mapIndex] = 1;
1768 ++numDirty;
1769 }
1770}
1771
1772template <class SRC>
1773QRfbHextileEncoder<SRC>::QRfbHextileEncoder(QVNCServer *s)
1774 : QRfbEncoder(s),
1775 singleColorHextile(this), dualColorHextile(this), multiColorHextile(this)
1776{
1777}
1778
1779/*
1780 \internal
1781 Send dirty rects using hextile encoding.
1782*/
1783template <class SRC>
1784void QRfbHextileEncoder<SRC>::write()
1785{
1786 QWSDisplay::grab(true);
1787
1788 QVNCDirtyMap *map = server->dirtyMap();
1789 QTcpSocket *socket = server->clientSocket();
1790
1791 const quint32 encoding = htonl(5); // hextile encoding
1792 const int bytesPerPixel = server->clientBytesPerPixel();
1793
1794 {
1795 const char tmp[2] = { 0, 0 }; // msg type, padding
1796 socket->write(tmp, sizeof(tmp));
1797 }
1798 {
1799 const quint16 count = htons(map->numDirty);
1800 socket->write((char *)&count, sizeof(count));
1801 }
1802
1803 if (map->numDirty <= 0) {
1804 QWSDisplay::ungrab();
1805 return;
1806 }
1807
1808 newBg = true;
1809 newFg = true;
1810
1811 const QImage screenImage = server->screenImage();
1812 QRfbRect rect(0, 0, MAP_TILE_SIZE, MAP_TILE_SIZE);
1813
1814 for (int y = 0; y < map->mapHeight; ++y) {
1815 if (rect.y + MAP_TILE_SIZE > server->screen()->height())
1816 rect.h = server->screen()->height() - rect.y;
1817 rect.w = MAP_TILE_SIZE;
1818 for (int x = 0; x < map->mapWidth; ++x) {
1819 if (!map->dirty(x, y))
1820 continue;
1821 map->setClean(x, y);
1822
1823 rect.x = x * MAP_TILE_SIZE;
1824 if (rect.x + MAP_TILE_SIZE > server->screen()->deviceWidth())
1825 rect.w = server->screen()->deviceWidth() - rect.x;
1826 rect.write(socket);
1827
1828 socket->write((char *)&encoding, sizeof(encoding));
1829
1830 const uchar *screendata = screenImage.scanLine(rect.y)
1831 + rect.x * screenImage.depth() / 8;
1832 int linestep = screenImage.bytesPerLine();
1833
1834#ifndef QT_NO_QWS_CURSOR
1835 // hardware cursors must be blended with the screen memory
1836 const bool doBlendCursor = qt_screencursor
1837 && !server->hasClientCursor()
1838 && qt_screencursor->isAccelerated();
1839 QImage tileImage;
1840 if (doBlendCursor) {
1841 const QRect tileRect(rect.x, rect.y, rect.w, rect.h);
1842 const QRect cursorRect = qt_screencursor->boundingRect()
1843 .translated(-server->screen()->offset());
1844 if (tileRect.intersects(cursorRect)) {
1845 tileImage = screenImage.copy(tileRect);
1846 blendCursor(tileImage,
1847 tileRect.translated(server->screen()->offset()));
1848 screendata = tileImage.bits();
1849 linestep = tileImage.bytesPerLine();
1850 }
1851 }
1852#endif // QT_NO_QWS_CURSOR
1853
1854 if (singleColorHextile.read(screendata, rect.w, rect.h, linestep)) {
1855 singleColorHextile.write(socket);
1856 } else if (dualColorHextile.read(screendata, rect.w, rect.h, linestep)) {
1857 dualColorHextile.write(socket);
1858 } else if (multiColorHextile.read(screendata, rect.w, rect.h, linestep)) {
1859 multiColorHextile.write(socket);
1860 } else if (server->doPixelConversion()) {
1861 const int bufferSize = rect.w * rect.h * bytesPerPixel + 1;
1862 const int padding = sizeof(quint32) - sizeof(char);
1863 buffer.resize(bufferSize + padding);
1864
1865 buffer[padding] = 1; // Raw subencoding
1866
1867 // convert pixels
1868 char *b = buffer.data() + padding + 1;
1869 const int bstep = rect.w * bytesPerPixel;
1870 for (int i = 0; i < rect.h; ++i) {
1871 server->convertPixels(b, (const char*)screendata, rect.w);
1872 screendata += linestep;
1873 b += bstep;
1874 }
1875 socket->write(buffer.constData() + padding, bufferSize);
1876 } else {
1877 quint8 subenc = 1; // Raw subencoding
1878 socket->write((char *)&subenc, 1);
1879
1880 // send pixels
1881 for (int i = 0; i < rect.h; ++i) {
1882 socket->write((const char*)screendata,
1883 rect.w * bytesPerPixel);
1884 screendata += linestep;
1885 }
1886 }
1887 }
1888 if (socket->state() == QAbstractSocket::UnconnectedState)
1889 break;
1890 rect.y += MAP_TILE_SIZE;
1891 }
1892 socket->flush();
1893 Q_ASSERT(map->numDirty == 0);
1894
1895 QWSDisplay::ungrab();
1896}
1897
1898void QRfbRawEncoder::write()
1899{
1900 QWSDisplay::grab(false);
1901
1902 QVNCDirtyMap *map = server->dirtyMap();
1903 QTcpSocket *socket = server->clientSocket();
1904
1905 const int bytesPerPixel = server->clientBytesPerPixel();
1906
1907 // create a region from the dirty rects and send the region's merged rects.
1908 QRegion rgn;
1909 if (map) {
1910 for (int y = 0; y < map->mapHeight; ++y) {
1911 for (int x = 0; x < map->mapWidth; ++x) {
1912 if (!map->dirty(x, y))
1913 continue;
1914 rgn += QRect(x * MAP_TILE_SIZE, y * MAP_TILE_SIZE,
1915 MAP_TILE_SIZE, MAP_TILE_SIZE);
1916 map->setClean(x, y);
1917 }
1918 }
1919
1920 rgn &= QRect(0, 0, server->screen()->deviceWidth(),
1921 server->screen()->deviceHeight());
1922 }
1923 const QVector<QRect> rects = rgn.rects();
1924
1925 {
1926 const char tmp[2] = { 0, 0 }; // msg type, padding
1927 socket->write(tmp, sizeof(tmp));
1928 }
1929
1930 {
1931 const quint16 count = htons(rects.size());
1932 socket->write((char *)&count, sizeof(count));
1933 }
1934
1935 if (rects.size() <= 0) {
1936 QWSDisplay::ungrab();
1937 return;
1938 }
1939
1940 const QImage screenImage = server->screenImage();
1941
1942 for (int i = 0; i < rects.size(); ++i) {
1943 const QRect tileRect = rects.at(i);
1944 const QRfbRect rect(tileRect.x(), tileRect.y(),
1945 tileRect.width(), tileRect.height());
1946 rect.write(socket);
1947
1948 const quint32 encoding = htonl(0); // raw encoding
1949 socket->write((char *)&encoding, sizeof(encoding));
1950
1951 int linestep = screenImage.bytesPerLine();
1952 const uchar *screendata = screenImage.scanLine(rect.y)
1953 + rect.x * screenImage.depth() / 8;
1954
1955#ifndef QT_NO_QWS_CURSOR
1956 // hardware cursors must be blended with the screen memory
1957 const bool doBlendCursor = qt_screencursor
1958 && !server->hasClientCursor()
1959 && qt_screencursor->isAccelerated();
1960 QImage tileImage;
1961 if (doBlendCursor) {
1962 const QRect cursorRect = qt_screencursor->boundingRect()
1963 .translated(-server->screen()->offset());
1964 if (tileRect.intersects(cursorRect)) {
1965 tileImage = screenImage.copy(tileRect);
1966 blendCursor(tileImage,
1967 tileRect.translated(server->screen()->offset()));
1968 screendata = tileImage.bits();
1969 linestep = tileImage.bytesPerLine();
1970 }
1971 }
1972#endif // QT_NO_QWS_CURSOR
1973
1974 if (server->doPixelConversion()) {
1975 const int bufferSize = rect.w * rect.h * bytesPerPixel;
1976 if (bufferSize > buffer.size())
1977 buffer.resize(bufferSize);
1978
1979 // convert pixels
1980 char *b = buffer.data();
1981 const int bstep = rect.w * bytesPerPixel;
1982 for (int i = 0; i < rect.h; ++i) {
1983 server->convertPixels(b, (const char*)screendata, rect.w);
1984 screendata += linestep;
1985 b += bstep;
1986 }
1987 socket->write(buffer.constData(), bufferSize);
1988 } else {
1989 for (int i = 0; i < rect.h; ++i) {
1990 socket->write((const char*)screendata, rect.w * bytesPerPixel);
1991 screendata += linestep;
1992 }
1993 }
1994 if (socket->state() == QAbstractSocket::UnconnectedState)
1995 break;
1996 }
1997 socket->flush();
1998
1999 QWSDisplay::ungrab();
2000}
2001
2002inline QImage QVNCServer::screenImage() const
2003{
2004 return QImage(qvnc_screen->base(), qvnc_screen->deviceWidth(),
2005 qvnc_screen->deviceHeight(), qvnc_screen->linestep(),
2006 qvnc_screen->pixelFormat());
2007}
2008
2009void QVNCServer::checkUpdate()
2010{
2011 if (!wantUpdate)
2012 return;
2013
2014 if (dirtyCursor) {
2015#ifndef QT_NO_QWS_CURSOR
2016 Q_ASSERT(qvnc_cursor);
2017 qvnc_cursor->write();
2018#endif
2019 dirtyCursor = false;
2020 wantUpdate = false;
2021 return;
2022 }
2023
2024 if (dirtyMap()->numDirty > 0) {
2025 if (encoder)
2026 encoder->write();
2027 wantUpdate = false;
2028 }
2029}
2030
2031void QVNCServer::discardClient()
2032{
2033 timer->stop();
2034 state = Unconnected;
2035 delete encoder;
2036 encoder = 0;
2037#ifndef QT_NO_QWS_CURSOR
2038 delete qvnc_cursor;
2039 qvnc_cursor = 0;
2040#endif
2041 if (!qvnc_screen->screen() && !qvnc_screen->d_ptr->noDisablePainting && QWSServer::instance())
2042 QWSServer::instance()->enablePainting(false);
2043}
2044
2045
2046//===========================================================================
2047
2048/*!
2049 \class QVNCScreen
2050 \internal
2051 \ingroup qws
2052
2053 \brief The QVNCScreen class implements a screen driver for VNC
2054 servers.
2055
2056 Note that this class is only available in \l{Qt for Embedded Linux}.
2057 Custom screen drivers can be added by subclassing the QScreen
2058 class, using the QScreenDriverFactory class to dynamically load
2059 the driver into the application.
2060
2061 The VNC protocol allows you to view and interact with the
2062 computer's display from anywhere on the network. See the
2063 \l{The VNC Protocol and Qt for Embedded Linux}{VNC protocol}
2064 documentation for more details.
2065
2066 The default implementation of QVNCScreen inherits QLinuxFbScreen,
2067 but any QScreen subclass, or QScreen itself, can serve as its base
2068 class. This is easily achieved by manipulating the \c
2069 VNCSCREEN_BASE definition in the header file.
2070
2071 \sa QScreen, {Running Applications}
2072*/
2073
2074/*!
2075 \fn QVNCScreen::QVNCScreen(int displayId)
2076
2077 Constructs a QVNCScreen object. The \a displayId argument
2078 identifies the Qt for Embedded Linux server to connect to.
2079*/
2080QVNCScreen::QVNCScreen(int display_id)
2081 : QProxyScreen(display_id, VNCClass)
2082{
2083 d_ptr = new QVNCScreenPrivate(this);
2084}
2085
2086/*!
2087 Destroys this QVNCScreen object.
2088*/
2089QVNCScreen::~QVNCScreen()
2090{
2091 delete d_ptr;
2092}
2093
2094/*!
2095 \reimp
2096*/
2097void QVNCScreen::setDirty(const QRect &rect)
2098{
2099 d_ptr->setDirty(rect);
2100}
2101
2102void QVNCScreenPrivate::setDirty(const QRect& rect, bool force)
2103{
2104 if (rect.isEmpty())
2105 return;
2106
2107 if (q_ptr->screen())
2108 q_ptr->screen()->setDirty(rect);
2109
2110 if (!vncServer || !vncServer->isConnected())
2111 return;
2112
2113 const QRect r = rect.translated(-q_ptr->offset());
2114 const int x1 = r.x() / MAP_TILE_SIZE;
2115 int y = r.y() / MAP_TILE_SIZE;
2116 for (; (y <= r.bottom() / MAP_TILE_SIZE) && y < dirty->mapHeight; y++)
2117 for (int x = x1; (x <= r.right() / MAP_TILE_SIZE) && x < dirty->mapWidth; x++)
2118 dirty->setDirty(x, y, force);
2119
2120 vncServer->setDirty();
2121}
2122
2123static int getDisplayId(const QString &spec)
2124{
2125 QRegExp regexp(QLatin1String(":(\\d+)\\b"));
2126 if (regexp.lastIndexIn(spec) != -1) {
2127 const QString capture = regexp.cap(1);
2128 return capture.toInt();
2129 }
2130 return 0;
2131}
2132
2133/*!
2134 \reimp
2135*/
2136bool QVNCScreen::connect(const QString &displaySpec)
2137{
2138 QString dspec = displaySpec;
2139 if (dspec.startsWith(QLatin1String("vnc:"), Qt::CaseInsensitive))
2140 dspec = dspec.mid(QString::fromLatin1("vnc:").size());
2141 else if (dspec.compare(QLatin1String("vnc"), Qt::CaseInsensitive) == 0)
2142 dspec = QString();
2143
2144 const QString displayIdSpec = QString::fromLatin1(" :%1").arg(displayId);
2145 if (dspec.endsWith(displayIdSpec))
2146 dspec = dspec.left(dspec.size() - displayIdSpec.size());
2147
2148 QStringList args = dspec.split(QLatin1Char(':'),
2149 QString::SkipEmptyParts);
2150 QRegExp refreshRegexp(QLatin1String("^refreshrate=(\\d+)$"));
2151 int index = args.indexOf(refreshRegexp);
2152 if (index >= 0) {
2153 d_ptr->refreshRate = refreshRegexp.cap(1).toInt();
2154 args.removeAt(index);
2155 dspec = args.join(QLatin1String(":"));
2156 }
2157
2158 QString driver = dspec;
2159 int colon = driver.indexOf(QLatin1Char(':'));
2160 if (colon >= 0)
2161 driver.truncate(colon);
2162
2163 if (QScreenDriverFactory::keys().contains(driver, Qt::CaseInsensitive)) {
2164 const int id = getDisplayId(dspec);
2165 QScreen *s = qt_get_screen(id, dspec.toLatin1().constData());
2166 if (s->pixelFormat() == QImage::Format_Indexed8
2167 || s->pixelFormat() == QImage::Format_Invalid && s->depth() == 8)
2168 qFatal("QVNCScreen: unsupported screen format");
2169 setScreen(s);
2170 } else { // create virtual screen
2171#if Q_BYTE_ORDER == Q_BIG_ENDIAN
2172 QScreen::setFrameBufferLittleEndian(false);
2173#endif
2174
2175 d = qgetenv("QWS_DEPTH").toInt();
2176 if (!d)
2177 d = 16;
2178
2179 QByteArray str = qgetenv("QWS_SIZE");
2180 if(!str.isEmpty()) {
2181 sscanf(str.constData(), "%dx%d", &w, &h);
2182 dw = w;
2183 dh = h;
2184 } else {
2185 dw = w = 640;
2186 dh = h = 480;
2187 }
2188
2189 const QStringList args = displaySpec.split(QLatin1Char(':'),
2190 QString::SkipEmptyParts);
2191
2192 if (args.contains(QLatin1String("paintonscreen"), Qt::CaseInsensitive))
2193 d_ptr->doOnScreenSurface = true;
2194
2195 QRegExp depthRegexp(QLatin1String("^depth=(\\d+)$"));
2196 if (args.indexOf(depthRegexp) != -1)
2197 d = depthRegexp.cap(1).toInt();
2198
2199 QRegExp sizeRegexp(QLatin1String("^size=(\\d+)x(\\d+)$"));
2200 if (args.indexOf(sizeRegexp) != -1) {
2201 dw = w = sizeRegexp.cap(1).toInt();
2202 dh = h = sizeRegexp.cap(2).toInt();
2203 }
2204
2205 // Handle display physical size spec.
2206 QRegExp mmWidthRegexp(QLatin1String("^mmWidth=?(\\d+)$"));
2207 if (args.indexOf(mmWidthRegexp) != -1) {
2208 const int mmWidth = mmWidthRegexp.cap(1).toInt();
2209 if (mmWidth > 0)
2210 d_ptr->dpiX = dw * 25.4 / mmWidth;
2211 }
2212 QRegExp mmHeightRegexp(QLatin1String("^mmHeight=?(\\d+)$"));
2213 if (args.indexOf(mmHeightRegexp) != -1) {
2214 const int mmHeight = mmHeightRegexp.cap(1).toInt();
2215 if (mmHeight > 0)
2216 d_ptr->dpiY = dh * 25.4 / mmHeight;
2217 }
2218 QRegExp dpiRegexp(QLatin1String("^dpi=(\\d+)(?:,(\\d+))?$"));
2219 if (args.indexOf(dpiRegexp) != -1) {
2220 const qreal dpiX = dpiRegexp.cap(1).toFloat();
2221 const qreal dpiY = dpiRegexp.cap(2).toFloat();
2222 if (dpiX > 0)
2223 d_ptr->dpiX = dpiX;
2224 d_ptr->dpiY = (dpiY > 0 ? dpiY : dpiX);
2225 }
2226
2227 if (args.contains(QLatin1String("noDisablePainting")))
2228 d_ptr->noDisablePainting = true;
2229
2230 QWSServer::setDefaultMouse("None");
2231 QWSServer::setDefaultKeyboard("None");
2232
2233 d_ptr->configure();
2234 }
2235
2236 // XXX
2237 qt_screen = this;
2238
2239 return true;
2240}
2241
2242/*!
2243 \reimp
2244*/
2245void QVNCScreen::disconnect()
2246{
2247 QProxyScreen::disconnect();
2248#if !defined(QT_NO_QWS_MULTIPROCESS) && !defined(QT_NO_SHAREDMEMORY)
2249 d_ptr->shm.detach();
2250#endif
2251}
2252
2253/*!
2254 \reimp
2255*/
2256bool QVNCScreen::initDevice()
2257{
2258 if (!QProxyScreen::screen() && d == 4) {
2259 screencols = 16;
2260 int val = 0;
2261 for (int idx = 0; idx < 16; idx++, val += 17) {
2262 screenclut[idx] = qRgb(val, val, val);
2263 }
2264 }
2265 d_ptr->vncServer = new QVNCServer(this, displayId);
2266 d_ptr->vncServer->setRefreshRate(d_ptr->refreshRate);
2267
2268 switch (depth()) {
2269#ifdef QT_QWS_DEPTH_32
2270 case 32:
2271 d_ptr->dirty = new QVNCDirtyMapOptimized<quint32>(this);
2272 break;
2273#endif
2274#ifdef QT_QWS_DEPTH_24
2275 case 24:
2276 d_ptr->dirty = new QVNCDirtyMapOptimized<qrgb888>(this);
2277 break;
2278#endif
2279#ifdef QT_QWS_DEPTH_18
2280 case 18:
2281 d_ptr->dirty = new QVNCDirtyMapOptimized<qrgb666>(this);
2282 break;
2283#endif
2284#ifdef QT_QWS_DEPTH_16
2285 case 16:
2286 d_ptr->dirty = new QVNCDirtyMapOptimized<quint16>(this);
2287 break;
2288#endif
2289#ifdef QT_QWS_DEPTH_15
2290 case 15:
2291 d_ptr->dirty = new QVNCDirtyMapOptimized<qrgb555>(this);
2292 break;
2293#endif
2294#ifdef QT_QWS_DEPTH_12
2295 case 12:
2296 d_ptr->dirty = new QVNCDirtyMapOptimized<qrgb444>(this);
2297 break;
2298#endif
2299#ifdef QT_QWS_DEPTH_8
2300 case 8:
2301 d_ptr->dirty = new QVNCDirtyMapOptimized<quint8>(this);
2302 break;
2303#endif
2304 default:
2305 qWarning("QVNCScreen::initDevice: No support for screen depth %d",
2306 depth());
2307 d_ptr->dirty = 0;
2308 return false;
2309 }
2310
2311
2312 const bool ok = QProxyScreen::initDevice();
2313#ifndef QT_NO_QWS_CURSOR
2314 qt_screencursor = new QVNCCursor(this);
2315#endif
2316 if (QProxyScreen::screen())
2317 return ok;
2318
2319 // Disable painting if there is only 1 display and nothing is attached to the VNC server
2320 if (!d_ptr->noDisablePainting)
2321 QWSServer::instance()->enablePainting(false);
2322
2323 return true;
2324}
2325
2326/*!
2327 \reimp
2328*/
2329void QVNCScreen::shutdownDevice()
2330{
2331 QProxyScreen::shutdownDevice();
2332 delete d_ptr->vncServer;
2333 delete d_ptr->dirty;
2334}
2335
2336QT_END_NAMESPACE
2337
2338#endif // QT_NO_QWS_VNC
Note: See TracBrowser for help on using the repository browser.