Annotation of micropolis/src/tk/tkplace.c, revision 1.1.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.