home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tkisrc04.zip / tk / os2 / tkSelect.c < prev    next >
C/C++ Source or Header  |  1998-08-07  |  39KB  |  1,342 lines

  1. /* 
  2.  * tkSelect.c --
  3.  *
  4.  *    This file manages the selection for the Tk toolkit,
  5.  *    translating between the standard X ICCCM conventions
  6.  *    and Tcl commands.
  7.  *
  8.  * Copyright (c) 1990-1993 The Regents of the University of California.
  9.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * SCCS: @(#) tkSelect.c 1.56 96/03/21 13:16:29
  15.  */
  16.  
  17. #include "tkInt.h"
  18. #include "tkSelect.h"
  19.  
  20. /*
  21.  * When a selection handler is set up by invoking "selection handle",
  22.  * one of the following data structures is set up to hold information
  23.  * about the command to invoke and its interpreter.
  24.  */
  25.  
  26. typedef struct {
  27.     Tcl_Interp *interp;        /* Interpreter in which to invoke command. */
  28.     int cmdLength;        /* # of non-NULL bytes in command. */
  29.     char command[4];        /* Command to invoke.  Actual space is
  30.                  * allocated as large as necessary.  This
  31.                  * must be the last entry in the structure. */
  32. } CommandInfo;
  33.  
  34. /*
  35.  * When selection ownership is claimed with the "selection own" Tcl command,
  36.  * one of the following structures is created to record the Tcl command
  37.  * to be executed when the selection is lost again.
  38.  */
  39.  
  40. typedef struct LostCommand {
  41.     Tcl_Interp *interp;        /* Interpreter in which to invoke command. */
  42.     char command[4];        /* Command to invoke.  Actual space is
  43.                  * allocated as large as necessary.  This
  44.                  * must be the last entry in the structure. */
  45. } LostCommand;
  46.  
  47. /*
  48.  * Shared variables:
  49.  */
  50.  
  51. TkSelInProgress *pendingPtr = NULL;
  52.                 /* Topmost search in progress, or
  53.                  * NULL if none. */
  54.  
  55. /*
  56.  * Forward declarations for procedures defined in this file:
  57.  */
  58.  
  59. static int        HandleTclCommand _ANSI_ARGS_((ClientData clientData,
  60.                 int offset, char *buffer, int maxBytes));
  61. static void        LostSelection _ANSI_ARGS_((ClientData clientData));
  62. static int        SelGetProc _ANSI_ARGS_((ClientData clientData,
  63.                 Tcl_Interp *interp, char *portion));
  64.  
  65. /*
  66.  *--------------------------------------------------------------
  67.  *
  68.  * Tk_CreateSelHandler --
  69.  *
  70.  *    This procedure is called to register a procedure
  71.  *    as the handler for selection requests of a particular
  72.  *    target type on a particular window for a particular
  73.  *    selection.
  74.  *
  75.  * Results:
  76.  *    None.
  77.  *
  78.  * Side effects:
  79.  *    In the future, whenever the selection is in tkwin's
  80.  *    window and someone requests the selection in the
  81.  *    form given by target, proc will be invoked to provide
  82.  *    part or all of the selection in the given form.  If
  83.  *    there was already a handler declared for the given
  84.  *    window, target and selection type, then it is replaced.
  85.  *    Proc should have the following form:
  86.  *
  87.  *    int
  88.  *    proc(clientData, offset, buffer, maxBytes)
  89.  *        ClientData clientData;
  90.  *        int offset;
  91.  *        char *buffer;
  92.  *        int maxBytes;
  93.  *    {
  94.  *    }
  95.  *
  96.  *    The clientData argument to proc will be the same as
  97.  *    the clientData argument to this procedure.  The offset
  98.  *    argument indicates which portion of the selection to
  99.  *    return:  skip the first offset bytes.  Buffer is a
  100.  *    pointer to an area in which to place the converted
  101.  *    selection, and maxBytes gives the number of bytes
  102.  *    available at buffer.  Proc should place the selection
  103.  *    in buffer as a string, and return a count of the number
  104.  *    of bytes of selection actually placed in buffer (not
  105.  *    including the terminating NULL character).  If the
  106.  *    return value equals maxBytes, this is a sign that there
  107.  *    is probably still more selection information available.
  108.  *
  109.  *--------------------------------------------------------------
  110.  */
  111.  
  112. void
  113. Tk_CreateSelHandler(tkwin, selection, target, proc, clientData, format)
  114.     Tk_Window tkwin;        /* Token for window. */
  115.     Atom selection;        /* Selection to be handled. */
  116.     Atom target;        /* The kind of selection conversions
  117.                  * that can be handled by proc,
  118.                  * e.g. TARGETS or STRING. */
  119.     Tk_SelectionProc *proc;    /* Procedure to invoke to convert
  120.                  * selection to type "target". */
  121.     ClientData clientData;    /* Value to pass to proc. */
  122.     Atom format;        /* Format in which the selection
  123.                  * information should be returned to
  124.                  * the requestor. XA_STRING is best by
  125.                  * far, but anything listed in the ICCCM
  126.                  * will be tolerated (blech). */
  127. {
  128.     register TkSelHandler *selPtr;
  129.     TkWindow *winPtr = (TkWindow *) tkwin;
  130.  
  131.     if (winPtr->dispPtr->multipleAtom == None) {
  132.     TkSelInit(tkwin);
  133.     }
  134.  
  135.     /*
  136.      * See if there's already a handler for this target and selection on
  137.      * this window.  If so, re-use it.  If not, create a new one.
  138.      */
  139.  
  140.     for (selPtr = winPtr->selHandlerList; ; selPtr = selPtr->nextPtr) {
  141.     if (selPtr == NULL) {
  142.         selPtr = (TkSelHandler *) ckalloc(sizeof(TkSelHandler));
  143.         selPtr->nextPtr = winPtr->selHandlerList;
  144.         winPtr->selHandlerList = selPtr;
  145.         break;
  146.     }
  147.     if ((selPtr->selection == selection) && (selPtr->target == target)) {
  148.  
  149.         /*
  150.          * Special case:  when replacing handler created by
  151.          * "selection handle", free up memory.  Should there be a
  152.          * callback to allow other clients to do this too?
  153.          */
  154.  
  155.         if (selPtr->proc == HandleTclCommand) {
  156.         ckfree((char *) selPtr->clientData);
  157.         }
  158.         break;
  159.     }
  160.     }
  161.     selPtr->selection = selection;
  162.     selPtr->target = target;
  163.     selPtr->format = format;
  164.     selPtr->proc = proc;
  165.     selPtr->clientData = clientData;
  166.     if (format == XA_STRING) {
  167.     selPtr->size = 8;
  168.     } else {
  169.     selPtr->size = 32;
  170.     }
  171. }
  172.  
  173. /*
  174.  *----------------------------------------------------------------------
  175.  *
  176.  * Tk_DeleteSelHandler --
  177.  *
  178.  *    Remove the selection handler for a given window, target, and
  179.  *    selection, if it exists.
  180.  *
  181.  * Results:
  182.  *    None.
  183.  *
  184.  * Side effects:
  185.  *    The selection handler for tkwin and target is removed.  If there
  186.  *    is no such handler then nothing happens.
  187.  *
  188.  *----------------------------------------------------------------------
  189.  */
  190.  
  191. void
  192. Tk_DeleteSelHandler(tkwin, selection, target)
  193.     Tk_Window tkwin;            /* Token for window. */
  194.     Atom selection;            /* The selection whose handler
  195.                      * is to be removed. */
  196.     Atom target;            /* The target whose selection
  197.                      * handler is to be removed. */
  198. {
  199.     TkWindow *winPtr = (TkWindow *) tkwin;
  200.     register TkSelHandler *selPtr, *prevPtr;
  201.     register TkSelInProgress *ipPtr;
  202.  
  203.     /*
  204.      * Find the selection handler to be deleted, or return if it doesn't
  205.      * exist.
  206.      */ 
  207.  
  208.     for (selPtr = winPtr->selHandlerList, prevPtr = NULL; ;
  209.         prevPtr = selPtr, selPtr = selPtr->nextPtr) {
  210.     if (selPtr == NULL) {
  211.         return;
  212.     }
  213.     if ((selPtr->selection == selection) && (selPtr->target == target)) {
  214.         break;
  215.     }
  216.     }
  217.  
  218.     /*
  219.      * If ConvertSelection is processing this handler, tell it that the
  220.      * handler is dead.
  221.      */
  222.  
  223.     for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
  224.     if (ipPtr->selPtr == selPtr) {
  225.         ipPtr->selPtr = NULL;
  226.     }
  227.     }
  228.  
  229.     /*
  230.      * Free resources associated with the handler.
  231.      */
  232.  
  233.     if (prevPtr == NULL) {
  234.     winPtr->selHandlerList = selPtr->nextPtr;
  235.     } else {
  236.     prevPtr->nextPtr = selPtr->nextPtr;
  237.     }
  238.     if (selPtr->proc == HandleTclCommand) {
  239.     ckfree((char *) selPtr->clientData);
  240.     }
  241.     ckfree((char *) selPtr);
  242. }
  243.  
  244. /*
  245.  *--------------------------------------------------------------
  246.  *
  247.  * Tk_OwnSelection --
  248.  *
  249.  *    Arrange for tkwin to become the owner of a selection.
  250.  *
  251.  * Results:
  252.  *    None.
  253.  *
  254.  * Side effects:
  255.  *    From now on, requests for the selection will be directed
  256.  *    to procedures associated with tkwin (they must have been
  257.  *    declared with calls to Tk_CreateSelHandler).  When the
  258.  *    selection is lost by this window, proc will be invoked
  259.  *    (see the manual entry for details).  This procedure may
  260.  *    invoke callbacks, including Tcl scripts, so any calling
  261.  *    function should be reentrant at the point where
  262.  *    Tk_OwnSelection is invoked.
  263.  *
  264.  *--------------------------------------------------------------
  265.  */
  266.  
  267. void
  268. Tk_OwnSelection(tkwin, selection, proc, clientData)
  269.     Tk_Window tkwin;        /* Window to become new selection
  270.                  * owner. */
  271.     Atom selection;        /* Selection that window should own. */
  272.     Tk_LostSelProc *proc;    /* Procedure to call when selection
  273.                  * is taken away from tkwin. */
  274.     ClientData clientData;    /* Arbitrary one-word argument to
  275.                  * pass to proc. */
  276. {
  277.     register TkWindow *winPtr = (TkWindow *) tkwin;
  278.     TkDisplay *dispPtr = winPtr->dispPtr;
  279.     TkSelectionInfo *infoPtr;
  280.     Tk_LostSelProc *clearProc = NULL;
  281.     ClientData clearData = NULL;    /* Initialization needed only to
  282.                      * prevent compiler warning. */
  283.     
  284.     
  285.     if (dispPtr->multipleAtom == None) {
  286.     TkSelInit(tkwin);
  287.     }
  288.     Tk_MakeWindowExist(tkwin);
  289.  
  290.     /*
  291.      * This code is somewhat tricky.  First, we find the specified selection
  292.      * on the selection list.  If the previous owner is in this process, and
  293.      * is a different window, then we need to invoke the clearProc.  However,
  294.      * it's dangerous to call the clearProc right now, because it could
  295.      * invoke a Tcl script that wrecks the current state (e.g. it could
  296.      * delete the window).  To be safe, defer the call until the end of the
  297.      * procedure when we no longer care about the state.
  298.      */
  299.  
  300.     for (infoPtr = dispPtr->selectionInfoPtr; infoPtr != NULL;
  301.         infoPtr = infoPtr->nextPtr) {
  302.     if (infoPtr->selection == selection) {
  303.         break;
  304.     }
  305.     }
  306.     if (infoPtr == NULL) {
  307.     infoPtr = (TkSelectionInfo*) ckalloc(sizeof(TkSelectionInfo));
  308.     infoPtr->selection = selection;
  309.     infoPtr->nextPtr = dispPtr->selectionInfoPtr;
  310.     dispPtr->selectionInfoPtr = infoPtr;
  311.     } else if (infoPtr->clearProc != NULL) {
  312.     if (infoPtr->owner != tkwin) {
  313.         clearProc = infoPtr->clearProc;
  314.         clearData = infoPtr->clearData;
  315.     } else if (infoPtr->clearProc == LostSelection) {
  316.         /*
  317.          * If the selection handler is one created by "selection own",
  318.          * be sure to free the record for it;  otherwise there will be
  319.          * a memory leak.
  320.          */
  321.  
  322.         ckfree((char *) infoPtr->clearData);
  323.     }
  324.     }
  325.  
  326.     infoPtr->owner = tkwin;
  327.     infoPtr->serial = NextRequest(winPtr->display);
  328.     infoPtr->clearProc = proc;
  329.     infoPtr->clearData = clientData;
  330.  
  331.     /*
  332.      * Note that we are using CurrentTime, even though ICCCM recommends against
  333.      * this practice (the problem is that we don't necessarily have a valid
  334.      * time to use).  We will not be able to retrieve a useful timestamp for
  335.      * the TIMESTAMP target later.
  336.      */
  337.  
  338.     infoPtr->time = CurrentTime;
  339.  
  340.     /*
  341.      * Note that we are not checking to see if the selection claim succeeded.
  342.      * If the ownership does not change, then the clearProc may never be
  343.      * invoked, and we will return incorrect information when queried for the
  344.      * current selection owner.
  345.      */
  346.  
  347.     XSetSelectionOwner(winPtr->display, infoPtr->selection, winPtr->window,
  348.         infoPtr->time);
  349.  
  350.     /*
  351.      * Now that we are done, we can invoke clearProc without running into
  352.      * reentrancy problems.
  353.      */
  354.  
  355.     if (clearProc != NULL) {
  356.     (*clearProc)(clearData);
  357.     }
  358. }
  359.  
  360. /*
  361.  *----------------------------------------------------------------------
  362.  *
  363.  * Tk_ClearSelection --
  364.  *
  365.  *    Eliminate the specified selection on tkwin's display, if there is one.
  366.  *
  367.  * Results:
  368.  *    None.
  369.  *
  370.  * Side effects:
  371.  *    The specified selection is cleared, so that future requests to retrieve
  372.  *    it will fail until some application owns it again.  This procedure
  373.  *    invokes callbacks, possibly including Tcl scripts, so any calling
  374.  *    function should be reentrant at the point Tk_ClearSelection is invoked.
  375.  *
  376.  *----------------------------------------------------------------------
  377.  */
  378.  
  379. void
  380. Tk_ClearSelection(tkwin, selection)
  381.     Tk_Window tkwin;        /* Window that selects a display. */
  382.     Atom selection;        /* Selection to be cancelled. */
  383. {
  384.     register TkWindow *winPtr = (TkWindow *) tkwin;
  385.     TkDisplay *dispPtr = winPtr->dispPtr;
  386.     TkSelectionInfo *infoPtr;
  387.     TkSelectionInfo *prevPtr;
  388.     TkSelectionInfo *nextPtr;
  389.     Tk_LostSelProc *clearProc = NULL;
  390.     ClientData clearData = NULL;    /* Initialization needed only to
  391.                      * prevent compiler warning. */
  392.  
  393.     if (dispPtr->multipleAtom == None) {
  394.     TkSelInit(tkwin);
  395.     }
  396.  
  397.     for (infoPtr = dispPtr->selectionInfoPtr, prevPtr = NULL;
  398.          infoPtr != NULL; infoPtr = nextPtr) {
  399.     nextPtr = infoPtr->nextPtr;
  400.     if (infoPtr->selection == selection) {
  401.         if (prevPtr == NULL) {
  402.         dispPtr->selectionInfoPtr = nextPtr;
  403.         } else {
  404.         prevPtr->nextPtr = nextPtr;
  405.         }
  406.         break;
  407.     }
  408.     prevPtr = infoPtr;
  409.     }
  410.     
  411.     if (infoPtr != NULL) {
  412.     clearProc = infoPtr->clearProc;
  413.     clearData = infoPtr->clearData;
  414.     ckfree((char *) infoPtr);
  415.     }
  416.     XSetSelectionOwner(winPtr->display, selection, None, CurrentTime);
  417.  
  418.     if (clearProc != NULL) {
  419.     (*clearProc)(clearData);
  420.     }
  421. }
  422.  
  423. /*
  424.  *--------------------------------------------------------------
  425.  *
  426.  * Tk_GetSelection --
  427.  *
  428.  *    Retrieve the value of a selection and pass it off (in
  429.  *    pieces, possibly) to a given procedure.
  430.  *
  431.  * Results:
  432.  *    The return value is a standard Tcl return value.
  433.  *    If an error occurs (such as no selection exists)
  434.  *    then an error message is left in interp->result.
  435.  *
  436.  * Side effects:
  437.  *    The standard X11 protocols are used to retrieve the
  438.  *    selection.  When it arrives, it is passed to proc.  If
  439.  *    the selection is very large, it will be passed to proc
  440.  *    in several pieces.  Proc should have the following
  441.  *    structure:
  442.  *
  443.  *    int
  444.  *    proc(clientData, interp, portion)
  445.  *        ClientData clientData;
  446.  *        Tcl_Interp *interp;
  447.  *        char *portion;
  448.  *    {
  449.  *    }
  450.  *
  451.  *    The interp and clientData arguments to proc will be the
  452.  *    same as the corresponding arguments to Tk_GetSelection.
  453.  *    The portion argument points to a character string
  454.  *    containing part of the selection, and numBytes indicates
  455.  *    the length of the portion, not including the terminating
  456.  *    NULL character.  If the selection arrives in several pieces,
  457.  *    the "portion" arguments in separate calls will contain
  458.  *    successive parts of the selection.  Proc should normally
  459.  *    return TCL_OK.  If it detects an error then it should return
  460.  *    TCL_ERROR and leave an error message in interp->result; the
  461.  *    remainder of the selection retrieval will be aborted.
  462.  *
  463.  *--------------------------------------------------------------
  464.  */
  465.  
  466. int
  467. Tk_GetSelection(interp, tkwin, selection, target, proc, clientData)
  468.     Tcl_Interp *interp;        /* Interpreter to use for reporting
  469.                  * errors. */
  470.     Tk_Window tkwin;        /* Window on whose behalf to retrieve
  471.                  * the selection (determines display
  472.                  * from which to retrieve). */
  473.     Atom selection;        /* Selection to retrieve. */
  474.     Atom target;        /* Desired form in which selection
  475.                  * is to be returned. */
  476.     Tk_GetSelProc *proc;    /* Procedure to call to process the
  477.                  * selection, once it has been retrieved. */
  478.     ClientData clientData;    /* Arbitrary value to pass to proc. */
  479. {
  480.     TkWindow *winPtr = (TkWindow *) tkwin;
  481.     TkDisplay *dispPtr = winPtr->dispPtr;
  482.     TkSelectionInfo *infoPtr;
  483.  
  484.     if (dispPtr->multipleAtom == None) {
  485.     TkSelInit(tkwin);
  486.     }
  487.  
  488.     /*
  489.      * If the selection is owned by a window managed by this
  490.      * process, then call the retrieval procedure directly,
  491.      * rather than going through the X server (it's dangerous
  492.      * to go through the X server in this case because it could
  493.      * result in deadlock if an INCR-style selection results).
  494.      */
  495.  
  496.     for (infoPtr = dispPtr->selectionInfoPtr; infoPtr != NULL;
  497.         infoPtr = infoPtr->nextPtr) {
  498.     if (infoPtr->selection == selection)
  499.         break;
  500.     }
  501.     if (infoPtr != NULL) {
  502.     register TkSelHandler *selPtr;
  503.     int offset, result, count;
  504.     char buffer[TK_SEL_BYTES_AT_ONCE+1];
  505.     TkSelInProgress ip;
  506.  
  507.     for (selPtr = ((TkWindow *) infoPtr->owner)->selHandlerList;
  508.         selPtr != NULL; selPtr = selPtr->nextPtr) {
  509.         if ((selPtr->target == target)
  510.             && (selPtr->selection == selection)) {
  511.         break;
  512.         }
  513.     }
  514.     if (selPtr == NULL) {
  515.         Atom type;
  516.  
  517.         count = TkSelDefaultSelection(infoPtr, target, buffer,
  518.             TK_SEL_BYTES_AT_ONCE, &type);
  519.         if (count > TK_SEL_BYTES_AT_ONCE) {
  520.         panic("selection handler returned too many bytes");
  521.         }
  522.         if (count < 0) {
  523.         goto cantget;
  524.         }
  525.         buffer[count] = 0;
  526.         result = (*proc)(clientData, interp, buffer);
  527.     } else {
  528.         offset = 0;
  529.         result = TCL_OK;
  530.         ip.selPtr = selPtr;
  531.         ip.nextPtr = pendingPtr;
  532.         pendingPtr = &ip;
  533.         while (1) {
  534.         count = (selPtr->proc)(selPtr->clientData, offset, buffer,
  535.             TK_SEL_BYTES_AT_ONCE);
  536.         if ((count < 0) || (ip.selPtr == NULL)) {
  537.             pendingPtr = ip.nextPtr;
  538.             goto cantget;
  539.         }
  540.         if (count > TK_SEL_BYTES_AT_ONCE) {
  541.             panic("selection handler returned too many bytes");
  542.         }
  543.         buffer[count] = '\0';
  544.         result = (*proc)(clientData, interp, buffer);
  545.         if ((result != TCL_OK) || (count < TK_SEL_BYTES_AT_ONCE)
  546.             || (ip.selPtr == NULL)) {
  547.             break;
  548.         }
  549.         offset += count;
  550.         }
  551.         pendingPtr = ip.nextPtr;
  552.     }
  553.     return result;
  554.     }
  555.  
  556.     /*
  557.      * The selection is owned by some other process.
  558.      */
  559.  
  560.     return TkSelGetSelection(interp, tkwin, selection, target, proc,
  561.         clientData);
  562.  
  563.     cantget:
  564.     Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection),
  565.     " selection doesn't exist or form \"", Tk_GetAtomName(tkwin, target),
  566.     "\" not defined", (char *) NULL);
  567.     return TCL_ERROR;
  568. }
  569.  
  570. /*
  571.  *--------------------------------------------------------------
  572.  *
  573.  * Tk_SelectionCmd --
  574.  *
  575.  *    This procedure is invoked to process the "selection" Tcl
  576.  *    command.  See the user documentation for details on what
  577.  *    it does.
  578.  *
  579.  * Results:
  580.  *    A standard Tcl result.
  581.  *
  582.  * Side effects:
  583.  *    See the user documentation.
  584.  *
  585.  *--------------------------------------------------------------
  586.  */
  587.  
  588. int
  589. Tk_SelectionCmd(clientData, interp, argc, argv)
  590.     ClientData clientData;    /* Main window associated with
  591.                  * interpreter. */
  592.     Tcl_Interp *interp;        /* Current interpreter. */
  593.     int argc;            /* Number of arguments. */
  594.     char **argv;        /* Argument strings. */
  595. {
  596.     Tk_Window tkwin = (Tk_Window) clientData;
  597.     char *path = NULL;
  598.     Atom selection;
  599.     char *selName = NULL;
  600.     int c, count;
  601.     size_t length;
  602.     char **args;
  603.  
  604.     if (argc < 2) {
  605.     sprintf(interp->result,
  606.         "wrong # args: should be \"%.50s option ?arg arg ...?\"",
  607.         argv[0]);
  608.     return TCL_ERROR;
  609.     }
  610.     c = argv[1][0];
  611.     length = strlen(argv[1]);
  612.     if ((c == 'c') && (strncmp(argv[1], "clear", length) == 0)) {
  613.     for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) {
  614.         if (args[0][0] != '-') {
  615.         break;
  616.         }
  617.         if (count < 2) {
  618.         Tcl_AppendResult(interp, "value for \"", *args,
  619.             "\" missing", (char *) NULL);
  620.         return TCL_ERROR;
  621.         }
  622.         c = args[0][1];
  623.         length = strlen(args[0]);
  624.         if ((c == 'd') && (strncmp(args[0], "-displayof", length) == 0)) {
  625.         path = args[1];
  626.         } else if ((c == 's')
  627.             && (strncmp(args[0], "-selection", length) == 0)) {
  628.         selName = args[1];
  629.         } else {
  630.         Tcl_AppendResult(interp, "unknown option \"", args[0],
  631.             "\"", (char *) NULL);
  632.         return TCL_ERROR;
  633.         }
  634.     }
  635.     if (count == 1) {
  636.         path = args[0];
  637.     } else if (count > 1) {
  638.         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  639.             " clear ?options?\"", (char *) NULL);
  640.         return TCL_ERROR;
  641.     }
  642.     if (path != NULL) {
  643.         tkwin = Tk_NameToWindow(interp, path, tkwin);
  644.     }
  645.     if (tkwin == NULL) {
  646.         return TCL_ERROR;
  647.     }
  648.     if (selName != NULL) {
  649.         selection = Tk_InternAtom(tkwin, selName);
  650.     } else {
  651.         selection = XA_PRIMARY;
  652.     }
  653.         
  654.     Tk_ClearSelection(tkwin, selection);
  655.     return TCL_OK;
  656.     } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
  657.     Atom target;
  658.     char *targetName = NULL;
  659.     Tcl_DString selBytes;
  660.     int result;
  661.     
  662.     for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) {
  663.         if (args[0][0] != '-') {
  664.         break;
  665.         }
  666.         if (count < 2) {
  667.         Tcl_AppendResult(interp, "value for \"", *args,
  668.             "\" missing", (char *) NULL);
  669.         return TCL_ERROR;
  670.         }
  671.         c = args[0][1];
  672.         length = strlen(args[0]);
  673.         if ((c == 'd') && (strncmp(args[0], "-displayof", length) == 0)) {
  674.         path = args[1];
  675.         } else if ((c == 's')
  676.             && (strncmp(args[0], "-selection", length) == 0)) {
  677.         selName = args[1];
  678.         } else if ((c == 't')
  679.             && (strncmp(args[0], "-type", length) == 0)) {
  680.         targetName = args[1];
  681.         } else {
  682.         Tcl_AppendResult(interp, "unknown option \"", args[0],
  683.             "\"", (char *) NULL);
  684.         return TCL_ERROR;
  685.         }
  686.     }
  687.     if (path != NULL) {
  688.         tkwin = Tk_NameToWindow(interp, path, tkwin);
  689.     }
  690.     if (tkwin == NULL) {
  691.         return TCL_ERROR;
  692.     }
  693.     if (selName != NULL) {
  694.         selection = Tk_InternAtom(tkwin, selName);
  695.     } else {
  696.         selection = XA_PRIMARY;
  697.     }
  698.     if (count > 1) {
  699.         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  700.             " get ?options?\"", (char *) NULL);
  701.         return TCL_ERROR;
  702.     } else if (count == 1) {
  703.         target = Tk_InternAtom(tkwin, args[0]);
  704.     } else if (targetName != NULL) {
  705.         target = Tk_InternAtom(tkwin, targetName);
  706.     } else {
  707.         target = XA_STRING;
  708.     }
  709.  
  710.     Tcl_DStringInit(&selBytes);
  711.     result = Tk_GetSelection(interp, tkwin, selection, target, SelGetProc,
  712.         (ClientData) &selBytes);
  713.     if (result == TCL_OK) {
  714.         Tcl_DStringResult(interp, &selBytes);
  715.     } else {
  716.         Tcl_DStringFree(&selBytes);
  717.     }
  718.     return result;
  719.     } else if ((c == 'h') && (strncmp(argv[1], "handle", length) == 0)) {
  720.     Atom target, format;
  721.     char *targetName = NULL;
  722.     char *formatName = NULL;
  723.     register CommandInfo *cmdInfoPtr;
  724.     int cmdLength;
  725.     
  726.     for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) {
  727.         if (args[0][0] != '-') {
  728.         break;
  729.         }
  730.         if (count < 2) {
  731.         Tcl_AppendResult(interp, "value for \"", *args,
  732.             "\" missing", (char *) NULL);
  733.         return TCL_ERROR;
  734.         }
  735.         c = args[0][1];
  736.         length = strlen(args[0]);
  737.         if ((c == 'f') && (strncmp(args[0], "-format", length) == 0)) {
  738.         formatName = args[1];
  739.         } else if ((c == 's')
  740.             && (strncmp(args[0], "-selection", length) == 0)) {
  741.         selName = args[1];
  742.         } else if ((c == 't')
  743.             && (strncmp(args[0], "-type", length) == 0)) {
  744.         targetName = args[1];
  745.         } else {
  746.         Tcl_AppendResult(interp, "unknown option \"", args[0],
  747.             "\"", (char *) NULL);
  748.         return TCL_ERROR;
  749.         }
  750.     }
  751.  
  752.     if ((count < 2) || (count > 4)) {
  753.         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  754.             " handle ?options? window command\"", (char *) NULL);
  755.         return TCL_ERROR;
  756.     }
  757.     tkwin = Tk_NameToWindow(interp, args[0], tkwin);
  758.     if (tkwin == NULL) {
  759.         return TCL_ERROR;
  760.     }
  761.     if (selName != NULL) {
  762.         selection = Tk_InternAtom(tkwin, selName);
  763.     } else {
  764.         selection = XA_PRIMARY;
  765.     }
  766.         
  767.     if (count > 2) {
  768.         target = Tk_InternAtom(tkwin, args[2]);
  769.     } else if (targetName != NULL) {
  770.         target = Tk_InternAtom(tkwin, targetName);
  771.     } else {
  772.         target = XA_STRING;
  773.     }
  774.     if (count > 3) {
  775.         format = Tk_InternAtom(tkwin, args[3]);
  776.     } else if (formatName != NULL) {
  777.         format = Tk_InternAtom(tkwin, formatName);
  778.     } else {
  779.         format = XA_STRING;
  780.     }
  781.     cmdLength = strlen(args[1]);
  782.     if (cmdLength == 0) {
  783.         Tk_DeleteSelHandler(tkwin, selection, target);
  784.     } else {
  785.         cmdInfoPtr = (CommandInfo *) ckalloc((unsigned) (
  786.             sizeof(CommandInfo) - 3 + cmdLength));
  787.         cmdInfoPtr->interp = interp;
  788.         cmdInfoPtr->cmdLength = cmdLength;
  789.         strcpy(cmdInfoPtr->command, args[1]);
  790.         Tk_CreateSelHandler(tkwin, selection, target, HandleTclCommand,
  791.             (ClientData) cmdInfoPtr, format);
  792.     }
  793.     return TCL_OK;
  794.     } else if ((c == 'o') && (strncmp(argv[1], "own", length) == 0)) {
  795.     register LostCommand *lostPtr;
  796.     char *script = NULL;
  797.     int cmdLength;
  798.  
  799.     for (count = argc-2, args = argv+2; count > 0; count -= 2, args += 2) {
  800.         if (args[0][0] != '-') {
  801.         break;
  802.         }
  803.         if (count < 2) {
  804.         Tcl_AppendResult(interp, "value for \"", *args,
  805.             "\" missing", (char *) NULL);
  806.         return TCL_ERROR;
  807.         }
  808.         c = args[0][1];
  809.         length = strlen(args[0]);
  810.         if ((c == 'c') && (strncmp(args[0], "-command", length) == 0)) {
  811.         script = args[1];
  812.         } else if ((c == 'd')
  813.             && (strncmp(args[0], "-displayof", length) == 0)) {
  814.         path = args[1];
  815.         } else if ((c == 's')
  816.             && (strncmp(args[0], "-selection", length) == 0)) {
  817.         selName = args[1];
  818.         } else {
  819.         Tcl_AppendResult(interp, "unknown option \"", args[0],
  820.             "\"", (char *) NULL);
  821.         return TCL_ERROR;
  822.         }
  823.     }
  824.  
  825.     if (count > 2) {
  826.         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  827.             " own ?options? ?window?\"", (char *) NULL);
  828.         return TCL_ERROR;
  829.     }
  830.     if (selName != NULL) {
  831.         selection = Tk_InternAtom(tkwin, selName);
  832.     } else {
  833.         selection = XA_PRIMARY;
  834.     }
  835.     if (count == 0) {
  836.         TkSelectionInfo *infoPtr;
  837.         TkWindow *winPtr;
  838.         if (path != NULL) {
  839.         tkwin = Tk_NameToWindow(interp, path, tkwin);
  840.         }
  841.         if (tkwin == NULL) {
  842.         return TCL_ERROR;
  843.         }
  844.         winPtr = (TkWindow *)tkwin;
  845.         for (infoPtr = winPtr->dispPtr->selectionInfoPtr; infoPtr != NULL;
  846.             infoPtr = infoPtr->nextPtr) {
  847.         if (infoPtr->selection == selection)
  848.             break;
  849.         }
  850.  
  851.         /*
  852.          * Ignore the internal clipboard window.
  853.          */
  854.  
  855.         if ((infoPtr != NULL)
  856.             && (infoPtr->owner != winPtr->dispPtr->clipWindow)) {
  857.         interp->result = Tk_PathName(infoPtr->owner);
  858.         }
  859.         return TCL_OK;
  860.     }
  861.     tkwin = Tk_NameToWindow(interp, args[0], tkwin);
  862.     if (tkwin == NULL) {
  863.         return TCL_ERROR;
  864.     }
  865.     if (count == 2) {
  866.         script = args[1];
  867.     }
  868.     if (script == NULL) {
  869.         Tk_OwnSelection(tkwin, selection, (Tk_LostSelProc *) NULL,
  870.             (ClientData) NULL);
  871.         return TCL_OK;
  872.     }
  873.     cmdLength = strlen(script);
  874.     lostPtr = (LostCommand *) ckalloc((unsigned) (sizeof(LostCommand)
  875.         -3 + cmdLength));
  876.     lostPtr->interp = interp;
  877.     strcpy(lostPtr->command, script);
  878.     Tk_OwnSelection(tkwin, selection, LostSelection, (ClientData) lostPtr);
  879.     return TCL_OK;
  880.     } else {
  881.     sprintf(interp->result,
  882.         "bad option \"%.50s\": must be clear, get, handle, or own",
  883.         argv[1]);
  884.     return TCL_ERROR;
  885.     }
  886. }
  887.  
  888. /*
  889.  *----------------------------------------------------------------------
  890.  *
  891.  * TkSelDeadWindow --
  892.  *
  893.  *    This procedure is invoked just before a TkWindow is deleted.
  894.  *    It performs selection-related cleanup.
  895.  *
  896.  * Results:
  897.  *    None.
  898.  *
  899.  * Side effects:
  900.  *    Frees up memory associated with the selection.
  901.  *
  902.  *----------------------------------------------------------------------
  903.  */
  904.  
  905. void
  906. TkSelDeadWindow(winPtr)
  907.     register TkWindow *winPtr;    /* Window that's being deleted. */
  908. {
  909.     register TkSelHandler *selPtr;
  910.     register TkSelInProgress *ipPtr;
  911.     TkSelectionInfo *infoPtr, *prevPtr, *nextPtr;
  912.  
  913.     /*
  914.      * While deleting all the handlers, be careful to check whether
  915.      * ConvertSelection or TkSelPropProc are about to process one of the
  916.      * deleted handlers.
  917.      */
  918.  
  919.     while (winPtr->selHandlerList != NULL) {
  920.     selPtr = winPtr->selHandlerList;
  921.     winPtr->selHandlerList = selPtr->nextPtr;
  922.     for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
  923.         if (ipPtr->selPtr == selPtr) {
  924.         ipPtr->selPtr = NULL;
  925.         }
  926.     }
  927.     if (selPtr->proc == HandleTclCommand) {
  928.         ckfree((char *) selPtr->clientData);
  929.     }
  930.     ckfree((char *) selPtr);
  931.     }
  932.  
  933.     /*
  934.      * Remove selections owned by window being deleted.
  935.      */
  936.  
  937.     for (infoPtr = winPtr->dispPtr->selectionInfoPtr, prevPtr = NULL;
  938.          infoPtr != NULL; infoPtr = nextPtr) {
  939.     nextPtr = infoPtr->nextPtr;
  940.     if (infoPtr->owner == (Tk_Window) winPtr) {
  941.         if (infoPtr->clearProc == LostSelection) {
  942.         ckfree((char *) infoPtr->clearData);
  943.         }
  944.         ckfree((char *) infoPtr);
  945.         infoPtr = prevPtr;
  946.         if (prevPtr == NULL) {
  947.         winPtr->dispPtr->selectionInfoPtr = nextPtr;
  948.         } else {
  949.         prevPtr->nextPtr = nextPtr;
  950.         }
  951.     }
  952.     prevPtr = infoPtr;
  953.     }
  954. }
  955.  
  956. /*
  957.  *----------------------------------------------------------------------
  958.  *
  959.  * TkSelInit --
  960.  *
  961.  *    Initialize selection-related information for a display.
  962.  *
  963.  * Results:
  964.  *    None.
  965.  *
  966.  * Side effects:
  967.  *    Selection-related information is initialized.
  968.  *
  969.  *----------------------------------------------------------------------
  970.  */
  971.  
  972. void
  973. TkSelInit(tkwin)
  974.     Tk_Window tkwin;        /* Window token (used to find
  975.                  * display to initialize). */
  976. {
  977.     register TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  978.  
  979.     /*
  980.      * Fetch commonly-used atoms.
  981.      */
  982.  
  983.     dispPtr->multipleAtom = Tk_InternAtom(tkwin, "MULTIPLE");
  984.     dispPtr->incrAtom = Tk_InternAtom(tkwin, "INCR");
  985.     dispPtr->targetsAtom = Tk_InternAtom(tkwin, "TARGETS");
  986.     dispPtr->timestampAtom = Tk_InternAtom(tkwin, "TIMESTAMP");
  987.     dispPtr->textAtom = Tk_InternAtom(tkwin, "TEXT");
  988.     dispPtr->compoundTextAtom = Tk_InternAtom(tkwin, "COMPOUND_TEXT");
  989.     dispPtr->applicationAtom = Tk_InternAtom(tkwin, "TK_APPLICATION");
  990.     dispPtr->windowAtom = Tk_InternAtom(tkwin, "TK_WINDOW");
  991.     dispPtr->clipboardAtom = Tk_InternAtom(tkwin, "CLIPBOARD");
  992. }
  993.  
  994. /*
  995.  *----------------------------------------------------------------------
  996.  *
  997.  * TkSelClearSelection --
  998.  *
  999.  *    This procedure is invoked to process a SelectionClear event.
  1000.  *
  1001.  * Results:
  1002.  *    None.
  1003.  *
  1004.  * Side effects:
  1005.  *    Invokes the clear procedure for the window which lost the
  1006.  *    selection.
  1007.  *
  1008.  *----------------------------------------------------------------------
  1009.  */
  1010.  
  1011. void
  1012. TkSelClearSelection(tkwin, eventPtr)
  1013.     Tk_Window tkwin;        /* Window for which event was targeted. */
  1014.     register XEvent *eventPtr;    /* X SelectionClear event. */
  1015. {
  1016.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1017.     TkDisplay *dispPtr = winPtr->dispPtr;
  1018.     TkSelectionInfo *infoPtr;
  1019.     TkSelectionInfo *prevPtr;
  1020.  
  1021.     /*
  1022.      * Invoke clear procedure for window that just lost the selection.  This
  1023.      * code is a bit tricky, because any callbacks due to selection changes
  1024.      * between windows managed by the process have already been made.  Thus,
  1025.      * ignore the event unless it refers to the window that's currently the
  1026.      * selection owner and the event was generated after the server saw the
  1027.      * SetSelectionOwner request.
  1028.      */
  1029.  
  1030.     for (infoPtr = dispPtr->selectionInfoPtr, prevPtr = NULL;
  1031.      infoPtr != NULL; infoPtr = infoPtr->nextPtr) {
  1032.     if (infoPtr->selection == eventPtr->xselectionclear.selection) {
  1033.         break;
  1034.     }
  1035.     prevPtr = infoPtr;
  1036.     }
  1037.  
  1038.     if (infoPtr != NULL && (infoPtr->owner == tkwin)
  1039.         && (eventPtr->xselectionclear.serial >= infoPtr->serial)) {
  1040.     if (prevPtr == NULL) {
  1041.         dispPtr->selectionInfoPtr = infoPtr->nextPtr;
  1042.     } else {
  1043.         prevPtr->nextPtr = infoPtr->nextPtr;
  1044.     }
  1045.  
  1046.     /*
  1047.      * Because of reentrancy problems, calling clearProc must be done
  1048.      * after the infoPtr has been removed from the selectionInfoPtr
  1049.      * list (clearProc could modify the list, e.g. by creating
  1050.      * a new selection).
  1051.      */
  1052.  
  1053.     if (infoPtr->clearProc != NULL) {
  1054.         (*infoPtr->clearProc)(infoPtr->clearData);
  1055.     }
  1056.     ckfree((char *) infoPtr);
  1057.     }
  1058. }
  1059.  
  1060. /*
  1061.  *--------------------------------------------------------------
  1062.  *
  1063.  * SelGetProc --
  1064.  *
  1065.  *    This procedure is invoked to process pieces of the selection
  1066.  *    as they arrive during "selection get" commands.
  1067.  *
  1068.  * Results:
  1069.  *    Always returns TCL_OK.
  1070.  *
  1071.  * Side effects:
  1072.  *    Bytes get appended to the dynamic string pointed to by the
  1073.  *    clientData argument.
  1074.  *
  1075.  *--------------------------------------------------------------
  1076.  */
  1077.  
  1078.     /* ARGSUSED */
  1079. static int
  1080. SelGetProc(clientData, interp, portion)
  1081.     ClientData clientData;    /* Dynamic string holding partially
  1082.                  * assembled selection. */
  1083.     Tcl_Interp *interp;        /* Interpreter used for error
  1084.                  * reporting (not used). */
  1085.     char *portion;        /* New information to be appended. */
  1086. {
  1087.     Tcl_DStringAppend((Tcl_DString *) clientData, portion, -1);
  1088.     return TCL_OK;
  1089. }
  1090.  
  1091. /*
  1092.  *----------------------------------------------------------------------
  1093.  *
  1094.  * HandleTclCommand --
  1095.  *
  1096.  *    This procedure acts as selection handler for handlers created
  1097.  *    by the "selection handle" command.  It invokes a Tcl command to
  1098.  *    retrieve the selection.
  1099.  *
  1100.  * Results:
  1101.  *    The return value is a count of the number of bytes actually
  1102.  *    stored at buffer, or -1 if an error occurs while executing
  1103.  *    the Tcl command to retrieve the selection.
  1104.  *
  1105.  * Side effects:
  1106.  *    None except for things done by the Tcl command.
  1107.  *
  1108.  *----------------------------------------------------------------------
  1109.  */
  1110.  
  1111. static int
  1112. HandleTclCommand(clientData, offset, buffer, maxBytes)
  1113.     ClientData clientData;    /* Information about command to execute. */
  1114.     int offset;            /* Return selection bytes starting at this
  1115.                  * offset. */
  1116.     char *buffer;        /* Place to store converted selection. */
  1117.     int maxBytes;        /* Maximum # of bytes to store at buffer. */
  1118. {
  1119.     CommandInfo *cmdInfoPtr = (CommandInfo *) clientData;
  1120.     int spaceNeeded, length;
  1121. #define MAX_STATIC_SIZE 100
  1122.     char staticSpace[MAX_STATIC_SIZE];
  1123.     char *command;
  1124.     Tcl_Interp *interp;
  1125.     Tcl_DString oldResult;
  1126.  
  1127.     /*
  1128.      * We must copy the interpreter pointer from CommandInfo because the
  1129.      * command could delete the handler, freeing the CommandInfo data before we
  1130.      * are done using it. We must also protect the interpreter from being
  1131.      * deleted too soo.
  1132.      */
  1133.  
  1134.     interp = cmdInfoPtr->interp;
  1135.     Tcl_Preserve((ClientData) interp);
  1136.  
  1137.     /*
  1138.      * First, generate a command by taking the command string
  1139.      * and appending the offset and maximum # of bytes.
  1140.      */
  1141.  
  1142.     spaceNeeded = cmdInfoPtr->cmdLength + 30;
  1143.     if (spaceNeeded < MAX_STATIC_SIZE) {
  1144.     command = staticSpace;
  1145.     } else {
  1146.     command = (char *) ckalloc((unsigned) spaceNeeded);
  1147.     }
  1148.     sprintf(command, "%s %d %d", cmdInfoPtr->command, offset, maxBytes);
  1149.  
  1150.     /*
  1151.      * Execute the command.  Be sure to restore the state of the
  1152.      * interpreter after executing the command.
  1153.      */
  1154.  
  1155.     Tcl_DStringInit(&oldResult);
  1156.     Tcl_DStringGetResult(interp, &oldResult);
  1157.     if (TkCopyAndGlobalEval(interp, command) == TCL_OK) {
  1158.     length = strlen(interp->result);
  1159.     if (length > maxBytes) {
  1160.         length = maxBytes;
  1161.     }
  1162.     memcpy((VOID *) buffer, (VOID *) interp->result, (size_t) length);
  1163.     buffer[length] = '\0';
  1164.     } else {
  1165.     length = -1;
  1166.     }
  1167.     Tcl_DStringResult(interp, &oldResult);
  1168.  
  1169.     if (command != staticSpace) {
  1170.     ckfree(command);
  1171.     }
  1172.  
  1173.     Tcl_Release((ClientData) interp);
  1174.     return length;
  1175. }
  1176.  
  1177. /*
  1178.  *----------------------------------------------------------------------
  1179.  *
  1180.  * TkSelDefaultSelection --
  1181.  *
  1182.  *    This procedure is called to generate selection information
  1183.  *    for a few standard targets such as TIMESTAMP and TARGETS.
  1184.  *    It is invoked only if no handler has been declared by the
  1185.  *    application.
  1186.  *
  1187.  * Results:
  1188.  *    If "target" is a standard target understood by this procedure,
  1189.  *    the selection is converted to that form and stored as a
  1190.  *    character string in buffer.  The type of the selection (e.g.
  1191.  *    STRING or ATOM) is stored in *typePtr, and the return value is
  1192.  *    a count of the # of non-NULL bytes at buffer.  If the target
  1193.  *    wasn't understood, or if there isn't enough space at buffer
  1194.  *    to hold the entire selection (no INCR-mode transfers for this
  1195.  *    stuff!), then -1 is returned.
  1196.  *
  1197.  * Side effects:
  1198.  *    None.
  1199.  *
  1200.  *----------------------------------------------------------------------
  1201.  */
  1202.  
  1203. int
  1204. TkSelDefaultSelection(infoPtr, target, buffer, maxBytes, typePtr)
  1205.     TkSelectionInfo *infoPtr;    /* Info about selection being retrieved. */
  1206.     Atom target;        /* Desired form of selection. */
  1207.     char *buffer;        /* Place to put selection characters. */
  1208.     int maxBytes;        /* Maximum # of bytes to store at buffer. */
  1209.     Atom *typePtr;        /* Store here the type of the selection,
  1210.                  * for use in converting to proper X format. */
  1211. {
  1212.     register TkWindow *winPtr = (TkWindow *) infoPtr->owner;
  1213.     TkDisplay *dispPtr = winPtr->dispPtr;
  1214.  
  1215.     if (target == dispPtr->timestampAtom) {
  1216.     if (maxBytes < 20) {
  1217.         return -1;
  1218.     }
  1219.     sprintf(buffer, "0x%x", (unsigned int) infoPtr->time);
  1220.     *typePtr = XA_INTEGER;
  1221.     return strlen(buffer);
  1222.     }
  1223.  
  1224.     if (target == dispPtr->targetsAtom) {
  1225.     register TkSelHandler *selPtr;
  1226.     char *atomString;
  1227.     int length, atomLength;
  1228.  
  1229.     if (maxBytes < 50) {
  1230.         return -1;
  1231.     }
  1232.     strcpy(buffer, "MULTIPLE TARGETS TIMESTAMP TK_APPLICATION TK_WINDOW");
  1233.     length = strlen(buffer);
  1234.     for (selPtr = winPtr->selHandlerList; selPtr != NULL;
  1235.         selPtr = selPtr->nextPtr) {
  1236.         if ((selPtr->selection == infoPtr->selection)
  1237.             && (selPtr->target != dispPtr->applicationAtom)
  1238.             && (selPtr->target != dispPtr->windowAtom)) {
  1239.         atomString = Tk_GetAtomName((Tk_Window) winPtr,
  1240.             selPtr->target);
  1241.         atomLength = strlen(atomString) + 1;
  1242.         if ((length + atomLength) >= maxBytes) {
  1243.             return -1;
  1244.         }
  1245.         sprintf(buffer+length, " %s", atomString);
  1246.         length += atomLength;
  1247.         }
  1248.     }
  1249.     *typePtr = XA_ATOM;
  1250.     return length;
  1251.     }
  1252.  
  1253.     if (target == dispPtr->applicationAtom) {
  1254.     int length;
  1255.     char *name = winPtr->mainPtr->winPtr->nameUid;
  1256.  
  1257.     length = strlen(name);
  1258.     if (maxBytes <= length) {
  1259.         return -1;
  1260.     }
  1261.     strcpy(buffer, name);
  1262.     *typePtr = XA_STRING;
  1263.     return length;
  1264.     }
  1265.  
  1266.     if (target == dispPtr->windowAtom) {
  1267.     int length;
  1268.     char *name = winPtr->pathName;
  1269.  
  1270.     length = strlen(name);
  1271.     if (maxBytes <= length) {
  1272.         return -1;
  1273.     }
  1274.     strcpy(buffer, name);
  1275.     *typePtr = XA_STRING;
  1276.     return length;
  1277.     }
  1278.  
  1279.     return -1;
  1280. }
  1281.  
  1282. /*
  1283.  *----------------------------------------------------------------------
  1284.  *
  1285.  * LostSelection --
  1286.  *
  1287.  *    This procedure is invoked when a window has lost ownership of
  1288.  *    the selection and the ownership was claimed with the command
  1289.  *    "selection own".
  1290.  *
  1291.  * Results:
  1292.  *    None.
  1293.  *
  1294.  * Side effects:
  1295.  *    A Tcl script is executed;  it can do almost anything.
  1296.  *
  1297.  *----------------------------------------------------------------------
  1298.  */
  1299.  
  1300. static void
  1301. LostSelection(clientData)
  1302.     ClientData clientData;        /* Pointer to CommandInfo structure. */
  1303. {
  1304.     LostCommand *lostPtr = (LostCommand *) clientData;
  1305.     char *oldResultString;
  1306.     Tcl_FreeProc *oldFreeProc;
  1307.     Tcl_Interp *interp;
  1308.  
  1309.     interp = lostPtr->interp;
  1310.     Tcl_Preserve((ClientData) interp);
  1311.     
  1312.     /*
  1313.      * Execute the command.  Save the interpreter's result, if any, and
  1314.      * restore it after executing the command.
  1315.      */
  1316.  
  1317.     oldFreeProc = interp->freeProc;
  1318.     if (oldFreeProc != TCL_STATIC) {
  1319.     oldResultString = interp->result;
  1320.     } else {
  1321.     oldResultString = (char *) ckalloc((unsigned)
  1322.         (strlen(interp->result) + 1));
  1323.     strcpy(oldResultString, interp->result);
  1324.     oldFreeProc = TCL_DYNAMIC;
  1325.     }
  1326.     interp->freeProc = TCL_STATIC;
  1327.     if (TkCopyAndGlobalEval(interp, lostPtr->command) != TCL_OK) {
  1328.     Tcl_BackgroundError(interp);
  1329.     }
  1330.     Tcl_FreeResult(interp);
  1331.     interp->result = oldResultString;
  1332.     interp->freeProc = oldFreeProc;
  1333.  
  1334.     Tcl_Release((ClientData) interp);
  1335.     
  1336.     /*
  1337.      * Free the storage for the command, since we're done with it now.
  1338.      */
  1339.  
  1340.     ckfree((char *) lostPtr);
  1341. }
  1342.