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

1.1     ! root        1: /* 
        !             2:  * tkPlace.c --
        !             3:  *
        !             4:  *     This file contains code to implement a simple geometry manager
        !             5:  *     for Tk based on absolute placement or "rubber-sheet" placement.
        !             6:  *
        !             7:  * Copyright 1992 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 this copyright
        !            11:  * notice appears 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/tkPlace.c,v 1.6 92/06/10 08:59:28 ouster Exp $ SPRITE (Berkeley)";
        !            19: #endif /* not lint */
        !            20: 
        !            21: #include "tkconfig.h"
        !            22: #include "tkint.h"
        !            23: 
        !            24: /*
        !            25:  * Border modes for relative placement:
        !            26:  *
        !            27:  * BM_INSIDE:          relative distances computed using area inside
        !            28:  *                     all borders of master window.
        !            29:  * BM_OUTSIDE:         relative distances computed using outside area
        !            30:  *                     that includes all borders of master.
        !            31:  * BM_IGNORE:          border issues are ignored:  place relative to
        !            32:  *                     master's actual window size.
        !            33:  */
        !            34: 
        !            35: typedef enum {BM_INSIDE, BM_OUTSIDE, BM_IGNORE} BorderMode;
        !            36: 
        !            37: /*
        !            38:  * For each window whose geometry is managed by the placer there is
        !            39:  * a structure of the following type:
        !            40:  */
        !            41: 
        !            42: typedef struct Slave {
        !            43:     Tk_Window tkwin;           /* Tk's token for window. */
        !            44:     struct Master *masterPtr;  /* Pointer to information for window
        !            45:                                 * relative to which tkwin is placed.
        !            46:                                 * This isn't necessarily the logical
        !            47:                                 * parent of tkwin.  NULL means the
        !            48:                                 * master was deleted or never assigned. */
        !            49:     struct Slave *nextPtr;     /* Next in list of windows placed relative
        !            50:                                 * to same master (NULL for end of list). */
        !            51: 
        !            52:     /*
        !            53:      * Geometry information for window;  where there are both relative
        !            54:      * and absolute values for the same attribute (e.g. x and relX) only
        !            55:      * one of them is actually used, depending on flags.
        !            56:      */
        !            57: 
        !            58:     int x, y;                  /* X and Y pixel coordinates for tkwin. */
        !            59:     float relX, relY;          /* X and Y coordinates relative to size of
        !            60:                                 * master. */
        !            61:     int width, height;         /* Absolute dimensions for tkwin. */
        !            62:     float relWidth, relHeight; /* Dimensions for tkwin relative to size of
        !            63:                                 * master. */
        !            64:     Tk_Anchor anchor;          /* Which point on tkwin is placed at the
        !            65:                                 * given position. */
        !            66:     BorderMode borderMode;     /* How to treat borders of master window. */
        !            67:     int flags;                 /* Various flags;  see below for bit
        !            68:                                 * definitions. */
        !            69: } Slave;
        !            70: 
        !            71: /*
        !            72:  * Flag definitions for Slave structures:
        !            73:  *
        !            74:  * CHILD_REL_X -               1 means use relX field;  0 means use x.
        !            75:  * CHILD_REL_Y -               1 means use relY field;  0 means use y;
        !            76:  * CHILD_WIDTH -               1 means use width field;
        !            77:  * CHILD_REL_WIDTH -           1 means use relWidth;  if neither this nor
        !            78:  *                             CHILD_WIDTH is 1, use window's requested
        !            79:  *                             width.
        !            80:  * CHILD_HEIGHT -              1 means use height field;
        !            81:  * CHILD_REL_HEIGHT -          1 means use relHeight;  if neither this nor
        !            82:  *                             CHILD_HEIGHT is 1, use window's requested
        !            83:  *                             height.
        !            84:  */
        !            85: 
        !            86: #define CHILD_REL_X            1
        !            87: #define CHILD_REL_Y            2
        !            88: #define CHILD_WIDTH            4
        !            89: #define CHILD_REL_WIDTH                8
        !            90: #define CHILD_HEIGHT           0x10
        !            91: #define CHILD_REL_HEIGHT       0x20
        !            92: 
        !            93: /*
        !            94:  * For each master window that has a slave managed by the placer there
        !            95:  * is a structure of the following form:
        !            96:  */
        !            97: 
        !            98: typedef struct Master {
        !            99:     Tk_Window tkwin;           /* Tk's token for master window. */
        !           100:     struct Slave *slavePtr;    /* First in linked list of slaves
        !           101:                                 * placed relative to this master. */
        !           102:     int flags;                 /* See below for bit definitions. */
        !           103: } Master;
        !           104: 
        !           105: /*
        !           106:  * Flag definitions for masters:
        !           107:  *
        !           108:  * PARENT_RECONFIG_PENDING -   1 means that a call to RecomputePlacement
        !           109:  *                             is already pending via a Do_When_Idle handler.
        !           110:  */
        !           111: 
        !           112: #define PARENT_RECONFIG_PENDING        1
        !           113: 
        !           114: /*
        !           115:  * The hash tables below both use Tk_Window tokens as keys.  They map
        !           116:  * from Tk_Windows to Slave and Master structures for windows, if they
        !           117:  * exist.
        !           118:  */
        !           119: 
        !           120: static int initialized = 0;
        !           121: static Tcl_HashTable masterTable;
        !           122: static Tcl_HashTable slaveTable;
        !           123: 
        !           124: /*
        !           125:  * Forward declarations for procedures defined later in this file:
        !           126:  */
        !           127: 
        !           128: static void            SlaveStructureProc _ANSI_ARGS_((ClientData clientData,
        !           129:                            XEvent *eventPtr));
        !           130: static int             ConfigureSlave _ANSI_ARGS_((Tcl_Interp *interp,
        !           131:                            Slave *slavePtr, int argc, char **argv));
        !           132: static Slave *         FindSlave _ANSI_ARGS_((Tk_Window tkwin));
        !           133: static Master *                FindMaster _ANSI_ARGS_((Tk_Window tkwin));
        !           134: static void            MasterStructureProc _ANSI_ARGS_((ClientData clientData,
        !           135:                            XEvent *eventPtr));
        !           136: static void            PlaceRequestProc _ANSI_ARGS_((ClientData clientData,
        !           137:                            Tk_Window tkwin));
        !           138: static void            RecomputePlacement _ANSI_ARGS_((ClientData clientData));
        !           139: static void            UnlinkSlave _ANSI_ARGS_((Slave *slavePtr));
        !           140: 
        !           141: /*
        !           142:  *--------------------------------------------------------------
        !           143:  *
        !           144:  * Tk_PlaceCmd --
        !           145:  *
        !           146:  *     This procedure is invoked to process the "place" Tcl
        !           147:  *     commands.  See the user documentation for details on
        !           148:  *     what it does.
        !           149:  *
        !           150:  * Results:
        !           151:  *     A standard Tcl result.
        !           152:  *
        !           153:  * Side effects:
        !           154:  *     See the user documentation.
        !           155:  *
        !           156:  *--------------------------------------------------------------
        !           157:  */
        !           158: 
        !           159: int
        !           160: Tk_PlaceCmd(clientData, interp, argc, argv)
        !           161:     ClientData clientData;     /* Main window associated with interpreter. */
        !           162:     Tcl_Interp *interp;                /* Current interpreter. */
        !           163:     int argc;                  /* Number of arguments. */
        !           164:     char **argv;               /* Argument strings. */
        !           165: {
        !           166:     Tk_Window tkwin;
        !           167:     Slave *slavePtr;
        !           168:     Tcl_HashEntry *hPtr;
        !           169:     int length;
        !           170:     char c;
        !           171: 
        !           172:     /*
        !           173:      * Initialize, if that hasn't been done yet.
        !           174:      */
        !           175: 
        !           176:     if (!initialized) {
        !           177:        Tcl_InitHashTable(&masterTable, TCL_ONE_WORD_KEYS);
        !           178:        Tcl_InitHashTable(&slaveTable, TCL_ONE_WORD_KEYS);
        !           179:        initialized = 1;
        !           180:     }
        !           181: 
        !           182:     if (argc < 3) {
        !           183:        Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           184:                argv[0], " option|pathName args", (char *) NULL);
        !           185:        return TCL_ERROR;
        !           186:     }
        !           187:     c = argv[1][0];
        !           188:     length = strlen(argv[1]);
        !           189: 
        !           190:     /*
        !           191:      * Handle special shortcut where window name is first argument.
        !           192:      */
        !           193: 
        !           194:     if (c == '.') {
        !           195:        tkwin = Tk_NameToWindow(interp, argv[1], (Tk_Window) clientData);
        !           196:        if (tkwin == NULL) {
        !           197:            return TCL_ERROR;
        !           198:        }
        !           199:        slavePtr = FindSlave(tkwin);
        !           200:        return ConfigureSlave(interp, slavePtr, argc-2, argv+2);
        !           201:     }
        !           202: 
        !           203:     /*
        !           204:      * Handle more general case of option followed by window name followed
        !           205:      * by possible additional arguments.
        !           206:      */
        !           207: 
        !           208:     tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData);
        !           209:     if (tkwin == NULL) {
        !           210:        return TCL_ERROR;
        !           211:     }
        !           212:     if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
        !           213:        if (argc < 5) {
        !           214:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           215:                    argv[0],
        !           216:                    " configure pathName option value ?option value ...?\"",
        !           217:                    (char *) NULL);
        !           218:            return TCL_ERROR;
        !           219:        }
        !           220:        slavePtr = FindSlave(tkwin);
        !           221:        return ConfigureSlave(interp, slavePtr, argc-3, argv+3);
        !           222:     } else if ((c == 'd') && (strncmp(argv[1], "dependents", length) == 0)) {
        !           223:        if (argc != 3) {
        !           224:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           225:                    argv[0], " dependents pathName\"", (char *) NULL);
        !           226:            return TCL_ERROR;
        !           227:        }
        !           228:        hPtr = Tcl_FindHashEntry(&masterTable, (char *) tkwin);
        !           229:        if (hPtr != NULL) {
        !           230:            Master *masterPtr;
        !           231:            masterPtr = (Master *) Tcl_GetHashValue(hPtr);
        !           232:            for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
        !           233:                    slavePtr = slavePtr->nextPtr) {
        !           234:                Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin), 0);
        !           235:            }
        !           236:        }
        !           237:     } else if ((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) {
        !           238:        if (argc != 3) {
        !           239:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           240:                    argv[0], " forget pathName\"", (char *) NULL);
        !           241:            return TCL_ERROR;
        !           242:        }
        !           243:        hPtr = Tcl_FindHashEntry(&slaveTable, (char *) tkwin);
        !           244:        if (hPtr == NULL) {
        !           245:            return TCL_OK;
        !           246:        }
        !           247:        slavePtr = (Slave *) Tcl_GetHashValue(hPtr);
        !           248:        UnlinkSlave(slavePtr);
        !           249:        Tcl_DeleteHashEntry(hPtr);
        !           250:        Tk_DeleteEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc,
        !           251:                (ClientData) slavePtr);
        !           252:        Tk_ManageGeometry(tkwin, (Tk_GeometryProc *) NULL, (ClientData) NULL);
        !           253:        Tk_UnmapWindow(tkwin);
        !           254:        ckfree((char *) slavePtr);
        !           255:     } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {
        !           256:        char buffer[50];
        !           257: 
        !           258:        if (argc != 3) {
        !           259:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           260:                    argv[0], " info pathName\"", (char *) NULL);
        !           261:            return TCL_ERROR;
        !           262:        }
        !           263:        hPtr = Tcl_FindHashEntry(&slaveTable, (char *) tkwin);
        !           264:        if (hPtr == NULL) {
        !           265:            return TCL_OK;
        !           266:        }
        !           267:        slavePtr = (Slave *) Tcl_GetHashValue(hPtr);
        !           268:        if (slavePtr->flags & CHILD_REL_X) {
        !           269:            sprintf(buffer, "-relx %.4g", slavePtr->relX);
        !           270:        } else {
        !           271:            sprintf(buffer, "-x %d", slavePtr->x);
        !           272:        }
        !           273:        Tcl_AppendResult(interp, buffer, (char *) NULL);
        !           274:        if (slavePtr->flags & CHILD_REL_Y) {
        !           275:            sprintf(buffer, " -rely %.4g", slavePtr->relY);
        !           276:        } else {
        !           277:            sprintf(buffer, " -y %d", slavePtr->y);
        !           278:        }
        !           279:        Tcl_AppendResult(interp, buffer, (char *) NULL);
        !           280:        if (slavePtr->flags & CHILD_REL_WIDTH) {
        !           281:            sprintf(buffer, " -relwidth %.4g", slavePtr->relWidth);
        !           282:            Tcl_AppendResult(interp, buffer, (char *) NULL);
        !           283:        } else if (slavePtr->flags & CHILD_WIDTH) {
        !           284:            sprintf(buffer, " -width %d", slavePtr->width);
        !           285:            Tcl_AppendResult(interp, buffer, (char *) NULL);
        !           286:        }
        !           287:        if (slavePtr->flags & CHILD_REL_HEIGHT) {
        !           288:            sprintf(buffer, " -relheight %.4g", slavePtr->relHeight);
        !           289:            Tcl_AppendResult(interp, buffer, (char *) NULL);
        !           290:        } else if (slavePtr->flags & CHILD_HEIGHT) {
        !           291:            sprintf(buffer, " -height %d", slavePtr->height);
        !           292:            Tcl_AppendResult(interp, buffer, (char *) NULL);
        !           293:        }
        !           294:        Tcl_AppendResult(interp, " -anchor ", Tk_NameOfAnchor(slavePtr->anchor),
        !           295:                (char *) NULL);
        !           296:        if (slavePtr->borderMode == BM_OUTSIDE) {
        !           297:            Tcl_AppendResult(interp, " -bordermode outside", (char *) NULL);
        !           298:        } else if (slavePtr->borderMode == BM_IGNORE) {
        !           299:            Tcl_AppendResult(interp, " -bordermode ignore", (char *) NULL);
        !           300:        }
        !           301:        if ((slavePtr->masterPtr != NULL)
        !           302:                && (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin))) {
        !           303:            Tcl_AppendResult(interp, " -in ",
        !           304:                    Tk_PathName(slavePtr->masterPtr->tkwin), (char *) NULL);
        !           305:        }
        !           306:     } else {
        !           307:        Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
        !           308:                "\": must be configure, dependents, forget, or info",
        !           309:                (char *) NULL);
        !           310:        return TCL_ERROR;
        !           311:     }
        !           312:     return TCL_OK;
        !           313: }
        !           314: 
        !           315: /*
        !           316:  *----------------------------------------------------------------------
        !           317:  *
        !           318:  * FindSlave --
        !           319:  *
        !           320:  *     Given a Tk_Window token, find the Slave structure corresponding
        !           321:  *     to that token (making a new one if necessary).
        !           322:  *
        !           323:  * Results:
        !           324:  *     None.
        !           325:  *
        !           326:  * Side effects:
        !           327:  *     A new Slave structure may be created.
        !           328:  *
        !           329:  *----------------------------------------------------------------------
        !           330:  */
        !           331: 
        !           332: static Slave *
        !           333: FindSlave(tkwin)
        !           334:     Tk_Window tkwin;           /* Token for desired slave. */
        !           335: {
        !           336:     Tcl_HashEntry *hPtr;
        !           337:     register Slave *slavePtr;
        !           338:     int new;
        !           339: 
        !           340:     hPtr = Tcl_CreateHashEntry(&slaveTable, (char *) tkwin, &new);
        !           341:     if (new) {
        !           342:        slavePtr = (Slave *) ckalloc(sizeof(Slave));
        !           343:        slavePtr->tkwin = tkwin;
        !           344:        slavePtr->masterPtr = NULL;
        !           345:        slavePtr->nextPtr = NULL;
        !           346:        slavePtr->x = slavePtr->y = 0;
        !           347:        slavePtr->relX = slavePtr->relY = 0.0;
        !           348:        slavePtr->width = slavePtr->height = 0;
        !           349:        slavePtr->relWidth = slavePtr->relHeight = 0.0;
        !           350:        slavePtr->anchor = TK_ANCHOR_NW;
        !           351:        slavePtr->borderMode = BM_INSIDE;
        !           352:        slavePtr->flags = 0;
        !           353:        Tcl_SetHashValue(hPtr, slavePtr);
        !           354:        Tk_CreateEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc,
        !           355:                (ClientData) slavePtr);
        !           356:        Tk_ManageGeometry(tkwin, PlaceRequestProc, (ClientData) slavePtr);
        !           357:     } else {
        !           358:        slavePtr = (Slave *) Tcl_GetHashValue(hPtr);
        !           359:     }
        !           360:     return slavePtr;
        !           361: }
        !           362: 
        !           363: /*
        !           364:  *----------------------------------------------------------------------
        !           365:  *
        !           366:  * UnlinkSlave --
        !           367:  *
        !           368:  *     This procedure removes a slave window from the chain of slaves
        !           369:  *     in its master.
        !           370:  *
        !           371:  * Results:
        !           372:  *     None.
        !           373:  *
        !           374:  * Side effects:
        !           375:  *     The slave list of slavePtr's master changes.
        !           376:  *
        !           377:  *----------------------------------------------------------------------
        !           378:  */
        !           379: 
        !           380: static void
        !           381: UnlinkSlave(slavePtr)
        !           382:     Slave *slavePtr;           /* Slave structure to be unlinked. */
        !           383: {
        !           384:     register Master *masterPtr;
        !           385:     register Slave *prevPtr;
        !           386: 
        !           387:     masterPtr = slavePtr->masterPtr;
        !           388:     if (masterPtr == NULL) {
        !           389:        return;
        !           390:     }
        !           391:     if (masterPtr->slavePtr == slavePtr) {
        !           392:        masterPtr->slavePtr = slavePtr->nextPtr;
        !           393:     } else {
        !           394:        for (prevPtr = masterPtr->slavePtr; ;
        !           395:                prevPtr = prevPtr->nextPtr) {
        !           396:            if (prevPtr == NULL) {
        !           397:                panic("UnlinkSlave couldn't find slave to unlink");
        !           398:            }
        !           399:            if (prevPtr->nextPtr == slavePtr) {
        !           400:                prevPtr->nextPtr = slavePtr->nextPtr;
        !           401:                break;
        !           402:            }
        !           403:        }
        !           404:     }
        !           405:     slavePtr->masterPtr = NULL;
        !           406: }
        !           407: 
        !           408: /*
        !           409:  *----------------------------------------------------------------------
        !           410:  *
        !           411:  * FindMaster --
        !           412:  *
        !           413:  *     Given a Tk_Window token, find the Master structure corresponding
        !           414:  *     to that token (making a new one if necessary).
        !           415:  *
        !           416:  * Results:
        !           417:  *     None.
        !           418:  *
        !           419:  * Side effects:
        !           420:  *     A new Master structure may be created.
        !           421:  *
        !           422:  *----------------------------------------------------------------------
        !           423:  */
        !           424: 
        !           425: static Master *
        !           426: FindMaster(tkwin)
        !           427:     Tk_Window tkwin;           /* Token for desired master. */
        !           428: {
        !           429:     Tcl_HashEntry *hPtr;
        !           430:     register Master *masterPtr;
        !           431:     int new;
        !           432: 
        !           433:     hPtr = Tcl_CreateHashEntry(&masterTable, (char *) tkwin, &new);
        !           434:     if (new) {
        !           435:        masterPtr = (Master *) ckalloc(sizeof(Master));
        !           436:        masterPtr->tkwin = tkwin;
        !           437:        masterPtr->slavePtr = NULL;
        !           438:        masterPtr->flags = 0;
        !           439:        Tcl_SetHashValue(hPtr, masterPtr);
        !           440:        Tk_CreateEventHandler(masterPtr->tkwin, StructureNotifyMask,
        !           441:                MasterStructureProc, (ClientData) masterPtr);
        !           442:     } else {
        !           443:        masterPtr = (Master *) Tcl_GetHashValue(hPtr);
        !           444:     }
        !           445:     return masterPtr;
        !           446: }
        !           447: 
        !           448: /*
        !           449:  *----------------------------------------------------------------------
        !           450:  *
        !           451:  * ConfigureSlave --
        !           452:  *
        !           453:  *     This procedure is called to process an argv/argc list to
        !           454:  *     reconfigure the placement of a window.
        !           455:  *
        !           456:  * Results:
        !           457:  *     A standard Tcl result.  If an error occurs then a message is
        !           458:  *     left in interp->result.
        !           459:  *
        !           460:  * Side effects:
        !           461:  *     Information in slavePtr may change, and slavePtr's master is
        !           462:  *     scheduled for reconfiguration.
        !           463:  *
        !           464:  *----------------------------------------------------------------------
        !           465:  */
        !           466: 
        !           467: static int
        !           468: ConfigureSlave(interp, slavePtr, argc, argv)
        !           469:     Tcl_Interp *interp;                /* Used for error reporting. */
        !           470:     Slave *slavePtr;           /* Pointer to current information
        !           471:                                 * about slave. */
        !           472:     int argc;                  /* Number of config arguments. */
        !           473:     char **argv;               /* String values for arguments. */
        !           474: {
        !           475:     register Master *masterPtr;
        !           476:     int c, length, result;
        !           477:     double d;
        !           478: 
        !           479:     result = TCL_OK;
        !           480:     for ( ; argc > 0; argc -= 2, argv += 2) {
        !           481:        if (argc < 2) {
        !           482:            Tcl_AppendResult(interp, "extra option \"", argv[0],
        !           483:                    "\" (option with no value?)", (char *) NULL);
        !           484:            result = TCL_ERROR;
        !           485:            goto done;
        !           486:        }
        !           487:        length = strlen(argv[0]);
        !           488:        c = argv[0][1];
        !           489:        if ((c == 'a') && (strncmp(argv[0], "-anchor", length) == 0)) {
        !           490:            if (Tk_GetAnchor(interp, argv[1], &slavePtr->anchor) != TCL_OK) {
        !           491:                result = TCL_ERROR;
        !           492:                goto done;
        !           493:            }
        !           494:        } else if ((c == 'b')
        !           495:                && (strncmp(argv[0], "-bordermode", length) == 0)) {
        !           496:            c = argv[1][0];
        !           497:            length = strlen(argv[1]);
        !           498:            if ((c == 'i') && (strncmp(argv[1], "ignore", length) == 0)
        !           499:                    && (length >= 2)) {
        !           500:                slavePtr->borderMode = BM_IGNORE;
        !           501:            } else if ((c == 'i') && (strncmp(argv[1], "inside", length) == 0)
        !           502:                    && (length >= 2)) {
        !           503:                slavePtr->borderMode = BM_INSIDE;
        !           504:            } else if ((c == 'o')
        !           505:                    && (strncmp(argv[1], "outside", length) == 0)) {
        !           506:                slavePtr->borderMode = BM_OUTSIDE;
        !           507:            } else {
        !           508:                Tcl_AppendResult(interp, "bad border mode \"", argv[1],
        !           509:                        "\": must be ignore, inside, or outside",
        !           510:                        (char *) NULL);
        !           511:                result = TCL_ERROR;
        !           512:                goto done;
        !           513:            }
        !           514:        } else if ((c == 'h') && (strncmp(argv[0], "-height", length) == 0)) {
        !           515:            if (argv[1][0] == 0) {
        !           516:                slavePtr->flags &= ~(CHILD_REL_HEIGHT|CHILD_HEIGHT);
        !           517:            } else {
        !           518:                if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
        !           519:                        &slavePtr->height) != TCL_OK) {
        !           520:                    result = TCL_ERROR;
        !           521:                    goto done;
        !           522:                }
        !           523:                slavePtr->flags &= ~CHILD_REL_HEIGHT;
        !           524:                slavePtr->flags |= CHILD_HEIGHT;
        !           525:            }
        !           526:        } else if ((c == 'i') && (strncmp(argv[0], "-in", length) == 0)) {
        !           527:            Tk_Window tkwin;
        !           528:            Tk_Window ancestor;
        !           529: 
        !           530:            tkwin = Tk_NameToWindow(interp, argv[1], slavePtr->tkwin);
        !           531:            if (tkwin == NULL) {
        !           532:                result = TCL_ERROR;
        !           533:                goto done;
        !           534:            }
        !           535: 
        !           536:            /*
        !           537:             * Make sure that the new master is either the logical parent
        !           538:             * of the slave or a descendant of that window.
        !           539:             */
        !           540: 
        !           541:            for (ancestor = tkwin; ; ancestor = Tk_Parent(ancestor)) {
        !           542:                if (ancestor == Tk_Parent(slavePtr->tkwin)) {
        !           543:                    break;
        !           544:                }
        !           545:                if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_LEVEL) {
        !           546:                    Tcl_AppendResult(interp, "can't place ",
        !           547:                            Tk_PathName(slavePtr->tkwin), " relative to ",
        !           548:                            Tk_PathName(tkwin), (char *) NULL);
        !           549:                    result = TCL_ERROR;
        !           550:                    goto done;
        !           551:                }
        !           552:            }
        !           553:            UnlinkSlave(slavePtr);
        !           554:            slavePtr->masterPtr = FindMaster(tkwin);
        !           555:            slavePtr->nextPtr = slavePtr->masterPtr->slavePtr;
        !           556:            slavePtr->masterPtr->slavePtr = slavePtr;
        !           557:        } else if ((c == 'r') && (strncmp(argv[0], "-relheight", length) == 0)
        !           558:                && (length >= 5)) {
        !           559:            if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
        !           560:                result = TCL_ERROR;
        !           561:                goto done;
        !           562:            }
        !           563:            slavePtr->relHeight = d;
        !           564:            slavePtr->flags |= CHILD_REL_HEIGHT;
        !           565:            slavePtr->flags &= ~CHILD_HEIGHT;
        !           566:        } else if ((c == 'r') && (strncmp(argv[0], "-relwidth", length) == 0)
        !           567:                && (length >= 5)) {
        !           568:            if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
        !           569:                result = TCL_ERROR;
        !           570:                goto done;
        !           571:            }
        !           572:            slavePtr->relWidth = d;
        !           573:            slavePtr->flags |= CHILD_REL_WIDTH;
        !           574:            slavePtr->flags &= ~CHILD_WIDTH;
        !           575:        } else if ((c == 'r') && (strncmp(argv[0], "-relx", length) == 0)
        !           576:                && (length >= 5)) {
        !           577:            if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
        !           578:                result = TCL_ERROR;
        !           579:                goto done;
        !           580:            }
        !           581:            slavePtr->relX = d;
        !           582:            slavePtr->flags |= CHILD_REL_X;
        !           583:        } else if ((c == 'r') && (strncmp(argv[0], "-rely", length) == 0)
        !           584:                && (length >= 5)) {
        !           585:            if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
        !           586:                result = TCL_ERROR;
        !           587:                goto done;
        !           588:            }
        !           589:            slavePtr->relY = d;
        !           590:            slavePtr->flags |= CHILD_REL_Y;
        !           591:        } else if ((c == 'w') && (strncmp(argv[0], "-width", length) == 0)) {
        !           592:            if (argv[1][0] == 0) {
        !           593:                slavePtr->flags &= ~(CHILD_REL_WIDTH|CHILD_WIDTH);
        !           594:            } else {
        !           595:                if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
        !           596:                        &slavePtr->width) != TCL_OK) {
        !           597:                    result = TCL_ERROR;
        !           598:                    goto done;
        !           599:                }
        !           600:                slavePtr->flags &= ~CHILD_REL_WIDTH;
        !           601:                slavePtr->flags |= CHILD_WIDTH;
        !           602:            }
        !           603:        } else if ((c == 'x') && (strncmp(argv[0], "-x", length) == 0)) {
        !           604:            if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
        !           605:                    &slavePtr->x) != TCL_OK) {
        !           606:                result = TCL_ERROR;
        !           607:                goto done;
        !           608:            }
        !           609:            slavePtr->flags &= ~CHILD_REL_X;
        !           610:        } else if ((c == 'y') && (strncmp(argv[0], "-y", length) == 0)) {
        !           611:            if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
        !           612:                    &slavePtr->y) != TCL_OK) {
        !           613:                result = TCL_ERROR;
        !           614:                goto done;
        !           615:            }
        !           616:            slavePtr->flags &= ~CHILD_REL_Y;
        !           617:        } else {
        !           618:            Tcl_AppendResult(interp, "unknown or ambiguous option \"",
        !           619:                    argv[0], "\": must be -anchor, -bordermode, -height, ",
        !           620:                    "-in, -relheight, -relwidth, -relx, -rely, -width, ",
        !           621:                    "-x, or -y", (char *) NULL);
        !           622:            result = TCL_ERROR;
        !           623:            goto done;
        !           624:        }
        !           625:     }
        !           626: 
        !           627:     /*
        !           628:      * If there's no master specified for this slave, use its Tk_Parent.
        !           629:      * Then arrange for a placement recalculation in the master.
        !           630:      */
        !           631: 
        !           632:     done:
        !           633:     masterPtr = slavePtr->masterPtr;
        !           634:     if (masterPtr == NULL) {
        !           635:        masterPtr = FindMaster(Tk_Parent(slavePtr->tkwin));
        !           636:        slavePtr->masterPtr = masterPtr;
        !           637:        slavePtr->nextPtr = masterPtr->slavePtr;
        !           638:        masterPtr->slavePtr = slavePtr;
        !           639:     }
        !           640:     if (!(masterPtr->flags & PARENT_RECONFIG_PENDING)) {
        !           641:        masterPtr->flags |= PARENT_RECONFIG_PENDING;
        !           642:        Tk_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr);
        !           643:     }
        !           644:     return result;
        !           645: }
        !           646: 
        !           647: /*
        !           648:  *----------------------------------------------------------------------
        !           649:  *
        !           650:  * RecomputePlacement --
        !           651:  *
        !           652:  *     This procedure is called as a when-idle handler.  It recomputes
        !           653:  *     the geometries of all the slaves of a given master.
        !           654:  *
        !           655:  * Results:
        !           656:  *     None.
        !           657:  *
        !           658:  * Side effects:
        !           659:  *     Windows may change size or shape.
        !           660:  *
        !           661:  *----------------------------------------------------------------------
        !           662:  */
        !           663: 
        !           664: static void
        !           665: RecomputePlacement(clientData)
        !           666:     ClientData clientData;     /* Pointer to Master record. */
        !           667: {
        !           668:     register Master *masterPtr = (Master *) clientData;
        !           669:     register Slave *slavePtr;
        !           670:     Tk_Window ancestor, realMaster;
        !           671:     int x, y, width, height;
        !           672:     int masterWidth, masterHeight, masterBW;
        !           673: 
        !           674:     masterPtr->flags &= ~PARENT_RECONFIG_PENDING;
        !           675: 
        !           676:     /*
        !           677:      * Iterate over all the slaves for the master.  Each slave's
        !           678:      * geometry can be computed independently of the other slaves.
        !           679:      */
        !           680: 
        !           681:     for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
        !           682:            slavePtr = slavePtr->nextPtr) {
        !           683:        /*
        !           684:         * Step 1: compute size and borderwidth of master, taking into
        !           685:         * account desired border mode.
        !           686:         */
        !           687: 
        !           688:        masterBW = 0;
        !           689:        masterWidth = Tk_Width(masterPtr->tkwin);
        !           690:        masterHeight = Tk_Height(masterPtr->tkwin);
        !           691:        if (slavePtr->borderMode == BM_INSIDE) {
        !           692:            masterBW = Tk_InternalBorderWidth(masterPtr->tkwin);
        !           693:        } else if (slavePtr->borderMode == BM_OUTSIDE) {
        !           694:            masterBW = -Tk_Changes(masterPtr->tkwin)->border_width;
        !           695:        }
        !           696:        masterWidth -= 2*masterBW;
        !           697:        masterHeight -= 2*masterBW;
        !           698: 
        !           699:        /*
        !           700:         * Step 2:  compute size of slave (outside dimensions including
        !           701:         * border) and location of anchor point within master.
        !           702:         */
        !           703: 
        !           704:        x = slavePtr->x;
        !           705:        if (slavePtr->flags & CHILD_REL_X) {
        !           706:            x = (slavePtr->relX*masterWidth) +
        !           707:                ((slavePtr->relX > 0) ? 0.5 : -0.5);
        !           708:        }
        !           709:        x += masterBW;
        !           710:        y = slavePtr->y;
        !           711:        if (slavePtr->flags & CHILD_REL_Y) {
        !           712:            y = (slavePtr->relY*masterHeight) +
        !           713:                ((slavePtr->relY > 0) ? 0.5 : -0.5);
        !           714:        }
        !           715:        y += masterBW;
        !           716:        if (slavePtr->flags & CHILD_REL_WIDTH) {
        !           717:            width = (slavePtr->relWidth*masterWidth) + 0.5;
        !           718:        } else if (slavePtr->flags & CHILD_WIDTH) {
        !           719:            width = slavePtr->width;
        !           720:        } else {
        !           721:            width = Tk_ReqWidth(slavePtr->tkwin)
        !           722:                    + 2*Tk_Changes(slavePtr->tkwin)->border_width;
        !           723:        }
        !           724:        if (slavePtr->flags & CHILD_REL_HEIGHT) {
        !           725:            height = (slavePtr->relHeight*masterHeight) + 0.5;
        !           726:        } else if (slavePtr->flags & CHILD_HEIGHT) {
        !           727:            height = slavePtr->height;
        !           728:        } else {
        !           729:            height = Tk_ReqHeight(slavePtr->tkwin)
        !           730:                    + 2*Tk_Changes(slavePtr->tkwin)->border_width;
        !           731:        }
        !           732: 
        !           733:        /*
        !           734:         * Step 3: adjust the x and y positions so that the desired
        !           735:         * anchor point on the slave appears at that position.  Also
        !           736:         * adjust for the border mode and master's border.
        !           737:         */
        !           738: 
        !           739:        switch (slavePtr->anchor) {
        !           740:            case TK_ANCHOR_N:
        !           741:                x -= width/2;
        !           742:                break;
        !           743:            case TK_ANCHOR_NE:
        !           744:                x -= width;
        !           745:                break;
        !           746:            case TK_ANCHOR_E:
        !           747:                x -= width;
        !           748:                y -= height/2;
        !           749:                break;
        !           750:            case TK_ANCHOR_SE:
        !           751:                x -= width;
        !           752:                y -= height;
        !           753:                break;
        !           754:            case TK_ANCHOR_S:
        !           755:                x -= width/2;
        !           756:                y -= height;
        !           757:                break;
        !           758:            case TK_ANCHOR_SW:
        !           759:                y -= height;
        !           760:                break;
        !           761:            case TK_ANCHOR_W:
        !           762:                y -= height/2;
        !           763:                break;
        !           764:            case TK_ANCHOR_NW:
        !           765:                break;
        !           766:            case TK_ANCHOR_CENTER:
        !           767:                x -= width/2;
        !           768:                y -= height/2;
        !           769:                break;
        !           770:        }
        !           771: 
        !           772:        /*
        !           773:         * Step 4: if masterPtr isn't actually the X master of slavePtr,
        !           774:         * then translate the x and y coordinates back into the coordinate
        !           775:         * system of masterPtr.
        !           776:         */
        !           777: 
        !           778:        for (ancestor = masterPtr->tkwin,
        !           779:                realMaster = Tk_Parent(slavePtr->tkwin);
        !           780:                ancestor != realMaster; ancestor = Tk_Parent(ancestor)) {
        !           781:            x += Tk_X(ancestor) + Tk_Changes(ancestor)->border_width;
        !           782:            y += Tk_Y(ancestor) + Tk_Changes(ancestor)->border_width;
        !           783:        }
        !           784: 
        !           785:        /*
        !           786:         * Step 5: adjust width and height again to reflect inside dimensions
        !           787:         * of window rather than outside.  Also make sure that the width and
        !           788:         * height aren't zero.
        !           789:         */
        !           790: 
        !           791:        width -= 2*Tk_Changes(slavePtr->tkwin)->border_width;
        !           792:        height -= 2*Tk_Changes(slavePtr->tkwin)->border_width;
        !           793:        if (width <= 0) {
        !           794:            width = 1;
        !           795:        }
        !           796:        if (height <= 0) {
        !           797:            height = 1;
        !           798:        }
        !           799: 
        !           800:        /*
        !           801:         * Step 6: see if the window's size or location has changed;  if
        !           802:         * so then tell X to reconfigure it.
        !           803:         */
        !           804: 
        !           805:        if ((x != Tk_X(slavePtr->tkwin))
        !           806:                || (y != Tk_Y(slavePtr->tkwin))
        !           807:                || (width != Tk_Width(slavePtr->tkwin))
        !           808:                || (height != Tk_Height(slavePtr->tkwin))) {
        !           809:            Tk_MoveResizeWindow(slavePtr->tkwin, x, y,
        !           810:                    (unsigned int) width, (unsigned int) height);
        !           811:        }
        !           812:        Tk_MapWindow(slavePtr->tkwin);
        !           813:     }
        !           814: }
        !           815: 
        !           816: /*
        !           817:  *----------------------------------------------------------------------
        !           818:  *
        !           819:  * MasterStructureProc --
        !           820:  *
        !           821:  *     This procedure is invoked by the Tk event handler when
        !           822:  *     StructureNotify events occur for a master window.
        !           823:  *
        !           824:  * Results:
        !           825:  *     None.
        !           826:  *
        !           827:  * Side effects:
        !           828:  *     Structures get cleaned up if the window was deleted.  If the
        !           829:  *     window was resized then slave geometries get recomputed.
        !           830:  *
        !           831:  *----------------------------------------------------------------------
        !           832:  */
        !           833: 
        !           834: static void
        !           835: MasterStructureProc(clientData, eventPtr)
        !           836:     ClientData clientData;     /* Pointer to Master structure for window
        !           837:                                 * referred to by eventPtr. */
        !           838:     XEvent *eventPtr;          /* Describes what just happened. */
        !           839: {
        !           840:     register Master *masterPtr = (Master *) clientData;
        !           841:     register Slave *slavePtr, *nextPtr;
        !           842: 
        !           843:     if (eventPtr->type == ConfigureNotify) {
        !           844:        if ((masterPtr->slavePtr != NULL)
        !           845:                && !(masterPtr->flags & PARENT_RECONFIG_PENDING)) {
        !           846:            masterPtr->flags |= PARENT_RECONFIG_PENDING;
        !           847:            Tk_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr);
        !           848:        }
        !           849:     } else if (eventPtr->type == DestroyNotify) {
        !           850:        for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
        !           851:                slavePtr = nextPtr) {
        !           852:            slavePtr->masterPtr = NULL;
        !           853:            nextPtr = slavePtr->nextPtr;
        !           854:            slavePtr->nextPtr = NULL;
        !           855:        }
        !           856:        Tcl_DeleteHashEntry(Tcl_FindHashEntry(&masterTable,
        !           857:                (char *) masterPtr->tkwin));
        !           858:        if (masterPtr->flags & PARENT_RECONFIG_PENDING) {
        !           859:            Tk_CancelIdleCall(RecomputePlacement, (ClientData) masterPtr);
        !           860:        }
        !           861:        masterPtr->tkwin = NULL;
        !           862:        ckfree((char *) masterPtr);
        !           863:     }
        !           864: }
        !           865: 
        !           866: /*
        !           867:  *----------------------------------------------------------------------
        !           868:  *
        !           869:  * SlaveStructureProc --
        !           870:  *
        !           871:  *     This procedure is invoked by the Tk event handler when
        !           872:  *     StructureNotify events occur for a slave window.
        !           873:  *
        !           874:  * Results:
        !           875:  *     None.
        !           876:  *
        !           877:  * Side effects:
        !           878:  *     Structures get cleaned up if the window was deleted.
        !           879:  *
        !           880:  *----------------------------------------------------------------------
        !           881:  */
        !           882: 
        !           883: static void
        !           884: SlaveStructureProc(clientData, eventPtr)
        !           885:     ClientData clientData;     /* Pointer to Slave structure for window
        !           886:                                 * referred to by eventPtr. */
        !           887:     XEvent *eventPtr;          /* Describes what just happened. */
        !           888: {
        !           889:     register Slave *slavePtr = (Slave *) clientData;
        !           890: 
        !           891:     if (eventPtr->type == DestroyNotify) {
        !           892:        UnlinkSlave(slavePtr);
        !           893:        Tcl_DeleteHashEntry(Tcl_FindHashEntry(&slaveTable,
        !           894:                (char *) slavePtr->tkwin));
        !           895:        ckfree((char *) slavePtr);
        !           896:     }
        !           897: }
        !           898: 
        !           899: /*
        !           900:  *----------------------------------------------------------------------
        !           901:  *
        !           902:  * PlaceRequestProc --
        !           903:  *
        !           904:  *     This procedure is invoked by Tk whenever a slave managed by us
        !           905:  *     changes its requested geometry.
        !           906:  *
        !           907:  * Results:
        !           908:  *     None.
        !           909:  *
        !           910:  * Side effects:
        !           911:  *     The window will get relayed out, if its requested size has
        !           912:  *     anything to do with its actual size.
        !           913:  *
        !           914:  *----------------------------------------------------------------------
        !           915:  */
        !           916: 
        !           917:        /* ARGSUSED */
        !           918: static void
        !           919: PlaceRequestProc(clientData, tkwin)
        !           920:     ClientData clientData;             /* Pointer to our record for slave. */
        !           921:     Tk_Window tkwin;                   /* Window that changed its desired
        !           922:                                         * size. */
        !           923: {
        !           924:     Slave *slavePtr = (Slave *) clientData;
        !           925:     Master *masterPtr;
        !           926: 
        !           927:     if (((slavePtr->flags & (CHILD_WIDTH|CHILD_REL_WIDTH)) != 0)
        !           928:            && ((slavePtr->flags & (CHILD_HEIGHT|CHILD_REL_HEIGHT)) != 0)) {
        !           929:        return;
        !           930:     }
        !           931:     masterPtr = slavePtr->masterPtr;
        !           932:     if (masterPtr == NULL) {
        !           933:        return;
        !           934:     }
        !           935:     if (!(masterPtr->flags & PARENT_RECONFIG_PENDING)) {
        !           936:        masterPtr->flags |= PARENT_RECONFIG_PENDING;
        !           937:        Tk_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr);
        !           938:     }
        !           939: }

unix.superglobalmegacorp.com

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