4 * This module implements a message widgets for the Tk
5 * toolkit. A message widget displays a multi-line string
6 * in a window according to a particular aspect ratio.
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/tkMessage.c,v 1.36 92/06/08 11:06:05 ouster Exp $ SPRITE (Berkeley)";
27 * A data structure of the following type is kept for each message
28 * widget managed by this file:
32 Tk_Window tkwin
; /* Window that embodies the message. NULL
33 * means that the window has been destroyed
34 * but the data structures haven't yet been
36 Tcl_Interp
*interp
; /* Interpreter associated with message. */
37 Tk_Uid string
; /* String displayed in message. */
38 int numChars
; /* Number of characters in string, not
39 * including terminating NULL character. */
40 char *textVarName
; /* Name of variable (malloc'ed) or NULL.
41 * If non-NULL, message displays the contents
42 * of this variable. */
45 * Information used when displaying widget:
48 Tk_3DBorder border
; /* Structure used to draw 3-D border and
49 * background. NULL means a border hasn't
50 * been created yet. */
51 int borderWidth
; /* Width of border. */
52 int relief
; /* 3-D effect: TK_RELIEF_RAISED, etc. */
53 XFontStruct
*fontPtr
; /* Information about text font, or NULL. */
54 XColor
*fgColorPtr
; /* Foreground color in normal mode. */
55 GC textGC
; /* GC for drawing text in normal mode. */
56 int padX
, padY
; /* User-requested extra space around text. */
57 Tk_Anchor anchor
; /* Where to position text within window region
58 * if window is larger or smaller than
60 int width
; /* User-requested width, in pixels. 0 means
61 * compute width using aspect ratio below. */
62 int aspect
; /* Desired aspect ratio for window
63 * (100*width/height). */
64 int lineLength
; /* Length of each line, in pixels. Computed
65 * from width and/or aspect. */
66 int msgHeight
; /* Total number of pixels in vertical direction
67 * needed to display message. */
68 Tk_Justify justify
; /* Justification for text. */
71 * Miscellaneous information:
74 Cursor cursor
; /* Current cursor for window, or None. */
75 int flags
; /* Various flags; see below for
80 * Flag bits for messages:
82 * REDRAW_PENDING: Non-zero means a DoWhenIdle handler
83 * has already been queued to redraw
85 * CLEAR_NEEDED; Need to clear the window when redrawing.
88 #define REDRAW_PENDING 1
89 #define CLEAR_NEEDED 2
92 * Information used for argv parsing.
96 static Tk_ConfigSpec configSpecs
[] = {
97 {TK_CONFIG_ANCHOR
, "-anchor", "anchor", "Anchor",
98 DEF_MESSAGE_ANCHOR
, Tk_Offset(Message
, anchor
), 0},
99 {TK_CONFIG_INT
, "-aspect", "aspect", "Aspect",
100 DEF_MESSAGE_ASPECT
, Tk_Offset(Message
, aspect
), 0},
101 {TK_CONFIG_BORDER
, "-background", "background", "Background",
102 DEF_MESSAGE_BG_COLOR
, Tk_Offset(Message
, border
),
103 TK_CONFIG_COLOR_ONLY
},
104 {TK_CONFIG_BORDER
, "-background", "background", "Background",
105 DEF_MESSAGE_BG_MONO
, Tk_Offset(Message
, border
),
106 TK_CONFIG_MONO_ONLY
},
107 {TK_CONFIG_SYNONYM
, "-bd", "borderWidth", (char *) NULL
,
108 (char *) NULL
, 0, 0},
109 {TK_CONFIG_SYNONYM
, "-bg", "background", (char *) NULL
,
110 (char *) NULL
, 0, 0},
111 {TK_CONFIG_PIXELS
, "-borderwidth", "borderWidth", "BorderWidth",
112 DEF_MESSAGE_BORDER_WIDTH
, Tk_Offset(Message
, borderWidth
), 0},
113 {TK_CONFIG_ACTIVE_CURSOR
, "-cursor", "cursor", "Cursor",
114 DEF_MESSAGE_CURSOR
, Tk_Offset(Message
, cursor
), TK_CONFIG_NULL_OK
},
115 {TK_CONFIG_SYNONYM
, "-fg", "foreground", (char *) NULL
,
116 (char *) NULL
, 0, 0},
117 {TK_CONFIG_FONT
, "-font", "font", "Font",
118 DEF_MESSAGE_FONT
, Tk_Offset(Message
, fontPtr
), 0},
119 {TK_CONFIG_COLOR
, "-foreground", "foreground", "Foreground",
120 DEF_MESSAGE_FG
, Tk_Offset(Message
, fgColorPtr
), 0},
121 {TK_CONFIG_JUSTIFY
, "-justify", "justify", "Justify",
122 DEF_MESSAGE_JUSTIFY
, Tk_Offset(Message
, justify
), 0},
123 {TK_CONFIG_PIXELS
, "-padx", "padX", "Pad",
124 DEF_MESSAGE_PADX
, Tk_Offset(Message
, padX
), 0},
125 {TK_CONFIG_PIXELS
, "-pady", "padY", "Pad",
126 DEF_MESSAGE_PADY
, Tk_Offset(Message
, padY
), 0},
127 {TK_CONFIG_RELIEF
, "-relief", "relief", "Relief",
128 DEF_MESSAGE_RELIEF
, Tk_Offset(Message
, relief
), 0},
129 {TK_CONFIG_STRING
, "-text", "text", "Text",
130 DEF_MESSAGE_TEXT
, Tk_Offset(Message
, string
), 0},
131 {TK_CONFIG_STRING
, "-textvariable", "textVariable", "Variable",
132 DEF_MESSAGE_TEXT_VARIABLE
, Tk_Offset(Message
, textVarName
),
134 {TK_CONFIG_PIXELS
, "-width", "width", "Width",
135 DEF_MESSAGE_WIDTH
, Tk_Offset(Message
, width
), 0},
136 {TK_CONFIG_END
, (char *) NULL
, (char *) NULL
, (char *) NULL
,
141 * Forward declarations for procedures defined later in this file:
144 static void MessageEventProc
_ANSI_ARGS_((ClientData clientData
,
146 static char * MessageTextVarProc
_ANSI_ARGS_((ClientData clientData
,
147 Tcl_Interp
*interp
, char *name1
, char *name2
,
149 static int MessageWidgetCmd
_ANSI_ARGS_((ClientData clientData
,
150 Tcl_Interp
*interp
, int argc
, char **argv
));
151 static void ComputeMessageGeometry
_ANSI_ARGS_((Message
*msgPtr
));
152 static int ConfigureMessage
_ANSI_ARGS_((Tcl_Interp
*interp
,
153 Message
*msgPtr
, int argc
, char **argv
,
155 static void DestroyMessage
_ANSI_ARGS_((ClientData clientData
));
156 static void DisplayMessage
_ANSI_ARGS_((ClientData clientData
));
159 *--------------------------------------------------------------
163 * This procedure is invoked to process the "message" Tcl
164 * command. See the user documentation for details on what
168 * A standard Tcl result.
171 * See the user documentation.
173 *--------------------------------------------------------------
178 ClientData clientData
, /* Main window associated with
180 Tcl_Interp
*interp
, /* Current interpreter. */
181 int argc
, /* Number of arguments. */
182 char **argv
/* Argument strings. */
185 register Message
*msgPtr
;
187 Tk_Window tkwin
= (Tk_Window
) clientData
;
190 Tcl_AppendResult(interp
, "wrong # args: should be \"",
191 argv
[0], " pathName ?options?\"", (char *) NULL
);
195 new = Tk_CreateWindowFromPath(interp
, tkwin
, argv
[1], (char *) NULL
);
200 msgPtr
= (Message
*) ckalloc(sizeof(Message
));
202 msgPtr
->interp
= interp
;
203 msgPtr
->string
= NULL
;
204 msgPtr
->textVarName
= NULL
;
205 msgPtr
->border
= NULL
;
206 msgPtr
->borderWidth
= 0;
207 msgPtr
->relief
= TK_RELIEF_FLAT
;
208 msgPtr
->fontPtr
= NULL
;
209 msgPtr
->fgColorPtr
= NULL
;
210 msgPtr
->textGC
= NULL
;
214 msgPtr
->aspect
= 150;
215 msgPtr
->justify
= TK_JUSTIFY_LEFT
;
216 msgPtr
->cursor
= None
;
219 Tk_SetClass(msgPtr
->tkwin
, "Message");
220 Tk_CreateEventHandler(msgPtr
->tkwin
, ExposureMask
|StructureNotifyMask
,
221 MessageEventProc
, (ClientData
) msgPtr
);
222 Tcl_CreateCommand(interp
, Tk_PathName(msgPtr
->tkwin
), MessageWidgetCmd
,
223 (ClientData
) msgPtr
, (void (*)(int *)) NULL
);
224 if (ConfigureMessage(interp
, msgPtr
, argc
-2, argv
+2, 0) != TCL_OK
) {
228 interp
->result
= Tk_PathName(msgPtr
->tkwin
);
232 Tk_DestroyWindow(msgPtr
->tkwin
);
237 *--------------------------------------------------------------
239 * MessageWidgetCmd --
241 * This procedure is invoked to process the Tcl command
242 * that corresponds to a widget managed by this module.
243 * See the user documentation for details on what it does.
246 * A standard Tcl result.
249 * See the user documentation.
251 *--------------------------------------------------------------
256 ClientData clientData
, /* Information about message widget. */
257 Tcl_Interp
*interp
, /* Current interpreter. */
258 int argc
, /* Number of arguments. */
259 char **argv
/* Argument strings. */
262 register Message
*msgPtr
= (Message
*) clientData
;
267 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
268 " option ?arg arg ...?\"", (char *) NULL
);
272 length
= strlen(argv
[1]);
273 if ((c
== 'c') && (strncmp(argv
[1], "configure", length
) == 0)) {
275 return Tk_ConfigureInfo(interp
, msgPtr
->tkwin
, configSpecs
,
276 (char *) msgPtr
, (char *) NULL
, 0);
277 } else if (argc
== 3) {
278 return Tk_ConfigureInfo(interp
, msgPtr
->tkwin
, configSpecs
,
279 (char *) msgPtr
, argv
[2], 0);
281 return ConfigureMessage(interp
, msgPtr
, argc
-2, argv
+2,
282 TK_CONFIG_ARGV_ONLY
);
285 Tcl_AppendResult(interp
, "bad option \"", argv
[1],
286 "\": must be configure", (char *) NULL
);
292 *----------------------------------------------------------------------
296 * This procedure is invoked by Tk_EventuallyFree or Tk_Release
297 * to clean up the internal structure of a message at a safe time
298 * (when no-one is using it anymore).
304 * Everything associated with the message is freed up.
306 *----------------------------------------------------------------------
311 ClientData clientData
/* Info about message widget. */
314 register Message
*msgPtr
= (Message
*) clientData
;
316 if (msgPtr
->string
!= NULL
) {
317 ckfree(msgPtr
->string
);
319 if (msgPtr
->textVarName
!= NULL
) {
320 Tcl_UntraceVar(msgPtr
->interp
, msgPtr
->textVarName
,
321 TCL_GLOBAL_ONLY
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
,
322 MessageTextVarProc
, (ClientData
) msgPtr
);
323 ckfree(msgPtr
->textVarName
);
325 if (msgPtr
->border
!= NULL
) {
326 Tk_Free3DBorder(msgPtr
->border
);
328 if (msgPtr
->fontPtr
!= NULL
) {
329 Tk_FreeFontStruct(msgPtr
->fontPtr
);
331 if (msgPtr
->fgColorPtr
!= NULL
) {
332 Tk_FreeColor(msgPtr
->fgColorPtr
);
334 if (msgPtr
->textGC
!= None
) {
335 Tk_FreeGC(msgPtr
->textGC
);
337 if (msgPtr
->cursor
!= None
) {
338 Tk_FreeCursor(msgPtr
->cursor
);
340 ckfree((char *) msgPtr
);
344 *----------------------------------------------------------------------
346 * ConfigureMessage --
348 * This procedure is called to process an argv/argc list, plus
349 * the Tk option database, in order to configure (or
350 * reconfigure) a message widget.
353 * The return value is a standard Tcl result. If TCL_ERROR is
354 * returned, then interp->result contains an error message.
357 * Configuration information, such as text string, colors, font,
358 * etc. get set for msgPtr; old resources get freed, if there
361 *----------------------------------------------------------------------
366 Tcl_Interp
*interp
, /* Used for error reporting. */
367 register Message
*msgPtr
, /* Information about widget; may or may
368 * not already have values for some fields. */
369 int argc
, /* Number of valid entries in argv. */
370 char **argv
, /* Arguments. */
371 int flags
/* Flags to pass to Tk_ConfigureWidget. */
378 * Eliminate any existing trace on a variable monitored by the message.
381 if (msgPtr
->textVarName
!= NULL
) {
382 Tcl_UntraceVar(interp
, msgPtr
->textVarName
,
383 TCL_GLOBAL_ONLY
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
,
384 MessageTextVarProc
, (ClientData
) msgPtr
);
387 if (Tk_ConfigureWidget(interp
, msgPtr
->tkwin
, configSpecs
,
388 argc
, argv
, (char *) msgPtr
, flags
) != TCL_OK
) {
393 * If the message is to display the value of a variable, then set up
394 * a trace on the variable's value, create the variable if it doesn't
395 * exist, and fetch its current value.
398 if (msgPtr
->textVarName
!= NULL
) {
401 value
= Tcl_GetVar(interp
, msgPtr
->textVarName
, TCL_GLOBAL_ONLY
);
403 Tcl_SetVar(interp
, msgPtr
->textVarName
, msgPtr
->string
,
406 if (msgPtr
->string
!= NULL
) {
407 ckfree(msgPtr
->string
);
409 msgPtr
->string
= ckalloc((unsigned) (strlen(value
) + 1));
410 strcpy(msgPtr
->string
, value
);
412 Tcl_TraceVar(interp
, msgPtr
->textVarName
,
413 TCL_GLOBAL_ONLY
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
,
414 MessageTextVarProc
, (ClientData
) msgPtr
);
418 * A few other options need special processing, such as setting
419 * the background from a 3-D border or handling special defaults
420 * that couldn't be specified to Tk_ConfigureWidget.
423 msgPtr
->numChars
= strlen(msgPtr
->string
);
425 Tk_SetBackgroundFromBorder(msgPtr
->tkwin
, msgPtr
->border
);
427 gcValues
.font
= msgPtr
->fontPtr
->fid
;
428 gcValues
.foreground
= msgPtr
->fgColorPtr
->pixel
;
429 newGC
= Tk_GetGC(msgPtr
->tkwin
, GCForeground
|GCFont
,
431 if (msgPtr
->textGC
!= None
) {
432 Tk_FreeGC(msgPtr
->textGC
);
434 msgPtr
->textGC
= newGC
;
436 if (msgPtr
->padX
== -1) {
437 msgPtr
->padX
= msgPtr
->fontPtr
->ascent
/2;
440 if (msgPtr
->padY
== -1) {
441 msgPtr
->padY
= msgPtr
->fontPtr
->ascent
/4;
444 if (msgPtr
->justify
== TK_JUSTIFY_FILL
) {
445 interp
->result
= "can't use \"fill\" justify style in messages";
450 * Recompute the desired geometry for the window, and arrange for
451 * the window to be redisplayed.
454 ComputeMessageGeometry(msgPtr
);
455 if ((msgPtr
->tkwin
!= NULL
) && Tk_IsMapped(msgPtr
->tkwin
)
456 && !(msgPtr
->flags
& REDRAW_PENDING
)) {
457 Tk_DoWhenIdle(DisplayMessage
, (ClientData
) msgPtr
);
458 msgPtr
->flags
|= REDRAW_PENDING
|CLEAR_NEEDED
;
465 *--------------------------------------------------------------
467 * ComputeMessageGeometry --
469 * Compute the desired geometry for a message window,
470 * taking into account the desired aspect ratio for the
477 * Tk_GeometryRequest is called to inform the geometry
478 * manager of the desired geometry for this window.
480 *--------------------------------------------------------------
484 ComputeMessageGeometry (
485 register Message
*msgPtr
/* Information about window. */
489 int width
, inc
, height
, numLines
;
490 int thisWidth
, maxWidth
;
491 int aspect
, lowerBound
, upperBound
;
494 * Compute acceptable bounds for the final aspect ratio.
496 aspect
= msgPtr
->aspect
/10;
500 lowerBound
= msgPtr
->aspect
- aspect
;
501 upperBound
= msgPtr
->aspect
+ aspect
;
504 * Do the computation in multiple passes: start off with
505 * a very wide window, and compute its height. Then change
506 * the width and try again. Reduce the size of the change
507 * and iterate until dimensions are found that approximate
508 * the desired aspect ratio. Or, if the user gave an explicit
509 * width then just use that.
512 if (msgPtr
->width
> 0) {
513 width
= msgPtr
->width
;
516 width
= WidthOfScreen(Tk_Screen(msgPtr
->tkwin
))/2;
519 for ( ; ; inc
/= 2) {
521 for (numLines
= 1, p
= msgPtr
->string
; ; numLines
++) {
526 p
+= TkMeasureChars(msgPtr
->fontPtr
, p
,
527 msgPtr
->numChars
- (p
- msgPtr
->string
), 0, width
,
528 TK_WHOLE_WORDS
|TK_AT_LEAST_ONE
, &thisWidth
);
529 if (thisWidth
> maxWidth
) {
530 maxWidth
= thisWidth
;
537 * Skip spaces and tabs at the beginning of a line, unless
538 * they follow a user-requested newline.
541 while (isspace(*p
)) {
550 height
= numLines
* (msgPtr
->fontPtr
->ascent
551 + msgPtr
->fontPtr
->descent
) + 2*msgPtr
->borderWidth
556 aspect
= (100*(maxWidth
+ 2*msgPtr
->borderWidth
557 + 2*msgPtr
->padX
))/height
;
558 if (aspect
< lowerBound
) {
560 } else if (aspect
> upperBound
) {
566 msgPtr
->lineLength
= maxWidth
;
567 msgPtr
->msgHeight
= numLines
* (msgPtr
->fontPtr
->ascent
568 + msgPtr
->fontPtr
->descent
);
569 Tk_GeometryRequest(msgPtr
->tkwin
,
570 maxWidth
+ 2*msgPtr
->borderWidth
+ 2*msgPtr
->padX
, height
);
571 Tk_SetInternalBorder(msgPtr
->tkwin
, msgPtr
->borderWidth
);
575 *--------------------------------------------------------------
579 * This procedure redraws the contents of a message window.
585 * Information appears on the screen.
587 *--------------------------------------------------------------
592 ClientData clientData
/* Information about window. */
595 register Message
*msgPtr
= (Message
*) clientData
;
596 register Tk_Window tkwin
= msgPtr
->tkwin
;
598 int x
, y
, lineLength
, numChars
, charsLeft
;
600 msgPtr
->flags
&= ~REDRAW_PENDING
;
601 if ((msgPtr
->tkwin
== NULL
) || !Tk_IsMapped(tkwin
)) {
604 if (msgPtr
->flags
& CLEAR_NEEDED
) {
605 XClearWindow(Tk_Display(tkwin
), Tk_WindowId(tkwin
));
606 msgPtr
->flags
&= ~CLEAR_NEEDED
;
610 * Compute starting y-location for message based on message size
614 switch (msgPtr
->anchor
) {
615 case TK_ANCHOR_NW
: case TK_ANCHOR_N
: case TK_ANCHOR_NE
:
616 y
= msgPtr
->borderWidth
+ msgPtr
->padY
;
618 case TK_ANCHOR_W
: case TK_ANCHOR_CENTER
: case TK_ANCHOR_E
:
619 y
= (Tk_Height(tkwin
) - msgPtr
->msgHeight
)/2;
622 y
= Tk_Height(tkwin
) - msgPtr
->borderWidth
- msgPtr
->padY
626 y
+= msgPtr
->fontPtr
->ascent
;
629 * Work through the string to display one line at a time.
630 * Display each line in three steps. First compute the
631 * line's width, then figure out where to display the
632 * line to justify it properly, then display the line.
635 for (p
= msgPtr
->string
, charsLeft
= msgPtr
->numChars
; *p
!= 0;
636 y
+= msgPtr
->fontPtr
->ascent
+ msgPtr
->fontPtr
->descent
) {
642 numChars
= TkMeasureChars(msgPtr
->fontPtr
, p
, charsLeft
, 0,
643 msgPtr
->lineLength
, TK_WHOLE_WORDS
|TK_AT_LEAST_ONE
,
645 switch (msgPtr
->anchor
) {
646 case TK_ANCHOR_NW
: case TK_ANCHOR_W
: case TK_ANCHOR_SW
:
647 x
= msgPtr
->borderWidth
+ msgPtr
->padX
;
649 case TK_ANCHOR_N
: case TK_ANCHOR_CENTER
: case TK_ANCHOR_S
:
650 x
= (Tk_Width(tkwin
) - msgPtr
->lineLength
)/2;
653 x
= Tk_Width(tkwin
) - msgPtr
->borderWidth
- msgPtr
->padX
654 - msgPtr
->lineLength
;
657 if (msgPtr
->justify
== TK_JUSTIFY_CENTER
) {
658 x
+= (msgPtr
->lineLength
- lineLength
)/2;
659 } else if (msgPtr
->justify
== TK_JUSTIFY_RIGHT
) {
660 x
+= msgPtr
->lineLength
- lineLength
;
662 TkDisplayChars(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
663 msgPtr
->textGC
, msgPtr
->fontPtr
, p
, numChars
, x
, y
, 0);
665 charsLeft
-= numChars
;
668 * Skip blanks at the beginning of a line, unless they follow
669 * a user-requested newline.
672 while (isspace(*p
)) {
682 if (msgPtr
->relief
!= TK_RELIEF_FLAT
) {
683 Tk_Draw3DRectangle(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
684 msgPtr
->border
, 0, 0, Tk_Width(tkwin
), Tk_Height(tkwin
),
685 msgPtr
->borderWidth
, msgPtr
->relief
);
690 *--------------------------------------------------------------
692 * MessageEventProc --
694 * This procedure is invoked by the Tk dispatcher for various
695 * events on messages.
701 * When the window gets deleted, internal structures get
702 * cleaned up. When it gets exposed, it is redisplayed.
704 *--------------------------------------------------------------
709 ClientData clientData
, /* Information about window. */
710 XEvent
*eventPtr
/* Information about event. */
713 Message
*msgPtr
= (Message
*) clientData
;
715 if ((eventPtr
->type
== Expose
) && (eventPtr
->xexpose
.count
== 0)) {
716 if ((msgPtr
->tkwin
!= NULL
) && !(msgPtr
->flags
& REDRAW_PENDING
)) {
717 Tk_DoWhenIdle(DisplayMessage
, (ClientData
) msgPtr
);
718 msgPtr
->flags
|= REDRAW_PENDING
;
720 } else if (eventPtr
->type
== DestroyNotify
) {
721 Tcl_DeleteCommand(msgPtr
->interp
, Tk_PathName(msgPtr
->tkwin
));
722 msgPtr
->tkwin
= NULL
;
723 if (msgPtr
->flags
& REDRAW_PENDING
) {
724 Tk_CancelIdleCall(DisplayMessage
, (ClientData
) msgPtr
);
726 Tk_EventuallyFree((ClientData
) msgPtr
, DestroyMessage
);
731 *--------------------------------------------------------------
733 * MessageTextVarProc --
735 * This procedure is invoked when someone changes the variable
736 * whose contents are to be displayed in a message.
739 * NULL is always returned.
742 * The text displayed in the message will change to match the
745 *--------------------------------------------------------------
751 ClientData clientData
, /* Information about message. */
752 Tcl_Interp
*interp
, /* Interpreter containing variable. */
753 char *name1
, /* Name of variable. */
754 char *name2
, /* Second part of variable name. */
755 int flags
/* Information about what happened. */
758 register Message
*msgPtr
= (Message
*) clientData
;
762 * If the variable is unset, then immediately recreate it unless
763 * the whole interpreter is going away.
766 if (flags
& TCL_TRACE_UNSETS
) {
767 if ((flags
& TCL_TRACE_DESTROYED
) && !(flags
& TCL_INTERP_DESTROYED
)) {
768 Tcl_SetVar2(interp
, name1
, name2
, msgPtr
->string
,
769 flags
& TCL_GLOBAL_ONLY
);
770 Tcl_TraceVar2(interp
, name1
, name2
,
771 TCL_GLOBAL_ONLY
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
,
772 MessageTextVarProc
, clientData
);
774 return (char *) NULL
;
777 value
= Tcl_GetVar2(interp
, name1
, name2
, flags
& TCL_GLOBAL_ONLY
);
781 if (msgPtr
->string
!= NULL
) {
782 ckfree(msgPtr
->string
);
784 msgPtr
->numChars
= strlen(value
);
785 msgPtr
->string
= ckalloc((unsigned) (msgPtr
->numChars
+ 1));
786 strcpy(msgPtr
->string
, value
);
787 ComputeMessageGeometry(msgPtr
);
789 msgPtr
->flags
|= CLEAR_NEEDED
;
790 if ((msgPtr
->tkwin
!= NULL
) && Tk_IsMapped(msgPtr
->tkwin
)
791 && !(msgPtr
->flags
& REDRAW_PENDING
)) {
792 Tk_DoWhenIdle(DisplayMessage
, (ClientData
) msgPtr
);
793 msgPtr
->flags
|= REDRAW_PENDING
;
795 return (char *) NULL
;