VirtualBox

Changeset 82906 in vbox for trunk/src/VBox/GuestHost


Ignore:
Timestamp:
Jan 29, 2020 12:45:51 PM (5 years ago)
Author:
vboxsync
Message:

Shared Clipboard/x11: Factored out common guest/host X11 testcases / smoktests into own files to clean up this #ifdef maze. tstClipboardGH-XXX also will emphasize what this actually is testing. bugref:9437

Location:
trunk/src/VBox/GuestHost
Files:
4 added
1 deleted
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/GuestHost/Makefile.kmk

    r80427 r82906  
    2424endif
    2525
    26 ifdef VBOX_WITH_HGCM
    27  include $(PATH_SUB_CURRENT)/SharedClipboard/Makefile.kmk
    28 endif
    29 
    3026ifdef VBOX_WITH_DRAG_AND_DROP
    3127 include $(PATH_SUB_CURRENT)/DragAndDrop/Makefile.kmk
  • trunk/src/VBox/GuestHost/SharedClipboard/clipboard-x11.cpp

    r82901 r82906  
    1515 */
    1616
    17 /* Note: to automatically run regression tests on the shared clipboard,
    18  * execute the tstClipboardX11 testcase.  If you often make changes to the
     17/* Note: to automatically run regression tests on the Shared Clipboard,
     18 * execute the tstClipboardGH-X11 testcase.  If you often make changes to the
    1919 * clipboard code, adding the line
    20  *   OTHERS += $(PATH_tstClipboardX11)/tstClipboardX11.run
     20 *
     21 *   OTHERS += $(PATH_tstClipboardGH-X11)/tstClipboardGH-X11.run
     22 *
    2123 * to LocalConfig.kmk will cause the tests to be run every time the code is
    22  * changed. */
     24 * changed.
     25 */
    2326
    2427
     
    6568#include <VBox/HostServices/VBoxClipboardSvc.h>
    6669
     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
    6778
    6879/*********************************************************************************************************************************
    69 *   Internal Functions                                                                                                           *
     80*   Externals                                                                                                                    *
     81*********************************************************************************************************************************/
     82#ifdef TESTCASE
     83extern void tstClipQueueToEventThread(void (*proc)(void *, void *), void *client_data);
     84extern void tstClipRequestData(SHCLX11CTX* pCtx, SHCLX11FMTIDX target, void *closure);
     85extern void tstRequestTargets(SHCLX11CTX* pCtx);
     86#endif
     87
     88
     89/*********************************************************************************************************************************
     90*   Prototypes                                                                                                                   *
    7091*********************************************************************************************************************************/
    7192class formats;
    72 static Atom clipGetAtom(PSHCLX11CTX pCtx, const char *pszName);
     93SHCL_X11_DECL(Atom) clipGetAtom(PSHCLX11CTX pCtx, const char *pszName);
    7394
    7495
     
    81102 * and to the corresponding VBox clipboard formats.
    82103 */
    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[] =
     104SHCL_X11_DECL(SHCLX11FMTTABLE) g_aFormats[] =
    92105{
    93106    { "INVALID",                            SHCLX11FMT_INVALID,     VBOX_SHCL_FMT_NONE },
     
    116129    /** @todo Add Wayland / Weston support. */
    117130#endif
     131    { "LAST",                               SHCLX11FMT_INVALID,     VBOX_SHCL_FMT_NONE },
    118132};
    119133
    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 */
     150typedef 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
    125162
    126163
     
    145182 * @param   uFmtIdx             Format index to look up SHCLX11CLIPFMT for.
    146183 */
    147 static SHCLX11FMT clipRealFormatForX11Format(SHCLX11FMTIDX uFmtIdx)
     184SHCL_X11_DECL(SHCLX11FMT) clipRealFormatForX11Format(SHCLX11FMTIDX uFmtIdx)
    148185{
    149186    AssertReturn(uFmtIdx <= RT_ELEMENTS(g_aFormats), SHCLX11FMT_INVALID);
     
    177214    return NIL_CLIPX11FORMAT;
    178215}
    179 
    180 #ifdef TESTCASE
    181 /**
    182  * Looks up the X11 format matching a given X11 atom text.
    183  *
    184  * @returns the format on success, NIL_CLIPX11FORMAT on failure
    185  * @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 #endif
    195216
    196217/**
     
    320341 * @param   pcszName            Name of atom to return atom for.
    321342 */
    322 static Atom clipGetAtom(PSHCLX11CTX pCtx, const char *pcszName)
     343SHCL_X11_DECL(Atom) clipGetAtom(PSHCLX11CTX pCtx, const char *pcszName)
    323344{
    324345    AssertPtrReturn(pcszName, None);
    325346    return XInternAtom(XtDisplay(pCtx->pWidget), pcszName, False);
    326347}
    327 
    328 #ifdef TESTCASE
    329 static void tstClipQueueToEventThread(void (*proc)(void *, void *),
    330                                       void *client_data);
    331 #endif
    332348
    333349/** String written to the wakeup pipe. */
     
    414430 * @param  pCtx                 The X11 clipboard context to use.
    415431 */
    416 static void clipReportEmptyX11CB(PSHCLX11CTX pCtx)
     432SHCL_X11_DECL(void) clipReportEmptyX11CB(PSHCLX11CTX pCtx)
    417433{
    418434    clipResetX11Formats(pCtx);
     
    430446 * @param  cTargets             The size of the list in @a pTargets.
    431447 */
    432 static SHCLX11FMTIDX clipGetTextFormatFromTargets(PSHCLX11CTX pCtx,
    433                                                   SHCLX11FMTIDX *pTargets,
    434                                                   size_t cTargets)
     448SHCL_X11_DECL(SHCLX11FMTIDX) clipGetTextFormatFromTargets(PSHCLX11CTX pCtx,
     449                                                          SHCLX11FMTIDX *pTargets,
     450                                                          size_t cTargets)
    435451{
    436452    AssertPtrReturn(pCtx, NIL_CLIPX11FORMAT);
     
    455471}
    456472
    457 #ifdef TESTCASE
    458 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 #endif
    476 
    477473/**
    478474 * Goes through an array of X11 clipboard targets to see if they contain a bitmap
     
    544540}
    545541
    546 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     542# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    547543/**
    548544 * Goes through an array of X11 clipboard targets to see if they contain an URI list
     
    578574    return bestURIListFormat;
    579575}
    580 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
     576# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
    581577
    582578/**
     
    615611}
    616612
    617 static DECLCALLBACK(void) clipQueryX11FormatsCallback(PSHCLX11CTX pCtx);
    618 
    619613/**
    620614 * Updates the context's information about targets currently supported by X11,
    621615 * based on an array of X11 atoms.
    622616 *
    623  * @param   pCtx                The X11 clipboard context to use.
     617 * @param  pCtx                 The X11 clipboard context to use.
    624618 * @param  pTargets             The array of atoms describing the targets supported.
    625619 * @param  cTargets             The size of the array @a pTargets.
    626620 */
    627 static void clipUpdateX11Targets(PSHCLX11CTX pCtx, SHCLX11FMTIDX *pTargets, size_t cTargets)
     621SHCL_X11_DECL(void) clipUpdateX11Targets(PSHCLX11CTX pCtx, SHCLX11FMTIDX *pTargets, size_t cTargets)
    628622{
    629623    LogFlowFuncEnter();
     
    648642 *        unit test.  So keep it simple, be paranoid and log everything.
    649643 */
    650 static void clipConvertX11TargetsCallback(Widget widget, XtPointer pClient,
    651                                           Atom * /* selection */, Atom *atomType,
    652                                           XtPointer pValue, long unsigned int *pcLen,
    653                                           int *piFormat)
     644SHCL_X11_DECL(DECLCALLBACK(void)) clipConvertX11TargetsCallback(Widget widget, XtPointer pClient,
     645                                                                Atom * /* selection */, Atom *atomType,
     646                                                                XtPointer pValue, long unsigned int *pcLen,
     647                                                                int *piFormat)
    654648{
    655649    RT_NOREF(piFormat);
     
    734728}
    735729
    736 #ifdef TESTCASE
    737     void tstRequestTargets(PSHCLX11CTX pCtx);
    738 #endif
    739 
    740730/**
    741731 * Callback to notify us when the contents of the X11 clipboard change.
     
    743733 * @param   pCtx                The X11 clipboard context to use.
    744734 */
    745 static DECLCALLBACK(void) clipQueryX11FormatsCallback(PSHCLX11CTX pCtx)
    746 {
    747     LogFlowFuncEnter();
    748 
     735SHCL_X11_DECL(DECLCALLBACK(void)) clipQueryX11FormatsCallback(PSHCLX11CTX pCtx)
     736{
    749737#ifndef TESTCASE
    750738    LogFlowFunc(("fXtBusy=%RTbool\n", pCtx->fXtBusy));
     
    767755#endif
    768756}
    769 
    770 #ifndef TESTCASE
    771757
    772758typedef struct
     
    812798}
    813799
     800#ifndef TESTCASE
    814801/**
    815802 * The main loop of our X11 event thread.
     
    839826    return VINF_SUCCESS;
    840827}
    841 #endif /* !TESTCASE */
     828#endif
    842829
    843830/**
     
    12181205    const unsigned cFixedTargets = 3;
    12191206
    1220     Atom *atomTargets = (Atom *)XtMalloc((MAX_CLIP_X11_FORMATS + cFixedTargets) * sizeof(Atom));
     1207    Atom *atomTargets = (Atom *)XtMalloc((SHCL_MAX_X11_FORMATS + cFixedTargets) * sizeof(Atom));
    12211208    unsigned cTargets = 0;
    12221209    SHCLX11FMTIDX format = NIL_CLIPX11FORMAT;
     
    19801967
    19811968/**
    1982  * A structure containing information about where to store a request
    1983  * for the X11 clipboard contents.
    1984  */
    1985 typedef struct _CLIPREADX11CBREQ
    1986 {
    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 /**
    19981969 * Converts the data obtained from the X11 clipboard to the required format,
    19991970 * place it in the buffer supplied and signal that data has arrived.
     
    20051976 *        the X11 clipboard contains a format we understand.
    20061977 */
    2007 static void clipConvertDataFromX11CallbackWorker(void *pClient, void *pvSrc, unsigned cbSrc)
     1978SHCL_X11_DECL(void) clipConvertDataFromX11CallbackWorker(void *pClient, void *pvSrc, unsigned cbSrc)
    20081979{
    20091980    CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *)pClient;
     
    21432114        }
    21442115    }
    2145 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     2116# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    21462117    else if (pReq->mFormat == VBOX_SHCL_FMT_URI_LIST)
    21472118    {
     
    21912162        }
    21922163    }
    2193 #endif
     2164# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
    21942165    else
    21952166        rc = VERR_NOT_SUPPORTED;
     
    22032174}
    22042175
    2205 #ifndef TESTCASE
    22062176/**
    22072177 * Converts the data obtained from the X11 clipboard to the required format,
     
    22142184 *        the X11 clipboard contains a format we understand.
    22152185 */
    2216 static void clipConvertDataFromX11Callback(Widget widget, XtPointer pClient,
    2217                                            Atom * /* selection */, Atom *atomType,
    2218                                            XtPointer pvSrc, long unsigned int *pcLen,
    2219                                            int *piFormat)
     2186SHCL_X11_DECL(void) clipConvertDataFromX11Callback(Widget widget, XtPointer pClient,
     2187                                                   Atom * /* selection */, Atom *atomType,
     2188                                                   XtPointer pvSrc, long unsigned int *pcLen,
     2189                                                   int *piFormat)
    22202190{
    22212191    RT_NOREF(widget);
     
    22272197    XtFree((char *)pvSrc);
    22282198}
    2229 #endif
    2230 
    2231 #ifdef TESTCASE
    2232 static void tstClipRequestData(SHCLX11CTX* pCtx, SHCLX11FMTIDX target,
    2233                                void *closure);
    2234 #endif
    22352199
    22362200static int clipGetSelectionValue(PSHCLX11CTX pCtx, SHCLX11FMTIDX format,
     
    23582322}
    23592323
    2360 #ifdef TESTCASE
    2361 
    2362 /** @todo This unit test currently works by emulating the X11 and X toolkit
    2363  * APIs to exercise the code, since I didn't want to rewrite the code too much
    2364  * when I wrote the tests.  However, this makes it rather ugly and hard to
    2365  * understand.  Anyone doing any work on the code should feel free to
    2366  * 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)0xffff
    2372 
    2373 /* For the purpose of the test case, we just execute the procedure to be
    2374  * 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 an
    2488  * 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 the
    2512  * 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 a
    2564  * 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     else
    2665     {
    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 256
    2687 
    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     else
    2703         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_10
    2716 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 #else
    2729 const char XtStrings [] = "";
    2730 _WidgetClassRec* applicationShellWidgetClass;
    2731 const char XtShellStrings [] = "";
    2732 #endif
    2733 
    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     else
    2743     {
    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         else
    2759         {
    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                 else
    2776                 {
    2777                     if (memcmp(pc, wcExp, cbExp) == 0)
    2778                         retval = true;
    2779                     else
    2780                         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     else
    2800     {
    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         else
    2816         {
    2817             RTUTF16 wcExp[TESTCASE_MAX_BUF_SIZE / 2];
    2818             //RTUTF16 *pwcExp = wcExp; - unused
    2819             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             else
    2830             {
    2831                 if (memcmp(pc, wcExp, cbExp) == 0)
    2832                     retval = true;
    2833                 else
    2834                     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 != typeExp
    2856             || length != lenExp
    2857             || format != 8
    2858             || 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         else
    2866             retval = true;
    2867     }
    2868     else
    2869         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     else
    2913     {
    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 format
    3011      */
    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 X11
    3022      */
    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 clipboard
    3029      */
    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 X11
    3044      */
    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 X11
    3053      */
    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 have
    3056      * 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 X11
    3068      */
    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 conversion
    3084      */
    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 VBox
    3091      */
    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 VBox
    3133      */
    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 clipboard
    3140      */
    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 format
    3150      */
    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 format
    3161      */
    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 tests
    3171      */
    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 #endif
    3204 
    3205 #ifdef SMOKETEST
    3206 
    3207 /* This is a simple test case that just starts a copy of the X11 clipboard
    3208  * backend, checks the X11 clipboard and exits.  If ever needed I will add an
    3209  * interactive mode in which the user can read and copy to the clipboard from
    3210  * 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 success
    3247      * 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.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette