summaryrefslogtreecommitdiff
path: root/src/VBox/GuestHost/SharedClipboard
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/GuestHost/SharedClipboard')
-rw-r--r--src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp4
-rw-r--r--src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp862
2 files changed, 388 insertions, 478 deletions
diff --git a/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp b/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp
index 3834683b..ad96ece7 100644
--- a/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp
+++ b/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp
@@ -4,9 +4,9 @@
*/
/*
- * Includes contributions from François Revol
+ * Includes contributions from François Revol
*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp b/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp
index 2dbfc859..d5cd9333 100644
--- a/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp
+++ b/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -53,7 +53,7 @@
#include <VBox/GuestHost/clipboard-helper.h>
#include <VBox/HostServices/VBoxClipboardSvc.h>
-static Atom clipGetAtom(Widget widget, const char *pszName);
+static Atom clipGetAtom(CLIPBACKEND *pCtx, const char *pszName);
/** The different clipboard formats which we support. */
enum CLIPFORMAT
@@ -61,8 +61,8 @@ enum CLIPFORMAT
INVALID = 0,
TARGETS,
TEXT, /* Treat this as Utf8, but it may really be ascii */
- CTEXT,
- UTF8
+ UTF8,
+ BMP
};
/** The table mapping X11 names to data formats and to the corresponding
@@ -87,7 +87,10 @@ static struct _CLIPFORMATTABLE
{ "STRING", TEXT, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT },
{ "TEXT", TEXT, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT },
{ "text/plain", TEXT, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT },
- { "COMPOUND_TEXT", CTEXT, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT }
+ { "image/bmp", BMP, VBOX_SHARED_CLIPBOARD_FMT_BITMAP },
+ { "image/x-bmp", BMP, VBOX_SHARED_CLIPBOARD_FMT_BITMAP },
+ { "image/x-MS-bmp", BMP, VBOX_SHARED_CLIPBOARD_FMT_BITMAP },
+ /* TODO: Inkscape exports image/png but not bmp... */
};
typedef unsigned CLIPX11FORMAT;
@@ -101,9 +104,9 @@ enum
/** Return the atom corresponding to a supported X11 format.
* @param widget a valid Xt widget
*/
-static Atom clipAtomForX11Format(Widget widget, CLIPX11FORMAT format)
+static Atom clipAtomForX11Format(CLIPBACKEND *pCtx, CLIPX11FORMAT format)
{
- return clipGetAtom(widget, g_aFormats[format].pcszAtom);
+ return clipGetAtom(pCtx, g_aFormats[format].pcszAtom);
}
/** Return the CLIPFORMAT corresponding to a supported X11 format. */
@@ -122,10 +125,22 @@ static uint32_t clipVBoxFormatForX11Format(CLIPX11FORMAT format)
* @returns the format on success, NIL_CLIPX11FORMAT on failure
* @param widget a valid Xt widget
*/
-static CLIPX11FORMAT clipFindX11FormatByAtom(Widget widget, Atom atomFormat)
+static CLIPX11FORMAT clipFindX11FormatByAtom(CLIPBACKEND *pCtx, Atom atomFormat)
{
for (unsigned i = 0; i < RT_ELEMENTS(g_aFormats); ++i)
- if (clipAtomForX11Format(widget, i) == atomFormat)
+ if (clipAtomForX11Format(pCtx, i) == atomFormat)
+ return i;
+ return NIL_CLIPX11FORMAT;
+}
+
+/** Lookup the X11 format matching a given X11 atom text.
+ * @returns the format on success, NIL_CLIPX11FORMAT on failure
+ * @param widget a valid Xt widget
+ */
+static CLIPX11FORMAT clipFindX11FormatByAtomText(const char *pcsz)
+{
+ for (unsigned i = 0; i < RT_ELEMENTS(g_aFormats); ++i)
+ if (!strcmp(g_aFormats[i].pcszAtom, pcsz))
return i;
return NIL_CLIPX11FORMAT;
}
@@ -187,6 +202,12 @@ struct _CLIPBACKEND
void (*fixesSelectInput)(Display *, Window, Atom, unsigned long);
/** The first XFixes event number */
int fixesEventBase;
+ /** The Xt Intrinsics can only handle one outstanding clipboard operation
+ * at a time, so we keep track of whether one is in process. */
+ bool fBusy;
+ /** We can't handle a clipboard update event while we are busy, so remember
+ * it for later. */
+ bool fUpdateNeeded;
};
/** The number of simultaneous instances we support. For all normal purposes
@@ -263,42 +284,40 @@ static CLIPBACKEND *clipLookupContext(Widget widget)
/** Convert an atom name string to an X11 atom, looking it up in a cache
* before asking the server */
-static Atom clipGetAtom(Widget widget, const char *pszName)
+static Atom clipGetAtom(CLIPBACKEND *pCtx, const char *pszName)
{
AssertPtrReturn(pszName, None);
- Atom retval = None;
- XrmValue nameVal, atomVal;
- nameVal.addr = (char *) pszName;
- nameVal.size = strlen(pszName);
- atomVal.size = sizeof(Atom);
- atomVal.addr = (char *) &retval;
- XtConvertAndStore(widget, XtRString, &nameVal, XtRAtom, &atomVal);
- return retval;
+ return XInternAtom(XtDisplay(pCtx->widget), pszName, False);
}
-static void clipQueueToEventThread(CLIPBACKEND *pCtx,
- XtTimerCallbackProc proc,
- XtPointer client_data);
+#ifdef TESTCASE
+static void testQueueToEventThread(void (*proc)(void *, void *),
+ void *client_data);
+#endif
/** String written to the wakeup pipe. */
#define WAKE_UP_STRING "WakeUp!"
/** Length of the string written. */
#define WAKE_UP_STRING_LEN ( sizeof(WAKE_UP_STRING) - 1 )
-#ifndef TESTCASE
/** Schedule a function call to run on the Xt event thread by passing it to
* the application context as a 0ms timeout and waking up the event loop by
* writing to the wakeup pipe which it monitors. */
void clipQueueToEventThread(CLIPBACKEND *pCtx,
- XtTimerCallbackProc proc,
- XtPointer client_data)
+ void (*proc)(void *, void *),
+ void *client_data)
{
LogRel2(("clipQueueToEventThread: proc=%p, client_data=%p\n",
proc, client_data));
- XtAppAddTimeOut(pCtx->appContext, 0, proc, client_data);
- write(pCtx->wakeupPipeWrite, WAKE_UP_STRING, WAKE_UP_STRING_LEN);
-}
+#ifndef TESTCASE
+ XtAppAddTimeOut(pCtx->appContext, 0, (XtTimerCallbackProc)proc,
+ (XtPointer)client_data);
+ ssize_t cbWritten = write(pCtx->wakeupPipeWrite, WAKE_UP_STRING, WAKE_UP_STRING_LEN);
+ NOREF(cbWritten);
+#else
+ testQueueToEventThread(proc, client_data);
#endif
+}
/**
* Report the formats currently supported by the X11 clipboard to VBox.
@@ -306,6 +325,7 @@ void clipQueueToEventThread(CLIPBACKEND *pCtx,
static void clipReportFormatsToVBox(CLIPBACKEND *pCtx)
{
uint32_t u32VBoxFormats = clipVBoxFormatForX11Format(pCtx->X11TextFormat);
+ u32VBoxFormats |= clipVBoxFormatForX11Format(pCtx->X11BitmapFormat);
ClipReportX11Formats(pCtx->pFrontend, u32VBoxFormats);
}
@@ -328,13 +348,13 @@ static void clipReportEmptyX11CB(CLIPBACKEND *pCtx)
/**
* Go through an array of X11 clipboard targets to see if they contain a text
* format we can support, and if so choose the ones we prefer (e.g. we like
- * Utf8 better than compound text).
+ * Utf8 better than plain text).
* @param pCtx the clipboard backend context structure
* @param pTargets the list of targets
* @param cTargets the size of the list in @a pTargets
*/
static CLIPX11FORMAT clipGetTextFormatFromTargets(CLIPBACKEND *pCtx,
- Atom *pTargets,
+ CLIPX11FORMAT *pTargets,
size_t cTargets)
{
CLIPX11FORMAT bestTextFormat = NIL_CLIPX11FORMAT;
@@ -343,8 +363,7 @@ static CLIPX11FORMAT clipGetTextFormatFromTargets(CLIPBACKEND *pCtx,
AssertReturn(VALID_PTR(pTargets) || cTargets == 0, NIL_CLIPX11FORMAT);
for (unsigned i = 0; i < cTargets; ++i)
{
- CLIPX11FORMAT format = clipFindX11FormatByAtom(pCtx->widget,
- pTargets[i]);
+ CLIPX11FORMAT format = pTargets[i];
if (format != NIL_CLIPX11FORMAT)
{
if ( (clipVBoxFormatForX11Format(format)
@@ -363,18 +382,16 @@ static CLIPX11FORMAT clipGetTextFormatFromTargets(CLIPBACKEND *pCtx,
static bool clipTestTextFormatConversion(CLIPBACKEND *pCtx)
{
bool success = true;
- Atom targets[3];
+ CLIPX11FORMAT targets[2];
CLIPX11FORMAT x11Format;
- targets[0] = clipGetAtom(NULL, "COMPOUND_TEXT");
- targets[1] = clipGetAtom(NULL, "text/plain");
- targets[2] = clipGetAtom(NULL, "TARGETS");
- x11Format = clipGetTextFormatFromTargets(pCtx, targets, 3);
- if (clipRealFormatForX11Format(x11Format) != CTEXT)
+ targets[0] = clipFindX11FormatByAtomText("text/plain");
+ targets[1] = clipFindX11FormatByAtomText("image/bmp");
+ x11Format = clipGetTextFormatFromTargets(pCtx, targets, 2);
+ if (clipRealFormatForX11Format(x11Format) != TEXT)
success = false;
- targets[0] = clipGetAtom(NULL, "UTF8_STRING");
- targets[1] = clipGetAtom(NULL, "text/plain");
- targets[2] = clipGetAtom(NULL, "COMPOUND_TEXT");
- x11Format = clipGetTextFormatFromTargets(pCtx, targets, 3);
+ targets[0] = clipFindX11FormatByAtomText("UTF8_STRING");
+ targets[1] = clipFindX11FormatByAtomText("text/plain");
+ x11Format = clipGetTextFormatFromTargets(pCtx, targets, 2);
if (clipRealFormatForX11Format(x11Format) != UTF8)
success = false;
return success;
@@ -382,37 +399,68 @@ static bool clipTestTextFormatConversion(CLIPBACKEND *pCtx)
#endif
/**
+ * Go through an array of X11 clipboard targets to see if they contain a bitmap
+ * format we can support, and if so choose the ones we prefer (e.g. we like
+ * BMP better than PNG because we don't have to convert).
+ * @param pCtx the clipboard backend context structure
+ * @param pTargets the list of targets
+ * @param cTargets the size of the list in @a pTargets
+ */
+static CLIPX11FORMAT clipGetBitmapFormatFromTargets(CLIPBACKEND *pCtx,
+ CLIPX11FORMAT *pTargets,
+ size_t cTargets)
+{
+ CLIPX11FORMAT bestBitmapFormat = NIL_CLIPX11FORMAT;
+ CLIPFORMAT enmBestBitmapTarget = INVALID;
+ AssertPtrReturn(pCtx, NIL_CLIPX11FORMAT);
+ AssertReturn(VALID_PTR(pTargets) || cTargets == 0, NIL_CLIPX11FORMAT);
+ for (unsigned i = 0; i < cTargets; ++i)
+ {
+ CLIPX11FORMAT format = pTargets[i];
+ if (format != NIL_CLIPX11FORMAT)
+ {
+ if ( (clipVBoxFormatForX11Format(format)
+ == VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
+ && enmBestBitmapTarget < clipRealFormatForX11Format(format))
+ {
+ enmBestBitmapTarget = clipRealFormatForX11Format(format);
+ bestBitmapFormat = format;
+ }
+ }
+ }
+ return bestBitmapFormat;
+}
+
+/**
* Go through an array of X11 clipboard targets to see if we can support any
* of them and if relevant to choose the ones we prefer (e.g. we like Utf8
- * better than compound text).
+ * better than plain text).
* @param pCtx the clipboard backend context structure
* @param pTargets the list of targets
* @param cTargets the size of the list in @a pTargets
*/
-static void clipGetFormatsFromTargets(CLIPBACKEND *pCtx, Atom *pTargets,
- size_t cTargets)
+static void clipGetFormatsFromTargets(CLIPBACKEND *pCtx,
+ CLIPX11FORMAT *pTargets, size_t cTargets)
{
AssertPtrReturnVoid(pCtx);
AssertPtrReturnVoid(pTargets);
CLIPX11FORMAT bestTextFormat;
+ CLIPX11FORMAT bestBitmapFormat;
bestTextFormat = clipGetTextFormatFromTargets(pCtx, pTargets, cTargets);
if (pCtx->X11TextFormat != bestTextFormat)
{
pCtx->X11TextFormat = bestTextFormat;
-#if defined(DEBUG) && !defined(TESTCASE)
- for (unsigned i = 0; i < cTargets; ++i)
- if (pTargets[i])
- {
- char *pszName = XGetAtomName(XtDisplay(pCtx->widget),
- pTargets[i]);
- LogRel2(("%s: found target %s\n", __PRETTY_FUNCTION__, pszName));
- XFree(pszName);
- }
-#endif
}
pCtx->X11BitmapFormat = INVALID; /* not yet supported */
+ bestBitmapFormat = clipGetBitmapFormatFromTargets(pCtx, pTargets, cTargets);
+ if (pCtx->X11BitmapFormat != bestBitmapFormat)
+ {
+ pCtx->X11BitmapFormat = bestBitmapFormat;
+ }
}
+static void clipQueryX11CBFormats(CLIPBACKEND *pCtx);
+
/**
* Update the context's information about targets currently supported by X11,
* based on an array of X11 atoms.
@@ -420,10 +468,23 @@ static void clipGetFormatsFromTargets(CLIPBACKEND *pCtx, Atom *pTargets,
* @param pTargets the array of atoms describing the targets supported
* @param cTargets the size of the array @a pTargets
*/
-static void clipUpdateX11Targets(CLIPBACKEND *pCtx, Atom *pTargets,
+static void clipUpdateX11Targets(CLIPBACKEND *pCtx, CLIPX11FORMAT *pTargets,
size_t cTargets)
{
- LogRel2 (("%s: called\n", __PRETTY_FUNCTION__));
+ LogRel2 (("%s: called\n", __FUNCTION__));
+ pCtx->fBusy = false;
+ if (pCtx->fUpdateNeeded)
+ {
+ /* We may already be out of date. */
+ pCtx->fUpdateNeeded = false;
+ clipQueryX11CBFormats(pCtx);
+ return;
+ }
+ if (pTargets == NULL) {
+ /* No data available */
+ clipReportEmptyX11CB(pCtx);
+ return;
+ }
clipGetFormatsFromTargets(pCtx, pTargets, cTargets);
clipReportFormatsToVBox(pCtx);
}
@@ -431,39 +492,89 @@ static void clipUpdateX11Targets(CLIPBACKEND *pCtx, Atom *pTargets,
/**
* Notify the VBox clipboard about available data formats, based on the
* "targets" information obtained from the X11 clipboard.
- * @note callback for XtGetSelectionValue
+ * @note Callback for XtGetSelectionValue
+ * @note This function is treated as API glue, and as such is not part of any
+ * unit test. So keep it simple, be paranoid and log everything.
*/
-static void clipConvertX11Targets(Widget, XtPointer pClientData,
+static void clipConvertX11Targets(Widget widget, XtPointer pClientData,
Atom * /* selection */, Atom *atomType,
XtPointer pValue, long unsigned int *pcLen,
int *piFormat)
{
CLIPBACKEND *pCtx =
reinterpret_cast<CLIPBACKEND *>(pClientData);
- LogRel2(("clipConvertX11Targets: pValue=%p, *pcLen=%u, *atomType=%d, XT_CONVERT_FAIL=%d\n",
- pValue, *pcLen, *atomType, XT_CONVERT_FAIL));
- if ( (*atomType == XT_CONVERT_FAIL) /* timeout */
- || (pValue == NULL)) /* No data available */
+ Atom *pAtoms = (Atom *)pValue;
+ unsigned i, j;
+ LogRel2(("%s: pValue=%p, *pcLen=%u, *atomType=%d%s\n", __FUNCTION__,
+ pValue, *pcLen, *atomType,
+ *atomType == XT_CONVERT_FAIL ? " (XT_CONVERT_FAIL)" : ""));
+ CLIPX11FORMAT *pFormats = NULL;
+ if (*pcLen && pValue && (*atomType != XT_CONVERT_FAIL /* time out */))
+ pFormats = (CLIPX11FORMAT *)RTMemAllocZ(*pcLen * sizeof(CLIPX11FORMAT));
+#if defined(DEBUG) && !defined(TESTCASE)
+ if (pValue)
+ for (i = 0; i < *pcLen; ++i)
+ if (pAtoms[i])
+ {
+ char *pszName = XGetAtomName(XtDisplay(widget), pAtoms[i]);
+ LogRel2(("%s: found target %s\n", __FUNCTION__,
+ pszName));
+ XFree(pszName);
+ }
+ else
+ LogRel2(("%s: found empty target.\n", __FUNCTION__));
+#endif
+ if (pFormats)
{
- clipReportEmptyX11CB(pCtx);
- return;
+ for (i = 0; i < *pcLen; ++i)
+ {
+ for (j = 0; j < RT_ELEMENTS(g_aFormats); ++j)
+ {
+ Atom target = XInternAtom(XtDisplay(widget),
+ g_aFormats[j].pcszAtom, False);
+ if (*(pAtoms + i) == target)
+ pFormats[i] = j;
+ }
+#if defined(DEBUG) && !defined(TESTCASE)
+ LogRel2(("%s: reporting format %d (%s)\n", __FUNCTION__,
+ pFormats[i], g_aFormats[pFormats[i]].pcszAtom));
+#endif
+ }
}
- clipUpdateX11Targets(pCtx, (Atom *)pValue, *pcLen);
+ else
+ LogRel2(("%s: reporting empty targets (none reported or allocation failure).\n",
+ __FUNCTION__));
+ clipUpdateX11Targets(pCtx, pFormats, *pcLen);
+ RTMemFree(pFormats);
XtFree(reinterpret_cast<char *>(pValue));
}
+#ifdef TESTCASE
+ void testRequestTargets(CLIPBACKEND *pCtx);
+#endif
+
/**
* Callback to notify us when the contents of the X11 clipboard change.
*/
-void clipQueryX11CBFormats(CLIPBACKEND *pCtx)
+static void clipQueryX11CBFormats(CLIPBACKEND *pCtx)
{
LogRel2 (("%s: requesting the targets that the X11 clipboard offers\n",
__PRETTY_FUNCTION__));
+ if (pCtx->fBusy)
+ {
+ pCtx->fUpdateNeeded = true;
+ return;
+ }
+ pCtx->fBusy = true;
+#ifndef TESTCASE
XtGetSelectionValue(pCtx->widget,
- clipGetAtom(pCtx->widget, "CLIPBOARD"),
- clipGetAtom(pCtx->widget, "TARGETS"),
+ clipGetAtom(pCtx, "CLIPBOARD"),
+ clipGetAtom(pCtx, "TARGETS"),
clipConvertX11Targets, pCtx,
CurrentTime);
+#else
+ testRequestTargets(pCtx);
+#endif
}
#ifndef TESTCASE
@@ -554,7 +665,7 @@ static void clipUninit(CLIPBACKEND *pCtx)
/** Worker function for stopping the clipboard which runs on the event
* thread. */
-static void clipStopEventThreadWorker(XtPointer pUserData, XtIntervalId *)
+static void clipStopEventThreadWorker(void *pUserData, void *)
{
CLIPBACKEND *pCtx = (CLIPBACKEND *)pUserData;
@@ -663,7 +774,7 @@ static int clipInit(CLIPBACKEND *pCtx)
#ifndef TESTCASE
/* Enable clipboard update notification */
pCtx->fixesSelectInput(pDisplay, XtWindow(pCtx->widget),
- clipGetAtom(pCtx->widget, "CLIPBOARD"),
+ clipGetAtom(pCtx, "CLIPBOARD"),
7 /* All XFixes*Selection*NotifyMask flags */);
#endif
}
@@ -845,15 +956,14 @@ static int clipCreateX11Targets(CLIPBACKEND *pCtx, Atom *atomTypeReturn,
format = clipEnumX11Formats(pCtx->vboxFormats, format);
if (format != NIL_CLIPX11FORMAT)
{
- atomTargets[cTargets] = clipAtomForX11Format(pCtx->widget,
- format);
+ atomTargets[cTargets] = clipAtomForX11Format(pCtx, format);
++cTargets;
}
} while (format != NIL_CLIPX11FORMAT);
/* We always offer these */
- atomTargets[cTargets] = clipGetAtom(pCtx->widget, "TARGETS");
- atomTargets[cTargets + 1] = clipGetAtom(pCtx->widget, "MULTIPLE");
- atomTargets[cTargets + 2] = clipGetAtom(pCtx->widget, "TIMESTAMP");
+ atomTargets[cTargets] = clipGetAtom(pCtx, "TARGETS");
+ atomTargets[cTargets + 1] = clipGetAtom(pCtx, "MULTIPLE");
+ atomTargets[cTargets + 2] = clipGetAtom(pCtx, "TIMESTAMP");
*atomTypeReturn = XA_ATOM;
*pValReturn = (XtPointer)atomTargets;
*pcLenReturn = cTargets + 3;
@@ -1009,83 +1119,14 @@ static int clipWinTxtToUtf8ForX11CB(Display *pDisplay, PRTUTF16 pwszSrc,
}
/**
- * Satisfy a request from X11 to convert the clipboard text to
- * COMPOUND_TEXT. We return null-terminated text, but can cope with non-null-
- * terminated input.
- *
- * @returns iprt status code
- * @param pDisplay an X11 display structure, needed for conversions
- * performed by Xlib
- * @param pv the text to be converted (UCS-2 with Windows EOLs)
- * @param cb the length of the text in @cb in bytes
- * @param atomTypeReturn where to store the atom for the type of the data
- * we are returning
- * @param pValReturn where to store the pointer to the data we are
- * returning. This should be to memory allocated by
- * XtMalloc, which will be freed by the Xt toolkit
- * later.
- * @param pcLenReturn where to store the length of the data we are
- * returning
- * @param piFormatReturn where to store the bit width (8, 16, 32) of the
- * data we are returning
- */
-static int clipWinTxtToCTextForX11CB(Display *pDisplay, PRTUTF16 pwszSrc,
- size_t cbSrc, Atom *atomTypeReturn,
- XtPointer *pValReturn,
- unsigned long *pcLenReturn,
- int *piFormatReturn)
-{
- char *pszTmp = NULL, *pszTmp2 = NULL;
- size_t cbTmp = 0, cbActual = 0;
- XTextProperty property;
- int rc = VINF_SUCCESS, xrc = 0;
-
- LogRelFlowFunc(("pwszSrc=%.*ls, cbSrc=%u\n", cbSrc / 2, pwszSrc, cbSrc));
- AssertPtrReturn(pDisplay, false);
- AssertPtrReturn(pwszSrc, false);
- rc = clipWinTxtBufSizeForUtf8(pwszSrc, cbSrc / 2, &cbTmp);
- if (RT_SUCCESS(rc))
- {
- pszTmp = (char *)RTMemAlloc(cbTmp);
- if (!pszTmp)
- rc = VERR_NO_MEMORY;
- }
- if (RT_SUCCESS(rc))
- rc = clipWinTxtToUtf8(pwszSrc, cbSrc, pszTmp, cbTmp + 1,
- &cbActual);
- /* Convert the Utf8 text to the current encoding (usually a noop). */
- if (RT_SUCCESS(rc))
- rc = RTStrUtf8ToCurrentCP(&pszTmp2, pszTmp);
- /* And finally (!) convert the resulting text to compound text. */
- if (RT_SUCCESS(rc))
- xrc = XmbTextListToTextProperty(pDisplay, &pszTmp2, 1,
- XCompoundTextStyle, &property);
- if (RT_SUCCESS(rc) && xrc < 0)
- rc = ( xrc == XNoMemory ? VERR_NO_MEMORY
- : xrc == XLocaleNotSupported ? VERR_NOT_SUPPORTED
- : xrc == XConverterNotFound ? VERR_NOT_SUPPORTED
- : VERR_UNRESOLVED_ERROR);
- RTMemFree(pszTmp);
- RTStrFree(pszTmp2);
- *atomTypeReturn = property.encoding;
- *pValReturn = reinterpret_cast<XtPointer>(property.value);
- *pcLenReturn = property.nitems + 1;
- *piFormatReturn = property.format;
- LogRelFlowFunc(("returning %Rrc\n", rc));
- if (RT_SUCCESS(rc))
- LogRelFlowFunc (("converted string is %s\n", property.value));
- return rc;
-}
-
-/**
* Does this atom correspond to one of the two selection types we support?
* @param widget a valid Xt widget
* @param selType the atom in question
*/
-static bool clipIsSupportedSelectionType(Widget widget, Atom selType)
+static bool clipIsSupportedSelectionType(CLIPBACKEND *pCtx, Atom selType)
{
- return( (selType == clipGetAtom(widget, "CLIPBOARD"))
- || (selType == clipGetAtom(widget, "PRIMARY")));
+ return( (selType == clipGetAtom(pCtx, "CLIPBOARD"))
+ || (selType == clipGetAtom(pCtx, "PRIMARY")));
}
/**
@@ -1100,7 +1141,7 @@ static void clipTrimTrailingNul(XtPointer pText, unsigned long *pcText,
{
AssertPtrReturnVoid(pText);
AssertPtrReturnVoid(pcText);
- AssertReturnVoid((format == UTF8) || (format == CTEXT) || (format == TEXT));
+ AssertReturnVoid((format == UTF8) || (format == TEXT));
if (((char *)pText)[*pcText - 1] == '\0')
--(*pcText);
}
@@ -1112,10 +1153,9 @@ static int clipConvertVBoxCBForX11(CLIPBACKEND *pCtx, Atom *atomTarget,
int *piFormatReturn)
{
int rc = VINF_SUCCESS;
- CLIPX11FORMAT x11Format = clipFindX11FormatByAtom(pCtx->widget,
- *atomTarget);
+ CLIPX11FORMAT x11Format = clipFindX11FormatByAtom(pCtx, *atomTarget);
CLIPFORMAT format = clipRealFormatForX11Format(x11Format);
- if ( ((format == UTF8) || (format == CTEXT) || (format == TEXT))
+ if ( ((format == UTF8) || (format == TEXT))
&& (pCtx->vboxFormats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT))
{
void *pv = NULL;
@@ -1130,15 +1170,36 @@ static int clipConvertVBoxCBForX11(CLIPBACKEND *pCtx, Atom *atomTarget,
(PRTUTF16)pv, cb, atomTarget,
atomTypeReturn, pValReturn,
pcLenReturn, piFormatReturn);
- else if (RT_SUCCESS(rc) && (format == CTEXT))
- rc = clipWinTxtToCTextForX11CB(XtDisplay(pCtx->widget),
- (PRTUTF16)pv, cb,
- atomTypeReturn, pValReturn,
- pcLenReturn, piFormatReturn);
if (RT_SUCCESS(rc))
clipTrimTrailingNul(*(XtPointer *)pValReturn, pcLenReturn, format);
RTMemFree(pv);
}
+ else if ( (format == BMP)
+ && (pCtx->vboxFormats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP))
+ {
+ void *pv = NULL;
+ uint32_t cb = 0;
+ rc = clipReadVBoxClipboard(pCtx,
+ VBOX_SHARED_CLIPBOARD_FMT_BITMAP,
+ &pv, &cb);
+ if (RT_SUCCESS(rc) && (cb == 0))
+ rc = VERR_NO_DATA;
+ if (RT_SUCCESS(rc) && (format == BMP))
+ {
+ /* Create a full BMP from it */
+ rc = vboxClipboardDibToBmp(pv, cb, (void **)pValReturn,
+ (size_t *)pcLenReturn);
+ }
+ else
+ rc = VERR_NOT_SUPPORTED;
+
+ if (RT_SUCCESS(rc))
+ {
+ *atomTypeReturn = *atomTarget;
+ *piFormatReturn = 8;
+ }
+ RTMemFree(pv);
+ }
else
rc = VERR_NOT_SUPPORTED;
return rc;
@@ -1161,9 +1222,9 @@ static Boolean clipXtConvertSelectionProc(Widget widget, Atom *atomSelection,
LogRelFlowFunc(("\n"));
if (!pCtx)
return false;
- if (!clipIsSupportedSelectionType(pCtx->widget, *atomSelection))
+ if (!clipIsSupportedSelectionType(pCtx, *atomSelection))
return false;
- if (*atomTarget == clipGetAtom(pCtx->widget, "TARGETS"))
+ if (*atomTarget == clipGetAtom(pCtx, "TARGETS"))
rc = clipCreateX11Targets(pCtx, atomTypeReturn, pValReturn,
pcLenReturn, piFormatReturn);
else
@@ -1197,13 +1258,23 @@ static void clipInvalidateVBoxCBCache(CLIPBACKEND *pCtx)
*/
static void clipGrabX11CB(CLIPBACKEND *pCtx, uint32_t u32Formats)
{
- if (XtOwnSelection(pCtx->widget, clipGetAtom(pCtx->widget, "CLIPBOARD"),
+ if (XtOwnSelection(pCtx->widget, clipGetAtom(pCtx, "CLIPBOARD"),
CurrentTime, clipXtConvertSelectionProc, NULL, 0))
{
pCtx->vboxFormats = u32Formats;
/* Grab the middle-button paste selection too. */
- XtOwnSelection(pCtx->widget, clipGetAtom(pCtx->widget, "PRIMARY"),
+ XtOwnSelection(pCtx->widget, clipGetAtom(pCtx, "PRIMARY"),
CurrentTime, clipXtConvertSelectionProc, NULL, 0);
+#ifndef TESTCASE
+ /* Xt suppresses these if we already own the clipboard, so send them
+ * ourselves. */
+ XSetSelectionOwner(XtDisplay(pCtx->widget),
+ clipGetAtom(pCtx, "CLIPBOARD"),
+ XtWindow(pCtx->widget), CurrentTime);
+ XSetSelectionOwner(XtDisplay(pCtx->widget),
+ clipGetAtom(pCtx, "PRIMARY"),
+ XtWindow(pCtx->widget), CurrentTime);
+#endif
}
}
@@ -1214,8 +1285,8 @@ static void clipGrabX11CB(CLIPBACKEND *pCtx, uint32_t u32Formats)
* information about the VBox formats available and the
* clipboard context data. Must be freed by the worker.
*/
-static void clipNewVBoxFormatsWorker(XtPointer pUserData,
- XtIntervalId * /* interval */)
+static void clipNewVBoxFormatsWorker(void *pUserData,
+ void * /* interval */)
{
CLIPNEWVBOXFORMATS *pFormats = (CLIPNEWVBOXFORMATS *)pUserData;
CLIPBACKEND *pCtx = pFormats->pCtx;
@@ -1335,77 +1406,6 @@ static int clipUtf8ToWinTxt(const char *pcSrc, unsigned cbSrc,
}
/**
- * Convert COMPOUND TEXT with CR end-of-lines into Utf-16 as Windows expects
- * it and return the result in a RTMemAlloc allocated buffer.
- * @returns IPRT status code
- * @param widget An Xt widget, necessary because we use Xt/Xlib for the
- * conversion
- * @param pcSrc The source text
- * @param cbSrc The size of the source in bytes, not counting the
- * terminating zero
- * @param ppwszDest Where to store the buffer address
- * @param pcbDest On success, where to store the number of bytes written.
- * Undefined otherwise. Optional
- */
-static int clipCTextToWinTxt(Widget widget, unsigned char *pcSrc,
- unsigned cbSrc, PRTUTF16 *ppwszDest,
- uint32_t *pcbDest)
-{
- LogRelFlowFunc(("widget=%p, pcSrc=%p, cbSrc=%u, ppwszDest=%p\n", widget,
- pcSrc, cbSrc, ppwszDest));
- AssertReturn(widget, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pcSrc, VERR_INVALID_POINTER);
- AssertPtrReturn(ppwszDest, VERR_INVALID_POINTER);
- if (pcbDest)
- *pcbDest = 0;
-
- /* Special case as X*TextProperty* can't seem to handle empty strings. */
- if (cbSrc == 0)
- {
- *ppwszDest = (PRTUTF16) RTMemAlloc(2);
- if (!*ppwszDest)
- return VERR_NO_MEMORY;
- **ppwszDest = 0;
- if (pcbDest)
- *pcbDest = 2;
- return VINF_SUCCESS;
- }
-
- if (pcbDest)
- *pcbDest = 0;
- /* Intermediate conversion to Utf8 */
- int rc = VINF_SUCCESS;
- XTextProperty property;
- char **ppcTmp = NULL, *pszTmp = NULL;
- int cProps;
-
- property.value = pcSrc;
- property.encoding = clipGetAtom(widget, "COMPOUND_TEXT");
- property.format = 8;
- property.nitems = cbSrc;
- int xrc = XmbTextPropertyToTextList(XtDisplay(widget), &property,
- &ppcTmp, &cProps);
- if (xrc < 0)
- rc = ( xrc == XNoMemory ? VERR_NO_MEMORY
- : xrc == XLocaleNotSupported ? VERR_NOT_SUPPORTED
- : xrc == XConverterNotFound ? VERR_NOT_SUPPORTED
- : VERR_UNRESOLVED_ERROR);
- /* Convert the text returned to UTF8 */
- if (RT_SUCCESS(rc))
- rc = RTStrCurrentCPToUtf8(&pszTmp, *ppcTmp);
- /* Now convert the UTF8 to UTF16 */
- if (RT_SUCCESS(rc))
- rc = clipUtf8ToWinTxt(pszTmp, strlen(pszTmp), ppwszDest, pcbDest);
- if (ppcTmp != NULL)
- XFreeStringList(ppcTmp);
- RTStrFree(pszTmp);
- LogRelFlowFunc(("Returning %Rrc\n", rc));
- if (pcbDest)
- LogRelFlowFunc(("*pcbDest=%u\n", *pcbDest));
- return rc;
-}
-
-/**
* Convert Latin-1 text with CR end-of-lines into Utf-16 as Windows expects
* it and return the result in a RTMemAlloc allocated buffer.
* @returns IPRT status code
@@ -1474,6 +1474,8 @@ struct _CLIPREADX11CBREQ
uint32_t mFormat;
/** The text format we requested from X11 if we requested text */
CLIPX11FORMAT mTextFormat;
+ /** The bitmap format we requested from X11 if we requested bitmap */
+ CLIPX11FORMAT mBitmapFormat;
/** The clipboard context this request is associated with */
CLIPBACKEND *mCtx;
/** The request structure passed in from the backend. */
@@ -1483,41 +1485,38 @@ struct _CLIPREADX11CBREQ
typedef struct _CLIPREADX11CBREQ CLIPREADX11CBREQ;
/**
- * Convert the text obtained from the X11 clipboard to UTF-16LE with Windows
- * EOLs, place it in the buffer supplied and signal that data has arrived.
+ * Convert the data obtained from the X11 clipboard to the required format,
+ * place it in the buffer supplied and signal that data has arrived.
+ * Convert the text obtained UTF-16LE with Windows EOLs.
+ * Convert full BMP data to DIB format.
* @note X11 backend code, callback for XtGetSelectionValue, for use when
- * the X11 clipboard contains a text format we understand.
+ * the X11 clipboard contains a format we understand.
*/
-static void clipConvertX11CB(Widget widget, XtPointer pClientData,
- Atom * /* selection */, Atom *atomType,
- XtPointer pvSrc, long unsigned int *pcLen,
- int *piFormat)
+static void clipConvertX11CB(void *pClientData, void *pvSrc, unsigned cbSrc)
{
CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *) pClientData;
- LogRelFlowFunc(("pReq->mFormat=%02X, pReq->mTextFormat=%u, pReq->mCtx=%p\n",
- pReq->mFormat, pReq->mTextFormat, pReq->mCtx));
+ LogRelFlowFunc(("pReq->mFormat=%02X, pReq->mTextFormat=%u, "
+ "pReq->mBitmapFormat=%u, pReq->mCtx=%p\n",
+ pReq->mFormat, pReq->mTextFormat, pReq->mBitmapFormat,
+ pReq->mCtx));
AssertPtr(pReq->mCtx);
Assert(pReq->mFormat != 0); /* sanity */
int rc = VINF_SUCCESS;
CLIPBACKEND *pCtx = pReq->mCtx;
- unsigned cbSrc = (*pcLen) * (*piFormat) / 8;
void *pvDest = NULL;
uint32_t cbDest = 0;
+ pCtx->fBusy = false;
+ if (pCtx->fUpdateNeeded)
+ clipQueryX11CBFormats(pCtx);
if (pvSrc == NULL)
/* The clipboard selection may have changed before we could get it. */
rc = VERR_NO_DATA;
- else if (*atomType == XT_CONVERT_FAIL) /* Xt timeout */
- rc = VERR_TIMEOUT;
else if (pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
{
/* In which format is the clipboard data? */
switch (clipRealFormatForX11Format(pReq->mTextFormat))
{
- case CTEXT:
- rc = clipCTextToWinTxt(widget, (unsigned char *)pvSrc, cbSrc,
- (PRTUTF16 *) &pvDest, &cbDest);
- break;
case UTF8:
case TEXT:
{
@@ -1536,9 +1535,36 @@ static void clipConvertX11CB(Widget widget, XtPointer pClientData,
rc = VERR_INVALID_PARAMETER;
}
}
+ else if (pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
+ {
+ /* In which format is the clipboard data? */
+ switch (clipRealFormatForX11Format(pReq->mBitmapFormat))
+ {
+ case BMP:
+ {
+ const void *pDib;
+ size_t cbDibSize;
+ rc = vboxClipboardBmpGetDib((const void *)pvSrc, cbSrc,
+ &pDib, &cbDibSize);
+ if (RT_SUCCESS(rc))
+ {
+ pvDest = RTMemAlloc(cbDibSize);
+ if (!pvDest)
+ rc = VERR_NO_MEMORY;
+ else
+ {
+ memcpy(pvDest, pDib, cbDibSize);
+ cbDest = cbDibSize;
+ }
+ }
+ break;
+ }
+ default:
+ rc = VERR_INVALID_PARAMETER;
+ }
+ }
else
rc = VERR_NOT_IMPLEMENTED;
- XtFree((char *)pvSrc);
ClipCompleteDataRequestFromX11(pReq->mCtx->pFrontend, rc, pReq->mReq,
pvDest, cbDest);
RTMemFree(pvDest);
@@ -1546,21 +1572,66 @@ static void clipConvertX11CB(Widget widget, XtPointer pClientData,
LogRelFlowFunc(("rc=%Rrc\n", rc));
}
+/**
+ * Convert the data obtained from the X11 clipboard to the required format,
+ * place it in the buffer supplied and signal that data has arrived.
+ * Convert the text obtained UTF-16LE with Windows EOLs.
+ * Convert full BMP data to DIB format.
+ * @note X11 backend code, callback for XtGetSelectionValue, for use when
+ * the X11 clipboard contains a format we understand.
+ */
+static void cbConvertX11CB(Widget widget, XtPointer pClientData,
+ Atom * /* selection */, Atom *atomType,
+ XtPointer pvSrc, long unsigned int *pcLen,
+ int *piFormat)
+{
+ if (*atomType == XT_CONVERT_FAIL) /* Xt timeout */
+ clipConvertX11CB(pClientData, NULL, 0);
+ else
+ clipConvertX11CB(pClientData, pvSrc, (*pcLen) * (*piFormat) / 8);
+
+ XtFree((char *)pvSrc);
+}
+
+#ifdef TESTCASE
+static void testRequestData(CLIPBACKEND* pCtx, CLIPX11FORMAT target,
+ void *closure);
+#endif
+
+static void getSelectionValue(CLIPBACKEND *pCtx, CLIPX11FORMAT format,
+ CLIPREADX11CBREQ *pReq)
+{
+#ifndef TESTCASE
+ XtGetSelectionValue(pCtx->widget, clipGetAtom(pCtx, "CLIPBOARD"),
+ clipAtomForX11Format(pCtx, format),
+ cbConvertX11CB,
+ reinterpret_cast<XtPointer>(pReq),
+ CurrentTime);
+#else
+ testRequestData(pCtx, format, (void *)pReq);
+#endif
+}
+
/** Worker function for ClipRequestDataFromX11 which runs on the event
* thread. */
-static void vboxClipboardReadX11Worker(XtPointer pUserData,
- XtIntervalId * /* interval */)
+static void vboxClipboardReadX11Worker(void *pUserData,
+ void * /* interval */)
{
CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *)pUserData;
CLIPBACKEND *pCtx = pReq->mCtx;
LogRelFlowFunc (("pReq->mFormat = %02X\n", pReq->mFormat));
int rc = VINF_SUCCESS;
- /*
- * VBox wants to read data in the given format.
- */
- if (pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
+ bool fBusy = pCtx->fBusy;
+ pCtx->fBusy = true;
+ if (fBusy)
+ /* If the clipboard is busy just fend off the request. */
+ rc = VERR_TRY_AGAIN;
+ else if (pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
{
+ /*
+ * VBox wants to read data in the given format.
+ */
pReq->mTextFormat = pCtx->X11TextFormat;
if (pReq->mTextFormat == INVALID)
/* VBox thinks we have data and we don't */
@@ -1568,12 +1639,18 @@ static void vboxClipboardReadX11Worker(XtPointer pUserData,
else
/* Send out a request for the data to the current clipboard
* owner */
- XtGetSelectionValue(pCtx->widget, clipGetAtom(pCtx->widget, "CLIPBOARD"),
- clipAtomForX11Format(pCtx->widget,
- pCtx->X11TextFormat),
- clipConvertX11CB,
- reinterpret_cast<XtPointer>(pReq),
- CurrentTime);
+ getSelectionValue(pCtx, pCtx->X11TextFormat, pReq);
+ }
+ else if (pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
+ {
+ pReq->mBitmapFormat = pCtx->X11BitmapFormat;
+ if (pReq->mBitmapFormat == INVALID)
+ /* VBox thinks we have data and we don't */
+ rc = VERR_NO_DATA;
+ else
+ /* Send out a request for the data to the current clipboard
+ * owner */
+ getSelectionValue(pCtx, pCtx->X11BitmapFormat, pReq);
}
else
rc = VERR_NOT_IMPLEMENTED;
@@ -1640,9 +1717,8 @@ int ClipRequestDataFromX11(CLIPBACKEND *pCtx, uint32_t u32Format,
/* For the purpose of the test case, we just execute the procedure to be
* scheduled, as we are running single threaded. */
-void clipQueueToEventThread(CLIPBACKEND *pCtx,
- XtTimerCallbackProc proc,
- XtPointer client_data)
+void testQueueToEventThread(void (*proc)(void *, void *),
+ void *client_data)
{
proc(client_data, NULL);
}
@@ -1708,79 +1784,6 @@ int ClipRequestDataForX11(VBOXCLIPBOARDCONTEXT *pCtx,
Display *XtDisplay(Widget w)
{ return (Display *) 0xffff; }
-int XmbTextListToTextProperty(Display *display, char **list, int count,
- XICCEncodingStyle style,
- XTextProperty *text_prop_return)
-{
- /* We don't fully reimplement this API for obvious reasons. */
- AssertReturn(count == 1, XLocaleNotSupported);
- AssertReturn(style == XCompoundTextStyle, XLocaleNotSupported);
- /* We simplify the conversion by only accepting ASCII. */
- for (unsigned i = 0; (*list)[i] != 0; ++i)
- AssertReturn(((*list)[i] & 0x80) == 0, XLocaleNotSupported);
- text_prop_return->value =
- (unsigned char*)RTMemDup(*list, strlen(*list) + 1);
- text_prop_return->encoding = clipGetAtom(NULL, "COMPOUND_TEXT");
- text_prop_return->format = 8;
- text_prop_return->nitems = strlen(*list);
- return 0;
-}
-
-int Xutf8TextListToTextProperty(Display *display, char **list, int count,
- XICCEncodingStyle style,
- XTextProperty *text_prop_return)
-{
- return XmbTextListToTextProperty(display, list, count, style,
- text_prop_return);
-}
-
-int XmbTextPropertyToTextList(Display *display,
- const XTextProperty *text_prop,
- char ***list_return, int *count_return)
-{
- int rc = 0;
- if (text_prop->nitems == 0)
- {
- *list_return = NULL;
- *count_return = 0;
- return 0;
- }
- /* Only accept simple ASCII properties */
- for (unsigned i = 0; i < text_prop->nitems; ++i)
- AssertReturn(!(text_prop->value[i] & 0x80), XConverterNotFound);
- char **ppList = (char **)RTMemAlloc(sizeof(char *));
- char *pValue = (char *)RTMemAlloc(text_prop->nitems + 1);
- if (pValue)
- {
- memcpy(pValue, text_prop->value, text_prop->nitems);
- pValue[text_prop->nitems] = 0;
- }
- if (ppList)
- *ppList = pValue;
- if (!ppList || !pValue)
- {
- RTMemFree(ppList);
- RTMemFree(pValue);
- rc = XNoMemory;
- }
- else
- {
- /* NULL-terminate the string */
- pValue[text_prop->nitems] = '\0';
- *count_return = 1;
- *list_return = ppList;
- }
- return rc;
-}
-
-int Xutf8TextPropertyToTextList(Display *display,
- const XTextProperty *text_prop,
- char ***list_return, int *count_return)
-{
- return XmbTextPropertyToTextList(display, text_prop, list_return,
- count_return);
-}
-
void XtAppSetExitFlag(XtAppContext app_context) {}
void XtDestroyWidget(Widget w) {}
@@ -1823,85 +1826,54 @@ static const char *g_apszSupAtoms[] =
/* This just looks for the atom names in a couple of tables and returns an
* index with an offset added. */
-Boolean XtConvertAndStore(Widget widget, _Xconst _XtString from_type,
- XrmValue* from, _Xconst _XtString to_type,
- XrmValue* to_in_out)
-{
- Boolean rc = False;
- /* What we support is: */
- AssertReturn(from_type == XtRString, False);
- AssertReturn(to_type == XtRAtom, False);
+Atom XInternAtom(Display *, const char *pcsz, int)
+{
+ Atom atom = 0;
for (unsigned i = 0; i < RT_ELEMENTS(g_aFormats); ++i)
- if (!strcmp(from->addr, g_aFormats[i].pcszAtom))
- {
- *(Atom *)(to_in_out->addr) = (Atom) (i + 0x1000);
- rc = True;
- }
+ if (!strcmp(pcsz, g_aFormats[i].pcszAtom))
+ atom = (Atom) (i + 0x1000);
for (unsigned i = 0; i < RT_ELEMENTS(g_apszSupAtoms); ++i)
- if (!strcmp(from->addr, g_apszSupAtoms[i]))
- {
- *(Atom *)(to_in_out->addr) = (Atom) (i + 0x2000);
- rc = True;
- }
- Assert(rc == True); /* Have we missed any atoms? */
- return rc;
+ if (!strcmp(pcsz, g_apszSupAtoms[i]))
+ atom = (Atom) (i + 0x2000);
+ Assert(atom); /* Have we missed any atoms? */
+ return atom;
+}
+
+/* Take a request for the targets we are currently offering. */
+static CLIPX11FORMAT g_selTargets[10] = { 0 };
+static size_t g_cTargets = 0;
+
+void testRequestTargets(CLIPBACKEND* pCtx)
+{
+ clipUpdateX11Targets(pCtx, g_selTargets, g_cTargets);
}
/* The current values of the X selection, which will be returned to the
* XtGetSelectionValue callback. */
-static Atom g_selTarget[1] = { 0 };
static Atom g_selType = 0;
static const void *g_pSelData = NULL;
static unsigned long g_cSelData = 0;
static int g_selFormat = 0;
-static bool g_fTargetsTimeout = false;
-static bool g_fTargetsFailure = false;
-void XtGetSelectionValue(Widget widget, Atom selection, Atom target,
- XtSelectionCallbackProc callback,
- XtPointer closure, Time time)
+void testRequestData(CLIPBACKEND* pCtx, CLIPX11FORMAT target, void *closure)
{
unsigned long count = 0;
int format = 0;
- Atom type = XA_STRING;
- if ( ( selection != clipGetAtom(NULL, "PRIMARY")
- && selection != clipGetAtom(NULL, "CLIPBOARD")
- && selection != clipGetAtom(NULL, "TARGETS"))
- || ( target != g_selTarget[0]
- && target != clipGetAtom(NULL, "TARGETS")))
+ if (target != g_selTargets[0])
{
- /* Otherwise this is probably a caller error. */
- Assert(target != g_selTarget[0]);
- callback(widget, closure, &selection, &type, NULL, &count, &format);
- /* Could not convert to target. */
+ clipConvertX11CB(closure, NULL, 0); /* Could not convert to target. */
return;
}
- XtPointer pValue = NULL;
- if (target == clipGetAtom(NULL, "TARGETS"))
- {
- if (g_fTargetsFailure)
- pValue = NULL;
- else
- pValue = (XtPointer) RTMemDup(&g_selTarget, sizeof(g_selTarget));
- type = g_fTargetsTimeout ? XT_CONVERT_FAIL : XA_ATOM;
- count = g_fTargetsFailure ? 0 : RT_ELEMENTS(g_selTarget);
- format = 32;
- }
- else
- {
- pValue = (XtPointer) g_pSelData ? RTMemDup(g_pSelData, g_cSelData)
- : NULL;
- type = g_selType;
- count = g_pSelData ? g_cSelData : 0;
- format = g_selFormat;
- }
+ void *pValue = NULL;
+ pValue = g_pSelData ? RTMemDup(g_pSelData, g_cSelData) : NULL;
+ count = g_pSelData ? g_cSelData : 0;
+ format = g_selFormat;
if (!pValue)
{
count = 0;
format = 0;
}
- callback(widget, closure, &selection, &type, pValue,
- &count, &format);
+ clipConvertX11CB(closure, pValue, count * format / 8);
}
/* The formats currently on offer from X11 via the shared clipboard */
@@ -1938,7 +1910,7 @@ Boolean XtOwnSelection(Widget widget, Atom selection, Time time,
XtLoseSelectionProc lose,
XtSelectionDoneProc done)
{
- if (selection != clipGetAtom(NULL, "CLIPBOARD"))
+ if (selection != XInternAtom(NULL, "CLIPBOARD", 0))
return True; /* We don't really care about this. */
g_ownsSel = true; /* Always succeed. */
g_pfnSelConvert = convert;
@@ -1960,7 +1932,7 @@ static bool clipConvertSelection(const char *pcszTarget, Atom *type,
XtPointer *value, unsigned long *length,
int *format)
{
- Atom target = clipGetAtom(NULL, pcszTarget);
+ Atom target = XInternAtom(NULL, pcszTarget, 0);
if (target == 0)
return false;
/* Initialise all return values in case we make a quick exit. */
@@ -1972,7 +1944,7 @@ static bool clipConvertSelection(const char *pcszTarget, Atom *type,
return false;
if (!g_pfnSelConvert)
return false;
- Atom clipAtom = clipGetAtom(NULL, "CLIPBOARD");
+ Atom clipAtom = XInternAtom(NULL, "CLIPBOARD", 0);
if (!g_pfnSelConvert(TEST_WIDGET, &clipAtom, &target, type,
value, length, format))
return false;
@@ -1986,8 +1958,9 @@ static void clipSetSelectionValues(const char *pcszTarget, Atom type,
const void *data,
unsigned long count, int format)
{
- Atom clipAtom = clipGetAtom(NULL, "CLIPBOARD");
- g_selTarget[0] = clipGetAtom(NULL, pcszTarget);
+ Atom clipAtom = XInternAtom(NULL, "CLIPBOARD", 0);
+ g_selTargets[0] = clipFindX11FormatByAtomText(pcszTarget);
+ g_cTargets = 1;
g_selType = type;
g_pSelData = data;
g_cSelData = count;
@@ -1995,20 +1968,17 @@ static void clipSetSelectionValues(const char *pcszTarget, Atom type,
if (g_pfnSelLose)
g_pfnSelLose(TEST_WIDGET, &clipAtom);
g_ownsSel = false;
- g_fTargetsTimeout = false;
- g_fTargetsFailure = false;
}
static void clipSendTargetUpdate(CLIPBACKEND *pCtx)
{
- clipUpdateX11Targets(pCtx, g_selTarget, RT_ELEMENTS(g_selTarget));
+ clipQueryX11CBFormats(pCtx);
}
/* Configure if and how the X11 TARGETS clipboard target will fail */
-static void clipSetTargetsFailure(bool fTimeout, bool fFailure)
+static void clipSetTargetsFailure(void)
{
- g_fTargetsTimeout = fTimeout;
- g_fTargetsFailure = fFailure;
+ g_cTargets = 0;
}
char *XtMalloc(Cardinal size) { return (char *) RTMemAlloc(size); }
@@ -2325,33 +2295,6 @@ int main()
"hello world", sizeof("hello world") - 1, 8);
testStringFromX11(hTest, pCtx, "hello world", VINF_SUCCESS);
- /*** COMPOUND TEXT from X11 ***/
- RTTestSub(hTest, "reading compound text from X11");
- /* Simple test */
- clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello world",
- sizeof("hello world"), 8);
- testStringFromX11(hTest, pCtx, "hello world", VINF_SUCCESS);
- /* With an embedded carriage return */
- clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello\nworld",
- sizeof("hello\nworld"), 8);
- testStringFromX11(hTest, pCtx, "hello\r\nworld", VINF_SUCCESS);
- /* With an embedded CRLF */
- clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello\r\nworld",
- sizeof("hello\r\nworld"), 8);
- testStringFromX11(hTest, pCtx, "hello\r\r\nworld", VINF_SUCCESS);
- /* With an embedded LFCR */
- clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello\n\rworld",
- sizeof("hello\n\rworld"), 8);
- testStringFromX11(hTest, pCtx, "hello\r\n\rworld", VINF_SUCCESS);
- /* An empty string */
- clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "",
- sizeof(""), 8);
- testStringFromX11(hTest, pCtx, "", VINF_SUCCESS);
- /* A non-zero-terminated string */
- clipSetSelectionValues("COMPOUND_TEXT", XA_STRING,
- "hello world", sizeof("hello world") - 1, 8);
- testStringFromX11(hTest, pCtx, "hello world", VINF_SUCCESS);
-
/*** Latin1 from X11 ***/
RTTestSub(hTest, "reading Latin1 from X11");
/* Simple test */
@@ -2387,9 +2330,8 @@ int main()
/*** Timeout from X11 ***/
RTTestSub(hTest, "X11 timeout");
- clipSetSelectionValues("UTF8_STRING", XT_CONVERT_FAIL, "hello world",
- sizeof("hello world"), 8);
- testStringFromX11(hTest, pCtx, "hello world", VERR_TIMEOUT);
+ clipSetSelectionValues("UTF8_STRING", XT_CONVERT_FAIL, NULL,0, 8);
+ testStringFromX11(hTest, pCtx, "", VERR_NO_DATA);
/*** No data in X11 clipboard ***/
RTTestSub(hTest, "a data request from an empty X11 clipboard");
@@ -2427,7 +2369,7 @@ int main()
RTTestSub(hTest, "X11 targets conversion failure");
clipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world",
sizeof("hello world"), 8);
- clipSetTargetsFailure(false, true);
+ clipSetTargetsFailure();
Atom atom = XA_STRING;
long unsigned int cLen = 0;
int format = 8;
@@ -2448,72 +2390,40 @@ int main()
clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world",
sizeof("hello world") * 2);
testStringFromVBox(hTest, pCtx, "UTF8_STRING",
- clipGetAtom(NULL, "UTF8_STRING"), "hello world");
+ clipGetAtom(pCtx, "UTF8_STRING"), "hello world");
/* With an embedded carriage return */
clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello\r\nworld",
sizeof("hello\r\nworld") * 2);
testStringFromVBox(hTest, pCtx, "text/plain;charset=UTF-8",
- clipGetAtom(NULL, "text/plain;charset=UTF-8"),
+ clipGetAtom(pCtx, "text/plain;charset=UTF-8"),
"hello\nworld");
/* With an embedded CRCRLF */
clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello\r\r\nworld",
sizeof("hello\r\r\nworld") * 2);
testStringFromVBox(hTest, pCtx, "text/plain;charset=UTF-8",
- clipGetAtom(NULL, "text/plain;charset=UTF-8"),
+ clipGetAtom(pCtx, "text/plain;charset=UTF-8"),
"hello\r\nworld");
/* With an embedded CRLFCR */
clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello\r\n\rworld",
sizeof("hello\r\n\rworld") * 2);
testStringFromVBox(hTest, pCtx, "text/plain;charset=UTF-8",
- clipGetAtom(NULL, "text/plain;charset=UTF-8"),
+ clipGetAtom(pCtx, "text/plain;charset=UTF-8"),
"hello\n\rworld");
/* An empty string */
clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "", 2);
testStringFromVBox(hTest, pCtx, "text/plain;charset=utf-8",
- clipGetAtom(NULL, "text/plain;charset=utf-8"), "");
+ clipGetAtom(pCtx, "text/plain;charset=utf-8"), "");
/* With an embedded Utf-8 character. */
clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "100\xE2\x82\xAC" /* 100 Euro */,
10);
testStringFromVBox(hTest, pCtx, "STRING",
- clipGetAtom(NULL, "STRING"), "100\xE2\x82\xAC");
+ clipGetAtom(pCtx, "STRING"), "100\xE2\x82\xAC");
/* A non-zero-terminated string */
clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world",
sizeof("hello world") * 2 - 2);
- testStringFromVBox(hTest, pCtx, "TEXT", clipGetAtom(NULL, "TEXT"),
+ testStringFromVBox(hTest, pCtx, "TEXT", clipGetAtom(pCtx, "TEXT"),
"hello world");
- /*** COMPOUND TEXT from VBox ***/
- RTTestSub(hTest, "reading COMPOUND TEXT from VBox");
- /* Simple test */
- clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world",
- sizeof("hello world") * 2);
- testStringFromVBox(hTest, pCtx, "COMPOUND_TEXT",
- clipGetAtom(NULL, "COMPOUND_TEXT"), "hello world");
- /* With an embedded carriage return */
- clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello\r\nworld",
- sizeof("hello\r\nworld") * 2);
- testStringFromVBox(hTest, pCtx, "COMPOUND_TEXT",
- clipGetAtom(NULL, "COMPOUND_TEXT"), "hello\nworld");
- /* With an embedded CRCRLF */
- clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello\r\r\nworld",
- sizeof("hello\r\r\nworld") * 2);
- testStringFromVBox(hTest, pCtx, "COMPOUND_TEXT",
- clipGetAtom(NULL, "COMPOUND_TEXT"), "hello\r\nworld");
- /* With an embedded CRLFCR */
- clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello\r\n\rworld",
- sizeof("hello\r\n\rworld") * 2);
- testStringFromVBox(hTest, pCtx, "COMPOUND_TEXT",
- clipGetAtom(NULL, "COMPOUND_TEXT"), "hello\n\rworld");
- /* An empty string */
- clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "", 2);
- testStringFromVBox(hTest, pCtx, "COMPOUND_TEXT",
- clipGetAtom(NULL, "COMPOUND_TEXT"), "");
- /* A non-zero-terminated string */
- clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world",
- sizeof("hello world") * 2 - 2);
- testStringFromVBox(hTest, pCtx, "COMPOUND_TEXT",
- clipGetAtom(NULL, "COMPOUND_TEXT"), "hello world");
-
/*** Timeout from VBox ***/
RTTestSub(hTest, "reading from VBox with timeout");
clipEmptyVBox(pCtx, VERR_TIMEOUT);