VirtualBox

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

Last change on this file since 81790 was 81746, 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: 13.0 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-x11.cpp 81746 2019-11-08 08:28:06Z 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
59int ShClSvcImplInit(void)
60{
61 LogFlowFuncEnter();
62 return VINF_SUCCESS;
63}
64
65void ShClSvcImplDestroy(void)
66{
67 LogFlowFuncEnter();
68}
69
70/**
71 * @note On the host, we assume that some other application already owns
72 * the clipboard and leave ownership to X11.
73 */
74int ShClSvcImplConnect(PSHCLCLIENT pClient, bool fHeadless)
75{
76 int rc = VINF_SUCCESS;
77
78 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)RTMemAllocZ(sizeof(SHCLCONTEXT));
79 if (pCtx)
80 {
81 RTCritSectInit(&pCtx->CritSect);
82 CLIPBACKEND *pBackend = ClipConstructX11(pCtx, fHeadless);
83 if (!pBackend)
84 {
85 rc = VERR_NO_MEMORY;
86 }
87 else
88 {
89 pCtx->pBackend = pBackend;
90 pClient->State.pCtx = pCtx;
91 pCtx->pClient = pClient;
92
93 rc = ClipStartX11(pBackend, true /* grab shared clipboard */);
94 if (RT_FAILURE(rc))
95 ClipDestructX11(pBackend);
96 }
97
98 if (RT_FAILURE(rc))
99 {
100 RTCritSectDelete(&pCtx->CritSect);
101 RTMemFree(pCtx);
102 }
103 }
104 else
105 rc = VERR_NO_MEMORY;
106
107 LogFlowFuncLeaveRC(rc);
108 return rc;
109}
110
111int ShClSvcImplSync(PSHCLCLIENT pClient)
112{
113 LogFlowFuncEnter();
114
115 /* Tell the guest we have no data in case X11 is not available. If
116 * there is data in the host clipboard it will automatically be sent to
117 * the guest when the clipboard starts up. */
118 SHCLFORMATDATA formatData;
119 RT_ZERO(formatData);
120
121 formatData.uFormats = VBOX_SHCL_FMT_NONE;
122
123 return ShClSvcFormatsReport(pClient, &formatData);
124}
125
126/**
127 * Shut down the shared clipboard service and "disconnect" the guest.
128 * @note Host glue code
129 */
130int ShClSvcImplDisconnect(PSHCLCLIENT pClient)
131{
132 LogFlowFuncEnter();
133
134 PSHCLCONTEXT pCtx = pClient->State.pCtx;
135 AssertPtr(pCtx);
136
137 /* Drop the reference to the client, in case it is still there. This
138 * will cause any outstanding clipboard data requests from X11 to fail
139 * immediately. */
140 pCtx->fShuttingDown = true;
141
142 int rc = ClipStopX11(pCtx->pBackend);
143 /** @todo handle this slightly more reasonably, or be really sure
144 * it won't go wrong. */
145 AssertRC(rc);
146
147 if (RT_SUCCESS(rc)) /* And if not? */
148 {
149 ClipDestructX11(pCtx->pBackend);
150 RTCritSectDelete(&pCtx->CritSect);
151 RTMemFree(pCtx);
152 }
153
154 LogFlowFuncLeaveRC(rc);
155 return rc;
156}
157
158int ShClSvcImplFormatAnnounce(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx,
159 PSHCLFORMATDATA pFormats)
160{
161 RT_NOREF(pCmdCtx);
162
163 int rc = ClipAnnounceFormatToX11(pClient->State.pCtx->pBackend, pFormats->uFormats);
164
165 LogFlowFuncLeaveRC(rc);
166 return rc;
167}
168
169/** Structure describing a request for clipoard data from the guest. */
170struct _CLIPREADCBREQ
171{
172 /** User-supplied data pointer, based on the request type. */
173 void *pv;
174 /** The size (in bytes) of the the user-supplied pointer in pv. */
175 uint32_t cb;
176 /** The actual size of the data written. */
177 uint32_t *pcbActual;
178 /** The request's event ID. */
179 SHCLEVENTID uEvent;
180};
181
182/**
183 * @note We always fail or complete asynchronously.
184 * @note On success allocates a CLIPREADCBREQ structure which must be
185 * freed in ClipCompleteDataRequestFromX11 when it is called back from
186 * the backend code.
187 */
188int ShClSvcImplReadData(PSHCLCLIENT pClient,
189 PSHCLCLIENTCMDCTX pCmdCtx, PSHCLDATABLOCK pData, uint32_t *pcbActual)
190{
191 RT_NOREF(pCmdCtx);
192
193 LogFlowFunc(("pClient=%p, uFormat=%02X, pv=%p, cb=%u, pcbActual=%p\n",
194 pClient, pData->uFormat, pData->pvData, pData->cbData, pcbActual));
195
196 int rc = VINF_SUCCESS;
197
198 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(CLIPREADCBREQ));
199 if (pReq)
200 {
201 const SHCLEVENTID uEvent = ShClEventIDGenerate(&pClient->Events);
202
203 pReq->pv = pData->pvData;
204 pReq->cb = pData->cbData;
205 pReq->pcbActual = pcbActual;
206 pReq->uEvent = uEvent;
207
208 rc = ShClEventRegister(&pClient->Events, uEvent);
209 if (RT_SUCCESS(rc))
210 {
211 rc = ClipRequestDataFromX11(pClient->State.pCtx->pBackend, pData->uFormat, pReq);
212 if (RT_SUCCESS(rc))
213 {
214 PSHCLEVENTPAYLOAD pPayload;
215 rc = ShClEventWait(&pClient->Events, uEvent, 30 * 1000, &pPayload);
216 if (RT_SUCCESS(rc))
217 {
218 memcpy(pData->pvData, pPayload->pvData, RT_MIN(pData->cbData, pPayload->cbData));
219 pData->cbData = pPayload->cbData;
220
221 Assert(pData->cbData == pPayload->cbData); /* Sanity. */
222 }
223 }
224
225 ShClEventUnregister(&pClient->Events, uEvent);
226 }
227 }
228 else
229 rc = VERR_NO_MEMORY;
230
231 LogFlowFuncLeaveRC(rc);
232 return rc;
233}
234
235int ShClSvcImplWriteData(PSHCLCLIENT pClient,
236 PSHCLCLIENTCMDCTX pCmdCtx, PSHCLDATABLOCK pData)
237{
238 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
239 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
240 AssertPtrReturn(pData, VERR_INVALID_POINTER);
241
242 LogFlowFunc(("pClient=%p, pv=%p, cb=%RU32, uFormat=%02X\n",
243 pClient, pData->pvData, pData->cbData, pData->uFormat));
244
245 int rc = ShClSvcDataReadSignal(pClient, pCmdCtx, pData);
246
247 LogFlowFuncLeaveRC(rc);
248 return rc;
249}
250
251/**
252 * Reports formats available in the X11 clipboard to VBox.
253 *
254 * @note Runs in Xt event thread.
255 *
256 * @param pCtx Opaque context pointer for the glue code.
257 * @param u32Formats The formats available.
258 */
259DECLCALLBACK(void) ClipReportX11FormatsCallback(PSHCLCONTEXT pCtx, uint32_t u32Formats)
260{
261 LogFlowFunc(("pCtx=%p, u32Formats=%02X\n", pCtx, u32Formats));
262
263 if (u32Formats == VBOX_SHCL_FMT_NONE) /* No formats to report? Bail out early. */
264 return;
265
266 SHCLFORMATDATA formatData;
267 RT_ZERO(formatData);
268
269 formatData.uFormats = u32Formats;
270
271 int rc = ShClSvcFormatsReport(pCtx->pClient, &formatData);
272 RT_NOREF(rc);
273
274 LogFlowFuncLeaveRC(rc);
275}
276
277/**
278 * Completes a request from the host service for reading the X11 clipboard data.
279 * The data should be written to the buffer provided in the initial request.
280 *
281 * @note Runs in Xt event thread.
282 *
283 * @param pCtx Request context information.
284 * @param rcCompletion The completion status of the request.
285 * @param pReq Request to complete.
286 * @param pv Address of data from completed request. Optional.
287 * @param cb Size (in bytes) of data from completed request. Optional.
288 *
289 * @todo Change this to deal with the buffer issues rather than offloading them onto the caller.
290 */
291DECLCALLBACK(void) ClipRequestFromX11CompleteCallback(PSHCLCONTEXT pCtx, int rcCompletion,
292 CLIPREADCBREQ *pReq, void *pv, uint32_t cb)
293{
294 RT_NOREF(rcCompletion);
295
296 LogFlowFunc(("rcCompletion=%Rrc, pReq=%p, pv=%p, cb=%RU32, uEvent=%RU32\n", rcCompletion, pReq, pv, cb, pReq->uEvent));
297
298 AssertMsgRC(rcCompletion, ("Clipboard data completion from X11 failed with %Rrc\n", rcCompletion));
299
300 if (pReq->uEvent != NIL_SHCLEVENTID)
301 {
302 int rc2;
303
304 PSHCLEVENTPAYLOAD pPayload = NULL;
305 if (pv && cb)
306 {
307 rc2 = ShClPayloadAlloc(pReq->uEvent, pv, cb, &pPayload);
308 AssertRC(rc2);
309 }
310
311 rc2 = ShClEventSignal(&pCtx->pClient->Events, pReq->uEvent, pPayload);
312 AssertRC(rc2);
313 }
314
315 RTMemFree(pReq);
316}
317
318/**
319 * Reads clipboard data from the guest and passes it to the X11 clipboard.
320 *
321 * @note Runs in Xt event thread.
322 *
323 * @param pCtx Pointer to the host clipboard structure.
324 * @param u32Format The format in which the data should be transferred
325 * @param ppv On success and if pcb > 0, this will point to a buffer
326 * to be freed with RTMemFree containing the data read.
327 * @param pcb On success, this contains the number of bytes of data
328 * returned.
329 */
330DECLCALLBACK(int) ClipRequestDataForX11Callback(PSHCLCONTEXT pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb)
331{
332 LogFlowFunc(("pCtx=%p, u32Format=%02X, ppv=%p\n", pCtx, u32Format, ppv));
333
334 if (pCtx->fShuttingDown)
335 {
336 /* The shared clipboard is disconnecting. */
337 LogRel(("Shared Clipboard: Host requested guest clipboard data after guest had disconnected\n"));
338 return VERR_WRONG_ORDER;
339 }
340
341 /* Request data from the guest. */
342 SHCLDATAREQ dataReq;
343 RT_ZERO(dataReq);
344
345 dataReq.uFmt = u32Format;
346 dataReq.cbSize = _64K; /** @todo Make this more dynamic. */
347
348 SHCLEVENTID uEvent;
349 int rc = ShClSvcDataReadRequest(pCtx->pClient, &dataReq, &uEvent);
350 if (RT_SUCCESS(rc))
351 {
352 PSHCLEVENTPAYLOAD pPayload;
353 rc = ShClEventWait(&pCtx->pClient->Events, uEvent, 30 * 1000, &pPayload);
354 if (RT_SUCCESS(rc))
355 {
356 *ppv = pPayload->pvData;
357 *pcb = pPayload->cbData;
358
359 /* Detach the payload, as the caller then will own the data. */
360 ShClEventPayloadDetach(&pCtx->pClient->Events, uEvent);
361 }
362
363 ShClEventUnregister(&pCtx->pClient->Events, uEvent);
364 }
365
366 LogFlowFuncLeaveRC(rc);
367 return rc;
368}
369
370#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
371int ShClSvcImplTransferCreate(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
372{
373 RT_NOREF(pClient, pTransfer);
374
375 int rc = VINF_SUCCESS;
376
377 LogFlowFuncLeaveRC(rc);
378 return rc;
379}
380
381int ShClSvcImplTransferDestroy(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
382{
383 RT_NOREF(pClient, pTransfer);
384
385 int rc = VINF_SUCCESS;
386
387 LogFlowFuncLeaveRC(rc);
388 return rc;
389}
390
391int ShClSvcImplTransferGetRoots(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
392{
393 LogFlowFuncEnter();
394
395 int rc;
396
397 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(CLIPREADCBREQ));
398 if (pReq)
399 {
400 pReq->pv = pTransfer;
401 pReq->cb = sizeof(SHCLTRANSFER);
402 pReq->uEvent = NIL_SHCLEVENTID; /* No event handling needed. */
403
404 #if 0
405 SHCLEVENTID uEvent = ShClEventIDGenerate(&pClient->Events);
406
407 rc = ShClEventRegister(&pClient->Events, uEvent);
408 if (RT_SUCCESS(rc))
409 {
410 #endif
411 rc = ClipRequestDataFromX11(pClient->State.pCtx->pBackend, VBOX_SHCL_FMT_URI_LIST, pReq);
412 #if 0
413 if (RT_SUCCESS(rc))
414 {
415 /* X supplies the data asynchronously, so we need to wait for data to arrive first. */
416 rc = ShClEventWait(&pClient->Events, uEvent, 30 * 1000, NULL /* pPayload */);
417 }
418
419 ShClEventUnregister(&pClient->Events, uEvent);
420 }
421 #endif
422 }
423 else
424 rc = VERR_NO_MEMORY;
425
426 LogFlowFuncLeaveRC(rc);
427 return rc;
428}
429#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