VirtualBox

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

Last change on this file since 44528 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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