2 *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
3 *Copyright (C) Colin Harrison 2005-2008
5 *Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 *"Software"), to deal in the Software without restriction, including
8 *without limitation the rights to use, copy, modify, merge, publish,
9 *distribute, sublicense, and/or sell copies of the Software, and to
10 *permit persons to whom the Software is furnished to do so, subject to
11 *the following conditions:
13 *The above copyright notice and this permission notice shall be
14 *included in all copies or substantial portions of the Software.
16 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
20 *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21 *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *Except as contained in this notice, the name of the copyright holder(s)
25 *and author(s) shall not be used in advertising or otherwise to promote
26 *the sale, use or other dealings in this Software without prior written
27 *authorization from the copyright holder(s) and author(s).
29 * Authors: Harold L Hunt II
33 #ifdef HAVE_XWIN_CONFIG_H
34 #include <xwin-config.h>
36 #include "winclipboard.h"
40 * Process any pending X events
44 winClipboardFlushXEvents(HWND hwnd
,
45 int iWindow
, Display
* pDisplay
, Bool fUseUnicode
)
47 static Atom atomLocalProperty
;
48 static Atom atomCompoundText
;
49 static Atom atomUTF8String
;
50 static Atom atomTargets
;
51 static int generation
;
53 if (generation
!= serverGeneration
) {
54 generation
= serverGeneration
;
55 atomLocalProperty
= XInternAtom(pDisplay
, WIN_LOCAL_PROPERTY
, False
);
56 atomUTF8String
= XInternAtom(pDisplay
, "UTF8_STRING", False
);
57 atomCompoundText
= XInternAtom(pDisplay
, "COMPOUND_TEXT", False
);
58 atomTargets
= XInternAtom(pDisplay
, "TARGETS", False
);
61 /* Process all pending events */
62 while (XPending(pDisplay
)) {
63 XTextProperty xtpText
= { 0 };
65 XSelectionEvent eventSelection
;
66 unsigned long ulReturnBytesLeft
;
67 char *pszReturnData
= NULL
;
68 char *pszGlobalData
= NULL
;
70 HGLOBAL hGlobal
= NULL
;
71 XICCEncodingStyle xiccesStyle
;
72 int iConvertDataLen
= 0;
73 char *pszConvertData
= NULL
;
74 char *pszTextList
[2] = { NULL
};
76 char **ppszTextList
= NULL
;
77 wchar_t *pwszUnicodeStr
= NULL
;
79 int iReturnDataLen
= 0;
82 Bool fCloseClipboard
= FALSE
;
83 Bool fSetClipboardData
= TRUE
;
85 /* Get the next event - will not block because one is ready */
86 XNextEvent(pDisplay
, &event
);
88 /* Branch on the event type */
94 case SelectionRequest
:
96 char *pszAtomName
= NULL
;
98 winDebug("SelectionRequest - target %d\n",
99 event
.xselectionrequest
.target
);
101 pszAtomName
= XGetAtomName(pDisplay
,
102 event
.xselectionrequest
.target
);
103 winDebug("SelectionRequest - Target atom name %s\n", pszAtomName
);
108 /* Abort if invalid target type */
109 if (event
.xselectionrequest
.target
!= XA_STRING
110 && event
.xselectionrequest
.target
!= atomUTF8String
111 && event
.xselectionrequest
.target
!= atomCompoundText
112 && event
.xselectionrequest
.target
!= atomTargets
) {
115 goto winClipboardFlushXEvents_SelectionRequest_Done
;
118 /* Handle targets type of request */
119 if (event
.xselectionrequest
.target
== atomTargets
) {
120 Atom atomTargetArr
[] = { atomTargets
,
126 /* Try to change the property */
127 iReturn
= XChangeProperty(pDisplay
,
128 event
.xselectionrequest
.requestor
,
129 event
.xselectionrequest
.property
,
133 (unsigned char *) atomTargetArr
,
134 (sizeof(atomTargetArr
)
135 / sizeof(atomTargetArr
[0])));
136 if (iReturn
== BadAlloc
137 || iReturn
== BadAtom
138 || iReturn
== BadMatch
139 || iReturn
== BadValue
|| iReturn
== BadWindow
) {
140 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
141 "XChangeProperty failed: %d\n", iReturn
);
144 /* Setup selection notify xevent */
145 eventSelection
.type
= SelectionNotify
;
146 eventSelection
.send_event
= True
;
147 eventSelection
.display
= pDisplay
;
148 eventSelection
.requestor
= event
.xselectionrequest
.requestor
;
149 eventSelection
.selection
= event
.xselectionrequest
.selection
;
150 eventSelection
.target
= event
.xselectionrequest
.target
;
151 eventSelection
.property
= event
.xselectionrequest
.property
;
152 eventSelection
.time
= event
.xselectionrequest
.time
;
155 * Notify the requesting window that
156 * the operation has completed
158 iReturn
= XSendEvent(pDisplay
,
159 eventSelection
.requestor
,
160 False
, 0L, (XEvent
*) &eventSelection
);
161 if (iReturn
== BadValue
|| iReturn
== BadWindow
) {
162 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
163 "XSendEvent () failed\n");
168 /* Close clipboard if we have it open already */
169 if (GetOpenClipboardWindow() == hwnd
) {
173 /* Access the clipboard */
174 if (!OpenClipboard(hwnd
)) {
175 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
176 "OpenClipboard () failed: %08lx\n", GetLastError());
180 goto winClipboardFlushXEvents_SelectionRequest_Done
;
183 /* Indicate that clipboard was opened */
184 fCloseClipboard
= TRUE
;
186 /* Check that clipboard format is available */
187 if (fUseUnicode
&& !IsClipboardFormatAvailable(CF_UNICODETEXT
)) {
188 static int count
; /* Hack to stop acroread spamming the log */
189 static HWND lasthwnd
; /* I've not seen any other client get here repeatedly? */
191 if (hwnd
!= lasthwnd
)
195 ErrorF("winClipboardFlushXEvents - CF_UNICODETEXT is not "
196 "available from Win32 clipboard. Aborting %d.\n",
202 goto winClipboardFlushXEvents_SelectionRequest_Done
;
204 else if (!fUseUnicode
&& !IsClipboardFormatAvailable(CF_TEXT
)) {
205 ErrorF("winClipboardFlushXEvents - CF_TEXT is not "
206 "available from Win32 clipboard. Aborting.\n");
210 goto winClipboardFlushXEvents_SelectionRequest_Done
;
213 /* Setup the string style */
214 if (event
.xselectionrequest
.target
== XA_STRING
)
215 xiccesStyle
= XStringStyle
;
216 #ifdef X_HAVE_UTF8_STRING
217 else if (event
.xselectionrequest
.target
== atomUTF8String
)
218 xiccesStyle
= XUTF8StringStyle
;
220 else if (event
.xselectionrequest
.target
== atomCompoundText
)
221 xiccesStyle
= XCompoundTextStyle
;
223 xiccesStyle
= XStringStyle
;
225 /* Get a pointer to the clipboard text, in desired format */
227 /* Retrieve clipboard data */
228 hGlobal
= GetClipboardData(CF_UNICODETEXT
);
231 /* Retrieve clipboard data */
232 hGlobal
= GetClipboardData(CF_TEXT
);
235 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
236 "GetClipboardData () failed: %08lx\n", GetLastError());
240 goto winClipboardFlushXEvents_SelectionRequest_Done
;
242 pszGlobalData
= (char *) GlobalLock(hGlobal
);
244 /* Convert the Unicode string to UTF8 (MBCS) */
246 iConvertDataLen
= WideCharToMultiByte(CP_UTF8
,
248 (LPCWSTR
) pszGlobalData
,
249 -1, NULL
, 0, NULL
, NULL
);
250 /* NOTE: iConvertDataLen includes space for null terminator */
251 pszConvertData
= (char *) malloc(iConvertDataLen
);
252 WideCharToMultiByte(CP_UTF8
,
254 (LPCWSTR
) pszGlobalData
,
257 iConvertDataLen
, NULL
, NULL
);
260 pszConvertData
= strdup(pszGlobalData
);
261 iConvertDataLen
= strlen(pszConvertData
) + 1;
264 /* Convert DOS string to UNIX string */
265 winClipboardDOStoUNIX(pszConvertData
, strlen(pszConvertData
));
267 /* Setup our text list */
268 pszTextList
[0] = pszConvertData
;
269 pszTextList
[1] = NULL
;
271 /* Initialize the text property */
272 xtpText
.value
= NULL
;
275 /* Create the text property from the text list */
277 #ifdef X_HAVE_UTF8_STRING
278 iReturn
= Xutf8TextListToTextProperty(pDisplay
,
280 1, xiccesStyle
, &xtpText
);
284 iReturn
= XmbTextListToTextProperty(pDisplay
,
286 1, xiccesStyle
, &xtpText
);
288 if (iReturn
== XNoMemory
|| iReturn
== XLocaleNotSupported
) {
289 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
290 "X*TextListToTextProperty failed: %d\n", iReturn
);
294 goto winClipboardFlushXEvents_SelectionRequest_Done
;
297 /* Free the converted string */
298 free(pszConvertData
);
299 pszConvertData
= NULL
;
301 /* Copy the clipboard text to the requesting window */
302 iReturn
= XChangeProperty(pDisplay
,
303 event
.xselectionrequest
.requestor
,
304 event
.xselectionrequest
.property
,
305 event
.xselectionrequest
.target
,
308 xtpText
.value
, xtpText
.nitems
);
309 if (iReturn
== BadAlloc
|| iReturn
== BadAtom
310 || iReturn
== BadMatch
|| iReturn
== BadValue
311 || iReturn
== BadWindow
) {
312 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
313 "XChangeProperty failed: %d\n", iReturn
);
317 goto winClipboardFlushXEvents_SelectionRequest_Done
;
320 /* Release the clipboard data */
321 GlobalUnlock(hGlobal
);
322 pszGlobalData
= NULL
;
323 fCloseClipboard
= FALSE
;
327 XFree(xtpText
.value
);
328 xtpText
.value
= NULL
;
331 /* Setup selection notify event */
332 eventSelection
.type
= SelectionNotify
;
333 eventSelection
.send_event
= True
;
334 eventSelection
.display
= pDisplay
;
335 eventSelection
.requestor
= event
.xselectionrequest
.requestor
;
336 eventSelection
.selection
= event
.xselectionrequest
.selection
;
337 eventSelection
.target
= event
.xselectionrequest
.target
;
338 eventSelection
.property
= event
.xselectionrequest
.property
;
339 eventSelection
.time
= event
.xselectionrequest
.time
;
341 /* Notify the requesting window that the operation has completed */
342 iReturn
= XSendEvent(pDisplay
,
343 eventSelection
.requestor
,
344 False
, 0L, (XEvent
*) &eventSelection
);
345 if (iReturn
== BadValue
|| iReturn
== BadWindow
) {
346 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
347 "XSendEvent () failed\n");
351 goto winClipboardFlushXEvents_SelectionRequest_Done
;
354 winClipboardFlushXEvents_SelectionRequest_Done
:
355 /* Free allocated resources */
357 XFree(xtpText
.value
);
358 xtpText
.value
= NULL
;
361 free(pszConvertData
);
362 if (hGlobal
&& pszGlobalData
)
363 GlobalUnlock(hGlobal
);
366 * Send a SelectionNotify event to the requesting
367 * client when we abort.
370 /* Setup selection notify event */
371 eventSelection
.type
= SelectionNotify
;
372 eventSelection
.send_event
= True
;
373 eventSelection
.display
= pDisplay
;
374 eventSelection
.requestor
= event
.xselectionrequest
.requestor
;
375 eventSelection
.selection
= event
.xselectionrequest
.selection
;
376 eventSelection
.target
= event
.xselectionrequest
.target
;
377 eventSelection
.property
= None
;
378 eventSelection
.time
= event
.xselectionrequest
.time
;
380 /* Notify the requesting window that the operation is complete */
381 iReturn
= XSendEvent(pDisplay
,
382 eventSelection
.requestor
,
383 False
, 0L, (XEvent
*) &eventSelection
);
384 if (iReturn
== BadValue
|| iReturn
== BadWindow
) {
386 * Should not be a problem if XSendEvent fails because
387 * the client may simply have exited.
389 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
390 "XSendEvent () failed for abort event.\n");
394 /* Close clipboard if it was opened */
395 if (fCloseClipboard
) {
396 fCloseClipboard
= FALSE
;
405 case SelectionNotify
:
407 winDebug("winClipboardFlushXEvents - SelectionNotify\n");
411 pszAtomName
= XGetAtomName(pDisplay
,
412 event
.xselection
.selection
);
415 ("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n",
421 * Request conversion of UTF8 and CompoundText targets.
423 if (event
.xselection
.property
== None
) {
424 if (event
.xselection
.target
== XA_STRING
) {
425 winDebug("winClipboardFlushXEvents - SelectionNotify - "
428 return WIN_XEVENTS_CONVERT
;
430 else if (event
.xselection
.target
== atomUTF8String
) {
431 winDebug("winClipboardFlushXEvents - SelectionNotify - "
432 "Requesting conversion of UTF8 target.\n");
434 XConvertSelection(pDisplay
,
435 event
.xselection
.selection
,
437 atomLocalProperty
, iWindow
, CurrentTime
);
439 /* Process the ConvertSelection event */
441 return WIN_XEVENTS_CONVERT
;
443 #ifdef X_HAVE_UTF8_STRING
444 else if (event
.xselection
.target
== atomCompoundText
) {
445 winDebug("winClipboardFlushXEvents - SelectionNotify - "
446 "Requesting conversion of CompoundText target.\n");
448 XConvertSelection(pDisplay
,
449 event
.xselection
.selection
,
451 atomLocalProperty
, iWindow
, CurrentTime
);
453 /* Process the ConvertSelection event */
455 return WIN_XEVENTS_CONVERT
;
459 ErrorF("winClipboardFlushXEvents - SelectionNotify - "
460 "Unknown format. Cannot request conversion, "
466 /* Retrieve the size of the stored data */
467 iReturn
= XGetWindowProperty(pDisplay
, iWindow
, atomLocalProperty
, 0, 0, /* Don't get data, just size */
473 &ulReturnBytesLeft
, &xtpText
.value
);
474 if (iReturn
!= Success
) {
475 ErrorF("winClipboardFlushXEvents - SelectionNotify - "
476 "XGetWindowProperty () failed, aborting: %d\n", iReturn
);
480 winDebug("SelectionNotify - returned data %d left %d\n",
481 xtpText
.nitems
, ulReturnBytesLeft
);
483 /* Request the selection data */
484 iReturn
= XGetWindowProperty(pDisplay
,
494 &ulReturnBytesLeft
, &xtpText
.value
);
495 if (iReturn
!= Success
) {
496 ErrorF("winClipboardFlushXEvents - SelectionNotify - "
497 "XGetWindowProperty () failed, aborting: %d\n", iReturn
);
502 char *pszAtomName
= NULL
;
504 winDebug("SelectionNotify - returned data %d left %d\n",
505 xtpText
.nitems
, ulReturnBytesLeft
);
506 pszAtomName
= XGetAtomName(pDisplay
, xtpText
.encoding
);
507 winDebug("Notify atom name %s\n", pszAtomName
);
513 #ifdef X_HAVE_UTF8_STRING
514 /* Convert the text property to a text list */
515 iReturn
= Xutf8TextPropertyToTextList(pDisplay
,
517 &ppszTextList
, &iCount
);
521 iReturn
= XmbTextPropertyToTextList(pDisplay
,
523 &ppszTextList
, &iCount
);
525 if (iReturn
== Success
|| iReturn
> 0) {
526 /* Conversion succeeded or some unconvertible characters */
527 if (ppszTextList
!= NULL
) {
529 for (i
= 0; i
< iCount
; i
++) {
530 iReturnDataLen
+= strlen(ppszTextList
[i
]);
532 pszReturnData
= malloc(iReturnDataLen
+ 1);
533 pszReturnData
[0] = '\0';
534 for (i
= 0; i
< iCount
; i
++) {
535 strcat(pszReturnData
, ppszTextList
[i
]);
539 ErrorF("winClipboardFlushXEvents - SelectionNotify - "
540 "X*TextPropertyToTextList list_return is NULL.\n");
541 pszReturnData
= malloc(1);
542 pszReturnData
[0] = '\0';
546 ErrorF("winClipboardFlushXEvents - SelectionNotify - "
547 "X*TextPropertyToTextList returned: ");
550 ErrorF("XNoMemory\n");
552 case XLocaleNotSupported
:
553 ErrorF("XLocaleNotSupported\n");
555 case XConverterNotFound
:
556 ErrorF("XConverterNotFound\n");
559 ErrorF("%d\n", iReturn
);
562 pszReturnData
= malloc(1);
563 pszReturnData
[0] = '\0';
566 /* Free the data returned from XGetWindowProperty */
568 XFreeStringList(ppszTextList
);
570 XFree(xtpText
.value
);
571 xtpText
.value
= NULL
;
574 /* Convert the X clipboard string to DOS format */
575 winClipboardUNIXtoDOS(&pszReturnData
, strlen(pszReturnData
));
578 /* Find out how much space needed to convert MBCS to Unicode */
579 iUnicodeLen
= MultiByteToWideChar(CP_UTF8
,
581 pszReturnData
, -1, NULL
, 0);
583 /* Allocate memory for the Unicode string */
585 = (wchar_t *) malloc(sizeof(wchar_t) * (iUnicodeLen
+ 1));
586 if (!pwszUnicodeStr
) {
587 ErrorF("winClipboardFlushXEvents - SelectionNotify "
588 "malloc failed for pwszUnicodeStr, aborting.\n");
592 goto winClipboardFlushXEvents_SelectionNotify_Done
;
595 /* Do the actual conversion */
596 MultiByteToWideChar(CP_UTF8
,
599 -1, pwszUnicodeStr
, iUnicodeLen
);
601 /* Allocate global memory for the X clipboard data */
602 hGlobal
= GlobalAlloc(GMEM_MOVEABLE
,
603 sizeof(wchar_t) * (iUnicodeLen
+ 1));
606 pszConvertData
= strdup(pszReturnData
);
607 iConvertDataLen
= strlen(pszConvertData
) + 1;
609 /* Allocate global memory for the X clipboard data */
610 hGlobal
= GlobalAlloc(GMEM_MOVEABLE
, iConvertDataLen
);
615 /* Check that global memory was allocated */
617 ErrorF("winClipboardFlushXEvents - SelectionNotify "
618 "GlobalAlloc failed, aborting: %ld\n", GetLastError());
622 goto winClipboardFlushXEvents_SelectionNotify_Done
;
625 /* Obtain a pointer to the global memory */
626 pszGlobalData
= GlobalLock(hGlobal
);
627 if (pszGlobalData
== NULL
) {
628 ErrorF("winClipboardFlushXEvents - Could not lock global "
629 "memory for clipboard transfer\n");
633 goto winClipboardFlushXEvents_SelectionNotify_Done
;
636 /* Copy the returned string into the global memory */
638 memcpy(pszGlobalData
,
639 pwszUnicodeStr
, sizeof(wchar_t) * (iUnicodeLen
+ 1));
640 free(pwszUnicodeStr
);
641 pwszUnicodeStr
= NULL
;
644 strcpy(pszGlobalData
, pszConvertData
);
645 free(pszConvertData
);
646 pszConvertData
= NULL
;
649 /* Release the pointer to the global memory */
650 GlobalUnlock(hGlobal
);
651 pszGlobalData
= NULL
;
653 /* Push the selection data to the Windows clipboard */
655 SetClipboardData(CF_UNICODETEXT
, hGlobal
);
657 SetClipboardData(CF_TEXT
, hGlobal
);
659 /* Flag that SetClipboardData has been called */
660 fSetClipboardData
= FALSE
;
663 * NOTE: Do not try to free pszGlobalData, it is owned by
664 * Windows after the call to SetClipboardData ().
667 winClipboardFlushXEvents_SelectionNotify_Done
:
668 /* Free allocated resources */
670 XFreeStringList(ppszTextList
);
672 XFree(xtpText
.value
);
673 xtpText
.value
= NULL
;
676 free(pszConvertData
);
677 free(pwszUnicodeStr
);
678 if (hGlobal
&& pszGlobalData
)
679 GlobalUnlock(hGlobal
);
680 if (fSetClipboardData
) {
681 SetClipboardData(CF_UNICODETEXT
, NULL
);
682 SetClipboardData(CF_TEXT
, NULL
);
684 return WIN_XEVENTS_NOTIFY
;
687 winDebug("SelectionClear - doing nothing\n");
697 ErrorF("winClipboardFlushXEvents - unexpected event type %d\n",
703 return WIN_XEVENTS_SUCCESS
;