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

1.1     ! root        1: /* 
        !             2:  * tkPack.c --
        !             3:  *
        !             4:  *     This file contains code to implement the "packer"
        !             5:  *     geometry manager for Tk.
        !             6:  *
        !             7:  * Copyright 1990 Regents of the University of California.
        !             8:  * Permission to use, copy, modify, and distribute this
        !             9:  * software and its documentation for any purpose and without
        !            10:  * fee is hereby granted, provided that the above copyright
        !            11:  * notice appear in all copies.  The University of California
        !            12:  * makes no representations about the suitability of this
        !            13:  * software for any purpose.  It is provided "as is" without
        !            14:  * express or implied warranty.
        !            15:  */
        !            16: 
        !            17: #ifndef lint
        !            18: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkPack.c,v 1.27 92/01/04 15:16:41 ouster Exp $ SPRITE (Berkeley)";
        !            19: #endif
        !            20: 
        !            21: #include "tkconfig.h"
        !            22: #include "tkint.h"
        !            23: 
        !            24: typedef enum {TOP, BOTTOM, LEFT, RIGHT} Side;
        !            25: 
        !            26: /* For each window that the packer cares about (either because
        !            27:  * the window is managed by the packer or because the window
        !            28:  * has children that are managed by the packer), there is a
        !            29:  * structure of the following type:
        !            30:  */
        !            31: 
        !            32: typedef struct Packer {
        !            33:     Tk_Window tkwin;           /* Tk token for window.  NULL means that
        !            34:                                 * the window has been deleted, but the
        !            35:                                 * packet hasn't had a chance to clean up
        !            36:                                 * yet because the structure is still in
        !            37:                                 * use. */
        !            38:     struct Packer *parentPtr;  /* Parent within which this window
        !            39:                                 * is packed (NULL means this window
        !            40:                                 * isn't managed by the packer). */
        !            41:     struct Packer *nextPtr;    /* Next window packed within same
        !            42:                                 * parent.  List is priority-ordered:
        !            43:                                 * first on list gets packed first. */
        !            44:     struct Packer *childPtr;   /* First in list of children packed
        !            45:                                 * inside this window (NULL means
        !            46:                                 * no packed children). */
        !            47:     Side side;                 /* Side of parent against which
        !            48:                                 * this window is packed. */
        !            49:     Tk_Anchor anchorPoint;     /* If frame allocated for window is larger
        !            50:                                 * than window needs, this indicates how
        !            51:                                 * where to position window in frame. */
        !            52:     int padX, padY;            /* Additional amounts of space to give window
        !            53:                                 * besides what it asked for. */
        !            54:     int doubleBw;              /* Twice the window's last known border
        !            55:                                 * width.  If this changes, the window
        !            56:                                 * must be repacked within its parent. */
        !            57:     int *abortPtr;             /* If non-NULL, it means that there is a nested
        !            58:                                 * call to ArrangePacking already working on
        !            59:                                 * this window.  *abortPtr may be set to 1 to
        !            60:                                 * abort that nested call.  This happens, for
        !            61:                                 * example, if tkwin or any of its children
        !            62:                                 * is deleted. */
        !            63:     int flags;                 /* Miscellaneous flags;  see below
        !            64:                                 * for definitions. */
        !            65: } Packer;
        !            66: 
        !            67: /*
        !            68:  * Flag values for Packer structures:
        !            69:  *
        !            70:  * REQUESTED_REPACK:           1 means a Tk_DoWhenIdle request
        !            71:  *                             has already been made to repack
        !            72:  *                             all the children of this window.
        !            73:  * FILLX:                      1 means if frame allocated for window
        !            74:  *                             is wider than window needs, expand window
        !            75:  *                             to fill frame.  0 means don't make window
        !            76:  *                             any larger than needed.
        !            77:  * FILLY:                      Same as FILLX, except for height.
        !            78:  * EXPAND:                     1 means this window's frame will absorb any
        !            79:  *                             extra space in the parent window.
        !            80:  */
        !            81: 
        !            82: #define REQUESTED_REPACK       1
        !            83: #define FILLX                  2
        !            84: #define FILLY                  4
        !            85: #define EXPAND                 8
        !            86: 
        !            87: /*
        !            88:  * Hash table used to map from Tk_Window tokens to corresponding
        !            89:  * Packer structures:
        !            90:  */
        !            91: 
        !            92: static Tcl_HashTable packerHashTable;
        !            93: 
        !            94: /*
        !            95:  * Have statics in this module been initialized?
        !            96:  */
        !            97: 
        !            98: static initialized = 0;
        !            99: 
        !           100: /*
        !           101:  * Forward declarations for procedures defined later in this file:
        !           102:  */
        !           103: 
        !           104: static void            ArrangePacking _ANSI_ARGS_((ClientData clientData));
        !           105: static Packer *                GetPacker _ANSI_ARGS_((Tk_Window tkwin));
        !           106: static int             PackAfter _ANSI_ARGS_((Tcl_Interp *interp,
        !           107:                            Packer *prevPtr, Packer *parentPtr, int argc,
        !           108:                            char **argv));
        !           109: static void            PackReqProc _ANSI_ARGS_((ClientData clientData,
        !           110:                            Tk_Window tkwin));
        !           111: static void            PackStructureProc _ANSI_ARGS_((ClientData clientData,
        !           112:                            XEvent *eventPtr));
        !           113: static void            Unlink _ANSI_ARGS_((Packer *packPtr));
        !           114: 
        !           115: /*
        !           116:  *--------------------------------------------------------------
        !           117:  *
        !           118:  * Tk_PackCmd --
        !           119:  *
        !           120:  *     This procedure is invoked to process the "pack" Tcl command.
        !           121:  *     See the user documentation for details on what it does.
        !           122:  *
        !           123:  * Results:
        !           124:  *     A standard Tcl result.
        !           125:  *
        !           126:  * Side effects:
        !           127:  *     See the user documentation.
        !           128:  *
        !           129:  *--------------------------------------------------------------
        !           130:  */
        !           131: 
        !           132: int
        !           133: Tk_PackCmd(clientData, interp, argc, argv)
        !           134:     ClientData clientData;     /* Main window associated with
        !           135:                                 * interpreter. */
        !           136:     Tcl_Interp *interp;                /* Current interpreter. */
        !           137:     int argc;                  /* Number of arguments. */
        !           138:     char **argv;               /* Argument strings. */
        !           139: {
        !           140:     Tk_Window tkwin = (Tk_Window) clientData;
        !           141:     int length;
        !           142:     char c;
        !           143: 
        !           144:     if (argc < 3) {
        !           145:        Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           146:                argv[0], " option arg ?arg ...?\"", (char *) NULL);
        !           147:        return TCL_ERROR;
        !           148:     }
        !           149:     c = argv[1][0];
        !           150:     length = strlen(argv[1]);
        !           151:     if ((c == 'a') && (length >= 2)
        !           152:            && (strncmp(argv[1], "after", length) == 0)) {
        !           153:        Packer *prevPtr;
        !           154:        Tk_Window tkwin2;
        !           155: 
        !           156:        tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
        !           157:        if (tkwin2 == NULL) {
        !           158:            return TCL_ERROR;
        !           159:        }
        !           160:        prevPtr = GetPacker(tkwin2);
        !           161:        if (prevPtr->parentPtr == NULL) {
        !           162:            Tcl_AppendResult(interp, "window \"", argv[2],
        !           163:                    "\" isn't packed", (char *) NULL);
        !           164:            return TCL_ERROR;
        !           165:        }
        !           166:        return PackAfter(interp, prevPtr, prevPtr->parentPtr, argc-3, argv+3);
        !           167:     } else if ((c == 'a') && (length >= 2)
        !           168:            && (strncmp(argv[1], "append", length) == 0)) {
        !           169:        Packer *parentPtr;
        !           170:        register Packer *prevPtr;
        !           171:        Tk_Window tkwin2;
        !           172: 
        !           173:        tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
        !           174:        if (tkwin2 == NULL) {
        !           175:            return TCL_ERROR;
        !           176:        }
        !           177:        parentPtr = GetPacker(tkwin2);
        !           178:        prevPtr = parentPtr->childPtr;
        !           179:        if (prevPtr != NULL) {
        !           180:            while (prevPtr->nextPtr != NULL) {
        !           181:                prevPtr = prevPtr->nextPtr;
        !           182:            }
        !           183:        }
        !           184:        return PackAfter(interp, prevPtr, parentPtr, argc-3, argv+3);
        !           185:     } else if ((c == 'b') && (strncmp(argv[1], "before", length) == 0)) {
        !           186:        Packer *packPtr, *parentPtr;
        !           187:        register Packer *prevPtr;
        !           188:        Tk_Window tkwin2;
        !           189: 
        !           190:        tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
        !           191:        if (tkwin2 == NULL) {
        !           192:            return TCL_ERROR;
        !           193:        }
        !           194:        packPtr = GetPacker(tkwin2);
        !           195:        if (packPtr->parentPtr == NULL) {
        !           196:            Tcl_AppendResult(interp, "window \"", argv[2],
        !           197:                    "\" isn't packed", (char *) NULL);
        !           198:            return TCL_ERROR;
        !           199:        }
        !           200:        parentPtr = packPtr->parentPtr;
        !           201:        prevPtr = parentPtr->childPtr;
        !           202:        if (prevPtr == packPtr) {
        !           203:            prevPtr = NULL;
        !           204:        } else {
        !           205:            for ( ; ; prevPtr = prevPtr->nextPtr) {
        !           206:                if (prevPtr == NULL) {
        !           207:                    panic("\"pack before\" couldn't find predecessor");
        !           208:                }
        !           209:                if (prevPtr->nextPtr == packPtr) {
        !           210:                    break;
        !           211:                }
        !           212:            }
        !           213:        }
        !           214:        return PackAfter(interp, prevPtr, parentPtr, argc-3, argv+3);
        !           215:     } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {
        !           216:        char *prefix;
        !           217:        register Packer *packPtr;
        !           218:        Tk_Window tkwin2;
        !           219:        char tmp[20];
        !           220:        static char *sideNames[] = {"top", "bottom", "left", "right"};
        !           221: 
        !           222:        if (argc != 3) {
        !           223:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           224:                    argv[0], " info window\"", (char *) NULL);
        !           225:            return TCL_ERROR;
        !           226:        }
        !           227:        tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
        !           228:        if (tkwin2 == NULL) {
        !           229:            return TCL_ERROR;
        !           230:        }
        !           231:        packPtr = GetPacker(tkwin2);
        !           232:        prefix = "";
        !           233:        for (packPtr = packPtr->childPtr; packPtr != NULL;
        !           234:                packPtr = packPtr->nextPtr) {
        !           235:            Tcl_AppendResult(interp, prefix, Tk_PathName(packPtr->tkwin),
        !           236:                    " {", sideNames[(int) packPtr->side],
        !           237:                    " frame ", Tk_NameOfAnchor(packPtr->anchorPoint),
        !           238:                    (char *) NULL);
        !           239:            if (packPtr->padX != 0) {
        !           240:                sprintf(tmp, "%d", packPtr->padX);
        !           241:                Tcl_AppendResult(interp, " padx ", tmp, (char *) NULL);
        !           242:            }
        !           243:            if (packPtr->padY != 0) {
        !           244:                sprintf(tmp, "%d", packPtr->padY);
        !           245:                Tcl_AppendResult(interp, " pady ", tmp, (char *) NULL);
        !           246:            }
        !           247:            if (packPtr->flags & EXPAND) {
        !           248:                Tcl_AppendResult(interp, " expand", (char *) NULL);
        !           249:            }
        !           250:            if ((packPtr->flags & (FILLX|FILLY)) == (FILLX|FILLY)) {
        !           251:                Tcl_AppendResult(interp, " fill", (char *) NULL);
        !           252:            } else if (packPtr->flags & FILLX) {
        !           253:                Tcl_AppendResult(interp, " fillx", (char *) NULL);
        !           254:            } else if (packPtr->flags & FILLY) {
        !           255:                Tcl_AppendResult(interp, " filly", (char *) NULL);
        !           256:            }
        !           257:            Tcl_AppendResult(interp, "}", (char *) NULL);
        !           258:            prefix = " ";
        !           259:        }
        !           260:        return TCL_OK;
        !           261:     } else if ((c == 'u') && (strncmp(argv[1], "unpack", length) == 0)) {
        !           262:        Tk_Window tkwin2;
        !           263:        Packer *packPtr;
        !           264: 
        !           265:        if (argc != 3) {
        !           266:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           267:                    argv[0], " unpack window\"", (char *) NULL);
        !           268:            return TCL_ERROR;
        !           269:        }
        !           270:        tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
        !           271:        if (tkwin2 == NULL) {
        !           272:            return TCL_ERROR;
        !           273:        }
        !           274:        packPtr = GetPacker(tkwin2);
        !           275:        if ((packPtr != NULL) && (packPtr->parentPtr != NULL)) {
        !           276:            Tk_ManageGeometry(tkwin2, (Tk_GeometryProc *) NULL,
        !           277:                    (ClientData) NULL);
        !           278:            Unlink(packPtr);
        !           279:            Tk_UnmapWindow(packPtr->tkwin);
        !           280:        }
        !           281:     } else {
        !           282:        Tcl_AppendResult(interp, "bad option \"", argv[1],
        !           283:                "\":  must be after, append, before, or info", (char *) NULL);
        !           284:        return TCL_ERROR;
        !           285:     }
        !           286:     return TCL_OK;
        !           287: }
        !           288: 
        !           289: /*
        !           290:  *--------------------------------------------------------------
        !           291:  *
        !           292:  * PackReqProc --
        !           293:  *
        !           294:  *     This procedure is invoked by Tk_GeometryRequest for
        !           295:  *     windows managed by the packer.
        !           296:  *
        !           297:  * Results:
        !           298:  *     None.
        !           299:  *
        !           300:  * Side effects:
        !           301:  *     Arranges for tkwin, and all its managed siblings, to
        !           302:  *     be re-packed at the next idle point.
        !           303:  *
        !           304:  *--------------------------------------------------------------
        !           305:  */
        !           306: 
        !           307:        /* ARGSUSED */
        !           308: static void
        !           309: PackReqProc(clientData, tkwin)
        !           310:     ClientData clientData;     /* Packer's information about
        !           311:                                 * window that got new preferred
        !           312:                                 * geometry.  */
        !           313:     Tk_Window tkwin;           /* Other Tk-related information
        !           314:                                 * about the window. */
        !           315: {
        !           316:     register Packer *packPtr = (Packer *) clientData;
        !           317: 
        !           318:     packPtr = packPtr->parentPtr;
        !           319:     if (!(packPtr->flags & REQUESTED_REPACK)) {
        !           320:        packPtr->flags |= REQUESTED_REPACK;
        !           321:        Tk_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
        !           322:     }
        !           323: }
        !           324: 
        !           325: /*
        !           326:  *--------------------------------------------------------------
        !           327:  *
        !           328:  * ArrangePacking --
        !           329:  *
        !           330:  *     This procedure is invoked (using the Tk_DoWhenIdle
        !           331:  *     mechanism) to re-layout a set of windows managed by
        !           332:  *     the packer.  It is invoked at idle time so that a
        !           333:  *     series of packer requests can be merged into a single
        !           334:  *     layout operation.
        !           335:  *
        !           336:  * Results:
        !           337:  *     None.
        !           338:  *
        !           339:  * Side effects:
        !           340:  *     The packed children of parentPtr may get resized or
        !           341:  *     moved.
        !           342:  *
        !           343:  *--------------------------------------------------------------
        !           344:  */
        !           345: 
        !           346: static void
        !           347: ArrangePacking(clientData)
        !           348:     ClientData clientData;     /* Structure describing parent
        !           349:                                 * whose children are to be
        !           350:                                 * re-layed out. */
        !           351: {
        !           352:     register Packer *parentPtr = (Packer *) clientData;
        !           353:     register Packer *childPtr; 
        !           354:     int numExpX, numExpY;      /* # of windows that are expandable in
        !           355:                                 * each direction. */
        !           356:     int spareX, spareY;                /* Amount of extra space to give to each
        !           357:                                 * expandable window. */
        !           358:     int leftOverX, leftOverY;  /* Extra chunk of space to give to last
        !           359:                                 * expandable window. */
        !           360:     int cavityX, cavityY, cavityWidth, cavityHeight;
        !           361:                                /* These variables keep track of the
        !           362:                                 * as-yet-unallocated space remaining in
        !           363:                                 * the middle of the parent window. */
        !           364:     int frameX, frameY, frameWidth, frameHeight;
        !           365:                                /* These variables keep track of the frame
        !           366:                                 * allocated to the current window. */
        !           367:     int x, y, width, height;   /* These variables are used to hold the
        !           368:                                 * actual geometry of the current window. */
        !           369:     int intBWidth;             /* Width of internal border in parent window,
        !           370:                                 * if any. */
        !           371:     int abort;                 /* May get set to non-zero to abort this
        !           372:                                 * repacking operation. */
        !           373:     int maxWidth, maxHeight, tmp;
        !           374: 
        !           375:     parentPtr->flags &= ~REQUESTED_REPACK;
        !           376: 
        !           377:     /*
        !           378:      * If the parent has no children anymore, then don't do anything
        !           379:      * at all:  just leave the parent's size as-is.
        !           380:      */
        !           381: 
        !           382:     if (parentPtr->childPtr == NULL) {
        !           383:        return;
        !           384:     }
        !           385: 
        !           386:     /*
        !           387:      * Abort any nested call to ArrangePacking for this window, since
        !           388:      * we'll do everything necessary here, and set up so this call
        !           389:      * can be aborted if necessary.  
        !           390:      */
        !           391: 
        !           392:     if (parentPtr->abortPtr != NULL) {
        !           393:        *parentPtr->abortPtr = 1;
        !           394:     }
        !           395:     parentPtr->abortPtr = &abort;
        !           396:     abort = 0;
        !           397:     Tk_Preserve((ClientData) parentPtr);
        !           398: 
        !           399:     /*
        !           400:      * Pass #1: scan all the children to figure out the total amount
        !           401:      * of space needed.  Two separate widths and heights are computed.
        !           402:      *
        !           403:      * "Width" and "height" compute the minimum parent size to meet
        !           404:      * the needs of each window in the direction "where there is
        !           405:      * flexibility".  For example, if a child is packed TOP, then
        !           406:      * y is the flexible direction:  the child's requested height
        !           407:      * will determine its size.  For this window x is the inflexible
        !           408:      * direction:  the window's width will be determined by the amount
        !           409:      * of space left in the parent's cavity, not by the window's
        !           410:      * requested width.  "Width" and "height" are needed in order to
        !           411:      * compute how much extra space there is, so that it can be divided
        !           412:      * among the windows that have the EXPAND flag.
        !           413:      *
        !           414:      * "MaxWidth" and "maxHeight" compute the minimum parent size to
        !           415:      * meet all the needs of every window in both directions, flexible
        !           416:      * or inflexible.  These values are needed to make geometry requests
        !           417:      * of the parent's parent.
        !           418:      */
        !           419: 
        !           420:     intBWidth = Tk_InternalBorderWidth(parentPtr->tkwin);
        !           421:     width = height = maxWidth = maxHeight = 2*intBWidth;
        !           422:     numExpX = numExpY = 0;
        !           423:     for (childPtr = parentPtr->childPtr; childPtr != NULL;
        !           424:            childPtr = childPtr->nextPtr) {
        !           425:        if ((childPtr->side == TOP) || (childPtr->side == BOTTOM)) {
        !           426:            tmp = Tk_ReqWidth(childPtr->tkwin) + childPtr->doubleBw
        !           427:                    + childPtr->padX + width;
        !           428:            if (tmp > maxWidth) {
        !           429:                maxWidth = tmp;
        !           430:            }
        !           431:            height += Tk_ReqHeight(childPtr->tkwin) + childPtr->doubleBw
        !           432:                    + childPtr->padY;
        !           433:            if (childPtr->flags & EXPAND) {
        !           434:                numExpY++;
        !           435:            }
        !           436:        } else {
        !           437:            tmp = Tk_ReqHeight(childPtr->tkwin) + childPtr->doubleBw
        !           438:                    + childPtr->padY + height;
        !           439:            if (tmp > maxHeight) {
        !           440:                maxHeight = tmp;
        !           441:            }
        !           442:            width += Tk_ReqWidth(childPtr->tkwin) + childPtr->doubleBw
        !           443:                    + childPtr->padX;
        !           444:            if (childPtr->flags & EXPAND) {
        !           445:                numExpX++;
        !           446:            }
        !           447:        }
        !           448:     }
        !           449:     if (width > maxWidth) {
        !           450:        maxWidth = width;
        !           451:     }
        !           452:     if (height > maxHeight) {
        !           453:        maxHeight = height;
        !           454:     }
        !           455: 
        !           456:     /*
        !           457:      * If the total amount of space needed in the parent window has
        !           458:      * changed, then notify the next geometry manager up and requeue
        !           459:      * ourselves to start again after the parent has had a chance to
        !           460:      * resize us.
        !           461:      */
        !           462: 
        !           463:     if ((maxWidth != Tk_ReqWidth(parentPtr->tkwin))
        !           464:            || (maxHeight != Tk_ReqHeight(parentPtr->tkwin))) {
        !           465:        Tk_GeometryRequest(parentPtr->tkwin, maxWidth, maxHeight);
        !           466:        parentPtr->flags |= REQUESTED_REPACK;
        !           467:        Tk_DoWhenIdle(ArrangePacking, (ClientData) parentPtr);
        !           468:        goto done;
        !           469:     }
        !           470: 
        !           471:     /*
        !           472:      * If there is spare space, figure out how much of it goes to
        !           473:      * each of the windows that is expandable.
        !           474:      */
        !           475: 
        !           476:     spareX = Tk_Width(parentPtr->tkwin) - width;
        !           477:     spareY = Tk_Height(parentPtr->tkwin) - height;
        !           478:     if ((spareX <= 0) || (numExpX == 0)) {
        !           479:        leftOverX = 0;
        !           480:        spareX = 0;
        !           481:     } else {
        !           482:        leftOverX = spareX % numExpX;
        !           483:        spareX /= numExpX;
        !           484:     }
        !           485:     if ((spareY <= 0) || (numExpY == 0)) {
        !           486:        leftOverY = spareY;
        !           487:        spareY = 0;
        !           488:     } else {
        !           489:        leftOverY = spareY % numExpY;
        !           490:        spareY /= numExpY;
        !           491:     }
        !           492: 
        !           493:     /*
        !           494:      * Pass #2: scan the children a second time assigning
        !           495:      * new sizes.  The "cavity" variables keep track of the
        !           496:      * unclaimed space in the cavity of the window;  this
        !           497:      * shrinks inward as we allocate windows around the
        !           498:      * edges.  The "frame" variables keep track of the space
        !           499:      * allocated to the current window and its frame.  The
        !           500:      * current window is then placed somewhere inside the
        !           501:      * frame, depending on anchorPoint.
        !           502:      */
        !           503: 
        !           504:     cavityX = cavityY = x = y = intBWidth;
        !           505:     cavityWidth = Tk_Width(parentPtr->tkwin) - 2*intBWidth;
        !           506:     cavityHeight = Tk_Height(parentPtr->tkwin) - 2*intBWidth;
        !           507:     for (childPtr = parentPtr->childPtr; childPtr != NULL;
        !           508:            childPtr = childPtr->nextPtr) {
        !           509:        if ((childPtr->side == TOP) || (childPtr->side == BOTTOM)) {
        !           510:            frameWidth = cavityWidth;
        !           511:            frameHeight = Tk_ReqHeight(childPtr->tkwin) + childPtr->padY
        !           512:                    + childPtr->doubleBw;
        !           513:            if (childPtr->flags & EXPAND) {
        !           514:                frameHeight += spareY;
        !           515:                numExpY--;
        !           516:                if (numExpY == 0) {
        !           517:                    frameHeight += leftOverY;
        !           518:                }
        !           519:            }
        !           520:            cavityHeight -= frameHeight;
        !           521:            if (cavityHeight < 0) {
        !           522:                frameHeight += cavityHeight;
        !           523:                cavityHeight = 0;
        !           524:            }
        !           525:            frameX = cavityX;
        !           526:            if (childPtr->side == TOP) {
        !           527:                frameY = cavityY;
        !           528:                cavityY += frameHeight;
        !           529:            } else {
        !           530:                frameY = cavityY + cavityHeight;
        !           531:            }
        !           532:        } else {
        !           533:            frameHeight = cavityHeight;
        !           534:            frameWidth = Tk_ReqWidth(childPtr->tkwin) + childPtr->padX
        !           535:                    + childPtr->doubleBw;
        !           536:            if (childPtr->flags & EXPAND) {
        !           537:                frameWidth += spareX;
        !           538:                numExpX--;
        !           539:                if (numExpX == 0) {
        !           540:                    frameWidth += leftOverX;
        !           541:                }
        !           542:            }
        !           543:            cavityWidth -= frameWidth;
        !           544:            if (cavityWidth < 0) {
        !           545:                frameWidth += cavityWidth;
        !           546:                cavityWidth = 0;
        !           547:            }
        !           548:            frameY = cavityY;
        !           549:            if (childPtr->side == LEFT) {
        !           550:                frameX = cavityX;
        !           551:                cavityX += frameWidth;
        !           552:            } else {
        !           553:                frameX = cavityX + cavityWidth;
        !           554:            }
        !           555:        }
        !           556: 
        !           557:        /*
        !           558:         * Now that we've got the size of the frame for the window,
        !           559:         * compute the window's actual size and location using the
        !           560:         * fill and frame factors.
        !           561:         */
        !           562: 
        !           563:        width = Tk_ReqWidth(childPtr->tkwin) + childPtr->doubleBw;
        !           564:        if ((childPtr->flags & FILLX) || (width > frameWidth)) {
        !           565:            width = frameWidth;
        !           566:        }
        !           567:        height = Tk_ReqHeight(childPtr->tkwin) + childPtr->doubleBw;
        !           568:        if ((childPtr->flags & FILLY) || (height > frameHeight)) {
        !           569:            height = frameHeight;
        !           570:        }
        !           571:        switch (childPtr->anchorPoint) {
        !           572:            case TK_ANCHOR_N:
        !           573:                x = frameX + (frameWidth - width)/2;
        !           574:                y = frameY;
        !           575:                break;
        !           576:            case TK_ANCHOR_NE:
        !           577:                x = frameX + frameWidth - width;
        !           578:                y = frameY;
        !           579:                break;
        !           580:            case TK_ANCHOR_E:
        !           581:                x = frameX + frameWidth - width;
        !           582:                y = frameY + (frameHeight - height)/2;
        !           583:                break;
        !           584:            case TK_ANCHOR_SE:
        !           585:                x = frameX + frameWidth - width;
        !           586:                y = frameY + frameHeight - height;
        !           587:                break;
        !           588:            case TK_ANCHOR_S:
        !           589:                x = frameX + (frameWidth - width)/2;
        !           590:                y = frameY + frameHeight - height;
        !           591:                break;
        !           592:            case TK_ANCHOR_SW:
        !           593:                x = frameX;
        !           594:                y = frameY + frameHeight - height;
        !           595:                break;
        !           596:            case TK_ANCHOR_W:
        !           597:                x = frameX;
        !           598:                y = frameY + (frameHeight - height)/2;
        !           599:                break;
        !           600:            case TK_ANCHOR_NW:
        !           601:                x = frameX;
        !           602:                y = frameY;
        !           603:                break;
        !           604:            case TK_ANCHOR_CENTER:
        !           605:                x = frameX + (frameWidth - width)/2;
        !           606:                y = frameY + (frameHeight - height)/2;
        !           607:                break;
        !           608:            default:
        !           609:                panic("bad frame factor in ArrangePacking");
        !           610:        }
        !           611:        width -= childPtr->doubleBw;
        !           612:        height -= childPtr->doubleBw;
        !           613: 
        !           614:        /*
        !           615:         * If the window is too small to be interesting then
        !           616:         * unmap it.  Otherwise configure it and then make sure
        !           617:         * it's mapped.
        !           618:         */
        !           619: 
        !           620:        if ((width <= 0) || (height <= 0)) {
        !           621:            Tk_UnmapWindow(childPtr->tkwin);
        !           622:        } else {
        !           623:            if ((x != Tk_X(childPtr->tkwin))
        !           624:                    || (y != Tk_Y(childPtr->tkwin))
        !           625:                    || (width != Tk_Width(childPtr->tkwin))
        !           626:                    || (height != Tk_Height(childPtr->tkwin))) {
        !           627:                Tk_MoveResizeWindow(childPtr->tkwin, x, y,
        !           628:                        (unsigned int) width, (unsigned int) height);
        !           629:            }
        !           630:            if (abort) {
        !           631:                goto done;
        !           632:            }
        !           633:            Tk_MapWindow(childPtr->tkwin);
        !           634:        }
        !           635: 
        !           636:        /*
        !           637:         * Changes to the window's structure could cause almost anything
        !           638:         * to happen, including deleting the parent or child.  If this
        !           639:         * happens, we'll be told to abort.
        !           640:         */
        !           641: 
        !           642:        if (abort) {
        !           643:            goto done;
        !           644:        }
        !           645:     }
        !           646: 
        !           647:     done:
        !           648:     parentPtr->abortPtr = NULL;
        !           649:     Tk_Release((ClientData) parentPtr);
        !           650: }
        !           651: 
        !           652: /*
        !           653:  *--------------------------------------------------------------
        !           654:  *
        !           655:  * GetPacker --
        !           656:  *
        !           657:  *     This internal procedure is used to locate a Packer
        !           658:  *     structure for a given window, creating one if one
        !           659:  *     doesn't exist already.
        !           660:  *
        !           661:  * Results:
        !           662:  *     The return value is a pointer to the Packer structure
        !           663:  *     corresponding to tkwin.
        !           664:  *
        !           665:  * Side effects:
        !           666:  *     A new packer structure may be created.  If so, then
        !           667:  *     a callback is set up to clean things up when the
        !           668:  *     window is deleted.
        !           669:  *
        !           670:  *--------------------------------------------------------------
        !           671:  */
        !           672: 
        !           673: static Packer *
        !           674: GetPacker(tkwin)
        !           675:     Tk_Window tkwin;           /* Token for window for which
        !           676:                                 * packer structure is desired. */
        !           677: {
        !           678:     register Packer *packPtr;
        !           679:     Tcl_HashEntry *hPtr;
        !           680:     int new;
        !           681: 
        !           682:     if (!initialized) {
        !           683:        initialized = 1;
        !           684:        Tcl_InitHashTable(&packerHashTable, TCL_ONE_WORD_KEYS);
        !           685:     }
        !           686: 
        !           687:     /*
        !           688:      * See if there's already packer for this window.  If not,
        !           689:      * then create a new one.
        !           690:      */
        !           691: 
        !           692:     hPtr = Tcl_CreateHashEntry(&packerHashTable, (char *) tkwin, &new);
        !           693:     if (!new) {
        !           694:        return (Packer *) Tcl_GetHashValue(hPtr);
        !           695:     }
        !           696:     packPtr = (Packer *) ckalloc(sizeof(Packer));
        !           697:     packPtr->tkwin = tkwin;
        !           698:     packPtr->parentPtr = NULL;
        !           699:     packPtr->nextPtr = NULL;
        !           700:     packPtr->childPtr = NULL;
        !           701:     packPtr->side = TOP;
        !           702:     packPtr->anchorPoint = TK_ANCHOR_CENTER;
        !           703:     packPtr->padX = packPtr->padY = 0;
        !           704:     packPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;
        !           705:     packPtr->abortPtr = NULL;
        !           706:     packPtr->flags = 0;
        !           707:     Tcl_SetHashValue(hPtr, packPtr);
        !           708:     Tk_CreateEventHandler(tkwin, StructureNotifyMask,
        !           709:            PackStructureProc, (ClientData) packPtr);
        !           710:     return packPtr;
        !           711: }
        !           712: 
        !           713: /*
        !           714:  *--------------------------------------------------------------
        !           715:  *
        !           716:  * PackAfter --
        !           717:  *
        !           718:  *     This procedure does most of the real work of adding
        !           719:  *     one or more windows into the packing order for its parent.
        !           720:  *
        !           721:  * Results:
        !           722:  *     A standard Tcl return value.
        !           723:  *
        !           724:  * Side effects:
        !           725:  *     The geometry of the specified windows may change, both now and
        !           726:  *     again in the future.
        !           727:  *
        !           728:  *--------------------------------------------------------------
        !           729:  */
        !           730: 
        !           731: static int
        !           732: PackAfter(interp, prevPtr, parentPtr, argc, argv)
        !           733:     Tcl_Interp *interp;                /* Interpreter for error reporting. */
        !           734:     Packer *prevPtr;           /* Pack windows in argv just after this
        !           735:                                 * window;  NULL means pack as first
        !           736:                                 * child of parentPtr. */
        !           737:     Packer *parentPtr;         /* Parent in which to pack windows. */
        !           738:     int argc;                  /* Number of elements in argv. */
        !           739:     char **argv;               /* Array of lists, each containing 2
        !           740:                                 * elements:  window name and side
        !           741:                                 * against which to pack. */
        !           742: {
        !           743:     register Packer *packPtr;
        !           744:     Tk_Window tkwin;
        !           745:     int length, optionCount;
        !           746:     char **options;
        !           747:     int index;
        !           748:     char c;
        !           749: 
        !           750:     /*
        !           751:      * Iterate over all of the window specifiers, each consisting of
        !           752:      * two arguments.  The first argument contains the window name and
        !           753:      * the additional arguments contain options such as "top" or
        !           754:      * "padx 20".
        !           755:      */
        !           756: 
        !           757:     for ( ; argc > 0; argc -= 2, argv += 2, prevPtr = packPtr) {
        !           758:        if (argc < 2) {
        !           759:            Tcl_AppendResult(interp, "wrong # args: window \"",
        !           760:                    argv[0], "\" should be followed by options",
        !           761:                    (char *) NULL);
        !           762:            return TCL_ERROR;
        !           763:        }
        !           764: 
        !           765:        /*
        !           766:         * Find the packer for the window to be packed, and make sure
        !           767:         * that the window in which it will be packed is its parent.
        !           768:         */
        !           769: 
        !           770:        tkwin = Tk_NameToWindow(interp, argv[0], parentPtr->tkwin);
        !           771:        if (tkwin == NULL) {
        !           772:            return TCL_ERROR;
        !           773:        }
        !           774:        if (Tk_Parent(tkwin) != parentPtr->tkwin) {
        !           775:            Tcl_AppendResult(interp, "tried to pack \"",
        !           776:                    argv[0], "\" in window that isn't its parent",
        !           777:                    (char *) NULL);
        !           778:            return TCL_ERROR;
        !           779:        }
        !           780:        packPtr = GetPacker(tkwin);
        !           781: 
        !           782:        /*
        !           783:         * Process options for this window.
        !           784:         */
        !           785: 
        !           786:        if (Tcl_SplitList(interp, argv[1], &optionCount, &options) != TCL_OK) {
        !           787:            return TCL_ERROR;
        !           788:        }
        !           789:        packPtr->side = TOP;
        !           790:        packPtr->anchorPoint = TK_ANCHOR_CENTER;
        !           791:        packPtr->padX = packPtr->padY = 0;
        !           792:        packPtr->flags &= ~(FILLX|FILLY|EXPAND);
        !           793:        for (index = 0 ; index < optionCount; index++) {
        !           794:            char *curOpt = options[index];
        !           795: 
        !           796:            c = curOpt[0];
        !           797:            length = strlen(curOpt);
        !           798: 
        !           799:            if ((c == 't')
        !           800:                    && (strncmp(curOpt, "top", length)) == 0) {
        !           801:                packPtr->side = TOP;
        !           802:            } else if ((c == 'b')
        !           803:                    && (strncmp(curOpt, "bottom", length)) == 0) {
        !           804:                packPtr->side = BOTTOM;
        !           805:            } else if ((c == 'l')
        !           806:                    && (strncmp(curOpt, "left", length)) == 0) {
        !           807:                packPtr->side = LEFT;
        !           808:            } else if ((c == 'r')
        !           809:                    && (strncmp(curOpt, "right", length)) == 0) {
        !           810:                packPtr->side = RIGHT;
        !           811:            } else if ((c == 'e')
        !           812:                    && (strncmp(curOpt, "expand", length)) == 0) {
        !           813:                packPtr->flags |= EXPAND;
        !           814:            } else if ((c == 'f')
        !           815:                    && (strcmp(curOpt, "fill")) == 0) {
        !           816:                packPtr->flags |= FILLX|FILLY;
        !           817:            } else if ((length == 5) && (strcmp(curOpt, "fillx")) == 0) {
        !           818:                packPtr->flags |= FILLX;
        !           819:            } else if ((length == 5) && (strcmp(curOpt, "filly")) == 0) {
        !           820:                packPtr->flags |= FILLY;
        !           821:            } else if ((c == 'p') && (strcmp(curOpt, "padx")) == 0) {
        !           822:                if (optionCount < (index+2)) {
        !           823:                    missingPad:
        !           824:                    Tcl_AppendResult(interp, "wrong # args: \"", curOpt,
        !           825:                            "\" option must be followed by count",
        !           826:                            (char *) NULL);
        !           827:                    goto error;
        !           828:                }
        !           829:                if ((Tcl_GetInt(interp, options[index+1], &packPtr->padX)
        !           830:                        != TCL_OK) || (packPtr->padX < 0)) {
        !           831:                    badPad:
        !           832:                    Tcl_AppendResult(interp, "bad pad value \"",
        !           833:                            options[index+1], "\":  must be positive integer",
        !           834:                            (char *) NULL);
        !           835:                    goto error;
        !           836:                }
        !           837:                index++;
        !           838:            } else if ((c == 'p') && (strcmp(curOpt, "pady")) == 0) {
        !           839:                if (optionCount < (index+2)) {
        !           840:                    goto missingPad;
        !           841:                }
        !           842:                if ((Tcl_GetInt(interp, options[index+1], &packPtr->padY)
        !           843:                        != TCL_OK) || (packPtr->padY < 0)) {
        !           844:                    goto badPad;
        !           845:                }
        !           846:                index++;
        !           847:            } else if ((c == 'f') && (length > 1)
        !           848:                    && (strncmp(curOpt, "frame", length) == 0)) {
        !           849:                if (optionCount < (index+2)) {
        !           850:                    Tcl_AppendResult(interp, "wrong # args: \"frame\" ",
        !           851:                            "option must be followed by anchor point",
        !           852:                            (char *) NULL);
        !           853:                    goto error;
        !           854:                }
        !           855:                if (Tk_GetAnchor(interp, options[index+1],
        !           856:                        &packPtr->anchorPoint) != TCL_OK) {
        !           857:                    goto error;
        !           858:                }
        !           859:                index++;
        !           860:            } else {
        !           861:                Tcl_AppendResult(interp, "bad option \"", curOpt,
        !           862:                        "\":  should be top, bottom, left, right, ",
        !           863:                        "expand, fill, fillx, filly, padx, pady, or frame",
        !           864:                        (char *) NULL);
        !           865:                goto error;
        !           866:            }
        !           867:        }
        !           868: 
        !           869:        if (packPtr != prevPtr) {
        !           870: 
        !           871:            /*
        !           872:             * Unpack this window if it's currently packed.
        !           873:             */
        !           874:        
        !           875:            if (packPtr->parentPtr != NULL) {
        !           876:                Unlink(packPtr);
        !           877:            }
        !           878:        
        !           879:            /*
        !           880:             * Add the window in the correct place in its parent's
        !           881:             * packing order, then make sure that the window is
        !           882:             * managed by us.
        !           883:             */
        !           884: 
        !           885:            packPtr->parentPtr = parentPtr;
        !           886:            if (prevPtr == NULL) {
        !           887:                packPtr->nextPtr = parentPtr->childPtr;
        !           888:                parentPtr->childPtr = packPtr;
        !           889:            } else {
        !           890:                packPtr->nextPtr = prevPtr->nextPtr;
        !           891:                prevPtr->nextPtr = packPtr;
        !           892:            }
        !           893:            Tk_ManageGeometry(tkwin, PackReqProc, (ClientData) packPtr);
        !           894:        }
        !           895:        ckfree((char *) options);
        !           896:     }
        !           897: 
        !           898:     /*
        !           899:      * Arrange for the parent to be re-packed at the first
        !           900:      * idle moment.
        !           901:      */
        !           902: 
        !           903:     if (parentPtr->abortPtr != NULL) {
        !           904:        *parentPtr->abortPtr = 1;
        !           905:     }
        !           906:     if (!(parentPtr->flags & REQUESTED_REPACK)) {
        !           907:        parentPtr->flags |= REQUESTED_REPACK;
        !           908:        Tk_DoWhenIdle(ArrangePacking, (ClientData) parentPtr);
        !           909:     }
        !           910:     return TCL_OK;
        !           911: 
        !           912:     error:
        !           913:     ckfree((char *) options);
        !           914:     return TCL_ERROR;
        !           915: }
        !           916: 
        !           917: /*
        !           918:  *----------------------------------------------------------------------
        !           919:  *
        !           920:  * Unlink --
        !           921:  *
        !           922:  *     Remove a packer from its parent's list of children.
        !           923:  *
        !           924:  * Results:
        !           925:  *     None.
        !           926:  *
        !           927:  * Side effects:
        !           928:  *     The parent will be scheduled for repacking.
        !           929:  *
        !           930:  *----------------------------------------------------------------------
        !           931:  */
        !           932: 
        !           933: static void
        !           934: Unlink(packPtr)
        !           935:     register Packer *packPtr;          /* Window to unlink. */
        !           936: {
        !           937:     register Packer *parentPtr, *packPtr2;
        !           938: 
        !           939:     parentPtr = packPtr->parentPtr;
        !           940:     if (parentPtr == NULL) {
        !           941:        return;
        !           942:     }
        !           943:     if (parentPtr->childPtr == packPtr) {
        !           944:        parentPtr->childPtr = packPtr->nextPtr;
        !           945:     } else {
        !           946:        for (packPtr2 = parentPtr->childPtr; ; packPtr2 = packPtr2->nextPtr) {
        !           947:            if (packPtr2 == NULL) {
        !           948:                panic("Unlink couldn't find previous window");
        !           949:            }
        !           950:            if (packPtr2->nextPtr == packPtr) {
        !           951:                packPtr2->nextPtr = packPtr->nextPtr;
        !           952:                break;
        !           953:            }
        !           954:        }
        !           955:     }
        !           956:     if (!(parentPtr->flags & REQUESTED_REPACK)) {
        !           957:        parentPtr->flags |= REQUESTED_REPACK;
        !           958:        Tk_DoWhenIdle(ArrangePacking, (ClientData) parentPtr);
        !           959:     }
        !           960:     if (parentPtr->abortPtr != NULL) {
        !           961:        *parentPtr->abortPtr = 1;
        !           962:     }
        !           963: 
        !           964:     packPtr->parentPtr = NULL;
        !           965: }
        !           966: 
        !           967: /*
        !           968:  *----------------------------------------------------------------------
        !           969:  *
        !           970:  * DestroyPacker --
        !           971:  *
        !           972:  *     This procedure is invoked by Tk_EventuallyFree or Tk_Release
        !           973:  *     to clean up the internal structure of a packer at a safe time
        !           974:  *     (when no-one is using it anymore).
        !           975:  *
        !           976:  * Results:
        !           977:  *     None.
        !           978:  *
        !           979:  * Side effects:
        !           980:  *     Everything associated with the packer is freed up.
        !           981:  *
        !           982:  *----------------------------------------------------------------------
        !           983:  */
        !           984: 
        !           985: static void
        !           986: DestroyPacker(clientData)
        !           987:     ClientData clientData;             /* Info about packed window that
        !           988:                                         * is now dead. */
        !           989: {
        !           990:     register Packer *packPtr = (Packer *) clientData;
        !           991:     ckfree((char *) packPtr);
        !           992: }
        !           993: 
        !           994: /*
        !           995:  *----------------------------------------------------------------------
        !           996:  *
        !           997:  * PackStructureProc --
        !           998:  *
        !           999:  *     This procedure is invoked by the Tk event dispatcher in response
        !          1000:  *     to StructureNotify events.
        !          1001:  *
        !          1002:  * Results:
        !          1003:  *     None.
        !          1004:  *
        !          1005:  * Side effects:
        !          1006:  *     If a window was just deleted, clean up all its packer-related
        !          1007:  *     information.  If it was just resized, repack its children, if
        !          1008:  *     any.
        !          1009:  *
        !          1010:  *----------------------------------------------------------------------
        !          1011:  */
        !          1012: 
        !          1013: static void
        !          1014: PackStructureProc(clientData, eventPtr)
        !          1015:     ClientData clientData;             /* Our information about window
        !          1016:                                         * referred to by eventPtr. */
        !          1017:     XEvent *eventPtr;                  /* Describes what just happened. */
        !          1018: {
        !          1019:     register Packer *packPtr = (Packer *) clientData;
        !          1020:     if (eventPtr->type == ConfigureNotify) {
        !          1021:        if ((packPtr->childPtr != NULL)
        !          1022:                && !(packPtr->flags & REQUESTED_REPACK)) {
        !          1023:            packPtr->flags |= REQUESTED_REPACK;
        !          1024:            Tk_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
        !          1025:        }
        !          1026:        if (packPtr->doubleBw != 2*Tk_Changes(packPtr->tkwin)->border_width) {
        !          1027:            if ((packPtr->parentPtr != NULL)
        !          1028:                    && !(packPtr->parentPtr->flags & REQUESTED_REPACK)) {
        !          1029:                packPtr->doubleBw = 2*Tk_Changes(packPtr->tkwin)->border_width;
        !          1030:                packPtr->parentPtr->flags |= REQUESTED_REPACK;
        !          1031:                Tk_DoWhenIdle(ArrangePacking, (ClientData) packPtr->parentPtr);
        !          1032:            }
        !          1033:        }
        !          1034:     } else if (eventPtr->type == DestroyNotify) {
        !          1035:        register Packer *packPtr2;
        !          1036: 
        !          1037:        if (packPtr->parentPtr != NULL) {
        !          1038:            Unlink(packPtr);
        !          1039:        }
        !          1040:        for (packPtr2 = packPtr->childPtr; packPtr2 != NULL;
        !          1041:                packPtr2 = packPtr2->nextPtr) {
        !          1042:            packPtr2->parentPtr = NULL;
        !          1043:            packPtr2->nextPtr = NULL;
        !          1044:        }
        !          1045:        Tcl_DeleteHashEntry(Tcl_FindHashEntry(&packerHashTable,
        !          1046:                (char *) packPtr->tkwin));
        !          1047:        if (packPtr->flags & REQUESTED_REPACK) {
        !          1048:            Tk_CancelIdleCall(ArrangePacking, (ClientData) packPtr);
        !          1049:        }
        !          1050:        packPtr->tkwin = NULL;
        !          1051:        Tk_EventuallyFree((ClientData) packPtr, DestroyPacker);
        !          1052:     }
        !          1053: }

unix.superglobalmegacorp.com

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