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 |
|
---|
63 | QT_BEGIN_NAMESPACE
|
---|
64 |
|
---|
65 | //#define QT_QWS_VNC_DEBUG
|
---|
66 |
|
---|
67 | extern QString qws_qtePipeFilename();
|
---|
68 |
|
---|
69 | #ifndef QT_NO_QWS_CURSOR
|
---|
70 |
|
---|
71 | QVNCCursor::QVNCCursor(QVNCScreen *s)
|
---|
72 | : screen(s)
|
---|
73 | {
|
---|
74 | if (qt_screencursor)
|
---|
75 | setScreenCursor(qt_screencursor);
|
---|
76 | else
|
---|
77 | hwaccel = true;
|
---|
78 | }
|
---|
79 |
|
---|
80 | QVNCCursor::~QVNCCursor()
|
---|
81 | {
|
---|
82 | if (screenCursor())
|
---|
83 | qt_screencursor = screenCursor();
|
---|
84 | }
|
---|
85 |
|
---|
86 | void QVNCCursor::setDirty(const QRect &r) const
|
---|
87 | {
|
---|
88 | screen->d_ptr->setDirty(r, true);
|
---|
89 | }
|
---|
90 |
|
---|
91 | void QVNCCursor::hide()
|
---|
92 | {
|
---|
93 | QProxyScreenCursor::hide();
|
---|
94 | if (enable)
|
---|
95 | setDirty(boundingRect());
|
---|
96 | }
|
---|
97 |
|
---|
98 | void QVNCCursor::show()
|
---|
99 | {
|
---|
100 | QProxyScreenCursor::show();
|
---|
101 | if (enable)
|
---|
102 | setDirty(boundingRect());
|
---|
103 | }
|
---|
104 |
|
---|
105 | void 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 |
|
---|
117 | void 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 |
|
---|
133 | QVNCClientCursor::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 |
|
---|
143 | QVNCClientCursor::~QVNCClientCursor()
|
---|
144 | {
|
---|
145 | qt_screencursor = screenCursor();
|
---|
146 | }
|
---|
147 |
|
---|
148 | void QVNCClientCursor::set(const QImage &image, int hotx, int hoty)
|
---|
149 | {
|
---|
150 | QScreenCursor::set(image, hotx, hoty);
|
---|
151 | server->setDirtyCursor();
|
---|
152 | }
|
---|
153 |
|
---|
154 | void 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 |
|
---|
196 | QVNCScreenPrivate::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 |
|
---|
208 | QVNCScreenPrivate::~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 |
|
---|
221 | void 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 |
|
---|
290 | static 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 |
|
---|
361 | void 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 |
|
---|
371 | void 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 |
|
---|
381 | void 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 |
|
---|
407 | void 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 |
|
---|
434 | void QRfbServerInit::setName(const char *n)
|
---|
435 | {
|
---|
436 | delete[] name;
|
---|
437 | name = new char [strlen(n) + 1];
|
---|
438 | strcpy(name, n);
|
---|
439 | }
|
---|
440 |
|
---|
441 | void 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 |
|
---|
458 | void 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 |
|
---|
471 | bool 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 |
|
---|
484 | bool 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 |
|
---|
495 | bool 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 |
|
---|
533 | bool 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 |
|
---|
557 | bool 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 |
|
---|
572 | QVNCServer::QVNCServer(QVNCScreen *screen)
|
---|
573 | : qvnc_screen(screen)
|
---|
574 | {
|
---|
575 | init(5900);
|
---|
576 | }
|
---|
577 |
|
---|
578 | QVNCServer::QVNCServer(QVNCScreen *screen, int id)
|
---|
579 | : qvnc_screen(screen)
|
---|
580 | {
|
---|
581 | init(5900 + id);
|
---|
582 | }
|
---|
583 |
|
---|
584 | void 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 |
|
---|
613 | QVNCServer::~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 |
|
---|
625 | void QVNCServer::setDirty()
|
---|
626 | {
|
---|
627 | if (state == Connected && !timer->isActive() &&
|
---|
628 | ((dirtyMap()->numDirty > 0) || dirtyCursor)) {
|
---|
629 | timer->start();
|
---|
630 | }
|
---|
631 | }
|
---|
632 |
|
---|
633 | void 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 |
|
---|
659 | void 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
|
---|
832 | bool 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 |
|
---|
843 | void 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 |
|
---|
875 | void 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 |
|
---|
1006 | void 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 |
|
---|
1022 | void 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 |
|
---|
1032 | void 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 |
|
---|
1052 | void 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
|
---|
1072 | template <class SRC>
|
---|
1073 | bool 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 |
|
---|
1130 | template <class SRC>
|
---|
1131 | void 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 |
|
---|
1149 | template <class SRC>
|
---|
1150 | bool 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 |
|
---|
1182 | found_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 |
|
---|
1245 | template <class SRC>
|
---|
1246 | void 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 |
|
---|
1276 | template <class SRC>
|
---|
1277 | void 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 |
|
---|
1292 | template <class SRC>
|
---|
1293 | inline void QRfbMultiColorHextile<SRC>::setColor(SRC color)
|
---|
1294 | {
|
---|
1295 | encoder->server->convertPixels(reinterpret_cast<char*>(rect(numRects)),
|
---|
1296 | (const char*)&color, 1);
|
---|
1297 | }
|
---|
1298 |
|
---|
1299 | template <class SRC>
|
---|
1300 | inline 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 |
|
---|
1308 | template <class SRC>
|
---|
1309 | inline void QRfbMultiColorHextile<SRC>::endRect()
|
---|
1310 | {
|
---|
1311 | setHeight(numRects, 1);
|
---|
1312 | ++numRects;
|
---|
1313 | }
|
---|
1314 |
|
---|
1315 | template <class SRC>
|
---|
1316 | bool 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 |
|
---|
1364 | template <class SRC>
|
---|
1365 | void 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 |
|
---|
1393 | bool 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
|
---|
1432 | void 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
|
---|
1651 | static 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 |
|
---|
1664 | QVNCDirtyMap::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 |
|
---|
1679 | QVNCDirtyMap::~QVNCDirtyMap()
|
---|
1680 | {
|
---|
1681 | delete[] map;
|
---|
1682 | delete[] buffer;
|
---|
1683 | }
|
---|
1684 |
|
---|
1685 | void QVNCDirtyMap::reset()
|
---|
1686 | {
|
---|
1687 | memset(map, 1, numTiles);
|
---|
1688 | memset(buffer, 0, bufferHeight * bufferStride);
|
---|
1689 | numDirty = numTiles;
|
---|
1690 | }
|
---|
1691 |
|
---|
1692 | inline bool QVNCDirtyMap::dirty(int x, int y) const
|
---|
1693 | {
|
---|
1694 | return map[y * mapWidth + x];
|
---|
1695 | }
|
---|
1696 |
|
---|
1697 | inline void QVNCDirtyMap::setClean(int x, int y)
|
---|
1698 | {
|
---|
1699 | map[y * mapWidth + x] = 0;
|
---|
1700 | --numDirty;
|
---|
1701 | }
|
---|
1702 |
|
---|
1703 | template <class T>
|
---|
1704 | void 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 |
|
---|
1772 | template <class SRC>
|
---|
1773 | QRfbHextileEncoder<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 | */
|
---|
1783 | template <class SRC>
|
---|
1784 | void 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 |
|
---|
1898 | void 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 |
|
---|
2002 | inline 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 |
|
---|
2009 | void 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 |
|
---|
2031 | void 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 | */
|
---|
2080 | QVNCScreen::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 | */
|
---|
2089 | QVNCScreen::~QVNCScreen()
|
---|
2090 | {
|
---|
2091 | delete d_ptr;
|
---|
2092 | }
|
---|
2093 |
|
---|
2094 | /*!
|
---|
2095 | \reimp
|
---|
2096 | */
|
---|
2097 | void QVNCScreen::setDirty(const QRect &rect)
|
---|
2098 | {
|
---|
2099 | d_ptr->setDirty(rect);
|
---|
2100 | }
|
---|
2101 |
|
---|
2102 | void 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 |
|
---|
2123 | static 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 | */
|
---|
2136 | bool 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 | */
|
---|
2245 | void 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 | */
|
---|
2256 | bool 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 | */
|
---|
2329 | void QVNCScreen::shutdownDevice()
|
---|
2330 | {
|
---|
2331 | QProxyScreen::shutdownDevice();
|
---|
2332 | delete d_ptr->vncServer;
|
---|
2333 | delete d_ptr->dirty;
|
---|
2334 | }
|
---|
2335 |
|
---|
2336 | QT_END_NAMESPACE
|
---|
2337 |
|
---|
2338 | #endif // QT_NO_QWS_VNC
|
---|