VirtualBox

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

Last change on this file since 33983 was 33595, checked in by vboxsync, 14 years ago

src/*: more spelling fixes (logging), thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 9.6 KB
Line 
1/** $Id: clipboard.cpp 33595 2010-10-29 10:35:00Z vboxsync $ */
2/** @file
3 * Guest Additions - X11 Shared Clipboard.
4 */
5
6/*
7 * Copyright (C) 2007 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#include "clipboard.h"
37
38/****************************************************************************
39* Global Variables *
40****************************************************************************/
41
42/**
43 * Global clipboard context information.
44 */
45struct _VBOXCLIPBOARDCONTEXT
46{
47 /** Client ID for the clipboard subsystem */
48 uint32_t client;
49
50 /** Pointer to the X11 clipboard backend */
51 CLIPBACKEND *pBackend;
52};
53
54/** Only one client is supported. There seems to be no need for more clients. */
55static VBOXCLIPBOARDCONTEXT g_ctx;
56
57
58/**
59 * Transfer clipboard data from the guest to the host.
60 *
61 * @returns VBox result code
62 * @param u32Format The format of the data being sent
63 * @param pv Pointer to the data being sent
64 * @param cb Size of the data being sent in bytes
65 */
66static int vboxClipboardSendData(uint32_t u32Format, void *pv, uint32_t cb)
67{
68 int rc;
69 LogRelFlowFunc(("u32Format=%d, pv=%p, cb=%d\n", u32Format, pv, cb));
70 rc = VbglR3ClipboardWriteData(g_ctx.client, u32Format, pv, cb);
71 LogRelFlowFunc(("rc=%Rrc\n", rc));
72 return rc;
73}
74
75
76/**
77 * Get clipboard data from the host.
78 *
79 * @returns VBox result code
80 * @param u32Format The format of the data being requested
81 * @retval ppv On success and if pcb > 0, this will point to a buffer
82 * to be freed with RTMemFree containing the data read.
83 * @retval pcb On success, this contains the number of bytes of data
84 * returned
85 */
86int ClipRequestDataForX11(VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format,
87 void **ppv, uint32_t *pcb)
88{
89 int rc = VINF_SUCCESS;
90 uint32_t cb = 1024;
91 void *pv = RTMemAlloc(cb);
92
93 *ppv = 0;
94 LogRelFlowFunc(("u32Format=%u\n", u32Format));
95 if (RT_UNLIKELY(!pv))
96 rc = VERR_NO_MEMORY;
97 if (RT_SUCCESS(rc))
98 rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb);
99 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
100 *ppv = pv;
101 /* A return value of VINF_BUFFER_OVERFLOW tells us to try again with a
102 * larger buffer. The size of the buffer needed is placed in *pcb.
103 * So we start all over again. */
104 if (rc == VINF_BUFFER_OVERFLOW)
105 {
106 cb = *pcb;
107 RTMemFree(pv);
108 pv = RTMemAlloc(cb);
109 if (RT_UNLIKELY(!pv))
110 rc = VERR_NO_MEMORY;
111 if (RT_SUCCESS(rc))
112 rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb);
113 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
114 *ppv = pv;
115 }
116 /* Catch other errors. This also catches the case in which the buffer was
117 * too small a second time, possibly because the clipboard contents
118 * changed half-way through the operation. Since we can't say whether or
119 * not this is actually an error, we just return size 0.
120 */
121 if (RT_FAILURE(rc) || (VINF_BUFFER_OVERFLOW == rc))
122 {
123 *pcb = 0;
124 if (pv != NULL)
125 RTMemFree(pv);
126 }
127 LogRelFlowFunc(("returning %Rrc\n", rc));
128 if (RT_SUCCESS(rc))
129 LogRelFlow((" *pcb=%d\n", *pcb));
130 return rc;
131}
132
133/** Opaque data structure describing a request from the host for clipboard
134 * data, passed in when the request is forwarded to the X11 backend so that
135 * it can be completed correctly. */
136struct _CLIPREADCBREQ
137{
138 /** The data format that was requested. */
139 uint32_t u32Format;
140};
141
142/**
143 * Tell the host that new clipboard formats are available.
144 *
145 * @param u32Formats The formats to advertise
146 */
147void ClipReportX11Formats(VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Formats)
148{
149 int rc;
150 LogRelFlowFunc(("u32Formats=%d\n", u32Formats));
151 rc = VbglR3ClipboardReportFormats(g_ctx.client, u32Formats);
152 LogRelFlowFunc(("rc=%Rrc\n", rc));
153}
154
155/** This is called by the backend to tell us that a request for data from
156 * X11 has completed.
157 * @param pCtx Our context information
158 * @param rc the iprt result code of the request
159 * @param pReq the request structure that we passed in when we started
160 * the request. We RTMemFree() this in this function.
161 * @param pv the clipboard data returned from X11 if the request
162 * succeeded (see @a rc)
163 * @param cb the size of the data in @a pv
164 */
165void ClipCompleteDataRequestFromX11(VBOXCLIPBOARDCONTEXT *pCtx, int rc,
166 CLIPREADCBREQ *pReq, void *pv,
167 uint32_t cb)
168{
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);
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 (RT_FAILURE(rc) && 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
281class ClipboardService : public VBoxClient::Service
282{
283public:
284 virtual const char *getPidFilePath()
285 {
286 return ".vboxclient-clipboard.pid";
287 }
288 virtual int run(bool fDaemonised /* = false */)
289 {
290 int rc = vboxClipboardConnect();
291 if (RT_SUCCESS(rc))
292 rc = vboxClipboardMain();
293 if (RT_FAILURE(rc))
294 LogRelFunc(("guest clipboard service terminated abnormally: return code %Rrc\n", rc));
295 return rc;
296 }
297 virtual void cleanup()
298 {
299 /* Nothing to do. */
300 }
301};
302
303VBoxClient::Service *VBoxClient::GetClipboardService()
304{
305 return new ClipboardService;
306}
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