Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qvnc.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#include "qvnc_p.h"
4#include "qvncscreen.h"
5#include "qvncclient.h"
6#include "QtNetwork/qtcpserver.h"
7#include "QtNetwork/qtcpsocket.h"
8#include <qendian.h>
9#include <qthread.h>
10
11#include <QtGui/qguiapplication.h>
12#include <QtGui/QWindow>
13
14#ifdef Q_OS_WIN
15#include <winsock2.h>
16#else
17#include <arpa/inet.h>
18#endif
19
20#include <QtCore/QDebug>
21
23
24Q_LOGGING_CATEGORY(lcVnc, "qt.qpa.vnc");
25
27 : screen(screen), bytesPerPixel(0), numDirty(0)
28{
29 bytesPerPixel = (screen->depth() + 7) / 8;
30 bufferWidth = screen->geometry().width();
31 bufferHeight = screen->geometry().height();
33 buffer = new uchar[bufferHeight * bufferStride];
34
38 map = new uchar[numTiles];
39}
40
42{
43 delete[] map;
44 delete[] buffer;
45}
46
48{
49 memset(map, 1, numTiles);
50 memset(buffer, 0, bufferHeight * bufferStride);
52}
53
54inline bool QVncDirtyMap::dirty(int x, int y) const
55{
56 return map[y * mapWidth + x];
57}
58
59inline void QVncDirtyMap::setClean(int x, int y)
60{
61 map[y * mapWidth + x] = 0;
62 --numDirty;
63}
64
65template <class T>
66void QVncDirtyMapOptimized<T>::setDirty(int tileX, int tileY, bool force)
67{
68 static bool alwaysForce = qEnvironmentVariableIsSet("QT_VNC_NO_COMPAREBUFFER");
69 if (alwaysForce)
70 force = true;
71
72 bool changed = false;
73
74 if (!force) {
75 const int lstep = bufferStride;
76 const int startX = tileX * MAP_TILE_SIZE;
77 const int startY = tileY * MAP_TILE_SIZE;
78 const uchar *scrn = screen->image()->constBits()
79 + startY * lstep + startX * bytesPerPixel;
80 uchar *old = buffer + startY * bufferStride + startX * sizeof(T);
81
82 const int tileHeight = (startY + MAP_TILE_SIZE > bufferHeight ?
83 bufferHeight - startY : MAP_TILE_SIZE);
84 const int tileWidth = (startX + MAP_TILE_SIZE > bufferWidth ?
85 bufferWidth - startX : MAP_TILE_SIZE);
86 const bool doInlines = (tileWidth == MAP_TILE_SIZE);
87
88 int y = tileHeight;
89
90 if (doInlines) { // hw: memcmp/memcpy is inlined when using constants
91 while (y) {
92 if (memcmp(old, scrn, sizeof(T) * MAP_TILE_SIZE)) {
93 changed = true;
94 break;
95 }
96 scrn += lstep;
97 old += bufferStride;
98 --y;
99 }
100
101 while (y) {
102 memcpy(old, scrn, sizeof(T) * MAP_TILE_SIZE);
103 scrn += lstep;
104 old += bufferStride;
105 --y;
106 }
107 } else {
108 while (y) {
109 if (memcmp(old, scrn, sizeof(T) * tileWidth)) {
110 changed = true;
111 break;
112 }
113 scrn += lstep;
114 old += bufferStride;
115 --y;
116 }
117
118 while (y) {
119 memcpy(old, scrn, sizeof(T) * tileWidth);
120 scrn += lstep;
121 old += bufferStride;
122 --y;
123 }
124 }
125 }
126
127 const int mapIndex = tileY * mapWidth + tileX;
128 if ((force || changed) && !map[mapIndex]) {
129 map[mapIndex] = 1;
130 ++numDirty;
131 }
132}
133
134template class QVncDirtyMapOptimized<unsigned char>;
135template class QVncDirtyMapOptimized<unsigned short>;
136template class QVncDirtyMapOptimized<unsigned int>;
137
138static const struct {
141} keyMap[] = {
142 { 0xff08, Qt::Key_Backspace },
143 { 0xff09, Qt::Key_Tab },
144 { 0xff0d, Qt::Key_Return },
145 { 0xff1b, Qt::Key_Escape },
146 { 0xff63, Qt::Key_Insert },
147 { 0xffff, Qt::Key_Delete },
148 { 0xff50, Qt::Key_Home },
149 { 0xff57, Qt::Key_End },
150 { 0xff55, Qt::Key_PageUp },
151 { 0xff56, Qt::Key_PageDown },
152 { 0xff51, Qt::Key_Left },
153 { 0xff52, Qt::Key_Up },
154 { 0xff53, Qt::Key_Right },
155 { 0xff54, Qt::Key_Down },
156 { 0xffbe, Qt::Key_F1 },
157 { 0xffbf, Qt::Key_F2 },
158 { 0xffc0, Qt::Key_F3 },
159 { 0xffc1, Qt::Key_F4 },
160 { 0xffc2, Qt::Key_F5 },
161 { 0xffc3, Qt::Key_F6 },
162 { 0xffc4, Qt::Key_F7 },
163 { 0xffc5, Qt::Key_F8 },
164 { 0xffc6, Qt::Key_F9 },
165 { 0xffc7, Qt::Key_F10 },
166 { 0xffc8, Qt::Key_F11 },
167 { 0xffc9, Qt::Key_F12 },
168 { 0xffe1, Qt::Key_Shift },
169 { 0xffe2, Qt::Key_Shift },
170 { 0xffe3, Qt::Key_Control },
171 { 0xffe4, Qt::Key_Control },
172 { 0xffe7, Qt::Key_Meta },
173 { 0xffe8, Qt::Key_Meta },
174 { 0xffe9, Qt::Key_Alt },
175 { 0xffea, Qt::Key_Alt },
176
177 { 0xffb0, Qt::Key_0 },
178 { 0xffb1, Qt::Key_1 },
179 { 0xffb2, Qt::Key_2 },
180 { 0xffb3, Qt::Key_3 },
181 { 0xffb4, Qt::Key_4 },
182 { 0xffb5, Qt::Key_5 },
183 { 0xffb6, Qt::Key_6 },
184 { 0xffb7, Qt::Key_7 },
185 { 0xffb8, Qt::Key_8 },
186 { 0xffb9, Qt::Key_9 },
187
188 { 0xff8d, Qt::Key_Return },
189 { 0xffaa, Qt::Key_Asterisk },
190 { 0xffab, Qt::Key_Plus },
191 { 0xffad, Qt::Key_Minus },
192 { 0xffae, Qt::Key_Period },
193 { 0xffaf, Qt::Key_Slash },
194
195 { 0xff95, Qt::Key_Home },
196 { 0xff96, Qt::Key_Left },
197 { 0xff97, Qt::Key_Up },
198 { 0xff98, Qt::Key_Right },
199 { 0xff99, Qt::Key_Down },
200 { 0xff9a, Qt::Key_PageUp },
201 { 0xff9b, Qt::Key_PageDown },
202 { 0xff9c, Qt::Key_End },
203 { 0xff9e, Qt::Key_Insert },
204 { 0xff9f, Qt::Key_Delete },
205
206 { 0, 0 }
208
209void QRfbRect::read(QTcpSocket *s)
210{
211 quint16 buf[4];
212 s->read(reinterpret_cast<char*>(buf), 8);
213 x = ntohs(buf[0]);
214 y = ntohs(buf[1]);
215 w = ntohs(buf[2]);
216 h = ntohs(buf[3]);
217}
218
219void QRfbRect::write(QTcpSocket *s) const
220{
221 quint16 buf[4];
222 buf[0] = htons(x);
223 buf[1] = htons(y);
224 buf[2] = htons(w);
225 buf[3] = htons(h);
226 s->write(reinterpret_cast<char*>(buf) , 8);
227}
228
229void QRfbPixelFormat::read(QTcpSocket *s)
230{
231 char buf[16];
232 s->read(buf, 16);
233 bitsPerPixel = buf[0];
234 depth = buf[1];
235 bigEndian = buf[2];
236 trueColor = buf[3];
237
238 quint16 a = ntohs(*reinterpret_cast<quint16 *>(buf + 4));
239 redBits = 0;
240 while (a) { a >>= 1; redBits++; }
241
242 a = ntohs(*reinterpret_cast<quint16 *>(buf + 6));
243 greenBits = 0;
244 while (a) { a >>= 1; greenBits++; }
245
246 a = ntohs(*reinterpret_cast<quint16 *>(buf + 8));
247 blueBits = 0;
248 while (a) { a >>= 1; blueBits++; }
249
250 redShift = buf[10];
251 greenShift = buf[11];
252 blueShift = buf[12];
253}
254
255void QRfbPixelFormat::write(QTcpSocket *s)
256{
257 char buf[16];
258 buf[0] = bitsPerPixel;
259 buf[1] = depth;
260 buf[2] = bigEndian;
261 buf[3] = trueColor;
262
263 quint16 a = 0;
264 for (int i = 0; i < redBits; i++) a = (a << 1) | 1;
265 *reinterpret_cast<quint16 *>(buf + 4) = htons(a);
266
267 a = 0;
268 for (int i = 0; i < greenBits; i++) a = (a << 1) | 1;
269 *reinterpret_cast<quint16 *>(buf + 6) = htons(a);
270
271 a = 0;
272 for (int i = 0; i < blueBits; i++) a = (a << 1) | 1;
273 *reinterpret_cast<quint16 *>(buf + 8) = htons(a);
274
275 buf[10] = redShift;
276 buf[11] = greenShift;
277 buf[12] = blueShift;
278 s->write(buf, 16);
279}
280
281
282void QRfbServerInit::setName(const char *n)
283{
284 delete[] name;
285 name = new char [strlen(n) + 1];
286 strcpy(name, n);
287}
288
289void QRfbServerInit::read(QTcpSocket *s)
290{
291 s->read(reinterpret_cast<char *>(&width), 2);
292 width = ntohs(width);
293 s->read(reinterpret_cast<char *>(&height), 2);
294 height = ntohs(height);
296
297 quint32 len;
298 s->read(reinterpret_cast<char *>(&len), 4);
299 len = ntohl(len);
300
301 name = new char [len + 1];
302 s->read(name, len);
303 name[len] = '\0';
304}
305
306void QRfbServerInit::write(QTcpSocket *s)
307{
308 quint16 t = htons(width);
309 s->write(reinterpret_cast<char *>(&t), 2);
310 t = htons(height);
311 s->write(reinterpret_cast<char *>(&t), 2);
313 quint32 len = static_cast<quint32>(strlen(name));
314 len = htonl(len);
315 s->write(reinterpret_cast<char *>(&len), 4);
316 s->write(name, static_cast<qint64>(strlen(name)));
317}
318
319bool QRfbSetEncodings::read(QTcpSocket *s)
320{
321 if (s->bytesAvailable() < 3)
322 return false;
323
324 char tmp;
325 s->read(&tmp, 1); // padding
326 s->read(reinterpret_cast<char *>(&count), 2);
327 count = ntohs(count);
328
329 return true;
330}
331
333{
334 if (s->bytesAvailable() < 9)
335 return false;
336
337 s->read(&incremental, 1);
338 rect.read(s);
339
340 return true;
341}
342
343bool QRfbKeyEvent::read(QTcpSocket *s)
344{
345 if (s->bytesAvailable() < 7)
346 return false;
347
348 s->read(&down, 1);
349 quint16 tmp;
350 s->read(reinterpret_cast<char *>(&tmp), 2); // padding
351
352 quint32 key;
353 s->read(reinterpret_cast<char *>(&key), 4);
354 key = ntohl(key);
355
356 unicode = 0;
357 keycode = 0;
358 int i = 0;
359 while (keyMap[i].keysym && !keycode) {
360 if (keyMap[i].keysym == static_cast<int>(key))
361 keycode = keyMap[i].keycode;
362 i++;
363 }
364
365 if (keycode >= ' ' && keycode <= '~')
367
368 if (!keycode) {
369 if (key <= 0xff) {
370 unicode = key;
371 if (key >= 'a' && key <= 'z')
372 keycode = Qt::Key_A + key - 'a';
373 else if (key >= ' ' && key <= '~')
374 keycode = Qt::Key_Space + key - ' ';
375 }
376 }
377
378 return true;
379}
380
381bool QRfbPointerEvent::read(QTcpSocket *s)
382{
383 if (s->bytesAvailable() < 5)
384 return false;
385
386 char buttonMask;
387 s->read(&buttonMask, 1);
388 buttons = Qt::NoButton;
389 if (buttonMask & 1)
390 buttons |= Qt::LeftButton;
391 if (buttonMask & 2)
392 buttons |= Qt::MiddleButton;
393 if (buttonMask & 4)
394 buttons |= Qt::RightButton;
395
396 quint16 tmp;
397 s->read(reinterpret_cast<char *>(&tmp), 2);
398 x = ntohs(tmp);
399 s->read(reinterpret_cast<char *>(&tmp), 2);
400 y = ntohs(tmp);
401
402 return true;
403}
404
405bool QRfbClientCutText::read(QTcpSocket *s)
406{
407 if (s->bytesAvailable() < 7)
408 return false;
409
410 char tmp[3];
411 s->read(tmp, 3); // padding
412 s->read(reinterpret_cast<char *>(&length), 4);
413 length = ntohl(length);
414
415 return true;
416}
417
419{
420// QVncDirtyMap *map = server->dirtyMap();
421 QTcpSocket *socket = client->clientSocket();
422
423 const int bytesPerPixel = client->clientBytesPerPixel();
424
425 // create a region from the dirty rects and send the region's merged rects.
426 // ### use the tile map again
427 QRegion rgn = client->dirtyRegion();
428 qCDebug(lcVnc) << "QRfbRawEncoder::write()" << rgn;
429// if (map) {
430// for (int y = 0; y < map->mapHeight; ++y) {
431// for (int x = 0; x < map->mapWidth; ++x) {
432// if (!map->dirty(x, y))
433// continue;
434// rgn += QRect(x * MAP_TILE_SIZE, y * MAP_TILE_SIZE,
435// MAP_TILE_SIZE, MAP_TILE_SIZE);
436// map->setClean(x, y);
437// }
438// }
439
440// rgn &= QRect(0, 0, server->screen()->geometry().width(),
441// server->screen()->geometry().height());
442// }
443
444 const QImage screenImage = client->server()->screenImage();
445 rgn &= screenImage.rect();
446
447 const auto rectsInRegion = rgn.rectCount();
448
449 {
450 const char tmp[2] = { 0, 0 }; // msg type, padding
451 socket->write(tmp, sizeof(tmp));
452 }
453
454 {
455 const quint16 count = htons(rectsInRegion);
456 socket->write(reinterpret_cast<const char *>(&count), sizeof(count));
457 }
458
459 if (rectsInRegion <= 0)
460 return;
461
462 for (const QRect &tileRect: rgn) {
463 const QRfbRect rect(tileRect.x(), tileRect.y(),
464 tileRect.width(), tileRect.height());
465 rect.write(socket);
466
467 const quint32 encoding = htonl(0); // raw encoding
468 socket->write(reinterpret_cast<const char *>(&encoding), sizeof(encoding));
469
470 qsizetype linestep = screenImage.bytesPerLine();
471 const uchar *screendata = screenImage.scanLine(rect.y)
472 + rect.x * screenImage.depth() / 8;
473
474 if (client->doPixelConversion()) {
475 const int bufferSize = rect.w * rect.h * bytesPerPixel;
476 if (bufferSize > buffer.size())
477 buffer.resize(bufferSize);
478
479 // convert pixels
480 char *b = buffer.data();
481 const int bstep = rect.w * bytesPerPixel;
482 const int depth = screenImage.depth();
483 for (int i = 0; i < rect.h; ++i) {
484 client->convertPixels(b, reinterpret_cast<const char*>(screendata), rect.w, depth);
485 screendata += linestep;
486 b += bstep;
487 }
488 socket->write(buffer.constData(), bufferSize);
489 } else {
490 for (int i = 0; i < rect.h; ++i) {
491 socket->write(reinterpret_cast<const char*>(screendata), rect.w * bytesPerPixel);
492 screendata += linestep;
493 }
494 }
495 if (socket->state() == QAbstractSocket::UnconnectedState)
496 break;
497 }
498 socket->flush();
499}
500
501#if QT_CONFIG(cursor)
502QVncClientCursor::QVncClientCursor()
503{
504 QWindow *w = QGuiApplication::focusWindow();
505 QCursor c = w ? w->cursor() : QCursor(Qt::ArrowCursor);
506 changeCursor(&c, nullptr);
507}
508
509QVncClientCursor::~QVncClientCursor()
510{
511}
512
513void QVncClientCursor::write(QVncClient *client) const
514{
515 QTcpSocket *socket = client->clientSocket();
516
517 // FramebufferUpdate header
518 {
519 const quint16 tmp[6] = { htons(0),
520 htons(1),
521 htons(static_cast<uint16_t>(hotspot.x())), htons(static_cast<uint16_t>(hotspot.y())),
522 htons(static_cast<uint16_t>(cursor.width())),
523 htons(static_cast<uint16_t>(cursor.height())) };
524 socket->write(reinterpret_cast<const char*>(tmp), sizeof(tmp));
525
526 const qint32 encoding = qToBigEndian(-239);
527 socket->write(reinterpret_cast<const char*>(&encoding), sizeof(encoding));
528 }
529
530 if (cursor.isNull())
531 return;
532
533 // write pixels
534 Q_ASSERT(cursor.hasAlphaChannel());
535 const QImage img = cursor.convertToFormat(client->server()->screen()->format());
536 const int n = client->clientBytesPerPixel() * img.width();
537 const int depth = img.depth();
538 char *buffer = new char[n];
539 for (int i = 0; i < img.height(); ++i) {
540 client->convertPixels(buffer, (const char*)img.scanLine(i), img.width(), depth);
541 socket->write(buffer, n);
542 }
543 delete[] buffer;
544
545 // write mask
546 const QImage bitmap = cursor.createAlphaMask().convertToFormat(QImage::Format_Mono);
547 Q_ASSERT(bitmap.depth() == 1);
548 Q_ASSERT(bitmap.size() == img.size());
549 const int width = (bitmap.width() + 7) / 8;
550 for (int i = 0; i < bitmap.height(); ++i)
551 socket->write(reinterpret_cast<const char*>(bitmap.scanLine(i)), width);
552}
553
554void QVncClientCursor::changeCursor(QCursor *widgetCursor, QWindow *window)
555{
556 Q_UNUSED(window);
557 const Qt::CursorShape shape = widgetCursor ? widgetCursor->shape() : Qt::ArrowCursor;
558
559 if (shape == Qt::BitmapCursor) {
560 // application supplied cursor
561 hotspot = widgetCursor->hotSpot();
562 cursor = widgetCursor->pixmap().toImage();
563 } else {
564 // system cursor
565 QPlatformCursorImage platformImage(nullptr, nullptr, 0, 0, 0, 0);
566 platformImage.set(shape);
567 cursor = *platformImage.image();
568 hotspot = platformImage.hotspot();
569 }
570 for (auto client : std::as_const(clients))
571 client->setDirtyCursor();
572}
573
574void QVncClientCursor::addClient(QVncClient *client)
575{
576 if (!clients.contains(client)) {
577 clients.append(client);
578 // Force a cursor update when the client connects.
579 client->setDirtyCursor();
580 }
581}
582
583uint QVncClientCursor::removeClient(QVncClient *client)
584{
585 clients.removeOne(client);
586 return clients.size();
587}
588#endif // QT_CONFIG(cursor)
589
590QVncServer::QVncServer(QVncScreen *screen, quint16 port)
591 : qvnc_screen(screen)
592 , m_port(port)
593{
594 QMetaObject::invokeMethod(this, "init", Qt::QueuedConnection);
595}
596
597void QVncServer::init()
598{
599 serverSocket = new QTcpServer(this);
600 if (!serverSocket->listen(QHostAddress::Any, m_port))
601 qWarning() << "QVncServer could not connect:" << serverSocket->errorString();
602 else
603 qWarning("QVncServer created on port %d", m_port);
604
605 connect(serverSocket, SIGNAL(newConnection()), this, SLOT(newConnection()));
606
607}
608
610{
611 qDeleteAll(clients);
612}
613
615{
616 for (auto client : std::as_const(clients))
617 client->setDirty(qvnc_screen->dirtyRegion);
618
619 qvnc_screen->clearDirty();
620}
621
622
623void QVncServer::newConnection()
624{
625 auto clientSocket = serverSocket->nextPendingConnection();
626 clients.append(new QVncClient(clientSocket, this));
627
629
630 qCDebug(lcVnc) << "new Connection from: " << clientSocket->localAddress();
631
632 qvnc_screen->setPowerState(QPlatformScreen::PowerStateOn);
633}
634
636{
637 clients.removeOne(client);
638 qvnc_screen->disableClientCursor(client);
639 client->deleteLater();
640 if (clients.isEmpty())
641 qvnc_screen->setPowerState(QPlatformScreen::PowerStateOff);
642}
643
645{
646 return *qvnc_screen->image();
647}
648
649QT_END_NAMESPACE
650
651#include "moc_qvnc_p.cpp"
bool read(QTcpSocket *s)
Definition qvnc.cpp:405
QVncClient * client
Definition qvnc_p.h:175
bool read(QTcpSocket *s)
Definition qvnc.cpp:332
int keycode
Definition qvnc_p.h:144
bool read(QTcpSocket *s)
Definition qvnc.cpp:343
char down
Definition qvnc_p.h:143
int unicode
Definition qvnc_p.h:145
bool trueColor
Definition qvnc_p.h:94
bool bigEndian
Definition qvnc_p.h:93
void read(QTcpSocket *s)
Definition qvnc.cpp:229
int bitsPerPixel
Definition qvnc_p.h:91
void write(QTcpSocket *s)
Definition qvnc.cpp:255
bool read(QTcpSocket *s)
Definition qvnc.cpp:381
void write() override
Definition qvnc.cpp:418
void read(QTcpSocket *s)
Definition qvnc.cpp:209
void write(QTcpSocket *s) const
Definition qvnc.cpp:219
void read(QTcpSocket *s)
Definition qvnc.cpp:289
QRfbPixelFormat format
Definition qvnc_p.h:117
void setName(const char *n)
Definition qvnc.cpp:282
char * name
Definition qvnc_p.h:118
void write(QTcpSocket *s)
Definition qvnc.cpp:306
bool read(QTcpSocket *s)
Definition qvnc.cpp:319
int clientBytesPerPixel() const
Definition qvncclient.h:40
QTcpSocket * clientSocket() const
QVncServer * server() const
Definition qvncclient.h:33
void setDirty(int x, int y, bool force=false) override
Definition qvnc.cpp:66
int bufferStride
Definition qvnc_p.h:51
int mapWidth
Definition qvnc_p.h:43
int bytesPerPixel
Definition qvnc_p.h:41
int numTiles
Definition qvnc_p.h:52
int mapHeight
Definition qvnc_p.h:44
int bufferHeight
Definition qvnc_p.h:50
QVncDirtyMap(QVncScreen *screen)
Definition qvnc.cpp:26
QVncScreen * screen
Definition qvnc_p.h:40
int numDirty
Definition qvnc_p.h:42
void reset()
Definition qvnc.cpp:47
virtual ~QVncDirtyMap()
Definition qvnc.cpp:41
int bufferWidth
Definition qvnc_p.h:49
bool dirty(int x, int y) const
Definition qvnc.cpp:54
void setClean(int x, int y)
Definition qvnc.cpp:59
void clearDirty()
Definition qvncscreen.h:39
void disableClientCursor(QVncClient *client)
~QVncServer()
Definition qvnc.cpp:609
QImage screenImage() const
Definition qvnc.cpp:644
void discardClient(QVncClient *client)
Definition qvnc.cpp:635
void setDirty()
Definition qvnc.cpp:614
QVncDirtyMap * dirtyMap() const
Definition qvnc_p.h:365
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
int keycode
Definition qvnc.cpp:140
int keysym
Definition qvnc.cpp:139
#define MAP_TILE_SIZE
Definition qvnc_p.h:27