/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkmessage.c
ViewVC logotype

Annotation of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkmessage.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 69 - (hide annotations) (download)
Sat Nov 5 10:54:17 2016 UTC (7 years, 6 months ago) by dashley
File MIME type: text/plain
File size: 27408 byte(s)
License and property (keyword) changes.
1 dashley 69 /* $Header$ */
2 dashley 25
3     /*
4     * tkMessage.c --
5     *
6     * This module implements a message widgets for the Tk
7     * toolkit. A message widget displays a multi-line string
8     * in a window according to a particular aspect ratio.
9     *
10     * Copyright (c) 1990-1994 The Regents of the University of California.
11     * Copyright (c) 1994-1997 Sun Microsystems, Inc.
12     *
13     * See the file "license.terms" for information on usage and redistribution
14     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15     *
16     * RCS: @(#) $Id: tkmessage.c,v 1.1.1.1 2001/06/13 05:06:15 dtashley Exp $
17     */
18    
19     #include "tkPort.h"
20     #include "default.h"
21     #include "tkInt.h"
22    
23     /*
24     * A data structure of the following type is kept for each message
25     * widget managed by this file:
26     */
27    
28     typedef struct {
29     Tk_Window tkwin; /* Window that embodies the message. NULL
30     * means that the window has been destroyed
31     * but the data structures haven't yet been
32     * cleaned up.*/
33     Display *display; /* Display containing widget. Used, among
34     * other things, so that resources can be
35     * freed even after tkwin has gone away. */
36     Tcl_Interp *interp; /* Interpreter associated with message. */
37     Tcl_Command widgetCmd; /* Token for message's widget command. */
38    
39     /*
40     * Information used when displaying widget:
41     */
42    
43     char *string; /* String displayed in message. */
44     int numChars; /* Number of characters in string, not
45     * including terminating NULL. */
46     char *textVarName; /* Name of variable (malloc'ed) or NULL.
47     * If non-NULL, message displays the contents
48     * of this variable. */
49     Tk_3DBorder border; /* Structure used to draw 3-D border and
50     * background. NULL means a border hasn't
51     * been created yet. */
52     int borderWidth; /* Width of border. */
53     int relief; /* 3-D effect: TK_RELIEF_RAISED, etc. */
54     int highlightWidth; /* Width in pixels of highlight to draw
55     * around widget when it has the focus.
56     * <= 0 means don't draw a highlight. */
57     XColor *highlightBgColorPtr;
58     /* Color for drawing traversal highlight
59     * area when highlight is off. */
60     XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
61     Tk_Font tkfont; /* Information about text font, or NULL. */
62     XColor *fgColorPtr; /* Foreground color in normal mode. */
63     int padX, padY; /* User-requested extra space around text. */
64     int width; /* User-requested width, in pixels. 0 means
65     * compute width using aspect ratio below. */
66     int aspect; /* Desired aspect ratio for window
67     * (100*width/height). */
68     int msgWidth; /* Width in pixels needed to display
69     * message. */
70     int msgHeight; /* Height in pixels needed to display
71     * message. */
72     Tk_Anchor anchor; /* Where to position text within window region
73     * if window is larger or smaller than
74     * needed. */
75     Tk_Justify justify; /* Justification for text. */
76    
77     GC textGC; /* GC for drawing text in normal mode. */
78     Tk_TextLayout textLayout; /* Saved layout information. */
79    
80     /*
81     * Miscellaneous information:
82     */
83    
84     Tk_Cursor cursor; /* Current cursor for window, or None. */
85     char *takeFocus; /* Value of -takefocus option; not used in
86     * the C code, but used by keyboard traversal
87     * scripts. Malloc'ed, but may be NULL. */
88     int flags; /* Various flags; see below for
89     * definitions. */
90     } Message;
91    
92     /*
93     * Flag bits for messages:
94     *
95     * REDRAW_PENDING: Non-zero means a DoWhenIdle handler
96     * has already been queued to redraw
97     * this window.
98     * GOT_FOCUS: Non-zero means this button currently
99     * has the input focus.
100     */
101    
102     #define REDRAW_PENDING 1
103     #define GOT_FOCUS 4
104    
105     /*
106     * Information used for argv parsing.
107     */
108    
109     static Tk_ConfigSpec configSpecs[] = {
110     {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor",
111     DEF_MESSAGE_ANCHOR, Tk_Offset(Message, anchor), 0},
112     {TK_CONFIG_INT, "-aspect", "aspect", "Aspect",
113     DEF_MESSAGE_ASPECT, Tk_Offset(Message, aspect), 0},
114     {TK_CONFIG_BORDER, "-background", "background", "Background",
115     DEF_MESSAGE_BG_COLOR, Tk_Offset(Message, border),
116     TK_CONFIG_COLOR_ONLY},
117     {TK_CONFIG_BORDER, "-background", "background", "Background",
118     DEF_MESSAGE_BG_MONO, Tk_Offset(Message, border),
119     TK_CONFIG_MONO_ONLY},
120     {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
121     (char *) NULL, 0, 0},
122     {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
123     (char *) NULL, 0, 0},
124     {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
125     DEF_MESSAGE_BORDER_WIDTH, Tk_Offset(Message, borderWidth), 0},
126     {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
127     DEF_MESSAGE_CURSOR, Tk_Offset(Message, cursor), TK_CONFIG_NULL_OK},
128     {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
129     (char *) NULL, 0, 0},
130     {TK_CONFIG_FONT, "-font", "font", "Font",
131     DEF_MESSAGE_FONT, Tk_Offset(Message, tkfont), 0},
132     {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
133     DEF_MESSAGE_FG, Tk_Offset(Message, fgColorPtr), 0},
134     {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
135     "HighlightBackground", DEF_MESSAGE_HIGHLIGHT_BG,
136     Tk_Offset(Message, highlightBgColorPtr), 0},
137     {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
138     DEF_MESSAGE_HIGHLIGHT, Tk_Offset(Message, highlightColorPtr), 0},
139     {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
140     "HighlightThickness",
141     DEF_MESSAGE_HIGHLIGHT_WIDTH, Tk_Offset(Message, highlightWidth), 0},
142     {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
143     DEF_MESSAGE_JUSTIFY, Tk_Offset(Message, justify), 0},
144     {TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
145     DEF_MESSAGE_PADX, Tk_Offset(Message, padX), 0},
146     {TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
147     DEF_MESSAGE_PADY, Tk_Offset(Message, padY), 0},
148     {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
149     DEF_MESSAGE_RELIEF, Tk_Offset(Message, relief), 0},
150     {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
151     DEF_MESSAGE_TAKE_FOCUS, Tk_Offset(Message, takeFocus),
152     TK_CONFIG_NULL_OK},
153     {TK_CONFIG_STRING, "-text", "text", "Text",
154     DEF_MESSAGE_TEXT, Tk_Offset(Message, string), 0},
155     {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable",
156     DEF_MESSAGE_TEXT_VARIABLE, Tk_Offset(Message, textVarName),
157     TK_CONFIG_NULL_OK},
158     {TK_CONFIG_PIXELS, "-width", "width", "Width",
159     DEF_MESSAGE_WIDTH, Tk_Offset(Message, width), 0},
160     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
161     (char *) NULL, 0, 0}
162     };
163    
164     /*
165     * Forward declarations for procedures defined later in this file:
166     */
167    
168     static void MessageCmdDeletedProc _ANSI_ARGS_((
169     ClientData clientData));
170     static void MessageEventProc _ANSI_ARGS_((ClientData clientData,
171     XEvent *eventPtr));
172     static char * MessageTextVarProc _ANSI_ARGS_((ClientData clientData,
173     Tcl_Interp *interp, char *name1, char *name2,
174     int flags));
175     static int MessageWidgetCmd _ANSI_ARGS_((ClientData clientData,
176     Tcl_Interp *interp, int argc, char **argv));
177     static void MessageWorldChanged _ANSI_ARGS_((
178     ClientData instanceData));
179     static void ComputeMessageGeometry _ANSI_ARGS_((Message *msgPtr));
180     static int ConfigureMessage _ANSI_ARGS_((Tcl_Interp *interp,
181     Message *msgPtr, int argc, char **argv,
182     int flags));
183     static void DestroyMessage _ANSI_ARGS_((char *memPtr));
184     static void DisplayMessage _ANSI_ARGS_((ClientData clientData));
185    
186     /*
187     * The structure below defines message class behavior by means of procedures
188     * that can be invoked from generic window code.
189     */
190    
191     static TkClassProcs messageClass = {
192     NULL, /* createProc. */
193     MessageWorldChanged, /* geometryProc. */
194     NULL /* modalProc. */
195     };
196    
197    
198     /*
199     *--------------------------------------------------------------
200     *
201     * Tk_MessageCmd --
202     *
203     * This procedure is invoked to process the "message" Tcl
204     * command. See the user documentation for details on what
205     * it does.
206     *
207     * Results:
208     * A standard Tcl result.
209     *
210     * Side effects:
211     * See the user documentation.
212     *
213     *--------------------------------------------------------------
214     */
215    
216     int
217     Tk_MessageCmd(clientData, interp, argc, argv)
218     ClientData clientData; /* Main window associated with
219     * interpreter. */
220     Tcl_Interp *interp; /* Current interpreter. */
221     int argc; /* Number of arguments. */
222     char **argv; /* Argument strings. */
223     {
224     register Message *msgPtr;
225     Tk_Window new;
226     Tk_Window tkwin = (Tk_Window) clientData;
227    
228     if (argc < 2) {
229     Tcl_AppendResult(interp, "wrong # args: should be \"",
230     argv[0], " pathName ?options?\"", (char *) NULL);
231     return TCL_ERROR;
232     }
233    
234     new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
235     if (new == NULL) {
236     return TCL_ERROR;
237     }
238    
239     msgPtr = (Message *) ckalloc(sizeof(Message));
240     msgPtr->tkwin = new;
241     msgPtr->display = Tk_Display(new);
242     msgPtr->interp = interp;
243     msgPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(msgPtr->tkwin),
244     MessageWidgetCmd, (ClientData) msgPtr, MessageCmdDeletedProc);
245     msgPtr->textLayout = NULL;
246     msgPtr->string = NULL;
247     msgPtr->numChars = 0;
248     msgPtr->textVarName = NULL;
249     msgPtr->border = NULL;
250     msgPtr->borderWidth = 0;
251     msgPtr->relief = TK_RELIEF_FLAT;
252     msgPtr->highlightWidth = 0;
253     msgPtr->highlightBgColorPtr = NULL;
254     msgPtr->highlightColorPtr = NULL;
255     msgPtr->tkfont = NULL;
256     msgPtr->fgColorPtr = NULL;
257     msgPtr->textGC = None;
258     msgPtr->padX = 0;
259     msgPtr->padY = 0;
260     msgPtr->anchor = TK_ANCHOR_CENTER;
261     msgPtr->width = 0;
262     msgPtr->aspect = 150;
263     msgPtr->msgWidth = 0;
264     msgPtr->msgHeight = 0;
265     msgPtr->justify = TK_JUSTIFY_LEFT;
266     msgPtr->cursor = None;
267     msgPtr->takeFocus = NULL;
268     msgPtr->flags = 0;
269    
270     Tk_SetClass(msgPtr->tkwin, "Message");
271     TkSetClassProcs(msgPtr->tkwin, &messageClass, (ClientData) msgPtr);
272     Tk_CreateEventHandler(msgPtr->tkwin,
273     ExposureMask|StructureNotifyMask|FocusChangeMask,
274     MessageEventProc, (ClientData) msgPtr);
275     if (ConfigureMessage(interp, msgPtr, argc-2, argv+2, 0) != TCL_OK) {
276     goto error;
277     }
278    
279     Tcl_SetResult(interp, Tk_PathName(msgPtr->tkwin), TCL_STATIC);
280     return TCL_OK;
281    
282     error:
283     Tk_DestroyWindow(msgPtr->tkwin);
284     return TCL_ERROR;
285     }
286    
287     /*
288     *--------------------------------------------------------------
289     *
290     * MessageWidgetCmd --
291     *
292     * This procedure is invoked to process the Tcl command
293     * that corresponds to a widget managed by this module.
294     * See the user documentation for details on what it does.
295     *
296     * Results:
297     * A standard Tcl result.
298     *
299     * Side effects:
300     * See the user documentation.
301     *
302     *--------------------------------------------------------------
303     */
304    
305     static int
306     MessageWidgetCmd(clientData, interp, argc, argv)
307     ClientData clientData; /* Information about message widget. */
308     Tcl_Interp *interp; /* Current interpreter. */
309     int argc; /* Number of arguments. */
310     char **argv; /* Argument strings. */
311     {
312     register Message *msgPtr = (Message *) clientData;
313     size_t length;
314     int c;
315    
316     if (argc < 2) {
317     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
318     " option ?arg arg ...?\"", (char *) NULL);
319     return TCL_ERROR;
320     }
321     c = argv[1][0];
322     length = strlen(argv[1]);
323     if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
324     && (length >= 2)) {
325     if (argc != 3) {
326     Tcl_AppendResult(interp, "wrong # args: should be \"",
327     argv[0], " cget option\"",
328     (char *) NULL);
329     return TCL_ERROR;
330     }
331     return Tk_ConfigureValue(interp, msgPtr->tkwin, configSpecs,
332     (char *) msgPtr, argv[2], 0);
333     } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
334     && (length >= 2)) {
335     if (argc == 2) {
336     return Tk_ConfigureInfo(interp, msgPtr->tkwin, configSpecs,
337     (char *) msgPtr, (char *) NULL, 0);
338     } else if (argc == 3) {
339     return Tk_ConfigureInfo(interp, msgPtr->tkwin, configSpecs,
340     (char *) msgPtr, argv[2], 0);
341     } else {
342     return ConfigureMessage(interp, msgPtr, argc-2, argv+2,
343     TK_CONFIG_ARGV_ONLY);
344     }
345     } else {
346     Tcl_AppendResult(interp, "bad option \"", argv[1],
347     "\": must be cget or configure", (char *) NULL);
348     return TCL_ERROR;
349     }
350     }
351    
352     /*
353     *----------------------------------------------------------------------
354     *
355     * DestroyMessage --
356     *
357     * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
358     * to clean up the internal structure of a message at a safe time
359     * (when no-one is using it anymore).
360     *
361     * Results:
362     * None.
363     *
364     * Side effects:
365     * Everything associated with the message is freed up.
366     *
367     *----------------------------------------------------------------------
368     */
369    
370     static void
371     DestroyMessage(memPtr)
372     char *memPtr; /* Info about message widget. */
373     {
374     register Message *msgPtr = (Message *) memPtr;
375    
376     /*
377     * Free up all the stuff that requires special handling, then
378     * let Tk_FreeOptions handle all the standard option-related
379     * stuff.
380     */
381    
382     Tk_FreeTextLayout(msgPtr->textLayout);
383     if (msgPtr->textVarName != NULL) {
384     Tcl_UntraceVar(msgPtr->interp, msgPtr->textVarName,
385     TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
386     MessageTextVarProc, (ClientData) msgPtr);
387     }
388     if (msgPtr->textGC != None) {
389     Tk_FreeGC(msgPtr->display, msgPtr->textGC);
390     }
391     Tk_FreeOptions(configSpecs, (char *) msgPtr, msgPtr->display, 0);
392     ckfree((char *) msgPtr);
393     }
394    
395     /*
396     *----------------------------------------------------------------------
397     *
398     * ConfigureMessage --
399     *
400     * This procedure is called to process an argv/argc list, plus
401     * the Tk option database, in order to configure (or
402     * reconfigure) a message widget.
403     *
404     * Results:
405     * The return value is a standard Tcl result. If TCL_ERROR is
406     * returned, then the interp's result contains an error message.
407     *
408     * Side effects:
409     * Configuration information, such as text string, colors, font,
410     * etc. get set for msgPtr; old resources get freed, if there
411     * were any.
412     *
413     *----------------------------------------------------------------------
414     */
415    
416     static int
417     ConfigureMessage(interp, msgPtr, argc, argv, flags)
418     Tcl_Interp *interp; /* Used for error reporting. */
419     register Message *msgPtr; /* Information about widget; may or may
420     * not already have values for some fields. */
421     int argc; /* Number of valid entries in argv. */
422     char **argv; /* Arguments. */
423     int flags; /* Flags to pass to Tk_ConfigureWidget. */
424     {
425     /*
426     * Eliminate any existing trace on a variable monitored by the message.
427     */
428    
429     if (msgPtr->textVarName != NULL) {
430     Tcl_UntraceVar(interp, msgPtr->textVarName,
431     TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
432     MessageTextVarProc, (ClientData) msgPtr);
433     }
434    
435     if (Tk_ConfigureWidget(interp, msgPtr->tkwin, configSpecs,
436     argc, argv, (char *) msgPtr, flags) != TCL_OK) {
437     return TCL_ERROR;
438     }
439    
440     /*
441     * If the message is to display the value of a variable, then set up
442     * a trace on the variable's value, create the variable if it doesn't
443     * exist, and fetch its current value.
444     */
445    
446     if (msgPtr->textVarName != NULL) {
447     char *value;
448    
449     value = Tcl_GetVar(interp, msgPtr->textVarName, TCL_GLOBAL_ONLY);
450     if (value == NULL) {
451     Tcl_SetVar(interp, msgPtr->textVarName, msgPtr->string,
452     TCL_GLOBAL_ONLY);
453     } else {
454     if (msgPtr->string != NULL) {
455     ckfree(msgPtr->string);
456     }
457     msgPtr->string = strcpy(ckalloc(strlen(value) + 1), value);
458     }
459     Tcl_TraceVar(interp, msgPtr->textVarName,
460     TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
461     MessageTextVarProc, (ClientData) msgPtr);
462     }
463    
464     /*
465     * A few other options need special processing, such as setting
466     * the background from a 3-D border or handling special defaults
467     * that couldn't be specified to Tk_ConfigureWidget.
468     */
469    
470     msgPtr->numChars = Tcl_NumUtfChars(msgPtr->string, -1);
471    
472     if (msgPtr->highlightWidth < 0) {
473     msgPtr->highlightWidth = 0;
474     }
475    
476     MessageWorldChanged((ClientData) msgPtr);
477     return TCL_OK;
478     }
479    
480     /*
481     *---------------------------------------------------------------------------
482     *
483     * MessageWorldChanged --
484     *
485     * This procedure is called when the world has changed in some
486     * way and the widget needs to recompute all its graphics contexts
487     * and determine its new geometry.
488     *
489     * Results:
490     * None.
491     *
492     * Side effects:
493     * Message will be relayed out and redisplayed.
494     *
495     *---------------------------------------------------------------------------
496     */
497    
498     static void
499     MessageWorldChanged(instanceData)
500     ClientData instanceData; /* Information about widget. */
501     {
502     XGCValues gcValues;
503     GC gc = None;
504     Tk_FontMetrics fm;
505     Message *msgPtr;
506    
507     msgPtr = (Message *) instanceData;
508    
509     if (msgPtr->border != NULL) {
510     Tk_SetBackgroundFromBorder(msgPtr->tkwin, msgPtr->border);
511     }
512    
513     gcValues.font = Tk_FontId(msgPtr->tkfont);
514     gcValues.foreground = msgPtr->fgColorPtr->pixel;
515     gc = Tk_GetGC(msgPtr->tkwin, GCForeground | GCFont, &gcValues);
516     if (msgPtr->textGC != None) {
517     Tk_FreeGC(msgPtr->display, msgPtr->textGC);
518     }
519     msgPtr->textGC = gc;
520    
521     Tk_GetFontMetrics(msgPtr->tkfont, &fm);
522     if (msgPtr->padX < 0) {
523     msgPtr->padX = fm.ascent / 2;
524     }
525     if (msgPtr->padY == -1) {
526     msgPtr->padY = fm.ascent / 4;
527     }
528    
529     /*
530     * Recompute the desired geometry for the window, and arrange for
531     * the window to be redisplayed.
532     */
533    
534     ComputeMessageGeometry(msgPtr);
535     if ((msgPtr->tkwin != NULL) && Tk_IsMapped(msgPtr->tkwin)
536     && !(msgPtr->flags & REDRAW_PENDING)) {
537     Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
538     msgPtr->flags |= REDRAW_PENDING;
539     }
540     }
541    
542     /*
543     *--------------------------------------------------------------
544     *
545     * ComputeMessageGeometry --
546     *
547     * Compute the desired geometry for a message window,
548     * taking into account the desired aspect ratio for the
549     * window.
550     *
551     * Results:
552     * None.
553     *
554     * Side effects:
555     * Tk_GeometryRequest is called to inform the geometry
556     * manager of the desired geometry for this window.
557     *
558     *--------------------------------------------------------------
559     */
560    
561     static void
562     ComputeMessageGeometry(msgPtr)
563     register Message *msgPtr; /* Information about window. */
564     {
565     int width, inc, height;
566     int thisWidth, thisHeight, maxWidth;
567     int aspect, lowerBound, upperBound, inset;
568    
569     Tk_FreeTextLayout(msgPtr->textLayout);
570    
571     inset = msgPtr->borderWidth + msgPtr->highlightWidth;
572    
573     /*
574     * Compute acceptable bounds for the final aspect ratio.
575     */
576    
577     aspect = msgPtr->aspect/10;
578     if (aspect < 5) {
579     aspect = 5;
580     }
581     lowerBound = msgPtr->aspect - aspect;
582     upperBound = msgPtr->aspect + aspect;
583    
584     /*
585     * Do the computation in multiple passes: start off with
586     * a very wide window, and compute its height. Then change
587     * the width and try again. Reduce the size of the change
588     * and iterate until dimensions are found that approximate
589     * the desired aspect ratio. Or, if the user gave an explicit
590     * width then just use that.
591     */
592    
593     if (msgPtr->width > 0) {
594     width = msgPtr->width;
595     inc = 0;
596     } else {
597     width = WidthOfScreen(Tk_Screen(msgPtr->tkwin))/2;
598     inc = width/2;
599     }
600    
601     for ( ; ; inc /= 2) {
602     msgPtr->textLayout = Tk_ComputeTextLayout(msgPtr->tkfont,
603     msgPtr->string, msgPtr->numChars, width, msgPtr->justify,
604     0, &thisWidth, &thisHeight);
605     maxWidth = thisWidth + 2 * (inset + msgPtr->padX);
606     height = thisHeight + 2 * (inset + msgPtr->padY);
607    
608     if (inc <= 2) {
609     break;
610     }
611     aspect = (100 * maxWidth) / height;
612    
613     if (aspect < lowerBound) {
614     width += inc;
615     } else if (aspect > upperBound) {
616     width -= inc;
617     } else {
618     break;
619     }
620     Tk_FreeTextLayout(msgPtr->textLayout);
621     }
622     msgPtr->msgWidth = thisWidth;
623     msgPtr->msgHeight = thisHeight;
624     Tk_GeometryRequest(msgPtr->tkwin, maxWidth, height);
625     Tk_SetInternalBorder(msgPtr->tkwin, inset);
626     }
627    
628     /*
629     *--------------------------------------------------------------
630     *
631     * DisplayMessage --
632     *
633     * This procedure redraws the contents of a message window.
634     *
635     * Results:
636     * None.
637     *
638     * Side effects:
639     * Information appears on the screen.
640     *
641     *--------------------------------------------------------------
642     */
643    
644     static void
645     DisplayMessage(clientData)
646     ClientData clientData; /* Information about window. */
647     {
648     register Message *msgPtr = (Message *) clientData;
649     register Tk_Window tkwin = msgPtr->tkwin;
650     int x, y;
651     int borderWidth = msgPtr->highlightWidth;
652    
653     msgPtr->flags &= ~REDRAW_PENDING;
654     if ((msgPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
655     return;
656     }
657     if (msgPtr->border != NULL) {
658     borderWidth += msgPtr->borderWidth;
659     }
660     if (msgPtr->relief == TK_RELIEF_FLAT) {
661     borderWidth = msgPtr->highlightWidth;
662     }
663     Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border,
664     borderWidth, borderWidth,
665     Tk_Width(tkwin) - 2 * borderWidth,
666     Tk_Height(tkwin) - 2 * borderWidth,
667     0, TK_RELIEF_FLAT);
668    
669     /*
670     * Compute starting y-location for message based on message size
671     * and anchor option.
672     */
673    
674     TkComputeAnchor(msgPtr->anchor, tkwin, msgPtr->padX, msgPtr->padY,
675     msgPtr->msgWidth, msgPtr->msgHeight, &x, &y);
676     Tk_DrawTextLayout(Tk_Display(tkwin), Tk_WindowId(tkwin), msgPtr->textGC,
677     msgPtr->textLayout, x, y, 0, -1);
678    
679     if (borderWidth > msgPtr->highlightWidth) {
680     Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border,
681     msgPtr->highlightWidth, msgPtr->highlightWidth,
682     Tk_Width(tkwin) - 2*msgPtr->highlightWidth,
683     Tk_Height(tkwin) - 2*msgPtr->highlightWidth,
684     msgPtr->borderWidth, msgPtr->relief);
685     }
686     if (msgPtr->highlightWidth != 0) {
687     GC fgGC, bgGC;
688    
689     bgGC = Tk_GCForColor(msgPtr->highlightBgColorPtr, Tk_WindowId(tkwin));
690     if (msgPtr->flags & GOT_FOCUS) {
691     fgGC = Tk_GCForColor(msgPtr->highlightColorPtr, Tk_WindowId(tkwin));
692     TkpDrawHighlightBorder(tkwin, fgGC, bgGC, msgPtr->highlightWidth,
693     Tk_WindowId(tkwin));
694     } else {
695     TkpDrawHighlightBorder(tkwin, bgGC, bgGC, msgPtr->highlightWidth,
696     Tk_WindowId(tkwin));
697     }
698     }
699     }
700    
701     /*
702     *--------------------------------------------------------------
703     *
704     * MessageEventProc --
705     *
706     * This procedure is invoked by the Tk dispatcher for various
707     * events on messages.
708     *
709     * Results:
710     * None.
711     *
712     * Side effects:
713     * When the window gets deleted, internal structures get
714     * cleaned up. When it gets exposed, it is redisplayed.
715     *
716     *--------------------------------------------------------------
717     */
718    
719     static void
720     MessageEventProc(clientData, eventPtr)
721     ClientData clientData; /* Information about window. */
722     XEvent *eventPtr; /* Information about event. */
723     {
724     Message *msgPtr = (Message *) clientData;
725    
726     if (((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0))
727     || (eventPtr->type == ConfigureNotify)) {
728     goto redraw;
729     } else if (eventPtr->type == DestroyNotify) {
730     if (msgPtr->tkwin != NULL) {
731     msgPtr->tkwin = NULL;
732     Tcl_DeleteCommandFromToken(msgPtr->interp, msgPtr->widgetCmd);
733     }
734     if (msgPtr->flags & REDRAW_PENDING) {
735     Tcl_CancelIdleCall(DisplayMessage, (ClientData) msgPtr);
736     }
737     Tcl_EventuallyFree((ClientData) msgPtr, DestroyMessage);
738     } else if (eventPtr->type == FocusIn) {
739     if (eventPtr->xfocus.detail != NotifyInferior) {
740     msgPtr->flags |= GOT_FOCUS;
741     if (msgPtr->highlightWidth > 0) {
742     goto redraw;
743     }
744     }
745     } else if (eventPtr->type == FocusOut) {
746     if (eventPtr->xfocus.detail != NotifyInferior) {
747     msgPtr->flags &= ~GOT_FOCUS;
748     if (msgPtr->highlightWidth > 0) {
749     goto redraw;
750     }
751     }
752     }
753     return;
754    
755     redraw:
756     if ((msgPtr->tkwin != NULL) && !(msgPtr->flags & REDRAW_PENDING)) {
757     Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
758     msgPtr->flags |= REDRAW_PENDING;
759     }
760     }
761    
762     /*
763     *----------------------------------------------------------------------
764     *
765     * MessageCmdDeletedProc --
766     *
767     * This procedure is invoked when a widget command is deleted. If
768     * the widget isn't already in the process of being destroyed,
769     * this command destroys it.
770     *
771     * Results:
772     * None.
773     *
774     * Side effects:
775     * The widget is destroyed.
776     *
777     *----------------------------------------------------------------------
778     */
779    
780     static void
781     MessageCmdDeletedProc(clientData)
782     ClientData clientData; /* Pointer to widget record for widget. */
783     {
784     Message *msgPtr = (Message *) clientData;
785     Tk_Window tkwin = msgPtr->tkwin;
786    
787     /*
788     * This procedure could be invoked either because the window was
789     * destroyed and the command was then deleted (in which case tkwin
790     * is NULL) or because the command was deleted, and then this procedure
791     * destroys the widget.
792     */
793    
794     if (tkwin != NULL) {
795     msgPtr->tkwin = NULL;
796     Tk_DestroyWindow(tkwin);
797     }
798     }
799    
800     /*
801     *--------------------------------------------------------------
802     *
803     * MessageTextVarProc --
804     *
805     * This procedure is invoked when someone changes the variable
806     * whose contents are to be displayed in a message.
807     *
808     * Results:
809     * NULL is always returned.
810     *
811     * Side effects:
812     * The text displayed in the message will change to match the
813     * variable.
814     *
815     *--------------------------------------------------------------
816     */
817    
818     /* ARGSUSED */
819     static char *
820     MessageTextVarProc(clientData, interp, name1, name2, flags)
821     ClientData clientData; /* Information about message. */
822     Tcl_Interp *interp; /* Interpreter containing variable. */
823     char *name1; /* Name of variable. */
824     char *name2; /* Second part of variable name. */
825     int flags; /* Information about what happened. */
826     {
827     register Message *msgPtr = (Message *) clientData;
828     char *value;
829    
830     /*
831     * If the variable is unset, then immediately recreate it unless
832     * the whole interpreter is going away.
833     */
834    
835     if (flags & TCL_TRACE_UNSETS) {
836     if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
837     Tcl_SetVar(interp, msgPtr->textVarName, msgPtr->string,
838     TCL_GLOBAL_ONLY);
839     Tcl_TraceVar(interp, msgPtr->textVarName,
840     TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
841     MessageTextVarProc, clientData);
842     }
843     return (char *) NULL;
844     }
845    
846     value = Tcl_GetVar(interp, msgPtr->textVarName, TCL_GLOBAL_ONLY);
847     if (value == NULL) {
848     value = "";
849     }
850     if (msgPtr->string != NULL) {
851     ckfree(msgPtr->string);
852     }
853     msgPtr->numChars = Tcl_NumUtfChars(value, -1);
854     msgPtr->string = (char *) ckalloc((unsigned) (strlen(value) + 1));
855     strcpy(msgPtr->string, value);
856     ComputeMessageGeometry(msgPtr);
857    
858     if ((msgPtr->tkwin != NULL) && Tk_IsMapped(msgPtr->tkwin)
859     && !(msgPtr->flags & REDRAW_PENDING)) {
860     Tcl_DoWhenIdle(DisplayMessage, (ClientData) msgPtr);
861     msgPtr->flags |= REDRAW_PENDING;
862     }
863     return (char *) NULL;
864     }
865    
866 dashley 69 /* End of tkmessage.c */

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25