summaryrefslogtreecommitdiff
path: root/tk/unix/tkUnixSelect.c
diff options
context:
space:
mode:
Diffstat (limited to 'tk/unix/tkUnixSelect.c')
-rw-r--r--tk/unix/tkUnixSelect.c566
1 files changed, 442 insertions, 124 deletions
diff --git a/tk/unix/tkUnixSelect.c b/tk/unix/tkUnixSelect.c
index e42da31d91c..d240b1e0f40 100644
--- a/tk/unix/tkUnixSelect.c
+++ b/tk/unix/tkUnixSelect.c
@@ -4,7 +4,7 @@
* This file contains X specific routines for manipulating
* selections.
*
- * Copyright (c) 1995 Sun Microsystems, Inc.
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -15,6 +15,19 @@
#include "tkInt.h"
#include "tkSelect.h"
+typedef struct ConvertInfo {
+ int offset; /* The starting byte offset into the selection
+ * for the next chunk; -1 means all data has
+ * been transferred for this conversion. -2
+ * means only the final zero-length transfer
+ * still has to be done. Otherwise it is the
+ * offset of the next chunk of data to
+ * transfer. */
+ Tcl_EncodingState state; /* The encoding state needed across chunks. */
+ char buffer[TCL_UTF_MAX]; /* A buffer to hold part of a UTF character
+ * that is split across chunks.*/
+} ConvertInfo;
+
/*
* When handling INCR-style selection retrievals, the selection owner
* uses the following data structure to communicate between the
@@ -31,17 +44,21 @@ typedef struct IncrInfo {
* MULTIPLE retrievals) or to a static
* array. */
unsigned long numConversions;
- /* Number of entries in offsets (same as
+ /* Number of entries in converts (same as
* # of pairs in multAtoms). */
- int *offsets; /* One entry for each pair in
- * multAtoms; -1 means all data has
- * been transferred for this
- * conversion. -2 means only the
- * final zero-length transfer still
- * has to be done. Otherwise it is the
- * offset of the next chunk of data
- * to transfer. This array is malloc-ed. */
- int numIncrs; /* Number of entries in offsets that
+ ConvertInfo *converts; /* One entry for each pair in multAtoms.
+ * This array is malloc-ed. */
+ char **tempBufs; /* One pointer for each pair in multAtoms;
+ * each pointer is either NULL, or it points
+ * to a small bit of character data that was
+ * left over from the previous chunk. */
+ Tcl_EncodingState *state; /* One state info per pair in multAtoms:
+ * State info for encoding conversions
+ * that span multiple buffers. */
+ int *flags; /* One state flag per pair in multAtoms:
+ * Encoding flags, set to TCL_ENCODING_START
+ * at the beginning of an INCR transfer. */
+ int numIncrs; /* Number of entries in converts that
* aren't -1 (i.e. # of INCR-mode transfers
* not yet completed). */
Tcl_TimerToken timeout; /* Token for timer procedure. */
@@ -57,9 +74,12 @@ typedef struct IncrInfo {
* retrievals currently pending. */
} IncrInfo;
-static IncrInfo *pendingIncrs = NULL;
- /* List of all incr structures
+
+typedef struct ThreadSpecificData {
+ IncrInfo *pendingIncrs; /* List of all incr structures
* currently active. */
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
/*
* Largest property that we'll accept when sending or receiving the
@@ -98,7 +118,7 @@ static void SelTimeoutProc _ANSI_ARGS_((ClientData clientData));
* Results:
* The return value is a standard Tcl return value.
* If an error occurs (such as no selection exists)
- * then an error message is left in interp->result.
+ * then an error message is left in the interp's result.
*
* Side effects:
* None.
@@ -147,7 +167,9 @@ TkSelGetSelection(interp, tkwin, selection, target, proc, clientData)
retr.clientData = clientData;
retr.result = -1;
retr.idleTime = 0;
+ retr.encFlags = TCL_ENCODING_START;
retr.nextPtr = pendingRetrievals;
+ Tcl_DStringInit(&retr.buf);
pendingRetrievals = &retr;
/*
@@ -192,6 +214,7 @@ TkSelGetSelection(interp, tkwin, selection, target, proc, clientData)
}
}
}
+ Tcl_DStringFree(&retr.buf);
return retr.result;
}
@@ -223,13 +246,19 @@ TkSelPropProc(eventPtr)
register XEvent *eventPtr; /* X PropertyChange event. */
{
register IncrInfo *incrPtr;
- int i, format;
+ int i, length, numItems, flags;
+ Tcl_Encoding encoding;
+ int srcLen, dstLen, result, srcRead, dstWrote, soFar;
+ Tcl_DString ds;
+ char *src, *dst;
Atom target, formatType;
register TkSelHandler *selPtr;
long buffer[TK_SEL_WORDS_AT_ONCE];
- int numItems;
char *propPtr;
+ TkDisplay *dispPtr = TkGetDisplay(eventPtr->xany.display);
Tk_ErrorHandler errorHandler;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
/*
* See if this event announces the deletion of a property being
@@ -240,91 +269,234 @@ TkSelPropProc(eventPtr)
if (eventPtr->xproperty.state != PropertyDelete) {
return;
}
- for (incrPtr = pendingIncrs; incrPtr != NULL;
+ for (incrPtr = tsdPtr->pendingIncrs; incrPtr != NULL;
incrPtr = incrPtr->nextPtr) {
if (incrPtr->reqWindow != eventPtr->xproperty.window) {
continue;
}
+
+ /*
+ * For each conversion that has been requested, handle any
+ * chunks that haven't been transmitted yet.
+ */
+
for (i = 0; i < incrPtr->numConversions; i++) {
if ((eventPtr->xproperty.atom != incrPtr->multAtoms[2*i + 1])
- || (incrPtr->offsets[i] == -1)){
+ || (incrPtr->converts[i].offset == -1)) {
continue;
}
target = incrPtr->multAtoms[2*i];
incrPtr->idleTime = 0;
+
+ /*
+ * Look for a matching selection handler.
+ */
+
for (selPtr = incrPtr->winPtr->selHandlerList; ;
selPtr = selPtr->nextPtr) {
if (selPtr == NULL) {
+ /*
+ * No handlers match, so mark the conversion as done.
+ */
+
incrPtr->multAtoms[2*i + 1] = None;
- incrPtr->offsets[i] = -1;
+ incrPtr->converts[i].offset = -1;
incrPtr->numIncrs --;
return;
}
if ((selPtr->target == target)
&& (selPtr->selection == incrPtr->selection)) {
- formatType = selPtr->format;
- if (incrPtr->offsets[i] == -2) {
- numItems = 0;
- ((char *) buffer)[0] = 0;
- } else {
- TkSelInProgress ip;
- ip.selPtr = selPtr;
- ip.nextPtr = pendingPtr;
- pendingPtr = &ip;
- numItems = (*selPtr->proc)(selPtr->clientData,
- incrPtr->offsets[i], (char *) buffer,
- TK_SEL_BYTES_AT_ONCE);
- pendingPtr = ip.nextPtr;
- if (ip.selPtr == NULL) {
- /*
- * The selection handler deleted itself.
- */
-
- return;
- }
- if (numItems > TK_SEL_BYTES_AT_ONCE) {
- panic("selection handler returned too many bytes");
- } else {
- if (numItems < 0) {
- numItems = 0;
- }
- }
- ((char *) buffer)[numItems] = '\0';
- }
- if (numItems < TK_SEL_BYTES_AT_ONCE) {
- if (numItems <= 0) {
- incrPtr->offsets[i] = -1;
- incrPtr->numIncrs--;
- } else {
- incrPtr->offsets[i] = -2;
- }
- } else {
- incrPtr->offsets[i] += numItems;
- }
- if (formatType == XA_STRING) {
- propPtr = (char *) buffer;
- format = 8;
- } else {
- propPtr = (char *) SelCvtToX((char *) buffer,
- formatType, (Tk_Window) incrPtr->winPtr,
- &numItems);
- format = 32;
+ break;
+ }
+ }
+
+ /*
+ * We found a handler, so get the next chunk from it.
+ */
+
+ formatType = selPtr->format;
+ if (incrPtr->converts[i].offset == -2) {
+ /*
+ * We already got the last chunk, so send a null chunk
+ * to indicate that we are finished.
+ */
+
+ numItems = 0;
+ length = 0;
+ } else {
+ TkSelInProgress ip;
+ ip.selPtr = selPtr;
+ ip.nextPtr = TkSelGetInProgress();
+ TkSelSetInProgress(&ip);
+
+ /*
+ * Copy any bytes left over from a partial character at the end
+ * of the previous chunk into the beginning of the buffer.
+ * Pass the rest of the buffer space into the selection
+ * handler.
+ */
+
+ length = strlen(incrPtr->converts[i].buffer);
+ strcpy((char *)buffer, incrPtr->converts[i].buffer);
+
+ numItems = (*selPtr->proc)(selPtr->clientData,
+ incrPtr->converts[i].offset,
+ ((char *) buffer) + length,
+ TK_SEL_BYTES_AT_ONCE - length);
+ TkSelSetInProgress(ip.nextPtr);
+ if (ip.selPtr == NULL) {
+ /*
+ * The selection handler deleted itself.
+ */
+
+ return;
+ }
+ if (numItems < 0) {
+ numItems = 0;
+ }
+ numItems += length;
+ if (numItems > TK_SEL_BYTES_AT_ONCE) {
+ panic("selection handler returned too many bytes");
+ }
+ }
+ ((char *) buffer)[numItems] = 0;
+
+ /*
+ * Encode the data using the proper format for each type.
+ */
+
+ if ((formatType == XA_STRING)
+ || (dispPtr
+ && (formatType == dispPtr->compoundTextAtom))) {
+ /*
+ * Set up the encoding state based on the format and whether
+ * this is the first and/or last chunk.
+ */
+
+ flags = 0;
+ if (incrPtr->converts[i].offset == 0) {
+ flags |= TCL_ENCODING_START;
+ }
+ if (numItems < TK_SEL_BYTES_AT_ONCE) {
+ flags |= TCL_ENCODING_END;
+ }
+ if (formatType == XA_STRING) {
+ encoding = Tcl_GetEncoding(NULL, "iso8859-1");
+ } else {
+ encoding = Tcl_GetEncoding(NULL, "iso2022");
+ }
+
+ /*
+ * Now convert the data.
+ */
+
+ src = (char *)buffer;
+ srcLen = numItems;
+ Tcl_DStringInit(&ds);
+ dst = Tcl_DStringValue(&ds);
+ dstLen = ds.spaceAvl - 1;
+
+
+ /*
+ * Now convert the data, growing the destination buffer
+ * as needed.
+ */
+
+ while (1) {
+ result = Tcl_UtfToExternal(NULL, encoding,
+ src, srcLen, flags,
+ &incrPtr->converts[i].state,
+ dst, dstLen, &srcRead, &dstWrote, NULL);
+ soFar = dst + dstWrote - Tcl_DStringValue(&ds);
+ flags &= ~TCL_ENCODING_START;
+ src += srcRead;
+ srcLen -= srcRead;
+ if (result != TCL_CONVERT_NOSPACE) {
+ Tcl_DStringSetLength(&ds, soFar);
+ break;
}
- errorHandler = Tk_CreateErrorHandler(
- eventPtr->xproperty.display, -1, -1, -1,
- (int (*)()) NULL, (ClientData) NULL);
- XChangeProperty(eventPtr->xproperty.display,
- eventPtr->xproperty.window,
- eventPtr->xproperty.atom, formatType,
- format, PropModeReplace,
- (unsigned char *) propPtr, numItems);
- Tk_DeleteErrorHandler(errorHandler);
- if (propPtr != (char *) buffer) {
- ckfree(propPtr);
+ if (Tcl_DStringLength(&ds) == 0) {
+ Tcl_DStringSetLength(&ds, dstLen);
}
- return;
+ Tcl_DStringSetLength(&ds,
+ 2 * Tcl_DStringLength(&ds) + 1);
+ dst = Tcl_DStringValue(&ds) + soFar;
+ dstLen = Tcl_DStringLength(&ds) - soFar - 1;
+ }
+ Tcl_DStringSetLength(&ds, soFar);
+
+ if (encoding) {
+ Tcl_FreeEncoding(encoding);
+ }
+
+ /*
+ * Set the property to the encoded string value.
+ */
+
+ errorHandler = Tk_CreateErrorHandler(
+ eventPtr->xproperty.display, -1, -1, -1,
+ (int (*)()) NULL, (ClientData) NULL);
+ XChangeProperty(eventPtr->xproperty.display,
+ eventPtr->xproperty.window,
+ eventPtr->xproperty.atom, formatType, 8,
+ PropModeReplace,
+ (unsigned char *) Tcl_DStringValue(&ds),
+ Tcl_DStringLength(&ds));
+ Tk_DeleteErrorHandler(errorHandler);
+
+ /*
+ * Preserve any left-over bytes.
+ */
+
+ if (srcLen > TCL_UTF_MAX) {
+ panic("selection conversion left too many bytes unconverted");
+ }
+ memcpy(incrPtr->converts[i].buffer, src, (size_t) srcLen+1);
+ Tcl_DStringFree(&ds);
+ } else {
+ propPtr = (char *) SelCvtToX((char *) buffer,
+ formatType, (Tk_Window) incrPtr->winPtr,
+ &numItems);
+
+ /*
+ * Set the property to the encoded string value.
+ */
+
+ errorHandler = Tk_CreateErrorHandler(
+ eventPtr->xproperty.display, -1, -1, -1,
+ (int (*)()) NULL, (ClientData) NULL);
+ XChangeProperty(eventPtr->xproperty.display,
+ eventPtr->xproperty.window,
+ eventPtr->xproperty.atom, formatType, 8,
+ PropModeReplace,
+ (unsigned char *) Tcl_DStringValue(&ds), numItems);
+ Tk_DeleteErrorHandler(errorHandler);
+
+ ckfree(propPtr);
+ }
+
+ /*
+ * Compute the next offset value. If this was the last chunk,
+ * then set the offset to -2. If this was an empty chunk,
+ * then set the offset to -1 to indicate we are done.
+ */
+
+ if (numItems < TK_SEL_BYTES_AT_ONCE) {
+ if (numItems <= 0) {
+ incrPtr->converts[i].offset = -1;
+ incrPtr->numIncrs--;
+ } else {
+ incrPtr->converts[i].offset = -2;
}
+ } else {
+ /*
+ * Advance over the selection data that was consumed
+ * this time.
+ */
+
+ incrPtr->converts[i].offset += numItems - length;
}
+ return;
}
}
}
@@ -378,6 +550,7 @@ TkSelEventProc(tkwin, eventPtr)
Atom type;
int format, result;
unsigned long numItems, bytesAfter;
+ Tcl_DString ds;
for (retrPtr = pendingRetrievals; ; retrPtr = retrPtr->nextPtr) {
if (retrPtr == NULL) {
@@ -421,18 +594,45 @@ TkSelEventProc(tkwin, eventPtr)
}
if ((type == XA_STRING) || (type == dispPtr->textAtom)
|| (type == dispPtr->compoundTextAtom)) {
+ Tcl_Encoding encoding;
if (format != 8) {
- sprintf(retrPtr->interp->result,
- "bad format for string selection: wanted \"8\", got \"%d\"",
- format);
+ char buf[64 + TCL_INTEGER_SPACE];
+
+ sprintf(buf,
+ "bad format for string selection: wanted \"8\", got \"%d\"",
+ format);
+ Tcl_SetResult(retrPtr->interp, buf, TCL_VOLATILE);
retrPtr->result = TCL_ERROR;
return;
}
interp = retrPtr->interp;
Tcl_Preserve((ClientData) interp);
+
+ /*
+ * Convert the X selection data into UTF before passing it
+ * to the selection callback. Note that the COMPOUND_TEXT
+ * uses a modified iso2022 encoding, not the current system
+ * encoding. For now we'll just blindly apply the iso2022
+ * encoding. This is probably wrong, but it's a placeholder
+ * until we figure out what we're really supposed to do. For
+ * STRING, we need to use Latin-1 instead. Again, it's not
+ * really the full iso8859-1 space, but this is close enough.
+ */
+
+ if (type == dispPtr->compoundTextAtom) {
+ encoding = Tcl_GetEncoding(NULL, "iso2022");
+ } else {
+ encoding = Tcl_GetEncoding(NULL, "iso8859-1");
+ }
+ Tcl_ExternalToUtfDString(encoding, propInfo, (int)numItems, &ds);
+ if (encoding) {
+ Tcl_FreeEncoding(encoding);
+ }
+
retrPtr->result = (*retrPtr->proc)(retrPtr->clientData,
- interp, propInfo);
- Tcl_Release((ClientData) interp);
+ interp, Tcl_DStringValue(&ds));
+ Tcl_DStringFree(&ds);
+ Tcl_Release((ClientData) interp);
} else if (type == dispPtr->incrAtom) {
/*
@@ -456,9 +656,12 @@ TkSelEventProc(tkwin, eventPtr)
char *string;
if (format != 32) {
- sprintf(retrPtr->interp->result,
- "bad format for selection: wanted \"32\", got \"%d\"",
- format);
+ char buf[64 + TCL_INTEGER_SPACE];
+
+ sprintf(buf,
+ "bad format for selection: wanted \"32\", got \"%d\"",
+ format);
+ Tcl_SetResult(retrPtr->interp, buf, TCL_VOLATILE);
retrPtr->result = TCL_ERROR;
return;
}
@@ -580,6 +783,8 @@ ConvertSelection(winPtr, eventPtr)
Tk_ErrorHandler errorHandler;
TkSelectionInfo *infoPtr;
TkSelInProgress ip;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
errorHandler = Tk_CreateErrorHandler(eventPtr->display, -1, -1,-1,
(int (*)()) NULL, (ClientData) NULL);
@@ -657,8 +862,8 @@ ConvertSelection(winPtr, eventPtr)
* be returned below).
*/
- incr.offsets = (int *) ckalloc((unsigned)
- (incr.numConversions*sizeof(int)));
+ incr.converts = (ConvertInfo *) ckalloc((unsigned)
+ (incr.numConversions*sizeof(ConvertInfo)));
incr.numIncrs = 0;
for (i = 0; i < incr.numConversions; i++) {
Atom target, property, type;
@@ -669,7 +874,8 @@ ConvertSelection(winPtr, eventPtr)
target = incr.multAtoms[2*i];
property = incr.multAtoms[2*i + 1];
- incr.offsets[i] = -1;
+ incr.converts[i].offset = -1;
+ incr.converts[i].buffer[0] = '\0';
for (selPtr = winPtr->selHandlerList; selPtr != NULL;
selPtr = selPtr->nextPtr) {
@@ -694,12 +900,12 @@ ConvertSelection(winPtr, eventPtr)
}
} else {
ip.selPtr = selPtr;
- ip.nextPtr = pendingPtr;
- pendingPtr = &ip;
+ ip.nextPtr = TkSelGetInProgress();
+ TkSelSetInProgress(&ip);
type = selPtr->format;
numItems = (*selPtr->proc)(selPtr->clientData, 0,
(char *) buffer, TK_SEL_BYTES_AT_ONCE);
- pendingPtr = ip.nextPtr;
+ TkSelSetInProgress(ip.nextPtr);
if ((ip.selPtr == NULL) || (numItems < 0)) {
incr.multAtoms[2*i + 1] = None;
continue;
@@ -730,19 +936,42 @@ ConvertSelection(winPtr, eventPtr)
numItems = 1;
propPtr = (char *) buffer;
format = 32;
- incr.offsets[i] = 0;
- } else if (type == XA_STRING) {
- propPtr = (char *) buffer;
- format = 8;
+ incr.converts[i].offset = 0;
+ XChangeProperty(reply.display, reply.requestor,
+ property, type, format, PropModeReplace,
+ (unsigned char *) propPtr, numItems);
+ } else if ((type == XA_STRING)
+ || (type == winPtr->dispPtr->compoundTextAtom)) {
+ Tcl_DString ds;
+ Tcl_Encoding encoding;
+
+ /*
+ * STRING is Latin-1, COMPOUND_TEXT is an iso2022 variant.
+ * We need to convert the selection text into these external
+ * forms before modifying the property.
+ */
+
+ if (type == XA_STRING) {
+ encoding = Tcl_GetEncoding(NULL, "iso8859-1");
+ } else {
+ encoding = Tcl_GetEncoding(NULL, "iso2022");
+ }
+ Tcl_UtfToExternalDString(encoding, (char*)buffer, -1, &ds);
+ XChangeProperty(reply.display, reply.requestor,
+ property, type, 8, PropModeReplace,
+ (unsigned char *) Tcl_DStringValue(&ds),
+ Tcl_DStringLength(&ds));
+ if (encoding) {
+ Tcl_FreeEncoding(encoding);
+ }
+ Tcl_DStringFree(&ds);
} else {
propPtr = (char *) SelCvtToX((char *) buffer,
type, (Tk_Window) winPtr, &numItems);
format = 32;
- }
- XChangeProperty(reply.display, reply.requestor,
- property, type, format, PropModeReplace,
- (unsigned char *) propPtr, numItems);
- if (propPtr != (char *) buffer) {
+ XChangeProperty(reply.display, reply.requestor,
+ property, type, format, PropModeReplace,
+ (unsigned char *) propPtr, numItems);
ckfree(propPtr);
}
}
@@ -761,8 +990,8 @@ ConvertSelection(winPtr, eventPtr)
incr.idleTime = 0;
incr.reqWindow = reply.requestor;
incr.time = infoPtr->time;
- incr.nextPtr = pendingIncrs;
- pendingIncrs = &incr;
+ incr.nextPtr = tsdPtr->pendingIncrs;
+ tsdPtr->pendingIncrs = &incr;
}
if (multiple) {
XChangeProperty(reply.display, reply.requestor, reply.property,
@@ -798,10 +1027,10 @@ ConvertSelection(winPtr, eventPtr)
-1, -1,-1, (int (*)()) NULL, (ClientData) NULL);
XSelectInput(reply.display, reply.requestor, 0L);
Tk_DeleteErrorHandler(errorHandler);
- if (pendingIncrs == &incr) {
- pendingIncrs = incr.nextPtr;
+ if (tsdPtr->pendingIncrs == &incr) {
+ tsdPtr->pendingIncrs = incr.nextPtr;
} else {
- for (incrPtr2 = pendingIncrs; incrPtr2 != NULL;
+ for (incrPtr2 = tsdPtr->pendingIncrs; incrPtr2 != NULL;
incrPtr2 = incrPtr2->nextPtr) {
if (incrPtr2->nextPtr == &incr) {
incrPtr2->nextPtr = incr.nextPtr;
@@ -815,7 +1044,7 @@ ConvertSelection(winPtr, eventPtr)
* All done. Cleanup and return.
*/
- ckfree((char *) incr.offsets);
+ ckfree((char *) incr.converts);
if (multiple) {
XFree((char *) incr.multAtoms);
}
@@ -860,11 +1089,13 @@ SelRcvIncrProc(clientData, eventPtr)
register XEvent *eventPtr; /* X PropertyChange event. */
{
register TkSelRetrievalInfo *retrPtr = (TkSelRetrievalInfo *) clientData;
- char *propInfo;
+ char *propInfo, *dst, *src;
Atom type;
- int format, result;
+ int format, result, srcLen, dstLen, srcRead, dstWrote, soFar;
unsigned long numItems, bytesAfter;
+ Tcl_DString *dstPtr, temp;
Tcl_Interp *interp;
+ Tcl_Encoding encoding;
if ((eventPtr->xproperty.atom != retrPtr->property)
|| (eventPtr->xproperty.state != PropertyNewValue)
@@ -885,34 +1116,120 @@ SelRcvIncrProc(clientData, eventPtr)
retrPtr->result = TCL_ERROR;
goto done;
}
- if (numItems == 0) {
- retrPtr->result = TCL_OK;
- } else if ((type == XA_STRING)
+ if ((type == XA_STRING)
|| (type == retrPtr->winPtr->dispPtr->textAtom)
|| (type == retrPtr->winPtr->dispPtr->compoundTextAtom)) {
if (format != 8) {
- Tcl_SetResult(retrPtr->interp, (char *) NULL, TCL_STATIC);
- sprintf(retrPtr->interp->result,
- "bad format for string selection: wanted \"8\", got \"%d\"",
- format);
+ char buf[64 + TCL_INTEGER_SPACE];
+
+ sprintf(buf,
+ "bad format for string selection: wanted \"8\", got \"%d\"",
+ format);
+ Tcl_SetResult(retrPtr->interp, buf, TCL_VOLATILE);
retrPtr->result = TCL_ERROR;
goto done;
}
interp = retrPtr->interp;
Tcl_Preserve((ClientData) interp);
- result = (*retrPtr->proc)(retrPtr->clientData, interp, propInfo);
+
+ if (type == retrPtr->winPtr->dispPtr->compoundTextAtom) {
+ encoding = Tcl_GetEncoding(NULL, "iso2022");
+ } else {
+ encoding = Tcl_GetEncoding(NULL, "iso8859-1");
+ }
+
+ /*
+ * Check to see if there is any data left over from the previous
+ * chunk. If there is, copy the old data and the new data into
+ * a new buffer.
+ */
+
+ Tcl_DStringInit(&temp);
+ if (Tcl_DStringLength(&retrPtr->buf) > 0) {
+ Tcl_DStringAppend(&temp, Tcl_DStringValue(&retrPtr->buf),
+ Tcl_DStringLength(&retrPtr->buf));
+ if (numItems > 0) {
+ Tcl_DStringAppend(&temp, propInfo, (int)numItems);
+ }
+ src = Tcl_DStringValue(&temp);
+ srcLen = Tcl_DStringLength(&temp);
+ } else if (numItems == 0) {
+ /*
+ * There is no new data, so we're done.
+ */
+
+ retrPtr->result = TCL_OK;
+ goto done;
+ } else {
+ src = propInfo;
+ srcLen = numItems;
+ }
+
+ /*
+ * Set up the destination buffer so we can use as much space as
+ * is available.
+ */
+
+ dstPtr = &retrPtr->buf;
+ dst = Tcl_DStringValue(dstPtr);
+ dstLen = dstPtr->spaceAvl - 1;
+
+ /*
+ * Now convert the data, growing the destination buffer as needed.
+ */
+
+ while (1) {
+ result = Tcl_ExternalToUtf(NULL, encoding, src, srcLen,
+ retrPtr->encFlags, &retrPtr->encState,
+ dst, dstLen, &srcRead, &dstWrote, NULL);
+ soFar = dst + dstWrote - Tcl_DStringValue(dstPtr);
+ retrPtr->encFlags &= ~TCL_ENCODING_START;
+ src += srcRead;
+ srcLen -= srcRead;
+ if (result != TCL_CONVERT_NOSPACE) {
+ Tcl_DStringSetLength(dstPtr, soFar);
+ break;
+ }
+ if (Tcl_DStringLength(dstPtr) == 0) {
+ Tcl_DStringSetLength(dstPtr, dstLen);
+ }
+ Tcl_DStringSetLength(dstPtr, 2 * Tcl_DStringLength(dstPtr) + 1);
+ dst = Tcl_DStringValue(dstPtr) + soFar;
+ dstLen = Tcl_DStringLength(dstPtr) - soFar - 1;
+ }
+ Tcl_DStringSetLength(dstPtr, soFar);
+
+ result = (*retrPtr->proc)(retrPtr->clientData, interp,
+ Tcl_DStringValue(dstPtr));
Tcl_Release((ClientData) interp);
+
+ /*
+ * Copy any unused data into the destination buffer so we can
+ * pick it up next time around.
+ */
+
+ Tcl_DStringSetLength(dstPtr, 0);
+ Tcl_DStringAppend(dstPtr, src, srcLen);
+
+ Tcl_DStringFree(&temp);
+ if (encoding) {
+ Tcl_FreeEncoding(encoding);
+ }
if (result != TCL_OK) {
retrPtr->result = result;
}
+ } else if (numItems == 0) {
+ retrPtr->result = TCL_OK;
} else {
char *string;
if (format != 32) {
- Tcl_SetResult(retrPtr->interp, (char *) NULL, TCL_STATIC);
- sprintf(retrPtr->interp->result,
- "bad format for selection: wanted \"32\", got \"%d\"",
- format);
+ char buf[64 + TCL_INTEGER_SPACE];
+
+ sprintf(buf,
+ "bad format for selection: wanted \"32\", got \"%d\"",
+ format);
+ Tcl_SetResult(retrPtr->interp, buf, TCL_VOLATILE);
retrPtr->result = TCL_ERROR;
goto done;
}
@@ -964,8 +1281,8 @@ SelectionSize(selPtr)
size = TK_SEL_BYTES_AT_ONCE;
ip.selPtr = selPtr;
- ip.nextPtr = pendingPtr;
- pendingPtr = &ip;
+ ip.nextPtr = TkSelGetInProgress();
+ TkSelSetInProgress(&ip);
do {
chunkSize = (*selPtr->proc)(selPtr->clientData, size,
(char *) buffer, TK_SEL_BYTES_AT_ONCE);
@@ -975,7 +1292,7 @@ SelectionSize(selPtr)
}
size += chunkSize;
} while (chunkSize == TK_SEL_BYTES_AT_ONCE);
- pendingPtr = ip.nextPtr;
+ TkSelSetInProgress(ip.nextPtr);
return size;
}
@@ -1187,3 +1504,4 @@ SelCvtFromX(propPtr, numValues, type, tkwin)
}
return result;
}
+