head	1.34;
access;
symbols
	core-8-5-9:1.20
	core-8-5-8:1.20
	macosx-cocoa-merge:1.29
	macosx-cocoa-premerge:1.28
	macosx-carbon-freeze:1.28
	core-8-5-7:1.20
	core-8-5-6:1.20
	core-8-6-b1:1.27
	core-8-6-a3:1.23
	core-8-5-5:1.20
	core-8-6-a2:1.22
	core-8-5-4:1.20
	core-8-5-3:1.20
	core-8-6-a1:1.21
	core-8-4-19:1.13.2.1
	core-8-5-branch:1.20.0.4
	core-8-5-2:1.20
	core-8-4-18:1.13.2.1
	core-8-5-1:1.20
	core-8-4-17:1.13.2.1
	core-8-5-0:1.20
	core-8-5-b3:1.20
	core-8-5-b2:1.20
	core-8-4-16:1.13.2.1
	core-8-5-b1:1.20
	core-stablilizer-merge:1.20
	core-stabilizer-branch:1.20.0.2
	core-stabilizer-merge:1.20
	core-8-4-15:1.13.2.1
	core-8-5-a6:1.20
	core-8-5-a5:1.19
	core-8-4-14:1.13.2.1
	core-8-5-a4:1.19
	core-8-4-13:1.13.2.1
	core-8-4-12:1.13.2.1
	core-8-4-11:1.13
	core-8-5-a3:1.15
	core-8-4-10:1.13
	core-8-4-9-branch:1.13.0.6
	core-8-5-a2:1.15
	core-8-4-9:1.13
	core-8-4-8:1.13
	core-8-4-7:1.13
	core-8-5-a1:1.14
	core-8-4-6:1.13
	core-8-4-5:1.13
	mistachkin-dev-branch:1.13.0.4
	core-8-4-4:1.13
	core-8-4-3:1.13
	core-8-4-branch:1.13.0.2
	core-8-4-2:1.13
	core-8-4-1:1.12
	core-8-3-5:1.5.8.1
	core-8-4-0:1.12
	macosx-8-4-merge-2002-08-31-trunk:1.12
	macosx-8-4-premerge-2002-08-31-branch:1.7.2.4
	macosx-8-4-premerge-2002-08-31-trunk:1.11
	macosx-8-4-merge-2002-08-30-branch:1.7.2.4
	macosx-8-4-merge-2002-08-30-trunk:1.11
	macosx-8-4-merge-2002-08-20-branch:1.7.2.4
	macosx-8-4-merge-2002-08-20-trunk:1.11
	core-8-4-b2:1.11
	core-8-4-b1:1.10
	macosx-premerge-6-9-02:1.7.2.3
	core-8-4-a4:1.10
	core-8-3-4:1.5
	macosx-8-4-branch:1.7.0.2
	macosx-8-4-branchpoint:1.7
	core-8-4-a3:1.7
	core-8-3-3:1.5
	dgp-privates-into-namespace:1.6.0.4
	tclpro-1-5-0:1.5
	core-8-4-win-speedup:1.6.0.2
	core-8-4-a2:1.6
	tclpro-1-4-1:1.5
	tclpro-1-4-0:1.5
	core-8-3-2:1.5
	ajuba-ajuba2-2-1-base:1.5
	ajuba-ajuba2-2-0:1.5
	core-8-4-a1:1.5
	core-8-3-1-branch:1.5.0.8
	core-8-3-1:1.5
	scriptics-sc-2-0-b5:1.5
	scriptics-sc-2-0-fixed:1.5
	scriptics-sc-2-0-b2:1.5
	scriptics-sc-2-0-b1:1.5
	core-8-3-0:1.5
	core-8-3-b2:1.5
	core-8-3-b1:1.5
	scriptics-sc-1-1:1.5
	scriptics-sc-1-1-b1:1.5
	core-8-2-3:1.5
	scriptics-sc-1-1-branch:1.5.0.6
	scriptics-sc-1-1-base:1.5
	scriptics-sc-1-0:1.5
	scriptics-sc-1-0-branch:1.5.0.4
	scriptics-sc-1-0-base:1.5
	core-8-2-2:1.5
	core-8-2-1:1.5
	scriptics-bc-1-0-b1:1.5
	core-8-2-1-branch:1.5.0.2
	scriptics-tclpro-1-3-0:1.5
	core-8-2-0:1.5
	core-8-2-b3-branch:1.4.0.2
	core-8-2-b3-base:1.4
	scriptics-tclpro-1-3-b4:1.4
	core-8-2-b2:1.4
	scriptics-tclpro-1-3-b3:1.4
	core-8-2-b1:1.4
	scriptics-tclpro-1-3-b2:1.3
	merge-to-mainline-5/21/99:1.3
	scriptics-tclpro-1-3-b2-branch:1.3.0.2
	core-8-1-1:1.3
	scriptics-tclpro-1-3-b1:1.3
	core-8-1-1-base:1.3
	core-8-1-0:1.3
	merge-to-mainline-4-29-99:1.3
	merge-to-mainline-4-23-99:1.3
	core-8-1-branch-old:1.1.0.4
	core-8-0-6-branch:1.2.0.6
	core-8-0-6-base:1.2
	core-8-0-5:1.2
	core-8-1-b3:1.1.4.3
	core-8-1-b2:1.1.4.3
	dev-8-1-stubs-branch:1.1.4.3.0.2
	dev-stubs-branch:1.2.0.4
	scriptics-tclpro-1-2:1.2
	scriptics-tclpro-1-2-b2:1.2
	core-8-1-merge-2/10/99:1.2
	core-8-0-5-branch:1.2.0.2
	core-8-0-5-base:1.2
	scriptics-tclpro-1-2-b1:1.2
	scriptics-tclpro-1-2-a1:1.2
	core-8-1-b1:1.1.4.2
	core-8-0-4:1.2
	core-8-1-a2:1.1.4.1
	core-8-0-2:1.1
	core-8-0-3:1.2;
locks; strict;
comment	@ * @;


1.34
date	2011.01.24.19.51.00;	author jenglish;	state Exp;
branches;
next	1.33;

1.33
date	2010.12.06.10.30.49;	author nijtmans;	state Exp;
branches;
next	1.32;

1.32
date	2010.11.29.09.07.13;	author nijtmans;	state Exp;
branches;
next	1.31;

1.31
date	2010.01.02.22.52.38;	author dkf;	state Exp;
branches;
next	1.30;

1.30
date	2009.07.23.22.21.35;	author dkf;	state Exp;
branches;
next	1.29;

1.29
date	2009.06.29.14.35.01;	author das;	state Exp;
branches;
next	1.28;

1.28
date	2009.02.03.23.55.47;	author nijtmans;	state Exp;
branches;
next	1.27;

1.27
date	2008.12.09.21.22.56;	author dgp;	state Exp;
branches;
next	1.26;

1.26
date	2008.11.08.18.44.40;	author dkf;	state Exp;
branches;
next	1.25;

1.25
date	2008.10.28.22.33.06;	author nijtmans;	state Exp;
branches;
next	1.24;

1.24
date	2008.10.17.23.18.37;	author nijtmans;	state Exp;
branches;
next	1.23;

1.23
date	2008.10.05.18.22.21;	author dkf;	state Exp;
branches;
next	1.22;

1.22
date	2008.07.23.23.24.21;	author nijtmans;	state Exp;
branches;
next	1.21;

1.21
date	2008.04.27.22.38.58;	author dkf;	state Exp;
branches;
next	1.20;

1.20
date	2007.04.17.14.36.49;	author dkf;	state Exp;
branches
	1.20.4.1;
next	1.19;

1.19
date	2005.11.22.11.16.25;	author dkf;	state Exp;
branches;
next	1.18;

1.18
date	2005.11.17.16.21.56;	author dkf;	state Exp;
branches;
next	1.17;

1.17
date	2005.11.14.16.29.15;	author dkf;	state Exp;
branches;
next	1.16;

1.16
date	2005.10.17.22.02.44;	author dkf;	state Exp;
branches;
next	1.15;

1.15
date	2004.03.17.18.15.44;	author das;	state Exp;
branches;
next	1.14;

1.14
date	2004.01.13.02.06.00;	author davygrvy;	state Exp;
branches;
next	1.13;

1.13
date	2003.01.14.19.24.56;	author jenglish;	state Exp;
branches
	1.13.2.1;
next	1.12;

1.12
date	2002.08.31.06.12.26;	author das;	state Exp;
branches;
next	1.11;

1.11
date	2002.08.05.04.30.40;	author dgp;	state Exp;
branches;
next	1.10;

1.10
date	2002.01.17.05.13.11;	author dgp;	state Exp;
branches;
next	1.9;

1.9
date	2002.01.17.03.35.00;	author dgp;	state Exp;
branches;
next	1.8;

1.8
date	2002.01.04.16.35.04;	author dgp;	state Exp;
branches;
next	1.7;

1.7
date	2001.07.03.01.03.16;	author hobbs;	state Exp;
branches
	1.7.2.1;
next	1.6;

1.6
date	2000.08.07.21.49.16;	author ericm;	state Exp;
branches
	1.6.2.1
	1.6.4.1;
next	1.5;

1.5
date	99.08.13.17.52.13;	author redman;	state Exp;
branches
	1.5.8.1;
next	1.4;

1.4
date	99.06.03.18.50.46;	author stanton;	state Exp;
branches;
next	1.3;

1.3
date	99.04.16.01.51.21;	author stanton;	state Exp;
branches;
next	1.2;

1.2
date	98.09.14.18.23.17;	author stanton;	state Exp;
branches;
next	1.1;

1.1
date	98.04.01.09.52.03;	author rjohnson;	state Exp;
branches
	1.1.4.1;
next	;

1.1.4.1
date	98.09.29.00.25.25;	author stanton;	state Exp;
branches;
next	1.1.4.2;

1.1.4.2
date	98.09.30.02.17.18;	author stanton;	state Exp;
branches;
next	1.1.4.3;

1.1.4.3
date	98.12.13.08.16.11;	author lfb;	state Exp;
branches;
next	;

1.5.8.1
date	2002.01.04.16.39.57;	author dgp;	state Exp;
branches;
next	;

1.6.2.1
date	2002.04.02.21.00.59;	author hobbs;	state Exp;
branches;
next	;

1.6.4.1
date	2001.07.03.20.01.09;	author dgp;	state Exp;
branches;
next	;

1.7.2.1
date	2001.10.15.09.22.00;	author wolfsuit;	state Exp;
branches;
next	1.7.2.2;

1.7.2.2
date	2001.10.17.07.10.46;	author wolfsuit;	state Exp;
branches;
next	1.7.2.3;

1.7.2.3
date	2002.02.05.02.25.15;	author wolfsuit;	state Exp;
branches;
next	1.7.2.4;

1.7.2.4
date	2002.08.20.20.27.07;	author das;	state Exp;
branches;
next	;

1.13.2.1
date	2005.11.22.11.32.37;	author dkf;	state Exp;
branches;
next	1.13.2.2;

1.13.2.2
date	2011.01.25.08.49.59;	author nijtmans;	state Exp;
branches;
next	;

1.20.4.1
date	2011.01.25.08.31.37;	author nijtmans;	state Exp;
branches;
next	;


desc
@@


1.34
log
@tkSelect.c: Fix for [Bug #3164879] (memory allocation bug
introduced by [Patch #3129527])
@
text
@/*
 * tkSelect.c --
 *
 *	This file manages the selection for the Tk toolkit, translating
 *	between the standard X ICCCM conventions and Tcl commands.
 *
 * Copyright (c) 1990-1993 The Regents of the University of California.
 * Copyright (c) 1994-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.
 *
 * RCS: @@(#) $Id: tkSelect.c,v 1.33 2010/12/06 10:30:49 nijtmans Exp $
 */

#include "tkInt.h"
#include "tkSelect.h"

/*
 * When a selection handler is set up by invoking "selection handle", one of
 * the following data structures is set up to hold information about the
 * command to invoke and its interpreter.
 */

typedef struct {
    Tcl_Interp *interp;		/* Interpreter in which to invoke command. */
    int cmdLength;		/* # of non-NULL bytes in command. */
    int charOffset;		/* The offset of the next char to retrieve. */
    int byteOffset;		/* The expected byte offset of the next
				 * chunk. */
    char buffer[TCL_UTF_MAX];	/* A buffer to hold part of a UTF character
				 * that is split across chunks. */
    char command[1];		/* Command to invoke. Actual space is
				 * allocated as large as necessary. This must
				 * be the last entry in the structure. */
} CommandInfo;

/*
 * When selection ownership is claimed with the "selection own" Tcl command,
 * one of the following structures is created to record the Tcl command to be
 * executed when the selection is lost again.
 */

typedef struct LostCommand {
    Tcl_Interp *interp;		/* Interpreter in which to invoke command. */
    Tcl_Obj *cmdObj;		/* Reference to command to invoke. */
} LostCommand;

/*
 * The structure below is used to keep each thread's pending list separate.
 */

typedef struct ThreadSpecificData {
    TkSelInProgress *pendingPtr;
				/* Topmost search in progress, or NULL if
				 * none. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;

/*
 * Forward declarations for functions defined in this file:
 */

static int		HandleTclCommand(ClientData clientData,
			    int offset, char *buffer, int maxBytes);
static void		LostSelection(ClientData clientData);
static int		SelGetProc(ClientData clientData,
			    Tcl_Interp *interp, const char *portion);

/*
 *--------------------------------------------------------------
 *
 * Tk_CreateSelHandler --
 *
 *	This function is called to register a function as the handler for
 *	selection requests of a particular target type on a particular window
 *	for a particular selection.
 *
 * Results:
 *	None.
 *
 * Side effects:

 *	In the future, whenever the selection is in tkwin's window and someone
 *	requests the selection in the form given by target, proc will be
 *	invoked to provide part or all of the selection in the given form. If
 *	there was already a handler declared for the given window, target and
 *	selection type, then it is replaced. Proc should have the following
 *	form:
 *
 *	int
 *	proc(
 *	    ClientData clientData,
 *	    int offset,
 *	    char *buffer,
 *	    int maxBytes)
 *	{
 *	}
 *
 *	The clientData argument to proc will be the same as the clientData
 *	argument to this function. The offset argument indicates which portion
 *	of the selection to return: skip the first offset bytes. Buffer is a
 *	pointer to an area in which to place the converted selection, and
 *	maxBytes gives the number of bytes available at buffer. Proc should
 *	place the selection in buffer as a string, and return a count of the
 *	number of bytes of selection actually placed in buffer (not including
 *	the terminating NULL character). If the return value equals maxBytes,
 *	this is a sign that there is probably still more selection information
 *	available.
 *
 *--------------------------------------------------------------
 */

void
Tk_CreateSelHandler(
    Tk_Window tkwin,		/* Token for window. */
    Atom selection,		/* Selection to be handled. */
    Atom target,		/* The kind of selection conversions that can
				 * be handled by proc, e.g. TARGETS or
				 * STRING. */
    Tk_SelectionProc *proc,	/* Function to invoke to convert selection to
				 * type "target". */
    ClientData clientData,	/* Value to pass to proc. */
    Atom format)		/* Format in which the selection information
				 * should be returned to the requestor.
				 * XA_STRING is best by far, but anything
				 * listed in the ICCCM will be tolerated
				 * (blech). */
{
    register TkSelHandler *selPtr;
    TkWindow *winPtr = (TkWindow *) tkwin;

    if (winPtr->dispPtr->multipleAtom == None) {
	TkSelInit(tkwin);
    }

    /*
     * See if there's already a handler for this target and selection on this
     * window. If so, re-use it. If not, create a new one.
     */

    for (selPtr = winPtr->selHandlerList; ; selPtr = selPtr->nextPtr) {
	if (selPtr == NULL) {
	    selPtr = (TkSelHandler *) ckalloc(sizeof(TkSelHandler));
	    selPtr->nextPtr = winPtr->selHandlerList;
	    winPtr->selHandlerList = selPtr;
	    break;
	}
	if ((selPtr->selection == selection) && (selPtr->target == target)) {
	    /*
	     * Special case: when replacing handler created by "selection
	     * handle", free up memory. Should there be a callback to allow
	     * other clients to do this too?
	     */

	    if (selPtr->proc == HandleTclCommand) {
		ckfree((char *) selPtr->clientData);
	    }
	    break;
	}
    }
    selPtr->selection = selection;
    selPtr->target = target;
    selPtr->format = format;
    selPtr->proc = proc;
    selPtr->clientData = clientData;
    if (format == XA_STRING) {
	selPtr->size = 8;
    } else {
	selPtr->size = 32;
    }

    if ((target == XA_STRING) && (winPtr->dispPtr->utf8Atom != (Atom) 0)) {
	/*
	 * If the user asked for a STRING handler and we understand
	 * UTF8_STRING, we implicitly create a UTF8_STRING handler for them.
	 */

	target = winPtr->dispPtr->utf8Atom;
	for (selPtr = winPtr->selHandlerList; ; selPtr = selPtr->nextPtr) {
	    if (selPtr == NULL) {
		selPtr = (TkSelHandler *) ckalloc(sizeof(TkSelHandler));
		selPtr->nextPtr = winPtr->selHandlerList;
		winPtr->selHandlerList = selPtr;
		selPtr->selection = selection;
		selPtr->target = target;
		selPtr->format = target; /* We want UTF8_STRING format */
		selPtr->proc = proc;
		if (selPtr->proc == HandleTclCommand) {
		    /*
		     * The clientData is selection controlled memory, so we
		     * should make a copy for this selPtr.
		     */

		    unsigned cmdInfoLen = Tk_Offset(CommandInfo, command) +
			    ((CommandInfo *)clientData)->cmdLength + 1;

		    selPtr->clientData = ckalloc(cmdInfoLen);
		    memcpy(selPtr->clientData, clientData, cmdInfoLen);
		} else {
		    selPtr->clientData = clientData;
		}
		selPtr->size = 8;
		break;
	    }
	    if (selPtr->selection==selection && selPtr->target==target) {
		/*
		 * Looks like we had a utf-8 target already. Leave it alone.
		 */

		break;
	    }
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
 * Tk_DeleteSelHandler --
 *
 *	Remove the selection handler for a given window, target, and
 *	selection, if it exists.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The selection handler for tkwin and target is removed. If there is no
 *	such handler then nothing happens.
 *
 *----------------------------------------------------------------------
 */

void
Tk_DeleteSelHandler(
    Tk_Window tkwin,		/* Token for window. */
    Atom selection,		/* The selection whose handler is to be
				 * removed. */
    Atom target)		/* The target whose selection handler is to be
				 * removed. */
{
    TkWindow *winPtr = (TkWindow *) tkwin;
    register TkSelHandler *selPtr, *prevPtr;
    register TkSelInProgress *ipPtr;
    ThreadSpecificData *tsdPtr =
	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    /*
     * Find the selection handler to be deleted, or return if it doesn't
     * exist.
     */

    for (selPtr = winPtr->selHandlerList, prevPtr = NULL; ;
	    prevPtr = selPtr, selPtr = selPtr->nextPtr) {
	if (selPtr == NULL) {
	    return;
	}
	if ((selPtr->selection == selection) && (selPtr->target == target)) {
	    break;
	}
    }

    /*
     * If ConvertSelection is processing this handler, tell it that the
     * handler is dead.
     */

    for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL;
	    ipPtr = ipPtr->nextPtr) {
	if (ipPtr->selPtr == selPtr) {
	    ipPtr->selPtr = NULL;
	}
    }

    /*
     * Free resources associated with the handler.
     */

    if (prevPtr == NULL) {
	winPtr->selHandlerList = selPtr->nextPtr;
    } else {
	prevPtr->nextPtr = selPtr->nextPtr;
    }

    if ((target == XA_STRING) && (winPtr->dispPtr->utf8Atom != (Atom) 0)) {
	/*
	 * If the user asked for a STRING handler and we understand
	 * UTF8_STRING, we may have implicitly created a UTF8_STRING handler
	 * for them. Look for it and delete it as necessary.
	 */

	TkSelHandler *utf8selPtr;

	target = winPtr->dispPtr->utf8Atom;
	for (utf8selPtr = winPtr->selHandlerList; utf8selPtr != NULL;
		utf8selPtr = utf8selPtr->nextPtr) {
	    if ((utf8selPtr->selection == selection)
		    && (utf8selPtr->target == target)) {
		break;
	    }
	}
	if (utf8selPtr != NULL) {
	    if ((utf8selPtr->format == target)
		    && (utf8selPtr->proc == selPtr->proc)
		    && (utf8selPtr->size == selPtr->size)) {
		/*
		 * This recursive call is OK, because we've changed the value
		 * of 'target'.
		 */

		Tk_DeleteSelHandler(tkwin, selection, target);
	    }
	}
    }

    if (selPtr->proc == HandleTclCommand) {
	/*
	 * Mark the CommandInfo as deleted and free it if we can.
	 */

	((CommandInfo *) selPtr->clientData)->interp = NULL;
	Tcl_EventuallyFree(selPtr->clientData, TCL_DYNAMIC);
    }
    ckfree((char *) selPtr);
}

/*
 *--------------------------------------------------------------
 *
 * Tk_OwnSelection --
 *
 *	Arrange for tkwin to become the owner of a selection.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	From now on, requests for the selection will be directed to functions
 *	associated with tkwin (they must have been declared with calls to
 *	Tk_CreateSelHandler). When the selection is lost by this window, proc
 *	will be invoked (see the manual entry for details). This function may
 *	invoke callbacks, including Tcl scripts, so any calling function
 *	should be reentrant at the point where Tk_OwnSelection is invoked.
 *
 *--------------------------------------------------------------
 */

void
Tk_OwnSelection(
    Tk_Window tkwin,		/* Window to become new selection owner. */
    Atom selection,		/* Selection that window should own. */
    Tk_LostSelProc *proc,	/* Function to call when selection is taken
				 * away from tkwin. */
    ClientData clientData)	/* Arbitrary one-word argument to pass to
				 * proc. */
{
    register TkWindow *winPtr = (TkWindow *) tkwin;
    TkDisplay *dispPtr = winPtr->dispPtr;
    TkSelectionInfo *infoPtr;
    Tk_LostSelProc *clearProc = NULL;
    ClientData clearData = NULL;/* Initialization needed only to prevent
				 * compiler warning. */

    if (dispPtr->multipleAtom == None) {
	TkSelInit(tkwin);
    }
    Tk_MakeWindowExist(tkwin);

    /*
     * This code is somewhat tricky. First, we find the specified selection on
     * the selection list. If the previous owner is in this process, and is a
     * different window, then we need to invoke the clearProc. However, it's
     * dangerous to call the clearProc right now, because it could invoke a
     * Tcl script that wrecks the current state (e.g. it could delete the
     * window). To be safe, defer the call until the end of the function when
     * we no longer care about the state.
     */

    for (infoPtr = dispPtr->selectionInfoPtr; infoPtr != NULL;
	    infoPtr = infoPtr->nextPtr) {
	if (infoPtr->selection == selection) {
	    break;
	}
    }
    if (infoPtr == NULL) {
	infoPtr = (TkSelectionInfo *) ckalloc(sizeof(TkSelectionInfo));
	infoPtr->selection = selection;
	infoPtr->nextPtr = dispPtr->selectionInfoPtr;
	dispPtr->selectionInfoPtr = infoPtr;
    } else if (infoPtr->clearProc != NULL) {
	if (infoPtr->owner != tkwin) {
	    clearProc = infoPtr->clearProc;
	    clearData = infoPtr->clearData;
	} else if (infoPtr->clearProc == LostSelection) {
	    /*
	     * If the selection handler is one created by "selection own", be
	     * sure to free the record for it; otherwise there will be a
	     * memory leak.
	     */

	    ckfree((char *) infoPtr->clearData);
	}
    }

    infoPtr->owner = tkwin;
    infoPtr->serial = NextRequest(winPtr->display);
    infoPtr->clearProc = proc;
    infoPtr->clearData = clientData;

    /*
     * Note that we are using CurrentTime, even though ICCCM recommends
     * against this practice (the problem is that we don't necessarily have a
     * valid time to use). We will not be able to retrieve a useful timestamp
     * for the TIMESTAMP target later.
     */

    infoPtr->time = CurrentTime;

    /*
     * Note that we are not checking to see if the selection claim succeeded.
     * If the ownership does not change, then the clearProc may never be
     * invoked, and we will return incorrect information when queried for the
     * current selection owner.
     */

    XSetSelectionOwner(winPtr->display, infoPtr->selection, winPtr->window,
	    infoPtr->time);

    /*
     * Now that we are done, we can invoke clearProc without running into
     * reentrancy problems.
     */

    if (clearProc != NULL) {
	clearProc(clearData);
    }
}

/*
 *----------------------------------------------------------------------
 *
 * Tk_ClearSelection --
 *
 *	Eliminate the specified selection on tkwin's display, if there is one.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The specified selection is cleared, so that future requests to
 *	retrieve it will fail until some application owns it again. This
 *	function invokes callbacks, possibly including Tcl scripts, so any
 *	calling function should be reentrant at the point Tk_ClearSelection is
 *	invoked.
 *
 *----------------------------------------------------------------------
 */

void
Tk_ClearSelection(
    Tk_Window tkwin,		/* Window that selects a display. */
    Atom selection)		/* Selection to be cancelled. */
{
    register TkWindow *winPtr = (TkWindow *) tkwin;
    TkDisplay *dispPtr = winPtr->dispPtr;
    TkSelectionInfo *infoPtr;
    TkSelectionInfo *prevPtr;
    TkSelectionInfo *nextPtr;
    Tk_LostSelProc *clearProc = NULL;
    ClientData clearData = NULL;/* Initialization needed only to prevent
				 * compiler warning. */

    if (dispPtr->multipleAtom == None) {
	TkSelInit(tkwin);
    }

    for (infoPtr = dispPtr->selectionInfoPtr, prevPtr = NULL;
	    infoPtr != NULL; infoPtr = nextPtr) {
	nextPtr = infoPtr->nextPtr;
	if (infoPtr->selection == selection) {
	    if (prevPtr == NULL) {
		dispPtr->selectionInfoPtr = nextPtr;
	    } else {
		prevPtr->nextPtr = nextPtr;
	    }
	    break;
	}
	prevPtr = infoPtr;
    }

    if (infoPtr != NULL) {
	clearProc = infoPtr->clearProc;
	clearData = infoPtr->clearData;
	ckfree((char *) infoPtr);
    }
    XSetSelectionOwner(winPtr->display, selection, None, CurrentTime);

    if (clearProc != NULL) {
	clearProc(clearData);
    }
}

/*
 *--------------------------------------------------------------
 *
 * Tk_GetSelection --
 *
 *	Retrieve the value of a selection and pass it off (in pieces,
 *	possibly) to a given function.
 *
 * 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 the
 *	interp's result.
 *
 * Side effects:
 *	The standard X11 protocols are used to retrieve the selection. When it
 *	arrives, it is passed to proc. If the selection is very large, it will
 *	be passed to proc in several pieces. Proc should have the following
 *	structure:
 *
 *	int
 *	proc(
 *	    ClientData clientData,
 *	    Tcl_Interp *interp,
 *	    char *portion)
 *	{
 *	}
 *
 *	The interp and clientData arguments to proc will be the same as the
 *	corresponding arguments to Tk_GetSelection. The portion argument
 *	points to a character string containing part of the selection, and
 *	numBytes indicates the length of the portion, not including the
 *	terminating NULL character. If the selection arrives in several
 *	pieces, the "portion" arguments in separate calls will contain
 *	successive parts of the selection. Proc should normally return TCL_OK.
 *	If it detects an error then it should return TCL_ERROR and leave an
 *	error message in the interp's result; the remainder of the selection
 *	retrieval will be aborted.
 *
 *--------------------------------------------------------------
 */

int
Tk_GetSelection(
    Tcl_Interp *interp,		/* Interpreter to use for reporting errors. */
    Tk_Window tkwin,		/* Window on whose behalf to retrieve the
				 * selection (determines display from which to
				 * retrieve). */
    Atom selection,		/* Selection to retrieve. */
    Atom target,		/* Desired form in which selection is to be
				 * returned. */
    Tk_GetSelProc *proc,	/* Function to call to process the selection,
				 * once it has been retrieved. */
    ClientData clientData)	/* Arbitrary value to pass to proc. */
{
    TkWindow *winPtr = (TkWindow *) tkwin;
    TkDisplay *dispPtr = winPtr->dispPtr;
    TkSelectionInfo *infoPtr;
    ThreadSpecificData *tsdPtr =
	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    if (dispPtr->multipleAtom == None) {
	TkSelInit(tkwin);
    }

    /*
     * If the selection is owned by a window managed by this process, then
     * call the retrieval function directly, rather than going through the X
     * server (it's dangerous to go through the X server in this case because
     * it could result in deadlock if an INCR-style selection results).
     */

    for (infoPtr = dispPtr->selectionInfoPtr; infoPtr != NULL;
	    infoPtr = infoPtr->nextPtr) {
	if (infoPtr->selection == selection) {
	    break;
	}
    }
    if (infoPtr != NULL) {
	register TkSelHandler *selPtr;
	int offset, result, count;
	char buffer[TK_SEL_BYTES_AT_ONCE+1];
	TkSelInProgress ip;

	for (selPtr = ((TkWindow *) infoPtr->owner)->selHandlerList;
		selPtr != NULL; selPtr = selPtr->nextPtr) {
	    if (selPtr->target==target && selPtr->selection==selection) {
		break;
	    }
	}
	if (selPtr == NULL) {
	    Atom type;

	    count = TkSelDefaultSelection(infoPtr, target, buffer,
		    TK_SEL_BYTES_AT_ONCE, &type);
	    if (count > TK_SEL_BYTES_AT_ONCE) {
		Tcl_Panic("selection handler returned too many bytes");
	    }
	    if (count < 0) {
		goto cantget;
	    }
	    buffer[count] = 0;
	    result = proc(clientData, interp, buffer);
	} else {
	    offset = 0;
	    result = TCL_OK;
	    ip.selPtr = selPtr;
	    ip.nextPtr = tsdPtr->pendingPtr;
	    tsdPtr->pendingPtr = &ip;
	    while (1) {
		count = selPtr->proc(selPtr->clientData, offset, buffer,
			TK_SEL_BYTES_AT_ONCE);
		if ((count < 0) || (ip.selPtr == NULL)) {
		    tsdPtr->pendingPtr = ip.nextPtr;
		    goto cantget;
		}
		if (count > TK_SEL_BYTES_AT_ONCE) {
		    Tcl_Panic("selection handler returned too many bytes");
		}
		buffer[count] = '\0';
		result = proc(clientData, interp, buffer);
		if ((result != TCL_OK) || (count < TK_SEL_BYTES_AT_ONCE)
			|| (ip.selPtr == NULL)) {
		    break;
		}
		offset += count;
	    }
	    tsdPtr->pendingPtr = ip.nextPtr;
	}
	return result;
    }

    /*
     * The selection is owned by some other process.
     */

    return TkSelGetSelection(interp, tkwin, selection, target, proc,
	    clientData);

  cantget:
    Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection),
	    " selection doesn't exist or form \"",
	    Tk_GetAtomName(tkwin, target), "\" not defined", NULL);
    return TCL_ERROR;
}

/*
 *--------------------------------------------------------------
 *
 * Tk_SelectionObjCmd --
 *
 *	This function is invoked to process the "selection" Tcl command. See
 *	the user documentation for details on what it does.
 *
 * Results:
 *	A standard Tcl result.
 *
 * Side effects:
 *	See the user documentation.
 *
 *--------------------------------------------------------------
 */

int
Tk_SelectionObjCmd(
    ClientData clientData,	/* Main window associated with
				 * interpreter. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tk_Window tkwin = clientData;
    const char *path = NULL;
    Atom selection;
    const char *selName = NULL;
    const char *string;
    int count, index;
    Tcl_Obj **objs;
    static const char *const optionStrings[] = {
	"clear", "get", "handle", "own", NULL
    };
    enum options {
	SELECTION_CLEAR, SELECTION_GET, SELECTION_HANDLE, SELECTION_OWN
    };

    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
	return TCL_ERROR;
    }

    if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
	    &index) != TCL_OK) {
	return TCL_ERROR;
    }

    switch ((enum options) index) {
    case SELECTION_CLEAR: {
	static const char *const clearOptionStrings[] = {
	    "-displayof", "-selection", NULL
	};
	enum clearOptions { CLEAR_DISPLAYOF, CLEAR_SELECTION };
	int clearIndex;

	for (count = objc-2, objs = ((Tcl_Obj **)objv)+2; count > 0;
		count-=2, objs+=2) {
	    string = Tcl_GetString(objs[0]);
	    if (string[0] != '-') {
		break;
	    }
	    if (count < 2) {
		Tcl_AppendResult(interp, "value for \"", string,
			"\" missing", NULL);
		return TCL_ERROR;
	    }

	    if (Tcl_GetIndexFromObj(interp, objs[0], clearOptionStrings,
		    "option", 0, &clearIndex) != TCL_OK) {
		return TCL_ERROR;
	    }
	    switch ((enum clearOptions) clearIndex) {
	    case CLEAR_DISPLAYOF:
		path = Tcl_GetString(objs[1]);
		break;
	    case CLEAR_SELECTION:
		selName = Tcl_GetString(objs[1]);
		break;
	    }
	}

	if (count == 1) {
	    path = Tcl_GetString(objs[0]);
	} else if (count > 1) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?-option value ...?");
	    return TCL_ERROR;
	}
	if (path != NULL) {
	    tkwin = Tk_NameToWindow(interp, path, tkwin);
	}
	if (tkwin == NULL) {
	    return TCL_ERROR;
	}
	if (selName != NULL) {
	    selection = Tk_InternAtom(tkwin, selName);
	} else {
	    selection = XA_PRIMARY;
	}

	Tk_ClearSelection(tkwin, selection);
	break;
    }

    case SELECTION_GET: {
	Atom target;
	const char *targetName = NULL;
	Tcl_DString selBytes;
	int result;
	static const char *const getOptionStrings[] = {
	    "-displayof", "-selection", "-type", NULL
	};
	enum getOptions { GET_DISPLAYOF, GET_SELECTION, GET_TYPE };
	int getIndex;

	for (count = objc-2, objs = ((Tcl_Obj **)objv)+2; count>0;
		count-=2, objs+=2) {
	    string = Tcl_GetString(objs[0]);
	    if (string[0] != '-') {
		break;
	    }
	    if (count < 2) {
		Tcl_AppendResult(interp, "value for \"", string,
			"\" missing", NULL);
		return TCL_ERROR;
	    }

	    if (Tcl_GetIndexFromObj(interp, objs[0], getOptionStrings,
		    "option", 0, &getIndex) != TCL_OK) {
		return TCL_ERROR;
	    }

	    switch ((enum getOptions) getIndex) {
	    case GET_DISPLAYOF:
		path = Tcl_GetString(objs[1]);
		break;
	    case GET_SELECTION:
		selName = Tcl_GetString(objs[1]);
		break;
	    case GET_TYPE:
		targetName = Tcl_GetString(objs[1]);
		break;
	    }
	}

	if (path != NULL) {
	    tkwin = Tk_NameToWindow(interp, path, tkwin);
	}
	if (tkwin == NULL) {
	    return TCL_ERROR;
	}
	if (selName != NULL) {
	    selection = Tk_InternAtom(tkwin, selName);
	} else {
	    selection = XA_PRIMARY;
	}
	if (count > 1) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?-option value ...?");
	    return TCL_ERROR;
	} else if (count == 1) {
	    target = Tk_InternAtom(tkwin, Tcl_GetString(objs[0]));
	} else if (targetName != NULL) {
	    target = Tk_InternAtom(tkwin, targetName);
	} else {
	    target = XA_STRING;
	}

	Tcl_DStringInit(&selBytes);
	result = Tk_GetSelection(interp, tkwin, selection, target,
		SelGetProc, &selBytes);
	if (result == TCL_OK) {
	    Tcl_DStringResult(interp, &selBytes);
	} else {
	    Tcl_DStringFree(&selBytes);
	}
	return result;
    }

    case SELECTION_HANDLE: {
	Atom target, format;
	const char *targetName = NULL;
	const char *formatName = NULL;
	register CommandInfo *cmdInfoPtr;
	int cmdLength;
	static const char *const handleOptionStrings[] = {
	    "-format", "-selection", "-type", NULL
	};
	enum handleOptions {
	    HANDLE_FORMAT, HANDLE_SELECTION, HANDLE_TYPE
	};
	int handleIndex;

	for (count = objc-2, objs = ((Tcl_Obj **)objv)+2; count > 0;
		count-=2, objs+=2) {
	    string = Tcl_GetString(objs[0]);
	    if (string[0] != '-') {
		break;
	    }
	    if (count < 2) {
		Tcl_AppendResult(interp, "value for \"", string,
			"\" missing", NULL);
		return TCL_ERROR;
	    }

	    if (Tcl_GetIndexFromObj(interp, objs[0],handleOptionStrings,
		    "option", 0, &handleIndex) != TCL_OK) {
		return TCL_ERROR;
	    }

	    switch ((enum handleOptions) handleIndex) {
	    case HANDLE_FORMAT:
		formatName = Tcl_GetString(objs[1]);
		break;
	    case HANDLE_SELECTION:
		selName = Tcl_GetString(objs[1]);
		break;
	    case HANDLE_TYPE:
		targetName = Tcl_GetString(objs[1]);
		break;
	    }
	}

	if ((count < 2) || (count > 4)) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?-option value ...? window command");
	    return TCL_ERROR;
	}
	tkwin = Tk_NameToWindow(interp, Tcl_GetString(objs[0]), tkwin);
	if (tkwin == NULL) {
	    return TCL_ERROR;
	}
	if (selName != NULL) {
	    selection = Tk_InternAtom(tkwin, selName);
	} else {
	    selection = XA_PRIMARY;
	}

	if (count > 2) {
	    target = Tk_InternAtom(tkwin, Tcl_GetString(objs[2]));
	} else if (targetName != NULL) {
	    target = Tk_InternAtom(tkwin, targetName);
	} else {
	    target = XA_STRING;
	}
	if (count > 3) {
	    format = Tk_InternAtom(tkwin, Tcl_GetString(objs[3]));
	} else if (formatName != NULL) {
	    format = Tk_InternAtom(tkwin, formatName);
	} else {
	    format = XA_STRING;
	}
	string = Tcl_GetStringFromObj(objs[1], &cmdLength);
	if (cmdLength == 0) {
	    Tk_DeleteSelHandler(tkwin, selection, target);
	} else {
	    cmdInfoPtr = (CommandInfo *) ckalloc((unsigned) (
		    (Tk_Offset(CommandInfo, command) + 1) + cmdLength));
	    cmdInfoPtr->interp = interp;
	    cmdInfoPtr->charOffset = 0;
	    cmdInfoPtr->byteOffset = 0;
	    cmdInfoPtr->buffer[0] = '\0';
	    cmdInfoPtr->cmdLength = cmdLength;
	    memcpy(cmdInfoPtr->command, string, cmdLength + 1);
	    Tk_CreateSelHandler(tkwin, selection, target, HandleTclCommand,
		    cmdInfoPtr, format);
	}
	return TCL_OK;
    }

    case SELECTION_OWN: {
	register LostCommand *lostPtr;
	Tcl_Obj *commandObj = NULL;
	static const char *const ownOptionStrings[] = {
	    "-command", "-displayof", "-selection", NULL
	};
	enum ownOptions { OWN_COMMAND, OWN_DISPLAYOF, OWN_SELECTION };
	int ownIndex;

	for (count = objc-2, objs = ((Tcl_Obj **)objv)+2; count > 0;
		count-=2, objs+=2) {
	    string = Tcl_GetString(objs[0]);
	    if (string[0] != '-') {
		break;
	    }
	    if (count < 2) {
		Tcl_AppendResult(interp, "value for \"", string,
			"\" missing", NULL);
		return TCL_ERROR;
	    }

	    if (Tcl_GetIndexFromObj(interp, objs[0], ownOptionStrings,
		    "option", 0, &ownIndex) != TCL_OK) {
		return TCL_ERROR;
	    }

	    switch ((enum ownOptions) ownIndex) {
	    case OWN_COMMAND:
		commandObj = objs[1];
		break;
	    case OWN_DISPLAYOF:
		path = Tcl_GetString(objs[1]);
		break;
	    case OWN_SELECTION:
		selName = Tcl_GetString(objs[1]);
		break;
	    }
	}

	if (count > 2) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?-option value ...? ?window?");
	    return TCL_ERROR;
	}
	if (selName != NULL) {
	    selection = Tk_InternAtom(tkwin, selName);
	} else {
	    selection = XA_PRIMARY;
	}

	if (count == 0) {
	    TkSelectionInfo *infoPtr;
	    TkWindow *winPtr;

	    if (path != NULL) {
		tkwin = Tk_NameToWindow(interp, path, tkwin);
	    }
	    if (tkwin == NULL) {
		return TCL_ERROR;
	    }
	    winPtr = (TkWindow *)tkwin;
	    for (infoPtr = winPtr->dispPtr->selectionInfoPtr;
		    infoPtr != NULL; infoPtr = infoPtr->nextPtr) {
		if (infoPtr->selection == selection) {
		    break;
		}
	    }

	    /*
	     * Ignore the internal clipboard window.
	     */

	    if ((infoPtr != NULL)
		    && (infoPtr->owner != winPtr->dispPtr->clipWindow)) {
		Tcl_SetResult(interp, Tk_PathName(infoPtr->owner), TCL_STATIC);
	    }
	    return TCL_OK;
	}

	tkwin = Tk_NameToWindow(interp, Tcl_GetString(objs[0]), tkwin);
	if (tkwin == NULL) {
	    return TCL_ERROR;
	}
	if (count == 2) {
	    commandObj = objs[1];
	}
	if (commandObj == NULL) {
	    Tk_OwnSelection(tkwin, selection, NULL, NULL);
	    return TCL_OK;
	}
	lostPtr = (LostCommand *) ckalloc(sizeof(LostCommand));
	lostPtr->interp = interp;
	lostPtr->cmdObj = commandObj;
	Tcl_IncrRefCount(commandObj);
	Tk_OwnSelection(tkwin, selection, LostSelection, lostPtr);
	return TCL_OK;
    }
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TkSelGetInProgress --
 *
 *	This function returns a pointer to the thread-local list of pending
 *	searches.
 *
 * Results:
 *	The return value is a pointer to the first search in progress, or NULL
 *	if there are none.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

TkSelInProgress *
TkSelGetInProgress(void)
{
    ThreadSpecificData *tsdPtr =
	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    return tsdPtr->pendingPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * TkSelSetInProgress --
 *
 *	This function is used to set the thread-local list of pending
 *	searches. It is required because the pending list is kept in thread
 *	local storage.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */
void
TkSelSetInProgress(
    TkSelInProgress *pendingPtr)
{
    ThreadSpecificData *tsdPtr =
	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    tsdPtr->pendingPtr = pendingPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * TkSelDeadWindow --
 *
 *	This function is invoked just before a TkWindow is deleted. It
 *	performs selection-related cleanup.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Frees up memory associated with the selection.
 *
 *----------------------------------------------------------------------
 */

void
TkSelDeadWindow(
    register TkWindow *winPtr)	/* Window that's being deleted. */
{
    register TkSelHandler *selPtr;
    register TkSelInProgress *ipPtr;
    TkSelectionInfo *infoPtr, *prevPtr, *nextPtr;
    ThreadSpecificData *tsdPtr =
	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    /*
     * While deleting all the handlers, be careful to check whether
     * ConvertSelection or TkSelPropProc are about to process one of the
     * deleted handlers.
     */

    while (winPtr->selHandlerList != NULL) {
	selPtr = winPtr->selHandlerList;
	winPtr->selHandlerList = selPtr->nextPtr;
	for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL;
		ipPtr = ipPtr->nextPtr) {
	    if (ipPtr->selPtr == selPtr) {
		ipPtr->selPtr = NULL;
	    }
	}
	if (selPtr->proc == HandleTclCommand) {
	    /*
	     * Mark the CommandInfo as deleted and free it when we can.
	     */

	    ((CommandInfo *) selPtr->clientData)->interp = NULL;
	    Tcl_EventuallyFree(selPtr->clientData, TCL_DYNAMIC);
	}
	ckfree((char *) selPtr);
    }

    /*
     * Remove selections owned by window being deleted.
     */

    for (infoPtr = winPtr->dispPtr->selectionInfoPtr, prevPtr = NULL;
	    infoPtr != NULL; infoPtr = nextPtr) {
	nextPtr = infoPtr->nextPtr;
	if (infoPtr->owner == (Tk_Window) winPtr) {
	    if (infoPtr->clearProc == LostSelection) {
		ckfree((char *) infoPtr->clearData);
	    }
	    ckfree((char *) infoPtr);
	    infoPtr = prevPtr;
	    if (prevPtr == NULL) {
		winPtr->dispPtr->selectionInfoPtr = nextPtr;
	    } else {
		prevPtr->nextPtr = nextPtr;
	    }
	}
	prevPtr = infoPtr;
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TkSelInit --
 *
 *	Initialize selection-related information for a display.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Selection-related information is initialized.
 *
 *----------------------------------------------------------------------
 */

void
TkSelInit(
    Tk_Window tkwin)		/* Window token (used to find display to
				 * initialize). */
{
    register TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;

    /*
     * Fetch commonly-used atoms.
     */

    dispPtr->multipleAtom	= Tk_InternAtom(tkwin, "MULTIPLE");
    dispPtr->incrAtom		= Tk_InternAtom(tkwin, "INCR");
    dispPtr->targetsAtom	= Tk_InternAtom(tkwin, "TARGETS");
    dispPtr->timestampAtom	= Tk_InternAtom(tkwin, "TIMESTAMP");
    dispPtr->textAtom		= Tk_InternAtom(tkwin, "TEXT");
    dispPtr->compoundTextAtom	= Tk_InternAtom(tkwin, "COMPOUND_TEXT");
    dispPtr->applicationAtom	= Tk_InternAtom(tkwin, "TK_APPLICATION");
    dispPtr->windowAtom		= Tk_InternAtom(tkwin, "TK_WINDOW");
    dispPtr->clipboardAtom	= Tk_InternAtom(tkwin, "CLIPBOARD");

    /*
     * Using UTF8_STRING instead of the XA_UTF8_STRING macro allows us to
     * support older X servers that didn't have UTF8_STRING yet. This is
     * necessary on Unix systems. For more information, see:
     *	  http://www.cl.cam.ac.uk/~mgk25/unicode.html#x11
     */

#if !defined(__WIN32__)
    dispPtr->utf8Atom		= Tk_InternAtom(tkwin, "UTF8_STRING");
#else
    dispPtr->utf8Atom		= (Atom) 0;
#endif
}

/*
 *----------------------------------------------------------------------
 *
 * TkSelClearSelection --
 *
 *	This function is invoked to process a SelectionClear event.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Invokes the clear function for the window which lost the
 *	selection.
 *
 *----------------------------------------------------------------------
 */

void
TkSelClearSelection(
    Tk_Window tkwin,		/* Window for which event was targeted. */
    register XEvent *eventPtr)	/* X SelectionClear event. */
{
    register TkWindow *winPtr = (TkWindow *) tkwin;
    TkDisplay *dispPtr = winPtr->dispPtr;
    TkSelectionInfo *infoPtr;
    TkSelectionInfo *prevPtr;

    /*
     * Invoke clear function for window that just lost the selection. This
     * code is a bit tricky, because any callbacks due to selection changes
     * between windows managed by the process have already been made. Thus,
     * ignore the event unless it refers to the window that's currently the
     * selection owner and the event was generated after the server saw the
     * SetSelectionOwner request.
     */

    for (infoPtr = dispPtr->selectionInfoPtr, prevPtr = NULL;
	    infoPtr != NULL; infoPtr = infoPtr->nextPtr) {
	if (infoPtr->selection == eventPtr->xselectionclear.selection) {
	    break;
	}
	prevPtr = infoPtr;
    }

    if (infoPtr != NULL && (infoPtr->owner == tkwin) &&
	    (eventPtr->xselectionclear.serial >= (unsigned) infoPtr->serial)) {
	if (prevPtr == NULL) {
	    dispPtr->selectionInfoPtr = infoPtr->nextPtr;
	} else {
	    prevPtr->nextPtr = infoPtr->nextPtr;
	}

	/*
	 * Because of reentrancy problems, calling clearProc must be done
	 * after the infoPtr has been removed from the selectionInfoPtr list
	 * (clearProc could modify the list, e.g. by creating a new
	 * selection).
	 */

	if (infoPtr->clearProc != NULL) {
	    infoPtr->clearProc(infoPtr->clearData);
	}
	ckfree((char *) infoPtr);
    }
}

/*
 *--------------------------------------------------------------
 *
 * SelGetProc --
 *
 *	This function is invoked to process pieces of the selection as they
 *	arrive during "selection get" commands.
 *
 * Results:
 *	Always returns TCL_OK.
 *
 * Side effects:
 *	Bytes get appended to the dynamic string pointed to by the clientData
 *	argument.
 *
 *--------------------------------------------------------------
 */

	/* ARGSUSED */
static int
SelGetProc(
    ClientData clientData,	/* Dynamic string holding partially assembled
				 * selection. */
    Tcl_Interp *interp,		/* Interpreter used for error reporting (not
				 * used). */
    const char *portion)		/* New information to be appended. */
{
    Tcl_DStringAppend(clientData, portion, -1);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * HandleTclCommand --
 *
 *	This function acts as selection handler for handlers created by the
 *	"selection handle" command. It invokes a Tcl command to retrieve the
 *	selection.
 *
 * Results:
 *	The return value is a count of the number of bytes actually stored at
 *	buffer, or -1 if an error occurs while executing the Tcl command to
 *	retrieve the selection.
 *
 * Side effects:
 *	None except for things done by the Tcl command.
 *
 *----------------------------------------------------------------------
 */

static int
HandleTclCommand(
    ClientData clientData,	/* Information about command to execute. */
    int offset,			/* Return selection bytes starting at this
				 * offset. */
    char *buffer,		/* Place to store converted selection. */
    int maxBytes)		/* Maximum # of bytes to store at buffer. */
{
    CommandInfo *cmdInfoPtr = clientData;
    int spaceNeeded, length;
#define MAX_STATIC_SIZE 100
    char staticSpace[MAX_STATIC_SIZE];
    char *command;
    const char *string;
    Tcl_Interp *interp = cmdInfoPtr->interp;
    Tcl_DString oldResult;
    int extraBytes, charOffset, count, numChars, code;
    const char *p;

    /*
     * We must also protect the interpreter and the command from being deleted
     * too soon.
     */

    Tcl_Preserve(clientData);
    Tcl_Preserve(interp);

    /*
     * Compute the proper byte offset in the case where the last chunk split a
     * character.
     */

    if (offset == cmdInfoPtr->byteOffset) {
	charOffset = cmdInfoPtr->charOffset;
	extraBytes = strlen(cmdInfoPtr->buffer);
	if (extraBytes > 0) {
	    strcpy(buffer, cmdInfoPtr->buffer);
	    maxBytes -= extraBytes;
	    buffer += extraBytes;
	}
    } else {
	cmdInfoPtr->byteOffset = 0;
	cmdInfoPtr->charOffset = 0;
	extraBytes = 0;
	charOffset = 0;
    }

    /*
     * First, generate a command by taking the command string and appending
     * the offset and maximum # of bytes.
     */

    spaceNeeded = cmdInfoPtr->cmdLength + 30;
    if (spaceNeeded < MAX_STATIC_SIZE) {
	command = staticSpace;
    } else {
	command = (char *) ckalloc((unsigned) spaceNeeded);
    }
    sprintf(command, "%s %d %d", cmdInfoPtr->command, charOffset, maxBytes);

    /*
     * Execute the command. Be sure to restore the state of the interpreter
     * after executing the command.
     */

    Tcl_DStringInit(&oldResult);
    Tcl_DStringGetResult(interp, &oldResult);
    code = Tcl_EvalEx(interp, command, -1, TCL_EVAL_GLOBAL);
    if (code == TCL_OK) {
	string = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &length);
	count = (length > maxBytes) ? maxBytes : length;
	memcpy(buffer, string, (size_t) count);
	buffer[count] = '\0';

	/*
	 * Update the partial character information for the next retrieval if
	 * the command has not been deleted.
	 */

	if (cmdInfoPtr->interp != NULL) {
	    if (length <= maxBytes) {
		cmdInfoPtr->charOffset += Tcl_NumUtfChars(string, -1);
		cmdInfoPtr->buffer[0] = '\0';
	    } else {
		p = string;
		string += count;
		numChars = 0;
		while (p < string) {
		    p = Tcl_UtfNext(p);
		    numChars++;
		}
		cmdInfoPtr->charOffset += numChars;
		length = p - string;
		if (length > 0) {
		    strncpy(cmdInfoPtr->buffer, string, (size_t) length);
		}
		cmdInfoPtr->buffer[length] = '\0';
	    }
	    cmdInfoPtr->byteOffset += count + extraBytes;
	}
	count += extraBytes;
    } else {
	/*
	 * Something went wrong. Log errors as background errors, and silently
	 * drop everything else.
	 */

	if (code == TCL_ERROR) {
	    Tcl_AddErrorInfo(interp, "\n    (command handling selection)");
	    Tcl_BackgroundException(interp, code);
	}
	count = -1;
    }
    Tcl_DStringResult(interp, &oldResult);

    if (command != staticSpace) {
	ckfree(command);
    }

    Tcl_Release(clientData);
    Tcl_Release(interp);
    return count;
}

/*
 *----------------------------------------------------------------------
 *
 * TkSelDefaultSelection --
 *
 *	This function is called to generate selection information for a few
 *	standard targets such as TIMESTAMP and TARGETS. It is invoked only if
 *	no handler has been declared by the application.
 *
 * Results:
 *	If "target" is a standard target understood by this function, the
 *	selection is converted to that form and stored as a character string
 *	in buffer. The type of the selection (e.g. STRING or ATOM) is stored
 *	in *typePtr, and the return value is a count of the # of non-NULL
 *	bytes at buffer. If the target wasn't understood, or if there isn't
 *	enough space at buffer to hold the entire selection (no INCR-mode
 *	transfers for this stuff!), then -1 is returned.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
TkSelDefaultSelection(
    TkSelectionInfo *infoPtr,	/* Info about selection being retrieved. */
    Atom target,		/* Desired form of selection. */
    char *buffer,		/* Place to put selection characters. */
    int maxBytes,		/* Maximum # of bytes to store at buffer. */
    Atom *typePtr)		/* Store here the type of the selection, for
				 * use in converting to proper X format. */
{
    register TkWindow *winPtr = (TkWindow *) infoPtr->owner;
    TkDisplay *dispPtr = winPtr->dispPtr;

    if (target == dispPtr->timestampAtom) {
	if (maxBytes < 20) {
	    return -1;
	}
	sprintf(buffer, "0x%x", (unsigned int) infoPtr->time);
	*typePtr = XA_INTEGER;
	return strlen(buffer);
    }

    if (target == dispPtr->targetsAtom) {
	register TkSelHandler *selPtr;
	int length;
	Tcl_DString ds;

	if (maxBytes < 50) {
	    return -1;
	}
	Tcl_DStringInit(&ds);
	Tcl_DStringAppend(&ds,
		"MULTIPLE TARGETS TIMESTAMP TK_APPLICATION TK_WINDOW", -1);
	for (selPtr = winPtr->selHandlerList; selPtr != NULL;
		selPtr = selPtr->nextPtr) {
	    if ((selPtr->selection == infoPtr->selection)
		    && (selPtr->target != dispPtr->applicationAtom)
		    && (selPtr->target != dispPtr->windowAtom)) {
		const char *atomString = Tk_GetAtomName((Tk_Window) winPtr,
			selPtr->target);
		Tcl_DStringAppendElement(&ds, atomString);
	    }
	}
	length = Tcl_DStringLength(&ds);
	if (length >= maxBytes) {
	    Tcl_DStringFree(&ds);
	    return -1;
	}
	memcpy(buffer, Tcl_DStringValue(&ds), (unsigned) (1+length));
	Tcl_DStringFree(&ds);
	*typePtr = XA_ATOM;
	return length;
    }

    if (target == dispPtr->applicationAtom) {
	int length;
	Tk_Uid name = winPtr->mainPtr->winPtr->nameUid;

	length = strlen(name);
	if (maxBytes <= length) {
	    return -1;
	}
	strcpy(buffer, name);
	*typePtr = XA_STRING;
	return length;
    }

    if (target == dispPtr->windowAtom) {
	int length;
	char *name = winPtr->pathName;

	length = strlen(name);
	if (maxBytes <= length) {
	    return -1;
	}
	strcpy(buffer, name);
	*typePtr = XA_STRING;
	return length;
    }

    return -1;
}

/*
 *----------------------------------------------------------------------
 *
 * LostSelection --
 *
 *	This function is invoked when a window has lost ownership of the
 *	selection and the ownership was claimed with the command "selection
 *	own".
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	A Tcl script is executed; it can do almost anything.
 *
 *----------------------------------------------------------------------
 */

static void
LostSelection(
    ClientData clientData)	/* Pointer to LostCommand structure. */
{
    LostCommand *lostPtr = clientData;
    Tcl_Obj *objPtr;
    Tcl_Interp *interp;
    int code;

    interp = lostPtr->interp;
    Tcl_Preserve(interp);

    /*
     * Execute the command. Save the interpreter's result, if any, and restore
     * it after executing the command.
     */

    objPtr = Tcl_GetObjResult(interp);
    Tcl_IncrRefCount(objPtr);
    Tcl_ResetResult(interp);

    code = Tcl_EvalObjEx(interp, lostPtr->cmdObj, TCL_EVAL_GLOBAL);
    if (code != TCL_OK) {
	Tcl_BackgroundException(interp, code);
    }

    Tcl_SetObjResult(interp, objPtr);
    Tcl_DecrRefCount(objPtr);

    Tcl_Release(interp);

    /*
     * Free the storage for the command, since we're done with it now.
     */

    Tcl_DecrRefCount(lostPtr->cmdObj);
    ckfree((char *) lostPtr);
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */
@


1.33
log
@[Bug 3129527]: Fix buffer overflow w/ GCC 4.5 and -D_FORTIFY_SOURCE=2
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.32 2010/11/29 09:07:13 nijtmans Exp $
d195 2
a196 2
		    unsigned cmdInfoLen = sizeof(CommandInfo) +
			    ((CommandInfo *) clientData)->cmdLength - 3;
@


1.32
log
@Fix various 64-bit gcc(-4.5.2) warnings: cast from pointer to integer of different size
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.31 2010/01/02 22:52:38 dkf Exp $
d33 1
a33 1
    char command[4];		/* Command to invoke. Actual space is
d905 1
a905 1
		    sizeof(CommandInfo) - 3 + cmdLength));
d911 1
a911 1
	    strcpy(cmdInfoPtr->command, string);
@


1.31
log
@SMALL FIX: Remove useless explicit casts now that we require C89 or later.
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.30 2009/07/23 22:21:35 dkf Exp $
d173 1
a173 1
    if ((target == XA_STRING) && (winPtr->dispPtr->utf8Atom != (Atom) NULL)) {
d286 1
a286 1
    if ((target == XA_STRING) && (winPtr->dispPtr->utf8Atom != (Atom) NULL)) {
d1195 1
a1195 1
    dispPtr->utf8Atom		= (Atom) NULL;
@


1.30
log
@Fix [Bug 2441988]. Also squelch use of TkCopyAndGlobalEval, we can do better!
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.29 2009/06/29 14:35:01 das Exp $
d196 1
a196 1
			    ((CommandInfo*)clientData)->cmdLength - 3;
d198 1
a198 1
		    selPtr->clientData = (ClientData) ckalloc(cmdInfoLen);
d246 1
a246 1
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
d387 1
a387 1
	infoPtr = (TkSelectionInfo*) ckalloc(sizeof(TkSelectionInfo));
d561 1
a561 1
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
d1039 1
a1039 1
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
d1066 1
a1066 1
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
d1096 1
a1096 1
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
@


1.29
log
@Merge of TkAqua Cocoa port
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.28 2009/02/03 23:55:47 nijtmans Exp $
d46 1
a46 3
    char command[4];		/* Command to invoke. Actual space is
				 * allocated as large as necessary. This must
				 * be the last entry in the structure. */
d920 1
a920 2
	const char *script = NULL;
	int cmdLength;
d946 1
a946 1
		script = Tcl_GetString(objs[1]);
d1001 1
a1001 1
	    script = Tcl_GetString(objs[1]);
d1003 1
a1003 1
	if (script == NULL) {
d1007 1
a1007 3
	cmdLength = strlen(script);
	lostPtr = (LostCommand *)
		ckalloc((unsigned) (sizeof(LostCommand) - 3 + cmdLength));
d1009 2
a1010 1
	strcpy(lostPtr->command, script);
d1332 1
a1332 1
    int extraBytes, charOffset, count, numChars;
d1383 2
a1384 1
    if (TkCopyAndGlobalEval(interp, command) == TCL_OK) {
d1418 9
d1585 1
a1585 1
    code = TkCopyAndGlobalEval(interp, lostPtr->command);
d1599 1
@


1.28
log
@- eliminate some unnessary type casts
- some internal const decorations
- spacing
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.27 2008/12/09 21:22:56 dgp Exp $
d1196 1
a1196 1
#if !(defined(__WIN32__) || defined(MAC_OSX_TK))
@


1.27
log
@        TIP 337

        * generic/tkBind.c:     Updated callers of Tcl_BackgroundError()
        * generic/tkCanvas.c:   to use the new routine
        * generic/tkEntry.c:    Tcl_BackgroundException() as appropriate.
        * generic/tkImgBmap.c:
        * generic/tkListbox.c:
        * generic/tkSelect.c:
        * generic/tkTextDisp.c:
        * generic/tkTextWind.c:
        * macosx/tkMacOSXHLEvents.c:
        * macosx/tkMacOSXMenu.c:
        * macosx/tkMacOSXMenus.c:
        * macosx/tkMacOSXScale.c:
        * macosx/tkMacOSXWindowEvent.c:
        * unix/tkUnixScale.c:
        * unix/tkUnixWm.c:
        * win/tkWinButton.c:
        * win/tkWinMenu.c:
        * win/tkWinScrlbr.c:
        * win/tkWinWm.c:
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.26 2008/11/08 18:44:40 dkf Exp $
d677 1
a677 1
    char *path = NULL;
d679 2
a680 1
    char *selName = NULL, *string;
d758 1
a758 1
	char *targetName = NULL;
d832 2
a833 2
	char *targetName = NULL;
	char *formatName = NULL;
d922 1
a922 1
	char *script = NULL;
d1332 2
a1333 1
    char *command, *string;
@


1.26
log
@Lots of small changes to make code more pretty and C89-like.
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.25 2008/10/28 22:33:06 nijtmans Exp $
d1563 1
d1577 3
a1579 2
    if (TkCopyAndGlobalEval(interp, lostPtr->command) != TCL_OK) {
	Tcl_BackgroundError(interp);
@


1.25
log
@CONSTify TkPrintPadAmount, TkCreateFrame, TkCreateMainWindow
and Tk_ParseArgv. move TkSelGetSelection to internal stub table
(needed in tkWinTest.c)
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.24 2008/10/17 23:18:37 nijtmans Exp $
d438 1
a438 1
	(*clearProc)(clearData);
d502 1
a502 1
	(*clearProc)(clearData);
d607 1
a607 1
	    result = (*proc)(clientData, interp, buffer);
d615 1
a615 1
		count = (selPtr->proc)(selPtr->clientData, offset, buffer,
d625 1
a625 1
		result = (*proc)(clientData, interp, buffer);
d1262 1
a1262 1
	    (*infoPtr->clearProc)(infoPtr->clearData);
@


1.24
log
@Add "const" to many internal
const tables, so those will be
put by the C-compiler in the
TEXT segment in stead of the
DATA segment. This makes those
table sharable in shared libraries.
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.23 2008/10/05 18:22:21 dkf Exp $
d70 1
a70 1
			    Tcl_Interp *interp, char *portion);
d1293 1
a1293 1
    char *portion)		/* New information to be appended. */
@


1.23
log
@Greatly clean up Tk's handling of the writability of the Tcl result object.
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.22 2008/07/23 23:24:21 nijtmans Exp $
d682 1
a682 1
    static const char *optionStrings[] = {
d701 1
a701 1
	static const char *clearOptionStrings[] = {
d760 1
a760 1
	static const char *getOptionStrings[] = {
d835 1
a835 1
	static const char *handleOptionStrings[] = {
d923 1
a923 1
	static const char *ownOptionStrings[] = {
@


1.22
log
@fix [2021443] inconsistant "wrong # args" messages (for Tk)
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.21 2008/04/27 22:38:58 dkf Exp $
a1333 1
    Tcl_Obj *objPtr;
d1386 1
a1386 2
	objPtr = Tcl_GetObjResult(interp);
	string = Tcl_GetStringFromObj(objPtr, &length);
@


1.21
log
@Get rid of pre-C89-isms (esp. CONST vs const).
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.20 2007/04/17 14:36:49 dkf Exp $
d690 1
a690 1
	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
d736 1
a736 1
	    Tcl_WrongNumArgs(interp, 2, objv, "?options?");
d808 1
a808 1
	    Tcl_WrongNumArgs(interp, 2, objv, "?options?");
d874 1
a874 1
	    Tcl_WrongNumArgs(interp, 2, objv, "?options? window command");
d960 1
a960 1
	    Tcl_WrongNumArgs(interp, 2, objv, "?options? ?window?");
@


1.20
log
@Eliminate use of (VOID*) casts when calling memset or memcpy.
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.19 2005/11/22 11:16:25 dkf Exp $
d200 1
a200 1
		    selPtr->clientData = (ClientData)ckalloc(cmdInfoLen);
d324 1
a324 1
	((CommandInfo*)selPtr->clientData)->interp = NULL;
d674 1
a674 1
    Tcl_Obj *CONST objv[])	/* Argument objects. */
d676 1
a676 1
    Tk_Window tkwin = (Tk_Window) clientData;
d682 1
a682 1
    static CONST char *optionStrings[] = {
d701 1
a701 1
	static CONST char *clearOptionStrings[] = {
d760 1
a760 1
	static CONST char *getOptionStrings[] = {
d820 1
a820 1
		SelGetProc, (ClientData) &selBytes);
d835 1
a835 1
	static CONST char *handleOptionStrings[] = {
d914 1
a914 1
		    (ClientData) cmdInfoPtr, format);
d923 1
a923 1
	static CONST char *ownOptionStrings[] = {
d1006 1
a1006 1
	    Tk_OwnSelection(tkwin, selection, NULL, (ClientData) NULL);
d1010 2
a1011 2
	lostPtr = (LostCommand *) ckalloc((unsigned) (sizeof(LostCommand)
		-3 + cmdLength));
d1014 1
a1014 1
	Tk_OwnSelection(tkwin, selection, LostSelection, (ClientData) lostPtr);
d1122 1
a1122 1
	    ((CommandInfo*)selPtr->clientData)->interp = NULL;
d1295 1
a1295 1
    Tcl_DStringAppend((Tcl_DString *) clientData, portion, -1);
d1327 1
a1327 1
    CommandInfo *cmdInfoPtr = (CommandInfo *) clientData;
d1336 1
a1336 1
    CONST char *p;
d1344 1
a1344 1
    Tcl_Preserve((ClientData) interp);
d1430 1
a1430 1
    Tcl_Release((ClientData) interp);
d1495 1
a1495 1
		CONST char *atomString = Tk_GetAtomName((Tk_Window) winPtr,
d1562 1
a1562 1
    LostCommand *lostPtr = (LostCommand *) clientData;
d1567 1
a1567 1
    Tcl_Preserve((ClientData) interp);
d1585 1
a1585 1
    Tcl_Release((ClientData) interp);
@


1.20.4.1
log
@[Patch #3129527]: Fix buffer overflow w/ GCC 4.5 and -D_FORTIFY_SOURCE=2.
Just the strcpy->memcpy part, to prevent anything like [Bug #3164879]
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.20 2007/04/17 14:36:49 dkf Exp $
d912 1
a912 1
	    memcpy(cmdInfoPtr->command, string, cmdLength + 1);
@


1.19
log
@Plug potential memory leak...
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.18 2005/11/17 16:21:56 dkf Exp $
d1390 1
a1390 1
	memcpy((VOID *) buffer, (VOID *) string, (size_t) count);
@


1.18
log
@ANSIfy and reduce casting of NULL to promote readability
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.17 2005/11/14 16:29:15 dkf Exp $
d1502 1
@


1.17
log
@Fix problem in default selection handler outlined by test select-9.5
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.16 2005/10/17 22:02:44 dkf Exp $
d647 1
a647 1
	    Tk_GetAtomName(tkwin, target), "\" not defined", (char *) NULL);
d683 1
a683 1
	"clear", "get", "handle", "own", (char *) NULL
d702 1
a702 1
	    "-displayof", "-selection", (char *) NULL
d715 1
a715 1
			"\" missing", (char *) NULL);
d761 1
a761 1
	    "-displayof", "-selection", "-type", (char *) NULL
d774 1
a774 1
			"\" missing", (char *) NULL);
d836 1
a836 1
	    "-format", "-selection", "-type", (char *) NULL
d851 1
a851 1
			"\" missing", (char *) NULL);
d924 1
a924 1
	    "-command", "-displayof", "-selection", (char *) NULL
d937 1
a937 1
			"\" missing", (char *) NULL);
d1006 1
a1006 2
	    Tk_OwnSelection(tkwin, selection, (Tk_LostSelProc *) NULL,
		    (ClientData) NULL);
@


1.16
log
@Format for style and remove non-ANSI decls
@
text
@d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.15 2004/03/17 18:15:44 das Exp $
d1482 2
a1483 2
	CONST char *atomString;
	int length, atomLength;
d1488 3
a1490 2
	strcpy(buffer, "MULTIPLE TARGETS TIMESTAMP TK_APPLICATION TK_WINDOW");
	length = strlen(buffer);
d1496 1
a1496 1
		atomString = Tk_GetAtomName((Tk_Window) winPtr,
d1498 1
a1498 6
		atomLength = strlen(atomString) + 1;
		if ((length + atomLength) >= maxBytes) {
		    return -1;
		}
		sprintf(buffer+length, " %s", atomString);
		length += atomLength;
d1501 6
@


1.15
log
@Removed support for Mac OS Classic platform [Patch 918139]
@
text
@d1 1
a1 1
/* 
d4 2
a5 3
 *	This file manages the selection for the Tk toolkit,
 *	translating between the standard X ICCCM conventions
 *	and Tcl commands.
d10 2
a11 2
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
d13 1
a13 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.14 2004/01/13 02:06:00 davygrvy Exp $
d20 3
a22 3
 * When a selection handler is set up by invoking "selection handle",
 * one of the following data structures is set up to hold information
 * about the command to invoke and its interpreter.
d32 4
a35 4
				 * that is split across chunks.*/
    char command[4];		/* Command to invoke.  Actual space is
				 * allocated as large as necessary.  This
				 * must be the last entry in the structure. */
d40 2
a41 2
 * one of the following structures is created to record the Tcl command
 * to be executed when the selection is lost again.
d46 3
a48 3
    char command[4];		/* Command to invoke.  Actual space is
				 * allocated as large as necessary.  This
				 * must be the last entry in the structure. */
d52 1
a52 2
 * The structure below is used to keep each thread's pending list
 * separate.
d57 2
a58 2
				/* Topmost search in progress, or
				 * NULL if none. */
d63 1
a63 1
 * Forward declarations for procedures defined in this file:
d66 5
a70 5
static int		HandleTclCommand _ANSI_ARGS_((ClientData clientData,
			    int offset, char *buffer, int maxBytes));
static void		LostSelection _ANSI_ARGS_((ClientData clientData));
static int		SelGetProc _ANSI_ARGS_((ClientData clientData,
			    Tcl_Interp *interp, char *portion));
d77 3
a79 4
 *	This procedure is called to register a procedure
 *	as the handler for selection requests of a particular
 *	target type on a particular window for a particular
 *	selection.
d85 7
a91 7
 *	In the future, whenever the selection is in tkwin's
 *	window and someone requests the selection in the
 *	form given by target, proc will be invoked to provide
 *	part or all of the selection in the given form.  If
 *	there was already a handler declared for the given
 *	window, target and selection type, then it is replaced.
 *	Proc should have the following form:
d94 5
a98 5
 *	proc(clientData, offset, buffer, maxBytes)
 *	    ClientData clientData;
 *	    int offset;
 *	    char *buffer;
 *	    int maxBytes;
d102 10
a111 12
 *	The clientData argument to proc will be the same as
 *	the clientData argument to this procedure.  The offset
 *	argument indicates which portion of the selection to
 *	return:  skip the first offset bytes.  Buffer is a
 *	pointer to an area in which to place the converted
 *	selection, and maxBytes gives the number of bytes
 *	available at buffer.  Proc should place the selection
 *	in buffer as a string, and return a count of the number
 *	of bytes of selection actually placed in buffer (not
 *	including the terminating NULL character).  If the
 *	return value equals maxBytes, this is a sign that there
 *	is probably still more selection information available.
d117 14
a130 14
Tk_CreateSelHandler(tkwin, selection, target, proc, clientData, format)
    Tk_Window tkwin;		/* Token for window. */
    Atom selection;		/* Selection to be handled. */
    Atom target;		/* The kind of selection conversions
				 * that can be handled by proc,
				 * e.g. TARGETS or STRING. */
    Tk_SelectionProc *proc;	/* Procedure to invoke to convert
				 * selection to type "target". */
    ClientData clientData;	/* Value to pass to proc. */
    Atom format;		/* Format in which the selection
				 * information should be returned to
				 * the requestor. XA_STRING is best by
				 * far, but anything listed in the ICCCM
				 * will be tolerated (blech). */
d140 2
a141 2
     * See if there's already a handler for this target and selection on
     * this window.  If so, re-use it.  If not, create a new one.
a151 1

d153 3
a155 3
	     * Special case:  when replacing handler created by
	     * "selection handle", free up memory.  Should there be a
	     * callback to allow other clients to do this too?
d182 1
a182 2
	for (selPtr = winPtr->selHandlerList; ;
	     selPtr = selPtr->nextPtr) {
d193 2
a194 2
		     * The clientData is selection controlled memory, so
		     * we should make a copy for this selPtr.
d196 2
a197 1
		    unsigned cmdInfoLen = sizeof(CommandInfo) + 
d199 1
d208 1
a208 2
	    if ((selPtr->selection == selection)
		    && (selPtr->target == target)) {
d210 1
a210 1
		 * Looks like we had a utf-8 target already.  Leave it alone.
d231 2
a232 2
 *	The selection handler for tkwin and target is removed.  If there
 *	is no such handler then nothing happens.
d238 6
a243 6
Tk_DeleteSelHandler(tkwin, selection, target)
    Tk_Window tkwin;			/* Token for window. */
    Atom selection;			/* The selection whose handler
					 * is to be removed. */
    Atom target;			/* The target whose selection
					 * handler is to be removed. */
d248 2
a249 2
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
d254 1
a254 1
     */ 
d271 2
a272 2
    for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; 
            ipPtr = ipPtr->nextPtr) {
d292 1
a292 1
	 * for them.  Look for it and delete it as necessary.
d294 1
d299 1
a299 1
	     utf8selPtr = utf8selPtr->nextPtr) {
d310 2
a311 2
		 * This recursive call is OK, because we've
		 * changed the value of 'target'
d313 1
d341 6
a346 8
 *	From now on, requests for the selection will be directed
 *	to procedures associated with tkwin (they must have been
 *	declared with calls to Tk_CreateSelHandler).  When the
 *	selection is lost by this window, proc will be invoked
 *	(see the manual entry for details).  This procedure may
 *	invoke callbacks, including Tcl scripts, so any calling
 *	function should be reentrant at the point where
 *	Tk_OwnSelection is invoked.
d352 7
a358 8
Tk_OwnSelection(tkwin, selection, proc, clientData)
    Tk_Window tkwin;		/* Window to become new selection
				 * owner. */
    Atom selection;		/* Selection that window should own. */
    Tk_LostSelProc *proc;	/* Procedure to call when selection
				 * is taken away from tkwin. */
    ClientData clientData;	/* Arbitrary one-word argument to
				 * pass to proc. */
d364 3
a366 4
    ClientData clearData = NULL;	/* Initialization needed only to
					 * prevent compiler warning. */
    
    
d373 7
a379 7
     * This code is somewhat tricky.  First, we find the specified selection
     * on the selection list.  If the previous owner is in this process, and
     * is a different window, then we need to invoke the clearProc.  However,
     * it's dangerous to call the clearProc right now, because it could
     * invoke a Tcl script that wrecks the current state (e.g. it could
     * delete the window).  To be safe, defer the call until the end of the
     * procedure when we no longer care about the state.
d399 3
a401 3
	     * If the selection handler is one created by "selection own",
	     * be sure to free the record for it;  otherwise there will be
	     * a memory leak.
d414 4
a417 4
     * Note that we are using CurrentTime, even though ICCCM recommends against
     * this practice (the problem is that we don't necessarily have a valid
     * time to use).  We will not be able to retrieve a useful timestamp for
     * the TIMESTAMP target later.
d453 5
a457 4
 *	The specified selection is cleared, so that future requests to retrieve
 *	it will fail until some application owns it again.  This procedure
 *	invokes callbacks, possibly including Tcl scripts, so any calling
 *	function should be reentrant at the point Tk_ClearSelection is invoked.
d463 3
a465 3
Tk_ClearSelection(tkwin, selection)
    Tk_Window tkwin;		/* Window that selects a display. */
    Atom selection;		/* Selection to be cancelled. */
d473 2
a474 2
    ClientData clearData = NULL;	/* Initialization needed only to
					 * prevent compiler warning. */
d481 1
a481 1
	     infoPtr != NULL; infoPtr = nextPtr) {
d493 1
a493 1
    
d511 2
a512 2
 *	Retrieve the value of a selection and pass it off (in
 *	pieces, possibly) to a given procedure.
d515 3
a517 3
 *	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 the interp's result.
d520 3
a522 4
 *	The standard X11 protocols are used to retrieve the
 *	selection.  When it arrives, it is passed to proc.  If
 *	the selection is very large, it will be passed to proc
 *	in several pieces.  Proc should have the following
d526 4
a529 4
 *	proc(clientData, interp, portion)
 *	    ClientData clientData;
 *	    Tcl_Interp *interp;
 *	    char *portion;
d533 10
a542 11
 *	The interp and clientData arguments to proc will be the
 *	same as the corresponding arguments to Tk_GetSelection.
 *	The portion argument points to a character string
 *	containing part of the selection, and numBytes indicates
 *	the length of the portion, not including the terminating
 *	NULL character.  If the selection arrives in several pieces,
 *	the "portion" arguments in separate calls will contain
 *	successive parts of the selection.  Proc should normally
 *	return TCL_OK.  If it detects an error then it should return
 *	TCL_ERROR and leave an error message in the interp's result; the
 *	remainder of the selection retrieval will be aborted.
d548 11
a558 12
Tk_GetSelection(interp, tkwin, selection, target, proc, clientData)
    Tcl_Interp *interp;		/* Interpreter to use for reporting
				 * errors. */
    Tk_Window tkwin;		/* Window on whose behalf to retrieve
				 * the selection (determines display
				 * from which to retrieve). */
    Atom selection;		/* Selection to retrieve. */
    Atom target;		/* Desired form in which selection
				 * is to be returned. */
    Tk_GetSelProc *proc;	/* Procedure to call to process the
				 * selection, once it has been retrieved. */
    ClientData clientData;	/* Arbitrary value to pass to proc. */
d563 2
a564 2
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
d571 4
a574 5
     * If the selection is owned by a window managed by this
     * process, then call the retrieval procedure directly,
     * rather than going through the X server (it's dangerous
     * to go through the X server in this case because it could
     * result in deadlock if an INCR-style selection results).
d579 1
a579 1
	if (infoPtr->selection == selection)
d581 1
d590 2
a591 3
	     selPtr != NULL; selPtr = selPtr->nextPtr) {
	    if  ((selPtr->target == target)
		    && (selPtr->selection == selection)) {
d644 1
a644 1
    cantget:
d646 2
a647 2
	" selection doesn't exist or form \"", Tk_GetAtomName(tkwin, target),
	"\" not defined", (char *) NULL);
d656 2
a657 3
 *	This procedure is invoked to process the "selection" Tcl
 *	command.  See the user documentation for details on what
 *	it does.
d669 2
a670 2
Tk_SelectionObjCmd(clientData, interp, objc, objv)
    ClientData clientData;	/* Main window associated with
d672 3
a674 3
    Tcl_Interp *interp;		/* Current interpreter. */
    int objc;			/* Number of arguments. */
    Tcl_Obj *CONST objv[];	/* Argument objects. */
d685 4
a688 3
    enum options { SELECTION_CLEAR, SELECTION_GET, SELECTION_HANDLE,
		       SELECTION_OWN };
    
d700 12
a711 31
	case SELECTION_CLEAR: {
	    static CONST char *clearOptionStrings[] = {
		"-displayof", "-selection", (char *) NULL
	    };
	    enum clearOptions { CLEAR_DISPLAYOF, CLEAR_SELECTION };
	    int clearIndex;
	    
	    for (count = objc-2, objs = ((Tcl_Obj **)objv)+2; count > 0;
		 count-=2, objs+=2) {
		string = Tcl_GetString(objs[0]);
		if (string[0] != '-') {
		    break;
		}
		if (count < 2) {
		    Tcl_AppendResult(interp, "value for \"", string,
			    "\" missing", (char *) NULL);
		    return TCL_ERROR;
		}

		if (Tcl_GetIndexFromObj(interp, objs[0], clearOptionStrings,
			"option", 0, &clearIndex) != TCL_OK) {
		    return TCL_ERROR;
		}
		switch ((enum clearOptions) clearIndex) {
		    case CLEAR_DISPLAYOF:
			path = Tcl_GetString(objs[1]);
			break;
		    case CLEAR_SELECTION:
			selName = Tcl_GetString(objs[1]);
			break;
		}
d713 3
a715 4
	    if (count == 1) {
		path = Tcl_GetString(objs[0]);
	    } else if (count > 1) {
		Tcl_WrongNumArgs(interp, 2, objv, "?options?");
d718 3
a720 4
	    if (path != NULL) {
		tkwin = Tk_NameToWindow(interp, path, tkwin);
	    }
	    if (tkwin == NULL) {
d723 7
a729 4
	    if (selName != NULL) {
		selection = Tk_InternAtom(tkwin, selName);
	    } else {
		selection = XA_PRIMARY;
a730 3
	    
	    Tk_ClearSelection(tkwin, selection);
	    break;
d733 21
a753 27
	case SELECTION_GET: {
	    Atom target;
	    char *targetName = NULL;
	    Tcl_DString selBytes;
	    int result;
	    static CONST char *getOptionStrings[] = {
		"-displayof", "-selection", "-type", (char *) NULL
	    };
	    enum getOptions { GET_DISPLAYOF, GET_SELECTION, GET_TYPE };
	    int getIndex;
	    
	    for (count = objc-2, objs = ((Tcl_Obj **)objv)+2; count>0;
		 count-=2, objs+=2) {
		string = Tcl_GetString(objs[0]);
		if (string[0] != '-') {
		    break;
		}
		if (count < 2) {
		    Tcl_AppendResult(interp, "value for \"", string,
			    "\" missing", (char *) NULL);
		    return TCL_ERROR;
		}
		
		if (Tcl_GetIndexFromObj(interp, objs[0], getOptionStrings,
			"option", 0, &getIndex) != TCL_OK) {
		    return TCL_ERROR;
		}
d755 16
a770 11
		switch ((enum getOptions) getIndex) {
		    case GET_DISPLAYOF:
			path = Tcl_GetString(objs[1]);
			break;
		    case GET_SELECTION:
			selName = Tcl_GetString(objs[1]);
			break;
		    case GET_TYPE:
			targetName = Tcl_GetString(objs[1]);
			break;
		}
d772 3
a774 4
	    if (path != NULL) {
		tkwin = Tk_NameToWindow(interp, path, tkwin);
	    }
	    if (tkwin == NULL) {
d777 3
a779 7
	    if (selName != NULL) {
		selection = Tk_InternAtom(tkwin, selName);
	    } else {
		selection = XA_PRIMARY;
	    }
	    if (count > 1) {
		Tcl_WrongNumArgs(interp, 2, objv, "?options?");
a780 6
	    } else if (count == 1) {
		target = Tk_InternAtom(tkwin, Tcl_GetString(objs[0]));
	    } else if (targetName != NULL) {
		target = Tk_InternAtom(tkwin, targetName);
	    } else {
		target = XA_STRING;
d783 10
a792 7
	    Tcl_DStringInit(&selBytes);
	    result = Tk_GetSelection(interp, tkwin, selection, target,
		    SelGetProc,	(ClientData) &selBytes);
	    if (result == TCL_OK) {
		Tcl_DStringResult(interp, &selBytes);
	    } else {
		Tcl_DStringFree(&selBytes);
a793 1
	    return result;
d796 21
a816 24
	case SELECTION_HANDLE: {
	    Atom target, format;
	    char *targetName = NULL;
	    char *formatName = NULL;
	    register CommandInfo *cmdInfoPtr;
	    int cmdLength;
	    static CONST char *handleOptionStrings[] = {
		"-format", "-selection", "-type", (char *) NULL
	    };
	    enum handleOptions { HANDLE_FORMAT, HANDLE_SELECTION,
				     HANDLE_TYPE };
	    int handleIndex;
	    
	    for (count = objc-2, objs = ((Tcl_Obj **)objv)+2; count > 0;
		 count-=2, objs+=2) {
		string = Tcl_GetString(objs[0]);
		if (string[0] != '-') {
		    break;
		}
		if (count < 2) {
		    Tcl_AppendResult(interp, "value for \"", string,
			    "\" missing", (char *) NULL);
		    return TCL_ERROR;
		}
d818 10
a827 4
		if (Tcl_GetIndexFromObj(interp, objs[0],handleOptionStrings,
			"option", 0, &handleIndex) != TCL_OK) {
		    return TCL_ERROR;
		}
d829 24
a852 11
		switch ((enum handleOptions) handleIndex) {
		    case HANDLE_FORMAT:
			formatName = Tcl_GetString(objs[1]);
			break;
		    case HANDLE_SELECTION:
			selName = Tcl_GetString(objs[1]);
			break;
		    case HANDLE_TYPE:
			targetName = Tcl_GetString(objs[1]);
			break;
		}
d855 2
a856 2
	    if ((count < 2) || (count > 4)) {
		Tcl_WrongNumArgs(interp, 2, objv, "?options? window command");
d859 11
a869 3
	    tkwin = Tk_NameToWindow(interp, Tcl_GetString(objs[0]), tkwin);
	    if (tkwin == NULL) {
		return TCL_ERROR;
d871 63
a933 4
	    if (selName != NULL) {
		selection = Tk_InternAtom(tkwin, selName);
	    } else {
		selection = XA_PRIMARY;
d935 4
a938 7
	    
	    if (count > 2) {
		target = Tk_InternAtom(tkwin, Tcl_GetString(objs[2]));
	    } else if (targetName != NULL) {
		target = Tk_InternAtom(tkwin, targetName);
	    } else {
		target = XA_STRING;
d940 4
a943 6
	    if (count > 3) {
		format = Tk_InternAtom(tkwin, Tcl_GetString(objs[3]));
	    } else if (formatName != NULL) {
		format = Tk_InternAtom(tkwin, formatName);
	    } else {
		format = XA_STRING;
d945 11
a955 14
	    string = Tcl_GetStringFromObj(objs[1], &cmdLength);
	    if (cmdLength == 0) {
		Tk_DeleteSelHandler(tkwin, selection, target);
	    } else {
		cmdInfoPtr = (CommandInfo *) ckalloc((unsigned) (
		    sizeof(CommandInfo) - 3 + cmdLength));
		cmdInfoPtr->interp = interp;
		cmdInfoPtr->charOffset = 0;
		cmdInfoPtr->byteOffset = 0;
		cmdInfoPtr->buffer[0] = '\0';
		cmdInfoPtr->cmdLength = cmdLength;
		strcpy(cmdInfoPtr->command, string);
		Tk_CreateSelHandler(tkwin, selection, target, HandleTclCommand,
			(ClientData) cmdInfoPtr, format);
a956 1
	    return TCL_OK;
a957 22
	
	case SELECTION_OWN: {
	    register LostCommand *lostPtr;
	    char *script = NULL;
	    int cmdLength;
	    static CONST char *ownOptionStrings[] = {
		"-command", "-displayof", "-selection", (char *) NULL
	    };
	    enum ownOptions { OWN_COMMAND, OWN_DISPLAYOF, OWN_SELECTION };
	    int ownIndex;
	    
	    for (count = objc-2, objs = ((Tcl_Obj **)objv)+2; count > 0;
		 count-=2, objs+=2) {
		string = Tcl_GetString(objs[0]);
		if (string[0] != '-') {
		    break;
		}
		if (count < 2) {
		    Tcl_AppendResult(interp, "value for \"", string,
			    "\" missing", (char *) NULL);
		    return TCL_ERROR;
		}
d959 13
a971 4
		if (Tcl_GetIndexFromObj(interp, objs[0], ownOptionStrings,
			"option", 0, &ownIndex) != TCL_OK) {
		    return TCL_ERROR;
		}
d973 2
a974 11
		switch ((enum ownOptions) ownIndex) {
		    case OWN_COMMAND:
			script = Tcl_GetString(objs[1]);
			break;
		    case OWN_DISPLAYOF:
			path = Tcl_GetString(objs[1]);
			break;
		    case OWN_SELECTION:
			selName = Tcl_GetString(objs[1]);
			break;
		}
d976 1
a976 3
	    
	    if (count > 2) {
		Tcl_WrongNumArgs(interp, 2, objv, "?options? ?window?");
d979 5
a983 10
	    if (selName != NULL) {
		selection = Tk_InternAtom(tkwin, selName);
	    } else {
		selection = XA_PRIMARY;
	    }
	    if (count == 0) {
		TkSelectionInfo *infoPtr;
		TkWindow *winPtr;
		if (path != NULL) {
		    tkwin = Tk_NameToWindow(interp, path, tkwin);
a984 20
		if (tkwin == NULL) {
		    return TCL_ERROR;
		}
		winPtr = (TkWindow *)tkwin;
		for (infoPtr = winPtr->dispPtr->selectionInfoPtr;
		     infoPtr != NULL; infoPtr = infoPtr->nextPtr) {
		    if (infoPtr->selection == selection)
			break;
		}
		
		/*
		 * Ignore the internal clipboard window.
		 */
		
		if ((infoPtr != NULL)
			&& (infoPtr->owner != winPtr->dispPtr->clipWindow)) {
		    Tcl_SetResult(interp, Tk_PathName(infoPtr->owner),
			    TCL_STATIC);
		}
		return TCL_OK;
d986 8
a993 3
	    tkwin = Tk_NameToWindow(interp, Tcl_GetString(objs[0]), tkwin);
	    if (tkwin == NULL) {
		return TCL_ERROR;
a994 15
	    if (count == 2) {
		script = Tcl_GetString(objs[1]);
	    }
	    if (script == NULL) {
		Tk_OwnSelection(tkwin, selection, (Tk_LostSelProc *) NULL,
			(ClientData) NULL);
		return TCL_OK;
	    }
	    cmdLength = strlen(script);
	    lostPtr = (LostCommand *) ckalloc((unsigned) (sizeof(LostCommand)
		    -3 + cmdLength));
	    lostPtr->interp = interp;
	    strcpy(lostPtr->command, script);
	    Tk_OwnSelection(tkwin, selection, LostSelection,
		    (ClientData) lostPtr);
d997 21
d1027 2
a1028 2
 *	This procedure returns a pointer to the thread-local
 *      list of pending searches.
d1031 2
a1032 2
 *	The return value is a pointer to the first search in progress, 
 *      or NULL if there are none. 
d1041 1
a1041 1
TkSelGetInProgress _ANSI_ARGS_((void))
d1043 2
a1044 2
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
d1054 3
a1056 3
 *	This procedure is used to set the thread-local list of pending 
 *      searches.  It is required because the pending list is kept
 *      in thread local storage.
d1067 2
a1068 2
TkSelSetInProgress(pendingPtr)
    TkSelInProgress *pendingPtr;
d1070 2
a1071 2
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
d1073 1
a1073 1
   tsdPtr->pendingPtr = pendingPtr;
d1081 2
a1082 2
 *	This procedure is invoked just before a TkWindow is deleted.
 *	It performs selection-related cleanup.
d1094 2
a1095 2
TkSelDeadWindow(winPtr)
    register TkWindow *winPtr;	/* Window that's being deleted. */
d1100 2
a1101 2
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
d1112 2
a1113 2
	for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; 
                ipPtr = ipPtr->nextPtr) {
d1134 1
a1134 1
	     infoPtr != NULL; infoPtr = nextPtr) {
d1169 3
a1171 3
TkSelInit(tkwin)
    Tk_Window tkwin;		/* Window token (used to find
				 * display to initialize). */
d1190 4
a1193 5
     * Using UTF8_STRING instead of the XA_UTF8_STRING macro allows us
     * to support older X servers that didn't have UTF8_STRING yet.
     * This is necessary on Unix systems.
     * For more information, see:
     *    http://www.cl.cam.ac.uk/~mgk25/unicode.html#x11
d1208 1
a1208 1
 *	This procedure is invoked to process a SelectionClear event.
d1214 1
a1214 1
 *	Invokes the clear procedure for the window which lost the
d1221 3
a1223 3
TkSelClearSelection(tkwin, eventPtr)
    Tk_Window tkwin;		/* Window for which event was targeted. */
    register XEvent *eventPtr;	/* X SelectionClear event. */
d1231 1
a1231 1
     * Invoke clear procedure for window that just lost the selection.  This
d1233 1
a1233 1
     * between windows managed by the process have already been made.  Thus,
d1240 1
a1240 1
	 infoPtr != NULL; infoPtr = infoPtr->nextPtr) {
d1247 2
a1248 2
    if (infoPtr != NULL && (infoPtr->owner == tkwin)
	    && (eventPtr->xselectionclear.serial >= (unsigned) infoPtr->serial)) {
d1257 3
a1259 3
	 * after the infoPtr has been removed from the selectionInfoPtr
	 * list (clearProc could modify the list, e.g. by creating
	 * a new selection).
d1274 2
a1275 2
 *	This procedure is invoked to process pieces of the selection
 *	as they arrive during "selection get" commands.
d1281 2
a1282 2
 *	Bytes get appended to the dynamic string pointed to by the
 *	clientData argument.
d1289 6
a1294 6
SelGetProc(clientData, interp, portion)
    ClientData clientData;	/* Dynamic string holding partially
				 * assembled selection. */
    Tcl_Interp *interp;		/* Interpreter used for error
				 * reporting (not used). */
    char *portion;		/* New information to be appended. */
d1305 3
a1307 3
 *	This procedure acts as selection handler for handlers created
 *	by the "selection handle" command.  It invokes a Tcl command to
 *	retrieve the selection.
d1310 3
a1312 3
 *	The return value is a count of the number of bytes actually
 *	stored at buffer, or -1 if an error occurs while executing
 *	the Tcl command to retrieve the selection.
d1321 3
a1323 3
HandleTclCommand(clientData, offset, buffer, maxBytes)
    ClientData clientData;	/* Information about command to execute. */
    int offset;			/* Return selection bytes starting at this
d1325 2
a1326 2
    char *buffer;		/* Place to store converted selection. */
    int maxBytes;		/* Maximum # of bytes to store at buffer. */
d1340 2
a1341 2
     * We must also protect the interpreter and the command from being
     * deleted too soon.
d1348 2
a1349 2
     * Compute the proper byte offset in the case where the last chunk
     * split a character.
d1368 2
a1369 2
     * First, generate a command by taking the command string
     * and appending the offset and maximum # of bytes.
d1381 2
a1382 2
     * Execute the command.  Be sure to restore the state of the
     * interpreter after executing the command.
d1395 2
a1396 2
	 * Update the partial character information for the next
	 * retrieval if the command has not been deleted.
d1417 1
a1417 1
	    }		
a1429 1

d1440 3
a1442 4
 *	This procedure is called to generate selection information
 *	for a few standard targets such as TIMESTAMP and TARGETS.
 *	It is invoked only if no handler has been declared by the
 *	application.
d1445 7
a1451 8
 *	If "target" is a standard target understood by this procedure,
 *	the selection is converted to that form and stored as a
 *	character string in buffer.  The type of the selection (e.g.
 *	STRING or ATOM) is stored in *typePtr, and the return value is
 *	a count of the # of non-NULL bytes at buffer.  If the target
 *	wasn't understood, or if there isn't enough space at buffer
 *	to hold the entire selection (no INCR-mode transfers for this
 *	stuff!), then -1 is returned.
d1460 7
a1466 7
TkSelDefaultSelection(infoPtr, target, buffer, maxBytes, typePtr)
    TkSelectionInfo *infoPtr;	/* Info about selection being retrieved. */
    Atom target;		/* Desired form of selection. */
    char *buffer;		/* Place to put selection characters. */
    int maxBytes;		/* Maximum # of bytes to store at buffer. */
    Atom *typePtr;		/* Store here the type of the selection,
				 * for use in converting to proper X format. */
d1543 3
a1545 3
 *	This procedure is invoked when a window has lost ownership of
 *	the selection and the ownership was claimed with the command
 *	"selection own".
d1551 1
a1551 1
 *	A Tcl script is executed;  it can do almost anything.
d1557 2
a1558 2
LostSelection(clientData)
    ClientData clientData;		/* Pointer to LostCommand structure. */
d1566 1
a1566 1
    
d1568 2
a1569 2
     * Execute the command.  Save the interpreter's result, if any, and
     * restore it after executing the command.
d1584 1
a1584 1
    
d1591 8
@


1.14
log
@	* generic/tk3d.c:	All uses of 'panic' (the macro) changed
	* generic/tkBind.c:	to 'Tcl_Panic' (the function).  The #define
	* generic/tkBitmap.c:	of panic in tcl.h clearly states it is
	* generic/tkCanvArc.c:	deprecated in the comments.
	* generic/tkCanvBmap.c: [Tcl Patch 865264]
	* generic/tkCanvImg.c:
	* generic/tkCanvLine.c:
	* generic/tkCanvPoly.c:
	* generic/tkCanvText.c:
	* generic/tkCanvWind.c:
	* generic/tkColor.c:
	* generic/tkConfig.c:
	* generic/tkCursor.c:
	* generic/tkError.c:
	* generic/tkEvent.c:
	* generic/tkFocus.c:
	* generic/tkFont.c:
	* generic/tkFrame.c:
	* generic/tkGC.c:
	* generic/tkGrid.c:
	* generic/tkImgBmap.c:
	* generic/tkImgPhoto.c:
	* generic/tkImgUtil.c:
	* generic/tkMenu.c:
	* generic/tkObj.c:
	* generic/tkPack.c:
	* generic/tkPlace.c:
	* generic/tkRectOval.c:
	* generic/tkSelect.c:
	* generic/tkText.c:
	* generic/tkTextBTree.c:
	* generic/tkTextDisp.c:
	* generic/tkTextImage.c:
	* generic/tkTextIndex.c:
	* generic/tkTextMark.c:
	* generic/tkTextWind.c:
	* generic/tkVisual.c:
	* generic/tkWindow.c:
	* mac/tkMacAppInit.c:
	* mac/tkMacAppearanceStubs.c:
	* mac/tkMacButton.c:
	* mac/tkMacDraw.c:
	* mac/tkMacEmbed.c:
	* mac/tkMacFont.c:
	* mac/tkMacInit.c:
	* mac/tkMacMenus.c:
	* mac/tkMacPort.h:
	* mac/tkMacSubwindows.c:
	* mac/tkMacWm.c:
	* mac/tkMacXStubs.c:
	* macosx/tkMacOSXEmbed.c:
	* macosx/tkMacOSXFont.c:
	* macosx/tkMacOSXMenus.c:
	* macosx/tkMacOSXNotify.c:
	* macosx/tkMacOSXPort.h:
	* macosx/tkMacOSXSubwindows.c:
	* macosx/tkMacOSXWm.c:
	* macosx/tkMacOSXXStubs.c:
	* unix/tkUnix3d.c:
	* unix/tkUnixColor.c:
	* unix/tkUnixEmbed.c:
	* unix/tkUnixEvent.c:
	* unix/tkUnixFocus.c:
	* unix/tkUnixFont.c:
	* unix/tkUnixSelect.c:
	* unix/tkUnixSend.c:
	* unix/tkUnixWm.c:
	* win/tkWin3d.c:
	* win/tkWinButton.c:
	* win/tkWinColor.c:
	* win/tkWinDialog.c:
	* win/tkWinDraw.c:
	* win/tkWinEmbed.c:
	* win/tkWinFont.c:
	* win/tkWinPixmap.c:
	* win/tkWinPointer.c:
	* win/tkWinScrlbr.c:
	* win/tkWinWm.c:
	* win/tkWinX.c:
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.13 2003/01/14 19:24:56 jenglish Exp $
d1203 1
a1203 1
#if !(defined(__WIN32__) || defined(MAC_TCL) || defined(MAC_OSX_TK))
@


1.13
log
@* generic/tkSelect.c (Tk_CreateSelHandler):
Fix for #666346 "Selection handling crashes under KDE 3.0"
* tests/unixSelect.test (unixSelect-1.20): Added test case.
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.12 2002/08/31 06:12:26 das Exp $
d612 1
a612 1
		panic("selection handler returned too many bytes");
d633 1
a633 1
		    panic("selection handler returned too many bytes");
@


1.13.2.1
log
@Backport of fixes for [Bug 1353414]
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.13 2003/01/14 19:24:56 jenglish Exp $
d1492 2
a1493 2
	int length;
	Tcl_DString ds;
d1498 2
a1499 3
	Tcl_DStringInit(&ds);
	Tcl_DStringAppend(&ds,
		"MULTIPLE TARGETS TIMESTAMP TK_APPLICATION TK_WINDOW", -1);
d1505 1
a1505 1
		CONST char *atomString = Tk_GetAtomName((Tk_Window) winPtr,
d1507 6
a1512 1
		Tcl_DStringAppendElement(&ds, atomString);
a1514 7
	length = Tcl_DStringLength(&ds);
	if (length >= maxBytes) {
	    Tcl_DStringFree(&ds);
	    return -1;
	}
	memcpy(buffer, Tcl_DStringValue(&ds), (unsigned) (1+length));
	Tcl_DStringFree(&ds);
@


1.13.2.2
log
@[Patch #3129527]: Fix buffer overflow w/ GCC 4.5 and -D_FORTIFY_SOURCE=2.
Just the strcpy->memcpy part, to prevent anything like [Bug #3164879]
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.13.2.1 2005/11/22 11:32:37 dkf Exp $
d920 1
a920 1
		memcpy(cmdInfoPtr->command, string, cmdLength + 1);
d1019 1
a1019 1
	    memcpy(lostPtr->command, script, cmdLength + 1);
@


1.12
log
@	*** macosx-8-4-branch merged into the mainline [tcl patch #602770] ***

	* generic/tk.decls:
	* generic/tkInt.decls: added new "aqua" specific entries to the
	stubs tables. Changed all "unix" entries to "x11" to allow us to
	distinguish and build both "aqua" on MacOSX and "x11" on MacOSX.

	* generic/tk.h: added a #ifnded RESOURCE_INCLUDED so that tk.h can
	be passed to the resource compiler.

	* generic/tkCmds.c (Tk_TkObjCmd): added [tk windowingsystem]
	subcommand: returns "x11" when running on X11, "win32" on Windows,
	"classic" on MacOS9 and "aqua" on MacOSX Aqua (i.e. Carbon)

	* generic/tkFont.c (TkFontGetFirstTextLayout): new private function
	returning the first chunk of a Tk_TextLayout, i.e. until the first
	font change on the first line (or the whole first line if there is
	no such font change).

	* generic/tkMain.c: made Tcl_ThreadDataKey static

	* library/demos/puzzle.tcl: fixed button metrics for aqua

	* tests/cursor.test: check for presence of arrow cursor instead of
	heart cursor

	* xlib/xcolors.c: changed xColors static initialization to more
	standard C

	* macosx/Wish.pbproj/jingham.pbxuser (new):
	* macosx/Wish.pbproj/project.pbxproj (new): project for Apple's
	ProjectBuilder IDE.

	* macosx/Makefile (new): simple makefile for building the project
	from the command line via the ProjectBuilder tool 'pbxbuild'.

	* macosx/tkMacOSXAppInit.c (new): macosx specific AppInit looking
	for a AppMain.tcl file in its bundled Resources/Scripts folder. If
	present, argv[1] is set to that file and the Scripts folder is
	added to the auto_path. This allows tk apps to embed scripts within
	their bundle directory structure.

	* macosx/tkMacOSXInit.c (new): macosx adapted version of
	tkUnixInit.c: we initialize & cache the Carbon native encoding
	(e.g. 'macRoman') and try to find the tk script library files
	inside Tk packaged as a framework.

	* macosx/tkMacOSXNotify.c (new): new macosx specific merged
	Carbon/select-based notifier.

	* macosx/tkMacOSXEvent.c (new):
	* macosx/tkMacOSXEvent.h (new):
	* macosx/tkMacOSXKeyEvent.c (new):
	* macosx/tkMacOSXMouseEvent.c (new):
	* macosx/tkMacOSXWindowEvent.c (new): new macosx specific event
	handling functionality.

	* macosx/tkMacOSX.h (new):
	* macosx/tkMacOSXBitmap.c (new):
	* macosx/tkMacOSXButton.c (new):
	* macosx/tkMacOSXClipboard.c (new):
	* macosx/tkMacOSXColor.c (new):
	* macosx/tkMacOSXConfig.c (new):
	* macosx/tkMacOSXCursor.c (new):
	* macosx/tkMacOSXDefault.h (new):
	* macosx/tkMacOSXDialog.c (new):
	* macosx/tkMacOSXDraw.c (new):
	* macosx/tkMacOSXEmbed.c (new):
	* macosx/tkMacOSXFont.c (new):
	* macosx/tkMacOSXHLEvents.c (new):
	* macosx/tkMacOSXInt.h (new):
	* macosx/tkMacOSXKeyboard.c (new):
	* macosx/tkMacOSXMenu.c (new):
	* macosx/tkMacOSXMenubutton.c (new):
	* macosx/tkMacOSXMenus.c (new):
	* macosx/tkMacOSXPort.h (new):
	* macosx/tkMacOSXRegion.c (new):
	* macosx/tkMacOSXScale.c (new):
	* macosx/tkMacOSXScrlbr.c (new):
	* macosx/tkMacOSXSubwindows.c (new):
	* macosx/tkMacOSXTest.c (new):
	* macosx/tkMacOSXUtil.c (new):
	* macosx/tkMacOSXUtil.h (new):
	* macosx/tkMacOSXWm.c (new):
	* macosx/tkMacOSXWm.h (new):
	* macosx/tkMacOSXXStubs.c (new): macosx ports of classic mac Tk
	implementation in tk/mac.

	* macosx/tkMacOSXSend.c (new): only send to local interp
	implemented currently.

	* macosx/tkMacOSXDebug.h (new):
	* macosx/tkMacOSXDebug.c (new): new macosx specific functions for
	debugging MacOS events, regions, etc.

	* macosx/tkAboutDlg.r (new):
	* macosx/tkMacOSXApplication.r (new):
	* macosx/tkMacOSXCursors.r (new):
	* macosx/tkMacOSXLibrary.r (new):
	* macosx/tkMacOSXMenu.r (new):
	* macosx/tkMacOSXResource.r (new):
	* macosx/tkMacOSXXCursors.r (new):
	* macosx/tclets.r (new): sources for Rez resource compiler.

	* macosx/Wish.icns (new): Wish application icon.

	* generic/tk.h:
	* generic/default.h:
	* generic/tkBind.c:
	* generic/tkCmds.c:
	* generic/tkGrab.c:
	* generic/tkPointer.c:
	* generic/tkPort.h:
	* generic/tkSelect.c:
	* generic/tkStubLib.c:
	* generic/tkTest.c:
	* generic/tkText.c:
	* generic/tkWindow.c:
	* unix/tkUnix3d.c:
	* xlib/xgc.c:
	* xlib/X11/X.h:
	* xlib/X11/Xlib.h:
	* xlib/X11/Xutil.h: added #includes and #ifdefs for macosx

	* library/bgerror.tcl:
	* library/button.tcl:
	* library/console.tcl:
	* library/dialog.tcl:
	* library/entry.tcl:
	* library/listbox.tcl:
	* library/menu.tcl:
	* library/msgbox.tcl:
	* library/scrlbar.tcl:
	* library/spinbox.tcl:
	* library/text.tcl:
	* library/tk.tcl:
	* library/demos/menu.tcl:
	* library/demos/menubu.tcl:
	* library/demos/widget: check [tk windowingsystem] instead of
	and/or in addition to $tcl_platform(platform).

	* generic/tkInt.h:
	* mac/tkMacBitmap.c:
	* mac/tkMacWm.c: added missing CONSTification

	* generic/tkIntDecls.h:
	* generic/tkIntPlatDecls.h:
	* generic/tkIntXlibDecls.h:
	* generic/tkPlatDecls.h:
	* generic/tkStubInit.c: regen
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id$
d203 4
a206 3
		    selPtr->clientData =
			(ClientData) ckalloc(sizeof(clientData));
		    memcpy(selPtr->clientData, clientData, sizeof(clientData));
@


1.11
log
@Applied companion patch for Tcl Patch 585105,
updating Tk to use Tcl 8.4's fully CONST-ified
interface, and fully CONSTifying Tk at the
same time.

This patch includes purging Tk of its last
direct access to interp->result.  [Bug 589853]

The substantial changes include copying
event sequence strings into Tcl_DStrings
in tkBind.c, and copying [text] indices into
Tcl_DStrings because parsing them involved
overwriting them.  If this causes performance
trouble, that can be resolved by further
converting them to Tcl_Obj's.

The #defines USE_NON_CONST and USE_COMPAT_CONST
have the same effect for Tk as they do for Tcl.
(They actually change tcl.h)
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.10 2002/01/17 05:13:11 dgp Exp $
d1202 1
a1202 1
#if !defined(__WIN32__) && !defined(MAC_TCL)
@


1.10
log
@	* Updates to handle change in type of tablePtr
        argument of Tcl_GetIndexFromObj(Struct) from (char **) to
        (CONST char **).  [TIP 27] [Patch 504705]
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.9 2002/01/17 03:35:00 dgp Exp $
d1491 1
a1491 1
	char *atomString;
d1520 1
a1520 1
	char *name = winPtr->mainPtr->winPtr->nameUid;
@


1.9
log
@	* Updated callers of Tcl_Utf* and Tcl_Regexp* APIs to reflect TIP 27
	API changes (see Tcl Patch 471509). [Patch 471513]
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.8 2002/01/04 16:35:04 dgp Exp $
d693 3
a695 2
    static char *optionStrings[] = { "clear", "get", "handle", "own",
					 (char *) NULL };
d711 3
a713 2
	    static char *clearOptionStrings[] = { "-displayof", "-selection",
						      (char *) NULL };
d769 3
a771 2
	    static char *getOptionStrings[] = { "-displayof", "-selection",
						    "-type", (char *) NULL };
d843 3
a845 2
	    static char *handleOptionStrings[] = { "-format", "-selection",
						    "-type", (char *) NULL };
d930 1
a930 1
	    static char *ownOptionStrings[] = {
@


1.8
log
@	* generic/tkBind.c (TkBindFree):
        * generic/tkGrid.c (ResolveConstraints,CheckSlotData,DestroyGrid):
        * generic/tkSelect.c (Tk_DeleteSelHandler,TkSelDeadWindow): Replaced
        Tcl_Free calls with ckfree so that memory debugging is fully supported.
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.7 2001/07/03 01:03:16 hobbs Exp $
d1339 1
a1339 1
    char *p;
@


1.7
log
@	* library/console.tcl:
	* library/entry.tcl:
	* library/spinbox.tcl:
	* library/text.tcl:
	* library/tk.tcl: added private ::tk::GetSelection command to
	handle requesting selection.  This is to support requesting
	UTF8_STRING before generic STRING on Unix.  Changed Text, Spinbox,
	Entry and Console to use this command.

	* tests/select.test:
	* generic/tkSelect.c (Tk_CreateSelHandler, Tk_DeleteSelHandler):
	on Unix, a UTF8_STRING handler will be created when the user
	requests a STRING handler (in addition to the STRING handler).
	This provides implicit support for the new UTF8_STRING selection
	target.
	* unix/tkUnixSelect.c (TkSelEventProc, ConvertSelection): Added
	support for UTF8_STRING target. [RFE #418653, Patch #433283]

	* generic/tkInt.h: added utf8Atom to TkDisplay structure.
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.6 2000/08/07 21:49:16 ericm Exp $
d328 1
a328 1
	Tcl_EventuallyFree(selPtr->clientData, Tcl_Free);
d1125 1
a1125 1
	    Tcl_EventuallyFree(selPtr->clientData, Tcl_Free);
@


1.7.2.1
log
@First checkin of support for Tk on Mac OS X.
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id$
d1198 1
a1198 1
#if !(defined(__WIN32__) || defined(MAC_TCL) || defined(MAC_OSX_TCL))
@


1.7.2.2
log
@Rest of the updated files for the MAC_OSX_TCL -> MAC_OSX_TK conversion.
@
text
@d1198 1
a1198 1
#if !(defined(__WIN32__) || defined(MAC_TCL) || defined(MAC_OSX_TK))
@


1.7.2.3
log
@Merge with current TOT
Added support for the wm stackorder command
Fixed crash when selecting Menu items in the Application menu that we didn't
put there.
Added first bits of the use of CG for low-level drawing.  The line-drawing works,
the rest doesn't yet.  You have to set the file static useCGDrawing to 1 and
rebuild to activate this code.
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.7.2.2 2001/10/17 07:10:46 wolfsuit Exp $
d328 1
a328 1
	Tcl_EventuallyFree(selPtr->clientData, TCL_DYNAMIC);
d693 2
a694 3
    static CONST char *optionStrings[] = {
	"clear", "get", "handle", "own", (char *) NULL
    };
d710 2
a711 3
	    static CONST char *clearOptionStrings[] = {
		"-displayof", "-selection", (char *) NULL
	    };
d767 2
a768 3
	    static CONST char *getOptionStrings[] = {
		"-displayof", "-selection", "-type", (char *) NULL
	    };
d840 2
a841 3
	    static CONST char *handleOptionStrings[] = {
		"-format", "-selection", "-type", (char *) NULL
	    };
d926 1
a926 1
	    static CONST char *ownOptionStrings[] = {
d1125 1
a1125 1
	    Tcl_EventuallyFree(selPtr->clientData, TCL_DYNAMIC);
d1339 1
a1339 1
    CONST char *p;
@


1.7.2.4
log
@merged with trunk at tag macosx-8-4-merge-2002-08-20-trunk
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id$
d1491 1
a1491 1
	CONST char *atomString;
d1520 1
a1520 1
	Tk_Uid name = winPtr->mainPtr->winPtr->nameUid;
@


1.6
log
@* generic/tkWindow.c: Updated [selection] command entry to use
new Tcl_Obj interface.

* generic/tkInt.h: Replaced Tk_SelectionCmd prototype with
Tk_SelectionObjCmd prototype.

* tests/select.test: Updated test suite to recognize standardized
error messages.

* generic/tkSelect.c (Tk_SelectionObjCmd): Tcl_Obj'ified
[selection] command.
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.5 1999/08/13 17:52:13 redman Exp $
d180 42
d292 30
d599 2
a600 2
		selPtr != NULL; selPtr = selPtr->nextPtr) {
	    if ((selPtr->target == target)
d926 3
a928 4
	    static char *ownOptionStrings[] = { "-command",
						    "-displayof",
						    "-selection",
						    (char *) NULL };
d1121 1
a1121 1
	     * Mark the CommandInfo as deleted and free it if we can.
d1180 23
a1202 9
    dispPtr->multipleAtom = Tk_InternAtom(tkwin, "MULTIPLE");
    dispPtr->incrAtom = Tk_InternAtom(tkwin, "INCR");
    dispPtr->targetsAtom = Tk_InternAtom(tkwin, "TARGETS");
    dispPtr->timestampAtom = Tk_InternAtom(tkwin, "TIMESTAMP");
    dispPtr->textAtom = Tk_InternAtom(tkwin, "TEXT");
    dispPtr->compoundTextAtom = Tk_InternAtom(tkwin, "COMPOUND_TEXT");
    dispPtr->applicationAtom = Tk_InternAtom(tkwin, "TK_APPLICATION");
    dispPtr->windowAtom = Tk_InternAtom(tkwin, "TK_WINDOW");
    dispPtr->clipboardAtom = Tk_InternAtom(tkwin, "CLIPBOARD");
@


1.6.2.1
log
@sync with head
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.10 2002/01/17 05:13:11 dgp Exp $
a179 42

    if ((target == XA_STRING) && (winPtr->dispPtr->utf8Atom != (Atom) NULL)) {
	/*
	 * If the user asked for a STRING handler and we understand
	 * UTF8_STRING, we implicitly create a UTF8_STRING handler for them.
	 */

	target = winPtr->dispPtr->utf8Atom;
	for (selPtr = winPtr->selHandlerList; ;
	     selPtr = selPtr->nextPtr) {
	    if (selPtr == NULL) {
		selPtr = (TkSelHandler *) ckalloc(sizeof(TkSelHandler));
		selPtr->nextPtr = winPtr->selHandlerList;
		winPtr->selHandlerList = selPtr;
		selPtr->selection = selection;
		selPtr->target = target;
		selPtr->format = target; /* We want UTF8_STRING format */
		selPtr->proc = proc;
		if (selPtr->proc == HandleTclCommand) {
		    /*
		     * The clientData is selection controlled memory, so
		     * we should make a copy for this selPtr.
		     */
		    selPtr->clientData =
			(ClientData) ckalloc(sizeof(clientData));
		    memcpy(selPtr->clientData, clientData, sizeof(clientData));
		} else {
		    selPtr->clientData = clientData;
		}
		selPtr->size = 8;
		break;
	    }
	    if ((selPtr->selection == selection)
		    && (selPtr->target == target)) {
		/*
		 * Looks like we had a utf-8 target already.  Leave it alone.
		 */

		break;
	    }
	}
    }
a249 30

    if ((target == XA_STRING) && (winPtr->dispPtr->utf8Atom != (Atom) NULL)) {
	/*
	 * If the user asked for a STRING handler and we understand
	 * UTF8_STRING, we may have implicitly created a UTF8_STRING handler
	 * for them.  Look for it and delete it as necessary.
	 */
	TkSelHandler *utf8selPtr;

	target = winPtr->dispPtr->utf8Atom;
	for (utf8selPtr = winPtr->selHandlerList; utf8selPtr != NULL;
	     utf8selPtr = utf8selPtr->nextPtr) {
	    if ((utf8selPtr->selection == selection)
		    && (utf8selPtr->target == target)) {
		break;
	    }
	}
	if (utf8selPtr != NULL) {
	    if ((utf8selPtr->format == target)
		    && (utf8selPtr->proc == selPtr->proc)
		    && (utf8selPtr->size == selPtr->size)) {
		/*
		 * This recursive call is OK, because we've
		 * changed the value of 'target'
		 */
		Tk_DeleteSelHandler(tkwin, selection, target);
	    }
	}
    }

d256 1
a256 1
	Tcl_EventuallyFree(selPtr->clientData, TCL_DYNAMIC);
d527 2
a528 2
	     selPtr != NULL; selPtr = selPtr->nextPtr) {
	    if  ((selPtr->target == target)
d621 2
a622 3
    static CONST char *optionStrings[] = {
	"clear", "get", "handle", "own", (char *) NULL
    };
d638 2
a639 3
	    static CONST char *clearOptionStrings[] = {
		"-displayof", "-selection", (char *) NULL
	    };
d695 2
a696 3
	    static CONST char *getOptionStrings[] = {
		"-displayof", "-selection", "-type", (char *) NULL
	    };
d768 2
a769 3
	    static CONST char *handleOptionStrings[] = {
		"-format", "-selection", "-type", (char *) NULL
	    };
d854 4
a857 3
	    static CONST char *ownOptionStrings[] = {
		"-command", "-displayof", "-selection", (char *) NULL
	    };
d1050 1
a1050 1
	     * Mark the CommandInfo as deleted and free it when we can.
d1054 1
a1054 1
	    Tcl_EventuallyFree(selPtr->clientData, TCL_DYNAMIC);
d1109 9
a1117 23
    dispPtr->multipleAtom	= Tk_InternAtom(tkwin, "MULTIPLE");
    dispPtr->incrAtom		= Tk_InternAtom(tkwin, "INCR");
    dispPtr->targetsAtom	= Tk_InternAtom(tkwin, "TARGETS");
    dispPtr->timestampAtom	= Tk_InternAtom(tkwin, "TIMESTAMP");
    dispPtr->textAtom		= Tk_InternAtom(tkwin, "TEXT");
    dispPtr->compoundTextAtom	= Tk_InternAtom(tkwin, "COMPOUND_TEXT");
    dispPtr->applicationAtom	= Tk_InternAtom(tkwin, "TK_APPLICATION");
    dispPtr->windowAtom		= Tk_InternAtom(tkwin, "TK_WINDOW");
    dispPtr->clipboardAtom	= Tk_InternAtom(tkwin, "CLIPBOARD");

    /*
     * Using UTF8_STRING instead of the XA_UTF8_STRING macro allows us
     * to support older X servers that didn't have UTF8_STRING yet.
     * This is necessary on Unix systems.
     * For more information, see:
     *    http://www.cl.cam.ac.uk/~mgk25/unicode.html#x11
     */

#if !defined(__WIN32__) && !defined(MAC_TCL)
    dispPtr->utf8Atom		= Tk_InternAtom(tkwin, "UTF8_STRING");
#else
    dispPtr->utf8Atom		= (Atom) NULL;
#endif
d1254 1
a1254 1
    CONST char *p;
@


1.6.4.1
log
@        * Merged in updates from HEAD branch.
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.7 2001/07/03 01:03:16 hobbs Exp $
a179 42

    if ((target == XA_STRING) && (winPtr->dispPtr->utf8Atom != (Atom) NULL)) {
	/*
	 * If the user asked for a STRING handler and we understand
	 * UTF8_STRING, we implicitly create a UTF8_STRING handler for them.
	 */

	target = winPtr->dispPtr->utf8Atom;
	for (selPtr = winPtr->selHandlerList; ;
	     selPtr = selPtr->nextPtr) {
	    if (selPtr == NULL) {
		selPtr = (TkSelHandler *) ckalloc(sizeof(TkSelHandler));
		selPtr->nextPtr = winPtr->selHandlerList;
		winPtr->selHandlerList = selPtr;
		selPtr->selection = selection;
		selPtr->target = target;
		selPtr->format = target; /* We want UTF8_STRING format */
		selPtr->proc = proc;
		if (selPtr->proc == HandleTclCommand) {
		    /*
		     * The clientData is selection controlled memory, so
		     * we should make a copy for this selPtr.
		     */
		    selPtr->clientData =
			(ClientData) ckalloc(sizeof(clientData));
		    memcpy(selPtr->clientData, clientData, sizeof(clientData));
		} else {
		    selPtr->clientData = clientData;
		}
		selPtr->size = 8;
		break;
	    }
	    if ((selPtr->selection == selection)
		    && (selPtr->target == target)) {
		/*
		 * Looks like we had a utf-8 target already.  Leave it alone.
		 */

		break;
	    }
	}
    }
a249 30

    if ((target == XA_STRING) && (winPtr->dispPtr->utf8Atom != (Atom) NULL)) {
	/*
	 * If the user asked for a STRING handler and we understand
	 * UTF8_STRING, we may have implicitly created a UTF8_STRING handler
	 * for them.  Look for it and delete it as necessary.
	 */
	TkSelHandler *utf8selPtr;

	target = winPtr->dispPtr->utf8Atom;
	for (utf8selPtr = winPtr->selHandlerList; utf8selPtr != NULL;
	     utf8selPtr = utf8selPtr->nextPtr) {
	    if ((utf8selPtr->selection == selection)
		    && (utf8selPtr->target == target)) {
		break;
	    }
	}
	if (utf8selPtr != NULL) {
	    if ((utf8selPtr->format == target)
		    && (utf8selPtr->proc == selPtr->proc)
		    && (utf8selPtr->size == selPtr->size)) {
		/*
		 * This recursive call is OK, because we've
		 * changed the value of 'target'
		 */
		Tk_DeleteSelHandler(tkwin, selection, target);
	    }
	}
    }

d527 2
a528 2
	     selPtr != NULL; selPtr = selPtr->nextPtr) {
	    if  ((selPtr->target == target)
d854 4
a857 3
	    static char *ownOptionStrings[] = {
		"-command", "-displayof", "-selection", (char *) NULL
	    };
d1050 1
a1050 1
	     * Mark the CommandInfo as deleted and free it when we can.
d1109 9
a1117 23
    dispPtr->multipleAtom	= Tk_InternAtom(tkwin, "MULTIPLE");
    dispPtr->incrAtom		= Tk_InternAtom(tkwin, "INCR");
    dispPtr->targetsAtom	= Tk_InternAtom(tkwin, "TARGETS");
    dispPtr->timestampAtom	= Tk_InternAtom(tkwin, "TIMESTAMP");
    dispPtr->textAtom		= Tk_InternAtom(tkwin, "TEXT");
    dispPtr->compoundTextAtom	= Tk_InternAtom(tkwin, "COMPOUND_TEXT");
    dispPtr->applicationAtom	= Tk_InternAtom(tkwin, "TK_APPLICATION");
    dispPtr->windowAtom		= Tk_InternAtom(tkwin, "TK_WINDOW");
    dispPtr->clipboardAtom	= Tk_InternAtom(tkwin, "CLIPBOARD");

    /*
     * Using UTF8_STRING instead of the XA_UTF8_STRING macro allows us
     * to support older X servers that didn't have UTF8_STRING yet.
     * This is necessary on Unix systems.
     * For more information, see:
     *    http://www.cl.cam.ac.uk/~mgk25/unicode.html#x11
     */

#if !defined(__WIN32__) && !defined(MAC_TCL)
    dispPtr->utf8Atom		= Tk_InternAtom(tkwin, "UTF8_STRING");
#else
    dispPtr->utf8Atom		= (Atom) NULL;
#endif
@


1.5
log
@Fixed ANSI-style function definitions so that they work on K&R
compilers properly.
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.4 1999/06/03 18:50:46 stanton Exp $
d592 1
a592 1
 * Tk_SelectionCmd --
d608 1
a608 1
Tk_SelectionCmd(clientData, interp, argc, argv)
d612 2
a613 2
    int argc;			/* Number of arguments. */
    char **argv;		/* Argument strings. */
d618 15
a632 8
    char *selName = NULL;
    int c, count;
    size_t length;
    char **args;

    if (argc < 2) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		" option ?arg arg ...?\"", (char *) NULL);
d635 41
a675 6
    c = argv[1][0];
    length = strlen(argv[1]);
    if ((c == 'c') && (strncmp(argv[1], "clear", length) == 0)) {
	for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) {
	    if (args[0][0] != '-') {
		break;
d677 1
a677 3
	    if (count < 2) {
		Tcl_AppendResult(interp, "value for \"", *args,
			"\" missing", (char *) NULL);
d680 2
a681 7
	    c = args[0][1];
	    length = strlen(args[0]);
	    if ((c == 'd') && (strncmp(args[0], "-displayof", length) == 0)) {
		path = args[1];
	    } else if ((c == 's')
		    && (strncmp(args[0], "-selection", length) == 0)) {
		selName = args[1];
d683 1
a683 3
		Tcl_AppendResult(interp, "unknown option \"", args[0],
			"\"", (char *) NULL);
		return TCL_ERROR;
d685 3
d689 10
a698 18
	if (count == 1) {
	    path = args[0];
	} else if (count > 1) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		    " clear ?options?\"", (char *) NULL);
	    return TCL_ERROR;
	}
	if (path != NULL) {
	    tkwin = Tk_NameToWindow(interp, path, tkwin);
	}
	if (tkwin == NULL) {
	    return TCL_ERROR;
	}
	if (selName != NULL) {
	    selection = Tk_InternAtom(tkwin, selName);
	} else {
	    selection = XA_PRIMARY;
	}
d700 31
a730 11
	Tk_ClearSelection(tkwin, selection);
	return TCL_OK;
    } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
	Atom target;
	char *targetName = NULL;
	Tcl_DString selBytes;
	int result;
	
	for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) {
	    if (args[0][0] != '-') {
		break;
d732 1
a732 3
	    if (count < 2) {
		Tcl_AppendResult(interp, "value for \"", *args,
			"\" missing", (char *) NULL);
d735 2
a736 10
	    c = args[0][1];
	    length = strlen(args[0]);
	    if ((c == 'd') && (strncmp(args[0], "-displayof", length) == 0)) {
		path = args[1];
	    } else if ((c == 's')
		    && (strncmp(args[0], "-selection", length) == 0)) {
		selName = args[1];
	    } else if ((c == 't')
		    && (strncmp(args[0], "-type", length) == 0)) {
		targetName = args[1];
d738 4
a741 2
		Tcl_AppendResult(interp, "unknown option \"", args[0],
			"\"", (char *) NULL);
d743 15
d759 1
a759 22
	}
	if (path != NULL) {
	    tkwin = Tk_NameToWindow(interp, path, tkwin);
	}
	if (tkwin == NULL) {
	    return TCL_ERROR;
	}
	if (selName != NULL) {
	    selection = Tk_InternAtom(tkwin, selName);
	} else {
	    selection = XA_PRIMARY;
	}
	if (count > 1) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		    " get ?options?\"", (char *) NULL);
	    return TCL_ERROR;
	} else if (count == 1) {
	    target = Tk_InternAtom(tkwin, args[0]);
	} else if (targetName != NULL) {
	    target = Tk_InternAtom(tkwin, targetName);
	} else {
	    target = XA_STRING;
d762 45
a806 19
	Tcl_DStringInit(&selBytes);
	result = Tk_GetSelection(interp, tkwin, selection, target, SelGetProc,
		(ClientData) &selBytes);
	if (result == TCL_OK) {
	    Tcl_DStringResult(interp, &selBytes);
	} else {
	    Tcl_DStringFree(&selBytes);
	}
	return result;
    } else if ((c == 'h') && (strncmp(argv[1], "handle", length) == 0)) {
	Atom target, format;
	char *targetName = NULL;
	char *formatName = NULL;
	register CommandInfo *cmdInfoPtr;
	int cmdLength;
	
	for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) {
	    if (args[0][0] != '-') {
		break;
d808 2
a809 3
	    if (count < 2) {
		Tcl_AppendResult(interp, "value for \"", *args,
			"\" missing", (char *) NULL);
d812 23
a834 10
	    c = args[0][1];
	    length = strlen(args[0]);
	    if ((c == 'f') && (strncmp(args[0], "-format", length) == 0)) {
		formatName = args[1];
	    } else if ((c == 's')
		    && (strncmp(args[0], "-selection", length) == 0)) {
		selName = args[1];
	    } else if ((c == 't')
		    && (strncmp(args[0], "-type", length) == 0)) {
		targetName = args[1];
d836 10
a845 3
		Tcl_AppendResult(interp, "unknown option \"", args[0],
			"\"", (char *) NULL);
		return TCL_ERROR;
d847 1
d849 23
d873 4
a876 49
	if ((count < 2) || (count > 4)) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		    " handle ?options? window command\"", (char *) NULL);
	    return TCL_ERROR;
	}
	tkwin = Tk_NameToWindow(interp, args[0], tkwin);
	if (tkwin == NULL) {
	    return TCL_ERROR;
	}
	if (selName != NULL) {
	    selection = Tk_InternAtom(tkwin, selName);
	} else {
	    selection = XA_PRIMARY;
	}
	    
	if (count > 2) {
	    target = Tk_InternAtom(tkwin, args[2]);
	} else if (targetName != NULL) {
	    target = Tk_InternAtom(tkwin, targetName);
	} else {
	    target = XA_STRING;
	}
	if (count > 3) {
	    format = Tk_InternAtom(tkwin, args[3]);
	} else if (formatName != NULL) {
	    format = Tk_InternAtom(tkwin, formatName);
	} else {
	    format = XA_STRING;
	}
	cmdLength = strlen(args[1]);
	if (cmdLength == 0) {
	    Tk_DeleteSelHandler(tkwin, selection, target);
	} else {
	    cmdInfoPtr = (CommandInfo *) ckalloc((unsigned) (
		    sizeof(CommandInfo) - 3 + cmdLength));
	    cmdInfoPtr->interp = interp;
	    cmdInfoPtr->charOffset = 0;
	    cmdInfoPtr->byteOffset = 0;
	    cmdInfoPtr->buffer[0] = '\0';
	    cmdInfoPtr->cmdLength = cmdLength;
	    strcpy(cmdInfoPtr->command, args[1]);
	    Tk_CreateSelHandler(tkwin, selection, target, HandleTclCommand,
		    (ClientData) cmdInfoPtr, format);
	}
	return TCL_OK;
    } else if ((c == 'o') && (strncmp(argv[1], "own", length) == 0)) {
	register LostCommand *lostPtr;
	char *script = NULL;
	int cmdLength;
d878 11
a888 3
	for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) {
	    if (args[0][0] != '-') {
		break;
d890 3
a892 3
	    if (count < 2) {
		Tcl_AppendResult(interp, "value for \"", *args,
			"\" missing", (char *) NULL);
d895 2
a896 10
	    c = args[0][1];
	    length = strlen(args[0]);
	    if ((c == 'c') && (strncmp(args[0], "-command", length) == 0)) {
		script = args[1];
	    } else if ((c == 'd')
		    && (strncmp(args[0], "-displayof", length) == 0)) {
		path = args[1];
	    } else if ((c == 's')
		    && (strncmp(args[0], "-selection", length) == 0)) {
		selName = args[1];
d898 1
a898 3
		Tcl_AppendResult(interp, "unknown option \"", args[0],
			"\"", (char *) NULL);
		return TCL_ERROR;
d900 26
a925 17
	}

	if (count > 2) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		    " own ?options? ?window?\"", (char *) NULL);
	    return TCL_ERROR;
	}
	if (selName != NULL) {
	    selection = Tk_InternAtom(tkwin, selName);
	} else {
	    selection = XA_PRIMARY;
	}
	if (count == 0) {
	    TkSelectionInfo *infoPtr;
	    TkWindow *winPtr;
	    if (path != NULL) {
		tkwin = Tk_NameToWindow(interp, path, tkwin);
d927 1
d931 2
a932 14
	    winPtr = (TkWindow *)tkwin;
	    for (infoPtr = winPtr->dispPtr->selectionInfoPtr; infoPtr != NULL;
		    infoPtr = infoPtr->nextPtr) {
		if (infoPtr->selection == selection)
		    break;
	    }

	    /*
	     * Ignore the internal clipboard window.
	     */

	    if ((infoPtr != NULL)
		    && (infoPtr->owner != winPtr->dispPtr->clipWindow)) {
		Tcl_SetResult(interp, Tk_PathName(infoPtr->owner), TCL_STATIC);
d934 12
a947 23
	tkwin = Tk_NameToWindow(interp, args[0], tkwin);
	if (tkwin == NULL) {
	    return TCL_ERROR;
	}
	if (count == 2) {
	    script = args[1];
	}
	if (script == NULL) {
	    Tk_OwnSelection(tkwin, selection, (Tk_LostSelProc *) NULL,
		    (ClientData) NULL);
	    return TCL_OK;
	}
	cmdLength = strlen(script);
	lostPtr = (LostCommand *) ckalloc((unsigned) (sizeof(LostCommand)
		-3 + cmdLength));
	lostPtr->interp = interp;
	strcpy(lostPtr->command, script);
	Tk_OwnSelection(tkwin, selection, LostSelection, (ClientData) lostPtr);
	return TCL_OK;
    } else {
	Tcl_AppendResult(interp, "bad option \"", argv[1],
		"\": must be clear, get, handle, or own", (char *) NULL);
	return TCL_ERROR;
d949 1
@


1.5.8.1
log
@	* generic/tkBind.c (TkBindFree):
        * generic/tkGrid.c (Tk_GridCmd,ResolveConstraints,CheckSlotData,
        DestroyGrid):
        * generic/tkSelect.c (Tk_DeleteSelHandler,TkSelDeadWindow): Replaced
        Tcl_Free calls with ckfree so that memory debugging is fully supported.
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.5 1999/08/13 17:52:13 redman Exp $
d256 1
a256 1
	Tcl_EventuallyFree(selPtr->clientData, TCL_DYNAMIC);
d1010 1
a1010 1
	    Tcl_EventuallyFree(selPtr->clientData, TCL_DYNAMIC);
@


1.4
log
@* unix/tkUnixSelect.c:
* tests/unixSelect.test:
* generic/tkSelect.c: Fixed selection code to handle Unicode data
in COMPOUND_TEXT and STRING selections. [Bug: 1791]
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.3 1999/04/16 01:51:21 stanton Exp $
d927 1
a927 1
TkSelGetInProgress(void)
@


1.3
log
@* Merged 8.1 branch into the main trunk
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id$
d29 5
d251 6
a256 1
	ckfree((char *) selPtr->clientData);
d806 3
d1005 6
a1010 1
	    ckfree((char *) selPtr->clientData);
d1205 2
a1206 2
    char *command;
    Tcl_Interp *interp;
d1208 3
d1213 2
a1214 4
     * We must copy the interpreter pointer from CommandInfo because the
     * command could delete the handler, freeing the CommandInfo data before we
     * are done using it. We must also protect the interpreter from being
     * deleted too soo.
d1217 1
a1217 1
    interp = cmdInfoPtr->interp;
d1221 20
d1251 1
a1251 1
    sprintf(command, "%s %d %d", cmdInfoPtr->command, offset, maxBytes);
d1261 33
a1293 7
	length = strlen(Tcl_GetStringResult(interp));
	if (length > maxBytes) {
	    length = maxBytes;
	}
	memcpy((VOID *) buffer, (VOID *) Tcl_GetStringResult(interp),
		(size_t) length);
	buffer[length] = '\0';
d1295 1
a1295 1
	length = -1;
d1303 2
d1306 1
a1306 1
    return length;
d1434 1
a1434 1
    ClientData clientData;		/* Pointer to CommandInfo structure. */
@


1.2
log
@Replaced SCCS strings, fixed binary files
@
text
@d9 1
a9 1
 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
d48 2
a49 1
 * Shared variables:
d52 2
a53 1
TkSelInProgress *pendingPtr = NULL;
d56 2
d206 2
d229 2
a230 1
    for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
d441 1
a441 1
 *	then an error message is left in interp->result.
d467 1
a467 1
 *	TCL_ERROR and leave an error message in interp->result; the
d490 2
d540 2
a541 2
	    ip.nextPtr = pendingPtr;
	    pendingPtr = &ip;
d546 1
a546 1
		    pendingPtr = ip.nextPtr;
d560 1
a560 1
	    pendingPtr = ip.nextPtr;
d614 2
a615 3
	sprintf(interp->result,
		"wrong # args: should be \"%.50s option ?arg arg ...?\"",
		argv[0]);
d865 1
a865 1
		interp->result = Tk_PathName(infoPtr->owner);
d889 2
a890 3
	sprintf(interp->result,
		"bad option \"%.50s\": must be clear, get, handle, or own",
		argv[1]);
d898 54
d973 2
d985 2
a986 1
	for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
d1222 1
a1222 1
	length = strlen(interp->result);
d1226 2
a1227 1
	memcpy((VOID *) buffer, (VOID *) interp->result, (size_t) length);
d1370 1
a1370 2
    char *oldResultString;
    Tcl_FreeProc *oldFreeProc;
d1381 4
a1384 10
    oldFreeProc = interp->freeProc;
    if (oldFreeProc != TCL_STATIC) {
	oldResultString = interp->result;
    } else {
	oldResultString = (char *) ckalloc((unsigned)
		(strlen(interp->result) + 1));
	strcpy(oldResultString, interp->result);
	oldFreeProc = TCL_DYNAMIC;
    }
    interp->freeProc = TCL_STATIC;
d1388 3
a1390 3
    Tcl_FreeResult(interp);
    interp->result = oldResultString;
    interp->freeProc = oldFreeProc;
@


1.1
log
@Initial revision
@
text
@d14 1
a14 1
 * SCCS: @@(#) tkSelect.c 1.57 96/05/03 10:52:40
@


1.1.4.1
log
@initial tk8.1a2 version
@
text
@d9 1
a9 1
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
d14 1
a14 1
 * SCCS: @@(#) tkSelect.c 1.58 97/11/07 21:17:56
d434 1
a434 1
 *	then an error message is left in the interp's result.
d460 1
a460 1
 *	TCL_ERROR and leave an error message in the interp's result; the
d605 3
a607 2
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		" option ?arg arg ...?\"", (char *) NULL);
d857 1
a857 1
		Tcl_SetResult(interp, Tk_PathName(infoPtr->owner), TCL_STATIC);
d881 3
a883 2
	Tcl_AppendResult(interp, "bad option \"", argv[1],
		"\": must be clear, get, handle, or own", (char *) NULL);
d1158 1
a1158 1
	length = strlen(Tcl_GetStringResult(interp));
d1162 1
a1162 2
	memcpy((VOID *) buffer, (VOID *) Tcl_GetStringResult(interp),
		(size_t) length);
d1305 2
a1306 1
    Tcl_Obj *objPtr;
d1317 10
a1326 4
    objPtr = Tcl_GetObjResult(interp);
    Tcl_IncrRefCount(objPtr);
    Tcl_ResetResult(interp);

d1330 3
a1332 3

    Tcl_SetObjResult(interp, objPtr);
    Tcl_DecrRefCount(objPtr);
@


1.1.4.2
log
@Merged 8.0.3 changes into 8.1
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.2 1998/09/14 18:23:17 stanton Exp $
@


1.1.4.3
log
@
Tk 8.1 Muti-threading changes.

Moved static and global data elements into thread-local storage,
or introduced locks where not possible, as first stage of adding
thread safety to Tk.
@
text
@d14 1
a14 1
 * RCS: @@(#) $Id: tkSelect.c,v 1.1.4.2 1998/09/30 02:17:18 stanton Exp $
d48 1
a48 2
 * The structure below is used to keep each thread's pending list
 * separate.
d51 1
a51 2
typedef struct ThreadSpecificData {
    TkSelInProgress *pendingPtr;
a53 2
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
a201 2
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
d223 1
a223 2
    for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; 
            ipPtr = ipPtr->nextPtr) {
a482 2
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
d531 2
a532 2
	    ip.nextPtr = tsdPtr->pendingPtr;
	    tsdPtr->pendingPtr = &ip;
d537 1
a537 1
		    tsdPtr->pendingPtr = ip.nextPtr;
d551 1
a551 1
	    tsdPtr->pendingPtr = ip.nextPtr;
a888 54
 * TkSelGetInProgress --
 *
 *	This procedure returns a pointer to the thread-local
 *      list of pending searches.
 *
 * Results:
 *	The return value is a pointer to the first search in progress, 
 *      or NULL if there are none. 
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

TkSelInProgress *
TkSelGetInProgress(void)
{
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    return tsdPtr->pendingPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * TkSelSetInProgress --
 *
 *	This procedure is used to set the thread-local list of pending 
 *      searches.  It is required because the pending list is kept
 *      in thread local storage.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */
void
TkSelSetInProgress(pendingPtr)
    TkSelInProgress *pendingPtr;
{
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

   tsdPtr->pendingPtr = pendingPtr;
}

/*
 *----------------------------------------------------------------------
 *
a909 2
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
            Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
d920 1
a920 2
	for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; 
                ipPtr = ipPtr->nextPtr) {
@


