Skip to content

Commit

Permalink
Merge branch 'master' into multicastvnc
Browse files Browse the repository at this point in the history
  • Loading branch information
bk138 committed Dec 19, 2024
2 parents ef3b574 + 0640ba5 commit b4d4a09
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 19 deletions.
51 changes: 50 additions & 1 deletion examples/client/qt5client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,13 @@ class VncViewer : public QWidget
int serverPort;
std::thread *vncThread() const;
void paintEvent(QPaintEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void closeEvent(QCloseEvent *event) override;

private:
bool m_startFlag = false;
QImage m_image;
rfbClient *cl;
std::thread *m_vncThread;
Expand All @@ -74,6 +79,7 @@ void VncViewer::finishedFramebufferUpdate(rfbClient *cl)

update();
}

void VncViewer::paintEvent(QPaintEvent *event)
{
event->accept();
Expand All @@ -82,6 +88,45 @@ void VncViewer::paintEvent(QPaintEvent *event)
painter.drawImage(this->rect(), m_image);
}

void VncViewer::mouseMoveEvent(QMouseEvent *event)
{
if (m_startFlag) {
SendPointerEvent(cl,
event->localPos().x() / width() * cl->width,
event->localPos().y() / height() * cl->height,
(event->buttons() & Qt::LeftButton) ? 1 : 0);
}
}

void VncViewer::mousePressEvent(QMouseEvent *event)
{
if (m_startFlag) {
SendPointerEvent(cl,
event->localPos().x() / width() * cl->width,
event->localPos().y() / height() * cl->height,
1);
}
}

void VncViewer::mouseReleaseEvent(QMouseEvent *event)
{
if (m_startFlag) {
SendPointerEvent(cl,
event->localPos().x() / width() * cl->width,
event->localPos().y() / height() * cl->height,
0);
}
}

void VncViewer::closeEvent(QCloseEvent *event)
{
m_startFlag = false;
if (m_vncThread->joinable()) {
m_vncThread->join();
}
QWidget::closeEvent(event);
}

void VncViewer::start()
{
cl = rfbGetClient(8, 3, 4);
Expand Down Expand Up @@ -109,9 +154,13 @@ void VncViewer::start()
std::cout << "[INFO] disconnected" << std::endl;
return;
}
m_startFlag = true;

std::cout << "[INFO] screen size: " << cl->width << " x " << cl->height << std::endl;
this->resize(cl->width, cl->height);

m_vncThread = new std::thread([this]() {
while (true) {
while (m_startFlag) {
int i = WaitForMessage(cl, 500);
if (i < 0) {
std::cout << "[INFO] disconnected" << std::endl;
Expand Down
2 changes: 2 additions & 0 deletions include/rfb/rfb.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ typedef struct _rfbScreenInfo
uintptr_t listener_thread;
#endif
#ifdef LIBVNCSERVER_HAVE_LIBZ
/** This is called when UTF-8 cut-text is received from a client.
* Set this callback to enable ExtendedClipboard support. */
rfbSetXCutTextUTF8ProcPtr setXCutTextUTF8;
#endif

Expand Down
50 changes: 44 additions & 6 deletions src/libvncclient/rfbclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -1870,6 +1870,43 @@ sendExtClientCutTextNotify(rfbClient *client)
return ret;
}

/**
* Due to bugs, many servers (including most versions of LibVNCServer) can't
* properly handle zlib streams created by compress() function of zlib library.
*
* Primary bug is that these servers don't expect inflate() to return Z_STREAM_END
* which is the case for (correct) streams created by compress().
*
* So this function creates a compatible stream, for which inflate() returns Z_OK.
* This is how some clients create zlib streams, unintentionally avoiding the bug.
*/
static int
CompressClipData(Bytef *dest, uLongf *destLen, Bytef *source, uLong sourceLen)
{
int ret;
z_stream *zs = (z_stream*)malloc(sizeof(z_stream));
memset(zs, 0, sizeof(z_stream));

zs->zfree = Z_NULL;
zs->zalloc = Z_NULL;
zs->opaque = Z_NULL;
ret = deflateInit(zs, Z_DEFAULT_COMPRESSION);
if (ret == Z_OK) {
zs->avail_in = sourceLen;
zs->next_in = source;
zs->avail_out = *destLen;
zs->next_out = dest;

do {
// Using Z_SYNC_FLUSH instead of Z_FINISH is the key here.
ret = deflate(zs, Z_SYNC_FLUSH);
} while (ret >= 0 && zs->avail_in > 0);

*destLen = zs->total_out;
deflateEnd(zs);
}
return ret;
}

/*
* sendExtClientCutTextProvide
Expand All @@ -1880,20 +1917,21 @@ static rfbBool
sendExtClientCutTextProvide(rfbClient *client, char* data, int len)
{
rfbClientCutTextMsg cct = {0, };
int sentLen = len + 1; /* Sent data is null terminated*/
const uint32_t be_flags = rfbClientSwap32IfLE(rfbExtendedClipboard_Provide
| rfbExtendedClipboard_Text); /*text and provide*/
const uint32_t be_size = rfbClientSwap32IfLE(len);
const size_t sz_to_compressed = sizeof(be_size) + len; /*size, data*/
uLong csz = compressBound(sz_to_compressed + 1); /*tricky, some server need extar byte to flush data*/
const uint32_t be_size = rfbClientSwap32IfLE(sentLen);
const size_t sz_to_compressed = sizeof(be_size) + sentLen; /*size, data*/
uLong csz = compressBound(sz_to_compressed);

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

unsigned char *cbuf = malloc(sizeof(be_flags) + csz); /*flag, compressed*/
if (!cbuf) {
Expand All @@ -1902,7 +1940,7 @@ sendExtClientCutTextProvide(rfbClient *client, char* data, int len)
return FALSE;
}
memcpy(cbuf, &be_flags, sizeof(be_flags));
if (compress(cbuf + sizeof(be_flags), &csz, buf, sz_to_compressed + 1) != Z_OK) {
if (CompressClipData(cbuf + sizeof(be_flags), &csz, buf, sz_to_compressed) != Z_OK) {
rfbClientLog("sendExtClientCutTextProvide: compress cbuf failed\n");
free(buf);
free(cbuf);
Expand Down
2 changes: 1 addition & 1 deletion src/libvncserver/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1133,7 +1133,7 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
screen->ptrAddEvent = rfbDefaultPtrAddEvent;
screen->setXCutText = rfbDefaultSetXCutText;
#ifdef LIBVNCSERVER_HAVE_LIBZ
screen->setXCutTextUTF8 = rfbDefaultSetXCutText;
screen->setXCutTextUTF8 = NULL;
#endif
screen->getCursorPtr = rfbDefaultGetCursorPtr;
screen->setTranslateFunction = rfbSetTranslateFunction;
Expand Down
26 changes: 15 additions & 11 deletions src/libvncserver/rfbserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -2293,7 +2293,8 @@ rfbProcessExtendedServerCutTextData(rfbClientPtr cl, uint32_t flags, const char
}
stream.avail_out = size;
stream.next_out = (unsigned char *)buf;
if (inflate(&stream, Z_NO_FLUSH) != Z_OK) {
err = inflate(&stream, Z_NO_FLUSH);
if (err != Z_OK && err != Z_STREAM_END) {
rfbLogPerror("rfbProcessExtendedServerCutTextData: zlib inflation error");
free(buf);
inflateEnd(&stream);
Expand All @@ -2302,7 +2303,7 @@ rfbProcessExtendedServerCutTextData(rfbClientPtr cl, uint32_t flags, const char
}
if (i == 0) {
/* text */
if (!cl->viewOnly) {
if (!cl->viewOnly && cl->screen->setXCutTextUTF8) {
cl->screen->setXCutTextUTF8(buf, size, cl);
}
}
Expand Down Expand Up @@ -2592,14 +2593,16 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
break;
#ifdef LIBVNCSERVER_HAVE_LIBZ
case rfbEncodingExtendedClipboard:
if (!cl->enableExtendedClipboard) {
rfbLog("Enabling ExtendedClipboard extension for client "
"%s\n", cl->host);
cl->enableExtendedClipboard = TRUE;
}
/* send the capabilities we support, currently only text */
if (!rfbSendExtendedClipboardCapability(cl)) {
return;
if (cl->screen->setXCutTextUTF8) {
if (!cl->enableExtendedClipboard) {
rfbLog("Enabling ExtendedClipboard extension for client "
"%s\n", cl->host);
cl->enableExtendedClipboard = TRUE;
}
/* send the capabilities we support, currently only text */
if (!rfbSendExtendedClipboardCapability(cl)) {
return;
}
}
break;
#endif
Expand Down Expand Up @@ -5035,9 +5038,9 @@ rfbSendServerCutTextUTF8(rfbScreenInfoPtr rfbScreen,char *str, int len, char *fa
iterator = rfbGetClientIterator(rfbScreen);
while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
sct.type = rfbServerCutText;
sct.length = Swap32IfLE(len);
LOCK(cl->sendMutex);
if (cl->enableExtendedClipboard) {
sct.length = Swap32IfLE(len);
if (cl->extClipboardData != NULL) {
free(cl->extClipboardData);
cl->extClipboardData = NULL;
Expand Down Expand Up @@ -5065,6 +5068,7 @@ rfbSendServerCutTextUTF8(rfbScreenInfoPtr rfbScreen,char *str, int len, char *fa
}
UNLOCK(cl->sendMutex);
} else if (fallbackLatin1Str != NULL) {
sct.length = Swap32IfLE(latin1Len);
if (rfbWriteExact(cl, (char *)&sct,
sz_rfbServerCutTextMsg) < 0) {
rfbLogPerror("rfbSendServerCutText: write");
Expand Down

0 comments on commit b4d4a09

Please sign in to comment.