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 *--------------------------------------------------------------
169 Tk_RegisterInterp(interp
, name
, tkwin
)
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. */
179 #define TCL_MAX_NAME_LENGTH 1000
180 char propInfo
[TCL_MAX_NAME_LENGTH
+ 20];
181 register RegisteredInterp
*riPtr
;
183 TkWindow
*winPtr
= (TkWindow
*) tkwin
;
186 if (strchr(name
, '|') != NULL
) {
188 "interpreter name cannot contain '|' character";
192 dispPtr
= winPtr
->dispPtr
;
193 if (dispPtr
->commWindow
== NULL
) {
196 result
= SendInit(interp
, dispPtr
);
197 if (result
!= TCL_OK
) {
203 * Make sure the name is unique, and append info about it to
204 * the registry property. Eventually, it would probably be
205 * a good idea to lock the server here to prevent conflicting
206 * changes to the registry property. But that would make
207 * testing more difficult, and probably isn't necessary
208 * anyway because new windows don't get created all that often.
211 w
= LookupName(dispPtr
, name
, 0);
212 if (w
!= (Window
) 0) {
213 Tcl_Interp
*tmpInterp
;
214 RegisteredInterp tmpRi
;
219 * Name already exists. Ping the interpreter with a
220 * NULL command to see if it already exists. If not,
221 * unregister the old name (this could happen if an
222 * application dies without cleaning up the registry).
225 tmpInterp
= Tcl_CreateInterp();
229 tmpRi
.dispPtr
= dispPtr
;
230 tmpRi
.winPtr
= winPtr
;
231 result
= Tk_SendCmd((ClientData
) &tmpRi
, tmpInterp
, 3, argv
);
232 Tcl_DeleteInterp(tmpInterp
);
233 if (result
== TCL_OK
) {
234 Tcl_AppendResult(interp
, "interpreter name \"", name
,
235 "\" is already in use", (char *) NULL
);
238 (void) LookupName(winPtr
->dispPtr
, name
, 1);
240 sprintf(propInfo
, "%x %.*s", Tk_WindowId(dispPtr
->commWindow
),
241 TCL_MAX_NAME_LENGTH
, name
);
242 XChangeProperty(dispPtr
->display
,
243 Tk_DefaultRootWindow(dispPtr
->display
),
244 dispPtr
->registryProperty
, XA_STRING
, 8, PropModeAppend
,
245 (unsigned char *) propInfo
, strlen(propInfo
)+1);
248 * Add an entry in the local registry of names owned by this
252 riPtr
= (RegisteredInterp
*) ckalloc(sizeof(RegisteredInterp
));
253 riPtr
->name
= (char *) ckalloc((unsigned) (strlen(name
) + 1));
254 strcpy(riPtr
->name
, name
);
255 riPtr
->interp
= interp
;
256 riPtr
->dispPtr
= dispPtr
;
257 riPtr
->winPtr
= winPtr
;
258 riPtr
->nextPtr
= registry
;
262 * Add the "send" command to this interpreter, and arrange for
263 * us to be notified when the interpreter is deleted (actually,
264 * when the "send" command is deleted).
267 Tcl_CreateCommand(interp
, "send", Tk_SendCmd
, (ClientData
) riPtr
,
274 *--------------------------------------------------------------
278 * This procedure is invoked to process the "send" Tcl command.
279 * See the user documentation for details on what it does.
282 * A standard Tcl result.
285 * See the user documentation.
287 *--------------------------------------------------------------
291 Tk_SendCmd(clientData
, interp
, argc
, argv
)
292 ClientData clientData
; /* Information about sender (only
293 * dispPtr field is used). */
294 Tcl_Interp
*interp
; /* Current interpreter. */
295 int argc
; /* Number of arguments. */
296 char **argv
; /* Argument strings. */
298 RegisteredInterp
*senderRiPtr
= (RegisteredInterp
*) clientData
;
300 #define STATIC_PROP_SPACE 100
301 char *property
, staticSpace
[STATIC_PROP_SPACE
];
304 static int serial
= 0; /* Running count of sent commands.
305 * Used to give each command a
306 * different serial number. */
307 PendingCommand pending
;
308 Tk_TimerToken timeout
;
309 register RegisteredInterp
*riPtr
;
312 Bool (*prevRestrictProc
)();
314 TkWindow
*winPtr
= senderRiPtr
->winPtr
;
315 TkDisplay
*dispPtr
= senderRiPtr
->dispPtr
;
319 Tk_Window tkwin
= NULL
;
321 if ((argv
[1][0] == '-') &&
322 (strncmp(argv
[1], "-quick", strlen(argv
[1])) == 0)) {
324 argv
+= 1; argc
-= 1;
329 Tk_Window tkwin
= NULL
;
331 if ((argv
[1][0] == '-') &&
332 (strncmp(argv
[1], "-server", strlen(argv
[1])) == 0)) {
334 tkwin
= Tk_NameToWindow(interp
, argv
[2], (Tk_Window
) winPtr
);
336 Tcl_AppendResult(interp
, "bad server arg, should be window name: ",
337 argv
[2], (char *) NULL
);
340 winPtr
= (TkWindow
*) tkwin
;
341 dispPtr
= winPtr
->dispPtr
;
342 argv
+= 2; argc
-= 2;
346 if (dispPtr
->commWindow
== NULL
) {
347 result
= SendInit(interp
, dispPtr
);
348 if (result
!= TCL_OK
) {
355 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
356 " interpName arg ?arg ...?\"", (char *) NULL
);
363 cmd
= Tcl_Concat(argc
-2, argv
+2);
367 * See if the target interpreter is local. If so, execute
368 * the command directly without going through the X server.
369 * The only tricky thing is passing the result from the target
370 * interpreter to the invoking interpreter. Watch out: they
374 for (riPtr
= registry
; riPtr
!= NULL
; riPtr
= riPtr
->nextPtr
) {
375 if (strcmp(riPtr
->name
, argv
[1]) != 0) {
378 if (interp
== riPtr
->interp
) {
379 result
= Tcl_GlobalEval(interp
, cmd
);
381 result
= Tcl_GlobalEval(riPtr
->interp
, cmd
);
382 interp
->result
= riPtr
->interp
->result
;
383 interp
->freeProc
= riPtr
->interp
->freeProc
;
384 riPtr
->interp
->freeProc
= 0;
385 Tcl_ResetResult(riPtr
->interp
);
387 if (cmd
!= argv
[2]) {
394 * Bind the interpreter name to a communication window.
397 w
= LookupName(dispPtr
, argv
[1], 0);
399 Tcl_AppendResult(interp
, "no registered interpeter named \"",
400 argv
[1], "\"", (char *) NULL
);
401 if (cmd
!= argv
[2]) {
409 * Register the fact that we're waiting for a command to
410 * complete (this is needed by SendEventProc and by
411 * AppendErrorProc to pass back the command's results).
415 pending
.serial
= serial
;
416 pending
.target
= argv
[1];
417 pending
.interp
= interp
;
418 pending
.result
= NULL
;
419 pending
.nextPtr
= pendingCommands
;
420 pendingCommands
= &pending
;
424 * Send the command to target interpreter by appending it to the
425 * comm window in the communication window.
428 length
= strlen(argv
[1]) + strlen(cmd
) + 30;
429 if (length
<= STATIC_PROP_SPACE
) {
430 property
= staticSpace
;
432 property
= (char *) ckalloc((unsigned) length
);
434 sprintf(property
, "C %x %x %s|%s",
435 Tk_WindowId(dispPtr
->commWindow
), serial
, argv
[1], cmd
);
436 (void) AppendPropCarefully(dispPtr
->display
, w
, dispPtr
->commProperty
,
438 if (length
> STATIC_PROP_SPACE
) {
441 if (cmd
!= argv
[2]) {
446 sprintf(interp
->result
, "NoReturnValue");
451 * Enter a loop processing X events until the result comes
452 * in. If no response is received within a few seconds,
453 * then timeout. While waiting for a result, look only at
454 * send-related events (otherwise it would be possible for
455 * additional input events, such as mouse motion, to cause
456 * other sends, leading eventually to such a large number
457 * of nested Tcl_Eval calls that the Tcl interpreter panics).
460 prevRestrictProc
= Tk_RestrictEvents(SendRestrictProc
,
461 (char *) dispPtr
->commWindow
, &prevArg
);
462 timeout
= Tk_CreateTimerHandler(5000, TimeoutProc
,
463 (ClientData
) &pending
);
464 while (pending
.result
== NULL
) {
467 Tk_DeleteTimerHandler(timeout
);
468 (void) Tk_RestrictEvents(prevRestrictProc
, prevArg
, &prevArg
);
471 * Unregister the information about the pending command
472 * and return the result.
475 if (pendingCommands
== &pending
) {
476 pendingCommands
= pending
.nextPtr
;
478 PendingCommand
*pcPtr
;
480 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
;
481 pcPtr
= pcPtr
->nextPtr
) {
482 if (pcPtr
->nextPtr
== &pending
) {
483 pcPtr
->nextPtr
= pending
.nextPtr
;
488 Tcl_SetResult(interp
, pending
.result
, TCL_DYNAMIC
);
494 *----------------------------------------------------------------------
496 * TkGetInterpNames --
498 * This procedure is invoked to fetch a list of all the
499 * interpreter names currently registered for the display
500 * of a particular window.
503 * A standard Tcl return value. Interp->result will be set
504 * to hold a list of all the interpreter names defined for
505 * tkwin's display. If an error occurs, then TCL_ERROR
506 * is returned and interp->result will hold an error message.
511 *----------------------------------------------------------------------
515 TkGetInterpNames(interp
, tkwin
)
516 Tcl_Interp
*interp
; /* Interpreter for returning a result. */
517 Tk_Window tkwin
; /* Window whose display is to be used
520 TkDisplay
*dispPtr
= ((TkWindow
*) tkwin
)->dispPtr
;
521 char *regProp
, *separator
, *name
;
523 int result
, actualFormat
;
524 unsigned long numItems
, bytesAfter
;
528 * Read the registry property.
532 result
= XGetWindowProperty(dispPtr
->display
,
533 Tk_DefaultRootWindow(dispPtr
->display
),
534 dispPtr
->registryProperty
, 0, MAX_PROP_WORDS
,
535 False
, XA_STRING
, &actualType
, &actualFormat
,
536 &numItems
, &bytesAfter
, (unsigned char **) ®Prop
);
538 if (actualType
== None
) {
539 sprintf(interp
->result
, "couldn't read intepreter registry property");
544 * If the property is improperly formed, then delete it.
547 if ((result
!= Success
) || (actualFormat
!= 8)
548 || (actualType
!= XA_STRING
)) {
549 if (regProp
!= NULL
) {
552 sprintf(interp
->result
, "intepreter registry property is badly formed");
557 * Scan all of the names out of the property.
561 for (p
= regProp
; (p
-regProp
) < numItems
; p
++) {
563 while ((*p
!= 0) && (!isspace(*p
))) {
568 name
= Tcl_Merge(1, &name
);
569 Tcl_AppendResult(interp
, separator
, name
, (char *) NULL
);
581 *--------------------------------------------------------------
585 * This procedure is called to initialize the
586 * communication channels for sending commands and
590 * The result is a standard Tcl return value, which is
591 * normally TCL_OK. If an error occurs then an error
592 * message is left in interp->result and TCL_ERROR is
596 * Sets up various data structures and windows.
598 *--------------------------------------------------------------
602 SendInit(interp
, dispPtr
)
603 Tcl_Interp
*interp
; /* Interpreter to use for error
605 register TkDisplay
*dispPtr
;/* Display to initialize. */
608 XSetWindowAttributes atts
;
611 * Create the window used for communication, and set up an
612 * event handler for it.
615 dispPtr
->commWindow
= Tk_CreateWindow(interp
, (Tk_Window
) NULL
,
616 "_comm", DisplayString(dispPtr
->display
));
617 if (dispPtr
->commWindow
== NULL
) {
620 atts
.override_redirect
= True
;
621 Tk_ChangeWindowAttributes(dispPtr
->commWindow
,
622 CWOverrideRedirect
, &atts
);
623 Tk_CreateEventHandler(dispPtr
->commWindow
, PropertyChangeMask
,
624 SendEventProc
, (ClientData
) dispPtr
);
625 Tk_MakeWindowExist(dispPtr
->commWindow
);
628 * Get atoms used as property names.
631 dispPtr
->commProperty
= XInternAtom(dispPtr
->display
,
633 dispPtr
->registryProperty
= XInternAtom(dispPtr
->display
,
634 "InterpRegistry", False
);
639 *--------------------------------------------------------------
643 * Given an interpreter name, see if the name exists in
644 * the interpreter registry for a particular display.
647 * If the given name is registered, return the ID of
648 * the window associated with the name. If the name
649 * isn't registered, then return 0.
652 * If the registry property is improperly formed, then
653 * it is deleted. If "delete" is non-zero, then if the
654 * named interpreter is found it is removed from the
657 *--------------------------------------------------------------
661 LookupName(dispPtr
, name
, delete)
662 register TkDisplay
*dispPtr
;
663 /* Display whose registry to check. */
664 char *name
; /* Name of an interpreter. */
665 int delete; /* If non-zero, delete info about name. */
667 char *regProp
, *entry
;
669 int result
, actualFormat
;
670 unsigned long numItems
, bytesAfter
;
675 * Read the registry property.
679 result
= XGetWindowProperty(dispPtr
->display
,
680 Tk_DefaultRootWindow(dispPtr
->display
),
681 dispPtr
->registryProperty
, 0, MAX_PROP_WORDS
,
682 False
, XA_STRING
, &actualType
, &actualFormat
,
683 &numItems
, &bytesAfter
, (unsigned char **) ®Prop
);
685 if (actualType
== None
) {
690 * If the property is improperly formed, then delete it.
693 if ((result
!= Success
) || (actualFormat
!= 8)
694 || (actualType
!= XA_STRING
)) {
695 if (regProp
!= NULL
) {
698 XDeleteProperty(dispPtr
->display
,
699 Tk_DefaultRootWindow(dispPtr
->display
),
700 dispPtr
->registryProperty
);
705 * Scan the property for the desired name.
708 returnValue
= (Window
) 0;
709 entry
= NULL
; /* Not needed, but eliminates compiler warning. */
710 for (p
= regProp
; (p
-regProp
) < numItems
; ) {
712 while ((*p
!= 0) && (!isspace(*p
))) {
715 if ((*p
!= 0) && (strcmp(name
, p
+1) == 0)) {
716 sscanf(entry
, "%x", &returnValue
);
726 * Delete the property, if that is desired (copy down the
727 * remainder of the registry property to overlay the deleted
728 * info, then rewrite the property).
731 if ((delete) && (returnValue
!= 0)) {
738 count
= numItems
- (p
-regProp
);
740 memcpy((VOID
*) entry
, (VOID
*) p
, count
);
742 XChangeProperty(dispPtr
->display
,
743 Tk_DefaultRootWindow(dispPtr
->display
),
744 dispPtr
->registryProperty
, XA_STRING
, 8,
745 PropModeReplace
, (unsigned char *) regProp
,
746 (int) (numItems
- (p
-entry
)));
747 XSync(dispPtr
->display
, False
);
755 *--------------------------------------------------------------
759 * This procedure is invoked automatically by the toolkit
760 * event manager when a property changes on the communication
761 * window. This procedure reads the property and handles
762 * command requests and responses.
768 * If there are command requests in the property, they
769 * are executed. If there are responses in the property,
770 * their information is saved for the (ostensibly waiting)
771 * "send" commands. The property is deleted.
773 *--------------------------------------------------------------
777 SendEventProc(clientData
, eventPtr
)
778 ClientData clientData
; /* Display information. */
779 XEvent
*eventPtr
; /* Information about event. */
781 TkDisplay
*dispPtr
= (TkDisplay
*) clientData
;
784 int result
, actualFormat
;
785 unsigned long numItems
, bytesAfter
;
788 if ((eventPtr
->xproperty
.atom
!= dispPtr
->commProperty
)
789 || (eventPtr
->xproperty
.state
!= PropertyNewValue
)) {
794 * Read the comm property and delete it.
798 result
= XGetWindowProperty(dispPtr
->display
,
799 Tk_WindowId(dispPtr
->commWindow
),
800 dispPtr
->commProperty
, 0, MAX_PROP_WORDS
, True
,
801 XA_STRING
, &actualType
, &actualFormat
,
802 &numItems
, &bytesAfter
, (unsigned char **) &propInfo
);
805 * If the property doesn't exist or is improperly formed
809 if ((result
!= Success
) || (actualType
!= XA_STRING
)
810 || (actualFormat
!= 8)) {
811 if (propInfo
!= NULL
) {
818 * The property is divided into records separated by null
819 * characters. Each record represents one command request
820 * or response. Scan through the property one record at a
824 for (p
= propInfo
; (p
-propInfo
) < numItems
; ) {
827 int serial
, resultSize
;
828 char *resultString
, *interpName
, *returnProp
, *end
;
829 register RegisteredInterp
*riPtr
;
831 #define STATIC_RESULT_SPACE 100
832 char staticSpace
[STATIC_RESULT_SPACE
];
835 *-----------------------------------------------------
836 * This is an incoming command sent by another window.
837 * Parse the fields of the command string. If the command
838 * string isn't properly formed, send back an error message
839 * if there's enough well-formed information to generate
840 * a proper reply; otherwise just ignore the message.
841 *-----------------------------------------------------
845 window
= (Window
) strtol(p
, &end
, 16);
854 serial
= strtol(p
, &end
, 16);
864 while ((*p
!= 0) && (*p
!= '|')) {
869 resultString
= "bad property format for sent command";
876 * Locate the interpreter for the command, then
877 * execute the command.
880 for (riPtr
= registry
; ; riPtr
= riPtr
->nextPtr
) {
884 "receiver never heard of interpreter \"%.40s\"",
886 resultString
= errorMsg
;
889 if (strcmp(riPtr
->name
, interpName
) == 0) {
893 result
= Tcl_GlobalEval(riPtr
->interp
, p
);
894 resultString
= riPtr
->interp
->result
;
897 * Return the result to the sender.
901 resultSize
= strlen(resultString
) + 30;
902 if (resultSize
<= STATIC_RESULT_SPACE
) {
903 returnProp
= staticSpace
;
905 returnProp
= (char *) ckalloc((unsigned) resultSize
);
907 sprintf(returnProp
, "R %x %d %s", serial
, result
,
909 (void) AppendPropCarefully(dispPtr
->display
, window
,
910 dispPtr
->commProperty
, returnProp
,
911 (PendingCommand
*) NULL
);
912 if (returnProp
!= staticSpace
) {
915 } else if (*p
== 'R') {
918 register PendingCommand
*pcPtr
;
921 *-----------------------------------------------------
922 * This record in the property is a result being
923 * returned for a command sent from here. First
925 *-----------------------------------------------------
929 serial
= strtol(p
, &end
, 16);
938 code
= strtol(p
, &end
, 10);
949 * Give the result information to anyone who's
953 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
;
954 pcPtr
= pcPtr
->nextPtr
) {
955 if ((serial
!= pcPtr
->serial
) || (pcPtr
->result
!= NULL
)) {
959 pcPtr
->result
= ckalloc((unsigned) (strlen(p
) + 1));
960 strcpy(pcPtr
->result
, p
);
975 *--------------------------------------------------------------
977 * AppendPropCarefully --
979 * Append a given property to a given window, but set up
980 * an X error handler so that if the append fails this
981 * procedure can return an error code rather than having
988 * The given property on the given window is appended to.
989 * If this operation fails and if pendingPtr is non-NULL,
990 * then the pending operation is marked as complete with
993 *--------------------------------------------------------------
997 AppendPropCarefully(display
, window
, property
, value
, pendingPtr
)
998 Display
*display
; /* Display on which to operate. */
999 Window window
; /* Window whose property is to
1001 Atom property
; /* Name of property. */
1002 char *value
; /* Characters (null-terminated) to
1003 * append to property. */
1004 PendingCommand
*pendingPtr
; /* Pending command to mark complete
1005 * if an error occurs during the
1006 * property op. NULL means just
1007 * ignore the error. */
1009 Tk_ErrorHandler handler
;
1011 handler
= Tk_CreateErrorHandler(display
, -1, -1, -1, AppendErrorProc
,
1012 (ClientData
) pendingPtr
);
1013 XChangeProperty(display
, window
, property
, XA_STRING
, 8,
1014 PropModeAppend
, (unsigned char *) value
, strlen(value
)+1);
1015 Tk_DeleteErrorHandler(handler
);
1019 * The procedure below is invoked if an error occurs during
1020 * the XChangeProperty operation above.
1025 AppendErrorProc(clientData
, errorPtr
)
1026 ClientData clientData
; /* Command to mark complete, or NULL. */
1027 XErrorEvent
*errorPtr
; /* Information about error. */
1029 PendingCommand
*pendingPtr
= (PendingCommand
*) clientData
;
1030 register PendingCommand
*pcPtr
;
1032 if (pendingPtr
== NULL
) {
1037 * Make sure this command is still pending.
1040 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
;
1041 pcPtr
= pcPtr
->nextPtr
) {
1042 if ((pcPtr
== pendingPtr
) && (pcPtr
->result
== NULL
)) {
1043 pcPtr
->result
= ckalloc((unsigned) (strlen(pcPtr
->target
) + 50));
1044 sprintf(pcPtr
->result
,
1045 "send to \"%s\" failed (no communication window)",
1047 pcPtr
->code
= TCL_ERROR
;
1055 *--------------------------------------------------------------
1059 * This procedure is invoked when too much time has elapsed
1060 * during the processing of a sent command.
1066 * Mark the pending command as complete, with an error
1067 * message signalling the timeout.
1069 *--------------------------------------------------------------
1073 TimeoutProc(clientData
)
1074 ClientData clientData
; /* Information about command that
1075 * has been sent but not yet
1078 PendingCommand
*pcPtr
= (PendingCommand
*) clientData
;
1079 register PendingCommand
*pcPtr2
;
1082 * Make sure that the command is still in the pending list
1083 * and that it hasn't already completed. Then register the
1087 for (pcPtr2
= pendingCommands
; pcPtr2
!= NULL
;
1088 pcPtr2
= pcPtr2
->nextPtr
) {
1089 static char msg
[] = "remote interpreter did not respond";
1090 if ((pcPtr2
!= pcPtr
) || (pcPtr2
->result
!= NULL
)) {
1093 pcPtr2
->code
= TCL_ERROR
;
1094 pcPtr2
->result
= ckalloc((unsigned) (sizeof(msg
) + 1));
1095 strcpy(pcPtr2
->result
, msg
);
1101 *--------------------------------------------------------------
1105 * This procedure is invoked by Tcl when a registered
1106 * interpreter is about to be deleted. It unregisters
1113 * The interpreter given by riPtr is unregistered.
1115 *--------------------------------------------------------------
1119 DeleteProc(clientData
)
1120 ClientData clientData
; /* Info about registration, passed
1123 RegisteredInterp
*riPtr
= (RegisteredInterp
*) clientData
;
1124 register RegisteredInterp
*riPtr2
;
1126 (void) LookupName(riPtr
->dispPtr
, riPtr
->name
, 1);
1127 if (registry
== riPtr
) {
1128 registry
= riPtr
->nextPtr
;
1130 for (riPtr2
= registry
; riPtr2
!= NULL
;
1131 riPtr2
= riPtr2
->nextPtr
) {
1132 if (riPtr2
->nextPtr
== riPtr
) {
1133 riPtr2
->nextPtr
= riPtr
->nextPtr
;
1138 ckfree((char *) riPtr
->name
);
1139 ckfree((char *) riPtr
);
1143 *----------------------------------------------------------------------
1145 * SendRestrictProc --
1147 * This procedure filters incoming events when a "send" command
1148 * is outstanding. It defers all events except those containing
1149 * send commands and results.
1152 * False is returned except for property-change events on the
1158 *----------------------------------------------------------------------
1163 SendRestrictProc(display
, eventPtr
, arg
)
1164 Display
*display
; /* Display from which event arrived. */
1165 register XEvent
*eventPtr
; /* Event that just arrived. */
1166 char *arg
; /* Comunication window in which
1167 * we're interested. */
1169 register Tk_Window comm
= (Tk_Window
) arg
;
1171 if ((display
!= Tk_Display(comm
))
1172 || (eventPtr
->type
!= PropertyNotify
)
1173 || (eventPtr
->xproperty
.window
!= Tk_WindowId(comm
))) {