VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp@ 18852

Last change on this file since 18852 was 18852, checked in by vboxsync, 16 years ago

GuestHost/SharedClipboard: removed Utf16 support for X11 and split a function

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.2 KB
Line 
1/** @file
2 *
3 * Shared Clipboard:
4 * X11 backend code.
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
24
25#include <vector>
26
27#ifdef RT_OS_SOLARIS
28#include <tsol/label.h>
29#endif
30
31#include <X11/Xlib.h>
32#include <X11/Xatom.h>
33#include <X11/Intrinsic.h>
34#include <X11/Shell.h>
35#include <X11/Xproto.h>
36#include <X11/StringDefs.h>
37
38#include <iprt/env.h>
39#include <iprt/mem.h>
40#include <iprt/semaphore.h>
41#include <iprt/thread.h>
42
43#include <VBox/log.h>
44
45#include <VBox/GuestHost/SharedClipboard.h>
46#include <VBox/GuestHost/clipboard-helper.h>
47#include <VBox/HostServices/VBoxClipboardSvc.h>
48
49/** Do we want to test Utf8 by disabling other text formats? */
50static bool g_testUtf8 = false;
51/** Do we want to test compount text by disabling other text formats? */
52static bool g_testCText = false;
53/** Are we currently debugging the clipboard code? */
54static bool g_debugClipboard = false;
55
56/** The different clipboard formats which we support. */
57enum g_eClipboardFormats
58{
59 INVALID = 0,
60 TARGETS,
61 CTEXT,
62 UTF8
63};
64
65/** The X11 clipboard uses several names for the same format. This
66 * structure maps an X11 name to a format. */
67typedef struct {
68 Atom atom;
69 g_eClipboardFormats format;
70 unsigned guestFormat;
71} VBOXCLIPBOARDFORMAT;
72
73/** Global context information used by the X11 clipboard backend */
74struct _VBOXCLIPBOARDCONTEXTX11
75{
76 /** Opaque data structure describing the front-end. */
77 VBOXCLIPBOARDCONTEXT *pFrontend;
78 /** The X Toolkit application context structure */
79 XtAppContext appContext;
80
81 /** We have a separate thread to wait for Window and Clipboard events */
82 RTTHREAD thread;
83 /** The X Toolkit widget which we use as our clipboard client. It is never made visible. */
84 Widget widget;
85
86 /** X11 atom refering to the clipboard: CLIPBOARD */
87 Atom atomClipboard;
88 /** X11 atom refering to the selection: PRIMARY */
89 Atom atomPrimary;
90 /** X11 atom refering to the clipboard targets: TARGETS */
91 Atom atomTargets;
92 /** X11 atom refering to the clipboard multiple target: MULTIPLE */
93 Atom atomMultiple;
94 /** X11 atom refering to the clipboard timestamp target: TIMESTAMP */
95 Atom atomTimestamp;
96 /** X11 atom refering to the clipboard utf8 text format: UTF8_STRING */
97 Atom atomUtf8;
98 /** X11 atom refering to the clipboard compound text format: COMPOUND_TEXT */
99 Atom atomCText;
100
101 /** A list of the X11 formats which we support, mapped to our identifier for them, in the
102 order we prefer to have them in. */
103 std::vector<VBOXCLIPBOARDFORMAT> formatList;
104
105 /** Does VBox or X11 currently own the clipboard? */
106 volatile enum g_eOwner eOwner;
107
108 /** What is the best text format X11 has to offer? INVALID for none. */
109 g_eClipboardFormats X11TextFormat;
110 /** Atom corresponding to the X11 text format */
111 Atom atomX11TextFormat;
112 /** What is the best bitmap format X11 has to offer? INVALID for none. */
113 g_eClipboardFormats X11BitmapFormat;
114 /** Atom corresponding to the X11 Bitmap format */
115 Atom atomX11BitmapFormat;
116 /** What formats does VBox have on offer? */
117 int vboxFormats;
118 /** Windows hosts and guests cache the clipboard data they receive.
119 * Since we have no way of knowing whether their cache is still valid,
120 * we always send a "data changed" message after a successful transfer
121 * to invalidate it. */
122 bool notifyVBox;
123
124 /** Since the clipboard data moves asynchronously, we use an event
125 * semaphore to wait for it. When a function issues a request for
126 * clipboard data it must wait for this semaphore, which is triggered
127 * when the data arrives. */
128 RTSEMEVENT waitForData;
129};
130
131/* Only one client is supported. There seems to be no need for more clients.
132 */
133static VBOXCLIPBOARDCONTEXTX11 g_ctxX11;
134static VBOXCLIPBOARDCONTEXTX11 *g_pCtx;
135
136/* Are we actually connected to the X server? */
137static bool g_fHaveX11;
138
139static int vboxClipboardWriteUtf16LE(VBOXCLIPBOARDCONTEXTX11 *pCtx,
140 PRTUTF16 pu16SrcText,
141 size_t cwSrcLen,
142 void *pv, unsigned cb,
143 uint32_t *pcbActual)
144{
145 size_t cwDestLen;
146 PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);
147 int rc = VINF_SUCCESS;
148 /* Check how much longer will the converted text will be. */
149 rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen);
150 if (RT_SUCCESS(rc) && (cb < cwDestLen * 2))
151 {
152 /* Not enough buffer space provided - report the amount needed. */
153 LogFlowFunc (("guest buffer too small: size %d bytes, needed %d. Returning.\n",
154 cb, cwDestLen * 2));
155 *pcbActual = cwDestLen * 2;
156 rc = VERR_BUFFER_OVERFLOW;
157 }
158 /* Convert the text. */
159 if (RT_SUCCESS(rc))
160 rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2);
161 if (RT_SUCCESS(rc))
162 {
163 LogFlowFunc (("converted string is %.*ls\n", cwDestLen, pu16DestText));
164 *pcbActual = cwDestLen * 2;
165 }
166 return rc;
167}
168
169/**
170 * Convert the UTF-8 text obtained from the X11 clipboard to UTF-16LE with
171 * Windows EOLs, place it in the buffer supplied and signal that data has
172 * arrived.
173 *
174 * @param pValue Source UTF-8 text
175 * @param cbSourceLen Length in 8-bit bytes of the source text
176 * @param pv Where to store the converted data
177 * @param cb Length in bytes of the buffer pointed to by pv
178 * @param pcbActual Where to store the size of the converted data
179 * @param pClient Pointer to the client context structure
180 * @note X11 backend code, called from the Xt callback when we wish to read
181 * the X11 clipboard.
182 */
183static void vboxClipboardGetUtf8FromX11(VBOXCLIPBOARDCONTEXTX11 *pCtx,
184 XtPointer pValue, unsigned cbSrcLen,
185 void *pv, unsigned cb,
186 uint32_t *pcbActual)
187{
188 size_t cwSrcLen;
189 char *pu8SrcText = reinterpret_cast<char *>(pValue);
190 PRTUTF16 pu16SrcText = NULL;
191
192 LogFlowFunc (("converting Utf-8 to Utf-16LE. cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n",
193 cbSrcLen, cb, cbSrcLen, pu8SrcText));
194 *pcbActual = 0; /* Only set this to the right value on success. */
195 /* First convert the UTF8 to UTF16 */
196 int rc = RTStrToUtf16Ex(pu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen);
197 if (RT_SUCCESS(rc))
198 rc = vboxClipboardWriteUtf16LE(pCtx, pu16SrcText, cwSrcLen,
199 pv, cb, pcbActual);
200 XtFree(reinterpret_cast<char *>(pValue));
201 RTUtf16Free(pu16SrcText);
202 RTSemEventSignal(pCtx->waitForData);
203 LogFlowFunc(("Returning. Status is %Rrc", rc));
204}
205
206/**
207 * Convert the COMPOUND_TEXT obtained from the X11 clipboard to UTF-16LE with
208 * Windows EOLs, place it in the buffer supplied and signal that data has
209 * arrived.
210 *
211 * @param pValue Source COMPOUND_TEXT
212 * @param cbSourceLen Length in 8-bit bytes of the source text
213 * @param pv Where to store the converted data
214 * @param cb Length in bytes of the buffer pointed to by pv
215 * @param pcbActual Where to store the size of the converted data
216 * @param pClient Pointer to the client context structure
217 * @note X11 backend code, called from the Xt callback when we wish to read
218 * the X11 clipboard.
219 */
220static void vboxClipboardGetCTextFromX11(VBOXCLIPBOARDCONTEXTX11 *pCtx,
221 XtPointer pValue, unsigned cbSrcLen,
222 void *pv, unsigned cb,
223 uint32_t *pcbActual)
224{
225 size_t cwSrcLen;
226 char **ppu8SrcText = NULL;
227 PRTUTF16 pu16SrcText = NULL;
228 XTextProperty property;
229 int rc = VINF_SUCCESS;
230 int cProps;
231
232 LogFlowFunc (("converting COMPOUND TEXT to Utf-16LE. cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n",
233 cbSrcLen, cb, cbSrcLen, reinterpret_cast<char *>(pValue)));
234 *pcbActual = 0; /* Only set this to the right value on success. */
235 /* First convert the compound text to Utf8 */
236 property.value = reinterpret_cast<unsigned char *>(pValue);
237 property.encoding = pCtx->atomCText;
238 property.format = 8;
239 property.nitems = cbSrcLen;
240#ifdef RT_OS_SOLARIS
241 int xrc = XmbTextPropertyToTextList(XtDisplay(pCtx->widget), &property,
242 &ppu8SrcText, &cProps);
243#else
244 int xrc = Xutf8TextPropertyToTextList(XtDisplay(pCtx->widget),
245 &property, &ppu8SrcText, &cProps);
246#endif
247 XtFree(reinterpret_cast<char *>(pValue));
248 if (xrc < 0)
249 switch(xrc)
250 {
251 case XNoMemory:
252 rc = VERR_NO_MEMORY;
253 break;
254 case XLocaleNotSupported:
255 case XConverterNotFound:
256 rc = VERR_NOT_SUPPORTED;
257 break;
258 default:
259 rc = VERR_UNRESOLVED_ERROR;
260 }
261 /* Now convert the UTF8 to UTF16 */
262 if (RT_SUCCESS(rc))
263 rc = RTStrToUtf16Ex(*ppu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen);
264 if (RT_SUCCESS(rc))
265 rc = vboxClipboardWriteUtf16LE(pCtx, pu16SrcText, cwSrcLen,
266 pv, cb, pcbActual);
267 if (ppu8SrcText != NULL)
268 XFreeStringList(ppu8SrcText);
269 RTUtf16Free(pu16SrcText);
270 LogFlowFunc(("Returning. Status is %Rrc\n", rc));
271 RTSemEventSignal(pCtx->waitForData);
272}
273
274/**
275 * Convert the Latin1 text obtained from the X11 clipboard to UTF-16LE with
276 * Windows EOLs, place it in the buffer supplied and signal that data has
277 * arrived.
278 *
279 * @param pValue Source Latin1 text
280 * @param cbSourceLen Length in 8-bit bytes of the source text
281 * @param pv Where to store the converted data
282 * @param cb Length in bytes of the buffer pointed to by cb
283 * @param pcbActual Where to store the size of the converted data
284 * @param pClient Pointer to the client context structure
285 * @note X11 backend code, called from the Xt callback when we wish to read
286 * the X11 clipboard.
287 */
288static void vboxClipboardGetLatin1FromX11(VBOXCLIPBOARDCONTEXTX11 *pCtx,
289 XtPointer pValue,
290 unsigned cbSourceLen, void *pv,
291 unsigned cb, uint32_t *pcbActual)
292{
293 unsigned cwDestLen = cbSourceLen + 1;
294 char *pu8SourceText = reinterpret_cast<char *>(pValue);
295 PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);
296 int rc = VINF_SUCCESS;
297
298 LogFlowFunc (("converting Latin1 to Utf-16LE. Original is %.*s\n",
299 cbSourceLen, pu8SourceText));
300 *pcbActual = 0; /* Only set this to the right value on success. */
301 for (unsigned i = 0; i < cbSourceLen; i++)
302 if (pu8SourceText[i] == LINEFEED)
303 ++cwDestLen;
304 if (cb < cwDestLen * 2)
305 {
306 /* Not enough buffer space provided - report the amount needed. */
307 LogFlowFunc (("guest buffer too small: size %d bytes\n", cb));
308 *pcbActual = cwDestLen * 2;
309 rc = VERR_BUFFER_OVERFLOW;
310 }
311 if (RT_SUCCESS(rc))
312 {
313 for (unsigned i = 0, j = 0; i < cbSourceLen; ++i, ++j)
314 if (pu8SourceText[i] != LINEFEED)
315 pu16DestText[j] = pu8SourceText[i]; /* latin1 < utf-16LE */
316 else
317 {
318 pu16DestText[j] = CARRIAGERETURN;
319 ++j;
320 pu16DestText[j] = LINEFEED;
321 }
322 pu16DestText[cwDestLen - 1] = 0;
323 *pcbActual = cwDestLen * 2;
324 LogFlowFunc (("converted text is %.*ls\n", cwDestLen, pu16DestText));
325 }
326 XtFree(reinterpret_cast<char *>(pValue));
327 RTSemEventSignal(pCtx->waitForData);
328 LogFlowFunc(("Returning. Status is %Rrc\n", rc));
329}
330
331/**
332 * Convert the text obtained from the X11 clipboard to UTF-16LE with Windows
333 * EOLs, place it in the buffer supplied and signal that data has arrived.
334 * @note X11 backend code, callback for XtGetSelectionValue, for use when
335 * the X11 clipboard contains a text format we understand.
336 */
337static void vboxClipboardGetDataFromX11(Widget, XtPointer pClientData,
338 Atom * /* selection */,
339 Atom *atomType,
340 XtPointer pValue,
341 long unsigned int *pcLen,
342 int *piFormat)
343{
344 VBOXCLIPBOARDREQUEST *pRequest
345 = reinterpret_cast<VBOXCLIPBOARDREQUEST *>(pClientData);
346 VBOXCLIPBOARDCONTEXTX11 *pCtx = pRequest->pCtx;
347 LogFlowFunc(("pClientData=%p, *pcLen=%lu, *piFormat=%d\n", pClientData,
348 *pcLen, *piFormat));
349 LogFlowFunc(("pCtx->X11TextFormat=%d, pRequest->cb=%d\n",
350 pCtx->X11TextFormat, pRequest->cb));
351 unsigned cTextLen = (*pcLen) * (*piFormat) / 8;
352 /* The X Toolkit may have failed to get the clipboard selection for us. */
353 if (*atomType == XT_CONVERT_FAIL)
354 return;
355 /* The clipboard selection may have changed before we could get it. */
356 if (NULL == pValue)
357 return;
358 /* In which format is the clipboard data? */
359 switch (pCtx->X11TextFormat)
360 {
361 case CTEXT:
362 vboxClipboardGetCTextFromX11(pCtx, pValue, cTextLen, pRequest->pv,
363 pRequest->cb, pRequest->pcbActual);
364 break;
365 case UTF8:
366 {
367 /* If we are given broken Utf-8, we treat it as Latin1. Is this acceptable? */
368 size_t cStringLen;
369 char *pu8SourceText = reinterpret_cast<char *>(pValue);
370
371 if ((pCtx->X11TextFormat == UTF8)
372 && (RTStrUniLenEx(pu8SourceText, *pcLen, &cStringLen) == VINF_SUCCESS))
373 {
374 vboxClipboardGetUtf8FromX11(pCtx, pValue, cTextLen, pRequest->pv,
375 pRequest->cb, pRequest->pcbActual);
376 break;
377 }
378 else
379 {
380 vboxClipboardGetLatin1FromX11(pCtx, pValue, cTextLen,
381 pRequest->pv, pRequest->cb,
382 pRequest->pcbActual);
383 break;
384 }
385 }
386 default:
387 LogFunc (("bad target format\n"));
388 XtFree(reinterpret_cast<char *>(pValue));
389 return;
390 }
391 pCtx->notifyVBox = true;
392}
393
394/**
395 * Notify the host clipboard about the data formats we support, based on the
396 * "targets" (available data formats) information obtained from the X11
397 * clipboard.
398 * @note X11 backend code, callback for XtGetSelectionValue, called when we
399 * poll for available targets.
400 */
401static void vboxClipboardGetTargetsFromX11(Widget,
402 XtPointer pClientData,
403 Atom * /* selection */,
404 Atom *atomType,
405 XtPointer pValue,
406 long unsigned int *pcLen,
407 int *piFormat)
408{
409 VBOXCLIPBOARDCONTEXTX11 *pCtx =
410 reinterpret_cast<VBOXCLIPBOARDCONTEXTX11 *>(pClientData);
411 Atom *atomTargets = reinterpret_cast<Atom *>(pValue);
412 unsigned cAtoms = *pcLen;
413 g_eClipboardFormats eBestTarget = INVALID;
414 Atom atomBestTarget = None;
415
416 Log3 (("%s: called\n", __PRETTY_FUNCTION__));
417 if (*atomType == XT_CONVERT_FAIL)
418 {
419 LogFunc (("reading clipboard from host, X toolkit failed to convert the selection\n"));
420 return;
421 }
422
423 for (unsigned i = 0; i < cAtoms; ++i)
424 {
425 for (unsigned j = 0; j != pCtx->formatList.size(); ++j)
426 if (pCtx->formatList[j].atom == atomTargets[i])
427 {
428 if (eBestTarget < pCtx->formatList[j].format)
429 {
430 eBestTarget = pCtx->formatList[j].format;
431 atomBestTarget = pCtx->formatList[j].atom;
432 }
433 break;
434 }
435 if (g_debugClipboard)
436 {
437 char *szAtomName = XGetAtomName(XtDisplay(pCtx->widget),
438 atomTargets[i]);
439 if (szAtomName != 0)
440 {
441 Log2 (("%s: the host offers target %s\n", __PRETTY_FUNCTION__,
442 szAtomName));
443 XFree(szAtomName);
444 }
445 }
446 }
447 pCtx->atomX11TextFormat = atomBestTarget;
448 if ((eBestTarget != pCtx->X11TextFormat) || (pCtx->notifyVBox == true))
449 {
450 uint32_t u32Formats = 0;
451 if (g_debugClipboard)
452 {
453 if (atomBestTarget != None)
454 {
455 char *szAtomName = XGetAtomName(XtDisplay(pCtx->widget),
456 atomBestTarget);
457 Log2 (("%s: switching to host text target %s. Available targets are:\n",
458 __PRETTY_FUNCTION__, szAtomName));
459 XFree(szAtomName);
460 }
461 else
462 Log2(("%s: no supported host text target found. Available targets are:\n",
463 __PRETTY_FUNCTION__));
464 for (unsigned i = 0; i < cAtoms; ++i)
465 {
466 char *szAtomName = XGetAtomName(XtDisplay(pCtx->widget),
467 atomTargets[i]);
468 if (szAtomName != 0)
469 {
470 Log2 (("%s: %s\n", __PRETTY_FUNCTION__, szAtomName));
471 XFree(szAtomName);
472 }
473 }
474 }
475 pCtx->X11TextFormat = eBestTarget;
476 if (eBestTarget != INVALID)
477 u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
478 VBoxX11ClipboardReportX11Formats(pCtx->pFrontend, u32Formats);
479 pCtx->notifyVBox = false;
480 }
481 XtFree(reinterpret_cast<char *>(pValue));
482}
483
484/**
485 * This timer callback is called every 200ms to check the contents of the X11
486 * clipboard.
487 * @note X11 backend code, callback for XtAppAddTimeOut, recursively
488 * re-armed.
489 * @todo Use the XFIXES extension to check for new clipboard data when
490 * available.
491 */
492static void vboxClipboardPollX11ForTargets(XtPointer pUserData,
493 XtIntervalId * /* hTimerId */)
494{
495 VBOXCLIPBOARDCONTEXTX11 *pCtx =
496 reinterpret_cast<VBOXCLIPBOARDCONTEXTX11 *>(pUserData);
497 Log3 (("%s: called\n", __PRETTY_FUNCTION__));
498 /* Get the current clipboard contents */
499 if (pCtx->eOwner == X11)
500 {
501 Log3 (("%s: requesting the targets that the host clipboard offers\n",
502 __PRETTY_FUNCTION__));
503 XtGetSelectionValue(pCtx->widget, pCtx->atomClipboard,
504 pCtx->atomTargets,
505 vboxClipboardGetTargetsFromX11, pCtx,
506 CurrentTime);
507 }
508 /* Re-arm our timer */
509 XtAppAddTimeOut(pCtx->appContext, 200 /* ms */,
510 vboxClipboardPollX11ForTargets, pCtx);
511}
512
513/** We store information about the target formats we can handle in a global
514 * vector for internal use.
515 * @note X11 backend code.
516 */
517static void vboxClipboardAddFormat(VBOXCLIPBOARDCONTEXTX11 *pCtx,
518 const char *pszName,
519 g_eClipboardFormats eFormat,
520 unsigned guestFormat)
521{
522 VBOXCLIPBOARDFORMAT sFormat;
523 /* Get an atom from the X server for that target format */
524 Atom atomFormat = XInternAtom(XtDisplay(pCtx->widget), pszName, false);
525 sFormat.atom = atomFormat;
526 sFormat.format = eFormat;
527 sFormat.guestFormat = guestFormat;
528 pCtx->formatList.push_back(sFormat);
529 LogFlow (("vboxClipboardAddFormat: added format %s (%d)\n", pszName, eFormat));
530}
531
532/**
533 * The main loop of our clipboard reader.
534 * @note X11 backend code.
535 */
536static int vboxClipboardThread(RTTHREAD self, void *pvUser)
537{
538 LogRel(("Shared clipboard: starting host clipboard thread\n"));
539
540 VBOXCLIPBOARDCONTEXTX11 *pCtx =
541 reinterpret_cast<VBOXCLIPBOARDCONTEXTX11 *>(pvUser);
542 /* Set up a timer to poll the host clipboard */
543 XtAppAddTimeOut(pCtx->appContext, 200 /* ms */,
544 vboxClipboardPollX11ForTargets, pCtx);
545
546 XtAppMainLoop(pCtx->appContext);
547 pCtx->formatList.clear();
548 LogRel(("Shared clipboard: host clipboard thread terminated successfully\n"));
549 return VINF_SUCCESS;
550}
551
552/** X11 specific initialisation for the shared clipboard.
553 * @note X11 backend code.
554 */
555static int vboxClipboardInitX11 (VBOXCLIPBOARDCONTEXTX11 *pCtx)
556{
557 /* Create a window and make it a clipboard viewer. */
558 int cArgc = 0;
559 char *pcArgv = 0;
560 int rc = VINF_SUCCESS;
561 // static String szFallbackResources[] = { (char*)"*.width: 1", (char*)"*.height: 1", NULL };
562 Display *pDisplay;
563
564 /* Make sure we are thread safe */
565 XtToolkitThreadInitialize();
566 /* Set up the Clipbard application context and main window. We call all these functions
567 directly instead of calling XtOpenApplication() so that we can fail gracefully if we
568 can't get an X11 display. */
569 XtToolkitInitialize();
570 pCtx->appContext = XtCreateApplicationContext();
571 // XtAppSetFallbackResources(pCtx->appContext, szFallbackResources);
572 pDisplay = XtOpenDisplay(pCtx->appContext, 0, 0, "VBoxClipboard", 0, 0, &cArgc, &pcArgv);
573 if (NULL == pDisplay)
574 {
575 LogRel(("Shared clipboard: failed to connect to the host clipboard - the window system may not be running.\n"));
576 rc = VERR_NOT_SUPPORTED;
577 }
578 if (RT_SUCCESS(rc))
579 {
580 pCtx->widget = XtVaAppCreateShell(0, "VBoxClipboard", applicationShellWidgetClass, pDisplay,
581 XtNwidth, 1, XtNheight, 1, NULL);
582 if (NULL == pCtx->widget)
583 {
584 LogRel(("Shared clipboard: failed to construct the X11 window for the host clipboard manager.\n"));
585 rc = VERR_NO_MEMORY;
586 }
587 }
588 if (RT_SUCCESS(rc))
589 {
590 XtSetMappedWhenManaged(pCtx->widget, false);
591 XtRealizeWidget(pCtx->widget);
592
593 /* Get hold of the atoms which we need */
594 pCtx->atomClipboard = XInternAtom(XtDisplay(pCtx->widget), "CLIPBOARD", false /* only_if_exists */);
595 pCtx->atomPrimary = XInternAtom(XtDisplay(pCtx->widget), "PRIMARY", false);
596 pCtx->atomTargets = XInternAtom(XtDisplay(pCtx->widget), "TARGETS", false);
597 pCtx->atomMultiple = XInternAtom(XtDisplay(pCtx->widget), "MULTIPLE", false);
598 pCtx->atomTimestamp = XInternAtom(XtDisplay(pCtx->widget), "TIMESTAMP", false);
599 pCtx->atomUtf8 = XInternAtom(XtDisplay(pCtx->widget), "UTF_STRING", false);
600 /* And build up the vector of supported formats */
601 pCtx->atomCText = XInternAtom(XtDisplay(pCtx->widget), "COMPOUND_TEXT", false);
602 /* And build up the vector of supported formats */
603 if (!g_testCText)
604 {
605 vboxClipboardAddFormat(pCtx, "UTF8_STRING", UTF8,
606 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
607 vboxClipboardAddFormat(pCtx, "text/plain;charset=UTF-8", UTF8,
608 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
609 vboxClipboardAddFormat(pCtx, "text/plain;charset=utf-8", UTF8,
610 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
611 vboxClipboardAddFormat(pCtx, "STRING", UTF8,
612 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
613 vboxClipboardAddFormat(pCtx, "TEXT", UTF8,
614 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
615 vboxClipboardAddFormat(pCtx, "text/plain", UTF8,
616 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
617}
618 if (!g_testUtf8)
619 vboxClipboardAddFormat(pCtx, "COMPOUND_TEXT", CTEXT,
620 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
621 }
622 return rc;
623}
624
625/**
626 * Construct the X11 backend of the shared clipboard.
627 * @note X11 backend code
628 */
629VBOXCLIPBOARDCONTEXTX11 *VBoxX11ClipboardConstructX11
630 (VBOXCLIPBOARDCONTEXT *pFrontend)
631{
632 int rc;
633
634 VBOXCLIPBOARDCONTEXTX11 *pCtx = &g_ctxX11;
635 /** @todo we still only support one backend at a time, because the X
636 * toolkit intrinsics don't support user data in XtOwnSelection.
637 * This function should not fail like this. */
638 AssertReturn(g_pCtx == NULL, NULL);
639 g_pCtx = &g_ctxX11;
640 if (!RTEnvGet("DISPLAY"))
641 {
642 /*
643 * If we don't find the DISPLAY environment variable we assume that
644 * we are not connected to an X11 server. Don't actually try to do
645 * this then, just fail silently and report success on every call.
646 * This is important for VBoxHeadless.
647 */
648 LogRelFunc(("X11 DISPLAY variable not set -- disabling shared clipboard\n"));
649 g_fHaveX11 = false;
650 return pCtx;
651 }
652
653 if (RTEnvGet("VBOX_CBTEST_UTF8"))
654 {
655 g_testUtf8 = true;
656 LogRel(("Host clipboard: testing Utf8\n"));
657 }
658 else if (RTEnvGet("VBOX_CBTEST_CTEXT"))
659 {
660 g_testCText = true;
661 LogRel(("Host clipboard: testing compound text\n"));
662 }
663 else if (RTEnvGet("VBOX_CBDEBUG"))
664 {
665 g_debugClipboard = true;
666 LogRel(("Host clipboard: enabling additional debugging output\n"));
667 }
668
669 g_fHaveX11 = true;
670
671 LogRel(("Initializing X11 clipboard backend\n"));
672 pCtx->pFrontend = pFrontend;
673 RTSemEventCreate(&pCtx->waitForData);
674 return pCtx;
675}
676
677/**
678 * Destruct the shared clipboard X11 backend.
679 * @note X11 backend code
680 */
681void VBoxX11ClipboardDestructX11(VBOXCLIPBOARDCONTEXTX11 *pCtx)
682{
683 /*
684 * Immediately return if we are not connected to the host X server.
685 */
686 if (!g_fHaveX11)
687 return;
688
689 /* We set this to NULL when the event thread exits. It really should
690 * have exited at this point, when we are about to unload the code from
691 * memory. */
692 Assert(pCtx->widget == NULL);
693 RTSemEventDestroy(pCtx->waitForData);
694}
695
696/**
697 * Announce to the X11 backend that we are ready to start.
698 * @param owner who is the initial clipboard owner
699 */
700int VBoxX11ClipboardStartX11(VBOXCLIPBOARDCONTEXTX11 *pCtx,
701 bool fOwnsClipboard)
702{
703 int rc = VINF_SUCCESS;
704 LogFlowFunc(("\n"));
705 /*
706 * Immediately return if we are not connected to the host X server.
707 */
708 if (!g_fHaveX11)
709 return VINF_SUCCESS;
710
711 rc = vboxClipboardInitX11(pCtx);
712 if (RT_SUCCESS(rc))
713 {
714 rc = RTThreadCreate(&pCtx->thread, vboxClipboardThread, pCtx, 0,
715 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
716 if (RT_FAILURE(rc))
717 LogRel(("Failed to initialise the shared clipboard X11 backend.\n"));
718 }
719 if (RT_SUCCESS(rc))
720 {
721 if (fOwnsClipboard)
722 {
723 pCtx->eOwner = X11;
724 pCtx->notifyVBox = true;
725 }
726 else
727 {
728 /** @todo Check whether the guest gets a format announcement at
729 * startup. */
730 pCtx->eOwner = VB;
731 VBoxX11ClipboardAnnounceVBoxFormat(pCtx, 0);
732 }
733 }
734 return rc;
735}
736
737/**
738 * Called when the VBox may have fallen out of sync with the backend.
739 * @note X11 backend code
740 */
741void VBoxX11ClipboardRequestSyncX11(VBOXCLIPBOARDCONTEXTX11 *pCtx)
742{
743 /*
744 * Immediately return if we are not connected to the host X server.
745 */
746 if (!g_fHaveX11)
747 return;
748 pCtx->notifyVBox = true;
749}
750
751/**
752 * Shut down the shared clipboard X11 backend.
753 * @note X11 backend code
754 * @note Any requests from this object to get clipboard data from VBox
755 * *must* have completed or aborted before we are called, as
756 * otherwise the X11 event loop will still be waiting for the request
757 * to return and will not be able to terminate.
758 */
759int VBoxX11ClipboardStopX11(VBOXCLIPBOARDCONTEXTX11 *pCtx)
760{
761 int rc, rcThread;
762 unsigned count = 0;
763 XEvent ev;
764 /*
765 * Immediately return if we are not connected to the host X server.
766 */
767 if (!g_fHaveX11)
768 return VINF_SUCCESS;
769
770 /* This might mean that we are getting stopped twice. */
771 AssertReturn(pCtx->widget != NULL, VERR_WRONG_ORDER);
772 pCtx->eOwner = NONE;
773 pCtx->X11TextFormat = INVALID;
774 pCtx->X11BitmapFormat = INVALID;
775 LogRelFunc(("stopping the shared clipboard X11 backend\n"));
776
777 /* Set the termination flag to tell the Xt event loop to exit. We
778 * reiterate that any outstanding requests from the X11 event loop to
779 * the VBox part *must* have returned before we do this. */
780 XtAppSetExitFlag(pCtx->appContext);
781 /* Wake up the event loop */
782 memset(&ev, 0, sizeof(ev));
783 ev.xclient.type = ClientMessage;
784 ev.xclient.format = 8;
785 XSendEvent(XtDisplay(pCtx->widget), XtWindow(pCtx->widget), false, 0, &ev);
786 XFlush(XtDisplay(pCtx->widget));
787 do
788 {
789 rc = RTThreadWait(pCtx->thread, 1000, &rcThread);
790 ++count;
791 Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5)));
792 } while ((VERR_TIMEOUT == rc) && (count < 300));
793 if (RT_SUCCESS(rc))
794 AssertRC(rcThread);
795 else
796 LogRelFunc(("rc=%Rrc\n", rc));
797 XtCloseDisplay(XtDisplay(pCtx->widget));
798 pCtx->widget = NULL; /* For sanity assertions. */
799 LogFlowFunc(("returning %Rrc.\n", rc));
800 return rc;
801}
802
803/**
804 * Satisfy a request from X11 for clipboard targets supported by VBox.
805 *
806 * @returns true if we successfully convert the data to the format
807 * requested, false otherwise.
808 *
809 * @param atomTypeReturn The type of the data we are returning
810 * @param pValReturn A pointer to the data we are returning. This
811 * should be set to memory allocated by XtMalloc,
812 * which will be freed later by the Xt toolkit.
813 * @param pcLenReturn The length of the data we are returning
814 * @param piFormatReturn The format (8bit, 16bit, 32bit) of the data we are
815 * returning
816 * @note X11 backend code, called by the XtOwnSelection callback.
817 */
818static Boolean vboxClipboardConvertTargetsForX11(VBOXCLIPBOARDCONTEXTX11
819 *pCtx,
820 Atom *atomTypeReturn,
821 XtPointer *pValReturn,
822 unsigned long *pcLenReturn,
823 int *piFormatReturn)
824{
825 unsigned uListSize = pCtx->formatList.size();
826 Atom *atomTargets = reinterpret_cast<Atom *>(XtMalloc((uListSize + 3) * sizeof(Atom)));
827 unsigned cTargets = 0;
828
829 LogFlowFunc (("called\n"));
830 for (unsigned i = 0; i < uListSize; ++i)
831 {
832 if ( ((pCtx->vboxFormats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) != 0)
833 && ( pCtx->formatList[i].guestFormat
834 == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT))
835 {
836 atomTargets[cTargets] = pCtx->formatList[i].atom;
837 ++cTargets;
838 }
839 }
840 atomTargets[cTargets] = pCtx->atomTargets;
841 atomTargets[cTargets + 1] = pCtx->atomMultiple;
842 atomTargets[cTargets + 2] = pCtx->atomTimestamp;
843 if (g_debugClipboard)
844 {
845 for (unsigned i = 0; i < cTargets + 3; i++)
846 {
847 char *szAtomName = XGetAtomName(XtDisplay(pCtx->widget), atomTargets[i]);
848 if (szAtomName != 0)
849 {
850 Log2 (("%s: returning target %s\n", __PRETTY_FUNCTION__,
851 szAtomName));
852 XFree(szAtomName);
853 }
854 else
855 {
856 Log(("%s: invalid atom %d in the list!\n", __PRETTY_FUNCTION__,
857 atomTargets[i]));
858 }
859 }
860 }
861 *atomTypeReturn = XA_ATOM;
862 *pValReturn = reinterpret_cast<XtPointer>(atomTargets);
863 *pcLenReturn = cTargets + 3;
864 *piFormatReturn = 32;
865 return true;
866}
867
868/**
869 * Satisfy a request from X11 to convert the clipboard text to Utf8. We
870 * return non-zero terminated text.
871 * @todo that works, but it is bad. Change it to return zero-terminated
872 * text.
873 *
874 * @returns true if we successfully convert the data to the format
875 * requested, false otherwise.
876 *
877 * @param atomTypeReturn Where to store the atom for the type of the data
878 * we are returning
879 * @param pValReturn Where to store the pointer to the data we are
880 * returning. This should be to memory allocated by
881 * XtMalloc, which will be freed by the Xt toolkit
882 * later.
883 * @param pcLenReturn Where to store the length of the data we are
884 * returning
885 * @param piFormatReturn Where to store the bit width (8, 16, 32) of the
886 * data we are returning
887 * @note X11 backend code, called by the callback for XtOwnSelection.
888 */
889static Boolean vboxClipboardConvertToUtf8ForX11(VBOXCLIPBOARDCONTEXTX11
890 *pCtx,
891 Atom *atomTypeReturn,
892 XtPointer *pValReturn,
893 unsigned long *pcLenReturn,
894 int *piFormatReturn)
895{
896 PRTUTF16 pu16SrcText, pu16DestText;
897 char *pu8DestText;
898 void *pvVBox;
899 uint32_t cbVBox;
900 size_t cwSrcLen, cwDestLen, cbDestLen;
901 int rc;
902
903 LogFlowFunc (("called\n"));
904 /* Read the clipboard data from the guest. */
905 rc = VBoxX11ClipboardReadVBoxData(pCtx->pFrontend, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &pvVBox, &cbVBox);
906 if ((rc != VINF_SUCCESS) || (cbVBox == 0))
907 {
908 /* If VBoxX11ClipboardReadVBoxData fails then pClient may be invalid */
909 LogRelFunc (("VBoxX11ClipboardReadVBoxData returned %Rrc%s\n", rc,
910 RT_SUCCESS(rc) ? ", cbVBox == 0" : ""));
911 RTMemFree(pvVBox);
912 return false;
913 }
914 pu16SrcText = reinterpret_cast<PRTUTF16>(pvVBox);
915 cwSrcLen = cbVBox / 2;
916 /* How long will the converted text be? */
917 rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen);
918 if (RT_FAILURE(rc))
919 {
920 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));
921 RTMemFree(pvVBox);
922 AssertRCReturn(rc, false);
923 }
924 if (cwDestLen == 0)
925 {
926 LogFlowFunc(("received empty clipboard data from the guest, returning false.\n"));
927 RTMemFree(pvVBox);
928 return false;
929 }
930 pu16DestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwDestLen * 2));
931 if (pu16DestText == 0)
932 {
933 LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 2));
934 RTMemFree(pvVBox);
935 return false;
936 }
937 /* Convert the text. */
938 rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen);
939 if (RT_FAILURE(rc))
940 {
941 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc));
942 RTMemFree(reinterpret_cast<void *>(pu16DestText));
943 RTMemFree(pvVBox);
944 return false;
945 }
946 /* Allocate enough space, as RTUtf16ToUtf8Ex may fail if the
947 space is too tightly calculated. */
948 pu8DestText = XtMalloc(cwDestLen * 4);
949 if (pu8DestText == 0)
950 {
951 LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 4));
952 RTMemFree(reinterpret_cast<void *>(pu16DestText));
953 RTMemFree(pvVBox);
954 return false;
955 }
956 /* Convert the Utf16 string to Utf8. */
957 rc = RTUtf16ToUtf8Ex(pu16DestText + 1, cwDestLen - 1, &pu8DestText, cwDestLen * 4,
958 &cbDestLen);
959 RTMemFree(reinterpret_cast<void *>(pu16DestText));
960 if (RT_FAILURE(rc))
961 {
962 LogRelFunc (("clipboard conversion failed. RTUtf16ToUtf8Ex() returned %Rrc. Abandoning.\n", rc));
963 XtFree(pu8DestText);
964 RTMemFree(pvVBox);
965 return false;
966 }
967 LogFlowFunc (("converted string is %.*s. Returning.\n", cbDestLen, pu8DestText));
968 RTMemFree(pvVBox);
969 *atomTypeReturn = pCtx->atomUtf8;
970 *pValReturn = reinterpret_cast<XtPointer>(pu8DestText);
971 *pcLenReturn = cbDestLen;
972 *piFormatReturn = 8;
973 return true;
974}
975
976/**
977 * Satisfy a request from X11 to convert the clipboard text to
978 * COMPOUND_TEXT. We return non-zero terminated text.
979 * @todo that works, but it is bad. Change it to return zero-terminated
980 * text.
981 *
982 * @returns true if we successfully convert the data to the format
983 * requested, false otherwise.
984 *
985 * @param atomTypeReturn Where to store the atom for the type of the data
986 * we are returning
987 * @param pValReturn Where to store the pointer to the data we are
988 * returning. This should be to memory allocated by
989 * XtMalloc, which will be freed by the Xt toolkit
990 * later.
991 * @param pcLenReturn Where to store the length of the data we are
992 * returning
993 * @param piFormatReturn Where to store the bit width (8, 16, 32) of the
994 * data we are returning
995 * @note X11 backend code, called by the callback for XtOwnSelection.
996 */
997static Boolean vboxClipboardConvertToCTextForX11(VBOXCLIPBOARDCONTEXTX11
998 *pCtx,
999 Atom *atomTypeReturn,
1000 XtPointer *pValReturn,
1001 unsigned long *pcLenReturn,
1002 int *piFormatReturn)
1003{
1004 PRTUTF16 pu16SrcText, pu16DestText;
1005 void *pvVBox;
1006 uint32_t cbVBox;
1007 char *pu8DestText = 0;
1008 size_t cwSrcLen, cwDestLen, cbDestLen;
1009 XTextProperty property;
1010 int rc;
1011
1012 LogFlowFunc (("called\n"));
1013 /* Read the clipboard data from the guest. */
1014 rc = VBoxX11ClipboardReadVBoxData(pCtx->pFrontend, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &pvVBox, &cbVBox);
1015 if ((rc != VINF_SUCCESS) || (cbVBox == 0))
1016 {
1017 /* If VBoxX11ClipboardReadVBoxData fails then pClient may be invalid */
1018 LogRelFunc (("VBoxX11ClipboardReadVBoxData returned %Rrc%s\n", rc,
1019 RT_SUCCESS(rc) ? ", cbVBox == 0" : ""));
1020 RTMemFree(pvVBox);
1021 return false;
1022 }
1023 pu16SrcText = reinterpret_cast<PRTUTF16>(pvVBox);
1024 cwSrcLen = cbVBox / 2;
1025 /* How long will the converted text be? */
1026 rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen);
1027 if (RT_FAILURE(rc))
1028 {
1029 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));
1030 RTMemFree(pvVBox);
1031 AssertRCReturn(rc, false);
1032 }
1033 if (cwDestLen == 0)
1034 {
1035 LogFlowFunc(("received empty clipboard data from the guest, returning false.\n"));
1036 RTMemFree(pvVBox);
1037 return false;
1038 }
1039 pu16DestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwDestLen * 2));
1040 if (pu16DestText == 0)
1041 {
1042 LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 2));
1043 RTMemFree(pvVBox);
1044 return false;
1045 }
1046 /* Convert the text. */
1047 rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen);
1048 if (RT_FAILURE(rc))
1049 {
1050 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc));
1051 RTMemFree(reinterpret_cast<void *>(pu16DestText));
1052 RTMemFree(pvVBox);
1053 return false;
1054 }
1055 /* Convert the Utf16 string to Utf8. */
1056 rc = RTUtf16ToUtf8Ex(pu16DestText + 1, cwDestLen - 1, &pu8DestText, 0, &cbDestLen);
1057 RTMemFree(reinterpret_cast<void *>(pu16DestText));
1058 if (RT_FAILURE(rc))
1059 {
1060 LogRelFunc (("clipboard conversion failed. RTUtf16ToUtf8Ex() returned %Rrc. Abandoning.\n", rc));
1061 RTMemFree(pvVBox);
1062 return false;
1063 }
1064 /* And finally (!) convert the Utf8 text to compound text. */
1065#ifdef RT_OS_SOLARIS
1066 rc = XmbTextListToTextProperty(XtDisplay(pCtx->widget), &pu8DestText, 1,
1067 XCompoundTextStyle, &property);
1068#else
1069 rc = Xutf8TextListToTextProperty(XtDisplay(pCtx->widget), &pu8DestText, 1,
1070 XCompoundTextStyle, &property);
1071#endif
1072 RTMemFree(pu8DestText);
1073 if (rc < 0)
1074 {
1075 const char *pcReason;
1076 switch(rc)
1077 {
1078 case XNoMemory:
1079 pcReason = "out of memory";
1080 break;
1081 case XLocaleNotSupported:
1082 pcReason = "locale (Utf8) not supported";
1083 break;
1084 case XConverterNotFound:
1085 pcReason = "converter not found";
1086 break;
1087 default:
1088 pcReason = "unknown error";
1089 }
1090 LogRelFunc (("Xutf8TextListToTextProperty failed. Reason: %s\n",
1091 pcReason));
1092 RTMemFree(pvVBox);
1093 return false;
1094 }
1095 LogFlowFunc (("converted string is %s. Returning.\n", property.value));
1096 RTMemFree(pvVBox);
1097 *atomTypeReturn = property.encoding;
1098 *pValReturn = reinterpret_cast<XtPointer>(property.value);
1099 *pcLenReturn = property.nitems;
1100 *piFormatReturn = property.format;
1101 return true;
1102}
1103
1104/**
1105 * Return VBox's clipboard data for an X11 client.
1106 * @note X11 backend code, callback for XtOwnSelection
1107 */
1108static Boolean vboxClipboardConvertForX11(Widget, Atom *atomSelection,
1109 Atom *atomTarget,
1110 Atom *atomTypeReturn,
1111 XtPointer *pValReturn,
1112 unsigned long *pcLenReturn,
1113 int *piFormatReturn)
1114{
1115 g_eClipboardFormats eFormat = INVALID;
1116 /** @todo find a better way around the lack of user data. */
1117 VBOXCLIPBOARDCONTEXTX11 *pCtx = g_pCtx;
1118
1119 LogFlowFunc(("\n"));
1120 /* Drop requests that we receive too late. */
1121 if (pCtx->eOwner != VB)
1122 return false;
1123 if ( (*atomSelection != pCtx->atomClipboard)
1124 && (*atomSelection != pCtx->atomPrimary)
1125 )
1126 {
1127 LogFlowFunc(("rc = false\n"));
1128 return false;
1129 }
1130 if (g_debugClipboard)
1131 {
1132 char *szAtomName = XGetAtomName(XtDisplay(pCtx->widget), *atomTarget);
1133 if (szAtomName != 0)
1134 {
1135 Log2 (("%s: request for format %s\n", __PRETTY_FUNCTION__, szAtomName));
1136 XFree(szAtomName);
1137 }
1138 else
1139 {
1140 LogFunc (("request for invalid target atom %d!\n", *atomTarget));
1141 }
1142 }
1143 if (*atomTarget == pCtx->atomTargets)
1144 {
1145 eFormat = TARGETS;
1146 }
1147 else
1148 {
1149 for (unsigned i = 0; i != pCtx->formatList.size(); ++i)
1150 {
1151 if (pCtx->formatList[i].atom == *atomTarget)
1152 {
1153 eFormat = pCtx->formatList[i].format;
1154 break;
1155 }
1156 }
1157 }
1158 switch (eFormat)
1159 {
1160 case TARGETS:
1161 return vboxClipboardConvertTargetsForX11(pCtx, atomTypeReturn,
1162 pValReturn, pcLenReturn,
1163 piFormatReturn);
1164 case UTF8:
1165 return vboxClipboardConvertToUtf8ForX11(pCtx, atomTypeReturn,
1166 pValReturn, pcLenReturn,
1167 piFormatReturn);
1168 case CTEXT:
1169 return vboxClipboardConvertToCTextForX11(pCtx, atomTypeReturn,
1170 pValReturn, pcLenReturn,
1171 piFormatReturn);
1172 default:
1173 LogFunc (("bad format\n"));
1174 return false;
1175 }
1176}
1177
1178/**
1179 * This is called by the X toolkit intrinsics to let us know that another
1180 * X11 client has taken the clipboard. In this case we notify VBox that
1181 * we want ownership of the clipboard.
1182 * @note X11 backend code, callback for XtOwnSelection
1183 */
1184static void vboxClipboardReturnToX11(Widget, Atom *)
1185{
1186 /** @todo find a better way around the lack of user data */
1187 VBOXCLIPBOARDCONTEXTX11 *pCtx = g_pCtx;
1188 LogFlowFunc (("called, giving VBox clipboard ownership\n"));
1189 pCtx->eOwner = X11;
1190 pCtx->notifyVBox = true;
1191}
1192
1193/**
1194 * VBox is taking possession of the shared clipboard.
1195 *
1196 * @param u32Formats Clipboard formats the guest is offering
1197 * @note X11 backend code
1198 */
1199void VBoxX11ClipboardAnnounceVBoxFormat(VBOXCLIPBOARDCONTEXTX11 *pCtx,
1200 uint32_t u32Formats)
1201{
1202 /*
1203 * Immediately return if we are not connected to the host X server.
1204 */
1205 if (!g_fHaveX11)
1206 return;
1207
1208 pCtx->vboxFormats = u32Formats;
1209 LogFlowFunc (("u32Formats=%d\n", u32Formats));
1210 if (u32Formats == 0)
1211 {
1212 /* This is just an automatism, not a genuine anouncement */
1213 LogFlowFunc(("returning\n"));
1214 return;
1215 }
1216 if (pCtx->eOwner == VB)
1217 {
1218 /* We already own the clipboard, so no need to grab it, especially as that can lead
1219 to races due to the asynchronous nature of the X11 clipboard. This event may also
1220 have been sent out by the guest to invalidate the Windows clipboard cache. */
1221 LogFlowFunc(("returning\n"));
1222 return;
1223 }
1224 Log2 (("%s: giving the guest clipboard ownership\n", __PRETTY_FUNCTION__));
1225 pCtx->eOwner = VB;
1226 pCtx->X11TextFormat = INVALID;
1227 pCtx->X11BitmapFormat = INVALID;
1228 if (XtOwnSelection(pCtx->widget, pCtx->atomClipboard, CurrentTime,
1229 vboxClipboardConvertForX11, vboxClipboardReturnToX11,
1230 0) != True)
1231 {
1232 Log2 (("%s: returning clipboard ownership to the host\n", __PRETTY_FUNCTION__));
1233 /* We set this so that the guest gets notified when we take the clipboard, even if no
1234 guest formats are found which we understand. */
1235 pCtx->notifyVBox = true;
1236 pCtx->eOwner = X11;
1237 }
1238 XtOwnSelection(pCtx->widget, pCtx->atomPrimary, CurrentTime, vboxClipboardConvertForX11,
1239 NULL, 0);
1240 LogFlowFunc(("returning\n"));
1241
1242}
1243
1244/**
1245 * Called when VBox wants to read the X11 clipboard.
1246 *
1247 * @param pClient Context information about the guest VM
1248 * @param u32Format The format that the guest would like to receive the data in
1249 * @param pv Where to write the data to
1250 * @param cb The size of the buffer to write the data to
1251 * @param pcbActual Where to write the actual size of the written data
1252 * @note X11 backend code
1253 */
1254int VBoxX11ClipboardReadX11Data(VBOXCLIPBOARDCONTEXTX11 *pCtx,
1255 uint32_t u32Format,
1256 VBOXCLIPBOARDREQUEST *pRequest)
1257{
1258 /*
1259 * Immediately return if we are not connected to the host X server.
1260 */
1261 if (!g_fHaveX11)
1262 {
1263 /* no data available */
1264 *pRequest->pcbActual = 0;
1265 return VINF_SUCCESS;
1266 }
1267
1268 LogFlowFunc (("u32Format = %d, cb = %d\n", u32Format, pRequest->cb));
1269
1270 /*
1271 * The guest wants to read data in the given format.
1272 */
1273 if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
1274 {
1275 if (pCtx->X11TextFormat == INVALID)
1276 {
1277 /* No data available. */
1278 *pRequest->pcbActual = 0;
1279 return VERR_NO_DATA; /* The guest thinks we have data and we don't */
1280 }
1281 /* Initially set the size of the data read to zero in case we fail
1282 * somewhere. */
1283 *pRequest->pcbActual = 0;
1284 /* Send out a request for the data to the current clipboard owner */
1285 XtGetSelectionValue(pCtx->widget, pCtx->atomClipboard,
1286 pCtx->atomX11TextFormat,
1287 vboxClipboardGetDataFromX11,
1288 reinterpret_cast<XtPointer>(pRequest),
1289 CurrentTime);
1290 /* When the data arrives, the vboxClipboardGetDataFromX11 callback will be called. The
1291 callback will signal the event semaphore when it has processed the data for us. */
1292
1293 int rc = RTSemEventWait(pCtx->waitForData, RT_INDEFINITE_WAIT);
1294 if (RT_FAILURE(rc))
1295 return rc;
1296 }
1297 else
1298 {
1299 return VERR_NOT_IMPLEMENTED;
1300 }
1301 return VINF_SUCCESS;
1302}
1303
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette