VirtualBox

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

Last change on this file since 99196 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

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