/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkselect.c
ViewVC logotype

Annotation of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkselect.c

Parent Directory Parent Directory | Revision Log Revision Log


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

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25