Changeset 19505 in vbox
- Timestamp:
- May 7, 2009 8:04:03 PM (16 years ago)
- Location:
- trunk/src/VBox/GuestHost/SharedClipboard
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/GuestHost/SharedClipboard/Makefile.kmk
r18892 r19505 29 29 # 30 30 if1of ($(KBUILD_TARGET),freebsd linux netbsd openbsd solaris) 31 PROGRAMS += tstClipboardX11 31 PROGRAMS += tstClipboardX11 tstClipboardX11Smoke 32 32 tstClipboardX11_TEMPLATE = VBOXR3TSTEXE 33 # The second define here is to ensure that the testcase will run fast, without34 # waiting for any thread synchronisation.35 33 tstClipboardX11_DEFS = VBOX_WITH_HGCM TESTCASE 36 34 tstClipboardX11_SOURCES = x11-clipboard.cpp clipboard-helper.cpp 37 tstClipboardX11_LIBPATH = $(VBOX_LIBPATH_X11) 38 tstClipboardX11_LIBS = $(LIB_RUNTIME) X11 Xt 35 tstClipboardX11_LIBS = $(LIB_RUNTIME) 36 37 tstClipboardX11Smoke_TEMPLATE = VBOXR3TSTEXE 38 tstClipboardX11Smoke_DEFS = VBOX_WITH_HGCM SMOKETEST 39 tstClipboardX11Smoke_SOURCES = x11-clipboard.cpp clipboard-helper.cpp 40 tstClipboardX11Smoke_LIBPATH = $(VBOX_LIBPATH_X11) 41 tstClipboardX11Smoke_LIBS = $(LIB_RUNTIME) X11 Xt 39 42 40 43 # Set this in LocalConfig.kmk if you are working on the X11 clipboard service … … 47 50 export VBOX_LOG_DEST=nofile; $(INSTARGET_tstClipboardX11) quiet 48 51 $(QUIET)$(APPEND) -t "$@" "done" 52 53 TESTING += $(PATH_tstClipboardX11Smoke)/tstClipboardX11Smoke.run 54 OTHERS += $(PATH_tstClipboardX11Smoke)/tstClipboardX11Smoke.run 55 $$(PATH_tstClipboardX11Smoke)/tstClipboardX11Smoke.run: \ 56 $$(INSTARGET_tstClipboardX11) 57 export VBOX_LOG_DEST=nofile; $(INSTARGET_tstClipboardX11Smoke) quiet 58 $(QUIET)$(APPEND) -t "$@" "done" 49 59 endif 50 60 endif -
trunk/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp
r18398 r19505 32 32 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc)); 33 33 AssertLogRelMsgReturn(pwszSrc != NULL, ("vboxClipboardUtf16GetWinSize: received a null Utf16 string, returning VERR_INVALID_PARAMETER\n"), VERR_INVALID_PARAMETER); 34 if (cwSrc == 0) 35 { 36 *pcwDest = 0; 37 LogFlowFunc(("empty source string, returning\n")); 38 return VINF_SUCCESS; 39 } 34 40 /** @todo convert the remainder of the Assert stuff to AssertLogRel. */ 35 41 /* We only take little endian Utf16 */ … … 38 44 LogRel(("vboxClipboardUtf16GetWinSize: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n")); 39 45 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER); 40 }41 if (cwSrc == 0)42 {43 *pcwDest = 0;44 LogFlowFunc(("empty source string, returning\n"));45 return VINF_SUCCESS;46 46 } 47 47 cwDest = 0; … … 79 79 AssertReturn(VALID_PTR(pwszSrc) && VALID_PTR(pu16Dest), VERR_INVALID_PARAMETER); 80 80 } 81 if (cwSrc == 0) 82 { 83 if (cwDest == 0) 84 { 85 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n")); 86 return VERR_BUFFER_OVERFLOW; 87 } 88 pu16Dest[0] = 0; 89 LogFlowFunc(("empty source string, returning\n")); 90 return VINF_SUCCESS; 91 } 81 92 /* We only take little endian Utf16 */ 82 93 if (pwszSrc[0] == UTF16BEMARKER) … … 84 95 LogRel(("vboxClipboardUtf16LinToWin: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n")); 85 96 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER); 86 }87 if (cwSrc == 0)88 {89 if (cwDest == 0)90 {91 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));92 return VERR_BUFFER_OVERFLOW;93 }94 pu16Dest[0] = 0;95 LogFlowFunc(("empty source string, returning\n"));96 return VINF_SUCCESS;97 97 } 98 98 /* Don't copy the endian marker. */ … … 155 155 AssertReturn(VALID_PTR(pwszSrc), VERR_INVALID_PARAMETER); 156 156 } 157 if (cwSrc == 0) 158 { 159 LogFlowFunc(("empty source string, returning VINF_SUCCESS\n")); 160 *pcwDest = 0; 161 return VINF_SUCCESS; 162 } 157 163 /* We only take little endian Utf16 */ 158 164 if (pwszSrc[0] == UTF16BEMARKER) … … 160 166 LogRel(("vboxClipboardUtf16GetLinSize: received a big endian Utf16 string. Returning VERR_INVALID_PARAMETER.\n")); 161 167 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER); 162 }163 if (cwSrc == 0)164 {165 LogFlowFunc(("empty source string, returning VINF_SUCCESS\n"));166 *pcwDest = 0;167 return VINF_SUCCESS;168 168 } 169 169 /* Calculate the size of the destination text string. */ -
trunk/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp
r19220 r19505 283 283 int rc = RTStrToUtf16Ex(pu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen); 284 284 if (RT_SUCCESS(rc)) 285 rc = vboxClipboardWriteUtf16LE(pCtx, pu16SrcText, cwSrcLen ,285 rc = vboxClipboardWriteUtf16LE(pCtx, pu16SrcText, cwSrcLen + 1, 286 286 pv, cb, pcbActual); 287 287 XtFree(reinterpret_cast<char *>(pValue)); … … 360 360 rc = RTStrToUtf16Ex(*ppu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen); 361 361 if (RT_SUCCESS(rc)) 362 rc = vboxClipboardWriteUtf16LE(pCtx, pu16SrcText, cwSrcLen ,362 rc = vboxClipboardWriteUtf16LE(pCtx, pu16SrcText, cwSrcLen + 1, 363 363 pv, cb, pcbActual); 364 364 if (ppu8SrcText != NULL) … … 625 625 } 626 626 627 enum { TIMER_FREQ = 200 /* ms */ }; 628 629 static void vboxClipboardPollX11ForTargets(XtPointer pUserData, 630 XtIntervalId * /* hTimerId */); 631 static void clipSchedulePoller(VBOXCLIPBOARDCONTEXTX11 *pCtx, 632 XtTimerCallbackProc proc); 633 634 #ifndef TESTCASE 635 void clipSchedulePoller(VBOXCLIPBOARDCONTEXTX11 *pCtx, 636 XtTimerCallbackProc proc) 637 { 638 XtAppAddTimeOut(pCtx->appContext, TIMER_FREQ, proc, pCtx); 639 } 640 #endif 641 627 642 /** 628 643 * This timer callback is called every 200ms to check the contents of the X11 … … 633 648 * available. 634 649 */ 635 staticvoid vboxClipboardPollX11ForTargets(XtPointer pUserData,636 650 void vboxClipboardPollX11ForTargets(XtPointer pUserData, 651 XtIntervalId * /* hTimerId */) 637 652 { 638 653 VBOXCLIPBOARDCONTEXTX11 *pCtx = … … 650 665 } 651 666 /* Re-arm our timer */ 652 XtAppAddTimeOut(pCtx->appContext, 200 /* ms */,653 vboxClipboardPollX11ForTargets, pCtx); 654 } 655 667 clipSchedulePoller(pCtx, vboxClipboardPollX11ForTargets); 668 } 669 670 #ifndef TESTCASE 656 671 /** 657 672 * The main loop of our clipboard reader. … … 664 679 VBOXCLIPBOARDCONTEXTX11 *pCtx = 665 680 reinterpret_cast<VBOXCLIPBOARDCONTEXTX11 *>(pvUser); 666 /* Set up a timer to poll the host clipboard */667 XtAppAddTimeOut(pCtx->appContext, 200 /* ms */,668 vboxClipboardPollX11ForTargets, pCtx);669 670 681 while (XtAppGetExitFlag(pCtx->appContext) == FALSE) 671 682 XtAppProcessEvent(pCtx->appContext, XtIMAll); … … 673 684 return VINF_SUCCESS; 674 685 } 686 #endif 675 687 676 688 /** X11 specific uninitialisation for the shared clipboard. … … 759 771 XtSetMappedWhenManaged(pCtx->widget, false); 760 772 XtRealizeWidget(pCtx->widget); 773 /* Set up a timer to poll the host clipboard */ 774 clipSchedulePoller(pCtx, vboxClipboardPollX11ForTargets); 761 775 } 762 776 /* Create the pipes */ … … 766 780 pCtx->wakeupPipeRead = pipes[0]; 767 781 pCtx->wakeupPipeWrite = pipes[1]; 768 XtAppAddInput(pCtx->appContext, pCtx->wakeupPipeRead, 769 (XtPointer) XtInputReadMask, vboxClipboardStopWorker, 770 (XtPointer) pCtx); 782 if (!XtAppAddInput(pCtx->appContext, pCtx->wakeupPipeRead, 783 (XtPointer) XtInputReadMask, 784 vboxClipboardStopWorker, (XtPointer) pCtx)) 785 rc = VERR_NO_MEMORY; /* What failure means is not doc'ed. */ 771 786 } 772 787 else … … 857 872 858 873 rc = vboxClipboardInitX11(pCtx); 874 #ifndef TESTCASE 859 875 if (RT_SUCCESS(rc)) 860 876 { … … 864 880 LogRel(("Failed to initialise the shared clipboard X11 backend.\n")); 865 881 } 882 #endif 866 883 if (RT_SUCCESS(rc)) 867 884 { … … 1123 1140 *atomTypeReturn = clipGetAtom(pCtx->widget, "UTF8_STRING"); 1124 1141 *pValReturn = reinterpret_cast<XtPointer>(pu8DestText); 1125 *pcLenReturn = cbDestLen ;1142 *pcLenReturn = cbDestLen + 1; 1126 1143 *piFormatReturn = 8; 1127 1144 return true; … … 1253 1270 *atomTypeReturn = property.encoding; 1254 1271 *pValReturn = reinterpret_cast<XtPointer>(property.value); 1255 *pcLenReturn = property.nitems ;1272 *pcLenReturn = property.nitems + 1; 1256 1273 *piFormatReturn = property.format; 1257 1274 return true; … … 1349 1366 } 1350 1367 1368 static void clipSchedule(XtAppContext app_context, XtTimerCallbackProc proc, 1369 XtPointer client_data); 1370 #ifndef TESTCASE 1371 void clipSchedule(XtAppContext app_context, XtTimerCallbackProc proc, 1372 XtPointer client_data) 1373 { 1374 XtAppAddTimeOut(app_context, 0, proc, client_data); 1375 } 1376 #endif 1377 1351 1378 /** Structure used to pass information about formats that VBox supports */ 1352 1379 typedef struct _VBOXCLIPBOARDFORMATS … … 1429 1456 pFormats->pCtx = pCtx; 1430 1457 pFormats->formats = u32Formats; 1431 XtAppAddTimeOut(pCtx->appContext, 0, vboxClipboardAnnounceWorker,1432 1458 clipSchedule(pCtx->appContext, vboxClipboardAnnounceWorker, 1459 (XtPointer) pFormats); 1433 1460 } 1434 1461 } … … 1518 1545 { 1519 1546 /* We use this to schedule a worker function on the event thread. */ 1520 XtAppAddTimeOut(pCtx->appContext, 0, vboxClipboardReadX11Worker,1521 1547 clipSchedule(pCtx->appContext, vboxClipboardReadX11Worker, 1548 (XtPointer) &request); 1522 1549 rc = RTSemEventWait(request.finished, RT_INDEFINITE_WAIT); 1523 1550 if (RT_SUCCESS(rc)) … … 1532 1559 #include <iprt/initterm.h> 1533 1560 #include <iprt/stream.h> 1534 1535 enum { MAX_ATTEMPTS = 10 }; 1536 1537 static VBOXCLIPBOARDCONTEXTX11 *g_pCtxTestX11; 1538 static VBOXCLIPBOARDCONTEXTX11 *g_pCtxTestVBox; 1539 1540 /** Quick Utf16 string class, initialised from a Utf8 string */ 1541 class testUtf16String 1542 { 1543 /** Stores the Utf16 data. NULL if something went wrong. */ 1544 PRTUTF16 mData; 1545 /** Stores the size in bytes of the data. 0 if something went wrong. */ 1546 size_t mSize; 1547 public: 1548 /** Constructor 1549 * @param aString the Utf8 representation of the string data 1550 */ 1551 testUtf16String(const char *aString) 1552 { 1553 int rc = RTStrToUtf16(aString, &mData); 1554 if (RT_FAILURE(rc)) 1555 { 1556 mData = NULL; 1557 mSize = 0; 1558 return; 1559 } 1560 mSize = RTUtf16Len(mData) * 2 + 2; 1561 } 1562 /** Destructor */ 1563 ~testUtf16String() 1564 { 1565 RTUtf16Free(mData); 1566 } 1567 /** Getter for the data */ 1568 PCRTUTF16 getData() { return mData; } 1569 /** Getter for the data size */ 1570 size_t getSize() { return mSize; } 1571 }; 1572 1573 /** Parameters for a test run. */ 1574 static struct testData 1575 { 1576 /** The string data we are offering. */ 1577 testUtf16String data; 1578 /** The size of the buffer to receive the request data */ 1579 uint32_t cchBuffer; 1580 /** The format we request the data in */ 1581 PCRTUTF16 getData() { return data.getData(); } 1582 /** Getter for the Utf16 string data size in bytes */ 1583 size_t getSize() { return data.getSize(); } 1584 /** Is the test expected to produce a buffer overflow? */ 1585 bool overflow() { return cchBuffer < getSize(); } 1586 } g_sTestData[] = 1587 { 1588 { "Hello world\r\n", 256 }, 1589 { "Goodbye world", 28 }, 1590 { "", 2 }, 1591 /* This should produce a buffer overflow */ 1592 { "Goodbye world", 27 }, 1593 }; 1594 1595 /** Which line of the table above are we currently testing? */ 1596 size_t g_testNum = 0; 1597 enum { MAX_TESTS = RT_ELEMENTS(g_sTestData) }; 1598 /** Are we doing a timeout test? Ugly, but whatever. */ 1599 static bool g_testTimeout = false; 1600 1601 /** @todo the current code can't test the following conditions: 1602 * * the X11 clipboard offers non-Utf8 text 1603 * * the X11 clipboard offers invalid Utf8 text 1604 */ 1605 /** @todo stress test our context store code? Probably not important... */ 1606 1561 #include <poll.h> 1562 1563 #define TEST_NAME "tstClipboardX11" 1564 #define TEST_WIDGET (Widget)0xffff 1565 1566 /* Our X11 clipboard target poller */ 1567 static XtTimerCallbackProc g_pfnPoller = NULL; 1568 /* User data for the poller function. */ 1569 static XtPointer g_pPollerData = NULL; 1570 1571 /* For the testcase, we install the poller function in a global variable 1572 * which is called when the testcase updates the X11 targets. */ 1573 void clipSchedulePoller(VBOXCLIPBOARDCONTEXTX11 *pCtx, 1574 XtTimerCallbackProc proc) 1575 { 1576 g_pfnPoller = proc; 1577 g_pPollerData = (XtPointer)pCtx; 1578 } 1579 1580 static bool clipPollTargets() 1581 { 1582 if (!g_pfnPoller) 1583 return false; 1584 g_pfnPoller(g_pPollerData, NULL); 1585 return true; 1586 } 1587 1588 /* For the purpose of the test case, we just execute the procedure to be 1589 * scheduled, as we are running single threaded. */ 1590 void clipSchedule(XtAppContext app_context, XtTimerCallbackProc proc, 1591 XtPointer client_data) 1592 { 1593 proc(client_data, NULL); 1594 } 1595 1596 void XtFree(char *ptr) 1597 { RTMemFree((void *) ptr); } 1598 1599 /* The data in the simulated VBox clipboard */ 1600 static int g_vboxDataRC = VINF_SUCCESS; 1601 static void *g_vboxDatapv = NULL; 1602 static uint32_t g_vboxDatacb = 0; 1603 1604 /* Set empty data in the simulated VBox clipboard. */ 1605 static void clipEmptyVBox(VBOXCLIPBOARDCONTEXTX11 *pCtx, int retval) 1606 { 1607 g_vboxDataRC = retval; 1608 g_vboxDatapv = NULL; 1609 g_vboxDatacb = 0; 1610 VBoxX11ClipboardAnnounceVBoxFormat(pCtx, 0); 1611 } 1612 1613 /* Set the data in the simulated VBox clipboard. */ 1614 static int clipSetVBoxUtf16(VBOXCLIPBOARDCONTEXTX11 *pCtx, int retval, 1615 const char *pcszData) 1616 { 1617 PRTUTF16 pwszData = NULL; 1618 size_t cwData = 0; 1619 int rc = RTStrToUtf16Ex(pcszData, RTSTR_MAX, &pwszData, 0, &cwData); 1620 if (RT_FAILURE(rc)) 1621 return rc; 1622 size_t cb = cwData * 2 + 2; 1623 void *pv = RTMemDup(pwszData, cb); 1624 RTUtf16Free(pwszData); 1625 if (pv == NULL) 1626 return VERR_NO_MEMORY; 1627 if (g_vboxDatapv) 1628 RTMemFree(g_vboxDatapv); 1629 g_vboxDataRC = retval; 1630 g_vboxDatapv = pv; 1631 g_vboxDatacb = cb; 1632 VBoxX11ClipboardAnnounceVBoxFormat(pCtx, 1633 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 1634 return VINF_SUCCESS; 1635 } 1636 1637 /* Return the data in the simulated VBox clipboard. */ 1607 1638 int VBoxX11ClipboardReadVBoxData(VBOXCLIPBOARDCONTEXT *pCtx, 1608 1639 uint32_t u32Format, void **ppv, 1609 1640 uint32_t *pcb) 1610 1641 { 1611 LogFlowFunc(("pCtx = %p\n", pCtx)); 1612 /* This should only ever be called for the second "test" clipboard. */ 1613 AssertReturn(pCtx == (VBOXCLIPBOARDCONTEXT *)g_pCtxTestX11 1614 /* Magic cookie */, VERR_WRONG_ORDER); 1615 /* Timeout test hack */ 1616 if (g_testTimeout) 1617 { 1618 RTThreadSleep(200); 1619 /* Try to return data after we have been timed out. */ 1620 *ppv = RTMemDup((const void *) "Scribblings", sizeof("Scribblings")); 1621 *pcb = sizeof("Scribblings"); 1622 LogFlowFunc(("sleep finished, returning\n")); 1623 return VINF_SUCCESS; 1624 } 1625 /* Sanity. */ 1626 AssertReturn(g_testNum < MAX_TESTS, VERR_WRONG_ORDER); 1627 testData *pData = &g_sTestData[g_testNum]; 1628 AssertPtrReturn(pData->getData(), VERR_NO_MEMORY); 1629 AssertReturn(pData->getSize(), VERR_WRONG_ORDER); 1630 void *retval = RTMemDup((const void *) pData->getData(), 1631 pData->getSize()); 1632 AssertPtrReturn(retval, VERR_NO_MEMORY); 1633 *ppv = (void *) retval; 1634 *pcb = pData->getSize(); 1635 LogFlowFunc(("returning\n")); 1636 return VINF_SUCCESS; 1637 } 1638 1639 /** As long as our test is running, we grab back the clipboard if X11 ever 1640 * tries to take it away. I hope we don't end up with a tug of war... */ 1642 *pcb = g_vboxDatacb; 1643 if (g_vboxDatapv != NULL) 1644 { 1645 void *pv = RTMemDup(g_vboxDatapv, g_vboxDatacb); 1646 *ppv = pv; 1647 return pv != NULL ? g_vboxDataRC : VERR_NO_MEMORY; 1648 } 1649 *ppv = NULL; 1650 return g_vboxDataRC; 1651 } 1652 1653 Display *XtDisplay(Widget w) 1654 { return (Display *) 0xffff; } 1655 1656 int XmbTextListToTextProperty(Display *display, char **list, int count, 1657 XICCEncodingStyle style, 1658 XTextProperty *text_prop_return) 1659 { 1660 /* We don't fully reimplement this API for obvious reasons. */ 1661 AssertReturn(count == 1, XLocaleNotSupported); 1662 AssertReturn(style == XCompoundTextStyle, XLocaleNotSupported); 1663 /* We simplify the conversion by only accepting ASCII. */ 1664 for (unsigned i = 0; (*list)[i] != 0; ++i) 1665 AssertReturn(((*list)[i] & 0x80) == 0, XLocaleNotSupported); 1666 text_prop_return->value = 1667 (unsigned char*)RTMemDup(*list, strlen(*list) + 1); 1668 text_prop_return->encoding = clipGetAtom(NULL, "COMPOUND_TEXT"); 1669 text_prop_return->format = 8; 1670 text_prop_return->nitems = strlen(*list); 1671 return 0; 1672 } 1673 1674 int Xutf8TextListToTextProperty(Display *display, char **list, int count, 1675 XICCEncodingStyle style, 1676 XTextProperty *text_prop_return) 1677 { 1678 return XmbTextListToTextProperty(display, list, count, style, 1679 text_prop_return); 1680 } 1681 1682 int XmbTextPropertyToTextList(Display *display, 1683 const XTextProperty *text_prop, 1684 char ***list_return, int *count_return) 1685 { 1686 int rc = 0; 1687 if (text_prop->nitems == 0) 1688 { 1689 *list_return = NULL; 1690 *count_return = 0; 1691 return 0; 1692 } 1693 /* Only accept simple ASCII properties */ 1694 for (unsigned i = 0; i < text_prop->nitems; ++i) 1695 AssertReturn(!(text_prop->value[i] & 0x80), XConverterNotFound); 1696 char **ppList = (char **)RTMemAlloc(sizeof(char *)); 1697 char *pValue = (char *)RTMemDup(text_prop->value, text_prop->nitems + 1); 1698 if (ppList) 1699 *ppList = pValue; 1700 if (!ppList || !pValue) 1701 { 1702 RTMemFree(ppList); 1703 RTMemFree(pValue); 1704 rc = XNoMemory; 1705 } 1706 else 1707 { 1708 /* NULL-terminate the string */ 1709 pValue[text_prop->nitems] = '\0'; 1710 *count_return = 1; 1711 *list_return = ppList; 1712 } 1713 return rc; 1714 } 1715 1716 int Xutf8TextPropertyToTextList(Display *display, 1717 const XTextProperty *text_prop, 1718 char ***list_return, int *count_return) 1719 { 1720 return XmbTextPropertyToTextList(display, text_prop, list_return, 1721 count_return); 1722 } 1723 1724 void XtAppSetExitFlag(XtAppContext app_context) {} 1725 1726 void XtDestroyWidget(Widget w) {} 1727 1728 XtAppContext XtCreateApplicationContext(void) { return (XtAppContext)0xffff; } 1729 1730 void XtDestroyApplicationContext(XtAppContext app_context) {} 1731 1732 void XtToolkitInitialize(void) {} 1733 1734 Boolean XtToolkitThreadInitialize(void) { return True; } 1735 1736 Display *XtOpenDisplay(XtAppContext app_context, 1737 _Xconst _XtString display_string, 1738 _Xconst _XtString application_name, 1739 _Xconst _XtString application_class, 1740 XrmOptionDescRec *options, Cardinal num_options, 1741 int *argc, char **argv) 1742 { return (Display *)0xffff; } 1743 1744 Widget XtVaAppCreateShell(_Xconst _XtString application_name, 1745 _Xconst _XtString application_class, 1746 WidgetClass widget_class, Display *display, ...) 1747 { return TEST_WIDGET; } 1748 1749 void XtSetMappedWhenManaged(Widget widget, _XtBoolean mapped_when_managed) {} 1750 1751 void XtRealizeWidget(Widget widget) {} 1752 1753 XtInputId XtAppAddInput(XtAppContext app_context, int source, 1754 XtPointer condition, XtInputCallbackProc proc, 1755 XtPointer closure) 1756 { return 0xffff; } 1757 1758 /* Atoms we need other than the formats we support. */ 1759 static const char *g_apszSupAtoms[] = 1760 { 1761 "PRIMARY", "CLIPBOARD", "TARGETS", "MULTIPLE", "TIMESTAMP" 1762 }; 1763 1764 /* This just looks for the atom names in a couple of tables and returns an 1765 * index with an offset added. */ 1766 Boolean XtConvertAndStore(Widget widget, _Xconst _XtString from_type, 1767 XrmValue* from, _Xconst _XtString to_type, 1768 XrmValue* to_in_out) 1769 { 1770 Boolean rc = False; 1771 /* What we support is: */ 1772 AssertReturn(from_type == XtRString, False); 1773 AssertReturn(to_type == XtRAtom, False); 1774 for (unsigned i = 0; i < RT_ELEMENTS(g_aFormats); ++i) 1775 if (!strcmp(from->addr, g_aFormats[i].pcszAtom)) 1776 { 1777 *(Atom *)(to_in_out->addr) = (Atom) (i + 0x1000); 1778 rc = True; 1779 } 1780 for (unsigned i = 0; i < RT_ELEMENTS(g_apszSupAtoms); ++i) 1781 if (!strcmp(from->addr, g_apszSupAtoms[i])) 1782 { 1783 *(Atom *)(to_in_out->addr) = (Atom) (i + 0x2000); 1784 rc = True; 1785 } 1786 Assert(rc == True); /* Have we missed any atoms? */ 1787 return rc; 1788 } 1789 1790 /* The current values of the X selection, which will be returned to the 1791 * XtGetSelectionValue callback. */ 1792 static Atom g_selTarget = 0; 1793 static Atom g_selType = 0; 1794 static const void *g_pSelData = NULL; 1795 static unsigned long g_cSelData = 0; 1796 static int g_selFormat = 0; 1797 1798 void XtGetSelectionValue(Widget widget, Atom selection, Atom target, 1799 XtSelectionCallbackProc callback, 1800 XtPointer closure, Time time) 1801 { 1802 unsigned long count = 0; 1803 int format = 0; 1804 Atom type = XA_STRING; 1805 if ( ( selection != clipGetAtom(NULL, "PRIMARY") 1806 && selection != clipGetAtom(NULL, "CLIPBOARD") 1807 && selection != clipGetAtom(NULL, "TARGETS")) 1808 || ( target != g_selTarget 1809 && target != clipGetAtom(NULL, "TARGETS"))) 1810 { 1811 /* Otherwise this is probably a caller error. */ 1812 Assert(target != g_selTarget); 1813 callback(NULL, closure, &selection, &type, NULL, &count, &format); 1814 /* Could not convert to target. */ 1815 return; 1816 } 1817 XtPointer pValue = NULL; 1818 if (target == clipGetAtom(NULL, "TARGETS")) 1819 { 1820 pValue = (XtPointer) RTMemDup(&g_selTarget, sizeof(g_selTarget)); 1821 type = XA_ATOM; 1822 count = 1; 1823 format = 32; 1824 } 1825 else 1826 { 1827 pValue = (XtPointer) g_pSelData ? RTMemDup(g_pSelData, g_cSelData) 1828 : NULL; 1829 type = g_selType; 1830 count = g_pSelData ? g_cSelData : 0; 1831 format = g_selFormat; 1832 } 1833 if (!pValue) 1834 { 1835 count = 0; 1836 format = 0; 1837 } 1838 callback(NULL, closure, &selection, &type, pValue, 1839 &count, &format); 1840 } 1841 1842 /* The formats currently on offer from X11 via the shared clipboard */ 1843 static uint32_t g_fX11Formats = 0; 1844 1845 void VBoxX11ClipboardReportX11Formats(VBOXCLIPBOARDCONTEXT* pCtx, 1846 uint32_t u32Formats) 1847 { 1848 g_fX11Formats = u32Formats; 1849 } 1850 1851 static uint32_t clipQueryFormats() 1852 { 1853 return g_fX11Formats; 1854 } 1855 1856 /* Does our clipboard code currently own the selection? */ 1857 static bool g_ownsSel = false; 1858 /* The procedure that is called when we should convert the selection to a 1859 * given format. */ 1860 static XtConvertSelectionProc g_pfnSelConvert = NULL; 1861 /* The procedure which is called when we lose the selection. */ 1862 static XtLoseSelectionProc g_pfnSelLose = NULL; 1863 /* The procedure which is called when the selection transfer has completed. */ 1864 static XtSelectionDoneProc g_pfnSelDone = NULL; 1865 1866 Boolean XtOwnSelection(Widget widget, Atom selection, Time time, 1867 XtConvertSelectionProc convert, 1868 XtLoseSelectionProc lose, 1869 XtSelectionDoneProc done) 1870 { 1871 if (selection != clipGetAtom(NULL, "CLIPBOARD")) 1872 return True; /* We don't really care about this. */ 1873 g_ownsSel = true; /* Always succeed. */ 1874 g_pfnSelConvert = convert; 1875 g_pfnSelLose = lose; 1876 g_pfnSelDone = done; 1877 return True; 1878 } 1879 1880 void XtDisownSelection(Widget widget, Atom selection, Time time) 1881 { 1882 g_ownsSel = false; 1883 g_pfnSelConvert = NULL; 1884 g_pfnSelLose = NULL; 1885 g_pfnSelDone = NULL; 1886 } 1887 1888 /* Request the shared clipboard to convert its data to a given format. */ 1889 static bool clipConvertSelection(const char *pcszTarget, Atom *type, 1890 XtPointer *value, unsigned long *length, 1891 int *format) 1892 { 1893 Atom target = clipGetAtom(NULL, pcszTarget); 1894 if (target == 0) 1895 return false; 1896 /* Initialise all return values in case we make a quick exit. */ 1897 *type = XA_STRING; 1898 *value = NULL; 1899 *length = 0; 1900 *format = 0; 1901 if (!g_ownsSel) 1902 return false; 1903 if (!g_pfnSelConvert) 1904 return false; 1905 Atom clipAtom = clipGetAtom(NULL, "CLIPBOARD"); 1906 if (!g_pfnSelConvert(TEST_WIDGET, &clipAtom, &target, type, 1907 value, length, format)) 1908 return false; 1909 if (g_pfnSelDone) 1910 g_pfnSelDone(TEST_WIDGET, &clipAtom, &target); 1911 return true; 1912 } 1913 1914 /* Set the current X selection data */ 1915 static void clipSetSelectionValues(const char *pcszTarget, Atom type, 1916 const void *data, 1917 unsigned long count, int format) 1918 { 1919 Atom clipAtom = clipGetAtom(NULL, "CLIPBOARD"); 1920 g_selTarget = clipGetAtom(NULL, pcszTarget); 1921 g_selType = type; 1922 g_pSelData = data; 1923 g_cSelData = count; 1924 g_selFormat = format; 1925 if (g_pfnSelLose) 1926 g_pfnSelLose(TEST_WIDGET, &clipAtom); 1927 g_ownsSel = false; 1928 g_fX11Formats = 0; 1929 } 1930 1931 char *XtMalloc(Cardinal size) { return (char *) RTMemAlloc(size); } 1932 1933 char *XGetAtomName(Display *display, Atom atom) 1934 { 1935 AssertReturn((unsigned)atom < RT_ELEMENTS(g_aFormats) + 1, NULL); 1936 const char *pcszName = NULL; 1937 if (atom < 0x1000) 1938 return NULL; 1939 else if (0x1000 <= atom && atom < 0x2000) 1940 { 1941 unsigned index = atom - 0x1000; 1942 AssertReturn(index < RT_ELEMENTS(g_aFormats), NULL); 1943 pcszName = g_aFormats[index].pcszAtom; 1944 } 1945 else 1946 { 1947 unsigned index = atom - 0x2000; 1948 AssertReturn(index < RT_ELEMENTS(g_apszSupAtoms), NULL); 1949 pcszName = g_apszSupAtoms[index]; 1950 } 1951 return (char *)RTMemDup(pcszName, sizeof(pcszName) + 1); 1952 } 1953 1954 int XFree(void *data) 1955 { 1956 RTMemFree(data); 1957 return 0; 1958 } 1959 1960 void XFreeStringList(char **list) 1961 { 1962 if (list) 1963 RTMemFree(*list); 1964 RTMemFree(list); 1965 } 1966 1967 const char XtStrings [] = ""; 1968 _WidgetClassRec* applicationShellWidgetClass; 1969 const char XtShellStrings [] = ""; 1970 1971 #define MAX_BUF_SIZE 256 1972 1973 static bool testStringFromX11(VBOXCLIPBOARDCONTEXTX11 *pCtx, uint32_t cbBuf, 1974 const char *pcszExp, int rcExp) 1975 { 1976 bool retval = false; 1977 AssertReturn(cbBuf <= MAX_BUF_SIZE, false); 1978 if (!clipPollTargets()) 1979 RTPrintf("Failed to poll for targets\n"); 1980 else if (clipQueryFormats() != VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) 1981 RTPrintf("Wrong targets reported: %02X\n", clipQueryFormats()); 1982 else 1983 { 1984 char pc[MAX_BUF_SIZE]; 1985 uint32_t cbActual; 1986 int rc = VBoxX11ClipboardReadX11Data(pCtx, 1987 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 1988 (void *) pc, cbBuf, &cbActual); 1989 if (rc != rcExp) 1990 RTPrintf("Wrong return code, expected %Rrc, got %Rrc\n", rcExp, 1991 rc); 1992 else if (RT_FAILURE(rcExp)) 1993 retval = true; 1994 else 1995 { 1996 RTUTF16 wcExp[MAX_BUF_SIZE / 2]; 1997 RTUTF16 *pwcExp = wcExp; 1998 size_t cwc = 0; 1999 rc = RTStrToUtf16Ex(pcszExp, RTSTR_MAX, &pwcExp, 2000 RT_ELEMENTS(wcExp), &cwc); 2001 size_t cbExp = cwc * 2 + 2; 2002 AssertRC(rc); 2003 if (RT_SUCCESS(rc)) 2004 { 2005 if (cbActual != cbExp) 2006 { 2007 RTPrintf("Returned string is the wrong size, string \"%.*ls\", size %u\n", 2008 RT_MIN(MAX_BUF_SIZE, cbActual), pc, cbActual); 2009 RTPrintf("Expected \"%s\", size %u\n", pcszExp, 2010 cbExp); 2011 } 2012 else 2013 { 2014 if (memcmp(pc, wcExp, cbExp) == 0) 2015 retval = true; 2016 else 2017 RTPrintf("Returned string \"%.*ls\" does not match expected string \"%s\"\n", 2018 MAX_BUF_SIZE, pc, pcszExp); 2019 } 2020 } 2021 } 2022 } 2023 if (!retval) 2024 RTPrintf("Expected: string \"%s\", rc %Rrc (buffer size %u)\n", 2025 pcszExp, rcExp, cbBuf); 2026 return retval; 2027 } 2028 2029 static bool testStringFromVBox(VBOXCLIPBOARDCONTEXTX11 *pCtx, 2030 const char *pcszTarget, Atom typeExp, 2031 const void *valueExp, unsigned long lenExp, 2032 int formatExp) 2033 { 2034 bool retval = false; 2035 Atom type; 2036 XtPointer value = NULL; 2037 unsigned long length; 2038 int format; 2039 if (clipConvertSelection(pcszTarget, &type, &value, &length, &format)) 2040 { 2041 if ( type != typeExp 2042 || length != lenExp 2043 || format != formatExp 2044 || memcmp((const void *) value, (const void *)valueExp, 2045 lenExp)) 2046 { 2047 RTPrintf("Bad data: type %d, (expected %d), length %u, (%u), format %d (%d),\n", 2048 type, typeExp, length, lenExp, format, formatExp); 2049 RTPrintf("value \"%.*s\" (\"%.*s\")", RT_MIN(length, 20), value, 2050 RT_MIN(lenExp, 20), valueExp); 2051 } 2052 else 2053 retval = true; 2054 } 2055 else 2056 RTPrintf("Conversion failed\n"); 2057 XtFree((char *)value); 2058 if (!retval) 2059 RTPrintf("Conversion to %s, expected \"%s\"\n", pcszTarget, valueExp); 2060 return retval; 2061 } 2062 2063 static bool testStringFromVBoxFailed(VBOXCLIPBOARDCONTEXTX11 *pCtx, 2064 const char *pcszTarget) 2065 { 2066 bool retval = false; 2067 Atom type; 2068 XtPointer value = NULL; 2069 unsigned long length; 2070 int format; 2071 if (!clipConvertSelection(pcszTarget, &type, &value, &length, &format)) 2072 retval = true; 2073 XtFree((char *)value); 2074 if (!retval) 2075 { 2076 RTPrintf("Conversion to target %s, should have failed but didn't\n", 2077 pcszTarget); 2078 RTPrintf("Returned type %d, length %u, format %d, value \"%.*s\"\n", 2079 type, length, format, RT_MIN(length, 20), value); 2080 } 2081 return retval; 2082 } 2083 2084 int main() 2085 { 2086 RTR3Init(); 2087 VBOXCLIPBOARDCONTEXTX11 *pCtx = VBoxX11ClipboardConstructX11(NULL); 2088 unsigned cErrs = 0; 2089 char pc[MAX_BUF_SIZE]; 2090 uint32_t cbActual; 2091 int rc = VBoxX11ClipboardStartX11(pCtx); 2092 AssertRCReturn(rc, 1); 2093 2094 /***********/ 2095 RTPrintf(TEST_NAME ": TESTING reading Utf-8 from X11\n"); 2096 clipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world", 2097 sizeof("hello world"), 8); 2098 if (!testStringFromX11(pCtx, 256, "hello world", VINF_SUCCESS)) 2099 ++cErrs; 2100 if (!testStringFromX11(pCtx, sizeof("hello world") * 2, "hello world", 2101 VINF_SUCCESS)) 2102 ++cErrs; 2103 if (!testStringFromX11(pCtx, sizeof("hello world") * 2 - 1, "hello world", 2104 VERR_BUFFER_OVERFLOW)) 2105 ++cErrs; 2106 if (!testStringFromX11(pCtx, 0, "hello world", VERR_BUFFER_OVERFLOW)) 2107 ++cErrs; 2108 clipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world\n", 2109 sizeof("hello world\n"), 8); 2110 if (!testStringFromX11(pCtx, sizeof("hello world\r\n") * 2, 2111 "hello world\r\n", VINF_SUCCESS)) 2112 ++cErrs; 2113 clipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world\n", 2114 sizeof("hello world\n"), 8); 2115 if (!testStringFromX11(pCtx, sizeof("hello world\r\n") * 2, 2116 "hello world\r\n", VINF_SUCCESS)) 2117 ++cErrs; 2118 clipSetSelectionValues("UTF8_STRING", XA_STRING, "", 2119 sizeof(""), 8); 2120 if (!testStringFromX11(pCtx, sizeof("") * 2, "", VINF_SUCCESS)) 2121 ++cErrs; 2122 /* This next one is Utf-8 only. */ 2123 clipSetSelectionValues("UTF8_STRING", XA_STRING, 2124 "100\xE2\x82\xAC" /* 100 Euro */, 2125 sizeof("100\xE2\x82\xAC"), 8); 2126 if (!testStringFromX11(pCtx, sizeof("100\xE2\x82\xAC") * 2, 2127 "100\xE2\x82\xAC", VINF_SUCCESS)) 2128 ++cErrs; 2129 2130 /***********/ 2131 RTPrintf(TEST_NAME ": TESTING reading compound text from X11\n"); 2132 clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello world", 2133 sizeof("hello world"), 8); 2134 if (!testStringFromX11(pCtx, 256, "hello world", VINF_SUCCESS)) 2135 ++cErrs; 2136 if (!testStringFromX11(pCtx, sizeof("hello world") * 2, "hello world", 2137 VINF_SUCCESS)) 2138 ++cErrs; 2139 if (!testStringFromX11(pCtx, sizeof("hello world") * 2 - 1, "hello world", 2140 VERR_BUFFER_OVERFLOW)) 2141 ++cErrs; 2142 if (!testStringFromX11(pCtx, 0, "hello world", VERR_BUFFER_OVERFLOW)) 2143 ++cErrs; 2144 clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello world\n", 2145 sizeof("hello world\n"), 8); 2146 if (!testStringFromX11(pCtx, sizeof("hello world\r\n") * 2, 2147 "hello world\r\n", VINF_SUCCESS)) 2148 ++cErrs; 2149 clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello world\n", 2150 sizeof("hello world\n"), 8); 2151 if (!testStringFromX11(pCtx, sizeof("hello world\r\n") * 2, 2152 "hello world\r\n", VINF_SUCCESS)) 2153 ++cErrs; 2154 clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "", 2155 sizeof(""), 8); 2156 if (!testStringFromX11(pCtx, sizeof("") * 2, "", VINF_SUCCESS)) 2157 ++cErrs; 2158 2159 /***********/ 2160 RTPrintf(TEST_NAME ": TESTING X11 timeout\n"); 2161 clipSetSelectionValues("UTF8_STRING", XT_CONVERT_FAIL, "hello world", 2162 sizeof("hello world"), 8); 2163 if (!testStringFromX11(pCtx, 256, "hello world", VERR_TIMEOUT)) 2164 ++cErrs; 2165 2166 /***********/ 2167 RTPrintf(TEST_NAME ": TESTING a data request from an empty X11 clipboard\n"); 2168 clipSetSelectionValues("UTF8_STRING", XA_STRING, NULL, 2169 0, 8); 2170 rc = VBoxX11ClipboardReadX11Data(pCtx, 2171 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 2172 (void *) pc, sizeof(pc), &cbActual); 2173 if (rc != VERR_NO_DATA) 2174 { 2175 RTPrintf("Returned %Rrc instead of VERR_NO_DATA\n", rc); 2176 ++cErrs; 2177 } 2178 2179 /***********/ 2180 RTPrintf(TEST_NAME ": TESTING a request for an invalid host format from X11\n"); 2181 rc = VBoxX11ClipboardReadX11Data(pCtx, 0xffff, (void *) pc, 2182 sizeof(pc), &cbActual); 2183 if (rc != VERR_NOT_IMPLEMENTED) 2184 { 2185 RTPrintf("Returned %Rrc instead of VERR_NOT_IMPLEMENTED\n", rc); 2186 ++cErrs; 2187 } 2188 2189 /***********/ 2190 RTPrintf(TEST_NAME ": TESTING reading Utf-8 from VBox\n"); 2191 clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world"); 2192 if (!testStringFromVBox(pCtx, "UTF8_STRING", 2193 clipGetAtom(NULL, "UTF8_STRING"), 2194 "hello world", sizeof("hello world"), 8)) 2195 ++cErrs; 2196 clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world\r\n"); 2197 if (!testStringFromVBox(pCtx, "UTF8_STRING", 2198 clipGetAtom(NULL, "UTF8_STRING"), 2199 "hello world\n", sizeof("hello world\n"), 8)) 2200 ++cErrs; 2201 clipSetVBoxUtf16(pCtx, VINF_SUCCESS, ""); 2202 if (!testStringFromVBox(pCtx, "UTF8_STRING", 2203 clipGetAtom(NULL, "UTF8_STRING"), 2204 "", sizeof(""), 8)) 2205 ++cErrs; 2206 /* This next one is Utf-8 only. */ 2207 clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "100\xE2\x82\xAC" /* 100 Euro */); 2208 if (!testStringFromVBox(pCtx, "UTF8_STRING", 2209 clipGetAtom(NULL, "UTF8_STRING"), 2210 "100\xE2\x82\xAC", sizeof("100\xE2\x82\xAC"), 8)) 2211 ++cErrs; 2212 2213 /***********/ 2214 RTPrintf(TEST_NAME ": TESTING reading COMPOUND TEXT from VBox\n"); 2215 clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world"); 2216 if (!testStringFromVBox(pCtx, "COMPOUND_TEXT", 2217 clipGetAtom(NULL, "COMPOUND_TEXT"), 2218 "hello world", sizeof("hello world"), 8)) 2219 ++cErrs; 2220 clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world\r\n"); 2221 if (!testStringFromVBox(pCtx, "COMPOUND_TEXT", 2222 clipGetAtom(NULL, "COMPOUND_TEXT"), 2223 "hello world\n", sizeof("hello world\n"), 8)) 2224 ++cErrs; 2225 clipSetVBoxUtf16(pCtx, VINF_SUCCESS, ""); 2226 if (!testStringFromVBox(pCtx, "COMPOUND_TEXT", 2227 clipGetAtom(NULL, "COMPOUND_TEXT"), 2228 "", sizeof(""), 8)) 2229 ++cErrs; 2230 2231 /***********/ 2232 RTPrintf(TEST_NAME ": TESTING reading from VBox with timeout\n"); 2233 clipEmptyVBox(pCtx, VERR_TIMEOUT); 2234 if (!testStringFromVBoxFailed(pCtx, "UTF8_STRING")) 2235 ++cErrs; 2236 2237 /***********/ 2238 RTPrintf(TEST_NAME ": TESTING reading from VBox with no data\n"); 2239 clipEmptyVBox(pCtx, VINF_SUCCESS); 2240 if (!testStringFromVBoxFailed(pCtx, "UTF8_STRING")) 2241 ++cErrs; 2242 if (cErrs > 0) 2243 RTPrintf("Failed with %u error(s)\n", cErrs); 2244 return cErrs > 0 ? 1 : 0; 2245 } 2246 2247 #endif 2248 2249 #ifdef SMOKETEST 2250 2251 /* This is a simple test case that just starts a copy of the X11 clipboard 2252 * backend, checks the X11 clipboard and exits. If ever needed I will add an 2253 * interactive mode in which the user can read and copy to the clipboard from 2254 * the command line. */ 2255 2256 #include <iprt/initterm.h> 2257 #include <iprt/stream.h> 2258 2259 #define TEST_NAME "tstClipboardX11Smoke" 2260 2261 int VBoxX11ClipboardReadVBoxData(VBOXCLIPBOARDCONTEXT *pCtx, 2262 uint32_t u32Format, void **ppv, 2263 uint32_t *pcb) 2264 { 2265 return VERR_NO_DATA; 2266 } 2267 1641 2268 void VBoxX11ClipboardReportX11Formats(VBOXCLIPBOARDCONTEXT *pCtx, 1642 2269 uint32_t u32Formats) 1643 { 1644 LogFlowFunc(("pCtx = %p\n", pCtx)); 1645 if (pCtx == (VBOXCLIPBOARDCONTEXT *)g_pCtxTestX11) /* Magic cookie */ 1646 VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestVBox, 1647 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 1648 } 1649 1650 /** Initial tests that can be done while the clipboard contents are still 1651 * invalid. 1652 * @returns boolean success value 1653 * @note prints status information to stdout 1654 */ 1655 bool testInvalid(void) 1656 { 1657 bool fSuccess = true; 1658 char pc[256]; 1659 uint32_t cbActual; 1660 RTPrintf("tstClipboardX11: TESTING a request for an invalid data format\n"); 1661 int rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 0xffff, (void *) pc, 1662 sizeof(pc), &cbActual); 1663 RTPrintf("Returned %Rrc - %s\n", rc, 1664 rc == VERR_NOT_IMPLEMENTED ? "SUCCESS" : "FAILURE"); 1665 if (rc != VERR_NOT_IMPLEMENTED) 1666 fSuccess = false; 1667 RTPrintf("tstClipboardX11: TESTING a request for data from an empty clipboard\n"); 1668 VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestX11, 1669 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 1670 VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestX11, 1671 0); 1672 rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 1673 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 1674 (void *) pc, sizeof(pc), &cbActual); 1675 RTPrintf("Returned %Rrc - %s\n", rc, 1676 rc == VERR_NO_DATA ? "SUCCESS" : "FAILURE"); 1677 if (rc != VERR_NO_DATA) 1678 fSuccess = false; 1679 return fSuccess; 1680 } 1681 1682 /** Tests an entry in the table above. 1683 * @returns boolean success value 1684 * @note prints status information to stdout 1685 */ 1686 bool testEntry(testData *pData) 1687 { 1688 bool fSuccess = false; 1689 char pc[256]; 1690 uint32_t cbActual; 1691 for (int i = 0; (i < MAX_ATTEMPTS) && !fSuccess; ++i) 1692 { 1693 VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestVBox, 1694 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 1695 int rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 1696 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 1697 (void *) pc, sizeof(pc), 1698 &cbActual); 1699 AssertRCReturn(rc, 1); 1700 /* Did we expect and get an overflow? */ 1701 if ( RT_SUCCESS(rc) 1702 && (cbActual == pData->getSize()) 1703 && pData->overflow()) 1704 fSuccess = true; 1705 /* Did we expect a string and get it? */ 1706 else if ( RT_SUCCESS(rc) 1707 && (memcmp(pc, pData->getData(), 1708 pData->getSize()) == 0)) 1709 fSuccess = true; 1710 else 1711 RTThreadSleep(50); 1712 if (fSuccess) 1713 RTPrintf("text %ls, %sretval %Rrc - SUCCESS\n", 1714 pData->getData(), 1715 pData->overflow() ? "buffer overflow as expected, " 1716 : "", rc); 1717 else 1718 RTPrintf("text %ls, retval %Rrc, attempt %d of %d\n", 1719 pData->getData(), rc, i + 1, 1720 MAX_ATTEMPTS); 1721 } 1722 if (!fSuccess) 1723 RTPrintf("FAILURE. Last string obtained was %.*lS\n", 1724 RT_MIN(cbActual / 2, 20), pc); 1725 return fSuccess; 1726 } 2270 {} 1727 2271 1728 2272 int main() 1729 2273 { 1730 2274 int rc = VINF_SUCCESS; 1731 int status = 0; 1732 g_debugClipboard = true; 2275 RTR3Init(); 1733 2276 /* We can't test anything without an X session, so just return success 1734 2277 * in that case. */ 1735 2278 if (!RTEnvGet("DISPLAY")) 2279 { 2280 RTPrintf(TEST_NAME ": X11 not available, not running test\n"); 1736 2281 return 0; 1737 RTR3Init();1738 g_pCtxTestX11 = VBoxX11ClipboardConstructX11(NULL);1739 g_pCtxTestVBox =1740 VBoxX11ClipboardConstructX11((VBOXCLIPBOARDCONTEXT *)g_pCtxTestX11);1741 rc = VBoxX11ClipboardStartX11( g_pCtxTestVBox);2282 } 2283 RTPrintf(TEST_NAME ": TESTING\n"); 2284 VBOXCLIPBOARDCONTEXTX11 *pCtx = VBoxX11ClipboardConstructX11(NULL); 2285 AssertReturn(pCtx, 1); 2286 rc = VBoxX11ClipboardStartX11(pCtx); 1742 2287 AssertRCReturn(rc, 1); 1743 bool fSuccess = false; 1744 /* Test a request for an invalid data format and data from an empty 1745 * clipboard */ 1746 for (unsigned i = 0; (i < MAX_ATTEMPTS) && !fSuccess; ++i) 1747 { 1748 rc = VBoxX11ClipboardStartX11(g_pCtxTestX11); 1749 AssertRCReturn(rc, 1); 1750 fSuccess = testInvalid(); 1751 VBoxX11ClipboardStopX11(g_pCtxTestX11); 1752 if (!fSuccess) 1753 { 1754 RTPrintf("attempt %d of %d\n", i + 1, MAX_ATTEMPTS + 1); 1755 RTThreadSleep(50); 1756 } 1757 } 1758 if (!fSuccess) 1759 status = 1; 1760 rc = VBoxX11ClipboardStartX11(g_pCtxTestX11); 2288 /* Give the clipboard time to synchronise. */ 2289 RTThreadSleep(500); 2290 rc = VBoxX11ClipboardStopX11(pCtx); 1761 2291 AssertRCReturn(rc, 1); 1762 /* Claim the clipboard and make sure we get it */ 1763 VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestVBox, 1764 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 1765 for (unsigned i = 0; 1766 i < 255 1767 && g_pCtxTestX11->X11TextFormat == INVALID; 1768 ++i) 1769 RTThreadSleep(50); 1770 AssertReturn(g_pCtxTestX11->X11TextFormat != INVALID, 1); 1771 /* Do general purpose clipboard tests */ 1772 for (int i = 0; i < 2; ++i) 1773 { 1774 g_testUtf8 = (i == 0); 1775 g_testCText = (i == 1); 1776 RTPrintf("tstClipboardX11: TESTING sending and receiving of %s\n", 1777 i == 0 ? "Utf-8" : "COMPOUND TEXT"); 1778 for (g_testNum = 0; g_testNum < MAX_TESTS; ++g_testNum) 1779 { 1780 if (!testEntry(&g_sTestData[g_testNum])) 1781 status = 1; 1782 } 1783 } 1784 /* Finally test timeouts. */ 1785 XtAppSetSelectionTimeout(g_pCtxTestX11->appContext, 10); 1786 RTPrintf("tstClipboardX11: TESTING the clipboard timeout\n"); 1787 rc = VINF_SUCCESS; 1788 g_testTimeout = true; 1789 for (unsigned i = 0; (i < MAX_ATTEMPTS) && (rc != VERR_TIMEOUT); ++i) 1790 { 1791 char pc[256]; 1792 uint32_t cbActual; 1793 VBoxX11ClipboardAnnounceVBoxFormat(g_pCtxTestVBox, 1794 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); 1795 rc = VBoxX11ClipboardReadX11Data(g_pCtxTestX11, 1796 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 1797 (void *) pc, sizeof(pc), &cbActual); 1798 AssertMsg( RT_SUCCESS(rc) 1799 || (rc == VERR_TIMEOUT) 1800 || (rc == VERR_NO_DATA), 1801 ("rc = %Rrc\n", rc)); 1802 if (rc == VERR_TIMEOUT) 1803 RTPrintf("SUCCESS\n"); 1804 else 1805 { 1806 RTPrintf("Attempt %d of %d\n", i + 1, MAX_ATTEMPTS); 1807 RTThreadSleep(50); 1808 } 1809 } 1810 if (rc != VERR_TIMEOUT) 1811 status = 1; 1812 rc = VBoxX11ClipboardStopX11(g_pCtxTestX11); 1813 AssertRCReturn(rc, 1); 1814 rc = VBoxX11ClipboardStopX11(g_pCtxTestVBox); 1815 AssertRCReturn(rc, 1); 1816 VBoxX11ClipboardDestructX11(g_pCtxTestX11); 1817 VBoxX11ClipboardDestructX11(g_pCtxTestVBox); 1818 return status; 1819 } 1820 1821 #endif /* TESTCASE defined */ 2292 VBoxX11ClipboardDestructX11(pCtx); 2293 return 0; 2294 } 2295 2296 #endif /* SMOKETEST defined */
Note:
See TracChangeset
for help on using the changeset viewer.