Changeset 19152 in vbox for trunk/src/VBox/GuestHost/SharedClipboard
- Timestamp:
- Apr 23, 2009 9:23:45 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 46398
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp
r19027 r19152 23 23 #define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD 24 24 25 #include <errno.h> 25 26 #include <vector> 27 28 #include <unistd.h> 26 29 27 30 #ifdef RT_OS_SOLARIS … … 103 106 std::vector<VBOXCLIPBOARDFORMAT> formatList; 104 107 105 /** Does VBox or X11 currently own the clipboard? */ 106 volatile enum g_eOwner eOwner; 108 /** Does VBox currently own the clipboard? If so, we don't need to poll 109 * X11 for supported formats. */ 110 bool fOwnsClipboard; 107 111 108 112 /** What is the best text format X11 has to offer? INVALID for none. */ … … 110 114 /** Atom corresponding to the X11 text format */ 111 115 Atom atomX11TextFormat; 112 /** What is the best bitmap format X11 has to offer? INVALID for none. */ 116 /** What is the best bitmap format X11 has to offer? INVALID for none. 117 */ 113 118 g_eClipboardFormats X11BitmapFormat; 114 119 /** Atom corresponding to the X11 Bitmap format */ … … 121 126 * to invalidate it. */ 122 127 bool notifyVBox; 123 124 /** Since the clipboard data moves asynchronously, we use an event 125 * semaphore to wait for it. When a function issues a request for 126 * clipboard data it must wait for this semaphore, which is triggered 127 * when the data arrives. */ 128 RTSEMEVENT waitForData; 128 /** Cache of the last unicode data that we received */ 129 void *pvUnicodeCache; 130 /** Size of the unicode data in the cache */ 131 uint32_t cbUnicodeCache; 132 /** When we wish the clipboard to exit, we have to wake up the event 133 * loop. We do this by writing into a pipe. This end of the pipe is 134 * the end that another thread can write to. */ 135 int wakeupPipeWrite; 136 /** The reader end of the pipe */ 137 int wakeupPipeRead; 129 138 }; 130 139 … … 248 257 * the X11 clipboard. 249 258 */ 250 static voidvboxClipboardGetUtf8FromX11(VBOXCLIPBOARDCONTEXTX11 *pCtx,251 252 253 259 static int vboxClipboardGetUtf8FromX11(VBOXCLIPBOARDCONTEXTX11 *pCtx, 260 XtPointer pValue, unsigned cbSrcLen, 261 void *pv, unsigned cb, 262 uint32_t *pcbActual) 254 263 { 255 264 size_t cwSrcLen; … … 267 276 XtFree(reinterpret_cast<char *>(pValue)); 268 277 RTUtf16Free(pu16SrcText); 269 RTSemEventSignal(pCtx->waitForData);270 LogFlowFunc(("Returning. Status is %Rrc\n", rc));278 LogFlowFunc(("Returning %Rrc\n", rc)); 279 return rc; 271 280 } 272 281 … … 285 294 * the X11 clipboard. 286 295 */ 287 static voidvboxClipboardGetCTextFromX11(VBOXCLIPBOARDCONTEXTX11 *pCtx,288 289 290 296 static int vboxClipboardGetCTextFromX11(VBOXCLIPBOARDCONTEXTX11 *pCtx, 297 XtPointer pValue, unsigned cbSrcLen, 298 void *pv, unsigned cb, 299 uint32_t *pcbActual) 291 300 { 292 301 size_t cwSrcLen; … … 335 344 XFreeStringList(ppu8SrcText); 336 345 RTUtf16Free(pu16SrcText); 337 LogFlowFunc(("Returning . Status is%Rrc\n", rc));338 RTSemEventSignal(pCtx->waitForData);346 LogFlowFunc(("Returning %Rrc\n", rc)); 347 return rc; 339 348 } 340 349 … … 353 362 * the X11 clipboard. 354 363 */ 355 static voidvboxClipboardGetLatin1FromX11(VBOXCLIPBOARDCONTEXTX11 *pCtx,356 357 358 364 static int vboxClipboardGetLatin1FromX11(VBOXCLIPBOARDCONTEXTX11 *pCtx, 365 XtPointer pValue, 366 unsigned cbSourceLen, void *pv, 367 unsigned cb, uint32_t *pcbActual) 359 368 { 360 369 unsigned cwDestLen = cbSourceLen + 1; … … 392 401 } 393 402 XtFree(reinterpret_cast<char *>(pValue)); 394 RTSemEventSignal(pCtx->waitForData);395 LogFlowFunc(("Returning. Status is %Rrc\n", rc));403 LogFlowFunc(("Returning %Rrc\n", rc)); 404 return rc; 396 405 } 397 406 … … 412 421 = reinterpret_cast<VBOXCLIPBOARDREQUEST *>(pClientData); 413 422 VBOXCLIPBOARDCONTEXTX11 *pCtx = pRequest->pCtx; 423 if (pCtx->fOwnsClipboard == true) 424 { 425 /* We don't want to request data from ourselves! */ 426 pRequest->rc = VERR_NO_DATA; 427 RTSemEventSignal(pRequest->finished); 428 return; 429 } 414 430 pRequest->rc = VINF_SUCCESS; 415 431 LogFlowFunc(("pClientData=%p, *pcLen=%lu, *piFormat=%d\n", pClientData, … … 422 438 { 423 439 pRequest->rc = VERR_TIMEOUT; 424 RTSemEventSignal(p Ctx->waitForData);440 RTSemEventSignal(pRequest->finished); 425 441 return; 426 442 } … … 429 445 { 430 446 pRequest->rc = VERR_NO_DATA; 431 RTSemEventSignal(p Ctx->waitForData);447 RTSemEventSignal(pRequest->finished); 432 448 return; 433 449 } … … 436 452 { 437 453 case CTEXT: 438 vboxClipboardGetCTextFromX11(pCtx, pValue, cTextLen, pRequest->pv, 439 pRequest->cb, pRequest->pcbActual); 454 pRequest->rc = vboxClipboardGetCTextFromX11(pCtx, pValue, cTextLen, 455 pRequest->pv, 456 pRequest->cb, 457 pRequest->pcbActual); 458 RTSemEventSignal(pRequest->finished); 440 459 break; 441 460 case UTF8: … … 448 467 && (RTStrUniLenEx(pu8SourceText, *pcLen, &cStringLen) == VINF_SUCCESS)) 449 468 { 450 vboxClipboardGetUtf8FromX11(pCtx, pValue, cTextLen, pRequest->pv, 451 pRequest->cb, pRequest->pcbActual); 469 pRequest->rc = vboxClipboardGetUtf8FromX11(pCtx, pValue, 470 cTextLen, 471 pRequest->pv, 472 pRequest->cb, 473 pRequest->pcbActual); 474 RTSemEventSignal(pRequest->finished); 452 475 break; 453 476 } 454 477 else 455 478 { 456 vboxClipboardGetLatin1FromX11(pCtx, pValue, cTextLen, 457 pRequest->pv, pRequest->cb, 458 pRequest->pcbActual); 479 pRequest->rc = vboxClipboardGetLatin1FromX11(pCtx, pValue, 480 cTextLen, 481 pRequest->pv, 482 pRequest->cb, 483 pRequest->pcbActual); 484 RTSemEventSignal(pRequest->finished); 459 485 break; 460 486 } … … 464 490 XtFree(reinterpret_cast<char *>(pValue)); 465 491 pRequest->rc = VERR_INVALID_PARAMETER; 466 RTSemEventSignal(p Ctx->waitForData);492 RTSemEventSignal(pRequest->finished); 467 493 return; 468 494 } … … 493 519 494 520 Log3 (("%s: called\n", __PRETTY_FUNCTION__)); 495 if (*atomType == XT_CONVERT_FAIL) /* timeout */ 496 { 497 LogFunc (("reading clipboard from host, X toolkit failed to convert the selection\n")); 521 if ( (*atomType == XT_CONVERT_FAIL) /* timeout */ 522 || (pCtx->fOwnsClipboard == true) /* VBox currently owns the 523 * clipboard */ 524 ) 525 { 498 526 pCtx->atomX11TextFormat = None; 499 527 pCtx->X11TextFormat = INVALID; … … 576 604 reinterpret_cast<VBOXCLIPBOARDCONTEXTX11 *>(pUserData); 577 605 Log3 (("%s: called\n", __PRETTY_FUNCTION__)); 578 /* Get the current clipboard contents */579 if ( (pCtx->eOwner != VB))606 /* Get the current clipboard contents if we don't own it ourselves */ 607 if (!pCtx->fOwnsClipboard) 580 608 { 581 609 Log3 (("%s: requesting the targets that the host clipboard offers\n", … … 642 670 vboxClipboardRemoveContext(pCtx); 643 671 XtDestroyWidget(pCtx->widget); 644 pCtx->widget = NULL;645 }672 } 673 pCtx->widget = NULL; 646 674 if (pCtx->appContext) 647 {648 675 XtDestroyApplicationContext(pCtx->appContext); 649 pCtx->appContext = NULL; 650 } 676 pCtx->appContext = NULL; 677 if (pCtx->wakeupPipeRead != 0) 678 close(pCtx->wakeupPipeRead); 679 if (pCtx->wakeupPipeWrite != 0) 680 close(pCtx->wakeupPipeWrite); 681 pCtx->wakeupPipeRead = 0; 682 pCtx->wakeupPipeWrite = 0; 683 } 684 685 /** Worker function for stopping the clipboard which runs on the event 686 * thread. */ 687 static void vboxClipboardStopWorker(XtPointer pUserData, int * /* source */, 688 XtInputId * /* id */) 689 { 690 691 VBOXCLIPBOARDCONTEXTX11 *pCtx = (VBOXCLIPBOARDCONTEXTX11 *)pUserData; 692 693 /* This might mean that we are getting stopped twice. */ 694 Assert(pCtx->widget != NULL); 695 696 /* Set the termination flag to tell the Xt event loop to exit. We 697 * reiterate that any outstanding requests from the X11 event loop to 698 * the VBox part *must* have returned before we do this. */ 699 XtAppSetExitFlag(pCtx->appContext); 700 pCtx->fOwnsClipboard = false; 701 pCtx->X11TextFormat = INVALID; 702 pCtx->X11BitmapFormat = INVALID; 651 703 } 652 704 … … 721 773 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 722 774 } 775 /* Create the pipes */ 776 int pipes[2]; 777 if (!pipe(pipes)) 778 { 779 pCtx->wakeupPipeRead = pipes[0]; 780 pCtx->wakeupPipeWrite = pipes[1]; 781 XtAppAddInput(pCtx->appContext, pCtx->wakeupPipeRead, 782 (XtPointer) XtInputReadMask, vboxClipboardStopWorker, 783 (XtPointer) pCtx); 784 } 785 else 786 rc = RTErrConvertFromErrno(errno); 723 787 if (RT_FAILURE(rc)) 724 788 vboxClipboardUninitX11(pCtx); … … 770 834 LogRel(("Initializing X11 clipboard backend\n")); 771 835 if (pCtx) 772 {773 836 pCtx->pFrontend = pFrontend; 774 RTSemEventCreate(&pCtx->waitForData);775 }776 837 return pCtx; 777 838 } … … 793 854 * memory. */ 794 855 Assert(pCtx->widget == NULL); 795 RTSemEventDestroy(pCtx->waitForData);796 856 } 797 857 798 858 /** 799 859 * Announce to the X11 backend that we are ready to start. 800 * @param owner who is the initial clipboard owner 801 */ 802 int VBoxX11ClipboardStartX11(VBOXCLIPBOARDCONTEXTX11 *pCtx, 803 bool fOwnsClipboard) 860 */ 861 int VBoxX11ClipboardStartX11(VBOXCLIPBOARDCONTEXTX11 *pCtx) 804 862 { 805 863 int rc = VINF_SUCCESS; … … 821 879 if (RT_SUCCESS(rc)) 822 880 { 823 if (fOwnsClipboard) 824 { 825 pCtx->eOwner = X11; 826 pCtx->notifyVBox = true; 827 } 828 else 829 { 830 /** @todo Check whether the guest gets a format announcement at 831 * startup. */ 832 pCtx->eOwner = NONE; 833 VBoxX11ClipboardAnnounceVBoxFormat(pCtx, 0); 834 } 881 pCtx->fOwnsClipboard = false; 882 pCtx->notifyVBox = true; 835 883 } 836 884 return rc; 837 885 } 838 886 839 /** 840 * Called when the VBox may have fallen out of sync with the backend. 841 * @note X11 backend code 842 */ 843 void VBoxX11ClipboardRequestSyncX11(VBOXCLIPBOARDCONTEXTX11 *pCtx) 844 { 845 /* 846 * Immediately return if we are not connected to the host X server. 847 */ 848 if (!g_fHaveX11) 849 return; 850 pCtx->notifyVBox = true; 851 } 887 /** String written to the wakeup pipe. */ 888 #define WAKE_UP_STRING "WakeUp!" 889 /** Length of the string written. */ 890 #define WAKE_UP_STRING_LEN ( sizeof(WAKE_UP_STRING) - 1 ) 852 891 853 892 /** … … 863 902 int rc, rcThread; 864 903 unsigned count = 0; 865 XEvent ev;866 904 /* 867 905 * Immediately return if we are not connected to the host X server. … … 870 908 return VINF_SUCCESS; 871 909 872 /* This might mean that we are getting stopped twice. */873 AssertReturn(pCtx->widget != NULL, VERR_WRONG_ORDER);874 910 LogRelFunc(("stopping the shared clipboard X11 backend\n")); 875 876 /* Set the termination flag to tell the Xt event loop to exit. We 877 * reiterate that any outstanding requests from the X11 event loop to 878 * the VBox part *must* have returned before we do this. */ 879 XtAppSetExitFlag(pCtx->appContext); 880 /* Wake up the event loop */ 881 memset(&ev, 0, sizeof(ev)); 882 ev.xclient.type = ClientMessage; 883 ev.xclient.format = 8; 884 XSendEvent(XtDisplay(pCtx->widget), XtWindow(pCtx->widget), false, 0, &ev); 885 XFlush(XtDisplay(pCtx->widget)); 886 pCtx->eOwner = NONE; 887 pCtx->X11TextFormat = INVALID; 888 pCtx->X11BitmapFormat = INVALID; 911 /* Write to the "stop" pipe */ 912 rc = write(pCtx->wakeupPipeWrite, WAKE_UP_STRING, WAKE_UP_STRING_LEN); 889 913 do 890 914 { … … 965 989 *piFormatReturn = 32; 966 990 return true; 991 } 992 993 /** This is a wrapper around VBoxX11ClipboardReadVBoxData that will cache the 994 * data returned. This is unfortunately necessary, because if the other side 995 * of the shared clipboard is also an X11 system, it may send a format 996 * announcement message every time its clipboard is read, for reasons that 997 * are explained elsewhere. Unfortunately, some applications on our side 998 * like to read the clipboard several times in short succession in different 999 * formats. This can fail if it collides with a format announcement message. 1000 * @todo any ideas about how to do this better are welcome. 1001 */ 1002 static int vboxClipboardReadVBoxData (VBOXCLIPBOARDCONTEXTX11 *pCtx, 1003 uint32_t u32Format, void **ppv, 1004 uint32_t *pcb) 1005 { 1006 int rc = VINF_SUCCESS; 1007 LogFlowFunc(("pCtx=%p, u32Format=%02X, ppv=%p, pcb=%p\n", pCtx, 1008 u32Format, ppv, pcb)); 1009 if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) 1010 { 1011 if (pCtx->pvUnicodeCache == NULL) 1012 rc = VBoxX11ClipboardReadVBoxData(pCtx->pFrontend, u32Format, 1013 &pCtx->pvUnicodeCache, 1014 &pCtx->cbUnicodeCache); 1015 if (RT_SUCCESS(rc)) 1016 { 1017 *ppv = RTMemDup(pCtx->pvUnicodeCache, pCtx->cbUnicodeCache); 1018 *pcb = pCtx->cbUnicodeCache; 1019 if (*ppv == NULL) 1020 rc = VERR_NO_MEMORY; 1021 } 1022 } 1023 else 1024 rc = VBoxX11ClipboardReadVBoxData(pCtx->pFrontend, u32Format, 1025 ppv, pcb); 1026 LogFlowFunc(("returning %Rrc\n", rc)); 1027 if (RT_SUCCESS(rc)) 1028 LogFlowFunc(("*ppv=%.*ls, *pcb=%u\n", *pcb, *ppv, *pcb)); 1029 return rc; 967 1030 } 968 1031 … … 1004 1067 LogFlowFunc (("called\n")); 1005 1068 /* Read the clipboard data from the guest. */ 1006 rc = VBoxX11ClipboardReadVBoxData(pCtx->pFrontend, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &pvVBox, &cbVBox); 1069 rc = vboxClipboardReadVBoxData(pCtx, 1070 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 1071 &pvVBox, &cbVBox); 1007 1072 if ((rc != VINF_SUCCESS) || (cbVBox == 0)) 1008 1073 { 1009 /* If VBoxX11ClipboardReadVBoxData fails then pClient may be invalid*/1010 LogRelFunc ((" VBoxX11ClipboardReadVBoxData returned %Rrc%s\n", rc,1074 /* If vboxClipboardReadVBoxData fails then we may be terminating */ 1075 LogRelFunc (("vboxClipboardReadVBoxData returned %Rrc%s\n", rc, 1011 1076 RT_SUCCESS(rc) ? ", cbVBox == 0" : "")); 1012 1077 RTMemFree(pvVBox); … … 1113 1178 LogFlowFunc (("called\n")); 1114 1179 /* Read the clipboard data from the guest. */ 1115 rc = VBoxX11ClipboardReadVBoxData(pCtx->pFrontend, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &pvVBox, &cbVBox); 1180 rc = vboxClipboardReadVBoxData(pCtx, 1181 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 1182 &pvVBox, &cbVBox); 1116 1183 if ((rc != VINF_SUCCESS) || (cbVBox == 0)) 1117 1184 { 1118 /* If VBoxX11ClipboardReadVBoxData fails then pClient may be invalid*/1119 LogRelFunc ((" VBoxX11ClipboardReadVBoxData returned %Rrc%s\n", rc,1185 /* If vboxClipboardReadVBoxData fails then we may be terminating */ 1186 LogRelFunc (("vboxClipboardReadVBoxData returned %Rrc%s\n", rc, 1120 1187 RT_SUCCESS(rc) ? ", cbVBox == 0" : "")); 1121 1188 RTMemFree(pvVBox); … … 1219 1286 LogFlowFunc(("\n")); 1220 1287 /* Drop requests that we receive too late. */ 1221 if ( pCtx->eOwner != VB)1288 if (!pCtx->fOwnsClipboard) 1222 1289 return false; 1223 1290 if ( (*atomSelection != pCtx->atomClipboard) … … 1285 1352 { 1286 1353 VBOXCLIPBOARDCONTEXTX11 *pCtx = vboxClipboardFindContext(widget); 1287 LogFlowFunc (("called, giving VBox clipboard ownership\n")); 1288 pCtx->eOwner = X11; 1354 LogFlowFunc (("called, giving X11 clipboard ownership\n")); 1355 /* These should be set to the right values as soon as we start polling */ 1356 pCtx->X11TextFormat = INVALID; 1357 pCtx->X11BitmapFormat = INVALID; 1358 pCtx->fOwnsClipboard = false; 1289 1359 pCtx->notifyVBox = true; 1360 } 1361 1362 /** Structure used to pass information about formats that VBox supports */ 1363 typedef struct _VBOXCLIPBOARDFORMATS 1364 { 1365 /** Context information for the X11 clipboard */ 1366 VBOXCLIPBOARDCONTEXTX11 *pCtx; 1367 /** Formats supported by VBox */ 1368 uint32_t formats; 1369 } VBOXCLIPBOARDFORMATS; 1370 1371 /** Worker function for VBoxX11ClipboardAnnounceVBoxFormat which runs on the 1372 * event thread. */ 1373 static void vboxClipboardAnnounceWorker(XtPointer pUserData, 1374 XtIntervalId * /* interval */) 1375 { 1376 /* Extract and free the user data */ 1377 VBOXCLIPBOARDFORMATS *pFormats = (VBOXCLIPBOARDFORMATS *)pUserData; 1378 VBOXCLIPBOARDCONTEXTX11 *pCtx = pFormats->pCtx; 1379 uint32_t u32Formats = pFormats->formats; 1380 RTMemFree(pFormats); 1381 LogFlowFunc (("u32Formats=%d\n", u32Formats)); 1382 pCtx->vboxFormats = u32Formats; 1383 /* Invalidate the clipboard cache */ 1384 if (pCtx->pvUnicodeCache != NULL) 1385 { 1386 RTMemFree(pCtx->pvUnicodeCache); 1387 pCtx->pvUnicodeCache = NULL; 1388 } 1389 if (u32Formats == 0) 1390 { 1391 /* This is just an automatism, not a genuine anouncement */ 1392 XtDisownSelection(pCtx->widget, pCtx->atomClipboard, CurrentTime); 1393 pCtx->fOwnsClipboard = false; 1394 LogFlowFunc(("returning\n")); 1395 return; 1396 } 1397 Log2 (("%s: giving the guest clipboard ownership\n", __PRETTY_FUNCTION__)); 1398 if (XtOwnSelection(pCtx->widget, pCtx->atomClipboard, CurrentTime, 1399 vboxClipboardConvertForX11, vboxClipboardReturnToX11, 1400 0) == True) 1401 { 1402 pCtx->fOwnsClipboard = true; 1403 /* Grab the middle-button paste selection too. */ 1404 XtOwnSelection(pCtx->widget, pCtx->atomPrimary, CurrentTime, 1405 vboxClipboardConvertForX11, NULL, 0); 1406 } 1407 else 1408 { 1409 /* Another X11 client claimed the clipboard just after us, so let it 1410 * go again. */ 1411 Log2 (("%s: returning clipboard ownership to the X11\n", 1412 __PRETTY_FUNCTION__)); 1413 /* VBox thinks it currently owns the clipboard, so we must notify it 1414 * as soon as we know what formats X11 has to offer. */ 1415 pCtx->notifyVBox = true; 1416 pCtx->fOwnsClipboard = false; 1417 } 1418 LogFlowFunc(("returning\n")); 1290 1419 } 1291 1420 … … 1304 1433 if (!g_fHaveX11) 1305 1434 return; 1306 1307 LogFlowFunc (("u32Formats=%d\n", u32Formats)); 1308 pCtx->vboxFormats = u32Formats; 1309 if (u32Formats == 0) 1310 { 1311 /* This is just an automatism, not a genuine anouncement */ 1312 XtDisownSelection(pCtx->widget, pCtx->atomClipboard, CurrentTime); 1313 pCtx->eOwner = NONE; 1314 LogFlowFunc(("returning\n")); 1315 return; 1316 } 1317 Log2 (("%s: giving the guest clipboard ownership\n", __PRETTY_FUNCTION__)); 1318 pCtx->eOwner = VB; 1319 pCtx->X11TextFormat = INVALID; 1320 pCtx->X11BitmapFormat = INVALID; 1321 if (XtOwnSelection(pCtx->widget, pCtx->atomClipboard, CurrentTime, 1322 vboxClipboardConvertForX11, vboxClipboardReturnToX11, 1323 0) != True) 1324 { 1325 Log2 (("%s: returning clipboard ownership to the host\n", __PRETTY_FUNCTION__)); 1326 /* We set this so that the guest gets notified when we take the clipboard, even if no 1327 guest formats are found which we understand. */ 1328 pCtx->notifyVBox = true; 1329 pCtx->eOwner = X11; 1330 } 1331 XtOwnSelection(pCtx->widget, pCtx->atomPrimary, CurrentTime, vboxClipboardConvertForX11, 1332 NULL, 0); 1333 LogFlowFunc(("returning\n")); 1334 1435 /* This must be freed by the worker callback */ 1436 VBOXCLIPBOARDFORMATS *pFormats = 1437 (VBOXCLIPBOARDFORMATS *) RTMemAlloc(sizeof(VBOXCLIPBOARDFORMATS)); 1438 if (pFormats != NULL) /* if it is we will soon have other problems */ 1439 { 1440 pFormats->pCtx = pCtx; 1441 pFormats->formats = u32Formats; 1442 XtAppAddTimeOut(pCtx->appContext, 0, vboxClipboardAnnounceWorker, 1443 (XtPointer) pFormats); 1444 } 1445 } 1446 1447 /** Worker function for VBoxX11ClipboardReadX11Data which runs on the event 1448 * thread. */ 1449 static void vboxClipboardReadX11Worker(XtPointer pUserData, 1450 XtIntervalId * /* interval */) 1451 { 1452 VBOXCLIPBOARDREQUEST *pRequest = (VBOXCLIPBOARDREQUEST *)pUserData; 1453 VBOXCLIPBOARDCONTEXTX11 *pCtx = pRequest->pCtx; 1454 LogFlowFunc (("u32Format = %d, cb = %d\n", pRequest->format, 1455 pRequest->cb)); 1456 1457 int rc = VINF_SUCCESS; 1458 /* Set this to start with, just in case */ 1459 *pRequest->pcbActual = 0; 1460 /* Do not continue if we already own the clipboard */ 1461 if (pCtx->fOwnsClipboard == true) 1462 rc = VERR_NO_DATA; /** @todo should this be VINF? */ 1463 else 1464 { 1465 /* 1466 * VBox wants to read data in the given format. 1467 */ 1468 if (pRequest->format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) 1469 { 1470 if (pCtx->atomX11TextFormat == None) 1471 /* VBox thinks we have data and we don't */ 1472 rc = VERR_NO_DATA; 1473 else 1474 /* Send out a request for the data to the current clipboard 1475 * owner */ 1476 XtGetSelectionValue(pCtx->widget, pCtx->atomClipboard, 1477 pCtx->atomX11TextFormat, 1478 vboxClipboardGetDataFromX11, 1479 reinterpret_cast<XtPointer>(pRequest), 1480 CurrentTime); 1481 } 1482 else 1483 rc = VERR_NOT_IMPLEMENTED; 1484 } 1485 if (RT_FAILURE(rc)) 1486 { 1487 pRequest->rc = rc; 1488 /* The clipboard callback was never scheduled, so we must signal 1489 * that the request processing is finished ourselves. */ 1490 RTSemEventSignal(pRequest->finished); 1491 } 1492 LogFlowFunc(("status %Rrc\n", rc)); 1335 1493 } 1336 1494 … … 1346 1504 */ 1347 1505 int VBoxX11ClipboardReadX11Data(VBOXCLIPBOARDCONTEXTX11 *pCtx, 1348 uint32_t u32Format, 1349 VBOXCLIPBOARDREQUEST *pRequest) 1350 { 1506 uint32_t u32Format, void *pv, uint32_t cb, 1507 uint32_t *pcbActual) 1508 { 1509 /* Initially set the size of the data read to zero in case we fail 1510 * somewhere or X11 is not available. */ 1511 *pcbActual = 0; 1512 1351 1513 /* 1352 1514 * Immediately return if we are not connected to the host X server. 1353 1515 */ 1354 1516 if (!g_fHaveX11) 1355 {1356 /* no data available */1357 *pRequest->pcbActual = 0;1358 pRequest->rc = VINF_SUCCESS;1359 1517 return VINF_SUCCESS; 1360 } 1361 1362 LogFlowFunc (("u32Format = %d, cb = %d\n", u32Format, pRequest->cb)); 1363 pRequest->rc = VERR_WRONG_ORDER; 1364 1365 /* 1366 * VBox wants to read data in the given format. 1367 */ 1368 if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) 1369 { 1370 if (pCtx->X11TextFormat == INVALID) 1371 { 1372 /* No data available. */ 1373 *pRequest->pcbActual = 0; 1374 return VERR_NO_DATA; /* VBox thinks we have data and we don't */ 1375 } 1376 /* Initially set the size of the data read to zero in case we fail 1377 * somewhere. */ 1378 *pRequest->pcbActual = 0; 1379 /* Send out a request for the data to the current clipboard owner */ 1380 XtGetSelectionValue(pCtx->widget, pCtx->atomClipboard, 1381 pCtx->atomX11TextFormat, 1382 vboxClipboardGetDataFromX11, 1383 reinterpret_cast<XtPointer>(pRequest), 1384 CurrentTime); 1385 /* When the data arrives, the vboxClipboardGetDataFromX11 callback 1386 * will be called. The callback will signal the event semaphore when 1387 * it has processed the data for us. */ 1388 1389 int rc = RTSemEventWait(pCtx->waitForData, RT_INDEFINITE_WAIT); 1390 if (RT_FAILURE(rc)) 1391 return rc; 1392 } 1393 else 1394 { 1395 return VERR_NOT_IMPLEMENTED; 1396 } 1397 LogFlowFunc(("returning %Rrc\n", pRequest->rc)); 1398 return pRequest->rc; 1518 1519 VBOXCLIPBOARDREQUEST request; 1520 request.rc = VERR_WRONG_ORDER; 1521 request.pv = pv; 1522 request.cb = cb; 1523 request.pcbActual = pcbActual; 1524 request.format = u32Format; 1525 request.pCtx = pCtx; 1526 /* The worker function will signal this when it has finished. */ 1527 int rc = RTSemEventCreate(&request.finished); 1528 if (RT_SUCCESS(rc)) 1529 { 1530 /* We use this to schedule a worker function on the event thread. */ 1531 XtAppAddTimeOut(pCtx->appContext, 0, vboxClipboardReadX11Worker, 1532 (XtPointer) &request); 1533 rc = RTSemEventWait(request.finished, RT_INDEFINITE_WAIT); 1534 if (RT_SUCCESS(rc)) 1535 rc = request.rc; 1536 RTSemEventDestroy(request.finished); 1537 } 1538 return rc; 1399 1539 } 1400 1540 … … 1529 1669 char pc[256]; 1530 1670 uint32_t cbActual; 1531 VBOXCLIPBOARDREQUEST request = {(void *) pc, sizeof(pc),1532 &cbActual, VINF_SUCCESS, g_pCtxTestX11};1533 1671 RTPrintf("tstClipboardX11: TESTING a request for an invalid data format\n"); 1534 int rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 1535 0xffff, &request);1672 int rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 0xffff, (void *) pc, 1673 sizeof(pc), &cbActual); 1536 1674 RTPrintf("Returned %Rrc - %s\n", rc, 1537 1675 rc == VERR_NOT_IMPLEMENTED ? "SUCCESS" : "FAILURE"); … … 1539 1677 fSuccess = false; 1540 1678 RTPrintf("tstClipboardX11: TESTING a request for data from an empty clipboard\n"); 1679 VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestX11, 1680 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 1681 VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestX11, 1682 0); 1541 1683 rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 1542 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &request); 1684 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 1685 (void *) pc, sizeof(pc), &cbActual); 1543 1686 RTPrintf("Returned %Rrc - %s\n", rc, 1544 1687 rc == VERR_NO_DATA ? "SUCCESS" : "FAILURE"); … … 1557 1700 char pc[256]; 1558 1701 uint32_t cbActual; 1559 VBOXCLIPBOARDREQUEST request = {(void *) pc, pData->cchBuffer,1560 &cbActual, VINF_SUCCESS, g_pCtxTestX11};1561 1702 for (int i = 0; (i < MAX_ATTEMPTS) && !fSuccess; ++i) 1562 1703 { 1704 VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestVBox, 1705 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 1563 1706 int rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 1564 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &request); 1565 AssertReturn(RT_SUCCESS(rc), 1); 1707 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 1708 (void *) pc, sizeof(pc), 1709 &cbActual); 1710 AssertRCReturn(rc, 1); 1566 1711 /* Did we expect and get an overflow? */ 1567 1712 if ( RT_SUCCESS(rc) … … 1596 1741 int rc = VINF_SUCCESS; 1597 1742 int status = 0; 1598 /* We can't reasonably test anything without an X session, so just1599 * continue. */1743 /* We can't test anything without an X session, so just return success 1744 * in that case. */ 1600 1745 if (!RTEnvGet("DISPLAY")) 1601 1746 return 0; 1602 g_debugClipboard = true;1603 1747 RTR3Init(); 1604 1748 g_pCtxTestX11 = VBoxX11ClipboardConstructX11(NULL); 1605 1749 g_pCtxTestVBox = 1606 1750 VBoxX11ClipboardConstructX11((VBOXCLIPBOARDCONTEXT *)g_pCtxTestX11); 1607 rc = VBoxX11ClipboardStartX11(g_pCtxTestVBox , false);1751 rc = VBoxX11ClipboardStartX11(g_pCtxTestVBox); 1608 1752 AssertRCReturn(rc, 1); 1609 1753 bool fSuccess = false; … … 1612 1756 for (unsigned i = 0; (i < MAX_ATTEMPTS) && !fSuccess; ++i) 1613 1757 { 1614 rc = VBoxX11ClipboardStartX11(g_pCtxTestX11 , false);1758 rc = VBoxX11ClipboardStartX11(g_pCtxTestX11); 1615 1759 AssertRCReturn(rc, 1); 1616 1760 fSuccess = testInvalid(); … … 1624 1768 if (!fSuccess) 1625 1769 status = 1; 1626 rc = VBoxX11ClipboardStartX11(g_pCtxTestX11 , true);1770 rc = VBoxX11ClipboardStartX11(g_pCtxTestX11); 1627 1771 AssertRCReturn(rc, 1); 1628 1772 /* Claim the clipboard and make sure we get it */ … … 1657 1801 char pc[256]; 1658 1802 uint32_t cbActual; 1659 VBOXCLIPBOARDREQUEST request = {(void *) pc, sizeof(pc), 1660 &cbActual, VINF_SUCCESS, 1661 g_pCtxTestX11}; 1803 VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestVBox, 1804 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 1662 1805 rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 1663 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &request); 1806 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 1807 (void *) pc, sizeof(pc), &cbActual); 1664 1808 AssertMsg( RT_SUCCESS(rc) 1665 1809 || (rc == VERR_TIMEOUT)
Note:
See TracChangeset
for help on using the changeset viewer.