VirtualBox

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

Last change on this file since 7359 was 7249, checked in by vboxsync, 17 years ago

Use the critsect to serialize access to the pastboard so that the polling thread doesn't enter it at the same time as the service thread. Fixed the return code handling around queryNewPasteboardFormats (VERR_NOT_SUPPORTED should not propagate to Connect and Sync, even if returns codes are generally ignored by the service layer). Use pClient instead of the global (/me hates globals).

  • Property eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 11.3 KB
Line 
1/* $Id: darwin-pasteboard.cpp 7249 2008-03-03 17:50:55Z vboxsync $ */
2/** @file
3 * Shared Clipboard: Mac OS X host implementation.
4 */
5
6/*
7 * Copyright (C) 2008 innotek GmbH
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#include <Carbon/Carbon.h>
19
20#include <iprt/mem.h>
21#include <iprt/assert.h>
22#include "iprt/err.h"
23
24#define LOG_GROUP LOG_GROUP_HGCM
25#include "VBox/log.h"
26#include "VBox/HostServices/VBoxClipboardSvc.h"
27#include "clipboard-helper.h"
28
29/* For debugging */
30//#define SHOW_CLIPBOARD_CONTENT
31
32/**
33 * Initialize the global pasteboard and return a reference to it.
34 *
35 * @param pPasteboardRef Reference to the global pasteboard.
36 *
37 * @returns IPRT status code.
38 */
39int initPasteboard (PasteboardRef *pPasteboardRef)
40{
41 int rc = VINF_SUCCESS;
42
43 if (PasteboardCreate (kPasteboardClipboard, pPasteboardRef))
44 rc = VERR_NOT_SUPPORTED;
45
46 return rc;
47}
48
49/**
50 * Release the reference to the global pasteboard.
51 *
52 * @param pPasteboardRef Reference to the global pasteboard.
53 */
54void destroyPasteboard (PasteboardRef *pPasteboardRef)
55{
56 CFRelease (*pPasteboardRef);
57 *pPasteboardRef = NULL;
58}
59
60/**
61 * Inspect the global pasteboard for new content. Check if there is some type
62 * that is supported by vbox and return it.
63 *
64 * @param pPasteboardRef Reference to the global pasteboard.
65 * @param pfFormats Pointer for the bit combination of the
66 * supported types.
67 * @param pbChanged True if something has changed after the
68 * last call.
69 *
70 * @returns IPRT status code. (Always VINF_SUCCESS atm.)
71 */
72int queryNewPasteboardFormats (PasteboardRef pPasteboard, uint32_t *pfFormats, bool *pfChanged)
73{
74 Log (("queryNewPasteboardFormats\n"));
75
76 OSStatus err = noErr;
77 *pfChanged = true;
78
79 PasteboardSyncFlags syncFlags;
80 /* Make sure all is in sync */
81 syncFlags = PasteboardSynchronize (pPasteboard);
82 /* If nothing changed return */
83 if (!(syncFlags & kPasteboardModified))
84 {
85 *pfChanged = false;
86 return VINF_SUCCESS;
87 }
88
89 /* Are some items in the pasteboard? */
90 ItemCount itemCount;
91 err = PasteboardGetItemCount (pPasteboard, &itemCount);
92 if (itemCount < 1)
93 return VINF_SUCCESS;
94
95 /* The id of the first element in the pasteboard */
96 int rc = VINF_SUCCESS;
97 PasteboardItemID itemID;
98 if (!(err = PasteboardGetItemIdentifier (pPasteboard, 1, &itemID)))
99 {
100 /* Retrieve all flavors in the pasteboard, maybe there
101 * is something we can use. */
102 CFArrayRef flavorTypeArray;
103 if (!(err = PasteboardCopyItemFlavors (pPasteboard, itemID, &flavorTypeArray)))
104 {
105 CFIndex flavorCount;
106 flavorCount = CFArrayGetCount (flavorTypeArray);
107 for (CFIndex flavorIndex = 0; flavorIndex < flavorCount; flavorIndex++)
108 {
109 CFStringRef flavorType;
110 flavorType = static_cast <CFStringRef> (CFArrayGetValueAtIndex (flavorTypeArray,
111 flavorIndex));
112 /* Currently only unicode supported */
113 if (UTTypeConformsTo (flavorType, CFSTR ("public.utf8-plain-text")) ||
114 UTTypeConformsTo (flavorType, CFSTR ("public.utf16-plain-text")))
115 {
116 Log (("Unicode flavor detected.\n"));
117 *pfFormats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
118 }
119 }
120 CFRelease (flavorTypeArray);
121 }
122 }
123
124 Log (("queryNewPasteboardFormats: rc = %02X\n", rc));
125 return rc;
126}
127
128/**
129 * Read content from the host clipboard and write it to the internal clipboard
130 * structure for further processing.
131 *
132 * @param pPasteboardRef Reference to the global pasteboard.
133 * @param fFormats The format type which should be read.
134 * @param pv The destination buffer.
135 * @param cb The size of the destination buffer.
136 * @param pcbActual The size which is needed to transfer the content.
137 *
138 * @returns IPRT status code.
139 */
140int readFromPasteboard (PasteboardRef pPasteboard, uint32_t fFormat, void *pv, uint32_t cb, uint32_t *pcbActual)
141{
142 Log (("readFromPasteboard: fFormat = %02X\n", fFormat));
143
144 OSStatus err = noErr;
145
146 /* Make sure all is in sync */
147 PasteboardSynchronize (pPasteboard);
148
149 /* Are some items in the pasteboard? */
150 ItemCount itemCount;
151 err = PasteboardGetItemCount (pPasteboard, &itemCount);
152 if (itemCount < 1)
153 return VINF_SUCCESS;
154
155 /* The id of the first element in the pasteboard */
156 int rc = VERR_NOT_SUPPORTED;
157 PasteboardItemID itemID;
158 if (!(err = PasteboardGetItemIdentifier (pPasteboard, 1, &itemID)))
159 {
160 /* The guest request unicode */
161 if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
162 {
163 CFDataRef outData;
164 PRTUTF16 pwszTmp = NULL;
165 /* Utf-16 is currently broken on more than one line.
166 * Has to be investigated. */
167#if 0
168 /* Try utf-16 first */
169 if (!(err = PasteboardCopyItemFlavorData (pPasteboard, itemID, CFSTR ("public.utf16-plain-text"), &outData)))
170 {
171 Log (("Clipboard content is utf-16\n"));
172 rc = RTUtf16DupEx (&pwszTmp, (PRTUTF16)CFDataGetBytePtr (outData), 0);
173 }
174 /* Second try is utf-8 */
175 else
176#endif
177 if (!(err = PasteboardCopyItemFlavorData (pPasteboard, itemID, CFSTR ("public.utf8-plain-text"), &outData)))
178 {
179 Log (("readFromPasteboard: clipboard content is utf-8\n"));
180 rc = RTStrToUtf16 ((const char*)CFDataGetBytePtr (outData), &pwszTmp);
181 }
182 if (pwszTmp)
183 {
184 /* Check how much longer will the converted text will be. */
185 size_t cwSrc = RTUtf16Len (pwszTmp);
186 size_t cwDest;
187 rc = vboxClipboardUtf16GetWinSize (pwszTmp, cwSrc, &cwDest);
188 if (RT_FAILURE (rc))
189 {
190 RTUtf16Free (pwszTmp);
191 Log (("readFromPasteboard: clipboard conversion failed. vboxClipboardUtf16GetWinSize returned %Vrc. Abandoning.\n", rc));
192 AssertRCReturn (rc, rc);
193 }
194 /* Set the actually needed data size */
195 *pcbActual = cwDest * 2;
196 /* Return success state */
197 rc = VINF_SUCCESS;
198 /* Do not copy data if the dst buffer is not big enough. */
199 if (*pcbActual <= cb)
200 {
201 rc = vboxClipboardUtf16LinToWin (pwszTmp, RTUtf16Len (pwszTmp), static_cast <PRTUTF16> (pv), cb / 2);
202 if (RT_FAILURE (rc))
203 {
204 RTUtf16Free (pwszTmp);
205 Log (("readFromPasteboard: clipboard conversion failed. vboxClipboardUtf16LinToWin() returned %Vrc. Abandoning.\n", rc));
206 AssertRCReturn (rc, rc);
207 }
208#ifdef SHOW_CLIPBOARD_CONTENT
209 Log (("readFromPasteboard: clipboard content: %ls\n", static_cast <PRTUTF16> (pv)));
210#endif
211 }
212 /* Free the temp string */
213 RTUtf16Free (pwszTmp);
214 }
215 }
216 }
217
218 Log (("readFromPasteboard: rc = %02X\n", rc));
219 return rc;
220}
221
222/**
223 * Write clipboard content to the host clipboard from the internal clipboard
224 * structure.
225 *
226 * @param pPasteboardRef Reference to the global pasteboard.
227 * @param pv The source buffer.
228 * @param cb The size of the source buffer.
229 * @param fFormats The format type which should be written.
230 *
231 * @returns IPRT status code.
232 */
233int writeToPasteboard (PasteboardRef pPasteboard, void *pv, uint32_t cb, uint32_t fFormat)
234{
235 Log (("writeToPasteboard: fFormat = %02X\n", fFormat));
236
237 /* Clear the pasteboard */
238 if (PasteboardClear (pPasteboard))
239 return VERR_NOT_SUPPORTED;
240
241 /* Make sure all is in sync */
242 PasteboardSynchronize (pPasteboard);
243
244 int rc = VERR_NOT_SUPPORTED;
245 /* Handle the unicode text */
246 if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
247 {
248 PRTUTF16 pwszSrcText = static_cast <PRTUTF16> (pv);
249 size_t cwSrc = cb / 2;
250 size_t cwDest = 0;
251 /* How long will the converted text be? */
252 rc = vboxClipboardUtf16GetLinSize (pwszSrcText, cwSrc, &cwDest);
253 if (RT_FAILURE (rc))
254 {
255 Log (("writeToPasteboard: clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Vrc. Abandoning.\n", rc));
256 AssertRCReturn (rc, rc);
257 }
258 /* Empty clipboard? Not critical */
259 if (cwDest == 0)
260 {
261 Log (("writeToPasteboard: received empty clipboard data from the guest, returning false.\n"));
262 return VINF_SUCCESS;
263 }
264 /* Allocate the necessary memory */
265 PRTUTF16 pwszDestText = static_cast <PRTUTF16> (RTMemAlloc (cwDest * 2));
266 if (pwszDestText == NULL)
267 {
268 Log (("writeToPasteboard: failed to allocate %d bytes\n", cwDest * 2));
269 return VERR_NO_MEMORY;
270 }
271 /* Convert the EOL */
272 rc = vboxClipboardUtf16WinToLin (pwszSrcText, cwSrc, pwszDestText, cwDest);
273 if (RT_FAILURE (rc))
274 {
275 Log (("writeToPasteboard: clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Vrc. Abandoning.\n", rc));
276 RTMemFree (pwszDestText);
277 AssertRCReturn (rc, rc);
278 }
279
280 CFDataRef textData = NULL;
281 /* Item id is 1. Nothing special here. */
282 PasteboardItemID itemId = (PasteboardItemID)1;
283 /* Create a CData object which we could pass to the pasteboard */
284 if ((textData = CFDataCreate (kCFAllocatorDefault,
285 reinterpret_cast<UInt8*> (pwszDestText), cwDest * 2)))
286 {
287 /* Put the Utf-16 version to the pasteboard */
288 PasteboardPutItemFlavor (pPasteboard, itemId,
289 CFSTR ("public.utf16-plain-text"),
290 textData, 0);
291 }
292 /* Create a Utf-8 version */
293 char *pszDestText;
294 rc = RTUtf16ToUtf8 (pwszDestText, &pszDestText);
295 if (RT_SUCCESS (rc))
296 {
297 /* Create a CData object which we could pass to the pasteboard */
298 if ((textData = CFDataCreate (kCFAllocatorDefault,
299 reinterpret_cast<UInt8*> (pszDestText), strlen(pszDestText))))
300 {
301 /* Put the Utf-8 version to the pasteboard */
302 PasteboardPutItemFlavor (pPasteboard, itemId,
303 CFSTR ("public.utf8-plain-text"),
304 textData, 0);
305 }
306 RTStrFree (pszDestText);
307 }
308
309 RTMemFree (pwszDestText);
310 rc = VINF_SUCCESS;
311 }
312 else
313 rc = VERR_NOT_IMPLEMENTED;
314
315 Log (("writeToPasteboard: rc = %02X\n", rc));
316 return rc;
317}
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