x11.cpp revision 68e0f2909a5fe490fd5c33346b911815ca5b02a5
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/** @file
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Shared Clipboard:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Linux host.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
441579693f771e49eb05f2bd20c316232155675bvboxsync/*
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * available from http://www.virtualbox.org. This file is free software;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * you can redistribute it and/or modify it under the terms of the GNU
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * General Public License (GPL) as published by the Free Software
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * additional information or have any questions.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <vector>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <VBox/HostServices/VBoxClipboardSvc.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <iprt/alloc.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <iprt/asm.h> /* For atomic operations */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <iprt/assert.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <iprt/env.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <iprt/mem.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <iprt/string.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <iprt/thread.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <iprt/process.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <iprt/semaphore.h>
441579693f771e49eb05f2bd20c316232155675bvboxsync#include <string.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <stdio.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <stdint.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include "VBoxClipboard.h"
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include "clipboard-helper.h"
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <X11/Xlib.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <X11/Xatom.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <X11/Intrinsic.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <X11/Shell.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <X11/Xproto.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <X11/StringDefs.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#ifdef RT_OS_SOLARIS
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#include <tsol/label.h>
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#endif
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/** Do we want to test Utf16 by disabling other text formats? */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic bool g_testUtf16 = false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/** Do we want to test Utf8 by disabling other text formats? */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic bool g_testUtf8 = false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/** Do we want to test compount text by disabling other text formats? */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic bool g_testCText = false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/** Are we currently debugging the clipboard code? */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic bool g_debugClipboard = false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/** The different clipboard formats which we support. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncenum g_eClipboardFormats
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync INVALID = 0,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync TARGETS,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync CTEXT,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync UTF8,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync UTF16
6ef855ecf2121f708685307839f1262e0db1a024vboxsync};
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/** The X11 clipboard uses several names for the same format. This structure maps an X11
6ef855ecf2121f708685307839f1262e0db1a024vboxsync name to a format. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsynctypedef struct {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom atom;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_eClipboardFormats format;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned guestFormat;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync} VBOXCLIPBOARDFORMAT;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/** Does the host or the guest currently own the clipboard? */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncenum g_eClipboardOwner { NONE = 0, HOST, GUEST };
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsynctypedef struct {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** BMP file type marker - must always contain 'BM' */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync uint16_t bfType;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** The size of the BMP file in bytes (the MS docs say that this is not reliable) */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync uint32_t bfSize;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** Reserved, must always be zero */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync uint16_t bfReserved1;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** Reserved, must always be zero */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync uint16_t bfReserved2;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** Offset from the beginning of this header to the actual image bits */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync} VBOXBITMAPFILEHEADER;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/** Global clipboard context information */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstruct _VBOXCLIPBOARDCONTEXT
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** The X Toolkit application context structure */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtAppContext appContext;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** We have a separate thread to wait for Window and Clipboard events */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTTHREAD thread;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** The X Toolkit widget which we use as our clipboard client. It is never made visible. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Widget widget;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** X11 atom refering to the clipboard: CLIPBOARD */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom atomClipboard;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** X11 atom refering to the selection: PRIMARY */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom atomPrimary;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** X11 atom refering to the clipboard targets: TARGETS */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom atomTargets;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** X11 atom refering to the clipboard multiple target: MULTIPLE */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom atomMultiple;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** X11 atom refering to the clipboard timestamp target: TIMESTAMP */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom atomTimestamp;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** X11 atom refering to the clipboard utf16 text format: text/plain;charset=ISO-10646-UCS-2 */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom atomUtf16;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** X11 atom refering to the clipboard utf8 text format: UTF8_STRING */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom atomUtf8;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** X11 atom refering to the clipboard compound text format: COMPOUND_TEXT */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom atomCText;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** A list of the X11 formats which we support, mapped to our identifier for them, in the
6ef855ecf2121f708685307839f1262e0db1a024vboxsync order we prefer to have them in. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync std::vector<VBOXCLIPBOARDFORMAT> formatList;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** Does the host or the guest currently own the clipboard? */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync volatile enum g_eClipboardOwner eOwner;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** What is the best text format the host has to offer? INVALID for none. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_eClipboardFormats hostTextFormat;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** Atom corresponding to the host text format */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom atomHostTextFormat;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** What is the best bitmap format the host has to offer? INVALID for none. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_eClipboardFormats hostBitmapFormat;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** Atom corresponding to the host Bitmap format */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom atomHostBitmapFormat;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** What formats does the guest have on offer? */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int guestFormats;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** Windows caches the clipboard data it receives. Since we have no way of knowing whether
6ef855ecf2121f708685307839f1262e0db1a024vboxsync that data is still valid, we always send a "data changed" message after a successful
6ef855ecf2121f708685307839f1262e0db1a024vboxsync transfer to invalidate the cache. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync bool notifyGuest;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** Since the clipboard data moves asynchronously, we use an event semaphore to wait for
6ef855ecf2121f708685307839f1262e0db1a024vboxsync it. When a function issues a request for clipboard data it must wait for this
6ef855ecf2121f708685307839f1262e0db1a024vboxsync semaphore, which is triggered when the data arrives. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSEMEVENT waitForData;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** And because it would not do for the guest to be waiting for the host while the host
6ef855ecf2121f708685307839f1262e0db1a024vboxsync is waiting for the guest, we set a flag and assert horribly if we spot a deadlock. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync uint32_t waiter;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** This mutex is held while an asynchronous operation completes (i.e. the host clipboard is
6ef855ecf2121f708685307839f1262e0db1a024vboxsync being queried) to make sure that the clipboard is not disconnected during that time. It
6ef855ecf2121f708685307839f1262e0db1a024vboxsync is also grabbed when the clipboard client disconnects. When an asynchronous operation
6ef855ecf2121f708685307839f1262e0db1a024vboxsync starts completing, it checks that the same client is still connected immediately after
6ef855ecf2121f708685307839f1262e0db1a024vboxsync grabbing the mutex. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSEMMUTEX asyncMutex;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** Format which we are reading from the host clipboard (valid during a request for the
6ef855ecf2121f708685307839f1262e0db1a024vboxsync host clipboard) */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_eClipboardFormats requestHostFormat;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** The guest buffer to write host clipboard data to (valid during a request for the host
6ef855ecf2121f708685307839f1262e0db1a024vboxsync clipboard) */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync void *requestBuffer;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** The size of the guest buffer to write host clipboard data to (valid during a request for
6ef855ecf2121f708685307839f1262e0db1a024vboxsync the host clipboard) */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned requestBufferSize;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** The size of the host clipboard data written to the guest buffer (valid during a request
6ef855ecf2121f708685307839f1262e0db1a024vboxsync for the host clipboard) */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync uint32_t *requestActualSize;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /** Pointer to the client data structure */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync VBOXCLIPBOARDCLIENTDATA *pClient;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync};
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/* Only one client is supported. There seems to be no need for more clients. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic VBOXCLIPBOARDCONTEXT g_ctx;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/* Are we actually connected to the X11 servicer? */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic bool g_fHaveX11;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Send a request to VBox to transfer the contents of its clipboard to X11.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pCtx Pointer to the host clipboard structure
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param u32Format The format in which the data should be transfered
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread clipboard X11 event thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note called by vboxClipboardConvert*
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic int vboxClipboardReadDataFromVBox (VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync VBOXCLIPBOARDCLIENTDATA *pClient = pCtx->pClient;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("u32Format=%02X\n", u32Format));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Assert that no other transfer is in process (requests are serialised)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * and that the last transfer cleaned up properly. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync AssertLogRelReturn( pCtx->pClient->data.pv == NULL
6ef855ecf2121f708685307839f1262e0db1a024vboxsync && pCtx->pClient->data.cb == 0
6ef855ecf2121f708685307839f1262e0db1a024vboxsync && pCtx->pClient->data.u32Format == 0,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync VERR_WRONG_ORDER
6ef855ecf2121f708685307839f1262e0db1a024vboxsync );
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* No one else (X11 or VBox) should currently be waiting. The first because
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * requests from X11 are serialised and the second because VBox previously
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * grabbed the clipboard, so it should not be waiting for data from us. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync AssertLogRelReturn (ASMAtomicCmpXchgU32(&pCtx->waiter, 1, 0), VERR_DEADLOCK);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (pClient == 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* This can legitimately happen if we disconnect during a request for
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * data from X11. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFunc(("host requested guest clipboard data after guest had disconnected.\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pCtx->guestFormats = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pCtx->waiter = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return VERR_TIMEOUT;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Request data from the guest */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxSvcClipboardReportMsg (pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Format);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Which will signal us when it is ready. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int rc = RTSemEventWait(pCtx->waitForData, RT_INDEFINITE_WAIT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync AssertLogRelRCSuccess(rc);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_FAILURE(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* I believe this should not happen. Wait until the assertions arrive
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * to prove the contrary. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pCtx->guestFormats = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pCtx->waiter = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return rc;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pCtx->waiter = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("wait completed. Returning.\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return VINF_SUCCESS;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Convert the UTF-16 text returned from the X11 clipboard to UTF-16LE with Windows EOLs
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * and place it in the global g_pcClipboardText variable. We are reading the host clipboard to
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * make it available to the guest.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pValue Source UTF-16 text
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param cwSourceLen Length in 16-bit words of the source text
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pv Where to store the converted data
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param cb Length in bytes of the buffer pointed to by cb
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pcbActual Where to store the size of the converted data
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pClient Pointer to the client context structure
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic void vboxClipboardGetUtf16(XtPointer pValue, unsigned cwSrcLen, void *pv, unsigned cb,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync uint32_t *pcbActual)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync size_t cwDestLen;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync PRTUTF16 pu16SrcText = reinterpret_cast<PRTUTF16>(pValue);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("converting Utf-16 to Utf-16LE. cwSrcLen=%d, cb=%d, pu16SrcText+1=%.*ls\n",
6ef855ecf2121f708685307839f1262e0db1a024vboxsync cwSrcLen, cb, cwSrcLen - 1, pu16SrcText + 1));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = 0; /* Only set this to the right value on success. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* How long will the converted text be? */
441579693f771e49eb05f2bd20c316232155675bvboxsync int rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc) && (cb < cwDestLen * 2))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Not enough buffer space provided - report the amount needed. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n",
6ef855ecf2121f708685307839f1262e0db1a024vboxsync cb, cwDestLen * 2));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = cwDestLen * 2;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = VERR_BUFFER_OVERFLOW;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Convert the text. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("converted string is %.*ls\n", cwDestLen, pu16DestText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = cwDestLen * 2;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* We need to do this whether we succeed or fail. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtFree(reinterpret_cast<char *>(pValue));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemEventSignal(g_ctx.waitForData);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("Returning. Status is %Rrc\n", rc));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Convert the UTF-8 text returned from the X11 clipboard to UTF-16LE with Windows EOLS.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * We are reading the X11 clipboard to make it available to VBox.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pValue Source UTF-8 text
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param cbSourceLen Length in 8-bit bytes of the source text
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pv Where to store the converted data
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param cb Length in bytes of the buffer pointed to by pv
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pcbActual Where to store the size of the converted data
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pClient Pointer to the client context structure
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread clipboard X11 event thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note called by vboxClipboardGetDataFromX11
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic void vboxClipboardGetUtf8FromX11(XtPointer pValue, unsigned cbSrcLen,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync void *pv, unsigned cb,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync uint32_t *pcbActual)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync size_t cwSrcLen, cwDestLen;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync char *pu8SrcText = reinterpret_cast<char *>(pValue);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync PRTUTF16 pu16SrcText = NULL;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("converting Utf-8 to Utf-16LE. cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n",
6ef855ecf2121f708685307839f1262e0db1a024vboxsync cbSrcLen, cb, cbSrcLen, pu8SrcText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = 0; /* Only set this to the right value on success. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* First convert the UTF8 to UTF16 */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int rc = RTStrToUtf16Ex(pu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Check how much longer will the converted text will be. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc) && (cb < cwDestLen * 2))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Not enough buffer space provided - report the amount needed. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n",
6ef855ecf2121f708685307839f1262e0db1a024vboxsync cb, cwDestLen * 2));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = cwDestLen * 2;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = VERR_BUFFER_OVERFLOW;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Convert the text. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("converted string is %.*ls.\n", cwDestLen, pu16DestText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = cwDestLen * 2;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtFree(reinterpret_cast<char *>(pValue));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTUtf16Free(pu16SrcText);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemEventSignal(g_ctx.waitForData);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("Returning. Status is %Rrc", rc));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Convert the COMPOUND_TEXT text returned from the X11 clipboard to UTF-16LE with Windows
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * EOLS. We are reading the X11 clipboard to make it available to VBox.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pValue Source COMPOUND_TEXT text
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param cbSourceLen Length in 8-bit bytes of the source text
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pv Where to store the converted data
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param cb Length in bytes of the buffer pointed to by pv
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pcbActual Where to store the size of the converted data
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pClient Pointer to the client context structure
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread clipboard X11 event thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note called by vboxClipboardGetDataFromX11
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic void vboxClipboardGetCTextFromX11(XtPointer pValue, unsigned cbSrcLen,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync void *pv, unsigned cb,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync uint32_t *pcbActual)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync size_t cwSrcLen, cwDestLen;
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync char **ppu8SrcText = NULL;
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync PRTUTF16 pu16SrcText = NULL;
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync XTextProperty property;
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync int rc = VINF_SUCCESS;
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync int cProps;
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync LogFlowFunc (("converting COMPOUND TEXT to Utf-16LE. cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n",
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync cbSrcLen, cb, cbSrcLen, reinterpret_cast<char *>(pValue)));
939e2ecb812c6402abcc63e7d615c5444acfd02evboxsync *pcbActual = 0; /* Only set this to the right value on success. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* First convert the compound text to Utf8 */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync property.value = reinterpret_cast<unsigned char *>(pValue);
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync property.encoding = g_ctx.atomCText;
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync property.format = 8;
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync property.nitems = cbSrcLen;
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync#ifdef RT_OS_SOLARIS
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync int xrc = XmbTextPropertyToTextList(XtDisplay(g_ctx.widget), &property, &ppu8SrcText, &cProps);
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync#else
58015215080abff9c3a752cb331b6efe29fe8933vboxsync int xrc = Xutf8TextPropertyToTextList(XtDisplay(g_ctx.widget), &property, &ppu8SrcText, &cProps);
adbb0da2a65fc315cb37869fd2c6c80c7d8d5b8bvboxsync#endif
58015215080abff9c3a752cb331b6efe29fe8933vboxsync XtFree(reinterpret_cast<char *>(pValue));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (xrc < 0)
58015215080abff9c3a752cb331b6efe29fe8933vboxsync switch(xrc)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync case XNoMemory:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = VERR_NO_MEMORY;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync break;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync case XLocaleNotSupported:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync case XConverterNotFound:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = VERR_NOT_SUPPORTED;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync break;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync default:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = VERR_UNRESOLVED_ERROR;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Now convert the UTF8 to UTF16 */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = RTStrToUtf16Ex(*ppu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Check how much longer will the converted text will be. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc) && (cb < cwDestLen * 2))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Not enough buffer space provided - report the amount needed. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n",
6ef855ecf2121f708685307839f1262e0db1a024vboxsync cb, cwDestLen * 2));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = cwDestLen * 2;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = VERR_BUFFER_OVERFLOW;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Convert the text. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("converted string is %.*ls\n", cwDestLen, pu16DestText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = cwDestLen * 2;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (ppu8SrcText != NULL)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XFreeStringList(ppu8SrcText);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTUtf16Free(pu16SrcText);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("Returning. Status is %Rrc\n", rc));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemEventSignal(g_ctx.waitForData);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Convert the Latin1 text returned from the X11 clipboard to UTF-16LE with Windows EOLS
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * and place it in the global g_pcClipboardText variable. We are reading the X11 clipboard to
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * make it available to VBox.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pValue Source Latin1 text
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param cbSourceLen Length in 8-bit bytes of the source text
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pv Where to store the converted data
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param cb Length in bytes of the buffer pointed to by cb
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pcbActual Where to store the size of the converted data
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pClient Pointer to the client context structure
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread clipboard X11 event thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note called by vboxClipboardGetDataFromX11
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic void vboxClipboardGetLatin1FromX11(XtPointer pValue, unsigned cbSourceLen, void *pv, unsigned cb,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync uint32_t *pcbActual)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned cwDestLen = cbSourceLen + 1;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync char *pu8SourceText = reinterpret_cast<char *>(pValue);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int rc = VINF_SUCCESS;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("converting Latin1 to Utf-16LE. Original is %.*s\n",
6ef855ecf2121f708685307839f1262e0db1a024vboxsync cbSourceLen, pu8SourceText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = 0; /* Only set this to the right value on success. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync for (unsigned i = 0; i < cbSourceLen; i++)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (pu8SourceText[i] == LINEFEED)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync ++cwDestLen;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (cb < cwDestLen * 2)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Not enough buffer space provided - report the amount needed. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("guest buffer too small: size %d bytes\n", cb));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = cwDestLen * 2;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = VERR_BUFFER_OVERFLOW;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync for (unsigned i = 0, j = 0; i < cbSourceLen; ++i, ++j)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (pu8SourceText[i] != LINEFEED)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pu16DestText[j] = pu8SourceText[i]; /* latin1 < utf-16LE */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync else
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pu16DestText[j] = CARRIAGERETURN;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync ++j;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pu16DestText[j] = LINEFEED;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pu16DestText[cwDestLen - 1] = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = cwDestLen * 2;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("converted text is %.*ls\n", cwDestLen, pu16DestText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtFree(reinterpret_cast<char *>(pValue));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemEventSignal(g_ctx.waitForData);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("Returning. Status is %Rrc\n", rc));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Convert the clipboard text from the current format to Utf-16 with Windows line breaks.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * We are reading the X11 clipboard to make it available to VBox.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread clipboard X11 event thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note Callback for XtGetSelectionValue, called from vboxClipboardReadData
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic void vboxClipboardGetDataFromX11(Widget, XtPointer pClientData,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom * /* selection */, Atom *atomType,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtPointer pValue,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync long unsigned int *pcLen,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int *piFormat)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("pClientData=%p, *pcLen=%lu, *piFormat=%d\n", pClientData, *pcLen, *piFormat));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("g_ctx.requestHostFormat=%d, g_ctx.requestBufferSize=%d\n",
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.requestHostFormat, g_ctx.requestBufferSize));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned cTextLen = (*pcLen) * (*piFormat) / 8;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* The X Toolkit may have failed to get the clipboard selection for us. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (*atomType == XT_CONVERT_FAIL)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* The clipboard selection may have changed before we could get it. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (NULL == pValue)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* We grab this mutex whenever an asynchronous clipboard operation completes and while
6ef855ecf2121f708685307839f1262e0db1a024vboxsync disconnecting a client from the clipboard to stop these operations colliding. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemMutexRequest(g_ctx.asyncMutex, RT_INDEFINITE_WAIT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (reinterpret_cast<VBOXCLIPBOARDCLIENTDATA *>(pClientData) != g_ctx.pClient)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* If the client is no longer connected, just return. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtFree(reinterpret_cast<char *>(pValue));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("client is no longer connected, returning\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemMutexRelease(g_ctx.asyncMutex);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* In which format did we request the clipboard data? */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync switch (g_ctx.requestHostFormat)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync case UTF16:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardGetUtf16(pValue, cTextLen / 2, g_ctx.requestBuffer, g_ctx.requestBufferSize,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.requestActualSize);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync break;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync case CTEXT:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardGetCTextFromX11(pValue, cTextLen, g_ctx.requestBuffer, g_ctx.requestBufferSize,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.requestActualSize);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync break;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync case UTF8:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* If we are given broken Utf-8, we treat it as Latin1. Is this acceptable? */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync size_t cStringLen;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync char *pu8SourceText = reinterpret_cast<char *>(pValue);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if ((g_ctx.requestHostFormat == UTF8)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync && (RTStrUniLenEx(pu8SourceText, *pcLen, &cStringLen) == VINF_SUCCESS))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardGetUtf8FromX11(pValue, cTextLen, g_ctx.requestBuffer, g_ctx.requestBufferSize,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.requestActualSize);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync break;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync else
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardGetLatin1FromX11(pValue, cTextLen, g_ctx.requestBuffer, g_ctx.requestBufferSize,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.requestActualSize);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync break;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync default:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFunc (("bad target format\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtFree(reinterpret_cast<char *>(pValue));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemMutexRelease(g_ctx.asyncMutex);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.notifyGuest = true;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemMutexRelease(g_ctx.asyncMutex);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Find out what targets the current X11 clipboard holder can handle. We are
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * reading the X11 clipboard to make it available to VBox.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread clipboard X11 event thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note Callback for XtGetSelectionValue, called from vboxClipboardPollX11ForTargets
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic void vboxClipboardGetTargetsFromX11(Widget, XtPointer pClientData,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom * /* selection */,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom *atomType,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtPointer pValue,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync long unsigned int *pcLen,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int *piFormat)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom *atomTargets = reinterpret_cast<Atom *>(pValue);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned cAtoms = *pcLen;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_eClipboardFormats eBestTarget = INVALID;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom atomBestTarget = None;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Log3 (("%s: called\n", __PRETTY_FUNCTION__));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (*atomType == XT_CONVERT_FAIL)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFunc (("reading clipboard from host, X toolkit failed to convert the selection\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* We grab this mutex whenever an asynchronous clipboard operation completes and while
6ef855ecf2121f708685307839f1262e0db1a024vboxsync disconnecting a client from the clipboard to stop these operations colliding. */
30dced101cb78acf27e752f25c88c1f637539a1evboxsync RTSemMutexRequest(g_ctx.asyncMutex, RT_INDEFINITE_WAIT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (reinterpret_cast<VBOXCLIPBOARDCLIENTDATA *>(pClientData) != g_ctx.pClient)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* If the client is no longer connected, just return. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("client is no longer connected, returning\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemMutexRelease(g_ctx.asyncMutex);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync for (unsigned i = 0; i < cAtoms; ++i)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync for (unsigned j = 0; j != g_ctx.formatList.size(); ++j)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (g_ctx.formatList[j].atom == atomTargets[i])
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (eBestTarget < g_ctx.formatList[j].format)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync eBestTarget = g_ctx.formatList[j].format;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync atomBestTarget = g_ctx.formatList[j].atom;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync break;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (g_debugClipboard)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync char *szAtomName = XGetAtomName(XtDisplay(g_ctx.widget), atomTargets[i]);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (szAtomName != 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Log2 (("%s: the host offers target %s\n", __PRETTY_FUNCTION__,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync szAtomName));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XFree(szAtomName);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
441579693f771e49eb05f2bd20c316232155675bvboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.atomHostTextFormat = atomBestTarget;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if ((eBestTarget != g_ctx.hostTextFormat) || (g_ctx.notifyGuest == true))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync uint32_t u32Formats = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (g_debugClipboard)
441579693f771e49eb05f2bd20c316232155675bvboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (atomBestTarget != None)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync char *szAtomName = XGetAtomName(XtDisplay(g_ctx.widget), atomBestTarget);
441579693f771e49eb05f2bd20c316232155675bvboxsync Log2 (("%s: switching to host text target %s. Available targets are:\n",
6ef855ecf2121f708685307839f1262e0db1a024vboxsync __PRETTY_FUNCTION__, szAtomName));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XFree(szAtomName);
441579693f771e49eb05f2bd20c316232155675bvboxsync }
441579693f771e49eb05f2bd20c316232155675bvboxsync else
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Log2(("%s: no supported host text target found. Available targets are:\n",
6ef855ecf2121f708685307839f1262e0db1a024vboxsync __PRETTY_FUNCTION__));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync for (unsigned i = 0; i < cAtoms; ++i)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync char *szAtomName = XGetAtomName(XtDisplay(g_ctx.widget), atomTargets[i]);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (szAtomName != 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Log2 (("%s: %s\n", __PRETTY_FUNCTION__, szAtomName));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XFree(szAtomName);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.hostTextFormat = eBestTarget;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (eBestTarget != INVALID)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxSvcClipboardReportMsg (g_ctx.pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync u32Formats);
441579693f771e49eb05f2bd20c316232155675bvboxsync g_ctx.notifyGuest = false;
441579693f771e49eb05f2bd20c316232155675bvboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtFree(reinterpret_cast<char *>(pValue));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemMutexRelease(g_ctx.asyncMutex);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * This callback is called every 200ms to check the contents of the X11 clipboard.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread clipboard X11 event thread
441579693f771e49eb05f2bd20c316232155675bvboxsync * @note Callback for XtAppAddTimeOut, called from vboxClipboardThread and
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * recursively retriggered
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic void vboxClipboardPollX11ForTargets(XtPointer /* pUserData */, XtIntervalId * /* hTimerId */)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Log3 (("%s: called\n", __PRETTY_FUNCTION__));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Get the current clipboard contents */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (g_ctx.eOwner == HOST && g_ctx.pClient != 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Log3 (("%s: requesting the targets that the host clipboard offers\n",
6ef855ecf2121f708685307839f1262e0db1a024vboxsync __PRETTY_FUNCTION__));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtGetSelectionValue(g_ctx.widget, g_ctx.atomClipboard, g_ctx.atomTargets,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardGetTargetsFromX11, reinterpret_cast<XtPointer>(g_ctx.pClient),
6ef855ecf2121f708685307839f1262e0db1a024vboxsync CurrentTime);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Re-arm our timer */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtAppAddTimeOut(g_ctx.appContext, 200 /* ms */, vboxClipboardPollX11ForTargets, 0);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/** We store information about the target formats we can handle in a global vector for internal
6ef855ecf2121f708685307839f1262e0db1a024vboxsync use. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic void vboxClipboardAddFormat(const char *pszName, g_eClipboardFormats eFormat,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned guestFormat)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync VBOXCLIPBOARDFORMAT sFormat;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Get an atom from the X server for that target format */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom atomFormat = XInternAtom(XtDisplay(g_ctx.widget), pszName, false);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync sFormat.atom = atomFormat;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync sFormat.format = eFormat;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync sFormat.guestFormat = guestFormat;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.formatList.push_back(sFormat);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlow (("vboxClipboardAddFormat: added format %s (%d)\n", pszName, eFormat));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * The main loop of our clipboard reader.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread clipboard X11 event thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic int vboxClipboardThread(RTTHREAD self, void * /* pvUser */)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRel(("Shared clipboard: starting host clipboard thread\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Set up a timer to poll the host clipboard */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtAppAddTimeOut(g_ctx.appContext, 200 /* ms */, vboxClipboardPollX11ForTargets, 0);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtAppMainLoop(g_ctx.appContext);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.formatList.clear();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRel(("Shared clipboard: host clipboard thread terminated successfully\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return VINF_SUCCESS;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/** X11 specific initialisation for the shared clipboard. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncint vboxClipboardInitX11 (void)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Create a window and make it a clipboard viewer. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int cArgc = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync char *pcArgv = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int rc = VINF_SUCCESS;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync // static String szFallbackResources[] = { (char*)"*.width: 1", (char*)"*.height: 1", NULL };
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Display *pDisplay;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Make sure we are thread safe */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtToolkitThreadInitialize();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Set up the Clipbard application context and main window. We call all these functions
6ef855ecf2121f708685307839f1262e0db1a024vboxsync directly instead of calling XtOpenApplication() so that we can fail gracefully if we
6ef855ecf2121f708685307839f1262e0db1a024vboxsync can't get an X11 display. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtToolkitInitialize();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.appContext = XtCreateApplicationContext();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync // XtAppSetFallbackResources(g_ctx.appContext, szFallbackResources);
939e2ecb812c6402abcc63e7d615c5444acfd02evboxsync pDisplay = XtOpenDisplay(g_ctx.appContext, 0, 0, "VBoxClipboard", 0, 0, &cArgc, &pcArgv);
383d5bd7b4b12176fbba2defc6c162e5b84e8ac0vboxsync if (NULL == pDisplay)
383d5bd7b4b12176fbba2defc6c162e5b84e8ac0vboxsync {
383d5bd7b4b12176fbba2defc6c162e5b84e8ac0vboxsync LogRel(("Shared clipboard: failed to connect to the host clipboard - the window system may not be running.\n"));
383d5bd7b4b12176fbba2defc6c162e5b84e8ac0vboxsync rc = VERR_NOT_SUPPORTED;
383d5bd7b4b12176fbba2defc6c162e5b84e8ac0vboxsync }
383d5bd7b4b12176fbba2defc6c162e5b84e8ac0vboxsync if (RT_SUCCESS(rc))
383d5bd7b4b12176fbba2defc6c162e5b84e8ac0vboxsync {
383d5bd7b4b12176fbba2defc6c162e5b84e8ac0vboxsync g_ctx.widget = XtVaAppCreateShell(0, "VBoxClipboard", applicationShellWidgetClass, pDisplay,
383d5bd7b4b12176fbba2defc6c162e5b84e8ac0vboxsync XtNwidth, 1, XtNheight, 1, NULL);
383d5bd7b4b12176fbba2defc6c162e5b84e8ac0vboxsync if (NULL == g_ctx.widget)
939e2ecb812c6402abcc63e7d615c5444acfd02evboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRel(("Shared clipboard: failed to construct the X11 window for the host clipboard manager.\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = VERR_NO_MEMORY;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
441579693f771e49eb05f2bd20c316232155675bvboxsync if (RT_SUCCESS(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtSetMappedWhenManaged(g_ctx.widget, false);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtRealizeWidget(g_ctx.widget);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Get hold of the atoms which we need */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.atomClipboard = XInternAtom(XtDisplay(g_ctx.widget), "CLIPBOARD", false /* only_if_exists */);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.atomPrimary = XInternAtom(XtDisplay(g_ctx.widget), "PRIMARY", false);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.atomTargets = XInternAtom(XtDisplay(g_ctx.widget), "TARGETS", false);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.atomMultiple = XInternAtom(XtDisplay(g_ctx.widget), "MULTIPLE", false);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.atomTimestamp = XInternAtom(XtDisplay(g_ctx.widget), "TIMESTAMP", false);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.atomUtf16 = XInternAtom(XtDisplay(g_ctx.widget),
6ef855ecf2121f708685307839f1262e0db1a024vboxsync "text/plain;charset=ISO-10646-UCS-2", false);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.atomUtf8 = XInternAtom(XtDisplay(g_ctx.widget), "UTF_STRING", false);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* And build up the vector of supported formats */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.atomCText = XInternAtom(XtDisplay(g_ctx.widget), "COMPOUND_TEXT", false);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* And build up the vector of supported formats */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (!g_testUtf8 && !g_testCText)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardAddFormat("text/plain;charset=ISO-10646-UCS-2", UTF16,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (!g_testUtf16 && !g_testCText)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardAddFormat("UTF8_STRING", UTF8,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardAddFormat("text/plain;charset=UTF-8", UTF8,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardAddFormat("text/plain;charset=utf-8", UTF8,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardAddFormat("STRING", UTF8,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardAddFormat("TEXT", UTF8,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardAddFormat("text/plain", UTF8,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (!g_testUtf16 && !g_testUtf8)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardAddFormat("COMPOUND_TEXT", CTEXT,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return rc;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Initialise the host side of the shared clipboard.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note Called by the HGCM clipboard service
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread HGCM clipboard service thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncint vboxClipboardInit (void)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int rc;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (!RTEnvGet("DISPLAY"))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /*
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * If we don't find the DISPLAY environment variable we assume that we are not
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * connected to an X11 server. Don't actually try to do this then, just fail
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * silently and report success on every call. This is important for VBoxHeadless.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc(("no X11 detected -- host clipboard disabled\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_fHaveX11 = false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return VINF_SUCCESS;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RTEnvGet("VBOX_CBTEST_UTF16"))
441579693f771e49eb05f2bd20c316232155675bvboxsync {
441579693f771e49eb05f2bd20c316232155675bvboxsync g_testUtf16 = true;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRel(("Host clipboard: testing Utf16\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync else if (RTEnvGet("VBOX_CBTEST_UTF8"))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_testUtf8 = true;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRel(("Host clipboard: testing Utf8\n"));
441579693f771e49eb05f2bd20c316232155675bvboxsync }
441579693f771e49eb05f2bd20c316232155675bvboxsync else if (RTEnvGet("VBOX_CBTEST_CTEXT"))
441579693f771e49eb05f2bd20c316232155675bvboxsync {
441579693f771e49eb05f2bd20c316232155675bvboxsync g_testCText = true;
441579693f771e49eb05f2bd20c316232155675bvboxsync LogRel(("Host clipboard: testing compound text\n"));
441579693f771e49eb05f2bd20c316232155675bvboxsync }
441579693f771e49eb05f2bd20c316232155675bvboxsync else if (RTEnvGet("VBOX_CBDEBUG"))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_debugClipboard = true;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRel(("Host clipboard: enabling additional debugging output\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_fHaveX11 = true;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRel(("Initializing host clipboard service\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemEventCreate(&g_ctx.waitForData);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemMutexCreate(&g_ctx.asyncMutex);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardInitX11();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = RTThreadCreate(&g_ctx.thread, vboxClipboardThread, 0, 0,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_FAILURE(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRel(("Failed to start the host shared clipboard thread.\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_FAILURE(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemEventDestroy(g_ctx.waitForData);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemMutexDestroy(g_ctx.asyncMutex);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return rc;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Terminate the host side of the shared clipboard.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note Called by the HGCM clipboard service
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread HGCM clipboard service thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncvoid vboxClipboardDestroy (void)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int rc, rcThread;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned count = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XEvent ev;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /*
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Immediately return if we are not connected to the host X server.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (!g_fHaveX11)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRel(("vboxClipboardDestroy: shutting down host clipboard\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Drop the reference to the client, in case it is still there. This will
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * cause any outstanding clipboard data requests from X11 to fail
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * immediately. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.pClient = NULL;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Set the termination flag. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtAppSetExitFlag(g_ctx.appContext);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Wake up the event loop */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync memset(&ev, 0, sizeof(ev));
441579693f771e49eb05f2bd20c316232155675bvboxsync ev.xclient.type = ClientMessage;
441579693f771e49eb05f2bd20c316232155675bvboxsync ev.xclient.format = 8;
441579693f771e49eb05f2bd20c316232155675bvboxsync XSendEvent(XtDisplay(g_ctx.widget), XtWindow(g_ctx.widget), false, 0, &ev);
441579693f771e49eb05f2bd20c316232155675bvboxsync XFlush(XtDisplay(g_ctx.widget));
441579693f771e49eb05f2bd20c316232155675bvboxsync if (g_ctx.eOwner == GUEST)
441579693f771e49eb05f2bd20c316232155675bvboxsync /* X11 may be waiting for data from VBox. At this point it is no
441579693f771e49eb05f2bd20c316232155675bvboxsync * longer going to arrive, and we must release it to allow the event
441579693f771e49eb05f2bd20c316232155675bvboxsync * loop to terminate. In this case the buffer where VBox would have
441579693f771e49eb05f2bd20c316232155675bvboxsync * written the clipboard data will still be empty and we will just
441579693f771e49eb05f2bd20c316232155675bvboxsync * return "no data" to X11. Any subsequent attempts to get the data
441579693f771e49eb05f2bd20c316232155675bvboxsync * from VBox will fail immediately as the client reference is gone. */
441579693f771e49eb05f2bd20c316232155675bvboxsync RTSemEventSignal(g_ctx.waitForData);
441579693f771e49eb05f2bd20c316232155675bvboxsync do
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = RTThreadWait(g_ctx.thread, 1000, &rcThread);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync ++count;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5)));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync } while ((VERR_TIMEOUT == rc) && (count < 300));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_SUCCESS(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /*
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * No one should be waiting on this by now. Justification:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * - Case 1: VBox is waiting for data from X11:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Not possible, as it would be waiting on this thread.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * - Case 2: X11 is waiting for data from VBox:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Not possible, as we checked that the X11 event thread exited
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * successfully.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemEventDestroy(g_ctx.waitForData);
441579693f771e49eb05f2bd20c316232155675bvboxsync RTSemMutexDestroy(g_ctx.asyncMutex);
441579693f771e49eb05f2bd20c316232155675bvboxsync AssertRC(rcThread);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync else
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRel(("vboxClipboardDestroy: rc=%Rrc\n", rc));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtCloseDisplay(XtDisplay(g_ctx.widget));
6c6531128b39093daeac902a8705c0bdf15b31ccvboxsync LogFlowFunc(("returning.\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Connect a guest the shared clipboard.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pClient Structure containing context information about the guest system
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @returns RT status code
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note Called by the HGCM clipboard service
441579693f771e49eb05f2bd20c316232155675bvboxsync * @thread HGCM clipboard service thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncint vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /*
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Immediately return if we are not connected to the host X server.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (!g_fHaveX11)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return VINF_SUCCESS;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlow(("vboxClipboardConnect\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Only one client is supported for now */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync AssertLogRelReturn(g_ctx.pClient == 0, VERR_NOT_SUPPORTED);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pClient->pCtx = &g_ctx;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pClient->pCtx->pClient = pClient;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.eOwner = HOST;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.notifyGuest = true;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return VINF_SUCCESS;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Synchronise the contents of the host clipboard with the guest, called
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * after a save and restore of the guest.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note Called by the HGCM clipboard service
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread HGCM clipboard service thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncint vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA *pClient)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /*
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Immediately return if we are not connected to the host X server.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (!g_fHaveX11)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return VINF_SUCCESS;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* On a Linux host, the guest should never synchronise/cache its clipboard contents, as
6ef855ecf2121f708685307839f1262e0db1a024vboxsync we have no way of reliably telling when the host clipboard data changes. So instead
6ef855ecf2121f708685307839f1262e0db1a024vboxsync of synchronising, we tell the guest to empty its clipboard, and we set the cached
6ef855ecf2121f708685307839f1262e0db1a024vboxsync flag so that we report formats to the guest next time we poll for them. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxSvcClipboardReportMsg (g_ctx.pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, 0);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.notifyGuest = true;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return VINF_SUCCESS;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Shut down the shared clipboard service and "disconnect" the guest.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note Called by the HGCM clipboard service
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread HGCM clipboard service thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncvoid vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /*
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Immediately return if we are not connected to the host X server.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (!g_fHaveX11)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlow(("vboxClipboardDisconnect\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemMutexRequest(g_ctx.asyncMutex, RT_INDEFINITE_WAIT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.pClient = NULL;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.eOwner = NONE;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.hostTextFormat = INVALID;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.hostBitmapFormat = INVALID;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemMutexRelease(g_ctx.asyncMutex);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Satisfy a request from X11 for clipboard targets supported by VBox.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @returns true if we successfully convert the data to the format requested, false otherwise.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param atomTypeReturn The type of the data we are returning
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pValReturn A pointer to the data we are returning. This should be to memory
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * allocated by XtMalloc, which will be freed by the toolkit later
6c6531128b39093daeac902a8705c0bdf15b31ccvboxsync * @param pcLenReturn The length of the data we are returning
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param piFormatReturn The format (8bit, 16bit, 32bit) of the data we are returning
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread clipboard X11 event thread
6c6531128b39093daeac902a8705c0bdf15b31ccvboxsync * @note called by vboxClipboardConvertForX11
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic Boolean vboxClipboardConvertTargetsForX11(Atom *atomTypeReturn, XtPointer *pValReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned long *pcLenReturn, int *piFormatReturn)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned uListSize = g_ctx.formatList.size();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom *atomTargets = reinterpret_cast<Atom *>(XtMalloc((uListSize + 3) * sizeof(Atom)));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned cTargets = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("called\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync for (unsigned i = 0; i < uListSize; ++i)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if ( ((g_ctx.guestFormats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) != 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync && (g_ctx.formatList[i].guestFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync atomTargets[cTargets] = g_ctx.formatList[i].atom;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync ++cTargets;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync atomTargets[cTargets] = g_ctx.atomTargets;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync atomTargets[cTargets + 1] = g_ctx.atomMultiple;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync atomTargets[cTargets + 2] = g_ctx.atomTimestamp;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (g_debugClipboard)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync for (unsigned i = 0; i < cTargets + 3; i++)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync char *szAtomName = XGetAtomName(XtDisplay(g_ctx.widget), atomTargets[i]);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (szAtomName != 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Log2 (("%s: returning target %s\n", __PRETTY_FUNCTION__,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync szAtomName));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XFree(szAtomName);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync else
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Log(("%s: invalid atom %d in the list!\n", __PRETTY_FUNCTION__,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync atomTargets[i]));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *atomTypeReturn = XA_ATOM;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pValReturn = reinterpret_cast<XtPointer>(atomTargets);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcLenReturn = cTargets + 3;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *piFormatReturn = 32;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return true;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Reset the contents of the buffer used to pass clipboard data from VBox to X11.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * This must be done after every clipboard transfer.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic void vboxClipboardEmptyGuestBuffer(void)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (g_ctx.pClient->data.pv != 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTMemFree(g_ctx.pClient->data.pv);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.pClient->data.pv = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.pClient->data.cb = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.pClient->data.u32Format = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Satisfy a request from the host to convert the clipboard text to Utf16. We return non-zero
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * terminated text.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @returns true if we successfully convert the data to the format requested, false otherwise.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @retval atomTypeReturn The type of the data we are returning
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @retval pValReturn A pointer to the data we are returning. This should be to memory
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * allocated by XtMalloc, which will be freed by the toolkit later
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @retval pcLenReturn The length of the data we are returning
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @retval piFormatReturn The format (8bit, 16bit, 32bit) of the data we are returning
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic Boolean vboxClipboardConvertUtf16(Atom *atomTypeReturn, XtPointer *pValReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned long *pcLenReturn, int *piFormatReturn)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync PRTUTF16 pu16SrcText, pu16DestText;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync size_t cwSrcLen, cwDestLen;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int rc;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("called\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardReadDataFromVBox(&g_ctx, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if ((RT_FAILURE(rc)) || (g_ctx.pClient->data.cb == 0))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* If vboxClipboardReadDataFromVBox fails then pClient may be invalid */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc (("vboxClipboardReadDataFromVBox returned %Rrc%s\n", rc,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RT_SUCCESS(rc) ? ", g_ctx.pClient->data.cb == 0" : ""));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pu16SrcText = reinterpret_cast<PRTUTF16>(g_ctx.pClient->data.pv);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync cwSrcLen = g_ctx.pClient->data.cb / 2;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* How long will the converted text be? */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_FAILURE(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRel(("vboxClipboardConvertUtf16: clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync AssertRCReturn(rc, false);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (cwDestLen == 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("received empty clipboard data from the guest, returning false.\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pu16DestText = reinterpret_cast<PRTUTF16>(XtMalloc(cwDestLen * 2));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (pu16DestText == 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRel(("vboxClipboardConvertUtf16: failed to allocate %d bytes\n", cwDestLen * 2));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Convert the text. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_FAILURE(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRel(("vboxClipboardConvertUtf16: clipboard conversion failed. vboxClipboardUtf16WinToLin returned %Rrc. Abandoning.\n", rc));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtFree(reinterpret_cast<char *>(pu16DestText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("converted string is %.*ls. Returning.\n", cwDestLen, pu16DestText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *atomTypeReturn = g_ctx.atomUtf16;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pValReturn = reinterpret_cast<XtPointer>(pu16DestText);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcLenReturn = cwDestLen;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *piFormatReturn = 16;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return true;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Satisfy a request from the host to convert the clipboard text to Utf8.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @returns true if we successfully convert the data to the format requested, false otherwise.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param atomTypeReturn The type of the data we are returning
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pValReturn A pointer to the data we are returning. This should be to memory
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * allocated by XtMalloc, which will be freed by the toolkit later
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pcLenReturn The length of the data we are returning
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param piFormatReturn The format (8bit, 16bit, 32bit) of the data we are returning
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread clipboard X11 event thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note called by vboxClipboardConvertForX11
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic Boolean vboxClipboardConvertToUtf8ForX11(Atom *atomTypeReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtPointer *pValReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned long *pcLenReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int *piFormatReturn)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync PRTUTF16 pu16SrcText, pu16DestText;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync char *pu8DestText;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync size_t cwSrcLen, cwDestLen, cbDestLen;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int rc;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("called\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Read the clipboard data from the guest. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardReadDataFromVBox(&g_ctx, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if ((rc != VINF_SUCCESS) || (g_ctx.pClient->data.cb == 0))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* If vboxClipboardReadDataFromVBox fails then pClient may be invalid */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc (("vboxClipboardReadDataFromVBox returned %Rrc%s\n", rc,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RT_SUCCESS(rc) ? ", g_ctx.pClient->data.cb == 0" : ""));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pu16SrcText = reinterpret_cast<PRTUTF16>(g_ctx.pClient->data.pv);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync cwSrcLen = g_ctx.pClient->data.cb / 2;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* How long will the converted text be? */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_FAILURE(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync AssertRCReturn(rc, false);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (cwDestLen == 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("received empty clipboard data from the guest, returning false.\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pu16DestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwDestLen * 2));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (pu16DestText == 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 2));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Convert the text. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_FAILURE(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTMemFree(reinterpret_cast<void *>(pu16DestText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Allocate enough space, as RTUtf16ToUtf8Ex may fail if the
6ef855ecf2121f708685307839f1262e0db1a024vboxsync space is too tightly calculated. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pu8DestText = XtMalloc(cwDestLen * 4);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (pu8DestText == 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 4));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTMemFree(reinterpret_cast<void *>(pu16DestText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Convert the Utf16 string to Utf8. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = RTUtf16ToUtf8Ex(pu16DestText + 1, cwDestLen - 1, &pu8DestText, cwDestLen * 4,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync &cbDestLen);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTMemFree(reinterpret_cast<void *>(pu16DestText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_FAILURE(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc (("clipboard conversion failed. RTUtf16ToUtf8Ex() returned %Rrc. Abandoning.\n", rc));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtFree(pu8DestText);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("converted string is %.*s. Returning.\n", cbDestLen, pu8DestText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *atomTypeReturn = g_ctx.atomUtf8;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pValReturn = reinterpret_cast<XtPointer>(pu8DestText);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcLenReturn = cbDestLen;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *piFormatReturn = 8;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return true;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Satisfy a request from the host to convert the clipboard text to COMPOUND_TEXT.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @returns true if we successfully convert the data to the format requested, false otherwise.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param atomTypeReturn The type of the data we are returning
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pValReturn A pointer to the data we are returning. This should be to memory
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * allocated by XtMalloc, which will be freed by the toolkit later
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pcLenReturn The length of the data we are returning
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param piFormatReturn The format (8bit, 16bit, 32bit) of the data we are returning
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread clipboard X11 event thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note called by vboxClipboardConvertForX11
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic Boolean vboxClipboardConvertToCTextForX11(Atom *atomTypeReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtPointer *pValReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned long *pcLenReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int *piFormatReturn)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync PRTUTF16 pu16SrcText, pu16DestText;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync char *pu8DestText = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync size_t cwSrcLen, cwDestLen, cbDestLen;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XTextProperty property;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int rc;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("called\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Read the clipboard data from the guest. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardReadDataFromVBox(&g_ctx, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if ((rc != VINF_SUCCESS) || (g_ctx.pClient->data.cb == 0))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* If vboxClipboardReadDataFromVBox fails then pClient may be invalid */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc (("vboxClipboardReadDataFromVBox returned %Rrc%s\n", rc,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RT_SUCCESS(rc) ? ", g_ctx.pClient->data.cb == 0" : ""));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pu16SrcText = reinterpret_cast<PRTUTF16>(g_ctx.pClient->data.pv);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync cwSrcLen = g_ctx.pClient->data.cb / 2;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* How long will the converted text be? */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_FAILURE(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync AssertRCReturn(rc, false);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (cwDestLen == 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("received empty clipboard data from the guest, returning false.\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pu16DestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwDestLen * 2));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (pu16DestText == 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 2));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Convert the text. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_FAILURE(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTMemFree(reinterpret_cast<void *>(pu16DestText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Convert the Utf16 string to Utf8. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = RTUtf16ToUtf8Ex(pu16DestText + 1, cwDestLen - 1, &pu8DestText, 0, &cbDestLen);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTMemFree(reinterpret_cast<void *>(pu16DestText));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_FAILURE(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc (("clipboard conversion failed. RTUtf16ToUtf8Ex() returned %Rrc. Abandoning.\n", rc));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* And finally (!) convert the Utf8 text to compound text. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#ifdef RT_OS_SOLARIS
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = XmbTextListToTextProperty(XtDisplay(g_ctx.widget), &pu8DestText, 1,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XCompoundTextStyle, &property);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#else
6ef855ecf2121f708685307839f1262e0db1a024vboxsync rc = Xutf8TextListToTextProperty(XtDisplay(g_ctx.widget), &pu8DestText, 1,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XCompoundTextStyle, &property);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync#endif
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTMemFree(pu8DestText);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (rc < 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync const char *pcReason;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync switch(rc)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync case XNoMemory:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pcReason = "out of memory";
6ef855ecf2121f708685307839f1262e0db1a024vboxsync break;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync case XLocaleNotSupported:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pcReason = "locale (Utf8) not supported";
6ef855ecf2121f708685307839f1262e0db1a024vboxsync break;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync case XConverterNotFound:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pcReason = "converter not found";
6ef855ecf2121f708685307839f1262e0db1a024vboxsync break;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync default:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pcReason = "unknown error";
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogRelFunc (("Xutf8TextListToTextProperty failed. Reason: %s\n",
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pcReason));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XFree(property.value);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("converted string is %s. Returning.\n", property.value));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardEmptyGuestBuffer();
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *atomTypeReturn = property.encoding;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pValReturn = reinterpret_cast<XtPointer>(property.value);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcLenReturn = property.nitems;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *piFormatReturn = property.format;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return true;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Callback to request VBox's clipboard data for an X11 client. Called by the
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * X Toolkit.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread clipboard X11 event thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note callback for XtOwnSelection, called by vboxClipboardFormatAnnounce
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic Boolean vboxClipboardConvertForX11(Widget, Atom *atomSelection,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom *atomTarget,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Atom *atomTypeReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtPointer *pValReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync unsigned long *pcLenReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int *piFormatReturn)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_eClipboardFormats eFormat = INVALID;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Drop requests that we receive too late. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (g_ctx.eOwner != GUEST)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if ( (*atomSelection != g_ctx.atomClipboard)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync && (*atomSelection != g_ctx.atomPrimary)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync )
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("rc = false\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (g_debugClipboard)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync char *szAtomName = XGetAtomName(XtDisplay(g_ctx.widget), *atomTarget);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (szAtomName != 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Log2 (("%s: request for format %s\n", __PRETTY_FUNCTION__, szAtomName));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XFree(szAtomName);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync else
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFunc (("request for invalid target atom %d!\n", *atomTarget));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (*atomTarget == g_ctx.atomTargets)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync eFormat = TARGETS;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync else
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync for (unsigned i = 0; i != g_ctx.formatList.size(); ++i)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (g_ctx.formatList[i].atom == *atomTarget)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync eFormat = g_ctx.formatList[i].format;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync break;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync switch (eFormat)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync case TARGETS:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return vboxClipboardConvertTargetsForX11(atomTypeReturn, pValReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pcLenReturn, piFormatReturn);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync case UTF16:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return vboxClipboardConvertUtf16(atomTypeReturn, pValReturn, pcLenReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync piFormatReturn);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync case UTF8:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return vboxClipboardConvertToUtf8ForX11(atomTypeReturn, pValReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pcLenReturn, piFormatReturn);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync case CTEXT:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return vboxClipboardConvertToCTextForX11(atomTypeReturn, pValReturn,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pcLenReturn, piFormatReturn);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync default:
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFunc (("bad format\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return false;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * This is called by the X toolkit intrinsics to let us know that another
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * X11 client has taken the clipboard.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note callback for XtOwnSelection, called from vboxClipboardFormatAnnounce
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread clipboard X11 event thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncstatic void vboxClipboardReturnToX11(Widget, Atom *)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("called, giving VBox clipboard ownership\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.eOwner = HOST;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.notifyGuest = true;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * VBox is taking possession of the shared clipboard.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pClient Context data for the guest system
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param u32Formats Clipboard formats the guest is offering
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note Called by the HGCM clipboard service
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread HGCM clipboard service thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncvoid vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Formats)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /*
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Immediately return if we are not connected to the host X server.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (!g_fHaveX11)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pClient->pCtx->guestFormats = u32Formats;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("u32Formats=%d\n", u32Formats));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (u32Formats == 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* This is just an automatism, not a genuine anouncement */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("returning\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (g_ctx.eOwner == GUEST)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* We already own the clipboard, so no need to grab it, especially as that can lead
6ef855ecf2121f708685307839f1262e0db1a024vboxsync to races due to the asynchronous nature of the X11 clipboard. This event may also
6ef855ecf2121f708685307839f1262e0db1a024vboxsync have been sent out by the guest to invalidate the Windows clipboard cache. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("returning\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Log2 (("%s: giving the guest clipboard ownership\n", __PRETTY_FUNCTION__));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.eOwner = GUEST;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.hostTextFormat = INVALID;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.hostBitmapFormat = INVALID;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (XtOwnSelection(g_ctx.widget, g_ctx.atomClipboard, CurrentTime, vboxClipboardConvertForX11,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardReturnToX11, 0) != True)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync Log2 (("%s: returning clipboard ownership to the host\n", __PRETTY_FUNCTION__));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* We set this so that the guest gets notified when we take the clipboard, even if no
6ef855ecf2121f708685307839f1262e0db1a024vboxsync guest formats are found which we understand. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.notifyGuest = true;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.eOwner = HOST;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtOwnSelection(g_ctx.widget, g_ctx.atomPrimary, CurrentTime, vboxClipboardConvertForX11,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync NULL, 0);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc(("returning\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Called when VBox wants to read the X11 clipboard.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pClient Context information about the guest VM
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param u32Format The format that the guest would like to receive the data in
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pv Where to write the data to
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param cb The size of the buffer to write the data to
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pcbActual Where to write the actual size of the written data
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note Called by the HGCM clipboard service
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread HGCM clipboard service thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncint vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Format, void *pv,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync uint32_t cb, uint32_t *pcbActual)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /*
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Immediately return if we are not connected to the host X server.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (!g_fHaveX11)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* no data available */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return VINF_SUCCESS;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("u32Format = %d, cb = %d\n", u32Format, cb));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /*
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * The guest wants to read data in the given format.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (g_ctx.hostTextFormat == INVALID)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* No data available. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return VERR_NO_DATA; /* The guest thinks we have data and we don't */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* No one else (VBox or X11) should currently be waiting. The first because
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * requests from VBox are serialised and the second because X11 previously
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * grabbed the clipboard, so it should not be waiting for data from us. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync AssertLogRelReturn (ASMAtomicCmpXchgU32(&g_ctx.waiter, 1, 0), VERR_DEADLOCK);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.requestHostFormat = g_ctx.hostTextFormat;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.requestBuffer = pv;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.requestBufferSize = cb;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.requestActualSize = pcbActual;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Initially set the size of the data read to zero in case we fail
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * somewhere. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *pcbActual = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Send out a request for the data to the current clipboard owner */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync XtGetSelectionValue(g_ctx.widget, g_ctx.atomClipboard, g_ctx.atomHostTextFormat,
6ef855ecf2121f708685307839f1262e0db1a024vboxsync vboxClipboardGetDataFromX11, reinterpret_cast<XtPointer>(g_ctx.pClient),
6ef855ecf2121f708685307839f1262e0db1a024vboxsync CurrentTime);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* When the data arrives, the vboxClipboardGetDataFromX11 callback will be called. The
6ef855ecf2121f708685307839f1262e0db1a024vboxsync callback will signal the event semaphore when it has processed the data for us. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync int rc = RTSemEventWait(g_ctx.waitForData, RT_INDEFINITE_WAIT);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (RT_FAILURE(rc))
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.waiter = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return rc;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync g_ctx.waiter = 0;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync else
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return VERR_NOT_IMPLEMENTED;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return VINF_SUCCESS;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync/**
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * Called when we have requested data from VBox and that data has arrived.
6ef855ecf2121f708685307839f1262e0db1a024vboxsync *
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pClient Context information about the guest VM
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param pv Buffer to which the data was written
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param cb The size of the data written
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @param u32Format The format of the data written
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @note Called by the HGCM clipboard service
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * @thread HGCM clipboard service thread
6ef855ecf2121f708685307839f1262e0db1a024vboxsync */
6ef855ecf2121f708685307839f1262e0db1a024vboxsyncvoid vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient, void *pv, uint32_t cb, uint32_t u32Format)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync{
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (!g_fHaveX11)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync return;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync LogFlowFunc (("called\n"));
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync /* Assert that no other transfer is in process (requests are serialised)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync * or has not cleaned up properly. */
6ef855ecf2121f708685307839f1262e0db1a024vboxsync AssertLogRelReturnVoid ( pClient->data.pv == NULL
6ef855ecf2121f708685307839f1262e0db1a024vboxsync && pClient->data.cb == 0
6ef855ecf2121f708685307839f1262e0db1a024vboxsync && pClient->data.u32Format == 0);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (cb > 0)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pClient->data.pv = RTMemAlloc (cb);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync if (pClient->data.pv)
6ef855ecf2121f708685307839f1262e0db1a024vboxsync {
6ef855ecf2121f708685307839f1262e0db1a024vboxsync memcpy (pClient->data.pv, pv, cb);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pClient->data.cb = cb;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync pClient->data.u32Format = u32Format;
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync }
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync RTSemEventSignal(g_ctx.waitForData);
6ef855ecf2121f708685307839f1262e0db1a024vboxsync}
6ef855ecf2121f708685307839f1262e0db1a024vboxsync
6ef855ecf2121f708685307839f1262e0db1a024vboxsync