VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-darwin.cpp@ 94348

Last change on this file since 94348 was 93919, checked in by vboxsync, 3 years ago

Shared Clipboard: Resolved a @todo (renamed ShClBackendFormatAnnounce -> ShClBackendReportFormats).

  • Property eol-style set to native
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.4 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-darwin.cpp 93919 2022-02-24 13:59:11Z vboxsync $ */
2/** @file
3 * Shared Clipboard Service - Mac OS X host.
4 */
5
6/*
7 * Copyright (C) 2008-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
23#include <VBox/HostServices/VBoxClipboardSvc.h>
24
25#include <iprt/assert.h>
26#include <iprt/asm.h>
27#include <iprt/process.h>
28#include <iprt/rand.h>
29#include <iprt/string.h>
30#include <iprt/thread.h>
31
32#include "VBoxSharedClipboardSvc-internal.h"
33#include "darwin-pasteboard.h"
34
35
36/*********************************************************************************************************************************
37* Structures and Typedefs *
38*********************************************************************************************************************************/
39/** Global clipboard context information */
40typedef struct SHCLCONTEXT
41{
42 /** We have a separate thread to poll for new clipboard content. */
43 RTTHREAD hThread;
44 /** Termination indicator. */
45 bool volatile fTerminate;
46 /** The reference to the current pasteboard */
47 PasteboardRef hPasteboard;
48 /** Shared clipboard client. */
49 PSHCLCLIENT pClient;
50 /** Random 64-bit number embedded into szGuestOwnershipFlavor. */
51 uint64_t idGuestOwnership;
52 /** Ownership flavor CFStringRef returned by takePasteboardOwnership().
53 * This is the same a szGuestOwnershipFlavor only in core foundation terms. */
54 void *hStrOwnershipFlavor;
55 /** The guest ownership flavor (type) string. */
56 char szGuestOwnershipFlavor[64];
57} SHCLCONTEXT;
58
59
60/*********************************************************************************************************************************
61* Global Variables *
62*********************************************************************************************************************************/
63/** Only one client is supported. There seems to be no need for more clients. */
64static SHCLCONTEXT g_ctx;
65
66
67/**
68 * Checks if something is present on the clipboard and calls shclSvcReportMsg.
69 *
70 * @returns IPRT status code (ignored).
71 * @param pCtx The context.
72 *
73 * @note Call must own lock.
74 */
75static int vboxClipboardChanged(SHCLCONTEXT *pCtx)
76{
77 if (pCtx->pClient == NULL)
78 return VINF_SUCCESS;
79
80 /* Retrieve the formats currently in the clipboard and supported by vbox */
81 uint32_t fFormats = 0;
82 bool fChanged = false;
83 int rc = queryNewPasteboardFormats(pCtx->hPasteboard, pCtx->idGuestOwnership, pCtx->hStrOwnershipFlavor,
84 &fFormats, &fChanged);
85 if ( RT_SUCCESS(rc)
86 && fChanged
87 && ShClSvcIsBackendActive())
88 rc = ShClSvcHostReportFormats(pCtx->pClient, fFormats);
89
90 LogFlowFuncLeaveRC(rc);
91 return rc;
92}
93
94/**
95 * @callback_method_impl{FNRTTHREAD, The poller thread.
96 *
97 * This thread will check for the arrival of new data on the clipboard.}
98 */
99static DECLCALLBACK(int) vboxClipboardThread(RTTHREAD ThreadSelf, void *pvUser)
100{
101 SHCLCONTEXT *pCtx = (SHCLCONTEXT *)pvUser;
102 AssertPtr(pCtx);
103 LogFlowFuncEnter();
104
105 while (!pCtx->fTerminate)
106 {
107 /* call this behind the lock because we don't know if the api is
108 thread safe and in any case we're calling several methods. */
109 ShClSvcLock();
110 vboxClipboardChanged(pCtx);
111 ShClSvcUnlock();
112
113 /* Sleep for 200 msecs before next poll */
114 RTThreadUserWait(ThreadSelf, 200);
115 }
116
117 LogFlowFuncLeaveRC(VINF_SUCCESS);
118 return VINF_SUCCESS;
119}
120
121
122int ShClBackendInit(PSHCLBACKEND pBackend, VBOXHGCMSVCFNTABLE *pTable)
123{
124 RT_NOREF(pBackend, pTable);
125 g_ctx.fTerminate = false;
126
127 int rc = initPasteboard(&g_ctx.hPasteboard);
128 AssertRCReturn(rc, rc);
129
130 rc = RTThreadCreate(&g_ctx.hThread, vboxClipboardThread, &g_ctx, 0,
131 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
132 if (RT_FAILURE(rc))
133 {
134 g_ctx.hThread = NIL_RTTHREAD;
135 destroyPasteboard(&g_ctx.hPasteboard);
136 }
137
138 return rc;
139}
140
141void ShClBackendDestroy(PSHCLBACKEND pBackend)
142{
143 RT_NOREF(pBackend);
144
145 /*
146 * Signal the termination of the polling thread and wait for it to respond.
147 */
148 ASMAtomicWriteBool(&g_ctx.fTerminate, true);
149 int rc = RTThreadUserSignal(g_ctx.hThread);
150 AssertRC(rc);
151 rc = RTThreadWait(g_ctx.hThread, RT_INDEFINITE_WAIT, NULL);
152 AssertRC(rc);
153
154 /*
155 * Destroy the hPasteboard and uninitialize the global context record.
156 */
157 destroyPasteboard(&g_ctx.hPasteboard);
158 g_ctx.hThread = NIL_RTTHREAD;
159 g_ctx.pClient = NULL;
160}
161
162int ShClBackendConnect(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, bool fHeadless)
163{
164 RT_NOREF(pBackend, fHeadless);
165
166 if (g_ctx.pClient != NULL)
167 {
168 /* One client only. */
169 return VERR_NOT_SUPPORTED;
170 }
171
172 ShClSvcLock();
173
174 pClient->State.pCtx = &g_ctx;
175 pClient->State.pCtx->pClient = pClient;
176
177 ShClSvcUnlock();
178
179 return VINF_SUCCESS;
180}
181
182int ShClBackendSync(PSHCLBACKEND pBackend, PSHCLCLIENT pClient)
183{
184 RT_NOREF(pBackend);
185
186 /* Sync the host clipboard content with the client. */
187 ShClSvcLock();
188
189 int rc = vboxClipboardChanged(pClient->State.pCtx);
190
191 ShClSvcUnlock();
192
193 return rc;
194}
195
196int ShClBackendDisconnect(PSHCLBACKEND pBackend, PSHCLCLIENT pClient)
197{
198 RT_NOREF(pBackend);
199
200 ShClSvcLock();
201
202 pClient->State.pCtx->pClient = NULL;
203
204 ShClSvcUnlock();
205
206 return VINF_SUCCESS;
207}
208
209int ShClBackendReportFormats(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, SHCLFORMATS fFormats)
210{
211 RT_NOREF(pBackend);
212
213 LogFlowFunc(("fFormats=%02X\n", fFormats));
214
215 /** @todo r=bird: BUGBUG: The following is probably a mistake. */
216 /** @todo r=andy: BUGBUG: Has been there since forever; needs investigation first before removing. */
217 if (fFormats == VBOX_SHCL_FMT_NONE)
218 {
219 /* This is just an automatism, not a genuine announcement */
220 return VINF_SUCCESS;
221 }
222
223#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
224 if (fFormats & VBOX_SHCL_FMT_URI_LIST) /* No transfer support yet. */
225 return VINF_SUCCESS;
226#endif
227
228 SHCLCONTEXT *pCtx = pClient->State.pCtx;
229 ShClSvcLock();
230
231 /*
232 * Generate a unique flavor string for this format announcement.
233 */
234 uint64_t idFlavor = RTRandU64();
235 pCtx->idGuestOwnership = idFlavor;
236 RTStrPrintf(pCtx->szGuestOwnershipFlavor, sizeof(pCtx->szGuestOwnershipFlavor),
237 "org.virtualbox.sharedclipboard.%RTproc.%RX64", RTProcSelf(), idFlavor);
238
239 /*
240 * Empty the pasteboard and put our ownership indicator flavor there
241 * with the stringified formats as value.
242 */
243 char szValue[32];
244 RTStrPrintf(szValue, sizeof(szValue), "%#x", fFormats);
245
246 takePasteboardOwnership(pCtx->hPasteboard, pCtx->idGuestOwnership, pCtx->szGuestOwnershipFlavor, szValue,
247 &pCtx->hStrOwnershipFlavor);
248
249 ShClSvcUnlock();
250
251 /*
252 * Now, request the data from the guest.
253 */
254 return ShClSvcGuestDataRequest(pClient, fFormats, NULL /* pidEvent */);
255}
256
257int ShClBackendReadData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT fFormat,
258 void *pvData, uint32_t cbData, uint32_t *pcbActual)
259{
260 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
261 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
262 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
263 AssertPtrReturn(pcbActual, VERR_INVALID_POINTER);
264
265 RT_NOREF(pBackend, pCmdCtx);
266
267 ShClSvcLock();
268
269 /* Default to no data available. */
270 *pcbActual = 0;
271
272 int rc = readFromPasteboard(pClient->State.pCtx->hPasteboard, fFormat, pvData, cbData, pcbActual);
273 if (RT_FAILURE(rc))
274 LogRel(("Shared Clipboard: Error reading host clipboard data from macOS, rc=%Rrc\n", rc));
275
276 ShClSvcUnlock();
277
278 return rc;
279}
280
281int ShClBackendWriteData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData)
282{
283 RT_NOREF(pBackend, pCmdCtx);
284
285 LogFlowFuncEnter();
286
287 ShClSvcLock();
288
289 writeToPasteboard(pClient->State.pCtx->hPasteboard, pClient->State.pCtx->idGuestOwnership, pvData, cbData, fFormat);
290
291 ShClSvcUnlock();
292
293 LogFlowFuncLeaveRC(VINF_SUCCESS);
294 return VINF_SUCCESS;
295}
296
297#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
298
299int ShClBackendTransferReadDir(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLDIRDATA pDirData)
300{
301 RT_NOREF(pBackend, pClient, pDirData);
302 return VERR_NOT_IMPLEMENTED;
303}
304
305int ShClBackendTransferWriteDir(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLDIRDATA pDirData)
306{
307 RT_NOREF(pBackend, pClient, pDirData);
308 return VERR_NOT_IMPLEMENTED;
309}
310
311int ShClBackendTransferReadFileHdr(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLFILEHDR pFileHdr)
312{
313 RT_NOREF(pBackend, pClient, pFileHdr);
314 return VERR_NOT_IMPLEMENTED;
315}
316
317int ShClBackendTransferWriteFileHdr(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLFILEHDR pFileHdr)
318{
319 RT_NOREF(pBackend, pClient, pFileHdr);
320 return VERR_NOT_IMPLEMENTED;
321}
322
323int ShClBackendTransferReadFileData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLFILEDATA pFileData)
324{
325 RT_NOREF(pBackend, pClient, pFileData);
326 return VERR_NOT_IMPLEMENTED;
327}
328
329int ShClBackendTransferWriteFileData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLFILEDATA pFileData)
330{
331 RT_NOREF(pBackend, pClient, pFileData);
332 return VERR_NOT_IMPLEMENTED;
333}
334
335#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
336
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette