diff options
Diffstat (limited to 'src/VBox/Additions/darwin/VBoxClient')
6 files changed, 1513 insertions, 0 deletions
diff --git a/src/VBox/Additions/darwin/VBoxClient/Makefile.kmk b/src/VBox/Additions/darwin/VBoxClient/Makefile.kmk new file mode 100644 index 00000000..012ec806 --- /dev/null +++ b/src/VBox/Additions/darwin/VBoxClient/Makefile.kmk @@ -0,0 +1,57 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for the VirtualBox Guest Addition Darwin Client. +# + +# +# Copyright (C) 2006-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +# +# VBoxClient - shared clipboard support. +# + +PROGRAMS += VBoxClient + +VBoxClient_TEMPLATE = NewVBoxGuestR3Exe +VBoxClient_DEFS += VBOX_WITH_HGCM + +VBoxClient_SOURCES = \ + VBoxClient.cpp + +ifdef VBOX_WITH_SHARED_CLIPBOARD + VBoxClient_DEFS += \ + VBOX_WITH_SHARED_CLIPBOARD + VBoxClient_SOURCES += \ + VBoxClientClipboard.cpp \ + VBoxClientClipboardHostToGuest.cpp \ + VBoxClientClipboardGuestToHost.cpp \ + $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp +endif + +VBoxClient_LDFLAGS = -framework IOKit -framework ApplicationServices +VBoxClient_INST = $(INST_ADDITIONS) + +include $(FILE_KBUILD_SUB_FOOTER) + diff --git a/src/VBox/Additions/darwin/VBoxClient/VBoxClient.cpp b/src/VBox/Additions/darwin/VBoxClient/VBoxClient.cpp new file mode 100644 index 00000000..dc12c2c0 --- /dev/null +++ b/src/VBox/Additions/darwin/VBoxClient/VBoxClient.cpp @@ -0,0 +1,298 @@ +/** $Id: VBoxClient.cpp $ */ +/** @file + * VBoxClient - User specific services, Darwin. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +#include <stdlib.h> + +#include <VBox/log.h> +#include <VBox/VBoxGuestLib.h> +#include <iprt/stream.h> +#include <iprt/initterm.h> +#include <iprt/message.h> +#include <iprt/process.h> +#include <iprt/string.h> + +#include "VBoxClientInternal.h" + + +/********************************************************************************************************************************* +* Glogal Variables * +*********************************************************************************************************************************/ + +static int g_cVerbosity = 0; +static PRTLOGGER g_pLogger = NULL; + +static VBOXCLIENTSERVICE g_aServices[] = +{ +#ifdef VBOX_WITH_SHARED_CLIPBOARD + g_ClipboardService +#endif +}; + + +/** + * Create default logger in order to print output to the specified file. + * + * @return IPRT status code. + */ +static int vbclInitLogger(char *pszLogFileName) +{ + static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES; + int rc = RTLogCreateEx(&g_pLogger, "VBOXCLIENT_RELEASE_LOG", RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG, "all", + RT_ELEMENTS(s_apszGroups), s_apszGroups, UINT32_MAX /*cMaxEntriesPerGroup*/, + 0 /*cBufDescs*/, NULL /*paBufDescs*/, RTLOGDEST_STDOUT, + NULL /*pfnPhase*/, + pszLogFileName ? 10 : 0 /*cHistory*/, + pszLogFileName ? 100 * _1M : 0 /*cbHistoryFileMax*/, + pszLogFileName ? RT_SEC_1DAY : 0 /*cSecsHistoryTimeSlot*/, + NULL /*pOutputIf*/, NULL /*pvOutputIfUser*/, + NULL /*pErrInfo*/, "%s", pszLogFileName ? pszLogFileName : ""); + AssertRCReturn(rc, rc); + + /* Register this logger as the release logger */ + RTLogRelSetDefaultInstance(g_pLogger); + + /* Explicitly flush the log in case of VBOXCLIENT_RELEASE_LOG=buffered. */ + RTLogFlush(g_pLogger); + + return VINF_SUCCESS; +} + + +/** + * Destroy logger. + */ +static void vbclTermLogger(char *szLogFileName) +{ + // Why SIGBUS here? + RTLogDestroy(RTLogRelSetDefaultInstance(NULL)); + + if (szLogFileName) + RTStrFree(szLogFileName); +} + +/** + * Displays a verbose message. + * + * @param iLevel Minimum log level required to display this message. + * @param pszFormat The message text. + * @param ... Format arguments. + */ +void VBoxClientVerbose(int iLevel, const char *pszFormat, ...) +{ + if (iLevel > g_cVerbosity) + return; + + va_list args; + va_start(args, pszFormat); + char *psz = NULL; + RTStrAPrintfV(&psz, pszFormat, args); + va_end(args); + + AssertPtr(psz); + LogRel(("%s", psz)); + + RTStrFree(psz); +} + +/** + * Wait for signals in order to safely terminate process. + */ +static void vbclWait(void) +{ + sigset_t signalMask; + int iSignal; + + /* Register signals that we are waiting for */ + sigemptyset(&signalMask); + sigaddset(&signalMask, SIGHUP); + sigaddset(&signalMask, SIGINT); + sigaddset(&signalMask, SIGQUIT); + sigaddset(&signalMask, SIGABRT); + sigaddset(&signalMask, SIGTERM); + pthread_sigmask(SIG_BLOCK, &signalMask, NULL); + + /* Ignoring return status */ + sigwait(&signalMask, &iSignal); +} + +/** + * Start registered services. + * + * @return IPRT status code. + */ +static int vbclStartServices(void) +{ + int rc; + unsigned int iServiceId = 0; + + VBoxClientVerbose(1, "Starting services...\n"); + for (iServiceId = 0; iServiceId < RT_ELEMENTS(g_aServices); iServiceId++) + { + VBoxClientVerbose(1, "Starting service: %s\n", g_aServices[iServiceId].pszName); + rc = (g_aServices[iServiceId].pfnStart)(); + if (RT_FAILURE(rc)) + { + VBoxClientVerbose(1, "unable to start service: %s (%Rrc)\n", g_aServices[iServiceId].pszName, rc); + VBoxClientVerbose(1, "Rolling back..\n"); + + /* Stop running services */ + do + { + VBoxClientVerbose(1, "Stopping service: %s\n", g_aServices[iServiceId].pszName); + int rcStop = (g_aServices[iServiceId].pfnStop)(); + if (RT_FAILURE(rcStop)) + VBoxClientVerbose(1, "unable to stop service: %s (%Rrc)\n", g_aServices[iServiceId].pszName, rcStop); + } while (--iServiceId != 0); + + break; + } + } + + if (RT_SUCCESS(rc)) + VBoxClientVerbose(1, "Services start completed.\n"); + + return rc; +} + +/** + * Stop registered services. + * + * @return IPRT status code. + */ +static void vbclStopServices(void) +{ + unsigned int iServiceId = 0; + + VBoxClientVerbose(1, "Stopping services...\n"); + for (iServiceId = 0; iServiceId < RT_ELEMENTS(g_aServices); iServiceId++) + { + VBoxClientVerbose(1, "Stopping service: %s\n", g_aServices[iServiceId].pszName); + int rc = (g_aServices[iServiceId].pfnStop)(); + if (RT_FAILURE(rc)) + VBoxClientVerbose(1, "unable to stop service: %s (%Rrc)\n", g_aServices[iServiceId].pszName, rc); + } + VBoxClientVerbose(1, "Services stop completed\n"); +} + + +static void usage(char *sProgName) +{ + RTPrintf("usage: %s [-fvl]\n", sProgName); + RTPrintf(" -f\tRun in foreground (default: no)\n"); + RTPrintf(" -v\tIncrease verbosity level (default: no verbosity)\n"); + RTPrintf(" -l\tSpecify log file name (default: no log file)\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + int rc; + int c; + + bool fDemonize = true; + static char *szLogFileName = NULL; + + rc = RTR3InitExe(argc, &argv, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("RTR3InitExe() failed: (%Rrc)\n", rc); + return RTMsgInitFailure(rc); + } + + /* Parse command line */ + while((c = getopt(argc, argv, "fvl:")) != -1) + { + switch(c) + { + case 'f': + fDemonize = false; + break; + case 'v': + g_cVerbosity++; + break; + case 'l': + szLogFileName = RTStrDup(optarg); + break; + + default : usage(argv[0]); + } + } + + /* No more arguments allowed */ + if ((argc - optind) != 0) + usage(argv[0]); + + if (fDemonize) + { + rc = RTProcDaemonizeUsingFork(true /* fNoChDir */, false /* fNoClose */, NULL); + if (RT_FAILURE(rc)) + { + RTPrintf("failed to run into background\n"); + return 1; + } + } + + rc = VbglR3Init(); + if (RT_SUCCESS(rc)) + { + rc = vbclInitLogger(szLogFileName); + if (RT_SUCCESS(rc)) + { + rc = vbclStartServices(); + if (RT_SUCCESS(rc)) + { + vbclWait(); + vbclStopServices(); + } + else + { + RTPrintf("failed to start services: (%Rrc)\n", rc); + } + + vbclTermLogger(szLogFileName); + } + else + { + RTPrintf("failed to start logger: (%Rrc)\n", rc); + } + + VbglR3Term(); + } + else + { + RTPrintf("failed to initialize guest library: (%Rrc)\n", rc); + } + + return 0; +} diff --git a/src/VBox/Additions/darwin/VBoxClient/VBoxClientClipboard.cpp b/src/VBox/Additions/darwin/VBoxClient/VBoxClientClipboard.cpp new file mode 100644 index 00000000..d2c70052 --- /dev/null +++ b/src/VBox/Additions/darwin/VBoxClient/VBoxClientClipboard.cpp @@ -0,0 +1,341 @@ +/** $Id: VBoxClientClipboard.cpp $ */ +/** @file + * VBoxClient - Shared Slipboard Dispatcher, Darwin. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <Carbon/Carbon.h> + +#include <iprt/asm.h> +#include <iprt/stream.h> +#include <iprt/thread.h> +#include <iprt/critsect.h> +#include <VBox/VBoxGuestLib.h> +#include <VBox/GuestHost/SharedClipboard.h> +#include <VBox/HostServices/VBoxClipboardSvc.h> +#include <VBox/GuestHost/clipboard-helper.h> +#include "VBoxClientInternal.h" + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ + +/** Host clipboard connection client ID */ +static uint32_t g_u32ClientId; +/* Guest clipboard reference */ +static PasteboardRef g_PasteboardRef; +/* Dispatcher tharead handle */ +RTTHREAD g_DispatcherThread; +/* Pasteboard polling tharead handle */ +RTTHREAD g_GuestPasteboardThread; +/* Flag that indicates whether or not dispatcher and Pasteboard polling threada should stop */ +static bool volatile g_fShouldStop; +/* Barrier for Pasteboard */ +static RTCRITSECT g_critsect; + + +/********************************************************************************************************************************* +* Local Macros * +*********************************************************************************************************************************/ + +#define VBOXCLIENT_SERVICE_NAME "clipboard" + + +/********************************************************************************************************************************* +* Local Function Prototypes * +*********************************************************************************************************************************/ +static DECLCALLBACK(int) vbclClipboardStop(void); + + +/** + * Clipboard dispatcher function. + * + * Forwards cliproard content between host and guest. + * + * @param ThreadSelf Unused parameter. + * @param pvUser Unused parameter. + * + * @return IPRT status code. + */ +static DECLCALLBACK(int) vbclClipboardDispatcher(RTTHREAD ThreadSelf, void *pvUser) +{ + bool fQuit = false; + NOREF(ThreadSelf); + NOREF(pvUser); + + VBoxClientVerbose(2, "starting host clipboard polling thread\n"); + + /* + * Block all signals for this thread. Only the main thread will handle signals. + */ + sigset_t signalMask; + sigfillset(&signalMask); + pthread_sigmask(SIG_BLOCK, &signalMask, NULL); + + while (!fQuit && !ASMAtomicReadBool(&g_fShouldStop)) + { + int rc; + uint32_t Msg; + uint32_t fFormats; + + VBoxClientVerbose(2, "waiting for new host request\n"); + + rc = VbglR3ClipboardGetHostMsgOld(g_u32ClientId, &Msg, &fFormats); + if (RT_SUCCESS(rc)) + { + RTCritSectEnter(&g_critsect); + switch (Msg) + { + /* The host is terminating */ + case VBOX_SHCL_HOST_MSG_QUIT: + VBoxClientVerbose(2, "host requested quit\n"); + fQuit = true; + break; + + /* The host needs data in the specified format */ + case VBOX_SHCL_HOST_MSG_READ_DATA: + VBoxClientVerbose(2, "host requested guest's clipboard read\n"); + rc = vbclClipboardForwardToHost(g_u32ClientId, g_PasteboardRef, fFormats); + AssertMsg(RT_SUCCESS(rc), ("paste to host failed\n")); + break; + + /* The host has announced available clipboard formats */ + case VBOX_SHCL_HOST_MSG_FORMATS_REPORT: + VBoxClientVerbose(2, "host requested guest's clipboard write\n"); + rc = vbclClipboardForwardToGuest(g_u32ClientId, g_PasteboardRef, fFormats); + AssertMsg(RT_SUCCESS(rc), ("paste to guest failed\n")); + break; + + default: + VBoxClientVerbose(2, "received unknow command from host service\n"); + RTThreadSleep(1000); + } + + RTCritSectLeave(&g_critsect); + } + else + { + RTThreadSleep(1000); + } + } + + VBoxClientVerbose(2, "host clipboard polling thread stopped\n"); + + return VINF_SUCCESS; +} + + +/** + * Clipboard dispatcher function. + * + * Forwards cliproard content between host and guest. + * + * @param hThreadSelf Unused parameter. + * @param pvUser Unused parameter. + * + * @return IPRT status code. + */ +static DECLCALLBACK(int) vbclGuestPasteboardPoll(RTTHREAD hThreadSelf, void *pvUser) +{ + RT_NOREF(hThreadSelf, pvUser); + + /* + * Block all signals for this thread. Only the main thread will handle signals. + */ + sigset_t signalMask; + sigfillset(&signalMask); + pthread_sigmask(SIG_BLOCK, &signalMask, NULL); + + VBoxClientVerbose(2, "starting guest clipboard polling thread\n"); + + while (!ASMAtomicReadBool(&g_fShouldStop)) + { + PasteboardSyncFlags fSyncFlags; + uint32_t fFormats; + int rc; + + RTCritSectEnter(&g_critsect); + + fSyncFlags = PasteboardSynchronize(g_PasteboardRef); + if (fSyncFlags & kPasteboardModified) + { + fFormats = vbclClipboardGetAvailableFormats(g_PasteboardRef); + rc = VbglR3ClipboardReportFormats(g_u32ClientId, fFormats); + if (RT_FAILURE(rc)) + { + VBoxClientVerbose(2, "failed to report pasteboard update (%Rrc)\n", rc); + } + else + { + VBoxClientVerbose(2, "guest clipboard update reported: %d\n", (int)fFormats); + } + } + + RTCritSectLeave(&g_critsect); + + /* Check pasteboard every 200 ms */ + RTThreadSleep(200); + } + + VBoxClientVerbose(2, "guest clipboard polling thread stopped\n"); + + return VINF_SUCCESS; +} + + +/** + * Initialize host and guest clipboards, start clipboard dispatcher loop. + * + * @return IPRT status code. + */ +static DECLCALLBACK(int) vbclClipboardStart(void) +{ + int rc; + + VBoxClientVerbose(2, "starting clipboard\n"); + + rc = RTCritSectInit(&g_critsect); + if (RT_FAILURE(rc)) + return VERR_GENERAL_FAILURE; + + rc = VbglR3ClipboardConnect(&g_u32ClientId); + if (RT_SUCCESS(rc)) + { + rc = PasteboardCreate(kPasteboardClipboard, &g_PasteboardRef); + if (rc == noErr) + { + /* Start dispatcher loop */ + ASMAtomicWriteBool(&g_fShouldStop, false); + rc = RTThreadCreate(&g_DispatcherThread, + vbclClipboardDispatcher, + (void *)NULL, + 0, + RTTHREADTYPE_DEFAULT, + RTTHREADFLAGS_WAITABLE, + VBOXCLIENT_SERVICE_NAME); + if (RT_SUCCESS(rc)) + { + /* Start dispatcher loop */ + ASMAtomicWriteBool(&g_fShouldStop, false); + rc = RTThreadCreate(&g_GuestPasteboardThread, + vbclGuestPasteboardPoll, + (void *)NULL, + 0, + RTTHREADTYPE_DEFAULT, + RTTHREADFLAGS_WAITABLE, + VBOXCLIENT_SERVICE_NAME); + if (RT_SUCCESS(rc)) + return VINF_SUCCESS; + + /* Stop dispatcher thread */ + ASMAtomicWriteBool(&g_fShouldStop, true); + RTThreadWait(g_DispatcherThread, 10 * 1000 /* Wait 10 seconds */, NULL); + + } + VBoxClientVerbose(2, "unable create dispatcher thread\n"); + CFRelease(g_PasteboardRef); + g_PasteboardRef = NULL; + + } + else + { + rc = VERR_GENERAL_FAILURE; + VBoxClientVerbose(2, "unable access guest clipboard\n"); + } + + vbclClipboardStop(); + + } + else + { + VBoxClientVerbose(2, "unable to establish connection to clipboard service: %Rrc\n", rc); + } + + RTCritSectDelete(&g_critsect); + + return rc; +} + + +/** + * Release host and guest clipboards, stop clipboard dispatcher loop. + * + * @return IPRT status code. + */ +static DECLCALLBACK(int) vbclClipboardStop(void) +{ + int rc; + + VBoxClientVerbose(2, "stopping clipboard\n"); + + AssertReturn(g_u32ClientId != 0, VERR_GENERAL_FAILURE); + + VbglR3ClipboardReportFormats(g_u32ClientId, 0); + + rc = VbglR3ClipboardDisconnect(g_u32ClientId); + if (RT_SUCCESS(rc)) + g_u32ClientId = 0; + else + VBoxClientVerbose(2, "unable to close clipboard service connection: %Rrc\n", rc); + + if (g_PasteboardRef) + { + CFRelease(g_PasteboardRef); + g_PasteboardRef = NULL; + } + + /* Stop dispatcher thread */ + ASMAtomicWriteBool(&g_fShouldStop, true); + rc = RTThreadWait(g_DispatcherThread, 10 * 1000 /* Wait 10 seconds */, NULL); + if (RT_FAILURE(rc)) + VBoxClientVerbose(2, "failed to stop dispatcher thread"); + + /* Stop Pasteboard polling thread */ + rc = RTThreadWait(g_GuestPasteboardThread, 10 * 1000 /* Wait 10 seconds */, NULL); + if (RT_FAILURE(rc)) + VBoxClientVerbose(2, "failed to stop pasteboard polling thread"); + + RTCritSectDelete(&g_critsect); + + return rc; +} + + +/* Clipboard service struct */ +VBOXCLIENTSERVICE g_ClipboardService = +{ + /* pszName */ + VBOXCLIENT_SERVICE_NAME, + + /* pfnStart */ + vbclClipboardStart, + + /* pfnStop */ + vbclClipboardStop, +}; diff --git a/src/VBox/Additions/darwin/VBoxClient/VBoxClientClipboardGuestToHost.cpp b/src/VBox/Additions/darwin/VBoxClient/VBoxClientClipboardGuestToHost.cpp new file mode 100644 index 00000000..a4e4e425 --- /dev/null +++ b/src/VBox/Additions/darwin/VBoxClient/VBoxClientClipboardGuestToHost.cpp @@ -0,0 +1,390 @@ +/** $Id: VBoxClientClipboardGuestToHost.cpp $ */ +/** @file + * VBoxClient - Shared Clipboard Guest -> Host copying, Darwin. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <Carbon/Carbon.h> +#include <signal.h> +#include <stdlib.h> + +#include <iprt/thread.h> +#include <iprt/mem.h> +#include <iprt/initterm.h> +#include <iprt/message.h> +#include <iprt/stream.h> +#include <iprt/utf16.h> +#include <VBox/VBoxGuestLib.h> +#include <VBox/GuestHost/SharedClipboard.h> +#include <VBox/HostServices/VBoxClipboardSvc.h> +#include <VBox/GuestHost/clipboard-helper.h> +#include "VBoxClientInternal.h" + +/** + * Walk through pasteboard items and report currently available item types. + * + * @param pPasteboard Reference to guest Pasteboard. + * @returns Available formats bit field. + */ +uint32_t vbclClipboardGetAvailableFormats(PasteboardRef pPasteboard) +{ + uint32_t fFormats = 0; + ItemCount cItems = 0; + ItemCount iItem; + OSStatus rc; + +#define VBOXCL_ADD_FORMAT_IF_PRESENT(a_kDarwinFmt, a_fVBoxFmt) \ + if (PasteboardCopyItemFlavorData(pPasteboard, iItemID, a_kDarwinFmt, &flavorData) == noErr) \ + { \ + fFormats |= (uint32_t)a_fVBoxFmt; \ + CFRelease(flavorData); \ + } + + rc = PasteboardGetItemCount(pPasteboard, &cItems); + AssertReturn((rc == noErr) && (cItems > 0), fFormats); + + for (iItem = 1; iItem <= cItems; iItem++) + { + PasteboardItemID iItemID; + CFDataRef flavorData; + + rc = PasteboardGetItemIdentifier(pPasteboard, iItem, &iItemID); + if (rc == noErr) + { + VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeUTF16PlainText, VBOX_SHCL_FMT_UNICODETEXT); + VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeUTF8PlainText, VBOX_SHCL_FMT_UNICODETEXT); + VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeBMP, VBOX_SHCL_FMT_BITMAP ); + VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeHTML, VBOX_SHCL_FMT_HTML ); + +#ifdef CLIPBOARD_DUMP_CONTENT_FORMATS + CFArrayRef flavorTypeArray; + CFIndex flavorCount; + CFStringRef flavorType; + + rc = PasteboardCopyItemFlavors(pPasteboard, iItemID, &flavorTypeArray); + if (rc == noErr) + { + VBoxClientVerbose(3, "SCAN..\n"); + flavorCount = CFArrayGetCount(flavorTypeArray); + VBoxClientVerbose(3, "SCAN (%d)..\n", (int)flavorCount); + for(CFIndex flavorIndex = 0; flavorIndex < flavorCount; flavorIndex++) + { + VBoxClientVerbose(3, "SCAN #%d..\n", (int)flavorIndex); + flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, flavorIndex); + + CFDataRef flavorData1; + rc = PasteboardCopyItemFlavorData(pPasteboard, iItemID, flavorType, &flavorData1); + if (rc == noErr) + { + VBoxClientVerbose(3, "Found: %s, size: %d\n", (char *)CFStringGetCStringPtr(flavorType, kCFStringEncodingMacRoman), (int)CFDataGetLength(flavorData1)); + CFRelease(flavorData1); + } + } + VBoxClientVerbose(3, "SCAN COMPLETE\n"); + CFRelease(flavorTypeArray); + } +#endif /* CLIPBOARD_DUMP_CONTENT_FORMATS */ + } + } + +#undef VBOXCL_ADD_FORMAT_IF_PRESENT + + return fFormats; +} + + +/** + * Search for content of specified type in guest clipboard buffer and put + * it into newly allocated buffer. + * + * @param pPasteboard Guest PasteBoard reference. + * @param fFormat Data formats we are looking for. + * @param ppvData Where to return pointer to the received data. M + * @param pcbData Where to return the size of the data. + * @param pcbAlloc Where to return the size of the memory block + * *ppvData pointes to. (Usually greater than *cbData + * because the allocation is page aligned.) + * @returns IPRT status code. + */ +static int vbclClipboardReadGuestData(PasteboardRef pPasteboard, CFStringRef sFormat, void **ppvData, uint32_t *pcbData, + uint32_t *pcbAlloc) +{ + ItemCount cItems, iItem; + OSStatus rc; + + void *pvData = NULL; + uint32_t cbData = 0; + uint32_t cbAlloc = 0; + + AssertPtrReturn(ppvData, VERR_INVALID_POINTER); + AssertPtrReturn(pcbData, VERR_INVALID_POINTER); + AssertPtrReturn(pcbAlloc, VERR_INVALID_POINTER); + + rc = PasteboardGetItemCount(pPasteboard, &cItems); + AssertReturn(rc == noErr, VERR_INVALID_PARAMETER); + AssertReturn(cItems > 0, VERR_INVALID_PARAMETER); + + /* Walk through all the items in PasteBoard in order to find + that one that correcponds to requested data format. */ + for (iItem = 1; iItem <= cItems; iItem++) + { + PasteboardItemID iItemID; + CFDataRef flavorData; + + /* Now, get the item's flavors that corresponds to requested type. */ + rc = PasteboardGetItemIdentifier(pPasteboard, iItem, &iItemID); + AssertReturn(rc == noErr, VERR_INVALID_PARAMETER); + rc = PasteboardCopyItemFlavorData(pPasteboard, iItemID, sFormat, &flavorData); + if (rc == noErr) + { + void *flavorDataPtr = (void *)CFDataGetBytePtr(flavorData); + cbData = CFDataGetLength(flavorData); + if (flavorDataPtr && cbData > 0) + { + cbAlloc = RT_ALIGN_32(cbData, PAGE_SIZE); + pvData = RTMemPageAllocZ(cbAlloc); + if (pvData) + memcpy(pvData, flavorDataPtr, cbData); + } + + CFRelease(flavorData); + + /* Found first matching item, no more search. */ + break; + } + + } + + /* Found match */ + if (pvData) + { + *ppvData = pvData; + *pcbData = cbData; + *pcbAlloc = cbAlloc; + + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + + +/** + * Release resources occupied by vbclClipboardReadGuestData(). + */ +static void vbclClipboardReleaseGuestData(void **ppvData, uint32_t cbAlloc) +{ + AssertReturnVoid(ppvData); + RTMemPageFree(*ppvData, cbAlloc); + *ppvData = NULL; +} + +/** + * Pass data to host. + */ +static int vbclClipboardHostPasteData(uint32_t u32ClientId, uint32_t u32Format, const void *pvData, uint32_t cbData) +{ + /* Allow empty buffers */ + if (cbData == 0) + return VbglR3ClipboardWriteData(u32ClientId, u32Format, NULL, 0); + + AssertReturn(pvData, VERR_INVALID_PARAMETER); + return VbglR3ClipboardWriteData(u32ClientId, u32Format, (void *)pvData, cbData); /** @todo r=bird: Why on earth does a write function like VbglR3ClipboardWriteData take a non-const parameter? */ +} + +/** + * Paste text data into host clipboard. + * + * @param u32ClientId Host clipboard connection. + * @param pwszData UTF-16 encoded string. + * @param cbData The length of the string, in bytes, probably + * including a terminating zero. + */ +static int vbclClipboardHostPasteText(uint32_t u32ClientId, PRTUTF16 pwszData, uint32_t cbData) +{ + AssertReturn(cbData > 0, VERR_INVALID_PARAMETER); + AssertPtrReturn(pwszData, VERR_INVALID_POINTER); + + size_t cwcTmp; /* (includes a schwarzenegger character) */ + int rc = ShClUtf16LFLenUtf8(pwszData, cbData / sizeof(RTUTF16), &cwcTmp); + AssertRCReturn(rc, rc); + + cwcTmp++; /* Add space for terminator. */ + + PRTUTF16 pwszTmp = (PRTUTF16)RTMemAlloc(cwcTmp * sizeof(RTUTF16)); + AssertReturn(pwszTmp, VERR_NO_MEMORY); + + rc = ShClConvUtf16LFToCRLF(pwszData, cbData / sizeof(RTUTF16), pwszTmp, cwcTmp); + if (RT_SUCCESS(rc)) + rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHCL_FMT_UNICODETEXT, + pwszTmp, cwcTmp * sizeof(RTUTF16)); + + RTMemFree(pwszTmp); + + return rc; +} + + +/** + * Paste a bitmap onto the host clipboard. + * + * @param u32ClientId Host clipboard connection. + * @param pvData The bitmap data. + * @param cbData The size of the bitmap. + */ +static int vbclClipboardHostPasteBitmap(uint32_t u32ClientId, void *pvData, uint32_t cbData) +{ + const void *pvDib; + size_t cbDib; + int rc = ShClBmpGetDib(pvData, cbData, &pvDib, &cbDib); + AssertRCReturn(rc, rc); + + rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHCL_FMT_BITMAP, pvDib, cbDib); + + return rc; +} + + +/** + * Read guest's clipboard buffer and forward its content to host. + * + * @param u32ClientId Host clipboard connection. + * @param pPasteboard Guest PasteBoard reference. + * @param fFormats List of data formats (bit field) received from host. + * + * @returns IPRT status code. + */ +int vbclClipboardForwardToHost(uint32_t u32ClientId, PasteboardRef pPasteboard, uint32_t fFormats) +{ + int rc = VINF_SUCCESS; + + void *pvData = NULL; + uint32_t cbData = 0; + uint32_t cbAlloc = 0; + + VBoxClientVerbose(3, "vbclClipboardForwardToHost: %d\n", fFormats); + + /* Walk across all item(s) formats */ + uint32_t fFormatsLeft = fFormats; + while (fFormatsLeft) + { + if (fFormatsLeft & VBOX_SHCL_FMT_UNICODETEXT) + { + VBoxClientVerbose(3, "requested VBOX_SHCL_FMT_UNICODETEXT: %d\n", fFormats); + + RTUTF16 *pUtf16Str = NULL; + + /* First, try to get UTF16 encoded buffer */ + rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeUTF16PlainText, &pvData, &cbData, &cbAlloc); + if (RT_SUCCESS(rc)) + { + rc = RTUtf16DupEx(&pUtf16Str, (PRTUTF16)pvData, 0); + if (RT_FAILURE(rc)) + pUtf16Str = NULL; + } + else /* Failed to get UTF16 buffer */ + { + /* Then, try to get UTF8 encoded buffer */ + rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeUTF8PlainText, &pvData, &cbData, &cbAlloc); + if (RT_SUCCESS(rc)) + { + rc = RTStrToUtf16((const char *)pvData, &pUtf16Str); + if (RT_FAILURE(rc)) + pUtf16Str = NULL; + } + } + + /* Finally, we got UTF16 encoded buffer */ + if (RT_SUCCESS(rc)) + { + rc = vbclClipboardHostPasteText(u32ClientId, (PRTUTF16)pvData, cbData); + + if (pUtf16Str) + { + RTUtf16Free(pUtf16Str); + pUtf16Str = NULL; + } + + vbclClipboardReleaseGuestData(&pvData, cbAlloc); + } + else + { + /* No data found or error occurred: send empty buffer */ + rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHCL_FMT_UNICODETEXT, NULL, 0); + } + + fFormatsLeft &= ~(uint32_t)VBOX_SHCL_FMT_UNICODETEXT; + } + + else if (fFormatsLeft & VBOX_SHCL_FMT_BITMAP) + { + VBoxClientVerbose(3, "requested VBOX_SHCL_FMT_BITMAP: %d\n", fFormats); + + rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeBMP, &pvData, &cbData, &cbAlloc); + if (RT_SUCCESS(rc)) + { + rc = vbclClipboardHostPasteBitmap(u32ClientId, pvData, cbData); + vbclClipboardReleaseGuestData(&pvData, cbAlloc); + } + else + { + /* No data found or error occurred: send empty buffer */ + rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHCL_FMT_BITMAP, NULL, 0); + } + + fFormatsLeft &= ~(uint32_t)VBOX_SHCL_FMT_BITMAP; + } + + else if (fFormatsLeft & VBOX_SHCL_FMT_HTML) + { + VBoxClientVerbose(3, "requested VBOX_SHCL_FMT_HTML: %d\n", fFormats); + + rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeHTML, &pvData, &cbData, &cbAlloc); + if (RT_SUCCESS(rc)) + { + rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHCL_FMT_HTML, pvData, cbData); + vbclClipboardReleaseGuestData(&pvData, cbAlloc); + } + else + { + /* No data found or error occurred: send empty buffer */ + rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHCL_FMT_HTML, NULL, 0); + } + + fFormatsLeft &= ~(uint32_t)VBOX_SHCL_FMT_HTML; + } + + else + { + VBoxClientVerbose(3, "requested data in unsupported format: %#x\n", fFormatsLeft); + break; + } + } + + return rc; /** @todo r=bird: If there are multiple formats available, which rc is returned here? Does it matter? */ +} diff --git a/src/VBox/Additions/darwin/VBoxClient/VBoxClientClipboardHostToGuest.cpp b/src/VBox/Additions/darwin/VBoxClient/VBoxClientClipboardHostToGuest.cpp new file mode 100644 index 00000000..1227878f --- /dev/null +++ b/src/VBox/Additions/darwin/VBoxClient/VBoxClientClipboardHostToGuest.cpp @@ -0,0 +1,315 @@ +/** $Id: VBoxClientClipboardHostToGuest.cpp $ */ +/** @file + * VBoxClient - Shared Clipboard Host -> Guest copying, Darwin. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <Carbon/Carbon.h> +#include <signal.h> +#include <stdlib.h> + +#include <iprt/initterm.h> +#include <iprt/mem.h> +#include <iprt/message.h> +#include <iprt/stream.h> +#include <iprt/thread.h> +#include <iprt/utf16.h> +#include <VBox/VBoxGuestLib.h> +#include <VBox/GuestHost/SharedClipboard.h> +#include <VBox/HostServices/VBoxClipboardSvc.h> +#include <VBox/GuestHost/clipboard-helper.h> +#include "VBoxClientInternal.h" + +/** + * Allocate memory for host buffer and receive it. + * + * @param u32ClientId Host connection. + * @param fFormat Buffer data format. + * @param pData Where to store received data. + * @param cbDataSize The size of the received data. + * @param cbMemSize The actual size of memory occupied by *pData. + * + * @returns IPRT status code. + */ +static int vbclClipboardReadHostData(uint32_t u32ClientId, uint32_t fFormat, void **pData, uint32_t *cbDataSize, uint32_t *cbMemSize) +{ + int rc; + + AssertReturn(pData && cbDataSize && cbMemSize, VERR_INVALID_PARAMETER); + + uint32_t cbDataSizeInternal = _4K; + uint32_t cbMemSizeInternal = cbDataSizeInternal; + void *pDataInternal = RTMemPageAllocZ(cbDataSizeInternal); + + if (!pDataInternal) + return VERR_NO_MEMORY; + + rc = VbglR3ClipboardReadData(u32ClientId, fFormat, pDataInternal, cbMemSizeInternal, &cbDataSizeInternal); + if (rc == VINF_BUFFER_OVERFLOW) + { + /* Reallocate bigger buffer and receive all the data */ + RTMemPageFree(pDataInternal, cbMemSizeInternal); + cbDataSizeInternal = cbMemSizeInternal = RT_ALIGN_32(cbDataSizeInternal, PAGE_SIZE); + pDataInternal = RTMemPageAllocZ(cbMemSizeInternal); + if (!pDataInternal) + return VERR_NO_MEMORY; + + rc = VbglR3ClipboardReadData(u32ClientId, fFormat, pDataInternal, cbMemSizeInternal, &cbDataSizeInternal); + } + + /* Error occurred of zero-sized buffer */ + if (RT_FAILURE(rc)) + { + RTMemPageFree(pDataInternal, cbMemSizeInternal); + return VERR_NO_MEMORY; + } + + *pData = pDataInternal; + *cbDataSize = cbDataSizeInternal; + *cbMemSize = cbMemSizeInternal; + + return rc; +} + +/** + * Release memory occupied by host buffer. + * + * @param pData Pointer to memory occupied by host buffer. + * @param cbMemSize The actual size of memory occupied by *pData. + */ +static void vbclClipboardReleaseHostData(void **pData, uint32_t cbMemSize) +{ + AssertReturnVoid(pData && cbMemSize > 0); + RTMemPageFree(*pData, cbMemSize); +} + +/** + * Paste buffer into guest clipboard. + * + * @param pPasteboard Guest PasteBoard reference. + * @param pData Data to be pasted. + * @param cbDataSize The size of *pData. + * @param fFormat Buffer data format. + * @param fClear Whether or not clear guest clipboard before insert data. + * + * @returns IPRT status code. + */ +static int vbclClipboardGuestPasteData(PasteboardRef pPasteboard, UInt8 *pData, CFIndex cbDataSize, CFStringRef sFormat, bool fClear) +{ + PasteboardItemID itemId = (PasteboardItemID)1; + CFDataRef textData = NULL; + OSStatus rc; + + /* Ignoring sunchronization flags here */ + PasteboardSynchronize(pPasteboard); + + if (fClear) + { + rc = PasteboardClear(pPasteboard); + AssertReturn(rc == noErr, VERR_NOT_SUPPORTED); + } + + /* Create a CData object which we could pass to the pasteboard */ + if ((textData = CFDataCreate(kCFAllocatorDefault, pData, cbDataSize))) + { + /* Put the Utf-8 version to the pasteboard */ + rc = PasteboardPutItemFlavor(pPasteboard, itemId, sFormat, textData, 0); + CFRelease(textData); + if (rc != noErr) + { + VBoxClientVerbose(3, "unable to put data into guest's clipboard: %d\n", rc); + return VERR_GENERAL_FAILURE; + } + } + else + return VERR_NO_MEMORY; + + /* Synchronize updated content */ + PasteboardSynchronize(pPasteboard); + + return VINF_SUCCESS; +} + +/** + * Paste text data into guest clipboard. + * + * @param pPasteboard Guest PasteBoard reference. + * @param pData Data to be pasted. + * @param cbDataSize Size of *pData. + */ +static int vbclClipboardGuestPasteText(PasteboardRef pPasteboard, void *pData, uint32_t cbDataSize) +{ + AssertReturn(pData, VERR_INVALID_PARAMETER); + + /* Skip zero-sized buffer */ + AssertReturn(cbDataSize > 0, VINF_SUCCESS); + + /* If buffer content is Unicode text, then deliver + it in both formats UTF16 (original) and UTF8. */ + + /* Convert END-OF-LINE */ + size_t cwcDst; + int rc = ShClUtf16CRLFLenUtf8((RTUTF16 *)pData, cbDataSize / sizeof(RTUTF16), &cwcDst); + AssertRCReturn(rc, rc); + + cwcDst++; /* Add space for terminator. */ + + PRTUTF16 pwszDst = (RTUTF16 *)RTMemAlloc(cwcDst * sizeof(RTUTF16)); + AssertPtrReturn(pwszDst, VERR_NO_MEMORY); + + rc = ShClConvUtf16CRLFToLF((RTUTF16 *)pData, cbDataSize / sizeof(RTUTF16), pwszDst, cwcDst); + if (RT_SUCCESS(rc)) + { + /* Paste UTF16 */ + rc = vbclClipboardGuestPasteData(pPasteboard, (UInt8 *)pwszDst, cwcDst * sizeof(RTUTF16), kUTTypeUTF16PlainText, true); + if (RT_SUCCESS(rc)) + { + /* Paste UTF8 */ + char *pszDst; + rc = RTUtf16ToUtf8((PRTUTF16)pwszDst, &pszDst); + if (RT_SUCCESS(rc)) + { + rc = vbclClipboardGuestPasteData(pPasteboard, (UInt8 *)pszDst, strlen(pszDst), kUTTypeUTF8PlainText, false); + RTStrFree(pszDst); + } + } + + } + + RTMemFree(pwszDst); + + return rc; +} + +/** + * Paste picture data into guest clipboard. + * + * @param pPasteboard Guest PasteBoard reference. + * @param pData Data to be pasted. + * @param cbDataSize The size of *pData. + * + * @returns IPRT status code. + */ +static int vbclClipboardGuestPastePicture(PasteboardRef pPasteboard, void *pData, uint32_t cbDataSize) +{ + int rc; + void *pBmp; + size_t cbBmpSize; + + AssertReturn(pData, VERR_INVALID_PARAMETER); + /* Skip zero-sized buffer */ + AssertReturn(cbDataSize > 0, VINF_SUCCESS); + + rc = ShClDibToBmp(pData, cbDataSize, &pBmp, &cbBmpSize); + AssertReturn(RT_SUCCESS(rc), rc); + + rc = vbclClipboardGuestPasteData(pPasteboard, (UInt8 *)pBmp, cbBmpSize, kUTTypeBMP, true); + RTMemFree(pBmp); + + return rc; +} + +/** + * Read host's clipboard buffer and put its content to guest clipboard. + * + * @param u32ClientId Host connection. + * @param pPasteboard Guest PasteBoard reference. + * @param fFormats List of data formats (bit field) received from host. + * + * @returns IPRT status code. + */ +int vbclClipboardForwardToGuest(uint32_t u32ClientId, PasteboardRef pPasteboard, uint32_t fFormats) +{ + int rc = VERR_INVALID_PARAMETER; + void *pData; + uint32_t cbDataSize, cbMemSize; + uint32_t fFormatsInternal = fFormats; + + /* Walk across all item(s) formats */ + while (fFormatsInternal) + { + if (fFormatsInternal & VBOX_SHCL_FMT_UNICODETEXT) + { + VBoxClientVerbose(3, "found VBOX_SHCL_FMT_UNICODETEXT: %d\n", fFormatsInternal); + + rc = vbclClipboardReadHostData(u32ClientId, VBOX_SHCL_FMT_UNICODETEXT, &pData, &cbDataSize, &cbMemSize); + if (RT_SUCCESS(rc)) + { + /* Store data in guest buffer */ + rc = vbclClipboardGuestPasteText(pPasteboard, pData, cbDataSize); + + /* Release occupied resources */ + vbclClipboardReleaseHostData(&pData, cbMemSize); + } + + fFormatsInternal &= ~((uint32_t)VBOX_SHCL_FMT_UNICODETEXT); + } + + else if (fFormatsInternal & VBOX_SHCL_FMT_BITMAP) + { + VBoxClientVerbose(3, "found VBOX_SHCL_FMT_BITMAP: %d\n", fFormatsInternal); + + rc = vbclClipboardReadHostData(u32ClientId, VBOX_SHCL_FMT_BITMAP, &pData, &cbDataSize, &cbMemSize); + if (RT_SUCCESS(rc)) + { + /* Store data in guest buffer */ + rc = vbclClipboardGuestPastePicture(pPasteboard, pData, cbDataSize); + + /* Release occupied resources */ + vbclClipboardReleaseHostData(&pData, cbMemSize); + } + + fFormatsInternal &= ~((uint32_t)VBOX_SHCL_FMT_BITMAP); + } + + else if (fFormatsInternal & VBOX_SHCL_FMT_HTML) + { + VBoxClientVerbose(3, "found VBOX_SHCL_FMT_HTML: %d\n", fFormatsInternal); + + rc = vbclClipboardReadHostData(u32ClientId, VBOX_SHCL_FMT_HTML, &pData, &cbDataSize, &cbMemSize); + if (RT_SUCCESS(rc)) + { + /* Store data in guest buffer */ + rc = vbclClipboardGuestPasteData(pPasteboard, (UInt8 *)pData, cbDataSize, kUTTypeHTML, true); + + /* Release occupied resources */ + vbclClipboardReleaseHostData(&pData, cbMemSize); + } + + fFormatsInternal &= ~((uint32_t)VBOX_SHCL_FMT_HTML); + } + + else + { + VBoxClientVerbose(3, "received data in unsupported format: %d\n", fFormats); + break; + } + } + + return rc; +} diff --git a/src/VBox/Additions/darwin/VBoxClient/VBoxClientInternal.h b/src/VBox/Additions/darwin/VBoxClient/VBoxClientInternal.h new file mode 100644 index 00000000..23c73d8a --- /dev/null +++ b/src/VBox/Additions/darwin/VBoxClient/VBoxClientInternal.h @@ -0,0 +1,112 @@ +/** $Id: VBoxClientInternal.h $ */ +/** @file + * VBoxClient - common definitions, Darwin. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#ifndef GA_INCLUDED_SRC_darwin_VBoxClient_VBoxClientInternal_h +#define GA_INCLUDED_SRC_darwin_VBoxClient_VBoxClientInternal_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/VBoxGuestLib.h> +#include <Carbon/Carbon.h> + +/* Service description */ +typedef struct +{ + /** The service name. */ + const char *pszName; + + /** + * Start service. + * @returns VBox status code. + */ + DECLCALLBACKMEMBER(int, pfnStart,(void)); + + /** + * Stop service. + * @returns VBox status code. + */ + DECLCALLBACKMEMBER(int, pfnStop,(void)); + +} VBOXCLIENTSERVICE; + + +/* + * Services + */ + +RT_C_DECLS_BEGIN + +extern VBOXCLIENTSERVICE g_ClipboardService; + +RT_C_DECLS_END + + +/* + * Functions + */ + +/** + * Displays a verbose message. + * + * @param iLevel Minimum log level required to display this message. + * @param pszFormat The message text. + * @param ... Format arguments. + */ +extern void VBoxClientVerbose(int iLevel, const char *pszFormat, ...); + +/** + * Walk through pasteboard items and report currently available item types. + * + * @param pPasteboard Reference to guest Pasteboard. + # @returns Available formats bit field. + */ +extern uint32_t vbclClipboardGetAvailableFormats(PasteboardRef pPasteboard); + +/** + * Read host's clipboard buffer and put its content to guest clipboard. + * + * @param u32ClientId Host connection. + * @param pPasteboard Guest PasteBoard reference. + * @param fFormats List of data formats (bit field) received from host. + * + * @returns IPRT status code. + */ +extern int vbclClipboardForwardToGuest(uint32_t u32ClientId, PasteboardRef pPasteboard, uint32_t fFormats); + +/** + * Read guest's clipboard buffer and forward its content to host. + * + * @param u32ClientId Host clipboard connection. + * @param pPasteboard Guest PasteBoard reference. + * @param fFormats List of data formats (bit field) received from host. + * + * @returns IPRT status code. + */ +extern int vbclClipboardForwardToHost(uint32_t u32ClientId, PasteboardRef pPasteboard, uint32_t fFormats); + +#endif /* !GA_INCLUDED_SRC_darwin_VBoxClient_VBoxClientInternal_h */ |