Changeset 18612 in vbox
- Timestamp:
- Apr 1, 2009 6:08:01 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 45518
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp
r18596 r18612 2 2 * 3 3 * Shared Clipboard: 4 * Linux host.4 * X11 backend code. 5 5 */ 6 6 … … 24 24 #define LOG_GROUP LOG_GROUP_HGCM 25 25 26 #include <string.h> 27 28 #include <iprt/asm.h> /* For atomic operations */ 29 #include <iprt/assert.h> 26 #include <vector> 27 28 #ifdef RT_OS_SOLARIS 29 #include <tsol/label.h> 30 #endif 31 32 #include <X11/Xlib.h> 33 #include <X11/Xatom.h> 34 #include <X11/Intrinsic.h> 35 #include <X11/Shell.h> 36 #include <X11/Xproto.h> 37 #include <X11/StringDefs.h> 38 39 #include <iprt/env.h> 30 40 #include <iprt/mem.h> 31 41 #include <iprt/semaphore.h> 42 #include <iprt/thread.h> 32 43 33 44 #include <VBox/log.h> 34 45 35 46 #include <VBox/GuestHost/SharedClipboard.h> 47 #include <VBox/GuestHost/clipboard-helper.h> 36 48 #include <VBox/HostServices/VBoxClipboardSvc.h> 37 49 38 #include "VBoxClipboard.h" 39 40 /** Global context information used by the host glue for the X11 clipboard 41 * backend */ 42 struct _VBOXCLIPBOARDCONTEXT 43 { 50 /** Do we want to test Utf16 by disabling other text formats? */ 51 static bool g_testUtf16 = false; 52 /** Do we want to test Utf8 by disabling other text formats? */ 53 static bool g_testUtf8 = false; 54 /** Do we want to test compount text by disabling other text formats? */ 55 static bool g_testCText = false; 56 /** Are we currently debugging the clipboard code? */ 57 static bool g_debugClipboard = false; 58 59 /** The different clipboard formats which we support. */ 60 enum g_eClipboardFormats 61 { 62 INVALID = 0, 63 TARGETS, 64 CTEXT, 65 UTF8, 66 UTF16 67 }; 68 69 /** The X11 clipboard uses several names for the same format. This 70 * structure maps an X11 name to a format. */ 71 typedef struct { 72 Atom atom; 73 g_eClipboardFormats format; 74 unsigned guestFormat; 75 } VBOXCLIPBOARDFORMAT; 76 77 /** Global context information used by the X11 clipboard backend */ 78 struct _VBOXCLIPBOARDCONTEXTX11 79 { 80 /** Opaque data structure describing the front-end. */ 81 VBOXCLIPBOARDCONTEXT *pFrontend; 82 /** The X Toolkit application context structure */ 83 XtAppContext appContext; 84 85 /** We have a separate thread to wait for Window and Clipboard events */ 86 RTTHREAD thread; 87 /** The X Toolkit widget which we use as our clipboard client. It is never made visible. */ 88 Widget widget; 89 90 /** X11 atom refering to the clipboard: CLIPBOARD */ 91 Atom atomClipboard; 92 /** X11 atom refering to the selection: PRIMARY */ 93 Atom atomPrimary; 94 /** X11 atom refering to the clipboard targets: TARGETS */ 95 Atom atomTargets; 96 /** X11 atom refering to the clipboard multiple target: MULTIPLE */ 97 Atom atomMultiple; 98 /** X11 atom refering to the clipboard timestamp target: TIMESTAMP */ 99 Atom atomTimestamp; 100 /** X11 atom refering to the clipboard utf16 text format: text/plain;charset=ISO-10646-UCS-2 */ 101 Atom atomUtf16; 102 /** X11 atom refering to the clipboard utf8 text format: UTF8_STRING */ 103 Atom atomUtf8; 104 /** X11 atom refering to the clipboard compound text format: COMPOUND_TEXT */ 105 Atom atomCText; 106 107 /** A list of the X11 formats which we support, mapped to our identifier for them, in the 108 order we prefer to have them in. */ 109 std::vector<VBOXCLIPBOARDFORMAT> formatList; 110 111 /** Does VBox or X11 currently own the clipboard? */ 112 volatile enum g_eOwner eOwner; 113 114 /** What is the best text format X11 has to offer? INVALID for none. */ 115 g_eClipboardFormats X11TextFormat; 116 /** Atom corresponding to the X11 text format */ 117 Atom atomX11TextFormat; 118 /** What is the best bitmap format X11 has to offer? INVALID for none. */ 119 g_eClipboardFormats X11BitmapFormat; 120 /** Atom corresponding to the X11 Bitmap format */ 121 Atom atomX11BitmapFormat; 122 /** What formats does VBox have on offer? */ 123 int vboxFormats; 124 /** Windows hosts and guests cache the clipboard data they receive. 125 * Since we have no way of knowing whether their cache is still valid, 126 * we always send a "data changed" message after a successful transfer 127 * to invalidate it. */ 128 bool notifyVBox; 129 44 130 /** Since the clipboard data moves asynchronously, we use an event 45 131 * semaphore to wait for it. When a function issues a request for … … 47 133 * when the data arrives. */ 48 134 RTSEMEVENT waitForData; 49 /** Who (if anyone) is currently waiting for data? Used for sanity50 * checks when data arrives. */51 volatile uint32_t waiter;52 /** This mutex is grabbed during any critical operations on the clipboard53 * which might clash with others. */54 RTSEMMUTEX clipboardMutex;55 56 /** Pointer to the opaque X11 backend structure */57 VBOXCLIPBOARDCONTEXTX11 *pBackend;58 /** Pointer to the client data structure */59 VBOXCLIPBOARDCLIENTDATA *pClient;60 135 }; 61 136 62 137 /* Only one client is supported. There seems to be no need for more clients. 63 138 */ 64 static VBOXCLIPBOARDCONTEXT g_ctxHost; 65 66 /** 67 * Send a request to VBox to transfer the contents of its clipboard to X11. 68 * 69 * @param pCtx Pointer to the host clipboard structure 70 * @param u32Format The format in which the data should be transfered 71 * @param ppv On success and if pcb > 0, this will point to a buffer 72 * to be freed with RTMemFree containing the data read. 73 * @param pcb On success, this contains the number of bytes of data 74 * returned 75 * @note Host glue code. 76 */ 77 int VBoxX11ClipboardReadVBoxData (VBOXCLIPBOARDCONTEXT *pCtx, 78 uint32_t u32Format, void **ppv, 79 uint32_t *pcb) 80 { 81 volatile VBOXCLIPBOARDCLIENTDATA *pClient = pCtx->pClient; 82 83 LogFlowFunc(("u32Format=%02X\n", u32Format)); 84 if (pClient == NULL) 85 { 86 /* This can legitimately happen if we disconnect during a request for 87 * data from X11. */ 88 LogFunc(("host requested guest clipboard data after guest had disconnected.\n")); 89 VBoxX11ClipboardAnnounceVBoxFormat(pCtx->pBackend, 0); 90 pCtx->waiter = NONE; 91 return VERR_TIMEOUT; 92 } 93 /* Assert that no other transfer is in process (requests are serialised) 94 * and that the last transfer cleaned up properly. */ 95 AssertLogRelReturn( pClient->data.pv == NULL 96 && pClient->data.cb == 0 97 && pClient->data.u32Format == 0, 98 VERR_WRONG_ORDER 99 ); 100 /* No one else (X11 or VBox) should currently be waiting. The first because 101 * requests from X11 are serialised and the second because VBox previously 102 * grabbed the clipboard, so it should not be waiting for data from us. */ 103 AssertLogRelReturn (ASMAtomicCmpXchgU32(&pCtx->waiter, X11, NONE), VERR_DEADLOCK); 104 /* Request data from VBox */ 105 vboxSvcClipboardReportMsg(pCtx->pClient, 106 VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, 107 u32Format); 108 /* Which will signal us when it is ready. We use a timeout here because 109 * we can't be sure that the guest will behave correctly. */ 110 int rc = RTSemEventWait(pCtx->waitForData, CLIPBOARDTIMEOUT); 111 if (rc == VERR_TIMEOUT) 112 rc = VINF_SUCCESS; /* Timeout handling follows. */ 113 /* Now we have a potential race between the HGCM thread delivering the data 114 * and our setting waiter to NONE to say that we are no longer waiting for 115 * it. We solve this as follows: both of these operations are done under 116 * the clipboard mutex. The HGCM thread will only deliver the data if we 117 * are still waiting after it acquires the mutex. After we release the 118 * mutex, we finally do our check to see whether the data was delivered. */ 119 RTSemMutexRequest(g_ctxHost.clipboardMutex, RT_INDEFINITE_WAIT); 120 pCtx->waiter = NONE; 121 RTSemMutexRelease(g_ctxHost.clipboardMutex); 122 AssertLogRelRCSuccess(rc); 139 static VBOXCLIPBOARDCONTEXTX11 g_ctxX11; 140 141 /* Are we actually connected to the X server? */ 142 static bool g_fHaveX11; 143 144 /** 145 * Convert the UTF-16 text obtained from the X11 clipboard to UTF-16LE with 146 * Windows EOLs, place it in the buffer supplied and signal that data has 147 * arrived. 148 * 149 * @param pValue Source UTF-16 text 150 * @param cwSourceLen Length in 16-bit words of the source text 151 * @param pv Where to store the converted data 152 * @param cb Length in bytes of the buffer pointed to by cb 153 * @param pcbActual Where to store the size of the converted data 154 * @param pClient Pointer to the client context structure 155 * @note X11 backend code, called from the Xt callback when we wish to read 156 * the X11 clipboard. 157 */ 158 static void vboxClipboardGetUtf16(XtPointer pValue, unsigned cwSrcLen, 159 void *pv, unsigned cb, 160 uint32_t *pcbActual) 161 { 162 size_t cwDestLen; 163 PRTUTF16 pu16SrcText = reinterpret_cast<PRTUTF16>(pValue); 164 PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv); 165 166 LogFlowFunc (("converting Utf-16 to Utf-16LE. cwSrcLen=%d, cb=%d, pu16SrcText+1=%.*ls\n", 167 cwSrcLen, cb, cwSrcLen - 1, pu16SrcText + 1)); 168 *pcbActual = 0; /* Only set this to the right value on success. */ 169 /* How long will the converted text be? */ 170 int rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen); 171 if (RT_SUCCESS(rc) && (cb < cwDestLen * 2)) 172 { 173 /* Not enough buffer space provided - report the amount needed. */ 174 LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n", 175 cb, cwDestLen * 2)); 176 *pcbActual = cwDestLen * 2; 177 rc = VERR_BUFFER_OVERFLOW; 178 } 179 /* Convert the text. */ 180 if (RT_SUCCESS(rc)) 181 rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2); 182 if (RT_SUCCESS(rc)) 183 { 184 LogFlowFunc (("converted string is %.*ls\n", cwDestLen, pu16DestText)); 185 *pcbActual = cwDestLen * 2; 186 } 187 /* We need to do this whether we succeed or fail. */ 188 XtFree(reinterpret_cast<char *>(pValue)); 189 RTSemEventSignal(g_ctxX11.waitForData); 190 LogFlowFunc(("Returning. Status is %Rrc\n", rc)); 191 } 192 193 /** 194 * Convert the UTF-8 text obtained from the X11 clipboard to UTF-16LE with 195 * Windows EOLs, place it in the buffer supplied and signal that data has 196 * arrived. 197 * 198 * @param pValue Source UTF-8 text 199 * @param cbSourceLen Length in 8-bit bytes of the source text 200 * @param pv Where to store the converted data 201 * @param cb Length in bytes of the buffer pointed to by pv 202 * @param pcbActual Where to store the size of the converted data 203 * @param pClient Pointer to the client context structure 204 * @note X11 backend code, called from the Xt callback when we wish to read 205 * the X11 clipboard. 206 */ 207 static void vboxClipboardGetUtf8FromX11(XtPointer pValue, unsigned cbSrcLen, 208 void *pv, unsigned cb, 209 uint32_t *pcbActual) 210 { 211 size_t cwSrcLen, cwDestLen; 212 char *pu8SrcText = reinterpret_cast<char *>(pValue); 213 PRTUTF16 pu16SrcText = NULL; 214 PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv); 215 216 LogFlowFunc (("converting Utf-8 to Utf-16LE. cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n", 217 cbSrcLen, cb, cbSrcLen, pu8SrcText)); 218 *pcbActual = 0; /* Only set this to the right value on success. */ 219 /* First convert the UTF8 to UTF16 */ 220 int rc = RTStrToUtf16Ex(pu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen); 221 /* Check how much longer will the converted text will be. */ 222 if (RT_SUCCESS(rc)) 223 rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen); 224 if (RT_SUCCESS(rc) && (cb < cwDestLen * 2)) 225 { 226 /* Not enough buffer space provided - report the amount needed. */ 227 LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n", 228 cb, cwDestLen * 2)); 229 *pcbActual = cwDestLen * 2; 230 rc = VERR_BUFFER_OVERFLOW; 231 } 232 /* Convert the text. */ 233 if (RT_SUCCESS(rc)) 234 rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2); 235 if (RT_SUCCESS(rc)) 236 { 237 LogFlowFunc (("converted string is %.*ls.\n", cwDestLen, pu16DestText)); 238 *pcbActual = cwDestLen * 2; 239 } 240 XtFree(reinterpret_cast<char *>(pValue)); 241 RTUtf16Free(pu16SrcText); 242 RTSemEventSignal(g_ctxX11.waitForData); 243 LogFlowFunc(("Returning. Status is %Rrc", rc)); 244 } 245 246 /** 247 * Convert the COMPOUND_TEXT obtained from the X11 clipboard to UTF-16LE with 248 * Windows EOLs, place it in the buffer supplied and signal that data has 249 * arrived. 250 * 251 * @param pValue Source COMPOUND_TEXT 252 * @param cbSourceLen Length in 8-bit bytes of the source text 253 * @param pv Where to store the converted data 254 * @param cb Length in bytes of the buffer pointed to by pv 255 * @param pcbActual Where to store the size of the converted data 256 * @param pClient Pointer to the client context structure 257 * @note X11 backend code, called from the Xt callback when we wish to read 258 * the X11 clipboard. 259 */ 260 static void vboxClipboardGetCTextFromX11(XtPointer pValue, unsigned cbSrcLen, 261 void *pv, unsigned cb, 262 uint32_t *pcbActual) 263 { 264 size_t cwSrcLen, cwDestLen; 265 char **ppu8SrcText = NULL; 266 PRTUTF16 pu16SrcText = NULL; 267 PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv); 268 XTextProperty property; 269 int rc = VINF_SUCCESS; 270 int cProps; 271 272 LogFlowFunc (("converting COMPOUND TEXT to Utf-16LE. cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n", 273 cbSrcLen, cb, cbSrcLen, reinterpret_cast<char *>(pValue))); 274 *pcbActual = 0; /* Only set this to the right value on success. */ 275 /* First convert the compound text to Utf8 */ 276 property.value = reinterpret_cast<unsigned char *>(pValue); 277 property.encoding = g_ctxX11.atomCText; 278 property.format = 8; 279 property.nitems = cbSrcLen; 280 #ifdef RT_OS_SOLARIS 281 int xrc = XmbTextPropertyToTextList(XtDisplay(g_ctxX11.widget), &property, &ppu8SrcText, &cProps); 282 #else 283 int xrc = Xutf8TextPropertyToTextList(XtDisplay(g_ctxX11.widget), &property, &ppu8SrcText, &cProps); 284 #endif 285 XtFree(reinterpret_cast<char *>(pValue)); 286 if (xrc < 0) 287 switch(xrc) 288 { 289 case XNoMemory: 290 rc = VERR_NO_MEMORY; 291 break; 292 case XLocaleNotSupported: 293 case XConverterNotFound: 294 rc = VERR_NOT_SUPPORTED; 295 break; 296 default: 297 rc = VERR_UNRESOLVED_ERROR; 298 } 299 /* Now convert the UTF8 to UTF16 */ 300 if (RT_SUCCESS(rc)) 301 rc = RTStrToUtf16Ex(*ppu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen); 302 /* Check how much longer will the converted text will be. */ 303 if (RT_SUCCESS(rc)) 304 rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen); 305 if (RT_SUCCESS(rc) && (cb < cwDestLen * 2)) 306 { 307 /* Not enough buffer space provided - report the amount needed. */ 308 LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n", 309 cb, cwDestLen * 2)); 310 *pcbActual = cwDestLen * 2; 311 rc = VERR_BUFFER_OVERFLOW; 312 } 313 /* Convert the text. */ 314 if (RT_SUCCESS(rc)) 315 rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2); 316 if (RT_SUCCESS(rc)) 317 { 318 LogFlowFunc (("converted string is %.*ls\n", cwDestLen, pu16DestText)); 319 *pcbActual = cwDestLen * 2; 320 } 321 if (ppu8SrcText != NULL) 322 XFreeStringList(ppu8SrcText); 323 RTUtf16Free(pu16SrcText); 324 LogFlowFunc(("Returning. Status is %Rrc\n", rc)); 325 RTSemEventSignal(g_ctxX11.waitForData); 326 } 327 328 /** 329 * Convert the Latin1 text obtained from the X11 clipboard to UTF-16LE with 330 * Windows EOLs, place it in the buffer supplied and signal that data has 331 * arrived. 332 * 333 * @param pValue Source Latin1 text 334 * @param cbSourceLen Length in 8-bit bytes of the source text 335 * @param pv Where to store the converted data 336 * @param cb Length in bytes of the buffer pointed to by cb 337 * @param pcbActual Where to store the size of the converted data 338 * @param pClient Pointer to the client context structure 339 * @note X11 backend code, called from the Xt callback when we wish to read 340 * the X11 clipboard. 341 */ 342 static void vboxClipboardGetLatin1FromX11(XtPointer pValue, 343 unsigned cbSourceLen, void *pv, 344 unsigned cb, uint32_t *pcbActual) 345 { 346 unsigned cwDestLen = cbSourceLen + 1; 347 char *pu8SourceText = reinterpret_cast<char *>(pValue); 348 PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv); 349 int rc = VINF_SUCCESS; 350 351 LogFlowFunc (("converting Latin1 to Utf-16LE. Original is %.*s\n", 352 cbSourceLen, pu8SourceText)); 353 *pcbActual = 0; /* Only set this to the right value on success. */ 354 for (unsigned i = 0; i < cbSourceLen; i++) 355 if (pu8SourceText[i] == LINEFEED) 356 ++cwDestLen; 357 if (cb < cwDestLen * 2) 358 { 359 /* Not enough buffer space provided - report the amount needed. */ 360 LogFlowFunc (("guest buffer too small: size %d bytes\n", cb)); 361 *pcbActual = cwDestLen * 2; 362 rc = VERR_BUFFER_OVERFLOW; 363 } 364 if (RT_SUCCESS(rc)) 365 { 366 for (unsigned i = 0, j = 0; i < cbSourceLen; ++i, ++j) 367 if (pu8SourceText[i] != LINEFEED) 368 pu16DestText[j] = pu8SourceText[i]; /* latin1 < utf-16LE */ 369 else 370 { 371 pu16DestText[j] = CARRIAGERETURN; 372 ++j; 373 pu16DestText[j] = LINEFEED; 374 } 375 pu16DestText[cwDestLen - 1] = 0; 376 *pcbActual = cwDestLen * 2; 377 LogFlowFunc (("converted text is %.*ls\n", cwDestLen, pu16DestText)); 378 } 379 XtFree(reinterpret_cast<char *>(pValue)); 380 RTSemEventSignal(g_ctxX11.waitForData); 381 LogFlowFunc(("Returning. Status is %Rrc\n", rc)); 382 } 383 384 /** 385 * Convert the text obtained from the X11 clipboard to UTF-16LE with Windows 386 * EOLs, place it in the buffer supplied and signal that data has arrived. 387 * @note X11 backend code, callback for XtGetSelectionValue, for use when 388 * the X11 clipboard contains a text format we understand. 389 */ 390 static void vboxClipboardGetDataFromX11(Widget, XtPointer pClientData, 391 Atom * /* selection */, 392 Atom *atomType, 393 XtPointer pValue, 394 long unsigned int *pcLen, 395 int *piFormat) 396 { 397 VBOXCLIPBOARDREQUEST *pRequest 398 = reinterpret_cast<VBOXCLIPBOARDREQUEST *>(pClientData); 399 LogFlowFunc(("pClientData=%p, *pcLen=%lu, *piFormat=%d\n", pClientData, 400 *pcLen, *piFormat)); 401 LogFlowFunc(("g_ctxX11.X11TextFormat=%d, pRequest->cb=%d\n", 402 g_ctxX11.X11TextFormat, pRequest->cb)); 403 unsigned cTextLen = (*pcLen) * (*piFormat) / 8; 404 /* The X Toolkit may have failed to get the clipboard selection for us. */ 405 if (*atomType == XT_CONVERT_FAIL) 406 return; 407 /* The clipboard selection may have changed before we could get it. */ 408 if (NULL == pValue) 409 return; 410 /* In which format is the clipboard data? */ 411 switch (g_ctxX11.X11TextFormat) 412 { 413 case UTF16: 414 vboxClipboardGetUtf16(pValue, cTextLen / 2, pRequest->pv, 415 pRequest->cb, pRequest->pcbActual); 416 break; 417 case CTEXT: 418 vboxClipboardGetCTextFromX11(pValue, cTextLen, pRequest->pv, 419 pRequest->cb, pRequest->pcbActual); 420 break; 421 case UTF8: 422 { 423 /* If we are given broken Utf-8, we treat it as Latin1. Is this acceptable? */ 424 size_t cStringLen; 425 char *pu8SourceText = reinterpret_cast<char *>(pValue); 426 427 if ((g_ctxX11.X11TextFormat == UTF8) 428 && (RTStrUniLenEx(pu8SourceText, *pcLen, &cStringLen) == VINF_SUCCESS)) 429 { 430 vboxClipboardGetUtf8FromX11(pValue, cTextLen, pRequest->pv, 431 pRequest->cb, pRequest->pcbActual); 432 break; 433 } 434 else 435 { 436 vboxClipboardGetLatin1FromX11(pValue, cTextLen, pRequest->pv, 437 pRequest->cb, pRequest->pcbActual); 438 break; 439 } 440 } 441 default: 442 LogFunc (("bad target format\n")); 443 XtFree(reinterpret_cast<char *>(pValue)); 444 return; 445 } 446 g_ctxX11.notifyVBox = true; 447 } 448 449 /** 450 * Notify the host clipboard about the data formats we support, based on the 451 * "targets" (available data formats) information obtained from the X11 452 * clipboard. 453 * @note X11 backend code, callback for XtGetSelectionValue, called when we 454 * poll for available targets. 455 */ 456 static void vboxClipboardGetTargetsFromX11(Widget, 457 XtPointer /* pClientData */, 458 Atom * /* selection */, 459 Atom *atomType, 460 XtPointer pValue, 461 long unsigned int *pcLen, 462 int *piFormat) 463 { 464 Atom *atomTargets = reinterpret_cast<Atom *>(pValue); 465 unsigned cAtoms = *pcLen; 466 g_eClipboardFormats eBestTarget = INVALID; 467 Atom atomBestTarget = None; 468 469 Log3 (("%s: called\n", __PRETTY_FUNCTION__)); 470 if (*atomType == XT_CONVERT_FAIL) 471 { 472 LogFunc (("reading clipboard from host, X toolkit failed to convert the selection\n")); 473 return; 474 } 475 476 for (unsigned i = 0; i < cAtoms; ++i) 477 { 478 for (unsigned j = 0; j != g_ctxX11.formatList.size(); ++j) 479 if (g_ctxX11.formatList[j].atom == atomTargets[i]) 480 { 481 if (eBestTarget < g_ctxX11.formatList[j].format) 482 { 483 eBestTarget = g_ctxX11.formatList[j].format; 484 atomBestTarget = g_ctxX11.formatList[j].atom; 485 } 486 break; 487 } 488 if (g_debugClipboard) 489 { 490 char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), atomTargets[i]); 491 if (szAtomName != 0) 492 { 493 Log2 (("%s: the host offers target %s\n", __PRETTY_FUNCTION__, 494 szAtomName)); 495 XFree(szAtomName); 496 } 497 } 498 } 499 g_ctxX11.atomX11TextFormat = atomBestTarget; 500 if ((eBestTarget != g_ctxX11.X11TextFormat) || (g_ctxX11.notifyVBox == true)) 501 { 502 uint32_t u32Formats = 0; 503 if (g_debugClipboard) 504 { 505 if (atomBestTarget != None) 506 { 507 char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), atomBestTarget); 508 Log2 (("%s: switching to host text target %s. Available targets are:\n", 509 __PRETTY_FUNCTION__, szAtomName)); 510 XFree(szAtomName); 511 } 512 else 513 Log2(("%s: no supported host text target found. Available targets are:\n", 514 __PRETTY_FUNCTION__)); 515 for (unsigned i = 0; i < cAtoms; ++i) 516 { 517 char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), atomTargets[i]); 518 if (szAtomName != 0) 519 { 520 Log2 (("%s: %s\n", __PRETTY_FUNCTION__, szAtomName)); 521 XFree(szAtomName); 522 } 523 } 524 } 525 g_ctxX11.X11TextFormat = eBestTarget; 526 if (eBestTarget != INVALID) 527 u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT; 528 VBoxX11ClipboardReportX11Formats(g_ctxX11.pFrontend, u32Formats); 529 g_ctxX11.notifyVBox = false; 530 } 531 XtFree(reinterpret_cast<char *>(pValue)); 532 } 533 534 /** 535 * This timer callback is called every 200ms to check the contents of the X11 536 * clipboard. 537 * @note X11 backend code, callback for XtAppAddTimeOut, recursively 538 * re-armed. 539 * @todo Use the XFIXES extension to check for new clipboard data when 540 * available. 541 */ 542 static void vboxClipboardPollX11ForTargets(XtPointer /* pUserData */, XtIntervalId * /* hTimerId */) 543 { 544 Log3 (("%s: called\n", __PRETTY_FUNCTION__)); 545 /* Get the current clipboard contents */ 546 if (g_ctxX11.eOwner == X11) 547 { 548 Log3 (("%s: requesting the targets that the host clipboard offers\n", 549 __PRETTY_FUNCTION__)); 550 XtGetSelectionValue(g_ctxX11.widget, g_ctxX11.atomClipboard, 551 g_ctxX11.atomTargets, 552 vboxClipboardGetTargetsFromX11, NULL, 553 CurrentTime); 554 } 555 /* Re-arm our timer */ 556 XtAppAddTimeOut(g_ctxX11.appContext, 200 /* ms */, 557 vboxClipboardPollX11ForTargets, 0); 558 } 559 560 /** We store information about the target formats we can handle in a global 561 * vector for internal use. 562 * @note X11 backend code. 563 */ 564 static void vboxClipboardAddFormat(const char *pszName, g_eClipboardFormats eFormat, 565 unsigned guestFormat) 566 { 567 VBOXCLIPBOARDFORMAT sFormat; 568 /* Get an atom from the X server for that target format */ 569 Atom atomFormat = XInternAtom(XtDisplay(g_ctxX11.widget), pszName, false); 570 sFormat.atom = atomFormat; 571 sFormat.format = eFormat; 572 sFormat.guestFormat = guestFormat; 573 g_ctxX11.formatList.push_back(sFormat); 574 LogFlow (("vboxClipboardAddFormat: added format %s (%d)\n", pszName, eFormat)); 575 } 576 577 /** 578 * The main loop of our clipboard reader. 579 * @note X11 backend code. 580 */ 581 static int vboxClipboardThread(RTTHREAD self, void * /* pvUser */) 582 { 583 LogRel(("Shared clipboard: starting host clipboard thread\n")); 584 585 /* Set up a timer to poll the host clipboard */ 586 XtAppAddTimeOut(g_ctxX11.appContext, 200 /* ms */, vboxClipboardPollX11ForTargets, 0); 587 588 XtAppMainLoop(g_ctxX11.appContext); 589 g_ctxX11.formatList.clear(); 590 LogRel(("Shared clipboard: host clipboard thread terminated successfully\n")); 591 return VINF_SUCCESS; 592 } 593 594 /** X11 specific initialisation for the shared clipboard. 595 * @note X11 backend code. 596 */ 597 static int vboxClipboardInitX11 (void) 598 { 599 /* Create a window and make it a clipboard viewer. */ 600 int cArgc = 0; 601 char *pcArgv = 0; 602 int rc = VINF_SUCCESS; 603 // static String szFallbackResources[] = { (char*)"*.width: 1", (char*)"*.height: 1", NULL }; 604 Display *pDisplay; 605 606 /* Make sure we are thread safe */ 607 XtToolkitThreadInitialize(); 608 /* Set up the Clipbard application context and main window. We call all these functions 609 directly instead of calling XtOpenApplication() so that we can fail gracefully if we 610 can't get an X11 display. */ 611 XtToolkitInitialize(); 612 g_ctxX11.appContext = XtCreateApplicationContext(); 613 // XtAppSetFallbackResources(g_ctxX11.appContext, szFallbackResources); 614 pDisplay = XtOpenDisplay(g_ctxX11.appContext, 0, 0, "VBoxClipboard", 0, 0, &cArgc, &pcArgv); 615 if (NULL == pDisplay) 616 { 617 LogRel(("Shared clipboard: failed to connect to the host clipboard - the window system may not be running.\n")); 618 rc = VERR_NOT_SUPPORTED; 619 } 620 if (RT_SUCCESS(rc)) 621 { 622 g_ctxX11.widget = XtVaAppCreateShell(0, "VBoxClipboard", applicationShellWidgetClass, pDisplay, 623 XtNwidth, 1, XtNheight, 1, NULL); 624 if (NULL == g_ctxX11.widget) 625 { 626 LogRel(("Shared clipboard: failed to construct the X11 window for the host clipboard manager.\n")); 627 rc = VERR_NO_MEMORY; 628 } 629 } 630 if (RT_SUCCESS(rc)) 631 { 632 XtSetMappedWhenManaged(g_ctxX11.widget, false); 633 XtRealizeWidget(g_ctxX11.widget); 634 635 /* Get hold of the atoms which we need */ 636 g_ctxX11.atomClipboard = XInternAtom(XtDisplay(g_ctxX11.widget), "CLIPBOARD", false /* only_if_exists */); 637 g_ctxX11.atomPrimary = XInternAtom(XtDisplay(g_ctxX11.widget), "PRIMARY", false); 638 g_ctxX11.atomTargets = XInternAtom(XtDisplay(g_ctxX11.widget), "TARGETS", false); 639 g_ctxX11.atomMultiple = XInternAtom(XtDisplay(g_ctxX11.widget), "MULTIPLE", false); 640 g_ctxX11.atomTimestamp = XInternAtom(XtDisplay(g_ctxX11.widget), "TIMESTAMP", false); 641 g_ctxX11.atomUtf16 = XInternAtom(XtDisplay(g_ctxX11.widget), 642 "text/plain;charset=ISO-10646-UCS-2", false); 643 g_ctxX11.atomUtf8 = XInternAtom(XtDisplay(g_ctxX11.widget), "UTF_STRING", false); 644 /* And build up the vector of supported formats */ 645 g_ctxX11.atomCText = XInternAtom(XtDisplay(g_ctxX11.widget), "COMPOUND_TEXT", false); 646 /* And build up the vector of supported formats */ 647 if (!g_testUtf8 && !g_testCText) 648 vboxClipboardAddFormat("text/plain;charset=ISO-10646-UCS-2", UTF16, 649 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 650 if (!g_testUtf16 && !g_testCText) 651 { 652 vboxClipboardAddFormat("UTF8_STRING", UTF8, 653 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 654 vboxClipboardAddFormat("text/plain;charset=UTF-8", UTF8, 655 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 656 vboxClipboardAddFormat("text/plain;charset=utf-8", UTF8, 657 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 658 vboxClipboardAddFormat("STRING", UTF8, 659 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 660 vboxClipboardAddFormat("TEXT", UTF8, 661 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 662 vboxClipboardAddFormat("text/plain", UTF8, 663 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 664 } 665 if (!g_testUtf16 && !g_testUtf8) 666 vboxClipboardAddFormat("COMPOUND_TEXT", CTEXT, 667 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 668 } 669 return rc; 670 } 671 672 /** 673 * Initialise the X11 backend of the shared clipboard. 674 * @note X11 backend code 675 */ 676 int VBoxX11ClipboardInitX11(VBOXCLIPBOARDCONTEXT *pFrontend, 677 VBOXCLIPBOARDCONTEXTX11 **ppBackend) 678 { 679 int rc; 680 681 if (!RTEnvGet("DISPLAY")) 682 { 683 /* 684 * If we don't find the DISPLAY environment variable we assume that we are not 685 * connected to an X11 server. Don't actually try to do this then, just fail 686 * silently and report success on every call. This is important for VBoxHeadless. 687 */ 688 LogRelFunc(("X11 DISPLAY variable not set -- disabling shared clipboard\n")); 689 g_fHaveX11 = false; 690 return VINF_SUCCESS; 691 } 692 693 if (RTEnvGet("VBOX_CBTEST_UTF16")) 694 { 695 g_testUtf16 = true; 696 LogRel(("Host clipboard: testing Utf16\n")); 697 } 698 else if (RTEnvGet("VBOX_CBTEST_UTF8")) 699 { 700 g_testUtf8 = true; 701 LogRel(("Host clipboard: testing Utf8\n")); 702 } 703 else if (RTEnvGet("VBOX_CBTEST_CTEXT")) 704 { 705 g_testCText = true; 706 LogRel(("Host clipboard: testing compound text\n")); 707 } 708 else if (RTEnvGet("VBOX_CBDEBUG")) 709 { 710 g_debugClipboard = true; 711 LogRel(("Host clipboard: enabling additional debugging output\n")); 712 } 713 714 g_fHaveX11 = true; 715 716 LogRel(("Initializing X11 clipboard backend\n")); 717 g_ctxX11.pFrontend = pFrontend; 718 RTSemEventCreate(&g_ctxX11.waitForData); 719 rc = vboxClipboardInitX11(); 720 if (RT_SUCCESS(rc)) 721 { 722 rc = RTThreadCreate(&g_ctxX11.thread, vboxClipboardThread, 0, 0, 723 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP"); 724 if (RT_FAILURE(rc)) 725 LogRel(("Failed to initialise the shared clipboard X11 backend.\n")); 726 } 123 727 if (RT_FAILURE(rc)) 124 { 125 /* I believe this should not happen. Wait until the assertions arrive 126 * to prove the contrary. */ 127 RTMemFree(pClient->data.pv); 128 g_ctxHost.pClient->data.pv = 0; 129 g_ctxHost.pClient->data.cb = 0; 130 g_ctxHost.pClient->data.u32Format = 0; 131 vboxClipboardFormatAnnounce(NULL, 0); 132 return rc; 133 } 134 if (pClient->data.pv == NULL) 135 return VERR_TIMEOUT; 136 LogFlowFunc(("wait completed. Returning.\n")); 137 *ppv = pClient->data.pv; 138 *pcb = pClient->data.cb; 139 g_ctxHost.pClient->data.pv = 0; 140 g_ctxHost.pClient->data.cb = 0; 141 g_ctxHost.pClient->data.u32Format = 0; 728 RTSemEventDestroy(g_ctxX11.waitForData); 729 return rc; 730 } 731 732 /** 733 * Terminate the shared clipboard X11 backend. 734 * @note X11 backend code 735 */ 736 int VBoxX11ClipboardTermX11(VBOXCLIPBOARDCONTEXTX11 *pBackend) 737 { 738 int rc, rcThread; 739 unsigned count = 0; 740 XEvent ev; 741 742 /* 743 * Immediately return if we are not connected to the host X server. 744 */ 745 if (!g_fHaveX11) 746 return VINF_SUCCESS; 747 748 LogRelFunc(("shutting down the shared clipboard X11 backend\n")); 749 750 /* Set the termination flag. This has been observed to block if it was set 751 * during a request for clipboard data coming from X11, so only we do it 752 * after releasing any such requests. */ 753 XtAppSetExitFlag(g_ctxX11.appContext); 754 /* Wake up the event loop */ 755 memset(&ev, 0, sizeof(ev)); 756 ev.xclient.type = ClientMessage; 757 ev.xclient.format = 8; 758 XSendEvent(XtDisplay(g_ctxX11.widget), XtWindow(g_ctxX11.widget), false, 0, &ev); 759 XFlush(XtDisplay(g_ctxX11.widget)); 760 do 761 { 762 rc = RTThreadWait(g_ctxX11.thread, 1000, &rcThread); 763 ++count; 764 Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5))); 765 } while ((VERR_TIMEOUT == rc) && (count < 300)); 766 if (RT_SUCCESS(rc)) 767 { 768 /* We can safely destroy this now, as only this thread ever waits 769 * for it. */ 770 RTSemEventDestroy(g_ctxX11.waitForData); 771 AssertRC(rcThread); 772 } 773 else 774 LogRel(("vboxClipboardDestroy: rc=%Rrc\n", rc)); 775 XtCloseDisplay(XtDisplay(g_ctxX11.widget)); 776 LogFlowFunc(("returning %Rrc.\n", rc)); 777 return rc; 778 } 779 780 /** 781 * Announce to the X11 backend that we are ready to start. 782 * @param owner who is the initial clipboard owner 783 */ 784 int VBoxX11ClipboardStartX11(VBOXCLIPBOARDCONTEXTX11 *pBackend, 785 enum g_eOwner owner) 786 { 787 LogFlowFunc(("\n")); 788 /* 789 * Immediately return if we are not connected to the host X server. 790 */ 791 if (!g_fHaveX11) 792 return VINF_SUCCESS; 793 794 g_ctxX11.eOwner = owner; 795 if (owner == X11) 796 g_ctxX11.notifyVBox = true; 797 else 798 { 799 /** @todo Check whether the guest gets a format announcement at 800 * startup. */ 801 VBoxX11ClipboardAnnounceVBoxFormat(pBackend, 0); 802 } 142 803 return VINF_SUCCESS; 143 804 } 144 805 145 806 /** 146 * Report formats available in the X11 clipboard to VBox. 147 * @param pCtx Opaque context pointer for the glue code 148 * @param u32Formats The formats available 149 * @note Host glue code 150 */ 151 void VBoxX11ClipboardReportX11Formats(VBOXCLIPBOARDCONTEXT *pCtx, 152 uint32_t u32Formats) 153 { 154 vboxSvcClipboardReportMsg(pCtx->pClient, 155 VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, 156 u32Formats); 157 } 158 159 /** 160 * Initialise the host side of the shared clipboard. 161 * @note Host glue code 162 */ 163 int vboxClipboardInit (void) 164 { 165 int rc = VINF_SUCCESS; 166 VBOXCLIPBOARDCONTEXTX11 *pBackend = NULL; 167 168 LogRel(("Initializing host clipboard service\n")); 169 RTSemEventCreate(&g_ctxHost.waitForData); 170 RTSemMutexCreate(&g_ctxHost.clipboardMutex); 171 rc = VBoxX11ClipboardInitX11(&g_ctxHost, &pBackend); 807 * Called when the VBox may have fallen out of sync with the backend. 808 * @note X11 backend code 809 */ 810 void VBoxX11ClipboardRequestSyncX11(VBOXCLIPBOARDCONTEXTX11 *pBackend) 811 { 812 /* 813 * Immediately return if we are not connected to the host X server. 814 */ 815 if (!g_fHaveX11) 816 return; 817 g_ctxX11.notifyVBox = true; 818 } 819 820 /** 821 * Shut down the shared clipboard X11 backend. 822 * @note X11 backend code 823 */ 824 void VBoxX11ClipboardStopX11(VBOXCLIPBOARDCONTEXTX11 *pBackend) 825 { 826 /* 827 * Immediately return if we are not connected to the host X server. 828 */ 829 if (!g_fHaveX11) 830 return; 831 832 g_ctxX11.eOwner = NONE; 833 g_ctxX11.X11TextFormat = INVALID; 834 g_ctxX11.X11BitmapFormat = INVALID; 835 } 836 837 /** 838 * Satisfy a request from X11 for clipboard targets supported by VBox. 839 * 840 * @returns true if we successfully convert the data to the format 841 * requested, false otherwise. 842 * 843 * @param atomTypeReturn The type of the data we are returning 844 * @param pValReturn A pointer to the data we are returning. This 845 * should be set to memory allocated by XtMalloc, 846 * which will be freed later by the Xt toolkit. 847 * @param pcLenReturn The length of the data we are returning 848 * @param piFormatReturn The format (8bit, 16bit, 32bit) of the data we are 849 * returning 850 * @note X11 backend code, called by the XtOwnSelection callback. 851 */ 852 static Boolean vboxClipboardConvertTargetsForX11(Atom *atomTypeReturn, 853 XtPointer *pValReturn, 854 unsigned long *pcLenReturn, 855 int *piFormatReturn) 856 { 857 unsigned uListSize = g_ctxX11.formatList.size(); 858 Atom *atomTargets = reinterpret_cast<Atom *>(XtMalloc((uListSize + 3) * sizeof(Atom))); 859 unsigned cTargets = 0; 860 861 LogFlowFunc (("called\n")); 862 for (unsigned i = 0; i < uListSize; ++i) 863 { 864 if ( ((g_ctxX11.vboxFormats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) != 0) 865 && (g_ctxX11.formatList[i].guestFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)) 866 { 867 atomTargets[cTargets] = g_ctxX11.formatList[i].atom; 868 ++cTargets; 869 } 870 } 871 atomTargets[cTargets] = g_ctxX11.atomTargets; 872 atomTargets[cTargets + 1] = g_ctxX11.atomMultiple; 873 atomTargets[cTargets + 2] = g_ctxX11.atomTimestamp; 874 if (g_debugClipboard) 875 { 876 for (unsigned i = 0; i < cTargets + 3; i++) 877 { 878 char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), atomTargets[i]); 879 if (szAtomName != 0) 880 { 881 Log2 (("%s: returning target %s\n", __PRETTY_FUNCTION__, 882 szAtomName)); 883 XFree(szAtomName); 884 } 885 else 886 { 887 Log(("%s: invalid atom %d in the list!\n", __PRETTY_FUNCTION__, 888 atomTargets[i])); 889 } 890 } 891 } 892 *atomTypeReturn = XA_ATOM; 893 *pValReturn = reinterpret_cast<XtPointer>(atomTargets); 894 *pcLenReturn = cTargets + 3; 895 *piFormatReturn = 32; 896 return true; 897 } 898 899 /** 900 * Satisfy a request from X11 to convert the clipboard text to Utf16. We 901 * return non-zero terminated text. 902 * @todo that works, but it is bad. Change it to return zero-terminated 903 * text. 904 * 905 * @returns true if we successfully convert the data to the format 906 * requested, false otherwise. 907 * 908 * @param atomTypeReturn Where to store the atom for the type of the data 909 * we are returning 910 * @param pValReturn Where to store the pointer to the data we are 911 * returning. This should be to memory allocated by 912 * XtMalloc, which will be freed by the Xt toolkit 913 * later. 914 * @param pcLenReturn Where to store the length of the data we are 915 * returning 916 * @param piFormatReturn Where to store the bit width (8, 16, 32) of the 917 * data we are returning 918 * @note X11 backend code, called by the callback for XtOwnSelection. 919 */ 920 static Boolean vboxClipboardConvertUtf16(Atom *atomTypeReturn, 921 XtPointer *pValReturn, 922 unsigned long *pcLenReturn, 923 int *piFormatReturn) 924 { 925 PRTUTF16 pu16SrcText, pu16DestText; 926 void *pvVBox; 927 uint32_t cbVBox; 928 size_t cwSrcLen, cwDestLen; 929 int rc; 930 931 LogFlowFunc (("called\n")); 932 rc = VBoxX11ClipboardReadVBoxData(g_ctxX11.pFrontend, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &pvVBox, &cbVBox); 933 if ((RT_FAILURE(rc)) || (cbVBox == 0)) 934 { 935 /* If VBoxX11ClipboardReadVBoxData fails then pClient may be invalid */ 936 LogRelFunc (("VBoxX11ClipboardReadVBoxData returned %Rrc%s\n", rc, 937 RT_SUCCESS(rc) ? ", cbVBox == 0" : "")); 938 RTMemFree(pvVBox); 939 return false; 940 } 941 pu16SrcText = reinterpret_cast<PRTUTF16>(pvVBox); 942 cwSrcLen = cbVBox / 2; 943 /* How long will the converted text be? */ 944 rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen); 172 945 if (RT_FAILURE(rc)) 173 946 { 174 RTSemEventDestroy(g_ctxHost.waitForData); 175 RTSemMutexDestroy(g_ctxHost.clipboardMutex); 176 LogRel(("Failed to start the host shared clipboard service.\n")); 947 LogRel(("vboxClipboardConvertUtf16: clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc)); 948 RTMemFree(pvVBox); 949 AssertRCReturn(rc, false); 950 } 951 if (cwDestLen == 0) 952 { 953 LogFlowFunc(("received empty clipboard data from the guest, returning false.\n")); 954 RTMemFree(pvVBox); 955 return false; 956 } 957 pu16DestText = reinterpret_cast<PRTUTF16>(XtMalloc(cwDestLen * 2)); 958 if (pu16DestText == 0) 959 { 960 LogRel(("vboxClipboardConvertUtf16: failed to allocate %d bytes\n", cwDestLen * 2)); 961 RTMemFree(pvVBox); 962 return false; 963 } 964 /* Convert the text. */ 965 rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen); 966 if (RT_FAILURE(rc)) 967 { 968 LogRel(("vboxClipboardConvertUtf16: clipboard conversion failed. vboxClipboardUtf16WinToLin returned %Rrc. Abandoning.\n", rc)); 969 XtFree(reinterpret_cast<char *>(pu16DestText)); 970 RTMemFree(pvVBox); 971 return false; 972 } 973 LogFlowFunc (("converted string is %.*ls. Returning.\n", cwDestLen, pu16DestText)); 974 RTMemFree(pvVBox); 975 *atomTypeReturn = g_ctxX11.atomUtf16; 976 *pValReturn = reinterpret_cast<XtPointer>(pu16DestText); 977 *pcLenReturn = cwDestLen; 978 *piFormatReturn = 16; 979 return true; 980 } 981 982 /** 983 * Satisfy a request from X11 to convert the clipboard text to Utf8. We 984 * return non-zero terminated text. 985 * @todo that works, but it is bad. Change it to return zero-terminated 986 * text. 987 * 988 * @returns true if we successfully convert the data to the format 989 * requested, false otherwise. 990 * 991 * @param atomTypeReturn Where to store the atom for the type of the data 992 * we are returning 993 * @param pValReturn Where to store the pointer to the data we are 994 * returning. This should be to memory allocated by 995 * XtMalloc, which will be freed by the Xt toolkit 996 * later. 997 * @param pcLenReturn Where to store the length of the data we are 998 * returning 999 * @param piFormatReturn Where to store the bit width (8, 16, 32) of the 1000 * data we are returning 1001 * @note X11 backend code, called by the callback for XtOwnSelection. 1002 */ 1003 static Boolean vboxClipboardConvertToUtf8ForX11(Atom *atomTypeReturn, 1004 XtPointer *pValReturn, 1005 unsigned long *pcLenReturn, 1006 int *piFormatReturn) 1007 { 1008 PRTUTF16 pu16SrcText, pu16DestText; 1009 char *pu8DestText; 1010 void *pvVBox; 1011 uint32_t cbVBox; 1012 size_t cwSrcLen, cwDestLen, cbDestLen; 1013 int rc; 1014 1015 LogFlowFunc (("called\n")); 1016 /* Read the clipboard data from the guest. */ 1017 rc = VBoxX11ClipboardReadVBoxData(g_ctxX11.pFrontend, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &pvVBox, &cbVBox); 1018 if ((rc != VINF_SUCCESS) || (cbVBox == 0)) 1019 { 1020 /* If VBoxX11ClipboardReadVBoxData fails then pClient may be invalid */ 1021 LogRelFunc (("VBoxX11ClipboardReadVBoxData returned %Rrc%s\n", rc, 1022 RT_SUCCESS(rc) ? ", cbVBox == 0" : "")); 1023 RTMemFree(pvVBox); 1024 return false; 1025 } 1026 pu16SrcText = reinterpret_cast<PRTUTF16>(pvVBox); 1027 cwSrcLen = cbVBox / 2; 1028 /* How long will the converted text be? */ 1029 rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen); 1030 if (RT_FAILURE(rc)) 1031 { 1032 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc)); 1033 RTMemFree(pvVBox); 1034 AssertRCReturn(rc, false); 1035 } 1036 if (cwDestLen == 0) 1037 { 1038 LogFlowFunc(("received empty clipboard data from the guest, returning false.\n")); 1039 RTMemFree(pvVBox); 1040 return false; 1041 } 1042 pu16DestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwDestLen * 2)); 1043 if (pu16DestText == 0) 1044 { 1045 LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 2)); 1046 RTMemFree(pvVBox); 1047 return false; 1048 } 1049 /* Convert the text. */ 1050 rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen); 1051 if (RT_FAILURE(rc)) 1052 { 1053 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc)); 1054 RTMemFree(reinterpret_cast<void *>(pu16DestText)); 1055 RTMemFree(pvVBox); 1056 return false; 1057 } 1058 /* Allocate enough space, as RTUtf16ToUtf8Ex may fail if the 1059 space is too tightly calculated. */ 1060 pu8DestText = XtMalloc(cwDestLen * 4); 1061 if (pu8DestText == 0) 1062 { 1063 LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 4)); 1064 RTMemFree(reinterpret_cast<void *>(pu16DestText)); 1065 RTMemFree(pvVBox); 1066 return false; 1067 } 1068 /* Convert the Utf16 string to Utf8. */ 1069 rc = RTUtf16ToUtf8Ex(pu16DestText + 1, cwDestLen - 1, &pu8DestText, cwDestLen * 4, 1070 &cbDestLen); 1071 RTMemFree(reinterpret_cast<void *>(pu16DestText)); 1072 if (RT_FAILURE(rc)) 1073 { 1074 LogRelFunc (("clipboard conversion failed. RTUtf16ToUtf8Ex() returned %Rrc. Abandoning.\n", rc)); 1075 XtFree(pu8DestText); 1076 RTMemFree(pvVBox); 1077 return false; 1078 } 1079 LogFlowFunc (("converted string is %.*s. Returning.\n", cbDestLen, pu8DestText)); 1080 RTMemFree(pvVBox); 1081 *atomTypeReturn = g_ctxX11.atomUtf8; 1082 *pValReturn = reinterpret_cast<XtPointer>(pu8DestText); 1083 *pcLenReturn = cbDestLen; 1084 *piFormatReturn = 8; 1085 return true; 1086 } 1087 1088 /** 1089 * Satisfy a request from X11 to convert the clipboard text to 1090 * COMPOUND_TEXT. We return non-zero terminated text. 1091 * @todo that works, but it is bad. Change it to return zero-terminated 1092 * text. 1093 * 1094 * @returns true if we successfully convert the data to the format 1095 * requested, false otherwise. 1096 * 1097 * @param atomTypeReturn Where to store the atom for the type of the data 1098 * we are returning 1099 * @param pValReturn Where to store the pointer to the data we are 1100 * returning. This should be to memory allocated by 1101 * XtMalloc, which will be freed by the Xt toolkit 1102 * later. 1103 * @param pcLenReturn Where to store the length of the data we are 1104 * returning 1105 * @param piFormatReturn Where to store the bit width (8, 16, 32) of the 1106 * data we are returning 1107 * @note X11 backend code, called by the callback for XtOwnSelection. 1108 */ 1109 static Boolean vboxClipboardConvertToCTextForX11(Atom *atomTypeReturn, 1110 XtPointer *pValReturn, 1111 unsigned long *pcLenReturn, 1112 int *piFormatReturn) 1113 { 1114 PRTUTF16 pu16SrcText, pu16DestText; 1115 void *pvVBox; 1116 uint32_t cbVBox; 1117 char *pu8DestText = 0; 1118 size_t cwSrcLen, cwDestLen, cbDestLen; 1119 XTextProperty property; 1120 int rc; 1121 1122 LogFlowFunc (("called\n")); 1123 /* Read the clipboard data from the guest. */ 1124 rc = VBoxX11ClipboardReadVBoxData(g_ctxX11.pFrontend, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &pvVBox, &cbVBox); 1125 if ((rc != VINF_SUCCESS) || (cbVBox == 0)) 1126 { 1127 /* If VBoxX11ClipboardReadVBoxData fails then pClient may be invalid */ 1128 LogRelFunc (("VBoxX11ClipboardReadVBoxData returned %Rrc%s\n", rc, 1129 RT_SUCCESS(rc) ? ", cbVBox == 0" : "")); 1130 RTMemFree(pvVBox); 1131 return false; 1132 } 1133 pu16SrcText = reinterpret_cast<PRTUTF16>(pvVBox); 1134 cwSrcLen = cbVBox / 2; 1135 /* How long will the converted text be? */ 1136 rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen); 1137 if (RT_FAILURE(rc)) 1138 { 1139 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc)); 1140 RTMemFree(pvVBox); 1141 AssertRCReturn(rc, false); 1142 } 1143 if (cwDestLen == 0) 1144 { 1145 LogFlowFunc(("received empty clipboard data from the guest, returning false.\n")); 1146 RTMemFree(pvVBox); 1147 return false; 1148 } 1149 pu16DestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwDestLen * 2)); 1150 if (pu16DestText == 0) 1151 { 1152 LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 2)); 1153 RTMemFree(pvVBox); 1154 return false; 1155 } 1156 /* Convert the text. */ 1157 rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen); 1158 if (RT_FAILURE(rc)) 1159 { 1160 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc)); 1161 RTMemFree(reinterpret_cast<void *>(pu16DestText)); 1162 RTMemFree(pvVBox); 1163 return false; 1164 } 1165 /* Convert the Utf16 string to Utf8. */ 1166 rc = RTUtf16ToUtf8Ex(pu16DestText + 1, cwDestLen - 1, &pu8DestText, 0, &cbDestLen); 1167 RTMemFree(reinterpret_cast<void *>(pu16DestText)); 1168 if (RT_FAILURE(rc)) 1169 { 1170 LogRelFunc (("clipboard conversion failed. RTUtf16ToUtf8Ex() returned %Rrc. Abandoning.\n", rc)); 1171 RTMemFree(pvVBox); 1172 return false; 1173 } 1174 /* And finally (!) convert the Utf8 text to compound text. */ 1175 #ifdef RT_OS_SOLARIS 1176 rc = XmbTextListToTextProperty(XtDisplay(g_ctxX11.widget), &pu8DestText, 1, 1177 XCompoundTextStyle, &property); 1178 #else 1179 rc = Xutf8TextListToTextProperty(XtDisplay(g_ctxX11.widget), &pu8DestText, 1, 1180 XCompoundTextStyle, &property); 1181 #endif 1182 RTMemFree(pu8DestText); 1183 if (rc < 0) 1184 { 1185 const char *pcReason; 1186 switch(rc) 1187 { 1188 case XNoMemory: 1189 pcReason = "out of memory"; 1190 break; 1191 case XLocaleNotSupported: 1192 pcReason = "locale (Utf8) not supported"; 1193 break; 1194 case XConverterNotFound: 1195 pcReason = "converter not found"; 1196 break; 1197 default: 1198 pcReason = "unknown error"; 1199 } 1200 LogRelFunc (("Xutf8TextListToTextProperty failed. Reason: %s\n", 1201 pcReason)); 1202 RTMemFree(pvVBox); 1203 return false; 1204 } 1205 LogFlowFunc (("converted string is %s. Returning.\n", property.value)); 1206 RTMemFree(pvVBox); 1207 *atomTypeReturn = property.encoding; 1208 *pValReturn = reinterpret_cast<XtPointer>(property.value); 1209 *pcLenReturn = property.nitems; 1210 *piFormatReturn = property.format; 1211 return true; 1212 } 1213 1214 /** 1215 * Return VBox's clipboard data for an X11 client. 1216 * @note X11 backend code, callback for XtOwnSelection 1217 */ 1218 static Boolean vboxClipboardConvertForX11(Widget, Atom *atomSelection, 1219 Atom *atomTarget, 1220 Atom *atomTypeReturn, 1221 XtPointer *pValReturn, 1222 unsigned long *pcLenReturn, 1223 int *piFormatReturn) 1224 { 1225 g_eClipboardFormats eFormat = INVALID; 1226 1227 LogFlowFunc(("\n")); 1228 /* Drop requests that we receive too late. */ 1229 if (g_ctxX11.eOwner != VB) 1230 return false; 1231 if ( (*atomSelection != g_ctxX11.atomClipboard) 1232 && (*atomSelection != g_ctxX11.atomPrimary) 1233 ) 1234 { 1235 LogFlowFunc(("rc = false\n")); 1236 return false; 1237 } 1238 if (g_debugClipboard) 1239 { 1240 char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), *atomTarget); 1241 if (szAtomName != 0) 1242 { 1243 Log2 (("%s: request for format %s\n", __PRETTY_FUNCTION__, szAtomName)); 1244 XFree(szAtomName); 1245 } 1246 else 1247 { 1248 LogFunc (("request for invalid target atom %d!\n", *atomTarget)); 1249 } 1250 } 1251 if (*atomTarget == g_ctxX11.atomTargets) 1252 { 1253 eFormat = TARGETS; 177 1254 } 178 1255 else 179 g_ctxHost.pBackend = pBackend; 180 return rc; 181 } 182 183 /** 184 * Terminate the host side of the shared clipboard. 185 * @note host glue code 186 */ 187 void vboxClipboardDestroy (void) 188 { 189 int rc = VINF_SUCCESS; 190 LogRelFunc(("shutting down host clipboard\n")); 191 /* Drop the reference to the client, in case it is still there. This 192 * will cause any outstanding clipboard data requests from X11 to fail 193 * immediately. */ 194 g_ctxHost.pClient = NULL; 195 /* The backend may be waiting for data from VBox. At this point it is no 196 * longer going to arrive, and we must release it to allow the event 197 * loop to terminate. In this case the buffer where VBox would have 198 * written the clipboard data will still be empty and we will just 199 * return "no data" to the backend. Any subsequent attempts to get the 200 * data from VBox will fail immediately as the client reference is gone. 1256 { 1257 for (unsigned i = 0; i != g_ctxX11.formatList.size(); ++i) 1258 { 1259 if (g_ctxX11.formatList[i].atom == *atomTarget) 1260 { 1261 eFormat = g_ctxX11.formatList[i].format; 1262 break; 1263 } 1264 } 1265 } 1266 switch (eFormat) 1267 { 1268 case TARGETS: 1269 return vboxClipboardConvertTargetsForX11(atomTypeReturn, pValReturn, 1270 pcLenReturn, piFormatReturn); 1271 case UTF16: 1272 return vboxClipboardConvertUtf16(atomTypeReturn, pValReturn, pcLenReturn, 1273 piFormatReturn); 1274 case UTF8: 1275 return vboxClipboardConvertToUtf8ForX11(atomTypeReturn, pValReturn, 1276 pcLenReturn, piFormatReturn); 1277 case CTEXT: 1278 return vboxClipboardConvertToCTextForX11(atomTypeReturn, pValReturn, 1279 pcLenReturn, piFormatReturn); 1280 default: 1281 LogFunc (("bad format\n")); 1282 return false; 1283 } 1284 } 1285 1286 /** 1287 * This is called by the X toolkit intrinsics to let us know that another 1288 * X11 client has taken the clipboard. In this case we notify VBox that 1289 * we want ownership of the clipboard. 1290 * @note X11 backend code, callback for XtOwnSelection 1291 */ 1292 static void vboxClipboardReturnToX11(Widget, Atom *) 1293 { 1294 LogFlowFunc (("called, giving VBox clipboard ownership\n")); 1295 g_ctxX11.eOwner = X11; 1296 g_ctxX11.notifyVBox = true; 1297 } 1298 1299 /** 1300 * VBox is taking possession of the shared clipboard. 1301 * 1302 * @param u32Formats Clipboard formats the guest is offering 1303 * @note X11 backend code 1304 */ 1305 void VBoxX11ClipboardAnnounceVBoxFormat(VBOXCLIPBOARDCONTEXTX11 *pBackend, 1306 uint32_t u32Formats) 1307 { 1308 /* 1309 * Immediately return if we are not connected to the host X server. 201 1310 */ 202 /** @note This has been made unconditional, as it should do no harm 203 * even if we are not waiting. */ 204 RTSemEventSignal(g_ctxHost.waitForData); 205 rc = VBoxX11ClipboardTermX11(g_ctxHost.pBackend); 206 if (RT_SUCCESS(rc)) 207 { 208 /* We can safely destroy these as the backend has exited 209 * successfully and no other calls from the host code should be 210 * forthcoming. */ 211 /** @todo can the backend fail to exit successfully? What then? */ 212 RTSemEventDestroy(g_ctxHost.waitForData); 213 RTSemMutexDestroy(g_ctxHost.clipboardMutex); 214 } 215 } 216 217 /** 218 * Connect a guest to the shared clipboard. 219 * @note host glue code 220 * @note on the host, we assume that some other application already owns 221 * the clipboard and leave ownership to X11. 222 */ 223 int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient) 224 { 225 int rc = VINF_SUCCESS; 226 LogFlowFunc(("\n")); 227 /* Only one client is supported for now */ 228 AssertLogRelReturn(g_ctxHost.pClient == 0, VERR_NOT_SUPPORTED); 229 pClient->pCtx = &g_ctxHost; 230 pClient->pCtx->pClient = pClient; 231 /** The pClient pointer is a dummy anyway, as we only support a single 232 * client at a time. */ 233 rc = VBoxX11ClipboardStartX11(g_ctxHost.pBackend, 234 X11 /* initial owner */); 235 return rc; 236 } 237 238 /** 239 * Synchronise the contents of the host clipboard with the guest, called 240 * after a save and restore of the guest. 241 * @note Host glue code 242 */ 243 int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA *pClient) 244 { 245 246 /* On a Linux host, the guest should never synchronise/cache its 247 * clipboard contents, as we have no way of reliably telling when the 248 * host clipboard data changes. So instead of synchronising, we tell 249 * the guest to empty its clipboard, and we set the cached flag so that 250 * we report formats to the guest next time we poll for them. */ 251 /** @note This has been changed so that the message is sent even if 252 * X11 is not available. */ 253 vboxSvcClipboardReportMsg (g_ctxHost.pClient, 254 VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, 0); 255 VBoxX11ClipboardRequestSyncX11(g_ctxHost.pBackend); 256 257 return VINF_SUCCESS; 258 } 259 260 /** 261 * Shut down the shared clipboard service and "disconnect" the guest. 262 * @note Host glue code 263 */ 264 void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *) 265 { 266 LogFlow(("vboxClipboardDisconnect\n")); 267 268 RTSemMutexRequest(g_ctxHost.clipboardMutex, RT_INDEFINITE_WAIT); 269 g_ctxHost.pClient = NULL; 270 VBoxX11ClipboardStopX11(g_ctxHost.pBackend); 271 RTSemMutexRelease(g_ctxHost.clipboardMutex); 272 } 273 274 /** 275 * VBox is taking possession of the shared clipboard. 276 * 277 * @param pClient Context data for the guest system 278 * @param u32Formats Clipboard formats the guest is offering 279 * @note Host glue code 280 */ 281 void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Formats) 282 { 283 VBoxX11ClipboardAnnounceVBoxFormat (g_ctxHost.pBackend, u32Formats); 1311 if (!g_fHaveX11) 1312 return; 1313 1314 g_ctxX11.vboxFormats = u32Formats; 1315 LogFlowFunc (("u32Formats=%d\n", u32Formats)); 1316 if (u32Formats == 0) 1317 { 1318 /* This is just an automatism, not a genuine anouncement */ 1319 LogFlowFunc(("returning\n")); 1320 return; 1321 } 1322 if (g_ctxX11.eOwner == VB) 1323 { 1324 /* We already own the clipboard, so no need to grab it, especially as that can lead 1325 to races due to the asynchronous nature of the X11 clipboard. This event may also 1326 have been sent out by the guest to invalidate the Windows clipboard cache. */ 1327 LogFlowFunc(("returning\n")); 1328 return; 1329 } 1330 Log2 (("%s: giving the guest clipboard ownership\n", __PRETTY_FUNCTION__)); 1331 g_ctxX11.eOwner = VB; 1332 g_ctxX11.X11TextFormat = INVALID; 1333 g_ctxX11.X11BitmapFormat = INVALID; 1334 if (XtOwnSelection(g_ctxX11.widget, g_ctxX11.atomClipboard, CurrentTime, vboxClipboardConvertForX11, 1335 vboxClipboardReturnToX11, 0) != True) 1336 { 1337 Log2 (("%s: returning clipboard ownership to the host\n", __PRETTY_FUNCTION__)); 1338 /* We set this so that the guest gets notified when we take the clipboard, even if no 1339 guest formats are found which we understand. */ 1340 g_ctxX11.notifyVBox = true; 1341 g_ctxX11.eOwner = X11; 1342 } 1343 XtOwnSelection(g_ctxX11.widget, g_ctxX11.atomPrimary, CurrentTime, vboxClipboardConvertForX11, 1344 NULL, 0); 1345 LogFlowFunc(("returning\n")); 1346 284 1347 } 285 1348 … … 292 1355 * @param cb The size of the buffer to write the data to 293 1356 * @param pcbActual Where to write the actual size of the written data 294 * @note Host glue code 295 */ 296 int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient, 297 uint32_t u32Format, void *pv, uint32_t cb, 298 uint32_t *pcbActual) 299 { 300 int rc = VINF_SUCCESS; 301 VBOXCLIPBOARDREQUEST request; 302 /* No one else (VBox or X11) should currently be waiting. The first 303 * because requests from VBox are serialised and the second because X11 304 * previously grabbed the clipboard, so it should not be waiting for 305 * data from us. */ 306 AssertLogRelReturn (ASMAtomicCmpXchgU32(&g_ctxHost.waiter, VB, NONE), 307 VERR_DEADLOCK); 308 request.pv = pv; 309 request.cb = cb; 310 request.pcbActual = pcbActual; 311 rc = VBoxX11ClipboardReadX11Data(g_ctxHost.pBackend, u32Format, &request); 312 g_ctxHost.waiter = NONE; 313 return rc; 314 } 315 316 /** 317 * Called when we have requested data from VBox and that data has arrived. 318 * 319 * @param pClient Context information about the guest VM 320 * @param pv Buffer to which the data was written 321 * @param cb The size of the data written 322 * @param u32Format The format of the data written 323 * @note Host glue code 324 */ 325 void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient, 326 void *pv, uint32_t cb, uint32_t u32Format) 327 { 328 /* Assume that if this gets called at all then the X11 backend is running. */ 329 #if 0 1357 * @note X11 backend code 1358 */ 1359 int VBoxX11ClipboardReadX11Data(VBOXCLIPBOARDCONTEXTX11 *pBackend, 1360 uint32_t u32Format, 1361 VBOXCLIPBOARDREQUEST *pRequest) 1362 { 1363 /* 1364 * Immediately return if we are not connected to the host X server. 1365 */ 330 1366 if (!g_fHaveX11) 331 return; 332 #endif 333 334 LogFlowFunc (("called\n")); 335 336 /* Assert that no other transfer is in process (requests are serialised) 337 * or has not cleaned up properly. */ 338 AssertLogRelReturnVoid ( pClient->data.pv == NULL 339 && pClient->data.cb == 0 340 && pClient->data.u32Format == 0); 341 342 /* Grab the mutex and check that X11 is still waiting for the data before 343 * delivering it. See the explanation in VBoxX11ClipboardReadVBoxData. */ 344 RTSemMutexRequest(g_ctxHost.clipboardMutex, RT_INDEFINITE_WAIT); 345 if (g_ctxHost.waiter == X11 && cb > 0) 346 { 347 pClient->data.pv = RTMemAlloc (cb); 348 349 if (pClient->data.pv) 1367 { 1368 /* no data available */ 1369 *pRequest->pcbActual = 0; 1370 return VINF_SUCCESS; 1371 } 1372 1373 LogFlowFunc (("u32Format = %d, cb = %d\n", u32Format, pRequest->cb)); 1374 1375 /* 1376 * The guest wants to read data in the given format. 1377 */ 1378 if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) 1379 { 1380 if (g_ctxX11.X11TextFormat == INVALID) 350 1381 { 351 memcpy (pClient->data.pv, pv, cb);352 pClient->data.cb = cb;353 pClient->data.u32Format = u32Format;1382 /* No data available. */ 1383 *pRequest->pcbActual = 0; 1384 return VERR_NO_DATA; /* The guest thinks we have data and we don't */ 354 1385 } 355 } 356 RTSemMutexRelease(g_ctxHost.clipboardMutex); 357 358 RTSemEventSignal(g_ctxHost.waitForData); 359 } 360 1386 /* Initially set the size of the data read to zero in case we fail 1387 * somewhere. */ 1388 *pRequest->pcbActual = 0; 1389 /* Send out a request for the data to the current clipboard owner */ 1390 XtGetSelectionValue(g_ctxX11.widget, g_ctxX11.atomClipboard, 1391 g_ctxX11.atomX11TextFormat, 1392 vboxClipboardGetDataFromX11, 1393 reinterpret_cast<XtPointer>(pRequest), 1394 CurrentTime); 1395 /* When the data arrives, the vboxClipboardGetDataFromX11 callback will be called. The 1396 callback will signal the event semaphore when it has processed the data for us. */ 1397 1398 int rc = RTSemEventWait(g_ctxX11.waitForData, RT_INDEFINITE_WAIT); 1399 if (RT_FAILURE(rc)) 1400 return rc; 1401 } 1402 else 1403 { 1404 return VERR_NOT_IMPLEMENTED; 1405 } 1406 return VINF_SUCCESS; 1407 } 1408
Note:
See TracChangeset
for help on using the changeset viewer.