Index: /trunk/src/VBox/HostServices/SharedClipboard/Makefile.kmk
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/Makefile.kmk	(revision 78159)
+++ /trunk/src/VBox/HostServices/SharedClipboard/Makefile.kmk	(revision 78160)
@@ -34,9 +34,9 @@
 	VBoxSharedClipboardSvc.cpp
 VBoxSharedClipboard_SOURCES.win = \
-	VBoxClipboard-win.cpp \
+	VBoxSharedClipboardSvc-win.cpp \
 	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-win.cpp \
 	VBoxSharedClipboardSvc.rc
 VBoxSharedClipboard_SOURCES.darwin = \
-	darwin.cpp \
+	VBoxSharedClipboardSvc-darwin.cpp \
 	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp \
 	darwin-pasteboard.cpp
@@ -44,10 +44,10 @@
  ifndef VBOX_HEADLESS
   VBoxSharedClipboard_SOURCES += \
-  	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp \
-  	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp \
-  	x11-clipboard.cpp
+	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp \
+	$(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp \
+	VBoxSharedClipboardSvc-x11.cpp
  else
   VBoxSharedClipboard_SOURCES += \
-  	x11-stub.cpp
+	VBoxSharedClipboardSvc-x11-stubs.cpp
  endif
 endif
@@ -80,5 +80,5 @@
  tstClipboardX11-2_TEMPLATE = VBOXR3TSTEXE
  tstClipboardX11-2_DEFS     = VBOX_WITH_HGCM TESTCASE
- tstClipboardX11-2_SOURCES  = x11-clipboard.cpp
+ tstClipboardX11-2_SOURCES  = VBoxSharedClipboardSvc-x11.cpp
  tstClipboardX11-2_LIBS     = $(LIB_RUNTIME)
  tstClipboardX11-2_CLEANS   = $(tstClipboardX11-2_0_OUTDIR)/tstClipboardX11-2.run
Index: unk/src/VBox/HostServices/SharedClipboard/VBoxClipboard-win.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxClipboard-win.cpp	(revision 78159)
+++ 	(revision )
@@ -1,1060 +1,0 @@
-/* $Id$ */
-/** @file
- * Shared Clipboard Service - Win32 host.
- */
-
-/*
- * Copyright (C) 2006-2019 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*********************************************************************************************************************************
-*   Header Files                                                                                                                 *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
-#include <iprt/win/windows.h>
-
-#include <VBox/HostServices/VBoxClipboardSvc.h>
-#include <VBox/GuestHost/SharedClipboard-win.h>
-
-#include <iprt/alloc.h>
-#include <iprt/string.h>
-#include <iprt/asm.h>
-#include <iprt/assert.h>
-#include <iprt/thread.h>
-#include <iprt/ldr.h>
-#include <process.h>
-
-#include "VBoxClipboard.h"
-
-/** Static window class name. */
-static char s_szClipWndClassName[] = VBOX_CLIPBOARD_WNDCLASS_NAME;
-
-/*********************************************************************************************************************************
-*   Internal Functions                                                                                                           *
-*********************************************************************************************************************************/
-static int ConvertCFHtmlToMime(const char *pszSource, const uint32_t cch, char **ppszOutput, uint32_t *pch);
-static int ConvertMimeToCFHTML(const char *pszSource, size_t cb, char **ppszOutput, uint32_t *pcbOutput);
-static bool IsWindowsHTML(const char *source);
-static int vboxClipboardSyncInternal(PVBOXCLIPBOARDCONTEXT pCtx);
-
-struct _VBOXCLIPBOARDCONTEXT
-{
-    /** Handle for window message handling thread. */
-    RTTHREAD                 hThread;
-    /** Event which gets triggered if the host clipboard needs to render its data. */
-    HANDLE                   hRenderEvent;
-    /** Structure for keeping and communicating with client data (from the guest). */
-    PVBOXCLIPBOARDCLIENTDATA pClient;
-    /** Windows-specific context data. */
-    VBOXCLIPBOARDWINCTX      Win;
-};
-
-/* Only one client is supported. There seems to be no need for more clients. */
-static VBOXCLIPBOARDCONTEXT g_ctx;
-
-
-#ifdef LOG_ENABLED
-static void vboxClipboardDump(const void *pv, size_t cb, uint32_t u32Format)
-{
-    if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
-    {
-        LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT:\n"));
-        if (pv && cb)
-            LogFunc(("%ls\n", pv));
-        else
-            LogFunc(("%p %zu\n", pv, cb));
-    }
-    else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
-        LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n"));
-    else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_HTML)
-    {
-        LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_HTML:\n"));
-        if (pv && cb)
-        {
-            LogFunc(("%s\n", pv));
-
-            //size_t cb = RTStrNLen(pv, );
-            char *pszBuf = (char *)RTMemAllocZ(cb + 1);
-            RTStrCopy(pszBuf, cb + 1, (const char *)pv);
-            for (size_t off = 0; off < cb; ++off)
-            {
-                if (pszBuf[off] == '\n' || pszBuf[off] == '\r')
-                    pszBuf[off] = ' ';
-            }
-
-            LogFunc(("%s\n", pszBuf));
-            RTMemFree(pszBuf);
-        }
-        else
-            LogFunc(("%p %zu\n", pv, cb));
-    }
-    else
-        LogFunc(("Invalid format %02X\n", u32Format));
-}
-#else  /* !LOG_ENABLED */
-# define vboxClipboardDump(__pv, __cb, __format) do { NOREF(__pv); NOREF(__cb); NOREF(__format); } while (0)
-#endif /* !LOG_ENABLED */
-
-/** @todo Someone please explain the protocol wrt overflows...  */
-static void vboxClipboardGetData (uint32_t u32Format, const void *pvSrc, uint32_t cbSrc,
-                                  void *pvDst, uint32_t cbDst, uint32_t *pcbActualDst)
-{
-    LogFlow(("vboxClipboardGetData cbSrc = %d, cbDst = %d\n", cbSrc, cbDst));
-
-    if (   u32Format == VBOX_SHARED_CLIPBOARD_FMT_HTML
-        && IsWindowsHTML((const char *)pvSrc))
-    {
-        /** @todo r=bird: Why the double conversion? */
-        char *pszBuf = NULL;
-        uint32_t cbBuf = 0;
-        int rc = ConvertCFHtmlToMime((const char*)pvSrc, cbSrc, &pszBuf, &cbBuf);
-        if (RT_SUCCESS(rc))
-        {
-            *pcbActualDst = cbBuf;
-            if (cbBuf > cbDst)
-            {
-                /* Do not copy data. The dst buffer is not enough. */
-                RTMemFree(pszBuf);
-                return;
-            }
-            memcpy(pvDst, pszBuf, cbBuf);
-            RTMemFree(pszBuf);
-        }
-        else
-            *pcbActualDst = 0;
-    }
-    else
-    {
-        *pcbActualDst = cbSrc;
-
-        if (cbSrc > cbDst)
-        {
-            /* Do not copy data. The dst buffer is not enough. */
-            return;
-        }
-
-        memcpy(pvDst, pvSrc, cbSrc);
-    }
-
-    vboxClipboardDump(pvDst, cbSrc, u32Format);
-
-    return;
-}
-
-static int vboxClipboardReadDataFromClient (VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format)
-{
-    Assert(pCtx->pClient);
-    Assert(pCtx->hRenderEvent);
-    Assert(pCtx->pClient->data.pv == NULL && pCtx->pClient->data.cb == 0 && pCtx->pClient->data.u32Format == 0);
-
-    LogFlow(("vboxClipboardReadDataFromClient u32Format = %02X\n", u32Format));
-
-    ResetEvent (pCtx->hRenderEvent);
-
-    vboxSvcClipboardReportMsg (pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Format);
-
-    DWORD ret = WaitForSingleObject(pCtx->hRenderEvent, INFINITE);
-    LogFlow(("vboxClipboardReadDataFromClient wait completed, ret 0x%08X, err %d\n",
-             ret, GetLastError())); NOREF(ret);
-
-    return VINF_SUCCESS;
-}
-
-static LRESULT CALLBACK vboxClipboardWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
-    LRESULT rc = 0;
-
-    PVBOXCLIPBOARDCONTEXT pCtx = &g_ctx;
-
-    switch (msg)
-    {
-        case WM_CLIPBOARDUPDATE:
-        {
-            Log(("WM_CLIPBOARDUPDATE\n"));
-
-            if (GetClipboardOwner() != hwnd)
-            {
-                /* Clipboard was updated by another application, retrieve formats and report back. */
-                int vboxrc = vboxClipboardSyncInternal(pCtx);
-                AssertRC(vboxrc);
-            }
-        } break;
-
-        case WM_CHANGECBCHAIN:
-        {
-            Log(("WM_CHANGECBCHAIN\n"));
-
-            if (VBoxClipboardWinIsNewAPI(&pCtx->Win.newAPI))
-            {
-                rc = DefWindowProc(hwnd, msg, wParam, lParam);
-                break;
-            }
-
-            HWND hwndRemoved = (HWND)wParam;
-            HWND hwndNext    = (HWND)lParam;
-
-            if (hwndRemoved == pCtx->Win.hWndNextInChain)
-            {
-                /* The window that was next to our in the chain is being removed.
-                 * Relink to the new next window.
-                 */
-                pCtx->Win.hWndNextInChain = hwndNext;
-            }
-            else
-            {
-                if (pCtx->Win.hWndNextInChain)
-                {
-                    /* Pass the message further. */
-                    DWORD_PTR dwResult;
-                    rc = SendMessageTimeout(pCtx->Win.hWndNextInChain, WM_CHANGECBCHAIN, wParam, lParam, 0,
-                                            VBOX_CLIPBOARD_CBCHAIN_TIMEOUT_MS,
-                                            &dwResult);
-                    if (!rc)
-                        rc = (LRESULT)dwResult;
-                }
-            }
-        } break;
-
-        case WM_DRAWCLIPBOARD:
-        {
-            Log(("WM_DRAWCLIPBOARD\n"));
-
-            if (GetClipboardOwner() != hwnd)
-            {
-                /* Clipboard was updated by another application, retrieve formats and report back. */
-                int vboxrc = vboxClipboardSyncInternal(pCtx);
-                AssertRC(vboxrc);
-            }
-
-            if (pCtx->Win.hWndNextInChain)
-            {
-                Log(("WM_DRAWCLIPBOARD next %p\n", pCtx->Win.hWndNextInChain));
-                /* Pass the message to next windows in the clipboard chain. */
-                DWORD_PTR dwResult;
-                rc = SendMessageTimeout(pCtx->Win.hWndNextInChain, msg, wParam, lParam, 0, VBOX_CLIPBOARD_CBCHAIN_TIMEOUT_MS,
-                                        &dwResult);
-                if (!rc)
-                    rc = dwResult;
-            }
-        } break;
-
-        case WM_TIMER:
-        {
-            if (VBoxClipboardWinIsNewAPI(&pCtx->Win.newAPI))
-                break;
-
-            HWND hViewer = GetClipboardViewer();
-
-            /* Re-register ourselves in the clipboard chain if our last ping
-             * timed out or there seems to be no valid chain. */
-            if (!hViewer || pCtx->Win.oldAPI.fCBChainPingInProcess)
-            {
-                VBoxClipboardWinRemoveFromCBChain(&pCtx->Win);
-                VBoxClipboardWinAddToCBChain(&pCtx->Win);
-            }
-
-            /* Start a new ping by passing a dummy WM_CHANGECBCHAIN to be
-             * processed by ourselves to the chain. */
-            pCtx->Win.oldAPI.fCBChainPingInProcess = TRUE;
-
-            hViewer = GetClipboardViewer();
-            if (hViewer)
-                SendMessageCallback(hViewer, WM_CHANGECBCHAIN,
-                                    (WPARAM)pCtx->Win.hWndNextInChain, (LPARAM)pCtx->Win.hWndNextInChain,
-                                    VBoxClipboardWinChainPingProc, (ULONG_PTR)pCtx);
-        } break;
-
-        case WM_RENDERFORMAT:
-        {
-            /* Insert the requested clipboard format data into the clipboard. */
-            uint32_t u32Format = 0;
-
-            UINT format = (UINT)wParam;
-
-            Log(("WM_RENDERFORMAT %d\n", format));
-
-            switch (format)
-            {
-                case CF_UNICODETEXT:
-                    u32Format |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
-                    break;
-
-                case CF_DIB:
-                    u32Format |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
-                    break;
-
-                default:
-                    if (format >= 0xC000)
-                    {
-                        TCHAR szFormatName[256];
-
-                        int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR));
-
-                        if (cActual)
-                        {
-                            if (strcmp (szFormatName, "HTML Format") == 0)
-                            {
-                                u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
-                            }
-                        }
-                    }
-                    break;
-            }
-
-            if (u32Format == 0 || pCtx->pClient == NULL)
-            {
-                /* Unsupported clipboard format is requested. */
-                Log(("WM_RENDERFORMAT unsupported format requested or client is not active.\n"));
-                EmptyClipboard ();
-            }
-            else
-            {
-                int vboxrc = vboxClipboardReadDataFromClient (pCtx, u32Format);
-
-                LogFunc(("vboxClipboardReadDataFromClient vboxrc = %d, pv %p, cb %d, u32Format %d\n",
-                          vboxrc, pCtx->pClient->data.pv, pCtx->pClient->data.cb, pCtx->pClient->data.u32Format));
-
-                if (   RT_SUCCESS (vboxrc)
-                    && pCtx->pClient->data.pv != NULL
-                    && pCtx->pClient->data.cb > 0
-                    && pCtx->pClient->data.u32Format == u32Format)
-                {
-                    HANDLE hMem = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, pCtx->pClient->data.cb);
-
-                    LogFunc(("hMem %p\n", hMem));
-
-                    if (hMem)
-                    {
-                        void *pMem = GlobalLock (hMem);
-
-                        LogFunc(("pMem %p, GlobalSize %d\n", pMem, GlobalSize (hMem)));
-
-                        if (pMem)
-                        {
-                            Log(("WM_RENDERFORMAT setting data\n"));
-
-                            if (pCtx->pClient->data.pv)
-                            {
-                                memcpy (pMem, pCtx->pClient->data.pv, pCtx->pClient->data.cb);
-
-                                RTMemFree (pCtx->pClient->data.pv);
-                                pCtx->pClient->data.pv        = NULL;
-                            }
-
-                            pCtx->pClient->data.cb        = 0;
-                            pCtx->pClient->data.u32Format = 0;
-
-                            /* The memory must be unlocked before inserting to the Clipboard. */
-                            GlobalUnlock (hMem);
-
-                            /* 'hMem' contains the host clipboard data.
-                             * size is 'cb' and format is 'format'.
-                             */
-                            HANDLE hClip = SetClipboardData (format, hMem);
-
-                            LogFunc(("vboxClipboardHostEvent hClip %p\n", hClip));
-
-                            if (hClip)
-                            {
-                                /* The hMem ownership has gone to the system. Nothing to do. */
-                                break;
-                            }
-                        }
-
-                        GlobalFree (hMem);
-                    }
-                }
-
-                RTMemFree (pCtx->pClient->data.pv);
-                pCtx->pClient->data.pv        = NULL;
-                pCtx->pClient->data.cb        = 0;
-                pCtx->pClient->data.u32Format = 0;
-
-                /* Something went wrong. */
-                VBoxClipboardWinClear();
-            }
-        } break;
-
-        case WM_RENDERALLFORMATS:
-        {
-            Log(("WM_RENDERALLFORMATS\n"));
-
-            /* Do nothing. The clipboard formats will be unavailable now, because the
-             * windows is to be destroyed and therefore the guest side becomes inactive.
-             */
-            int vboxrc = VBoxClipboardWinOpen(hwnd);
-            if (RT_SUCCESS(vboxrc))
-            {
-                VBoxClipboardWinClear();
-                VBoxClipboardWinClose();
-            }
-            else
-            {
-                LogFlow(("vboxClipboardWndProc: WM_RENDERALLFORMATS: error in open clipboard. hwnd: %x, rc: %Rrc\n", hwnd, vboxrc));
-            }
-        } break;
-
-        case VBOX_CLIPBOARD_WM_SET_FORMATS:
-        {
-            if (pCtx->pClient == NULL || pCtx->pClient->fMsgFormats)
-            {
-                /* Host has pending formats message. Ignore the guest announcement,
-                 * because host clipboard has more priority.
-                 */
-                Log(("VBOX_CLIPBOARD_WM_SET_FORMATS ignored\n"));
-                break;
-            }
-
-            /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */
-            uint32_t u32Formats = (uint32_t)lParam;
-
-            Log(("VBOX_CLIPBOARD_WM_SET_FORMATS: u32Formats=%02X\n", u32Formats));
-
-            int vboxrc = VBoxClipboardWinOpen(hwnd);
-            if (RT_SUCCESS(vboxrc))
-            {
-                VBoxClipboardWinClear();
-
-                Log(("VBOX_CLIPBOARD_WM_SET_FORMATS emptied clipboard\n"));
-
-                HANDLE hClip = NULL;
-
-                if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
-                    hClip = SetClipboardData(CF_UNICODETEXT, NULL);
-
-                if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
-                    hClip = SetClipboardData(CF_DIB, NULL);
-
-                if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
-                {
-                    UINT format = RegisterClipboardFormat ("HTML Format");
-                    if (format != 0)
-                    {
-                        hClip = SetClipboardData (format, NULL);
-                    }
-                }
-
-                VBoxClipboardWinClose();
-
-                LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS: hClip=%p, lastErr=%ld\n", hClip, GetLastError ()));
-            }
-        } break;
-
-        case WM_DESTROY:
-        {
-            /* MS recommends to remove from Clipboard chain in this callback. */
-            VBoxClipboardWinRemoveFromCBChain(&pCtx->Win);
-            if (pCtx->Win.oldAPI.timerRefresh)
-            {
-                Assert(pCtx->Win.hWnd);
-                KillTimer(pCtx->Win.hWnd, 0);
-            }
-            PostQuitMessage(0);
-        } break;
-
-        default:
-        {
-            Log(("WM_ %p\n", msg));
-            rc = DefWindowProc(hwnd, msg, wParam, lParam);
-        }
-    }
-
-    Log(("WM_ rc %d\n", rc));
-    return rc;
-}
-
-DECLCALLBACK(int) VBoxClipboardThread (RTTHREAD hThreadSelf, void *pvUser)
-{
-    RT_NOREF2(hThreadSelf, pvUser);
-    /* Create a window and make it a clipboard viewer. */
-    int rc = VINF_SUCCESS;
-
-    LogFlow(("VBoxClipboardThread\n"));
-
-    const PVBOXCLIPBOARDCONTEXT pCtx = &g_ctx;
-
-    HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
-
-    /* Register the Window Class. */
-    WNDCLASS wc;
-    RT_ZERO(wc);
-
-    wc.style         = CS_NOCLOSE;
-    wc.lpfnWndProc   = vboxClipboardWndProc;
-    wc.hInstance     = hInstance;
-    wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
-    wc.lpszClassName = s_szClipWndClassName;
-
-    ATOM atomWindowClass = RegisterClass(&wc);
-
-    if (atomWindowClass == 0)
-    {
-        Log(("Failed to register window class\n"));
-        rc = VERR_NOT_SUPPORTED;
-    }
-    else
-    {
-        /* Create the window. */
-        pCtx->Win.hWnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
-                                         s_szClipWndClassName, s_szClipWndClassName,
-                                         WS_POPUPWINDOW,
-                                         -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
-        if (pCtx->Win.hWnd == NULL)
-        {
-            Log(("Failed to create window\n"));
-            rc = VERR_NOT_SUPPORTED;
-        }
-        else
-        {
-            SetWindowPos(pCtx->Win.hWnd, HWND_TOPMOST, -200, -200, 0, 0,
-                         SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
-
-            VBoxClipboardWinAddToCBChain(&pCtx->Win);
-            if (!VBoxClipboardWinIsNewAPI(&pCtx->Win.newAPI))
-                pCtx->Win.oldAPI.timerRefresh = SetTimer(pCtx->Win.hWnd, 0, 10 * 1000, NULL);
-
-            MSG msg;
-            BOOL msgret = 0;
-            while ((msgret = GetMessage(&msg, NULL, 0, 0)) > 0)
-            {
-                TranslateMessage(&msg);
-                DispatchMessage(&msg);
-            }
-            /*
-            * Window procedure can return error,
-            * but this is exceptional situation
-            * that should be identified in testing
-            */
-            Assert(msgret >= 0);
-            Log(("VBoxClipboardThread Message loop finished. GetMessage returned %d, message id: %d \n", msgret, msg.message));
-        }
-    }
-
-    pCtx->Win.hWnd = NULL;
-
-    if (atomWindowClass != 0)
-    {
-        UnregisterClass (s_szClipWndClassName, hInstance);
-        atomWindowClass = 0;
-    }
-
-    return 0;
-}
-
-/**
- * Synchronizes the host and the guest clipboard formats by sending all supported host clipboard
- * formats to the guest.
- *
- * @returns VBox status code.
- * @param   pCtx                Clipboard context to synchronize.
- */
-static int vboxClipboardSyncInternal(PVBOXCLIPBOARDCONTEXT pCtx)
-{
-    uint32_t uFormats;
-    int rc = VBoxClipboardWinGetFormats(&pCtx->Win, &uFormats);
-    if (RT_SUCCESS(rc))
-        vboxSvcClipboardReportMsg(pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, uFormats);
-
-    return rc;
-}
-
-/*
- * Public platform dependent functions.
- */
-int vboxClipboardInit (void)
-{
-    int rc = VINF_SUCCESS;
-
-    RT_ZERO(g_ctx);
-
-    /* Check that new Clipboard API is available. */
-    VBoxClipboardWinCheckAndInitNewAPI(&g_ctx.Win.newAPI);
-
-    g_ctx.hRenderEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-
-    rc = RTThreadCreate (&g_ctx.hThread, VBoxClipboardThread, NULL, 65536,
-                         RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
-
-    if (RT_FAILURE (rc))
-    {
-        CloseHandle (g_ctx.hRenderEvent);
-    }
-
-    return rc;
-}
-
-void vboxClipboardDestroy (void)
-{
-    Log(("vboxClipboardDestroy\n"));
-
-    if (g_ctx.Win.hWnd)
-    {
-        PostMessage (g_ctx.Win.hWnd, WM_CLOSE, 0, 0);
-    }
-
-    CloseHandle (g_ctx.hRenderEvent);
-
-    /* Wait for the window thread to terminate. */
-    RTThreadWait (g_ctx.hThread, RT_INDEFINITE_WAIT, NULL);
-
-    g_ctx.hThread = NIL_RTTHREAD;
-}
-
-int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient, bool fHeadless)
-{
-    NOREF(fHeadless);
-    Log(("vboxClipboardConnect\n"));
-
-    if (g_ctx.pClient != NULL)
-    {
-        /* One client only. */
-        return VERR_NOT_SUPPORTED;
-    }
-
-    pClient->pCtx = &g_ctx;
-
-    pClient->pCtx->pClient = pClient;
-
-    /* Sync the host clipboard content with the client. */
-    vboxClipboardSync (pClient);
-
-    return VINF_SUCCESS;
-}
-
-int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA *pClient)
-{
-    /* Sync the host clipboard content with the client. */
-    return vboxClipboardSyncInternal(pClient->pCtx);
-}
-
-void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *pClient)
-{
-    RT_NOREF1(pClient);
-    Log(("vboxClipboardDisconnect\n"));
-
-    g_ctx.pClient = NULL;
-}
-
-void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Formats)
-{
-    /*
-     * The guest announces formats. Forward to the window thread.
-     */
-    PostMessage (pClient->pCtx->Win.hWnd, WM_USER, 0, u32Formats);
-}
-
-int DumpHtml(const char *pszSrc, size_t cb)
-{
-    size_t cchIgnored = 0;
-    int rc = RTStrNLenEx(pszSrc, cb, &cchIgnored);
-    if (RT_SUCCESS(rc))
-    {
-        char *pszBuf = (char *)RTMemAllocZ(cb + 1);
-        if (pszBuf != NULL)
-        {
-            rc = RTStrCopy(pszBuf, cb + 1, (const char *)pszSrc);
-            if (RT_SUCCESS(rc))
-            {
-                for (size_t i = 0; i < cb; ++i)
-                    if (pszBuf[i] == '\n' || pszBuf[i] == '\r')
-                        pszBuf[i] = ' ';
-            }
-            else
-                Log(("Error in copying string.\n"));
-            Log(("Removed \\r\\n: %s\n", pszBuf));
-            RTMemFree(pszBuf);
-        }
-        else
-        {
-            rc = VERR_NO_MEMORY;
-            Log(("Not enough memory to allocate buffer.\n"));
-        }
-    }
-    return rc;
-}
-
-int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Format, void *pv, uint32_t cb, uint32_t *pcbActual)
-{
-    LogFlow(("vboxClipboardReadData: u32Format = %02X\n", u32Format));
-
-    HANDLE hClip = NULL;
-
-    /*
-     * The guest wants to read data in the given format.
-     */
-    int rc = VBoxClipboardWinOpen(pClient->pCtx->Win.hWnd);
-    if (RT_SUCCESS(rc))
-    {
-        LogFunc(("Clipboard opened.\n"));
-
-        if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
-        {
-            hClip = GetClipboardData (CF_DIB);
-
-            if (hClip != NULL)
-            {
-                LPVOID lp = GlobalLock (hClip);
-
-                if (lp != NULL)
-                {
-                    LogFunc(("CF_DIB\n"));
-
-                    vboxClipboardGetData (VBOX_SHARED_CLIPBOARD_FMT_BITMAP, lp, GlobalSize (hClip),
-                                          pv, cb, pcbActual);
-
-                    GlobalUnlock(hClip);
-                }
-                else
-                {
-                    hClip = NULL;
-                }
-            }
-        }
-        else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
-        {
-            hClip = GetClipboardData(CF_UNICODETEXT);
-
-            if (hClip != NULL)
-            {
-                LPWSTR uniString = (LPWSTR)GlobalLock (hClip);
-
-                if (uniString != NULL)
-                {
-                    LogFunc(("CF_UNICODETEXT\n"));
-
-                    vboxClipboardGetData (VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, uniString, (lstrlenW (uniString) + 1) * 2,
-                                          pv, cb, pcbActual);
-
-                    GlobalUnlock(hClip);
-                }
-                else
-                {
-                    hClip = NULL;
-                }
-            }
-        }
-        else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_HTML)
-        {
-            UINT format = RegisterClipboardFormat ("HTML Format");
-
-            if (format != 0)
-            {
-                hClip = GetClipboardData (format);
-
-                if (hClip != NULL)
-                {
-                    LPVOID lp = GlobalLock (hClip);
-
-                    if (lp != NULL)
-                    {
-                        LogFunc(("CF_HTML\n"));
-
-                        vboxClipboardGetData (VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize (hClip),
-                                              pv, cb, pcbActual);
-                        LogRelFlowFunc(("Raw HTML clipboard data from host :"));
-                        DumpHtml((char*)pv, cb);
-                        GlobalUnlock(hClip);
-                    }
-                    else
-                    {
-                        hClip = NULL;
-                    }
-                }
-            }
-        }
-
-        VBoxClipboardWinClose();
-    }
-    else
-    {
-        LogFunc(("vboxClipboardReadData: failed to open clipboard, rc: %Rrc\n", rc));
-    }
-
-    if (hClip == NULL)
-    {
-        /* Reply with empty data. */
-        vboxClipboardGetData (0, NULL, 0,
-                              pv, cb, pcbActual);
-    }
-
-    return VINF_SUCCESS;
-}
-
-void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient, void *pv, uint32_t cb, uint32_t u32Format)
-{
-    LogFlow(("vboxClipboardWriteData\n"));
-
-    /*
-     * The guest returns data that was requested in the WM_RENDERFORMAT handler.
-     */
-    Assert(pClient->data.pv == NULL && pClient->data.cb == 0 && pClient->data.u32Format == 0);
-
-    vboxClipboardDump(pv, cb, u32Format);
-
-    if (cb > 0)
-    {
-        char *pszResult = NULL;
-
-        if (   u32Format == VBOX_SHARED_CLIPBOARD_FMT_HTML
-            && !IsWindowsHTML((const char*)pv))
-        {
-            /* check that this is not already CF_HTML */
-            uint32_t cbResult;
-            int rc = ConvertMimeToCFHTML((const char *)pv, cb, &pszResult, &cbResult);
-            if (RT_SUCCESS(rc))
-            {
-                if (pszResult != NULL && cbResult != 0)
-                {
-                    pClient->data.pv        = pszResult;
-                    pClient->data.cb        = cbResult;
-                    pClient->data.u32Format = u32Format;
-                }
-            }
-        }
-        else
-        {
-            pClient->data.pv = RTMemDup(pv, cb);
-            if (pClient->data.pv)
-            {
-                pClient->data.cb = cb;
-                pClient->data.u32Format = u32Format;
-            }
-        }
-    }
-
-    SetEvent(pClient->pCtx->hRenderEvent);
-}
-
-
-/**
- * Extracts field value from CF_HTML struct
- *
- * @returns VBox status code
- * @param   pszSrc      source in CF_HTML format
- * @param   pszOption   Name of CF_HTML field
- * @param   puValue     Where to return extracted value of CF_HTML field
- */
-static int GetHeaderValue(const char *pszSrc, const char *pszOption, uint32_t *puValue)
-{
-    int rc = VERR_INVALID_PARAMETER;
-
-    Assert(pszSrc);
-    Assert(pszOption);
-
-    const char *pszOptionValue = RTStrStr(pszSrc, pszOption);
-    if (pszOptionValue)
-    {
-        size_t cchOption = strlen(pszOption);
-        Assert(cchOption);
-
-        rc = RTStrToUInt32Ex(pszOptionValue + cchOption, NULL, 10, puValue);
-    }
-    return rc;
-}
-
-
-/**
- * Check that the source string contains CF_HTML struct
- *
- * @param   pszSource   source string.
- *
- * @returns @c true if the @a pszSource string is in CF_HTML format
- */
-static bool IsWindowsHTML(const char *pszSource)
-{
-    return RTStrStr(pszSource, "Version:") != NULL
-        && RTStrStr(pszSource, "StartHTML:") != NULL;
-}
-
-
-/*
- * Converts clipboard data from CF_HTML format to mimie clipboard format
- *
- * Returns allocated buffer that contains html converted to text/html mime type
- *
- * @returns VBox status code.
- * @param   pszSource   The input.
- * @param   cch         The length of the input.
- * @param   ppszOutput  Where to return the result.  Free using RTMemFree.
- * @param   pcbOutput   Where to the return length of the result (bytes/chars).
- */
-static int ConvertCFHtmlToMime(const char *pszSource, const uint32_t cch, char **ppszOutput, uint32_t *pcbOutput)
-{
-    Assert(pszSource);
-    Assert(cch);
-    Assert(ppszOutput);
-    Assert(pcbOutput);
-
-    uint32_t offStart;
-    int rc = GetHeaderValue(pszSource, "StartFragment:", &offStart);
-    if (RT_SUCCESS(rc))
-    {
-        uint32_t offEnd;
-        rc = GetHeaderValue(pszSource, "EndFragment:", &offEnd);
-        if (RT_SUCCESS(rc))
-        {
-            if (   offStart > 0
-                && offEnd > 0
-                && offEnd > offStart
-                && offEnd <= cch)
-            {
-                uint32_t cchSubStr = offEnd - offStart;
-                char *pszResult = (char *)RTMemAlloc(cchSubStr + 1);
-                if (pszResult)
-                {
-                    rc = RTStrCopyEx(pszResult, cchSubStr + 1, pszSource + offStart, cchSubStr);
-                    if (RT_SUCCESS(rc))
-                    {
-                        *ppszOutput = pszResult;
-                        *pcbOutput  = (uint32_t)(cchSubStr + 1);
-                        rc = VINF_SUCCESS;
-                    }
-                    else
-                    {
-                        LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment. rc = %Rrc\n", rc));
-                        RTMemFree(pszResult);
-                    }
-                }
-                else
-                {
-                    LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment.\n"));
-                    rc = VERR_NO_MEMORY;
-                }
-            }
-            else
-            {
-                LogRelFlowFunc(("Error: CF_HTML out of bounds - offStart=%#x offEnd=%#x cch=%#x\n", offStart, offEnd, cch));
-                rc = VERR_INVALID_PARAMETER;
-            }
-        }
-        else
-        {
-            LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment. rc = %Rrc.\n", rc));
-            rc = VERR_INVALID_PARAMETER;
-        }
-    }
-    else
-    {
-        LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected StartFragment. rc = %Rrc.\n", rc));
-        rc = VERR_INVALID_PARAMETER;
-    }
-
-    return rc;
-}
-
-
-
-/**
- * Converts source UTF-8 MIME HTML clipboard data to UTF-8 CF_HTML format.
- *
- * This is just encapsulation work, slapping a header on the data.
- *
- * It allocates
- *
- * Calculations:
- *   Header length = format Length + (2*(10 - 5('%010d'))('digits')) - 2('%s') = format length + 8
- *   EndHtml       = Header length + fragment length
- *   StartHtml     = 105(constant)
- *   StartFragment = 141(constant) may vary if the header html content will be extended
- *   EndFragment   = Header length + fragment length - 38(ending length)
- *
- * @param   pszSource   Source buffer that contains utf-16 string in mime html format
- * @param   cb          Size of source buffer in bytes
- * @param   ppszOutput  Where to return the allocated output buffer to put converted UTF-8
- *                      CF_HTML clipboard data.  This function allocates memory for this.
- * @param   pcbOutput   Where to return the size of allocated result buffer in bytes/chars, including zero terminator
- *
- * @note    output buffer should be free using RTMemFree()
- * @note    Everything inside of fragment can be UTF8. Windows allows it. Everything in header should be Latin1.
- */
-static int ConvertMimeToCFHTML(const char *pszSource, size_t cb, char **ppszOutput, uint32_t *pcbOutput)
-{
-    Assert(ppszOutput);
-    Assert(pcbOutput);
-    Assert(pszSource);
-    Assert(cb);
-
-    /* construct CF_HTML formatted string */
-    char *pszResult = NULL;
-    size_t cchFragment;
-    int rc = RTStrNLenEx(pszSource, cb, &cchFragment);
-    if (!RT_SUCCESS(rc))
-    {
-        LogRelFlowFunc(("Error: invalid source fragment. rc = %Rrc.\n"));
-        return VERR_INVALID_PARAMETER;
-    }
-
-    /*
-    @StartHtml - pos before <html>
-    @EndHtml - whole size of text excluding ending zero char
-    @StartFragment - pos after <!--StartFragment-->
-    @EndFragment - pos before <!--EndFragment-->
-    @note: all values includes CR\LF inserted into text
-    Calculations:
-    Header length = format Length + (3*6('digits')) - 2('%s') = format length + 16 (control value - 183)
-    EndHtml  = Header length + fragment length
-    StartHtml = 105(constant)
-    StartFragment = 143(constant)
-    EndFragment  = Header length + fragment length - 40(ending length)
-    */
-    static const char s_szFormatSample[] =
-    /*   0:   */ "Version:1.0\r\n"
-    /*  13:   */ "StartHTML:000000101\r\n"
-    /*  34:   */ "EndHTML:%0000009u\r\n" // END HTML = Header length + fragment length
-    /*  53:   */ "StartFragment:000000137\r\n"
-    /*  78:   */ "EndFragment:%0000009u\r\n"
-    /* 101:   */ "<html>\r\n"
-    /* 109:   */ "<body>\r\n"
-    /* 117:   */ "<!--StartFragment-->"
-    /* 137:   */ "%s"
-    /* 137+2: */ "<!--EndFragment-->\r\n"
-    /* 157+2: */ "</body>\r\n"
-    /* 166+2: */ "</html>\r\n";
-    /* 175+2: */
-    AssertCompile(sizeof(s_szFormatSample) == 175+2+1);
-
-    /* calculate parameters of CF_HTML header */
-    size_t cchHeader      = sizeof(s_szFormatSample) - 1;
-    size_t offEndHtml     = cchHeader + cchFragment;
-    size_t offEndFragment = cchHeader + cchFragment - 38; /* 175-137 = 38 */
-    pszResult = (char *)RTMemAlloc(offEndHtml + 1);
-    if (pszResult == NULL)
-    {
-        LogRelFlowFunc(("Error: Cannot allocate memory for result buffer. rc = %Rrc.\n"));
-        return VERR_NO_MEMORY;
-    }
-
-    /* format result CF_HTML string */
-    size_t cchFormatted = RTStrPrintf(pszResult, offEndHtml + 1,
-                                      s_szFormatSample, offEndHtml, offEndFragment, pszSource);
-    Assert(offEndHtml == cchFormatted); NOREF(cchFormatted);
-
-#ifdef VBOX_STRICT
-    /* Control calculations. check consistency.*/
-    static const char s_szStartFragment[] = "<!--StartFragment-->";
-    static const char s_szEndFragment[] = "<!--EndFragment-->";
-
-    /* check 'StartFragment:' value */
-    const char *pszRealStartFragment = RTStrStr(pszResult, s_szStartFragment);
-    Assert(&pszRealStartFragment[sizeof(s_szStartFragment) - 1] - pszResult == 137);
-
-    /* check 'EndFragment:' value */
-    const char *pszRealEndFragment = RTStrStr(pszResult, s_szEndFragment);
-    Assert((size_t)(pszRealEndFragment - pszResult) == offEndFragment);
-#endif
-
-    *ppszOutput = pszResult;
-    *pcbOutput = (uint32_t)cchFormatted + 1;
-    Assert(*pcbOutput == cchFormatted + 1);
-
-    return VINF_SUCCESS;
-}
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-darwin.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-darwin.cpp	(revision 78160)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-darwin.cpp	(revision 78160)
@@ -0,0 +1,274 @@
+/* $Id$ */
+/** @file
+ * Shared Clipboard Service - Mac OS X host.
+ */
+
+/*
+ * Copyright (C) 2008-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
+#include <VBox/HostServices/VBoxClipboardSvc.h>
+
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/thread.h>
+
+#include "VBoxClipboard.h"
+#include "darwin-pasteboard.h"
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+/** Global clipboard context information */
+struct _VBOXCLIPBOARDCONTEXT
+{
+    /** We have a separate thread to poll for new clipboard content */
+    RTTHREAD thread;
+    bool volatile fTerminate;
+
+    /** The reference to the current pasteboard */
+    PasteboardRef pasteboard;
+
+    VBOXCLIPBOARDCLIENTDATA *pClient;
+};
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
+/** Only one client is supported. There seems to be no need for more clients. */
+static VBOXCLIPBOARDCONTEXT g_ctx;
+
+
+/**
+ * Checks if something is present on the clipboard and calls vboxSvcClipboardReportMsg.
+ *
+ * @returns IPRT status code (ignored).
+ * @param   pCtx    The context.
+ */
+static int vboxClipboardChanged (VBOXCLIPBOARDCONTEXT *pCtx)
+{
+    if (pCtx->pClient == NULL)
+        return VINF_SUCCESS;
+
+    uint32_t fFormats = 0;
+    bool fChanged = false;
+    /* Retrieve the formats currently in the clipboard and supported by vbox */
+    int rc = queryNewPasteboardFormats (pCtx->pasteboard, &fFormats, &fChanged);
+    if (RT_SUCCESS (rc) && fChanged)
+    {
+        vboxSvcClipboardReportMsg (pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, fFormats);
+        Log (("vboxClipboardChanged fFormats %02X\n", fFormats));
+    }
+
+    return rc;
+}
+
+
+/**
+ * The poller thread.
+ *
+ * This thread will check for the arrival of new data on the clipboard.
+ *
+ * @returns VINF_SUCCESS (not used).
+ * @param   ThreadSelf  Our thread handle.
+ * @param   pvUser      Pointer to the VBOXCLIPBOARDCONTEXT structure.
+ *
+ */
+static int vboxClipboardThread (RTTHREAD ThreadSelf, void *pvUser)
+{
+    Log (("vboxClipboardThread: starting clipboard thread\n"));
+
+    AssertPtrReturn (pvUser, VERR_INVALID_PARAMETER);
+    VBOXCLIPBOARDCONTEXT *pCtx = (VBOXCLIPBOARDCONTEXT *) pvUser;
+
+    while (!pCtx->fTerminate)
+    {
+        /* call this behind the lock because we don't know if the api is
+           thread safe and in any case we're calling several methods. */
+        VBoxSvcClipboardLock();
+        vboxClipboardChanged (pCtx);
+        VBoxSvcClipboardUnlock();
+
+        /* Sleep for 200 msecs before next poll */
+        RTThreadUserWait (ThreadSelf, 200);
+    }
+
+    Log (("vboxClipboardThread: clipboard thread terminated successfully with return code %Rrc\n", VINF_SUCCESS));
+    return VINF_SUCCESS;
+}
+
+/*
+ * Public platform dependent functions.
+ */
+
+/** Initialise the host side of the shared clipboard - called by the hgcm layer. */
+int vboxClipboardInit (void)
+{
+    Log (("vboxClipboardInit\n"));
+
+    g_ctx.fTerminate = false;
+
+    int rc = initPasteboard (&g_ctx.pasteboard);
+    AssertRCReturn (rc, rc);
+
+    rc = RTThreadCreate (&g_ctx.thread, vboxClipboardThread, &g_ctx, 0,
+                         RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
+    if (RT_FAILURE (rc))
+    {
+        g_ctx.thread = NIL_RTTHREAD;
+        destroyPasteboard (&g_ctx.pasteboard);
+    }
+
+    return rc;
+}
+
+/** Terminate the host side of the shared clipboard - called by the hgcm layer. */
+void vboxClipboardDestroy (void)
+{
+    Log (("vboxClipboardDestroy\n"));
+
+    /*
+     * Signal the termination of the polling thread and wait for it to respond.
+     */
+    ASMAtomicWriteBool (&g_ctx.fTerminate, true);
+    int rc = RTThreadUserSignal (g_ctx.thread);
+    AssertRC (rc);
+    rc = RTThreadWait (g_ctx.thread, RT_INDEFINITE_WAIT, NULL);
+    AssertRC (rc);
+
+    /*
+     * Destroy the pasteboard and uninitialize the global context record.
+     */
+    destroyPasteboard (&g_ctx.pasteboard);
+    g_ctx.thread = NIL_RTTHREAD;
+    g_ctx.pClient = NULL;
+}
+
+/**
+ * Enable the shared clipboard - called by the hgcm clipboard subsystem.
+ *
+ * @param   pClient Structure containing context information about the guest system
+ * @param   fHeadless Whether headless.
+ * @returns RT status code
+ */
+int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient, bool fHeadless)
+{
+    NOREF(fHeadless);
+    if (g_ctx.pClient != NULL)
+    {
+        /* One client only. */
+        return VERR_NOT_SUPPORTED;
+    }
+
+    VBoxSvcClipboardLock();
+
+    pClient->pCtx = &g_ctx;
+    pClient->pCtx->pClient = pClient;
+
+    /* Initially sync the host clipboard content with the client. */
+    int rc = vboxClipboardSync (pClient);
+
+    VBoxSvcClipboardUnlock();
+    return rc;
+}
+
+/**
+ * Synchronise the contents of the host clipboard with the guest, called by the HGCM layer
+ * after a save and restore of the guest.
+ */
+int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA *pClient)
+{
+    /* Sync the host clipboard content with the client. */
+    VBoxSvcClipboardLock();
+    int rc = vboxClipboardChanged (pClient->pCtx);
+    VBoxSvcClipboardUnlock();
+
+    return rc;
+}
+
+/**
+ * Shut down the shared clipboard subsystem and "disconnect" the guest.
+ */
+void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *pClient)
+{
+    Log (("vboxClipboardDisconnect\n"));
+
+    VBoxSvcClipboardLock();
+    pClient->pCtx->pClient = NULL;
+    VBoxSvcClipboardUnlock();
+}
+
+/**
+ * The guest is taking possession of the shared clipboard.  Called by the HGCM clipboard
+ * subsystem.
+ *
+ * @param pClient    Context data for the guest system
+ * @param u32Formats Clipboard formats the guest is offering
+ */
+void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Formats)
+{
+    Log (("vboxClipboardFormatAnnounce u32Formats %02X\n", u32Formats));
+    if (u32Formats == 0)
+    {
+        /* This is just an automatism, not a genuine announcement */
+        return;
+    }
+
+    vboxSvcClipboardReportMsg (pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA,
+                               u32Formats);
+}
+
+/**
+ * Called by the HGCM clipboard subsystem when the guest wants to read the host clipboard.
+ *
+ * @param pClient   Context information about the guest VM
+ * @param u32Format The format that the guest would like to receive the data in
+ * @param pv        Where to write the data to
+ * @param cb        The size of the buffer to write the data to
+ * @param pcbActual Where to write the actual size of the written data
+ */
+int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Format,
+                           void *pv, uint32_t cb, uint32_t * pcbActual)
+{
+    VBoxSvcClipboardLock();
+
+    /* Default to no data available. */
+    *pcbActual = 0;
+    int rc = readFromPasteboard (pClient->pCtx->pasteboard, u32Format, pv, cb, pcbActual);
+
+    VBoxSvcClipboardUnlock();
+    return rc;
+}
+
+/**
+ * Called by the HGCM clipboard subsystem when we have requested data and that data arrives.
+ *
+ * @param pClient   Context information about the guest VM
+ * @param pv        Buffer to which the data was written
+ * @param cb        The size of the data written
+ * @param u32Format The format of the data written
+ */
+void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient, void *pv,
+                             uint32_t cb, uint32_t u32Format)
+{
+    VBoxSvcClipboardLock();
+
+    writeToPasteboard (pClient->pCtx->pasteboard, pv, cb, u32Format);
+
+    VBoxSvcClipboardUnlock();
+}
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp	(revision 78160)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp	(revision 78160)
@@ -0,0 +1,1060 @@
+/* $Id$ */
+/** @file
+ * Shared Clipboard Service - Win32 host.
+ */
+
+/*
+ * Copyright (C) 2006-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
+#include <iprt/win/windows.h>
+
+#include <VBox/HostServices/VBoxClipboardSvc.h>
+#include <VBox/GuestHost/SharedClipboard-win.h>
+
+#include <iprt/alloc.h>
+#include <iprt/string.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/thread.h>
+#include <iprt/ldr.h>
+#include <process.h>
+
+#include "VBoxClipboard.h"
+
+/** Static window class name. */
+static char s_szClipWndClassName[] = VBOX_CLIPBOARD_WNDCLASS_NAME;
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+static int ConvertCFHtmlToMime(const char *pszSource, const uint32_t cch, char **ppszOutput, uint32_t *pch);
+static int ConvertMimeToCFHTML(const char *pszSource, size_t cb, char **ppszOutput, uint32_t *pcbOutput);
+static bool IsWindowsHTML(const char *source);
+static int vboxClipboardSyncInternal(PVBOXCLIPBOARDCONTEXT pCtx);
+
+struct _VBOXCLIPBOARDCONTEXT
+{
+    /** Handle for window message handling thread. */
+    RTTHREAD                 hThread;
+    /** Event which gets triggered if the host clipboard needs to render its data. */
+    HANDLE                   hRenderEvent;
+    /** Structure for keeping and communicating with client data (from the guest). */
+    PVBOXCLIPBOARDCLIENTDATA pClient;
+    /** Windows-specific context data. */
+    VBOXCLIPBOARDWINCTX      Win;
+};
+
+/* Only one client is supported. There seems to be no need for more clients. */
+static VBOXCLIPBOARDCONTEXT g_ctx;
+
+
+#ifdef LOG_ENABLED
+static void vboxClipboardDump(const void *pv, size_t cb, uint32_t u32Format)
+{
+    if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
+    {
+        LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT:\n"));
+        if (pv && cb)
+            LogFunc(("%ls\n", pv));
+        else
+            LogFunc(("%p %zu\n", pv, cb));
+    }
+    else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
+        LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n"));
+    else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_HTML)
+    {
+        LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_HTML:\n"));
+        if (pv && cb)
+        {
+            LogFunc(("%s\n", pv));
+
+            //size_t cb = RTStrNLen(pv, );
+            char *pszBuf = (char *)RTMemAllocZ(cb + 1);
+            RTStrCopy(pszBuf, cb + 1, (const char *)pv);
+            for (size_t off = 0; off < cb; ++off)
+            {
+                if (pszBuf[off] == '\n' || pszBuf[off] == '\r')
+                    pszBuf[off] = ' ';
+            }
+
+            LogFunc(("%s\n", pszBuf));
+            RTMemFree(pszBuf);
+        }
+        else
+            LogFunc(("%p %zu\n", pv, cb));
+    }
+    else
+        LogFunc(("Invalid format %02X\n", u32Format));
+}
+#else  /* !LOG_ENABLED */
+# define vboxClipboardDump(__pv, __cb, __format) do { NOREF(__pv); NOREF(__cb); NOREF(__format); } while (0)
+#endif /* !LOG_ENABLED */
+
+/** @todo Someone please explain the protocol wrt overflows...  */
+static void vboxClipboardGetData (uint32_t u32Format, const void *pvSrc, uint32_t cbSrc,
+                                  void *pvDst, uint32_t cbDst, uint32_t *pcbActualDst)
+{
+    LogFlow(("vboxClipboardGetData cbSrc = %d, cbDst = %d\n", cbSrc, cbDst));
+
+    if (   u32Format == VBOX_SHARED_CLIPBOARD_FMT_HTML
+        && IsWindowsHTML((const char *)pvSrc))
+    {
+        /** @todo r=bird: Why the double conversion? */
+        char *pszBuf = NULL;
+        uint32_t cbBuf = 0;
+        int rc = ConvertCFHtmlToMime((const char*)pvSrc, cbSrc, &pszBuf, &cbBuf);
+        if (RT_SUCCESS(rc))
+        {
+            *pcbActualDst = cbBuf;
+            if (cbBuf > cbDst)
+            {
+                /* Do not copy data. The dst buffer is not enough. */
+                RTMemFree(pszBuf);
+                return;
+            }
+            memcpy(pvDst, pszBuf, cbBuf);
+            RTMemFree(pszBuf);
+        }
+        else
+            *pcbActualDst = 0;
+    }
+    else
+    {
+        *pcbActualDst = cbSrc;
+
+        if (cbSrc > cbDst)
+        {
+            /* Do not copy data. The dst buffer is not enough. */
+            return;
+        }
+
+        memcpy(pvDst, pvSrc, cbSrc);
+    }
+
+    vboxClipboardDump(pvDst, cbSrc, u32Format);
+
+    return;
+}
+
+static int vboxClipboardReadDataFromClient (VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format)
+{
+    Assert(pCtx->pClient);
+    Assert(pCtx->hRenderEvent);
+    Assert(pCtx->pClient->data.pv == NULL && pCtx->pClient->data.cb == 0 && pCtx->pClient->data.u32Format == 0);
+
+    LogFlow(("vboxClipboardReadDataFromClient u32Format = %02X\n", u32Format));
+
+    ResetEvent (pCtx->hRenderEvent);
+
+    vboxSvcClipboardReportMsg (pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Format);
+
+    DWORD ret = WaitForSingleObject(pCtx->hRenderEvent, INFINITE);
+    LogFlow(("vboxClipboardReadDataFromClient wait completed, ret 0x%08X, err %d\n",
+             ret, GetLastError())); NOREF(ret);
+
+    return VINF_SUCCESS;
+}
+
+static LRESULT CALLBACK vboxClipboardWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    LRESULT rc = 0;
+
+    PVBOXCLIPBOARDCONTEXT pCtx = &g_ctx;
+
+    switch (msg)
+    {
+        case WM_CLIPBOARDUPDATE:
+        {
+            Log(("WM_CLIPBOARDUPDATE\n"));
+
+            if (GetClipboardOwner() != hwnd)
+            {
+                /* Clipboard was updated by another application, retrieve formats and report back. */
+                int vboxrc = vboxClipboardSyncInternal(pCtx);
+                AssertRC(vboxrc);
+            }
+        } break;
+
+        case WM_CHANGECBCHAIN:
+        {
+            Log(("WM_CHANGECBCHAIN\n"));
+
+            if (VBoxClipboardWinIsNewAPI(&pCtx->Win.newAPI))
+            {
+                rc = DefWindowProc(hwnd, msg, wParam, lParam);
+                break;
+            }
+
+            HWND hwndRemoved = (HWND)wParam;
+            HWND hwndNext    = (HWND)lParam;
+
+            if (hwndRemoved == pCtx->Win.hWndNextInChain)
+            {
+                /* The window that was next to our in the chain is being removed.
+                 * Relink to the new next window.
+                 */
+                pCtx->Win.hWndNextInChain = hwndNext;
+            }
+            else
+            {
+                if (pCtx->Win.hWndNextInChain)
+                {
+                    /* Pass the message further. */
+                    DWORD_PTR dwResult;
+                    rc = SendMessageTimeout(pCtx->Win.hWndNextInChain, WM_CHANGECBCHAIN, wParam, lParam, 0,
+                                            VBOX_CLIPBOARD_CBCHAIN_TIMEOUT_MS,
+                                            &dwResult);
+                    if (!rc)
+                        rc = (LRESULT)dwResult;
+                }
+            }
+        } break;
+
+        case WM_DRAWCLIPBOARD:
+        {
+            Log(("WM_DRAWCLIPBOARD\n"));
+
+            if (GetClipboardOwner() != hwnd)
+            {
+                /* Clipboard was updated by another application, retrieve formats and report back. */
+                int vboxrc = vboxClipboardSyncInternal(pCtx);
+                AssertRC(vboxrc);
+            }
+
+            if (pCtx->Win.hWndNextInChain)
+            {
+                Log(("WM_DRAWCLIPBOARD next %p\n", pCtx->Win.hWndNextInChain));
+                /* Pass the message to next windows in the clipboard chain. */
+                DWORD_PTR dwResult;
+                rc = SendMessageTimeout(pCtx->Win.hWndNextInChain, msg, wParam, lParam, 0, VBOX_CLIPBOARD_CBCHAIN_TIMEOUT_MS,
+                                        &dwResult);
+                if (!rc)
+                    rc = dwResult;
+            }
+        } break;
+
+        case WM_TIMER:
+        {
+            if (VBoxClipboardWinIsNewAPI(&pCtx->Win.newAPI))
+                break;
+
+            HWND hViewer = GetClipboardViewer();
+
+            /* Re-register ourselves in the clipboard chain if our last ping
+             * timed out or there seems to be no valid chain. */
+            if (!hViewer || pCtx->Win.oldAPI.fCBChainPingInProcess)
+            {
+                VBoxClipboardWinRemoveFromCBChain(&pCtx->Win);
+                VBoxClipboardWinAddToCBChain(&pCtx->Win);
+            }
+
+            /* Start a new ping by passing a dummy WM_CHANGECBCHAIN to be
+             * processed by ourselves to the chain. */
+            pCtx->Win.oldAPI.fCBChainPingInProcess = TRUE;
+
+            hViewer = GetClipboardViewer();
+            if (hViewer)
+                SendMessageCallback(hViewer, WM_CHANGECBCHAIN,
+                                    (WPARAM)pCtx->Win.hWndNextInChain, (LPARAM)pCtx->Win.hWndNextInChain,
+                                    VBoxClipboardWinChainPingProc, (ULONG_PTR)pCtx);
+        } break;
+
+        case WM_RENDERFORMAT:
+        {
+            /* Insert the requested clipboard format data into the clipboard. */
+            uint32_t u32Format = 0;
+
+            UINT format = (UINT)wParam;
+
+            Log(("WM_RENDERFORMAT %d\n", format));
+
+            switch (format)
+            {
+                case CF_UNICODETEXT:
+                    u32Format |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
+                    break;
+
+                case CF_DIB:
+                    u32Format |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
+                    break;
+
+                default:
+                    if (format >= 0xC000)
+                    {
+                        TCHAR szFormatName[256];
+
+                        int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR));
+
+                        if (cActual)
+                        {
+                            if (strcmp (szFormatName, "HTML Format") == 0)
+                            {
+                                u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
+                            }
+                        }
+                    }
+                    break;
+            }
+
+            if (u32Format == 0 || pCtx->pClient == NULL)
+            {
+                /* Unsupported clipboard format is requested. */
+                Log(("WM_RENDERFORMAT unsupported format requested or client is not active.\n"));
+                EmptyClipboard ();
+            }
+            else
+            {
+                int vboxrc = vboxClipboardReadDataFromClient (pCtx, u32Format);
+
+                LogFunc(("vboxClipboardReadDataFromClient vboxrc = %d, pv %p, cb %d, u32Format %d\n",
+                          vboxrc, pCtx->pClient->data.pv, pCtx->pClient->data.cb, pCtx->pClient->data.u32Format));
+
+                if (   RT_SUCCESS (vboxrc)
+                    && pCtx->pClient->data.pv != NULL
+                    && pCtx->pClient->data.cb > 0
+                    && pCtx->pClient->data.u32Format == u32Format)
+                {
+                    HANDLE hMem = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, pCtx->pClient->data.cb);
+
+                    LogFunc(("hMem %p\n", hMem));
+
+                    if (hMem)
+                    {
+                        void *pMem = GlobalLock (hMem);
+
+                        LogFunc(("pMem %p, GlobalSize %d\n", pMem, GlobalSize (hMem)));
+
+                        if (pMem)
+                        {
+                            Log(("WM_RENDERFORMAT setting data\n"));
+
+                            if (pCtx->pClient->data.pv)
+                            {
+                                memcpy (pMem, pCtx->pClient->data.pv, pCtx->pClient->data.cb);
+
+                                RTMemFree (pCtx->pClient->data.pv);
+                                pCtx->pClient->data.pv        = NULL;
+                            }
+
+                            pCtx->pClient->data.cb        = 0;
+                            pCtx->pClient->data.u32Format = 0;
+
+                            /* The memory must be unlocked before inserting to the Clipboard. */
+                            GlobalUnlock (hMem);
+
+                            /* 'hMem' contains the host clipboard data.
+                             * size is 'cb' and format is 'format'.
+                             */
+                            HANDLE hClip = SetClipboardData (format, hMem);
+
+                            LogFunc(("vboxClipboardHostEvent hClip %p\n", hClip));
+
+                            if (hClip)
+                            {
+                                /* The hMem ownership has gone to the system. Nothing to do. */
+                                break;
+                            }
+                        }
+
+                        GlobalFree (hMem);
+                    }
+                }
+
+                RTMemFree (pCtx->pClient->data.pv);
+                pCtx->pClient->data.pv        = NULL;
+                pCtx->pClient->data.cb        = 0;
+                pCtx->pClient->data.u32Format = 0;
+
+                /* Something went wrong. */
+                VBoxClipboardWinClear();
+            }
+        } break;
+
+        case WM_RENDERALLFORMATS:
+        {
+            Log(("WM_RENDERALLFORMATS\n"));
+
+            /* Do nothing. The clipboard formats will be unavailable now, because the
+             * windows is to be destroyed and therefore the guest side becomes inactive.
+             */
+            int vboxrc = VBoxClipboardWinOpen(hwnd);
+            if (RT_SUCCESS(vboxrc))
+            {
+                VBoxClipboardWinClear();
+                VBoxClipboardWinClose();
+            }
+            else
+            {
+                LogFlow(("vboxClipboardWndProc: WM_RENDERALLFORMATS: error in open clipboard. hwnd: %x, rc: %Rrc\n", hwnd, vboxrc));
+            }
+        } break;
+
+        case VBOX_CLIPBOARD_WM_SET_FORMATS:
+        {
+            if (pCtx->pClient == NULL || pCtx->pClient->fMsgFormats)
+            {
+                /* Host has pending formats message. Ignore the guest announcement,
+                 * because host clipboard has more priority.
+                 */
+                Log(("VBOX_CLIPBOARD_WM_SET_FORMATS ignored\n"));
+                break;
+            }
+
+            /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */
+            uint32_t u32Formats = (uint32_t)lParam;
+
+            Log(("VBOX_CLIPBOARD_WM_SET_FORMATS: u32Formats=%02X\n", u32Formats));
+
+            int vboxrc = VBoxClipboardWinOpen(hwnd);
+            if (RT_SUCCESS(vboxrc))
+            {
+                VBoxClipboardWinClear();
+
+                Log(("VBOX_CLIPBOARD_WM_SET_FORMATS emptied clipboard\n"));
+
+                HANDLE hClip = NULL;
+
+                if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
+                    hClip = SetClipboardData(CF_UNICODETEXT, NULL);
+
+                if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
+                    hClip = SetClipboardData(CF_DIB, NULL);
+
+                if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
+                {
+                    UINT format = RegisterClipboardFormat ("HTML Format");
+                    if (format != 0)
+                    {
+                        hClip = SetClipboardData (format, NULL);
+                    }
+                }
+
+                VBoxClipboardWinClose();
+
+                LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS: hClip=%p, lastErr=%ld\n", hClip, GetLastError ()));
+            }
+        } break;
+
+        case WM_DESTROY:
+        {
+            /* MS recommends to remove from Clipboard chain in this callback. */
+            VBoxClipboardWinRemoveFromCBChain(&pCtx->Win);
+            if (pCtx->Win.oldAPI.timerRefresh)
+            {
+                Assert(pCtx->Win.hWnd);
+                KillTimer(pCtx->Win.hWnd, 0);
+            }
+            PostQuitMessage(0);
+        } break;
+
+        default:
+        {
+            Log(("WM_ %p\n", msg));
+            rc = DefWindowProc(hwnd, msg, wParam, lParam);
+        }
+    }
+
+    Log(("WM_ rc %d\n", rc));
+    return rc;
+}
+
+DECLCALLBACK(int) VBoxClipboardThread (RTTHREAD hThreadSelf, void *pvUser)
+{
+    RT_NOREF2(hThreadSelf, pvUser);
+    /* Create a window and make it a clipboard viewer. */
+    int rc = VINF_SUCCESS;
+
+    LogFlow(("VBoxClipboardThread\n"));
+
+    const PVBOXCLIPBOARDCONTEXT pCtx = &g_ctx;
+
+    HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
+
+    /* Register the Window Class. */
+    WNDCLASS wc;
+    RT_ZERO(wc);
+
+    wc.style         = CS_NOCLOSE;
+    wc.lpfnWndProc   = vboxClipboardWndProc;
+    wc.hInstance     = hInstance;
+    wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
+    wc.lpszClassName = s_szClipWndClassName;
+
+    ATOM atomWindowClass = RegisterClass(&wc);
+
+    if (atomWindowClass == 0)
+    {
+        Log(("Failed to register window class\n"));
+        rc = VERR_NOT_SUPPORTED;
+    }
+    else
+    {
+        /* Create the window. */
+        pCtx->Win.hWnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
+                                         s_szClipWndClassName, s_szClipWndClassName,
+                                         WS_POPUPWINDOW,
+                                         -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
+        if (pCtx->Win.hWnd == NULL)
+        {
+            Log(("Failed to create window\n"));
+            rc = VERR_NOT_SUPPORTED;
+        }
+        else
+        {
+            SetWindowPos(pCtx->Win.hWnd, HWND_TOPMOST, -200, -200, 0, 0,
+                         SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
+
+            VBoxClipboardWinAddToCBChain(&pCtx->Win);
+            if (!VBoxClipboardWinIsNewAPI(&pCtx->Win.newAPI))
+                pCtx->Win.oldAPI.timerRefresh = SetTimer(pCtx->Win.hWnd, 0, 10 * 1000, NULL);
+
+            MSG msg;
+            BOOL msgret = 0;
+            while ((msgret = GetMessage(&msg, NULL, 0, 0)) > 0)
+            {
+                TranslateMessage(&msg);
+                DispatchMessage(&msg);
+            }
+            /*
+            * Window procedure can return error,
+            * but this is exceptional situation
+            * that should be identified in testing
+            */
+            Assert(msgret >= 0);
+            Log(("VBoxClipboardThread Message loop finished. GetMessage returned %d, message id: %d \n", msgret, msg.message));
+        }
+    }
+
+    pCtx->Win.hWnd = NULL;
+
+    if (atomWindowClass != 0)
+    {
+        UnregisterClass (s_szClipWndClassName, hInstance);
+        atomWindowClass = 0;
+    }
+
+    return 0;
+}
+
+/**
+ * Synchronizes the host and the guest clipboard formats by sending all supported host clipboard
+ * formats to the guest.
+ *
+ * @returns VBox status code.
+ * @param   pCtx                Clipboard context to synchronize.
+ */
+static int vboxClipboardSyncInternal(PVBOXCLIPBOARDCONTEXT pCtx)
+{
+    uint32_t uFormats;
+    int rc = VBoxClipboardWinGetFormats(&pCtx->Win, &uFormats);
+    if (RT_SUCCESS(rc))
+        vboxSvcClipboardReportMsg(pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, uFormats);
+
+    return rc;
+}
+
+/*
+ * Public platform dependent functions.
+ */
+int vboxClipboardInit (void)
+{
+    int rc = VINF_SUCCESS;
+
+    RT_ZERO(g_ctx);
+
+    /* Check that new Clipboard API is available. */
+    VBoxClipboardWinCheckAndInitNewAPI(&g_ctx.Win.newAPI);
+
+    g_ctx.hRenderEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+    rc = RTThreadCreate (&g_ctx.hThread, VBoxClipboardThread, NULL, 65536,
+                         RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
+
+    if (RT_FAILURE (rc))
+    {
+        CloseHandle (g_ctx.hRenderEvent);
+    }
+
+    return rc;
+}
+
+void vboxClipboardDestroy (void)
+{
+    Log(("vboxClipboardDestroy\n"));
+
+    if (g_ctx.Win.hWnd)
+    {
+        PostMessage (g_ctx.Win.hWnd, WM_CLOSE, 0, 0);
+    }
+
+    CloseHandle (g_ctx.hRenderEvent);
+
+    /* Wait for the window thread to terminate. */
+    RTThreadWait (g_ctx.hThread, RT_INDEFINITE_WAIT, NULL);
+
+    g_ctx.hThread = NIL_RTTHREAD;
+}
+
+int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient, bool fHeadless)
+{
+    NOREF(fHeadless);
+    Log(("vboxClipboardConnect\n"));
+
+    if (g_ctx.pClient != NULL)
+    {
+        /* One client only. */
+        return VERR_NOT_SUPPORTED;
+    }
+
+    pClient->pCtx = &g_ctx;
+
+    pClient->pCtx->pClient = pClient;
+
+    /* Sync the host clipboard content with the client. */
+    vboxClipboardSync (pClient);
+
+    return VINF_SUCCESS;
+}
+
+int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA *pClient)
+{
+    /* Sync the host clipboard content with the client. */
+    return vboxClipboardSyncInternal(pClient->pCtx);
+}
+
+void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *pClient)
+{
+    RT_NOREF1(pClient);
+    Log(("vboxClipboardDisconnect\n"));
+
+    g_ctx.pClient = NULL;
+}
+
+void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Formats)
+{
+    /*
+     * The guest announces formats. Forward to the window thread.
+     */
+    PostMessage (pClient->pCtx->Win.hWnd, WM_USER, 0, u32Formats);
+}
+
+int DumpHtml(const char *pszSrc, size_t cb)
+{
+    size_t cchIgnored = 0;
+    int rc = RTStrNLenEx(pszSrc, cb, &cchIgnored);
+    if (RT_SUCCESS(rc))
+    {
+        char *pszBuf = (char *)RTMemAllocZ(cb + 1);
+        if (pszBuf != NULL)
+        {
+            rc = RTStrCopy(pszBuf, cb + 1, (const char *)pszSrc);
+            if (RT_SUCCESS(rc))
+            {
+                for (size_t i = 0; i < cb; ++i)
+                    if (pszBuf[i] == '\n' || pszBuf[i] == '\r')
+                        pszBuf[i] = ' ';
+            }
+            else
+                Log(("Error in copying string.\n"));
+            Log(("Removed \\r\\n: %s\n", pszBuf));
+            RTMemFree(pszBuf);
+        }
+        else
+        {
+            rc = VERR_NO_MEMORY;
+            Log(("Not enough memory to allocate buffer.\n"));
+        }
+    }
+    return rc;
+}
+
+int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Format, void *pv, uint32_t cb, uint32_t *pcbActual)
+{
+    LogFlow(("vboxClipboardReadData: u32Format = %02X\n", u32Format));
+
+    HANDLE hClip = NULL;
+
+    /*
+     * The guest wants to read data in the given format.
+     */
+    int rc = VBoxClipboardWinOpen(pClient->pCtx->Win.hWnd);
+    if (RT_SUCCESS(rc))
+    {
+        LogFunc(("Clipboard opened.\n"));
+
+        if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
+        {
+            hClip = GetClipboardData (CF_DIB);
+
+            if (hClip != NULL)
+            {
+                LPVOID lp = GlobalLock (hClip);
+
+                if (lp != NULL)
+                {
+                    LogFunc(("CF_DIB\n"));
+
+                    vboxClipboardGetData (VBOX_SHARED_CLIPBOARD_FMT_BITMAP, lp, GlobalSize (hClip),
+                                          pv, cb, pcbActual);
+
+                    GlobalUnlock(hClip);
+                }
+                else
+                {
+                    hClip = NULL;
+                }
+            }
+        }
+        else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
+        {
+            hClip = GetClipboardData(CF_UNICODETEXT);
+
+            if (hClip != NULL)
+            {
+                LPWSTR uniString = (LPWSTR)GlobalLock (hClip);
+
+                if (uniString != NULL)
+                {
+                    LogFunc(("CF_UNICODETEXT\n"));
+
+                    vboxClipboardGetData (VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, uniString, (lstrlenW (uniString) + 1) * 2,
+                                          pv, cb, pcbActual);
+
+                    GlobalUnlock(hClip);
+                }
+                else
+                {
+                    hClip = NULL;
+                }
+            }
+        }
+        else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_HTML)
+        {
+            UINT format = RegisterClipboardFormat ("HTML Format");
+
+            if (format != 0)
+            {
+                hClip = GetClipboardData (format);
+
+                if (hClip != NULL)
+                {
+                    LPVOID lp = GlobalLock (hClip);
+
+                    if (lp != NULL)
+                    {
+                        LogFunc(("CF_HTML\n"));
+
+                        vboxClipboardGetData (VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize (hClip),
+                                              pv, cb, pcbActual);
+                        LogRelFlowFunc(("Raw HTML clipboard data from host :"));
+                        DumpHtml((char*)pv, cb);
+                        GlobalUnlock(hClip);
+                    }
+                    else
+                    {
+                        hClip = NULL;
+                    }
+                }
+            }
+        }
+
+        VBoxClipboardWinClose();
+    }
+    else
+    {
+        LogFunc(("vboxClipboardReadData: failed to open clipboard, rc: %Rrc\n", rc));
+    }
+
+    if (hClip == NULL)
+    {
+        /* Reply with empty data. */
+        vboxClipboardGetData (0, NULL, 0,
+                              pv, cb, pcbActual);
+    }
+
+    return VINF_SUCCESS;
+}
+
+void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient, void *pv, uint32_t cb, uint32_t u32Format)
+{
+    LogFlow(("vboxClipboardWriteData\n"));
+
+    /*
+     * The guest returns data that was requested in the WM_RENDERFORMAT handler.
+     */
+    Assert(pClient->data.pv == NULL && pClient->data.cb == 0 && pClient->data.u32Format == 0);
+
+    vboxClipboardDump(pv, cb, u32Format);
+
+    if (cb > 0)
+    {
+        char *pszResult = NULL;
+
+        if (   u32Format == VBOX_SHARED_CLIPBOARD_FMT_HTML
+            && !IsWindowsHTML((const char*)pv))
+        {
+            /* check that this is not already CF_HTML */
+            uint32_t cbResult;
+            int rc = ConvertMimeToCFHTML((const char *)pv, cb, &pszResult, &cbResult);
+            if (RT_SUCCESS(rc))
+            {
+                if (pszResult != NULL && cbResult != 0)
+                {
+                    pClient->data.pv        = pszResult;
+                    pClient->data.cb        = cbResult;
+                    pClient->data.u32Format = u32Format;
+                }
+            }
+        }
+        else
+        {
+            pClient->data.pv = RTMemDup(pv, cb);
+            if (pClient->data.pv)
+            {
+                pClient->data.cb = cb;
+                pClient->data.u32Format = u32Format;
+            }
+        }
+    }
+
+    SetEvent(pClient->pCtx->hRenderEvent);
+}
+
+
+/**
+ * Extracts field value from CF_HTML struct
+ *
+ * @returns VBox status code
+ * @param   pszSrc      source in CF_HTML format
+ * @param   pszOption   Name of CF_HTML field
+ * @param   puValue     Where to return extracted value of CF_HTML field
+ */
+static int GetHeaderValue(const char *pszSrc, const char *pszOption, uint32_t *puValue)
+{
+    int rc = VERR_INVALID_PARAMETER;
+
+    Assert(pszSrc);
+    Assert(pszOption);
+
+    const char *pszOptionValue = RTStrStr(pszSrc, pszOption);
+    if (pszOptionValue)
+    {
+        size_t cchOption = strlen(pszOption);
+        Assert(cchOption);
+
+        rc = RTStrToUInt32Ex(pszOptionValue + cchOption, NULL, 10, puValue);
+    }
+    return rc;
+}
+
+
+/**
+ * Check that the source string contains CF_HTML struct
+ *
+ * @param   pszSource   source string.
+ *
+ * @returns @c true if the @a pszSource string is in CF_HTML format
+ */
+static bool IsWindowsHTML(const char *pszSource)
+{
+    return RTStrStr(pszSource, "Version:") != NULL
+        && RTStrStr(pszSource, "StartHTML:") != NULL;
+}
+
+
+/*
+ * Converts clipboard data from CF_HTML format to mimie clipboard format
+ *
+ * Returns allocated buffer that contains html converted to text/html mime type
+ *
+ * @returns VBox status code.
+ * @param   pszSource   The input.
+ * @param   cch         The length of the input.
+ * @param   ppszOutput  Where to return the result.  Free using RTMemFree.
+ * @param   pcbOutput   Where to the return length of the result (bytes/chars).
+ */
+static int ConvertCFHtmlToMime(const char *pszSource, const uint32_t cch, char **ppszOutput, uint32_t *pcbOutput)
+{
+    Assert(pszSource);
+    Assert(cch);
+    Assert(ppszOutput);
+    Assert(pcbOutput);
+
+    uint32_t offStart;
+    int rc = GetHeaderValue(pszSource, "StartFragment:", &offStart);
+    if (RT_SUCCESS(rc))
+    {
+        uint32_t offEnd;
+        rc = GetHeaderValue(pszSource, "EndFragment:", &offEnd);
+        if (RT_SUCCESS(rc))
+        {
+            if (   offStart > 0
+                && offEnd > 0
+                && offEnd > offStart
+                && offEnd <= cch)
+            {
+                uint32_t cchSubStr = offEnd - offStart;
+                char *pszResult = (char *)RTMemAlloc(cchSubStr + 1);
+                if (pszResult)
+                {
+                    rc = RTStrCopyEx(pszResult, cchSubStr + 1, pszSource + offStart, cchSubStr);
+                    if (RT_SUCCESS(rc))
+                    {
+                        *ppszOutput = pszResult;
+                        *pcbOutput  = (uint32_t)(cchSubStr + 1);
+                        rc = VINF_SUCCESS;
+                    }
+                    else
+                    {
+                        LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment. rc = %Rrc\n", rc));
+                        RTMemFree(pszResult);
+                    }
+                }
+                else
+                {
+                    LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment.\n"));
+                    rc = VERR_NO_MEMORY;
+                }
+            }
+            else
+            {
+                LogRelFlowFunc(("Error: CF_HTML out of bounds - offStart=%#x offEnd=%#x cch=%#x\n", offStart, offEnd, cch));
+                rc = VERR_INVALID_PARAMETER;
+            }
+        }
+        else
+        {
+            LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment. rc = %Rrc.\n", rc));
+            rc = VERR_INVALID_PARAMETER;
+        }
+    }
+    else
+    {
+        LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected StartFragment. rc = %Rrc.\n", rc));
+        rc = VERR_INVALID_PARAMETER;
+    }
+
+    return rc;
+}
+
+
+
+/**
+ * Converts source UTF-8 MIME HTML clipboard data to UTF-8 CF_HTML format.
+ *
+ * This is just encapsulation work, slapping a header on the data.
+ *
+ * It allocates
+ *
+ * Calculations:
+ *   Header length = format Length + (2*(10 - 5('%010d'))('digits')) - 2('%s') = format length + 8
+ *   EndHtml       = Header length + fragment length
+ *   StartHtml     = 105(constant)
+ *   StartFragment = 141(constant) may vary if the header html content will be extended
+ *   EndFragment   = Header length + fragment length - 38(ending length)
+ *
+ * @param   pszSource   Source buffer that contains utf-16 string in mime html format
+ * @param   cb          Size of source buffer in bytes
+ * @param   ppszOutput  Where to return the allocated output buffer to put converted UTF-8
+ *                      CF_HTML clipboard data.  This function allocates memory for this.
+ * @param   pcbOutput   Where to return the size of allocated result buffer in bytes/chars, including zero terminator
+ *
+ * @note    output buffer should be free using RTMemFree()
+ * @note    Everything inside of fragment can be UTF8. Windows allows it. Everything in header should be Latin1.
+ */
+static int ConvertMimeToCFHTML(const char *pszSource, size_t cb, char **ppszOutput, uint32_t *pcbOutput)
+{
+    Assert(ppszOutput);
+    Assert(pcbOutput);
+    Assert(pszSource);
+    Assert(cb);
+
+    /* construct CF_HTML formatted string */
+    char *pszResult = NULL;
+    size_t cchFragment;
+    int rc = RTStrNLenEx(pszSource, cb, &cchFragment);
+    if (!RT_SUCCESS(rc))
+    {
+        LogRelFlowFunc(("Error: invalid source fragment. rc = %Rrc.\n"));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    /*
+    @StartHtml - pos before <html>
+    @EndHtml - whole size of text excluding ending zero char
+    @StartFragment - pos after <!--StartFragment-->
+    @EndFragment - pos before <!--EndFragment-->
+    @note: all values includes CR\LF inserted into text
+    Calculations:
+    Header length = format Length + (3*6('digits')) - 2('%s') = format length + 16 (control value - 183)
+    EndHtml  = Header length + fragment length
+    StartHtml = 105(constant)
+    StartFragment = 143(constant)
+    EndFragment  = Header length + fragment length - 40(ending length)
+    */
+    static const char s_szFormatSample[] =
+    /*   0:   */ "Version:1.0\r\n"
+    /*  13:   */ "StartHTML:000000101\r\n"
+    /*  34:   */ "EndHTML:%0000009u\r\n" // END HTML = Header length + fragment length
+    /*  53:   */ "StartFragment:000000137\r\n"
+    /*  78:   */ "EndFragment:%0000009u\r\n"
+    /* 101:   */ "<html>\r\n"
+    /* 109:   */ "<body>\r\n"
+    /* 117:   */ "<!--StartFragment-->"
+    /* 137:   */ "%s"
+    /* 137+2: */ "<!--EndFragment-->\r\n"
+    /* 157+2: */ "</body>\r\n"
+    /* 166+2: */ "</html>\r\n";
+    /* 175+2: */
+    AssertCompile(sizeof(s_szFormatSample) == 175+2+1);
+
+    /* calculate parameters of CF_HTML header */
+    size_t cchHeader      = sizeof(s_szFormatSample) - 1;
+    size_t offEndHtml     = cchHeader + cchFragment;
+    size_t offEndFragment = cchHeader + cchFragment - 38; /* 175-137 = 38 */
+    pszResult = (char *)RTMemAlloc(offEndHtml + 1);
+    if (pszResult == NULL)
+    {
+        LogRelFlowFunc(("Error: Cannot allocate memory for result buffer. rc = %Rrc.\n"));
+        return VERR_NO_MEMORY;
+    }
+
+    /* format result CF_HTML string */
+    size_t cchFormatted = RTStrPrintf(pszResult, offEndHtml + 1,
+                                      s_szFormatSample, offEndHtml, offEndFragment, pszSource);
+    Assert(offEndHtml == cchFormatted); NOREF(cchFormatted);
+
+#ifdef VBOX_STRICT
+    /* Control calculations. check consistency.*/
+    static const char s_szStartFragment[] = "<!--StartFragment-->";
+    static const char s_szEndFragment[] = "<!--EndFragment-->";
+
+    /* check 'StartFragment:' value */
+    const char *pszRealStartFragment = RTStrStr(pszResult, s_szStartFragment);
+    Assert(&pszRealStartFragment[sizeof(s_szStartFragment) - 1] - pszResult == 137);
+
+    /* check 'EndFragment:' value */
+    const char *pszRealEndFragment = RTStrStr(pszResult, s_szEndFragment);
+    Assert((size_t)(pszRealEndFragment - pszResult) == offEndFragment);
+#endif
+
+    *ppszOutput = pszResult;
+    *pcbOutput = (uint32_t)cchFormatted + 1;
+    Assert(*pcbOutput == cchFormatted + 1);
+
+    return VINF_SUCCESS;
+}
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11-stubs.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11-stubs.cpp	(revision 78160)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11-stubs.cpp	(revision 78160)
@@ -0,0 +1,137 @@
+/* $Id$*/
+/** @file
+ * Shared Clipboard Service - Linux host, a stub version with no functionality for use on headless hosts.
+ */
+
+/*
+ * Copyright (C) 2006-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
+#include <VBox/HostServices/VBoxClipboardSvc.h>
+
+#include <iprt/alloc.h>
+#include <iprt/asm.h>        /* For atomic operations */
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+#include <iprt/process.h>
+#include <iprt/semaphore.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include "VBoxClipboard.h"
+
+
+
+/** Initialise the host side of the shared clipboard - called by the hgcm layer. */
+int vboxClipboardInit (void)
+{
+    LogFlowFunc(("called, returning VINF_SUCCESS.\n"));
+    return VINF_SUCCESS;
+}
+
+/** Terminate the host side of the shared clipboard - called by the hgcm layer. */
+void vboxClipboardDestroy (void)
+{
+    LogFlowFunc(("called, returning.\n"));
+}
+
+/**
+  * Enable the shared clipboard - called by the hgcm clipboard subsystem.
+  *
+  * @param   pClient    Structure containing context information about the guest system
+  * @param   fHeadless  Whether headless.
+  * @returns RT status code
+  */
+int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient,
+                          bool fHeadless)
+{
+    RT_NOREF(pClient, fHeadless);
+    LogFlowFunc(("called, returning VINF_SUCCESS.\n"));
+    return VINF_SUCCESS;
+}
+
+/**
+ * Synchronise the contents of the host clipboard with the guest, called by the HGCM layer
+ * after a save and restore of the guest.
+ */
+int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA * /* pClient */)
+{
+    LogFlowFunc(("called, returning VINF_SUCCESS.\n"));
+    return VINF_SUCCESS;
+}
+
+/**
+ * Shut down the shared clipboard subsystem and "disconnect" the guest.
+ *
+ * @param   pClient    Structure containing context information about the guest system
+ */
+void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *pClient)
+{
+    RT_NOREF(pClient);
+    LogFlowFunc(("called, returning.\n"));
+}
+
+/**
+ * The guest is taking possession of the shared clipboard.  Called by the HGCM clipboard
+ * subsystem.
+ *
+ * @param pClient    Context data for the guest system
+ * @param u32Formats Clipboard formats the guest is offering
+ */
+void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient,
+                                  uint32_t u32Formats)
+{
+    RT_NOREF(pClient, u32Formats);
+    LogFlowFunc(("called, returning.\n"));
+}
+
+/**
+ * Called by the HGCM clipboard subsystem when the guest wants to read the host clipboard.
+ *
+ * @param pClient   Context information about the guest VM
+ * @param u32Format The format that the guest would like to receive the data in
+ * @param pv        Where to write the data to
+ * @param cb        The size of the buffer to write the data to
+ * @param pcbActual Where to write the actual size of the written data
+ */
+int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Format,
+                           void *pv, uint32_t cb, uint32_t *pcbActual)
+{
+    RT_NOREF(pClient, u32Format, pv, cb);
+    LogFlowFunc(("called, returning VINF_SUCCESS.\n"));
+    /* No data available. */
+    *pcbActual = 0;
+    return VINF_SUCCESS;
+}
+
+/**
+ * Called by the HGCM clipboard subsystem when we have requested data and that data arrives.
+ *
+ * @param pClient   Context information about the guest VM
+ * @param pv        Buffer to which the data was written
+ * @param cb        The size of the data written
+ * @param u32Format The format of the data written
+ */
+void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient, void *pv,
+                             uint32_t cb, uint32_t u32Format)
+{
+    RT_NOREF(pClient, pv, cb, u32Format);
+    LogFlowFunc(("called, returning.\n"));
+}
+
Index: /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11.cpp	(revision 78160)
+++ /trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11.cpp	(revision 78160)
@@ -0,0 +1,615 @@
+/* $Id$ */
+/** @file
+ * Shared Clipboard Service - Linux host.
+ */
+
+/*
+ * Copyright (C) 2006-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
+#include <iprt/assert.h>
+#include <iprt/critsect.h>
+#include <iprt/env.h>
+#include <iprt/mem.h>
+#include <iprt/semaphore.h>
+#include <iprt/string.h>
+
+#include <VBox/GuestHost/SharedClipboard.h>
+#include <VBox/HostServices/VBoxClipboardSvc.h>
+#include <VBox/err.h>
+
+#include "VBoxClipboard.h"
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+struct _VBOXCLIPBOARDREQFROMVBOX;
+typedef struct _VBOXCLIPBOARDREQFROMVBOX VBOXCLIPBOARDREQFROMVBOX;
+
+/** Global context information used by the host glue for the X11 clipboard
+ * backend */
+struct _VBOXCLIPBOARDCONTEXT
+{
+    /** This mutex is grabbed during any critical operations on the clipboard
+     * which might clash with others. */
+    RTCRITSECT clipboardMutex;
+    /** The currently pending request for data from VBox.  NULL if there is
+     * no request pending.  The protocol for completing a request is to grab
+     * the critical section, check that @a pReq is not NULL, fill in the data
+     * fields and set @a pReq to NULL.  The protocol for cancelling a pending
+     * request is to grab the critical section and set pReq to NULL.
+     * It is an error if a request arrives while another one is pending, and
+     * the backend is responsible for ensuring that this does not happen. */
+    VBOXCLIPBOARDREQFROMVBOX *pReq;
+
+    /** Pointer to the opaque X11 backend structure */
+    CLIPBACKEND *pBackend;
+    /** Pointer to the VBox host client data structure. */
+    VBOXCLIPBOARDCLIENTDATA *pClient;
+    /** We set this when we start shutting down as a hint not to post any new
+     * requests. */
+    bool fShuttingDown;
+};
+
+
+
+/**
+ * Report formats available in the X11 clipboard to VBox.
+ * @param  pCtx        Opaque context pointer for the glue code
+ * @param  u32Formats  The formats available
+ * @note  Host glue code
+ */
+void ClipReportX11Formats(VBOXCLIPBOARDCONTEXT *pCtx,
+                                      uint32_t u32Formats)
+{
+    LogRelFlowFunc(("called.  pCtx=%p, u32Formats=%02X\n", pCtx, u32Formats));
+    vboxSvcClipboardReportMsg(pCtx->pClient,
+                              VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS,
+                              u32Formats);
+}
+
+/**
+ * Initialise the host side of the shared clipboard.
+ * @note  Host glue code
+ */
+int vboxClipboardInit (void)
+{
+    return VINF_SUCCESS;
+}
+
+/**
+ * Terminate the host side of the shared clipboard.
+ * @note  host glue code
+ */
+void vboxClipboardDestroy (void)
+{
+
+}
+
+/**
+ * Connect a guest to the shared clipboard.
+ * @note  host glue code
+ * @note  on the host, we assume that some other application already owns
+ *        the clipboard and leave ownership to X11.
+ */
+int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient, bool fHeadless)
+{
+    int rc = VINF_SUCCESS;
+    CLIPBACKEND *pBackend = NULL;
+
+    LogRel(("Starting host clipboard service\n"));
+    VBOXCLIPBOARDCONTEXT *pCtx =
+        (VBOXCLIPBOARDCONTEXT *) RTMemAllocZ(sizeof(VBOXCLIPBOARDCONTEXT));
+    if (!pCtx)
+        rc = VERR_NO_MEMORY;
+    else
+    {
+        RTCritSectInit(&pCtx->clipboardMutex);
+        pBackend = ClipConstructX11(pCtx, fHeadless);
+        if (pBackend == NULL)
+            rc = VERR_NO_MEMORY;
+        else
+        {
+            pCtx->pBackend = pBackend;
+            pClient->pCtx = pCtx;
+            pCtx->pClient = pClient;
+            rc = ClipStartX11(pBackend, true /* grab shared clipboard */);
+        }
+        if (RT_FAILURE(rc))
+            RTCritSectDelete(&pCtx->clipboardMutex);
+    }
+    if (RT_FAILURE(rc))
+    {
+        RTMemFree(pCtx);
+        LogRel(("Failed to initialise the shared clipboard\n"));
+    }
+    LogRelFlowFunc(("returning %Rrc\n", rc));
+    return rc;
+}
+
+/**
+ * Synchronise the contents of the host clipboard with the guest, called
+ * after a save and restore of the guest.
+ * @note  Host glue code
+ */
+int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA *pClient)
+{
+    /* Tell the guest we have no data in case X11 is not available.  If
+     * there is data in the host clipboard it will automatically be sent to
+     * the guest when the clipboard starts up. */
+    vboxSvcClipboardReportMsg (pClient,
+                               VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, 0);
+    return VINF_SUCCESS;
+}
+
+/**
+ * Shut down the shared clipboard service and "disconnect" the guest.
+ * @note  Host glue code
+ */
+void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *pClient)
+{
+    LogRelFlow(("vboxClipboardDisconnect\n"));
+
+    LogRel(("Stopping the host clipboard service\n"));
+    VBOXCLIPBOARDCONTEXT *pCtx = pClient->pCtx;
+    /* Drop the reference to the client, in case it is still there.  This
+     * will cause any outstanding clipboard data requests from X11 to fail
+     * immediately. */
+    pCtx->fShuttingDown = true;
+    /* If there is a currently pending request, release it immediately. */
+    vboxClipboardWriteData(pClient, NULL, 0, 0);
+    int rc = ClipStopX11(pCtx->pBackend);
+    /** @todo handle this slightly more reasonably, or be really sure
+     *        it won't go wrong. */
+    AssertRC(rc);
+    if (RT_SUCCESS(rc))  /* And if not? */
+    {
+        ClipDestructX11(pCtx->pBackend);
+        RTCritSectDelete(&pCtx->clipboardMutex);
+        RTMemFree(pCtx);
+    }
+}
+
+/**
+ * VBox is taking possession of the shared clipboard.
+ *
+ * @param pClient    Context data for the guest system
+ * @param u32Formats Clipboard formats the guest is offering
+ * @note  Host glue code
+ */
+void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient,
+                                  uint32_t u32Formats)
+{
+    LogRelFlowFunc(("called.  pClient=%p, u32Formats=%02X\n", pClient,
+                 u32Formats));
+    ClipAnnounceFormatToX11 (pClient->pCtx->pBackend, u32Formats);
+}
+
+/** Structure describing a request for clipoard data from the guest. */
+struct _CLIPREADCBREQ
+{
+    /** Where to write the returned data to. */
+    void *pv;
+    /** The size of the buffer in pv */
+    uint32_t cb;
+    /** The actual size of the data written */
+    uint32_t *pcbActual;
+};
+
+/**
+ * Called when VBox wants to read the X11 clipboard.
+ *
+ * @returns VINF_SUCCESS on successful completion
+ * @returns VINF_HGCM_ASYNC_EXECUTE if the operation will complete
+ *          asynchronously
+ * @returns iprt status code on failure
+ * @param  pClient   Context information about the guest VM
+ * @param  u32Format The format that the guest would like to receive the data in
+ * @param  pv        Where to write the data to
+ * @param  cb        The size of the buffer to write the data to
+ * @param  pcbActual Where to write the actual size of the written data
+ * @note   We always fail or complete asynchronously
+ * @note   On success allocates a CLIPREADCBREQ structure which must be
+ *         freed in ClipCompleteDataRequestFromX11 when it is called back from
+ *         the backend code.
+ *
+ */
+int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient,
+                           uint32_t u32Format, void *pv, uint32_t cb,
+                           uint32_t *pcbActual)
+{
+    LogRelFlowFunc(("pClient=%p, u32Format=%02X, pv=%p, cb=%u, pcbActual=%p",
+                 pClient, u32Format, pv, cb, pcbActual));
+
+    int rc = VINF_SUCCESS;
+    CLIPREADCBREQ *pReq = (CLIPREADCBREQ *) RTMemAlloc(sizeof(CLIPREADCBREQ));
+    if (!pReq)
+        rc = VERR_NO_MEMORY;
+    else
+    {
+        pReq->pv = pv;
+        pReq->cb = cb;
+        pReq->pcbActual = pcbActual;
+        rc = ClipRequestDataFromX11(pClient->pCtx->pBackend, u32Format, pReq);
+        if (RT_SUCCESS(rc))
+            rc = VINF_HGCM_ASYNC_EXECUTE;
+    }
+    LogRelFlowFunc(("returning %Rrc\n", rc));
+    return rc;
+}
+
+/**
+ * Complete a request from VBox for the X11 clipboard data.  The data should
+ * be written to the buffer provided in the initial request.
+ * @param  pCtx  request context information
+ * @param  rc    the completion status of the request
+ * @param  pReq  request
+ * @param  pv    address
+ * @param  cb    size
+ *
+ * @todo   change this to deal with the buffer issues rather than offloading
+ *         them onto the caller
+ */
+void ClipCompleteDataRequestFromX11(VBOXCLIPBOARDCONTEXT *pCtx, int rc,
+                                    CLIPREADCBREQ *pReq, void *pv, uint32_t cb)
+{
+    if (cb <= pReq->cb && cb != 0)
+        memcpy(pReq->pv, pv, cb);
+    RTMemFree(pReq);
+    vboxSvcClipboardCompleteReadData(pCtx->pClient, rc, cb);
+}
+
+/** A request for clipboard data from VBox */
+struct _VBOXCLIPBOARDREQFROMVBOX
+{
+    /** Data received */
+    void *pv;
+    /** The size of the data */
+    uint32_t cb;
+    /** Format of the data */
+    uint32_t format;
+    /** A semaphore for waiting for the data */
+    RTSEMEVENT finished;
+};
+
+/** Wait for clipboard data requested from VBox to arrive. */
+static int clipWaitForDataFromVBox(VBOXCLIPBOARDCONTEXT *pCtx,
+                                   VBOXCLIPBOARDREQFROMVBOX *pReq,
+                                   uint32_t u32Format)
+{
+    int rc = VINF_SUCCESS;
+    LogRelFlowFunc(("pCtx=%p, pReq=%p, u32Format=%02X\n", pCtx, pReq, u32Format));
+    /* Request data from VBox */
+    vboxSvcClipboardReportMsg(pCtx->pClient,
+                              VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA,
+                              u32Format);
+    /* Which will signal us when it is ready.  We use a timeout here
+     * because we can't be sure that the guest will behave correctly.
+     */
+    rc = RTSemEventWait(pReq->finished, CLIPBOARD_TIMEOUT);
+    /* If the request hasn't yet completed then we cancel it.  We use
+     * the critical section to prevent these operations colliding. */
+    RTCritSectEnter(&pCtx->clipboardMutex);
+    /* The data may have arrived between the semaphore timing out and
+     * our grabbing the mutex. */
+    if (rc == VERR_TIMEOUT && pReq->pv != NULL)
+        rc = VINF_SUCCESS;
+    if (pCtx->pReq == pReq)
+        pCtx->pReq = NULL;
+    Assert(pCtx->pReq == NULL);
+    RTCritSectLeave(&pCtx->clipboardMutex);
+    if (RT_SUCCESS(rc) && (pReq->pv == NULL))
+        rc = VERR_NO_DATA;
+    LogRelFlowFunc(("returning %Rrc\n", rc));
+    return rc;
+}
+
+/** Post a request for clipboard data to VBox/the guest and wait for it to be
+ * completed. */
+static int clipRequestDataFromVBox(VBOXCLIPBOARDCONTEXT *pCtx,
+                                          VBOXCLIPBOARDREQFROMVBOX *pReq,
+                                          uint32_t u32Format)
+{
+    int rc = VINF_SUCCESS;
+    LogRelFlowFunc(("pCtx=%p, pReq=%p, u32Format=%02X\n", pCtx, pReq,
+                 u32Format));
+    /* Start by "posting" the request for the next invocation of
+     * vboxClipboardWriteData. */
+    RTCritSectEnter(&pCtx->clipboardMutex);
+    if (pCtx->pReq != NULL)
+    {
+        /* This would be a violation of the protocol, see the comments in the
+         * context structure definition. */
+        Assert(false);
+        rc = VERR_WRONG_ORDER;
+    }
+    else
+        pCtx->pReq = pReq;
+    RTCritSectLeave(&pCtx->clipboardMutex);
+    if (RT_SUCCESS(rc))
+        rc = clipWaitForDataFromVBox(pCtx, pReq, u32Format);
+    LogRelFlowFunc(("returning %Rrc\n", rc));
+    return rc;
+}
+
+/**
+ * Send a request to VBox to transfer the contents of its clipboard to X11.
+ *
+ * @param  pCtx      Pointer to the host clipboard structure
+ * @param  u32Format The format in which the data should be transferred
+ * @param  ppv       On success and if pcb > 0, this will point to a buffer
+ *                   to be freed with RTMemFree containing the data read.
+ * @param  pcb       On success, this contains the number of bytes of data
+ *                   returned
+ * @note   Host glue code.
+ */
+int ClipRequestDataForX11 (VBOXCLIPBOARDCONTEXT *pCtx,
+                                   uint32_t u32Format, void **ppv,
+                                   uint32_t *pcb)
+{
+    VBOXCLIPBOARDREQFROMVBOX request = { NULL, 0, 0, NIL_RTSEMEVENT };
+
+    LogRelFlowFunc(("pCtx=%p, u32Format=%02X, ppv=%p, pcb=%p\n", pCtx,
+                 u32Format, ppv, pcb));
+    if (pCtx->fShuttingDown)
+    {
+        /* The shared clipboard is disconnecting. */
+        LogRelFunc(("host requested guest clipboard data after guest had disconnected.\n"));
+        return VERR_WRONG_ORDER;
+    }
+    int rc = RTSemEventCreate(&request.finished);
+    if (RT_SUCCESS(rc))
+    {
+        rc = clipRequestDataFromVBox(pCtx, &request, u32Format);
+        RTSemEventDestroy(request.finished);
+    }
+    if (RT_SUCCESS(rc))
+    {
+        *ppv = request.pv;
+        *pcb = request.cb;
+    }
+    LogRelFlowFunc(("returning %Rrc\n", rc));
+    if (RT_SUCCESS(rc))
+        LogRelFlowFunc(("*ppv=%.*ls, *pcb=%u\n", *pcb / 2, *ppv, *pcb));
+    return rc;
+}
+
+/**
+ * Called when we have requested data from VBox and that data has arrived.
+ *
+ * @param  pClient   Context information about the guest VM
+ * @param  pv        Buffer to which the data was written
+ * @param  cb        The size of the data written
+ * @param  u32Format The format of the data written
+ * @note   Host glue code
+ */
+void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient,
+                             void *pv, uint32_t cb, uint32_t u32Format)
+{
+    LogRelFlowFunc (("called.  pClient=%p, pv=%p (%.*ls), cb=%u, u32Format=%02X\n",
+                  pClient, pv, cb / 2, pv, cb, u32Format));
+
+    VBOXCLIPBOARDCONTEXT *pCtx = pClient->pCtx;
+    /* Grab the mutex and check whether there is a pending request for data.
+     */
+    RTCritSectEnter(&pCtx->clipboardMutex);
+    VBOXCLIPBOARDREQFROMVBOX *pReq = pCtx->pReq;
+    if (pReq != NULL)
+    {
+        if (cb > 0)
+        {
+            pReq->pv = RTMemDup(pv, cb);
+            if (pReq->pv != NULL)  /* NULL may also mean no memory... */
+            {
+                pReq->cb = cb;
+                pReq->format = u32Format;
+            }
+        }
+        /* Signal that the request has been completed. */
+        RTSemEventSignal(pReq->finished);
+        pCtx->pReq = NULL;
+    }
+    RTCritSectLeave(&pCtx->clipboardMutex);
+}
+
+#ifdef TESTCASE
+#include <iprt/initterm.h>
+#include <iprt/stream.h>
+
+#define TEST_NAME "tstClipboardX11-2"
+
+struct _CLIPBACKEND
+{
+    uint32_t formats;
+    struct _READDATA
+    {
+        uint32_t format;
+        int rc;
+        CLIPREADCBREQ *pReq;
+    } readData;
+    struct _COMPLETEREAD
+    {
+        int rc;
+        uint32_t cbActual;
+    } completeRead;
+    struct _WRITEDATA
+    {
+        void *pv;
+        uint32_t cb;
+        uint32_t format;
+        bool timeout;
+    } writeData;
+    struct _REPORTDATA
+    {
+        uint32_t format;
+    } reportData;
+};
+
+void vboxSvcClipboardReportMsg (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Msg, uint32_t u32Formats)
+{
+    RT_NOREF1(u32Formats);
+    CLIPBACKEND *pBackend = pClient->pCtx->pBackend;
+    if (   (u32Msg == VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA)
+        && !pBackend->writeData.timeout)
+        vboxClipboardWriteData(pClient, pBackend->writeData.pv,
+                               pBackend->writeData.cb,
+                               pBackend->writeData.format);
+    else
+        return;
+}
+
+void vboxSvcClipboardCompleteReadData(VBOXCLIPBOARDCLIENTDATA *pClient, int rc, uint32_t cbActual)
+{
+    CLIPBACKEND *pBackend = pClient->pCtx->pBackend;
+    pBackend->completeRead.rc = rc;
+    pBackend->completeRead.cbActual = cbActual;
+}
+
+CLIPBACKEND *ClipConstructX11(VBOXCLIPBOARDCONTEXT *pFrontend, bool)
+{
+    RT_NOREF1(pFrontend);
+    return (CLIPBACKEND *)RTMemAllocZ(sizeof(CLIPBACKEND));
+}
+
+void ClipDestructX11(CLIPBACKEND *pBackend)
+{
+    RTMemFree(pBackend);
+}
+
+int ClipStartX11(CLIPBACKEND *pBackend, bool)
+{
+    RT_NOREF1(pBackend);
+    return VINF_SUCCESS;
+}
+
+int ClipStopX11(CLIPBACKEND *pBackend)
+{
+    RT_NOREF1(pBackend);
+    return VINF_SUCCESS;
+}
+
+void ClipAnnounceFormatToX11(CLIPBACKEND *pBackend,
+                                    uint32_t u32Formats)
+{
+    pBackend->formats = u32Formats;
+}
+
+extern int ClipRequestDataFromX11(CLIPBACKEND *pBackend, uint32_t u32Format,
+                                  CLIPREADCBREQ *pReq)
+{
+    pBackend->readData.format = u32Format;
+    pBackend->readData.pReq = pReq;
+    return pBackend->readData.rc;
+}
+
+int main()
+{
+    VBOXCLIPBOARDCLIENTDATA client;
+    unsigned cErrors = 0;
+    int rc = RTR3InitExeNoArguments(0);
+    RTPrintf(TEST_NAME ": TESTING\n");
+    AssertRCReturn(rc, 1);
+    rc = vboxClipboardConnect(&client, false);
+    CLIPBACKEND *pBackend = client.pCtx->pBackend;
+    AssertRCReturn(rc, 1);
+    vboxClipboardFormatAnnounce(&client,
+                                VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
+    if (pBackend->formats != VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
+    {
+        RTPrintf(TEST_NAME ": vboxClipboardFormatAnnounce failed with VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT\n");
+        ++cErrors;
+    }
+    pBackend->readData.rc = VINF_SUCCESS;
+    client.asyncRead.callHandle = (VBOXHGCMCALLHANDLE)pBackend;
+    client.asyncRead.paParms = (VBOXHGCMSVCPARM *)&client;
+    uint32_t u32Dummy;
+    rc = vboxClipboardReadData(&client, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
+                               &u32Dummy, 42, &u32Dummy);
+    if (rc != VINF_HGCM_ASYNC_EXECUTE)
+    {
+        RTPrintf(TEST_NAME ": vboxClipboardReadData returned %Rrc\n", rc);
+        ++cErrors;
+    }
+    else
+    {
+        if (   pBackend->readData.format !=
+                       VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT
+            || pBackend->readData.pReq->pv != &u32Dummy
+            || pBackend->readData.pReq->cb != 42
+            || pBackend->readData.pReq->pcbActual != &u32Dummy)
+        {
+            RTPrintf(TEST_NAME ": format=%u, pReq->pv=%p, pReq->cb=%u, pReq->pcbActual=%p\n",
+                     pBackend->readData.format, pBackend->readData.pReq->pv,
+                     pBackend->readData.pReq->cb,
+                     pBackend->readData.pReq->pcbActual);
+            ++cErrors;
+        }
+        else
+        {
+            ClipCompleteDataRequestFromX11(client.pCtx, VERR_NO_DATA,
+                                           pBackend->readData.pReq, NULL, 43);
+            if (   pBackend->completeRead.rc != VERR_NO_DATA
+                || pBackend->completeRead.cbActual != 43)
+            {
+                RTPrintf(TEST_NAME ": rc=%Rrc, cbActual=%u\n",
+                         pBackend->completeRead.rc,
+                         pBackend->completeRead.cbActual);
+                ++cErrors;
+            }
+        }
+    }
+    void *pv;
+    uint32_t cb;
+    pBackend->writeData.pv = (void *)"testing";
+    pBackend->writeData.cb = sizeof("testing");
+    pBackend->writeData.format = 1234;
+    pBackend->reportData.format = 4321;  /* XX this should be handled! */
+    rc = ClipRequestDataForX11(client.pCtx, 23, &pv, &cb);
+    if (   rc != VINF_SUCCESS
+        || strcmp((const char *)pv, "testing") != 0
+        || cb != sizeof("testing"))
+    {
+        RTPrintf("rc=%Rrc, pv=%p, cb=%u\n", rc, pv, cb);
+        ++cErrors;
+    }
+    else
+        RTMemFree(pv);
+    pBackend->writeData.timeout = true;
+    rc = ClipRequestDataForX11(client.pCtx, 23, &pv, &cb);
+    if (rc != VERR_TIMEOUT)
+    {
+        RTPrintf("rc=%Rrc, expected VERR_TIMEOUT\n", rc);
+        ++cErrors;
+    }
+    pBackend->writeData.pv = NULL;
+    pBackend->writeData.cb = 0;
+    pBackend->writeData.timeout = false;
+    rc = ClipRequestDataForX11(client.pCtx, 23, &pv, &cb);
+    if (rc != VERR_NO_DATA)
+    {
+        RTPrintf("rc=%Rrc, expected VERR_NO_DATA\n", rc);
+        ++cErrors;
+    }
+    /* Data arriving after a timeout should *not* cause any segfaults or
+     * memory leaks.  Check with Valgrind! */
+    vboxClipboardWriteData(&client, (void *)"tested", sizeof("tested"), 999);
+    vboxClipboardDisconnect(&client);
+    if (cErrors > 0)
+        RTPrintf(TEST_NAME ": errors: %u\n", cErrors);
+    return cErrors > 0 ? 1 : 0;
+}
+#endif  /* TESTCASE */
Index: unk/src/VBox/HostServices/SharedClipboard/darwin.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/darwin.cpp	(revision 78159)
+++ 	(revision )
@@ -1,274 +1,0 @@
-/* $Id$ */
-/** @file
- * Shared Clipboard Service - Mac OS X host.
- */
-
-/*
- * Copyright (C) 2008-2019 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*********************************************************************************************************************************
-*   Header Files                                                                                                                 *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
-#include <VBox/HostServices/VBoxClipboardSvc.h>
-
-#include <iprt/assert.h>
-#include <iprt/asm.h>
-#include <iprt/thread.h>
-
-#include "VBoxClipboard.h"
-#include "darwin-pasteboard.h"
-
-
-/*********************************************************************************************************************************
-*   Structures and Typedefs                                                                                                      *
-*********************************************************************************************************************************/
-/** Global clipboard context information */
-struct _VBOXCLIPBOARDCONTEXT
-{
-    /** We have a separate thread to poll for new clipboard content */
-    RTTHREAD thread;
-    bool volatile fTerminate;
-
-    /** The reference to the current pasteboard */
-    PasteboardRef pasteboard;
-
-    VBOXCLIPBOARDCLIENTDATA *pClient;
-};
-
-
-/*********************************************************************************************************************************
-*   Global Variables                                                                                                             *
-*********************************************************************************************************************************/
-/** Only one client is supported. There seems to be no need for more clients. */
-static VBOXCLIPBOARDCONTEXT g_ctx;
-
-
-/**
- * Checks if something is present on the clipboard and calls vboxSvcClipboardReportMsg.
- *
- * @returns IPRT status code (ignored).
- * @param   pCtx    The context.
- */
-static int vboxClipboardChanged (VBOXCLIPBOARDCONTEXT *pCtx)
-{
-    if (pCtx->pClient == NULL)
-        return VINF_SUCCESS;
-
-    uint32_t fFormats = 0;
-    bool fChanged = false;
-    /* Retrieve the formats currently in the clipboard and supported by vbox */
-    int rc = queryNewPasteboardFormats (pCtx->pasteboard, &fFormats, &fChanged);
-    if (RT_SUCCESS (rc) && fChanged)
-    {
-        vboxSvcClipboardReportMsg (pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, fFormats);
-        Log (("vboxClipboardChanged fFormats %02X\n", fFormats));
-    }
-
-    return rc;
-}
-
-
-/**
- * The poller thread.
- *
- * This thread will check for the arrival of new data on the clipboard.
- *
- * @returns VINF_SUCCESS (not used).
- * @param   ThreadSelf  Our thread handle.
- * @param   pvUser      Pointer to the VBOXCLIPBOARDCONTEXT structure.
- *
- */
-static int vboxClipboardThread (RTTHREAD ThreadSelf, void *pvUser)
-{
-    Log (("vboxClipboardThread: starting clipboard thread\n"));
-
-    AssertPtrReturn (pvUser, VERR_INVALID_PARAMETER);
-    VBOXCLIPBOARDCONTEXT *pCtx = (VBOXCLIPBOARDCONTEXT *) pvUser;
-
-    while (!pCtx->fTerminate)
-    {
-        /* call this behind the lock because we don't know if the api is
-           thread safe and in any case we're calling several methods. */
-        VBoxSvcClipboardLock();
-        vboxClipboardChanged (pCtx);
-        VBoxSvcClipboardUnlock();
-
-        /* Sleep for 200 msecs before next poll */
-        RTThreadUserWait (ThreadSelf, 200);
-    }
-
-    Log (("vboxClipboardThread: clipboard thread terminated successfully with return code %Rrc\n", VINF_SUCCESS));
-    return VINF_SUCCESS;
-}
-
-/*
- * Public platform dependent functions.
- */
-
-/** Initialise the host side of the shared clipboard - called by the hgcm layer. */
-int vboxClipboardInit (void)
-{
-    Log (("vboxClipboardInit\n"));
-
-    g_ctx.fTerminate = false;
-
-    int rc = initPasteboard (&g_ctx.pasteboard);
-    AssertRCReturn (rc, rc);
-
-    rc = RTThreadCreate (&g_ctx.thread, vboxClipboardThread, &g_ctx, 0,
-                         RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
-    if (RT_FAILURE (rc))
-    {
-        g_ctx.thread = NIL_RTTHREAD;
-        destroyPasteboard (&g_ctx.pasteboard);
-    }
-
-    return rc;
-}
-
-/** Terminate the host side of the shared clipboard - called by the hgcm layer. */
-void vboxClipboardDestroy (void)
-{
-    Log (("vboxClipboardDestroy\n"));
-
-    /*
-     * Signal the termination of the polling thread and wait for it to respond.
-     */
-    ASMAtomicWriteBool (&g_ctx.fTerminate, true);
-    int rc = RTThreadUserSignal (g_ctx.thread);
-    AssertRC (rc);
-    rc = RTThreadWait (g_ctx.thread, RT_INDEFINITE_WAIT, NULL);
-    AssertRC (rc);
-
-    /*
-     * Destroy the pasteboard and uninitialize the global context record.
-     */
-    destroyPasteboard (&g_ctx.pasteboard);
-    g_ctx.thread = NIL_RTTHREAD;
-    g_ctx.pClient = NULL;
-}
-
-/**
- * Enable the shared clipboard - called by the hgcm clipboard subsystem.
- *
- * @param   pClient Structure containing context information about the guest system
- * @param   fHeadless Whether headless.
- * @returns RT status code
- */
-int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient, bool fHeadless)
-{
-    NOREF(fHeadless);
-    if (g_ctx.pClient != NULL)
-    {
-        /* One client only. */
-        return VERR_NOT_SUPPORTED;
-    }
-
-    VBoxSvcClipboardLock();
-
-    pClient->pCtx = &g_ctx;
-    pClient->pCtx->pClient = pClient;
-
-    /* Initially sync the host clipboard content with the client. */
-    int rc = vboxClipboardSync (pClient);
-
-    VBoxSvcClipboardUnlock();
-    return rc;
-}
-
-/**
- * Synchronise the contents of the host clipboard with the guest, called by the HGCM layer
- * after a save and restore of the guest.
- */
-int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA *pClient)
-{
-    /* Sync the host clipboard content with the client. */
-    VBoxSvcClipboardLock();
-    int rc = vboxClipboardChanged (pClient->pCtx);
-    VBoxSvcClipboardUnlock();
-
-    return rc;
-}
-
-/**
- * Shut down the shared clipboard subsystem and "disconnect" the guest.
- */
-void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *pClient)
-{
-    Log (("vboxClipboardDisconnect\n"));
-
-    VBoxSvcClipboardLock();
-    pClient->pCtx->pClient = NULL;
-    VBoxSvcClipboardUnlock();
-}
-
-/**
- * The guest is taking possession of the shared clipboard.  Called by the HGCM clipboard
- * subsystem.
- *
- * @param pClient    Context data for the guest system
- * @param u32Formats Clipboard formats the guest is offering
- */
-void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Formats)
-{
-    Log (("vboxClipboardFormatAnnounce u32Formats %02X\n", u32Formats));
-    if (u32Formats == 0)
-    {
-        /* This is just an automatism, not a genuine announcement */
-        return;
-    }
-
-    vboxSvcClipboardReportMsg (pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA,
-                               u32Formats);
-}
-
-/**
- * Called by the HGCM clipboard subsystem when the guest wants to read the host clipboard.
- *
- * @param pClient   Context information about the guest VM
- * @param u32Format The format that the guest would like to receive the data in
- * @param pv        Where to write the data to
- * @param cb        The size of the buffer to write the data to
- * @param pcbActual Where to write the actual size of the written data
- */
-int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Format,
-                           void *pv, uint32_t cb, uint32_t * pcbActual)
-{
-    VBoxSvcClipboardLock();
-
-    /* Default to no data available. */
-    *pcbActual = 0;
-    int rc = readFromPasteboard (pClient->pCtx->pasteboard, u32Format, pv, cb, pcbActual);
-
-    VBoxSvcClipboardUnlock();
-    return rc;
-}
-
-/**
- * Called by the HGCM clipboard subsystem when we have requested data and that data arrives.
- *
- * @param pClient   Context information about the guest VM
- * @param pv        Buffer to which the data was written
- * @param cb        The size of the data written
- * @param u32Format The format of the data written
- */
-void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient, void *pv,
-                             uint32_t cb, uint32_t u32Format)
-{
-    VBoxSvcClipboardLock();
-
-    writeToPasteboard (pClient->pCtx->pasteboard, pv, cb, u32Format);
-
-    VBoxSvcClipboardUnlock();
-}
Index: unk/src/VBox/HostServices/SharedClipboard/x11-clipboard.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/x11-clipboard.cpp	(revision 78159)
+++ 	(revision )
@@ -1,615 +1,0 @@
-/* $Id$ */
-/** @file
- * Shared Clipboard Service - Linux host.
- */
-
-/*
- * Copyright (C) 2006-2019 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*********************************************************************************************************************************
-*   Header Files                                                                                                                 *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
-#include <iprt/assert.h>
-#include <iprt/critsect.h>
-#include <iprt/env.h>
-#include <iprt/mem.h>
-#include <iprt/semaphore.h>
-#include <iprt/string.h>
-
-#include <VBox/GuestHost/SharedClipboard.h>
-#include <VBox/HostServices/VBoxClipboardSvc.h>
-#include <VBox/err.h>
-
-#include "VBoxClipboard.h"
-
-
-/*********************************************************************************************************************************
-*   Structures and Typedefs                                                                                                      *
-*********************************************************************************************************************************/
-struct _VBOXCLIPBOARDREQFROMVBOX;
-typedef struct _VBOXCLIPBOARDREQFROMVBOX VBOXCLIPBOARDREQFROMVBOX;
-
-/** Global context information used by the host glue for the X11 clipboard
- * backend */
-struct _VBOXCLIPBOARDCONTEXT
-{
-    /** This mutex is grabbed during any critical operations on the clipboard
-     * which might clash with others. */
-    RTCRITSECT clipboardMutex;
-    /** The currently pending request for data from VBox.  NULL if there is
-     * no request pending.  The protocol for completing a request is to grab
-     * the critical section, check that @a pReq is not NULL, fill in the data
-     * fields and set @a pReq to NULL.  The protocol for cancelling a pending
-     * request is to grab the critical section and set pReq to NULL.
-     * It is an error if a request arrives while another one is pending, and
-     * the backend is responsible for ensuring that this does not happen. */
-    VBOXCLIPBOARDREQFROMVBOX *pReq;
-
-    /** Pointer to the opaque X11 backend structure */
-    CLIPBACKEND *pBackend;
-    /** Pointer to the VBox host client data structure. */
-    VBOXCLIPBOARDCLIENTDATA *pClient;
-    /** We set this when we start shutting down as a hint not to post any new
-     * requests. */
-    bool fShuttingDown;
-};
-
-
-
-/**
- * Report formats available in the X11 clipboard to VBox.
- * @param  pCtx        Opaque context pointer for the glue code
- * @param  u32Formats  The formats available
- * @note  Host glue code
- */
-void ClipReportX11Formats(VBOXCLIPBOARDCONTEXT *pCtx,
-                                      uint32_t u32Formats)
-{
-    LogRelFlowFunc(("called.  pCtx=%p, u32Formats=%02X\n", pCtx, u32Formats));
-    vboxSvcClipboardReportMsg(pCtx->pClient,
-                              VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS,
-                              u32Formats);
-}
-
-/**
- * Initialise the host side of the shared clipboard.
- * @note  Host glue code
- */
-int vboxClipboardInit (void)
-{
-    return VINF_SUCCESS;
-}
-
-/**
- * Terminate the host side of the shared clipboard.
- * @note  host glue code
- */
-void vboxClipboardDestroy (void)
-{
-
-}
-
-/**
- * Connect a guest to the shared clipboard.
- * @note  host glue code
- * @note  on the host, we assume that some other application already owns
- *        the clipboard and leave ownership to X11.
- */
-int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient, bool fHeadless)
-{
-    int rc = VINF_SUCCESS;
-    CLIPBACKEND *pBackend = NULL;
-
-    LogRel(("Starting host clipboard service\n"));
-    VBOXCLIPBOARDCONTEXT *pCtx =
-        (VBOXCLIPBOARDCONTEXT *) RTMemAllocZ(sizeof(VBOXCLIPBOARDCONTEXT));
-    if (!pCtx)
-        rc = VERR_NO_MEMORY;
-    else
-    {
-        RTCritSectInit(&pCtx->clipboardMutex);
-        pBackend = ClipConstructX11(pCtx, fHeadless);
-        if (pBackend == NULL)
-            rc = VERR_NO_MEMORY;
-        else
-        {
-            pCtx->pBackend = pBackend;
-            pClient->pCtx = pCtx;
-            pCtx->pClient = pClient;
-            rc = ClipStartX11(pBackend, true /* grab shared clipboard */);
-        }
-        if (RT_FAILURE(rc))
-            RTCritSectDelete(&pCtx->clipboardMutex);
-    }
-    if (RT_FAILURE(rc))
-    {
-        RTMemFree(pCtx);
-        LogRel(("Failed to initialise the shared clipboard\n"));
-    }
-    LogRelFlowFunc(("returning %Rrc\n", rc));
-    return rc;
-}
-
-/**
- * Synchronise the contents of the host clipboard with the guest, called
- * after a save and restore of the guest.
- * @note  Host glue code
- */
-int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA *pClient)
-{
-    /* Tell the guest we have no data in case X11 is not available.  If
-     * there is data in the host clipboard it will automatically be sent to
-     * the guest when the clipboard starts up. */
-    vboxSvcClipboardReportMsg (pClient,
-                               VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, 0);
-    return VINF_SUCCESS;
-}
-
-/**
- * Shut down the shared clipboard service and "disconnect" the guest.
- * @note  Host glue code
- */
-void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *pClient)
-{
-    LogRelFlow(("vboxClipboardDisconnect\n"));
-
-    LogRel(("Stopping the host clipboard service\n"));
-    VBOXCLIPBOARDCONTEXT *pCtx = pClient->pCtx;
-    /* Drop the reference to the client, in case it is still there.  This
-     * will cause any outstanding clipboard data requests from X11 to fail
-     * immediately. */
-    pCtx->fShuttingDown = true;
-    /* If there is a currently pending request, release it immediately. */
-    vboxClipboardWriteData(pClient, NULL, 0, 0);
-    int rc = ClipStopX11(pCtx->pBackend);
-    /** @todo handle this slightly more reasonably, or be really sure
-     *        it won't go wrong. */
-    AssertRC(rc);
-    if (RT_SUCCESS(rc))  /* And if not? */
-    {
-        ClipDestructX11(pCtx->pBackend);
-        RTCritSectDelete(&pCtx->clipboardMutex);
-        RTMemFree(pCtx);
-    }
-}
-
-/**
- * VBox is taking possession of the shared clipboard.
- *
- * @param pClient    Context data for the guest system
- * @param u32Formats Clipboard formats the guest is offering
- * @note  Host glue code
- */
-void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient,
-                                  uint32_t u32Formats)
-{
-    LogRelFlowFunc(("called.  pClient=%p, u32Formats=%02X\n", pClient,
-                 u32Formats));
-    ClipAnnounceFormatToX11 (pClient->pCtx->pBackend, u32Formats);
-}
-
-/** Structure describing a request for clipoard data from the guest. */
-struct _CLIPREADCBREQ
-{
-    /** Where to write the returned data to. */
-    void *pv;
-    /** The size of the buffer in pv */
-    uint32_t cb;
-    /** The actual size of the data written */
-    uint32_t *pcbActual;
-};
-
-/**
- * Called when VBox wants to read the X11 clipboard.
- *
- * @returns VINF_SUCCESS on successful completion
- * @returns VINF_HGCM_ASYNC_EXECUTE if the operation will complete
- *          asynchronously
- * @returns iprt status code on failure
- * @param  pClient   Context information about the guest VM
- * @param  u32Format The format that the guest would like to receive the data in
- * @param  pv        Where to write the data to
- * @param  cb        The size of the buffer to write the data to
- * @param  pcbActual Where to write the actual size of the written data
- * @note   We always fail or complete asynchronously
- * @note   On success allocates a CLIPREADCBREQ structure which must be
- *         freed in ClipCompleteDataRequestFromX11 when it is called back from
- *         the backend code.
- *
- */
-int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient,
-                           uint32_t u32Format, void *pv, uint32_t cb,
-                           uint32_t *pcbActual)
-{
-    LogRelFlowFunc(("pClient=%p, u32Format=%02X, pv=%p, cb=%u, pcbActual=%p",
-                 pClient, u32Format, pv, cb, pcbActual));
-
-    int rc = VINF_SUCCESS;
-    CLIPREADCBREQ *pReq = (CLIPREADCBREQ *) RTMemAlloc(sizeof(CLIPREADCBREQ));
-    if (!pReq)
-        rc = VERR_NO_MEMORY;
-    else
-    {
-        pReq->pv = pv;
-        pReq->cb = cb;
-        pReq->pcbActual = pcbActual;
-        rc = ClipRequestDataFromX11(pClient->pCtx->pBackend, u32Format, pReq);
-        if (RT_SUCCESS(rc))
-            rc = VINF_HGCM_ASYNC_EXECUTE;
-    }
-    LogRelFlowFunc(("returning %Rrc\n", rc));
-    return rc;
-}
-
-/**
- * Complete a request from VBox for the X11 clipboard data.  The data should
- * be written to the buffer provided in the initial request.
- * @param  pCtx  request context information
- * @param  rc    the completion status of the request
- * @param  pReq  request
- * @param  pv    address
- * @param  cb    size
- *
- * @todo   change this to deal with the buffer issues rather than offloading
- *         them onto the caller
- */
-void ClipCompleteDataRequestFromX11(VBOXCLIPBOARDCONTEXT *pCtx, int rc,
-                                    CLIPREADCBREQ *pReq, void *pv, uint32_t cb)
-{
-    if (cb <= pReq->cb && cb != 0)
-        memcpy(pReq->pv, pv, cb);
-    RTMemFree(pReq);
-    vboxSvcClipboardCompleteReadData(pCtx->pClient, rc, cb);
-}
-
-/** A request for clipboard data from VBox */
-struct _VBOXCLIPBOARDREQFROMVBOX
-{
-    /** Data received */
-    void *pv;
-    /** The size of the data */
-    uint32_t cb;
-    /** Format of the data */
-    uint32_t format;
-    /** A semaphore for waiting for the data */
-    RTSEMEVENT finished;
-};
-
-/** Wait for clipboard data requested from VBox to arrive. */
-static int clipWaitForDataFromVBox(VBOXCLIPBOARDCONTEXT *pCtx,
-                                   VBOXCLIPBOARDREQFROMVBOX *pReq,
-                                   uint32_t u32Format)
-{
-    int rc = VINF_SUCCESS;
-    LogRelFlowFunc(("pCtx=%p, pReq=%p, u32Format=%02X\n", pCtx, pReq, u32Format));
-    /* Request data from VBox */
-    vboxSvcClipboardReportMsg(pCtx->pClient,
-                              VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA,
-                              u32Format);
-    /* Which will signal us when it is ready.  We use a timeout here
-     * because we can't be sure that the guest will behave correctly.
-     */
-    rc = RTSemEventWait(pReq->finished, CLIPBOARD_TIMEOUT);
-    /* If the request hasn't yet completed then we cancel it.  We use
-     * the critical section to prevent these operations colliding. */
-    RTCritSectEnter(&pCtx->clipboardMutex);
-    /* The data may have arrived between the semaphore timing out and
-     * our grabbing the mutex. */
-    if (rc == VERR_TIMEOUT && pReq->pv != NULL)
-        rc = VINF_SUCCESS;
-    if (pCtx->pReq == pReq)
-        pCtx->pReq = NULL;
-    Assert(pCtx->pReq == NULL);
-    RTCritSectLeave(&pCtx->clipboardMutex);
-    if (RT_SUCCESS(rc) && (pReq->pv == NULL))
-        rc = VERR_NO_DATA;
-    LogRelFlowFunc(("returning %Rrc\n", rc));
-    return rc;
-}
-
-/** Post a request for clipboard data to VBox/the guest and wait for it to be
- * completed. */
-static int clipRequestDataFromVBox(VBOXCLIPBOARDCONTEXT *pCtx,
-                                          VBOXCLIPBOARDREQFROMVBOX *pReq,
-                                          uint32_t u32Format)
-{
-    int rc = VINF_SUCCESS;
-    LogRelFlowFunc(("pCtx=%p, pReq=%p, u32Format=%02X\n", pCtx, pReq,
-                 u32Format));
-    /* Start by "posting" the request for the next invocation of
-     * vboxClipboardWriteData. */
-    RTCritSectEnter(&pCtx->clipboardMutex);
-    if (pCtx->pReq != NULL)
-    {
-        /* This would be a violation of the protocol, see the comments in the
-         * context structure definition. */
-        Assert(false);
-        rc = VERR_WRONG_ORDER;
-    }
-    else
-        pCtx->pReq = pReq;
-    RTCritSectLeave(&pCtx->clipboardMutex);
-    if (RT_SUCCESS(rc))
-        rc = clipWaitForDataFromVBox(pCtx, pReq, u32Format);
-    LogRelFlowFunc(("returning %Rrc\n", rc));
-    return rc;
-}
-
-/**
- * Send a request to VBox to transfer the contents of its clipboard to X11.
- *
- * @param  pCtx      Pointer to the host clipboard structure
- * @param  u32Format The format in which the data should be transferred
- * @param  ppv       On success and if pcb > 0, this will point to a buffer
- *                   to be freed with RTMemFree containing the data read.
- * @param  pcb       On success, this contains the number of bytes of data
- *                   returned
- * @note   Host glue code.
- */
-int ClipRequestDataForX11 (VBOXCLIPBOARDCONTEXT *pCtx,
-                                   uint32_t u32Format, void **ppv,
-                                   uint32_t *pcb)
-{
-    VBOXCLIPBOARDREQFROMVBOX request = { NULL, 0, 0, NIL_RTSEMEVENT };
-
-    LogRelFlowFunc(("pCtx=%p, u32Format=%02X, ppv=%p, pcb=%p\n", pCtx,
-                 u32Format, ppv, pcb));
-    if (pCtx->fShuttingDown)
-    {
-        /* The shared clipboard is disconnecting. */
-        LogRelFunc(("host requested guest clipboard data after guest had disconnected.\n"));
-        return VERR_WRONG_ORDER;
-    }
-    int rc = RTSemEventCreate(&request.finished);
-    if (RT_SUCCESS(rc))
-    {
-        rc = clipRequestDataFromVBox(pCtx, &request, u32Format);
-        RTSemEventDestroy(request.finished);
-    }
-    if (RT_SUCCESS(rc))
-    {
-        *ppv = request.pv;
-        *pcb = request.cb;
-    }
-    LogRelFlowFunc(("returning %Rrc\n", rc));
-    if (RT_SUCCESS(rc))
-        LogRelFlowFunc(("*ppv=%.*ls, *pcb=%u\n", *pcb / 2, *ppv, *pcb));
-    return rc;
-}
-
-/**
- * Called when we have requested data from VBox and that data has arrived.
- *
- * @param  pClient   Context information about the guest VM
- * @param  pv        Buffer to which the data was written
- * @param  cb        The size of the data written
- * @param  u32Format The format of the data written
- * @note   Host glue code
- */
-void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient,
-                             void *pv, uint32_t cb, uint32_t u32Format)
-{
-    LogRelFlowFunc (("called.  pClient=%p, pv=%p (%.*ls), cb=%u, u32Format=%02X\n",
-                  pClient, pv, cb / 2, pv, cb, u32Format));
-
-    VBOXCLIPBOARDCONTEXT *pCtx = pClient->pCtx;
-    /* Grab the mutex and check whether there is a pending request for data.
-     */
-    RTCritSectEnter(&pCtx->clipboardMutex);
-    VBOXCLIPBOARDREQFROMVBOX *pReq = pCtx->pReq;
-    if (pReq != NULL)
-    {
-        if (cb > 0)
-        {
-            pReq->pv = RTMemDup(pv, cb);
-            if (pReq->pv != NULL)  /* NULL may also mean no memory... */
-            {
-                pReq->cb = cb;
-                pReq->format = u32Format;
-            }
-        }
-        /* Signal that the request has been completed. */
-        RTSemEventSignal(pReq->finished);
-        pCtx->pReq = NULL;
-    }
-    RTCritSectLeave(&pCtx->clipboardMutex);
-}
-
-#ifdef TESTCASE
-#include <iprt/initterm.h>
-#include <iprt/stream.h>
-
-#define TEST_NAME "tstClipboardX11-2"
-
-struct _CLIPBACKEND
-{
-    uint32_t formats;
-    struct _READDATA
-    {
-        uint32_t format;
-        int rc;
-        CLIPREADCBREQ *pReq;
-    } readData;
-    struct _COMPLETEREAD
-    {
-        int rc;
-        uint32_t cbActual;
-    } completeRead;
-    struct _WRITEDATA
-    {
-        void *pv;
-        uint32_t cb;
-        uint32_t format;
-        bool timeout;
-    } writeData;
-    struct _REPORTDATA
-    {
-        uint32_t format;
-    } reportData;
-};
-
-void vboxSvcClipboardReportMsg (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Msg, uint32_t u32Formats)
-{
-    RT_NOREF1(u32Formats);
-    CLIPBACKEND *pBackend = pClient->pCtx->pBackend;
-    if (   (u32Msg == VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA)
-        && !pBackend->writeData.timeout)
-        vboxClipboardWriteData(pClient, pBackend->writeData.pv,
-                               pBackend->writeData.cb,
-                               pBackend->writeData.format);
-    else
-        return;
-}
-
-void vboxSvcClipboardCompleteReadData(VBOXCLIPBOARDCLIENTDATA *pClient, int rc, uint32_t cbActual)
-{
-    CLIPBACKEND *pBackend = pClient->pCtx->pBackend;
-    pBackend->completeRead.rc = rc;
-    pBackend->completeRead.cbActual = cbActual;
-}
-
-CLIPBACKEND *ClipConstructX11(VBOXCLIPBOARDCONTEXT *pFrontend, bool)
-{
-    RT_NOREF1(pFrontend);
-    return (CLIPBACKEND *)RTMemAllocZ(sizeof(CLIPBACKEND));
-}
-
-void ClipDestructX11(CLIPBACKEND *pBackend)
-{
-    RTMemFree(pBackend);
-}
-
-int ClipStartX11(CLIPBACKEND *pBackend, bool)
-{
-    RT_NOREF1(pBackend);
-    return VINF_SUCCESS;
-}
-
-int ClipStopX11(CLIPBACKEND *pBackend)
-{
-    RT_NOREF1(pBackend);
-    return VINF_SUCCESS;
-}
-
-void ClipAnnounceFormatToX11(CLIPBACKEND *pBackend,
-                                    uint32_t u32Formats)
-{
-    pBackend->formats = u32Formats;
-}
-
-extern int ClipRequestDataFromX11(CLIPBACKEND *pBackend, uint32_t u32Format,
-                                  CLIPREADCBREQ *pReq)
-{
-    pBackend->readData.format = u32Format;
-    pBackend->readData.pReq = pReq;
-    return pBackend->readData.rc;
-}
-
-int main()
-{
-    VBOXCLIPBOARDCLIENTDATA client;
-    unsigned cErrors = 0;
-    int rc = RTR3InitExeNoArguments(0);
-    RTPrintf(TEST_NAME ": TESTING\n");
-    AssertRCReturn(rc, 1);
-    rc = vboxClipboardConnect(&client, false);
-    CLIPBACKEND *pBackend = client.pCtx->pBackend;
-    AssertRCReturn(rc, 1);
-    vboxClipboardFormatAnnounce(&client,
-                                VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
-    if (pBackend->formats != VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
-    {
-        RTPrintf(TEST_NAME ": vboxClipboardFormatAnnounce failed with VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT\n");
-        ++cErrors;
-    }
-    pBackend->readData.rc = VINF_SUCCESS;
-    client.asyncRead.callHandle = (VBOXHGCMCALLHANDLE)pBackend;
-    client.asyncRead.paParms = (VBOXHGCMSVCPARM *)&client;
-    uint32_t u32Dummy;
-    rc = vboxClipboardReadData(&client, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
-                               &u32Dummy, 42, &u32Dummy);
-    if (rc != VINF_HGCM_ASYNC_EXECUTE)
-    {
-        RTPrintf(TEST_NAME ": vboxClipboardReadData returned %Rrc\n", rc);
-        ++cErrors;
-    }
-    else
-    {
-        if (   pBackend->readData.format !=
-                       VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT
-            || pBackend->readData.pReq->pv != &u32Dummy
-            || pBackend->readData.pReq->cb != 42
-            || pBackend->readData.pReq->pcbActual != &u32Dummy)
-        {
-            RTPrintf(TEST_NAME ": format=%u, pReq->pv=%p, pReq->cb=%u, pReq->pcbActual=%p\n",
-                     pBackend->readData.format, pBackend->readData.pReq->pv,
-                     pBackend->readData.pReq->cb,
-                     pBackend->readData.pReq->pcbActual);
-            ++cErrors;
-        }
-        else
-        {
-            ClipCompleteDataRequestFromX11(client.pCtx, VERR_NO_DATA,
-                                           pBackend->readData.pReq, NULL, 43);
-            if (   pBackend->completeRead.rc != VERR_NO_DATA
-                || pBackend->completeRead.cbActual != 43)
-            {
-                RTPrintf(TEST_NAME ": rc=%Rrc, cbActual=%u\n",
-                         pBackend->completeRead.rc,
-                         pBackend->completeRead.cbActual);
-                ++cErrors;
-            }
-        }
-    }
-    void *pv;
-    uint32_t cb;
-    pBackend->writeData.pv = (void *)"testing";
-    pBackend->writeData.cb = sizeof("testing");
-    pBackend->writeData.format = 1234;
-    pBackend->reportData.format = 4321;  /* XX this should be handled! */
-    rc = ClipRequestDataForX11(client.pCtx, 23, &pv, &cb);
-    if (   rc != VINF_SUCCESS
-        || strcmp((const char *)pv, "testing") != 0
-        || cb != sizeof("testing"))
-    {
-        RTPrintf("rc=%Rrc, pv=%p, cb=%u\n", rc, pv, cb);
-        ++cErrors;
-    }
-    else
-        RTMemFree(pv);
-    pBackend->writeData.timeout = true;
-    rc = ClipRequestDataForX11(client.pCtx, 23, &pv, &cb);
-    if (rc != VERR_TIMEOUT)
-    {
-        RTPrintf("rc=%Rrc, expected VERR_TIMEOUT\n", rc);
-        ++cErrors;
-    }
-    pBackend->writeData.pv = NULL;
-    pBackend->writeData.cb = 0;
-    pBackend->writeData.timeout = false;
-    rc = ClipRequestDataForX11(client.pCtx, 23, &pv, &cb);
-    if (rc != VERR_NO_DATA)
-    {
-        RTPrintf("rc=%Rrc, expected VERR_NO_DATA\n", rc);
-        ++cErrors;
-    }
-    /* Data arriving after a timeout should *not* cause any segfaults or
-     * memory leaks.  Check with Valgrind! */
-    vboxClipboardWriteData(&client, (void *)"tested", sizeof("tested"), 999);
-    vboxClipboardDisconnect(&client);
-    if (cErrors > 0)
-        RTPrintf(TEST_NAME ": errors: %u\n", cErrors);
-    return cErrors > 0 ? 1 : 0;
-}
-#endif  /* TESTCASE */
Index: unk/src/VBox/HostServices/SharedClipboard/x11-stub.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedClipboard/x11-stub.cpp	(revision 78159)
+++ 	(revision )
@@ -1,137 +1,0 @@
-/* $Id$*/
-/** @file
- * Shared Clipboard Service - Linux host, a stub version with no functionality for use on headless hosts.
- */
-
-/*
- * Copyright (C) 2006-2019 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*********************************************************************************************************************************
-*   Header Files                                                                                                                 *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
-#include <VBox/HostServices/VBoxClipboardSvc.h>
-
-#include <iprt/alloc.h>
-#include <iprt/asm.h>        /* For atomic operations */
-#include <iprt/assert.h>
-#include <iprt/mem.h>
-#include <iprt/string.h>
-#include <iprt/thread.h>
-#include <iprt/process.h>
-#include <iprt/semaphore.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdint.h>
-
-#include "VBoxClipboard.h"
-
-
-
-/** Initialise the host side of the shared clipboard - called by the hgcm layer. */
-int vboxClipboardInit (void)
-{
-    LogFlowFunc(("called, returning VINF_SUCCESS.\n"));
-    return VINF_SUCCESS;
-}
-
-/** Terminate the host side of the shared clipboard - called by the hgcm layer. */
-void vboxClipboardDestroy (void)
-{
-    LogFlowFunc(("called, returning.\n"));
-}
-
-/**
-  * Enable the shared clipboard - called by the hgcm clipboard subsystem.
-  *
-  * @param   pClient    Structure containing context information about the guest system
-  * @param   fHeadless  Whether headless.
-  * @returns RT status code
-  */
-int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient,
-                          bool fHeadless)
-{
-    RT_NOREF(pClient, fHeadless);
-    LogFlowFunc(("called, returning VINF_SUCCESS.\n"));
-    return VINF_SUCCESS;
-}
-
-/**
- * Synchronise the contents of the host clipboard with the guest, called by the HGCM layer
- * after a save and restore of the guest.
- */
-int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA * /* pClient */)
-{
-    LogFlowFunc(("called, returning VINF_SUCCESS.\n"));
-    return VINF_SUCCESS;
-}
-
-/**
- * Shut down the shared clipboard subsystem and "disconnect" the guest.
- *
- * @param   pClient    Structure containing context information about the guest system
- */
-void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *pClient)
-{
-    RT_NOREF(pClient);
-    LogFlowFunc(("called, returning.\n"));
-}
-
-/**
- * The guest is taking possession of the shared clipboard.  Called by the HGCM clipboard
- * subsystem.
- *
- * @param pClient    Context data for the guest system
- * @param u32Formats Clipboard formats the guest is offering
- */
-void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient,
-                                  uint32_t u32Formats)
-{
-    RT_NOREF(pClient, u32Formats);
-    LogFlowFunc(("called, returning.\n"));
-}
-
-/**
- * Called by the HGCM clipboard subsystem when the guest wants to read the host clipboard.
- *
- * @param pClient   Context information about the guest VM
- * @param u32Format The format that the guest would like to receive the data in
- * @param pv        Where to write the data to
- * @param cb        The size of the buffer to write the data to
- * @param pcbActual Where to write the actual size of the written data
- */
-int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Format,
-                           void *pv, uint32_t cb, uint32_t *pcbActual)
-{
-    RT_NOREF(pClient, u32Format, pv, cb);
-    LogFlowFunc(("called, returning VINF_SUCCESS.\n"));
-    /* No data available. */
-    *pcbActual = 0;
-    return VINF_SUCCESS;
-}
-
-/**
- * Called by the HGCM clipboard subsystem when we have requested data and that data arrives.
- *
- * @param pClient   Context information about the guest VM
- * @param pv        Buffer to which the data was written
- * @param cb        The size of the data written
- * @param u32Format The format of the data written
- */
-void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient, void *pv,
-                             uint32_t cb, uint32_t u32Format)
-{
-    RT_NOREF(pClient, pv, cb, u32Format);
-    LogFlowFunc(("called, returning.\n"));
-}
-
