Changeset 82906 in vbox for trunk/src/VBox/GuestHost
- Timestamp:
- Jan 29, 2020 12:45:51 PM (5 years ago)
- Location:
- trunk/src/VBox/GuestHost
- Files:
-
- 4 added
- 1 deleted
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/GuestHost/Makefile.kmk
r80427 r82906 24 24 endif 25 25 26 ifdef VBOX_WITH_HGCM27 include $(PATH_SUB_CURRENT)/SharedClipboard/Makefile.kmk28 endif29 30 26 ifdef VBOX_WITH_DRAG_AND_DROP 31 27 include $(PATH_SUB_CURRENT)/DragAndDrop/Makefile.kmk -
trunk/src/VBox/GuestHost/SharedClipboard/clipboard-x11.cpp
r82901 r82906 15 15 */ 16 16 17 /* Note: to automatically run regression tests on the shared clipboard,18 * execute the tstClipboard X11 testcase. If you often make changes to the17 /* Note: to automatically run regression tests on the Shared Clipboard, 18 * execute the tstClipboardGH-X11 testcase. If you often make changes to the 19 19 * clipboard code, adding the line 20 * OTHERS += $(PATH_tstClipboardX11)/tstClipboardX11.run 20 * 21 * OTHERS += $(PATH_tstClipboardGH-X11)/tstClipboardGH-X11.run 22 * 21 23 * to LocalConfig.kmk will cause the tests to be run every time the code is 22 * changed. */ 24 * changed. 25 */ 23 26 24 27 … … 65 68 #include <VBox/HostServices/VBoxClipboardSvc.h> 66 69 70 /** Own macro for declaring function visibility / linkage based on whether this 71 * code runs as part of test cases or not. */ 72 #ifdef TESTCASE 73 # define SHCL_X11_DECL(x) x 74 #else 75 # define SHCL_X11_DECL(x) static x 76 #endif 77 67 78 68 79 /********************************************************************************************************************************* 69 * Internal Functions * 80 * Externals * 81 *********************************************************************************************************************************/ 82 #ifdef TESTCASE 83 extern void tstClipQueueToEventThread(void (*proc)(void *, void *), void *client_data); 84 extern void tstClipRequestData(SHCLX11CTX* pCtx, SHCLX11FMTIDX target, void *closure); 85 extern void tstRequestTargets(SHCLX11CTX* pCtx); 86 #endif 87 88 89 /********************************************************************************************************************************* 90 * Prototypes * 70 91 *********************************************************************************************************************************/ 71 92 class formats; 72 static AtomclipGetAtom(PSHCLX11CTX pCtx, const char *pszName);93 SHCL_X11_DECL(Atom) clipGetAtom(PSHCLX11CTX pCtx, const char *pszName); 73 94 74 95 … … 81 102 * and to the corresponding VBox clipboard formats. 82 103 */ 83 static struct _SHCLX11FMTTABLE 84 { 85 /** The X11 atom name of the format (several names can match one format). */ 86 const char *pcszAtom; 87 /** The format corresponding to the name. */ 88 SHCLX11FMT enmFmtX11; 89 /** The corresponding VBox clipboard format. */ 90 SHCLFORMAT uFmtVBox; 91 } g_aFormats[] = 104 SHCL_X11_DECL(SHCLX11FMTTABLE) g_aFormats[] = 92 105 { 93 106 { "INVALID", SHCLX11FMT_INVALID, VBOX_SHCL_FMT_NONE }, … … 116 129 /** @todo Add Wayland / Weston support. */ 117 130 #endif 131 { "LAST", SHCLX11FMT_INVALID, VBOX_SHCL_FMT_NONE }, 118 132 }; 119 133 120 enum 121 { 122 NIL_CLIPX11FORMAT = 0, 123 MAX_CLIP_X11_FORMATS = RT_ELEMENTS(g_aFormats) 124 }; 134 135 /********************************************************************************************************************************* 136 * Defines * 137 *********************************************************************************************************************************/ 138 139 #define SHCL_MAX_X11_FORMATS RT_ELEMENTS(g_aFormats) 140 141 142 /********************************************************************************************************************************* 143 * Internal structures * 144 *********************************************************************************************************************************/ 145 146 /** 147 * A structure containing information about where to store a request 148 * for the X11 clipboard contents. 149 */ 150 typedef struct _CLIPREADX11CBREQ 151 { 152 /** The format VBox would like the data in. */ 153 SHCLFORMAT mFormat; 154 /** The format we requested from X11. */ 155 SHCLX11FMTIDX mX11Format; 156 /** The clipboard context this request is associated with. */ 157 SHCLX11CTX *mpCtx; 158 /** The request structure passed in from the backend. */ 159 CLIPREADCBREQ *mpReq; 160 } CLIPREADX11CBREQ; 161 125 162 126 163 … … 145 182 * @param uFmtIdx Format index to look up SHCLX11CLIPFMT for. 146 183 */ 147 static SHCLX11FMTclipRealFormatForX11Format(SHCLX11FMTIDX uFmtIdx)184 SHCL_X11_DECL(SHCLX11FMT) clipRealFormatForX11Format(SHCLX11FMTIDX uFmtIdx) 148 185 { 149 186 AssertReturn(uFmtIdx <= RT_ELEMENTS(g_aFormats), SHCLX11FMT_INVALID); … … 177 214 return NIL_CLIPX11FORMAT; 178 215 } 179 180 #ifdef TESTCASE181 /**182 * Looks up the X11 format matching a given X11 atom text.183 *184 * @returns the format on success, NIL_CLIPX11FORMAT on failure185 * @param pcszAtom Atom text to look up format for.186 */187 static SHCLX11FMTIDX clipFindX11FormatByAtomText(const char *pcszAtom)188 {189 for (unsigned i = 0; i < RT_ELEMENTS(g_aFormats); ++i)190 if (!strcmp(g_aFormats[i].pcszAtom, pcszAtom))191 return i;192 return NIL_CLIPX11FORMAT;193 }194 #endif195 216 196 217 /** … … 320 341 * @param pcszName Name of atom to return atom for. 321 342 */ 322 static AtomclipGetAtom(PSHCLX11CTX pCtx, const char *pcszName)343 SHCL_X11_DECL(Atom) clipGetAtom(PSHCLX11CTX pCtx, const char *pcszName) 323 344 { 324 345 AssertPtrReturn(pcszName, None); 325 346 return XInternAtom(XtDisplay(pCtx->pWidget), pcszName, False); 326 347 } 327 328 #ifdef TESTCASE329 static void tstClipQueueToEventThread(void (*proc)(void *, void *),330 void *client_data);331 #endif332 348 333 349 /** String written to the wakeup pipe. */ … … 414 430 * @param pCtx The X11 clipboard context to use. 415 431 */ 416 static voidclipReportEmptyX11CB(PSHCLX11CTX pCtx)432 SHCL_X11_DECL(void) clipReportEmptyX11CB(PSHCLX11CTX pCtx) 417 433 { 418 434 clipResetX11Formats(pCtx); … … 430 446 * @param cTargets The size of the list in @a pTargets. 431 447 */ 432 static SHCLX11FMTIDXclipGetTextFormatFromTargets(PSHCLX11CTX pCtx,433 SHCLX11FMTIDX *pTargets,434 size_t cTargets)448 SHCL_X11_DECL(SHCLX11FMTIDX) clipGetTextFormatFromTargets(PSHCLX11CTX pCtx, 449 SHCLX11FMTIDX *pTargets, 450 size_t cTargets) 435 451 { 436 452 AssertPtrReturn(pCtx, NIL_CLIPX11FORMAT); … … 455 471 } 456 472 457 #ifdef TESTCASE458 static bool tstClipTextFormatConversion(PSHCLX11CTX pCtx)459 {460 bool fSuccess = true;461 SHCLX11FMTIDX targets[2];462 SHCLX11FMTIDX x11Format;463 targets[0] = clipFindX11FormatByAtomText("text/plain");464 targets[1] = clipFindX11FormatByAtomText("image/bmp");465 x11Format = clipGetTextFormatFromTargets(pCtx, targets, 2);466 if (clipRealFormatForX11Format(x11Format) != SHCLX11FMT_TEXT)467 fSuccess = false;468 targets[0] = clipFindX11FormatByAtomText("UTF8_STRING");469 targets[1] = clipFindX11FormatByAtomText("text/plain");470 x11Format = clipGetTextFormatFromTargets(pCtx, targets, 2);471 if (clipRealFormatForX11Format(x11Format) != SHCLX11FMT_UTF8)472 fSuccess = false;473 return fSuccess;474 }475 #endif476 477 473 /** 478 474 * Goes through an array of X11 clipboard targets to see if they contain a bitmap … … 544 540 } 545 541 546 # ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS542 # ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 547 543 /** 548 544 * Goes through an array of X11 clipboard targets to see if they contain an URI list … … 578 574 return bestURIListFormat; 579 575 } 580 # endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */576 # endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ 581 577 582 578 /** … … 615 611 } 616 612 617 static DECLCALLBACK(void) clipQueryX11FormatsCallback(PSHCLX11CTX pCtx);618 619 613 /** 620 614 * Updates the context's information about targets currently supported by X11, 621 615 * based on an array of X11 atoms. 622 616 * 623 * @param pCtxThe X11 clipboard context to use.617 * @param pCtx The X11 clipboard context to use. 624 618 * @param pTargets The array of atoms describing the targets supported. 625 619 * @param cTargets The size of the array @a pTargets. 626 620 */ 627 static voidclipUpdateX11Targets(PSHCLX11CTX pCtx, SHCLX11FMTIDX *pTargets, size_t cTargets)621 SHCL_X11_DECL(void) clipUpdateX11Targets(PSHCLX11CTX pCtx, SHCLX11FMTIDX *pTargets, size_t cTargets) 628 622 { 629 623 LogFlowFuncEnter(); … … 648 642 * unit test. So keep it simple, be paranoid and log everything. 649 643 */ 650 static voidclipConvertX11TargetsCallback(Widget widget, XtPointer pClient,651 Atom * /* selection */, Atom *atomType,652 XtPointer pValue, long unsigned int *pcLen,653 int *piFormat)644 SHCL_X11_DECL(DECLCALLBACK(void)) clipConvertX11TargetsCallback(Widget widget, XtPointer pClient, 645 Atom * /* selection */, Atom *atomType, 646 XtPointer pValue, long unsigned int *pcLen, 647 int *piFormat) 654 648 { 655 649 RT_NOREF(piFormat); … … 734 728 } 735 729 736 #ifdef TESTCASE737 void tstRequestTargets(PSHCLX11CTX pCtx);738 #endif739 740 730 /** 741 731 * Callback to notify us when the contents of the X11 clipboard change. … … 743 733 * @param pCtx The X11 clipboard context to use. 744 734 */ 745 static DECLCALLBACK(void) clipQueryX11FormatsCallback(PSHCLX11CTX pCtx) 746 { 747 LogFlowFuncEnter(); 748 735 SHCL_X11_DECL(DECLCALLBACK(void)) clipQueryX11FormatsCallback(PSHCLX11CTX pCtx) 736 { 749 737 #ifndef TESTCASE 750 738 LogFlowFunc(("fXtBusy=%RTbool\n", pCtx->fXtBusy)); … … 767 755 #endif 768 756 } 769 770 #ifndef TESTCASE771 757 772 758 typedef struct … … 812 798 } 813 799 800 #ifndef TESTCASE 814 801 /** 815 802 * The main loop of our X11 event thread. … … 839 826 return VINF_SUCCESS; 840 827 } 841 #endif /* !TESTCASE */828 #endif 842 829 843 830 /** … … 1218 1205 const unsigned cFixedTargets = 3; 1219 1206 1220 Atom *atomTargets = (Atom *)XtMalloc(( MAX_CLIP_X11_FORMATS + cFixedTargets) * sizeof(Atom));1207 Atom *atomTargets = (Atom *)XtMalloc((SHCL_MAX_X11_FORMATS + cFixedTargets) * sizeof(Atom)); 1221 1208 unsigned cTargets = 0; 1222 1209 SHCLX11FMTIDX format = NIL_CLIPX11FORMAT; … … 1980 1967 1981 1968 /** 1982 * A structure containing information about where to store a request1983 * for the X11 clipboard contents.1984 */1985 typedef struct _CLIPREADX11CBREQ1986 {1987 /** The format VBox would like the data in. */1988 SHCLFORMAT mFormat;1989 /** The format we requested from X11. */1990 SHCLX11FMTIDX mX11Format;1991 /** The clipboard context this request is associated with. */1992 SHCLX11CTX *mpCtx;1993 /** The request structure passed in from the backend. */1994 CLIPREADCBREQ *mpReq;1995 } CLIPREADX11CBREQ;1996 1997 /**1998 1969 * Converts the data obtained from the X11 clipboard to the required format, 1999 1970 * place it in the buffer supplied and signal that data has arrived. … … 2005 1976 * the X11 clipboard contains a format we understand. 2006 1977 */ 2007 static voidclipConvertDataFromX11CallbackWorker(void *pClient, void *pvSrc, unsigned cbSrc)1978 SHCL_X11_DECL(void) clipConvertDataFromX11CallbackWorker(void *pClient, void *pvSrc, unsigned cbSrc) 2008 1979 { 2009 1980 CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *)pClient; … … 2143 2114 } 2144 2115 } 2145 # ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS2116 # ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 2146 2117 else if (pReq->mFormat == VBOX_SHCL_FMT_URI_LIST) 2147 2118 { … … 2191 2162 } 2192 2163 } 2193 # endif2164 # endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ 2194 2165 else 2195 2166 rc = VERR_NOT_SUPPORTED; … … 2203 2174 } 2204 2175 2205 #ifndef TESTCASE2206 2176 /** 2207 2177 * Converts the data obtained from the X11 clipboard to the required format, … … 2214 2184 * the X11 clipboard contains a format we understand. 2215 2185 */ 2216 static voidclipConvertDataFromX11Callback(Widget widget, XtPointer pClient,2217 Atom * /* selection */, Atom *atomType,2218 XtPointer pvSrc, long unsigned int *pcLen,2219 int *piFormat)2186 SHCL_X11_DECL(void) clipConvertDataFromX11Callback(Widget widget, XtPointer pClient, 2187 Atom * /* selection */, Atom *atomType, 2188 XtPointer pvSrc, long unsigned int *pcLen, 2189 int *piFormat) 2220 2190 { 2221 2191 RT_NOREF(widget); … … 2227 2197 XtFree((char *)pvSrc); 2228 2198 } 2229 #endif2230 2231 #ifdef TESTCASE2232 static void tstClipRequestData(SHCLX11CTX* pCtx, SHCLX11FMTIDX target,2233 void *closure);2234 #endif2235 2199 2236 2200 static int clipGetSelectionValue(PSHCLX11CTX pCtx, SHCLX11FMTIDX format, … … 2358 2322 } 2359 2323 2360 #ifdef TESTCASE2361 2362 /** @todo This unit test currently works by emulating the X11 and X toolkit2363 * APIs to exercise the code, since I didn't want to rewrite the code too much2364 * when I wrote the tests. However, this makes it rather ugly and hard to2365 * understand. Anyone doing any work on the code should feel free to2366 * rewrite the tests and the code to make them cleaner and more readable. */2367 2368 #include <iprt/test.h>2369 #include <poll.h>2370 2371 #define TESTCASE_WIDGET_ID (Widget)0xffff2372 2373 /* For the purpose of the test case, we just execute the procedure to be2374 * scheduled, as we are running single threaded. */2375 void tstClipQueueToEventThread(void (*proc)(void *, void *),2376 void *client_data)2377 {2378 proc(client_data, NULL);2379 }2380 2381 void XtFree(char *ptr)2382 {2383 RTMemFree((void *)ptr);2384 }2385 2386 /* The data in the simulated VBox clipboard. */2387 static int g_tst_rcDataVBox = VINF_SUCCESS;2388 static void *g_tst_pvDataVBox = NULL;2389 static uint32_t g_tst_cbDataVBox = 0;2390 2391 /* Set empty data in the simulated VBox clipboard. */2392 static void tstClipEmptyVBox(PSHCLX11CTX pCtx, int retval)2393 {2394 g_tst_rcDataVBox = retval;2395 RTMemFree(g_tst_pvDataVBox);2396 g_tst_pvDataVBox = NULL;2397 g_tst_cbDataVBox = 0;2398 ShClX11ReportFormatsToX11(pCtx, 0);2399 }2400 2401 /* Set the data in the simulated VBox clipboard. */2402 static int tstClipSetVBoxUtf16(PSHCLX11CTX pCtx, int retval,2403 const char *pcszData, size_t cb)2404 {2405 PRTUTF16 pwszData = NULL;2406 size_t cwData = 0;2407 int rc = RTStrToUtf16Ex(pcszData, RTSTR_MAX, &pwszData, 0, &cwData);2408 if (RT_FAILURE(rc))2409 return rc;2410 AssertReturn(cb <= cwData * 2 + 2, VERR_BUFFER_OVERFLOW);2411 void *pv = RTMemDup(pwszData, cb);2412 RTUtf16Free(pwszData);2413 if (pv == NULL)2414 return VERR_NO_MEMORY;2415 if (g_tst_pvDataVBox)2416 RTMemFree(g_tst_pvDataVBox);2417 g_tst_rcDataVBox = retval;2418 g_tst_pvDataVBox = pv;2419 g_tst_cbDataVBox = cb;2420 ShClX11ReportFormatsToX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT);2421 return VINF_SUCCESS;2422 }2423 2424 /* Return the data in the simulated VBox clipboard. */2425 DECLCALLBACK(int) ShClX11RequestDataForX11Callback(PSHCLCONTEXT pCtx, uint32_t Format, void **ppv, uint32_t *pcb)2426 {2427 RT_NOREF(pCtx, Format);2428 *pcb = g_tst_cbDataVBox;2429 if (g_tst_pvDataVBox != NULL)2430 {2431 void *pv = RTMemDup(g_tst_pvDataVBox, g_tst_cbDataVBox);2432 *ppv = pv;2433 return pv != NULL ? g_tst_rcDataVBox : VERR_NO_MEMORY;2434 }2435 *ppv = NULL;2436 return g_tst_rcDataVBox;2437 }2438 2439 Display *XtDisplay(Widget w) { NOREF(w); return (Display *) 0xffff; }2440 2441 void XtAppSetExitFlag(XtAppContext app_context) { NOREF(app_context); }2442 2443 void XtDestroyWidget(Widget w) { NOREF(w); }2444 2445 XtAppContext XtCreateApplicationContext(void) { return (XtAppContext)0xffff; }2446 2447 void XtDestroyApplicationContext(XtAppContext app_context) { NOREF(app_context); }2448 2449 void XtToolkitInitialize(void) {}2450 2451 Boolean XtToolkitThreadInitialize(void) { return True; }2452 2453 Display *XtOpenDisplay(XtAppContext app_context,2454 _Xconst _XtString display_string,2455 _Xconst _XtString application_name,2456 _Xconst _XtString application_class,2457 XrmOptionDescRec *options, Cardinal num_options,2458 int *argc, char **argv)2459 {2460 RT_NOREF8(app_context, display_string, application_name, application_class, options, num_options, argc, argv);2461 return (Display *)0xffff;2462 }2463 2464 Widget XtVaAppCreateShell(_Xconst _XtString application_name, _Xconst _XtString application_class,2465 WidgetClass widget_class, Display *display, ...)2466 {2467 RT_NOREF(application_name, application_class, widget_class, display);2468 return TESTCASE_WIDGET_ID;2469 }2470 2471 void XtSetMappedWhenManaged(Widget widget, _XtBoolean mapped_when_managed) { RT_NOREF(widget, mapped_when_managed); }2472 2473 void XtRealizeWidget(Widget widget) { NOREF(widget); }2474 2475 XtInputId XtAppAddInput(XtAppContext app_context, int source, XtPointer condition, XtInputCallbackProc proc, XtPointer closure)2476 {2477 RT_NOREF(app_context, source, condition, proc, closure);2478 return 0xffff;2479 }2480 2481 /* Atoms we need other than the formats we support. */2482 static const char *g_tst_apszSupAtoms[] =2483 {2484 "PRIMARY", "CLIPBOARD", "TARGETS", "MULTIPLE", "TIMESTAMP"2485 };2486 2487 /* This just looks for the atom names in a couple of tables and returns an2488 * index with an offset added. */2489 Atom XInternAtom(Display *, const char *pcsz, int)2490 {2491 Atom atom = 0;2492 for (unsigned i = 0; i < RT_ELEMENTS(g_aFormats); ++i)2493 if (!strcmp(pcsz, g_aFormats[i].pcszAtom))2494 atom = (Atom) (i + 0x1000);2495 for (unsigned i = 0; i < RT_ELEMENTS(g_tst_apszSupAtoms); ++i)2496 if (!strcmp(pcsz, g_tst_apszSupAtoms[i]))2497 atom = (Atom) (i + 0x2000);2498 Assert(atom); /* Have we missed any atoms? */2499 return atom;2500 }2501 2502 /* Take a request for the targets we are currently offering. */2503 static SHCLX11FMTIDX g_tst_aSelTargetsIdx[10] = { 0 };2504 static size_t g_tst_cTargets = 0;2505 2506 void tstRequestTargets(SHCLX11CTX* pCtx)2507 {2508 clipUpdateX11Targets(pCtx, g_tst_aSelTargetsIdx, g_tst_cTargets);2509 }2510 2511 /* The current values of the X selection, which will be returned to the2512 * XtGetSelectionValue callback. */2513 static Atom g_tst_atmSelType = 0;2514 static const void *g_tst_pSelData = NULL;2515 static unsigned long g_tst_cSelData = 0;2516 static int g_tst_selFormat = 0;2517 2518 void tstClipRequestData(PSHCLX11CTX pCtx, SHCLX11FMTIDX target, void *closure)2519 {2520 RT_NOREF(pCtx);2521 unsigned long count = 0;2522 int format = 0;2523 if (target != g_tst_aSelTargetsIdx[0])2524 {2525 clipConvertDataFromX11CallbackWorker(closure, NULL, 0); /* Could not convert to target. */2526 return;2527 }2528 void *pValue = NULL;2529 pValue = g_tst_pSelData ? RTMemDup(g_tst_pSelData, g_tst_cSelData) : NULL;2530 count = g_tst_pSelData ? g_tst_cSelData : 0;2531 format = g_tst_selFormat;2532 if (!pValue)2533 {2534 count = 0;2535 format = 0;2536 }2537 clipConvertDataFromX11CallbackWorker(closure, pValue, count * format / 8);2538 if (pValue)2539 RTMemFree(pValue);2540 }2541 2542 /* The formats currently on offer from X11 via the shared clipboard. */2543 static uint32_t g_tst_uX11Formats = 0;2544 2545 DECLCALLBACK(void) ShClX11ReportFormatsCallback(PSHCLCONTEXT pCtx, SHCLFORMATS Formats)2546 {2547 RT_NOREF(pCtx);2548 g_tst_uX11Formats = Formats;2549 }2550 2551 static uint32_t tstClipQueryFormats(void)2552 {2553 return g_tst_uX11Formats;2554 }2555 2556 static void tstClipInvalidateFormats(void)2557 {2558 g_tst_uX11Formats = ~0;2559 }2560 2561 /* Does our clipboard code currently own the selection? */2562 static bool g_tst_fOwnsSel = false;2563 /* The procedure that is called when we should convert the selection to a2564 * given format. */2565 static XtConvertSelectionProc g_tst_pfnSelConvert = NULL;2566 /* The procedure which is called when we lose the selection. */2567 static XtLoseSelectionProc g_tst_pfnSelLose = NULL;2568 /* The procedure which is called when the selection transfer has completed. */2569 static XtSelectionDoneProc g_tst_pfnSelDone = NULL;2570 2571 Boolean XtOwnSelection(Widget widget, Atom selection, Time time,2572 XtConvertSelectionProc convert,2573 XtLoseSelectionProc lose,2574 XtSelectionDoneProc done)2575 {2576 RT_NOREF(widget, time);2577 if (selection != XInternAtom(NULL, "CLIPBOARD", 0))2578 return True; /* We don't really care about this. */2579 g_tst_fOwnsSel = true; /* Always succeed. */2580 g_tst_pfnSelConvert = convert;2581 g_tst_pfnSelLose = lose;2582 g_tst_pfnSelDone = done;2583 return True;2584 }2585 2586 void XtDisownSelection(Widget widget, Atom selection, Time time)2587 {2588 RT_NOREF(widget, time, selection);2589 g_tst_fOwnsSel = false;2590 g_tst_pfnSelConvert = NULL;2591 g_tst_pfnSelLose = NULL;2592 g_tst_pfnSelDone = NULL;2593 }2594 2595 /* Request the shared clipboard to convert its data to a given format. */2596 static bool tstClipConvertSelection(const char *pcszTarget, Atom *type,2597 XtPointer *value, unsigned long *length,2598 int *format)2599 {2600 Atom target = XInternAtom(NULL, pcszTarget, 0);2601 if (target == 0)2602 return false;2603 /* Initialise all return values in case we make a quick exit. */2604 *type = XA_STRING;2605 *value = NULL;2606 *length = 0;2607 *format = 0;2608 if (!g_tst_fOwnsSel)2609 return false;2610 if (!g_tst_pfnSelConvert)2611 return false;2612 Atom clipAtom = XInternAtom(NULL, "CLIPBOARD", 0);2613 if (!g_tst_pfnSelConvert(TESTCASE_WIDGET_ID, &clipAtom, &target, type,2614 value, length, format))2615 return false;2616 if (g_tst_pfnSelDone)2617 g_tst_pfnSelDone(TESTCASE_WIDGET_ID, &clipAtom, &target);2618 return true;2619 }2620 2621 /* Set the current X selection data */2622 static void tstClipSetSelectionValues(const char *pcszTarget, Atom type,2623 const void *data,2624 unsigned long count, int format)2625 {2626 Atom clipAtom = XInternAtom(NULL, "CLIPBOARD", 0);2627 g_tst_aSelTargetsIdx[0] = clipFindX11FormatByAtomText(pcszTarget);2628 g_tst_cTargets = 1;2629 g_tst_atmSelType = type;2630 g_tst_pSelData = data;2631 g_tst_cSelData = count;2632 g_tst_selFormat = format;2633 if (g_tst_pfnSelLose)2634 g_tst_pfnSelLose(TESTCASE_WIDGET_ID, &clipAtom);2635 g_tst_fOwnsSel = false;2636 }2637 2638 static void tstClipSendTargetUpdate(PSHCLX11CTX pCtx)2639 {2640 clipQueryX11FormatsCallback(pCtx);2641 }2642 2643 /* Configure if and how the X11 TARGETS clipboard target will fail. */2644 static void tstClipSetTargetsFailure(void)2645 {2646 g_tst_cTargets = 0;2647 }2648 2649 char *XtMalloc(Cardinal size) { return (char *) RTMemAlloc(size); }2650 2651 char *XGetAtomName(Display *display, Atom atom)2652 {2653 RT_NOREF(display);2654 AssertReturn((unsigned)atom < RT_ELEMENTS(g_aFormats) + 1, NULL);2655 const char *pcszName = NULL;2656 if (atom < 0x1000)2657 return NULL;2658 if (0x1000 <= atom && atom < 0x2000)2659 {2660 unsigned index = atom - 0x1000;2661 AssertReturn(index < RT_ELEMENTS(g_aFormats), NULL);2662 pcszName = g_aFormats[index].pcszAtom;2663 }2664 else2665 {2666 unsigned index = atom - 0x2000;2667 AssertReturn(index < RT_ELEMENTS(g_tst_apszSupAtoms), NULL);2668 pcszName = g_tst_apszSupAtoms[index];2669 }2670 return (char *)RTMemDup(pcszName, sizeof(pcszName) + 1);2671 }2672 2673 int XFree(void *data)2674 {2675 RTMemFree(data);2676 return 0;2677 }2678 2679 void XFreeStringList(char **list)2680 {2681 if (list)2682 RTMemFree(*list);2683 RTMemFree(list);2684 }2685 2686 #define TESTCASE_MAX_BUF_SIZE 2562687 2688 static int g_tst_rcCompleted = VINF_SUCCESS;2689 static int g_tst_cbCompleted = 0;2690 static CLIPREADCBREQ *g_tst_pCompletedReq = NULL;2691 static char g_tst_abCompletedBuf[TESTCASE_MAX_BUF_SIZE];2692 2693 void ShClX11RequestFromX11CompleteCallback(PSHCLCONTEXT pCtx, int rc, CLIPREADCBREQ *pReq, void *pv, uint32_t cb)2694 {2695 RT_NOREF(pCtx);2696 if (cb <= TESTCASE_MAX_BUF_SIZE)2697 {2698 g_tst_rcCompleted = rc;2699 if (cb != 0)2700 memcpy(g_tst_abCompletedBuf, pv, cb);2701 }2702 else2703 g_tst_rcCompleted = VERR_BUFFER_OVERFLOW;2704 g_tst_cbCompleted = cb;2705 g_tst_pCompletedReq = pReq;2706 }2707 2708 static void tstClipGetCompletedRequest(int *prc, char ** ppc, uint32_t *pcb, CLIPREADCBREQ **ppReq)2709 {2710 *prc = g_tst_rcCompleted;2711 *ppc = g_tst_abCompletedBuf;2712 *pcb = g_tst_cbCompleted;2713 *ppReq = g_tst_pCompletedReq;2714 }2715 #ifdef RT_OS_SOLARIS_102716 char XtStrings [] = "";2717 _WidgetClassRec* applicationShellWidgetClass;2718 char XtShellStrings [] = "";2719 int XmbTextPropertyToTextList(2720 Display* /* display */,2721 XTextProperty* /* text_prop */,2722 char*** /* list_return */,2723 int* /* count_return */2724 )2725 {2726 return 0;2727 }2728 #else2729 const char XtStrings [] = "";2730 _WidgetClassRec* applicationShellWidgetClass;2731 const char XtShellStrings [] = "";2732 #endif2733 2734 static void tstStringFromX11(RTTEST hTest, PSHCLX11CTX pCtx,2735 const char *pcszExp, int rcExp)2736 {2737 bool retval = true;2738 tstClipSendTargetUpdate(pCtx);2739 if (tstClipQueryFormats() != VBOX_SHCL_FMT_UNICODETEXT)2740 RTTestFailed(hTest, "Wrong targets reported: %02X\n",2741 tstClipQueryFormats());2742 else2743 {2744 char *pc;2745 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;2746 ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);2747 int rc = VINF_SUCCESS;2748 uint32_t cbActual = 0;2749 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);2750 if (rc != rcExp)2751 RTTestFailed(hTest, "Wrong return code, expected %Rrc, got %Rrc\n",2752 rcExp, rc);2753 else if (pReqRet != pReq)2754 RTTestFailed(hTest, "Wrong returned request data, expected %p, got %p\n",2755 pReq, pReqRet);2756 else if (RT_FAILURE(rcExp))2757 retval = true;2758 else2759 {2760 RTUTF16 wcExp[TESTCASE_MAX_BUF_SIZE / 2];2761 RTUTF16 *pwcExp = wcExp;2762 size_t cwc = 0;2763 rc = RTStrToUtf16Ex(pcszExp, RTSTR_MAX, &pwcExp,2764 RT_ELEMENTS(wcExp), &cwc);2765 size_t cbExp = cwc * 2 + 2;2766 AssertRC(rc);2767 if (RT_SUCCESS(rc))2768 {2769 if (cbActual != cbExp)2770 {2771 RTTestFailed(hTest, "Returned string is the wrong size, string \"%.*ls\", size %u, expected \"%s\", size %u\n",2772 RT_MIN(TESTCASE_MAX_BUF_SIZE, cbActual), pc, cbActual,2773 pcszExp, cbExp);2774 }2775 else2776 {2777 if (memcmp(pc, wcExp, cbExp) == 0)2778 retval = true;2779 else2780 RTTestFailed(hTest, "Returned string \"%.*ls\" does not match expected string \"%s\"\n",2781 TESTCASE_MAX_BUF_SIZE, pc, pcszExp);2782 }2783 }2784 }2785 }2786 if (!retval)2787 RTTestFailureDetails(hTest, "Expected: string \"%s\", rc %Rrc\n",2788 pcszExp, rcExp);2789 }2790 2791 static void tstLatin1FromX11(RTTEST hTest, PSHCLX11CTX pCtx,2792 const char *pcszExp, int rcExp)2793 {2794 bool retval = false;2795 tstClipSendTargetUpdate(pCtx);2796 if (tstClipQueryFormats() != VBOX_SHCL_FMT_UNICODETEXT)2797 RTTestFailed(hTest, "Wrong targets reported: %02X\n",2798 tstClipQueryFormats());2799 else2800 {2801 char *pc;2802 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;2803 ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);2804 int rc = VINF_SUCCESS;2805 uint32_t cbActual = 0;2806 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);2807 if (rc != rcExp)2808 RTTestFailed(hTest, "Wrong return code, expected %Rrc, got %Rrc\n",2809 rcExp, rc);2810 else if (pReqRet != pReq)2811 RTTestFailed(hTest, "Wrong returned request data, expected %p, got %p\n",2812 pReq, pReqRet);2813 else if (RT_FAILURE(rcExp))2814 retval = true;2815 else2816 {2817 RTUTF16 wcExp[TESTCASE_MAX_BUF_SIZE / 2];2818 //RTUTF16 *pwcExp = wcExp; - unused2819 size_t cwc;2820 for (cwc = 0; cwc == 0 || pcszExp[cwc - 1] != '\0'; ++cwc)2821 wcExp[cwc] = pcszExp[cwc];2822 size_t cbExp = cwc * 2;2823 if (cbActual != cbExp)2824 {2825 RTTestFailed(hTest, "Returned string is the wrong size, string \"%.*ls\", size %u, expected \"%s\", size %u\n",2826 RT_MIN(TESTCASE_MAX_BUF_SIZE, cbActual), pc, cbActual,2827 pcszExp, cbExp);2828 }2829 else2830 {2831 if (memcmp(pc, wcExp, cbExp) == 0)2832 retval = true;2833 else2834 RTTestFailed(hTest, "Returned string \"%.*ls\" does not match expected string \"%s\"\n",2835 TESTCASE_MAX_BUF_SIZE, pc, pcszExp);2836 }2837 }2838 }2839 if (!retval)2840 RTTestFailureDetails(hTest, "Expected: string \"%s\", rc %Rrc\n",2841 pcszExp, rcExp);2842 }2843 2844 static void tstStringFromVBox(RTTEST hTest, PSHCLX11CTX pCtx, const char *pcszTarget, Atom typeExp, const char *valueExp)2845 {2846 RT_NOREF(pCtx);2847 bool retval = false;2848 Atom type;2849 XtPointer value = NULL;2850 unsigned long length;2851 int format;2852 size_t lenExp = strlen(valueExp);2853 if (tstClipConvertSelection(pcszTarget, &type, &value, &length, &format))2854 {2855 if ( type != typeExp2856 || length != lenExp2857 || format != 82858 || memcmp((const void *) value, (const void *)valueExp,2859 lenExp))2860 {2861 RTTestFailed(hTest, "Bad data: type %d, (expected %d), length %u, (%u), format %d (%d), value \"%.*s\" (\"%.*s\")\n",2862 type, typeExp, length, lenExp, format, 8,2863 RT_MIN(length, 20), value, RT_MIN(lenExp, 20), valueExp);2864 }2865 else2866 retval = true;2867 }2868 else2869 RTTestFailed(hTest, "Conversion failed\n");2870 XtFree((char *)value);2871 if (!retval)2872 RTTestFailureDetails(hTest, "Conversion to %s, expected \"%s\"\n",2873 pcszTarget, valueExp);2874 }2875 2876 static void tstNoX11(PSHCLX11CTX pCtx, const char *pcszTestCtx)2877 {2878 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq;2879 int rc = ShClX11ReadDataFromX11(pCtx, VBOX_SHCL_FMT_UNICODETEXT, pReq);2880 RTTESTI_CHECK_MSG(rc == VERR_NO_DATA, ("context: %s\n", pcszTestCtx));2881 }2882 2883 static void tstStringFromVBoxFailed(RTTEST hTest, PSHCLX11CTX pCtx, const char *pcszTarget)2884 {2885 RT_NOREF(pCtx);2886 Atom type;2887 XtPointer value = NULL;2888 unsigned long length;2889 int format;2890 RTTEST_CHECK_MSG(hTest, !tstClipConvertSelection(pcszTarget, &type, &value,2891 &length, &format),2892 (hTest, "Conversion to target %s, should have failed but didn't, returned type %d, length %u, format %d, value \"%.*s\"\n",2893 pcszTarget, type, length, format, RT_MIN(length, 20),2894 value));2895 XtFree((char *)value);2896 }2897 2898 static void tstNoSelectionOwnership(PSHCLX11CTX pCtx, const char *pcszTestCtx)2899 {2900 RT_NOREF(pCtx);2901 RTTESTI_CHECK_MSG(!g_tst_fOwnsSel, ("context: %s\n", pcszTestCtx));2902 }2903 2904 static void tstBadFormatRequestFromHost(RTTEST hTest, PSHCLX11CTX pCtx)2905 {2906 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",2907 sizeof("hello world"), 8);2908 tstClipSendTargetUpdate(pCtx);2909 if (tstClipQueryFormats() != VBOX_SHCL_FMT_UNICODETEXT)2910 RTTestFailed(hTest, "Wrong targets reported: %02X\n",2911 tstClipQueryFormats());2912 else2913 {2914 char *pc;2915 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;2916 ShClX11ReadDataFromX11(pCtx, 0xF000 /* vboxFormat */, pReq); /* Bad format. */2917 int rc = VINF_SUCCESS;2918 uint32_t cbActual = 0;2919 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);2920 if (rc != VERR_NOT_IMPLEMENTED)2921 RTTestFailed(hTest, "Wrong return code, expected VERR_NOT_IMPLEMENTED, got %Rrc\n",2922 rc);2923 tstClipSetSelectionValues("", XA_STRING, "", sizeof(""), 8);2924 tstClipSendTargetUpdate(pCtx);2925 if (tstClipQueryFormats() == VBOX_SHCL_FMT_UNICODETEXT)2926 RTTestFailed(hTest, "Failed to report targets after bad host request.\n");2927 }2928 }2929 2930 int main()2931 {2932 /*2933 * Init the runtime, test and say hello.2934 */2935 RTTEST hTest;2936 int rc = RTTestInitAndCreate("tstClipboardX11", &hTest);2937 if (rc)2938 return rc;2939 RTTestBanner(hTest);2940 2941 /*2942 * Run the tests.2943 */2944 SHCLX11CTX X11Ctx;2945 rc = ShClX11Init(&X11Ctx, NULL, false);2946 AssertRCReturn(rc, 1);2947 char *pc;2948 uint32_t cbActual;2949 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;2950 rc = ShClX11ThreadStart(&X11Ctx, false /* fGrab */);2951 AssertRCReturn(rc, 1);2952 2953 /* UTF-8 from X11 */2954 RTTestSub(hTest, "reading UTF-8 from X11");2955 /* Simple test */2956 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",2957 sizeof("hello world"), 8);2958 tstStringFromX11(hTest, &X11Ctx, "hello world", VINF_SUCCESS);2959 /* With an embedded carriage return */2960 tstClipSetSelectionValues("text/plain;charset=UTF-8", XA_STRING,2961 "hello\nworld", sizeof("hello\nworld"), 8);2962 tstStringFromX11(hTest, &X11Ctx, "hello\r\nworld", VINF_SUCCESS);2963 /* With an embedded CRLF */2964 tstClipSetSelectionValues("text/plain;charset=UTF-8", XA_STRING,2965 "hello\r\nworld", sizeof("hello\r\nworld"), 8);2966 tstStringFromX11(hTest, &X11Ctx, "hello\r\r\nworld", VINF_SUCCESS);2967 /* With an embedded LFCR */2968 tstClipSetSelectionValues("text/plain;charset=UTF-8", XA_STRING,2969 "hello\n\rworld", sizeof("hello\n\rworld"), 8);2970 tstStringFromX11(hTest, &X11Ctx, "hello\r\n\rworld", VINF_SUCCESS);2971 /* An empty string */2972 tstClipSetSelectionValues("text/plain;charset=utf-8", XA_STRING, "",2973 sizeof(""), 8);2974 tstStringFromX11(hTest, &X11Ctx, "", VINF_SUCCESS);2975 /* With an embedded UTF-8 character. */2976 tstClipSetSelectionValues("STRING", XA_STRING,2977 "100\xE2\x82\xAC" /* 100 Euro */,2978 sizeof("100\xE2\x82\xAC"), 8);2979 tstStringFromX11(hTest, &X11Ctx, "100\xE2\x82\xAC", VINF_SUCCESS);2980 /* A non-zero-terminated string */2981 tstClipSetSelectionValues("TEXT", XA_STRING,2982 "hello world", sizeof("hello world") - 1, 8);2983 tstStringFromX11(hTest, &X11Ctx, "hello world", VINF_SUCCESS);2984 2985 /* Latin1 from X11 */2986 RTTestSub(hTest, "reading Latin1 from X11");2987 /* Simple test */2988 tstClipSetSelectionValues("STRING", XA_STRING, "Georges Dupr\xEA",2989 sizeof("Georges Dupr\xEA"), 8);2990 tstLatin1FromX11(hTest, &X11Ctx, "Georges Dupr\xEA", VINF_SUCCESS);2991 /* With an embedded carriage return */2992 tstClipSetSelectionValues("TEXT", XA_STRING, "Georges\nDupr\xEA",2993 sizeof("Georges\nDupr\xEA"), 8);2994 tstLatin1FromX11(hTest, &X11Ctx, "Georges\r\nDupr\xEA", VINF_SUCCESS);2995 /* With an embedded CRLF */2996 tstClipSetSelectionValues("TEXT", XA_STRING, "Georges\r\nDupr\xEA",2997 sizeof("Georges\r\nDupr\xEA"), 8);2998 tstLatin1FromX11(hTest, &X11Ctx, "Georges\r\r\nDupr\xEA", VINF_SUCCESS);2999 /* With an embedded LFCR */3000 tstClipSetSelectionValues("TEXT", XA_STRING, "Georges\n\rDupr\xEA",3001 sizeof("Georges\n\rDupr\xEA"), 8);3002 tstLatin1FromX11(hTest, &X11Ctx, "Georges\r\n\rDupr\xEA", VINF_SUCCESS);3003 /* A non-zero-terminated string */3004 tstClipSetSelectionValues("text/plain", XA_STRING,3005 "Georges Dupr\xEA!",3006 sizeof("Georges Dupr\xEA!") - 1, 8);3007 tstLatin1FromX11(hTest, &X11Ctx, "Georges Dupr\xEA!", VINF_SUCCESS);3008 3009 /*3010 * Unknown X11 format3011 */3012 RTTestSub(hTest, "handling of an unknown X11 format");3013 tstClipInvalidateFormats();3014 tstClipSetSelectionValues("CLIPBOARD", XA_STRING, "Test",3015 sizeof("Test"), 8);3016 tstClipSendTargetUpdate(&X11Ctx);3017 RTTEST_CHECK_MSG(hTest, tstClipQueryFormats() == 0,3018 (hTest, "Failed to send a format update notification\n"));3019 3020 /*3021 * Timeout from X113022 */3023 RTTestSub(hTest, "X11 timeout");3024 tstClipSetSelectionValues("UTF8_STRING", XT_CONVERT_FAIL, NULL,0, 8);3025 tstStringFromX11(hTest, &X11Ctx, "", VERR_NO_DATA);3026 3027 /*3028 * No data in X11 clipboard3029 */3030 RTTestSub(hTest, "a data request from an empty X11 clipboard");3031 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, NULL,3032 0, 8);3033 ShClX11ReadDataFromX11(&X11Ctx, VBOX_SHCL_FMT_UNICODETEXT, pReq);3034 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);3035 RTTEST_CHECK_MSG(hTest, rc == VERR_NO_DATA,3036 (hTest, "Returned %Rrc instead of VERR_NO_DATA\n",3037 rc));3038 RTTEST_CHECK_MSG(hTest, pReqRet == pReq,3039 (hTest, "Wrong returned request data, expected %p, got %p\n",3040 pReq, pReqRet));3041 3042 /*3043 * Ensure that VBox is notified when we return the CB to X113044 */3045 RTTestSub(hTest, "notification of switch to X11 clipboard");3046 tstClipInvalidateFormats();3047 clipReportEmptyX11CB(&X11Ctx);3048 RTTEST_CHECK_MSG(hTest, tstClipQueryFormats() == 0,3049 (hTest, "Failed to send a format update (release) notification\n"));3050 3051 /*3052 * Request for an invalid VBox format from X113053 */3054 RTTestSub(hTest, "a request for an invalid VBox format from X11");3055 /* Testing for 0xffff will go into handling VBOX_SHCL_FMT_UNICODETEXT, where we don't have3056 * have any data at the moment so far, so this will return VERR_NO_DATA. */3057 ShClX11ReadDataFromX11(&X11Ctx, 0xffff /* vboxFormat */, pReq);3058 tstClipGetCompletedRequest(&rc, &pc, &cbActual, &pReqRet);3059 RTTEST_CHECK_MSG(hTest, rc == VERR_NO_DATA,3060 (hTest, "Returned %Rrc instead of VERR_NO_DATA\n",3061 rc));3062 RTTEST_CHECK_MSG(hTest, pReqRet == pReq,3063 (hTest, "Wrong returned request data, expected %p, got %p\n",3064 pReq, pReqRet));3065 3066 /*3067 * Targets failure from X113068 */3069 RTTestSub(hTest, "X11 targets conversion failure");3070 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",3071 sizeof("hello world"), 8);3072 tstClipSetTargetsFailure();3073 Atom atom = XA_STRING;3074 long unsigned int cLen = 0;3075 int format = 8;3076 clipConvertX11TargetsCallback(NULL, (XtPointer) &X11Ctx, NULL, &atom, NULL, &cLen,3077 &format);3078 RTTEST_CHECK_MSG(hTest, tstClipQueryFormats() == 0,3079 (hTest, "Wrong targets reported: %02X\n",3080 tstClipQueryFormats()));3081 3082 /*3083 * X11 text format conversion3084 */3085 RTTestSub(hTest, "handling of X11 selection targets");3086 RTTEST_CHECK_MSG(hTest, tstClipTextFormatConversion(&X11Ctx),3087 (hTest, "failed to select the right X11 text formats\n"));3088 3089 /*3090 * UTF-8 from VBox3091 */3092 RTTestSub(hTest, "reading UTF-8 from VBox");3093 /* Simple test */3094 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello world",3095 sizeof("hello world") * 2);3096 tstStringFromVBox(hTest, &X11Ctx, "UTF8_STRING",3097 clipGetAtom(&X11Ctx, "UTF8_STRING"), "hello world");3098 /* With an embedded carriage return */3099 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello\r\nworld",3100 sizeof("hello\r\nworld") * 2);3101 tstStringFromVBox(hTest, &X11Ctx, "text/plain;charset=UTF-8",3102 clipGetAtom(&X11Ctx, "text/plain;charset=UTF-8"),3103 "hello\nworld");3104 /* With an embedded CRCRLF */3105 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello\r\r\nworld",3106 sizeof("hello\r\r\nworld") * 2);3107 tstStringFromVBox(hTest, &X11Ctx, "text/plain;charset=UTF-8",3108 clipGetAtom(&X11Ctx, "text/plain;charset=UTF-8"),3109 "hello\r\nworld");3110 /* With an embedded CRLFCR */3111 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello\r\n\rworld",3112 sizeof("hello\r\n\rworld") * 2);3113 tstStringFromVBox(hTest, &X11Ctx, "text/plain;charset=UTF-8",3114 clipGetAtom(&X11Ctx, "text/plain;charset=UTF-8"),3115 "hello\n\rworld");3116 /* An empty string */3117 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "", 2);3118 tstStringFromVBox(hTest, &X11Ctx, "text/plain;charset=utf-8",3119 clipGetAtom(&X11Ctx, "text/plain;charset=utf-8"), "");3120 /* With an embedded UTF-8 character. */3121 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "100\xE2\x82\xAC" /* 100 Euro */,3122 10);3123 tstStringFromVBox(hTest, &X11Ctx, "STRING",3124 clipGetAtom(&X11Ctx, "STRING"), "100\xE2\x82\xAC");3125 /* A non-zero-terminated string */3126 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello world",3127 sizeof("hello world") * 2 - 2);3128 tstStringFromVBox(hTest, &X11Ctx, "TEXT", clipGetAtom(&X11Ctx, "TEXT"),3129 "hello world");3130 3131 /*3132 * Timeout from VBox3133 */3134 RTTestSub(hTest, "reading from VBox with timeout");3135 tstClipEmptyVBox(&X11Ctx, VERR_TIMEOUT);3136 tstStringFromVBoxFailed(hTest, &X11Ctx, "UTF8_STRING");3137 3138 /*3139 * No data in VBox clipboard3140 */3141 RTTestSub(hTest, "an empty VBox clipboard");3142 tstClipSetSelectionValues("TEXT", XA_STRING, "", sizeof(""), 8);3143 tstClipEmptyVBox(&X11Ctx, VINF_SUCCESS);3144 RTTEST_CHECK_MSG(hTest, g_tst_fOwnsSel,3145 (hTest, "VBox grabbed the clipboard with no data and we ignored it\n"));3146 tstStringFromVBoxFailed(hTest, &X11Ctx, "UTF8_STRING");3147 3148 /*3149 * An unknown VBox format3150 */3151 RTTestSub(hTest, "reading an unknown VBox format");3152 tstClipSetSelectionValues("TEXT", XA_STRING, "", sizeof(""), 8);3153 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "", 2);3154 ShClX11ReportFormatsToX11(&X11Ctx, 0xa0000);3155 RTTEST_CHECK_MSG(hTest, g_tst_fOwnsSel,3156 (hTest, "VBox grabbed the clipboard with unknown data and we ignored it\n"));3157 tstStringFromVBoxFailed(hTest, &X11Ctx, "UTF8_STRING");3158 3159 /*3160 * VBox requests a bad format3161 */3162 RTTestSub(hTest, "recovery from a bad format request");3163 tstBadFormatRequestFromHost(hTest, &X11Ctx);3164 3165 rc = ShClX11ThreadStop(&X11Ctx);3166 AssertRCReturn(rc, 1);3167 ShClX11Destroy(&X11Ctx);3168 3169 /*3170 * Headless clipboard tests3171 */3172 rc = ShClX11Init(&X11Ctx, NULL, true);3173 AssertRCReturn(rc, 1);3174 rc = ShClX11ThreadStart(&X11Ctx, false /* fGrab */);3175 AssertRCReturn(rc, 1);3176 3177 /* Read from X11 */3178 RTTestSub(hTest, "reading from X11, headless clipboard");3179 /* Simple test */3180 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "",3181 sizeof("") * 2);3182 tstClipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",3183 sizeof("hello world"), 8);3184 tstNoX11(&X11Ctx, "reading from X11, headless clipboard");3185 3186 /* Read from VBox */3187 RTTestSub(hTest, "reading from VBox, headless clipboard");3188 /* Simple test */3189 tstClipEmptyVBox(&X11Ctx, VERR_WRONG_ORDER);3190 tstClipSetSelectionValues("TEXT", XA_STRING, "", sizeof(""), 8);3191 tstClipSetVBoxUtf16(&X11Ctx, VINF_SUCCESS, "hello world",3192 sizeof("hello world") * 2);3193 tstNoSelectionOwnership(&X11Ctx, "reading from VBox, headless clipboard");3194 3195 rc = ShClX11ThreadStop(&X11Ctx);3196 AssertRCReturn(rc, 1);3197 3198 ShClX11Destroy(&X11Ctx);3199 3200 return RTTestSummaryAndDestroy(hTest);3201 }3202 3203 #endif3204 3205 #ifdef SMOKETEST3206 3207 /* This is a simple test case that just starts a copy of the X11 clipboard3208 * backend, checks the X11 clipboard and exits. If ever needed I will add an3209 * interactive mode in which the user can read and copy to the clipboard from3210 * the command line. */3211 3212 # include <iprt/env.h>3213 # include <iprt/test.h>3214 3215 DECLCALLBACK(int) ShClX11RequestDataForX11Callback(PSHCLCONTEXT pCtx, SHCLFORMAT Format, void **ppv, uint32_t *pcb)3216 {3217 RT_NOREF(pCtx, Format, ppv, pcb);3218 return VERR_NO_DATA;3219 }3220 3221 DECLCALLBACK(void) ShClX11ReportFormatsCallback(PSHCLCONTEXT pCtx, SHCLFORMATS Formats)3222 {3223 RT_NOREF(pCtx, Formats);3224 }3225 3226 DECLCALLBACK(void) ShClX11RequestFromX11CompleteCallback(PSHCLCONTEXT pCtx, int rc, CLIPREADCBREQ *pReq, void *pv, uint32_t cb)3227 {3228 RT_NOREF(pCtx, rc, pReq, pv, cb);3229 }3230 3231 int main()3232 {3233 /*3234 * Init the runtime, test and say hello.3235 */3236 RTTEST hTest;3237 int rc = RTTestInitAndCreate("tstClipboardX11Smoke", &hTest);3238 if (rc)3239 return rc;3240 RTTestBanner(hTest);3241 3242 /*3243 * Run the test.3244 */3245 rc = VINF_SUCCESS;3246 /* We can't test anything without an X session, so just return success3247 * in that case. */3248 if (!RTEnvExist("DISPLAY"))3249 {3250 RTTestPrintf(hTest, RTTESTLVL_INFO,3251 "X11 not available, not running test\n");3252 return RTTestSummaryAndDestroy(hTest);3253 }3254 SHCLX11CTX X11Ctx;3255 rc = ShClX11Init(&X11Ctx, NULL, false);3256 AssertRCReturn(rc, 1);3257 rc = ShClX11ThreadStart(&X11Ctx, false /* fGrab */);3258 AssertRCReturn(rc, 1);3259 /* Give the clipboard time to synchronise. */3260 RTThreadSleep(500);3261 rc = ShClX11ThreadStop(&X11Ctx);3262 AssertRCReturn(rc, 1);3263 ShClX11Destroy(&X11Ctx);3264 return RTTestSummaryAndDestroy(hTest);3265 }3266 3267 #endif /* SMOKETEST defined */3268
Note:
See TracChangeset
for help on using the changeset viewer.