summaryrefslogtreecommitdiffstats
path: root/unix
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2019-07-01 11:37:50 +0200
committerPierre Ossman <ossman@cendio.se>2019-07-01 11:37:50 +0200
commit5b8a629661c25f7c11c4b37825b0c80c633c2bf6 (patch)
treef80a2734a4fc32acb2d5d1cacf33577b3a1fe4c7 /unix
parent1d696c6bfa2ccfd6a3655602593dd3dff968aebe (diff)
parent0ff2655456097926a1720545830b1e34f072371f (diff)
downloadtigervnc-5b8a629661c25f7c11c4b37825b0c80c633c2bf6.tar.gz
tigervnc-5b8a629661c25f7c11c4b37825b0c80c633c2bf6.zip
Merge branch 'exclipboard' of https://github.com/CendioOssman/tigervnc
Diffstat (limited to 'unix')
-rw-r--r--unix/x0vncserver/XDesktop.cxx2
-rw-r--r--unix/x0vncserver/XDesktop.h2
-rw-r--r--unix/xserver/hw/vnc/RFBGlue.cc34
-rw-r--r--unix/xserver/hw/vnc/RFBGlue.h9
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.cc54
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.h10
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.cc18
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.h6
-rw-r--r--unix/xserver/hw/vnc/vncSelection.c342
-rw-r--r--unix/xserver/hw/vnc/vncSelection.h6
10 files changed, 343 insertions, 140 deletions
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index 564b2d51..8be9aa3d 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -406,7 +406,7 @@ void XDesktop::keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down) {
#endif
}
-void XDesktop::clientCutText(const char* str, int len) {
+void XDesktop::clientCutText(const char* str) {
}
ScreenSet XDesktop::computeScreenLayout()
diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h
index 3e85aac3..840d4331 100644
--- a/unix/x0vncserver/XDesktop.h
+++ b/unix/x0vncserver/XDesktop.h
@@ -56,7 +56,7 @@ public:
virtual void pointerEvent(const rfb::Point& pos, int buttonMask);
KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down);
- virtual void clientCutText(const char* str, int len);
+ virtual void clientCutText(const char* str);
virtual unsigned int setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout);
diff --git a/unix/xserver/hw/vnc/RFBGlue.cc b/unix/xserver/hw/vnc/RFBGlue.cc
index 160177bd..f108fae4 100644
--- a/unix/xserver/hw/vnc/RFBGlue.cc
+++ b/unix/xserver/hw/vnc/RFBGlue.cc
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011-2015 Pierre Ossman for Cendio AB
+ * Copyright 2011-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -210,3 +210,35 @@ int vncIsTCPPortUsed(int port)
}
return 0;
}
+
+char* vncConvertLF(const char* src, size_t bytes)
+{
+ try {
+ return convertLF(src, bytes);
+ } catch (...) {
+ return NULL;
+ }
+}
+
+char* vncLatin1ToUTF8(const char* src, size_t bytes)
+{
+ try {
+ return latin1ToUTF8(src, bytes);
+ } catch (...) {
+ return NULL;
+ }
+}
+
+char* vncUTF8ToLatin1(const char* src, size_t bytes)
+{
+ try {
+ return utf8ToLatin1(src, bytes);
+ } catch (...) {
+ return NULL;
+ }
+}
+
+void vncStrFree(char* str)
+{
+ strFree(str);
+}
diff --git a/unix/xserver/hw/vnc/RFBGlue.h b/unix/xserver/hw/vnc/RFBGlue.h
index a63afd07..112405b8 100644
--- a/unix/xserver/hw/vnc/RFBGlue.h
+++ b/unix/xserver/hw/vnc/RFBGlue.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011-2015 Pierre Ossman for Cendio AB
+ * Copyright 2011-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -49,6 +49,13 @@ void vncListParams(int width, int nameWidth);
int vncGetSocketPort(int fd);
int vncIsTCPPortUsed(int port);
+char* vncConvertLF(const char* src, size_t bytes);
+
+char* vncLatin1ToUTF8(const char* src, size_t bytes);
+char* vncUTF8ToLatin1(const char* src, size_t bytes);
+
+void vncStrFree(char* str);
+
#ifdef __cplusplus
}
#endif
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index d8b3a4d4..4edffec7 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2017 Pierre Ossman for Cendio AB
+ * Copyright 2009-2019 Pierre Ossman for Cendio AB
* Copyright 2014 Brian P. Hinz
*
* This is free software; you can redistribute it and/or modify
@@ -182,25 +182,43 @@ void XserverDesktop::queryConnection(network::Socket* sock,
queryConnectTimer.start(queryConnectTimeout * 1000);
}
-void XserverDesktop::bell()
+void XserverDesktop::requestClipboard()
{
- server->bell();
+ try {
+ server->requestClipboard();
+ } catch (rdr::Exception& e) {
+ vlog.error("XserverDesktop::requestClipboard: %s",e.str());
+ }
}
-void XserverDesktop::setLEDState(unsigned int state)
+void XserverDesktop::announceClipboard(bool available)
{
- server->setLEDState(state);
+ try {
+ server->announceClipboard(available);
+ } catch (rdr::Exception& e) {
+ vlog.error("XserverDesktop::announceClipboard: %s",e.str());
+ }
}
-void XserverDesktop::serverCutText(const char* str, int len)
+void XserverDesktop::sendClipboardData(const char* data)
{
try {
- server->serverCutText(str, len);
+ server->sendClipboardData(data);
} catch (rdr::Exception& e) {
- vlog.error("XserverDesktop::serverCutText: %s",e.str());
+ vlog.error("XserverDesktop::sendClipboardData: %s",e.str());
}
}
+void XserverDesktop::bell()
+{
+ server->bell();
+}
+
+void XserverDesktop::setLEDState(unsigned int state)
+{
+ server->setLEDState(state);
+}
+
void XserverDesktop::setDesktopName(const char* name)
{
try {
@@ -436,11 +454,6 @@ void XserverDesktop::pointerEvent(const Point& pos, int buttonMask)
vncPointerButtonAction(buttonMask);
}
-void XserverDesktop::clientCutText(const char* str, int len)
-{
- vncClientCutText(str, len);
-}
-
unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout)
{
@@ -462,6 +475,21 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
return result;
}
+void XserverDesktop::handleClipboardRequest()
+{
+ vncHandleClipboardRequest();
+}
+
+void XserverDesktop::handleClipboardAnnounce(bool available)
+{
+ vncHandleClipboardAnnounce(available);
+}
+
+void XserverDesktop::handleClipboardData(const char* data_)
+{
+ vncHandleClipboardData(data_);
+}
+
void XserverDesktop::grabRegion(const rfb::Region& region)
{
if (directFbptr)
diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
index 1253935f..6c670689 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2015 Pierre Ossman for Cendio AB
+ * Copyright 2009-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -59,9 +59,11 @@ public:
void unblockUpdates();
void setFramebuffer(int w, int h, void* fbptr, int stride);
void refreshScreenLayout();
+ void requestClipboard();
+ void announceClipboard(bool available);
+ void sendClipboardData(const char* data);
void bell();
void setLEDState(unsigned int state);
- void serverCutText(const char* str, int len);
void setDesktopName(const char* name);
void setCursor(int width, int height, int hotX, int hotY,
const unsigned char *rgbaData);
@@ -92,9 +94,11 @@ public:
const char* userName);
virtual void pointerEvent(const rfb::Point& pos, int buttonMask);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
- virtual void clientCutText(const char* str, int len);
virtual unsigned int setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout);
+ virtual void handleClipboardRequest();
+ virtual void handleClipboardAnnounce(bool available);
+ virtual void handleClipboardData(const char* data);
// rfb::PixelBuffer callbacks
virtual void grabRegion(const rfb::Region& r);
diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
index 20072f48..6ab306b1 100644
--- a/unix/xserver/hw/vnc/vncExtInit.cc
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011-2015 Pierre Ossman for Cendio AB
+ * Copyright 2011-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -285,10 +285,22 @@ void vncUpdateDesktopName(void)
desktop[scr]->setDesktopName(desktopName);
}
-void vncServerCutText(const char *text, size_t len)
+void vncRequestClipboard(void)
{
for (int scr = 0; scr < vncGetScreenCount(); scr++)
- desktop[scr]->serverCutText(text, len);
+ desktop[scr]->requestClipboard();
+}
+
+void vncAnnounceClipboard(int available)
+{
+ for (int scr = 0; scr < vncGetScreenCount(); scr++)
+ desktop[scr]->announceClipboard(available);
+}
+
+void vncSendClipboardData(const char* data)
+{
+ for (int scr = 0; scr < vncGetScreenCount(); scr++)
+ desktop[scr]->sendClipboardData(data);
}
int vncConnectClient(const char *addr)
diff --git a/unix/xserver/hw/vnc/vncExtInit.h b/unix/xserver/hw/vnc/vncExtInit.h
index 5f97f96d..1fb87c19 100644
--- a/unix/xserver/hw/vnc/vncExtInit.h
+++ b/unix/xserver/hw/vnc/vncExtInit.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011-2015 Pierre Ossman for Cendio AB
+ * Copyright 2011-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -53,7 +53,9 @@ int vncGetSendPrimary(void);
void vncUpdateDesktopName(void);
-void vncServerCutText(const char *text, size_t len);
+void vncRequestClipboard(void);
+void vncAnnounceClipboard(int available);
+void vncSendClipboardData(const char* data);
int vncConnectClient(const char *addr);
diff --git a/unix/xserver/hw/vnc/vncSelection.c b/unix/xserver/hw/vnc/vncSelection.c
index 4f3538d4..5191bb94 100644
--- a/unix/xserver/hw/vnc/vncSelection.c
+++ b/unix/xserver/hw/vnc/vncSelection.c
@@ -1,4 +1,4 @@
-/* Copyright 2016 Pierre Ossman for Cendio AB
+/* Copyright 2016-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -47,15 +47,34 @@ static Atom xaTARGETS, xaTIMESTAMP, xaSTRING, xaTEXT, xaUTF8_STRING;
static WindowPtr pWindow;
static Window wid;
-static char* clientCutText;
-static int clientCutTextLen;
+static Bool probing;
+static Atom activeSelection = None;
+
+struct VncDataTarget {
+ ClientPtr client;
+ Atom selection;
+ Atom target;
+ Atom property;
+ Window requestor;
+ CARD32 time;
+ struct VncDataTarget* next;
+};
+
+static struct VncDataTarget* vncDataTargetHead;
static int vncCreateSelectionWindow(void);
static int vncOwnSelection(Atom selection);
+static int vncConvertSelection(ClientPtr client, Atom selection,
+ Atom target, Atom property,
+ Window requestor, CARD32 time,
+ const char* data);
static int vncProcConvertSelection(ClientPtr client);
+static void vncSelectionRequest(Atom selection, Atom target);
static int vncProcSendEvent(ClientPtr client);
static void vncSelectionCallback(CallbackListPtr *callbacks,
void * data, void * args);
+static void vncClientStateCallback(CallbackListPtr * l,
+ void * d, void * p);
static int (*origProcConvertSelection)(ClientPtr);
static int (*origProcSendEvent)(ClientPtr);
@@ -80,34 +99,99 @@ void vncSelectionInit(void)
if (!AddCallback(&SelectionCallback, vncSelectionCallback, 0))
FatalError("Add VNC SelectionCallback failed\n");
+ if (!AddCallback(&ClientStateCallback, vncClientStateCallback, 0))
+ FatalError("Add VNC ClientStateCallback failed\n");
}
-void vncClientCutText(const char* str, int len)
+void vncHandleClipboardRequest(void)
{
- int rc;
-
- if (clientCutText != NULL)
- free(clientCutText);
-
- clientCutText = malloc(len);
- if (clientCutText == NULL) {
- LOG_ERROR("Could not allocate clipboard buffer");
- DeleteWindowFromAnySelections(pWindow);
+ if (activeSelection == None) {
+ LOG_DEBUG("Got request for local clipboard although no clipboard is active");
return;
}
- memcpy(clientCutText, str, len);
- clientCutTextLen = len;
+ LOG_DEBUG("Got request for local clipboard, re-probing formats");
+
+ probing = FALSE;
+ vncSelectionRequest(activeSelection, xaTARGETS);
+}
+
+void vncHandleClipboardAnnounce(int available)
+{
+ if (available) {
+ int rc;
+
+ LOG_DEBUG("Remote clipboard announced, grabbing local ownership");
+
+ if (vncGetSetPrimary()) {
+ rc = vncOwnSelection(xaPRIMARY);
+ if (rc != Success)
+ LOG_ERROR("Could not set PRIMARY selection");
+ }
- if (vncGetSetPrimary()) {
- rc = vncOwnSelection(xaPRIMARY);
+ rc = vncOwnSelection(xaCLIPBOARD);
if (rc != Success)
- LOG_ERROR("Could not set PRIMARY selection");
+ LOG_ERROR("Could not set CLIPBOARD selection");
+ } else {
+ struct VncDataTarget* next;
+
+ if (pWindow == NULL)
+ return;
+
+ LOG_DEBUG("Remote clipboard lost, removing local ownership");
+
+ DeleteWindowFromAnySelections(pWindow);
+
+ /* Abort any pending transfer */
+ while (vncDataTargetHead != NULL) {
+ xEvent event;
+
+ event.u.u.type = SelectionNotify;
+ event.u.selectionNotify.time = vncDataTargetHead->time;
+ event.u.selectionNotify.requestor = vncDataTargetHead->requestor;
+ event.u.selectionNotify.selection = vncDataTargetHead->selection;
+ event.u.selectionNotify.target = vncDataTargetHead->target;
+ event.u.selectionNotify.property = None;
+ WriteEventsToClient(vncDataTargetHead->client, 1, &event);
+
+ next = vncDataTargetHead->next;
+ free(vncDataTargetHead);
+ vncDataTargetHead = next;
+ }
}
+}
- rc = vncOwnSelection(xaCLIPBOARD);
- if (rc != Success)
- LOG_ERROR("Could not set CLIPBOARD selection");
+void vncHandleClipboardData(const char* data)
+{
+ struct VncDataTarget* next;
+
+ LOG_DEBUG("Got remote clipboard data, sending to X11 clients");
+
+ while (vncDataTargetHead != NULL) {
+ int rc;
+ xEvent event;
+
+ rc = vncConvertSelection(vncDataTargetHead->client,
+ vncDataTargetHead->selection,
+ vncDataTargetHead->target,
+ vncDataTargetHead->property,
+ vncDataTargetHead->requestor,
+ vncDataTargetHead->time,
+ data);
+ if (rc != Success) {
+ event.u.u.type = SelectionNotify;
+ event.u.selectionNotify.time = vncDataTargetHead->time;
+ event.u.selectionNotify.requestor = vncDataTargetHead->requestor;
+ event.u.selectionNotify.selection = vncDataTargetHead->selection;
+ event.u.selectionNotify.target = vncDataTargetHead->target;
+ event.u.selectionNotify.property = None;
+ WriteEventsToClient(vncDataTargetHead->client, 1, &event);
+ }
+
+ next = vncDataTargetHead->next;
+ free(vncDataTargetHead);
+ vncDataTargetHead = next;
+ }
}
static int vncCreateSelectionWindow(void)
@@ -195,7 +279,8 @@ static int vncOwnSelection(Atom selection)
static int vncConvertSelection(ClientPtr client, Atom selection,
Atom target, Atom property,
- Window requestor, CARD32 time)
+ Window requestor, CARD32 time,
+ const char* data)
{
Selection *pSel;
WindowPtr pWin;
@@ -205,8 +290,13 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
xEvent event;
- LOG_DEBUG("Selection request for %s (type %s)",
- NameForAtom(selection), NameForAtom(target));
+ if (data == NULL) {
+ LOG_DEBUG("Selection request for %s (type %s)",
+ NameForAtom(selection), NameForAtom(target));
+ } else {
+ LOG_DEBUG("Sending data for selection request for %s (type %s)",
+ NameForAtom(selection), NameForAtom(target));
+ }
rc = dixLookupSelection(&pSel, selection, client, DixGetAttrAccess);
if (rc != Success)
@@ -243,51 +333,59 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
TRUE);
if (rc != Success)
return rc;
- } else if ((target == xaSTRING) || (target == xaTEXT)) {
- rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
- XA_STRING, 8, PropModeReplace,
- clientCutTextLen, clientCutText,
- TRUE);
- if (rc != Success)
- return rc;
- } else if (target == xaUTF8_STRING) {
- unsigned char* buffer;
- unsigned char* out;
- size_t len;
-
- const unsigned char* in;
- size_t in_len;
-
- buffer = malloc(clientCutTextLen*2);
- if (buffer == NULL)
- return BadAlloc;
-
- out = buffer;
- len = 0;
- in = clientCutText;
- in_len = clientCutTextLen;
- while (in_len > 0) {
- if (*in & 0x80) {
- *out++ = 0xc0 | (*in >> 6);
- *out++ = 0x80 | (*in & 0x3f);
- len += 2;
- in++;
- in_len--;
+ } else {
+ if (data == NULL) {
+ struct VncDataTarget* vdt;
+
+ if ((target != xaSTRING) && (target != xaTEXT) &&
+ (target != xaUTF8_STRING))
+ return BadMatch;
+
+ vdt = calloc(1, sizeof(struct VncDataTarget));
+ if (vdt == NULL)
+ return BadAlloc;
+
+ vdt->client = client;
+ vdt->selection = selection;
+ vdt->target = target;
+ vdt->property = property;
+ vdt->requestor = requestor;
+ vdt->time = time;
+
+ vdt->next = vncDataTargetHead;
+ vncDataTargetHead = vdt;
+
+ LOG_DEBUG("Requesting clipboard data from client");
+
+ vncRequestClipboard();
+
+ return Success;
+ } else {
+ if ((target == xaSTRING) || (target == xaTEXT)) {
+ char* latin1;
+
+ latin1 = vncUTF8ToLatin1(data, (size_t)-1);
+ if (latin1 == NULL)
+ return BadAlloc;
+
+ rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
+ XA_STRING, 8, PropModeReplace,
+ strlen(latin1), latin1, TRUE);
+
+ vncStrFree(latin1);
+
+ if (rc != Success)
+ return rc;
+ } else if (target == xaUTF8_STRING) {
+ rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
+ xaUTF8_STRING, 8, PropModeReplace,
+ strlen(data), data, TRUE);
+ if (rc != Success)
+ return rc;
} else {
- *out++ = *in++;
- len++;
- in_len--;
+ return BadMatch;
}
}
-
- rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
- xaUTF8_STRING, 8, PropModeReplace,
- len, buffer, TRUE);
- free(buffer);
- if (rc != Success)
- return rc;
- } else {
- return BadMatch;
}
event.u.u.type = SelectionNotify;
@@ -326,7 +424,7 @@ static int vncProcConvertSelection(ClientPtr client)
pSel->window == wid) {
rc = vncConvertSelection(client, stuff->selection,
stuff->target, stuff->property,
- stuff->requestor, stuff->time);
+ stuff->requestor, stuff->time, NULL);
if (rc != Success) {
xEvent event;
@@ -410,69 +508,61 @@ static void vncHandleSelection(Atom selection, Atom target,
if (prop->type != XA_ATOM)
return;
- if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size))
- vncSelectionRequest(selection, xaSTRING);
- else if (vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size))
- vncSelectionRequest(selection, xaUTF8_STRING);
+ if (probing) {
+ if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size) ||
+ vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size)) {
+ LOG_DEBUG("Compatible format found, notifying clients");
+ activeSelection = selection;
+ vncAnnounceClipboard(TRUE);
+ }
+ } else {
+ if (vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size))
+ vncSelectionRequest(selection, xaUTF8_STRING);
+ else if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size))
+ vncSelectionRequest(selection, xaSTRING);
+ }
} else if (target == xaSTRING) {
+ char* filtered;
+ char* utf8;
+
if (prop->format != 8)
return;
if (prop->type != xaSTRING)
return;
- vncServerCutText(prop->data, prop->size);
- } else if (target == xaUTF8_STRING) {
- unsigned char* buffer;
- unsigned char* out;
- size_t len;
+ filtered = vncConvertLF(prop->data, prop->size);
+ if (filtered == NULL)
+ return;
+
+ utf8 = vncLatin1ToUTF8(filtered, (size_t)-1);
+ vncStrFree(filtered);
+ if (utf8 == NULL)
+ return;
+
+ LOG_DEBUG("Sending clipboard to clients (%d bytes)",
+ (int)strlen(utf8));
- const unsigned char* in;
- size_t in_len;
+ vncSendClipboardData(utf8);
+
+ vncStrFree(utf8);
+ } else if (target == xaUTF8_STRING) {
+ char *filtered;
if (prop->format != 8)
return;
if (prop->type != xaUTF8_STRING)
return;
- buffer = malloc(prop->size);
- if (buffer == NULL)
+ filtered = vncConvertLF(prop->data, prop->size);
+ if (filtered == NULL)
return;
- out = buffer;
- len = 0;
- in = prop->data;
- in_len = prop->size;
- while (in_len > 0) {
- if ((*in & 0x80) == 0x00) {
- *out++ = *in++;
- len++;
- in_len--;
- } else if ((*in & 0xe0) == 0xc0) {
- unsigned ucs;
- ucs = (*in++ & 0x1f) << 6;
- in_len--;
- if (in_len > 0) {
- ucs |= (*in++ & 0x3f);
- in_len--;
- }
- if (ucs <= 0xff)
- *out++ = ucs;
- else
- *out++ = '?';
- len++;
- } else {
- *out++ = '?';
- len++;
- do {
- in++;
- in_len--;
- } while ((in_len > 0) && ((*in & 0xc0) == 0x80));
- }
- }
+ LOG_DEBUG("Sending clipboard to clients (%d bytes)",
+ (int)strlen(filtered));
- vncServerCutText((const char*)buffer, len);
+ vncSendClipboardData(filtered);
- free(buffer);
+ vncStrFree(filtered);
}
}
@@ -504,6 +594,12 @@ static void vncSelectionCallback(CallbackListPtr *callbacks,
{
SelectionInfoRec *info = (SelectionInfoRec *) args;
+ if (info->selection->selection == activeSelection) {
+ LOG_DEBUG("Local clipboard lost, notifying clients");
+ activeSelection = None;
+ vncAnnounceClipboard(FALSE);
+ }
+
if (info->kind != SelectionSetOwner)
return;
if (info->client == serverClient)
@@ -520,5 +616,25 @@ static void vncSelectionCallback(CallbackListPtr *callbacks,
!vncGetSendPrimary())
return;
+ LOG_DEBUG("Got clipboard notification, probing for formats");
+
+ probing = TRUE;
vncSelectionRequest(info->selection->selection, xaTARGETS);
}
+
+static void vncClientStateCallback(CallbackListPtr * l,
+ void * d, void * p)
+{
+ ClientPtr client = ((NewClientInfoRec*)p)->client;
+ if (client->clientState == ClientStateGone) {
+ struct VncDataTarget** nextPtr = &vncDataTargetHead;
+ for (struct VncDataTarget* cur = vncDataTargetHead; cur; cur = *nextPtr) {
+ if (cur->client == client) {
+ *nextPtr = cur->next;
+ free(cur);
+ continue;
+ }
+ nextPtr = &cur->next;
+ }
+ }
+}
diff --git a/unix/xserver/hw/vnc/vncSelection.h b/unix/xserver/hw/vnc/vncSelection.h
index 969f8958..ea52bf23 100644
--- a/unix/xserver/hw/vnc/vncSelection.h
+++ b/unix/xserver/hw/vnc/vncSelection.h
@@ -1,4 +1,4 @@
-/* Copyright 2016 Pierre Ossman for Cendio AB
+/* Copyright 2016-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,9 @@ extern "C" {
void vncSelectionInit(void);
-void vncClientCutText(const char* str, int len);
+void vncHandleClipboardRequest(void);
+void vncHandleClipboardAnnounce(int available);
+void vncHandleClipboardData(const char* data);
#ifdef __cplusplus
}