Changeset 18585 in vbox for trunk/src/VBox/HostServices/SharedClipboard
- Timestamp:
- Mar 31, 2009 7:58:06 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 45483
- Location:
- trunk/src/VBox/HostServices/SharedClipboard
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostServices/SharedClipboard/Makefile.kmk
r18398 r18585 44 44 VBoxSharedClipboard_SOURCES += \ 45 45 $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp \ 46 $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp \ 46 47 x11-clipboard.cpp 47 48 else -
trunk/src/VBox/HostServices/SharedClipboard/VBoxClipboard.h
r15928 r18585 25 25 #define LOG_GROUP LOG_GROUP_HGCM 26 26 #include <VBox/log.h> 27 28 enum {29 /** The number of milliseconds before the clipboard times out. */30 CLIPBOARDTIMEOUT = 500031 };32 27 33 28 struct _VBOXCLIPBOARDCONTEXT; -
trunk/src/VBox/HostServices/SharedClipboard/x11-clipboard.cpp
r18582 r18585 21 21 */ 22 22 23 /** @todo create a clipboard log group */ 24 #define LOG_GROUP LOG_GROUP_HGCM 25 23 26 #include <string.h> 24 #include <stdio.h> 25 #include <stdint.h> 26 27 #ifdef RT_OS_SOLARIS 28 #include <tsol/label.h> 29 #endif 30 31 #include <vector> 32 33 #include <X11/Xlib.h> 34 #include <X11/Xatom.h> 35 #include <X11/Intrinsic.h> 36 #include <X11/Shell.h> 37 #include <X11/Xproto.h> 38 #include <X11/StringDefs.h> 39 40 #include <iprt/alloc.h> 27 41 28 #include <iprt/asm.h> /* For atomic operations */ 42 29 #include <iprt/assert.h> 43 #include <iprt/env.h>44 30 #include <iprt/mem.h> 45 #include <iprt/string.h>46 #include <iprt/thread.h>47 #include <iprt/process.h>48 31 #include <iprt/semaphore.h> 49 32 50 #include <VBox/GuestHost/clipboard-helper.h> 33 #include <VBox/log.h> 34 35 #include <VBox/GuestHost/SharedClipboard.h> 51 36 #include <VBox/HostServices/VBoxClipboardSvc.h> 52 37 53 38 #include "VBoxClipboard.h" 54 55 /** Do we want to test Utf16 by disabling other text formats? */56 static bool g_testUtf16 = false;57 /** Do we want to test Utf8 by disabling other text formats? */58 static bool g_testUtf8 = false;59 /** Do we want to test compount text by disabling other text formats? */60 static bool g_testCText = false;61 /** Are we currently debugging the clipboard code? */62 static bool g_debugClipboard = false;63 64 /** The different clipboard formats which we support. */65 enum g_eClipboardFormats66 {67 INVALID = 0,68 TARGETS,69 CTEXT,70 UTF8,71 UTF1672 };73 74 /** The X11 clipboard uses several names for the same format. This structure maps an X1175 name to a format. */76 typedef struct {77 Atom atom;78 g_eClipboardFormats format;79 unsigned guestFormat;80 } VBOXCLIPBOARDFORMAT;81 82 /** Does X11 or VBox currently own the clipboard? */83 enum g_eOwner { NONE = 0, X11, VB };84 85 typedef struct {86 /** BMP file type marker - must always contain 'BM' */87 uint16_t bfType;88 /** The size of the BMP file in bytes (the MS docs say that this is not reliable) */89 uint32_t bfSize;90 /** Reserved, must always be zero */91 uint16_t bfReserved1;92 /** Reserved, must always be zero */93 uint16_t bfReserved2;94 /** Offset from the beginning of this header to the actual image bits */95 } VBOXBITMAPFILEHEADER;96 39 97 40 /** Global context information used by the host glue for the X11 clipboard … … 115 58 }; 116 59 117 /** Global context information used by the X11 clipboard backend */118 struct _VBOXCLIPBOARDCONTEXTX11119 {120 /** Opaque data structure describing the front-end. */121 VBOXCLIPBOARDCONTEXT *pFrontend;122 /** The X Toolkit application context structure */123 XtAppContext appContext;124 125 /** We have a separate thread to wait for Window and Clipboard events */126 RTTHREAD thread;127 /** The X Toolkit widget which we use as our clipboard client. It is never made visible. */128 Widget widget;129 130 /** X11 atom refering to the clipboard: CLIPBOARD */131 Atom atomClipboard;132 /** X11 atom refering to the selection: PRIMARY */133 Atom atomPrimary;134 /** X11 atom refering to the clipboard targets: TARGETS */135 Atom atomTargets;136 /** X11 atom refering to the clipboard multiple target: MULTIPLE */137 Atom atomMultiple;138 /** X11 atom refering to the clipboard timestamp target: TIMESTAMP */139 Atom atomTimestamp;140 /** X11 atom refering to the clipboard utf16 text format: text/plain;charset=ISO-10646-UCS-2 */141 Atom atomUtf16;142 /** X11 atom refering to the clipboard utf8 text format: UTF8_STRING */143 Atom atomUtf8;144 /** X11 atom refering to the clipboard compound text format: COMPOUND_TEXT */145 Atom atomCText;146 147 /** A list of the X11 formats which we support, mapped to our identifier for them, in the148 order we prefer to have them in. */149 std::vector<VBOXCLIPBOARDFORMAT> formatList;150 151 /** Does VBox or X11 currently own the clipboard? */152 volatile enum g_eOwner eOwner;153 154 /** What is the best text format X11 has to offer? INVALID for none. */155 g_eClipboardFormats X11TextFormat;156 /** Atom corresponding to the X11 text format */157 Atom atomX11TextFormat;158 /** What is the best bitmap format X11 has to offer? INVALID for none. */159 g_eClipboardFormats X11BitmapFormat;160 /** Atom corresponding to the X11 Bitmap format */161 Atom atomX11BitmapFormat;162 /** What formats does VBox have on offer? */163 int vboxFormats;164 /** Windows hosts and guests cache the clipboard data they receive.165 * Since we have no way of knowing whether their cache is still valid,166 * we always send a "data changed" message after a successful transfer167 * to invalidate it. */168 bool notifyVBox;169 170 /** Since the clipboard data moves asynchronously, we use an event171 * semaphore to wait for it. When a function issues a request for172 * clipboard data it must wait for this semaphore, which is triggered173 * when the data arrives. */174 RTSEMEVENT waitForData;175 };176 177 typedef struct _VBOXCLIPBOARDCONTEXTX11 VBOXCLIPBOARDCONTEXTX11;178 179 /** A structure containing information about where to store a request180 * for the X11 clipboard contents. */181 struct _VBOXCLIPBOARDREQUEST182 {183 /** The buffer to write X11 clipboard data to (valid during a request184 * for the clipboard contents) */185 void *pv;186 /** The size of the buffer to write X11 clipboard data to (valid during187 * a request for the clipboard contents) */188 unsigned cb;189 /** The size of the X11 clipboard data written to the buffer (valid190 * during a request for the clipboard contents) */191 uint32_t *pcbActual;192 };193 194 typedef struct _VBOXCLIPBOARDREQUEST VBOXCLIPBOARDREQUEST;195 196 60 /* Only one client is supported. There seems to be no need for more clients. 197 61 */ 198 62 static VBOXCLIPBOARDCONTEXT g_ctxHost; 199 static VBOXCLIPBOARDCONTEXTX11 g_ctxX11;200 201 /* Are we actually connected to the X server? */202 static bool g_fHaveX11;203 204 /** @todo this is a temporary declaration. */205 static void vboxClipboardFormatAnnounceBackend (uint32_t u32Formats);206 63 207 64 /** … … 216 73 * @note Host glue code. 217 74 */ 218 static int vboxClipboardReadDataFromVBox (VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb) 75 int VBoxX11ClipboardReadVBoxData (VBOXCLIPBOARDCONTEXT *pCtx, 76 uint32_t u32Format, void **ppv, 77 uint32_t *pcb) 219 78 { 220 79 volatile VBOXCLIPBOARDCLIENTDATA *pClient = pCtx->pClient; … … 226 85 * data from X11. */ 227 86 LogFunc(("host requested guest clipboard data after guest had disconnected.\n")); 228 vboxClipboardFormatAnnounceBackend(0);87 VBoxX11ClipboardAnnounceVBoxFormat(0); 229 88 pCtx->waiter = NONE; 230 89 return VERR_TIMEOUT; … … 283 142 284 143 /** 285 * Convert the UTF-16 text obtained from the X11 clipboard to UTF-16LE with286 * Windows EOLs, place it in the buffer supplied and signal that data has287 * arrived.288 *289 * @param pValue Source UTF-16 text290 * @param cwSourceLen Length in 16-bit words of the source text291 * @param pv Where to store the converted data292 * @param cb Length in bytes of the buffer pointed to by cb293 * @param pcbActual Where to store the size of the converted data294 * @param pClient Pointer to the client context structure295 * @note X11 backend code, called from the Xt callback when we wish to read296 * the X11 clipboard.297 */298 static void vboxClipboardGetUtf16(XtPointer pValue, unsigned cwSrcLen,299 void *pv, unsigned cb,300 uint32_t *pcbActual)301 {302 size_t cwDestLen;303 PRTUTF16 pu16SrcText = reinterpret_cast<PRTUTF16>(pValue);304 PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);305 306 LogFlowFunc (("converting Utf-16 to Utf-16LE. cwSrcLen=%d, cb=%d, pu16SrcText+1=%.*ls\n",307 cwSrcLen, cb, cwSrcLen - 1, pu16SrcText + 1));308 *pcbActual = 0; /* Only set this to the right value on success. */309 /* How long will the converted text be? */310 int rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen);311 if (RT_SUCCESS(rc) && (cb < cwDestLen * 2))312 {313 /* Not enough buffer space provided - report the amount needed. */314 LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n",315 cb, cwDestLen * 2));316 *pcbActual = cwDestLen * 2;317 rc = VERR_BUFFER_OVERFLOW;318 }319 /* Convert the text. */320 if (RT_SUCCESS(rc))321 rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2);322 if (RT_SUCCESS(rc))323 {324 LogFlowFunc (("converted string is %.*ls\n", cwDestLen, pu16DestText));325 *pcbActual = cwDestLen * 2;326 }327 /* We need to do this whether we succeed or fail. */328 XtFree(reinterpret_cast<char *>(pValue));329 RTSemEventSignal(g_ctxX11.waitForData);330 LogFlowFunc(("Returning. Status is %Rrc\n", rc));331 }332 333 /**334 * Convert the UTF-8 text obtained from the X11 clipboard to UTF-16LE with335 * Windows EOLs, place it in the buffer supplied and signal that data has336 * arrived.337 *338 * @param pValue Source UTF-8 text339 * @param cbSourceLen Length in 8-bit bytes of the source text340 * @param pv Where to store the converted data341 * @param cb Length in bytes of the buffer pointed to by pv342 * @param pcbActual Where to store the size of the converted data343 * @param pClient Pointer to the client context structure344 * @note X11 backend code, called from the Xt callback when we wish to read345 * the X11 clipboard.346 */347 static void vboxClipboardGetUtf8FromX11(XtPointer pValue, unsigned cbSrcLen,348 void *pv, unsigned cb,349 uint32_t *pcbActual)350 {351 size_t cwSrcLen, cwDestLen;352 char *pu8SrcText = reinterpret_cast<char *>(pValue);353 PRTUTF16 pu16SrcText = NULL;354 PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);355 356 LogFlowFunc (("converting Utf-8 to Utf-16LE. cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n",357 cbSrcLen, cb, cbSrcLen, pu8SrcText));358 *pcbActual = 0; /* Only set this to the right value on success. */359 /* First convert the UTF8 to UTF16 */360 int rc = RTStrToUtf16Ex(pu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen);361 /* Check how much longer will the converted text will be. */362 if (RT_SUCCESS(rc))363 rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen);364 if (RT_SUCCESS(rc) && (cb < cwDestLen * 2))365 {366 /* Not enough buffer space provided - report the amount needed. */367 LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n",368 cb, cwDestLen * 2));369 *pcbActual = cwDestLen * 2;370 rc = VERR_BUFFER_OVERFLOW;371 }372 /* Convert the text. */373 if (RT_SUCCESS(rc))374 rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2);375 if (RT_SUCCESS(rc))376 {377 LogFlowFunc (("converted string is %.*ls.\n", cwDestLen, pu16DestText));378 *pcbActual = cwDestLen * 2;379 }380 XtFree(reinterpret_cast<char *>(pValue));381 RTUtf16Free(pu16SrcText);382 RTSemEventSignal(g_ctxX11.waitForData);383 LogFlowFunc(("Returning. Status is %Rrc", rc));384 }385 386 /**387 * Convert the COMPOUND_TEXT obtained from the X11 clipboard to UTF-16LE with388 * Windows EOLs, place it in the buffer supplied and signal that data has389 * arrived.390 *391 * @param pValue Source COMPOUND_TEXT392 * @param cbSourceLen Length in 8-bit bytes of the source text393 * @param pv Where to store the converted data394 * @param cb Length in bytes of the buffer pointed to by pv395 * @param pcbActual Where to store the size of the converted data396 * @param pClient Pointer to the client context structure397 * @note X11 backend code, called from the Xt callback when we wish to read398 * the X11 clipboard.399 */400 static void vboxClipboardGetCTextFromX11(XtPointer pValue, unsigned cbSrcLen,401 void *pv, unsigned cb,402 uint32_t *pcbActual)403 {404 size_t cwSrcLen, cwDestLen;405 char **ppu8SrcText = NULL;406 PRTUTF16 pu16SrcText = NULL;407 PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);408 XTextProperty property;409 int rc = VINF_SUCCESS;410 int cProps;411 412 LogFlowFunc (("converting COMPOUND TEXT to Utf-16LE. cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n",413 cbSrcLen, cb, cbSrcLen, reinterpret_cast<char *>(pValue)));414 *pcbActual = 0; /* Only set this to the right value on success. */415 /* First convert the compound text to Utf8 */416 property.value = reinterpret_cast<unsigned char *>(pValue);417 property.encoding = g_ctxX11.atomCText;418 property.format = 8;419 property.nitems = cbSrcLen;420 #ifdef RT_OS_SOLARIS421 int xrc = XmbTextPropertyToTextList(XtDisplay(g_ctxX11.widget), &property, &ppu8SrcText, &cProps);422 #else423 int xrc = Xutf8TextPropertyToTextList(XtDisplay(g_ctxX11.widget), &property, &ppu8SrcText, &cProps);424 #endif425 XtFree(reinterpret_cast<char *>(pValue));426 if (xrc < 0)427 switch(xrc)428 {429 case XNoMemory:430 rc = VERR_NO_MEMORY;431 break;432 case XLocaleNotSupported:433 case XConverterNotFound:434 rc = VERR_NOT_SUPPORTED;435 break;436 default:437 rc = VERR_UNRESOLVED_ERROR;438 }439 /* Now convert the UTF8 to UTF16 */440 if (RT_SUCCESS(rc))441 rc = RTStrToUtf16Ex(*ppu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen);442 /* Check how much longer will the converted text will be. */443 if (RT_SUCCESS(rc))444 rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen);445 if (RT_SUCCESS(rc) && (cb < cwDestLen * 2))446 {447 /* Not enough buffer space provided - report the amount needed. */448 LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n",449 cb, cwDestLen * 2));450 *pcbActual = cwDestLen * 2;451 rc = VERR_BUFFER_OVERFLOW;452 }453 /* Convert the text. */454 if (RT_SUCCESS(rc))455 rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2);456 if (RT_SUCCESS(rc))457 {458 LogFlowFunc (("converted string is %.*ls\n", cwDestLen, pu16DestText));459 *pcbActual = cwDestLen * 2;460 }461 if (ppu8SrcText != NULL)462 XFreeStringList(ppu8SrcText);463 RTUtf16Free(pu16SrcText);464 LogFlowFunc(("Returning. Status is %Rrc\n", rc));465 RTSemEventSignal(g_ctxX11.waitForData);466 }467 468 /**469 * Convert the Latin1 text obtained from the X11 clipboard to UTF-16LE with470 * Windows EOLs, place it in the buffer supplied and signal that data has471 * arrived.472 *473 * @param pValue Source Latin1 text474 * @param cbSourceLen Length in 8-bit bytes of the source text475 * @param pv Where to store the converted data476 * @param cb Length in bytes of the buffer pointed to by cb477 * @param pcbActual Where to store the size of the converted data478 * @param pClient Pointer to the client context structure479 * @note X11 backend code, called from the Xt callback when we wish to read480 * the X11 clipboard.481 */482 static void vboxClipboardGetLatin1FromX11(XtPointer pValue,483 unsigned cbSourceLen, void *pv,484 unsigned cb, uint32_t *pcbActual)485 {486 unsigned cwDestLen = cbSourceLen + 1;487 char *pu8SourceText = reinterpret_cast<char *>(pValue);488 PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);489 int rc = VINF_SUCCESS;490 491 LogFlowFunc (("converting Latin1 to Utf-16LE. Original is %.*s\n",492 cbSourceLen, pu8SourceText));493 *pcbActual = 0; /* Only set this to the right value on success. */494 for (unsigned i = 0; i < cbSourceLen; i++)495 if (pu8SourceText[i] == LINEFEED)496 ++cwDestLen;497 if (cb < cwDestLen * 2)498 {499 /* Not enough buffer space provided - report the amount needed. */500 LogFlowFunc (("guest buffer too small: size %d bytes\n", cb));501 *pcbActual = cwDestLen * 2;502 rc = VERR_BUFFER_OVERFLOW;503 }504 if (RT_SUCCESS(rc))505 {506 for (unsigned i = 0, j = 0; i < cbSourceLen; ++i, ++j)507 if (pu8SourceText[i] != LINEFEED)508 pu16DestText[j] = pu8SourceText[i]; /* latin1 < utf-16LE */509 else510 {511 pu16DestText[j] = CARRIAGERETURN;512 ++j;513 pu16DestText[j] = LINEFEED;514 }515 pu16DestText[cwDestLen - 1] = 0;516 *pcbActual = cwDestLen * 2;517 LogFlowFunc (("converted text is %.*ls\n", cwDestLen, pu16DestText));518 }519 XtFree(reinterpret_cast<char *>(pValue));520 RTSemEventSignal(g_ctxX11.waitForData);521 LogFlowFunc(("Returning. Status is %Rrc\n", rc));522 }523 524 /**525 * Convert the text obtained from the X11 clipboard to UTF-16LE with Windows526 * EOLs, place it in the buffer supplied and signal that data has arrived.527 * @note X11 backend code, callback for XtGetSelectionValue, for use when528 * the X11 clipboard contains a text format we understand.529 */530 static void vboxClipboardGetDataFromX11(Widget, XtPointer pClientData,531 Atom * /* selection */,532 Atom *atomType,533 XtPointer pValue,534 long unsigned int *pcLen,535 int *piFormat)536 {537 VBOXCLIPBOARDREQUEST *pRequest538 = reinterpret_cast<VBOXCLIPBOARDREQUEST *>(pClientData);539 LogFlowFunc(("pClientData=%p, *pcLen=%lu, *piFormat=%d\n", pClientData,540 *pcLen, *piFormat));541 LogFlowFunc(("g_ctxX11.X11TextFormat=%d, pRequest->cb=%d\n",542 g_ctxX11.X11TextFormat, pRequest->cb));543 unsigned cTextLen = (*pcLen) * (*piFormat) / 8;544 /* The X Toolkit may have failed to get the clipboard selection for us. */545 if (*atomType == XT_CONVERT_FAIL)546 return;547 /* The clipboard selection may have changed before we could get it. */548 if (NULL == pValue)549 return;550 /* In which format is the clipboard data? */551 switch (g_ctxX11.X11TextFormat)552 {553 case UTF16:554 vboxClipboardGetUtf16(pValue, cTextLen / 2, pRequest->pv,555 pRequest->cb, pRequest->pcbActual);556 break;557 case CTEXT:558 vboxClipboardGetCTextFromX11(pValue, cTextLen, pRequest->pv,559 pRequest->cb, pRequest->pcbActual);560 break;561 case UTF8:562 {563 /* If we are given broken Utf-8, we treat it as Latin1. Is this acceptable? */564 size_t cStringLen;565 char *pu8SourceText = reinterpret_cast<char *>(pValue);566 567 if ((g_ctxX11.X11TextFormat == UTF8)568 && (RTStrUniLenEx(pu8SourceText, *pcLen, &cStringLen) == VINF_SUCCESS))569 {570 vboxClipboardGetUtf8FromX11(pValue, cTextLen, pRequest->pv,571 pRequest->cb, pRequest->pcbActual);572 break;573 }574 else575 {576 vboxClipboardGetLatin1FromX11(pValue, cTextLen, pRequest->pv,577 pRequest->cb, pRequest->pcbActual);578 break;579 }580 }581 default:582 LogFunc (("bad target format\n"));583 XtFree(reinterpret_cast<char *>(pValue));584 return;585 }586 g_ctxX11.notifyVBox = true;587 }588 589 /**590 144 * Report formats available in the X11 clipboard to VBox. 591 145 * @param pCtx Opaque context pointer for the glue code … … 599 153 VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, 600 154 u32Formats); 601 }602 603 604 /**605 * Notify the host clipboard about the data formats we support, based on the606 * "targets" (available data formats) information obtained from the X11607 * clipboard.608 * @note X11 backend code, callback for XtGetSelectionValue, called when we609 * poll for available targets.610 */611 static void vboxClipboardGetTargetsFromX11(Widget,612 XtPointer /* pClientData */,613 Atom * /* selection */,614 Atom *atomType,615 XtPointer pValue,616 long unsigned int *pcLen,617 int *piFormat)618 {619 Atom *atomTargets = reinterpret_cast<Atom *>(pValue);620 unsigned cAtoms = *pcLen;621 g_eClipboardFormats eBestTarget = INVALID;622 Atom atomBestTarget = None;623 624 Log3 (("%s: called\n", __PRETTY_FUNCTION__));625 if (*atomType == XT_CONVERT_FAIL)626 {627 LogFunc (("reading clipboard from host, X toolkit failed to convert the selection\n"));628 return;629 }630 631 for (unsigned i = 0; i < cAtoms; ++i)632 {633 for (unsigned j = 0; j != g_ctxX11.formatList.size(); ++j)634 if (g_ctxX11.formatList[j].atom == atomTargets[i])635 {636 if (eBestTarget < g_ctxX11.formatList[j].format)637 {638 eBestTarget = g_ctxX11.formatList[j].format;639 atomBestTarget = g_ctxX11.formatList[j].atom;640 }641 break;642 }643 if (g_debugClipboard)644 {645 char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), atomTargets[i]);646 if (szAtomName != 0)647 {648 Log2 (("%s: the host offers target %s\n", __PRETTY_FUNCTION__,649 szAtomName));650 XFree(szAtomName);651 }652 }653 }654 g_ctxX11.atomX11TextFormat = atomBestTarget;655 if ((eBestTarget != g_ctxX11.X11TextFormat) || (g_ctxX11.notifyVBox == true))656 {657 uint32_t u32Formats = 0;658 if (g_debugClipboard)659 {660 if (atomBestTarget != None)661 {662 char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), atomBestTarget);663 Log2 (("%s: switching to host text target %s. Available targets are:\n",664 __PRETTY_FUNCTION__, szAtomName));665 XFree(szAtomName);666 }667 else668 Log2(("%s: no supported host text target found. Available targets are:\n",669 __PRETTY_FUNCTION__));670 for (unsigned i = 0; i < cAtoms; ++i)671 {672 char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), atomTargets[i]);673 if (szAtomName != 0)674 {675 Log2 (("%s: %s\n", __PRETTY_FUNCTION__, szAtomName));676 XFree(szAtomName);677 }678 }679 }680 g_ctxX11.X11TextFormat = eBestTarget;681 if (eBestTarget != INVALID)682 u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;683 VBoxX11ClipboardReportX11Formats(g_ctxX11.pFrontend, u32Formats);684 g_ctxX11.notifyVBox = false;685 }686 XtFree(reinterpret_cast<char *>(pValue));687 }688 689 /**690 * This timer callback is called every 200ms to check the contents of the X11691 * clipboard.692 * @note X11 backend code, callback for XtAppAddTimeOut, recursively693 * re-armed.694 * @todo Use the XFIXES extension to check for new clipboard data when695 * available.696 */697 static void vboxClipboardPollX11ForTargets(XtPointer /* pUserData */, XtIntervalId * /* hTimerId */)698 {699 Log3 (("%s: called\n", __PRETTY_FUNCTION__));700 /* Get the current clipboard contents */701 if (g_ctxX11.eOwner == X11)702 {703 Log3 (("%s: requesting the targets that the host clipboard offers\n",704 __PRETTY_FUNCTION__));705 XtGetSelectionValue(g_ctxX11.widget, g_ctxX11.atomClipboard,706 g_ctxX11.atomTargets,707 vboxClipboardGetTargetsFromX11, NULL,708 CurrentTime);709 }710 /* Re-arm our timer */711 XtAppAddTimeOut(g_ctxX11.appContext, 200 /* ms */,712 vboxClipboardPollX11ForTargets, 0);713 }714 715 /** We store information about the target formats we can handle in a global716 * vector for internal use.717 * @note X11 backend code.718 */719 static void vboxClipboardAddFormat(const char *pszName, g_eClipboardFormats eFormat,720 unsigned guestFormat)721 {722 VBOXCLIPBOARDFORMAT sFormat;723 /* Get an atom from the X server for that target format */724 Atom atomFormat = XInternAtom(XtDisplay(g_ctxX11.widget), pszName, false);725 sFormat.atom = atomFormat;726 sFormat.format = eFormat;727 sFormat.guestFormat = guestFormat;728 g_ctxX11.formatList.push_back(sFormat);729 LogFlow (("vboxClipboardAddFormat: added format %s (%d)\n", pszName, eFormat));730 }731 732 /**733 * The main loop of our clipboard reader.734 * @note X11 backend code.735 */736 static int vboxClipboardThread(RTTHREAD self, void * /* pvUser */)737 {738 LogRel(("Shared clipboard: starting host clipboard thread\n"));739 740 /* Set up a timer to poll the host clipboard */741 XtAppAddTimeOut(g_ctxX11.appContext, 200 /* ms */, vboxClipboardPollX11ForTargets, 0);742 743 XtAppMainLoop(g_ctxX11.appContext);744 g_ctxX11.formatList.clear();745 LogRel(("Shared clipboard: host clipboard thread terminated successfully\n"));746 return VINF_SUCCESS;747 }748 749 /** X11 specific initialisation for the shared clipboard.750 * @note X11 backend code.751 */752 int vboxClipboardInitX11 (void)753 {754 /* Create a window and make it a clipboard viewer. */755 int cArgc = 0;756 char *pcArgv = 0;757 int rc = VINF_SUCCESS;758 // static String szFallbackResources[] = { (char*)"*.width: 1", (char*)"*.height: 1", NULL };759 Display *pDisplay;760 761 /* Make sure we are thread safe */762 XtToolkitThreadInitialize();763 /* Set up the Clipbard application context and main window. We call all these functions764 directly instead of calling XtOpenApplication() so that we can fail gracefully if we765 can't get an X11 display. */766 XtToolkitInitialize();767 g_ctxX11.appContext = XtCreateApplicationContext();768 // XtAppSetFallbackResources(g_ctxX11.appContext, szFallbackResources);769 pDisplay = XtOpenDisplay(g_ctxX11.appContext, 0, 0, "VBoxClipboard", 0, 0, &cArgc, &pcArgv);770 if (NULL == pDisplay)771 {772 LogRel(("Shared clipboard: failed to connect to the host clipboard - the window system may not be running.\n"));773 rc = VERR_NOT_SUPPORTED;774 }775 if (RT_SUCCESS(rc))776 {777 g_ctxX11.widget = XtVaAppCreateShell(0, "VBoxClipboard", applicationShellWidgetClass, pDisplay,778 XtNwidth, 1, XtNheight, 1, NULL);779 if (NULL == g_ctxX11.widget)780 {781 LogRel(("Shared clipboard: failed to construct the X11 window for the host clipboard manager.\n"));782 rc = VERR_NO_MEMORY;783 }784 }785 if (RT_SUCCESS(rc))786 {787 XtSetMappedWhenManaged(g_ctxX11.widget, false);788 XtRealizeWidget(g_ctxX11.widget);789 790 /* Get hold of the atoms which we need */791 g_ctxX11.atomClipboard = XInternAtom(XtDisplay(g_ctxX11.widget), "CLIPBOARD", false /* only_if_exists */);792 g_ctxX11.atomPrimary = XInternAtom(XtDisplay(g_ctxX11.widget), "PRIMARY", false);793 g_ctxX11.atomTargets = XInternAtom(XtDisplay(g_ctxX11.widget), "TARGETS", false);794 g_ctxX11.atomMultiple = XInternAtom(XtDisplay(g_ctxX11.widget), "MULTIPLE", false);795 g_ctxX11.atomTimestamp = XInternAtom(XtDisplay(g_ctxX11.widget), "TIMESTAMP", false);796 g_ctxX11.atomUtf16 = XInternAtom(XtDisplay(g_ctxX11.widget),797 "text/plain;charset=ISO-10646-UCS-2", false);798 g_ctxX11.atomUtf8 = XInternAtom(XtDisplay(g_ctxX11.widget), "UTF_STRING", false);799 /* And build up the vector of supported formats */800 g_ctxX11.atomCText = XInternAtom(XtDisplay(g_ctxX11.widget), "COMPOUND_TEXT", false);801 /* And build up the vector of supported formats */802 if (!g_testUtf8 && !g_testCText)803 vboxClipboardAddFormat("text/plain;charset=ISO-10646-UCS-2", UTF16,804 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);805 if (!g_testUtf16 && !g_testCText)806 {807 vboxClipboardAddFormat("UTF8_STRING", UTF8,808 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);809 vboxClipboardAddFormat("text/plain;charset=UTF-8", UTF8,810 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);811 vboxClipboardAddFormat("text/plain;charset=utf-8", UTF8,812 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);813 vboxClipboardAddFormat("STRING", UTF8,814 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);815 vboxClipboardAddFormat("TEXT", UTF8,816 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);817 vboxClipboardAddFormat("text/plain", UTF8,818 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);819 }820 if (!g_testUtf16 && !g_testUtf8)821 vboxClipboardAddFormat("COMPOUND_TEXT", CTEXT,822 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);823 }824 return rc;825 }826 827 /**828 * Initialise the X11 backend of the shared clipboard.829 * @note X11 backend code830 */831 int vboxClipboardInitBackend (VBOXCLIPBOARDCONTEXT *pFrontend)832 {833 int rc;834 835 if (!RTEnvGet("DISPLAY"))836 {837 /*838 * If we don't find the DISPLAY environment variable we assume that we are not839 * connected to an X11 server. Don't actually try to do this then, just fail840 * silently and report success on every call. This is important for VBoxHeadless.841 */842 LogRelFunc(("X11 DISPLAY variable not set -- disabling shared clipboard\n"));843 g_fHaveX11 = false;844 return VINF_SUCCESS;845 }846 847 if (RTEnvGet("VBOX_CBTEST_UTF16"))848 {849 g_testUtf16 = true;850 LogRel(("Host clipboard: testing Utf16\n"));851 }852 else if (RTEnvGet("VBOX_CBTEST_UTF8"))853 {854 g_testUtf8 = true;855 LogRel(("Host clipboard: testing Utf8\n"));856 }857 else if (RTEnvGet("VBOX_CBTEST_CTEXT"))858 {859 g_testCText = true;860 LogRel(("Host clipboard: testing compound text\n"));861 }862 else if (RTEnvGet("VBOX_CBDEBUG"))863 {864 g_debugClipboard = true;865 LogRel(("Host clipboard: enabling additional debugging output\n"));866 }867 868 g_fHaveX11 = true;869 870 LogRel(("Initializing X11 clipboard backend\n"));871 g_ctxX11.pFrontend = pFrontend;872 RTSemEventCreate(&g_ctxX11.waitForData);873 rc = vboxClipboardInitX11();874 if (RT_SUCCESS(rc))875 {876 rc = RTThreadCreate(&g_ctxX11.thread, vboxClipboardThread, 0, 0,877 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");878 if (RT_FAILURE(rc))879 LogRel(("Failed to initialise the shared clipboard X11 backend.\n"));880 }881 if (RT_FAILURE(rc))882 RTSemEventDestroy(g_ctxX11.waitForData);883 return rc;884 155 } 885 156 … … 894 165 RTSemEventCreate(&g_ctxHost.waitForData); 895 166 RTSemMutexCreate(&g_ctxHost.clipboardMutex); 896 rc = vboxClipboardInitBackend(&g_ctxHost);167 rc = VBoxX11ClipboardInitX11(&g_ctxHost); 897 168 if (RT_FAILURE(rc)) 898 169 { … … 901 172 LogRel(("Failed to start the host shared clipboard service.\n")); 902 173 } 903 return rc;904 }905 906 /**907 * Terminate the shared clipboard X11 backend.908 * @note X11 backend code909 */910 int vboxClipboardDestroyBackend (void)911 {912 int rc, rcThread;913 unsigned count = 0;914 XEvent ev;915 916 /*917 * Immediately return if we are not connected to the host X server.918 */919 if (!g_fHaveX11)920 return VINF_SUCCESS;921 922 LogRelFunc(("shutting down the shared clipboard X11 backend\n"));923 924 /* Set the termination flag. This has been observed to block if it was set925 * during a request for clipboard data coming from X11, so only we do it926 * after releasing any such requests. */927 XtAppSetExitFlag(g_ctxX11.appContext);928 /* Wake up the event loop */929 memset(&ev, 0, sizeof(ev));930 ev.xclient.type = ClientMessage;931 ev.xclient.format = 8;932 XSendEvent(XtDisplay(g_ctxX11.widget), XtWindow(g_ctxX11.widget), false, 0, &ev);933 XFlush(XtDisplay(g_ctxX11.widget));934 do935 {936 rc = RTThreadWait(g_ctxX11.thread, 1000, &rcThread);937 ++count;938 Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5)));939 } while ((VERR_TIMEOUT == rc) && (count < 300));940 if (RT_SUCCESS(rc))941 {942 /* We can safely destroy this now, as only this thread ever waits943 * for it. */944 RTSemEventDestroy(g_ctxX11.waitForData);945 AssertRC(rcThread);946 }947 else948 LogRel(("vboxClipboardDestroy: rc=%Rrc\n", rc));949 XtCloseDisplay(XtDisplay(g_ctxX11.widget));950 LogFlowFunc(("returning %Rrc.\n", rc));951 174 return rc; 952 175 } … … 974 197 * even if we are not waiting. */ 975 198 RTSemEventSignal(g_ctxHost.waitForData); 976 rc = vboxClipboardDestroyBackend();199 rc = VBoxX11ClipboardTermX11(); 977 200 if (RT_SUCCESS(rc)) 978 201 { … … 984 207 RTSemMutexDestroy(g_ctxHost.clipboardMutex); 985 208 } 986 }987 988 /**989 * Announce to the X11 backend that we are ready to start.990 * @param owner who is the initial clipboard owner991 */992 int vboxClipboardConnectBackend (enum g_eOwner owner)993 {994 LogFlowFunc(("\n"));995 /*996 * Immediately return if we are not connected to the host X server.997 */998 if (!g_fHaveX11)999 return VINF_SUCCESS;1000 1001 g_ctxX11.eOwner = owner;1002 if (owner == X11)1003 g_ctxX11.notifyVBox = true;1004 else1005 {1006 /** @todo Check whether the guest gets a format announcement at1007 * startup. */1008 vboxClipboardFormatAnnounceBackend(0);1009 }1010 return VINF_SUCCESS;1011 209 } 1012 210 … … 1027 225 /** The pClient pointer is a dummy anyway, as we only support a single 1028 226 * client at a time. */ 1029 rc = vboxClipboardConnectBackend(X11 /* initial owner */);227 rc = VBoxX11ClipboardStartX11(X11 /* initial owner */); 1030 228 return rc; 1031 }1032 1033 /**1034 * Called when the VBox may have fallen out of sync with the backend.1035 * @note X11 backend code1036 */1037 void vboxClipboardRequestSync (void)1038 {1039 /*1040 * Immediately return if we are not connected to the host X server.1041 */1042 if (!g_fHaveX11)1043 return;1044 g_ctxX11.notifyVBox = true;1045 229 } 1046 230 … … 1062 246 vboxSvcClipboardReportMsg (g_ctxHost.pClient, 1063 247 VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, 0); 1064 vboxClipboardRequestSync();248 VBoxX11ClipboardRequestSyncX11(); 1065 249 1066 250 return VINF_SUCCESS; 1067 }1068 1069 /**1070 * Shut down the shared clipboard X11 backend.1071 * @note X11 backend code1072 */1073 void vboxClipboardDisconnectBackend (void)1074 {1075 /*1076 * Immediately return if we are not connected to the host X server.1077 */1078 if (!g_fHaveX11)1079 return;1080 1081 g_ctxX11.eOwner = NONE;1082 g_ctxX11.X11TextFormat = INVALID;1083 g_ctxX11.X11BitmapFormat = INVALID;1084 251 } 1085 252 … … 1094 261 RTSemMutexRequest(g_ctxHost.clipboardMutex, RT_INDEFINITE_WAIT); 1095 262 g_ctxHost.pClient = NULL; 1096 vboxClipboardDisconnectBackend();263 VBoxX11ClipboardStopX11(); 1097 264 RTSemMutexRelease(g_ctxHost.clipboardMutex); 1098 }1099 1100 /**1101 * Satisfy a request from X11 for clipboard targets supported by VBox.1102 *1103 * @returns true if we successfully convert the data to the format1104 * requested, false otherwise.1105 *1106 * @param atomTypeReturn The type of the data we are returning1107 * @param pValReturn A pointer to the data we are returning. This1108 * should be set to memory allocated by XtMalloc,1109 * which will be freed later by the Xt toolkit.1110 * @param pcLenReturn The length of the data we are returning1111 * @param piFormatReturn The format (8bit, 16bit, 32bit) of the data we are1112 * returning1113 * @note X11 backend code, called by the XtOwnSelection callback.1114 */1115 static Boolean vboxClipboardConvertTargetsForX11(Atom *atomTypeReturn,1116 XtPointer *pValReturn,1117 unsigned long *pcLenReturn,1118 int *piFormatReturn)1119 {1120 unsigned uListSize = g_ctxX11.formatList.size();1121 Atom *atomTargets = reinterpret_cast<Atom *>(XtMalloc((uListSize + 3) * sizeof(Atom)));1122 unsigned cTargets = 0;1123 1124 LogFlowFunc (("called\n"));1125 for (unsigned i = 0; i < uListSize; ++i)1126 {1127 if ( ((g_ctxX11.vboxFormats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) != 0)1128 && (g_ctxX11.formatList[i].guestFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT))1129 {1130 atomTargets[cTargets] = g_ctxX11.formatList[i].atom;1131 ++cTargets;1132 }1133 }1134 atomTargets[cTargets] = g_ctxX11.atomTargets;1135 atomTargets[cTargets + 1] = g_ctxX11.atomMultiple;1136 atomTargets[cTargets + 2] = g_ctxX11.atomTimestamp;1137 if (g_debugClipboard)1138 {1139 for (unsigned i = 0; i < cTargets + 3; i++)1140 {1141 char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), atomTargets[i]);1142 if (szAtomName != 0)1143 {1144 Log2 (("%s: returning target %s\n", __PRETTY_FUNCTION__,1145 szAtomName));1146 XFree(szAtomName);1147 }1148 else1149 {1150 Log(("%s: invalid atom %d in the list!\n", __PRETTY_FUNCTION__,1151 atomTargets[i]));1152 }1153 }1154 }1155 *atomTypeReturn = XA_ATOM;1156 *pValReturn = reinterpret_cast<XtPointer>(atomTargets);1157 *pcLenReturn = cTargets + 3;1158 *piFormatReturn = 32;1159 return true;1160 }1161 1162 /**1163 * Satisfy a request from X11 to convert the clipboard text to Utf16. We1164 * return non-zero terminated text.1165 * @todo that works, but it is bad. Change it to return zero-terminated1166 * text.1167 *1168 * @returns true if we successfully convert the data to the format1169 * requested, false otherwise.1170 *1171 * @param atomTypeReturn Where to store the atom for the type of the data1172 * we are returning1173 * @param pValReturn Where to store the pointer to the data we are1174 * returning. This should be to memory allocated by1175 * XtMalloc, which will be freed by the Xt toolkit1176 * later.1177 * @param pcLenReturn Where to store the length of the data we are1178 * returning1179 * @param piFormatReturn Where to store the bit width (8, 16, 32) of the1180 * data we are returning1181 * @note X11 backend code, called by the callback for XtOwnSelection.1182 */1183 static Boolean vboxClipboardConvertUtf16(Atom *atomTypeReturn,1184 XtPointer *pValReturn,1185 unsigned long *pcLenReturn,1186 int *piFormatReturn)1187 {1188 PRTUTF16 pu16SrcText, pu16DestText;1189 void *pvVBox;1190 uint32_t cbVBox;1191 size_t cwSrcLen, cwDestLen;1192 int rc;1193 1194 LogFlowFunc (("called\n"));1195 rc = vboxClipboardReadDataFromVBox(g_ctxX11.pFrontend, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &pvVBox, &cbVBox);1196 if ((RT_FAILURE(rc)) || (cbVBox == 0))1197 {1198 /* If vboxClipboardReadDataFromVBox fails then pClient may be invalid */1199 LogRelFunc (("vboxClipboardReadDataFromVBox returned %Rrc%s\n", rc,1200 RT_SUCCESS(rc) ? ", cbVBox == 0" : ""));1201 RTMemFree(pvVBox);1202 return false;1203 }1204 pu16SrcText = reinterpret_cast<PRTUTF16>(pvVBox);1205 cwSrcLen = cbVBox / 2;1206 /* How long will the converted text be? */1207 rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen);1208 if (RT_FAILURE(rc))1209 {1210 LogRel(("vboxClipboardConvertUtf16: clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));1211 RTMemFree(pvVBox);1212 AssertRCReturn(rc, false);1213 }1214 if (cwDestLen == 0)1215 {1216 LogFlowFunc(("received empty clipboard data from the guest, returning false.\n"));1217 RTMemFree(pvVBox);1218 return false;1219 }1220 pu16DestText = reinterpret_cast<PRTUTF16>(XtMalloc(cwDestLen * 2));1221 if (pu16DestText == 0)1222 {1223 LogRel(("vboxClipboardConvertUtf16: failed to allocate %d bytes\n", cwDestLen * 2));1224 RTMemFree(pvVBox);1225 return false;1226 }1227 /* Convert the text. */1228 rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen);1229 if (RT_FAILURE(rc))1230 {1231 LogRel(("vboxClipboardConvertUtf16: clipboard conversion failed. vboxClipboardUtf16WinToLin returned %Rrc. Abandoning.\n", rc));1232 XtFree(reinterpret_cast<char *>(pu16DestText));1233 RTMemFree(pvVBox);1234 return false;1235 }1236 LogFlowFunc (("converted string is %.*ls. Returning.\n", cwDestLen, pu16DestText));1237 RTMemFree(pvVBox);1238 *atomTypeReturn = g_ctxX11.atomUtf16;1239 *pValReturn = reinterpret_cast<XtPointer>(pu16DestText);1240 *pcLenReturn = cwDestLen;1241 *piFormatReturn = 16;1242 return true;1243 }1244 1245 /**1246 * Satisfy a request from X11 to convert the clipboard text to Utf8. We1247 * return non-zero terminated text.1248 * @todo that works, but it is bad. Change it to return zero-terminated1249 * text.1250 *1251 * @returns true if we successfully convert the data to the format1252 * requested, false otherwise.1253 *1254 * @param atomTypeReturn Where to store the atom for the type of the data1255 * we are returning1256 * @param pValReturn Where to store the pointer to the data we are1257 * returning. This should be to memory allocated by1258 * XtMalloc, which will be freed by the Xt toolkit1259 * later.1260 * @param pcLenReturn Where to store the length of the data we are1261 * returning1262 * @param piFormatReturn Where to store the bit width (8, 16, 32) of the1263 * data we are returning1264 * @note X11 backend code, called by the callback for XtOwnSelection.1265 */1266 static Boolean vboxClipboardConvertToUtf8ForX11(Atom *atomTypeReturn,1267 XtPointer *pValReturn,1268 unsigned long *pcLenReturn,1269 int *piFormatReturn)1270 {1271 PRTUTF16 pu16SrcText, pu16DestText;1272 char *pu8DestText;1273 void *pvVBox;1274 uint32_t cbVBox;1275 size_t cwSrcLen, cwDestLen, cbDestLen;1276 int rc;1277 1278 LogFlowFunc (("called\n"));1279 /* Read the clipboard data from the guest. */1280 rc = vboxClipboardReadDataFromVBox(g_ctxX11.pFrontend, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &pvVBox, &cbVBox);1281 if ((rc != VINF_SUCCESS) || (cbVBox == 0))1282 {1283 /* If vboxClipboardReadDataFromVBox fails then pClient may be invalid */1284 LogRelFunc (("vboxClipboardReadDataFromVBox returned %Rrc%s\n", rc,1285 RT_SUCCESS(rc) ? ", cbVBox == 0" : ""));1286 RTMemFree(pvVBox);1287 return false;1288 }1289 pu16SrcText = reinterpret_cast<PRTUTF16>(pvVBox);1290 cwSrcLen = cbVBox / 2;1291 /* How long will the converted text be? */1292 rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen);1293 if (RT_FAILURE(rc))1294 {1295 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));1296 RTMemFree(pvVBox);1297 AssertRCReturn(rc, false);1298 }1299 if (cwDestLen == 0)1300 {1301 LogFlowFunc(("received empty clipboard data from the guest, returning false.\n"));1302 RTMemFree(pvVBox);1303 return false;1304 }1305 pu16DestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwDestLen * 2));1306 if (pu16DestText == 0)1307 {1308 LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 2));1309 RTMemFree(pvVBox);1310 return false;1311 }1312 /* Convert the text. */1313 rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen);1314 if (RT_FAILURE(rc))1315 {1316 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc));1317 RTMemFree(reinterpret_cast<void *>(pu16DestText));1318 RTMemFree(pvVBox);1319 return false;1320 }1321 /* Allocate enough space, as RTUtf16ToUtf8Ex may fail if the1322 space is too tightly calculated. */1323 pu8DestText = XtMalloc(cwDestLen * 4);1324 if (pu8DestText == 0)1325 {1326 LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 4));1327 RTMemFree(reinterpret_cast<void *>(pu16DestText));1328 RTMemFree(pvVBox);1329 return false;1330 }1331 /* Convert the Utf16 string to Utf8. */1332 rc = RTUtf16ToUtf8Ex(pu16DestText + 1, cwDestLen - 1, &pu8DestText, cwDestLen * 4,1333 &cbDestLen);1334 RTMemFree(reinterpret_cast<void *>(pu16DestText));1335 if (RT_FAILURE(rc))1336 {1337 LogRelFunc (("clipboard conversion failed. RTUtf16ToUtf8Ex() returned %Rrc. Abandoning.\n", rc));1338 XtFree(pu8DestText);1339 RTMemFree(pvVBox);1340 return false;1341 }1342 LogFlowFunc (("converted string is %.*s. Returning.\n", cbDestLen, pu8DestText));1343 RTMemFree(pvVBox);1344 *atomTypeReturn = g_ctxX11.atomUtf8;1345 *pValReturn = reinterpret_cast<XtPointer>(pu8DestText);1346 *pcLenReturn = cbDestLen;1347 *piFormatReturn = 8;1348 return true;1349 }1350 1351 /**1352 * Satisfy a request from X11 to convert the clipboard text to1353 * COMPOUND_TEXT. We return non-zero terminated text.1354 * @todo that works, but it is bad. Change it to return zero-terminated1355 * text.1356 *1357 * @returns true if we successfully convert the data to the format1358 * requested, false otherwise.1359 *1360 * @param atomTypeReturn Where to store the atom for the type of the data1361 * we are returning1362 * @param pValReturn Where to store the pointer to the data we are1363 * returning. This should be to memory allocated by1364 * XtMalloc, which will be freed by the Xt toolkit1365 * later.1366 * @param pcLenReturn Where to store the length of the data we are1367 * returning1368 * @param piFormatReturn Where to store the bit width (8, 16, 32) of the1369 * data we are returning1370 * @note X11 backend code, called by the callback for XtOwnSelection.1371 */1372 static Boolean vboxClipboardConvertToCTextForX11(Atom *atomTypeReturn,1373 XtPointer *pValReturn,1374 unsigned long *pcLenReturn,1375 int *piFormatReturn)1376 {1377 PRTUTF16 pu16SrcText, pu16DestText;1378 void *pvVBox;1379 uint32_t cbVBox;1380 char *pu8DestText = 0;1381 size_t cwSrcLen, cwDestLen, cbDestLen;1382 XTextProperty property;1383 int rc;1384 1385 LogFlowFunc (("called\n"));1386 /* Read the clipboard data from the guest. */1387 rc = vboxClipboardReadDataFromVBox(g_ctxX11.pFrontend, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &pvVBox, &cbVBox);1388 if ((rc != VINF_SUCCESS) || (cbVBox == 0))1389 {1390 /* If vboxClipboardReadDataFromVBox fails then pClient may be invalid */1391 LogRelFunc (("vboxClipboardReadDataFromVBox returned %Rrc%s\n", rc,1392 RT_SUCCESS(rc) ? ", cbVBox == 0" : ""));1393 RTMemFree(pvVBox);1394 return false;1395 }1396 pu16SrcText = reinterpret_cast<PRTUTF16>(pvVBox);1397 cwSrcLen = cbVBox / 2;1398 /* How long will the converted text be? */1399 rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen);1400 if (RT_FAILURE(rc))1401 {1402 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));1403 RTMemFree(pvVBox);1404 AssertRCReturn(rc, false);1405 }1406 if (cwDestLen == 0)1407 {1408 LogFlowFunc(("received empty clipboard data from the guest, returning false.\n"));1409 RTMemFree(pvVBox);1410 return false;1411 }1412 pu16DestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwDestLen * 2));1413 if (pu16DestText == 0)1414 {1415 LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 2));1416 RTMemFree(pvVBox);1417 return false;1418 }1419 /* Convert the text. */1420 rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen);1421 if (RT_FAILURE(rc))1422 {1423 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc));1424 RTMemFree(reinterpret_cast<void *>(pu16DestText));1425 RTMemFree(pvVBox);1426 return false;1427 }1428 /* Convert the Utf16 string to Utf8. */1429 rc = RTUtf16ToUtf8Ex(pu16DestText + 1, cwDestLen - 1, &pu8DestText, 0, &cbDestLen);1430 RTMemFree(reinterpret_cast<void *>(pu16DestText));1431 if (RT_FAILURE(rc))1432 {1433 LogRelFunc (("clipboard conversion failed. RTUtf16ToUtf8Ex() returned %Rrc. Abandoning.\n", rc));1434 RTMemFree(pvVBox);1435 return false;1436 }1437 /* And finally (!) convert the Utf8 text to compound text. */1438 #ifdef RT_OS_SOLARIS1439 rc = XmbTextListToTextProperty(XtDisplay(g_ctxX11.widget), &pu8DestText, 1,1440 XCompoundTextStyle, &property);1441 #else1442 rc = Xutf8TextListToTextProperty(XtDisplay(g_ctxX11.widget), &pu8DestText, 1,1443 XCompoundTextStyle, &property);1444 #endif1445 RTMemFree(pu8DestText);1446 if (rc < 0)1447 {1448 const char *pcReason;1449 switch(rc)1450 {1451 case XNoMemory:1452 pcReason = "out of memory";1453 break;1454 case XLocaleNotSupported:1455 pcReason = "locale (Utf8) not supported";1456 break;1457 case XConverterNotFound:1458 pcReason = "converter not found";1459 break;1460 default:1461 pcReason = "unknown error";1462 }1463 LogRelFunc (("Xutf8TextListToTextProperty failed. Reason: %s\n",1464 pcReason));1465 RTMemFree(pvVBox);1466 return false;1467 }1468 LogFlowFunc (("converted string is %s. Returning.\n", property.value));1469 RTMemFree(pvVBox);1470 *atomTypeReturn = property.encoding;1471 *pValReturn = reinterpret_cast<XtPointer>(property.value);1472 *pcLenReturn = property.nitems;1473 *piFormatReturn = property.format;1474 return true;1475 }1476 1477 /**1478 * Return VBox's clipboard data for an X11 client.1479 * @note X11 backend code, callback for XtOwnSelection1480 */1481 static Boolean vboxClipboardConvertForX11(Widget, Atom *atomSelection,1482 Atom *atomTarget,1483 Atom *atomTypeReturn,1484 XtPointer *pValReturn,1485 unsigned long *pcLenReturn,1486 int *piFormatReturn)1487 {1488 g_eClipboardFormats eFormat = INVALID;1489 1490 LogFlowFunc(("\n"));1491 /* Drop requests that we receive too late. */1492 if (g_ctxX11.eOwner != VB)1493 return false;1494 if ( (*atomSelection != g_ctxX11.atomClipboard)1495 && (*atomSelection != g_ctxX11.atomPrimary)1496 )1497 {1498 LogFlowFunc(("rc = false\n"));1499 return false;1500 }1501 if (g_debugClipboard)1502 {1503 char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), *atomTarget);1504 if (szAtomName != 0)1505 {1506 Log2 (("%s: request for format %s\n", __PRETTY_FUNCTION__, szAtomName));1507 XFree(szAtomName);1508 }1509 else1510 {1511 LogFunc (("request for invalid target atom %d!\n", *atomTarget));1512 }1513 }1514 if (*atomTarget == g_ctxX11.atomTargets)1515 {1516 eFormat = TARGETS;1517 }1518 else1519 {1520 for (unsigned i = 0; i != g_ctxX11.formatList.size(); ++i)1521 {1522 if (g_ctxX11.formatList[i].atom == *atomTarget)1523 {1524 eFormat = g_ctxX11.formatList[i].format;1525 break;1526 }1527 }1528 }1529 switch (eFormat)1530 {1531 case TARGETS:1532 return vboxClipboardConvertTargetsForX11(atomTypeReturn, pValReturn,1533 pcLenReturn, piFormatReturn);1534 case UTF16:1535 return vboxClipboardConvertUtf16(atomTypeReturn, pValReturn, pcLenReturn,1536 piFormatReturn);1537 case UTF8:1538 return vboxClipboardConvertToUtf8ForX11(atomTypeReturn, pValReturn,1539 pcLenReturn, piFormatReturn);1540 case CTEXT:1541 return vboxClipboardConvertToCTextForX11(atomTypeReturn, pValReturn,1542 pcLenReturn, piFormatReturn);1543 default:1544 LogFunc (("bad format\n"));1545 return false;1546 }1547 }1548 1549 /**1550 * This is called by the X toolkit intrinsics to let us know that another1551 * X11 client has taken the clipboard. In this case we notify VBox that1552 * we want ownership of the clipboard.1553 * @note X11 backend code, callback for XtOwnSelection1554 */1555 static void vboxClipboardReturnToX11(Widget, Atom *)1556 {1557 LogFlowFunc (("called, giving VBox clipboard ownership\n"));1558 g_ctxX11.eOwner = X11;1559 g_ctxX11.notifyVBox = true;1560 }1561 1562 /**1563 * VBox is taking possession of the shared clipboard.1564 *1565 * @param u32Formats Clipboard formats the guest is offering1566 * @note X11 backend code1567 */1568 void vboxClipboardFormatAnnounceBackend (uint32_t u32Formats)1569 {1570 /*1571 * Immediately return if we are not connected to the host X server.1572 */1573 if (!g_fHaveX11)1574 return;1575 1576 g_ctxX11.vboxFormats = u32Formats;1577 LogFlowFunc (("u32Formats=%d\n", u32Formats));1578 if (u32Formats == 0)1579 {1580 /* This is just an automatism, not a genuine anouncement */1581 LogFlowFunc(("returning\n"));1582 return;1583 }1584 if (g_ctxX11.eOwner == VB)1585 {1586 /* We already own the clipboard, so no need to grab it, especially as that can lead1587 to races due to the asynchronous nature of the X11 clipboard. This event may also1588 have been sent out by the guest to invalidate the Windows clipboard cache. */1589 LogFlowFunc(("returning\n"));1590 return;1591 }1592 Log2 (("%s: giving the guest clipboard ownership\n", __PRETTY_FUNCTION__));1593 g_ctxX11.eOwner = VB;1594 g_ctxX11.X11TextFormat = INVALID;1595 g_ctxX11.X11BitmapFormat = INVALID;1596 if (XtOwnSelection(g_ctxX11.widget, g_ctxX11.atomClipboard, CurrentTime, vboxClipboardConvertForX11,1597 vboxClipboardReturnToX11, 0) != True)1598 {1599 Log2 (("%s: returning clipboard ownership to the host\n", __PRETTY_FUNCTION__));1600 /* We set this so that the guest gets notified when we take the clipboard, even if no1601 guest formats are found which we understand. */1602 g_ctxX11.notifyVBox = true;1603 g_ctxX11.eOwner = X11;1604 }1605 XtOwnSelection(g_ctxX11.widget, g_ctxX11.atomPrimary, CurrentTime, vboxClipboardConvertForX11,1606 NULL, 0);1607 LogFlowFunc(("returning\n"));1608 1609 265 } 1610 266 … … 1618 274 void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Formats) 1619 275 { 1620 vboxClipboardFormatAnnounceBackend (u32Formats); 1621 } 1622 1623 /** 1624 * Called when VBox wants to read the X11 clipboard. 1625 * 1626 * @param pClient Context information about the guest VM 1627 * @param u32Format The format that the guest would like to receive the data in 1628 * @param pv Where to write the data to 1629 * @param cb The size of the buffer to write the data to 1630 * @param pcbActual Where to write the actual size of the written data 1631 * @note X11 backend code 1632 */ 1633 int vboxClipboardReadDataBackend (uint32_t u32Format, 1634 VBOXCLIPBOARDREQUEST *pRequest) 1635 { 1636 /* 1637 * Immediately return if we are not connected to the host X server. 1638 */ 1639 if (!g_fHaveX11) 1640 { 1641 /* no data available */ 1642 *pRequest->pcbActual = 0; 1643 return VINF_SUCCESS; 1644 } 1645 1646 LogFlowFunc (("u32Format = %d, cb = %d\n", u32Format, pRequest->cb)); 1647 1648 /* 1649 * The guest wants to read data in the given format. 1650 */ 1651 if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) 1652 { 1653 if (g_ctxX11.X11TextFormat == INVALID) 1654 { 1655 /* No data available. */ 1656 *pRequest->pcbActual = 0; 1657 return VERR_NO_DATA; /* The guest thinks we have data and we don't */ 1658 } 1659 /* Initially set the size of the data read to zero in case we fail 1660 * somewhere. */ 1661 *pRequest->pcbActual = 0; 1662 /* Send out a request for the data to the current clipboard owner */ 1663 XtGetSelectionValue(g_ctxX11.widget, g_ctxX11.atomClipboard, 1664 g_ctxX11.atomX11TextFormat, 1665 vboxClipboardGetDataFromX11, 1666 reinterpret_cast<XtPointer>(pRequest), 1667 CurrentTime); 1668 /* When the data arrives, the vboxClipboardGetDataFromX11 callback will be called. The 1669 callback will signal the event semaphore when it has processed the data for us. */ 1670 1671 int rc = RTSemEventWait(g_ctxX11.waitForData, RT_INDEFINITE_WAIT); 1672 if (RT_FAILURE(rc)) 1673 return rc; 1674 } 1675 else 1676 { 1677 return VERR_NOT_IMPLEMENTED; 1678 } 1679 return VINF_SUCCESS; 276 VBoxX11ClipboardAnnounceVBoxFormat (u32Formats); 1680 277 } 1681 278 … … 1705 302 request.cb = cb; 1706 303 request.pcbActual = pcbActual; 1707 rc = vboxClipboardReadDataBackend(u32Format, &request);304 rc = VBoxX11ClipboardReadX11Data(u32Format, &request); 1708 305 g_ctxHost.waiter = NONE; 1709 306 return rc; … … 1721 318 void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient, void *pv, uint32_t cb, uint32_t u32Format) 1722 319 { 320 /* Assume that if this gets called at all then the X11 backend is running. */ 321 #if 0 1723 322 if (!g_fHaveX11) 1724 323 return; 324 #endif 1725 325 1726 326 LogFlowFunc (("called\n")); … … 1733 333 1734 334 /* Grab the mutex and check that X11 is still waiting for the data before 1735 * delivering it. See the explanation in vboxClipboardReadDataFromVBox. */335 * delivering it. See the explanation in VBoxX11ClipboardReadVBoxData. */ 1736 336 RTSemMutexRequest(g_ctxHost.clipboardMutex, RT_INDEFINITE_WAIT); 1737 337 if (g_ctxHost.waiter == X11 && cb > 0)
Note:
See TracChangeset
for help on using the changeset viewer.