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 *--------------------------------------------------------------
177 Tk_MessageCmd(clientData
, interp
, argc
, argv
)
178 ClientData clientData
; /* Main window associated with
180 Tcl_Interp
*interp
; /* Current interpreter. */
181 int argc
; /* Number of arguments. */
182 char **argv
; /* Argument strings. */
184 register Message
*msgPtr
;
186 Tk_Window tkwin
= (Tk_Window
) clientData
;
189 Tcl_AppendResult(interp
, "wrong # args: should be \"",
190 argv
[0], " pathName ?options?\"", (char *) NULL
);
194 new = Tk_CreateWindowFromPath(interp
, tkwin
, argv
[1], (char *) NULL
);
199 msgPtr
= (Message
*) ckalloc(sizeof(Message
));
201 msgPtr
->interp
= interp
;
202 msgPtr
->string
= NULL
;
203 msgPtr
->textVarName
= NULL
;
204 msgPtr
->border
= NULL
;
205 msgPtr
->borderWidth
= 0;
206 msgPtr
->relief
= TK_RELIEF_FLAT
;
207 msgPtr
->fontPtr
= NULL
;
208 msgPtr
->fgColorPtr
= NULL
;
209 msgPtr
->textGC
= NULL
;
213 msgPtr
->aspect
= 150;
214 msgPtr
->justify
= TK_JUSTIFY_LEFT
;
215 msgPtr
->cursor
= None
;
218 Tk_SetClass(msgPtr
->tkwin
, "Message");
219 Tk_CreateEventHandler(msgPtr
->tkwin
, ExposureMask
|StructureNotifyMask
,
220 MessageEventProc
, (ClientData
) msgPtr
);
221 Tcl_CreateCommand(interp
, Tk_PathName(msgPtr
->tkwin
), MessageWidgetCmd
,
222 (ClientData
) msgPtr
, (void (*)()) NULL
);
223 if (ConfigureMessage(interp
, msgPtr
, argc
-2, argv
+2, 0) != TCL_OK
) {
227 interp
->result
= Tk_PathName(msgPtr
->tkwin
);
231 Tk_DestroyWindow(msgPtr
->tkwin
);
236 *--------------------------------------------------------------
238 * MessageWidgetCmd --
240 * This procedure is invoked to process the Tcl command
241 * that corresponds to a widget managed by this module.
242 * See the user documentation for details on what it does.
245 * A standard Tcl result.
248 * See the user documentation.
250 *--------------------------------------------------------------
254 MessageWidgetCmd(clientData
, interp
, argc
, argv
)
255 ClientData clientData
; /* Information about message widget. */
256 Tcl_Interp
*interp
; /* Current interpreter. */
257 int argc
; /* Number of arguments. */
258 char **argv
; /* Argument strings. */
260 register Message
*msgPtr
= (Message
*) clientData
;
265 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
266 " option ?arg arg ...?\"", (char *) NULL
);
270 length
= strlen(argv
[1]);
271 if ((c
== 'c') && (strncmp(argv
[1], "configure", length
) == 0)) {
273 return Tk_ConfigureInfo(interp
, msgPtr
->tkwin
, configSpecs
,
274 (char *) msgPtr
, (char *) NULL
, 0);
275 } else if (argc
== 3) {
276 return Tk_ConfigureInfo(interp
, msgPtr
->tkwin
, configSpecs
,
277 (char *) msgPtr
, argv
[2], 0);
279 return ConfigureMessage(interp
, msgPtr
, argc
-2, argv
+2,
280 TK_CONFIG_ARGV_ONLY
);
283 Tcl_AppendResult(interp
, "bad option \"", argv
[1],
284 "\": must be configure", (char *) NULL
);
290 *----------------------------------------------------------------------
294 * This procedure is invoked by Tk_EventuallyFree or Tk_Release
295 * to clean up the internal structure of a message at a safe time
296 * (when no-one is using it anymore).
302 * Everything associated with the message is freed up.
304 *----------------------------------------------------------------------
308 DestroyMessage(clientData
)
309 ClientData clientData
; /* Info about message widget. */
311 register Message
*msgPtr
= (Message
*) clientData
;
313 if (msgPtr
->string
!= NULL
) {
314 ckfree(msgPtr
->string
);
316 if (msgPtr
->textVarName
!= NULL
) {
317 Tcl_UntraceVar(msgPtr
->interp
, msgPtr
->textVarName
,
318 TCL_GLOBAL_ONLY
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
,
319 MessageTextVarProc
, (ClientData
) msgPtr
);
320 ckfree(msgPtr
->textVarName
);
322 if (msgPtr
->border
!= NULL
) {
323 Tk_Free3DBorder(msgPtr
->border
);
325 if (msgPtr
->fontPtr
!= NULL
) {
326 Tk_FreeFontStruct(msgPtr
->fontPtr
);
328 if (msgPtr
->fgColorPtr
!= NULL
) {
329 Tk_FreeColor(msgPtr
->fgColorPtr
);
331 if (msgPtr
->textGC
!= None
) {
332 Tk_FreeGC(msgPtr
->textGC
);
334 if (msgPtr
->cursor
!= None
) {
335 Tk_FreeCursor(msgPtr
->cursor
);
337 ckfree((char *) msgPtr
);
341 *----------------------------------------------------------------------
343 * ConfigureMessage --
345 * This procedure is called to process an argv/argc list, plus
346 * the Tk option database, in order to configure (or
347 * reconfigure) a message widget.
350 * The return value is a standard Tcl result. If TCL_ERROR is
351 * returned, then interp->result contains an error message.
354 * Configuration information, such as text string, colors, font,
355 * etc. get set for msgPtr; old resources get freed, if there
358 *----------------------------------------------------------------------
362 ConfigureMessage(interp
, msgPtr
, argc
, argv
, flags
)
363 Tcl_Interp
*interp
; /* Used for error reporting. */
364 register Message
*msgPtr
; /* Information about widget; may or may
365 * not already have values for some fields. */
366 int argc
; /* Number of valid entries in argv. */
367 char **argv
; /* Arguments. */
368 int flags
; /* Flags to pass to Tk_ConfigureWidget. */
374 * Eliminate any existing trace on a variable monitored by the message.
377 if (msgPtr
->textVarName
!= NULL
) {
378 Tcl_UntraceVar(interp
, msgPtr
->textVarName
,
379 TCL_GLOBAL_ONLY
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
,
380 MessageTextVarProc
, (ClientData
) msgPtr
);
383 if (Tk_ConfigureWidget(interp
, msgPtr
->tkwin
, configSpecs
,
384 argc
, argv
, (char *) msgPtr
, flags
) != TCL_OK
) {
389 * If the message is to display the value of a variable, then set up
390 * a trace on the variable's value, create the variable if it doesn't
391 * exist, and fetch its current value.
394 if (msgPtr
->textVarName
!= NULL
) {
397 value
= Tcl_GetVar(interp
, msgPtr
->textVarName
, TCL_GLOBAL_ONLY
);
399 Tcl_SetVar(interp
, msgPtr
->textVarName
, msgPtr
->string
,
402 if (msgPtr
->string
!= NULL
) {
403 ckfree(msgPtr
->string
);
405 msgPtr
->string
= ckalloc((unsigned) (strlen(value
) + 1));
406 strcpy(msgPtr
->string
, value
);
408 Tcl_TraceVar(interp
, msgPtr
->textVarName
,
409 TCL_GLOBAL_ONLY
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
,
410 MessageTextVarProc
, (ClientData
) msgPtr
);
414 * A few other options need special processing, such as setting
415 * the background from a 3-D border or handling special defaults
416 * that couldn't be specified to Tk_ConfigureWidget.
419 msgPtr
->numChars
= strlen(msgPtr
->string
);
421 Tk_SetBackgroundFromBorder(msgPtr
->tkwin
, msgPtr
->border
);
423 gcValues
.font
= msgPtr
->fontPtr
->fid
;
424 gcValues
.foreground
= msgPtr
->fgColorPtr
->pixel
;
425 newGC
= Tk_GetGC(msgPtr
->tkwin
, GCForeground
|GCFont
,
427 if (msgPtr
->textGC
!= None
) {
428 Tk_FreeGC(msgPtr
->textGC
);
430 msgPtr
->textGC
= newGC
;
432 if (msgPtr
->padX
== -1) {
433 msgPtr
->padX
= msgPtr
->fontPtr
->ascent
/2;
436 if (msgPtr
->padY
== -1) {
437 msgPtr
->padY
= msgPtr
->fontPtr
->ascent
/4;
440 if (msgPtr
->justify
== TK_JUSTIFY_FILL
) {
441 interp
->result
= "can't use \"fill\" justify style in messages";
446 * Recompute the desired geometry for the window, and arrange for
447 * the window to be redisplayed.
450 ComputeMessageGeometry(msgPtr
);
451 if ((msgPtr
->tkwin
!= NULL
) && Tk_IsMapped(msgPtr
->tkwin
)
452 && !(msgPtr
->flags
& REDRAW_PENDING
)) {
453 Tk_DoWhenIdle(DisplayMessage
, (ClientData
) msgPtr
);
454 msgPtr
->flags
|= REDRAW_PENDING
|CLEAR_NEEDED
;
461 *--------------------------------------------------------------
463 * ComputeMessageGeometry --
465 * Compute the desired geometry for a message window,
466 * taking into account the desired aspect ratio for the
473 * Tk_GeometryRequest is called to inform the geometry
474 * manager of the desired geometry for this window.
476 *--------------------------------------------------------------
480 ComputeMessageGeometry(msgPtr
)
481 register Message
*msgPtr
; /* Information about window. */
484 int width
, inc
, height
, numLines
;
485 int thisWidth
, maxWidth
;
486 int aspect
, lowerBound
, upperBound
;
489 * Compute acceptable bounds for the final aspect ratio.
491 aspect
= msgPtr
->aspect
/10;
495 lowerBound
= msgPtr
->aspect
- aspect
;
496 upperBound
= msgPtr
->aspect
+ aspect
;
499 * Do the computation in multiple passes: start off with
500 * a very wide window, and compute its height. Then change
501 * the width and try again. Reduce the size of the change
502 * and iterate until dimensions are found that approximate
503 * the desired aspect ratio. Or, if the user gave an explicit
504 * width then just use that.
507 if (msgPtr
->width
> 0) {
508 width
= msgPtr
->width
;
511 width
= WidthOfScreen(Tk_Screen(msgPtr
->tkwin
))/2;
514 for ( ; ; inc
/= 2) {
516 for (numLines
= 1, p
= msgPtr
->string
; ; numLines
++) {
521 p
+= TkMeasureChars(msgPtr
->fontPtr
, p
,
522 msgPtr
->numChars
- (p
- msgPtr
->string
), 0, width
,
523 TK_WHOLE_WORDS
|TK_AT_LEAST_ONE
, &thisWidth
);
524 if (thisWidth
> maxWidth
) {
525 maxWidth
= thisWidth
;
532 * Skip spaces and tabs at the beginning of a line, unless
533 * they follow a user-requested newline.
536 while (isspace(*p
)) {
545 height
= numLines
* (msgPtr
->fontPtr
->ascent
546 + msgPtr
->fontPtr
->descent
) + 2*msgPtr
->borderWidth
551 aspect
= (100*(maxWidth
+ 2*msgPtr
->borderWidth
552 + 2*msgPtr
->padX
))/height
;
553 if (aspect
< lowerBound
) {
555 } else if (aspect
> upperBound
) {
561 msgPtr
->lineLength
= maxWidth
;
562 msgPtr
->msgHeight
= numLines
* (msgPtr
->fontPtr
->ascent
563 + msgPtr
->fontPtr
->descent
);
564 Tk_GeometryRequest(msgPtr
->tkwin
,
565 maxWidth
+ 2*msgPtr
->borderWidth
+ 2*msgPtr
->padX
, height
);
566 Tk_SetInternalBorder(msgPtr
->tkwin
, msgPtr
->borderWidth
);
570 *--------------------------------------------------------------
574 * This procedure redraws the contents of a message window.
580 * Information appears on the screen.
582 *--------------------------------------------------------------
586 DisplayMessage(clientData
)
587 ClientData clientData
; /* Information about window. */
589 register Message
*msgPtr
= (Message
*) clientData
;
590 register Tk_Window tkwin
= msgPtr
->tkwin
;
592 int x
, y
, lineLength
, numChars
, charsLeft
;
594 msgPtr
->flags
&= ~REDRAW_PENDING
;
595 if ((msgPtr
->tkwin
== NULL
) || !Tk_IsMapped(tkwin
)) {
598 if (msgPtr
->flags
& CLEAR_NEEDED
) {
599 XClearWindow(Tk_Display(tkwin
), Tk_WindowId(tkwin
));
600 msgPtr
->flags
&= ~CLEAR_NEEDED
;
604 * Compute starting y-location for message based on message size
608 switch (msgPtr
->anchor
) {
609 case TK_ANCHOR_NW
: case TK_ANCHOR_N
: case TK_ANCHOR_NE
:
610 y
= msgPtr
->borderWidth
+ msgPtr
->padY
;
612 case TK_ANCHOR_W
: case TK_ANCHOR_CENTER
: case TK_ANCHOR_E
:
613 y
= (Tk_Height(tkwin
) - msgPtr
->msgHeight
)/2;
616 y
= Tk_Height(tkwin
) - msgPtr
->borderWidth
- msgPtr
->padY
620 y
+= msgPtr
->fontPtr
->ascent
;
623 * Work through the string to display one line at a time.
624 * Display each line in three steps. First compute the
625 * line's width, then figure out where to display the
626 * line to justify it properly, then display the line.
629 for (p
= msgPtr
->string
, charsLeft
= msgPtr
->numChars
; *p
!= 0;
630 y
+= msgPtr
->fontPtr
->ascent
+ msgPtr
->fontPtr
->descent
) {
636 numChars
= TkMeasureChars(msgPtr
->fontPtr
, p
, charsLeft
, 0,
637 msgPtr
->lineLength
, TK_WHOLE_WORDS
|TK_AT_LEAST_ONE
,
639 switch (msgPtr
->anchor
) {
640 case TK_ANCHOR_NW
: case TK_ANCHOR_W
: case TK_ANCHOR_SW
:
641 x
= msgPtr
->borderWidth
+ msgPtr
->padX
;
643 case TK_ANCHOR_N
: case TK_ANCHOR_CENTER
: case TK_ANCHOR_S
:
644 x
= (Tk_Width(tkwin
) - msgPtr
->lineLength
)/2;
647 x
= Tk_Width(tkwin
) - msgPtr
->borderWidth
- msgPtr
->padX
648 - msgPtr
->lineLength
;
651 if (msgPtr
->justify
== TK_JUSTIFY_CENTER
) {
652 x
+= (msgPtr
->lineLength
- lineLength
)/2;
653 } else if (msgPtr
->justify
== TK_JUSTIFY_RIGHT
) {
654 x
+= msgPtr
->lineLength
- lineLength
;
656 TkDisplayChars(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
657 msgPtr
->textGC
, msgPtr
->fontPtr
, p
, numChars
, x
, y
, 0);
659 charsLeft
-= numChars
;
662 * Skip blanks at the beginning of a line, unless they follow
663 * a user-requested newline.
666 while (isspace(*p
)) {
676 if (msgPtr
->relief
!= TK_RELIEF_FLAT
) {
677 Tk_Draw3DRectangle(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
678 msgPtr
->border
, 0, 0, Tk_Width(tkwin
), Tk_Height(tkwin
),
679 msgPtr
->borderWidth
, msgPtr
->relief
);
684 *--------------------------------------------------------------
686 * MessageEventProc --
688 * This procedure is invoked by the Tk dispatcher for various
689 * events on messages.
695 * When the window gets deleted, internal structures get
696 * cleaned up. When it gets exposed, it is redisplayed.
698 *--------------------------------------------------------------
702 MessageEventProc(clientData
, eventPtr
)
703 ClientData clientData
; /* Information about window. */
704 XEvent
*eventPtr
; /* Information about event. */
706 Message
*msgPtr
= (Message
*) clientData
;
708 if ((eventPtr
->type
== Expose
) && (eventPtr
->xexpose
.count
== 0)) {
709 if ((msgPtr
->tkwin
!= NULL
) && !(msgPtr
->flags
& REDRAW_PENDING
)) {
710 Tk_DoWhenIdle(DisplayMessage
, (ClientData
) msgPtr
);
711 msgPtr
->flags
|= REDRAW_PENDING
;
713 } else if (eventPtr
->type
== DestroyNotify
) {
714 Tcl_DeleteCommand(msgPtr
->interp
, Tk_PathName(msgPtr
->tkwin
));
715 msgPtr
->tkwin
= NULL
;
716 if (msgPtr
->flags
& REDRAW_PENDING
) {
717 Tk_CancelIdleCall(DisplayMessage
, (ClientData
) msgPtr
);
719 Tk_EventuallyFree((ClientData
) msgPtr
, DestroyMessage
);
724 *--------------------------------------------------------------
726 * MessageTextVarProc --
728 * This procedure is invoked when someone changes the variable
729 * whose contents are to be displayed in a message.
732 * NULL is always returned.
735 * The text displayed in the message will change to match the
738 *--------------------------------------------------------------
743 MessageTextVarProc(clientData
, interp
, name1
, name2
, flags
)
744 ClientData clientData
; /* Information about message. */
745 Tcl_Interp
*interp
; /* Interpreter containing variable. */
746 char *name1
; /* Name of variable. */
747 char *name2
; /* Second part of variable name. */
748 int flags
; /* Information about what happened. */
750 register Message
*msgPtr
= (Message
*) clientData
;
754 * If the variable is unset, then immediately recreate it unless
755 * the whole interpreter is going away.
758 if (flags
& TCL_TRACE_UNSETS
) {
759 if ((flags
& TCL_TRACE_DESTROYED
) && !(flags
& TCL_INTERP_DESTROYED
)) {
760 Tcl_SetVar2(interp
, name1
, name2
, msgPtr
->string
,
761 flags
& TCL_GLOBAL_ONLY
);
762 Tcl_TraceVar2(interp
, name1
, name2
,
763 TCL_GLOBAL_ONLY
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
,
764 MessageTextVarProc
, clientData
);
766 return (char *) NULL
;
769 value
= Tcl_GetVar2(interp
, name1
, name2
, flags
& TCL_GLOBAL_ONLY
);
773 if (msgPtr
->string
!= NULL
) {
774 ckfree(msgPtr
->string
);
776 msgPtr
->numChars
= strlen(value
);
777 msgPtr
->string
= ckalloc((unsigned) (msgPtr
->numChars
+ 1));
778 strcpy(msgPtr
->string
, value
);
779 ComputeMessageGeometry(msgPtr
);
781 msgPtr
->flags
|= CLEAR_NEEDED
;
782 if ((msgPtr
->tkwin
!= NULL
) && Tk_IsMapped(msgPtr
->tkwin
)
783 && !(msgPtr
->flags
& REDRAW_PENDING
)) {
784 Tk_DoWhenIdle(DisplayMessage
, (ClientData
) msgPtr
);
785 msgPtr
->flags
|= REDRAW_PENDING
;
787 return (char *) NULL
;