4 * This file provides procedures that implement the "send"
5 * command, allowing commands to be passed from interpreter
8 * Copyright 1989-1992 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/tkSend.c,v 1.26 92/08/13 10:29:26 ouster Exp $ SPRITE (Berkeley)";
26 * The following structure is used to keep track of the
27 * interpreters registered by this process.
30 typedef struct RegisteredInterp
{
31 char *name
; /* Interpreter's name (malloc-ed). */
32 Tcl_Interp
*interp
; /* Interpreter associated with
34 TkDisplay
*dispPtr
; /* Display associated with name. */
35 TkWindow
*winPtr
; /* Window associated with name. */
36 struct RegisteredInterp
*nextPtr
;
37 /* Next in list of names associated
38 * with interps in this process.
39 * NULL means end of list. */
42 static RegisteredInterp
*registry
= NULL
;
43 /* List of all interpreters
44 * registered by this process. */
47 * When a result is being awaited from a sent command, one of
48 * the following structures is present on a list of all outstanding
49 * sent commands. The information in the structure is used to
50 * process the result when it arrives. You're probably wondering
51 * how there could ever be multiple outstanding sent commands.
52 * This could happen if interpreters invoke each other recursively.
53 * It's unlikely, but possible.
56 typedef struct PendingCommand
{
57 int serial
; /* Serial number expected in
59 char *target
; /* Name of interpreter command is
61 Tcl_Interp
*interp
; /* Interpreter from which the send
63 int code
; /* Tcl return code for command
64 * will be stored here. */
65 char *result
; /* String result for command (malloc'ed).
66 * NULL means command still pending. */
67 struct PendingCommand
*nextPtr
;
68 /* Next in list of all outstanding
69 * commands. NULL means end of
73 static PendingCommand
*pendingCommands
= NULL
;
74 /* List of all commands currently
75 * being waited for. */
78 * The information below is used for communication between
79 * processes during "send" commands. Each process keeps a
80 * private window, never even mapped, with one property,
81 * "Comm". When a command is sent to an interpreter, the
82 * command is appended to the comm property of the communication
83 * window associated with the interp's process. Similarly, when a
84 * result is returned from a sent command, it is also appended
85 * to the comm property. In each case, the property information
86 * is in the form of an ASCII string. The exact syntaxes are:
89 * 'C' space window space serial space interpName '|' command '\0'
90 * The 'C' character indicates that this is a command and not
91 * a response. Window is the hex identifier for the comm
92 * window on which to append the response. Serial is a hex
93 * integer containing an identifying number assigned by the
94 * sender; it may be used by the sender to sort out concurrent
95 * responses. InterpName is the ASCII name of the desired
96 * interpreter, which must not contain any vertical bar characters
97 * The interpreter name is delimited by a vertical bar (this
98 * allows the name to include blanks), and is followed by
99 * the command to execute. The command is terminated by a
103 * 'R' space serial space code space result '\0'
104 * The 'R' character indicates that this is a response. Serial
105 * gives the identifier for the command (same value as in the
106 * command message). The code field is a decimal integer giving
107 * the Tcl return code from the command, and result is the string
108 * result. The result is terminated by a NULL character.
110 * The register of interpreters is kept in a property
111 * "InterpRegistry" on the root window of the display. It is
112 * organized as a series of zero or more concatenated strings
113 * (in no particular order), each of the form
114 * window space name '\0'
115 * where "window" is the hex id of the comm. window to use to talk
116 * to an interpreter named "name".
120 * Maximum size property that can be read at one time by
124 #define MAX_PROP_WORDS 100000
127 * Forward declarations for procedures defined later in this file:
130 static int AppendErrorProc
_ANSI_ARGS_((ClientData clientData
,
131 XErrorEvent
*errorPtr
));
132 static void AppendPropCarefully
_ANSI_ARGS_((Display
*display
,
133 Window window
, Atom property
, char *value
,
134 PendingCommand
*pendingPtr
));
135 static void DeleteProc
_ANSI_ARGS_((ClientData clientData
));
136 static Window LookupName
_ANSI_ARGS_((TkDisplay
*dispPtr
, char *name
,
138 static void SendEventProc
_ANSI_ARGS_((ClientData clientData
,
140 static int SendInit
_ANSI_ARGS_((Tcl_Interp
*interp
, TkDisplay
*dispPtr
));
141 static Bool SendRestrictProc
_ANSI_ARGS_((Display
*display
,
142 XEvent
*eventPtr
, char *arg
));
143 static void TimeoutProc
_ANSI_ARGS_((ClientData clientData
));
146 *--------------------------------------------------------------
148 * Tk_RegisterInterp --
150 * This procedure is called to associate an ASCII name
151 * with an interpreter. Tk_InitSend must previously
152 * have been called to set up communication channels
153 * and specify a display.
156 * Zero is returned if the name was registered successfully.
157 * Non-zero means the name was already in use.
160 * Registration info is saved, thereby allowing the
161 * "send" command to be used later to invoke commands
162 * in the interpreter. The registration will be removed
163 * automatically when the interpreter is deleted.
165 *--------------------------------------------------------------
170 Tcl_Interp
*interp
, /* Interpreter associated with name. */
171 char *name
, /* The name that will be used to
172 * refer to the interpreter in later
173 * "send" commands. Must be globally
175 Tk_Window tkwin
/* Token for window associated with
176 * interp; used to identify display
177 * for communication. */
180 #define TCL_MAX_NAME_LENGTH 1000
181 char propInfo
[TCL_MAX_NAME_LENGTH
+ 20];
182 register RegisteredInterp
*riPtr
;
184 TkWindow
*winPtr
= (TkWindow
*) tkwin
;
187 if (strchr(name
, '|') != NULL
) {
189 "interpreter name cannot contain '|' character";
193 dispPtr
= winPtr
->dispPtr
;
194 if (dispPtr
->commWindow
== NULL
) {
197 result
= SendInit(interp
, dispPtr
);
198 if (result
!= TCL_OK
) {
204 * Make sure the name is unique, and append info about it to
205 * the registry property. Eventually, it would probably be
206 * a good idea to lock the server here to prevent conflicting
207 * changes to the registry property. But that would make
208 * testing more difficult, and probably isn't necessary
209 * anyway because new windows don't get created all that often.
212 w
= LookupName(dispPtr
, name
, 0);
213 if (w
!= (Window
) 0) {
214 Tcl_Interp
*tmpInterp
;
215 RegisteredInterp tmpRi
;
220 * Name already exists. Ping the interpreter with a
221 * NULL command to see if it already exists. If not,
222 * unregister the old name (this could happen if an
223 * application dies without cleaning up the registry).
226 tmpInterp
= Tcl_CreateInterp();
230 tmpRi
.dispPtr
= dispPtr
;
231 tmpRi
.winPtr
= winPtr
;
232 result
= Tk_SendCmd((ClientData
) &tmpRi
, tmpInterp
, 3, argv
);
233 Tcl_DeleteInterp(tmpInterp
);
234 if (result
== TCL_OK
) {
235 Tcl_AppendResult(interp
, "interpreter name \"", name
,
236 "\" is already in use", (char *) NULL
);
239 (void) LookupName(winPtr
->dispPtr
, name
, 1);
241 sprintf(propInfo
, "%x %.*s", Tk_WindowId(dispPtr
->commWindow
),
242 TCL_MAX_NAME_LENGTH
, name
);
243 XChangeProperty(dispPtr
->display
,
244 Tk_DefaultRootWindow(dispPtr
->display
),
245 dispPtr
->registryProperty
, XA_STRING
, 8, PropModeAppend
,
246 (unsigned char *) propInfo
, strlen(propInfo
)+1);
249 * Add an entry in the local registry of names owned by this
253 riPtr
= (RegisteredInterp
*) ckalloc(sizeof(RegisteredInterp
));
254 riPtr
->name
= (char *) ckalloc((unsigned) (strlen(name
) + 1));
255 strcpy(riPtr
->name
, name
);
256 riPtr
->interp
= interp
;
257 riPtr
->dispPtr
= dispPtr
;
258 riPtr
->winPtr
= winPtr
;
259 riPtr
->nextPtr
= registry
;
263 * Add the "send" command to this interpreter, and arrange for
264 * us to be notified when the interpreter is deleted (actually,
265 * when the "send" command is deleted).
268 Tcl_CreateCommand(interp
, "send", Tk_SendCmd
, (ClientData
) riPtr
,
275 *--------------------------------------------------------------
279 * This procedure is invoked to process the "send" Tcl command.
280 * See the user documentation for details on what it does.
283 * A standard Tcl result.
286 * See the user documentation.
288 *--------------------------------------------------------------
293 ClientData clientData
, /* Information about sender (only
294 * dispPtr field is used). */
295 Tcl_Interp
*interp
, /* Current interpreter. */
296 int argc
, /* Number of arguments. */
297 char **argv
/* Argument strings. */
300 RegisteredInterp
*senderRiPtr
= (RegisteredInterp
*) clientData
;
302 #define STATIC_PROP_SPACE 100
303 char *property
, staticSpace
[STATIC_PROP_SPACE
];
306 static int serial
= 0; /* Running count of sent commands.
307 * Used to give each command a
308 * different serial number. */
309 PendingCommand pending
;
310 Tk_TimerToken timeout
;
311 register RegisteredInterp
*riPtr
;
314 Bool (*prevRestrictProc
)(Display
*, XEvent
*, char *);
316 TkWindow
*winPtr
= senderRiPtr
->winPtr
;
317 TkDisplay
*dispPtr
= senderRiPtr
->dispPtr
;
321 Tk_Window tkwin
= NULL
;
323 if ((argv
[1][0] == '-') &&
324 (strncmp(argv
[1], "-quick", strlen(argv
[1])) == 0)) {
326 argv
+= 1; argc
-= 1;
331 Tk_Window tkwin
= NULL
;
333 if ((argv
[1][0] == '-') &&
334 (strncmp(argv
[1], "-server", strlen(argv
[1])) == 0)) {
336 tkwin
= Tk_NameToWindow(interp
, argv
[2], (Tk_Window
) winPtr
);
338 Tcl_AppendResult(interp
, "bad server arg, should be window name: ",
339 argv
[2], (char *) NULL
);
342 winPtr
= (TkWindow
*) tkwin
;
343 dispPtr
= winPtr
->dispPtr
;
344 argv
+= 2; argc
-= 2;
348 if (dispPtr
->commWindow
== NULL
) {
349 result
= SendInit(interp
, dispPtr
);
350 if (result
!= TCL_OK
) {
357 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
358 " interpName arg ?arg ...?\"", (char *) NULL
);
365 cmd
= Tcl_Concat(argc
-2, argv
+2);
369 * See if the target interpreter is local. If so, execute
370 * the command directly without going through the X server.
371 * The only tricky thing is passing the result from the target
372 * interpreter to the invoking interpreter. Watch out: they
376 for (riPtr
= registry
; riPtr
!= NULL
; riPtr
= riPtr
->nextPtr
) {
377 if (strcmp(riPtr
->name
, argv
[1]) != 0) {
380 if (interp
== riPtr
->interp
) {
381 result
= Tcl_GlobalEval(interp
, cmd
);
383 result
= Tcl_GlobalEval(riPtr
->interp
, cmd
);
384 interp
->result
= riPtr
->interp
->result
;
385 interp
->freeProc
= riPtr
->interp
->freeProc
;
386 riPtr
->interp
->freeProc
= 0;
387 Tcl_ResetResult(riPtr
->interp
);
389 if (cmd
!= argv
[2]) {
396 * Bind the interpreter name to a communication window.
399 w
= LookupName(dispPtr
, argv
[1], 0);
401 Tcl_AppendResult(interp
, "no registered interpeter named \"",
402 argv
[1], "\"", (char *) NULL
);
403 if (cmd
!= argv
[2]) {
411 * Register the fact that we're waiting for a command to
412 * complete (this is needed by SendEventProc and by
413 * AppendErrorProc to pass back the command's results).
417 pending
.serial
= serial
;
418 pending
.target
= argv
[1];
419 pending
.interp
= interp
;
420 pending
.result
= NULL
;
421 pending
.nextPtr
= pendingCommands
;
422 pendingCommands
= &pending
;
426 * Send the command to target interpreter by appending it to the
427 * comm window in the communication window.
430 length
= strlen(argv
[1]) + strlen(cmd
) + 30;
431 if (length
<= STATIC_PROP_SPACE
) {
432 property
= staticSpace
;
434 property
= (char *) ckalloc((unsigned) length
);
436 sprintf(property
, "C %x %x %s|%s",
437 Tk_WindowId(dispPtr
->commWindow
), serial
, argv
[1], cmd
);
438 (void) AppendPropCarefully(dispPtr
->display
, w
, dispPtr
->commProperty
,
440 if (length
> STATIC_PROP_SPACE
) {
443 if (cmd
!= argv
[2]) {
448 sprintf(interp
->result
, "NoReturnValue");
453 * Enter a loop processing X events until the result comes
454 * in. If no response is received within a few seconds,
455 * then timeout. While waiting for a result, look only at
456 * send-related events (otherwise it would be possible for
457 * additional input events, such as mouse motion, to cause
458 * other sends, leading eventually to such a large number
459 * of nested Tcl_Eval calls that the Tcl interpreter panics).
462 prevRestrictProc
= Tk_RestrictEvents(SendRestrictProc
,
463 (char *) dispPtr
->commWindow
, &prevArg
);
464 timeout
= Tk_CreateTimerHandler(5000, TimeoutProc
,
465 (ClientData
) &pending
);
466 while (pending
.result
== NULL
) {
469 Tk_DeleteTimerHandler(timeout
);
470 (void) Tk_RestrictEvents(prevRestrictProc
, prevArg
, &prevArg
);
473 * Unregister the information about the pending command
474 * and return the result.
477 if (pendingCommands
== &pending
) {
478 pendingCommands
= pending
.nextPtr
;
480 PendingCommand
*pcPtr
;
482 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
;
483 pcPtr
= pcPtr
->nextPtr
) {
484 if (pcPtr
->nextPtr
== &pending
) {
485 pcPtr
->nextPtr
= pending
.nextPtr
;
490 Tcl_SetResult(interp
, pending
.result
, TCL_DYNAMIC
);
496 *----------------------------------------------------------------------
498 * TkGetInterpNames --
500 * This procedure is invoked to fetch a list of all the
501 * interpreter names currently registered for the display
502 * of a particular window.
505 * A standard Tcl return value. Interp->result will be set
506 * to hold a list of all the interpreter names defined for
507 * tkwin's display. If an error occurs, then TCL_ERROR
508 * is returned and interp->result will hold an error message.
513 *----------------------------------------------------------------------
518 Tcl_Interp
*interp
, /* Interpreter for returning a result. */
519 Tk_Window tkwin
/* Window whose display is to be used
523 TkDisplay
*dispPtr
= ((TkWindow
*) tkwin
)->dispPtr
;
524 char *regProp
, *separator
, *name
;
526 int result
, actualFormat
;
527 unsigned long numItems
, bytesAfter
;
531 * Read the registry property.
535 result
= XGetWindowProperty(dispPtr
->display
,
536 Tk_DefaultRootWindow(dispPtr
->display
),
537 dispPtr
->registryProperty
, 0, MAX_PROP_WORDS
,
538 False
, XA_STRING
, &actualType
, &actualFormat
,
539 &numItems
, &bytesAfter
, (unsigned char **) ®Prop
);
541 if (actualType
== None
) {
542 sprintf(interp
->result
, "couldn't read intepreter registry property");
547 * If the property is improperly formed, then delete it.
550 if ((result
!= Success
) || (actualFormat
!= 8)
551 || (actualType
!= XA_STRING
)) {
552 if (regProp
!= NULL
) {
555 sprintf(interp
->result
, "intepreter registry property is badly formed");
560 * Scan all of the names out of the property.
564 for (p
= regProp
; (p
-regProp
) < numItems
; p
++) {
566 while ((*p
!= 0) && (!isspace(*p
))) {
571 name
= Tcl_Merge(1, &name
);
572 Tcl_AppendResult(interp
, separator
, name
, (char *) NULL
);
584 *--------------------------------------------------------------
588 * This procedure is called to initialize the
589 * communication channels for sending commands and
593 * The result is a standard Tcl return value, which is
594 * normally TCL_OK. If an error occurs then an error
595 * message is left in interp->result and TCL_ERROR is
599 * Sets up various data structures and windows.
601 *--------------------------------------------------------------
606 Tcl_Interp
*interp
, /* Interpreter to use for error
608 register TkDisplay
*dispPtr
/* Display to initialize. */
612 XSetWindowAttributes atts
;
615 * Create the window used for communication, and set up an
616 * event handler for it.
619 dispPtr
->commWindow
= Tk_CreateWindow(interp
, (Tk_Window
) NULL
,
620 "_comm", DisplayString(dispPtr
->display
));
621 if (dispPtr
->commWindow
== NULL
) {
624 atts
.override_redirect
= True
;
625 Tk_ChangeWindowAttributes(dispPtr
->commWindow
,
626 CWOverrideRedirect
, &atts
);
627 Tk_CreateEventHandler(dispPtr
->commWindow
, PropertyChangeMask
,
628 SendEventProc
, (ClientData
) dispPtr
);
629 Tk_MakeWindowExist(dispPtr
->commWindow
);
632 * Get atoms used as property names.
635 dispPtr
->commProperty
= XInternAtom(dispPtr
->display
,
637 dispPtr
->registryProperty
= XInternAtom(dispPtr
->display
,
638 "InterpRegistry", False
);
643 *--------------------------------------------------------------
647 * Given an interpreter name, see if the name exists in
648 * the interpreter registry for a particular display.
651 * If the given name is registered, return the ID of
652 * the window associated with the name. If the name
653 * isn't registered, then return 0.
656 * If the registry property is improperly formed, then
657 * it is deleted. If "delete" is non-zero, then if the
658 * named interpreter is found it is removed from the
661 *--------------------------------------------------------------
666 register TkDisplay
*dispPtr
,
667 char *name
, /* Name of an interpreter. */
668 int delete /* If non-zero, delete info about name. */
671 char *regProp
, *entry
;
673 int result
, actualFormat
;
674 unsigned long numItems
, bytesAfter
;
679 * Read the registry property.
683 result
= XGetWindowProperty(dispPtr
->display
,
684 Tk_DefaultRootWindow(dispPtr
->display
),
685 dispPtr
->registryProperty
, 0, MAX_PROP_WORDS
,
686 False
, XA_STRING
, &actualType
, &actualFormat
,
687 &numItems
, &bytesAfter
, (unsigned char **) ®Prop
);
689 if (actualType
== None
) {
694 * If the property is improperly formed, then delete it.
697 if ((result
!= Success
) || (actualFormat
!= 8)
698 || (actualType
!= XA_STRING
)) {
699 if (regProp
!= NULL
) {
702 XDeleteProperty(dispPtr
->display
,
703 Tk_DefaultRootWindow(dispPtr
->display
),
704 dispPtr
->registryProperty
);
709 * Scan the property for the desired name.
712 returnValue
= (Window
) 0;
713 entry
= NULL
; /* Not needed, but eliminates compiler warning. */
714 for (p
= regProp
; (p
-regProp
) < numItems
; ) {
716 while ((*p
!= 0) && (!isspace(*p
))) {
719 if ((*p
!= 0) && (strcmp(name
, p
+1) == 0)) {
720 sscanf(entry
, "%x", &returnValue
);
730 * Delete the property, if that is desired (copy down the
731 * remainder of the registry property to overlay the deleted
732 * info, then rewrite the property).
735 if ((delete) && (returnValue
!= 0)) {
742 count
= numItems
- (p
-regProp
);
744 memcpy((VOID
*) entry
, (VOID
*) p
, count
);
746 XChangeProperty(dispPtr
->display
,
747 Tk_DefaultRootWindow(dispPtr
->display
),
748 dispPtr
->registryProperty
, XA_STRING
, 8,
749 PropModeReplace
, (unsigned char *) regProp
,
750 (int) (numItems
- (p
-entry
)));
751 XSync(dispPtr
->display
, False
);
759 *--------------------------------------------------------------
763 * This procedure is invoked automatically by the toolkit
764 * event manager when a property changes on the communication
765 * window. This procedure reads the property and handles
766 * command requests and responses.
772 * If there are command requests in the property, they
773 * are executed. If there are responses in the property,
774 * their information is saved for the (ostensibly waiting)
775 * "send" commands. The property is deleted.
777 *--------------------------------------------------------------
782 ClientData clientData
, /* Display information. */
783 XEvent
*eventPtr
/* Information about event. */
786 TkDisplay
*dispPtr
= (TkDisplay
*) clientData
;
789 int result
, actualFormat
;
790 unsigned long numItems
, bytesAfter
;
793 if ((eventPtr
->xproperty
.atom
!= dispPtr
->commProperty
)
794 || (eventPtr
->xproperty
.state
!= PropertyNewValue
)) {
799 * Read the comm property and delete it.
803 result
= XGetWindowProperty(dispPtr
->display
,
804 Tk_WindowId(dispPtr
->commWindow
),
805 dispPtr
->commProperty
, 0, MAX_PROP_WORDS
, True
,
806 XA_STRING
, &actualType
, &actualFormat
,
807 &numItems
, &bytesAfter
, (unsigned char **) &propInfo
);
810 * If the property doesn't exist or is improperly formed
814 if ((result
!= Success
) || (actualType
!= XA_STRING
)
815 || (actualFormat
!= 8)) {
816 if (propInfo
!= NULL
) {
823 * The property is divided into records separated by null
824 * characters. Each record represents one command request
825 * or response. Scan through the property one record at a
829 for (p
= propInfo
; (p
-propInfo
) < numItems
; ) {
832 int serial
, resultSize
;
833 char *resultString
, *interpName
, *returnProp
, *end
;
834 register RegisteredInterp
*riPtr
;
836 #define STATIC_RESULT_SPACE 100
837 char staticSpace
[STATIC_RESULT_SPACE
];
840 *-----------------------------------------------------
841 * This is an incoming command sent by another window.
842 * Parse the fields of the command string. If the command
843 * string isn't properly formed, send back an error message
844 * if there's enough well-formed information to generate
845 * a proper reply; otherwise just ignore the message.
846 *-----------------------------------------------------
850 window
= (Window
) strtol(p
, &end
, 16);
859 serial
= strtol(p
, &end
, 16);
869 while ((*p
!= 0) && (*p
!= '|')) {
874 resultString
= "bad property format for sent command";
881 * Locate the interpreter for the command, then
882 * execute the command.
885 for (riPtr
= registry
; ; riPtr
= riPtr
->nextPtr
) {
889 "receiver never heard of interpreter \"%.40s\"",
891 resultString
= errorMsg
;
894 if (strcmp(riPtr
->name
, interpName
) == 0) {
898 result
= Tcl_GlobalEval(riPtr
->interp
, p
);
899 resultString
= riPtr
->interp
->result
;
902 * Return the result to the sender.
906 resultSize
= strlen(resultString
) + 30;
907 if (resultSize
<= STATIC_RESULT_SPACE
) {
908 returnProp
= staticSpace
;
910 returnProp
= (char *) ckalloc((unsigned) resultSize
);
912 sprintf(returnProp
, "R %x %d %s", serial
, result
,
914 (void) AppendPropCarefully(dispPtr
->display
, window
,
915 dispPtr
->commProperty
, returnProp
,
916 (PendingCommand
*) NULL
);
917 if (returnProp
!= staticSpace
) {
920 } else if (*p
== 'R') {
923 register PendingCommand
*pcPtr
;
926 *-----------------------------------------------------
927 * This record in the property is a result being
928 * returned for a command sent from here. First
930 *-----------------------------------------------------
934 serial
= strtol(p
, &end
, 16);
943 code
= strtol(p
, &end
, 10);
954 * Give the result information to anyone who's
958 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
;
959 pcPtr
= pcPtr
->nextPtr
) {
960 if ((serial
!= pcPtr
->serial
) || (pcPtr
->result
!= NULL
)) {
964 pcPtr
->result
= ckalloc((unsigned) (strlen(p
) + 1));
965 strcpy(pcPtr
->result
, p
);
980 *--------------------------------------------------------------
982 * AppendPropCarefully --
984 * Append a given property to a given window, but set up
985 * an X error handler so that if the append fails this
986 * procedure can return an error code rather than having
993 * The given property on the given window is appended to.
994 * If this operation fails and if pendingPtr is non-NULL,
995 * then the pending operation is marked as complete with
998 *--------------------------------------------------------------
1002 AppendPropCarefully (
1003 Display
*display
, /* Display on which to operate. */
1004 Window window
, /* Window whose property is to
1006 Atom property
, /* Name of property. */
1007 char *value
, /* Characters (null-terminated) to
1008 * append to property. */
1009 PendingCommand
*pendingPtr
/* Pending command to mark complete
1010 * if an error occurs during the
1011 * property op. NULL means just
1012 * ignore the error. */
1015 Tk_ErrorHandler handler
;
1017 handler
= Tk_CreateErrorHandler(display
, -1, -1, -1, AppendErrorProc
,
1018 (ClientData
) pendingPtr
);
1019 XChangeProperty(display
, window
, property
, XA_STRING
, 8,
1020 PropModeAppend
, (unsigned char *) value
, strlen(value
)+1);
1021 Tk_DeleteErrorHandler(handler
);
1025 * The procedure below is invoked if an error occurs during
1026 * the XChangeProperty operation above.
1032 ClientData clientData
, /* Command to mark complete, or NULL. */
1033 XErrorEvent
*errorPtr
/* Information about error. */
1036 PendingCommand
*pendingPtr
= (PendingCommand
*) clientData
;
1037 register PendingCommand
*pcPtr
;
1039 if (pendingPtr
== NULL
) {
1044 * Make sure this command is still pending.
1047 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
;
1048 pcPtr
= pcPtr
->nextPtr
) {
1049 if ((pcPtr
== pendingPtr
) && (pcPtr
->result
== NULL
)) {
1050 pcPtr
->result
= ckalloc((unsigned) (strlen(pcPtr
->target
) + 50));
1051 sprintf(pcPtr
->result
,
1052 "send to \"%s\" failed (no communication window)",
1054 pcPtr
->code
= TCL_ERROR
;
1062 *--------------------------------------------------------------
1066 * This procedure is invoked when too much time has elapsed
1067 * during the processing of a sent command.
1073 * Mark the pending command as complete, with an error
1074 * message signalling the timeout.
1076 *--------------------------------------------------------------
1081 ClientData clientData
/* Information about command that
1082 * has been sent but not yet
1086 PendingCommand
*pcPtr
= (PendingCommand
*) clientData
;
1087 register PendingCommand
*pcPtr2
;
1090 * Make sure that the command is still in the pending list
1091 * and that it hasn't already completed. Then register the
1095 for (pcPtr2
= pendingCommands
; pcPtr2
!= NULL
;
1096 pcPtr2
= pcPtr2
->nextPtr
) {
1097 static char msg
[] = "remote interpreter did not respond";
1098 if ((pcPtr2
!= pcPtr
) || (pcPtr2
->result
!= NULL
)) {
1101 pcPtr2
->code
= TCL_ERROR
;
1102 pcPtr2
->result
= ckalloc((unsigned) (sizeof(msg
) + 1));
1103 strcpy(pcPtr2
->result
, msg
);
1109 *--------------------------------------------------------------
1113 * This procedure is invoked by Tcl when a registered
1114 * interpreter is about to be deleted. It unregisters
1121 * The interpreter given by riPtr is unregistered.
1123 *--------------------------------------------------------------
1128 ClientData clientData
/* Info about registration, passed
1132 RegisteredInterp
*riPtr
= (RegisteredInterp
*) clientData
;
1133 register RegisteredInterp
*riPtr2
;
1135 (void) LookupName(riPtr
->dispPtr
, riPtr
->name
, 1);
1136 if (registry
== riPtr
) {
1137 registry
= riPtr
->nextPtr
;
1139 for (riPtr2
= registry
; riPtr2
!= NULL
;
1140 riPtr2
= riPtr2
->nextPtr
) {
1141 if (riPtr2
->nextPtr
== riPtr
) {
1142 riPtr2
->nextPtr
= riPtr
->nextPtr
;
1147 ckfree((char *) riPtr
->name
);
1148 ckfree((char *) riPtr
);
1152 *----------------------------------------------------------------------
1154 * SendRestrictProc --
1156 * This procedure filters incoming events when a "send" command
1157 * is outstanding. It defers all events except those containing
1158 * send commands and results.
1161 * False is returned except for property-change events on the
1167 *----------------------------------------------------------------------
1173 Display
*display
, /* Display from which event arrived. */
1174 register XEvent
*eventPtr
, /* Event that just arrived. */
1175 char *arg
/* Comunication window in which
1176 * we're interested. */
1179 register Tk_Window comm
= (Tk_Window
) arg
;
1181 if ((display
!= Tk_Display(comm
))
1182 || (eventPtr
->type
!= PropertyNotify
)
1183 || (eventPtr
->xproperty
.window
!= Tk_WindowId(comm
))) {