- Timestamp:
- May 8, 2009 8:05:10 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp
r19536 r19540 137 137 * have a second instance that the first can interact with in order to have 138 138 * a more controlled environment. */ 139 enum { CLIP BOARD_NUM_CONTEXTS = 20 };139 enum { CLIP_MAX_CONTEXTS = 20 }; 140 140 141 141 /** Array of structures for mapping Xt widgets to context pointers. We … … 146 146 /** The context associated with the widget */ 147 147 CLIPBACKEND *pCtx; 148 } g_contexts[CLIP BOARD_NUM_CONTEXTS];148 } g_contexts[CLIP_MAX_CONTEXTS]; 149 149 150 150 /** Register a new X11 clipboard context. */ 151 static int vboxClipboardAddContext(CLIPBACKEND *pCtx)151 static int clipRegisterContext(CLIPBACKEND *pCtx) 152 152 { 153 153 bool found = false; … … 171 171 172 172 /** Unregister an X11 clipboard context. */ 173 static void vboxClipboardRemoveContext(CLIPBACKEND *pCtx)173 static void clipUnregisterContext(CLIPBACKEND *pCtx) 174 174 { 175 175 bool found = false; … … 191 191 192 192 /** Find an X11 clipboard context. */ 193 static CLIPBACKEND * vboxClipboardFindContext(Widget widget)193 static CLIPBACKEND *clipLookupContext(Widget widget) 194 194 { 195 195 AssertReturn(widget != NULL, NULL); … … 223 223 static bool g_fHaveX11; 224 224 225 static int vboxClipboardWriteUtf16LE(CLIPBACKEND *pCtx, 226 PRTUTF16 pu16SrcText, 227 size_t cwSrcLen, 228 void *pv, unsigned cb, 229 uint32_t *pcbActual) 230 { 231 size_t cwDestLen; 232 PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv); 225 /** 226 * Massage generic Utf16 with CR end-of-lines into the format Windows expects 227 * and put the result in a user-supplied buffer. 228 * @returns IPRT status code 229 * @returns VERR_BUFFER_OVERFLOW if the buffer is not large enough 230 * @param pwcSrc The source Utf16 231 * @param cwcSrc The number of 16bit elements in @a pwcSrc, not counting 232 * the terminating zero 233 * @param pvBuf The buffer to write the result into 234 * @param cbBuf The size of the buffer 235 * @param pcbActual On success, where to store the number of bytes written. 236 * On overflow, the buffer size needed. Undefined 237 * otherwise. Optional 238 */ 239 static int clipUtf16ToWinTxt(RTUTF16 *pwcSrc, size_t cwcSrc, 240 void *pvBuf, unsigned cbBuf, uint32_t *pcbActual) 241 { 242 LogFlowFunc(("pwcSrc=%p, cwcSrc=%u, pvBuf=%p, cbBuf=%u", pwcSrc, cwcSrc, 243 pvBuf, cbBuf)); 244 AssertPtrReturn(pwcSrc, VERR_INVALID_POINTER); 245 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 246 if (pcbActual) 247 *pcbActual = 0; 248 PRTUTF16 pwcDest = reinterpret_cast<PRTUTF16>(pvBuf); 249 size_t cwcDest; 250 int rc = vboxClipboardUtf16GetWinSize(pwcSrc, cwcSrc + 1, &cwcDest); 251 if (RT_SUCCESS(rc) && (cbBuf < cwcDest * 2)) 252 { 253 rc = VERR_BUFFER_OVERFLOW; 254 if (pcbActual) 255 *pcbActual = cwcDest * 2; 256 } 257 if (RT_SUCCESS(rc)) 258 rc = vboxClipboardUtf16LinToWin(pwcSrc, cwcSrc + 1, pwcDest, 259 cbBuf / 2); 260 if (RT_SUCCESS(rc)) 261 { 262 LogFlowFunc (("converted string is %.*ls\n", cwcDest, pwcDest)); 263 if (pcbActual) 264 *pcbActual = cwcDest * 2; 265 } 266 LogFlowFunc(("returning %Rrc\n", rc)); 267 if (pcbActual) 268 LogFlowFunc(("*pcbActual=%u\n", *pcbActual)); 269 return rc; 270 } 271 272 /** 273 * Convert Utf-8 text with CR end-of-lines into Utf-16 as Windows expects it 274 * and put the result in a user-supplied buffer. 275 * @returns IPRT status code 276 * @returns VERR_BUFFER_OVERFLOW if the buffer is not large enough 277 * @param pcSrc The source Utf-8 278 * @param cbSrc The size of the source in bytes, not counting the 279 * terminating zero 280 * @param pvBuf The buffer to write the result into 281 * @param cbBuf The size of the buffer 282 * @param pcbActual On success, where to store the number of bytes written. 283 * On overflow, the buffer size needed. Undefined 284 * otherwise. Optional 285 */ 286 static int clipUtf8ToWinTxt(const char *pcSrc, unsigned cbSrc, void *pvBuf, 287 unsigned cbBuf, uint32_t *pcbActual) 288 { 289 LogFlowFunc (("pcSrc = %.*s, cbSrc=%d, cbBuf=%d\n", cbSrc, pcSrc, cbSrc, 290 cbBuf)); 291 AssertPtrReturn(pcSrc, VERR_INVALID_POINTER); 292 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 293 if (pcbActual) 294 *pcbActual = 0; 295 /* Intermediate conversion to UTF16 */ 296 size_t cwcTmp; 297 PRTUTF16 pwcTmp = NULL; 298 int rc = RTStrToUtf16Ex(pcSrc, cbSrc, &pwcTmp, 0, &cwcTmp); 299 if (RT_SUCCESS(rc)) 300 rc = clipUtf16ToWinTxt(pwcTmp, cwcTmp, pvBuf, cbBuf, pcbActual); 301 RTUtf16Free(pwcTmp); 302 LogFlowFunc(("Returning %Rrc\n", rc)); 303 if (pcbActual) 304 LogFlowFunc(("*pcbActual=%u\n", *pcbActual)); 305 return rc; 306 } 307 308 /** 309 * Convert COMPOUND TEXT with CR end-of-lines into Utf-16 as Windows expects 310 * it and put the result in a user-supplied buffer. 311 * @returns IPRT status code 312 * @returns VERR_BUFFER_OVERFLOW if the buffer is not large enough 313 * @param widget An Xt widget, necessary because we use Xt/Xlib for the 314 * conversion 315 * @param pcSrc The source text 316 * @param cbSrc The size of the source in bytes, not counting the 317 * terminating zero 318 * @param pvBuf The buffer to write the result into 319 * @param cbBuf The size of the buffer 320 * @param pcbActual On success, where to store the number of bytes written. 321 * On overflow, the buffer size needed. Undefined 322 * otherwise. Optional 323 */ 324 static int clipCTextToWinTxt(Widget widget, unsigned char *pcSrc, 325 unsigned cbSrc, void *pvBuf, unsigned cbBuf, 326 uint32_t *pcbActual) 327 { 328 LogFlowFunc (("widget=%p, pcSrc=%.*s, cbSrc=%u, pvBuf=%p, cbBuf=%u\n", 329 widget, cbSrc, (char *) pcSrc, cbSrc, pvBuf, cbBuf)); 330 AssertReturn(widget, VERR_INVALID_PARAMETER); 331 AssertPtrReturn(pcSrc, VERR_INVALID_POINTER); 332 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 333 334 /* Special case as X*TextProperty* can't seem to handle empty strings. */ 335 if (cbSrc == 0) 336 { 337 *pcbActual = 2; 338 if (cbBuf < 2) 339 return VERR_BUFFER_OVERFLOW; 340 *(PRTUTF16) pvBuf = 0; 341 return VINF_SUCCESS; 342 } 343 344 if (pcbActual) 345 *pcbActual = 0; 346 /* Intermediate conversion to Utf8 */ 233 347 int rc = VINF_SUCCESS; 234 /* Check how much longer will the converted text will be. */235 rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen);236 if (RT_SUCCESS(rc) && (cb < cwDestLen * 2))237 {238 /* Not enough buffer space provided - report the amount needed. */239 LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n",240 cb, cwDestLen * 2));241 *pcbActual = cwDestLen * 2;242 rc = VERR_BUFFER_OVERFLOW;243 }244 /* Convert the text. */245 if (RT_SUCCESS(rc))246 rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2);247 if (RT_SUCCESS(rc))248 {249 LogFlowFunc (("converted string is %.*ls\n", cwDestLen, pu16DestText));250 *pcbActual = cwDestLen * 2;251 }252 return rc;253 }254 255 /**256 * Convert the UTF-8 text obtained from the X11 clipboard to UTF-16LE with257 * Windows EOLs, place it in the buffer supplied and signal that data has258 * arrived.259 *260 * @param pValue Source UTF-8 text261 * @param cbSourceLen Length in 8-bit bytes of the source text262 * @param pv Where to store the converted data263 * @param cb Length in bytes of the buffer pointed to by pv264 * @param pcbActual Where to store the size of the converted data265 * @param pClient Pointer to the client context structure266 * @note X11 backend code, called from the Xt callback when we wish to read267 * the X11 clipboard.268 */269 static int vboxClipboardGetUtf8FromX11(CLIPBACKEND *pCtx,270 XtPointer pValue, unsigned cbSrcLen,271 void *pv, unsigned cb,272 uint32_t *pcbActual)273 {274 size_t cwSrcLen;275 char *pu8SrcText = reinterpret_cast<char *>(pValue);276 PRTUTF16 pu16SrcText = NULL;277 278 LogFlowFunc (("converting Utf-8 to Utf-16LE. cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n",279 cbSrcLen, cb, cbSrcLen, pu8SrcText));280 *pcbActual = 0; /* Only set this to the right value on success. */281 /* First convert the UTF8 to UTF16 */282 int rc = RTStrToUtf16Ex(pu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen);283 if (RT_SUCCESS(rc))284 rc = vboxClipboardWriteUtf16LE(pCtx, pu16SrcText, cwSrcLen + 1,285 pv, cb, pcbActual);286 XtFree(reinterpret_cast<char *>(pValue));287 RTUtf16Free(pu16SrcText);288 LogFlowFunc(("Returning %Rrc\n", rc));289 return rc;290 }291 292 /**293 * Convert the COMPOUND_TEXT obtained from the X11 clipboard to UTF-16LE with294 * Windows EOLs, place it in the buffer supplied and signal that data has295 * arrived.296 *297 * @param pValue Source COMPOUND_TEXT298 * @param cbSourceLen Length in 8-bit bytes of the source text299 * @param pv Where to store the converted data300 * @param cb Length in bytes of the buffer pointed to by pv301 * @param pcbActual Where to store the size of the converted data302 * @param pClient Pointer to the client context structure303 * @note X11 backend code, called from the Xt callback when we wish to read304 * the X11 clipboard.305 */306 static int vboxClipboardGetCTextFromX11(CLIPBACKEND *pCtx,307 XtPointer pValue, unsigned cbSrcLen,308 void *pv, unsigned cb,309 uint32_t *pcbActual)310 {311 size_t cwSrcLen;312 char **ppu8SrcText = NULL;313 PRTUTF16 pu16SrcText = NULL;314 348 XTextProperty property; 315 int rc = VINF_SUCCESS;349 char **ppcTmp = NULL; 316 350 int cProps; 317 351 318 LogFlowFunc (("converting COMPOUND TEXT to Utf-16LE. cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n", 319 cbSrcLen, cb, cbSrcLen, reinterpret_cast<char *>(pValue))); 320 *pcbActual = 0; /* Only set this to the right value on success. */ 321 /** @todo quick fix for 2.2, do this properly. */ 322 if (cbSrcLen == 0) 323 { 324 XtFree(reinterpret_cast<char *>(pValue)); 325 if (cb < 2) 326 return VERR_BUFFER_OVERFLOW; 327 *(PRTUTF16) pv = 0; 328 *pcbActual = 2; 329 return VINF_SUCCESS; 330 } 331 /* First convert the compound text to Utf8 */ 332 property.value = reinterpret_cast<unsigned char *>(pValue); 333 property.encoding = clipGetAtom(pCtx->widget, "COMPOUND_TEXT"); 352 property.value = pcSrc; 353 property.encoding = clipGetAtom(widget, "COMPOUND_TEXT"); 334 354 property.format = 8; 335 property.nitems = cbSrc Len;336 #ifdef RT_OS_SOLARIS337 int xrc = X mbTextPropertyToTextList(XtDisplay(pCtx->widget), &property,338 &ppu8SrcText, &cProps);355 property.nitems = cbSrc; 356 #ifdef X_HAVE_UTF8_STRING 357 int xrc = Xutf8TextPropertyToTextList(XtDisplay(widget), &property, 358 &ppcTmp, &cProps); 339 359 #else 340 int xrc = X utf8TextPropertyToTextList(XtDisplay(pCtx->widget),341 &property, &ppu8SrcText, &cProps);360 int xrc = XmbTextPropertyToTextList(XtDisplay(widget), &property, 361 &ppcTmp, &cProps); 342 362 #endif 343 XtFree(reinterpret_cast<char *>(pValue));344 363 if (xrc < 0) 345 switch(xrc) 346 { 347 case XNoMemory: 348 rc = VERR_NO_MEMORY; 349 break; 350 case XLocaleNotSupported: 351 case XConverterNotFound: 352 rc = VERR_NOT_SUPPORTED; 353 break; 354 default: 355 rc = VERR_UNRESOLVED_ERROR; 356 } 364 rc = ( xrc == XNoMemory ? VERR_NO_MEMORY 365 : xrc == XLocaleNotSupported ? VERR_NOT_SUPPORTED 366 : xrc == XConverterNotFound ? VERR_NOT_SUPPORTED 367 : VERR_UNRESOLVED_ERROR); 357 368 /* Now convert the UTF8 to UTF16 */ 358 369 if (RT_SUCCESS(rc)) 359 rc = RTStrToUtf16Ex(*ppu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen); 370 rc = clipUtf8ToWinTxt(*ppcTmp, strlen(*ppcTmp), pvBuf, cbBuf, 371 pcbActual); 372 if (ppcTmp != NULL) 373 XFreeStringList(ppcTmp); 374 LogFlowFunc(("Returning %Rrc\n", rc)); 375 if (pcbActual) 376 LogFlowFunc(("*pcbActual=%u\n", *pcbActual)); 377 return rc; 378 } 379 380 /** 381 * Convert Latin-1 text with CR end-of-lines into Utf-16 as Windows expects 382 * it and put the result in a user-supplied buffer. 383 * @returns IPRT status code 384 * @returns VERR_BUFFER_OVERFLOW if the buffer is not large enough 385 * @param pcSrc The source text 386 * @param cbSrc The size of the source in bytes, not counting the 387 * terminating zero 388 * @param pvBuf The buffer to write the result into 389 * @param cbBuf The size of the buffer 390 * @param pcbActual On success, where to store the number of bytes written. 391 * On overflow, the buffer size needed. Undefined 392 * otherwise. Optional 393 */ 394 static int clipLatin1ToWinTxt(char *pcSrc, unsigned cbSrc, void *pvBuf, 395 size_t cbBuf, uint32_t *pcbActual) 396 { 397 LogFlowFunc (("pcSrc=%.*s, cbSrc=%u, pvBuf=%p, cbBuf=%u\n", cbSrc, 398 (char *) pcSrc, cbSrc, pvBuf, cbBuf)); 399 AssertPtrReturn(pcSrc, VERR_INVALID_POINTER); 400 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 401 int rc = VINF_SUCCESS; 402 403 /* Calculate the space needed */ 404 unsigned cwcDest = 0; 405 for (unsigned i = 0; i < cbSrc && pcSrc[i] != '\0'; ++i) 406 if (pcSrc[i] == LINEFEED) 407 cwcDest += 2; 408 else 409 ++cwcDest; 410 ++cwcDest; /* Leave space for the terminator */ 411 if (pcbActual) 412 *pcbActual = cwcDest * 2; 413 if (cbBuf < cwcDest * 2) 414 rc = VERR_BUFFER_OVERFLOW; 415 416 /* And do the convertion, bearing in mind that Latin-1 expands "naturally" 417 * to Utf-16. */ 360 418 if (RT_SUCCESS(rc)) 361 rc = vboxClipboardWriteUtf16LE(pCtx, pu16SrcText, cwSrcLen + 1, 362 pv, cb, pcbActual); 363 if (ppu8SrcText != NULL) 364 XFreeStringList(ppu8SrcText); 365 RTUtf16Free(pu16SrcText); 366 LogFlowFunc(("Returning %Rrc\n", rc)); 367 return rc; 368 } 369 370 /** 371 * Convert the Latin1 text obtained from the X11 clipboard to UTF-16LE with 372 * Windows EOLs, place it in the buffer supplied and signal that data has 373 * arrived. 374 * 375 * @param pValue Source Latin1 text 376 * @param cbSourceLen Length in 8-bit bytes of the source text 377 * @param pv Where to store the converted data 378 * @param cb Length in bytes of the buffer pointed to by cb 379 * @param pcbActual Where to store the size of the converted data 380 * @param pClient Pointer to the client context structure 381 * @note X11 backend code, called from the Xt callback when we wish to read 382 * the X11 clipboard. 383 */ 384 static int vboxClipboardGetLatin1FromX11(CLIPBACKEND *pCtx, 385 XtPointer pValue, 386 unsigned cbSourceLen, void *pv, 387 unsigned cb, uint32_t *pcbActual) 388 { 389 char *pu8SourceText = reinterpret_cast<char *>(pValue); 390 PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv); 391 int rc = VINF_SUCCESS; 392 393 LogFlowFunc (("converting Latin1 to Utf-16LE. Original is %.*s\n", 394 cbSourceLen, pu8SourceText)); 395 *pcbActual = 0; /* Only set this to the right value on success. */ 396 unsigned cwDestLen = 0; 397 for (unsigned i = 0; i < cbSourceLen && pu8SourceText[i] != '\0'; i++) 398 { 399 ++cwDestLen; 400 if (pu8SourceText[i] == LINEFEED) 401 ++cwDestLen; 402 } 403 /* Leave space for the terminator */ 404 ++cwDestLen; 405 if (cb < cwDestLen * 2) 406 { 407 /* Not enough buffer space provided - report the amount needed. */ 408 LogFlowFunc (("guest buffer too small: size %d bytes\n", cb)); 409 *pcbActual = cwDestLen * 2; 410 rc = VERR_BUFFER_OVERFLOW; 411 } 412 if (RT_SUCCESS(rc)) 413 { 414 for (unsigned i = 0, j = 0; i < cbSourceLen; ++i, ++j) 415 if (pu8SourceText[i] != LINEFEED) 416 pu16DestText[j] = pu8SourceText[i]; /* latin1 < utf-16LE */ 419 { 420 PRTUTF16 pwcDest = (PRTUTF16) pvBuf; 421 for (unsigned i = 0, j = 0; i < cbSrc; ++i, ++j) 422 if (pcSrc[i] != LINEFEED) 423 pwcDest[j] = pcSrc[i]; 417 424 else 418 425 { 419 pu16DestText[j] = CARRIAGERETURN; 426 pwcDest[j] = CARRIAGERETURN; 427 pwcDest[j + 1] = LINEFEED; 420 428 ++j; 421 pu16DestText[j] = LINEFEED;422 429 } 423 pu16DestText[cwDestLen - 1] = 0; 424 *pcbActual = cwDestLen * 2; 425 LogFlowFunc (("converted text is %.*ls\n", cwDestLen, pu16DestText)); 426 } 427 XtFree(reinterpret_cast<char *>(pValue)); 430 pwcDest[cwcDest - 1] = '\0'; /* Make sure we are zero-terminated. */ 431 LogFlowFunc (("converted text is %.*ls\n", cwcDest, pwcDest)); 432 } 428 433 LogFlowFunc(("Returning %Rrc\n", rc)); 434 if (pcbActual) 435 LogFlowFunc(("*pcbActual=%u\n", *pcbActual)); 429 436 return rc; 430 437 } … … 477 484 { 478 485 case CTEXT: 479 pRequest->rc = vboxClipboardGetCTextFromX11(pCtx, pValue, cTextLen, 480 pRequest->pv, 481 pRequest->cb, 482 pRequest->pcbActual); 486 pRequest->rc = clipCTextToWinTxt(pCtx->widget, 487 (unsigned char *)pValue, cTextLen, 488 pRequest->pv, pRequest->cb, 489 pRequest->pcbActual); 490 XtFree(reinterpret_cast<char *>(pValue)); 483 491 RTSemEventSignal(pRequest->finished); 484 492 break; … … 492 500 && (RTStrUniLenEx(pu8SourceText, *pcLen, &cStringLen) == VINF_SUCCESS)) 493 501 { 494 pRequest->rc = vboxClipboardGetUtf8FromX11(pCtx, pValue, 495 cTextLen, 496 pRequest->pv, 497 pRequest->cb, 498 pRequest->pcbActual); 502 pRequest->rc = clipUtf8ToWinTxt((const char *)pValue, cTextLen, 503 pRequest->pv, pRequest->cb, 504 pRequest->pcbActual); 505 XtFree(reinterpret_cast<char *>(pValue)); 499 506 RTSemEventSignal(pRequest->finished); 500 507 break; … … 502 509 else 503 510 { 504 pRequest->rc = vboxClipboardGetLatin1FromX11(pCtx, pValue, 505 cTextLen, 506 pRequest->pv, 507 pRequest->cb, 508 pRequest->pcbActual); 511 pRequest->rc = clipLatin1ToWinTxt((char *) pValue, cTextLen, 512 pRequest->pv, pRequest->cb, 513 pRequest->pcbActual); 514 XtFree(reinterpret_cast<char *>(pValue)); 509 515 RTSemEventSignal(pRequest->finished); 510 516 break; … … 655 661 /* Valid widget + invalid appcontext = bug. But don't return yet. */ 656 662 AssertPtr(pCtx->appContext); 657 vboxClipboardRemoveContext(pCtx);663 clipUnregisterContext(pCtx); 658 664 XtDestroyWidget(pCtx->widget); 659 665 } … … 724 730 } 725 731 else 726 rc = vboxClipboardAddContext(pCtx);732 rc = clipRegisterContext(pCtx); 727 733 } 728 734 if (RT_SUCCESS(rc)) … … 1213 1219 { 1214 1220 CLIPFORMAT enmFormat = INVALID; 1215 CLIPBACKEND *pCtx = vboxClipboardFindContext(widget);1221 CLIPBACKEND *pCtx = clipLookupContext(widget); 1216 1222 1217 1223 LogFlowFunc(("\n")); … … 1271 1277 static void vboxClipboardReturnToX11(Widget widget, Atom *) 1272 1278 { 1273 CLIPBACKEND *pCtx = vboxClipboardFindContext(widget);1279 CLIPBACKEND *pCtx = clipLookupContext(widget); 1274 1280 LogFlowFunc (("called, giving X11 clipboard ownership\n")); 1275 1281 /* These should be set to the right values as soon as we start polling */
Note:
See TracChangeset
for help on using the changeset viewer.