clipboard.cpp revision 13fdd42f1fc3e519650037a920e6a54c24973866
/** @file
*
* Shared Clipboard:
* Linux guest.
*/
/*
* Copyright (C) 2006 InnoTek Systemberatung GmbH
*
* 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 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.
*
* If you received this file as part of a commercial VirtualBox
* distribution, then only the terms of your commercial VirtualBox
* license agreement apply instead of the previous paragraph.
*/
/* The formats which we support in the guest. These can be deactivated in order to test specific
code paths. */
#define USE_UTF16
#define USE_UTF8
#define USE_LATIN1
#define LOG_GROUP LOG_GROUP_HGCM
#include <vector>
#include <iostream>
#include <VBox/VBoxGuest.h>
#include <iprt/initterm.h>
#include <iprt/semaphore.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <getopt.h>
// #include "VBoxClipboard.h"
#include <X11/Intrinsic.h>
} while (0)
/** 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 hostFormat;
/** Does the host or the guest 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 */
typedef struct
{
/** The Xt application context structure */
/** We have a separate thread to wait for Window and Clipboard events */
/** The Xt widget which we use as our clipboard client. It is never made visible. */
/** The file descriptor for the VirtualBox device which we use for pushing requests
to the host. */
int sendDevice;
/** The file descriptor for the VirtualBox device which we use for polling requests
from the host. */
int receiveDevice;
/** X11 atom refering to the clipboard: CLIPBOARD */
/** X11 atom refering to the clipboard: TARGETS */
/** X11 atom refering to the clipboard: MULTIPLE */
/** X11 atom refering to the clipboard: TIMESTAMP */
/** 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? */
volatile enum g_eClipboardOwner eOwner;
/** What is the best text format the guest has to offer? INVALID for none. */
/** Atom corresponding to the guest text format */
/** What is the best bitmap format the guest has to offer? INVALID for none. */
/** Atom corresponding to the guest Bitmap format */
/** What formats does the host have on offer? */
int hostFormats;
/** 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 notifyHost;
/** Since the clipboard data moves asynchronously, we use an event semaphore to wait for
it. */
/** Are we running as a daemon? */
bool daemonise;
/** Format which we are reading from the guest clipboard (valid during a request for the
guest clipboard) */
/** The guest buffer to write guest clipboard data to (valid during a request for the host
clipboard) */
void *requestBuffer;
/** The size of the host buffer to write guest clipboard data to (valid during a request for
the guest clipboard) */
unsigned requestBufferSize;
/** The size of the guest clipboard data written to the host buffer (valid during a request
for the guest clipboard) */
/** Client ID for the clipboard subsystem */
/* Only one client is supported. There seems to be no need for more clients. */
static VBOXCLIPBOARDCONTEXT g_ctx;
{
}
{
{
return VINF_SUCCESS;
}
LogFlowFunc(("rc=VERR_INVALID_PARAMETER\n"));
return VERR_INVALID_PARAMETER;
}
{
}
/**
* Transfer clipboard data from the guest to the host
*
* @returns VBox result code
* @param u32Format The format of the data being sent
* @param pv Pointer to the data being sent
* @param cb Size of the data being sent in bytes
*/
{
int rc = VERR_DEV_IO_ERROR;
{
}
return rc;
}
/**
* Get clipboard data from the host
*
* @returns VBox result code
* @param u32Format The format of the data being requested
* @retval ppv On success, this will point to a buffer to be freed with RTMemFree
* containing the data read if pcb > 0.
* @retval pcb On success, this contains the number of bytes of data returned
*/
{
int rc;
/* Allocate a 1K buffer for receiving the clipboard data to start with. If this is too small,
the host will tell us what size of buffer we need, and we will try again with a buffer of
that size. */
if (pv == 0)
{
LogFlowFunc(("rc=VERR_NO_MEMORY\n"));
return VERR_NO_MEMORY;
}
/* Set up the HGCM call structure and make the call to the host. */
{
LogFlowFunc(("rc=VERR_DEV_IO_ERROR\n"));
return VERR_DEV_IO_ERROR;
}
{
}
/* Check whether the buffer we supplied was big enough. */
{
*ppv = 0;
return rc;
}
{
/* Our initial 1024 byte buffer was big enough for the clipboard data. */
return VINF_SUCCESS;
}
/* Else if u32Size > cb, we try again with a buffer of size u32Size. */
if (pv == 0)
{
LogFlowFunc(("rc=VERR_NO_MEMORY\n"));
return VERR_NO_MEMORY;
}
/* Set up the HGCM call structure and make the call to the host. */
{
LogFlowFunc(("rc=VERR_DEV_IO_ERROR\n"));
return VERR_DEV_IO_ERROR;
}
{
}
/* Check whether the buffer we supplied was big enough. */
{
*ppv = 0;
return rc;
}
{
/* The buffer was big enough. */
return VINF_SUCCESS;
}
/* The buffer was to small again. Perhaps the clipboard contents changed half-way through
the operation. Since I can't say whether or not this is actually an error, we will just
return size 0. */
*pcb = 0;
LogFlowFunc(("*pcb=0 rc=VINF_SUCCESS\n"));
return VINF_SUCCESS;
}
/**
* Convert a Utf16 text with Linux EOLs to Utf16-LE with Windows EOLs, allocating memory
* for the converted text. Does no checking for validity.
*
* @returns VBox status code
*
* @param pu16Src Source Utf16 text to convert
* @param cwSrc Size of the source text in 16 bit words
* @retval ppu16Dest Where to store the pointer to the converted text. Only valid on success
* and if pcwDest is greater than 0.
* @retval pcwDest Size of the converted text in 16 bit words, including the trailing null
* if present
*/
{
if (cwSrc == 0)
{
*ppu16Dest = 0;
*pcwDest = 0;
LogFlowFunc(("*ppu16Dest=0, *pcwDest=0, rc=VINF_SUCCESS\n"));
return VINF_SUCCESS;
}
cwDest = 0;
{
{
++cwDest;
}
}
/* Leave space for a trailing null in any case */
++cwDest;
if (pu16Dest == 0)
{
LogFlowFunc(("rc=VERR_NO_MEMORY\n"));
return VERR_NO_MEMORY;
}
{
{
pu16Dest[j] = CARRIAGERETURN;
++j;
}
}
/* The trailing null */
pu16Dest[j] = 0;
return VINF_SUCCESS;
}
/**
* Convert the UTF-16 text returned from the guest X11 clipboard to UTF-16LE with Windows EOLs
* and send it to the host.
*
* @param pValue Source UTF-16 text
* @param cwSourceLen Length in 16-bit words of the source text
*/
{
int rc;
LogFlowFunc(("converting Utf-16 to Utf-16LE. Original is %.*ls\n",
if (rc != VINF_SUCCESS)
{
vboxClipboardSendData (0, 0, 0);
LogFlowFunc(("sending empty data and returning\n"));
return;
}
RTMemFree(reinterpret_cast<void *>(pu16DestText));
LogFlowFunc(("returning\n"));
}
/**
* Convert the UTF-8 text returned from the guest X11 clipboard to UTF-16LE with Windows EOLs
* and send it to the host.
*
* @param pValue Source UTF-8 text
* @param cbSourceLen Length in 8-bit bytes of the source text
*/
{
char *pu8SourceText = reinterpret_cast<char *>(pValue);
int rc;
LogFlowFunc(("\n"));
/* First convert the UTF8 to UTF16 */
if (rc != VINF_SUCCESS)
{
vboxClipboardSendData (0, 0, 0);
LogFlowFunc(("sending empty data and returning\n"));
return;
}
if (rc != VINF_SUCCESS)
{
RTMemFree(reinterpret_cast<void *>(pu16SourceText));
vboxClipboardSendData (0, 0, 0);
LogFlowFunc(("sending empty data and returning\n"));
return;
}
RTMemFree(reinterpret_cast<void *>(pu16SourceText));
RTMemFree(reinterpret_cast<void *>(pu16DestText));
LogFlowFunc(("returning\n"));
}
/**
* Convert the Latin1 text returned from the guest X11 clipboard to UTF-16LE with Windows EOLs
* and send it to the host.
*
* @param pValue Source Latin1 text
* @param cbSourceLen Length in 8-bit bytes of the source text
*/
{
/* Leave space for an additional null character at the end of the destination text. */
char *pu8SourceText = reinterpret_cast<char *>(pValue);
/* Find the size of the destination text */
for (size_t i = 0; i < cbSourceLen; i++)
{
if (pu8SourceText[i] == LINEFEED)
++cwDestLen;
}
if (pu16DestText == 0)
{
vboxClipboardSendData (0, NULL, 0);
LogFlowFunc(("sending empty data and returning\n"));
return;
}
/* Copy the original X clipboard string to the destination, replacing Linux EOLs with
Windows ones */
cwDestPos = 0;
{
if (pu8SourceText[i] == LINEFEED)
{
++cwDestPos;
}
/* latin1 < utf-16LE */
if (pu8SourceText[i] == 0)
break;
}
pu16DestText[cwDestPos] = 0;
RTMemFree(reinterpret_cast<void *>(pu16DestText));
LogFlowFunc(("returning\n"));
}
/** Convert the clipboard text from the current format to Utf-16 with Windows line breaks.
We are reading the guest clipboard to make it available to the host. */
int *piFormat)
{
/* The X Toolkit may have failed to get the clipboard selection for us. */
LogFlowFunc(("*pcLen=%lu, *piFormat=%d, requested target format: %d, g_ctx.requestBufferSize=%d\n",
if (*atomType == XT_CONVERT_FAIL)
{
vboxClipboardSendData (0, NULL, 0);
LogFlowFunc(("Xt failed to convert the data. Sending empty data and returning\n"));
return;
}
/* In which format did we request the clipboard data? */
switch (g_ctx.requestGuestFormat)
{
case UTF16:
break;
case UTF8:
case LATIN1:
{
/* 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:
Log (("vboxClipboardGetProc: bad target format\n"));
vboxClipboardSendData (0, NULL, 0);
LogFlowFunc(("sending empty data and returning\n"));
return;
}
g_ctx.notifyHost = true;
LogFlowFunc(("returning\n"));
}
/**
* Tell the host that new clipboard formats are available
*/
{
int rc = VERR_DEV_IO_ERROR;
{
}
if (VBOX_SUCCESS (rc))
{
}
return rc;
}
/** Callback to handle a reply to a request for the targets the current clipboard holder can
handle. We are reading the guest clipboard to make it available to the host. */
{
static int cCalls = 0;
/* The number of format atoms the clipboard holder is offering us */
/* The best clipboard format we have found so far */
/* The atom corresponding to our best clipboard format found */
if ((cCalls % 10) == 0)
if (*atomType == XT_CONVERT_FAIL)
{
Log (("vboxClipboardTargetsProc: reading clipboard from guest, X toolkit failed to convert the selection\n"));
LogFlowFunc(("returning\n"));
return;
}
/* Run through the atoms offered to us to see if we recognise them. If we find the atom for
a "better" format than the best we have found so far, we remember it as our new "best"
format. */
for (unsigned i = 0; i < cAtoms; ++i)
{
{
{
}
break;
}
#ifdef DEBUG
if (szAtomName != 0)
{
if ((cCalls % 10) == 0)
}
else
{
if ((cCalls % 10) == 0)
Log3 (("vboxClipboardTargetsProc: the guest returned a bad atom: %d\n",
atomTargets[i]));
}
#endif
}
/* If the available formats as seen by the host have changed, or if we suspect that
the host has cached the clipboard data (which can change without our noticing it),
then tell the host that new clipboard contents are available. */
{
uint32_t u32Formats = 0;
#ifdef DEBUG
if (atomBestTarget != None)
{
}
else
{
Log2(("vboxClipboardTargetsProc: no supported host text target found.\n"));
}
#endif
if (eBestTarget != INVALID)
g_ctx.notifyHost = false;
}
++cCalls;
}
/**
* This callback is called every 200ms to check the contents of the guest clipboard.
*/
{
static int cCalls = 0;
Log3 (("vboxClipboardTimerProc called\n"));
/* Get the current clipboard contents */
{
if ((cCalls % 10) == 0)
Log3 (("vboxClipboardTimerProc: requesting the targets that the guest clipboard offers\n"));
}
/* Re-arm our timer */
++cCalls;
}
/**
* Satisfy a request from the guest for available clipboard targets.
*
* @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
*/
unsigned long *pcLenReturn, int *piFormatReturn)
{
unsigned cTargets = 0;
LogFlowFunc(("\n"));
for (unsigned i = 0; i < uListSize; ++i)
{
{
++cTargets;
}
}
#ifdef DEBUG
for (unsigned i = 0; i < cTargets + 3; i++)
{
if (szAtomName != 0)
{
}
else
{
}
}
#endif
LogFlowFunc(("returning true\n"));
return true;
}
/**
* Get the size of the buffer needed to hold a Utf16 string with Linux EOLs converted from
* a Utf16 string with Windows EOLs.
*
* @returns The size of the buffer needed in bytes
*
* @param pu16Src The source Utf16 string
* @param cwSrc The length in 16 bit words of the source string
*/
{
/* We only take little endian Utf16 */
if (cwSrc == 0)
{
LogFlowFunc(("returning 0\n"));
return 0;
}
/* Calculate the size of the destination text string. */
/* Is this Utf16 or Utf16-LE? */
if (pu16Src[0] == 0xfeff)
cwDest = 0;
else
cwDest = 1;
{
if ( (i + 1 < cwSrc)
&& (pu16Src[i] == CARRIAGERETURN)
++i;
if (pu16Src[i] == 0)
{
/* The terminating zero is included in the size */
++cwDest;
break;
}
}
return cwDest * 2;
}
/**
* Convert Utf16-LE text with Windows EOLs to Utf16 with Linux EOLs. This function does not
* verify that the Utf16 is valid.
*
* @returns VBox status code
*
* @param pu16Src Text to convert
* @param cwSrc Size of the source text in 16 bit words
* @param pu16Dest The buffer to store the converted text to
* @param cwDest The size of the buffer for the destination text
*/
{
LogFlowFunc(("pu16Src=%.*ls, cwSrc=%u, pu16Dest=%p, cwDest=%u\n",
/* A buffer of size 0 may not be an error, but it is not a good idea either. */
/* We only take little endian Utf16 */
if (cwSrc == 0)
{
if (cwDest != 0)
pu16Dest[0] = 0;
LogFlowFunc(("set empty string. Returning VINF_SUCCESS\n"));
return VINF_SUCCESS;
}
/* Prepend the Utf16 byte order marker if it is missing. */
if (pu16Src[0] == 0xfeff)
{
cwDestPos = 0;
}
else
{
if (cwDest == 0)
{
LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
return VERR_BUFFER_OVERFLOW;
}
pu16Dest[0] = 0xfeff;
cwDestPos = 1;
}
{
{
LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
return VERR_BUFFER_OVERFLOW;
}
if ( (i + 1 < cwSrc)
&& (pu16Src[i] == CARRIAGERETURN)
{
++i;
}
if (pu16Src[i] == 0)
{
break;
}
}
return VINF_SUCCESS;
}
/**
* Satisfy a request from the guest to convert the clipboard text to Utf16.
*
* @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
*/
unsigned long *pcLenReturn, int *piFormatReturn)
{
int rc;
LogFlowFunc(("\n"));
reinterpret_cast<void **>(&pu16HostText), &cbHostText);
{
Log (("vboxClipboardConvertUtf16: vboxClipboardReadHostData returned %Vrc, %d bytes of data\n", rc, cbHostText));
g_ctx.hostFormats = 0;
LogFlowFunc(("rc = false\n"));
return false;
}
if (pu16GuestText == 0)
{
RTMemFree(reinterpret_cast<void *>(pu16HostText));
LogFlowFunc(("rc = false\n"));
return false;
}
if (rc != VINF_SUCCESS)
{
RTMemFree(reinterpret_cast<void *>(pu16HostText));
XtFree(reinterpret_cast<char *>(pu16GuestText));
LogFlowFunc(("rc = false\n"));
return false;
}
Log2 (("vboxClipboardConvertUtf16: returning Unicode, original text is %.*ls\n",
pu16GuestText + 1));
RTMemFree(reinterpret_cast<void *>(pu16HostText));
*piFormatReturn = 8;
LogFlowFunc(("rc = true\n"));
return true;
}
/**
* Satisfy a request from the guest 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
*/
unsigned long *pcLenReturn, int *piFormatReturn)
{
char *pcGuestText;
int rc;
LogFlowFunc(("\n"));
/* Get the host Utf16 data and convert it to Linux Utf16. */
reinterpret_cast<void **>(&pu16HostText), &cbHostText);
{
Log (("vboxClipboardConvertUtf16: vboxClipboardReadHostData returned %Vrc, %d bytes of data\n", rc, cbGuestText));
g_ctx.hostFormats = 0;
LogFlowFunc(("rc = false\n"));
return false;
}
if (pu16GuestText == 0)
{
RTMemFree(reinterpret_cast<char *>(pu16HostText));
LogFlowFunc(("rc = false\n"));
return false;
}
if (rc != VINF_SUCCESS)
{
RTMemFree(reinterpret_cast<char *>(pu16HostText));
RTMemFree(reinterpret_cast<char *>(pu16GuestText));
LogFlowFunc(("rc = false\n"));
return false;
}
/* Now convert the Utf16 Linux text to Utf8 */
if (rc != VINF_SUCCESS)
{
RTMemFree(reinterpret_cast<char *>(pu16HostText));
RTMemFree(reinterpret_cast<char *>(pu16GuestText));
LogFlowFunc(("rc = false\n"));
return false;
}
/* Our runtime can't cope with endian markers. */
if (rc != VINF_SUCCESS)
{
RTMemFree(reinterpret_cast<char *>(pu16HostText));
RTMemFree(reinterpret_cast<char *>(pu16GuestText));
LogFlowFunc(("rc = false\n"));
return false;
}
pu16HostText));
RTMemFree(reinterpret_cast<char *>(pu16HostText));
RTMemFree(reinterpret_cast<char *>(pu16GuestText));
*piFormatReturn = 8;
LogFlowFunc(("rc = true\n"));
return true;
}
/**
* Satisfy a request from the guest to convert the clipboard text to Latin1.
*
* @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
*/
unsigned long *pcLenReturn, int *piFormatReturn)
{
unsigned char *pcGuestText;
int rc;
LogFlowFunc(("\n"));
/* Get the host UTF16 data */
reinterpret_cast<void **>(&pu16HostText), &cbHostText);
{
Log (("vboxClipboardConvertUtf16: vboxClipboardReadHostData returned %Vrc, %d bytes of data\n", rc, cbGuestText));
g_ctx.hostFormats = 0;
LogFlowFunc(("rc = false\n"));
return false;
}
if (pcGuestText == 0)
{
RTMemFree(reinterpret_cast<void *>(pu16HostText));
LogFlowFunc(("rc = false\n"));
return false;
}
for (unsigned i = 0; i < cwHostText; ++i, ++cbGuestPos)
{
if ( (i + 1 < cwHostText)
&& (pu16HostText[i] == CARRIAGERETURN)
++i;
if (pu16HostText[i] < 256)
else
/* Any better ideas as to how to do this? */
}
pu16HostText));
pcGuestText));
RTMemFree(reinterpret_cast<void *>(pu16HostText));
*piFormatReturn = 8;
LogFlowFunc(("rc = true\n"));
return true;
}
/**
* Callback to convert the hosts clipboard data for an application on the guest. Called by the
* X Toolkit.
* @returns true if we successfully convert the data to the format requested, false otherwise.
*
* @param atomSelection The selection which is being requested. We only handle the clipboard.
* @param atomTarget The format we should convert the data to
* @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
*/
unsigned long *pcLenReturn, int *piFormatReturn)
{
int rc;
LogFlowFunc(("\n"));
{
LogFlowFunc(("rc = false\n"));
return false;
}
#ifdef DEBUG
if (szAtomName != 0)
{
}
else
{
}
#endif
{
}
else
{
{
{
break;
}
}
}
switch (eFormat)
{
case TARGETS:
return rc;
case UTF16:
return rc;
case UTF8:
return rc;
case LATIN1:
return rc;
default:
Log(("vboxClipboardConvertProc: bad format\n"));
LogFlowFunc(("rc = false\n"));
return false;
}
}
{
LogFlowFunc(("giving the guest clipboard ownership\n"));
LogFlowFunc(("returning\n"));
}
/**
* The host is taking possession of the shared clipboard. Called by the HGCM clipboard
* subsystem.
*
* @param u32Formats Clipboard formats the the guest is offering
*/
{
if (u32Formats == 0)
{
/* This is just an automatism, not a genuine anouncement */
LogFlowFunc(("returning\n"));
return;
}
Log2 (("vboxClipboardFormatAnnounce: giving the host clipboard ownership\n"));
vboxClipboardLoseProc, 0) == True)
{
/* We set this so that the host gets notified when we take the clipboard, even if no
guest formats are found which we understand. */
g_ctx.notifyHost = true;
}
else
{
Log2 (("vboxClipboardFormatAnnounce: returning clipboard ownership to the guest\n"));
}
LogFlowFunc(("returning\n"));
}
/**
* Called when the host wants to read the guest clipboard.
*
* @param u32Format The format that the host would like to receive the data in
*/
{
/*
* The guest wants to read data in the given format.
*/
{
{
/* No data available. */
vboxClipboardSendData (0, NULL, 0);
LogFlowFunc(("sent empty data, returned VINF_SUCCESS\n"));
return VINF_SUCCESS;
}
/* Send out a request for the data to the current clipboard owner */
/* When the data arrives, the vboxClipboardGetProc callback will be called. The
callback will signal the event semaphore when it has processed the data for us. */
}
else
{
vboxClipboardSendData (0, NULL, 0);
LogFlowFunc(("sent empty data, returned VERR_NOT_IMPLEMENTED\n"));
return VERR_NOT_IMPLEMENTED;
}
LogFlowFunc(("returned VINF_SUCCESS\n"));
return VINF_SUCCESS;
}
/** Terminate the guest side of the shared clipboard. */
void vboxClipboardDestroy (void)
{
LogFlowFunc(("\n"));
/* Set the termination flag. */
LogFlowFunc(("returning\n"));
}
/**
* The main loop of our clipboard reader.
*/
{
int rc = VINF_SUCCESS;
LogFlowFunc(("Starting clipboard thread\n"));
for (;;)
{
{
Log(("Failed to call the driver for host message.\n"));
/* Wait a bit before retrying. */
break;
continue;
}
if (VBOX_SUCCESS (rc))
{
if (VBOX_SUCCESS (rc))
{
if (VBOX_SUCCESS (rc))
{
switch (u32Msg)
{
{
/* The host has announced available clipboard formats.
* Save the information so that it is available for
* future requests from guest applications.
*/
} break;
{
/* The host needs data in the specified format.
*/
} break;
{
/* The host is terminating.
*/
} break;
default:
{
Log(("Unsupported message from host!!!\n"));
}
}
}
}
}
if (rc == VERR_INTERRUPTED)
{
/* Wait for termination event. */
break;
}
if (VBOX_FAILURE (rc))
{
/* Wait a bit before retrying. */
break;
continue;
}
}
return rc;
}
/**
* Disconnect the guest clipboard from the host.
*/
void vboxClipboardDisconnect (void)
{
LogFlowFunc(("\n"));
LogFlowFunc(("returning\n"));
}
{
char errorText[1024];
LogFlowFunc(("\n"));
{
/* This can be triggered in debug builds if a guest application passes a bad atom
in its list of supported clipboard formats. As such it is harmless. */
LogFlowFunc(("ignoring BadAtom error and returning\n"));
return 0;
}
{
}
Log(("%s: an X Window protocol error occurred: %s. Request code: %d, minor code: %d, serial number: %d\n",
LogFlowFunc(("exiting\n"));
exit(1);
}
void vboxClipboardSignalHandler(int number)
{
{
}
LogFlowFunc(("exiting\n"));
exit(1);
}
/**
* Connect the guest clipboard to the host.
*
* @returns RT status code
*/
int vboxClipboardConnect (void)
{
struct sigaction sSigAction;
LogFlowFunc(("\n"));
request.u32ClientID = 0;
/* Only one client is supported for now */
{
{
if (request.u32ClientID == 0)
{
return VERR_NOT_SUPPORTED;
}
}
else
{
LogFlowFunc(("returned VERR_NOT_SUPPORTED\n"));
return VERR_NOT_SUPPORTED;
}
}
else
{
LogFlowFunc(("returned VERR_NOT_SUPPORTED\n"));
return VERR_NOT_SUPPORTED;
}
/* If the programme exits without disconnecting from the shared clipboard service, we
will need to reboot the guest in order to use it again. So we set handlers for as
many fatal conditions as possible which disconnect and exit the programme. */
sSigAction.sa_flags = 0;
LogFlowFunc(("returned VINF_SUCCESS\n"));
return VINF_SUCCESS;
}
/** We store information about the target formats we can handle in a global vector for internal
use. */
unsigned hostFormat)
{
/* Get an atom from the X server for that target format */
if (atomFormat == 0)
{
LogFlowFunc(("atomFormat=0! returning...\n"));
return;
}
LogFlowFunc (("returning\n"));
}
/** Create the X11 window which we use to interact with the guest clipboard */
static int vboxClipboardCreateWindow(void)
{
/* Create a window and make it a clipboard viewer. */
int cArgc = 0;
char *pcArgv = 0;
/* Set up the Clipbard application context and main window. */
/* 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 */
#ifdef USE_UTF16
#endif
#ifdef USE_UTF8
#endif
#ifdef USE_LATIN1
#endif
return VINF_SUCCESS;
}
/** Initialise the guest side of the shared clipboard. */
int vboxClipboardMain (void)
{
int rc;
LogFlowFunc(("\n"));
if (VBOX_FAILURE(rc))
{
return rc;
}
RTTHREADFLAGS_WAITABLE, "SHCLIP");
/* Set up a timer to poll the host clipboard */
/* Set the termination signal. */
return rc;
}
/**
* Become a daemon process
*/
void vboxDaemonise(void)
{
/* First fork and exit the parent process, so that we are sure we are not session leader. */
if (fork() != 0)
{
exit(0);
}
/* Detach from the controlling terminal by creating our own session. */
setsid();
/* And change to the root directory to avoid holding the one we were started in open. */
chdir("/");
/* Close the standard files. */
close(0);
close(1);
close(2);
}
{
int rc;
/* Parse our option(s) */
while (1)
{
{
{"nodaemon", 0, 0, 'd'},
{0, 0, 0, 0}
};
if (cOpt == -1)
{
{
exit(1);
}
break;
}
switch(cOpt)
{
case 'd':
break;
default:
case '?':
exit(1);
}
}
/* Initialise our runtime before all else. */
RTR3Init(false);
LogFlowFunc(("\n"));
/* Initialise threading in Xt before we start any new threads. */
/* Initialise the termination semaphore. */
/* Open a connection to the driver for sending requests. */
if (g_ctx.sendDevice < 0)
{
LogFlowFunc(("returning 1\n"));
return 1;
}
/* Open a connection to the driver for polling for host requests. */
if (g_ctx.receiveDevice < 0)
{
LogFlowFunc(("returning 1\n"));
return 1;
}
/* Connect to the host clipboard. */
rc = vboxClipboardConnect();
if (rc != VINF_SUCCESS)
{
LogFlowFunc(("returning 1\n"));
return 1;
}
{
}
LogFlowFunc(("returning 0\n"));
return 0;
}