VirtualBox

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

Last change on this file since 64670 was 62883, checked in by vboxsync, 8 years ago

Additions/*: gcc warnings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 10.6 KB
Line 
1/** $Id: clipboard.cpp 62883 2016-08-02 15:51:18Z vboxsync $ */
2/** @file
3 * Guest Additions - X11 Shared Clipboard.
4 */
5
6/*
7 * Copyright (C) 2007-2016 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 _VBOXCLIPBOARDCONTEXT
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 VBOXCLIPBOARDCONTEXT 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 LogRelFlowFunc(("rc=%Rrc\n", rc));
73 return rc;
74}
75
76
77/**
78 * Get clipboard data from the host.
79 *
80 * @returns VBox result code
81 * @param u32Format The format of the data being requested
82 * @retval ppv On success and if pcb > 0, this will point to a buffer
83 * to be freed with RTMemFree containing the data read.
84 * @retval pcb On success, this contains the number of bytes of data
85 * returned
86 */
87int ClipRequestDataForX11(VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb)
88{
89 RT_NOREF1(pCtx);
90 int rc = VINF_SUCCESS;
91 uint32_t cb = 1024;
92 void *pv = RTMemAlloc(cb);
93
94 *ppv = 0;
95 LogRelFlowFunc(("u32Format=%u\n", u32Format));
96 if (RT_UNLIKELY(!pv))
97 rc = VERR_NO_MEMORY;
98 if (RT_SUCCESS(rc))
99 rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb);
100 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
101 *ppv = pv;
102 /* A return value of VINF_BUFFER_OVERFLOW tells us to try again with a
103 * larger buffer. The size of the buffer needed is placed in *pcb.
104 * So we start all over again. */
105 if (rc == VINF_BUFFER_OVERFLOW)
106 {
107 cb = *pcb;
108 RTMemFree(pv);
109 pv = RTMemAlloc(cb);
110 if (RT_UNLIKELY(!pv))
111 rc = VERR_NO_MEMORY;
112 if (RT_SUCCESS(rc))
113 rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb);
114 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
115 *ppv = pv;
116 }
117 /* Catch other errors. This also catches the case in which the buffer was
118 * too small a second time, possibly because the clipboard contents
119 * changed half-way through the operation. Since we can't say whether or
120 * not this is actually an error, we just return size 0.
121 */
122 if (RT_FAILURE(rc) || (VINF_BUFFER_OVERFLOW == rc))
123 {
124 *pcb = 0;
125 if (pv != NULL)
126 RTMemFree(pv);
127 }
128 LogRelFlowFunc(("returning %Rrc\n", rc));
129 if (RT_SUCCESS(rc))
130 LogRelFlow((" *pcb=%d\n", *pcb));
131 return rc;
132}
133
134/** Opaque data structure describing a request from the host for clipboard
135 * data, passed in when the request is forwarded to the X11 backend so that
136 * it can be completed correctly. */
137struct _CLIPREADCBREQ
138{
139 /** The data format that was requested. */
140 uint32_t u32Format;
141};
142
143/**
144 * Tell the host that new clipboard formats are available.
145 *
146 * @param u32Formats The formats to advertise
147 */
148void ClipReportX11Formats(VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Formats)
149{
150 RT_NOREF1(pCtx);
151 LogRelFlowFunc(("u32Formats=%d\n", u32Formats));
152 int rc = VbglR3ClipboardReportFormats(g_ctx.client, u32Formats);
153 LogRelFlowFunc(("rc=%Rrc\n", rc));
154}
155
156/** This is called by the backend to tell us that a request for data from
157 * X11 has completed.
158 * @param pCtx Our context information
159 * @param rc the iprt result code of the request
160 * @param pReq the request structure that we passed in when we started
161 * the request. We RTMemFree() this in this function.
162 * @param pv the clipboard data returned from X11 if the request
163 * succeeded (see @a rc)
164 * @param cb the size of the data in @a pv
165 */
166void ClipCompleteDataRequestFromX11(VBOXCLIPBOARDCONTEXT *pCtx, int rc, CLIPREADCBREQ *pReq, void *pv, uint32_t cb)
167{
168 RT_NOREF1(pCtx);
169 if (RT_SUCCESS(rc))
170 vboxClipboardSendData(pReq->u32Format, pv, cb);
171 else
172 vboxClipboardSendData(0, NULL, 0);
173 RTMemFree(pReq);
174}
175
176/**
177 * Connect the guest clipboard to the host.
178 *
179 * @returns VBox status code
180 */
181int vboxClipboardConnect(void)
182{
183 int rc = VINF_SUCCESS;
184 LogRelFlowFunc(("\n"));
185
186 /* Sanity */
187 AssertReturn(g_ctx.client == 0, VERR_WRONG_ORDER);
188 g_ctx.pBackend = ClipConstructX11(&g_ctx, false);
189 if (!g_ctx.pBackend)
190 rc = VERR_NO_MEMORY;
191 if (RT_SUCCESS(rc))
192 rc = ClipStartX11(g_ctx.pBackend);
193 if (RT_SUCCESS(rc))
194 {
195 rc = VbglR3ClipboardConnect(&g_ctx.client);
196 if (RT_FAILURE(rc))
197 LogRel(("Error connecting to host. rc=%Rrc\n", rc));
198 else if (!g_ctx.client)
199 {
200 LogRel(("Invalid client ID of 0\n"));
201 rc = VERR_NOT_SUPPORTED;
202 }
203 }
204
205 if (rc != VINF_SUCCESS && g_ctx.pBackend)
206 ClipDestructX11(g_ctx.pBackend);
207 LogRelFlowFunc(("g_ctx.client=%u rc=%Rrc\n", g_ctx.client, rc));
208 return rc;
209}
210
211/**
212 * The main loop of our clipboard reader.
213 */
214int vboxClipboardMain(void)
215{
216 int rc;
217 LogRelFlowFunc(("Starting guest clipboard service\n"));
218 bool fExiting = false;
219
220 while (!fExiting)
221 {
222 uint32_t Msg;
223 uint32_t fFormats;
224 rc = VbglR3ClipboardGetHostMsg(g_ctx.client, &Msg, &fFormats);
225 if (RT_SUCCESS(rc))
226 {
227 switch (Msg)
228 {
229 case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS:
230 {
231 /* The host has announced available clipboard formats.
232 * Save the information so that it is available for
233 * future requests from guest applications.
234 */
235 LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS fFormats=%x\n", fFormats));
236 ClipAnnounceFormatToX11(g_ctx.pBackend, fFormats);
237 break;
238 }
239
240 case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
241 {
242 /* The host needs data in the specified format. */
243 LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA fFormats=%x\n", fFormats));
244 CLIPREADCBREQ *pReq;
245 pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(*pReq));
246 if (!pReq)
247 {
248 rc = VERR_NO_MEMORY;
249 fExiting = true;
250 }
251 else
252 {
253 pReq->u32Format = fFormats;
254 ClipRequestDataFromX11(g_ctx.pBackend, fFormats,
255 pReq);
256 }
257 break;
258 }
259
260 case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
261 {
262 /* The host is terminating. */
263 LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT\n"));
264 if (RT_SUCCESS(ClipStopX11(g_ctx.pBackend)))
265 ClipDestructX11(g_ctx.pBackend);
266 fExiting = true;
267 break;
268 }
269
270 default:
271 LogRel2(("Unsupported message from host!!!\n"));
272 }
273 }
274
275 LogRelFlow(("processed host event rc = %d\n", rc));
276 }
277 LogRelFlowFunc(("rc=%d\n", rc));
278 return rc;
279}
280
281static const char *getPidFilePath()
282{
283 return ".vboxclient-clipboard.pid";
284}
285
286static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)
287{
288 RT_NOREF2(ppInterface, fDaemonised);
289
290 /* Initialise the guest library. */
291 int rc = VbglR3InitUser();
292 if (RT_FAILURE(rc))
293 VBClFatalError(("Failed to connect to the VirtualBox kernel service, rc=%Rrc\n", rc));
294 rc = vboxClipboardConnect();
295 /* Not RT_SUCCESS: VINF_PERMISSION_DENIED is host service not present. */
296 if (rc == VINF_SUCCESS)
297 rc = vboxClipboardMain();
298 if (rc == VERR_NOT_SUPPORTED)
299 rc = VINF_SUCCESS; /* Prevent automatic restart. */
300 if (RT_FAILURE(rc))
301 LogRelFunc(("guest clipboard service terminated abnormally: return code %Rrc\n", rc));
302 return rc;
303}
304
305static void cleanup(struct VBCLSERVICE **ppInterface)
306{
307 NOREF(ppInterface);
308 VbglR3Term();
309}
310
311struct VBCLSERVICE vbclClipboardInterface =
312{
313 getPidFilePath,
314 VBClServiceDefaultHandler, /* init */
315 run,
316 cleanup
317};
318
319struct CLIPBOARDSERVICE
320{
321 struct VBCLSERVICE *pInterface;
322};
323
324struct VBCLSERVICE **VBClGetClipboardService()
325{
326 struct CLIPBOARDSERVICE *pService =
327 (struct CLIPBOARDSERVICE *)RTMemAlloc(sizeof(*pService));
328
329 if (!pService)
330 VBClFatalError(("Out of memory\n"));
331 pService->pInterface = &vbclClipboardInterface;
332 return &pService->pInterface;
333}
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