Skip to content

Commit b4d4a09

Browse files
committed
Merge branch 'master' into multicastvnc
2 parents ef3b574 + 0640ba5 commit b4d4a09

5 files changed

Lines changed: 112 additions & 19 deletions

File tree

examples/client/qt5client.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,13 @@ class VncViewer : public QWidget
5353
int serverPort;
5454
std::thread *vncThread() const;
5555
void paintEvent(QPaintEvent *event) override;
56+
void mouseMoveEvent(QMouseEvent *event) override;
57+
void mousePressEvent(QMouseEvent *event) override;
58+
void mouseReleaseEvent(QMouseEvent *event) override;
59+
void closeEvent(QCloseEvent *event) override;
5660

5761
private:
62+
bool m_startFlag = false;
5863
QImage m_image;
5964
rfbClient *cl;
6065
std::thread *m_vncThread;
@@ -74,6 +79,7 @@ void VncViewer::finishedFramebufferUpdate(rfbClient *cl)
7479

7580
update();
7681
}
82+
7783
void VncViewer::paintEvent(QPaintEvent *event)
7884
{
7985
event->accept();
@@ -82,6 +88,45 @@ void VncViewer::paintEvent(QPaintEvent *event)
8288
painter.drawImage(this->rect(), m_image);
8389
}
8490

91+
void VncViewer::mouseMoveEvent(QMouseEvent *event)
92+
{
93+
if (m_startFlag) {
94+
SendPointerEvent(cl,
95+
event->localPos().x() / width() * cl->width,
96+
event->localPos().y() / height() * cl->height,
97+
(event->buttons() & Qt::LeftButton) ? 1 : 0);
98+
}
99+
}
100+
101+
void VncViewer::mousePressEvent(QMouseEvent *event)
102+
{
103+
if (m_startFlag) {
104+
SendPointerEvent(cl,
105+
event->localPos().x() / width() * cl->width,
106+
event->localPos().y() / height() * cl->height,
107+
1);
108+
}
109+
}
110+
111+
void VncViewer::mouseReleaseEvent(QMouseEvent *event)
112+
{
113+
if (m_startFlag) {
114+
SendPointerEvent(cl,
115+
event->localPos().x() / width() * cl->width,
116+
event->localPos().y() / height() * cl->height,
117+
0);
118+
}
119+
}
120+
121+
void VncViewer::closeEvent(QCloseEvent *event)
122+
{
123+
m_startFlag = false;
124+
if (m_vncThread->joinable()) {
125+
m_vncThread->join();
126+
}
127+
QWidget::closeEvent(event);
128+
}
129+
85130
void VncViewer::start()
86131
{
87132
cl = rfbGetClient(8, 3, 4);
@@ -109,9 +154,13 @@ void VncViewer::start()
109154
std::cout << "[INFO] disconnected" << std::endl;
110155
return;
111156
}
157+
m_startFlag = true;
158+
159+
std::cout << "[INFO] screen size: " << cl->width << " x " << cl->height << std::endl;
160+
this->resize(cl->width, cl->height);
112161

113162
m_vncThread = new std::thread([this]() {
114-
while (true) {
163+
while (m_startFlag) {
115164
int i = WaitForMessage(cl, 500);
116165
if (i < 0) {
117166
std::cout << "[INFO] disconnected" << std::endl;

include/rfb/rfb.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ typedef struct _rfbScreenInfo
376376
uintptr_t listener_thread;
377377
#endif
378378
#ifdef LIBVNCSERVER_HAVE_LIBZ
379+
/** This is called when UTF-8 cut-text is received from a client.
380+
* Set this callback to enable ExtendedClipboard support. */
379381
rfbSetXCutTextUTF8ProcPtr setXCutTextUTF8;
380382
#endif
381383

src/libvncclient/rfbclient.c

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1870,6 +1870,43 @@ sendExtClientCutTextNotify(rfbClient *client)
18701870
return ret;
18711871
}
18721872

1873+
/**
1874+
* Due to bugs, many servers (including most versions of LibVNCServer) can't
1875+
* properly handle zlib streams created by compress() function of zlib library.
1876+
*
1877+
* Primary bug is that these servers don't expect inflate() to return Z_STREAM_END
1878+
* which is the case for (correct) streams created by compress().
1879+
*
1880+
* So this function creates a compatible stream, for which inflate() returns Z_OK.
1881+
* This is how some clients create zlib streams, unintentionally avoiding the bug.
1882+
*/
1883+
static int
1884+
CompressClipData(Bytef *dest, uLongf *destLen, Bytef *source, uLong sourceLen)
1885+
{
1886+
int ret;
1887+
z_stream *zs = (z_stream*)malloc(sizeof(z_stream));
1888+
memset(zs, 0, sizeof(z_stream));
1889+
1890+
zs->zfree = Z_NULL;
1891+
zs->zalloc = Z_NULL;
1892+
zs->opaque = Z_NULL;
1893+
ret = deflateInit(zs, Z_DEFAULT_COMPRESSION);
1894+
if (ret == Z_OK) {
1895+
zs->avail_in = sourceLen;
1896+
zs->next_in = source;
1897+
zs->avail_out = *destLen;
1898+
zs->next_out = dest;
1899+
1900+
do {
1901+
// Using Z_SYNC_FLUSH instead of Z_FINISH is the key here.
1902+
ret = deflate(zs, Z_SYNC_FLUSH);
1903+
} while (ret >= 0 && zs->avail_in > 0);
1904+
1905+
*destLen = zs->total_out;
1906+
deflateEnd(zs);
1907+
}
1908+
return ret;
1909+
}
18731910

18741911
/*
18751912
* sendExtClientCutTextProvide
@@ -1880,20 +1917,21 @@ static rfbBool
18801917
sendExtClientCutTextProvide(rfbClient *client, char* data, int len)
18811918
{
18821919
rfbClientCutTextMsg cct = {0, };
1920+
int sentLen = len + 1; /* Sent data is null terminated*/
18831921
const uint32_t be_flags = rfbClientSwap32IfLE(rfbExtendedClipboard_Provide
18841922
| rfbExtendedClipboard_Text); /*text and provide*/
1885-
const uint32_t be_size = rfbClientSwap32IfLE(len);
1886-
const size_t sz_to_compressed = sizeof(be_size) + len; /*size, data*/
1887-
uLong csz = compressBound(sz_to_compressed + 1); /*tricky, some server need extar byte to flush data*/
1923+
const uint32_t be_size = rfbClientSwap32IfLE(sentLen);
1924+
const size_t sz_to_compressed = sizeof(be_size) + sentLen; /*size, data*/
1925+
uLong csz = compressBound(sz_to_compressed);
18881926

1889-
unsigned char *buf = malloc(sz_to_compressed + 1); /*tricky, some server need extra byte to flush data*/
1927+
unsigned char *buf = malloc(sz_to_compressed);
18901928
if (!buf) {
18911929
rfbClientLog("sendExtClientCutTextProvide. alloc buf failed\n");
18921930
return FALSE;
18931931
}
18941932
memcpy(buf, &be_size, sizeof(be_size));
18951933
memcpy(buf + sizeof(be_size), data, len);
1896-
buf[sz_to_compressed] = 0;
1934+
buf[sz_to_compressed - 1] = 0; /* Null terminate sent data */
18971935

18981936
unsigned char *cbuf = malloc(sizeof(be_flags) + csz); /*flag, compressed*/
18991937
if (!cbuf) {
@@ -1902,7 +1940,7 @@ sendExtClientCutTextProvide(rfbClient *client, char* data, int len)
19021940
return FALSE;
19031941
}
19041942
memcpy(cbuf, &be_flags, sizeof(be_flags));
1905-
if (compress(cbuf + sizeof(be_flags), &csz, buf, sz_to_compressed + 1) != Z_OK) {
1943+
if (CompressClipData(cbuf + sizeof(be_flags), &csz, buf, sz_to_compressed) != Z_OK) {
19061944
rfbClientLog("sendExtClientCutTextProvide: compress cbuf failed\n");
19071945
free(buf);
19081946
free(cbuf);

src/libvncserver/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,7 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
11331133
screen->ptrAddEvent = rfbDefaultPtrAddEvent;
11341134
screen->setXCutText = rfbDefaultSetXCutText;
11351135
#ifdef LIBVNCSERVER_HAVE_LIBZ
1136-
screen->setXCutTextUTF8 = rfbDefaultSetXCutText;
1136+
screen->setXCutTextUTF8 = NULL;
11371137
#endif
11381138
screen->getCursorPtr = rfbDefaultGetCursorPtr;
11391139
screen->setTranslateFunction = rfbSetTranslateFunction;

src/libvncserver/rfbserver.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2293,7 +2293,8 @@ rfbProcessExtendedServerCutTextData(rfbClientPtr cl, uint32_t flags, const char
22932293
}
22942294
stream.avail_out = size;
22952295
stream.next_out = (unsigned char *)buf;
2296-
if (inflate(&stream, Z_NO_FLUSH) != Z_OK) {
2296+
err = inflate(&stream, Z_NO_FLUSH);
2297+
if (err != Z_OK && err != Z_STREAM_END) {
22972298
rfbLogPerror("rfbProcessExtendedServerCutTextData: zlib inflation error");
22982299
free(buf);
22992300
inflateEnd(&stream);
@@ -2302,7 +2303,7 @@ rfbProcessExtendedServerCutTextData(rfbClientPtr cl, uint32_t flags, const char
23022303
}
23032304
if (i == 0) {
23042305
/* text */
2305-
if (!cl->viewOnly) {
2306+
if (!cl->viewOnly && cl->screen->setXCutTextUTF8) {
23062307
cl->screen->setXCutTextUTF8(buf, size, cl);
23072308
}
23082309
}
@@ -2592,14 +2593,16 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
25922593
break;
25932594
#ifdef LIBVNCSERVER_HAVE_LIBZ
25942595
case rfbEncodingExtendedClipboard:
2595-
if (!cl->enableExtendedClipboard) {
2596-
rfbLog("Enabling ExtendedClipboard extension for client "
2597-
"%s\n", cl->host);
2598-
cl->enableExtendedClipboard = TRUE;
2599-
}
2600-
/* send the capabilities we support, currently only text */
2601-
if (!rfbSendExtendedClipboardCapability(cl)) {
2602-
return;
2596+
if (cl->screen->setXCutTextUTF8) {
2597+
if (!cl->enableExtendedClipboard) {
2598+
rfbLog("Enabling ExtendedClipboard extension for client "
2599+
"%s\n", cl->host);
2600+
cl->enableExtendedClipboard = TRUE;
2601+
}
2602+
/* send the capabilities we support, currently only text */
2603+
if (!rfbSendExtendedClipboardCapability(cl)) {
2604+
return;
2605+
}
26032606
}
26042607
break;
26052608
#endif
@@ -5035,9 +5038,9 @@ rfbSendServerCutTextUTF8(rfbScreenInfoPtr rfbScreen,char *str, int len, char *fa
50355038
iterator = rfbGetClientIterator(rfbScreen);
50365039
while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
50375040
sct.type = rfbServerCutText;
5038-
sct.length = Swap32IfLE(len);
50395041
LOCK(cl->sendMutex);
50405042
if (cl->enableExtendedClipboard) {
5043+
sct.length = Swap32IfLE(len);
50415044
if (cl->extClipboardData != NULL) {
50425045
free(cl->extClipboardData);
50435046
cl->extClipboardData = NULL;
@@ -5065,6 +5068,7 @@ rfbSendServerCutTextUTF8(rfbScreenInfoPtr rfbScreen,char *str, int len, char *fa
50655068
}
50665069
UNLOCK(cl->sendMutex);
50675070
} else if (fallbackLatin1Str != NULL) {
5071+
sct.length = Swap32IfLE(latin1Len);
50685072
if (rfbWriteExact(cl, (char *)&sct,
50695073
sz_rfbServerCutTextMsg) < 0) {
50705074
rfbLogPerror("rfbSendServerCutText: write");

0 commit comments

Comments
 (0)