x11.cpp revision fb611a330fe41e74cea7e7ced3fc762f4f85ed41
/** @file
*
* Shared Clipboard:
* Linux host.
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
#include <vector>
#include <iprt/semaphore.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include "VBoxClipboard.h"
#include "clipboard-helper.h"
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#ifdef RT_OS_SOLARIS
#endif
/** Do we want to test Utf16 by disabling other text formats? */
static bool g_testUtf16 = false;
/** Do we want to test Utf8 by disabling other text formats? */
static bool g_testUtf8 = false;
/** Do we want to test compount text by disabling other text formats? */
static bool g_testCText = false;
/** Are we currently debugging the clipboard code? */
static bool g_debugClipboard = false;
/** The different clipboard formats which we support. */
enum g_eClipboardFormats
{
INVALID = 0,
UTF8,
};
/** The X11 clipboard uses several names for the same format. This structure maps an X11
name to a format. */
typedef struct {
unsigned guestFormat;
/** Does X11 or VBox currently own the clipboard? */
typedef struct {
/** BMP file type marker - must always contain 'BM' */
/** The size of the BMP file in bytes (the MS docs say that this is not reliable) */
/** Reserved, must always be zero */
/** Reserved, must always be zero */
/** Offset from the beginning of this header to the actual image bits */
/** Global clipboard context information */
struct _VBOXCLIPBOARDCONTEXT
{
/** The X Toolkit application context structure */
/** We have a separate thread to wait for Window and Clipboard events */
/** The X Toolkit widget which we use as our clipboard client. It is never made visible. */
/** X11 atom refering to the clipboard: CLIPBOARD */
/** X11 atom refering to the selection: PRIMARY */
/** X11 atom refering to the clipboard targets: TARGETS */
/** X11 atom refering to the clipboard multiple target: MULTIPLE */
/** X11 atom refering to the clipboard timestamp target: TIMESTAMP */
/** X11 atom refering to the clipboard utf8 text format: UTF8_STRING */
/** X11 atom refering to the clipboard compound text format: COMPOUND_TEXT */
/** A list of the X11 formats which we support, mapped to our identifier for them, in the
order we prefer to have them in. */
/** Does the host or the guest currently own the clipboard? */
/** What is the best text format the host has to offer? INVALID for none. */
/** Atom corresponding to the host text format */
/** What is the best bitmap format the host has to offer? INVALID for none. */
/** Atom corresponding to the host Bitmap format */
/** What formats does the guest have on offer? */
int guestFormats;
/** Windows caches the clipboard data it receives. Since we have no way of knowing whether
that data is still valid, we always send a "data changed" message after a successful
transfer to invalidate the cache. */
bool notifyGuest;
/** Since the clipboard data moves asynchronously, we use an event semaphore to wait for
it. When a function issues a request for clipboard data it must wait for this
semaphore, which is triggered when the data arrives. */
/** Who (if anyone) is currently waiting for data? Used for sanity checks
* when data arrives. */
/** This mutex is grabbed during any critical operations on the clipboard
* which might clash with others. */
/** Format which we are reading from the host clipboard (valid during a request for the
host clipboard) */
/** The guest buffer to write host clipboard data to (valid during a request for the host
clipboard) */
void *requestBuffer;
/** The size of the guest buffer to write host clipboard data to (valid during a request for
the host clipboard) */
unsigned requestBufferSize;
/** The size of the host clipboard data written to the guest buffer (valid during a request
for the host clipboard) */
/** Pointer to the client data structure */
};
/* Only one client is supported. There seems to be no need for more clients. */
static VBOXCLIPBOARDCONTEXT g_ctx;
/* Are we actually connected to the X11 servicer? */
static bool g_fHaveX11;
/**
* Reset the contents of the buffer used to pass clipboard data from VBox to X11.
* This must be done after every clipboard transfer.
*/
static void vboxClipboardEmptyGuestBuffer(void)
{
}
/**
* Send a request to VBox to transfer the contents of its clipboard to X11.
*
* @param pCtx Pointer to the host clipboard structure
* @param u32Format The format in which the data should be transfered
* @thread clipboard X11 event thread
* @note called by vboxClipboardConvert*
*/
{
{
/* This can legitimately happen if we disconnect during a request for
* data from X11. */
LogFunc(("host requested guest clipboard data after guest had disconnected.\n"));
pCtx->guestFormats = 0;
return VERR_TIMEOUT;
}
/* Assert that no other transfer is in process (requests are serialised)
* and that the last transfer cleaned up properly. */
);
/* No one else (X11 or VBox) should currently be waiting. The first because
* requests from X11 are serialised and the second because VBox previously
* grabbed the clipboard, so it should not be waiting for data from us. */
/* Request data from VBox */
/* Which will signal us when it is ready. We use a timeout here because
* we can't be sure that the guest will behave correctly. */
if (rc == VERR_TIMEOUT)
/* Now we have a potential race between the HGCM thread delivering the data
* and our setting waiter to NONE to say that we are no longer waiting for
* it. We solve this as follows: both of these operations are done under
* the clipboard mutex. The HGCM thread will only deliver the data if we
* are still waiting after it acquires the mutex. After we release the
* mutex, we finally do our check to see whether the data was delivered. */
if (RT_FAILURE(rc))
{
/* I believe this should not happen. Wait until the assertions arrive
* to prove the contrary. */
pCtx->guestFormats = 0;
return rc;
}
return VERR_TIMEOUT;
LogFlowFunc(("wait completed. Returning.\n"));
return VINF_SUCCESS;
}
/**
* Convert the UTF-16 text returned from the X11 clipboard to UTF-16LE with Windows EOLs
* and place it in the global g_pcClipboardText variable. We are reading the host clipboard to
* make it available to the guest.
*
* @param pValue Source UTF-16 text
* @param cwSourceLen Length in 16-bit words of the source text
* @param pv Where to store the converted data
* @param cb Length in bytes of the buffer pointed to by cb
* @param pcbActual Where to store the size of the converted data
* @param pClient Pointer to the client context structure
*/
{
LogFlowFunc (("converting Utf-16 to Utf-16LE. cwSrcLen=%d, cb=%d, pu16SrcText+1=%.*ls\n",
*pcbActual = 0; /* Only set this to the right value on success. */
/* How long will the converted text be? */
{
/* Not enough buffer space provided - report the amount needed. */
LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n",
}
/* Convert the text. */
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
}
/* We need to do this whether we succeed or fail. */
}
/**
* Convert the UTF-8 text returned from the X11 clipboard to UTF-16LE with Windows EOLS.
* We are reading the X11 clipboard to make it available to VBox.
*
* @param pValue Source UTF-8 text
* @param cbSourceLen Length in 8-bit bytes of the source text
* @param pv Where to store the converted data
* @param cb Length in bytes of the buffer pointed to by pv
* @param pcbActual Where to store the size of the converted data
* @param pClient Pointer to the client context structure
* @thread clipboard X11 event thread
* @note called by vboxClipboardGetDataFromX11
*/
{
char *pu8SrcText = reinterpret_cast<char *>(pValue);
LogFlowFunc (("converting Utf-8 to Utf-16LE. cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n",
*pcbActual = 0; /* Only set this to the right value on success. */
/* First convert the UTF8 to UTF16 */
/* Check how much longer will the converted text will be. */
if (RT_SUCCESS(rc))
{
/* Not enough buffer space provided - report the amount needed. */
LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n",
}
/* Convert the text. */
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
}
}
/**
* Convert the COMPOUND_TEXT text returned from the X11 clipboard to UTF-16LE with Windows
* EOLS. We are reading the X11 clipboard to make it available to VBox.
*
* @param pValue Source COMPOUND_TEXT text
* @param cbSourceLen Length in 8-bit bytes of the source text
* @param pv Where to store the converted data
* @param cb Length in bytes of the buffer pointed to by pv
* @param pcbActual Where to store the size of the converted data
* @param pClient Pointer to the client context structure
* @thread clipboard X11 event thread
* @note called by vboxClipboardGetDataFromX11
*/
{
char **ppu8SrcText = NULL;
int rc = VINF_SUCCESS;
int cProps;
LogFlowFunc (("converting COMPOUND TEXT to Utf-16LE. cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n",
*pcbActual = 0; /* Only set this to the right value on success. */
/* First convert the compound text to Utf8 */
#ifdef RT_OS_SOLARIS
#else
#endif
if (xrc < 0)
switch(xrc)
{
case XNoMemory:
rc = VERR_NO_MEMORY;
break;
case XLocaleNotSupported:
case XConverterNotFound:
break;
default:
}
/* Now convert the UTF8 to UTF16 */
if (RT_SUCCESS(rc))
/* Check how much longer will the converted text will be. */
if (RT_SUCCESS(rc))
{
/* Not enough buffer space provided - report the amount needed. */
LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n",
}
/* Convert the text. */
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
}
if (ppu8SrcText != NULL)
}
/**
* Convert the Latin1 text returned from the X11 clipboard to UTF-16LE with Windows EOLS
* and place it in the global g_pcClipboardText variable. We are reading the X11 clipboard to
* make it available to VBox.
*
* @param pValue Source Latin1 text
* @param cbSourceLen Length in 8-bit bytes of the source text
* @param pv Where to store the converted data
* @param cb Length in bytes of the buffer pointed to by cb
* @param pcbActual Where to store the size of the converted data
* @param pClient Pointer to the client context structure
* @thread clipboard X11 event thread
* @note called by vboxClipboardGetDataFromX11
*/
static void vboxClipboardGetLatin1FromX11(XtPointer pValue, unsigned cbSourceLen, void *pv, unsigned cb,
{
char *pu8SourceText = reinterpret_cast<char *>(pValue);
int rc = VINF_SUCCESS;
LogFlowFunc (("converting Latin1 to Utf-16LE. Original is %.*s\n",
*pcbActual = 0; /* Only set this to the right value on success. */
for (unsigned i = 0; i < cbSourceLen; i++)
if (pu8SourceText[i] == LINEFEED)
++cwDestLen;
{
/* Not enough buffer space provided - report the amount needed. */
}
if (RT_SUCCESS(rc))
{
for (unsigned i = 0, j = 0; i < cbSourceLen; ++i, ++j)
if (pu8SourceText[i] != LINEFEED)
else
{
pu16DestText[j] = CARRIAGERETURN;
++j;
pu16DestText[j] = LINEFEED;
}
}
}
/**
* Convert the clipboard text from the current format to Utf-16 with Windows line breaks.
* We are reading the X11 clipboard to make it available to VBox.
* @thread clipboard X11 event thread
* @note Callback for XtGetSelectionValue, called from vboxClipboardReadData
*/
long unsigned int *pcLen,
int *piFormat)
{
LogFlowFunc(("g_ctx.requestHostFormat=%d, g_ctx.requestBufferSize=%d\n",
/* The X Toolkit may have failed to get the clipboard selection for us. */
if (*atomType == XT_CONVERT_FAIL)
return;
/* The clipboard selection may have changed before we could get it. */
return;
/* We grab this mutex whenever an asynchronous clipboard operation completes and while
disconnecting a client from the clipboard to stop these operations colliding. */
{
/* If the client is no longer connected, just return. */
LogFlowFunc(("client is no longer connected, returning\n"));
return;
}
/* In which format did we request the clipboard data? */
switch (g_ctx.requestHostFormat)
{
case UTF16:
break;
case CTEXT:
break;
case UTF8:
{
/* If we are given broken Utf-8, we treat it as Latin1. Is this acceptable? */
char *pu8SourceText = reinterpret_cast<char *>(pValue);
{
break;
}
else
{
break;
}
}
default:
LogFunc (("bad target format\n"));
return;
}
g_ctx.notifyGuest = true;
}
/**
* Find out what targets the current X11 clipboard holder can handle. We are
* reading the X11 clipboard to make it available to VBox.
* @thread clipboard X11 event thread
* @note Callback for XtGetSelectionValue, called from vboxClipboardPollX11ForTargets
*/
Atom * /* selection */,
long unsigned int *pcLen,
int *piFormat)
{
if (*atomType == XT_CONVERT_FAIL)
{
LogFunc (("reading clipboard from host, X toolkit failed to convert the selection\n"));
return;
}
/* We grab this mutex whenever an asynchronous clipboard operation completes and while
disconnecting a client from the clipboard to stop these operations colliding. */
{
/* If the client is no longer connected, just return. */
LogFlowFunc(("client is no longer connected, returning\n"));
return;
}
for (unsigned i = 0; i < cAtoms; ++i)
{
{
{
}
break;
}
if (g_debugClipboard)
{
if (szAtomName != 0)
{
szAtomName));
}
}
}
{
uint32_t u32Formats = 0;
if (g_debugClipboard)
{
if (atomBestTarget != None)
{
Log2 (("%s: switching to host text target %s. Available targets are:\n",
}
else
Log2(("%s: no supported host text target found. Available targets are:\n",
for (unsigned i = 0; i < cAtoms; ++i)
{
if (szAtomName != 0)
{
}
}
}
if (eBestTarget != INVALID)
g_ctx.notifyGuest = false;
}
}
/**
* This callback is called every 200ms to check the contents of the X11 clipboard.
* @thread clipboard X11 event thread
* @note Callback for XtAppAddTimeOut, called from vboxClipboardThread and
* recursively retriggered
*/
static void vboxClipboardPollX11ForTargets(XtPointer /* pUserData */, XtIntervalId * /* hTimerId */)
{
/* Get the current clipboard contents */
{
Log3 (("%s: requesting the targets that the host clipboard offers\n",
}
/* Re-arm our timer */
}
/** We store information about the target formats we can handle in a global vector for internal
use. */
unsigned guestFormat)
{
/* Get an atom from the X server for that target format */
}
/**
* The main loop of our clipboard reader.
* @thread clipboard X11 event thread
*/
{
LogRel(("Shared clipboard: starting host clipboard thread\n"));
/* Set up a timer to poll the host clipboard */
LogRel(("Shared clipboard: host clipboard thread terminated successfully\n"));
return VINF_SUCCESS;
}
/** X11 specific initialisation for the shared clipboard. */
int vboxClipboardInitX11 (void)
{
/* Create a window and make it a clipboard viewer. */
int cArgc = 0;
char *pcArgv = 0;
int rc = VINF_SUCCESS;
// static String szFallbackResources[] = { (char*)"*.width: 1", (char*)"*.height: 1", NULL };
/* Make sure we are thread safe */
/* Set up the Clipbard application context and main window. We call all these functions
directly instead of calling XtOpenApplication() so that we can fail gracefully if we
can't get an X11 display. */
// XtAppSetFallbackResources(g_ctx.appContext, szFallbackResources);
{
LogRel(("Shared clipboard: failed to connect to the host clipboard - the window system may not be running.\n"));
}
if (RT_SUCCESS(rc))
{
{
LogRel(("Shared clipboard: failed to construct the X11 window for the host clipboard manager.\n"));
rc = VERR_NO_MEMORY;
}
}
if (RT_SUCCESS(rc))
{
/* Get hold of the atoms which we need */
g_ctx.atomClipboard = XInternAtom(XtDisplay(g_ctx.widget), "CLIPBOARD", false /* only_if_exists */);
/* And build up the vector of supported formats */
/* And build up the vector of supported formats */
if (!g_testUtf8 && !g_testCText)
if (!g_testUtf16 && !g_testCText)
{
}
if (!g_testUtf16 && !g_testUtf8)
}
return rc;
}
/**
* Initialise the host side of the shared clipboard.
* @note Called by the HGCM clipboard service
* @thread HGCM clipboard service thread
*/
int vboxClipboardInit (void)
{
int rc;
if (!RTEnvGet("DISPLAY"))
{
/*
* If we don't find the DISPLAY environment variable we assume that we are not
* connected to an X11 server. Don't actually try to do this then, just fail
* silently and report success on every call. This is important for VBoxHeadless.
*/
LogRelFunc(("no X11 detected -- host clipboard disabled\n"));
g_fHaveX11 = false;
return VINF_SUCCESS;
}
if (RTEnvGet("VBOX_CBTEST_UTF16"))
{
g_testUtf16 = true;
LogRel(("Host clipboard: testing Utf16\n"));
}
else if (RTEnvGet("VBOX_CBTEST_UTF8"))
{
g_testUtf8 = true;
LogRel(("Host clipboard: testing Utf8\n"));
}
else if (RTEnvGet("VBOX_CBTEST_CTEXT"))
{
g_testCText = true;
LogRel(("Host clipboard: testing compound text\n"));
}
else if (RTEnvGet("VBOX_CBDEBUG"))
{
g_debugClipboard = true;
LogRel(("Host clipboard: enabling additional debugging output\n"));
}
g_fHaveX11 = true;
LogRel(("Initializing host clipboard service\n"));
rc = vboxClipboardInitX11();
if (RT_SUCCESS(rc))
{
if (RT_FAILURE(rc))
LogRel(("Failed to start the host shared clipboard thread.\n"));
}
if (RT_FAILURE(rc))
{
}
return rc;
}
/**
* Terminate the host side of the shared clipboard.
* @note Called by the HGCM clipboard service
* @thread HGCM clipboard service thread
*/
void vboxClipboardDestroy (void)
{
unsigned count = 0;
/*
* Immediately return if we are not connected to the host X server.
*/
if (!g_fHaveX11)
return;
LogRel(("vboxClipboardDestroy: shutting down host clipboard\n"));
/* Drop the reference to the client, in case it is still there. This will
* cause any outstanding clipboard data requests from X11 to fail
* immediately. */
/* X11 may be waiting for data from VBox. At this point it is no
* longer going to arrive, and we must release it to allow the event
* loop to terminate. In this case the buffer where VBox would have
* written the clipboard data will still be empty and we will just
* return "no data" to X11. Any subsequent attempts to get the data
* from VBox will fail immediately as the client reference is gone. */
/* Set the termination flag. This has been observed to block if it was set
* during a request for clipboard data coming from X11, so only we do it
* after releasing any such requests. */
/* Wake up the event loop */
do
{
++count;
if (RT_SUCCESS(rc))
{
/*
* No one should be waiting on this by now. Justification:
* - Case 1: VBox is waiting for data from X11:
* Not possible, as it would be waiting on this thread.
* - Case 2: X11 is waiting for data from VBox:
* Not possible, as we checked that the X11 event thread exited
* successfully.
*/
}
else
LogFlowFunc(("returning.\n"));
}
/**
* Connect a guest the shared clipboard.
*
* @param pClient Structure containing context information about the guest system
* @returns RT status code
* @note Called by the HGCM clipboard service
* @thread HGCM clipboard service thread
*/
{
/*
* Immediately return if we are not connected to the host X server.
*/
if (!g_fHaveX11)
return VINF_SUCCESS;
LogFlow(("vboxClipboardConnect\n"));
/* Only one client is supported for now */
g_ctx.notifyGuest = true;
return VINF_SUCCESS;
}
/**
* Synchronise the contents of the host clipboard with the guest, called
* after a save and restore of the guest.
* @note Called by the HGCM clipboard service
* @thread HGCM clipboard service thread
*/
{
/*
* Immediately return if we are not connected to the host X server.
*/
if (!g_fHaveX11)
return VINF_SUCCESS;
/* On a Linux host, the guest should never synchronise/cache its clipboard contents, as
we have no way of reliably telling when the host clipboard data changes. So instead
of synchronising, we tell the guest to empty its clipboard, and we set the cached
flag so that we report formats to the guest next time we poll for them. */
g_ctx.notifyGuest = true;
return VINF_SUCCESS;
}
/**
* Shut down the shared clipboard service and "disconnect" the guest.
* @note Called by the HGCM clipboard service
* @thread HGCM clipboard service thread
*/
{
/*
* Immediately return if we are not connected to the host X server.
*/
if (!g_fHaveX11)
return;
LogFlow(("vboxClipboardDisconnect\n"));
}
/**
* Satisfy a request from X11 for clipboard targets supported by VBox.
*
* @returns true if we successfully convert the data to the format requested, false otherwise.
*
* @param atomTypeReturn The type of the data we are returning
* @param pValReturn A pointer to the data we are returning. This should be to memory
* allocated by XtMalloc, which will be freed by the toolkit later
* @param pcLenReturn The length of the data we are returning
* @param piFormatReturn The format (8bit, 16bit, 32bit) of the data we are returning
* @thread clipboard X11 event thread
* @note called by vboxClipboardConvertForX11
*/
unsigned long *pcLenReturn, int *piFormatReturn)
{
unsigned cTargets = 0;
LogFlowFunc (("called\n"));
for (unsigned i = 0; i < uListSize; ++i)
{
{
++cTargets;
}
}
if (g_debugClipboard)
{
for (unsigned i = 0; i < cTargets + 3; i++)
{
if (szAtomName != 0)
{
szAtomName));
}
else
{
atomTargets[i]));
}
}
}
*piFormatReturn = 32;
return true;
}
/**
* Satisfy a request from the host to convert the clipboard text to Utf16. We return non-zero
* terminated text.
*
* @returns true if we successfully convert the data to the format requested, false otherwise.
*
* @retval atomTypeReturn The type of the data we are returning
* @retval pValReturn A pointer to the data we are returning. This should be to memory
* allocated by XtMalloc, which will be freed by the toolkit later
* @retval pcLenReturn The length of the data we are returning
* @retval piFormatReturn The format (8bit, 16bit, 32bit) of the data we are returning
*/
unsigned long *pcLenReturn, int *piFormatReturn)
{
int rc;
LogFlowFunc (("called\n"));
{
/* If vboxClipboardReadDataFromVBox fails then pClient may be invalid */
return false;
}
/* How long will the converted text be? */
if (RT_FAILURE(rc))
{
LogRel(("vboxClipboardConvertUtf16: clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));
AssertRCReturn(rc, false);
}
if (cwDestLen == 0)
{
LogFlowFunc(("received empty clipboard data from the guest, returning false.\n"));
return false;
}
if (pu16DestText == 0)
{
return false;
}
/* Convert the text. */
if (RT_FAILURE(rc))
{
LogRel(("vboxClipboardConvertUtf16: clipboard conversion failed. vboxClipboardUtf16WinToLin returned %Rrc. Abandoning.\n", rc));
XtFree(reinterpret_cast<char *>(pu16DestText));
return false;
}
*pcLenReturn = cwDestLen;
*piFormatReturn = 16;
return true;
}
/**
* Satisfy a request from the host to convert the clipboard text to Utf8.
*
* @returns true if we successfully convert the data to the format requested, false otherwise.
*
* @param atomTypeReturn The type of the data we are returning
* @param pValReturn A pointer to the data we are returning. This should be to memory
* allocated by XtMalloc, which will be freed by the toolkit later
* @param pcLenReturn The length of the data we are returning
* @param piFormatReturn The format (8bit, 16bit, 32bit) of the data we are returning
* @thread clipboard X11 event thread
* @note called by vboxClipboardConvertForX11
*/
unsigned long *pcLenReturn,
int *piFormatReturn)
{
char *pu8DestText;
int rc;
LogFlowFunc (("called\n"));
/* Read the clipboard data from the guest. */
{
/* If vboxClipboardReadDataFromVBox fails then pClient may be invalid */
return false;
}
/* How long will the converted text be? */
if (RT_FAILURE(rc))
{
LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));
AssertRCReturn(rc, false);
}
if (cwDestLen == 0)
{
LogFlowFunc(("received empty clipboard data from the guest, returning false.\n"));
return false;
}
if (pu16DestText == 0)
{
return false;
}
/* Convert the text. */
if (RT_FAILURE(rc))
{
LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc));
RTMemFree(reinterpret_cast<void *>(pu16DestText));
return false;
}
/* Allocate enough space, as RTUtf16ToUtf8Ex may fail if the
space is too tightly calculated. */
if (pu8DestText == 0)
{
RTMemFree(reinterpret_cast<void *>(pu16DestText));
return false;
}
/* Convert the Utf16 string to Utf8. */
&cbDestLen);
RTMemFree(reinterpret_cast<void *>(pu16DestText));
if (RT_FAILURE(rc))
{
return false;
}
*pcLenReturn = cbDestLen;
*piFormatReturn = 8;
return true;
}
/**
* Satisfy a request from the host to convert the clipboard text to COMPOUND_TEXT.
*
* @returns true if we successfully convert the data to the format requested, false otherwise.
*
* @param atomTypeReturn The type of the data we are returning
* @param pValReturn A pointer to the data we are returning. This should be to memory
* allocated by XtMalloc, which will be freed by the toolkit later
* @param pcLenReturn The length of the data we are returning
* @param piFormatReturn The format (8bit, 16bit, 32bit) of the data we are returning
* @thread clipboard X11 event thread
* @note called by vboxClipboardConvertForX11
*/
unsigned long *pcLenReturn,
int *piFormatReturn)
{
char *pu8DestText = 0;
int rc;
LogFlowFunc (("called\n"));
/* Read the clipboard data from the guest. */
{
/* If vboxClipboardReadDataFromVBox fails then pClient may be invalid */
return false;
}
/* How long will the converted text be? */
if (RT_FAILURE(rc))
{
LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));
AssertRCReturn(rc, false);
}
if (cwDestLen == 0)
{
LogFlowFunc(("received empty clipboard data from the guest, returning false.\n"));
return false;
}
if (pu16DestText == 0)
{
return false;
}
/* Convert the text. */
if (RT_FAILURE(rc))
{
LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc));
RTMemFree(reinterpret_cast<void *>(pu16DestText));
return false;
}
/* Convert the Utf16 string to Utf8. */
RTMemFree(reinterpret_cast<void *>(pu16DestText));
if (RT_FAILURE(rc))
{
return false;
}
/* And finally (!) convert the Utf8 text to compound text. */
#ifdef RT_OS_SOLARIS
#else
#endif
if (rc < 0)
{
const char *pcReason;
switch(rc)
{
case XNoMemory:
pcReason = "out of memory";
break;
case XLocaleNotSupported:
pcReason = "locale (Utf8) not supported";
break;
case XConverterNotFound:
pcReason = "converter not found";
break;
default:
pcReason = "unknown error";
}
LogRelFunc (("Xutf8TextListToTextProperty failed. Reason: %s\n",
pcReason));
return false;
}
return true;
}
/**
* Callback to request VBox's clipboard data for an X11 client. Called by the
* X Toolkit.
* @thread clipboard X11 event thread
* @note callback for XtOwnSelection, called by vboxClipboardFormatAnnounce
*/
unsigned long *pcLenReturn,
int *piFormatReturn)
{
LogFlowFunc(("\n"));
/* Drop requests that we receive too late. */
return false;
)
{
LogFlowFunc(("rc = false\n"));
return false;
}
if (g_debugClipboard)
{
if (szAtomName != 0)
{
}
else
{
}
}
{
}
else
{
{
{
break;
}
}
}
switch (eFormat)
{
case TARGETS:
case UTF16:
case UTF8:
case CTEXT:
default:
LogFunc (("bad format\n"));
return false;
}
}
/**
* This is called by the X toolkit intrinsics to let us know that another
* X11 client has taken the clipboard.
* @note callback for XtOwnSelection, called from vboxClipboardFormatAnnounce
* @thread clipboard X11 event thread
*/
{
LogFlowFunc (("called, giving VBox clipboard ownership\n"));
g_ctx.notifyGuest = true;
}
/**
* VBox is taking possession of the shared clipboard.
*
* @param pClient Context data for the guest system
* @param u32Formats Clipboard formats the guest is offering
* @note Called by the HGCM clipboard service
* @thread HGCM clipboard service thread
*/
{
/*
* Immediately return if we are not connected to the host X server.
*/
if (!g_fHaveX11)
return;
if (u32Formats == 0)
{
/* This is just an automatism, not a genuine anouncement */
LogFlowFunc(("returning\n"));
return;
}
{
/* We already own the clipboard, so no need to grab it, especially as that can lead
to races due to the asynchronous nature of the X11 clipboard. This event may also
have been sent out by the guest to invalidate the Windows clipboard cache. */
LogFlowFunc(("returning\n"));
return;
}
vboxClipboardReturnToX11, 0) != True)
{
/* We set this so that the guest gets notified when we take the clipboard, even if no
guest formats are found which we understand. */
g_ctx.notifyGuest = true;
}
NULL, 0);
LogFlowFunc(("returning\n"));
}
/**
* Called when VBox wants to read the X11 clipboard.
*
* @param pClient Context information about the guest VM
* @param u32Format The format that the guest would like to receive the data in
* @param pv Where to write the data to
* @param cb The size of the buffer to write the data to
* @param pcbActual Where to write the actual size of the written data
* @note Called by the HGCM clipboard service
* @thread HGCM clipboard service thread
*/
{
/*
* Immediately return if we are not connected to the host X server.
*/
if (!g_fHaveX11)
{
/* no data available */
*pcbActual = 0;
return VINF_SUCCESS;
}
/*
* The guest wants to read data in the given format.
*/
{
{
/* No data available. */
*pcbActual = 0;
return VERR_NO_DATA; /* The guest thinks we have data and we don't */
}
/* No one else (VBox or X11) should currently be waiting. The first because
* requests from VBox are serialised and the second because X11 previously
* grabbed the clipboard, so it should not be waiting for data from us. */
/* Initially set the size of the data read to zero in case we fail
* somewhere. */
*pcbActual = 0;
/* Send out a request for the data to the current clipboard owner */
/* When the data arrives, the vboxClipboardGetDataFromX11 callback will be called. The
callback will signal the event semaphore when it has processed the data for us. */
if (RT_FAILURE(rc))
{
return rc;
}
}
else
{
return VERR_NOT_IMPLEMENTED;
}
return VINF_SUCCESS;
}
/**
* Called when we have requested data from VBox and that data has arrived.
*
* @param pClient Context information about the guest VM
* @param pv Buffer to which the data was written
* @param cb The size of the data written
* @param u32Format The format of the data written
* @note Called by the HGCM clipboard service
* @thread HGCM clipboard service thread
*/
void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient, void *pv, uint32_t cb, uint32_t u32Format)
{
if (!g_fHaveX11)
return;
LogFlowFunc (("called\n"));
/* Assert that no other transfer is in process (requests are serialised)
* or has not cleaned up properly. */
/* Grab the mutex and check that X11 is still waiting for the data before
* delivering it. See the explanation in vboxClipboardReadDataFromVBox. */
{
{
}
}
}