4 * This file manages the selection for the Tk toolkit,
5 * translating between the standard X ICCCM conventions
8 * Copyright 1990 Regents of the University of California.
9 * Permission to use, copy, modify, and distribute this
10 * software and its documentation for any purpose and without
11 * fee is hereby granted, provided that the above copyright
12 * notice appear in all copies. The University of California
13 * makes no representations about the suitability of this
14 * software for any purpose. It is provided "as is" without
15 * express or implied warranty.
19 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkSelect.c,v 1.27 92/08/10 15:03:03 ouster Exp $ SPRITE (Berkeley)";
26 * When the selection is being retrieved, one of the following
27 * structures is present on a list of pending selection retrievals.
28 * The structure is used to communicate between the background
29 * procedure that requests the selection and the foreground
30 * event handler that processes the events in which the selection
31 * is returned. There is a list of such structures so that there
32 * can be multiple simultaneous selection retrievals (e.g. on
33 * different displays).
36 typedef struct RetrievalInfo
{
37 Tcl_Interp
*interp
; /* Interpreter for error reporting. */
38 TkWindow
*winPtr
; /* Window used as requestor for
40 Atom property
; /* Property where selection will appear. */
41 Atom target
; /* Desired form for selection. */
42 int (*proc
) _ANSI_ARGS_((ClientData clientData
, Tcl_Interp
*interp
,
43 char *portion
)); /* Procedure to call to handle pieces
45 ClientData clientData
; /* Argument for proc. */
46 int result
; /* Initially -1. Set to a Tcl
47 * return value once the selection
48 * has been retrieved. */
49 Tk_TimerToken timeout
; /* Token for current timeout procedure. */
50 int idleTime
; /* Number of seconds that have gone by
51 * without hearing anything from the
53 struct RetrievalInfo
*nextPtr
;
54 /* Next in list of all pending
55 * selection retrievals. NULL means
59 static RetrievalInfo
*pendingRetrievals
= NULL
;
60 /* List of all retrievals currently
61 * being waited for. */
64 * When "selection get" is being used to retrieve the selection,
65 * the following data structure is used for communication between
66 * Tk_SelectionCmd and SelGetProc. Its purpose is to keep track
67 * of the selection contents, which are gradually assembled in a
72 char *string
; /* Contents of selection are
73 * here. This space is malloc-ed. */
74 int bytesAvl
; /* Total number of bytes available
76 int bytesUsed
; /* Bytes currently in use in string,
77 * not including the terminating
82 * When handling INCR-style selection retrievals, the selection owner
83 * uses the following data structure to communicate between the
84 * ConvertSelection procedure and TkSelPropProc.
87 typedef struct IncrInfo
{
88 TkWindow
*winPtr
; /* Window that owns selection. */
89 Atom
*multAtoms
; /* Information about conversions to
90 * perform: one or more pairs of
91 * (target, property). This either
92 * points to a retrieved property (for
93 * MULTIPLE retrievals) or to a static
95 unsigned long numConversions
;
96 /* Number of entries in offsets (same as
97 * # of pairs in multAtoms). */
98 int *offsets
; /* One entry for each pair in
99 * multAtoms; -1 means all data has
100 * been transferred for this
101 * conversion. -2 means only the
102 * final zero-length transfer still
103 * has to be done. Otherwise it is the
104 * offset of the next chunk of data
105 * to transfer. This array is malloc-ed. */
106 int numIncrs
; /* Number of entries in offsets that
107 * aren't -1 (i.e. # of INCR-mode transfers
108 * not yet completed). */
109 Tk_TimerToken timeout
; /* Token for timer procedure. */
110 int idleTime
; /* Number of seconds since we heard
111 * anything from the selection
113 Window reqWindow
; /* Requestor's window id. */
114 Time time
; /* Timestamp corresponding to
115 * selection at beginning of request;
116 * used to abort transfer if selection
118 struct IncrInfo
*nextPtr
; /* Next in list of all INCR-style
119 * retrievals currently pending. */
122 static IncrInfo
*pendingIncrs
= NULL
;
123 /* List of all IncrInfo structures
124 * currently active. */
127 * When a selection handler is set up by invoking "selection handle",
128 * one of the following data structures is set up to hold information
129 * about the command to invoke and its interpreter.
133 Tcl_Interp
*interp
; /* Interpreter in which to invoke command. */
134 int cmdLength
; /* # of non-NULL bytes in command. */
135 char command
[4]; /* Command to invoke. Actual space is
136 * allocated as large as necessary. This
137 * must be the last entry in the structure. */
141 * Chunk size for retrieving selection. It's defined both in
142 * words and in bytes; the word size is used to allocate
143 * buffer space that's guaranteed to be word-aligned and that
144 * has an extra character for the terminating NULL.
147 #define TK_SEL_BYTES_AT_ONCE 4000
148 #define TK_SEL_WORDS_AT_ONCE 1001
151 * Largest property that we'll accept when sending or receiving the
155 #define MAX_PROP_WORDS 100000
158 * Forward declarations for procedures defined in this file:
161 static void ConvertSelection
_ANSI_ARGS_((TkWindow
*winPtr
,
162 XSelectionRequestEvent
*eventPtr
));
163 static int DefaultSelection
_ANSI_ARGS_((TkWindow
*winPtr
,
164 Atom target
, char *buffer
, int maxBytes
,
166 static int HandleTclCommand
_ANSI_ARGS_((ClientData clientData
,
167 int offset
, char *buffer
, int maxBytes
));
168 static void IncrTimeoutProc
_ANSI_ARGS_((ClientData clientData
));
169 static char * SelCvtFromX
_ANSI_ARGS_((long *propPtr
, int numValues
,
170 Atom type
, Tk_Window tkwin
));
171 static long * SelCvtToX
_ANSI_ARGS_((char *string
, Atom type
,
172 Tk_Window tkwin
, int *numLongsPtr
));
173 static int SelGetProc
_ANSI_ARGS_((ClientData clientData
,
174 Tcl_Interp
*interp
, char *portion
));
175 static void SelInit
_ANSI_ARGS_((Tk_Window tkwin
));
176 static void SelRcvIncrProc
_ANSI_ARGS_((ClientData clientData
,
178 static void SelTimeoutProc
_ANSI_ARGS_((ClientData clientData
));
181 *--------------------------------------------------------------
183 * Tk_CreateSelHandler --
185 * This procedure is called to register a procedure
186 * as the handler for selection requests of a particular
187 * target type on a particular window.
193 * In the future, whenever the selection is in tkwin's
194 * window and someone requests the selection in the
195 * form given by target, proc will be invoked to provide
196 * part or all of the selection in the given form. If
197 * there was already a handler declared for the given
198 * window and target type, then it is replaced. Proc
199 * should have the following form:
202 * proc(clientData, offset, buffer, maxBytes)
203 * ClientData clientData;
210 * The clientData argument to proc will be the same as
211 * the clientData argument to this procedure. The offset
212 * argument indicates which portion of the selection to
213 * return: skip the first offset bytes. Buffer is a
214 * pointer to an area in which to place the converted
215 * selection, and maxBytes gives the number of bytes
216 * available at buffer. Proc should place the selection
217 * in buffer as a string, and return a count of the number
218 * of bytes of selection actually placed in buffer (not
219 * including the terminating NULL character). If the
220 * return value equals maxBytes, this is a sign that there
221 * is probably still more selection information available.
223 *--------------------------------------------------------------
227 Tk_CreateSelHandler (
228 Tk_Window tkwin
, /* Token for window. */
229 Atom target
, /* The kind of selection conversions
230 * that can be handled by proc,
231 * e.g. TARGETS or XA_STRING. */
232 Tk_SelectionProc
*proc
, /* Procedure to invoke to convert
233 * selection to type "target". */
234 ClientData clientData
, /* Value to pass to proc. */
235 Atom format
/* Format in which the selection
236 * information should be returned to
237 * the requestor. XA_STRING is best by
238 * far, but anything listed in the ICCCM
239 * will be tolerated (blech). */
242 register TkSelHandler
*selPtr
;
243 TkWindow
*winPtr
= (TkWindow
*) tkwin
;
245 if (winPtr
->dispPtr
->multipleAtom
== None
) {
250 * See if there's already a handler for this target on
251 * this window. If so, re-use it. If not, create a new one.
254 for (selPtr
= winPtr
->selHandlerList
; ; selPtr
= selPtr
->nextPtr
) {
255 if (selPtr
== NULL
) {
256 selPtr
= (TkSelHandler
*) ckalloc(sizeof(TkSelHandler
));
257 selPtr
->nextPtr
= winPtr
->selHandlerList
;
258 winPtr
->selHandlerList
= selPtr
;
261 if (selPtr
->target
== target
) {
264 * Special case: when replacing handler created by
265 * "selection handle" free up memory. Should there be a
266 * callback to allow other clients to do this too?
269 if (selPtr
->proc
== HandleTclCommand
) {
270 ckfree((char *) selPtr
->clientData
);
275 selPtr
->target
= target
;
276 selPtr
->format
= format
;
278 selPtr
->clientData
= clientData
;
279 if (format
== XA_STRING
) {
287 *--------------------------------------------------------------
291 * Arrange for tkwin to become the selection owner.
297 * From now on, requests for the selection will be
298 * directed to procedures associated with tkwin (they
299 * must have been declared with calls to Tk_CreateSelHandler).
300 * When the selection is lost by this window, proc will
301 * be invoked (see the manual entry for details).
303 *--------------------------------------------------------------
308 Tk_Window tkwin
, /* Window to become new selection
310 Tk_LostSelProc
*proc
, /* Procedure to call when selection
311 * is taken away from tkwin. */
312 ClientData clientData
/* Arbitrary one-word argument to
316 register TkWindow
*winPtr
= (TkWindow
*) tkwin
;
317 TkDisplay
*dispPtr
= winPtr
->dispPtr
;
319 if (dispPtr
->multipleAtom
== None
) {
323 winPtr
->selClearProc
= proc
;
324 winPtr
->selClearData
= clientData
;
325 if (dispPtr
->selectionOwner
!= tkwin
) {
326 TkWindow
*ownerPtr
= (TkWindow
*) dispPtr
->selectionOwner
;
328 if ((ownerPtr
!= NULL
)
329 && (ownerPtr
->selClearProc
!= NULL
)) {
330 (*ownerPtr
->selClearProc
)(ownerPtr
->selClearData
);
331 ownerPtr
->selClearProc
= NULL
;
334 dispPtr
->selectionOwner
= tkwin
;
335 dispPtr
->selectionSerial
= NextRequest(winPtr
->display
);
336 dispPtr
->selectionTime
= TkCurrentTime(dispPtr
);
337 XSetSelectionOwner(winPtr
->display
, XA_PRIMARY
, winPtr
->window
,
338 dispPtr
->selectionTime
);
342 *--------------------------------------------------------------
346 * Retrieve the selection and pass it off (in pieces,
347 * possibly) to a given procedure.
350 * The return value is a standard Tcl return value.
351 * If an error occurs (such as no selection exists)
352 * then an error message is left in interp->result.
355 * The standard X11 protocols are used to retrieve the
356 * selection. When it arrives, it is passed to proc. If
357 * the selection is very large, it will be passed to proc
358 * in several pieces. Proc should have the following
362 * proc(clientData, interp, portion)
363 * ClientData clientData;
364 * Tcl_Interp *interp;
369 * The interp and clientData arguments to proc will be the
370 * same as the corresponding arguments to Tk_GetSelection.
371 * The portion argument points to a character string
372 * containing part of the selection, and numBytes indicates
373 * the length of the portion, not including the terminating
374 * NULL character. If the selection arrives in several pieces,
375 * the "portion" arguments in separate calls will contain
376 * successive parts of the selection. Proc should normally
377 * return TCL_OK. If it detects an error then it should return
378 * TCL_ERROR and leave an error message in interp->result; the
379 * remainder of the selection retrieval will be aborted.
381 *--------------------------------------------------------------
386 Tcl_Interp
*interp
, /* Interpreter to use for reporting
388 Tk_Window tkwin
, /* Window on whose behalf to retrieve
389 * the selection (determines display
390 * from which to retrieve). */
391 Atom target
, /* Desired form in which selection
392 * is to be returned. */
393 Tk_GetSelProc
*proc
, /* Procedure to call to process the
394 * selection, once it has been retrieved. */
395 ClientData clientData
/* Arbitrary value to pass to proc. */
399 TkWindow
*winPtr
= (TkWindow
*) tkwin
;
400 TkDisplay
*dispPtr
= winPtr
->dispPtr
;
402 if (dispPtr
->multipleAtom
== None
) {
407 * If the selection is owned by a window managed by this
408 * process, then call the retrieval procedure directly,
409 * rather than going through the X server (it's dangerous
410 * to go through the X server in this case because it could
411 * result in deadlock if an INCR-style selection results).
414 if (dispPtr
->selectionOwner
!= NULL
) {
415 register TkSelHandler
*selPtr
;
416 int offset
, result
, count
;
417 char buffer
[TK_SEL_BYTES_AT_ONCE
+1];
421 * Make sure that the selection predates the request
425 time
= TkCurrentTime(dispPtr
);
426 if ((time
< dispPtr
->selectionTime
)
427 && (time
!= CurrentTime
)
428 && (dispPtr
->selectionTime
!= CurrentTime
)) {
429 interp
->result
= "selection changed before it could be retrieved";
433 for (selPtr
= ((TkWindow
*) dispPtr
->selectionOwner
)->selHandlerList
;
434 ; selPtr
= selPtr
->nextPtr
) {
435 if (selPtr
== NULL
) {
438 count
= DefaultSelection((TkWindow
*) dispPtr
->selectionOwner
,
439 target
, buffer
, TK_SEL_BYTES_AT_ONCE
, &type
);
440 if (count
> TK_SEL_BYTES_AT_ONCE
) {
441 panic("selection handler returned too many bytes");
445 Tcl_AppendResult(interp
, "selection doesn't exist",
446 " or form \"", Tk_GetAtomName(tkwin
, target
),
447 "\" not defined", (char *) NULL
);
451 return (*proc
)(clientData
, interp
, buffer
);
453 if (selPtr
->target
== target
) {
459 count
= (*selPtr
->proc
)(selPtr
->clientData
, offset
,
460 buffer
, TK_SEL_BYTES_AT_ONCE
);
464 if (count
> TK_SEL_BYTES_AT_ONCE
) {
465 panic("selection handler returned too many bytes");
467 buffer
[count
] = '\0';
468 result
= (*proc
)(clientData
, interp
, buffer
);
469 if (result
!= TCL_OK
) {
472 if (count
< TK_SEL_BYTES_AT_ONCE
) {
480 * The selection is owned by some other process. To
481 * retrieve it, first record information about the retrieval
482 * in progress. Also, try to use a non-top-level window
483 * as the requestor (property changes on this window may
484 * be monitored by a window manager, which will waste time).
487 retr
.interp
= interp
;
488 if ((winPtr
->flags
& TK_TOP_LEVEL
)
489 && (winPtr
->childList
!= NULL
)) {
490 winPtr
= winPtr
->childList
;
492 retr
.winPtr
= winPtr
;
493 retr
.property
= XA_PRIMARY
;
494 retr
.target
= target
;
496 retr
.clientData
= clientData
;
499 retr
.nextPtr
= pendingRetrievals
;
500 pendingRetrievals
= &retr
;
503 * Initiate the request for the selection.
506 XConvertSelection(winPtr
->display
, XA_PRIMARY
, target
,
507 retr
.property
, winPtr
->window
, TkCurrentTime(dispPtr
));
510 * Enter a loop processing X events until the selection
511 * has been retrieved and processed. If no response is
512 * received within a few seconds, then timeout.
515 retr
.timeout
= Tk_CreateTimerHandler(1000, SelTimeoutProc
,
517 while (retr
.result
== -1) {
520 Tk_DeleteTimerHandler(retr
.timeout
);
523 * Unregister the information about the selection retrieval
527 if (pendingRetrievals
== &retr
) {
528 pendingRetrievals
= retr
.nextPtr
;
530 RetrievalInfo
*retrPtr
;
532 for (retrPtr
= pendingRetrievals
; retrPtr
!= NULL
;
533 retrPtr
= retrPtr
->nextPtr
) {
534 if (retrPtr
->nextPtr
== &retr
) {
535 retrPtr
->nextPtr
= retr
.nextPtr
;
544 *--------------------------------------------------------------
548 * This procedure is invoked to process the "selection" Tcl
549 * command. See the user documentation for details on what
553 * A standard Tcl result.
556 * See the user documentation.
558 *--------------------------------------------------------------
563 ClientData clientData
, /* Main window associated with
565 Tcl_Interp
*interp
, /* Current interpreter. */
566 int argc
, /* Number of arguments. */
567 char **argv
/* Argument strings. */
570 Tk_Window tkwin
= (Tk_Window
) clientData
;
576 sprintf(interp
->result
,
577 "wrong # args: should be \"%.50s [-window win] option ?arg arg ...?\"",
584 length
= strlen(argv
[0]);
586 if ((c
== '-') && (strncmp(argv
[0], "-window", length
) == 0)) {
588 ((tkwin
= Tk_NameToWindow(interp
, argv
[1], tkwin
)) == NULL
)) {
589 sprintf(interp
->result
, "bad arg to %s -window", cmd
);
592 argc
-= 2; argv
+= 2;
595 sprintf(interp
->result
, "not enough args to %s", cmd
);
600 length
= strlen(argv
[0]);
603 if ((c
== 'g') && (strncmp(argv
[0], "get", length
) == 0)) {
611 sprintf(interp
->result
,
612 "too may args: should be \"%.50s get ?type?\"",
617 target
= Tk_InternAtom(tkwin
, argv
[0]);
621 getInfo
.string
= (char *) ckalloc(100);
622 getInfo
.bytesAvl
= 100;
623 getInfo
.bytesUsed
= 0;
624 result
= Tk_GetSelection(interp
, tkwin
, target
, SelGetProc
,
625 (ClientData
) &getInfo
);
626 if (result
== TCL_OK
) {
627 Tcl_SetResult(interp
, getInfo
.string
, TCL_DYNAMIC
);
629 ckfree(getInfo
.string
);
632 } else if ((c
== 'h') && (strncmp(argv
[0], "handle", length
) == 0)) {
635 register CommandInfo
*cmdInfoPtr
;
640 if ((argc
< 2) || (argc
> 4)) {
641 Tcl_AppendResult(interp
, "wrong # args: should be \"", cmd
,
642 " handle window command ?type? ?format?\"", (char *) NULL
);
645 window
= Tk_NameToWindow(interp
, argv
[0], tkwin
);
646 if (window
== NULL
) {
650 target
= Tk_InternAtom(window
, argv
[2]);
655 format
= Tk_InternAtom(window
, argv
[3]);
659 cmdLength
= strlen(argv
[1]);
660 cmdInfoPtr
= (CommandInfo
*) ckalloc((unsigned) (sizeof(CommandInfo
)
662 cmdInfoPtr
->interp
= interp
;
663 cmdInfoPtr
->cmdLength
= cmdLength
;
664 strcpy(cmdInfoPtr
->command
, argv
[1]);
665 Tk_CreateSelHandler(window
, target
, HandleTclCommand
,
666 (ClientData
) cmdInfoPtr
, format
);
669 sprintf(interp
->result
,
670 "bad option to \"%.50s\": must be get or handle",
677 *----------------------------------------------------------------------
681 * This procedure is invoked just before a TkWindow is deleted.
682 * It performs selection-related cleanup.
688 * Frees up memory associated with the selection.
690 *----------------------------------------------------------------------
695 register TkWindow
*winPtr
/* Window that's being deleted. */
698 register TkSelHandler
*selPtr
;
701 selPtr
= winPtr
->selHandlerList
;
702 if (selPtr
== NULL
) {
705 winPtr
->selHandlerList
= selPtr
->nextPtr
;
706 ckfree((char *) selPtr
);
708 winPtr
->selClearProc
= NULL
;
710 if (winPtr
->dispPtr
->selectionOwner
== (Tk_Window
) winPtr
) {
711 winPtr
->dispPtr
->selectionOwner
= NULL
;
716 *----------------------------------------------------------------------
720 * Initialize selection-related information for a display.
728 *----------------------------------------------------------------------
733 Tk_Window tkwin
/* Window token (used to find
734 * display to initialize). */
737 register TkDisplay
*dispPtr
= ((TkWindow
*) tkwin
)->dispPtr
;
740 * Fetch commonly-used atoms.
743 dispPtr
->multipleAtom
= Tk_InternAtom(tkwin
, "MULTIPLE");
744 dispPtr
->incrAtom
= Tk_InternAtom(tkwin
, "INCR");
745 dispPtr
->targetsAtom
= Tk_InternAtom(tkwin
, "TARGETS");
746 dispPtr
->timestampAtom
= Tk_InternAtom(tkwin
, "TIMESTAMP");
747 dispPtr
->textAtom
= Tk_InternAtom(tkwin
, "TEXT");
748 dispPtr
->compoundTextAtom
= Tk_InternAtom(tkwin
, "COMPOUND_TEXT");
752 *--------------------------------------------------------------
756 * This procedure is invoked whenever a selection-related
757 * event occurs. It does the lion's share of the work
758 * in implementing the selection protocol.
764 * Lots: depends on the type of event.
766 *--------------------------------------------------------------
771 Tk_Window tkwin
, /* Window for which event was
773 register XEvent
*eventPtr
/* X event: either SelectionClear,
774 * SelectionRequest, or
775 * SelectionNotify. */
778 register TkWindow
*winPtr
= (TkWindow
*) tkwin
;
781 * Case #1: SelectionClear events. Invoke clear procedure
782 * for window that just lost the selection. This code is a
783 * bit tricky, because any callbacks to due selection changes
784 * between windows managed by the process have already been
785 * made. Thus, ignore the event unless it refers to the
786 * window that's currently the selection owner and the event
787 * was generated after the server saw the SetSelectionOwner
791 if (eventPtr
->type
== SelectionClear
) {
792 if ((eventPtr
->xselectionclear
.selection
== XA_PRIMARY
)
793 && (winPtr
->dispPtr
->selectionOwner
== tkwin
)
794 && (eventPtr
->xselectionclear
.serial
795 >= winPtr
->dispPtr
->selectionSerial
)
796 && (winPtr
->selClearProc
!= NULL
)) {
797 (*winPtr
->selClearProc
)(winPtr
->selClearData
);
798 winPtr
->selClearProc
= NULL
;
799 winPtr
->dispPtr
->selectionOwner
= NULL
;
805 * Case #2: SelectionNotify events. Call the relevant procedure
806 * to handle the incoming selection.
809 if (eventPtr
->type
== SelectionNotify
) {
810 register RetrievalInfo
*retrPtr
;
814 unsigned long numItems
, bytesAfter
;
816 for (retrPtr
= pendingRetrievals
; ; retrPtr
= retrPtr
->nextPtr
) {
817 if (retrPtr
== NULL
) {
820 if ((retrPtr
->winPtr
== winPtr
)
821 && (eventPtr
->xselection
.selection
== XA_PRIMARY
)
822 && (retrPtr
->target
== eventPtr
->xselection
.target
)
823 && (retrPtr
->result
== -1)) {
824 if (retrPtr
->property
== eventPtr
->xselection
.property
) {
827 if (eventPtr
->xselection
.property
== None
) {
828 Tcl_SetResult(retrPtr
->interp
, (char *) NULL
, TCL_STATIC
);
829 Tcl_AppendResult(retrPtr
->interp
,
830 "selection doesn't exist or form \"",
831 Tk_GetAtomName(tkwin
, retrPtr
->target
),
832 "\" not defined", (char *) NULL
);
833 retrPtr
->result
= TCL_ERROR
;
840 result
= XGetWindowProperty(eventPtr
->xselection
.display
,
841 eventPtr
->xselection
.requestor
, retrPtr
->property
,
842 0, MAX_PROP_WORDS
, False
, (Atom
) AnyPropertyType
,
843 &type
, &format
, &numItems
, &bytesAfter
,
844 (unsigned char **) &propInfo
);
845 if ((result
!= Success
) || (type
== None
)) {
848 if (bytesAfter
!= 0) {
849 Tcl_SetResult(retrPtr
->interp
, "selection property too large",
851 retrPtr
->result
= TCL_ERROR
;
855 if ((type
== XA_STRING
) || (type
== winPtr
->dispPtr
->textAtom
)
856 || (type
== winPtr
->dispPtr
->compoundTextAtom
)) {
858 sprintf(retrPtr
->interp
->result
,
859 "bad format for string selection: wanted \"8\", got \"%d\"",
861 retrPtr
->result
= TCL_ERROR
;
864 retrPtr
->result
= (*retrPtr
->proc
)(retrPtr
->clientData
,
865 retrPtr
->interp
, propInfo
);
866 } else if (type
== winPtr
->dispPtr
->incrAtom
) {
869 * It's a !?#@!?!! INCR-style reception. Arrange to receive
870 * the selection in pieces, using the ICCCM protocol, then
871 * hang around until either the selection is all here or a
875 retrPtr
->idleTime
= 0;
876 Tk_CreateEventHandler(tkwin
, PropertyChangeMask
, SelRcvIncrProc
,
877 (ClientData
) retrPtr
);
878 XDeleteProperty(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
880 while (retrPtr
->result
== -1) {
883 Tk_DeleteEventHandler(tkwin
, PropertyChangeMask
, SelRcvIncrProc
,
884 (ClientData
) retrPtr
);
889 sprintf(retrPtr
->interp
->result
,
890 "bad format for selection: wanted \"32\", got \"%d\"",
892 retrPtr
->result
= TCL_ERROR
;
895 string
= SelCvtFromX((long *) propInfo
, (int) numItems
, type
,
897 retrPtr
->result
= (*retrPtr
->proc
)(retrPtr
->clientData
,
898 retrPtr
->interp
, string
);
906 * Case #3: SelectionRequest events. Call ConvertSelection to
910 if ((eventPtr
->type
== SelectionRequest
)
911 && (eventPtr
->xselectionrequest
.selection
== XA_PRIMARY
)) {
912 ConvertSelection(winPtr
, &eventPtr
->xselectionrequest
);
918 *--------------------------------------------------------------
922 * This procedure is invoked to process pieces of the
923 * selection as they arrive during "selection get"
927 * Always returns TCL_OK.
930 * Bytes get appended to the result currently stored
931 * in interp->result, and its memory area gets
932 * expanded if necessary.
934 *--------------------------------------------------------------
940 ClientData clientData
, /* Information about partially-
941 * assembled result. */
942 Tcl_Interp
*interp
, /* Interpreter used for error
943 * reporting (not used). */
944 char *portion
/* New information to be appended. */
947 register GetInfo
*getInfoPtr
= (GetInfo
*) clientData
;
950 newLength
= strlen(portion
) + getInfoPtr
->bytesUsed
;
953 * Grow the result area if we've run out of space.
956 if (newLength
>= getInfoPtr
->bytesAvl
) {
959 getInfoPtr
->bytesAvl
*= 2;
960 if (getInfoPtr
->bytesAvl
<= newLength
) {
961 getInfoPtr
->bytesAvl
= newLength
+ 1;
963 newString
= (char *) ckalloc((unsigned) getInfoPtr
->bytesAvl
);
964 memcpy((VOID
*) newString
, (VOID
*) getInfoPtr
->string
,
965 getInfoPtr
->bytesUsed
);
966 ckfree(getInfoPtr
->string
);
967 getInfoPtr
->string
= newString
;
971 * Append the new data to what was already there.
974 strcpy(getInfoPtr
->string
+ getInfoPtr
->bytesUsed
, portion
);
975 getInfoPtr
->bytesUsed
= newLength
;
980 *----------------------------------------------------------------------
984 * Given a selection represented as a string (the normal Tcl form),
985 * convert it to the ICCCM-mandated format for X, depending on
986 * the type argument. This procedure and SelCvtFromX are inverses.
989 * The return value is a malloc'ed buffer holding a value
990 * equivalent to "string", but formatted as for "type". It is
991 * the caller's responsibility to free the string when done with
992 * it. The word at *numLongsPtr is filled in with the number of
993 * 32-bit words returned in the result.
998 *----------------------------------------------------------------------
1003 char *string
, /* String representation of selection. */
1004 Atom type
, /* Atom specifying the X format that is
1005 * desired for the selection. Should not
1006 * be XA_STRING (if so, don't bother calling
1007 * this procedure at all). */
1008 Tk_Window tkwin
, /* Window that governs atom conversion. */
1009 int *numLongsPtr
/* Number of 32-bit words contained in the
1016 long *propPtr
, *longPtr
;
1017 #define MAX_ATOM_NAME_LENGTH 100
1018 char atomName
[MAX_ATOM_NAME_LENGTH
+1];
1021 * The string is assumed to consist of fields separated by spaces.
1022 * The property gets generated by converting each field to an
1023 * integer number, in one of two ways:
1024 * 1. If type is XA_ATOM, convert each field to its corresponding
1026 * 2. If type is anything else, convert each field from an ASCII number
1027 * to a 32-bit binary number.
1031 for (p
= string
; *p
!= 0; p
++) {
1036 propPtr
= (long *) ckalloc((unsigned) numFields
*sizeof(long));
1039 * Convert the fields one-by-one.
1042 for (longPtr
= propPtr
, *numLongsPtr
= 0, p
= string
;
1043 ; longPtr
++, (*numLongsPtr
)++) {
1044 while (isspace(*p
)) {
1051 while ((*p
!= 0) && !isspace(*p
)) {
1054 if (type
== XA_ATOM
) {
1058 if (length
> MAX_ATOM_NAME_LENGTH
) {
1059 length
= MAX_ATOM_NAME_LENGTH
;
1061 strncpy(atomName
, field
, length
);
1062 atomName
[length
] = 0;
1063 *longPtr
= (long) Tk_InternAtom(tkwin
, atomName
);
1067 *longPtr
= strtol(field
, &dummy
, 0);
1074 *----------------------------------------------------------------------
1078 * Given an X property value, formatted as a collection of 32-bit
1079 * values according to "type" and the ICCCM conventions, convert
1080 * the value to a string suitable for manipulation by Tcl. This
1081 * procedure is the inverse of SelCvtToX.
1084 * The return value is the string equivalent of "property". It is
1085 * malloc-ed and should be freed by the caller when no longer
1091 *----------------------------------------------------------------------
1096 register long *propPtr
, /* Property value from X. */
1097 int numValues
, /* Number of 32-bit values in property. */
1098 Atom type
, /* Type of property Should not be
1099 * XA_STRING (if so, don't bother calling
1100 * this procedure at all). */
1101 Tk_Window tkwin
/* Window to use for atom conversion. */
1105 int resultSpace
, curSize
, fieldSize
;
1109 * Convert each long in the property to a string value, which is
1110 * either the name of an atom (if type is XA_ATOM) or a hexadecimal
1111 * string. Make an initial guess about the size of the result, but
1112 * be prepared to enlarge the result if necessary.
1115 resultSpace
= 12*numValues
;
1117 atomName
= ""; /* Not needed, but eliminates compiler warning. */
1118 result
= (char *) ckalloc((unsigned) resultSpace
);
1119 for ( ; numValues
> 0; propPtr
++, numValues
--) {
1120 if (type
== XA_ATOM
) {
1121 atomName
= Tk_GetAtomName(tkwin
, (Atom
) *propPtr
);
1122 fieldSize
= strlen(atomName
) + 1;
1126 if (curSize
+fieldSize
>= resultSpace
) {
1130 if (curSize
+fieldSize
>= resultSpace
) {
1131 resultSpace
= curSize
+ fieldSize
+ 1;
1133 newResult
= (char *) ckalloc((unsigned) resultSpace
);
1134 strcpy(newResult
, result
);
1139 result
[curSize
] = ' ';
1142 if (type
== XA_ATOM
) {
1143 strcpy(result
+curSize
, atomName
);
1145 sprintf(result
+curSize
, "%#x", *propPtr
);
1147 curSize
+= strlen(result
+curSize
);
1153 *----------------------------------------------------------------------
1155 * ConvertSelection --
1157 * This procedure is invoked to handle SelectionRequest events.
1158 * It responds to the requests, obeying the ICCCM protocols.
1164 * Properties are created for the selection requestor, and a
1165 * SelectionNotify event is generated for the selection
1166 * requestor. In the event of long selections, this procedure
1167 * implements INCR-mode transfers, using the ICCCM protocol.
1169 *----------------------------------------------------------------------
1174 TkWindow
*winPtr
, /* Window that owns selection. */
1175 register XSelectionRequestEvent
*eventPtr
1177 /* Event describing request. */
1179 XSelectionEvent reply
; /* Used to notify requestor that
1180 * selection info is ready. */
1181 int multiple
; /* Non-zero means a MULTIPLE request
1182 * is being handled. */
1183 IncrInfo info
; /* State of selection conversion. */
1184 Atom singleInfo
[2]; /* info.multAtoms points here except
1185 * for multiple conversions. */
1187 Tk_ErrorHandler errorHandler
;
1189 errorHandler
= Tk_CreateErrorHandler(eventPtr
->display
, -1, -1,-1,
1190 (int (*)(int *, XErrorEvent
*)) NULL
, (ClientData
) NULL
);
1193 * Initialize the reply event.
1196 reply
.type
= SelectionNotify
;
1198 reply
.send_event
= True
;
1199 reply
.display
= eventPtr
->display
;
1200 reply
.requestor
= eventPtr
->requestor
;
1201 reply
.selection
= XA_PRIMARY
;
1202 reply
.target
= eventPtr
->target
;
1203 reply
.property
= eventPtr
->property
;
1204 if (reply
.property
== None
) {
1205 reply
.property
= reply
.target
;
1207 reply
.time
= eventPtr
->time
;
1210 * Watch out for races between conversion requests and
1211 * selection ownership changes: reject the conversion
1212 * request if it's for the wrong window or the wrong
1216 if ((winPtr
->dispPtr
->selectionOwner
!= (Tk_Window
) winPtr
)
1217 || ((eventPtr
->time
< winPtr
->dispPtr
->selectionTime
)
1218 && (eventPtr
->time
!= CurrentTime
)
1219 && (winPtr
->dispPtr
->selectionTime
!= CurrentTime
))) {
1224 * Figure out which kind(s) of conversion to perform. If handling
1225 * a MULTIPLE conversion, then read the property describing which
1226 * conversions to perform.
1229 info
.winPtr
= winPtr
;
1230 if (eventPtr
->target
!= winPtr
->dispPtr
->multipleAtom
) {
1232 singleInfo
[0] = reply
.target
;
1233 singleInfo
[1] = reply
.property
;
1234 info
.multAtoms
= singleInfo
;
1235 info
.numConversions
= 1;
1239 unsigned long bytesAfter
;
1242 info
.multAtoms
= NULL
;
1243 if (eventPtr
->property
== None
) {
1246 result
= XGetWindowProperty(eventPtr
->display
,
1247 eventPtr
->requestor
, eventPtr
->property
,
1248 0, MAX_PROP_WORDS
, False
, XA_ATOM
,
1249 &type
, &format
, &info
.numConversions
, &bytesAfter
,
1250 (unsigned char **) &info
.multAtoms
);
1251 if ((result
!= Success
) || (bytesAfter
!= 0) || (format
!= 32)
1252 || (type
== None
)) {
1253 if (info
.multAtoms
!= NULL
) {
1254 XFree((char *) info
.multAtoms
);
1258 info
.numConversions
/= 2; /* Two atoms per conversion. */
1262 * Loop through all of the requested conversions, and either return
1263 * the entire converted selection, if it can be returned in a single
1264 * bunch, or return INCR information only (the actual selection will
1265 * be returned below).
1268 info
.offsets
= (int *) ckalloc((unsigned) (info
.numConversions
*sizeof(int)));
1270 for (i
= 0; i
< info
.numConversions
; i
++) {
1271 Atom target
, property
;
1272 long buffer
[TK_SEL_WORDS_AT_ONCE
];
1273 register TkSelHandler
*selPtr
;
1275 target
= info
.multAtoms
[2*i
];
1276 property
= info
.multAtoms
[2*i
+ 1];
1277 info
.offsets
[i
] = -1;
1279 for (selPtr
= winPtr
->selHandlerList
; ; selPtr
= selPtr
->nextPtr
) {
1280 int numItems
, format
;
1284 if (selPtr
== NULL
) {
1287 * Nobody seems to know about this kind of request. If
1288 * it's of a sort that we can handle without any help, do
1289 * it. Otherwise mark the request as an errror.
1292 numItems
= DefaultSelection(winPtr
, target
, (char *) buffer
,
1293 TK_SEL_BYTES_AT_ONCE
, &type
);
1294 if (numItems
!= 0) {
1297 info
.multAtoms
[2*i
+ 1] = None
;
1299 } else if (selPtr
->target
== target
) {
1300 numItems
= (*selPtr
->proc
)(selPtr
->clientData
, 0,
1301 (char *) buffer
, TK_SEL_BYTES_AT_ONCE
);
1303 info
.multAtoms
[2*i
+ 1] = None
;
1306 if (numItems
> TK_SEL_BYTES_AT_ONCE
) {
1307 panic("selection handler returned too many bytes");
1309 ((char *) buffer
)[numItems
] = '\0';
1310 type
= selPtr
->format
;
1316 if (numItems
== TK_SEL_BYTES_AT_ONCE
) {
1318 type
= winPtr
->dispPtr
->incrAtom
;
1319 buffer
[0] = 10; /* Guess at # items avl. */
1321 propPtr
= (char *) buffer
;
1323 info
.offsets
[i
] = 0;
1324 } else if (type
== XA_STRING
) {
1325 propPtr
= (char *) buffer
;
1328 propPtr
= (char *) SelCvtToX((char *) buffer
,
1329 type
, (Tk_Window
) winPtr
, &numItems
);
1332 XChangeProperty(reply
.display
, reply
.requestor
,
1333 property
, type
, format
, PropModeReplace
,
1334 (unsigned char *) propPtr
, numItems
);
1335 if (propPtr
!= (char *) buffer
) {
1343 * Send an event back to the requestor to indicate that the
1344 * first stage of conversion is complete (everything is done
1345 * except for long conversions that have to be done in INCR
1349 if (info
.numIncrs
> 0) {
1350 XSelectInput(reply
.display
, reply
.requestor
, PropertyChangeMask
);
1351 info
.timeout
= Tk_CreateTimerHandler(1000, IncrTimeoutProc
,
1352 (ClientData
) &info
);
1354 info
.reqWindow
= reply
.requestor
;
1355 info
.time
= winPtr
->dispPtr
->selectionTime
;
1356 info
.nextPtr
= pendingIncrs
;
1357 pendingIncrs
= &info
;
1360 XChangeProperty(reply
.display
, reply
.requestor
, reply
.property
,
1361 XA_ATOM
, 32, PropModeReplace
,
1362 (unsigned char *) info
.multAtoms
,
1363 (int) info
.numConversions
*2);
1367 * Not a MULTIPLE request. The first property in "multAtoms"
1368 * got set to None if there was an error in conversion.
1371 reply
.property
= info
.multAtoms
[1];
1373 XSendEvent(reply
.display
, reply
.requestor
, False
, 0, (XEvent
*) &reply
);
1374 Tk_DeleteErrorHandler(errorHandler
);
1377 * Handle any remaining INCR-mode transfers. This all happens
1378 * in callbacks to TkSelPropProc, so just wait until the number
1379 * of uncompleted INCR transfers drops to zero.
1382 if (info
.numIncrs
> 0) {
1385 while (info
.numIncrs
> 0) {
1388 Tk_DeleteTimerHandler(info
.timeout
);
1389 errorHandler
= Tk_CreateErrorHandler(winPtr
->display
,
1390 -1, -1,-1, (int (*)(int *, XErrorEvent
*)) NULL
, (ClientData
) NULL
);
1391 XSelectInput(reply
.display
, reply
.requestor
, 0L);
1392 Tk_DeleteErrorHandler(errorHandler
);
1393 if (pendingIncrs
== &info
) {
1394 pendingIncrs
= info
.nextPtr
;
1396 for (infoPtr2
= pendingIncrs
; infoPtr2
!= NULL
;
1397 infoPtr2
= infoPtr2
->nextPtr
) {
1398 if (infoPtr2
->nextPtr
== &info
) {
1399 infoPtr2
->nextPtr
= info
.nextPtr
;
1407 * All done. Cleanup and return.
1410 ckfree((char *) info
.offsets
);
1412 XFree((char *) info
.multAtoms
);
1417 * An error occurred. Send back a refusal message.
1421 reply
.property
= None
;
1422 XSendEvent(reply
.display
, reply
.requestor
, False
, 0, (XEvent
*) &reply
);
1423 Tk_DeleteErrorHandler(errorHandler
);
1428 *----------------------------------------------------------------------
1432 * This procedure handles the INCR protocol on the receiving
1433 * side. It is invoked in response to property changes on
1434 * the requestor's window (which hopefully are because a new
1435 * chunk of the selection arrived).
1441 * If a new piece of selection has arrived, a procedure is
1442 * invoked to deal with that piece. When the whole selection
1443 * is here, a flag is left for the higher-level procedure that
1444 * initiated the selection retrieval.
1446 *----------------------------------------------------------------------
1451 ClientData clientData
, /* Information about retrieval. */
1452 register XEvent
*eventPtr
/* X PropertyChange event. */
1455 register RetrievalInfo
*retrPtr
= (RetrievalInfo
*) clientData
;
1459 unsigned long numItems
, bytesAfter
;
1461 if ((eventPtr
->xproperty
.atom
!= retrPtr
->property
)
1462 || (eventPtr
->xproperty
.state
!= PropertyNewValue
)
1463 || (retrPtr
->result
!= -1)) {
1467 result
= XGetWindowProperty(eventPtr
->xproperty
.display
,
1468 eventPtr
->xproperty
.window
, retrPtr
->property
, 0, MAX_PROP_WORDS
,
1469 True
, (Atom
) AnyPropertyType
, &type
, &format
, &numItems
,
1470 &bytesAfter
, (unsigned char **) &propInfo
);
1471 if ((result
!= Success
) || (type
== None
)) {
1474 if (bytesAfter
!= 0) {
1475 Tcl_SetResult(retrPtr
->interp
, "selection property too large",
1477 retrPtr
->result
= TCL_ERROR
;
1480 if (numItems
== 0) {
1481 retrPtr
->result
= TCL_OK
;
1482 } else if ((type
== XA_STRING
)
1483 || (type
== retrPtr
->winPtr
->dispPtr
->textAtom
)
1484 || (type
== retrPtr
->winPtr
->dispPtr
->compoundTextAtom
)) {
1486 Tcl_SetResult(retrPtr
->interp
, (char *) NULL
, TCL_STATIC
);
1487 sprintf(retrPtr
->interp
->result
,
1488 "bad format for string selection: wanted \"8\", got \"%d\"",
1490 retrPtr
->result
= TCL_ERROR
;
1493 result
= (*retrPtr
->proc
)(retrPtr
->clientData
, retrPtr
->interp
,
1495 if (result
!= TCL_OK
) {
1496 retrPtr
->result
= result
;
1502 Tcl_SetResult(retrPtr
->interp
, (char *) NULL
, TCL_STATIC
);
1503 sprintf(retrPtr
->interp
->result
,
1504 "bad format for selection: wanted \"32\", got \"%d\"",
1506 retrPtr
->result
= TCL_ERROR
;
1509 string
= SelCvtFromX((long *) propInfo
, (int) numItems
, type
,
1510 (Tk_Window
) retrPtr
->winPtr
);
1511 result
= (*retrPtr
->proc
)(retrPtr
->clientData
, retrPtr
->interp
,
1513 if (result
!= TCL_OK
) {
1514 retrPtr
->result
= result
;
1521 retrPtr
->idleTime
= 0;
1525 *----------------------------------------------------------------------
1529 * This procedure is invoked when property-change events
1530 * occur on windows not known to the toolkit. Its function
1531 * is to implement the sending side of the INCR selection
1532 * retrieval protocol when the selection requestor deletes
1533 * the property containing a part of the selection.
1539 * If the property that is receiving the selection was just
1540 * deleted, then a new piece of the selection is fetched and
1541 * placed in the property, until eventually there's no more
1542 * selection to fetch.
1544 *----------------------------------------------------------------------
1549 register XEvent
*eventPtr
/* X PropertyChange event. */
1552 register IncrInfo
*infoPtr
;
1555 register TkSelHandler
*selPtr
;
1556 long buffer
[TK_SEL_WORDS_AT_ONCE
];
1559 Tk_ErrorHandler errorHandler
;
1562 * See if this event announces the deletion of a property being
1563 * used for an INCR transfer. If so, then add the next chunk of
1564 * data to the property.
1567 if (eventPtr
->xproperty
.state
!= PropertyDelete
) {
1570 for (infoPtr
= pendingIncrs
; infoPtr
!= NULL
;
1571 infoPtr
= infoPtr
->nextPtr
) {
1574 * To avoid races between selection conversions and
1575 * changes in selection ownership, make sure the window
1576 * and timestamp for the current selection match those
1577 * in the INCR request.
1580 if ((infoPtr
->reqWindow
!= eventPtr
->xproperty
.window
)
1581 || (infoPtr
->winPtr
->dispPtr
->selectionOwner
1582 != (Tk_Window
) infoPtr
->winPtr
)
1583 || (infoPtr
->winPtr
->dispPtr
->selectionTime
1584 != infoPtr
->time
)) {
1587 for (i
= 0; i
< infoPtr
->numConversions
; i
++) {
1588 if ((eventPtr
->xproperty
.atom
!= infoPtr
->multAtoms
[2*i
+ 1])
1589 || (infoPtr
->offsets
[i
] == -1)){
1592 target
= infoPtr
->multAtoms
[2*i
];
1593 infoPtr
->idleTime
= 0;
1594 for (selPtr
= infoPtr
->winPtr
->selHandlerList
; ;
1595 selPtr
= selPtr
->nextPtr
) {
1596 if (selPtr
== NULL
) {
1597 infoPtr
->multAtoms
[2*i
+ 1] = None
;
1598 infoPtr
->offsets
[i
] = -1;
1599 infoPtr
->numIncrs
--;
1602 if (selPtr
->target
== target
) {
1603 if (infoPtr
->offsets
[i
] == -2) {
1605 ((char *) buffer
)[0] = 0;
1607 numItems
= (*selPtr
->proc
)(selPtr
->clientData
,
1608 infoPtr
->offsets
[i
], (char *) buffer
,
1609 TK_SEL_BYTES_AT_ONCE
);
1610 if (numItems
> TK_SEL_BYTES_AT_ONCE
) {
1611 panic("selection handler returned too many bytes");
1617 ((char *) buffer
)[numItems
] = '\0';
1619 if (numItems
< TK_SEL_BYTES_AT_ONCE
) {
1620 if (numItems
<= 0) {
1621 infoPtr
->offsets
[i
] = -1;
1622 infoPtr
->numIncrs
--;
1624 infoPtr
->offsets
[i
] = -2;
1627 infoPtr
->offsets
[i
] += numItems
;
1629 if (selPtr
->format
== XA_STRING
) {
1630 propPtr
= (char *) buffer
;
1633 propPtr
= (char *) SelCvtToX((char *) buffer
,
1635 (Tk_Window
) infoPtr
->winPtr
,
1639 errorHandler
= Tk_CreateErrorHandler(
1640 eventPtr
->xproperty
.display
, -1, -1, -1,
1641 (int (*)(int *, XErrorEvent
*)) NULL
, (ClientData
) NULL
);
1642 XChangeProperty(eventPtr
->xproperty
.display
,
1643 eventPtr
->xproperty
.window
,
1644 eventPtr
->xproperty
.atom
, selPtr
->format
,
1645 format
, PropModeReplace
,
1646 (unsigned char *) propPtr
, numItems
);
1647 Tk_DeleteErrorHandler(errorHandler
);
1648 if (propPtr
!= (char *) buffer
) {
1659 *----------------------------------------------------------------------
1661 * HandleTclCommand --
1663 * This procedure acts as selection handler for handlers created
1664 * by the "selection handle" command. It invokes a Tcl command to
1665 * retrieve the selection.
1668 * The return value is a count of the number of bytes actually
1672 * None except for things done by the Tcl command.
1674 *----------------------------------------------------------------------
1679 ClientData clientData
, /* Information about command to execute. */
1680 int offset
, /* Return selection bytes starting at this
1682 char *buffer
, /* Place to store converted selection. */
1683 int maxBytes
/* Maximum # of bytes to store at buffer. */
1686 register CommandInfo
*cmdInfoPtr
= (CommandInfo
*) clientData
;
1687 char *oldResultString
;
1688 Tcl_FreeProc
*oldFreeProc
;
1689 int spaceNeeded
, length
;
1690 #define MAX_STATIC_SIZE 100
1691 char staticSpace
[MAX_STATIC_SIZE
];
1695 * First, generate a command by taking the command string
1696 * and appending the offset and maximum # of bytes.
1699 spaceNeeded
= cmdInfoPtr
->cmdLength
+ 30;
1700 if (spaceNeeded
< MAX_STATIC_SIZE
) {
1701 command
= staticSpace
;
1703 command
= (char *) ckalloc((unsigned) spaceNeeded
);
1705 sprintf(command
, "%s %d %d", cmdInfoPtr
->command
, offset
, maxBytes
);
1708 * Execute the command. Be sure to restore the state of the
1709 * interpreter after executing the command.
1712 oldFreeProc
= cmdInfoPtr
->interp
->freeProc
;
1713 if (oldFreeProc
!= 0) {
1714 oldResultString
= cmdInfoPtr
->interp
->result
;
1716 oldResultString
= (char *) ckalloc((unsigned)
1717 (strlen(cmdInfoPtr
->interp
->result
) + 1));
1718 strcpy(oldResultString
, cmdInfoPtr
->interp
->result
);
1719 oldFreeProc
= TCL_DYNAMIC
;
1721 cmdInfoPtr
->interp
->freeProc
= 0;
1722 if (Tcl_GlobalEval(cmdInfoPtr
->interp
, command
) == TCL_OK
) {
1723 length
= strlen(cmdInfoPtr
->interp
->result
);
1727 if (length
> maxBytes
) {
1730 memcpy((VOID
*) buffer
, (VOID
*) cmdInfoPtr
->interp
->result
, length
);
1731 buffer
[length
] = '\0';
1732 Tcl_FreeResult(cmdInfoPtr
->interp
);
1733 cmdInfoPtr
->interp
->result
= oldResultString
;
1734 cmdInfoPtr
->interp
->freeProc
= oldFreeProc
;
1736 if (command
!= staticSpace
) {
1744 *----------------------------------------------------------------------
1748 * This procedure is invoked once every second while waiting for
1749 * the selection to be returned. After a while it gives up and
1750 * aborts the selection retrieval.
1756 * A new timer callback is created to call us again in another
1757 * second, unless time has expired, in which case an error is
1758 * recorded for the retrieval.
1760 *----------------------------------------------------------------------
1765 ClientData clientData
/* Information about retrieval
1769 register RetrievalInfo
*retrPtr
= (RetrievalInfo
*) clientData
;
1772 * Make sure that the retrieval is still in progress. Then
1773 * see how long it's been since any sort of response was received
1774 * from the other side.
1777 if (retrPtr
->result
!= -1) {
1780 retrPtr
->idleTime
++;
1781 if (retrPtr
->idleTime
>= 5) {
1784 * Use a careful procedure to store the error message, because
1785 * the result could already be partially filled in with a partial
1789 Tcl_SetResult(retrPtr
->interp
, "selection owner didn't respond",
1791 retrPtr
->result
= TCL_ERROR
;
1793 retrPtr
->timeout
= Tk_CreateTimerHandler(1000, SelTimeoutProc
,
1794 (ClientData
) retrPtr
);
1799 *----------------------------------------------------------------------
1801 * IncrTimeoutProc --
1803 * This procedure is invoked once a second while sending the
1804 * selection to a requestor in INCR mode. After a while it
1805 * gives up and aborts the selection operation.
1811 * A new timeout gets registered so that this procedure gets
1812 * called again in another second, unless too many seconds
1813 * have elapsed, in which case infoPtr is marked as "all done".
1815 *----------------------------------------------------------------------
1820 ClientData clientData
/* Information about INCR-mode
1821 * selection retrieval for which
1822 * we are selection owner. */
1825 register IncrInfo
*infoPtr
= (IncrInfo
*) clientData
;
1827 infoPtr
->idleTime
++;
1828 if (infoPtr
->idleTime
>= 5) {
1829 infoPtr
->numIncrs
= 0;
1831 infoPtr
->timeout
= Tk_CreateTimerHandler(1000, IncrTimeoutProc
,
1832 (ClientData
) infoPtr
);
1837 *----------------------------------------------------------------------
1839 * DefaultSelection --
1841 * This procedure is called to generate selection information
1842 * for a few standard targets such as TIMESTAMP and TARGETS.
1843 * It is invoked only if no handler has been declared by the
1847 * If "target" is a standard target understood by this procedure,
1848 * the selection is converted to that form and stored as a
1849 * character string in buffer. The type of the selection (e.g.
1850 * STRING or ATOM) is stored in *typePtr, and the return value is
1851 * a count of the # of non-NULL bytes at buffer. If the target
1852 * wasn't understood, or if there isn't enough space at buffer
1853 * to hold the entire selection (no INCR-mode transfers for this
1854 * stuff!), then -1 is returned.
1859 *----------------------------------------------------------------------
1864 TkWindow
*winPtr
, /* Window that owns selection. */
1865 Atom target
, /* Desired form of selection. */
1866 char *buffer
, /* Place to put selection characters. */
1867 int maxBytes
, /* Maximum # of bytes to store at buffer. */
1868 Atom
*typePtr
/* Store here the type of the selection,
1869 * for use in converting to proper X format. */
1872 if (target
== winPtr
->dispPtr
->timestampAtom
) {
1873 if (maxBytes
< 20) {
1876 sprintf(buffer
, "%#x", winPtr
->dispPtr
->selectionTime
);
1877 *typePtr
= XA_INTEGER
;
1878 return strlen(buffer
);
1881 if (target
== winPtr
->dispPtr
->targetsAtom
) {
1882 register TkSelHandler
*selPtr
;
1884 int length
, atomLength
;
1886 if (maxBytes
< 50) {
1889 strcpy(buffer
, "TARGETS MULTIPLE TIMESTAMP");
1890 length
= strlen(buffer
);
1891 for (selPtr
= winPtr
->selHandlerList
; selPtr
!= NULL
;
1892 selPtr
= selPtr
->nextPtr
) {
1893 atomString
= Tk_GetAtomName((Tk_Window
) winPtr
, selPtr
->target
);
1894 atomLength
= strlen(atomString
) + 1;
1895 if ((length
+ atomLength
) >= maxBytes
) {
1898 sprintf(buffer
+length
, " %s", atomString
);
1899 length
+= atomLength
;