VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/VBoxClient/clipboard.cpp@ 81060

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

Shared Clipboard/VBoxClient: Cleaned up connecting to host service.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 10.7 KB
Line 
1/** $Id: clipboard.cpp 81060 2019-09-27 14:32:13Z vboxsync $ */
2/** @file
3 * Guest Additions - X11 Shared Clipboard.
4 */
5
6/*
7 * Copyright (C) 2007-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#include <iprt/alloc.h>
23#include <iprt/asm.h>
24#include <iprt/assert.h>
25#include <iprt/initterm.h>
26#include <iprt/mem.h>
27#include <iprt/string.h>
28#include <iprt/process.h>
29#include <iprt/semaphore.h>
30
31#include <VBox/log.h>
32#include <VBox/VBoxGuestLib.h>
33#include <VBox/HostServices/VBoxClipboardSvc.h>
34#include <VBox/GuestHost/SharedClipboard.h>
35
36#include "VBoxClient.h"
37
38
39/*********************************************************************************************************************************
40* Global Variables *
41*********************************************************************************************************************************/
42
43/**
44 * Global clipboard context information.
45 */
46struct _SHCLCONTEXT
47{
48 /** Client ID for the clipboard subsystem */
49 uint32_t client;
50
51 /** Pointer to the X11 clipboard backend */
52 CLIPBACKEND *pBackend;
53};
54
55/** Only one client is supported. There seems to be no need for more clients. */
56static SHCLCONTEXT g_ctx;
57
58
59/**
60 * Transfer clipboard data from the guest to the host.
61 *
62 * @returns VBox result code
63 * @param u32Format The format of the data being sent
64 * @param pv Pointer to the data being sent
65 * @param cb Size of the data being sent in bytes
66 */
67static int vboxClipboardSendData(uint32_t u32Format, void *pv, uint32_t cb)
68{
69 int rc;
70 LogRelFlowFunc(("u32Format=%d, pv=%p, cb=%d\n", u32Format, pv, cb));
71 rc = VbglR3ClipboardWriteData(g_ctx.client, u32Format, pv, cb);
72 LogRelFlowFuncLeaveRC(rc);
73 return rc;
74}
75
76
77/**
78 * Get clipboard data from the host.
79 *
80 * @returns VBox result code
81 * @param pCtx Our context information
82 * @param u32Format The format of the data being requested
83 * @retval ppv On success and if pcb > 0, this will point to a buffer
84 * to be freed with RTMemFree containing the data read.
85 * @retval pcb On success, this contains the number of bytes of data
86 * returned
87 */
88DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb)
89{
90 RT_NOREF(pCtx);
91 int rc = VINF_SUCCESS;
92 uint32_t cb = 1024;
93 void *pv = RTMemAlloc(cb);
94
95 *ppv = 0;
96 LogRelFlowFunc(("u32Format=%u\n", u32Format));
97 if (RT_UNLIKELY(!pv))
98 rc = VERR_NO_MEMORY;
99 if (RT_SUCCESS(rc))
100 rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb);
101 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
102 *ppv = pv;
103 /* A return value of VINF_BUFFER_OVERFLOW tells us to try again with a
104 * larger buffer. The size of the buffer needed is placed in *pcb.
105 * So we start all over again. */
106 if (rc == VINF_BUFFER_OVERFLOW)
107 {
108 cb = *pcb;
109 RTMemFree(pv);
110 pv = RTMemAlloc(cb);
111 if (RT_UNLIKELY(!pv))
112 rc = VERR_NO_MEMORY;
113 if (RT_SUCCESS(rc))
114 rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb);
115 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
116 *ppv = pv;
117 }
118 /* Catch other errors. This also catches the case in which the buffer was
119 * too small a second time, possibly because the clipboard contents
120 * changed half-way through the operation. Since we can't say whether or
121 * not this is actually an error, we just return size 0.
122 */
123 if (RT_FAILURE(rc) || (VINF_BUFFER_OVERFLOW == rc))
124 {
125 *pcb = 0;
126 if (pv != NULL)
127 RTMemFree(pv);
128 }
129 LogRelFlowFuncLeaveRC(rc);
130 if (RT_SUCCESS(rc))
131 LogRelFlow((" *pcb=%d\n", *pcb));
132 return rc;
133}
134
135/** Opaque data structure describing a request from the host for clipboard
136 * data, passed in when the request is forwarded to the X11 backend so that
137 * it can be completed correctly. */
138struct _CLIPREADCBREQ
139{
140 /** The data format that was requested. */
141 uint32_t u32Format;
142};
143
144/**
145 * Tell the host that new clipboard formats are available.
146 *
147 * @param pCtx Our context information.
148 * @param u32Formats The formats to report.
149 */
150DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, uint32_t u32Formats)
151{
152 RT_NOREF(pCtx);
153 LogRelFlowFunc(("u32Formats=%d\n", u32Formats));
154 int rc = VbglR3ClipboardFormatsReport(g_ctx.client, u32Formats);
155 LogRelFlowFuncLeaveRC(rc);
156}
157
158/** This is called by the backend to tell us that a request for data from
159 * X11 has completed.
160 * @param pCtx Our context information
161 * @param rc the iprt result code of the request
162 * @param pReq the request structure that we passed in when we started
163 * the request. We RTMemFree() this in this function.
164 * @param pv the clipboard data returned from X11 if the request
165 * succeeded (see @a rc)
166 * @param cb the size of the data in @a pv
167 */
168DECLCALLBACK(void) ClipRequestFromX11CompleteCallback(SHCLCONTEXT *pCtx, int rc, CLIPREADCBREQ *pReq, void *pv, uint32_t cb)
169{
170 RT_NOREF(pCtx);
171 if (RT_SUCCESS(rc))
172 vboxClipboardSendData(pReq->u32Format, pv, cb);
173 else
174 vboxClipboardSendData(0, NULL, 0);
175 RTMemFree(pReq);
176}
177
178/**
179 * Connect the guest clipboard to the host.
180 *
181 * @returns VBox status code
182 */
183static int vboxClipboardConnect(void)
184{
185 LogFlowFuncEnter();
186
187 /* Sanity */
188 AssertReturn(g_ctx.client == 0, VERR_WRONG_ORDER);
189 AssertReturn(g_ctx.pBackend == NULL, VERR_WRONG_ORDER);
190
191 int rc;
192
193 g_ctx.pBackend = ClipConstructX11(&g_ctx, false);
194 if (g_ctx.pBackend)
195 {
196 rc = ClipStartX11(g_ctx.pBackend, false /* grab */);
197 if (RT_SUCCESS(rc))
198 {
199 rc = VbglR3ClipboardConnect(&g_ctx.client);
200 if (RT_SUCCESS(rc))
201 {
202 Assert(g_ctx.client);
203 }
204 else
205 VBClLogError("Error connecting to host, rc=%Rrc\n", rc);
206 }
207 }
208 else
209 rc = VERR_NO_MEMORY;
210
211 if (rc != VINF_SUCCESS && g_ctx.pBackend)
212 ClipDestructX11(g_ctx.pBackend);
213
214 LogRelFlowFuncLeaveRC(rc);
215 return rc;
216}
217
218/**
219 * The main loop of our clipboard reader.
220 */
221int vboxClipboardMain(void)
222{
223 int rc;
224 LogRelFlowFunc(("Starting guest clipboard service\n"));
225 bool fExiting = false;
226
227 while (!fExiting)
228 {
229 uint32_t Msg;
230 uint32_t fFormats;
231 rc = VbglR3ClipboardGetHostMsgOld(g_ctx.client, &Msg, &fFormats);
232 if (RT_SUCCESS(rc))
233 {
234 switch (Msg)
235 {
236 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
237 {
238 /* The host has announced available clipboard formats.
239 * Save the information so that it is available for
240 * future requests from guest applications.
241 */
242 LogRelFlowFunc(("VBOX_SHCL_HOST_MSG_FORMATS_WRITE fFormats=%x\n", fFormats));
243 ClipAnnounceFormatToX11(g_ctx.pBackend, fFormats);
244 break;
245 }
246
247 case VBOX_SHCL_HOST_MSG_READ_DATA:
248 {
249 /* The host needs data in the specified format. */
250 LogRelFlowFunc(("VBOX_SHCL_HOST_MSG_READ_DATA fFormats=%x\n", fFormats));
251 CLIPREADCBREQ *pReq;
252 pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(*pReq));
253 if (!pReq)
254 {
255 rc = VERR_NO_MEMORY;
256 fExiting = true;
257 }
258 else
259 {
260 pReq->u32Format = fFormats;
261 ClipRequestDataFromX11(g_ctx.pBackend, fFormats,
262 pReq);
263 }
264 break;
265 }
266
267 case VBOX_SHCL_HOST_MSG_QUIT:
268 {
269 /* The host is terminating. */
270 LogRelFlowFunc(("VBOX_SHCL_HOST_MSG_QUIT\n"));
271 if (RT_SUCCESS(ClipStopX11(g_ctx.pBackend)))
272 ClipDestructX11(g_ctx.pBackend);
273 fExiting = true;
274 break;
275 }
276
277 default:
278 {
279 VBClLogInfo("Unsupported message from host (%RU32)\n", Msg);
280 break;
281 }
282 }
283 }
284
285 LogRelFlow(("processed host event rc = %d\n", rc));
286 }
287 LogRelFlowFuncLeaveRC(rc);
288 return rc;
289}
290
291static const char *getName()
292{
293 return "Shared Clipboard";
294}
295
296static const char *getPidFilePath()
297{
298 return ".vboxclient-clipboard.pid";
299}
300
301static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)
302{
303 RT_NOREF(ppInterface, fDaemonised);
304
305 /* Initialise the guest library. */
306 int rc = vboxClipboardConnect();
307 if (RT_SUCCESS(rc))
308 {
309 rc = vboxClipboardMain();
310 }
311
312 if (RT_FAILURE(rc))
313 VBClLogError("Service terminated abnormally with %Rrc\n", rc);
314
315 if (rc == VERR_HGCM_SERVICE_NOT_FOUND)
316 rc = VINF_SUCCESS; /* Prevent automatic restart by daemon script if host service not available. */
317
318 return rc;
319}
320
321static void cleanup(struct VBCLSERVICE **ppInterface)
322{
323 RT_NOREF(ppInterface);
324 VbglR3Term();
325}
326
327struct VBCLSERVICE vbclClipboardInterface =
328{
329 getName,
330 getPidFilePath,
331 VBClServiceDefaultHandler, /* init */
332 run,
333 cleanup
334};
335
336struct CLIPBOARDSERVICE
337{
338 struct VBCLSERVICE *pInterface;
339};
340
341struct VBCLSERVICE **VBClGetClipboardService()
342{
343 struct CLIPBOARDSERVICE *pService =
344 (struct CLIPBOARDSERVICE *)RTMemAlloc(sizeof(*pService));
345
346 if (!pService)
347 VBClLogFatalError("Out of memory\n");
348 pService->pInterface = &vbclClipboardInterface;
349 return &pService->pInterface;
350}
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