Annotation of micropolis/src/tk/tkmsg.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * tkMessage.c --
        !             3:  *
        !             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.
        !             7:  *
        !             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.
        !            16:  */
        !            17: 
        !            18: #ifndef lint
        !            19: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkMessage.c,v 1.36 92/06/08 11:06:05 ouster Exp $ SPRITE (Berkeley)";
        !            20: #endif
        !            21: 
        !            22: #include "tkconfig.h"
        !            23: #include "default.h"
        !            24: #include "tkint.h"
        !            25: 
        !            26: /*
        !            27:  * A data structure of the following type is kept for each message
        !            28:  * widget managed by this file:
        !            29:  */
        !            30: 
        !            31: typedef struct {
        !            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
        !            35:                                 * cleaned up.*/
        !            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. */
        !            43: 
        !            44:     /*
        !            45:      * Information used when displaying widget:
        !            46:      */
        !            47: 
        !            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
        !            59:                                 * needed. */
        !            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. */
        !            69: 
        !            70:     /*
        !            71:      * Miscellaneous information:
        !            72:      */
        !            73: 
        !            74:     Cursor cursor;             /* Current cursor for window, or None. */
        !            75:     int flags;                 /* Various flags;  see below for
        !            76:                                 * definitions. */
        !            77: } Message;
        !            78: 
        !            79: /*
        !            80:  * Flag bits for messages:
        !            81:  *
        !            82:  * REDRAW_PENDING:             Non-zero means a DoWhenIdle handler
        !            83:  *                             has already been queued to redraw
        !            84:  *                             this window.
        !            85:  * CLEAR_NEEDED;               Need to clear the window when redrawing.
        !            86:  */
        !            87: 
        !            88: #define REDRAW_PENDING         1
        !            89: #define CLEAR_NEEDED           2
        !            90: 
        !            91: /*
        !            92:  * Information used for argv parsing.
        !            93:  */
        !            94: 
        !            95: 
        !            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),
        !           133:        TK_CONFIG_NULL_OK},
        !           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,
        !           137:        (char *) NULL, 0, 0}
        !           138: };
        !           139: 
        !           140: /*
        !           141:  * Forward declarations for procedures defined later in this file:
        !           142:  */
        !           143: 
        !           144: static void            MessageEventProc _ANSI_ARGS_((ClientData clientData,
        !           145:                            XEvent *eventPtr));
        !           146: static char *          MessageTextVarProc _ANSI_ARGS_((ClientData clientData,
        !           147:                            Tcl_Interp *interp, char *name1, char *name2,
        !           148:                            int flags));
        !           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,
        !           154:                            int flags));
        !           155: static void            DestroyMessage _ANSI_ARGS_((ClientData clientData));
        !           156: static void            DisplayMessage _ANSI_ARGS_((ClientData clientData));
        !           157: 
        !           158: /*
        !           159:  *--------------------------------------------------------------
        !           160:  *
        !           161:  * Tk_MessageCmd --
        !           162:  *
        !           163:  *     This procedure is invoked to process the "message" Tcl
        !           164:  *     command.  See the user documentation for details on what
        !           165:  *     it does.
        !           166:  *
        !           167:  * Results:
        !           168:  *     A standard Tcl result.
        !           169:  *
        !           170:  * Side effects:
        !           171:  *     See the user documentation.
        !           172:  *
        !           173:  *--------------------------------------------------------------
        !           174:  */
        !           175: 
        !           176: int
        !           177: Tk_MessageCmd(clientData, interp, argc, argv)
        !           178:     ClientData clientData;     /* Main window associated with
        !           179:                                 * interpreter. */
        !           180:     Tcl_Interp *interp;                /* Current interpreter. */
        !           181:     int argc;                  /* Number of arguments. */
        !           182:     char **argv;               /* Argument strings. */
        !           183: {
        !           184:     register Message *msgPtr;
        !           185:     Tk_Window new;
        !           186:     Tk_Window tkwin = (Tk_Window) clientData;
        !           187: 
        !           188:     if (argc < 2) {
        !           189:        Tcl_AppendResult(interp, "wrong # args:  should be \"",
        !           190:                argv[0], " pathName ?options?\"", (char *) NULL);
        !           191:        return TCL_ERROR;
        !           192:     }
        !           193: 
        !           194:     new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
        !           195:     if (new == NULL) {
        !           196:        return TCL_ERROR;
        !           197:     }
        !           198: 
        !           199:     msgPtr = (Message *) ckalloc(sizeof(Message));
        !           200:     msgPtr->tkwin = new;
        !           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;
        !           210:     msgPtr->padX = 0;
        !           211:     msgPtr->padY = 0;
        !           212:     msgPtr->width = 0;
        !           213:     msgPtr->aspect = 150;
        !           214:     msgPtr->justify = TK_JUSTIFY_LEFT;
        !           215:     msgPtr->cursor = None;
        !           216:     msgPtr->flags = 0;
        !           217: 
        !           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) {
        !           224:        goto error;
        !           225:     }
        !           226: 
        !           227:     interp->result = Tk_PathName(msgPtr->tkwin);
        !           228:     return TCL_OK;
        !           229: 
        !           230:     error:
        !           231:     Tk_DestroyWindow(msgPtr->tkwin);
        !           232:     return TCL_ERROR;
        !           233: }
        !           234: 
        !           235: /*
        !           236:  *--------------------------------------------------------------
        !           237:  *
        !           238:  * MessageWidgetCmd --
        !           239:  *
        !           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.
        !           243:  *
        !           244:  * Results:
        !           245:  *     A standard Tcl result.
        !           246:  *
        !           247:  * Side effects:
        !           248:  *     See the user documentation.
        !           249:  *
        !           250:  *--------------------------------------------------------------
        !           251:  */
        !           252: 
        !           253: static int
        !           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. */
        !           259: {
        !           260:     register Message *msgPtr = (Message *) clientData;
        !           261:     int length;
        !           262:     char c;
        !           263: 
        !           264:     if (argc < 2) {
        !           265:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           266:                " option ?arg arg ...?\"", (char *) NULL);
        !           267:        return TCL_ERROR;
        !           268:     }
        !           269:     c = argv[1][0];
        !           270:     length = strlen(argv[1]);
        !           271:     if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
        !           272:        if (argc == 2) {
        !           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);
        !           278:        } else {
        !           279:            return ConfigureMessage(interp, msgPtr, argc-2, argv+2,
        !           280:                    TK_CONFIG_ARGV_ONLY);
        !           281:        }
        !           282:     } else {
        !           283:        Tcl_AppendResult(interp, "bad option \"", argv[1],
        !           284:                "\":  must be configure", (char *) NULL);
        !           285:        return TCL_ERROR;
        !           286:     }
        !           287: }
        !           288: 
        !           289: /*
        !           290:  *----------------------------------------------------------------------
        !           291:  *
        !           292:  * DestroyMessage --
        !           293:  *
        !           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).
        !           297:  *
        !           298:  * Results:
        !           299:  *     None.
        !           300:  *
        !           301:  * Side effects:
        !           302:  *     Everything associated with the message is freed up.
        !           303:  *
        !           304:  *----------------------------------------------------------------------
        !           305:  */
        !           306: 
        !           307: static void
        !           308: DestroyMessage(clientData)
        !           309:     ClientData clientData;     /* Info about message widget. */
        !           310: {
        !           311:     register Message *msgPtr = (Message *) clientData;
        !           312: 
        !           313:     if (msgPtr->string != NULL) {
        !           314:        ckfree(msgPtr->string);
        !           315:     }
        !           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);
        !           321:     }
        !           322:     if (msgPtr->border != NULL) {
        !           323:        Tk_Free3DBorder(msgPtr->border);
        !           324:     }
        !           325:     if (msgPtr->fontPtr != NULL) {
        !           326:        Tk_FreeFontStruct(msgPtr->fontPtr);
        !           327:     }
        !           328:     if (msgPtr->fgColorPtr != NULL) {
        !           329:        Tk_FreeColor(msgPtr->fgColorPtr);
        !           330:     }
        !           331:     if (msgPtr->textGC != None) {
        !           332:        Tk_FreeGC(msgPtr->textGC);
        !           333:     }
        !           334:     if (msgPtr->cursor != None) {
        !           335:        Tk_FreeCursor(msgPtr->cursor);
        !           336:     }
        !           337:     ckfree((char *) msgPtr);
        !           338: }
        !           339: 
        !           340: /*
        !           341:  *----------------------------------------------------------------------
        !           342:  *
        !           343:  * ConfigureMessage --
        !           344:  *
        !           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.
        !           348:  *
        !           349:  * Results:
        !           350:  *     The return value is a standard Tcl result.  If TCL_ERROR is
        !           351:  *     returned, then interp->result contains an error message.
        !           352:  *
        !           353:  * Side effects:
        !           354:  *     Configuration information, such as text string, colors, font,
        !           355:  *     etc. get set for msgPtr;  old resources get freed, if there
        !           356:  *     were any.
        !           357:  *
        !           358:  *----------------------------------------------------------------------
        !           359:  */
        !           360: 
        !           361: static int
        !           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. */
        !           369: {
        !           370:     XGCValues gcValues;
        !           371:     GC newGC;
        !           372: 
        !           373:     /*
        !           374:      * Eliminate any existing trace on a variable monitored by the message.
        !           375:      */
        !           376: 
        !           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);
        !           381:     }
        !           382: 
        !           383:     if (Tk_ConfigureWidget(interp, msgPtr->tkwin, configSpecs,
        !           384:            argc, argv, (char *) msgPtr, flags) != TCL_OK) {
        !           385:        return TCL_ERROR;
        !           386:     }
        !           387: 
        !           388:     /*
        !           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.
        !           392:      */
        !           393: 
        !           394:     if (msgPtr->textVarName != NULL) {
        !           395:        char *value;
        !           396: 
        !           397:        value = Tcl_GetVar(interp, msgPtr->textVarName, TCL_GLOBAL_ONLY);
        !           398:        if (value == NULL) {
        !           399:            Tcl_SetVar(interp, msgPtr->textVarName, msgPtr->string,
        !           400:                    TCL_GLOBAL_ONLY);
        !           401:        } else {
        !           402:            if (msgPtr->string != NULL) {
        !           403:                ckfree(msgPtr->string);
        !           404:            }
        !           405:            msgPtr->string = ckalloc((unsigned) (strlen(value) + 1));
        !           406:            strcpy(msgPtr->string, value);
        !           407:        }
        !           408:        Tcl_TraceVar(interp, msgPtr->textVarName,
        !           409:                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
        !           410:                MessageTextVarProc, (ClientData) msgPtr);
        !           411:     }
        !           412: 
        !           413:     /*
        !           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.
        !           417:      */
        !           418: 
        !           419:     msgPtr->numChars = strlen(msgPtr->string);
        !           420: 
        !           421:     Tk_SetBackgroundFromBorder(msgPtr->tkwin, msgPtr->border);
        !           422: 
        !           423:     gcValues.font = msgPtr->fontPtr->fid;
        !           424:     gcValues.foreground = msgPtr->fgColorPtr->pixel;
        !           425:     newGC = Tk_GetGC(msgPtr->tkwin, GCForeground|GCFont,
        !           426:            &gcValues);
        !           427:     if (msgPtr->textGC != None) {
        !           428:        Tk_FreeGC(msgPtr->textGC);
        !           429:     }
        !           430:     msgPtr->textGC = newGC;
        !           431: 
        !           432:     if (msgPtr->padX == -1) {
        !           433:        msgPtr->padX = msgPtr->fontPtr->ascent/2;
        !           434:     }
        !           435: 
        !           436:     if (msgPtr->padY == -1) {
        !           437:        msgPtr->padY = msgPtr->fontPtr->ascent/4;
        !           438:     }
        !           439: 
        !           440:     if (msgPtr->justify == TK_JUSTIFY_FILL) {
        !           441:        interp->result = "can't use \"fill\" justify style in messages";
        !           442:        return TCL_ERROR;
        !           443:     }
        !           444: 
        !           445:     /*
        !           446:      * Recompute the desired geometry for the window, and arrange for
        !           447:      * the window to be redisplayed.
        !           448:      */
        !           449: 
        !           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;
        !           455:     }
        !           456: 
        !           457:     return TCL_OK;
        !           458: }
        !           459: 
        !           460: /*
        !           461:  *--------------------------------------------------------------
        !           462:  *
        !           463:  * ComputeMessageGeometry --
        !           464:  *
        !           465:  *     Compute the desired geometry for a message window,
        !           466:  *     taking into account the desired aspect ratio for the
        !           467:  *     window.
        !           468:  *
        !           469:  * Results:
        !           470:  *     None.
        !           471:  *
        !           472:  * Side effects:
        !           473:  *     Tk_GeometryRequest is called to inform the geometry
        !           474:  *     manager of the desired geometry for this window.
        !           475:  *
        !           476:  *--------------------------------------------------------------
        !           477:  */
        !           478: 
        !           479: static void
        !           480: ComputeMessageGeometry(msgPtr)
        !           481:     register Message *msgPtr;  /* Information about window. */
        !           482: {
        !           483:     char *p;
        !           484:     int width, inc, height, numLines;
        !           485:     int thisWidth, maxWidth;
        !           486:     int aspect, lowerBound, upperBound;
        !           487: 
        !           488:     /*
        !           489:      * Compute acceptable bounds for the final aspect ratio.
        !           490:      */
        !           491:     aspect = msgPtr->aspect/10;
        !           492:     if (aspect < 5) {
        !           493:        aspect = 5;
        !           494:     }
        !           495:     lowerBound = msgPtr->aspect - aspect;
        !           496:     upperBound = msgPtr->aspect + aspect;
        !           497: 
        !           498:     /*
        !           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.
        !           505:      */
        !           506: 
        !           507:     if (msgPtr->width > 0) {
        !           508:        width = msgPtr->width;
        !           509:        inc = 0;
        !           510:     } else {
        !           511:        width = WidthOfScreen(Tk_Screen(msgPtr->tkwin))/2;
        !           512:        inc = width/2;
        !           513:     }
        !           514:     for ( ; ; inc /= 2) {
        !           515:        maxWidth = 0;
        !           516:        for (numLines = 1, p = msgPtr->string; ; numLines++)  {
        !           517:            if (*p == '\n') {
        !           518:                p++;
        !           519:                continue;
        !           520:            }
        !           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;
        !           526:            }
        !           527:            if (*p == 0) {
        !           528:                break;
        !           529:            }
        !           530: 
        !           531:            /*
        !           532:             * Skip spaces and tabs at the beginning of a line, unless
        !           533:             * they follow a user-requested newline.
        !           534:             */
        !           535: 
        !           536:            while (isspace(*p)) {
        !           537:                if (*p == '\n') {
        !           538:                    p++;
        !           539:                    break;
        !           540:                }
        !           541:                p++;
        !           542:            }
        !           543:        }
        !           544: 
        !           545:        height = numLines * (msgPtr->fontPtr->ascent
        !           546:                + msgPtr->fontPtr->descent) + 2*msgPtr->borderWidth
        !           547:                + 2*msgPtr->padY;
        !           548:        if (inc <= 2) {
        !           549:            break;
        !           550:        }
        !           551:        aspect = (100*(maxWidth + 2*msgPtr->borderWidth
        !           552:                + 2*msgPtr->padX))/height;
        !           553:        if (aspect < lowerBound) {
        !           554:            width += inc;
        !           555:        } else if (aspect > upperBound) {
        !           556:            width -= inc;
        !           557:        } else {
        !           558:            break;
        !           559:        }
        !           560:     }
        !           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);
        !           567: }
        !           568: 
        !           569: /*
        !           570:  *--------------------------------------------------------------
        !           571:  *
        !           572:  * DisplayMessage --
        !           573:  *
        !           574:  *     This procedure redraws the contents of a message window.
        !           575:  *
        !           576:  * Results:
        !           577:  *     None.
        !           578:  *
        !           579:  * Side effects:
        !           580:  *     Information appears on the screen.
        !           581:  *
        !           582:  *--------------------------------------------------------------
        !           583:  */
        !           584: 
        !           585: static void
        !           586: DisplayMessage(clientData)
        !           587:     ClientData clientData;     /* Information about window. */
        !           588: {
        !           589:     register Message *msgPtr = (Message *) clientData;
        !           590:     register Tk_Window tkwin = msgPtr->tkwin;
        !           591:     char *p;
        !           592:     int x, y, lineLength, numChars, charsLeft;
        !           593: 
        !           594:     msgPtr->flags &= ~REDRAW_PENDING;
        !           595:     if ((msgPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
        !           596:        return;
        !           597:     }
        !           598:     if (msgPtr->flags & CLEAR_NEEDED) {
        !           599:        XClearWindow(Tk_Display(tkwin), Tk_WindowId(tkwin));
        !           600:        msgPtr->flags &= ~CLEAR_NEEDED;
        !           601:     }
        !           602: 
        !           603:     /*
        !           604:      * Compute starting y-location for message based on message size
        !           605:      * and anchor option.
        !           606:      */
        !           607: 
        !           608:     switch (msgPtr->anchor) {
        !           609:        case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE:
        !           610:            y = msgPtr->borderWidth + msgPtr->padY;
        !           611:            break;
        !           612:        case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E:
        !           613:            y = (Tk_Height(tkwin) - msgPtr->msgHeight)/2;
        !           614:            break;
        !           615:        default:
        !           616:            y = Tk_Height(tkwin) - msgPtr->borderWidth - msgPtr->padY
        !           617:                    - msgPtr->msgHeight;
        !           618:            break;
        !           619:     }
        !           620:     y += msgPtr->fontPtr->ascent;
        !           621: 
        !           622:     /*
        !           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.
        !           627:      */
        !           628: 
        !           629:     for (p = msgPtr->string, charsLeft = msgPtr->numChars; *p != 0;
        !           630:            y += msgPtr->fontPtr->ascent + msgPtr->fontPtr->descent) {
        !           631:        if (*p == '\n') {
        !           632:            p++;
        !           633:            charsLeft--;
        !           634:            continue;
        !           635:        }
        !           636:        numChars = TkMeasureChars(msgPtr->fontPtr, p, charsLeft, 0,
        !           637:                msgPtr->lineLength, TK_WHOLE_WORDS|TK_AT_LEAST_ONE,
        !           638:                &lineLength);
        !           639:        switch (msgPtr->anchor) {
        !           640:            case TK_ANCHOR_NW: case TK_ANCHOR_W: case TK_ANCHOR_SW:
        !           641:                x = msgPtr->borderWidth + msgPtr->padX;
        !           642:                break;
        !           643:            case TK_ANCHOR_N: case TK_ANCHOR_CENTER: case TK_ANCHOR_S:
        !           644:                x = (Tk_Width(tkwin) - msgPtr->lineLength)/2;
        !           645:                break;
        !           646:            default:
        !           647:                x = Tk_Width(tkwin) - msgPtr->borderWidth - msgPtr->padX
        !           648:                        - msgPtr->lineLength;
        !           649:                break;
        !           650:        }
        !           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;
        !           655:        }
        !           656:        TkDisplayChars(Tk_Display(tkwin), Tk_WindowId(tkwin),
        !           657:                msgPtr->textGC, msgPtr->fontPtr, p, numChars, x, y, 0);
        !           658:        p += numChars;
        !           659:        charsLeft -= numChars;
        !           660: 
        !           661:        /*
        !           662:         * Skip blanks at the beginning of a line, unless they follow
        !           663:         * a user-requested newline.
        !           664:         */
        !           665: 
        !           666:        while (isspace(*p)) {
        !           667:            charsLeft--;
        !           668:            if (*p == '\n') {
        !           669:                p++;
        !           670:                break;
        !           671:            }
        !           672:            p++;
        !           673:        }
        !           674:     }
        !           675: 
        !           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);
        !           680:     }
        !           681: }
        !           682: 
        !           683: /*
        !           684:  *--------------------------------------------------------------
        !           685:  *
        !           686:  * MessageEventProc --
        !           687:  *
        !           688:  *     This procedure is invoked by the Tk dispatcher for various
        !           689:  *     events on messages.
        !           690:  *
        !           691:  * Results:
        !           692:  *     None.
        !           693:  *
        !           694:  * Side effects:
        !           695:  *     When the window gets deleted, internal structures get
        !           696:  *     cleaned up.  When it gets exposed, it is redisplayed.
        !           697:  *
        !           698:  *--------------------------------------------------------------
        !           699:  */
        !           700: 
        !           701: static void
        !           702: MessageEventProc(clientData, eventPtr)
        !           703:     ClientData clientData;     /* Information about window. */
        !           704:     XEvent *eventPtr;          /* Information about event. */
        !           705: {
        !           706:     Message *msgPtr = (Message *) clientData;
        !           707: 
        !           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;
        !           712:        }
        !           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);
        !           718:        }
        !           719:        Tk_EventuallyFree((ClientData) msgPtr, DestroyMessage);
        !           720:     }
        !           721: }
        !           722: 
        !           723: /*
        !           724:  *--------------------------------------------------------------
        !           725:  *
        !           726:  * MessageTextVarProc --
        !           727:  *
        !           728:  *     This procedure is invoked when someone changes the variable
        !           729:  *     whose contents are to be displayed in a message.
        !           730:  *
        !           731:  * Results:
        !           732:  *     NULL is always returned.
        !           733:  *
        !           734:  * Side effects:
        !           735:  *     The text displayed in the message will change to match the
        !           736:  *     variable.
        !           737:  *
        !           738:  *--------------------------------------------------------------
        !           739:  */
        !           740: 
        !           741:        /* ARGSUSED */
        !           742: static char *
        !           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. */
        !           749: {
        !           750:     register Message *msgPtr = (Message *) clientData;
        !           751:     char *value;
        !           752: 
        !           753:     /*
        !           754:      * If the variable is unset, then immediately recreate it unless
        !           755:      * the whole interpreter is going away.
        !           756:      */
        !           757: 
        !           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);
        !           765:        }
        !           766:        return (char *) NULL;
        !           767:     }
        !           768: 
        !           769:     value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY);
        !           770:     if (value == NULL) {
        !           771:        value = "";
        !           772:     }
        !           773:     if (msgPtr->string != NULL) {
        !           774:        ckfree(msgPtr->string);
        !           775:     }
        !           776:     msgPtr->numChars = strlen(value);
        !           777:     msgPtr->string = ckalloc((unsigned) (msgPtr->numChars + 1));
        !           778:     strcpy(msgPtr->string, value);
        !           779:     ComputeMessageGeometry(msgPtr);
        !           780: 
        !           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;
        !           786:     }
        !           787:     return (char *) NULL;
        !           788: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.