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 (c) 1990-1994 The Regents of the University of California.
9 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
22 * A data structure of the following type is kept for each message
23 * widget managed by this file:
27 Tk_Window tkwin; /* Window that embodies the message. NULL
28 * means that the window has been destroyed
29 * but the data structures haven't yet been
31 Display *display; /* Display containing widget. Used, among
32 * other things, so that resources can be
33 * freed even after tkwin has gone away. */
34 Tcl_Interp *interp; /* Interpreter associated with message. */
35 Tcl_Command widgetCmd; /* Token for message's widget command. */
38 * Information used when displaying widget:
41 char *string; /* String displayed in message. */
42 int numChars; /* Number of characters in string, not
43 * including terminating NULL. */
44 char *textVarName; /* Name of variable (malloc'ed) or NULL.
45 * If non-NULL, message displays the contents
46 * of this variable. */
47 Tk_3DBorder border; /* Structure used to draw 3-D border and
48 * background. NULL means a border hasn't
49 * been created yet. */
50 int borderWidth; /* Width of border. */
51 int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
52 int highlightWidth; /* Width in pixels of highlight to draw
53 * around widget when it has the focus.
54 * <= 0 means don't draw a highlight. */
55 XColor *highlightBgColorPtr;
56 /* Color for drawing traversal highlight
57 * area when highlight is off. */
58 XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
59 Tk_Font tkfont; /* Information about text font, or NULL. */
60 XColor *fgColorPtr; /* Foreground color in normal mode. */
61 int padX, padY; /* User-requested extra space around text. */
62 int width; /* User-requested width, in pixels. 0 means
63 * compute width using aspect ratio below. */
64 int aspect; /* Desired aspect ratio for window
65 * (100*width/height). */
66 int msgWidth; /* Width in pixels needed to display
68 int msgHeight; /* Height in pixels needed to display
70 Tk_Anchor anchor; /* Where to position text within window region
71 * if window is larger or smaller than
73 Tk_Justify justify; /* Justification for text. */
75 GC textGC; /* GC for drawing text in normal mode. */
76 Tk_TextLayout textLayout; /* Saved layout information. */
79 * Miscellaneous information:
82 Tk_Cursor cursor; /* Current cursor for window, or None. */
83 char *takeFocus; /* Value of -takefocus option; not used in
84 * the C code, but used by keyboard traversal
85 * scripts. Malloc'ed, but may be NULL. */
86 int flags; /* Various flags; see below for
91 * Flag bits for messages:
93 * REDRAW_PENDING: Non-zero means a DoWhenIdle handler
94 * has already been queued to redraw
96 * GOT_FOCUS: Non-zero means this button currently
97 * has the input focus.
100 #define REDRAW_PENDING 1
104 * Information used for argv parsing.
107 static Tk_ConfigSpec configSpecs[] = {
108 {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor",
109 DEF_MESSAGE_ANCHOR, Tk_Offset(Message, anchor), 0},
110 {TK_CONFIG_INT, "-aspect", "aspect", "Aspect",
111 DEF_MESSAGE_ASPECT, Tk_Offset(Message, aspect), 0},
112 {TK_CONFIG_BORDER, "-background", "background", "Background",
113 DEF_MESSAGE_BG_COLOR, Tk_Offset(Message, border),
114 TK_CONFIG_COLOR_ONLY},
115 {TK_CONFIG_BORDER, "-background", "background", "Background",
116 DEF_MESSAGE_BG_MONO, Tk_Offset(Message, border),
117 TK_CONFIG_MONO_ONLY},
118 {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
119 (char *) NULL, 0, 0},
120 {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
121 (char *) NULL, 0, 0},
122 {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
123 DEF_MESSAGE_BORDER_WIDTH, Tk_Offset(Message, borderWidth), 0},
124 {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
125 DEF_MESSAGE_CURSOR, Tk_Offset(Message, cursor), TK_CONFIG_NULL_OK},
126 {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
127 (char *) NULL, 0, 0},
128 {TK_CONFIG_FONT, "-font", "font", "Font",
129 DEF_MESSAGE_FONT, Tk_Offset(Message, tkfont), 0},
130 {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
131 DEF_MESSAGE_FG, Tk_Offset(Message, fgColorPtr), 0},
132 {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
133 "HighlightBackground", DEF_MESSAGE_HIGHLIGHT_BG,
134 Tk_Offset(Message, highlightBgColorPtr), 0},
135 {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
136 DEF_MESSAGE_HIGHLIGHT, Tk_Offset(Message, highlightColorPtr), 0},
137 {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
138 "HighlightThickness",
139 DEF_MESSAGE_HIGHLIGHT_WIDTH, Tk_Offset(Message, highlightWidth), 0},
140 {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
141 DEF_MESSAGE_JUSTIFY, Tk_Offset(Message, justify), 0},
142 {TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
143 DEF_MESSAGE_PADX, Tk_Offset(Message, padX), 0},
144 {TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
145 DEF_MESSAGE_PADY, Tk_Offset(Message, padY), 0},
146 {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
147 DEF_MESSAGE_RELIEF, Tk_Offset(Message, relief), 0},
148 {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
149 DEF_MESSAGE_TAKE_FOCUS, Tk_Offset(Message, takeFocus),
151 {TK_CONFIG_STRING, "-text", "text", "Text",
152 DEF_MESSAGE_TEXT, Tk_Offset(Message, string), 0},
153 {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable",
154 DEF_MESSAGE_TEXT_VARIABLE, Tk_Offset(Message, textVarName),
156 {TK_CONFIG_PIXELS, "-width", "width", "Width",
157 DEF_MESSAGE_WIDTH, Tk_Offset(Message, width), 0},
158 {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
163 * Forward declarations for procedures defined later in this file:
166 static void MessageCmdDeletedProc _ANSI_ARGS_((
167 ClientData clientData));
168 static void MessageEventProc _ANSI_ARGS_((ClientData clientData,
170 static char * MessageTextVarProc _ANSI_ARGS_((ClientData clientData,
171 Tcl_Interp *interp, char *name1, char *name2,
173 static int MessageWidgetCmd _ANSI_ARGS_((ClientData clientData,
174 Tcl_Interp *interp, int argc, char **argv));
175 static void MessageWorldChanged _ANSI_ARGS_((
176 ClientData instanceData));
177 static void ComputeMessageGeometry _ANSI_ARGS_((Message *msgPtr));
178 static int ConfigureMessage _ANSI_ARGS_((Tcl_Interp *interp,
179 Message *msgPtr, int argc, char **argv,
181 static void DestroyMessage _ANSI_ARGS_((char *memPtr));
182 static void DisplayMessage _ANSI_ARGS_((ClientData clientData));
185 * The structure below defines message class behavior by means of procedures
186 * that can be invoked from generic window code.
189 static TkClassProcs messageClass = {
190 NULL, /* createProc. */
191 MessageWorldChanged, /* geometryProc. */
192 NULL /* modalProc. */
197 *--------------------------------------------------------------
201 * This procedure is invoked to process the "message" Tcl
202 * command. See the user documentation for details on what
206 * A standard Tcl result.
209 * See the user documentation.
211 *--------------------------------------------------------------
215 Tk_MessageCmd(clientData, interp, argc, argv)
216 ClientData clientData; /* Main window associated with
218 Tcl_Interp *interp; /* Current interpreter. */
219 int argc; /* Number of arguments. */
220 char **argv; /* Argument strings. */
222 register Message *msgPtr;
224 Tk_Window tkwin = (Tk_Window) clientData;
227 Tcl_AppendResult(interp, "wrong # args: should be \"",
228 argv[0], " pathName ?options?\"", (char *) NULL);
232 new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
237 msgPtr = (Message *) ckalloc(sizeof(Message));
239 msgPtr->display = Tk_Display(new);
240 msgPtr->interp = interp;
241 msgPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(msgPtr->tkwin),
242 MessageWidgetCmd, (ClientData) msgPtr, MessageCmdDeletedProc);
243 msgPtr->textLayout = NULL;
244 msgPtr->string = NULL;
245 msgPtr->numChars = 0;
246 msgPtr->textVarName = NULL;
247 msgPtr->border = NULL;
248 msgPtr->borderWidth = 0;
249 msgPtr->relief = TK_RELIEF_FLAT;
250 msgPtr->highlightWidth = 0;
251 msgPtr->highlightBgColorPtr = NULL;
252 msgPtr->highlightColorPtr = NULL;
253 msgPtr->tkfont = NULL;
254 msgPtr->fgColorPtr = NULL;
255 msgPtr->textGC = None;
258 msgPtr->anchor = TK_ANCHOR_CENTER;
260 msgPtr->aspect = 150;
261 msgPtr->msgWidth = 0;
262 msgPtr->msgHeight = 0;
263 msgPtr->justify = TK_JUSTIFY_LEFT;
264 msgPtr->cursor = None;
265 msgPtr->takeFocus = NULL;
268 Tk_SetClass(msgPtr->tkwin, "Message");
269 TkSetClassProcs(msgPtr->tkwin, &messageClass, (ClientData) msgPtr);
270 Tk_CreateEventHandler(msgPtr->tkwin,
271 ExposureMask|StructureNotifyMask|FocusChangeMask,
272 MessageEventProc, (ClientData) msgPtr);
273 if (ConfigureMessage(interp, msgPtr, argc-2, argv+2, 0) != TCL_OK) {
277 Tcl_SetResult(interp, Tk_PathName(msgPtr->tkwin), TCL_STATIC);
281 Tk_DestroyWindow(msgPtr->tkwin);
286 *--------------------------------------------------------------
288 * MessageWidgetCmd --
290 * This procedure is invoked to process the Tcl command
291 * that corresponds to a widget managed by this module.
292 * See the user documentation for details on what it does.
295 * A standard Tcl result.
298 * See the user documentation.
300 *--------------------------------------------------------------
304 MessageWidgetCmd(clientData, interp, argc, argv)
305 ClientData clientData; /* Information about message widget. */
306 Tcl_Interp *interp; /* Current interpreter. */
307 int argc; /* Number of arguments. */
308 char **argv; /* Argument strings. */
310 register Message *msgPtr = (Message *) clientData;
315 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
316 " option ?arg arg ...?\"", (char *) NULL);
320 length = strlen(argv[1]);
321 if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
324 Tcl_AppendResult(interp, "wrong # args: should be \"",
325 argv[0], " cget option\"",
329 return Tk_ConfigureValue(interp, msgPtr->tkwin, configSpecs,
330 (char *) msgPtr, argv[2], 0);
331 } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
334 return Tk_ConfigureInfo(interp, msgPtr->tkwin, configSpecs,
335 (char *) msgPtr, (char *) NULL, 0);
336 } else if (argc == 3) {
337 return Tk_ConfigureInfo(interp, msgPtr->tkwin, configSpecs,
338 (char *) msgPtr, argv[2], 0);
340 return ConfigureMessage(interp, msgPtr, argc-2, argv+2,
341 TK_CONFIG_ARGV_ONLY);
344 Tcl_AppendResult(interp, "bad option \"", argv[1],
345 "\": must be cget or configure", (char *) NULL);
351 *----------------------------------------------------------------------
355 * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
356 * to clean up the internal structure of a message at a safe time
357 * (when no-one is using it anymore).
363 * Everything associated with the message is freed up.
365 *----------------------------------------------------------------------
369 DestroyMessage(memPtr)
370 char *memPtr; /* Info about message widget. */
372 register Message *msgPtr = (Message *) memPtr;
375 * Free up all the stuff that requires special handling, then
376 * let Tk_FreeOptions handle all the standard option-related
380 Tk_FreeTextLayout(msgPtr->textLayout);
381 if (msgPtr->textVarName != NULL) {
382 Tcl_UntraceVar(msgPtr->interp, msgPtr->textVarName,
383 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
384 MessageTextVarProc, (ClientData) msgPtr);
386 if (msgPtr->textGC != None) {
387 Tk_FreeGC(msgPtr->display, msgPtr->textGC);
389 Tk_FreeOptions(configSpecs, (char *) msgPtr, msgPtr->display, 0);
390 ckfree((char *) msgPtr);
394 *----------------------------------------------------------------------
396 * ConfigureMessage --
398 * This procedure is called to process an argv/argc list, plus
399 * the Tk option database, in order to configure (or
400 * reconfigure) a message widget.
403 * The return value is a standard Tcl result. If TCL_ERROR is
404 * returned, then the interp's result contains an error message.
407 * Configuration information, such as text string, colors, font,
408 * etc. get set for msgPtr; old resources get freed, if there
411 *----------------------------------------------------------------------
415 ConfigureMessage(interp, msgPtr, argc, argv, flags)
416 Tcl_Interp *interp; /* Used for error reporting. */
417 register Message *msgPtr; /* Information about widget; may or may
418 * not already have values for some fields. */
419 int argc; /* Number of valid entries in argv. */
420 char **argv; /* Arguments. */
421 int flags; /* Flags to pass to Tk_ConfigureWidget. */
424 * Eliminate any existing trace on a variable monitored by the message.
427 if (msgPtr->textVarName != NULL) {
428 Tcl_UntraceVar(interp, msgPtr->textVarName,
429 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
430 MessageTextVarProc, (ClientData) msgPtr);
433 if (Tk_ConfigureWidget(interp, msgPtr->tkwin, configSpecs,
434 argc, argv, (char *) msgPtr, flags) != TCL_OK) {
439 * If the message is to display the value of a variable, then set up
440 * a trace on the variable's value, create the variable if it doesn't
441 * exist, and fetch its current value.
444 if (msgPtr->textVarName != NULL) {
447 value = Tcl_GetVar(interp, msgPtr->textVarName, TCL_GLOBAL_ONLY);
449 Tcl_SetVar(interp, msgPtr->textVarName, msgPtr->string,
452 if (msgPtr->string != NULL) {
453 ckfree(msgPtr->string);
455 msgPtr->string = strcpy(ckalloc(strlen(value) + 1), value);
457 Tcl_TraceVar(interp, msgPtr->textVarName,
458 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
459 MessageTextVarProc, (ClientData) msgPtr);
463 * A few other options need special processing, such as setting
464 * the background from a 3-D border or handling special defaults
465 * that couldn't be specified to Tk_ConfigureWidget.
468 msgPtr->numChars = Tcl_NumUtfChars(msgPtr->string, -1);
470 if (msgPtr->highlightWidth < 0) {
471 msgPtr->highlightWidth = 0;
474 MessageWorldChanged((ClientData) msgPtr);
479 *---------------------------------------------------------------------------
481 * MessageWorldChanged --
483 * This procedure is called when the world has changed in some
484 * way and the widget needs to recompute all its graphics contexts
485 * and determine its new geometry.
491 * Message will be relayed out and redisplayed.
493 *---------------------------------------------------------------------------
497 MessageWorldChanged(instanceData)
498 ClientData instanceData; /* Information about widget. */
505 msgPtr = (Message *) instanceData;
507 if (msgPtr->border != NULL) {
508 Tk_SetBackgroundFromBorder(msgPtr->tkwin, msgPtr->border);
511 gcValues.font = Tk_FontId(msgPtr->tkfont);
512 gcValues.foreground = msgPtr->fgColorPtr->pixel;
513 gc = Tk_GetGC(msgPtr->tkwin, GCForeground | GCFont, &gcValues);
514 if (msgPtr->textGC != None) {
515 Tk_FreeGC(msgPtr->display, msgPtr->textGC);
519 Tk_GetFontMetrics(msgPtr->tkfont, &fm);
520 if (msgPtr->padX < 0) {
521 msgPtr->padX = fm.ascent / 2;
523 if (msgPtr->padY == -1) {
524 msgPtr->padY = fm.ascent / 4;
528 * Recompute the desired geometry for the window, and arrange for
529 * the window to be redisplayed.
532 ComputeMessageGeometry(msgPtr);
533 if ((msgPtr->tkwin != NULL) && Tk_IsMapped(msgPtr->tkwin)
534 && !(msgPtr->flags & REDRAW_PENDING)) {
535 Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
536 msgPtr->flags |= REDRAW_PENDING;
541 *--------------------------------------------------------------
543 * ComputeMessageGeometry --
545 * Compute the desired geometry for a message window,
546 * taking into account the desired aspect ratio for the
553 * Tk_GeometryRequest is called to inform the geometry
554 * manager of the desired geometry for this window.
556 *--------------------------------------------------------------
560 ComputeMessageGeometry(msgPtr)
561 register Message *msgPtr; /* Information about window. */
563 int width, inc, height;
564 int thisWidth, thisHeight, maxWidth;
565 int aspect, lowerBound, upperBound, inset;
567 Tk_FreeTextLayout(msgPtr->textLayout);
569 inset = msgPtr->borderWidth + msgPtr->highlightWidth;
572 * Compute acceptable bounds for the final aspect ratio.
575 aspect = msgPtr->aspect/10;
579 lowerBound = msgPtr->aspect - aspect;
580 upperBound = msgPtr->aspect + aspect;
583 * Do the computation in multiple passes: start off with
584 * a very wide window, and compute its height. Then change
585 * the width and try again. Reduce the size of the change
586 * and iterate until dimensions are found that approximate
587 * the desired aspect ratio. Or, if the user gave an explicit
588 * width then just use that.
591 if (msgPtr->width > 0) {
592 width = msgPtr->width;
595 width = WidthOfScreen(Tk_Screen(msgPtr->tkwin))/2;
599 for ( ; ; inc /= 2) {
600 msgPtr->textLayout = Tk_ComputeTextLayout(msgPtr->tkfont,
601 msgPtr->string, msgPtr->numChars, width, msgPtr->justify,
602 0, &thisWidth, &thisHeight);
603 maxWidth = thisWidth + 2 * (inset + msgPtr->padX);
604 height = thisHeight + 2 * (inset + msgPtr->padY);
609 aspect = (100 * maxWidth) / height;
611 if (aspect < lowerBound) {
613 } else if (aspect > upperBound) {
618 Tk_FreeTextLayout(msgPtr->textLayout);
620 msgPtr->msgWidth = thisWidth;
621 msgPtr->msgHeight = thisHeight;
622 Tk_GeometryRequest(msgPtr->tkwin, maxWidth, height);
623 Tk_SetInternalBorder(msgPtr->tkwin, inset);
627 *--------------------------------------------------------------
631 * This procedure redraws the contents of a message window.
637 * Information appears on the screen.
639 *--------------------------------------------------------------
643 DisplayMessage(clientData)
644 ClientData clientData; /* Information about window. */
646 register Message *msgPtr = (Message *) clientData;
647 register Tk_Window tkwin = msgPtr->tkwin;
649 int borderWidth = msgPtr->highlightWidth;
651 msgPtr->flags &= ~REDRAW_PENDING;
652 if ((msgPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
655 if (msgPtr->border != NULL) {
656 borderWidth += msgPtr->borderWidth;
658 if (msgPtr->relief == TK_RELIEF_FLAT) {
659 borderWidth = msgPtr->highlightWidth;
661 Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border,
662 borderWidth, borderWidth,
663 Tk_Width(tkwin) - 2 * borderWidth,
664 Tk_Height(tkwin) - 2 * borderWidth,
668 * Compute starting y-location for message based on message size
672 TkComputeAnchor(msgPtr->anchor, tkwin, msgPtr->padX, msgPtr->padY,
673 msgPtr->msgWidth, msgPtr->msgHeight, &x, &y);
674 Tk_DrawTextLayout(Tk_Display(tkwin), Tk_WindowId(tkwin), msgPtr->textGC,
675 msgPtr->textLayout, x, y, 0, -1);
677 if (borderWidth > msgPtr->highlightWidth) {
678 Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border,
679 msgPtr->highlightWidth, msgPtr->highlightWidth,
680 Tk_Width(tkwin) - 2*msgPtr->highlightWidth,
681 Tk_Height(tkwin) - 2*msgPtr->highlightWidth,
682 msgPtr->borderWidth, msgPtr->relief);
684 if (msgPtr->highlightWidth != 0) {
687 bgGC = Tk_GCForColor(msgPtr->highlightBgColorPtr, Tk_WindowId(tkwin));
688 if (msgPtr->flags & GOT_FOCUS) {
689 fgGC = Tk_GCForColor(msgPtr->highlightColorPtr, Tk_WindowId(tkwin));
690 TkpDrawHighlightBorder(tkwin, fgGC, bgGC, msgPtr->highlightWidth,
693 TkpDrawHighlightBorder(tkwin, bgGC, bgGC, msgPtr->highlightWidth,
700 *--------------------------------------------------------------
702 * MessageEventProc --
704 * This procedure is invoked by the Tk dispatcher for various
705 * events on messages.
711 * When the window gets deleted, internal structures get
712 * cleaned up. When it gets exposed, it is redisplayed.
714 *--------------------------------------------------------------
718 MessageEventProc(clientData, eventPtr)
719 ClientData clientData; /* Information about window. */
720 XEvent *eventPtr; /* Information about event. */
722 Message *msgPtr = (Message *) clientData;
724 if (((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0))
725 || (eventPtr->type == ConfigureNotify)) {
727 } else if (eventPtr->type == DestroyNotify) {
728 if (msgPtr->tkwin != NULL) {
729 msgPtr->tkwin = NULL;
730 Tcl_DeleteCommandFromToken(msgPtr->interp, msgPtr->widgetCmd);
732 if (msgPtr->flags & REDRAW_PENDING) {
733 Tcl_CancelIdleCall(DisplayMessage, (ClientData) msgPtr);
735 Tcl_EventuallyFree((ClientData) msgPtr, DestroyMessage);
736 } else if (eventPtr->type == FocusIn) {
737 if (eventPtr->xfocus.detail != NotifyInferior) {
738 msgPtr->flags |= GOT_FOCUS;
739 if (msgPtr->highlightWidth > 0) {
743 } else if (eventPtr->type == FocusOut) {
744 if (eventPtr->xfocus.detail != NotifyInferior) {
745 msgPtr->flags &= ~GOT_FOCUS;
746 if (msgPtr->highlightWidth > 0) {
754 if ((msgPtr->tkwin != NULL) && !(msgPtr->flags & REDRAW_PENDING)) {
755 Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
756 msgPtr->flags |= REDRAW_PENDING;
761 *----------------------------------------------------------------------
763 * MessageCmdDeletedProc --
765 * This procedure is invoked when a widget command is deleted. If
766 * the widget isn't already in the process of being destroyed,
767 * this command destroys it.
773 * The widget is destroyed.
775 *----------------------------------------------------------------------
779 MessageCmdDeletedProc(clientData)
780 ClientData clientData; /* Pointer to widget record for widget. */
782 Message *msgPtr = (Message *) clientData;
783 Tk_Window tkwin = msgPtr->tkwin;
786 * This procedure could be invoked either because the window was
787 * destroyed and the command was then deleted (in which case tkwin
788 * is NULL) or because the command was deleted, and then this procedure
789 * destroys the widget.
793 msgPtr->tkwin = NULL;
794 Tk_DestroyWindow(tkwin);
799 *--------------------------------------------------------------
801 * MessageTextVarProc --
803 * This procedure is invoked when someone changes the variable
804 * whose contents are to be displayed in a message.
807 * NULL is always returned.
810 * The text displayed in the message will change to match the
813 *--------------------------------------------------------------
818 MessageTextVarProc(clientData, interp, name1, name2, flags)
819 ClientData clientData; /* Information about message. */
820 Tcl_Interp *interp; /* Interpreter containing variable. */
821 char *name1; /* Name of variable. */
822 char *name2; /* Second part of variable name. */
823 int flags; /* Information about what happened. */
825 register Message *msgPtr = (Message *) clientData;
829 * If the variable is unset, then immediately recreate it unless
830 * the whole interpreter is going away.
833 if (flags & TCL_TRACE_UNSETS) {
834 if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
835 Tcl_SetVar(interp, msgPtr->textVarName, msgPtr->string,
837 Tcl_TraceVar(interp, msgPtr->textVarName,
838 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
839 MessageTextVarProc, clientData);
841 return (char *) NULL;
844 value = Tcl_GetVar(interp, msgPtr->textVarName, TCL_GLOBAL_ONLY);
848 if (msgPtr->string != NULL) {
849 ckfree(msgPtr->string);
851 msgPtr->numChars = Tcl_NumUtfChars(value, -1);
852 msgPtr->string = (char *) ckalloc((unsigned) (strlen(value) + 1));
853 strcpy(msgPtr->string, value);
854 ComputeMessageGeometry(msgPtr);
856 if ((msgPtr->tkwin != NULL) && Tk_IsMapped(msgPtr->tkwin)
857 && !(msgPtr->flags & REDRAW_PENDING)) {
858 Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
859 msgPtr->flags |= REDRAW_PENDING;
861 return (char *) NULL;