VirtualBox

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

Last change on this file since 27709 was 24069, checked in by vboxsync, 15 years ago

VBoxClient: Added delay for host update check, misc logging.

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