hw/xwin: Implement INCR protocol for X clipboard -> Windows clipboard
Also, relax the timeout mechanism so it allows 1 second between events, rather than 1 second for the entire transfer, as transfers of large pastes can take more than 1 second. Also, prefer UTF8_STRING encoding to COMPOUND_TEXT encoding
This commit is contained in:
parent
4f95d87d66
commit
56a91f2067
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
|
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
|
||||||
*
|
*
|
||||||
|
@ -38,7 +37,7 @@
|
||||||
/* Windows headers */
|
/* Windows headers */
|
||||||
#include <X11/Xwindows.h>
|
#include <X11/Xwindows.h>
|
||||||
|
|
||||||
#define WIN_XEVENTS_SUCCESS 0
|
#define WIN_XEVENTS_SUCCESS 0 // more like 'CONTINUE'
|
||||||
#define WIN_XEVENTS_FAILED 1
|
#define WIN_XEVENTS_FAILED 1
|
||||||
#define WIN_XEVENTS_NOTIFY_DATA 3
|
#define WIN_XEVENTS_NOTIFY_DATA 3
|
||||||
#define WIN_XEVENTS_NOTIFY_TARGETS 4
|
#define WIN_XEVENTS_NOTIFY_TARGETS 4
|
||||||
|
@ -77,6 +76,7 @@ typedef struct
|
||||||
Atom atomUTF8String;
|
Atom atomUTF8String;
|
||||||
Atom atomCompoundText;
|
Atom atomCompoundText;
|
||||||
Atom atomTargets;
|
Atom atomTargets;
|
||||||
|
Atom atomIncr;
|
||||||
} ClipboardAtoms;
|
} ClipboardAtoms;
|
||||||
|
|
||||||
/* Modern clipboard API functions */
|
/* Modern clipboard API functions */
|
||||||
|
@ -111,6 +111,8 @@ typedef struct
|
||||||
{
|
{
|
||||||
Bool fUseUnicode;
|
Bool fUseUnicode;
|
||||||
Atom *targetList;
|
Atom *targetList;
|
||||||
|
unsigned char *incr;
|
||||||
|
unsigned long int incrsize;
|
||||||
} ClipboardConversionData;
|
} ClipboardConversionData;
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -199,6 +199,7 @@ winClipboardProc(Bool fUseUnicode, char *szDisplay)
|
||||||
atoms.atomUTF8String = XInternAtom (pDisplay, "UTF8_STRING", False);
|
atoms.atomUTF8String = XInternAtom (pDisplay, "UTF8_STRING", False);
|
||||||
atoms.atomCompoundText = XInternAtom (pDisplay, "COMPOUND_TEXT", False);
|
atoms.atomCompoundText = XInternAtom (pDisplay, "COMPOUND_TEXT", False);
|
||||||
atoms.atomTargets = XInternAtom (pDisplay, "TARGETS", False);
|
atoms.atomTargets = XInternAtom (pDisplay, "TARGETS", False);
|
||||||
|
atoms.atomIncr = XInternAtom (pDisplay, "INCR", False);
|
||||||
|
|
||||||
/* Create a messaging window */
|
/* Create a messaging window */
|
||||||
iWindow = XCreateSimpleWindow(pDisplay,
|
iWindow = XCreateSimpleWindow(pDisplay,
|
||||||
|
@ -265,6 +266,8 @@ winClipboardProc(Bool fUseUnicode, char *szDisplay)
|
||||||
}
|
}
|
||||||
|
|
||||||
data.fUseUnicode = fUseUnicode;
|
data.fUseUnicode = fUseUnicode;
|
||||||
|
data.incr = NULL;
|
||||||
|
data.incrsize = 0;
|
||||||
|
|
||||||
/* Loop for events */
|
/* Loop for events */
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
|
@ -73,9 +73,8 @@ winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay,
|
||||||
int iConnNumber;
|
int iConnNumber;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
int iReturn;
|
int iReturn;
|
||||||
DWORD dwStopTime = GetTickCount() + iTimeoutSec * 1000;
|
|
||||||
|
|
||||||
winDebug("winProcessXEventsTimeout () - pumping X events for %d seconds\n",
|
winDebug("winProcessXEventsTimeout () - pumping X events, timeout %d seconds\n",
|
||||||
iTimeoutSec);
|
iTimeoutSec);
|
||||||
|
|
||||||
/* Get our connection number */
|
/* Get our connection number */
|
||||||
|
@ -104,11 +103,9 @@ winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay,
|
||||||
FD_SET(iConnNumber, &fdsRead);
|
FD_SET(iConnNumber, &fdsRead);
|
||||||
|
|
||||||
/* Adjust timeout */
|
/* Adjust timeout */
|
||||||
remainingTime = dwStopTime - GetTickCount();
|
remainingTime = iTimeoutSec * 1000;
|
||||||
tv.tv_sec = remainingTime / 1000;
|
tv.tv_sec = remainingTime / 1000;
|
||||||
tv.tv_usec = (remainingTime % 1000) * 1000;
|
tv.tv_usec = (remainingTime % 1000) * 1000;
|
||||||
winDebug("winProcessXEventsTimeout () - %ld milliseconds left\n",
|
|
||||||
remainingTime);
|
|
||||||
|
|
||||||
/* Break out if no time left */
|
/* Break out if no time left */
|
||||||
if (remainingTime <= 0)
|
if (remainingTime <= 0)
|
||||||
|
@ -494,6 +491,9 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
|
||||||
/* Process X events */
|
/* Process X events */
|
||||||
data.fUseUnicode = fConvertToUnicode;
|
data.fUseUnicode = fConvertToUnicode;
|
||||||
|
data.incr = NULL;
|
||||||
|
data.incrsize = 0;
|
||||||
|
|
||||||
iReturn = winProcessXEventsTimeout(hwnd,
|
iReturn = winProcessXEventsTimeout(hwnd,
|
||||||
iWindow,
|
iWindow,
|
||||||
pDisplay,
|
pDisplay,
|
||||||
|
@ -517,10 +517,10 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
|
||||||
struct target_priority target_priority_table[] =
|
struct target_priority target_priority_table[] =
|
||||||
{
|
{
|
||||||
{ atoms->atomCompoundText, 0 },
|
|
||||||
#ifdef X_HAVE_UTF8_STRING
|
#ifdef X_HAVE_UTF8_STRING
|
||||||
{ atoms->atomUTF8String, 1 },
|
{ atoms->atomUTF8String, 0 },
|
||||||
#endif
|
#endif
|
||||||
|
{ atoms->atomCompoundText, 1 },
|
||||||
{ XA_STRING, 2 },
|
{ XA_STRING, 2 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -184,6 +184,271 @@ winClipboardSelectionNotifyTargets(HWND hwnd, Window iWindow, Display *pDisplay,
|
||||||
return WIN_XEVENTS_NOTIFY_TARGETS;
|
return WIN_XEVENTS_NOTIFY_TARGETS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms)
|
||||||
|
{
|
||||||
|
Atom encoding;
|
||||||
|
int format;
|
||||||
|
unsigned long int nitems;
|
||||||
|
unsigned long int after;
|
||||||
|
unsigned char *value;
|
||||||
|
XTextProperty xtpText = { 0 };
|
||||||
|
Bool fSetClipboardData = TRUE;
|
||||||
|
int iReturn;
|
||||||
|
char **ppszTextList = NULL;
|
||||||
|
int iCount;
|
||||||
|
char *pszReturnData = NULL;
|
||||||
|
wchar_t *pwszUnicodeStr = NULL;
|
||||||
|
HGLOBAL hGlobal = NULL;
|
||||||
|
char *pszConvertData = NULL;
|
||||||
|
char *pszGlobalData = NULL;
|
||||||
|
|
||||||
|
/* Retrieve the selection data and delete the property */
|
||||||
|
iReturn = XGetWindowProperty(pDisplay,
|
||||||
|
iWindow,
|
||||||
|
atoms->atomLocalProperty,
|
||||||
|
0,
|
||||||
|
INT_MAX,
|
||||||
|
True,
|
||||||
|
AnyPropertyType,
|
||||||
|
&encoding,
|
||||||
|
&format,
|
||||||
|
&nitems,
|
||||||
|
&after,
|
||||||
|
&value);
|
||||||
|
if (iReturn != Success) {
|
||||||
|
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
|
||||||
|
"XGetWindowProperty () failed, aborting: %d\n", iReturn);
|
||||||
|
goto winClipboardFlushXEvents_SelectionNotify_Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char *pszAtomName = NULL;
|
||||||
|
|
||||||
|
winDebug("SelectionNotify - returned data %lu left %lu\n", nitems, after);
|
||||||
|
pszAtomName = XGetAtomName(pDisplay, encoding);
|
||||||
|
winDebug("Notify atom name %s\n", pszAtomName);
|
||||||
|
XFree(pszAtomName);
|
||||||
|
pszAtomName = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* INCR reply indicates the start of a incremental transfer */
|
||||||
|
if (encoding == atoms->atomIncr) {
|
||||||
|
winDebug("winClipboardSelectionNotifyData: starting INCR, anticipated size %d\n", *(int *)value);
|
||||||
|
data->incrsize = 0;
|
||||||
|
data->incr = malloc(*(int *)value);
|
||||||
|
// XXX: if malloc failed, we have an error
|
||||||
|
return WIN_XEVENTS_SUCCESS;
|
||||||
|
}
|
||||||
|
else if (data->incr) {
|
||||||
|
/* If an INCR transfer is in progress ... */
|
||||||
|
if (nitems == 0) {
|
||||||
|
winDebug("winClipboardSelectionNotifyData: ending INCR, actual size %ld\n", data->incrsize);
|
||||||
|
/* a zero-length property indicates the end of the data */
|
||||||
|
xtpText.value = data->incr;
|
||||||
|
xtpText.encoding = encoding;
|
||||||
|
xtpText.format = format; // XXX: The type of the converted selection is the type of the first partial property. The remaining partial properties must have the same type.
|
||||||
|
xtpText.nitems = data->incrsize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Otherwise, continue appending the INCR data */
|
||||||
|
winDebug("winClipboardSelectionNotifyData: INCR, %ld bytes\n", nitems);
|
||||||
|
data->incr = realloc(data->incr, data->incrsize + nitems);
|
||||||
|
memcpy(data->incr + data->incrsize, value, nitems);
|
||||||
|
data->incrsize = data->incrsize + nitems;
|
||||||
|
return WIN_XEVENTS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Otherwise, the data is just contained in the property */
|
||||||
|
winDebug("winClipboardSelectionNotifyData: non-INCR, %ld bytes\n", nitems);
|
||||||
|
xtpText.value = value;
|
||||||
|
xtpText.encoding = encoding;
|
||||||
|
xtpText.format = format;
|
||||||
|
xtpText.nitems = nitems;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->fUseUnicode) {
|
||||||
|
#ifdef X_HAVE_UTF8_STRING
|
||||||
|
/* Convert the text property to a text list */
|
||||||
|
iReturn = Xutf8TextPropertyToTextList(pDisplay,
|
||||||
|
&xtpText,
|
||||||
|
&ppszTextList, &iCount);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
iReturn = XmbTextPropertyToTextList(pDisplay,
|
||||||
|
&xtpText,
|
||||||
|
&ppszTextList, &iCount);
|
||||||
|
}
|
||||||
|
if (iReturn == Success || iReturn > 0) {
|
||||||
|
/* Conversion succeeded or some unconvertible characters */
|
||||||
|
if (ppszTextList != NULL) {
|
||||||
|
int i;
|
||||||
|
int iReturnDataLen = 0;
|
||||||
|
for (i = 0; i < iCount; i++) {
|
||||||
|
iReturnDataLen += strlen(ppszTextList[i]);
|
||||||
|
}
|
||||||
|
pszReturnData = malloc(iReturnDataLen + 1);
|
||||||
|
pszReturnData[0] = '\0';
|
||||||
|
for (i = 0; i < iCount; i++) {
|
||||||
|
strcat(pszReturnData, ppszTextList[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
|
||||||
|
"X*TextPropertyToTextList list_return is NULL.\n");
|
||||||
|
pszReturnData = malloc(1);
|
||||||
|
pszReturnData[0] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
|
||||||
|
"X*TextPropertyToTextList returned: ");
|
||||||
|
switch (iReturn) {
|
||||||
|
case XNoMemory:
|
||||||
|
ErrorF("XNoMemory\n");
|
||||||
|
break;
|
||||||
|
case XLocaleNotSupported:
|
||||||
|
ErrorF("XLocaleNotSupported\n");
|
||||||
|
break;
|
||||||
|
case XConverterNotFound:
|
||||||
|
ErrorF("XConverterNotFound\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ErrorF("%d\n", iReturn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pszReturnData = malloc(1);
|
||||||
|
pszReturnData[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (ppszTextList)
|
||||||
|
XFreeStringList(ppszTextList);
|
||||||
|
ppszTextList = NULL;
|
||||||
|
|
||||||
|
/* Free the data returned from XGetWindowProperty */
|
||||||
|
XFree(value);
|
||||||
|
value = NULL;
|
||||||
|
nitems = 0;
|
||||||
|
|
||||||
|
/* Free any INCR data */
|
||||||
|
if (data->incr) {
|
||||||
|
free(data->incr);
|
||||||
|
data->incr = NULL;
|
||||||
|
data->incrsize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert the X clipboard string to DOS format */
|
||||||
|
winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData));
|
||||||
|
|
||||||
|
if (data->fUseUnicode) {
|
||||||
|
/* Find out how much space needed to convert MBCS to Unicode */
|
||||||
|
int iUnicodeLen = MultiByteToWideChar(CP_UTF8,
|
||||||
|
0,
|
||||||
|
pszReturnData, -1, NULL, 0);
|
||||||
|
|
||||||
|
/* NOTE: iUnicodeLen includes space for null terminator */
|
||||||
|
pwszUnicodeStr = malloc(sizeof(wchar_t) * iUnicodeLen);
|
||||||
|
if (!pwszUnicodeStr) {
|
||||||
|
ErrorF("winClipboardFlushXEvents - SelectionNotify "
|
||||||
|
"malloc failed for pwszUnicodeStr, aborting.\n");
|
||||||
|
|
||||||
|
/* Abort */
|
||||||
|
goto winClipboardFlushXEvents_SelectionNotify_Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do the actual conversion */
|
||||||
|
MultiByteToWideChar(CP_UTF8,
|
||||||
|
0,
|
||||||
|
pszReturnData,
|
||||||
|
-1, pwszUnicodeStr, iUnicodeLen);
|
||||||
|
|
||||||
|
/* Allocate global memory for the X clipboard data */
|
||||||
|
hGlobal = GlobalAlloc(GMEM_MOVEABLE,
|
||||||
|
sizeof(wchar_t) * iUnicodeLen);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int iConvertDataLen = 0;
|
||||||
|
pszConvertData = strdup(pszReturnData);
|
||||||
|
iConvertDataLen = strlen(pszConvertData) + 1;
|
||||||
|
|
||||||
|
/* Allocate global memory for the X clipboard data */
|
||||||
|
hGlobal = GlobalAlloc(GMEM_MOVEABLE, iConvertDataLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pszReturnData);
|
||||||
|
|
||||||
|
/* Check that global memory was allocated */
|
||||||
|
if (!hGlobal) {
|
||||||
|
ErrorF("winClipboardFlushXEvents - SelectionNotify "
|
||||||
|
"GlobalAlloc failed, aborting: %08x\n", (unsigned int)GetLastError());
|
||||||
|
|
||||||
|
/* Abort */
|
||||||
|
goto winClipboardFlushXEvents_SelectionNotify_Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Obtain a pointer to the global memory */
|
||||||
|
pszGlobalData = GlobalLock(hGlobal);
|
||||||
|
if (pszGlobalData == NULL) {
|
||||||
|
ErrorF("winClipboardFlushXEvents - Could not lock global "
|
||||||
|
"memory for clipboard transfer\n");
|
||||||
|
|
||||||
|
/* Abort */
|
||||||
|
goto winClipboardFlushXEvents_SelectionNotify_Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the returned string into the global memory */
|
||||||
|
if (data->fUseUnicode) {
|
||||||
|
wcscpy((wchar_t *)pszGlobalData, pwszUnicodeStr);
|
||||||
|
free(pwszUnicodeStr);
|
||||||
|
pwszUnicodeStr = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strcpy(pszGlobalData, pszConvertData);
|
||||||
|
free(pszConvertData);
|
||||||
|
pszConvertData = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the pointer to the global memory */
|
||||||
|
GlobalUnlock(hGlobal);
|
||||||
|
pszGlobalData = NULL;
|
||||||
|
|
||||||
|
/* Push the selection data to the Windows clipboard */
|
||||||
|
if (data->fUseUnicode)
|
||||||
|
SetClipboardData(CF_UNICODETEXT, hGlobal);
|
||||||
|
else
|
||||||
|
SetClipboardData(CF_TEXT, hGlobal);
|
||||||
|
|
||||||
|
/* Flag that SetClipboardData has been called */
|
||||||
|
fSetClipboardData = FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: Do not try to free pszGlobalData, it is owned by
|
||||||
|
* Windows after the call to SetClipboardData ().
|
||||||
|
*/
|
||||||
|
|
||||||
|
winClipboardFlushXEvents_SelectionNotify_Done:
|
||||||
|
/* Free allocated resources */
|
||||||
|
if (ppszTextList)
|
||||||
|
XFreeStringList(ppszTextList);
|
||||||
|
if (value) {
|
||||||
|
XFree(value);
|
||||||
|
value = NULL;
|
||||||
|
nitems = 0;
|
||||||
|
}
|
||||||
|
free(pszConvertData);
|
||||||
|
free(pwszUnicodeStr);
|
||||||
|
if (hGlobal && pszGlobalData)
|
||||||
|
GlobalUnlock(hGlobal);
|
||||||
|
if (fSetClipboardData) {
|
||||||
|
SetClipboardData(CF_UNICODETEXT, NULL);
|
||||||
|
SetClipboardData(CF_TEXT, NULL);
|
||||||
|
}
|
||||||
|
return WIN_XEVENTS_NOTIFY_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process any pending X events
|
* Process any pending X events
|
||||||
*/
|
*/
|
||||||
|
@ -193,7 +458,6 @@ winClipboardFlushXEvents(HWND hwnd,
|
||||||
Window iWindow, Display * pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms)
|
Window iWindow, Display * pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms)
|
||||||
{
|
{
|
||||||
Atom atomClipboard = atoms->atomClipboard;
|
Atom atomClipboard = atoms->atomClipboard;
|
||||||
Atom atomLocalProperty = atoms->atomLocalProperty;
|
|
||||||
Atom atomUTF8String = atoms->atomUTF8String;
|
Atom atomUTF8String = atoms->atomUTF8String;
|
||||||
Atom atomCompoundText = atoms->atomCompoundText;
|
Atom atomCompoundText = atoms->atomCompoundText;
|
||||||
Atom atomTargets = atoms->atomTargets;
|
Atom atomTargets = atoms->atomTargets;
|
||||||
|
@ -203,20 +467,14 @@ winClipboardFlushXEvents(HWND hwnd,
|
||||||
XTextProperty xtpText = { 0 };
|
XTextProperty xtpText = { 0 };
|
||||||
XEvent event;
|
XEvent event;
|
||||||
XSelectionEvent eventSelection;
|
XSelectionEvent eventSelection;
|
||||||
unsigned long ulReturnBytesLeft;
|
|
||||||
char *pszReturnData = NULL;
|
|
||||||
char *pszGlobalData = NULL;
|
char *pszGlobalData = NULL;
|
||||||
int iReturn;
|
int iReturn;
|
||||||
HGLOBAL hGlobal = NULL;
|
HGLOBAL hGlobal = NULL;
|
||||||
XICCEncodingStyle xiccesStyle;
|
XICCEncodingStyle xiccesStyle;
|
||||||
char *pszConvertData = NULL;
|
char *pszConvertData = NULL;
|
||||||
char *pszTextList[2] = { NULL };
|
char *pszTextList[2] = { NULL };
|
||||||
int iCount;
|
|
||||||
char **ppszTextList = NULL;
|
|
||||||
wchar_t *pwszUnicodeStr = NULL;
|
|
||||||
Bool fAbort = FALSE;
|
Bool fAbort = FALSE;
|
||||||
Bool fCloseClipboard = FALSE;
|
Bool fCloseClipboard = FALSE;
|
||||||
Bool fSetClipboardData = TRUE;
|
|
||||||
|
|
||||||
/* Get the next event - will not block because one is ready */
|
/* Get the next event - will not block because one is ready */
|
||||||
XNextEvent(pDisplay, &event);
|
XNextEvent(pDisplay, &event);
|
||||||
|
@ -569,214 +827,19 @@ winClipboardFlushXEvents(HWND hwnd,
|
||||||
return winClipboardSelectionNotifyTargets(hwnd, iWindow, pDisplay, data, atoms);
|
return winClipboardSelectionNotifyTargets(hwnd, iWindow, pDisplay, data, atoms);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve the selection data and delete the property */
|
return winClipboardSelectionNotifyData(hwnd, iWindow, pDisplay, data, atoms);
|
||||||
iReturn = XGetWindowProperty(pDisplay,
|
|
||||||
iWindow,
|
|
||||||
atomLocalProperty,
|
|
||||||
0,
|
|
||||||
INT_MAX,
|
|
||||||
True,
|
|
||||||
AnyPropertyType,
|
|
||||||
&xtpText.encoding,
|
|
||||||
&xtpText.format,
|
|
||||||
&xtpText.nitems,
|
|
||||||
&ulReturnBytesLeft, &xtpText.value);
|
|
||||||
if (iReturn != Success) {
|
|
||||||
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
|
|
||||||
"XGetWindowProperty () failed, aborting: %d\n", iReturn);
|
|
||||||
goto winClipboardFlushXEvents_SelectionNotify_Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
char *pszAtomName = NULL;
|
|
||||||
|
|
||||||
winDebug("SelectionNotify - returned data %lu left %lu\n",
|
|
||||||
xtpText.nitems, ulReturnBytesLeft);
|
|
||||||
pszAtomName = XGetAtomName(pDisplay, xtpText.encoding);
|
|
||||||
winDebug("Notify atom name %s\n", pszAtomName);
|
|
||||||
XFree(pszAtomName);
|
|
||||||
pszAtomName = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data->fUseUnicode) {
|
|
||||||
#ifdef X_HAVE_UTF8_STRING
|
|
||||||
/* Convert the text property to a text list */
|
|
||||||
iReturn = Xutf8TextPropertyToTextList(pDisplay,
|
|
||||||
&xtpText,
|
|
||||||
&ppszTextList, &iCount);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
iReturn = XmbTextPropertyToTextList(pDisplay,
|
|
||||||
&xtpText,
|
|
||||||
&ppszTextList, &iCount);
|
|
||||||
}
|
|
||||||
if (iReturn == Success || iReturn > 0) {
|
|
||||||
/* Conversion succeeded or some unconvertible characters */
|
|
||||||
if (ppszTextList != NULL) {
|
|
||||||
int i;
|
|
||||||
int iReturnDataLen = 0;
|
|
||||||
for (i = 0; i < iCount; i++) {
|
|
||||||
iReturnDataLen += strlen(ppszTextList[i]);
|
|
||||||
}
|
|
||||||
pszReturnData = malloc(iReturnDataLen + 1);
|
|
||||||
pszReturnData[0] = '\0';
|
|
||||||
for (i = 0; i < iCount; i++) {
|
|
||||||
strcat(pszReturnData, ppszTextList[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
|
|
||||||
"X*TextPropertyToTextList list_return is NULL.\n");
|
|
||||||
pszReturnData = malloc(1);
|
|
||||||
pszReturnData[0] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
|
|
||||||
"X*TextPropertyToTextList returned: ");
|
|
||||||
switch (iReturn) {
|
|
||||||
case XNoMemory:
|
|
||||||
ErrorF("XNoMemory\n");
|
|
||||||
break;
|
|
||||||
case XLocaleNotSupported:
|
|
||||||
ErrorF("XLocaleNotSupported\n");
|
|
||||||
break;
|
|
||||||
case XConverterNotFound:
|
|
||||||
ErrorF("XConverterNotFound\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ErrorF("%d\n", iReturn);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pszReturnData = malloc(1);
|
|
||||||
pszReturnData[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free the data returned from XGetWindowProperty */
|
|
||||||
if (ppszTextList)
|
|
||||||
XFreeStringList(ppszTextList);
|
|
||||||
ppszTextList = NULL;
|
|
||||||
XFree(xtpText.value);
|
|
||||||
xtpText.value = NULL;
|
|
||||||
xtpText.nitems = 0;
|
|
||||||
|
|
||||||
/* Convert the X clipboard string to DOS format */
|
|
||||||
winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData));
|
|
||||||
|
|
||||||
if (data->fUseUnicode) {
|
|
||||||
/* Find out how much space needed to convert MBCS to Unicode */
|
|
||||||
int iUnicodeLen = MultiByteToWideChar(CP_UTF8,
|
|
||||||
0,
|
|
||||||
pszReturnData, -1, NULL, 0);
|
|
||||||
|
|
||||||
/* NOTE: iUnicodeLen includes space for null terminator */
|
|
||||||
pwszUnicodeStr = malloc(sizeof(wchar_t) * iUnicodeLen);
|
|
||||||
if (!pwszUnicodeStr) {
|
|
||||||
ErrorF("winClipboardFlushXEvents - SelectionNotify "
|
|
||||||
"malloc failed for pwszUnicodeStr, aborting.\n");
|
|
||||||
|
|
||||||
/* Abort */
|
|
||||||
fAbort = TRUE;
|
|
||||||
goto winClipboardFlushXEvents_SelectionNotify_Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do the actual conversion */
|
|
||||||
MultiByteToWideChar(CP_UTF8,
|
|
||||||
0,
|
|
||||||
pszReturnData,
|
|
||||||
-1, pwszUnicodeStr, iUnicodeLen);
|
|
||||||
|
|
||||||
/* Allocate global memory for the X clipboard data */
|
|
||||||
hGlobal = GlobalAlloc(GMEM_MOVEABLE,
|
|
||||||
sizeof(wchar_t) * iUnicodeLen);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int iConvertDataLen = 0;
|
|
||||||
pszConvertData = strdup(pszReturnData);
|
|
||||||
iConvertDataLen = strlen(pszConvertData) + 1;
|
|
||||||
|
|
||||||
/* Allocate global memory for the X clipboard data */
|
|
||||||
hGlobal = GlobalAlloc(GMEM_MOVEABLE, iConvertDataLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(pszReturnData);
|
|
||||||
|
|
||||||
/* Check that global memory was allocated */
|
|
||||||
if (!hGlobal) {
|
|
||||||
ErrorF("winClipboardFlushXEvents - SelectionNotify "
|
|
||||||
"GlobalAlloc failed, aborting: %08x\n", (unsigned int)GetLastError());
|
|
||||||
|
|
||||||
/* Abort */
|
|
||||||
fAbort = TRUE;
|
|
||||||
goto winClipboardFlushXEvents_SelectionNotify_Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Obtain a pointer to the global memory */
|
|
||||||
pszGlobalData = GlobalLock(hGlobal);
|
|
||||||
if (pszGlobalData == NULL) {
|
|
||||||
ErrorF("winClipboardFlushXEvents - Could not lock global "
|
|
||||||
"memory for clipboard transfer\n");
|
|
||||||
|
|
||||||
/* Abort */
|
|
||||||
fAbort = TRUE;
|
|
||||||
goto winClipboardFlushXEvents_SelectionNotify_Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy the returned string into the global memory */
|
|
||||||
if (data->fUseUnicode) {
|
|
||||||
wcscpy((wchar_t *)pszGlobalData, pwszUnicodeStr);
|
|
||||||
free(pwszUnicodeStr);
|
|
||||||
pwszUnicodeStr = NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
strcpy(pszGlobalData, pszConvertData);
|
|
||||||
free(pszConvertData);
|
|
||||||
pszConvertData = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release the pointer to the global memory */
|
|
||||||
GlobalUnlock(hGlobal);
|
|
||||||
pszGlobalData = NULL;
|
|
||||||
|
|
||||||
/* Push the selection data to the Windows clipboard */
|
|
||||||
if (data->fUseUnicode)
|
|
||||||
SetClipboardData(CF_UNICODETEXT, hGlobal);
|
|
||||||
else
|
|
||||||
SetClipboardData(CF_TEXT, hGlobal);
|
|
||||||
|
|
||||||
/* Flag that SetClipboardData has been called */
|
|
||||||
fSetClipboardData = FALSE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE: Do not try to free pszGlobalData, it is owned by
|
|
||||||
* Windows after the call to SetClipboardData ().
|
|
||||||
*/
|
|
||||||
|
|
||||||
winClipboardFlushXEvents_SelectionNotify_Done:
|
|
||||||
/* Free allocated resources */
|
|
||||||
if (ppszTextList)
|
|
||||||
XFreeStringList(ppszTextList);
|
|
||||||
if (xtpText.value) {
|
|
||||||
XFree(xtpText.value);
|
|
||||||
xtpText.value = NULL;
|
|
||||||
xtpText.nitems = 0;
|
|
||||||
}
|
|
||||||
free(pszConvertData);
|
|
||||||
free(pwszUnicodeStr);
|
|
||||||
if (hGlobal && pszGlobalData)
|
|
||||||
GlobalUnlock(hGlobal);
|
|
||||||
if (fSetClipboardData) {
|
|
||||||
SetClipboardData(CF_UNICODETEXT, NULL);
|
|
||||||
SetClipboardData(CF_TEXT, NULL);
|
|
||||||
}
|
|
||||||
return WIN_XEVENTS_NOTIFY_DATA;
|
|
||||||
|
|
||||||
case SelectionClear:
|
case SelectionClear:
|
||||||
winDebug("SelectionClear - doing nothing\n");
|
winDebug("SelectionClear - doing nothing\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyNotify:
|
case PropertyNotify:
|
||||||
|
/* If INCR is in progress, collect the data */
|
||||||
|
if (data->incr &&
|
||||||
|
(event.xproperty.atom == atoms->atomLocalProperty) &&
|
||||||
|
(event.xproperty.state == PropertyNewValue))
|
||||||
|
return winClipboardSelectionNotifyData(hwnd, iWindow, pDisplay, data, atoms);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MappingNotify:
|
case MappingNotify:
|
||||||
|
|
|
@ -39,8 +39,8 @@ XWin(1)
|
||||||
.SH BUGS
|
.SH BUGS
|
||||||
Only text clipboard contents are supported.
|
Only text clipboard contents are supported.
|
||||||
|
|
||||||
The INCR (Incrememntal transfer) clipboard protocol for clipboard contents larger than the maximum size of an
|
The INCR (Incremental transfer) clipboard protocol for clipboard contents larger than the maximum size of an X
|
||||||
X request is not supported.
|
request (approximately 256K) is only supported for X -> Windows clipboard transfers.
|
||||||
|
|
||||||
Some X clients, notably ones written in Tcl/Tk, do not re-assert ownership of the PRIMARY selection or update
|
Some X clients, notably ones written in Tcl/Tk, do not re-assert ownership of the PRIMARY selection or update
|
||||||
it's timestamp when it's contents change, which currently prevents \fIxwinclip\fP from correctly noticing that
|
it's timestamp when it's contents change, which currently prevents \fIxwinclip\fP from correctly noticing that
|
||||||
|
@ -49,7 +49,8 @@ the PRIMARY selection's contents have changed.
|
||||||
Windows clipboard rendering is synchronous in the WM_RENDER*FORMAT message (that is, we must have placed the
|
Windows clipboard rendering is synchronous in the WM_RENDER*FORMAT message (that is, we must have placed the
|
||||||
contents onto the clipboard by the time we return from processing this message), but we must wait for the X
|
contents onto the clipboard by the time we return from processing this message), but we must wait for the X
|
||||||
client which owns the selection to convert the selection to our requested format. This is currently achieved
|
client which owns the selection to convert the selection to our requested format. This is currently achieved
|
||||||
using a fixed timeout of one second.
|
using a fixed timeout. After requesting conversion of the selection, if no events are received from the X
|
||||||
|
client which owns the selection for one second, the conversion is assumed to have failed.
|
||||||
|
|
||||||
The XWin(1) server should indicate somehow (by placing an atom on the root window?) that it is running with it's
|
The XWin(1) server should indicate somehow (by placing an atom on the root window?) that it is running with it's
|
||||||
internal clipboard integration enabled, and xwinclip should notice this and exit with an appropriate error.
|
internal clipboard integration enabled, and xwinclip should notice this and exit with an appropriate error.
|
||||||
|
|
Loading…
Reference in New Issue