]> source.dussan.org Git - tigervnc.git/commitdiff
Support UTF8_STRING selection target type
authorPierre Ossman <ossman@cendio.se>
Wed, 13 Jan 2016 11:19:13 +0000 (12:19 +0100)
committerPierre Ossman <ossman@cendio.se>
Fri, 5 Feb 2016 09:35:42 +0000 (10:35 +0100)
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

index 6faff1eeabce690b0d78279f5ef83c3b9b33f275..cea8ecf24c1af93e118ea30de32feba0c17b8895 100644 (file)
@@ -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);
   }
 }