clipboard.cpp revision b72771e8c6ba3b3d9ebdd7977730325131ae0f98
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/** $Id$ */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/** @file
45565249f149f7562fc6ee85be7ca3a3706e32e6vboxsync * Guest Additions - X11 Shared Clipboard.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/*
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Copyright (C) 2007 Sun Microsystems, Inc.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync *
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * available from http://www.virtualbox.org. This file is free software;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * you can redistribute it and/or modify it under the terms of the GNU
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * General Public License (GPL) as published by the Free Software
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync *
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * additional information or have any questions.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/*******************************************************************************
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync* Header Files *
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync*******************************************************************************/
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <VBox/HostServices/VBoxClipboardSvc.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <VBox/log.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/alloc.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/asm.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/assert.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/initterm.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/mem.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/string.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/thread.h>
45565249f149f7562fc6ee85be7ca3a3706e32e6vboxsync#include <iprt/process.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/semaphore.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <X11/Xlib.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <X11/Xatom.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <X11/Intrinsic.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <X11/Shell.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <X11/X.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <vector>
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include "clipboard.h"
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/** The formats which we support in the guest. These can be deactivated in order to test specific code paths. */
3393c62e395aa8388303d99f765a219efc289158vboxsync#define USE_UTF16
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#define USE_UTF8
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#define USE_CTEXT
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/*******************************************************************************
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync* Global Variables *
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync*******************************************************************************/
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync/** The different clipboard formats which we support. */
45565249f149f7562fc6ee85be7ca3a3706e32e6vboxsyncenum g_eClipboardFormat
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync{
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync INVALID = 0,
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync TARGETS,
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync CTEXT,
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync UTF8,
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync UTF16
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync};
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/** The X11 clipboard uses several names for the same format. This structure maps an X11 name to a format. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsynctypedef struct
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync{
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync Atom atom;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync g_eClipboardFormat format;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync unsigned hostFormat;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync} VBOXCLIPBOARDFORMAT;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync/** Does the host or the guest currently own the clipboard? */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsyncenum g_eClipboardOwner
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync{
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync NONE = 0,
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync HOST,
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync GUEST
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync};
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/**
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Global clipboard context information.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsynctypedef struct
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync{
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /** The Xt application context structure */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync XtAppContext appContext;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** We have a separate thread to wait for Window and Clipboard events */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync RTTHREAD thread;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** The Xt widget which we use as our clipboard client. It is never made visible. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync Widget widget;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /** X11 atom refering to the clipboard: CLIPBOARD */
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync Atom atomClipboard;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** X11 atom refering to the selection: PRIMARY */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync Atom atomPrimary;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** X11 atom refering to the clipboard: TARGETS */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync Atom atomTargets;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** X11 atom refering to the clipboard: MULTIPLE */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync Atom atomMultiple;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** X11 atom refering to the clipboard: TIMESTAMP */
8d7d0a641afd3eb2aacf2b3ba428e6d8894a6a5fvboxsync Atom atomTimestamp;
8d7d0a641afd3eb2aacf2b3ba428e6d8894a6a5fvboxsync /** X11 atom refering to the clipboard utf16 text format: text/plain;charset=ISO-10646-UCS-2 */
8d7d0a641afd3eb2aacf2b3ba428e6d8894a6a5fvboxsync Atom atomUtf16;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /** X11 atom refering to the clipboard utf8 text format: UTF8_STRING */
8d7d0a641afd3eb2aacf2b3ba428e6d8894a6a5fvboxsync Atom atomUtf8;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** X11 atom refering to the native X11 clipboard text format: COMPOUND_TEXT */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync Atom atomCText;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** A list of the X11 formats which we support, mapped to our identifier for them, in the order
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync we prefer to have them in. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync std::vector<VBOXCLIPBOARDFORMAT> formatList;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /** Does the host or the guest currently own the clipboard? */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync volatile enum g_eClipboardOwner eOwner;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
a93da6c0946d71f517dc6d64a633704cb99068b8vboxsync /** What is the best text format the guest has to offer? INVALID for none. */
a93da6c0946d71f517dc6d64a633704cb99068b8vboxsync g_eClipboardFormat guestTextFormat;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** Atom corresponding to the guest text format */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync Atom atomGuestTextFormat;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /** What is the best bitmap format the guest has to offer? INVALID for none. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync g_eClipboardFormat guestBitmapFormat;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** Atom corresponding to the guest Bitmap format */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync Atom atomGuestBitmapFormat;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** What formats does the host have on offer? */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync int hostFormats;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** Windows caches the clipboard data it receives. Since we have no way of knowing whether
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync that data is still valid, we always send a "data changed" message after a successful
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync transfer to invalidate the cache. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync bool notifyHost;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** Since the clipboard data moves asynchronously, we use an event semaphore to wait for it. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync RTSEMEVENT terminating;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** Format which we are reading from the guest clipboard (valid during a request for the
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync guest clipboard) */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync g_eClipboardFormat requestGuestFormat;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** The guest buffer to write guest clipboard data to (valid during a request for the host
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync clipboard) */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync void *requestBuffer;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** The size of the host buffer to write guest clipboard data to (valid during a request for
cf0b951d0e7a93540b3931ca506ed97c1dc300ccvboxsync the guest clipboard) */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync unsigned requestBufferSize;
cf0b951d0e7a93540b3931ca506ed97c1dc300ccvboxsync /** The size of the guest clipboard data written to the host buffer (valid during a request
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync for the guest clipboard) */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync uint32_t *requestActualSize;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** Client ID for the clipboard subsystem */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync uint32_t client;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync} VBOXCLIPBOARDCONTEXT;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/** Only one client is supported. There seems to be no need for more clients. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsyncstatic VBOXCLIPBOARDCONTEXT g_ctx;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/**
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Transfer clipboard data from the guest to the host.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync *
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * @returns VBox result code
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * @param u32Format The format of the data being sent
a93da6c0946d71f517dc6d64a633704cb99068b8vboxsync * @param pv Pointer to the data being sent
b47847090b3c99e4fdf905536053595e75845265vboxsync * @param cb Size of the data being sent in bytes
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsyncstatic int vboxClipboardSendData(uint32_t u32Format, void *pv, uint32_t cb)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync{
4b30f6c72b07654509606857da385afcc09aaae3vboxsync int rc;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync LogFlowFunc(("u32Format=%d, pv=%p, cb=%d\n", u32Format, pv, cb));
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync rc = VbglR3ClipboardWriteData(g_ctx.client, u32Format, pv, cb);
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync LogFlowFunc(("rc=%Rrc\n", rc));
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync return rc;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync}
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
ec382ee8bf6c277150eaad532778850e88273741vboxsync/**
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Get clipboard data from the host.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync *
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * @returns VBox result code
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @param u32Format The format of the data being requested
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * @retval ppv On success and if pcb > 0, this will point to a buffer
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * to be freed with RTMemFree containing the data read.
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @retval pcb On success, this contains the number of bytes of data
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * returned
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync */
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsyncstatic int vboxClipboardReadHostData(uint32_t u32Format, void **ppv, uint32_t *pcb)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync{
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync int rc = VINF_SUCCESS;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync uint32_t cb = 1024;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync void *pv = RTMemAlloc(cb);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync *ppv = 0;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("u32Format=%u\n", u32Format));
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (RT_UNLIKELY(!pv))
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync rc = VERR_NO_MEMORY;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (RT_SUCCESS(rc))
4b30f6c72b07654509606857da385afcc09aaae3vboxsync rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync *ppv = pv;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /* A return value of VINF_BUFFER_OVERFLOW tells us to try again with a
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * larger buffer. The size of the buffer needed is placed in *pcb.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * So we start all over again. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (rc == VINF_BUFFER_OVERFLOW)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync {
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync cb = *pcb;
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync RTMemFree(pv);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pv = RTMemAlloc(cb);
a93da6c0946d71f517dc6d64a633704cb99068b8vboxsync if (RT_UNLIKELY(!pv))
b47847090b3c99e4fdf905536053595e75845265vboxsync rc = VERR_NO_MEMORY;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (RT_SUCCESS(rc))
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync *ppv = pv;
4fe68a6b363f8944c4305b845a95580cd547937fvboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /* Catch other errors. This also catches the case in which the buffer was
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * too small a second time, possibly because the clipboard contents
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * changed half-way through the operation. Since we can't say whether or
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * not this is actually an error, we just return size 0.
4b30f6c72b07654509606857da385afcc09aaae3vboxsync */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (RT_FAILURE(rc) || (VINF_BUFFER_OVERFLOW == rc))
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync *pcb = 0;
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync if (pv != NULL)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync RTMemFree(pv);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync }
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync LogFlowFunc(("returning %Rrc\n", rc));
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (RT_SUCCESS(rc))
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlow((" *pcb=%d\n", *pcb));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return rc;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync}
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync/**
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * Convert a Utf16 text with Linux EOLs to zero-terminated Utf16-LE with Windows EOLs, allocating
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * memory for the converted text. Does no checking for validity.
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync *
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @returns VBox status code
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync *
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @param pu16Src Source Utf16 text to convert
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @param cwSrc Size of the source text in 16 bit words
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @retval ppu16Dest Where to store the pointer to the converted text. Only valid on success
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * and if pcwDest is greater than 0.
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @retval pcwDest Size of the converted text in 16 bit words, including the trailing null
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * if present
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsyncstatic int vboxClipboardUtf16LinToWin(PRTUTF16 pu16Src, size_t cwSrc, PRTUTF16 *ppu16Dest,
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync size_t *pcwDest)
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync{
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync enum { LINEFEED = 0xa, CARRIAGERETURN = 0xd };
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync PRTUTF16 pu16Dest;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync size_t cwDest, i, j;
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync LogFlowFunc(("pu16Src=%.*ls, cwSrc=%u\n", cwSrc, pu16Src, cwSrc));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (cwSrc == 0)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync *ppu16Dest = 0;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync *pcwDest = 0;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("*ppu16Dest=0, *pcwDest=0, rc=VINF_SUCCESS\n"));
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync return VINF_SUCCESS;
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync AssertReturn(VALID_PTR(pu16Src), VERR_INVALID_PARAMETER);
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync cwDest = 0;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync for (i = 0; i < cwSrc; ++i, ++cwDest)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (pu16Src[i] == LINEFEED)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync ++cwDest;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (pu16Src[i] == 0)
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync break;
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /* Leave space for a trailing null */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync ++cwDest;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pu16Dest = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwDest * 2));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (pu16Dest == 0)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("rc=VERR_NO_MEMORY\n"));
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync return VERR_NO_MEMORY;
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync }
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync for (i = (pu16Src[0] == 0xfeff ? 1 : 0), j = 0; i < cwSrc; ++i, ++j)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync {
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync if (pu16Src[i] == LINEFEED)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pu16Dest[j] = CARRIAGERETURN;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync ++j;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (pu16Src[i] == 0)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync break;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pu16Dest[j] = pu16Src[i];
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /* The trailing null */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pu16Dest[j] = 0;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync *ppu16Dest = pu16Dest;
fcabc02dcf564fb62371b7b90f9c6099b2fd54a5vboxsync *pcwDest = cwDest;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("*ppu16Dest=%p, *pcwDest=%d, rc=VINF_SUCCESS\n", pu16Dest, cwDest));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return VINF_SUCCESS;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync}
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync/**
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * Convert the UTF-16 text returned from the guest X11 clipboard to UTF-16LE with Windows EOLs
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * and send it to the host.
13e885122ee503a6b52b157f8d779f8a9a8dd716vboxsync *
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync * @param pValue Source UTF-16 text
13e885122ee503a6b52b157f8d779f8a9a8dd716vboxsync * @param cwSourceLen Length in 16-bit words of the source text
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync */
13e885122ee503a6b52b157f8d779f8a9a8dd716vboxsyncstatic void vboxClipboardGetUtf16(XtPointer pValue, size_t cwSourceLen)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync{
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync size_t cwDestLen;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync PRTUTF16 pu16DestText;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync PRTUTF16 pu16SourceText = reinterpret_cast<PRTUTF16>(pValue);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync int rc;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync LogFlowFunc(("converting Utf-16 to Utf-16LE. Original is %.*ls\n",
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync cwSourceLen - 1, pu16SourceText + 1));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync rc = vboxClipboardUtf16LinToWin(pu16SourceText, cwSourceLen, &pu16DestText, &cwDestLen);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (rc != VINF_SUCCESS)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync XtFree(reinterpret_cast<char *>(pValue));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardSendData(0, NULL, 0);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("sending empty data and returning\n"));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlow(("vboxClipboardGetUtf16: converted string is %.*ls\n", cwDestLen, pu16DestText));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardSendData(VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync reinterpret_cast<void *>(pu16DestText), cwDestLen * 2);
3a5d16e1911830b585d10278ea2cdbb408e261e6vboxsync RTMemFree(reinterpret_cast<void *>(pu16DestText));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync XtFree(reinterpret_cast<char *>(pValue));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("returning\n"));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync}
3a5d16e1911830b585d10278ea2cdbb408e261e6vboxsync
3a5d16e1911830b585d10278ea2cdbb408e261e6vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync/**
b47847090b3c99e4fdf905536053595e75845265vboxsync * Convert the UTF-8 text returned from the guest X11 clipboard to UTF-16LE with Windows EOLs
a93da6c0946d71f517dc6d64a633704cb99068b8vboxsync * and send it to the host.
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync *
b47847090b3c99e4fdf905536053595e75845265vboxsync * @param pValue Source UTF-8 text
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @param cbSourceLen Length in 8-bit bytes of the source text
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsyncstatic void vboxClipboardGetUtf8(XtPointer pValue, size_t cbSourceLen)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync{
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync size_t cwSourceLen, cwDestLen;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync char *pu8SourceText = reinterpret_cast<char *>(pValue);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync PRTUTF16 pu16SourceText = 0, pu16DestText;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync int rc;
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("\n"));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlow(("vboxClipboardGetUtf8: converting Utf-8 to Utf-16LE. Original is %.*s\n", cbSourceLen,
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pu8SourceText));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /* First convert the UTF8 to UTF16 */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync rc = RTStrToUtf16Ex(pu8SourceText, cbSourceLen, &pu16SourceText, 0, &cwSourceLen);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (rc != VINF_SUCCESS)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync XtFree(reinterpret_cast<char *>(pValue));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardSendData(0, NULL, 0);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("sending empty data and returning\n"));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
13e885122ee503a6b52b157f8d779f8a9a8dd716vboxsync rc = vboxClipboardUtf16LinToWin(pu16SourceText, cwSourceLen, &pu16DestText, &cwDestLen);
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync if (rc != VINF_SUCCESS)
13e885122ee503a6b52b157f8d779f8a9a8dd716vboxsync {
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync RTMemFree(reinterpret_cast<void *>(pu16SourceText));
13e885122ee503a6b52b157f8d779f8a9a8dd716vboxsync XtFree(reinterpret_cast<char *>(pValue));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardSendData(0, NULL, 0);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("sending empty data and returning\n"));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlow(("vboxClipboardGetUtf8: converted string is %.*ls\n", cwDestLen, pu16DestText));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardSendData(VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync reinterpret_cast<void *>(pu16DestText), cwDestLen * 2);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync RTMemFree(reinterpret_cast<void *>(pu16SourceText));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync RTMemFree(reinterpret_cast<void *>(pu16DestText));
a93da6c0946d71f517dc6d64a633704cb99068b8vboxsync XtFree(reinterpret_cast<char *>(pValue));
b47847090b3c99e4fdf905536053595e75845265vboxsync LogFlowFunc(("returning\n"));
b47847090b3c99e4fdf905536053595e75845265vboxsync}
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync/**
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * Convert the compound text returned from the guest X11 clipboard to UTF-16LE with Windows EOLs
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * and send it to the host.
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync *
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @param pValue Source compound text
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @param cbSourceLen Length in 8-bit bytes of the source text
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsyncstatic void vboxClipboardGetCText(XtPointer pValue, size_t cbSourceLen)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync{
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync size_t cwSourceLen, cwDestLen;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync char **ppu8SourceText = 0;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync PRTUTF16 pu16SourceText = 0, pu16DestText;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync XTextProperty property;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync int rc, cProps;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("\n"));
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync LogFlow(("vboxClipboardGetCText: converting compound text to Utf-16LE. Original is %.*s\n",
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync cbSourceLen, pValue));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /* First convert the compound text to Utf8 */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync property.value = reinterpret_cast<unsigned char *>(pValue);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync property.encoding = g_ctx.atomCText;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync property.format = 8;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync property.nitems = cbSourceLen;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync#ifdef RT_OS_SOLARIS
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync rc = XmbTextPropertyToTextList(XtDisplay(g_ctx.widget), &property, &ppu8SourceText, &cProps);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync#else
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync rc = Xutf8TextPropertyToTextList(XtDisplay(g_ctx.widget), &property, &ppu8SourceText, &cProps);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync#endif
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync XtFree(reinterpret_cast<char *>(pValue));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (rc < 0)
0dd363d45ea01de87d37118985064da6e0f86f36vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync const char *pcReason;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync switch(rc)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync {
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync case XNoMemory:
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pcReason = "out of memory";
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync break;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync case XLocaleNotSupported:
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pcReason = "locale (Utf8) not supported";
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync break;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync case XConverterNotFound:
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pcReason = "converter not found";
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync break;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync default:
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pcReason = "unknown error";
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync XFreeStringList(ppu8SourceText);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogRel(("vboxClipboardGetCText: Xutf8TextPropertyToTextList failed. Reason: %s\n", pcReason));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardSendData(0, NULL, 0);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("sending empty data and returning\n"));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /* Next convert the UTF8 to UTF16 */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync rc = RTStrToUtf16Ex(*ppu8SourceText, cbSourceLen, &pu16SourceText, 0, &cwSourceLen);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync XFreeStringList(ppu8SourceText);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (rc != VINF_SUCCESS)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardSendData(0, NULL, 0);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("sending empty data and returning\n"));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync rc = vboxClipboardUtf16LinToWin(pu16SourceText, cwSourceLen, &pu16DestText, &cwDestLen);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync RTMemFree(reinterpret_cast<void *>(pu16SourceText));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (rc != VINF_SUCCESS)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardSendData(0, NULL, 0);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("sending empty data and returning\n"));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlow(("vboxClipboardGetCText: converted string is %.*ls\n", cwDestLen, pu16DestText));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardSendData(VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync reinterpret_cast<void *>(pu16DestText), cwDestLen * 2);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync RTMemFree(reinterpret_cast<void *>(pu16DestText));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("returning\n"));
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync}
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync/**
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * Convert the Latin1 text returned from the guest X11 clipboard to UTF-16LE with Windows EOLs
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * and send it to the host.
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync *
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @param pValue Source Latin1 text
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @param cbSourceLen Length in 8-bit bytes of the source text
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsyncstatic void vboxClipboardGetLatin1(XtPointer pValue, size_t cbSourceLen)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync{
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync enum { LINEFEED = 0xa, CARRIAGERETURN = 0xd };
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /* Leave space for an additional null character at the end of the destination text. */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync size_t cwDestLen = cbSourceLen + 1, cwDestPos;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync char *pu8SourceText = reinterpret_cast<char *>(pValue);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync PRTUTF16 pu16DestText;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("converting Latin1 to Utf-16LE. Original is %.*s\n", cbSourceLen,
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pu8SourceText));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /* Find the size of the destination text */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync for (size_t i = 0; i < cbSourceLen; i++)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (pu8SourceText[i] == LINEFEED)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync ++cwDestLen;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pu16DestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwDestLen * 2));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (pu16DestText == 0)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync XtFree(reinterpret_cast<char *>(pValue));
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync LogFlow(("vboxClipboardGetLatin1: failed to allocate %d bytes!\n", cwDestLen * 2));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardSendData(0, NULL, 0);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("sending empty data and returning\n"));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /* Copy the original X clipboard string to the destination, replacing Linux EOLs with
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync Windows ones */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync cwDestPos = 0;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync for (size_t i = 0; i < cbSourceLen; ++i, ++cwDestPos)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (pu8SourceText[i] == LINEFEED)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pu16DestText[cwDestPos] = CARRIAGERETURN;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync ++cwDestPos;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /* latin1 < utf-16LE */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pu16DestText[cwDestPos] = pu8SourceText[i];
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (pu8SourceText[i] == 0)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync break;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pu16DestText[cwDestPos] = 0;
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync LogFlow(("vboxClipboardGetLatin1: converted text is %.*ls\n", cwDestPos, pu16DestText));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardSendData(VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync reinterpret_cast<void *>(pu16DestText), cwDestPos * 2);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync RTMemFree(reinterpret_cast<void *>(pu16DestText));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync XtFree(reinterpret_cast<char *>(pValue));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("returning\n"));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync}
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync/** Convert the clipboard text from the current format to Utf-16 with Windows line breaks.
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync We are reading the guest clipboard to make it available to the host. */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsyncstatic void vboxClipboardGetProc(Widget, XtPointer /* pClientData */, Atom * /* selection */,
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync Atom *atomType, XtPointer pValue, long unsigned int *pcLen,
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync int *piFormat)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync{
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /* The X Toolkit may have failed to get the clipboard selection for us. */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("*pcLen=%lu, *piFormat=%d, requested target format: %d, g_ctx.requestBufferSize=%d\n",
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync *pcLen, *piFormat, g_ctx.requestGuestFormat, g_ctx.requestBufferSize));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (*atomType == XT_CONVERT_FAIL)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardSendData(0, NULL, 0);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("Xt failed to convert the data. Sending empty data and returning\n"));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (NULL == pValue)
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync {
b47847090b3c99e4fdf905536053595e75845265vboxsync vboxClipboardSendData(0, NULL, 0);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync LogFlowFunc(("The clipboard contents changed while we were requesting them. Sending empty data and returning\n"));
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync }
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /* In which format did we request the clipboard data? */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync unsigned cTextLen = (*pcLen) * (*piFormat) / 8;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync switch (g_ctx.requestGuestFormat)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync case UTF16:
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardGetUtf16(pValue, cTextLen / 2);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync break;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync case CTEXT:
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync vboxClipboardGetCText(pValue, cTextLen);
36ebaddfec017eee7e82ee466c25de002cdc4231vboxsync break;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync case UTF8:
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /* If we are given broken Utf-8, we treat it as Latin1. Is this acceptable? */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync size_t cStringLen;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync char *pu8SourceText = reinterpret_cast<char *>(pValue);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync if (RTStrUniLenEx(pu8SourceText, *pcLen, &cStringLen) == VINF_SUCCESS)
3393c62e395aa8388303d99f765a219efc289158vboxsync vboxClipboardGetUtf8(pValue, cTextLen);
3393c62e395aa8388303d99f765a219efc289158vboxsync else
3393c62e395aa8388303d99f765a219efc289158vboxsync vboxClipboardGetLatin1(pValue, cTextLen);
3393c62e395aa8388303d99f765a219efc289158vboxsync break;
3393c62e395aa8388303d99f765a219efc289158vboxsync }
3393c62e395aa8388303d99f765a219efc289158vboxsync default:
3393c62e395aa8388303d99f765a219efc289158vboxsync {
3393c62e395aa8388303d99f765a219efc289158vboxsync XtFree(reinterpret_cast<char *>(pValue));
3393c62e395aa8388303d99f765a219efc289158vboxsync Log(("vboxClipboardGetProc: bad target format\n"));
3393c62e395aa8388303d99f765a219efc289158vboxsync vboxClipboardSendData(0, NULL, 0);
3393c62e395aa8388303d99f765a219efc289158vboxsync LogFlowFunc(("sending empty data and returning\n"));
3393c62e395aa8388303d99f765a219efc289158vboxsync return;
3393c62e395aa8388303d99f765a219efc289158vboxsync }
3393c62e395aa8388303d99f765a219efc289158vboxsync }
3393c62e395aa8388303d99f765a219efc289158vboxsync g_ctx.notifyHost = true;
3393c62e395aa8388303d99f765a219efc289158vboxsync LogFlowFunc(("returning\n"));
3393c62e395aa8388303d99f765a219efc289158vboxsync}
3393c62e395aa8388303d99f765a219efc289158vboxsync
3393c62e395aa8388303d99f765a219efc289158vboxsync
3393c62e395aa8388303d99f765a219efc289158vboxsync/**
3393c62e395aa8388303d99f765a219efc289158vboxsync * Tell the host that new clipboard formats are available.
3393c62e395aa8388303d99f765a219efc289158vboxsync *
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync * @returns VBox status code.
3393c62e395aa8388303d99f765a219efc289158vboxsync * @param u32Formats The formats to advertise
3393c62e395aa8388303d99f765a219efc289158vboxsync */
3393c62e395aa8388303d99f765a219efc289158vboxsyncstatic int vboxClipboardReportFormats(uint32_t u32Formats)
3393c62e395aa8388303d99f765a219efc289158vboxsync{
3393c62e395aa8388303d99f765a219efc289158vboxsync int rc;
3393c62e395aa8388303d99f765a219efc289158vboxsync LogFlowFunc(("u32Formats=%d\n", u32Formats));
3393c62e395aa8388303d99f765a219efc289158vboxsync rc = VbglR3ClipboardReportFormats(g_ctx.client, u32Formats);
3393c62e395aa8388303d99f765a219efc289158vboxsync LogFlowFunc(("rc=%Rrc\n", rc));
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync return rc;
3393c62e395aa8388303d99f765a219efc289158vboxsync}
3393c62e395aa8388303d99f765a219efc289158vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync/** Callback to handle a reply to a request for the targets the current clipboard holder can
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync handle. We are reading the guest clipboard to make it available to the host. */
0a769a6be37f526faeabe88f77422ee6291afa37vboxsyncstatic void vboxClipboardTargetsProc(Widget, XtPointer, Atom * /* selection */, Atom *atomType,
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync XtPointer pValue, long unsigned int *pcLen, int *piFormat)
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync{
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync static int cCalls = 0;
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync Atom *atomTargets = reinterpret_cast<Atom *>(pValue);
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync /* The number of format atoms the clipboard holder is offering us */
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync unsigned cAtoms = *pcLen;
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync /* The best clipboard format we have found so far */
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync g_eClipboardFormat eBestTarget = INVALID;
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync /* The atom corresponding to our best clipboard format found */
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync Atom atomBestTarget = None;
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync if ((cCalls % 10) == 0)
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync Log3(("vboxClipboardTargetsProc called, cAtoms=%d\n", cAtoms));
54912863a8d407402faac40cbfb00883f4af90bfvboxsync if (*atomType == XT_CONVERT_FAIL)
71b548af8b5b8adb865702432045250bc56ad7e5vboxsync {
71b548af8b5b8adb865702432045250bc56ad7e5vboxsync Log(("vboxClipboardTargetsProc: reading clipboard from guest, X toolkit failed to convert the selection\n"));
71b548af8b5b8adb865702432045250bc56ad7e5vboxsync LogFlowFunc(("returning\n"));
71b548af8b5b8adb865702432045250bc56ad7e5vboxsync return;
71b548af8b5b8adb865702432045250bc56ad7e5vboxsync }
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync /* Run through the atoms offered to us to see if we recognise them. If we find the atom for
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync a "better" format than the best we have found so far, we remember it as our new "best"
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync format. */
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync for (unsigned i = 0; i < cAtoms; ++i)
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync {
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync for (unsigned j = 0; j != g_ctx.formatList.size(); ++j)
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync if (g_ctx.formatList[j].atom == atomTargets[i])
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync {
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync if (eBestTarget < g_ctx.formatList[j].format)
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync {
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync eBestTarget = g_ctx.formatList[j].format;
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync atomBestTarget = g_ctx.formatList[j].atom;
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync }
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync break;
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync }
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync#ifdef DEBUG
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync char *szAtomName = XGetAtomName(XtDisplay(g_ctx.widget), atomTargets[i]);
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync if (szAtomName != 0)
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync {
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync if ((cCalls % 10) == 0)
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync Log3(("vboxClipboardTargetsProc: the guest offers target %s\n", szAtomName));
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync XFree(szAtomName);
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync }
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync else
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync {
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync if ((cCalls % 10) == 0)
c5019986bed37ec649721e6f7bc2117386fa5ac3vboxsync Log3(("vboxClipboardTargetsProc: the guest returned a bad atom: %d\n",
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync atomTargets[i]));
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync }
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync#endif
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync }
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync g_ctx.atomGuestTextFormat = atomBestTarget;
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync /* If the available formats as seen by the host have changed, or if we suspect that
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync the host has cached the clipboard data (which can change without our noticing it),
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync then tell the host that new clipboard contents are available. */
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync if ((eBestTarget != g_ctx.guestTextFormat) || (g_ctx.notifyHost == true))
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync {
fbce7e4e7123ca200586ee9257a12d663e928841vboxsync uint32_t u32Formats = 0;
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync#ifdef DEBUG
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync if (atomBestTarget != None)
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync {
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync char *szAtomName = XGetAtomName(XtDisplay(g_ctx.widget), atomBestTarget);
0a769a6be37f526faeabe88f77422ee6291afa37vboxsync LogFlow(("vboxClipboardTargetsProc: switching to guest text target %s. Available targets are:\n", szAtomName));
XFree(szAtomName);
}
else
LogFlow(("vboxClipboardTargetsProc: no supported host text target found. Available targets are:\n"));
for (unsigned i = 0; i < cAtoms; ++i)
{
char *szAtomName = XGetAtomName(XtDisplay(g_ctx.widget), atomTargets[i]);
if (szAtomName != 0)
{
LogFlow(("vboxClipboardTargetsProc: %s\n", szAtomName));
XFree(szAtomName);
}
}
#endif
g_ctx.guestTextFormat = eBestTarget;
if (eBestTarget != INVALID)
u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
vboxClipboardReportFormats(u32Formats);
g_ctx.notifyHost = false;
}
XtFree(reinterpret_cast<char *>(pValue));
++cCalls;
}
/**
* This callback is called every 200ms to check the contents of the guest clipboard.
*/
static void vboxClipboardTimerProc(XtPointer /* pUserData */, XtIntervalId * /* hTimerId */)
{
static int cCalls = 0;
/* Get the current clipboard contents */
if (g_ctx.eOwner == GUEST)
{
if ((cCalls % 10) == 0)
Log3(("vboxClipboardTimerProc: requesting the targets that the guest clipboard offers\n"));
XtGetSelectionValue(g_ctx.widget, g_ctx.atomClipboard, g_ctx.atomTargets,
vboxClipboardTargetsProc, 0, CurrentTime);
}
/* Re-arm our timer */
XtAppAddTimeOut(g_ctx.appContext, 200 /* ms */, vboxClipboardTimerProc, 0);
++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
*/
static Boolean vboxClipboardConvertTargets(Atom *atomTypeReturn, XtPointer *pValReturn,
unsigned long *pcLenReturn, int *piFormatReturn)
{
unsigned uListSize = g_ctx.formatList.size();
Atom *atomTargets = reinterpret_cast<Atom *>(XtMalloc((uListSize + 3) * sizeof(Atom)));
unsigned cTargets = 0;
LogFlowFunc(("\n"));
LogFlow(("vboxClipboardConvertTargets: uListSize=%u\n", uListSize));
for (unsigned i = 0; i < uListSize; ++i)
{
if ( ((g_ctx.hostFormats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) != 0)
&& (g_ctx.formatList[i].hostFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT))
{
atomTargets[cTargets] = g_ctx.formatList[i].atom;
++cTargets;
}
}
atomTargets[cTargets] = g_ctx.atomTargets;
atomTargets[cTargets + 1] = g_ctx.atomMultiple;
atomTargets[cTargets + 2] = g_ctx.atomTimestamp;
#ifdef DEBUG
for (unsigned i = 0; i < cTargets + 3; i++)
{
char *szAtomName = XGetAtomName(XtDisplay(g_ctx.widget), atomTargets[i]);
if (szAtomName != 0)
{
LogFlow(("vboxClipboardConvertTargets: returning target %s\n", szAtomName));
XFree(szAtomName);
}
else
Log(("vboxClipboardConvertTargets: invalid atom %d in the list!\n", atomTargets[i]));
}
#endif
*atomTypeReturn = XA_ATOM;
*pValReturn = reinterpret_cast<XtPointer>(atomTargets);
*pcLenReturn = cTargets + 3;
*piFormatReturn = 32;
LogFlowFunc(("returning true\n"));
return true;
}
/**
* Get the size of the buffer needed to hold a zero-terminated 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
*/
static int vboxClipboardUtf16GetLinSize(PRTUTF16 pu16Src, size_t cwSrc)
{
enum { LINEFEED = 0xa, CARRIAGERETURN = 0xd };
size_t cwDest;
LogFlowFunc(("pu16Src=%.*ls, cwSrc=%u\n", cwSrc, pu16Src, cwSrc));
AssertReturn(pu16Src != 0, VERR_INVALID_PARAMETER);
/* We only take little endian Utf16 */
AssertReturn(pu16Src[0] != 0xfffe, VERR_INVALID_PARAMETER);
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;
for (size_t i = 0; i < cwSrc; ++i, ++cwDest)
{
if ( (i + 1 < cwSrc)
&& (pu16Src[i] == CARRIAGERETURN)
&& (pu16Src[i + 1] == LINEFEED))
++i;
if (pu16Src[i] == 0)
break;
}
/* The terminating null */
++cwDest;
LogFlowFunc(("returning %d\n", cwDest * 2));
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
*/
static int vboxClipboardUtf16WinToLin(PRTUTF16 pu16Src, size_t cwSrc, PRTUTF16 pu16Dest,
size_t cwDest)
{
enum { LINEFEED = 0xa, CARRIAGERETURN = 0xd };
size_t cwDestPos;
LogFlowFunc(("pu16Src=%.*ls, cwSrc=%u, pu16Dest=%p, cwDest=%u\n",
cwSrc, pu16Src, cwSrc, pu16Dest, cwDest));
/* A buffer of size 0 may not be an error, but it is not a good idea either. */
Assert(cwDest > 0);
AssertReturn(VALID_PTR(pu16Src), VERR_INVALID_PARAMETER);
/* We only take little endian Utf16 */
AssertReturn(pu16Src[0] != 0xfffe, VERR_INVALID_PARAMETER);
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;
}
for (size_t i = 0; i < cwSrc; ++i, ++cwDestPos)
{
if (cwDestPos == cwDest)
{
LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
return VERR_BUFFER_OVERFLOW;
}
if ( (i + 1 < cwSrc)
&& (pu16Src[i] == CARRIAGERETURN)
&& (pu16Src[i + 1] == LINEFEED))
++i;
pu16Dest[cwDestPos] = pu16Src[i];
if (pu16Src[i] == 0)
break;
}
if (cwDestPos == cwDest)
{
LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
return VERR_BUFFER_OVERFLOW;
}
pu16Dest[cwDestPos] = 0;
LogFlowFunc(("set string %ls. Returning\n", pu16Dest + 1));
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
*/
static Boolean vboxClipboardConvertUtf16(Atom *atomTypeReturn, XtPointer *pValReturn,
unsigned long *pcLenReturn, int *piFormatReturn)
{
PRTUTF16 pu16GuestText, pu16HostText;
unsigned cbHostText, cwHostText, cwGuestText;
int rc;
LogFlowFunc(("\n"));
rc = vboxClipboardReadHostData(VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
reinterpret_cast<void **>(&pu16HostText), &cbHostText);
if ((rc != VINF_SUCCESS) || cbHostText == 0)
{
LogFlow(("vboxClipboardConvertUtf16: vboxClipboardReadHostData returned %Rrc, %d bytes of data\n", rc, cbHostText));
g_ctx.hostFormats = 0;
LogFlowFunc(("rc = false\n"));
return false;
}
cwHostText = cbHostText / 2;
cwGuestText = vboxClipboardUtf16GetLinSize(pu16HostText, cwHostText);
pu16GuestText = reinterpret_cast<PRTUTF16>(XtMalloc(cwGuestText * 2));
if (pu16GuestText == 0)
{
RTMemFree(reinterpret_cast<void *>(pu16HostText));
LogFlowFunc(("rc = false\n"));
return false;
}
rc = vboxClipboardUtf16WinToLin(pu16HostText, cwHostText, pu16GuestText, cwGuestText);
if (rc != VINF_SUCCESS)
{
LogFlow(("vboxClipboardConvertUtf16: vboxClipboardUtf16WinToLin returned %Rrc\n", rc));
RTMemFree(reinterpret_cast<void *>(pu16HostText));
XtFree(reinterpret_cast<char *>(pu16GuestText));
LogFlowFunc(("rc = false\n"));
return false;
}
LogFlow(("vboxClipboardConvertUtf16: returning Unicode, original text is %.*ls\n", cwHostText, pu16HostText));
LogFlow(("vboxClipboardConvertUtf16: converted text is %.*ls\n", cwGuestText - 1, pu16GuestText + 1));
RTMemFree(reinterpret_cast<void *>(pu16HostText));
*atomTypeReturn = g_ctx.atomUtf16;
*pValReturn = reinterpret_cast<XtPointer>(pu16GuestText);
*pcLenReturn = cwGuestText * 2;
*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
*/
static Boolean vboxClipboardConvertUtf8(Atom *atomTypeReturn, XtPointer *pValReturn,
unsigned long *pcLenReturn, int *piFormatReturn)
{
PRTUTF16 pu16GuestText, pu16HostText;
char *pcGuestText;
unsigned cbHostText, cwHostText, cwGuestText, cbGuestTextBuffer;
size_t cbGuestTextActual;
int rc;
LogFlowFunc(("\n"));
/* Get the host Utf16 data and convert it to Linux Utf16. */
rc = vboxClipboardReadHostData(VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
reinterpret_cast<void **>(&pu16HostText), &cbHostText);
if ((rc != VINF_SUCCESS) || cbHostText == 0)
{
LogFlow(("vboxClipboardConvertUtf16: vboxClipboardReadHostData returned %Rrc, %d bytes of data\n", rc, cbHostText));
g_ctx.hostFormats = 0;
LogFlowFunc(("rc = false\n"));
return false;
}
cwHostText = cbHostText / 2;
LogFlow(("vboxClipboardConvertUtf8: original text is %.*ls\n", cwHostText, pu16HostText));
cwGuestText = vboxClipboardUtf16GetLinSize(pu16HostText, cwHostText);
pu16GuestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwGuestText * 2));
if (pu16GuestText == 0)
{
RTMemFree(reinterpret_cast<char *>(pu16HostText));
LogFlowFunc(("rc = false\n"));
return false;
}
rc = vboxClipboardUtf16WinToLin(pu16HostText, cwHostText, pu16GuestText, cwGuestText);
RTMemFree(reinterpret_cast<char *>(pu16HostText));
if (rc != VINF_SUCCESS)
{
LogFlow(("vboxClipboardConvertUtf16: vboxClipboardUtf16WinToLin returned %Rrc\n", rc));
RTMemFree(reinterpret_cast<char *>(pu16GuestText));
LogFlowFunc(("rc = false\n"));
return false;
}
/* Now convert the Utf16 Linux text to Utf8 */
cbGuestTextBuffer = cwGuestText * 3; /* Should always be enough. */
pcGuestText = XtMalloc(cbGuestTextBuffer);
if (pcGuestText == 0)
{
RTMemFree(reinterpret_cast<char *>(pu16GuestText));
LogFlowFunc(("rc = false\n"));
return false;
}
/* Our runtime can't cope with endian markers. */
cbGuestTextActual = 0;
rc = RTUtf16ToUtf8Ex(pu16GuestText + 1, cwGuestText - 1, &pcGuestText, cbGuestTextBuffer, &cbGuestTextActual);
RTMemFree(reinterpret_cast<char *>(pu16GuestText));
if (rc != VINF_SUCCESS)
{
XtFree(pcGuestText);
LogFlowFunc(("rc = false\n"));
return false;
}
LogFlow(("vboxClipboardConvertUtf8: converted text is %.*s\n", cbGuestTextActual, pcGuestText));
*atomTypeReturn = g_ctx.atomUtf8;
*pValReturn = reinterpret_cast<XtPointer>(pcGuestText);
*pcLenReturn = (unsigned long)cbGuestTextActual;
*piFormatReturn = 8;
LogFlowFunc(("rc = true\n"));
return true;
}
/**
* Satisfy a request from the guest 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
*/
static Boolean vboxClipboardConvertCText(Atom *atomTypeReturn, XtPointer *pValReturn,
unsigned long *pcLenReturn, int *piFormatReturn)
{
PRTUTF16 pu16GuestText, pu16HostText;
char *pcUtf8Text;
unsigned cbHostText, cwHostText, cwGuestText, cbUtf8Text;
XTextProperty property;
int rc;
LogFlowFunc(("\n"));
/* Get the host Utf16 data and convert it to Linux Utf16. */
rc = vboxClipboardReadHostData(VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
reinterpret_cast<void **>(&pu16HostText), &cbHostText);
if ((rc != VINF_SUCCESS) || cbHostText == 0)
{
LogFlow(("vboxClipboardConvertCText: vboxClipboardReadHostData returned %Rrc, %d bytes of data\n", rc, cbHostText));
g_ctx.hostFormats = 0;
LogFlowFunc(("rc = false\n"));
return false;
}
LogFlow(("vboxClipboardConvertCText: original text is %.*ls\n", cwHostText, pu16HostText));
cwHostText = cbHostText / 2;
cwGuestText = vboxClipboardUtf16GetLinSize(pu16HostText, cwHostText);
pu16GuestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwGuestText * 2));
if (pu16GuestText == 0)
{
Log(("vboxClipboardConvertCText: out of memory\n"));
RTMemFree(reinterpret_cast<char *>(pu16HostText));
LogFlowFunc(("rc = false\n"));
return false;
}
rc = vboxClipboardUtf16WinToLin(pu16HostText, cwHostText, pu16GuestText, cwGuestText);
RTMemFree(reinterpret_cast<char *>(pu16HostText));
if (rc != VINF_SUCCESS)
{
LogFlow(("vboxClipboardConvertUtf16: vboxClipboardUtf16WinToLin returned %Rrc\n", rc));
RTMemFree(reinterpret_cast<char *>(pu16GuestText));
LogFlowFunc(("rc = false\n"));
return false;
}
/* Now convert the Utf16 Linux text to Utf8 */
cbUtf8Text = cwGuestText * 3; /* Should always be enough. */
pcUtf8Text = reinterpret_cast<char *>(RTMemAlloc(cbUtf8Text));
if (pcUtf8Text == 0)
{
Log(("vboxClipboardConvertCText: out of memory\n"));
RTMemFree(reinterpret_cast<char *>(pu16GuestText));
LogFlowFunc(("rc = false\n"));
return false;
}
/* Our runtime can't cope with endian markers. */
rc = RTUtf16ToUtf8Ex(pu16GuestText + 1, cwGuestText - 1, &pcUtf8Text, cbUtf8Text, 0);
RTMemFree(reinterpret_cast<char *>(pu16GuestText));
if (rc != VINF_SUCCESS)
{
Log(("vboxClipboardConvertCText: RTUtf16ToUtf8Ex failed: rc=%Rrc\n", rc));
XtFree(pcUtf8Text);
LogFlowFunc(("rc = false\n"));
return false;
}
/* And finally (!) convert the Utf8 text to compound text. */
#ifdef RT_OS_SOLARIS
rc = XmbTextListToTextProperty(XtDisplay(g_ctx.widget), &pcUtf8Text, 1,
XCompoundTextStyle, &property);
#else
rc = Xutf8TextListToTextProperty(XtDisplay(g_ctx.widget), &pcUtf8Text, 1,
XCompoundTextStyle, &property);
#endif
RTMemFree(pcUtf8Text);
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";
}
LogRel(("vboxClipboardConvertCText: Xutf8TextListToTextProperty failed. Reason: %s\n",
pcReason));
XFree(property.value);
LogFlowFunc(("rc = false\n"));
return false;
}
LogFlow(("vboxClipboardConvertCText: converted text is %s\n", property.value));
*atomTypeReturn = property.encoding;
*pValReturn = reinterpret_cast<XtPointer>(property.value);
*pcLenReturn = property.nitems;
*piFormatReturn = property.format;
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
*/
static Boolean vboxClipboardConvertProc(Widget, Atom *atomSelection, Atom *atomTarget,
Atom *atomTypeReturn, XtPointer *pValReturn,
unsigned long *pcLenReturn, int *piFormatReturn)
{
g_eClipboardFormat eFormat = INVALID;
int rc;
LogFlowFunc(("\n"));
if ( (*atomSelection != g_ctx.atomClipboard)
&& (*atomSelection != g_ctx.atomPrimary)
)
{
LogFlowFunc(("rc = false\n"));
return false;
}
#ifdef DEBUG
char *szAtomName = XGetAtomName(XtDisplay(g_ctx.widget), *atomTarget);
if (szAtomName != 0)
{
LogFlow(("vboxClipboardConvertProc: request for format %s\n", szAtomName));
XFree(szAtomName);
}
else
Log(("vboxClipboardConvertProc: request for invalid target atom %d!\n", *atomTarget));
#endif
if (*atomTarget == g_ctx.atomTargets)
eFormat = TARGETS;
else
{
for (unsigned i = 0; i != g_ctx.formatList.size(); ++i)
{
if (g_ctx.formatList[i].atom == *atomTarget)
{
eFormat = g_ctx.formatList[i].format;
break;
}
}
}
switch (eFormat)
{
case TARGETS:
rc = vboxClipboardConvertTargets(atomTypeReturn, pValReturn, pcLenReturn, piFormatReturn);
LogFlowFunc(("TARGETS rc=%d\n", rc));
return rc;
case UTF16:
rc = vboxClipboardConvertUtf16(atomTypeReturn, pValReturn, pcLenReturn, piFormatReturn);
LogFlowFunc(("UTF16 rc=%d\n", rc));
return rc;
case UTF8:
rc = vboxClipboardConvertUtf8(atomTypeReturn, pValReturn, pcLenReturn, piFormatReturn);
LogFlowFunc(("UTF8 rc=%d\n", rc));
return rc;
case CTEXT:
rc = vboxClipboardConvertCText(atomTypeReturn, pValReturn, pcLenReturn, piFormatReturn);
LogFlowFunc(("CTEXT rc=%d\n", rc));
return rc;
default:
Log(("vboxClipboardConvertProc: bad format\n"));
LogFlowFunc(("rc = false\n"));
return false;
}
}
static void vboxClipboardLoseProc(Widget, Atom *)
{
LogFlowFunc(("giving the guest clipboard ownership\n"));
g_ctx.eOwner = GUEST;
g_ctx.notifyHost = true;
LogFlowFunc(("returning\n"));
}
/**
* The host is taking possession of the shared clipboard. Called by the HGCM clipboard
* subsystem.
*
* @param u32Formats Clipboard formats the guest is offering
*/
void vboxClipboardFormatAnnounce (uint32_t u32Formats)
{
g_ctx.hostFormats = u32Formats;
LogFlowFunc(("u32Formats = %d\n", u32Formats));
if (u32Formats == 0)
{
/* This is just an automatism, not a genuine announcement */
LogFlowFunc(("returning\n"));
return;
}
LogFlow(("vboxClipboardFormatAnnounce: giving the host clipboard ownership\n"));
g_ctx.eOwner = HOST;
g_ctx.guestTextFormat = INVALID;
g_ctx.guestBitmapFormat = INVALID;
if (XtOwnSelection(g_ctx.widget, g_ctx.atomClipboard, CurrentTime, vboxClipboardConvertProc,
vboxClipboardLoseProc, 0) != True)
{
LogFlow(("vboxClipboardFormatAnnounce: returning clipboard ownership to the guest\n"));
g_ctx.notifyHost = true;
g_ctx.eOwner = GUEST;
}
XtOwnSelection(g_ctx.widget, g_ctx.atomPrimary, CurrentTime, vboxClipboardConvertProc,
NULL, 0);
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
*/
int vboxClipboardReadGuestData (uint32_t u32Format)
{
LogFlowFunc(("u32Format = %d\n", u32Format));
/*
* The guest wants to read data in the given format.
*/
if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
{
if (g_ctx.guestTextFormat == INVALID)
{
/* No data available. */
vboxClipboardSendData(0, NULL, 0);
LogFlowFunc(("sent empty data, returned VINF_SUCCESS\n"));
return VINF_SUCCESS;
}
g_ctx.requestGuestFormat = g_ctx.guestTextFormat;
/* Send out a request for the data to the current clipboard owner */
XtGetSelectionValue(g_ctx.widget, g_ctx.atomClipboard, g_ctx.atomGuestTextFormat,
vboxClipboardGetProc, 0, CurrentTime);
/* 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. */
XtAppSetExitFlag(g_ctx.appContext);
LogFlowFunc(("returning\n"));
}
/**
* The main loop of our clipboard reader.
*/
static int vboxClipboardThread(RTTHREAD /* ThreadSelf */, void * /* pvUser */)
{
int rc;
LogFlowFunc(("Starting clipboard thread\n"));
for (;;)
{
uint32_t Msg;
uint32_t fFormats;
rc = VbglR3ClipboardGetHostMsg(g_ctx.client, &Msg, &fFormats);
if (RT_SUCCESS(rc))
{
switch (Msg)
{
case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS:
{
/* The host has announced available clipboard formats.
* Save the information so that it is available for
* future requests from guest applications.
*/
LogFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS fFormats=%x\n", fFormats));
vboxClipboardFormatAnnounce(fFormats);
break;
}
case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
{
/* The host needs data in the specified format. */
LogFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA fFormats=%x\n", fFormats));
vboxClipboardReadGuestData(fFormats);
break;
}
case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
{
/* The host is terminating. */
LogFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT\n"));
vboxClipboardDestroy();
rc = VERR_INTERRUPTED;
break;
}
default:
Log(("Unsupported message from host!!!\n"));
}
}
if (rc == VERR_INTERRUPTED)
{
/* Wait for termination event. */
RTSemEventWait(g_ctx.terminating, RT_INDEFINITE_WAIT);
break;
}
if (RT_FAILURE(rc))
{
/* Wait a bit before retrying. */
if (RTSemEventWait(g_ctx.terminating, 1000) == VINF_SUCCESS)
break;
continue;
}
LogFlow(("processed host event rc = %d\n", rc));
}
LogFlowFunc(("rc=%d\n", rc));
return rc;
}
/**
* Disconnect the guest clipboard from the host.
*/
void vboxClipboardDisconnect(void)
{
#if 0
VMMDevHGCMDisconnect request;
#endif
LogFlowFunc(("\n"));
AssertReturn(g_ctx.client != 0, (void) 0);
VbglR3ClipboardDisconnect(g_ctx.client);
LogFlowFunc(("returning\n"));
}
/**
* Connect the guest clipboard to the host.
*
* @returns VBox status code
*/
int vboxClipboardConnect(void)
{
int rc;
LogFlowFunc(("\n"));
/* Only one client is supported for now */
AssertReturn(g_ctx.client == 0, VERR_NOT_SUPPORTED);
/* Initialise the termination semaphore. */
RTSemEventCreate(&g_ctx.terminating);
rc = VbglR3ClipboardConnect(&g_ctx.client);
if (RT_FAILURE(rc))
{
LogRel(("Error connecting to host. rc=%Rrc\n", rc));
return rc;
}
if (!g_ctx.client)
{
LogRel(("Invalid client ID of 0\n"));
return VERR_NOT_SUPPORTED;
}
g_ctx.eOwner = HOST;
LogFlowFunc(("g_ctx.client=%u rc=%Rrc\n", g_ctx.client, rc));
return rc;
}
/** We store information about the target formats we can handle in a global vector for internal
use. */
static void vboxClipboardAddFormat(const char *pszName, g_eClipboardFormat eFormat, unsigned hostFormat)
{
VBOXCLIPBOARDFORMAT sFormat;
LogFlowFunc(("pszName=%s, eFormat=%d, hostFormat=%u\n", pszName, eFormat, hostFormat));
/* Get an atom from the X server for that target format */
Atom atomFormat = XInternAtom(XtDisplay(g_ctx.widget), pszName, false);
LogFlow(("vboxClipboardAddFormat: atomFormat=%d\n", atomFormat));
if (atomFormat == 0)
{
LogFlowFunc(("atomFormat=0! returning...\n"));
return;
}
sFormat.atom = atomFormat;
sFormat.format = eFormat;
sFormat.hostFormat = hostFormat;
g_ctx.formatList.push_back(sFormat);
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;
String szFallbackResources[] = { (char*)"*.width: 1", (char*)"*.height: 1", 0 };
/* Set up the Clipbard application context and main window. */
g_ctx.widget = XtOpenApplication(&g_ctx.appContext, "VBoxClipboard", 0, 0, &cArgc, &pcArgv,
szFallbackResources, applicationShellWidgetClass, 0, 0);
AssertMsgReturn(g_ctx.widget != 0, ("Failed to construct the X clipboard window\n"),
VERR_ACCESS_DENIED);
XtSetMappedWhenManaged(g_ctx.widget, false);
XtRealizeWidget(g_ctx.widget);
/* Get hold of the atoms which we need */
g_ctx.atomClipboard = XInternAtom(XtDisplay(g_ctx.widget), "CLIPBOARD", false /* only_if_exists */);
g_ctx.atomPrimary = XInternAtom(XtDisplay(g_ctx.widget), "PRIMARY", false);
g_ctx.atomTargets = XInternAtom(XtDisplay(g_ctx.widget), "TARGETS", false);
g_ctx.atomMultiple = XInternAtom(XtDisplay(g_ctx.widget), "MULTIPLE", false);
g_ctx.atomTimestamp = XInternAtom(XtDisplay(g_ctx.widget), "TIMESTAMP", false);
g_ctx.atomUtf16 = XInternAtom(XtDisplay(g_ctx.widget),
"text/plain;charset=ISO-10646-UCS-2", false);
g_ctx.atomUtf8 = XInternAtom(XtDisplay(g_ctx.widget), "UTF_STRING", false);
g_ctx.atomCText = XInternAtom(XtDisplay(g_ctx.widget), "COMPOUND_TEXT", false);
/* And build up the vector of supported formats */
#ifdef USE_UTF16
vboxClipboardAddFormat("text/plain;charset=ISO-10646-UCS-2", UTF16, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
#endif
#ifdef USE_UTF8
vboxClipboardAddFormat("UTF8_STRING", UTF8, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
vboxClipboardAddFormat("text/plain;charset=UTF-8", UTF8, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
vboxClipboardAddFormat("text/plain;charset=utf-8", UTF8, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
vboxClipboardAddFormat("STRING", UTF8, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
vboxClipboardAddFormat("TEXT", UTF8, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
vboxClipboardAddFormat("text/plain", UTF8, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
#endif
#ifdef USE_CTEXT
vboxClipboardAddFormat("COMPOUND_TEXT", CTEXT, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
#endif
return VINF_SUCCESS;
}
/** Initialise the guest side of the shared clipboard. */
int vboxClipboardMain(void)
{
int rc;
LogFlowFunc(("\n"));
rc = vboxClipboardCreateWindow();
if (RT_FAILURE(rc))
return rc;
rc = RTThreadCreate(&g_ctx.thread, vboxClipboardThread, 0, 0, RTTHREADTYPE_IO,
RTTHREADFLAGS_WAITABLE, "SHCLIP");
AssertRCReturn(rc, rc);
/* Set up a timer to poll the host clipboard */
XtAppAddTimeOut(g_ctx.appContext, 200 /* ms */, vboxClipboardTimerProc, 0);
XtAppMainLoop(g_ctx.appContext);
g_ctx.formatList.clear();
XtDestroyApplicationContext(g_ctx.appContext);
/* Set the termination signal. */
RTSemEventSignal(g_ctx.terminating);
LogFlowFunc(("returning %d\n", rc));
return rc;
}