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.
10 * Copyright (c) 1998-2000 by Ajuba Solutions.
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
23 * A data structure of the following type is kept for each message
24 * widget managed by this file:
28 Tk_Window tkwin; /* Window that embodies the message. NULL
29 * means that the window has been destroyed
30 * but the data structures haven't yet been
32 Tk_OptionTable optionTable; /* Table that defines options available for
34 Display *display; /* Display containing widget. Used, among
35 * other things, so that resources can be
36 * freed even after tkwin has gone away. */
37 Tcl_Interp *interp; /* Interpreter associated with message. */
38 Tcl_Command widgetCmd; /* Token for message's widget command. */
41 * Information used when displaying widget:
44 char *string; /* String displayed in message. */
45 int numChars; /* Number of characters in string, not
46 * including terminating NULL. */
47 char *textVarName; /* Name of variable (malloc'ed) or NULL.
48 * If non-NULL, message displays the contents
49 * of this variable. */
50 Tk_3DBorder border; /* Structure used to draw 3-D border and
51 * background. NULL means a border hasn't
52 * been created yet. */
53 int borderWidth; /* Width of border. */
54 int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
55 int highlightWidth; /* Width in pixels of highlight to draw
56 * around widget when it has the focus.
57 * <= 0 means don't draw a highlight. */
58 XColor *highlightBgColorPtr;
59 /* Color for drawing traversal highlight
60 * area when highlight is off. */
61 XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
62 Tk_Font tkfont; /* Information about text font, or NULL. */
63 XColor *fgColorPtr; /* Foreground color in normal mode. */
64 Tcl_Obj *padXPtr, *padYPtr; /* Tcl_Obj rep's of padX, padY values. */
65 int padX, padY; /* User-requested extra space around text. */
66 int width; /* User-requested width, in pixels. 0 means
67 * compute width using aspect ratio below. */
68 int aspect; /* Desired aspect ratio for window
69 * (100*width/height). */
70 int msgWidth; /* Width in pixels needed to display
72 int msgHeight; /* Height in pixels needed to display
74 Tk_Anchor anchor; /* Where to position text within window region
75 * if window is larger or smaller than
77 Tk_Justify justify; /* Justification for text. */
79 GC textGC; /* GC for drawing text in normal mode. */
80 Tk_TextLayout textLayout; /* Saved layout information. */
83 * Miscellaneous information:
86 Tk_Cursor cursor; /* Current cursor for window, or None. */
87 char *takeFocus; /* Value of -takefocus option; not used in
88 * the C code, but used by keyboard traversal
89 * scripts. Malloc'ed, but may be NULL. */
90 int flags; /* Various flags; see below for
95 * Flag bits for messages:
97 * REDRAW_PENDING: Non-zero means a DoWhenIdle handler
98 * has already been queued to redraw
100 * GOT_FOCUS: Non-zero means this button currently
101 * has the input focus.
102 * MESSAGE_DELETED: The message has been effectively deleted.
105 #define REDRAW_PENDING 1
107 #define MESSAGE_DELETED 8
110 * Information used for argv parsing.
113 static Tk_OptionSpec optionSpecs[] = {
114 {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor", DEF_MESSAGE_ANCHOR,
115 -1, Tk_Offset(Message, anchor), 0, 0, 0},
116 {TK_OPTION_INT, "-aspect", "aspect", "Aspect", DEF_MESSAGE_ASPECT,
117 -1, Tk_Offset(Message, aspect), 0, 0, 0},
118 {TK_OPTION_BORDER, "-background", "background", "Background",
119 DEF_MESSAGE_BG_COLOR, -1, Tk_Offset(Message, border), 0,
120 (ClientData) DEF_MESSAGE_BG_MONO, 0},
121 {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, (char *) NULL,
122 0, -1, 0, (ClientData) "-borderwidth", 0},
123 {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, (char *) NULL,
124 0, -1, 0, (ClientData) "-background", 0},
125 {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
126 DEF_MESSAGE_BORDER_WIDTH, -1,
127 Tk_Offset(Message, borderWidth), 0, 0, 0},
128 {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor",
129 DEF_MESSAGE_CURSOR, -1, Tk_Offset(Message, cursor),
130 TK_OPTION_NULL_OK, 0, 0},
131 {TK_OPTION_SYNONYM, "-fg", (char *) NULL, (char *) NULL, (char *) NULL,
132 0, -1, 0, (ClientData) "-foreground", 0},
133 {TK_OPTION_FONT, "-font", "font", "Font",
134 DEF_MESSAGE_FONT, -1, Tk_Offset(Message, tkfont), 0, 0, 0},
135 {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground",
136 DEF_MESSAGE_FG, -1, Tk_Offset(Message, fgColorPtr), 0, 0, 0},
137 {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground",
138 "HighlightBackground", DEF_MESSAGE_HIGHLIGHT_BG, -1,
139 Tk_Offset(Message, highlightBgColorPtr), 0, 0},
140 {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
141 DEF_MESSAGE_HIGHLIGHT, -1, Tk_Offset(Message, highlightColorPtr),
143 {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness",
144 "HighlightThickness", DEF_MESSAGE_HIGHLIGHT_WIDTH, -1,
145 Tk_Offset(Message, highlightWidth), 0, 0, 0},
146 {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
147 DEF_MESSAGE_JUSTIFY, -1, Tk_Offset(Message, justify), 0, 0, 0},
148 {TK_OPTION_PIXELS, "-padx", "padX", "Pad",
149 DEF_MESSAGE_PADX, Tk_Offset(Message, padXPtr),
150 Tk_Offset(Message, padX), 0, 0, 0},
151 {TK_OPTION_PIXELS, "-pady", "padY", "Pad",
152 DEF_MESSAGE_PADY, Tk_Offset(Message, padYPtr),
153 Tk_Offset(Message, padY), 0, 0, 0},
154 {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
155 DEF_MESSAGE_RELIEF, -1, Tk_Offset(Message, relief), 0, 0, 0},
156 {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
157 DEF_MESSAGE_TAKE_FOCUS, -1, Tk_Offset(Message, takeFocus),
158 TK_OPTION_NULL_OK, 0, 0},
159 {TK_OPTION_STRING, "-text", "text", "Text",
160 DEF_MESSAGE_TEXT, -1, Tk_Offset(Message, string), 0, 0, 0},
161 {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable",
162 DEF_MESSAGE_TEXT_VARIABLE, -1, Tk_Offset(Message, textVarName),
163 TK_OPTION_NULL_OK, 0, 0},
164 {TK_OPTION_PIXELS, "-width", "width", "Width",
165 DEF_MESSAGE_WIDTH, -1, Tk_Offset(Message, width), 0, 0 ,0},
166 {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
167 (char *) NULL, 0, 0, 0, 0}
171 * Forward declarations for procedures defined later in this file:
174 static void MessageCmdDeletedProc _ANSI_ARGS_((
175 ClientData clientData));
176 static void MessageEventProc _ANSI_ARGS_((ClientData clientData,
178 static char * MessageTextVarProc _ANSI_ARGS_((ClientData clientData,
179 Tcl_Interp *interp, CONST char *name1,
180 CONST char *name2, int flags));
181 static int MessageWidgetObjCmd _ANSI_ARGS_((ClientData clientData,
182 Tcl_Interp *interp, int objc,
183 Tcl_Obj *CONST objv[]));
184 static void MessageWorldChanged _ANSI_ARGS_((
185 ClientData instanceData));
186 static void ComputeMessageGeometry _ANSI_ARGS_((Message *msgPtr));
187 static int ConfigureMessage _ANSI_ARGS_((Tcl_Interp *interp,
188 Message *msgPtr, int objc, Tcl_Obj *CONST objv[],
190 static void DestroyMessage _ANSI_ARGS_((char *memPtr));
191 static void DisplayMessage _ANSI_ARGS_((ClientData clientData));
194 * The structure below defines message class behavior by means of procedures
195 * that can be invoked from generic window code.
198 static Tk_ClassProcs messageClass = {
199 sizeof(Tk_ClassProcs), /* size */
200 MessageWorldChanged, /* worldChangedProc */
205 *--------------------------------------------------------------
207 * Tk_MessageObjCmd --
209 * This procedure is invoked to process the "message" Tcl
210 * command. See the user documentation for details on what
214 * A standard Tcl result.
217 * See the user documentation.
219 *--------------------------------------------------------------
223 Tk_MessageObjCmd(clientData, interp, objc, objv)
224 ClientData clientData; /* NULL. */
225 Tcl_Interp *interp; /* Current interpreter. */
226 int objc; /* Number of arguments. */
227 Tcl_Obj *CONST objv[]; /* Argument strings. */
229 register Message *msgPtr;
230 Tk_OptionTable optionTable;
234 Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?");
238 tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp),
239 Tcl_GetString(objv[1]), (char *) NULL);
245 * Create the option table for this widget class. If it has already
246 * been created, the cached pointer will be returned.
249 optionTable = Tk_CreateOptionTable(interp, optionSpecs);
251 msgPtr = (Message *) ckalloc(sizeof(Message));
252 memset(msgPtr, 0, (size_t) sizeof(Message));
255 * Set values for those fields that don't take a 0 or NULL value.
257 msgPtr->tkwin = tkwin;
258 msgPtr->display = Tk_Display(tkwin);
259 msgPtr->interp = interp;
260 msgPtr->widgetCmd = Tcl_CreateObjCommand(interp,
261 Tk_PathName(msgPtr->tkwin), MessageWidgetObjCmd,
262 (ClientData) msgPtr, MessageCmdDeletedProc);
263 msgPtr->optionTable = optionTable;
264 msgPtr->relief = TK_RELIEF_FLAT;
265 msgPtr->textGC = None;
266 msgPtr->anchor = TK_ANCHOR_CENTER;
267 msgPtr->aspect = 150;
268 msgPtr->justify = TK_JUSTIFY_LEFT;
269 msgPtr->cursor = None;
271 Tk_SetClass(msgPtr->tkwin, "Message");
272 Tk_SetClassProcs(msgPtr->tkwin, &messageClass, (ClientData) msgPtr);
273 Tk_CreateEventHandler(msgPtr->tkwin,
274 ExposureMask|StructureNotifyMask|FocusChangeMask,
275 MessageEventProc, (ClientData) msgPtr);
276 if (Tk_InitOptions(interp, (char *)msgPtr, optionTable, tkwin) != TCL_OK) {
277 Tk_DestroyWindow(msgPtr->tkwin);
281 if (ConfigureMessage(interp, msgPtr, objc-2, objv+2, 0) != TCL_OK) {
282 Tk_DestroyWindow(msgPtr->tkwin);
286 Tcl_SetResult(interp, Tk_PathName(msgPtr->tkwin), TCL_STATIC);
291 *--------------------------------------------------------------
293 * MessageWidgetObjCmd --
295 * This procedure is invoked to process the Tcl command
296 * that corresponds to a widget managed by this module.
297 * See the user documentation for details on what it does.
300 * A standard Tcl result.
303 * See the user documentation.
305 *--------------------------------------------------------------
309 MessageWidgetObjCmd(clientData, interp, objc, objv)
310 ClientData clientData; /* Information about message widget. */
311 Tcl_Interp *interp; /* Current interpreter. */
312 int objc; /* Number of arguments. */
313 Tcl_Obj *CONST objv[]; /* Argument strings. */
315 register Message *msgPtr = (Message *) clientData;
316 static CONST char *optionStrings[] = { "cget", "configure", (char *) NULL };
317 enum options { MESSAGE_CGET, MESSAGE_CONFIGURE };
323 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
327 if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
332 Tcl_Preserve((ClientData) msgPtr);
334 switch ((enum options) index) {
337 Tcl_WrongNumArgs(interp, 2, objv, "option");
340 objPtr = Tk_GetOptionValue(interp, (char *) msgPtr,
341 msgPtr->optionTable, objv[2], msgPtr->tkwin);
342 if (objPtr == NULL) {
345 Tcl_SetObjResult(interp, objPtr);
350 case MESSAGE_CONFIGURE: {
352 objPtr = Tk_GetOptionInfo(interp, (char *) msgPtr,
354 (objc == 3) ? objv[2] : (Tcl_Obj *) NULL,
356 if (objPtr == NULL) {
359 Tcl_SetObjResult(interp, objPtr);
363 result = ConfigureMessage(interp, msgPtr, objc-2, objv+2, 0);
369 Tcl_Release((ClientData) msgPtr);
374 *----------------------------------------------------------------------
378 * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
379 * to clean up the internal structure of a message at a safe time
380 * (when no-one is using it anymore).
386 * Everything associated with the message is freed up.
388 *----------------------------------------------------------------------
392 DestroyMessage(memPtr)
393 char *memPtr; /* Info about message widget. */
395 register Message *msgPtr = (Message *) memPtr;
397 msgPtr->flags |= MESSAGE_DELETED;
399 Tcl_DeleteCommandFromToken(msgPtr->interp, msgPtr->widgetCmd);
400 if (msgPtr->flags & REDRAW_PENDING) {
401 Tcl_CancelIdleCall(DisplayMessage, (ClientData) msgPtr);
405 * Free up all the stuff that requires special handling, then
406 * let Tk_FreeConfigOptions handle all the standard option-related
410 if (msgPtr->textGC != None) {
411 Tk_FreeGC(msgPtr->display, msgPtr->textGC);
413 if (msgPtr->textLayout != NULL) {
414 Tk_FreeTextLayout(msgPtr->textLayout);
416 if (msgPtr->textVarName != NULL) {
417 Tcl_UntraceVar(msgPtr->interp, msgPtr->textVarName,
418 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
419 MessageTextVarProc, (ClientData) msgPtr);
421 Tk_FreeConfigOptions((char *) msgPtr, msgPtr->optionTable, msgPtr->tkwin);
422 msgPtr->tkwin = NULL;
423 ckfree((char *) msgPtr);
427 *----------------------------------------------------------------------
429 * ConfigureMessage --
431 * This procedure is called to process an argv/argc list, plus
432 * the Tk option database, in order to configure (or
433 * reconfigure) a message widget.
436 * The return value is a standard Tcl result. If TCL_ERROR is
437 * returned, then the interp's result contains an error message.
440 * Configuration information, such as text string, colors, font,
441 * etc. get set for msgPtr; old resources get freed, if there
444 *----------------------------------------------------------------------
448 ConfigureMessage(interp, msgPtr, objc, objv, flags)
449 Tcl_Interp *interp; /* Used for error reporting. */
450 register Message *msgPtr; /* Information about widget; may or may
451 * not already have values for some fields. */
452 int objc; /* Number of valid entries in argv. */
453 Tcl_Obj *CONST objv[]; /* Arguments. */
454 int flags; /* Flags to pass to Tk_ConfigureWidget. */
456 Tk_SavedOptions savedOptions;
459 * Eliminate any existing trace on a variable monitored by the message.
462 if (msgPtr->textVarName != NULL) {
463 Tcl_UntraceVar(interp, msgPtr->textVarName,
464 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
465 MessageTextVarProc, (ClientData) msgPtr);
468 if (Tk_SetOptions(interp, (char *) msgPtr, msgPtr->optionTable, objc, objv,
469 msgPtr->tkwin, &savedOptions, (int *)NULL) != TCL_OK) {
470 Tk_RestoreSavedOptions(&savedOptions);
476 * If the message is to display the value of a variable, then set up
477 * a trace on the variable's value, create the variable if it doesn't
478 * exist, and fetch its current value.
481 if (msgPtr->textVarName != NULL) {
484 value = Tcl_GetVar(interp, msgPtr->textVarName, TCL_GLOBAL_ONLY);
486 Tcl_SetVar(interp, msgPtr->textVarName, msgPtr->string,
489 if (msgPtr->string != NULL) {
490 ckfree(msgPtr->string);
492 msgPtr->string = strcpy(ckalloc(strlen(value) + 1), value);
494 Tcl_TraceVar(interp, msgPtr->textVarName,
495 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
496 MessageTextVarProc, (ClientData) msgPtr);
500 * A few other options need special processing, such as setting
501 * the background from a 3-D border or handling special defaults
502 * that couldn't be specified to Tk_ConfigureWidget.
505 msgPtr->numChars = Tcl_NumUtfChars(msgPtr->string, -1);
507 if (msgPtr->highlightWidth < 0) {
508 msgPtr->highlightWidth = 0;
511 Tk_FreeSavedOptions(&savedOptions);
512 MessageWorldChanged((ClientData) msgPtr);
517 *---------------------------------------------------------------------------
519 * MessageWorldChanged --
521 * This procedure is called when the world has changed in some
522 * way and the widget needs to recompute all its graphics contexts
523 * and determine its new geometry.
529 * Message will be relayed out and redisplayed.
531 *---------------------------------------------------------------------------
535 MessageWorldChanged(instanceData)
536 ClientData instanceData; /* Information about widget. */
543 msgPtr = (Message *) instanceData;
545 if (msgPtr->border != NULL) {
546 Tk_SetBackgroundFromBorder(msgPtr->tkwin, msgPtr->border);
549 gcValues.font = Tk_FontId(msgPtr->tkfont);
550 gcValues.foreground = msgPtr->fgColorPtr->pixel;
551 gc = Tk_GetGC(msgPtr->tkwin, GCForeground | GCFont, &gcValues);
552 if (msgPtr->textGC != None) {
553 Tk_FreeGC(msgPtr->display, msgPtr->textGC);
557 Tk_GetFontMetrics(msgPtr->tkfont, &fm);
558 if (msgPtr->padX < 0) {
559 msgPtr->padX = fm.ascent / 2;
561 if (msgPtr->padY == -1) {
562 msgPtr->padY = fm.ascent / 4;
566 * Recompute the desired geometry for the window, and arrange for
567 * the window to be redisplayed.
570 ComputeMessageGeometry(msgPtr);
571 if ((msgPtr->tkwin != NULL) && Tk_IsMapped(msgPtr->tkwin)
572 && !(msgPtr->flags & REDRAW_PENDING)) {
573 Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
574 msgPtr->flags |= REDRAW_PENDING;
579 *--------------------------------------------------------------
581 * ComputeMessageGeometry --
583 * Compute the desired geometry for a message window,
584 * taking into account the desired aspect ratio for the
591 * Tk_GeometryRequest is called to inform the geometry
592 * manager of the desired geometry for this window.
594 *--------------------------------------------------------------
598 ComputeMessageGeometry(msgPtr)
599 register Message *msgPtr; /* Information about window. */
601 int width, inc, height;
602 int thisWidth, thisHeight, maxWidth;
603 int aspect, lowerBound, upperBound, inset;
605 Tk_FreeTextLayout(msgPtr->textLayout);
607 inset = msgPtr->borderWidth + msgPtr->highlightWidth;
610 * Compute acceptable bounds for the final aspect ratio.
613 aspect = msgPtr->aspect/10;
617 lowerBound = msgPtr->aspect - aspect;
618 upperBound = msgPtr->aspect + aspect;
621 * Do the computation in multiple passes: start off with
622 * a very wide window, and compute its height. Then change
623 * the width and try again. Reduce the size of the change
624 * and iterate until dimensions are found that approximate
625 * the desired aspect ratio. Or, if the user gave an explicit
626 * width then just use that.
629 if (msgPtr->width > 0) {
630 width = msgPtr->width;
633 width = WidthOfScreen(Tk_Screen(msgPtr->tkwin))/2;
637 for ( ; ; inc /= 2) {
638 msgPtr->textLayout = Tk_ComputeTextLayout(msgPtr->tkfont,
639 msgPtr->string, msgPtr->numChars, width, msgPtr->justify,
640 0, &thisWidth, &thisHeight);
641 maxWidth = thisWidth + 2 * (inset + msgPtr->padX);
642 height = thisHeight + 2 * (inset + msgPtr->padY);
647 aspect = (100 * maxWidth) / height;
649 if (aspect < lowerBound) {
651 } else if (aspect > upperBound) {
656 Tk_FreeTextLayout(msgPtr->textLayout);
658 msgPtr->msgWidth = thisWidth;
659 msgPtr->msgHeight = thisHeight;
660 Tk_GeometryRequest(msgPtr->tkwin, maxWidth, height);
661 Tk_SetInternalBorder(msgPtr->tkwin, inset);
665 *--------------------------------------------------------------
669 * This procedure redraws the contents of a message window.
675 * Information appears on the screen.
677 *--------------------------------------------------------------
681 DisplayMessage(clientData)
682 ClientData clientData; /* Information about window. */
684 register Message *msgPtr = (Message *) clientData;
685 register Tk_Window tkwin = msgPtr->tkwin;
687 int borderWidth = msgPtr->highlightWidth;
689 msgPtr->flags &= ~REDRAW_PENDING;
690 if ((msgPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
693 if (msgPtr->border != NULL) {
694 borderWidth += msgPtr->borderWidth;
696 if (msgPtr->relief == TK_RELIEF_FLAT) {
697 borderWidth = msgPtr->highlightWidth;
699 Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border,
700 borderWidth, borderWidth,
701 Tk_Width(tkwin) - 2 * borderWidth,
702 Tk_Height(tkwin) - 2 * borderWidth,
706 * Compute starting y-location for message based on message size
710 TkComputeAnchor(msgPtr->anchor, tkwin, msgPtr->padX, msgPtr->padY,
711 msgPtr->msgWidth, msgPtr->msgHeight, &x, &y);
712 Tk_DrawTextLayout(Tk_Display(tkwin), Tk_WindowId(tkwin), msgPtr->textGC,
713 msgPtr->textLayout, x, y, 0, -1);
715 if (borderWidth > msgPtr->highlightWidth) {
716 Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border,
717 msgPtr->highlightWidth, msgPtr->highlightWidth,
718 Tk_Width(tkwin) - 2*msgPtr->highlightWidth,
719 Tk_Height(tkwin) - 2*msgPtr->highlightWidth,
720 msgPtr->borderWidth, msgPtr->relief);
722 if (msgPtr->highlightWidth != 0) {
725 bgGC = Tk_GCForColor(msgPtr->highlightBgColorPtr, Tk_WindowId(tkwin));
726 if (msgPtr->flags & GOT_FOCUS) {
727 fgGC = Tk_GCForColor(msgPtr->highlightColorPtr, Tk_WindowId(tkwin));
728 TkpDrawHighlightBorder(tkwin, fgGC, bgGC, msgPtr->highlightWidth,
731 TkpDrawHighlightBorder(tkwin, bgGC, bgGC, msgPtr->highlightWidth,
738 *--------------------------------------------------------------
740 * MessageEventProc --
742 * This procedure is invoked by the Tk dispatcher for various
743 * events on messages.
749 * When the window gets deleted, internal structures get
750 * cleaned up. When it gets exposed, it is redisplayed.
752 *--------------------------------------------------------------
756 MessageEventProc(clientData, eventPtr)
757 ClientData clientData; /* Information about window. */
758 XEvent *eventPtr; /* Information about event. */
760 Message *msgPtr = (Message *) clientData;
762 if (((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0))
763 || (eventPtr->type == ConfigureNotify)) {
765 } else if (eventPtr->type == DestroyNotify) {
766 DestroyMessage((char *) clientData);
767 } else if (eventPtr->type == FocusIn) {
768 if (eventPtr->xfocus.detail != NotifyInferior) {
769 msgPtr->flags |= GOT_FOCUS;
770 if (msgPtr->highlightWidth > 0) {
774 } else if (eventPtr->type == FocusOut) {
775 if (eventPtr->xfocus.detail != NotifyInferior) {
776 msgPtr->flags &= ~GOT_FOCUS;
777 if (msgPtr->highlightWidth > 0) {
785 if ((msgPtr->tkwin != NULL) && !(msgPtr->flags & REDRAW_PENDING)) {
786 Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
787 msgPtr->flags |= REDRAW_PENDING;
792 *----------------------------------------------------------------------
794 * MessageCmdDeletedProc --
796 * This procedure is invoked when a widget command is deleted. If
797 * the widget isn't already in the process of being destroyed,
798 * this command destroys it.
804 * The widget is destroyed.
806 *----------------------------------------------------------------------
810 MessageCmdDeletedProc(clientData)
811 ClientData clientData; /* Pointer to widget record for widget. */
813 Message *msgPtr = (Message *) clientData;
816 * This procedure could be invoked either because the window was
817 * destroyed and the command was then deleted (in which case tkwin
818 * is NULL) or because the command was deleted, and then this procedure
819 * destroys the widget.
822 if (!(msgPtr->flags & MESSAGE_DELETED)) {
823 Tk_DestroyWindow(msgPtr->tkwin);
828 *--------------------------------------------------------------
830 * MessageTextVarProc --
832 * This procedure is invoked when someone changes the variable
833 * whose contents are to be displayed in a message.
836 * NULL is always returned.
839 * The text displayed in the message will change to match the
842 *--------------------------------------------------------------
847 MessageTextVarProc(clientData, interp, name1, name2, flags)
848 ClientData clientData; /* Information about message. */
849 Tcl_Interp *interp; /* Interpreter containing variable. */
850 CONST char *name1; /* Name of variable. */
851 CONST char *name2; /* Second part of variable name. */
852 int flags; /* Information about what happened. */
854 register Message *msgPtr = (Message *) clientData;
858 * If the variable is unset, then immediately recreate it unless
859 * the whole interpreter is going away.
862 if (flags & TCL_TRACE_UNSETS) {
863 if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
864 Tcl_SetVar(interp, msgPtr->textVarName, msgPtr->string,
866 Tcl_TraceVar(interp, msgPtr->textVarName,
867 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
868 MessageTextVarProc, clientData);
870 return (char *) NULL;
873 value = Tcl_GetVar(interp, msgPtr->textVarName, TCL_GLOBAL_ONLY);
877 if (msgPtr->string != NULL) {
878 ckfree(msgPtr->string);
880 msgPtr->numChars = Tcl_NumUtfChars(value, -1);
881 msgPtr->string = (char *) ckalloc((unsigned) (strlen(value) + 1));
882 strcpy(msgPtr->string, value);
883 ComputeMessageGeometry(msgPtr);
885 if ((msgPtr->tkwin != NULL) && Tk_IsMapped(msgPtr->tkwin)
886 && !(msgPtr->flags & REDRAW_PENDING)) {
887 Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
888 msgPtr->flags |= REDRAW_PENDING;
890 return (char *) NULL;