VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/darwin-pasteboard.cpp@ 46474

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

move contribution note

  • Property eol-style set to native
  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 13.8 KB
Line 
1/* $Id: darwin-pasteboard.cpp 43123 2012-08-30 19:12:33Z vboxsync $ */
2/** @file
3 * Shared Clipboard: Mac OS X host implementation.
4 */
5
6/*
7 * Includes contributions from François Revol
8 *
9 * Copyright (C) 2008-2012 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#define LOG_GROUP LOG_GROUP_HGCM
21#include <Carbon/Carbon.h>
22
23#include <iprt/mem.h>
24#include <iprt/assert.h>
25#include "iprt/err.h"
26
27#include "VBox/log.h"
28#include "VBox/HostServices/VBoxClipboardSvc.h"
29#include "VBox/GuestHost/clipboard-helper.h"
30
31/* For debugging */
32//#define SHOW_CLIPBOARD_CONTENT
33
34/**
35 * Initialize the global pasteboard and return a reference to it.
36 *
37 * @param pPasteboardRef Reference to the global pasteboard.
38 *
39 * @returns IPRT status code.
40 */
41int initPasteboard(PasteboardRef *pPasteboardRef)
42{
43 int rc = VINF_SUCCESS;
44
45 if (PasteboardCreate(kPasteboardClipboard, pPasteboardRef))
46 rc = VERR_NOT_SUPPORTED;
47
48 return rc;
49}
50
51/**
52 * Release the reference to the global pasteboard.
53 *
54 * @param pPasteboardRef Reference to the global pasteboard.
55 */
56void destroyPasteboard(PasteboardRef *pPasteboardRef)
57{
58 CFRelease(*pPasteboardRef);
59 *pPasteboardRef = NULL;
60}
61
62/**
63 * Inspect the global pasteboard for new content. Check if there is some type
64 * that is supported by vbox and return it.
65 *
66 * @param pPasteboardRef Reference to the global pasteboard.
67 * @param pfFormats Pointer for the bit combination of the
68 * supported types.
69 * @param pbChanged True if something has changed after the
70 * last call.
71 *
72 * @returns IPRT status code. (Always VINF_SUCCESS atm.)
73 */
74int queryNewPasteboardFormats(PasteboardRef pPasteboard, uint32_t *pfFormats, bool *pfChanged)
75{
76 Log(("queryNewPasteboardFormats\n"));
77
78 OSStatus err = noErr;
79 *pfChanged = true;
80
81 PasteboardSyncFlags syncFlags;
82 /* Make sure all is in sync */
83 syncFlags = PasteboardSynchronize(pPasteboard);
84 /* If nothing changed return */
85 if (!(syncFlags & kPasteboardModified))
86 {
87 *pfChanged = false;
88 return VINF_SUCCESS;
89 }
90
91 /* Are some items in the pasteboard? */
92 ItemCount itemCount;
93 err = PasteboardGetItemCount(pPasteboard, &itemCount);
94 if (itemCount < 1)
95 return VINF_SUCCESS;
96
97 /* The id of the first element in the pasteboard */
98 int rc = VINF_SUCCESS;
99 PasteboardItemID itemID;
100 if (!(err = PasteboardGetItemIdentifier(pPasteboard, 1, &itemID)))
101 {
102 /* Retrieve all flavors in the pasteboard, maybe there
103 * is something we can use. */
104 CFArrayRef flavorTypeArray;
105 if (!(err = PasteboardCopyItemFlavors(pPasteboard, itemID, &flavorTypeArray)))
106 {
107 CFIndex flavorCount;
108 flavorCount = CFArrayGetCount(flavorTypeArray);
109 for (CFIndex flavorIndex = 0; flavorIndex < flavorCount; flavorIndex++)
110 {
111 CFStringRef flavorType;
112 flavorType = static_cast <CFStringRef>(CFArrayGetValueAtIndex(flavorTypeArray,
113 flavorIndex));
114 /* Currently only unicode supported */
115 if (UTTypeConformsTo(flavorType, kUTTypeUTF8PlainText) ||
116 UTTypeConformsTo(flavorType, kUTTypeUTF16PlainText))
117 {
118 Log(("Unicode flavor detected.\n"));
119 *pfFormats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
120 }
121 else if (UTTypeConformsTo(flavorType, kUTTypeBMP))
122 {
123 Log(("BMP flavor detected.\n"));
124 *pfFormats |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
125 }
126 }
127 CFRelease(flavorTypeArray);
128 }
129 }
130
131 Log(("queryNewPasteboardFormats: rc = %02X\n", rc));
132 return rc;
133}
134
135/**
136 * Read content from the host clipboard and write it to the internal clipboard
137 * structure for further processing.
138 *
139 * @param pPasteboardRef Reference to the global pasteboard.
140 * @param fFormats The format type which should be read.
141 * @param pv The destination buffer.
142 * @param cb The size of the destination buffer.
143 * @param pcbActual The size which is needed to transfer the content.
144 *
145 * @returns IPRT status code.
146 */
147int readFromPasteboard(PasteboardRef pPasteboard, uint32_t fFormat, void *pv, uint32_t cb, uint32_t *pcbActual)
148{
149 Log(("readFromPasteboard: fFormat = %02X\n", fFormat));
150
151 OSStatus err = noErr;
152
153 /* Make sure all is in sync */
154 PasteboardSynchronize(pPasteboard);
155
156 /* Are some items in the pasteboard? */
157 ItemCount itemCount;
158 err = PasteboardGetItemCount(pPasteboard, &itemCount);
159 if (itemCount < 1)
160 return VINF_SUCCESS;
161
162 /* The id of the first element in the pasteboard */
163 int rc = VERR_NOT_SUPPORTED;
164 PasteboardItemID itemID;
165 if (!(err = PasteboardGetItemIdentifier(pPasteboard, 1, &itemID)))
166 {
167 /* The guest request unicode */
168 if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
169 {
170 CFDataRef outData;
171 PRTUTF16 pwszTmp = NULL;
172 /* Try utf-16 first */
173 if (!(err = PasteboardCopyItemFlavorData(pPasteboard, itemID, kUTTypeUTF16PlainText, &outData)))
174 {
175 Log(("Clipboard content is utf-16\n"));
176 rc = RTUtf16DupEx(&pwszTmp, (PRTUTF16)CFDataGetBytePtr(outData), 0);
177 }
178 /* Second try is utf-8 */
179 else
180 if (!(err = PasteboardCopyItemFlavorData(pPasteboard, itemID, kUTTypeUTF8PlainText, &outData)))
181 {
182 Log(("readFromPasteboard: clipboard content is utf-8\n"));
183 rc = RTStrToUtf16((const char*)CFDataGetBytePtr(outData), &pwszTmp);
184 }
185 if (pwszTmp)
186 {
187 /* Check how much longer will the converted text will be. */
188 size_t cwSrc = RTUtf16Len(pwszTmp);
189 size_t cwDest;
190 rc = vboxClipboardUtf16GetWinSize(pwszTmp, cwSrc, &cwDest);
191 if (RT_FAILURE(rc))
192 {
193 RTUtf16Free(pwszTmp);
194 Log(("readFromPasteboard: clipboard conversion failed. vboxClipboardUtf16GetWinSize returned %Rrc. Abandoning.\n", rc));
195 AssertRCReturn(rc, rc);
196 }
197 /* Set the actually needed data size */
198 *pcbActual = cwDest * 2;
199 /* Return success state */
200 rc = VINF_SUCCESS;
201 /* Do not copy data if the dst buffer is not big enough. */
202 if (*pcbActual <= cb)
203 {
204 rc = vboxClipboardUtf16LinToWin(pwszTmp, RTUtf16Len(pwszTmp), static_cast <PRTUTF16>(pv), cb / 2);
205 if (RT_FAILURE(rc))
206 {
207 RTUtf16Free(pwszTmp);
208 Log(("readFromPasteboard: clipboard conversion failed. vboxClipboardUtf16LinToWin() returned %Rrc. Abandoning.\n", rc));
209 AssertRCReturn(rc, rc);
210 }
211#ifdef SHOW_CLIPBOARD_CONTENT
212 Log(("readFromPasteboard: clipboard content: %ls\n", static_cast <PRTUTF16>(pv)));
213#endif
214 }
215 /* Free the temp string */
216 RTUtf16Free(pwszTmp);
217 }
218 }
219 /* The guest request BITMAP */
220 else if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
221 {
222 CFDataRef outData;
223 const void *pTmp = NULL;
224 size_t cbTmpSize;
225 /* Get the data from the pasteboard */
226 if (!(err = PasteboardCopyItemFlavorData(pPasteboard, itemID, kUTTypeBMP, &outData)))
227 {
228 Log(("Clipboard content is BMP\n"));
229 pTmp = CFDataGetBytePtr(outData);
230 cbTmpSize = CFDataGetLength(outData);
231 }
232 if (pTmp)
233 {
234 const void *pDib;
235 size_t cbDibSize;
236 rc = vboxClipboardBmpGetDib(pTmp, cbTmpSize, &pDib, &cbDibSize);
237 if (RT_FAILURE(rc))
238 {
239 rc = VERR_NOT_SUPPORTED;
240 Log(("readFromPasteboard: unknown bitmap format. vboxClipboardBmpGetDib returned %Rrc. Abandoning.\n", rc));
241 AssertRCReturn(rc, rc);
242 }
243
244 *pcbActual = cbDibSize;
245 /* Return success state */
246 rc = VINF_SUCCESS;
247 /* Do not copy data if the dst buffer is not big enough. */
248 if (*pcbActual <= cb)
249 {
250 memcpy(pv, pDib, cbDibSize);
251#ifdef SHOW_CLIPBOARD_CONTENT
252 Log(("readFromPasteboard: clipboard content bitmap %d bytes\n", cbDibSize));
253#endif
254 }
255 }
256 }
257 }
258
259 Log(("readFromPasteboard: rc = %02X\n", rc));
260 return rc;
261}
262
263/**
264 * Write clipboard content to the host clipboard from the internal clipboard
265 * structure.
266 *
267 * @param pPasteboardRef Reference to the global pasteboard.
268 * @param pv The source buffer.
269 * @param cb The size of the source buffer.
270 * @param fFormats The format type which should be written.
271 *
272 * @returns IPRT status code.
273 */
274int writeToPasteboard(PasteboardRef pPasteboard, void *pv, uint32_t cb, uint32_t fFormat)
275{
276 Log(("writeToPasteboard: fFormat = %02X\n", fFormat));
277
278 /* Clear the pasteboard */
279 if (PasteboardClear(pPasteboard))
280 return VERR_NOT_SUPPORTED;
281
282 /* Make sure all is in sync */
283 PasteboardSynchronize(pPasteboard);
284
285 int rc = VERR_NOT_SUPPORTED;
286 /* Handle the unicode text */
287 if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
288 {
289 PRTUTF16 pwszSrcText = static_cast <PRTUTF16>(pv);
290 size_t cwSrc = cb / 2;
291 size_t cwDest = 0;
292 /* How long will the converted text be? */
293 rc = vboxClipboardUtf16GetLinSize(pwszSrcText, cwSrc, &cwDest);
294 if (RT_FAILURE(rc))
295 {
296 Log(("writeToPasteboard: clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));
297 AssertRCReturn(rc, rc);
298 }
299 /* Empty clipboard? Not critical */
300 if (cwDest == 0)
301 {
302 Log(("writeToPasteboard: received empty clipboard data from the guest, returning false.\n"));
303 return VINF_SUCCESS;
304 }
305 /* Allocate the necessary memory */
306 PRTUTF16 pwszDestText = static_cast <PRTUTF16>(RTMemAlloc(cwDest * 2));
307 if (pwszDestText == NULL)
308 {
309 Log(("writeToPasteboard: failed to allocate %d bytes\n", cwDest * 2));
310 return VERR_NO_MEMORY;
311 }
312 /* Convert the EOL */
313 rc = vboxClipboardUtf16WinToLin(pwszSrcText, cwSrc, pwszDestText, cwDest);
314 if (RT_FAILURE(rc))
315 {
316 Log(("writeToPasteboard: clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc));
317 RTMemFree(pwszDestText);
318 AssertRCReturn(rc, rc);
319 }
320
321 CFDataRef textData = NULL;
322 /* Item id is 1. Nothing special here. */
323 PasteboardItemID itemId = (PasteboardItemID)1;
324 /* Create a CData object which we could pass to the pasteboard */
325 if ((textData = CFDataCreate(kCFAllocatorDefault,
326 reinterpret_cast<UInt8*>(pwszDestText), cwDest * 2)))
327 {
328 /* Put the Utf-16 version to the pasteboard */
329 PasteboardPutItemFlavor(pPasteboard, itemId,
330 kUTTypeUTF16PlainText,
331 textData, 0);
332 }
333 /* Create a Utf-8 version */
334 char *pszDestText;
335 rc = RTUtf16ToUtf8(pwszDestText, &pszDestText);
336 if (RT_SUCCESS(rc))
337 {
338 /* Create a CData object which we could pass to the pasteboard */
339 if ((textData = CFDataCreate(kCFAllocatorDefault,
340 reinterpret_cast<UInt8*>(pszDestText), strlen(pszDestText))))
341 {
342 /* Put the Utf-8 version to the pasteboard */
343 PasteboardPutItemFlavor(pPasteboard, itemId,
344 kUTTypeUTF8PlainText,
345 textData, 0);
346 }
347 RTStrFree(pszDestText);
348 }
349
350 RTMemFree(pwszDestText);
351 rc = VINF_SUCCESS;
352 }
353 /* Handle the bitmap */
354 else if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
355 {
356 /* Create a full BMP from it */
357 void *pBmp;
358 size_t cbBmpSize;
359 CFDataRef bmpData = NULL;
360 /* Item id is 1. Nothing special here. */
361 PasteboardItemID itemId = (PasteboardItemID)1;
362
363 rc = vboxClipboardDibToBmp(pv, cb, &pBmp, &cbBmpSize);
364 if (RT_SUCCESS(rc))
365 {
366 /* Create a CData object which we could pass to the pasteboard */
367 if ((bmpData = CFDataCreate(kCFAllocatorDefault,
368 reinterpret_cast<UInt8*>(pBmp), cbBmpSize)))
369 {
370 /* Put the Utf-8 version to the pasteboard */
371 PasteboardPutItemFlavor(pPasteboard, itemId,
372 kUTTypeBMP,
373 bmpData, 0);
374 }
375 RTMemFree(pBmp);
376 }
377 rc = VINF_SUCCESS;
378 }
379 else
380 rc = VERR_NOT_IMPLEMENTED;
381
382 Log(("writeToPasteboard: rc = %02X\n", rc));
383 return rc;
384}
385
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