VirtualBox

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

Last change on this file since 80849 was 80849, checked in by vboxsync, 6 years ago

Shared Clipboard/URI: Renamed VBOX_WITH_SHARED_CLIPBOARD_URI_LIST -> VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.9 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-x11.cpp 80849 2019-09-17 09:46:51Z 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 <VBox/err.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 * @note Host glue code
64 */
65void ClipReportX11Formats(SHCLCONTEXT *pCtx, uint32_t u32Formats)
66{
67 LogFlowFunc(("pCtx=%p, u32Formats=%02X\n", pCtx, u32Formats));
68
69 SHCLFORMATDATA formatData;
70 RT_ZERO(formatData);
71
72 formatData.uFormats = u32Formats;
73
74 int rc2 = sharedClipboardSvcFormatsReport(pCtx->pClient, &formatData);
75 AssertRC(rc2);
76}
77
78/**
79 * Initialise the host side of the shared clipboard.
80 * @note Host glue code
81 */
82int SharedClipboardSvcImplInit(void)
83{
84 LogFlowFuncEnter();
85 return VINF_SUCCESS;
86}
87
88/**
89 * Terminate the host side of the shared clipboard.
90 * @note host glue code
91 */
92void SharedClipboardSvcImplDestroy(void)
93{
94 LogFlowFuncEnter();
95}
96
97/**
98 * Connect a guest to the shared clipboard.
99 * @note on the host, we assume that some other application already owns
100 * the clipboard and leave ownership to X11.
101 */
102int SharedClipboardSvcImplConnect(PSHCLCLIENT pClient, bool fHeadless)
103{
104 int rc = VINF_SUCCESS;
105
106 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)RTMemAllocZ(sizeof(SHCLCONTEXT));
107 if (pCtx)
108 {
109 RTCritSectInit(&pCtx->CritSect);
110 CLIPBACKEND *pBackend = ClipConstructX11(pCtx, fHeadless);
111 if (!pBackend)
112 {
113 rc = VERR_NO_MEMORY;
114 }
115 else
116 {
117 pCtx->pBackend = pBackend;
118 pClient->State.pCtx = pCtx;
119 pCtx->pClient = pClient;
120
121 rc = ClipStartX11(pBackend, true /* grab shared clipboard */);
122 if (RT_FAILURE(rc))
123 ClipDestructX11(pBackend);
124 }
125
126 if (RT_FAILURE(rc))
127 {
128 RTCritSectDelete(&pCtx->CritSect);
129 RTMemFree(pCtx);
130 }
131 }
132 else
133 rc = VERR_NO_MEMORY;
134
135 LogFlowFuncLeaveRC(rc);
136 return rc;
137}
138
139/**
140 * Synchronise the contents of the host clipboard with the guest, called
141 * after a save and restore of the guest.
142 * @note Host glue code
143 */
144int SharedClipboardSvcImplSync(PSHCLCLIENT pClient)
145{
146 LogFlowFuncEnter();
147
148 /* Tell the guest we have no data in case X11 is not available. If
149 * there is data in the host clipboard it will automatically be sent to
150 * the guest when the clipboard starts up. */
151 SHCLFORMATDATA formatData;
152 RT_ZERO(formatData);
153
154 formatData.uFormats = VBOX_SHCL_FMT_NONE;
155
156 return sharedClipboardSvcFormatsReport(pClient, &formatData);
157}
158
159/**
160 * Shut down the shared clipboard service and "disconnect" the guest.
161 * @note Host glue code
162 */
163int SharedClipboardSvcImplDisconnect(PSHCLCLIENT pClient)
164{
165 LogFlowFuncEnter();
166
167 PSHCLCONTEXT pCtx = pClient->State.pCtx;
168
169 /* Drop the reference to the client, in case it is still there. This
170 * will cause any outstanding clipboard data requests from X11 to fail
171 * immediately. */
172 pCtx->fShuttingDown = true;
173
174 /* If there is a currently pending request, release it immediately. */
175 SHCLDATABLOCK dataBlock = { 0, NULL, 0 };
176 SharedClipboardSvcImplWriteData(pClient, NULL, &dataBlock);
177
178 int rc = ClipStopX11(pCtx->pBackend);
179 /** @todo handle this slightly more reasonably, or be really sure
180 * it won't go wrong. */
181 AssertRC(rc);
182
183 if (RT_SUCCESS(rc)) /* And if not? */
184 {
185 ClipDestructX11(pCtx->pBackend);
186 RTCritSectDelete(&pCtx->CritSect);
187 RTMemFree(pCtx);
188 }
189
190 LogFlowFuncLeaveRC(rc);
191 return rc;
192}
193
194/**
195 * VBox is taking possession of the shared clipboard.
196 *
197 * @param pClient Context data for the guest system.
198 * @param pCmdCtx Command context to use.
199 * @param pFormats Clipboard formats the guest is offering.
200 */
201int SharedClipboardSvcImplFormatAnnounce(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx,
202 PSHCLFORMATDATA pFormats)
203{
204 RT_NOREF(pCmdCtx);
205
206#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
207 if (pFormats->uFormats & VBOX_SHCL_FMT_URI_LIST) /* No URI support yet. */
208 return VINF_SUCCESS;
209#endif
210
211 ClipAnnounceFormatToX11(pClient->State.pCtx->pBackend, pFormats->uFormats);
212
213 return VINF_SUCCESS;
214}
215
216/** Structure describing a request for clipoard data from the guest. */
217struct _CLIPREADCBREQ
218{
219 /** Where to write the returned data to. Weak pointer! */
220 void *pv;
221 /** The size of the buffer in pv. */
222 uint32_t cb;
223 /** The actual size of the data written. */
224 uint32_t *pcbActual;
225 /** The request's event ID. */
226 SHCLEVENTID uEvent;
227};
228
229/**
230 * Called when the host service wants to read the X11 clipboard.
231 *
232 * @returns VINF_SUCCESS on successful completion.
233 * @returns VINF_HGCM_ASYNC_EXECUTE if the operation will complete asynchronously.
234 * @returns IPRT status code on failure.
235 *
236 * @param pClient Context information about the guest VM.
237 * @param pCmdCtx Command context to use.
238 * @param pData Data block to put read data into.
239 * @param pcbActual Where to write the actual size of the written data.
240 *
241 * @note We always fail or complete asynchronously.
242 * @note On success allocates a CLIPREADCBREQ structure which must be
243 * freed in ClipCompleteDataRequestFromX11 when it is called back from
244 * the backend code.
245 *
246 */
247int SharedClipboardSvcImplReadData(PSHCLCLIENT pClient,
248 PSHCLCLIENTCMDCTX pCmdCtx, PSHCLDATABLOCK pData, uint32_t *pcbActual)
249{
250 RT_NOREF(pCmdCtx);
251
252 LogFlowFunc(("pClient=%p, uFormat=%02X, pv=%p, cb=%u, pcbActual=%p\n",
253 pClient, pData->uFormat, pData->pvData, pData->cbData, pcbActual));
254
255 int rc = VINF_SUCCESS;
256
257 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(CLIPREADCBREQ));
258 if (pReq)
259 {
260 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pClient->Events);
261
262 pReq->pv = pData->pvData;
263 pReq->cb = pData->cbData;
264 pReq->pcbActual = pcbActual;
265 pReq->uEvent = uEvent;
266
267 rc = ClipRequestDataFromX11(pClient->State.pCtx->pBackend, pData->uFormat, pReq);
268 if (RT_SUCCESS(rc))
269 {
270 rc = SharedClipboardEventRegister(&pClient->Events, uEvent);
271 if (RT_SUCCESS(rc))
272 {
273 PSHCLEVENTPAYLOAD pPayload;
274 rc = SharedClipboardEventWait(&pClient->Events, uEvent, 30 * 1000, &pPayload);
275 if (RT_SUCCESS(rc))
276 {
277 memcpy(pData->pvData, pPayload->pvData, RT_MIN(pData->cbData, pPayload->cbData));
278 pData->cbData = pPayload->cbData;
279
280 Assert(pData->cbData == pPayload->cbData); /* Sanity. */
281 }
282
283 SharedClipboardEventUnregister(&pClient->Events, uEvent);
284 }
285 }
286 }
287 else
288 rc = VERR_NO_MEMORY;
289
290 LogFlowFuncLeaveRC(rc);
291 return rc;
292}
293
294/**
295 * Called when writing guest clipboard data to the host service.
296 *
297 * @param pClient Context information about the guest VM.
298 * @param pCmdCtx Pointer to the clipboard command context.
299 * @param pData Data block to write to clipboard.
300 */
301int SharedClipboardSvcImplWriteData(PSHCLCLIENT pClient,
302 PSHCLCLIENTCMDCTX pCmdCtx, PSHCLDATABLOCK pData)
303{
304 LogFlowFunc(("pClient=%p, pv=%p, cb=%RU32, uFormat=%02X\n",
305 pClient, pData->pvData, pData->cbData, pData->uFormat));
306
307 int rc = sharedClipboardSvcDataReadSignal(pClient, pCmdCtx, pData);
308
309 LogFlowFuncLeaveRC(rc);
310 return rc;
311}
312
313/**
314 * Completes a request from the host service for reading the X11 clipboard data.
315 * The data should be written to the buffer provided in the initial request.
316 *
317 * @param pCtx Request context information.
318 * @param rc The completion status of the request.
319 * @param pReq Request.
320 * @param pv Address.
321 * @param cb Size.
322 *
323 * @todo Change this to deal with the buffer issues rather than offloading them onto the caller.
324 */
325void ClipRequestFromX11CompleteCallback(SHCLCONTEXT *pCtx, int rc,
326 CLIPREADCBREQ *pReq, void *pv, uint32_t cb)
327{
328 AssertMsgRC(rc, ("Clipboard data completion from X11 failed with %Rrc\n", rc));
329
330 PSHCLEVENTPAYLOAD pPayload;
331 int rc2 = SharedClipboardPayloadAlloc(pReq->uEvent, pv, cb, &pPayload);
332 if (RT_SUCCESS(rc2))
333 rc2 = SharedClipboardEventSignal(&pCtx->pClient->Events, pReq->uEvent, pPayload);
334
335 AssertRC(rc);
336
337 RTMemFree(pReq);
338}
339
340/**
341 * Reads clipboard data from the guest and passes it to the X11 clipboard.
342 *
343 * @param pCtx Pointer to the host clipboard structure
344 * @param u32Format The format in which the data should be transferred
345 * @param ppv On success and if pcb > 0, this will point to a buffer
346 * to be freed with RTMemFree containing the data read.
347 * @param pcb On success, this contains the number of bytes of data
348 * returned
349 * @note Host glue code.
350 */
351int ClipRequestDataForX11(SHCLCONTEXT *pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb)
352{
353 LogFlowFunc(("pCtx=%p, u32Format=%02X, ppv=%p\n", pCtx, u32Format, ppv));
354
355 if (pCtx->fShuttingDown)
356 {
357 /* The shared clipboard is disconnecting. */
358 LogRel(("Shared Clipboard: Host requested guest clipboard data after guest had disconnected\n"));
359 return VERR_WRONG_ORDER;
360 }
361
362 /* Request data from the guest. */
363 SHCLDATAREQ dataReq;
364 RT_ZERO(dataReq);
365
366 dataReq.uFmt = u32Format;
367 dataReq.cbSize = _64K; /** @todo Make this more dynamic. */
368
369 SHCLEVENTID uEvent;
370 int rc = sharedClipboardSvcDataReadRequest(pCtx->pClient, &dataReq, &uEvent);
371 if (RT_SUCCESS(rc))
372 {
373 PSHCLEVENTPAYLOAD pPayload;
374 rc = SharedClipboardEventWait(&pCtx->pClient->Events, uEvent, 30 * 1000, &pPayload);
375 if (RT_SUCCESS(rc))
376 {
377 *ppv = pPayload->pvData;
378 *pcb = pPayload->cbData;
379
380 /* Detach the payload, as the caller then will own the data. */
381 SharedClipboardEventPayloadDetach(&pCtx->pClient->Events, uEvent);
382 }
383
384 SharedClipboardEventUnregister(&pCtx->pClient->Events, uEvent);
385 }
386
387 LogFlowFuncLeaveRC(rc);
388 return rc;
389}
390
391#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
392int SharedClipboardSvcImplURITransferCreate(PSHCLCLIENT pClient, PSHCLURITRANSFER pTransfer)
393{
394 RT_NOREF(pClient, pTransfer);
395 return VINF_SUCCESS;
396}
397
398int SharedClipboardSvcImplURITransferDestroy(PSHCLCLIENT pClient, PSHCLURITRANSFER pTransfer)
399{
400 RT_NOREF(pClient, pTransfer);
401 return VINF_SUCCESS;
402}
403#endif
Note: See TracBrowser for help on using the repository browser.

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