From ee04c6dd550b9198c37c78c14d41e52c29d7c5a7 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 13 Jan 2016 12:19:13 +0100 Subject: [PATCH] Support UTF8_STRING selection target type The protocol still only supports 8859-1 though, so we need to convert things to and from UTF-8. --- unix/xserver/hw/vnc/vncSelection.c | 95 +++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/unix/xserver/hw/vnc/vncSelection.c b/unix/xserver/hw/vnc/vncSelection.c index 6faff1ee..cea8ecf2 100644 --- a/unix/xserver/hw/vnc/vncSelection.c +++ b/unix/xserver/hw/vnc/vncSelection.c @@ -42,7 +42,7 @@ #define LOG_DEBUG(...) vncLogDebug(LOG_NAME, __VA_ARGS__) static Atom xaPRIMARY, xaCLIPBOARD; -static Atom xaTARGETS, xaTIMESTAMP, xaSTRING, xaTEXT; +static Atom xaTARGETS, xaTIMESTAMP, xaSTRING, xaTEXT, xaUTF8_STRING; static WindowPtr pWindow; static Window wid; @@ -69,6 +69,7 @@ void vncSelectionInit(void) xaTIMESTAMP = MakeAtom("TIMESTAMP", 9, TRUE); xaSTRING = MakeAtom("STRING", 6, TRUE); xaTEXT = MakeAtom("TEXT", 4, TRUE); + xaUTF8_STRING = MakeAtom("UTF8_STRING", 11, TRUE); /* There are no hooks for when these are internal windows, so * override the relevant handlers. */ @@ -223,7 +224,8 @@ static int vncConvertSelection(ClientPtr client, Atom selection, /* FIXME: MULTIPLE target */ if (target == xaTARGETS) { - Atom targets[] = { xaTARGETS, xaTIMESTAMP, xaSTRING, xaTEXT }; + Atom targets[] = { xaTARGETS, xaTIMESTAMP, + xaSTRING, xaTEXT, xaUTF8_STRING }; rc = ChangeWindowProperty(pWin, realProperty, XA_ATOM, 32, PropModeReplace, @@ -244,6 +246,41 @@ static int vncConvertSelection(ClientPtr client, Atom selection, 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 { + *out++ = *in++; + len++; + in_len--; + } + } + + rc = ChangeWindowProperty(pWin, realProperty, xaUTF8_STRING, 8, + PropModeReplace, len, buffer, TRUE); + free(buffer); + if (rc != Success) + return rc; } else { return BadMatch; } @@ -372,6 +409,8 @@ static void vncHandleSelection(Atom selection, Atom target, 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); } else if (target == xaSTRING) { if (prop->format != 8) return; @@ -379,6 +418,58 @@ static void vncHandleSelection(Atom selection, Atom target, return; vncServerCutText(prop->data, prop->size); + } else if (target == xaUTF8_STRING) { + unsigned char* buffer; + unsigned char* out; + size_t len; + + const unsigned char* in; + size_t in_len; + + if (prop->format != 8) + return; + if (prop->type != xaUTF8_STRING) + return; + + buffer = malloc(prop->size); + if (buffer == 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)); + } + } + + vncServerCutText((const char*)buffer, len); + + free(buffer); } } -- 2.39.5