Changeset 19027 in vbox for trunk/src/VBox/GuestHost/SharedClipboard
- Timestamp:
- Apr 20, 2009 1:52:58 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 46136
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp
r18890 r19027 412 412 = reinterpret_cast<VBOXCLIPBOARDREQUEST *>(pClientData); 413 413 VBOXCLIPBOARDCONTEXTX11 *pCtx = pRequest->pCtx; 414 pRequest->rc = VINF_SUCCESS; 414 415 LogFlowFunc(("pClientData=%p, *pcLen=%lu, *piFormat=%d\n", pClientData, 415 416 *pcLen, *piFormat)); … … 418 419 unsigned cTextLen = (*pcLen) * (*piFormat) / 8; 419 420 /* The X Toolkit may have failed to get the clipboard selection for us. */ 420 if (*atomType == XT_CONVERT_FAIL) 421 if (*atomType == XT_CONVERT_FAIL) /* timeout */ 422 { 423 pRequest->rc = VERR_TIMEOUT; 424 RTSemEventSignal(pCtx->waitForData); 421 425 return; 426 } 422 427 /* The clipboard selection may have changed before we could get it. */ 423 428 if (NULL == pValue) 429 { 430 pRequest->rc = VERR_NO_DATA; 431 RTSemEventSignal(pCtx->waitForData); 424 432 return; 433 } 425 434 /* In which format is the clipboard data? */ 426 435 switch (pCtx->X11TextFormat) … … 454 463 LogFunc (("bad target format\n")); 455 464 XtFree(reinterpret_cast<char *>(pValue)); 465 pRequest->rc = VERR_INVALID_PARAMETER; 466 RTSemEventSignal(pCtx->waitForData); 456 467 return; 457 468 } … … 482 493 483 494 Log3 (("%s: called\n", __PRETTY_FUNCTION__)); 484 if (*atomType == XT_CONVERT_FAIL) 495 if (*atomType == XT_CONVERT_FAIL) /* timeout */ 485 496 { 486 497 LogFunc (("reading clipboard from host, X toolkit failed to convert the selection\n")); 498 pCtx->atomX11TextFormat = None; 499 pCtx->X11TextFormat = INVALID; 487 500 return; 488 501 } … … 564 577 Log3 (("%s: called\n", __PRETTY_FUNCTION__)); 565 578 /* Get the current clipboard contents */ 566 if ( pCtx->eOwner == X11)579 if ((pCtx->eOwner != VB)) 567 580 { 568 581 Log3 (("%s: requesting the targets that the host clipboard offers\n", … … 817 830 /** @todo Check whether the guest gets a format announcement at 818 831 * startup. */ 819 pCtx->eOwner = VB;832 pCtx->eOwner = NONE; 820 833 VBoxX11ClipboardAnnounceVBoxFormat(pCtx, 0); 821 834 } … … 859 872 /* This might mean that we are getting stopped twice. */ 860 873 AssertReturn(pCtx->widget != NULL, VERR_WRONG_ORDER); 861 pCtx->eOwner = NONE;862 pCtx->X11TextFormat = INVALID;863 pCtx->X11BitmapFormat = INVALID;864 874 LogRelFunc(("stopping the shared clipboard X11 backend\n")); 865 875 … … 874 884 XSendEvent(XtDisplay(pCtx->widget), XtWindow(pCtx->widget), false, 0, &ev); 875 885 XFlush(XtDisplay(pCtx->widget)); 886 pCtx->eOwner = NONE; 887 pCtx->X11TextFormat = INVALID; 888 pCtx->X11BitmapFormat = INVALID; 876 889 do 877 890 { … … 984 997 PRTUTF16 pu16SrcText, pu16DestText; 985 998 char *pu8DestText; 986 void *pvVBox ;987 uint32_t cbVBox ;999 void *pvVBox = NULL; 1000 uint32_t cbVBox = 0; 988 1001 size_t cwSrcLen, cwDestLen, cbDestLen; 989 1002 int rc; … … 1091 1104 { 1092 1105 PRTUTF16 pu16SrcText, pu16DestText; 1093 void *pvVBox ;1094 uint32_t cbVBox ;1106 void *pvVBox = NULL; 1107 uint32_t cbVBox = 0; 1095 1108 char *pu8DestText = 0; 1096 1109 size_t cwSrcLen, cwDestLen, cbDestLen; … … 1293 1306 1294 1307 LogFlowFunc (("u32Formats=%d\n", u32Formats)); 1295 if ((pCtx->eOwner == VB) && (pCtx->vboxFormats == u32Formats))1296 {1297 /* We already own the clipboard, so no need to grab it, especially as1298 * that can lead to races due to the asynchronous nature of the X111299 * clipboard. This event may also have been sent out by the guest to1300 * invalidate the Windows clipboard cache, required because X11 can't1301 * always tell if the clipboard content has changed. */1302 /** @note what races? */1303 /** @note if pCtx->vboxFormats == 0, we may not have really grabbed1304 * the clipboard. */1305 /** @todo clean up the last, it is liable to cause problems. */1306 LogFlowFunc(("returning\n"));1307 return;1308 }1309 1308 pCtx->vboxFormats = u32Formats; 1310 1309 if (u32Formats == 0) 1311 1310 { 1312 1311 /* This is just an automatism, not a genuine anouncement */ 1312 XtDisownSelection(pCtx->widget, pCtx->atomClipboard, CurrentTime); 1313 pCtx->eOwner = NONE; 1313 1314 LogFlowFunc(("returning\n")); 1314 1315 return; … … 1355 1356 /* no data available */ 1356 1357 *pRequest->pcbActual = 0; 1358 pRequest->rc = VINF_SUCCESS; 1357 1359 return VINF_SUCCESS; 1358 1360 } 1359 1361 1360 1362 LogFlowFunc (("u32Format = %d, cb = %d\n", u32Format, pRequest->cb)); 1363 pRequest->rc = VERR_WRONG_ORDER; 1361 1364 1362 1365 /* 1363 * The guestwants to read data in the given format.1366 * VBox wants to read data in the given format. 1364 1367 */ 1365 if (u32Format &VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)1368 if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) 1366 1369 { 1367 1370 if (pCtx->X11TextFormat == INVALID) … … 1369 1372 /* No data available. */ 1370 1373 *pRequest->pcbActual = 0; 1371 return VERR_NO_DATA; /* The guestthinks we have data and we don't */1374 return VERR_NO_DATA; /* VBox thinks we have data and we don't */ 1372 1375 } 1373 1376 /* Initially set the size of the data read to zero in case we fail … … 1380 1383 reinterpret_cast<XtPointer>(pRequest), 1381 1384 CurrentTime); 1382 /* When the data arrives, the vboxClipboardGetDataFromX11 callback will be called. The 1383 callback will signal the event semaphore when it has processed the data for us. */ 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. */ 1384 1388 1385 1389 int rc = RTSemEventWait(pCtx->waitForData, RT_INDEFINITE_WAIT); … … 1391 1395 return VERR_NOT_IMPLEMENTED; 1392 1396 } 1393 return VINF_SUCCESS; 1397 LogFlowFunc(("returning %Rrc\n", pRequest->rc)); 1398 return pRequest->rc; 1394 1399 } 1395 1400 … … 1399 1404 #include <iprt/stream.h> 1400 1405 1406 enum { MAX_ATTEMPTS = 10 }; 1407 1401 1408 static VBOXCLIPBOARDCONTEXTX11 *g_pCtxTestX11; 1402 1409 static VBOXCLIPBOARDCONTEXTX11 *g_pCtxTestVBox; 1403 static const char g_au16Text[] = "H\0e\0l\0l\0o\0 \0w\0o\0r\0l\0d\0\r\0\n\0\0"; 1410 1411 /** Quick Utf16 string class, initialised from a Utf8 string */ 1412 class testUtf16String 1413 { 1414 /** Stores the Utf16 data. NULL if something went wrong. */ 1415 PRTUTF16 mData; 1416 /** Stores the size in bytes of the data. 0 if something went wrong. */ 1417 size_t mSize; 1418 public: 1419 /** Constructor 1420 * @param aString the Utf8 representation of the string data 1421 */ 1422 testUtf16String(const char *aString) 1423 { 1424 int rc = RTStrToUtf16(aString, &mData); 1425 if (RT_FAILURE(rc)) 1426 { 1427 mData = NULL; 1428 mSize = 0; 1429 return; 1430 } 1431 mSize = RTUtf16Len(mData) * 2 + 2; 1432 } 1433 /** Destructor */ 1434 ~testUtf16String() 1435 { 1436 RTUtf16Free(mData); 1437 } 1438 /** Getter for the data */ 1439 PCRTUTF16 getData() { return mData; } 1440 /** Getter for the data size */ 1441 size_t getSize() { return mSize; } 1442 }; 1443 1444 /** Parameters for a test run. */ 1445 static struct testData 1446 { 1447 /** The string data we are offering. */ 1448 testUtf16String data; 1449 /** The size of the buffer to receive the request data */ 1450 uint32_t cchBuffer; 1451 /** The format we request the data in */ 1452 PCRTUTF16 getData() { return data.getData(); } 1453 /** Getter for the Utf16 string data size in bytes */ 1454 size_t getSize() { return data.getSize(); } 1455 /** Is the test expected to produce a buffer overflow? */ 1456 bool overflow() { return cchBuffer < getSize(); } 1457 } g_sTestData[] = 1458 { 1459 { "Hello world\r\n", 256 }, 1460 { "Goodbye world", 28 }, 1461 { "", 2 }, 1462 /* This should produce a buffer overflow */ 1463 { "Goodbye world", 27 }, 1464 }; 1465 1466 /** Which line of the table above are we currently testing? */ 1467 size_t g_testNum = 0; 1468 enum { MAX_TESTS = RT_ELEMENTS(g_sTestData) }; 1469 /** Are we doing a timeout test? Ugly, but whatever. */ 1470 static bool g_testTimeout = false; 1471 1472 /** @todo the current code can't test the following conditions: 1473 * * the X11 clipboard offers non-Utf8 text 1474 * * the X11 clipboard offers invalid Utf8 text 1475 */ 1476 /** @todo stress test our context store code? Probably not important... */ 1404 1477 1405 1478 int VBoxX11ClipboardReadVBoxData(VBOXCLIPBOARDCONTEXT *pCtx, … … 1408 1481 { 1409 1482 LogFlowFunc(("pCtx = %p\n", pCtx)); 1410 void *retval = RTMemDup(g_au16Text, sizeof(g_au16Text)); 1411 if (!retval) 1412 return VERR_NO_MEMORY; 1483 /* This should only ever be called for the second "test" clipboard. */ 1484 AssertReturn(pCtx == (VBOXCLIPBOARDCONTEXT *)g_pCtxTestX11 1485 /* Magic cookie */, VERR_WRONG_ORDER); 1486 /* Timeout test hack */ 1487 if (g_testTimeout) 1488 { 1489 RTThreadSleep(200); 1490 /* Try to return data after we have been timed out. */ 1491 *ppv = RTMemDup((const void *) "Scribblings", sizeof("Scribblings")); 1492 *pcb = sizeof("Scribblings"); 1493 LogFlowFunc(("sleep finished, returning\n")); 1494 return VINF_SUCCESS; 1495 } 1496 /* Sanity. */ 1497 AssertReturn(g_testNum < MAX_TESTS, VERR_WRONG_ORDER); 1498 testData *pData = &g_sTestData[g_testNum]; 1499 AssertPtrReturn(pData->getData(), VERR_NO_MEMORY); 1500 AssertReturn(pData->getSize(), VERR_WRONG_ORDER); 1501 void *retval = RTMemDup((const void *) pData->getData(), 1502 pData->getSize()); 1503 AssertPtrReturn(retval, VERR_NO_MEMORY); 1413 1504 *ppv = (void *) retval; 1414 *pcb = sizeof(g_au16Text); 1505 *pcb = pData->getSize(); 1506 LogFlowFunc(("returning\n")); 1415 1507 return VINF_SUCCESS; 1416 1508 } … … 1427 1519 } 1428 1520 1521 /** Initial tests that can be done while the clipboard contents are still 1522 * invalid. 1523 * @returns boolean success value 1524 * @note prints status information to stdout 1525 */ 1526 bool testInvalid(void) 1527 { 1528 bool fSuccess = true; 1529 char pc[256]; 1530 uint32_t cbActual; 1531 VBOXCLIPBOARDREQUEST request = {(void *) pc, sizeof(pc), 1532 &cbActual, VINF_SUCCESS, g_pCtxTestX11}; 1533 RTPrintf("tstClipboardX11: TESTING a request for an invalid data format\n"); 1534 int rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 1535 0xffff, &request); 1536 RTPrintf("Returned %Rrc - %s\n", rc, 1537 rc == VERR_NOT_IMPLEMENTED ? "SUCCESS" : "FAILURE"); 1538 if (rc != VERR_NOT_IMPLEMENTED) 1539 fSuccess = false; 1540 RTPrintf("tstClipboardX11: TESTING a request for data from an empty clipboard\n"); 1541 rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 1542 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &request); 1543 RTPrintf("Returned %Rrc - %s\n", rc, 1544 rc == VERR_NO_DATA ? "SUCCESS" : "FAILURE"); 1545 if (rc != VERR_NO_DATA) 1546 fSuccess = false; 1547 return fSuccess; 1548 } 1549 1550 /** Tests an entry in the table above. 1551 * @returns boolean success value 1552 * @note prints status information to stdout 1553 */ 1554 bool testEntry(testData *pData) 1555 { 1556 bool fSuccess = false; 1557 char pc[256]; 1558 uint32_t cbActual; 1559 VBOXCLIPBOARDREQUEST request = {(void *) pc, pData->cchBuffer, 1560 &cbActual, VINF_SUCCESS, g_pCtxTestX11}; 1561 for (int i = 0; (i < MAX_ATTEMPTS) && !fSuccess; ++i) 1562 { 1563 int rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 1564 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &request); 1565 AssertReturn(RT_SUCCESS(rc), 1); 1566 /* Did we expect and get an overflow? */ 1567 if ( RT_SUCCESS(rc) 1568 && (cbActual == pData->getSize()) 1569 && pData->overflow()) 1570 fSuccess = true; 1571 /* Did we expect a string and get it? */ 1572 else if ( RT_SUCCESS(rc) 1573 && (memcmp(pc, pData->getData(), 1574 pData->getSize()) == 0)) 1575 fSuccess = true; 1576 else 1577 RTThreadSleep(50); 1578 if (fSuccess) 1579 RTPrintf("text %ls, %sretval %Rrc - SUCCESS\n", 1580 pData->getData(), 1581 pData->overflow() ? "buffer overflow as expected, " 1582 : "", rc); 1583 else 1584 RTPrintf("text %ls, retval %Rrc, attempt %d of %d\n", 1585 pData->getData(), rc, i + 1, 1586 MAX_ATTEMPTS); 1587 } 1588 if (!fSuccess) 1589 RTPrintf("FAILURE. Last string obtained was %.*lS\n", 1590 RT_MIN(cbActual / 2, 20), pc); 1591 return fSuccess; 1592 } 1593 1429 1594 int main() 1430 1595 { 1431 1596 int rc = VINF_SUCCESS; 1597 int status = 0; 1598 /* We can't reasonably test anything without an X session, so just 1599 * continue. */ 1600 if (!RTEnvGet("DISPLAY")) 1601 return 0; 1602 g_debugClipboard = true; 1432 1603 RTR3Init(); 1433 1604 g_pCtxTestX11 = VBoxX11ClipboardConstructX11(NULL); 1434 1605 g_pCtxTestVBox = 1435 1606 VBoxX11ClipboardConstructX11((VBOXCLIPBOARDCONTEXT *)g_pCtxTestX11); 1436 rc = VBoxX11ClipboardStartX11(g_pCtxTestX11, true);1437 1607 rc = VBoxX11ClipboardStartX11(g_pCtxTestVBox, false); 1438 1608 AssertRCReturn(rc, 1); 1609 bool fSuccess = false; 1610 /* Test a request for an invalid data format and data from an empty 1611 * clipboard */ 1612 for (unsigned i = 0; (i < MAX_ATTEMPTS) && !fSuccess; ++i) 1613 { 1614 rc = VBoxX11ClipboardStartX11(g_pCtxTestX11, false); 1615 AssertRCReturn(rc, 1); 1616 fSuccess = testInvalid(); 1617 VBoxX11ClipboardStopX11(g_pCtxTestX11); 1618 if (!fSuccess) 1619 { 1620 RTPrintf("attempt %d of %d\n", i + 1, MAX_ATTEMPTS + 1); 1621 RTThreadSleep(50); 1622 } 1623 } 1624 if (!fSuccess) 1625 status = 1; 1626 rc = VBoxX11ClipboardStartX11(g_pCtxTestX11, true); 1627 AssertRCReturn(rc, 1); 1628 /* Claim the clipboard and make sure we get it */ 1439 1629 VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestVBox, 1440 1630 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 1441 for (unsigned i = 0; i < 255 && g_pCtxTestX11->X11TextFormat == INVALID; 1631 for (unsigned i = 0; 1632 i < 255 1633 && g_pCtxTestX11->X11TextFormat == INVALID; 1442 1634 ++i) 1443 1635 RTThreadSleep(50); 1444 1636 AssertReturn(g_pCtxTestX11->X11TextFormat != INVALID, 1); 1445 char pc[256]; 1446 uint32_t cbActual; 1447 VBOXCLIPBOARDREQUEST request = {(void *) pc, sizeof(pc), &cbActual, 1448 g_pCtxTestX11}; 1637 /* Do general purpose clipboard tests */ 1449 1638 for (int i = 0; i < 2; ++i) 1450 1639 { 1451 enum { MAX_ATTEMPTS = 10 };1452 bool fSuccess = false;1453 1640 g_testUtf8 = (i == 0); 1454 1641 g_testCText = (i == 1); 1455 for (int j = 0; (j < MAX_ATTEMPTS) && !fSuccess; ++j) 1456 { 1457 RTPrintf("tstClipboardX11: TESTING sending and receiving of %s, attempt %d of %d\n", 1458 i == 0 ? "Utf-8" : "COMPOUND TEXT", j + 1, MAX_ATTEMPTS); 1459 rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 1460 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &request); 1461 AssertRCReturn(rc, 1); 1462 if (memcmp(pc, g_au16Text, sizeof(g_au16Text)) == 0) 1463 fSuccess = true; 1464 else 1465 RTThreadSleep(50); 1466 } 1467 if (fSuccess) 1642 RTPrintf("tstClipboardX11: TESTING sending and receiving of %s\n", 1643 i == 0 ? "Utf-8" : "COMPOUND TEXT"); 1644 for (g_testNum = 0; g_testNum < MAX_TESTS; ++g_testNum) 1645 { 1646 if (!testEntry(&g_sTestData[g_testNum])) 1647 status = 1; 1648 } 1649 } 1650 /* Finally test timeouts. */ 1651 XtAppSetSelectionTimeout(g_pCtxTestX11->appContext, 10); 1652 RTPrintf("tstClipboardX11: TESTING the clipboard timeout\n"); 1653 rc = VINF_SUCCESS; 1654 g_testTimeout = true; 1655 for (unsigned i = 0; (i < MAX_ATTEMPTS) && (rc != VERR_TIMEOUT); ++i) 1656 { 1657 char pc[256]; 1658 uint32_t cbActual; 1659 VBOXCLIPBOARDREQUEST request = {(void *) pc, sizeof(pc), 1660 &cbActual, VINF_SUCCESS, 1661 g_pCtxTestX11}; 1662 rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 1663 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &request); 1664 AssertMsg( RT_SUCCESS(rc) 1665 || (rc == VERR_TIMEOUT) 1666 || (rc == VERR_NO_DATA), 1667 ("rc = %Rrc\n", rc)); 1668 if (rc == VERR_TIMEOUT) 1468 1669 RTPrintf("SUCCESS\n"); 1469 1670 else 1470 RTPrintf("FAILURE. Last string obtained was %.*lS\n", 1471 RT_MIN(cbActual / 2, 20), pc); 1472 } 1671 { 1672 RTPrintf("Attempt %d of %d\n", i + 1, MAX_ATTEMPTS); 1673 RTThreadSleep(50); 1674 } 1675 } 1676 if (rc != VERR_TIMEOUT) 1677 status = 1; 1473 1678 rc = VBoxX11ClipboardStopX11(g_pCtxTestX11); 1474 1679 AssertRCReturn(rc, 1); … … 1477 1682 VBoxX11ClipboardDestructX11(g_pCtxTestX11); 1478 1683 VBoxX11ClipboardDestructX11(g_pCtxTestVBox); 1479 return 0;1684 return status; 1480 1685 } 1481 1686
Note:
See TracChangeset
for help on using the changeset viewer.