VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11.cpp@ 81699

Last change on this file since 81699 was 81699, checked in by vboxsync, 5 years ago

Shared Clipboard/Transfers: Update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.5 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-x11.cpp 81699 2019-11-06 10:54:35Z vboxsync $ */
2/** @file
3 * Shared Clipboard Service - Linux host.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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 <iprt/assert.h>
24#include <iprt/critsect.h>
25#include <iprt/env.h>
26#include <iprt/mem.h>
27#include <iprt/semaphore.h>
28#include <iprt/string.h>
29
30#include <VBox/GuestHost/SharedClipboard.h>
31#include <VBox/HostServices/VBoxClipboardSvc.h>
32#include <iprt/errcore.h>
33
34#include "VBoxSharedClipboardSvc-internal.h"
35
36
37/*********************************************************************************************************************************
38* Structures and Typedefs *
39*********************************************************************************************************************************/
40
41/**
42 * Global context information used by the host glue for the X11 clipboard backend.
43 */
44struct _SHCLCONTEXT
45{
46 /** This mutex is grabbed during any critical operations on the clipboard
47 * which might clash with others. */
48 RTCRITSECT CritSect;
49 /** Pointer to the opaque X11 backend structure */
50 CLIPBACKEND *pBackend;
51 /** Pointer to the VBox host client data structure. */
52 PSHCLCLIENT pClient;
53 /** We set this when we start shutting down as a hint not to post any new
54 * requests. */
55 bool fShuttingDown;
56};
57
58
59/**
60 * Report formats available in the X11 clipboard to VBox.
61 * @param pCtx Opaque context pointer for the glue code.
62 * @param u32Formats The formats available.
63 */
64DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, uint32_t u32Formats)
65{
66 LogFlowFunc(("pCtx=%p, u32Formats=%02X\n", pCtx, u32Formats));
67
68 if (u32Formats == VBOX_SHCL_FMT_NONE) /* No formats to report? Bail out early. */
69 return;
70
71 SHCLFORMATDATA formatData;
72 RT_ZERO(formatData);
73
74 formatData.uFormats = u32Formats;
75
76 int rc = shClSvcFormatsReport(pCtx->pClient, &formatData);
77 RT_NOREF(rc);
78
79 LogFlowFuncLeaveRC(rc);
80}
81
82int ShClSvcImplInit(void)
83{
84 LogFlowFuncEnter();
85 return VINF_SUCCESS;
86}
87
88void ShClSvcImplDestroy(void)
89{
90 LogFlowFuncEnter();
91}
92
93/**
94 * @note On the host, we assume that some other application already owns
95 * the clipboard and leave ownership to X11.
96 */
97int ShClSvcImplConnect(PSHCLCLIENT pClient, bool fHeadless)
98{
99 int rc = VINF_SUCCESS;
100
101 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)RTMemAllocZ(sizeof(SHCLCONTEXT));
102 if (pCtx)
103 {
104 RTCritSectInit(&pCtx->CritSect);
105 CLIPBACKEND *pBackend = ClipConstructX11(pCtx, fHeadless);
106 if (!pBackend)
107 {
108 rc = VERR_NO_MEMORY;
109 }
110 else
111 {
112 pCtx->pBackend = pBackend;
113 pClient->State.pCtx = pCtx;
114 pCtx->pClient = pClient;
115
116 rc = ClipStartX11(pBackend, true /* grab shared clipboard */);
117 if (RT_FAILURE(rc))
118 ClipDestructX11(pBackend);
119 }
120
121 if (RT_FAILURE(rc))
122 {
123 RTCritSectDelete(&pCtx->CritSect);
124 RTMemFree(pCtx);
125 }
126 }
127 else
128 rc = VERR_NO_MEMORY;
129
130 LogFlowFuncLeaveRC(rc);
131 return rc;
132}
133
134int ShClSvcImplSync(PSHCLCLIENT pClient)
135{
136 LogFlowFuncEnter();
137
138 /* Tell the guest we have no data in case X11 is not available. If
139 * there is data in the host clipboard it will automatically be sent to
140 * the guest when the clipboard starts up. */
141 SHCLFORMATDATA formatData;
142 RT_ZERO(formatData);
143
144 formatData.uFormats = VBOX_SHCL_FMT_NONE;
145
146 return shClSvcFormatsReport(pClient, &formatData);
147}
148
149/**
150 * Shut down the shared clipboard service and "disconnect" the guest.
151 * @note Host glue code
152 */
153int ShClSvcImplDisconnect(PSHCLCLIENT pClient)
154{
155 LogFlowFuncEnter();
156
157 PSHCLCONTEXT pCtx = pClient->State.pCtx;
158 AssertPtr(pCtx);
159
160 /* Drop the reference to the client, in case it is still there. This
161 * will cause any outstanding clipboard data requests from X11 to fail
162 * immediately. */
163 pCtx->fShuttingDown = true;
164
165 int rc = ClipStopX11(pCtx->pBackend);
166 /** @todo handle this slightly more reasonably, or be really sure
167 * it won't go wrong. */
168 AssertRC(rc);
169
170 if (RT_SUCCESS(rc)) /* And if not? */
171 {
172 ClipDestructX11(pCtx->pBackend);
173 RTCritSectDelete(&pCtx->CritSect);
174 RTMemFree(pCtx);
175 }
176
177 LogFlowFuncLeaveRC(rc);
178 return rc;
179}
180
181int ShClSvcImplFormatAnnounce(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx,
182 PSHCLFORMATDATA pFormats)
183{
184 RT_NOREF(pCmdCtx);
185
186 int rc = ClipAnnounceFormatToX11(pClient->State.pCtx->pBackend, pFormats->uFormats);
187
188 LogFlowFuncLeaveRC(rc);
189 return rc;
190}
191
192/** Structure describing a request for clipoard data from the guest. */
193struct _CLIPREADCBREQ
194{
195 /** Where to write the returned data to. Weak pointer! */
196 void *pv;
197 /** The size of the buffer in pv. */
198 uint32_t cb;
199 /** The actual size of the data written. */
200 uint32_t *pcbActual;
201 /** The request's event ID. */
202 SHCLEVENTID uEvent;
203};
204
205/**
206 * @note We always fail or complete asynchronously.
207 * @note On success allocates a CLIPREADCBREQ structure which must be
208 * freed in ClipCompleteDataRequestFromX11 when it is called back from
209 * the backend code.
210 */
211int ShClSvcImplReadData(PSHCLCLIENT pClient,
212 PSHCLCLIENTCMDCTX pCmdCtx, PSHCLDATABLOCK pData, uint32_t *pcbActual)
213{
214 RT_NOREF(pCmdCtx);
215
216 LogFlowFunc(("pClient=%p, uFormat=%02X, pv=%p, cb=%u, pcbActual=%p\n",
217 pClient, pData->uFormat, pData->pvData, pData->cbData, pcbActual));
218
219 int rc = VINF_SUCCESS;
220
221 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(CLIPREADCBREQ));
222 if (pReq)
223 {
224 const SHCLEVENTID uEvent = ShClEventIDGenerate(&pClient->Events);
225
226 pReq->pv = pData->pvData;
227 pReq->cb = pData->cbData;
228 pReq->pcbActual = pcbActual;
229 pReq->uEvent = uEvent;
230
231 rc = ClipRequestDataFromX11(pClient->State.pCtx->pBackend, pData->uFormat, pReq);
232 if (RT_SUCCESS(rc))
233 {
234 rc = ShClEventRegister(&pClient->Events, uEvent);
235 if (RT_SUCCESS(rc))
236 {
237 PSHCLEVENTPAYLOAD pPayload;
238 rc = ShClEventWait(&pClient->Events, uEvent, 30 * 1000, &pPayload);
239 if (RT_SUCCESS(rc))
240 {
241 memcpy(pData->pvData, pPayload->pvData, RT_MIN(pData->cbData, pPayload->cbData));
242 pData->cbData = pPayload->cbData;
243
244 Assert(pData->cbData == pPayload->cbData); /* Sanity. */
245 }
246
247 ShClEventUnregister(&pClient->Events, uEvent);
248 }
249 }
250 }
251 else
252 rc = VERR_NO_MEMORY;
253
254 LogFlowFuncLeaveRC(rc);
255 return rc;
256}
257
258int ShClSvcImplWriteData(PSHCLCLIENT pClient,
259 PSHCLCLIENTCMDCTX pCmdCtx, PSHCLDATABLOCK pData)
260{
261 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
262 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
263 AssertPtrReturn(pData, VERR_INVALID_POINTER);
264
265 LogFlowFunc(("pClient=%p, pv=%p, cb=%RU32, uFormat=%02X\n",
266 pClient, pData->pvData, pData->cbData, pData->uFormat));
267
268 int rc = shClSvcDataReadSignal(pClient, pCmdCtx, pData);
269
270 LogFlowFuncLeaveRC(rc);
271 return rc;
272}
273
274/**
275 * Completes a request from the host service for reading the X11 clipboard data.
276 * The data should be written to the buffer provided in the initial request.
277 *
278 * @param pCtx Request context information.
279 * @param rc The completion status of the request.
280 * @param pReq Request.
281 * @param pv Address.
282 * @param cb Size.
283 *
284 * @todo Change this to deal with the buffer issues rather than offloading them onto the caller.
285 */
286void ClipRequestFromX11CompleteCallback(SHCLCONTEXT *pCtx, int rc,
287 CLIPREADCBREQ *pReq, void *pv, uint32_t cb)
288{
289 AssertMsgRC(rc, ("Clipboard data completion from X11 failed with %Rrc\n", rc));
290
291 PSHCLEVENTPAYLOAD pPayload;
292 int rc2 = ShClPayloadAlloc(pReq->uEvent, pv, cb, &pPayload);
293 if (RT_SUCCESS(rc2))
294 rc2 = ShClEventSignal(&pCtx->pClient->Events, pReq->uEvent, pPayload);
295
296 AssertRC(rc);
297
298 RTMemFree(pReq);
299}
300
301/**
302 * Reads clipboard data from the guest and passes it to the X11 clipboard.
303 *
304 * @param pCtx Pointer to the host clipboard structure
305 * @param u32Format The format in which the data should be transferred
306 * @param ppv On success and if pcb > 0, this will point to a buffer
307 * to be freed with RTMemFree containing the data read.
308 * @param pcb On success, this contains the number of bytes of data
309 * returned
310 * @note Host glue code.
311 */
312DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb)
313{
314 LogFlowFunc(("pCtx=%p, u32Format=%02X, ppv=%p\n", pCtx, u32Format, ppv));
315
316 if (pCtx->fShuttingDown)
317 {
318 /* The shared clipboard is disconnecting. */
319 LogRel(("Shared Clipboard: Host requested guest clipboard data after guest had disconnected\n"));
320 return VERR_WRONG_ORDER;
321 }
322
323 /* Request data from the guest. */
324 SHCLDATAREQ dataReq;
325 RT_ZERO(dataReq);
326
327 dataReq.uFmt = u32Format;
328 dataReq.cbSize = _64K; /** @todo Make this more dynamic. */
329
330 SHCLEVENTID uEvent;
331 int rc = shClSvcDataReadRequest(pCtx->pClient, &dataReq, &uEvent);
332 if (RT_SUCCESS(rc))
333 {
334 PSHCLEVENTPAYLOAD pPayload;
335 rc = ShClEventWait(&pCtx->pClient->Events, uEvent, 30 * 1000, &pPayload);
336 if (RT_SUCCESS(rc))
337 {
338 *ppv = pPayload->pvData;
339 *pcb = pPayload->cbData;
340
341 /* Detach the payload, as the caller then will own the data. */
342 ShClEventPayloadDetach(&pCtx->pClient->Events, uEvent);
343 }
344
345 ShClEventUnregister(&pCtx->pClient->Events, uEvent);
346 }
347
348 LogFlowFuncLeaveRC(rc);
349 return rc;
350}
351
352#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
353int ShClSvcImplTransferCreate(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
354{
355 RT_NOREF(pClient, pTransfer);
356
357 int rc = VINF_SUCCESS;
358
359 LogFlowFuncLeaveRC(rc);
360 return rc;
361}
362
363int ShClSvcImplTransferDestroy(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
364{
365 RT_NOREF(pClient, pTransfer);
366
367 int rc = VINF_SUCCESS;
368
369 LogFlowFuncLeaveRC(rc);
370 return rc;
371}
372
373int ShClSvcImplTransferGetRoots(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
374{
375 RT_NOREF(pClient, pTransfer);
376
377 int rc = VINF_SUCCESS;
378
379 LogFlowFuncLeaveRC(rc);
380 return rc;
381}
382#endif
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