diff options
Diffstat (limited to 'tk/unix/tkUnixSelect.c')
-rw-r--r-- | tk/unix/tkUnixSelect.c | 566 |
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; } + |