Annotation of micropolis/src/tk/tkwm.c, revision 1.1.1.1

1.1       root        1: /* 
                      2:  * tkWm.c --
                      3:  *
                      4:  *     This module takes care of the interactions between a Tk-based
                      5:  *     application and the window manager.  Among other things, it
                      6:  *     implements the "wm" command and passes geometry information
                      7:  *     to the window manager.
                      8:  *
                      9:  * Copyright 1991 Regents of the University of California.
                     10:  * Permission to use, copy, modify, and distribute this
                     11:  * software and its documentation for any purpose and without
                     12:  * fee is hereby granted, provided that the above copyright
                     13:  * notice appear in all copies.  The University of California
                     14:  * makes no representations about the suitability of this
                     15:  * software for any purpose.  It is provided "as is" without
                     16:  * express or implied warranty.
                     17:  */
                     18: 
                     19: #ifndef lint
                     20: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkWm.c,v 1.32 92/08/21 16:26:31 ouster Exp $ SPRITE (Berkeley)";
                     21: #endif
                     22: 
                     23: #include "tkconfig.h"
                     24: #include "tkint.h"
                     25: #include "tkwm.h"
                     26: 
                     27: /*
                     28:  * The definitions below compensate for the lack of some definitions
                     29:  * under X11R3.
                     30:  */
                     31: 
                     32: #ifdef X11R3
                     33: #define PBaseSize      (1L<<8)
                     34: #endif
                     35: 
                     36: /*
                     37:  * A data structure of the following type holds window-manager-related
                     38:  * information for each top-level window in an application.
                     39:  */
                     40: 
                     41: typedef struct TkWmInfo {
                     42:     TkWindow *winPtr;          /* Pointer to main Tk information for
                     43:                                 * this window. */
                     44:     Window reparent;           /* If the window has been reparented, this
                     45:                                 * gives the ID of the ancestor of the window
                     46:                                 * that is a child of the root window (may
                     47:                                 * not be window's immediate parent).  If
                     48:                                 * the window isn't reparented, this has the
                     49:                                 * value None. */
                     50:     Tk_Uid titleUid;           /* Title to display in window caption.  If
                     51:                                 * NULL, use name of widget. */
                     52:     Tk_Uid iconName;           /* Name to display in icon. */
                     53:     Window master;             /* Master window for TRANSIENT_FOR property,
                     54:                                 * or None. */
                     55:     XWMHints hints;            /* Various pieces of information for
                     56:                                 * window manager. */
                     57:     Tk_Uid leaderName;         /* Path name of leader of window group
                     58:                                 * (corresponds to hints.window_group).
                     59:                                 * Note:  this field doesn't get updated
                     60:                                 * if leader is destroyed. */
                     61:     Tk_Uid iconWindowName;     /* Path name of window specified as icon
                     62:                                 * window for this window, or NULL.  Note:
                     63:                                 * this field doesn't get updated if
                     64:                                 * iconWindowName is destroyed. */
                     65:     Tk_Uid masterWindowName;   /* Path name of window specified as master
                     66:                                 * in "wm transient" command, or NULL.
                     67:                                 * Note:  this field doesn't get updated if
                     68:                                 * masterWindowName is destroyed. */
                     69: 
                     70:     /*
                     71:      * Information used to construct an XSizeHints structure for
                     72:      * the window manager:
                     73:      */
                     74: 
                     75:     int sizeHintsFlags;                /* Flags word for XSizeHints structure.
                     76:                                 * If the PBaseSize flag is set then the
                     77:                                 * window is gridded;  otherwise it isn't
                     78:                                 * gridded. */
                     79:     int minWidth, minHeight;   /* Minimum dimensions of window, in
                     80:                                 * grid units, not pixels. */
                     81:     int maxWidth, maxHeight;   /* Maximum dimensions of window, in
                     82:                                 * grid units, not pixels. */
                     83:     int widthInc, heightInc;   /* Increments for size changes (# pixels
                     84:                                 * per step). */
                     85:     struct {
                     86:        int x;  /* numerator */
                     87:        int y;  /* denominator */
                     88:     } minAspect, maxAspect;    /* Min/max aspect ratios for window. */
                     89:     int reqGridWidth, reqGridHeight;
                     90:                                /* The dimensions of the window (in
                     91:                                 * grid units) requested through
                     92:                                 * the geometry manager. */
                     93:     int gravity;               /* Desired window gravity. */
                     94: 
                     95:     /*
                     96:      * Information used to manage the size and location of a window.
                     97:      */
                     98: 
                     99:     int prevReqWidth, prevReqHeight;
                    100:                                /* Last known size preferences, as specified
                    101:                                 * to Tk_GeometryRequest.  Used to tell when
                    102:                                 * the preferred dimensions have changed. */
                    103:     int width, height;         /* Desired dimensions of window, specified
                    104:                                 * in grid units.  These values are
                    105:                                 * set by the "wm geometry" command and by
                    106:                                 * ConfigureNotify events (for when wm
                    107:                                 * resizes window).  -1 means user hasn't
                    108:                                 * requested dimensions. */
                    109:     int x, y;                  /* Desired X and Y coordinates for window.
                    110:                                 * These values are set by "wm geometry",
                    111:                                 * plus by ConfigureNotify events (when wm
                    112:                                 * moves window).  These numbers are
                    113:                                 * different than the numbers stored in
                    114:                                 * winPtr->changes because (a) they could be
                    115:                                 * measured from the right or bottom edge
                    116:                                 * of the screen (see WM_NEGATIVE_X and
                    117:                                 * WM_NEGATIVE_Y flags) and (b) if the window
                    118:                                 * has been reparented then they refer to the
                    119:                                 * parent rather than the window itself. */
                    120:     int parentWidth, parentHeight;
                    121:                                /* Width and height of reparent, in pixels
                    122:                                 * *including border*.  If window hasn't been
                    123:                                 * reparented then these will be the outer
                    124:                                 * dimensions of the window, including
                    125:                                 * border. */
                    126:     int xInParent, yInParent;  /* Offset of window within reparent,  measured
                    127:                                 * from upper-left outer corner of parent's
                    128:                                 * border.  If not reparented then these are
                    129:                                 * zero. */
                    130:     unsigned long configRequest;/* Serial number of last request that we
                    131:                                 * issued to change geometry of window.
                    132:                                 * Used to discard configure events that
                    133:                                 * we know will be superceded. */
                    134:     int configWidth, configHeight;
                    135:                                /* Dimensions passed to last request that we
                    136:                                 * issued to change geometry of window.  Used
                    137:                                 * to eliminate redundant resize operations. */
                    138: 
                    139:     int flags;                 /* Miscellaneous flags, defined below. */
                    140: 
                    141:     char *deleteCmd;            /* Command to execute when a WM_DELETE_WINDOW
                    142:                                 * ICCCM ClientMessage arrives for this window.
                    143:                                 *
                    144:                                 * If it is the empty string "" or has never
                    145:                                 * been set (is char *)NULL) via the "wm" tcl
                    146:                                 * command the window is destroyed.
                    147:                                 *
                    148:                                 * If it is a non-empty string, the name of 
                    149:                                 * the window is appended on to the end
                    150:                                 * of the string and it is executed
                    151:                                 * within the interpreter associated with
                    152:                                 * the top level window. 
                    153:                                 */
                    154:     struct TkWmInfo *nextPtr;  /* Next in list of all top-level windows. */
                    155: } WmInfo;
                    156: 
                    157: /*
                    158:  * Flag values for WmInfo structures:
                    159:  *
                    160:  * WM_NEVER_MAPPED -           non-zero means window has never been
                    161:  *                             mapped;  need to update all info when
                    162:  *                             window is first mapped.
                    163:  * WM_UPDATE_PENDING -         non-zero means a call to UpdateGeometryInfo
                    164:  *                             has already been scheduled for this
                    165:  *                             window;  no need to schedule another one.
                    166:  * WM_NEGATIVE_X -             non-zero means x-coordinate is measured in
                    167:  *                             pixels from right edge of screen, rather
                    168:  *                             than from left edge.
                    169:  * WM_NEGATIVE_Y -             non-zero means y-coordinate is measured in
                    170:  *                             pixels up from bottom of screen, rather than
                    171:  *                             down from top.
                    172:  * WM_UPDATE_SIZE_HINTS -      non-zero means that new size hints need to be
                    173:  *                             propagated to window manager.
                    174:  * WM_NESTED_REPARENT -                non-zero means that the window has been
                    175:  *                             reparented several levels deep in a hierarchy
                    176:  *                             (i.e. reparent isn't the window's immediate
                    177:  *                             parent).
                    178:  * WM_CONFIG_PENDING -         non-zero means we've asked for the top-level
                    179:  *                             window to be resized but haven't seen a
                    180:  *                             ConfigureNotify event to indicate that the
                    181:  *                             resize occurred.
                    182:  * WM_CONFIG_AGAIN -           non-zero means we need to reconfigure the
                    183:  *                             window again as soon as the current configure
                    184:  *                             request has been processed by the window
                    185:  *                             manager.
                    186:  * WM_FULL_SCREEN -            non-zero means that the window is in full screen mode.
                    187:  */
                    188: 
                    189: #define WM_NEVER_MAPPED                1
                    190: #define WM_UPDATE_PENDING      2
                    191: #define WM_NEGATIVE_X          4
                    192: #define WM_NEGATIVE_Y          8
                    193: #define WM_UPDATE_SIZE_HINTS   0x10
                    194: #define WM_NESTED_REPARENT     0x20
                    195: #define WM_CONFIG_PENDING      0x40
                    196: #define WM_CONFIG_AGAIN                0x100
                    197: #define WM_FULL_SCREEN         0x200
                    198: 
                    199: /*
                    200:  * This module keeps a list of all top-level windows, primarily to
                    201:  * simplify the job of Tk_CoordsToWindow.
                    202:  */
                    203: 
                    204: static WmInfo *firstWmPtr = NULL;      /* Points to first top-level window. */
                    205: 
                    206: #define IS_GRIDDED(wmPtr) ((wmPtr)->sizeHintsFlags & PBaseSize)
                    207: 
                    208: /*
                    209:  * Forward declarations for procedures defined in this file:
                    210:  */
                    211: 
                    212: static int             ParseGeometry _ANSI_ARGS_ ((Tcl_Interp *interp,
                    213:                            char *string, TkWindow *winPtr));
                    214: static void            TopLevelEventProc _ANSI_ARGS_((ClientData clientData,
                    215:                            XEvent *eventPtr));
                    216: static void            TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
                    217:                            Tk_Window tkwin));
                    218: static void            UpdateGeometryInfo _ANSI_ARGS_((
                    219:                            ClientData clientData));
                    220: static void            UpdateHints _ANSI_ARGS_((TkWindow *winPtr));
                    221: static void            UpdateSizeHints _ANSI_ARGS_((TkWindow *winPtr));
                    222: 
                    223: /*
                    224:  *--------------------------------------------------------------
                    225:  *
                    226:  * TkWmNewWindow --
                    227:  *
                    228:  *     This procedure is invoked whenever a new top-level
                    229:  *     window is created.  Its job is to initialize the WmInfo
                    230:  *     structure for the window.
                    231:  *
                    232:  * Results:
                    233:  *     None.
                    234:  *
                    235:  * Side effects:
                    236:  *     A WmInfo structure gets allocated and initialized.
                    237:  *
                    238:  *--------------------------------------------------------------
                    239:  */
                    240: 
                    241: void
                    242: TkWmNewWindow(winPtr)
                    243:     TkWindow *winPtr;          /* Newly-created top-level window. */
                    244: {
                    245:     register WmInfo *wmPtr;
                    246: 
                    247:     wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
                    248:     wmPtr->winPtr = winPtr;
                    249:     wmPtr->reparent = None;
                    250:     wmPtr->titleUid = NULL;
                    251:     wmPtr->iconName = NULL;
                    252:     wmPtr->master = None;
                    253:     wmPtr->hints.flags = InputHint | StateHint;
                    254:     wmPtr->hints.input = True;
                    255:     wmPtr->hints.initial_state = NormalState;
                    256:     wmPtr->hints.icon_pixmap = None;
                    257:     wmPtr->hints.icon_window = None;
                    258:     wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
                    259:     wmPtr->hints.icon_mask = None;
                    260:     wmPtr->hints.window_group = None;
                    261:     wmPtr->leaderName = NULL;
                    262:     wmPtr->iconWindowName = NULL;
                    263:     wmPtr->masterWindowName = NULL;
                    264:     wmPtr->sizeHintsFlags = 0;
                    265:     wmPtr->minWidth = wmPtr->minHeight = 0;
                    266:     wmPtr->maxWidth = wmPtr->maxHeight = 10000;
                    267:     wmPtr->widthInc = wmPtr->heightInc = 1;
                    268:     wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
                    269:     wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
                    270:     wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
                    271:     wmPtr->prevReqWidth = wmPtr->prevReqHeight = -1;
                    272:     wmPtr->gravity = NorthWestGravity;
                    273:     wmPtr->width = -1;
                    274:     wmPtr->height = -1;
                    275:     wmPtr->x = winPtr->changes.x;
                    276:     wmPtr->y = winPtr->changes.y;
                    277:     wmPtr->parentWidth = winPtr->changes.width
                    278:            + 2*winPtr->changes.border_width;
                    279:     wmPtr->parentHeight = winPtr->changes.height
                    280:            + 2*winPtr->changes.border_width;
                    281:     wmPtr->xInParent = wmPtr->yInParent = 0;
                    282:     wmPtr->configRequest = 0;
                    283:     wmPtr->configWidth = -1;
                    284:     wmPtr->configHeight = -1;
                    285:     wmPtr->flags = WM_NEVER_MAPPED;
                    286:     wmPtr->deleteCmd = (char *)0;
                    287:     wmPtr->nextPtr = firstWmPtr;
                    288:     firstWmPtr = wmPtr;
                    289:     winPtr->wmInfoPtr = wmPtr;
                    290: 
                    291:     /*
                    292:      * Tk must monitor certain events for top-level windows:
                    293:      * (a) structure events, in order to detect size and position changes
                    294:      *     caused by window managers.
                    295:      * (b) enter/level events, in order to perform focussing correctly.
                    296:      */
                    297: 
                    298:     Tk_CreateEventHandler((Tk_Window) winPtr,
                    299:            StructureNotifyMask|EnterWindowMask|LeaveWindowMask,
                    300:            TopLevelEventProc, (ClientData) winPtr);
                    301: 
                    302:     /*
                    303:      * Arrange for geometry requests to be reflected from the window
                    304:      * to the window manager.
                    305:      */
                    306: 
                    307:     Tk_ManageGeometry((Tk_Window) winPtr, TopLevelReqProc, (ClientData) 0);
                    308: }
                    309: 
                    310: /*
                    311:  *--------------------------------------------------------------
                    312:  *
                    313:  * TkWmMapWindow --
                    314:  *
                    315:  *     This procedure is invoked just before a top-level window
                    316:  *     is mapped.  It gives this module a chance to update all
                    317:  *     window-manager-related information in properties before
                    318:  *     the window manager sees the map event and checks the
                    319:  *     properties.
                    320:  *
                    321:  * Results:
                    322:  *     Returns non-zero if it's OK for the window to be mapped, 0
                    323:  *     if the caller shouldn't map the window after all (e.g. because
                    324:  *     it has been withdrawn).
                    325:  *
                    326:  * Side effects:
                    327:  *     Properties of winPtr may get updated to provide up-to-date
                    328:  *     information to the window manager.
                    329:  *
                    330:  *--------------------------------------------------------------
                    331:  */
                    332: 
                    333: int
                    334: TkWmMapWindow(winPtr)
                    335:     TkWindow *winPtr;          /* Top-level window that's about to
                    336:                                 * be mapped. */
                    337: {
                    338:     register WmInfo *wmPtr = winPtr->wmInfoPtr;
                    339: #ifndef X11R3
                    340:     XTextProperty textProp;
                    341: #endif
                    342: 
                    343:     /*
                    344:      * Set the MAPPED flag if the window is going to appear in its normal
                    345:      * state:  if it's going to be iconified or withdrawn then it won't
                    346:      * ever be mapped.
                    347:      */
                    348: 
                    349:     if (wmPtr->hints.initial_state == NormalState) {
                    350:        winPtr->flags |= TK_MAPPED;
                    351:     }
                    352:     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
                    353:        return 1;
                    354:     }
                    355:     wmPtr->flags &= ~WM_NEVER_MAPPED;
                    356: 
                    357:     /*
                    358:      * This is the first time this window has ever been mapped.
                    359:      * Store all the window-manager-related information for the
                    360:      * window.
                    361:      */
                    362: 
                    363: #ifndef X11R3
                    364:     if (wmPtr->titleUid == NULL) {
                    365:        wmPtr->titleUid = winPtr->nameUid;
                    366:     }
                    367:     if (XStringListToTextProperty(&wmPtr->titleUid, 1, &textProp)  != 0) {
                    368:        XSetWMName(winPtr->display, winPtr->window, &textProp);
                    369:        XFree((char *) textProp.value);
                    370:     }
                    371: #endif
                    372: 
                    373:     TkWmSetClass(winPtr);
                    374:     TkWmSetWmProtocols(winPtr);
                    375: 
                    376:     if (wmPtr->iconName != NULL) {
                    377:        XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
                    378:     }
                    379: 
                    380:     if (wmPtr->master != None) {
                    381:        XSetTransientForHint(winPtr->display, winPtr->window, wmPtr->master);
                    382:     }
                    383: 
                    384:     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
                    385:     UpdateGeometryInfo((ClientData) winPtr);
                    386:     UpdateHints(winPtr);
                    387:     if (wmPtr->hints.initial_state == WithdrawnState) {
                    388:        return 0;
                    389:     }
                    390:     return 1;
                    391: }
                    392: 
                    393: /*
                    394:  *--------------------------------------------------------------
                    395:  *
                    396:  * TkWmDeadWindow --
                    397:  *
                    398:  *     This procedure is invoked when a top-level window is
                    399:  *     about to be deleted.  It cleans up the wm-related data
                    400:  *     structures for the window.
                    401:  *
                    402:  * Results:
                    403:  *     None.
                    404:  *
                    405:  * Side effects:
                    406:  *     The WmInfo structure for winPtr gets freed up.
                    407:  *
                    408:  *--------------------------------------------------------------
                    409:  */
                    410: 
                    411: void
                    412: TkWmDeadWindow(winPtr)
                    413:     TkWindow *winPtr;          /* Newly-created top-level window. */
                    414: {
                    415:     register WmInfo *wmPtr = winPtr->wmInfoPtr;
                    416: 
                    417:     if (wmPtr == NULL) {
                    418:        return;
                    419:     }
                    420:     if (firstWmPtr == wmPtr) {
                    421:        firstWmPtr = wmPtr->nextPtr;
                    422:     } else {
                    423:        register WmInfo *prevPtr;
                    424: 
                    425:        for (prevPtr = firstWmPtr; ; prevPtr = prevPtr->nextPtr) {
                    426:            if (prevPtr == NULL) {
                    427:                panic("couldn't unlink window in TkWmDeadWindow");
                    428:            }
                    429:            if (prevPtr->nextPtr == wmPtr) {
                    430:                prevPtr->nextPtr = wmPtr->nextPtr;
                    431:                break;
                    432:            }
                    433:        }
                    434:     }
                    435:     if (wmPtr->hints.flags & IconPixmapHint) {
                    436:        Tk_FreeBitmap(wmPtr->hints.icon_pixmap);
                    437:     }
                    438:     if (wmPtr->hints.flags & IconMaskHint) {
                    439:        Tk_FreeBitmap(wmPtr->hints.icon_mask);
                    440:     }
                    441:     if (wmPtr->flags & WM_UPDATE_PENDING) {
                    442:        Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
                    443:     }
                    444:     if (wmPtr->deleteCmd) {
                    445:         ckfree(wmPtr->deleteCmd);
                    446:     }
                    447:     ckfree((char *) wmPtr);
                    448:     winPtr->wmInfoPtr = NULL;
                    449: }
                    450: 
                    451: /*
                    452:  *--------------------------------------------------------------
                    453:  *
                    454:  * TkWmSetClass --
                    455:  *
                    456:  *     This procedure is invoked whenever a top-level window's
                    457:  *     class is changed.  If the window has been mapped then this
                    458:  *     procedure updates the window manager property for the
                    459:  *     class.  If the window hasn't been mapped, the update is
                    460:  *     deferred until just before the first mapping.
                    461:  *
                    462:  * Results:
                    463:  *     None.
                    464:  *
                    465:  * Side effects:
                    466:  *     A window property may get updated.
                    467:  *
                    468:  *--------------------------------------------------------------
                    469:  */
                    470: 
                    471: void
                    472: TkWmSetClass(winPtr)
                    473:     TkWindow *winPtr;          /* Newly-created top-level window. */
                    474: {
                    475:     if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
                    476:        return;
                    477:     }
                    478: 
                    479: #ifndef X11R3
                    480:     if (winPtr->classUid != NULL) {
                    481:        XClassHint *classPtr;
                    482: 
                    483:        classPtr = XAllocClassHint();
                    484:        classPtr->res_name = winPtr->nameUid;
                    485:        classPtr->res_class = winPtr->classUid;
                    486:        XSetClassHint(winPtr->display, winPtr->window, classPtr);
                    487:        XFree((char *) classPtr);
                    488:     }
                    489: #endif
                    490: }
                    491: 
                    492: /*
                    493:  *----------------------------------------------------------------------
                    494:  *
                    495:  * Tk_WmCmd --
                    496:  *
                    497:  *     This procedure is invoked to process the "wm" Tcl command.
                    498:  *     See the user documentation for details on what it does.
                    499:  *
                    500:  * Results:
                    501:  *     A standard Tcl result.
                    502:  *
                    503:  * Side effects:
                    504:  *     See the user documentation.
                    505:  *
                    506:  *----------------------------------------------------------------------
                    507:  */
                    508: 
                    509:        /* ARGSUSED */
                    510: int
                    511: Tk_WmCmd(clientData, interp, argc, argv)
                    512:     ClientData clientData;     /* Main window associated with
                    513:                                 * interpreter. */
                    514:     Tcl_Interp *interp;                /* Current interpreter. */
                    515:     int argc;                  /* Number of arguments. */
                    516:     char **argv;               /* Argument strings. */
                    517: {
                    518:     Tk_Window tkwin = (Tk_Window) clientData;
                    519:     TkWindow *winPtr;
                    520:     register WmInfo *wmPtr;
                    521:     char c;
                    522:     int length;
                    523: 
                    524:     if (argc < 3) {
                    525:        Tcl_AppendResult(interp, "wrong # args: should be \"",
                    526:                argv[0], " option window ?arg ...?\"", (char *) NULL);
                    527:        return TCL_ERROR;
                    528:     }
                    529:     winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
                    530:     if (winPtr == NULL) {
                    531:        return TCL_ERROR;
                    532:     }
                    533:     if (!(winPtr->flags & TK_TOP_LEVEL)) {
                    534:        Tcl_AppendResult(interp, "window \"", winPtr->pathName,
                    535:                "\" isn't a top-level window", (char *) NULL);
                    536:        return TCL_ERROR;
                    537:     }
                    538:     wmPtr = winPtr->wmInfoPtr;
                    539:     c = argv[1][0];
                    540:     length = strlen(argv[1]);
                    541:     if ((c == 'a') && (strncmp(argv[1], "aspect", length) == 0)) {
                    542:        int numer1, denom1, numer2, denom2;
                    543: 
                    544:        if ((argc != 3) && (argc != 7)) {
                    545:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    546:                    argv[0], " aspect window ?minNumer minDenom ",
                    547:                    "maxNumer maxDenom?\"", (char *) NULL);
                    548:            return TCL_ERROR;
                    549:        }
                    550:        if (argc == 3) {
                    551:            if (wmPtr->sizeHintsFlags & PAspect) {
                    552:                sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x,
                    553:                        wmPtr->minAspect.y, wmPtr->maxAspect.x,
                    554:                        wmPtr->maxAspect.y);
                    555:            }
                    556:            return TCL_OK;
                    557:        }
                    558:        if (*argv[3] == '\0') {
                    559:            wmPtr->sizeHintsFlags &= ~PAspect;
                    560:        } else {
                    561:            if ((Tcl_GetInt(interp, argv[3], &numer1) != TCL_OK)
                    562:                    || (Tcl_GetInt(interp, argv[4], &denom1) != TCL_OK)
                    563:                    || (Tcl_GetInt(interp, argv[5], &numer2) != TCL_OK)
                    564:                    || (Tcl_GetInt(interp, argv[6], &denom2) != TCL_OK)) {
                    565:                return TCL_ERROR;
                    566:            }
                    567:            if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
                    568:                    (denom2 <= 0)) {
                    569:                interp->result = "aspect number can't be <= 0";
                    570:                return TCL_ERROR;
                    571:            }
                    572:            wmPtr->minAspect.x = numer1;
                    573:            wmPtr->minAspect.y = denom1;
                    574:            wmPtr->maxAspect.x = numer2;
                    575:            wmPtr->maxAspect.y = denom2;
                    576:            wmPtr->sizeHintsFlags |= PAspect;
                    577:        }
                    578:        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
                    579:        goto updateGeom;
                    580:     } else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) {
                    581:        if (argc != 3) {
                    582:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    583:                    argv[0], " deiconify window\"", (char *) NULL);
                    584:            return TCL_ERROR;
                    585:        }
                    586:        wmPtr->hints.initial_state = NormalState;
                    587:        if (wmPtr->flags & WM_NEVER_MAPPED) {
                    588:            return TCL_OK;
                    589:        }
                    590:        Tk_MapWindow((Tk_Window) winPtr);
                    591:     } else if ((c == 'f') && (strncmp(argv[1], "focusmodel", length) == 0)) {
                    592:        if ((argc != 3) && (argc != 4)) {
                    593:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    594:                    argv[0], " focusmodel window ?active|passive?\"",
                    595:                    (char *) NULL);
                    596:            return TCL_ERROR;
                    597:        }
                    598:        if (argc == 3) {
                    599:            interp->result = wmPtr->hints.input ? "passive" : "active";
                    600:            return TCL_OK;
                    601:        }
                    602:        c = argv[3][0];
                    603:        length = strlen(argv[3]);
                    604:        if ((c == 'a') && (strncmp(argv[3], "active", length) == 0)) {
                    605:            wmPtr->hints.input = False;
                    606:        } else if ((c == 'p') && (strncmp(argv[3], "passive", length) == 0)) {
                    607:            wmPtr->hints.input = True;
                    608:        } else {
                    609:            Tcl_AppendResult(interp, "bad argument \"", argv[3],
                    610:                    "\": must be active or passive", (char *) NULL);
                    611:            return TCL_ERROR;
                    612:        }
                    613:        UpdateHints(winPtr);
                    614:     } else if ((c == 'f') && (strncmp(argv[1], "fullscreen", length) == 0)) {
                    615:        if (argc != 4) {
                    616:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    617:                    argv[0], " fullscreen window on|off\"",
                    618:                    (char *) NULL);
                    619:            return TCL_ERROR;
                    620:        }
                    621:        c = argv[3][0];
                    622:        length = strlen(argv[3]);
                    623:        if (strncmp(argv[3], "on", length) == 0) {
                    624:            wmPtr->flags &= ~WM_FULL_SCREEN;
                    625:        } else if (strncmp(argv[3], "off", length) == 0) {
                    626:            wmPtr->flags |= WM_FULL_SCREEN;
                    627:        } else {
                    628:            Tcl_AppendResult(interp, "bad argument \"", argv[3],
                    629:                    "\": must be on or off", (char *) NULL);
                    630:            return TCL_ERROR;
                    631:        }
                    632: 
                    633:        static Atom _NET_WM_STATE;
                    634:        static Atom _NET_WM_STATE_REMOVE;
                    635:        static Atom _NET_WM_STATE_ADD;
                    636:        static Atom _NET_WM_STATE_FULLSCREEN;
                    637: 
                    638:        if (!_NET_WM_STATE) {
                    639: #define MAX_ATOMS 30
                    640:          Atom *atom_ptr[MAX_ATOMS];
                    641:          char *names[MAX_ATOMS];
                    642:          int i = 0;
                    643: #define atom(a,b) atom_ptr[i] = &a; names[i] = b; i++
                    644:          atom(_NET_WM_STATE, "_NET_WM_STATE");
                    645:          atom(_NET_WM_STATE_REMOVE, "_NET_WM_STATE_REMOVE");
                    646:          atom(_NET_WM_STATE_ADD, "_NET_WM_STATE_ADD");
                    647:          atom(_NET_WM_STATE_FULLSCREEN, "_NET_WM_STATE_FULLSCREEN");
                    648: #undef atom
                    649:          Atom atoms[MAX_ATOMS];
                    650:          XInternAtoms(winPtr->display, names, i, 0, atoms);
                    651:          for (; i--;) {
                    652:            *atom_ptr[i] = atoms[i];
                    653:          }
                    654:        }
                    655: 
                    656:        XEvent e;
                    657:        e.xany.type = ClientMessage;
                    658:        e.xany.window = winPtr->window;
                    659:        e.xclient.message_type = _NET_WM_STATE;
                    660:        e.xclient.format = 32;
                    661:        e.xclient.data.l[0] = 
                    662:          (wmPtr->flags & WM_FULL_SCREEN)
                    663:            ? _NET_WM_STATE_ADD
                    664:            : _NET_WM_STATE_REMOVE;
                    665:        e.xclient.data.l[1] = (long)_NET_WM_STATE_FULLSCREEN;
                    666:        e.xclient.data.l[2] = (long)0;
                    667:        e.xclient.data.l[3] = (long)0;
                    668:        e.xclient.data.l[4] = (long)0;
                    669:        XSendEvent(winPtr->display, RootWindow(winPtr->display, winPtr->screenNum), 0,
                    670:                   SubstructureNotifyMask|SubstructureRedirectMask, &e);
                    671: 
                    672:     } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0)
                    673:            && (length >= 2)) {
                    674:        char xSign, ySign;
                    675:        int width, height;
                    676: 
                    677:        if ((argc != 3) && (argc != 4)) {
                    678:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    679:                    argv[0], " geometry window ?newGeometry?\"",
                    680:                    (char *) NULL);
                    681:            return TCL_ERROR;
                    682:        }
                    683:        if (argc == 3) {
                    684:            xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
                    685:            ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
                    686:            if (wmPtr->width != -1) {
                    687:                width = wmPtr->width;
                    688:                height = wmPtr->height;
                    689:            } else if (IS_GRIDDED(wmPtr)) {
                    690:                width = wmPtr->reqGridWidth;
                    691:                height = wmPtr->reqGridHeight;
                    692:            } else {
                    693:                width = winPtr->reqWidth;
                    694:                height = winPtr->reqHeight;
                    695:            }
                    696:            sprintf(interp->result, "%dx%d%c%d%c%d", width, height,
                    697:                    xSign, wmPtr->x, ySign, wmPtr->y);
                    698:            return TCL_OK;
                    699:        }
                    700:        if (*argv[3] == '\0') {
                    701:            wmPtr->width = -1;
                    702:            wmPtr->height = -1;
                    703:            goto updateGeom;
                    704:        }
                    705:        return ParseGeometry(interp, argv[3], winPtr);
                    706:     } else if ((c == 'g') && (strncmp(argv[1], "grid", length) == 0)
                    707:            && (length >= 3)) {
                    708:        int reqWidth, reqHeight, widthInc, heightInc;
                    709: 
                    710:        if ((argc != 3) && (argc != 7)) {
                    711:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    712:                    argv[0], " reqsize window ?baseWidth baseHeight ",
                    713:                    "widthInc heightInc?\"", (char *) NULL);
                    714:            return TCL_ERROR;
                    715:        }
                    716:        if (argc == 3) {
                    717:            if (wmPtr->sizeHintsFlags & PBaseSize) {
                    718:                sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth,
                    719:                        wmPtr->reqGridHeight, wmPtr->widthInc,
                    720:                        wmPtr->heightInc);
                    721:            }
                    722:            return TCL_OK;
                    723:        }
                    724:        if (*argv[3] == '\0') {
                    725:            /*
                    726:             * Turn off gridding and reset the width and height
                    727:             * to make sense as ungridded numbers.
                    728:             */
                    729: 
                    730:            wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
                    731:            wmPtr->widthInc = 1;
                    732:            wmPtr->heightInc = 1;
                    733:            if (wmPtr->width != -1) {
                    734:                wmPtr->width = winPtr->reqWidth + (wmPtr->width
                    735:                        - wmPtr->reqGridWidth)*wmPtr->widthInc;
                    736:                wmPtr->height = winPtr->reqHeight + (wmPtr->height
                    737:                        - wmPtr->reqGridHeight)*wmPtr->heightInc;
                    738:            }
                    739:        } else {
                    740:            if ((Tcl_GetInt(interp, argv[3], &reqWidth) != TCL_OK)
                    741:                    || (Tcl_GetInt(interp, argv[4], &reqHeight) != TCL_OK)
                    742:                    || (Tcl_GetInt(interp, argv[5], &widthInc) != TCL_OK)
                    743:                    || (Tcl_GetInt(interp, argv[6], &heightInc) != TCL_OK)) {
                    744:                return TCL_ERROR;
                    745:            }
                    746:            if (reqWidth < 0) {
                    747:                interp->result = "baseWidth can't be < 0";
                    748:                return TCL_ERROR;
                    749:            }
                    750:            if (reqHeight < 0) {
                    751:                interp->result = "baseHeight can't be < 0";
                    752:                return TCL_ERROR;
                    753:            }
                    754:            if (widthInc < 0) {
                    755:                interp->result = "widthInc can't be < 0";
                    756:                return TCL_ERROR;
                    757:            }
                    758:            if (heightInc < 0) {
                    759:                interp->result = "heightInc can't be < 0";
                    760:                return TCL_ERROR;
                    761:            }
                    762:            Tk_SetGrid((Tk_Window) tkwin, reqWidth, reqHeight, widthInc,
                    763:                    heightInc);
                    764:        }
                    765:        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
                    766:        goto updateGeom;
                    767:     } else if ((c == 'g') && (strncmp(argv[1], "group", length) == 0)
                    768:            && (length >= 3)) {
                    769:        Tk_Window tkwin2;
                    770: 
                    771:        if ((argc != 3) && (argc != 4)) {
                    772:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    773:                    argv[0], " group window ?pathName?\"",
                    774:                    (char *) NULL);
                    775:            return TCL_ERROR;
                    776:        }
                    777:        if (argc == 3) {
                    778:            if (wmPtr->hints.flags & WindowGroupHint) {
                    779:                interp->result = wmPtr->leaderName;
                    780:            }
                    781:            return TCL_OK;
                    782:        }
                    783:        if (*argv[3] == '\0') {
                    784:            wmPtr->hints.flags &= ~WindowGroupHint;
                    785:            wmPtr->leaderName = NULL;
                    786:        } else {
                    787:            tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
                    788:            if (tkwin2 == NULL) {
                    789:                return TCL_ERROR;
                    790:            }
                    791:            Tk_MakeWindowExist(tkwin2);
                    792:            wmPtr->hints.window_group = Tk_WindowId(tkwin2);
                    793:            wmPtr->hints.flags |= WindowGroupHint;
                    794:            wmPtr->leaderName = Tk_PathName(tkwin2);
                    795:        }
                    796:        UpdateHints(winPtr);
                    797:     } else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0)
                    798:            && (length >= 5)) {
                    799:        Pixmap pixmap;
                    800: 
                    801:        if ((argc != 3) && (argc != 4)) {
                    802:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    803:                    argv[0], " iconbitmap window ?bitmap?\"",
                    804:                    (char *) NULL);
                    805:            return TCL_ERROR;
                    806:        }
                    807:        if (argc == 3) {
                    808:            if (wmPtr->hints.flags & IconPixmapHint) {
                    809:                interp->result = Tk_NameOfBitmap(wmPtr->hints.icon_pixmap);
                    810:            }
                    811:            return TCL_OK;
                    812:        }
                    813:        if (*argv[3] == '\0') {
                    814:            if (wmPtr->hints.icon_pixmap != None) {
                    815:                Tk_FreeBitmap(wmPtr->hints.icon_pixmap);
                    816:            }
                    817:            wmPtr->hints.flags &= ~IconPixmapHint;
                    818:        } else {
                    819:            pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3]));
                    820:            if (pixmap == None) {
                    821:                return TCL_ERROR;
                    822:            }
                    823:            wmPtr->hints.icon_pixmap = pixmap;
                    824:            wmPtr->hints.flags |= IconPixmapHint;
                    825:        }
                    826:        UpdateHints(winPtr);
                    827:     } else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0)
                    828:            && (length >= 5)) {
                    829:        if (argc != 3) {
                    830:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    831:                    argv[0], " iconify window\"", (char *) NULL);
                    832:            return TCL_ERROR;
                    833:        }
                    834:        wmPtr->hints.initial_state = IconicState;
                    835:        if (wmPtr->flags & WM_NEVER_MAPPED) {
                    836:            return TCL_OK;
                    837:        }
                    838: #ifndef X11R3
                    839:        if (XIconifyWindow(winPtr->display, winPtr->window,
                    840:                winPtr->screenNum) == 0) {
                    841:            interp->result =
                    842:                    "couldn't send iconify message to window manager";
                    843:            return TCL_ERROR;
                    844:        }
                    845: #else
                    846:        interp->result = "can't iconify under X11R3";
                    847:        return TCL_ERROR;
                    848: #endif
                    849:     } else if ((c == 'i') && (strncmp(argv[1], "iconmask", length) == 0)
                    850:            && (length >= 5)) {
                    851:        Pixmap pixmap;
                    852: 
                    853:        if ((argc != 3) && (argc != 4)) {
                    854:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    855:                    argv[0], " iconmask window ?bitmap?\"",
                    856:                    (char *) NULL);
                    857:            return TCL_ERROR;
                    858:        }
                    859:        if (argc == 3) {
                    860:            if (wmPtr->hints.flags & IconMaskHint) {
                    861:                interp->result = Tk_NameOfBitmap(wmPtr->hints.icon_mask);
                    862:            }
                    863:            return TCL_OK;
                    864:        }
                    865:        if (*argv[3] == '\0') {
                    866:            if (wmPtr->hints.icon_mask != None) {
                    867:                Tk_FreeBitmap(wmPtr->hints.icon_mask);
                    868:            }
                    869:            wmPtr->hints.flags &= ~IconMaskHint;
                    870:        } else {
                    871:            pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3]));
                    872:            if (pixmap == None) {
                    873:                return TCL_ERROR;
                    874:            }
                    875:            wmPtr->hints.icon_mask = pixmap;
                    876:            wmPtr->hints.flags |= IconMaskHint;
                    877:        }
                    878:        UpdateHints(winPtr);
                    879:     } else if ((c == 'i') && (strncmp(argv[1], "iconname", length) == 0)
                    880:            && (length >= 5)) {
                    881:        if (argc > 4) {
                    882:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    883:                    argv[0], " iconname window ?newName?\"", (char *) NULL);
                    884:            return TCL_ERROR;
                    885:        }
                    886:        if (argc == 3) {
                    887:            interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : "";
                    888:            return TCL_OK;
                    889:        } else {
                    890:            wmPtr->iconName = Tk_GetUid(argv[3]);
                    891:            if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
                    892:                XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
                    893:            }
                    894:        }
                    895:     } else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0)
                    896:            && (length >= 5)) {
                    897:        int x, y;
                    898: 
                    899:        if ((argc != 3) && (argc != 5)) {
                    900:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    901:                    argv[0], " iconposition window ?x y?\"",
                    902:                    (char *) NULL);
                    903:            return TCL_ERROR;
                    904:        }
                    905:        if (argc == 3) {
                    906:            if (wmPtr->hints.flags & IconPositionHint) {
                    907:                sprintf(interp->result, "%d %d", wmPtr->hints.icon_x,
                    908:                        wmPtr->hints.icon_y);
                    909:            }
                    910:            return TCL_OK;
                    911:        }
                    912:        if (*argv[3] == '\0') {
                    913:            wmPtr->hints.flags &= ~IconPositionHint;
                    914:        } else {
                    915:            if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
                    916:                    || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
                    917:                return TCL_ERROR;
                    918:            }
                    919:            wmPtr->hints.icon_x = x;
                    920:            wmPtr->hints.icon_y = y;
                    921:            wmPtr->hints.flags |= IconPositionHint;
                    922:        }
                    923:        UpdateHints(winPtr);
                    924:     } else if ((c == 'i') && (strncmp(argv[1], "iconwindow", length) == 0)
                    925:            && (length >= 5)) {
                    926:        Tk_Window tkwin2;
                    927: 
                    928:        if ((argc != 3) && (argc != 4)) {
                    929:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    930:                    argv[0], " iconwindow window ?pathName?\"",
                    931:                    (char *) NULL);
                    932:            return TCL_ERROR;
                    933:        }
                    934:        if (argc == 3) {
                    935:            if (wmPtr->hints.flags & IconWindowHint) {
                    936:                interp->result = wmPtr->iconWindowName;
                    937:            }
                    938:            return TCL_OK;
                    939:        }
                    940:        if (*argv[3] == '\0') {
                    941:            wmPtr->hints.flags &= ~IconWindowHint;
                    942:            wmPtr->iconWindowName = NULL;
                    943:        } else {
                    944:            tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
                    945:            if (tkwin2 == NULL) {
                    946:                return TCL_ERROR;
                    947:            }
                    948:            Tk_MakeWindowExist(tkwin2);
                    949:            wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
                    950:            wmPtr->hints.flags |= IconWindowHint;
                    951:            wmPtr->iconWindowName = Tk_PathName(tkwin2);
                    952:        }
                    953:        UpdateHints(winPtr);
                    954:     } else if ((c == 'm') && (strncmp(argv[1], "maxsize", length) == 0)
                    955:            && (length >= 2)) {
                    956:        int width, height;
                    957:        if ((argc != 3) && (argc != 5)) {
                    958:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    959:                    argv[0], " maxsize window ?width height?\"", (char *) NULL);
                    960:            return TCL_ERROR;
                    961:        }
                    962:        if (argc == 3) {
                    963:            if (wmPtr->sizeHintsFlags & PMaxSize) {
                    964:                sprintf(interp->result, "%d %d", wmPtr->maxWidth,
                    965:                        wmPtr->maxHeight);
                    966:            }
                    967:            return TCL_OK;
                    968:        }
                    969:        if (*argv[3] == '\0') {
                    970:            wmPtr->sizeHintsFlags &= ~PMaxSize;
                    971:        } else {
                    972:            if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
                    973:                    || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
                    974:                return TCL_ERROR;
                    975:            }
                    976:            wmPtr->maxWidth = width;
                    977:            wmPtr->maxHeight = height;
                    978:            wmPtr->sizeHintsFlags |= PMaxSize;
                    979:        }
                    980:        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
                    981:        goto updateGeom;
                    982:     } else if ((c == 'm') && (strncmp(argv[1], "minsize", length) == 0)
                    983:            && (length >= 2)) {
                    984:        int width, height;
                    985:        if ((argc != 3) && (argc != 5)) {
                    986:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                    987:                    argv[0], " minsize window ?width height?\"", (char *) NULL);
                    988:            return TCL_ERROR;
                    989:        }
                    990:        if (argc == 3) {
                    991:            if (wmPtr->sizeHintsFlags & PMinSize) {
                    992:                sprintf(interp->result, "%d %d", wmPtr->minWidth,
                    993:                        wmPtr->minHeight);
                    994:            }
                    995:            return TCL_OK;
                    996:        }
                    997:        if (*argv[3] == '\0') {
                    998:            wmPtr->sizeHintsFlags &= ~PMinSize;
                    999:        } else {
                   1000:            if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
                   1001:                    || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
                   1002:                return TCL_ERROR;
                   1003:            }
                   1004:            wmPtr->minWidth = width;
                   1005:            wmPtr->minHeight = height;
                   1006:            wmPtr->sizeHintsFlags |= PMinSize;
                   1007:        }
                   1008:        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
                   1009:        goto updateGeom;
                   1010:     } else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0)) {
                   1011:        if ((argc != 3) && (argc != 4)) {
                   1012:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                   1013:                    argv[0], " positionfrom window ?user/program?\"",
                   1014:                    (char *) NULL);
                   1015:            return TCL_ERROR;
                   1016:        }
                   1017:        if (argc == 3) {
                   1018:            if (wmPtr->sizeHintsFlags & USPosition) {
                   1019:                interp->result = "user";
                   1020:            } else if (wmPtr->sizeHintsFlags & PPosition) {
                   1021:                interp->result = "program";
                   1022:            }
                   1023:            return TCL_OK;
                   1024:        }
                   1025:        if (*argv[3] == '\0') {
                   1026:            wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
                   1027:        } else {
                   1028:            c = argv[3][0];
                   1029:            length = strlen(argv[3]);
                   1030:            if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
                   1031:                wmPtr->sizeHintsFlags &= ~PPosition;
                   1032:                wmPtr->sizeHintsFlags |= USPosition;
                   1033:            } else if ((c == 'p') && (strncmp(argv[3], "program", length) == 0)) {
                   1034:                wmPtr->sizeHintsFlags &= ~USPosition;
                   1035:                wmPtr->sizeHintsFlags |= PPosition;
                   1036:            } else {
                   1037:                Tcl_AppendResult(interp, "bad argument \"", argv[3],
                   1038:                        "\": must be program or user", (char *) NULL);
                   1039:                return TCL_ERROR;
                   1040:            }
                   1041:        }
                   1042:        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
                   1043:        goto updateGeom;
                   1044:     } else if ((c == 'r') && (strncmp(argv[1], "raise", length) == 0)) {
                   1045:        if (argc != 3) {
                   1046:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                   1047:                    argv[0], " raise window\"", (char *) NULL);
                   1048:            return TCL_ERROR;
                   1049:        }
                   1050:        Tk_MakeWindowExist((Tk_Window) winPtr);
                   1051:        XRaiseWindow(Tk_Display(winPtr), Tk_WindowId(winPtr));
                   1052:     } else if ((c == 's') && (strncmp(argv[1], "sizefrom", length) == 0)) {
                   1053:        if ((argc != 3) && (argc != 4)) {
                   1054:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                   1055:                    argv[0], " sizefrom window ?user|program?\"",
                   1056:                    (char *) NULL);
                   1057:            return TCL_ERROR;
                   1058:        }
                   1059:        if (argc == 3) {
                   1060:            if (wmPtr->sizeHintsFlags & USSize) {
                   1061:                interp->result = "user";
                   1062:            } else if (wmPtr->sizeHintsFlags & PSize) {
                   1063:                interp->result = "program";
                   1064:            }
                   1065:            return TCL_OK;
                   1066:        }
                   1067:        if (*argv[3] == '\0') {
                   1068:            wmPtr->sizeHintsFlags &= ~(USSize|PSize);
                   1069:        } else {
                   1070:            c = argv[3][0];
                   1071:            length = strlen(argv[3]);
                   1072:            if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
                   1073:                wmPtr->sizeHintsFlags &= ~PSize;
                   1074:                wmPtr->sizeHintsFlags |= USSize;
                   1075:            } else if ((c == 'p')
                   1076:                    && (strncmp(argv[3], "program", length) == 0)) {
                   1077:                wmPtr->sizeHintsFlags &= ~USSize;
                   1078:                wmPtr->sizeHintsFlags |= PSize;
                   1079:            } else {
                   1080:                Tcl_AppendResult(interp, "bad argument \"", argv[3],
                   1081:                        "\": must be program or user", (char *) NULL);
                   1082:                return TCL_ERROR;
                   1083:            }
                   1084:        }
                   1085:        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
                   1086:        goto updateGeom;
                   1087:     } else if ((c == 't') && (strncmp(argv[1], "title", length) == 0)
                   1088:            && (length >= 2)) {
                   1089:        if (argc > 4) {
                   1090:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                   1091:                    argv[0], " title window ?newTitle?\"", (char *) NULL);
                   1092:            return TCL_ERROR;
                   1093:        }
                   1094:        if (argc == 3) {
                   1095:            interp->result = (wmPtr->titleUid != NULL) ? wmPtr->titleUid
                   1096:                    : winPtr->nameUid;
                   1097:            return TCL_OK;
                   1098:        } else {
                   1099:            wmPtr->titleUid = Tk_GetUid(argv[3]);
                   1100: #ifndef X11R3
                   1101:            if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
                   1102:                XTextProperty textProp;
                   1103: 
                   1104:                if (XStringListToTextProperty(&wmPtr->titleUid, 1,
                   1105:                        &textProp)  != 0) {
                   1106:                    XSetWMName(winPtr->display, winPtr->window, &textProp);
                   1107:                    XFree((char *) textProp.value);
                   1108:                }
                   1109:            }
                   1110: #endif
                   1111:        }
                   1112: #ifndef X11R3
                   1113:     } else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0)
                   1114:            && (length >= 2)) {
                   1115:        Tk_Window master;
                   1116: 
                   1117:        if ((argc != 3) && (argc != 4)) {
                   1118:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                   1119:                    argv[0], " transient window ?master?\"", (char *) NULL);
                   1120:            return TCL_ERROR;
                   1121:        }
                   1122:        if (argc == 3) {
                   1123:            if (wmPtr->master != None) {
                   1124:                interp->result = wmPtr->masterWindowName;
                   1125:            }
                   1126:            return TCL_OK;
                   1127:        }
                   1128:        if (argv[3][0] == '\0') {
                   1129:            wmPtr->master = None;
                   1130:            wmPtr->masterWindowName = NULL;
                   1131:        } else {
                   1132:            master = Tk_NameToWindow(interp, argv[3], tkwin);
                   1133:            if (master == NULL) {
                   1134:                return TCL_ERROR;
                   1135:            }
                   1136:            Tk_MakeWindowExist(master);
                   1137:            wmPtr->master = Tk_WindowId(master);
                   1138:            wmPtr->masterWindowName = Tk_PathName(master);
                   1139:        }
                   1140:        if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
                   1141:            XSetTransientForHint(winPtr->display, winPtr->window,
                   1142:                    wmPtr->master);
                   1143:        }
                   1144:     } else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)) {
                   1145:        if (argc != 3) {
                   1146:            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                   1147:                    argv[0], " withdraw window\"", (char *) NULL);
                   1148:            return TCL_ERROR;
                   1149:        }
                   1150:        wmPtr->hints.initial_state = WithdrawnState;
                   1151:        if (wmPtr->flags & WM_NEVER_MAPPED) {
                   1152:            return TCL_OK;
                   1153:        }
                   1154:        if (XWithdrawWindow(winPtr->display, winPtr->window,
                   1155:                winPtr->screenNum) == 0) {
                   1156:            interp->result =
                   1157:                    "couldn't send withdraw message to window manager";
                   1158:            return TCL_ERROR;
                   1159:        }
                   1160:        winPtr->flags &= ~TK_MAPPED;
                   1161:     } else if ((c == 'p') && (strncmp(argv[1], "protocol", length) == 0)) {
                   1162:        /*
                   1163:          * handle various ICCCM WM_PROTOCOL attributes
                   1164:          */
                   1165:         if (argc < 4) {
                   1166:             Tcl_AppendResult(interp, "wrong # arguments: must be \"",
                   1167:                     argv[0], " protocol window type..\"", (char *) NULL);
                   1168:             return TCL_ERROR;
                   1169:         }
                   1170:         if (!strcmp(argv[3], "delete")) {
                   1171:            return WmProtocolCmd(interp, &(wmPtr->deleteCmd), argc, argv);
                   1172:        } else {
                   1173:            Tcl_AppendResult(interp,  argv[0], 
                   1174:                ": bad argument ", argv[3], " must be: ", 
                   1175:                "delete", (char *) NULL);
                   1176:             return TCL_ERROR;
                   1177:        }
                   1178: #endif
                   1179:     } else {
                   1180:        Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
                   1181:                "\": must be aspect, deiconify, focusmodel, ",
                   1182:                "fullscreen, geometry, grid, group, iconbitmap, ",
                   1183:                "iconify, iconmask, iconname, iconposition, ",
                   1184:                "iconwindow, maxsize, minsize, positionfrom, raise, ",
                   1185:                "sizefrom,  title, transient, withdraw, or protocol",
                   1186:                (char *) NULL);
                   1187:        return TCL_ERROR;
                   1188:     }
                   1189:     return TCL_OK;
                   1190: 
                   1191:     updateGeom:
                   1192:     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
                   1193:        Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
                   1194:        wmPtr->flags |= WM_UPDATE_PENDING;
                   1195:     }
                   1196:     return TCL_OK;
                   1197: }
                   1198: 
                   1199: /*
                   1200:  *----------------------------------------------------------------------
                   1201:  *
                   1202:  * Tk_SetGrid --
                   1203:  *
                   1204:  *     This procedure is invoked by a widget when it wishes to set a grid
                   1205:  *     coordinate system that controls the size of a top-level window.
                   1206:  *     It provides a C interface equivalent to the "wm grid" command and
                   1207:  *     is usually asscoiated with the -setgrid option.
                   1208:  *
                   1209:  * Results:
                   1210:  *     None.
                   1211:  *
                   1212:  * Side effects:
                   1213:  *     Grid-related information will be passed to the window manager, so
                   1214:  *     that the top-level window associated with tkwin will resize on
                   1215:  *     even grid units.
                   1216:  *
                   1217:  *----------------------------------------------------------------------
                   1218:  */
                   1219: 
                   1220: void
                   1221: Tk_SetGrid(tkwin, reqWidth, reqHeight, widthInc, heightInc)
                   1222:     Tk_Window tkwin;           /* Token for window.  New window mgr info
                   1223:                                 * will be posted for the top-level window
                   1224:                                 * associated with this window. */
                   1225:     int reqWidth;              /* Width (in grid units) corresponding to
                   1226:                                 * the requested geometry for tkwin. */
                   1227:     int reqHeight;             /* Height (in grid units) corresponding to
                   1228:                                 * the requested geometry for tkwin. */
                   1229:     int widthInc, heightInc;   /* Pixel increments corresponding to a
                   1230:                                 * change of one grid unit. */
                   1231: {
                   1232:     TkWindow *winPtr = (TkWindow *) tkwin;
                   1233:     register WmInfo *wmPtr;
                   1234: 
                   1235:     /*
                   1236:      * Find the top-level window for tkwin, plus the window manager
                   1237:      * information.
                   1238:      */
                   1239: 
                   1240:     while (!(winPtr->flags & TK_TOP_LEVEL)) {
                   1241:        winPtr = winPtr->parentPtr;
                   1242:     }
                   1243:     wmPtr = winPtr->wmInfoPtr;
                   1244: 
                   1245:     if ((wmPtr->reqGridWidth == reqWidth)
                   1246:            && (wmPtr->reqGridHeight != reqHeight)
                   1247:            && (wmPtr->widthInc != widthInc)
                   1248:            && (wmPtr->heightInc != heightInc)
                   1249:            && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
                   1250:                    == PBaseSize|PResizeInc)) {
                   1251:        return;
                   1252:     }
                   1253: 
                   1254:     /*
                   1255:      * If gridding was previously off, then forget about any window
                   1256:      * size requests made by the user or via "wm geometry":  these are
                   1257:      * in pixel units and there's no easy way to translate them to
                   1258:      * grid units since the new requested size of the top-level window in
                   1259:      * pixels may not yet have been registered yet (it may filter up
                   1260:      * the hierarchy in DoWhenIdle handlers).
                   1261:      */
                   1262: 
                   1263:     if (!(wmPtr->sizeHintsFlags & PBaseSize)) {
                   1264:        wmPtr->width = -1;
                   1265:        wmPtr->height = -1;
                   1266:     }
                   1267: 
                   1268:     /* 
                   1269:      * Set the new gridding information, and start the process of passing
                   1270:      * all of this information to the window manager.
                   1271:      */
                   1272: 
                   1273:     wmPtr->reqGridWidth = reqWidth;
                   1274:     wmPtr->reqGridHeight = reqHeight;
                   1275:     wmPtr->widthInc = widthInc;
                   1276:     wmPtr->heightInc = heightInc;
                   1277:     wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc;
                   1278:     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
                   1279:     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
                   1280:        Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
                   1281:        wmPtr->flags |= WM_UPDATE_PENDING;
                   1282:     }
                   1283: }
                   1284: 
                   1285: /*
                   1286:  *----------------------------------------------------------------------
                   1287:  *
                   1288:  * TopLevelEventProc --
                   1289:  *
                   1290:  *     This procedure is invoked when a top-level (or other externally-
                   1291:  *     managed window) is restructured in any way.
                   1292:  *
                   1293:  * Results:
                   1294:  *     None.
                   1295:  *
                   1296:  * Side effects:
                   1297:  *     Tk's internal data structures for the window get modified to
                   1298:  *     reflect the structural change.
                   1299:  *
                   1300:  *----------------------------------------------------------------------
                   1301:  */
                   1302: 
                   1303: static void
                   1304: TopLevelEventProc(clientData, eventPtr)
                   1305:     ClientData clientData;             /* Window for which event occurred. */
                   1306:     XEvent *eventPtr;                  /* Event that just happened. */
                   1307: {
                   1308:     register TkWindow *winPtr = (TkWindow *) clientData;
                   1309: 
                   1310:     if (eventPtr->type == DestroyNotify) {
                   1311:        if (!(winPtr->flags & TK_ALREADY_DEAD)) {
                   1312:            Tk_DestroyWindow((Tk_Window) winPtr);
                   1313:        }
                   1314:     } else if (eventPtr->type == ConfigureNotify) {
                   1315:        register WmInfo *wmPtr = winPtr->wmInfoPtr;
                   1316:        int diff, x, y;
                   1317: 
                   1318:        /*
                   1319:         * A top-level window has been reconfigured.  Problem #1:
                   1320:         * discard stale information.  If the application has recently
                   1321:         * tried to reconfigure itself, ignore all events until the
                   1322:         * response to that reconfiguration arrives (the response is
                   1323:         * assumed to be the first ConfigureNotify that arrives after
                   1324:         * the server has seen the request;  this suffers from potential
                   1325:         * races with user actions, but it's the best I can think of
                   1326:         * right now).
                   1327:         */
                   1328: 
                   1329:        diff = eventPtr->xconfigure.serial - wmPtr->configRequest;
                   1330:        if (diff < 0) {
                   1331:            return;
                   1332:        }
                   1333: 
                   1334:        /*
                   1335:         * Problem #2: reparenting window managers.  If the window
                   1336:         * manager reparents a top-level window then the x and y
                   1337:         * information that comes in events for the window is wrong:
                   1338:         * it gives the location of the window inside its decorative
                   1339:         * parent, rather than the location of the window in root
                   1340:         * coordinates, which is what we want.  Window managers
                   1341:         * are supposed to send synthetic events with the correct
                   1342:         * information, but ICCCM doesn't require them to do this
                   1343:         * under all conditions, and the information provided doesn't
                   1344:         * include everything we need here.  So, the code below
                   1345:         * maintains a bunch of information about the parent window.
                   1346:         * If the window hasn't been reparented, we pretend that
                   1347:         * there is a parent shrink-wrapped around the window.
                   1348:         */
                   1349: 
                   1350:        if (wmPtr->reparent == None) {
                   1351:            noReparent:
                   1352:            winPtr->changes.x = eventPtr->xconfigure.x;
                   1353:            winPtr->changes.y = eventPtr->xconfigure.y;
                   1354:            wmPtr->parentWidth = eventPtr->xconfigure.width
                   1355:                    + 2*eventPtr->xconfigure.border_width;
                   1356:            wmPtr->parentHeight = eventPtr->xconfigure.height
                   1357:                    + 2*eventPtr->xconfigure.border_width;
                   1358:        } else {
                   1359:            unsigned int width, height, bd, dummy;
                   1360:            Window dummy2;
                   1361:            Status status;
                   1362:            Tk_ErrorHandler handler;
                   1363: 
                   1364:            handler = Tk_CreateErrorHandler(winPtr->display, BadDrawable, -1,
                   1365:                    -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
                   1366:            status = XGetGeometry(winPtr->display, wmPtr->reparent,
                   1367:                    &dummy2, &x, &y, &width, &height, &bd, &dummy);
                   1368:            Tk_DeleteErrorHandler(handler);
                   1369:            if (status == 0) {
                   1370:                /*
                   1371:                 * It appears that the reparented parent went away and
                   1372:                 * no-one told us.  Reset the window to indicate that
                   1373:                 * it's not reparented, then handle it as a non-reparented
                   1374:                 * window.
                   1375:                 */
                   1376:                wmPtr->reparent = None;
                   1377:                wmPtr->flags &= ~WM_NESTED_REPARENT;
                   1378:                wmPtr->xInParent = wmPtr->yInParent = 0;
                   1379:                goto noReparent;
                   1380:            }
                   1381:            wmPtr->parentWidth = width + 2*bd;
                   1382:            wmPtr->parentHeight = height + 2*bd;
                   1383:            winPtr->changes.x = x;
                   1384:            winPtr->changes.y = y;
                   1385:            if (wmPtr->flags & WM_NESTED_REPARENT) {
                   1386:                int xOffset, yOffset;
                   1387: 
                   1388:                (void) XTranslateCoordinates(winPtr->display, winPtr->window,
                   1389:                    wmPtr->reparent, 0, 0, &xOffset, &yOffset, &dummy2);
                   1390:                wmPtr->xInParent = xOffset + bd - winPtr->changes.border_width;
                   1391:                wmPtr->yInParent = yOffset + bd - winPtr->changes.border_width;
                   1392:            } else {
                   1393:                if (!eventPtr->xconfigure.send_event) {
                   1394:                    wmPtr->xInParent = eventPtr->xconfigure.x + bd;
                   1395:                    wmPtr->yInParent = eventPtr->xconfigure.y + bd;
                   1396:                }
                   1397:            }
                   1398:            winPtr->changes.x = x + wmPtr->xInParent;
                   1399:            winPtr->changes.y = y + wmPtr->yInParent;
                   1400:        }
                   1401: 
                   1402:        /*
                   1403:         * Problem #3: if the window size or location was changed
                   1404:         * externally, update the geometry information in wmPtr to make
                   1405:         * it look just as if the user had typed a "wm geometry" command
                   1406:         * to make the change.  There are many tricky situations to deal
                   1407:         * with:
                   1408:         * (a) the event is simply a reflection of an internal geometry
                   1409:         *     request from the window's widgets (must leave width and
                   1410:         *     height alone in this case).
                   1411:         * (b) the window manager might respond to a size request from
                   1412:         *     us with a different size than requested (e.g. it might
                   1413:         *     have a minimum allowable window size).  Because of this,
                   1414:         *     can't just compare new size with requested size to determine
                   1415:         *     whether this event is a reflection of an internal request
                   1416:         *     from within the application.  Use WM_CONFIG_PENDING flag
                   1417:         *     instead.
                   1418:         * (c) ConfigureNotify events also arise if the window has been
                   1419:         *     moved, even if its size hasn't changed.  Must distinguish
                   1420:         *     between the user moving the window and the user resizing
                   1421:         *     the window.
                   1422:         */
                   1423: 
                   1424:        if (wmPtr->flags & WM_CONFIG_PENDING) {
                   1425:            int diff;
                   1426:            /*
                   1427:             * Size change is just a reflection of something coming from
                   1428:             * application.
                   1429:             */
                   1430: 
                   1431:            diff = eventPtr->xconfigure.serial - wmPtr->configRequest;
                   1432:            if (diff >= 0) {
                   1433:                if (wmPtr->flags & WM_CONFIG_AGAIN) {
                   1434:                    if (!(wmPtr->flags & WM_UPDATE_PENDING)) {
                   1435:                        Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
                   1436:                        wmPtr->flags |= WM_UPDATE_PENDING;
                   1437:                    }
                   1438:                }
                   1439:                wmPtr->flags &= ~(WM_CONFIG_PENDING|WM_CONFIG_AGAIN);
                   1440:            }
                   1441:        } else if ((winPtr->changes.width != eventPtr->xconfigure.width)
                   1442:                || (winPtr->changes.height != eventPtr->xconfigure.height)) {
                   1443:            wmPtr->configWidth = -1;
                   1444:            wmPtr->configHeight = -1;
                   1445:            if (IS_GRIDDED(wmPtr)) {
                   1446:                wmPtr->width = wmPtr->reqGridWidth
                   1447:                        + (eventPtr->xconfigure.width
                   1448:                        - winPtr->reqWidth)/wmPtr->widthInc;
                   1449:                if (wmPtr->width < 0) {
                   1450:                    wmPtr->width = 0;
                   1451:                }
                   1452:                wmPtr->height = wmPtr->reqGridHeight
                   1453:                        + (eventPtr->xconfigure.height
                   1454:                        - winPtr->reqHeight)/wmPtr->heightInc;
                   1455:                if (wmPtr->height < 0) {
                   1456:                    wmPtr->height = 0;
                   1457:                }
                   1458:            } else if ((eventPtr->xconfigure.width != winPtr->changes.width)
                   1459:                    || (eventPtr->xconfigure.height
                   1460:                            != winPtr->changes.height)) {
                   1461:                /*
                   1462:                 * The check above is needed so we don't think the user
                   1463:                 * requested a new size when all he/she did was to move
                   1464:                 * the window.
                   1465:                 */
                   1466: 
                   1467:                wmPtr->width = eventPtr->xconfigure.width;
                   1468:                wmPtr->height = eventPtr->xconfigure.height;
                   1469:            }
                   1470:        }
                   1471: 
                   1472:        winPtr->changes.width = eventPtr->xconfigure.width;
                   1473:        winPtr->changes.height = eventPtr->xconfigure.height;
                   1474:        winPtr->changes.border_width = eventPtr->xconfigure.border_width;
                   1475:        winPtr->changes.sibling = eventPtr->xconfigure.above;
                   1476:        winPtr->changes.stack_mode = Above;
                   1477: 
                   1478:        x = winPtr->changes.x - wmPtr->xInParent;
                   1479:        if (wmPtr->flags & WM_NEGATIVE_X) {
                   1480:            x = DisplayWidth(winPtr->display, winPtr->screenNum)
                   1481:                    - (x + wmPtr->parentWidth);
                   1482:        }
                   1483:        y = winPtr->changes.y - wmPtr->yInParent;
                   1484:        if (wmPtr->flags & WM_NEGATIVE_Y) {
                   1485:            y = DisplayHeight(winPtr->display, winPtr->screenNum)
                   1486:                    - (y + wmPtr->parentHeight);
                   1487:        }
                   1488:        if ((x != wmPtr->x) || (y != wmPtr->y)) {
                   1489:            wmPtr->x = x;
                   1490:            wmPtr->y = y;
                   1491:        }
                   1492:     } else if (eventPtr->type == MapNotify) {
                   1493:        winPtr->flags |= TK_MAPPED;
                   1494:     } else if (eventPtr->type == UnmapNotify) {
                   1495:        winPtr->flags &= ~TK_MAPPED;
                   1496:     } else if (eventPtr->type == ReparentNotify) {
                   1497:        WmInfo *wmPtr = winPtr->wmInfoPtr;
                   1498:        Window root, *children, dummy2, *virtualRootPtr;
                   1499:        Atom virtualRootAtom, actualType;
                   1500:        int actualFormat;
                   1501:        unsigned long numItems, bytesAfter;
                   1502:        unsigned int dummy;
                   1503: 
                   1504:        /*
                   1505:         * Locate the ancestor of this window that is just below the
                   1506:         * root window for the screen (could be the window itself).
                   1507:         * This code is a bit tricky because it allows for the
                   1508:         * possibility of a virtual root window, which is identified
                   1509:         * with a property named __SWM_VROOT.
                   1510:         */
                   1511: 
                   1512:        virtualRootAtom = Tk_InternAtom((Tk_Window) winPtr, "__SWM_VROOT");
                   1513:        wmPtr->flags &= ~WM_NESTED_REPARENT;
                   1514:        wmPtr->reparent = None;
                   1515:        root = eventPtr->xreparent.parent;
                   1516:        while (root != RootWindow(winPtr->display, winPtr->screenNum)) {
                   1517:            Tk_ErrorHandler handler1, handler2;
                   1518:            int status;
                   1519: 
                   1520:            virtualRootPtr = NULL;
                   1521: 
                   1522:            handler1 =
                   1523:              Tk_CreateErrorHandler(winPtr->display, BadDrawable,
                   1524:                                    -1, -1, (Tk_ErrorProc *) NULL,
                   1525:                                    (ClientData) NULL);
                   1526:            handler2 =
                   1527:              Tk_CreateErrorHandler(winPtr->display, BadWindow,
                   1528:                                    -1, -1, (Tk_ErrorProc *) NULL,
                   1529:                                    (ClientData) NULL);
                   1530: 
                   1531:            status = XGetWindowProperty(winPtr->display, root,
                   1532:                                        virtualRootAtom,
                   1533:                                        0, (long) 1, False, XA_WINDOW,
                   1534:                                        &actualType, &actualFormat,
                   1535:                                        &numItems, &bytesAfter,
                   1536:                                        (unsigned char **) &virtualRootPtr);
                   1537: 
                   1538:            Tk_DeleteErrorHandler(handler1);
                   1539:            Tk_DeleteErrorHandler(handler2);
                   1540: 
                   1541:            if (status == Success) {
                   1542:                if (virtualRootPtr != NULL) {
                   1543:                    if (*virtualRootPtr != root) {
                   1544:                        panic("TopLevelEventProc confused over virtual root");
                   1545:                    }
                   1546:                    XFree((char *) virtualRootPtr);
                   1547:                    break;
                   1548:                }
                   1549:            }
                   1550:            wmPtr->reparent = root;
                   1551:            (void) XQueryTree(winPtr->display, root, &dummy2, &root,
                   1552:                    &children, &dummy);
                   1553:            XFree((char *) children);
                   1554:        }
                   1555: 
                   1556:        /*
                   1557:         * The ancestor just below the (virtual) root is in wmPtr->reparent
                   1558:         * now, and the (virtual) root is in root.
                   1559:         */
                   1560: 
                   1561: 
                   1562:        if (eventPtr->xreparent.parent == root) {
                   1563:            wmPtr->reparent = None;
                   1564:            wmPtr->flags &= ~WM_NESTED_REPARENT;
                   1565:            wmPtr->parentWidth = winPtr->changes.width
                   1566:                    + 2*winPtr->changes.border_width;
                   1567:            wmPtr->parentHeight = winPtr->changes.height
                   1568:                    + 2*winPtr->changes.border_width;
                   1569:            wmPtr->xInParent = wmPtr->yInParent = 0;
                   1570:            winPtr->changes.x = eventPtr->xreparent.x;
                   1571:            winPtr->changes.y = eventPtr->xreparent.y;
                   1572:        } else {
                   1573:            int x, y, xOffset, yOffset;
                   1574:            unsigned int width, height, bd;
                   1575: 
                   1576:            if (wmPtr->reparent != eventPtr->xreparent.parent) {
                   1577:                wmPtr->flags |= WM_NESTED_REPARENT;
                   1578:            } else {
                   1579:                wmPtr->flags &= ~WM_NESTED_REPARENT;
                   1580:            }
                   1581: 
                   1582:            /*
                   1583:             * Compute and save information about reparent and about
                   1584:             * the window's position in reparent.
                   1585:             */
                   1586: 
                   1587:            (void) XGetGeometry(winPtr->display, wmPtr->reparent,
                   1588:                    &dummy2, &x, &y, &width, &height, &bd, &dummy);
                   1589:            wmPtr->parentWidth = width + 2*bd;
                   1590:            wmPtr->parentHeight = height + 2*bd;
                   1591:            (void) XTranslateCoordinates(winPtr->display, winPtr->window,
                   1592:                    wmPtr->reparent, 0, 0, &xOffset, &yOffset, &dummy2);
                   1593:            wmPtr->xInParent = xOffset + bd - winPtr->changes.border_width;
                   1594:            wmPtr->yInParent = yOffset + bd - winPtr->changes.border_width;
                   1595:            winPtr->changes.x = x + xOffset;
                   1596:            winPtr->changes.y = y + yOffset;
                   1597:        }
                   1598:     } else if ((eventPtr->type == EnterNotify)
                   1599:            || (eventPtr->type == LeaveNotify)) {
                   1600:        TkFocusEventProc(winPtr, eventPtr);
                   1601:     }
                   1602: }
                   1603: 
                   1604: /*
                   1605:  *----------------------------------------------------------------------
                   1606:  *
                   1607:  * TopLevelReqProc --
                   1608:  *
                   1609:  *     This procedure is invoked by the geometry manager whenever
                   1610:  *     the requested size for a top-level window is changed.
                   1611:  *
                   1612:  * Results:
                   1613:  *     None.
                   1614:  *
                   1615:  * Side effects:
                   1616:  *     Arrange for the window to be resized to satisfy the request
                   1617:  *     (this happens as a when-idle action).
                   1618:  *
                   1619:  *----------------------------------------------------------------------
                   1620:  */
                   1621: 
                   1622:        /* ARGSUSED */
                   1623: static void
                   1624: TopLevelReqProc(dummy, tkwin)
                   1625:     ClientData dummy;                  /* Not used. */
                   1626:     Tk_Window tkwin;                   /* Information about window. */
                   1627: {
                   1628:     TkWindow *winPtr = (TkWindow *) tkwin;
                   1629:     WmInfo *wmPtr;
                   1630: 
                   1631:     wmPtr = winPtr->wmInfoPtr;
                   1632:     if ((wmPtr->prevReqWidth == winPtr->reqWidth)
                   1633:            && (wmPtr->prevReqHeight == winPtr->reqHeight)) {
                   1634:        return;
                   1635:     }
                   1636:     wmPtr->prevReqWidth = winPtr->reqWidth;
                   1637:     wmPtr->prevReqHeight = winPtr->reqHeight;
                   1638:     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
                   1639:     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
                   1640:        Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
                   1641:        wmPtr->flags |= WM_UPDATE_PENDING;
                   1642:     }
                   1643: }
                   1644: 
                   1645: /*
                   1646:  *----------------------------------------------------------------------
                   1647:  *
                   1648:  * UpdateGeometryInfo --
                   1649:  *
                   1650:  *     This procedure is invoked when a top-level window is first
                   1651:  *     mapped, and also as a when-idle procedure, to bring the
                   1652:  *     geometry and/or position of a top-level window back into
                   1653:  *     line with what has been requested by the user and/or widgets.
                   1654:  *
                   1655:  * Results:
                   1656:  *     None.
                   1657:  *
                   1658:  * Side effects:
                   1659:  *     The window's size and location may change, unless the WM prevents
                   1660:  *     that from happening.
                   1661:  *
                   1662:  *----------------------------------------------------------------------
                   1663:  */
                   1664: 
                   1665: static void
                   1666: UpdateGeometryInfo(clientData)
                   1667:     ClientData clientData;             /* Pointer to the window's record. */
                   1668: {
                   1669:     register TkWindow *winPtr = (TkWindow *) clientData;
                   1670:     register WmInfo *wmPtr = winPtr->wmInfoPtr;
                   1671:     int x, y, width, height;
                   1672: 
                   1673:     /*
                   1674:      * It isn't safe to issue a new reconfigure request while there is
                   1675:      * another reconfigure request outstanding.  If this happens, skip
                   1676:      * the second reconfigure operation but set a flag so it will get
                   1677:      * done with the first one finishes.
                   1678:      */
                   1679: 
                   1680:     wmPtr->flags &= ~WM_UPDATE_PENDING;
                   1681:     if (wmPtr->flags & WM_CONFIG_PENDING) {
                   1682:        wmPtr->flags |= WM_CONFIG_AGAIN;
                   1683:        return;
                   1684:     }
                   1685: 
                   1686:     /*
                   1687:      * Compute the new size for the top-level window.  See the
                   1688:      * user documentation for details on this, but the size
                   1689:      * requested depends on (a) the size requested internally
                   1690:      * by the window's widgets, (b) the size requested by the
                   1691:      * user in a "wm geometry" command or via wm-based interactive
                   1692:      * resizing (if any), and (c) whether or not the window
                   1693:      * gridded.  Don't permit sizes <= 0 because this upsets
                   1694:      * the X server.
                   1695:      */
                   1696: 
                   1697:     if (wmPtr->width == -1) {
                   1698:        width = winPtr->reqWidth;
                   1699:        height = winPtr->reqHeight;
                   1700:     } else if (IS_GRIDDED(wmPtr)) {
                   1701:        width = winPtr->reqWidth
                   1702:                + (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc;
                   1703:        height = winPtr->reqHeight
                   1704:                + (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc;
                   1705:     } else {
                   1706:        width = wmPtr->width;
                   1707:        height = wmPtr->height;
                   1708:     }
                   1709:     if (width <= 0) {
                   1710:        width = 1;
                   1711:     }
                   1712:     if (height <= 0) {
                   1713:        height = 1;
                   1714:     }
                   1715: 
                   1716:     /*
                   1717:      * Compute the new position for the window.  This is tricky, because
                   1718:      * we need to include the border widths supplied by a reparented
                   1719:      * parent in this calculation, but can't use the parent's current
                   1720:      * overall size since that may change as a result of this code.
                   1721:      */
                   1722: 
                   1723:     if (wmPtr->flags & WM_NEGATIVE_X) {
                   1724:        x = DisplayWidth(winPtr->display, winPtr->screenNum) - wmPtr->x
                   1725:                - (width + (wmPtr->parentWidth - winPtr->changes.width))
                   1726:                + wmPtr->xInParent;
                   1727:     } else {
                   1728:        x =  wmPtr->x + wmPtr->xInParent;
                   1729:     }
                   1730:     if (wmPtr->flags & WM_NEGATIVE_Y) {
                   1731:        y = DisplayHeight(winPtr->display, winPtr->screenNum) - wmPtr->y
                   1732:                - (height + (wmPtr->parentHeight - winPtr->changes.height))
                   1733:                + wmPtr->yInParent;
                   1734:     } else {
                   1735:        y =  wmPtr->y + wmPtr->yInParent;
                   1736:     }
                   1737: 
                   1738:     /*
                   1739:      * If the window's size is going to change and the window is
                   1740:      * supposed to not be resizable by the user, then we have to
                   1741:      * update the size hints.  There may also be a size-hint-update
                   1742:      * request pending from somewhere else, too.
                   1743:      */
                   1744: 
                   1745:     if (((width != winPtr->changes.width) || (width != winPtr->changes.width))
                   1746:            && !IS_GRIDDED(wmPtr)
                   1747:            && ((wmPtr->sizeHintsFlags & (PMinSize|PMaxSize)) == 0)) {
                   1748:        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
                   1749:     }
                   1750:     if (wmPtr->flags & WM_UPDATE_SIZE_HINTS) {
                   1751:        UpdateSizeHints(winPtr);
                   1752:     }
                   1753: 
                   1754:     /*
                   1755:      * If the geometry hasn't changed, be careful to  use only a
                   1756:      * resize operation.  This is because of bugs in some window
                   1757:      * managers (e.g. twm, as of 4/24/91) where they don't interpret
                   1758:      * coordinates according to ICCCM.
                   1759:      */
                   1760: 
                   1761:     if ((x != winPtr->changes.x) || (y != winPtr->changes.y)) {
                   1762:        wmPtr->configRequest = XNextRequest(winPtr->display);
                   1763:        wmPtr->configWidth = width;
                   1764:        wmPtr->configHeight = height;
                   1765:        Tk_MoveResizeWindow((Tk_Window) winPtr, x, y, (unsigned) width,
                   1766:                (unsigned) height);
                   1767:        wmPtr->flags |= WM_CONFIG_PENDING;
                   1768:     } else if ((width != wmPtr->configWidth)
                   1769:            || (height != wmPtr->configHeight)) {
                   1770:        wmPtr->configRequest = XNextRequest(winPtr->display);
                   1771:        wmPtr->configWidth = width;
                   1772:        wmPtr->configHeight = height;
                   1773:        Tk_ResizeWindow((Tk_Window) winPtr, (unsigned) width,
                   1774:                (unsigned) height);
                   1775:        wmPtr->flags |= WM_CONFIG_PENDING;
                   1776:     }
                   1777: }
                   1778: 
                   1779: /*
                   1780:  *--------------------------------------------------------------
                   1781:  *
                   1782:  * UpdateSizeHints --
                   1783:  *
                   1784:  *     This procedure is called to update the window manager's
                   1785:  *     size hints information from the information in a WmInfo
                   1786:  *     structure.
                   1787:  *
                   1788:  * Results:
                   1789:  *     None.
                   1790:  *
                   1791:  * Side effects:
                   1792:  *     Properties get changed for winPtr.
                   1793:  *
                   1794:  *--------------------------------------------------------------
                   1795:  */
                   1796: 
                   1797: static void
                   1798: UpdateSizeHints(winPtr)
                   1799:     TkWindow *winPtr;
                   1800: {
                   1801:     register WmInfo *wmPtr = winPtr->wmInfoPtr;
                   1802:     XSizeHints *hintsPtr;
                   1803: 
                   1804:     wmPtr->flags &= ~WM_UPDATE_SIZE_HINTS;
                   1805: 
                   1806: #ifndef X11R3
                   1807:     hintsPtr = XAllocSizeHints();
                   1808:     if (hintsPtr == NULL) {
                   1809:        return;
                   1810:     }
                   1811: 
                   1812:     /*
                   1813:      * Compute the pixel-based sizes for the various fields in the
                   1814:      * size hints structure, based on the grid-based sizes in
                   1815:      * our structure.
                   1816:      */
                   1817: 
                   1818:     if (IS_GRIDDED(wmPtr)) {
                   1819:        hintsPtr->base_width = winPtr->reqWidth
                   1820:                - (wmPtr->reqGridWidth * wmPtr->widthInc);
                   1821:        if (hintsPtr->base_width < 0) {
                   1822:            hintsPtr->base_width = 0;
                   1823:        }
                   1824:        hintsPtr->base_height = winPtr->reqHeight
                   1825:                - (wmPtr->reqGridHeight * wmPtr->heightInc);
                   1826:        if (hintsPtr->base_height < 0) {
                   1827:            hintsPtr->base_height = 0;
                   1828:        }
                   1829:        hintsPtr->min_width = hintsPtr->base_width
                   1830:                + (wmPtr->minWidth * wmPtr->widthInc);
                   1831:        hintsPtr->min_height = hintsPtr->base_height
                   1832:                + (wmPtr->minHeight * wmPtr->heightInc);
                   1833:        hintsPtr->max_width = hintsPtr->base_width
                   1834:                + (wmPtr->maxWidth * wmPtr->widthInc);
                   1835:        hintsPtr->max_height = hintsPtr->base_height
                   1836:                + (wmPtr->maxHeight * wmPtr->heightInc);
                   1837:     } else {
                   1838:        hintsPtr->min_width = wmPtr->minWidth;
                   1839:        hintsPtr->min_height = wmPtr->minHeight;
                   1840:        hintsPtr->max_width = wmPtr->maxWidth;
                   1841:        hintsPtr->max_height = wmPtr->maxHeight;
                   1842:        hintsPtr->base_width = 0;
                   1843:        hintsPtr->base_height = 0;
                   1844:     }
                   1845:     hintsPtr->width_inc = wmPtr->widthInc;
                   1846:     hintsPtr->height_inc = wmPtr->heightInc;
                   1847:     hintsPtr->min_aspect.x = wmPtr->minAspect.x;
                   1848:     hintsPtr->min_aspect.y = wmPtr->minAspect.y;
                   1849:     hintsPtr->max_aspect.x = wmPtr->maxAspect.x;
                   1850:     hintsPtr->max_aspect.y = wmPtr->maxAspect.y;
                   1851:     hintsPtr->win_gravity = wmPtr->gravity;
                   1852:     hintsPtr->flags = wmPtr->sizeHintsFlags;
                   1853: 
                   1854:     /*
                   1855:      * If a window is non-gridded and no minimum or maximum size has
                   1856:      * been specified, don't let the window be resized at all.
                   1857:      */
                   1858: 
                   1859:     if (!IS_GRIDDED(wmPtr)
                   1860:            && ((wmPtr->sizeHintsFlags & (PMinSize|PMaxSize)) == 0)) {
                   1861:        int width, height;
                   1862: 
                   1863:        width = wmPtr->width;
                   1864:        height = wmPtr->height;
                   1865:        if (width < 0) {
                   1866:            width = winPtr->reqWidth;
                   1867:            height = winPtr->reqHeight;
                   1868:        }
                   1869:        hintsPtr->min_width = hintsPtr->max_width = width;
                   1870:        hintsPtr->min_height = hintsPtr->max_height = height;
                   1871:        hintsPtr->flags |= PMinSize|PMaxSize;
                   1872:     }
                   1873: 
                   1874:     /*
                   1875:      * If min or max size isn't specified, fill in with extreme values
                   1876:      * rather than leaving unspecified.  Otherwise window manager may
                   1877:      * do someting counter-intuitive like the last value ever specified.
                   1878:      */
                   1879: 
                   1880:     if (!(hintsPtr->flags & PMinSize)) {
                   1881:        hintsPtr->min_width = hintsPtr->min_height = 0;
                   1882:        hintsPtr->flags |= PMinSize;
                   1883:     }
                   1884:     if (!(hintsPtr->flags & PMaxSize)) {
                   1885:        hintsPtr->max_width = hintsPtr->max_height = 1000000;
                   1886:        hintsPtr->flags |= PMaxSize;
                   1887:     }
                   1888: 
                   1889:     XSetWMNormalHints(winPtr->display, winPtr->window, hintsPtr);
                   1890: 
                   1891:     XFree((char *) hintsPtr);
                   1892: #endif /* X11R3 */
                   1893: }
                   1894: 
                   1895: /*
                   1896:  *--------------------------------------------------------------
                   1897:  *
                   1898:  * UpdateHints --
                   1899:  *
                   1900:  *     This procedure is called to update the window manager's
                   1901:  *     hints information from the information in a WmInfo
                   1902:  *     structure.
                   1903:  *
                   1904:  * Results:
                   1905:  *     None.
                   1906:  *
                   1907:  * Side effects:
                   1908:  *     Properties get changed for winPtr.
                   1909:  *
                   1910:  *--------------------------------------------------------------
                   1911:  */
                   1912: 
                   1913: static void
                   1914: UpdateHints(winPtr)
                   1915:     TkWindow *winPtr;
                   1916: {
                   1917:     WmInfo *wmPtr = winPtr->wmInfoPtr;
                   1918: 
                   1919:     if (wmPtr->flags & WM_NEVER_MAPPED) {
                   1920:        return;
                   1921:     }
                   1922:     XSetWMHints(winPtr->display, winPtr->window, &wmPtr->hints);
                   1923: }
                   1924: 
                   1925: /*
                   1926:  *--------------------------------------------------------------
                   1927:  *
                   1928:  * ParseGeometry --
                   1929:  *
                   1930:  *     This procedure parses a geometry string and updates
                   1931:  *     information used to control the geometry of a top-level
                   1932:  *     window.
                   1933:  *
                   1934:  * Results:
                   1935:  *     A standard Tcl return value, plus an error message in
                   1936:  *     interp->result if an error occurs.
                   1937:  *
                   1938:  * Side effects:
                   1939:  *     The size and/or location of winPtr may change.
                   1940:  *
                   1941:  *--------------------------------------------------------------
                   1942:  */
                   1943: 
                   1944: static int
                   1945: ParseGeometry(interp, string, winPtr)
                   1946:     Tcl_Interp *interp;                /* Used for error reporting. */
                   1947:     char *string;      /* String containing new geometry.  Has the
                   1948:                                 * standard form "=wxh+x+y". */
                   1949:     TkWindow *winPtr;          /* Pointer to top-level window whose
                   1950:                                 * geometry is to be changed. */
                   1951: {
                   1952:     register WmInfo *wmPtr = winPtr->wmInfoPtr;
                   1953:     int x, y, width, height, flags;
                   1954:     char *end;
                   1955:     register char *p = string;
                   1956: 
                   1957:     /*
                   1958:      * The leading "=" is optional.
                   1959:      */
                   1960: 
                   1961:     if (*p == '=') {
                   1962:        p++;
                   1963:     }
                   1964: 
                   1965:     /*
                   1966:      * Parse the width and height, if they are present.  Don't
                   1967:      * actually update any of the fields of wmPtr until we've
                   1968:      * successfully parsed the entire geometry string.
                   1969:      */
                   1970: 
                   1971:     width = wmPtr->width;
                   1972:     height = wmPtr->height;
                   1973:     x = wmPtr->x;
                   1974:     y = wmPtr->y;
                   1975:     flags = wmPtr->flags;
                   1976:     if (isdigit(*p)) {
                   1977:        width = strtoul(p, &end, 10);
                   1978:        p = end;
                   1979:        if (*p != 'x') {
                   1980:            goto error;
                   1981:        }
                   1982:        p++;
                   1983:        if (!isdigit(*p)) {
                   1984:            goto error;
                   1985:        }
                   1986:        height = strtoul(p, &end, 10);
                   1987:        p = end;
                   1988:     }
                   1989: 
                   1990:     /*
                   1991:      * Parse the X and Y coordinates, if they are present.
                   1992:      */
                   1993: 
                   1994:     if (*p != '\0') {
                   1995:        flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
                   1996:        if (*p == '-') {
                   1997:            flags |= WM_NEGATIVE_X;
                   1998:        } else if (*p != '+') {
                   1999:            goto error;
                   2000:        }
                   2001:        x = strtol(p+1, &end, 10);
                   2002:        p = end;
                   2003:        if (*p == '-') {
                   2004:            flags |= WM_NEGATIVE_Y;
                   2005:        } else if (*p != '+') {
                   2006:            goto error;
                   2007:        }
                   2008:        y = strtol(p+1, &end, 10);
                   2009:        if (*end != '\0') {
                   2010:            goto error;
                   2011:        }
                   2012: 
                   2013:        /*
                   2014:         * Assume that the geometry information came from the user,
                   2015:         * unless an explicit source has been specified.  Otherwise
                   2016:         * most window managers assume that the size hints were
                   2017:         * program-specified and they ignore them.
                   2018:         */
                   2019: 
                   2020:        if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
                   2021:            wmPtr->sizeHintsFlags |= USPosition;
                   2022:            wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
                   2023:        }
                   2024:     }
                   2025: 
                   2026:     /*
                   2027:      * Everything was parsed OK.  Update the fields of *wmPtr and
                   2028:      * arrange for the appropriate information to be percolated out
                   2029:      * to the window manager at the next idle moment.
                   2030:      */
                   2031: 
                   2032:     wmPtr->width = width;
                   2033:     wmPtr->height = height;
                   2034:     wmPtr->x = x;
                   2035:     wmPtr->y = y;
                   2036:     wmPtr->flags = flags;
                   2037: 
                   2038:     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
                   2039:        Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
                   2040:        wmPtr->flags |= WM_UPDATE_PENDING;
                   2041:     }
                   2042:     return TCL_OK;
                   2043: 
                   2044:     error:
                   2045:     Tcl_AppendResult(interp, "bad geometry specifier \"",
                   2046:            string, "\"", (char *) NULL);
                   2047:     return TCL_ERROR;
                   2048: }
                   2049: 
                   2050: /*
                   2051:  *----------------------------------------------------------------------
                   2052:  *
                   2053:  * Tk_GetRootCoords --
                   2054:  *
                   2055:  *     Given a token for a window, this procedure traces through the
                   2056:  *     window's lineage to find the root-window coordinates corresponding
                   2057:  *     to point (0,0) in the window.
                   2058:  *
                   2059:  * Results:
                   2060:  *     The locations pointed to by xPtr and yPtr are filled in with
                   2061:  *     the root coordinates of the (0,0) point in tkwin.
                   2062:  *
                   2063:  * Side effects:
                   2064:  *     None.
                   2065:  *
                   2066:  *----------------------------------------------------------------------
                   2067:  */
                   2068: 
                   2069: void
                   2070: Tk_GetRootCoords(tkwin, xPtr, yPtr)
                   2071:     Tk_Window tkwin;           /* Token for window. */
                   2072:     int *xPtr;                 /* Where to store x-displacement of (0,0). */
                   2073:     int *yPtr;                 /* Where to store y-displacement of (0,0). */
                   2074: {
                   2075:     int x, y;
                   2076:     register TkWindow *winPtr = (TkWindow *) tkwin;
                   2077: 
                   2078:     /*
                   2079:      * Search back through this window's parents all the way to a
                   2080:      * top-level window, combining the offsets of each window within
                   2081:      * its parent.
                   2082:      */
                   2083: 
                   2084:     x = y = 0;
                   2085:     while (1) {
                   2086:        x += winPtr->changes.x + winPtr->changes.border_width;
                   2087:        y += winPtr->changes.y + winPtr->changes.border_width;
                   2088:        if (winPtr->flags & TK_TOP_LEVEL) {
                   2089:            break;
                   2090:        }
                   2091:        winPtr = winPtr->parentPtr;
                   2092:     }
                   2093:     *xPtr = x;
                   2094:     *yPtr = y;
                   2095: }
                   2096: 
                   2097: 
                   2098: 
                   2099: /*
                   2100:  *--------------------------------------------------------------
                   2101:  *
                   2102:  * TkWmSetWmProtocols --
                   2103:  *     Set the ICCCM WM_PROTOCOLS to be honored by this window.
                   2104:  *     Currently, it is just WM_DELETE_WINDOW.
                   2105:  *
                   2106:  * Results:
                   2107:  *     None.
                   2108:  *
                   2109:  * Side effects:
                   2110:  *     A window property may get updated.
                   2111:  *
                   2112:  *--------------------------------------------------------------
                   2113:  */
                   2114: 
                   2115: void
                   2116: TkWmSetWmProtocols(winPtr)
                   2117:     TkWindow *winPtr;          /* Newly-created top-level window. */
                   2118: {
                   2119:     if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
                   2120:        return;
                   2121:     }
                   2122: #ifndef X11R3
                   2123:     else {
                   2124:        /* assemble the WM_PROTOCOLS that we honor */
                   2125:        int count = 0;
                   2126:        Atom atomlist[8];
                   2127:        atomlist[count++] = Tk_InternAtom((Tk_Window) winPtr,
                   2128:                                          "WM_DELETE_WINDOW");
                   2129: /* 
                   2130:  *     other WM_PROTOCOLS go here -- e.g...
                   2131:  *     atomlist[count++] = Tk_InternAtom((Tk_Window) winPtr,
                   2132:  *                                       "WM_SAVE_YOURSELF");
                   2133:  */
                   2134: 
                   2135:        /* 
                   2136:         * assign the honor list to the window not all X11R4's have 
                   2137:         * XSetWmProtocols() so use XChangeProperty() 
                   2138:         */
                   2139: 
                   2140:        /* XSetWmProtocols(winPtr->display, winPtr->window, atomlist, count); */
                   2141: 
                   2142:        XChangeProperty(winPtr->display, 
                   2143:                        winPtr->window, 
                   2144:                        Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS"),
                   2145:                        XA_ATOM, 32,
                   2146:                        PropModeReplace,
                   2147:                        (unsigned char *)atomlist, 
                   2148:                        count);
                   2149: 
                   2150:     }
                   2151: #endif
                   2152: 
                   2153:     return;
                   2154: }
                   2155: 
                   2156: 
                   2157: /*
                   2158:  *----------------------------------------------------------------------
                   2159:  *
                   2160:  * TkWmProtocolEventProc --
                   2161:  *
                   2162:  *     Handle a WM_PROTOCOL ICCCM event sent by the window manager to
                   2163:  *     top level window.
                   2164:  *
                   2165:  *     The WM_PROTOCOL's currently handled are:
                   2166:  *
                   2167:  *             WM_DELETE_PROTOCOL:
                   2168:  *
                   2169:  * Results: None
                   2170:  *
                   2171:  * Side effects:
                   2172:  *     for WM_DELETE_WINDOW:
                   2173:  *             - window may be deleted if specified earlier by a 
                   2174:  *             wm tcl command
                   2175:  *             - a tcl command may be executed if sepcified earlier by a
                   2176:  *             wm tcl command
                   2177:  *     
                   2178:  *
                   2179:  */
                   2180: void
                   2181: TkWmProtocolEventProc(winPtr, eventPtr)
                   2182: TkWindow *winPtr; 
                   2183: XEvent *eventPtr;
                   2184: {
                   2185:     if ((Atom)(eventPtr->xclient.data.l)[0] ==
                   2186:        Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
                   2187: 
                   2188:        WmInfo *wmPtr = winPtr->wmInfoPtr;
                   2189: 
                   2190:        if (wmPtr->deleteCmd) {
                   2191:            if (*(wmPtr->deleteCmd) == '\0') {
                   2192:                /* callback is empty, just delete the window */
                   2193:                Tk_DestroyWindow((Tk_Window) winPtr);
                   2194:            } else {
                   2195:                /* there is a callback so run it */
                   2196:                (void) Tcl_Eval(winPtr->mainPtr->interp, 
                   2197:                                wmPtr->deleteCmd, 0, (char **)0);
                   2198:            }
                   2199:        } else {
                   2200:            Tk_DestroyWindow((Tk_Window) winPtr);
                   2201:        }
                   2202:     }
                   2203:     /*
                   2204:      * else { .. other WM_<ETC> cases go here ... }
                   2205:      */
                   2206:     return;
                   2207: }
                   2208: 
                   2209: 
                   2210: /* 
                   2211:  *----------------------------------------------------------------------
                   2212:  *
                   2213:  * WmProtocolCmd
                   2214:  *
                   2215:  * implements 
                   2216:  *
                   2217:  *     wm protocol <window> delete [command_str] 
                   2218:  *
                   2219:  * right now just delete is supported for OPTION
                   2220:  *
                   2221:  * Kind of artificial, But makes it easier to merge into new
                   2222:  * versions of Stock Tk.
                   2223:  */
                   2224: int
                   2225: WmProtocolCmd(interp, CmdPtr, argc, argv)
                   2226: Tcl_Interp *interp;
                   2227: char **CmdPtr;
                   2228: int argc;
                   2229: char **argv;
                   2230: {
                   2231: #define Cmd (*CmdPtr)
                   2232: 
                   2233:     switch(argc) {
                   2234:     case 4:
                   2235:        /* 
                   2236:         * return current command 
                   2237:         */
                   2238:        if (!Cmd || *Cmd == '\0') {
                   2239:            return TCL_OK;
                   2240:        } else {
                   2241:            /* 
                   2242:             * chop off the <blank><window_name>
                   2243:             * and return just the cmd 
                   2244:             */
                   2245:            int x = strlen(Cmd) - strlen(argv[2]) - 1;
                   2246:            char tmpc = Cmd[x];
                   2247:            Cmd[x] = '\0';
                   2248:            {
                   2249:                /* maybe should just have them put the window in the cmd */
                   2250:                Tcl_AppendResult(interp, Cmd, (char *)NULL);
                   2251:            }
                   2252:            /* 
                   2253:             * tack the blank and window name back on 
                   2254:             */
                   2255:            Cmd[x] = tmpc;
                   2256:            return TCL_OK;
                   2257:        }
                   2258:     case 5:
                   2259:        /* 
                   2260:         * (re)set command 
                   2261:         */
                   2262:        if (Cmd) {
                   2263:            ckfree(Cmd);
                   2264:            Cmd = (char *)NULL;
                   2265:        }
                   2266:        if (*argv[4] != '\0') {
                   2267:            int x = strlen(argv[4]) + strlen(argv[2]) + 2;
                   2268:            if (!(Cmd = ckalloc(x))) {
                   2269:                perror("wm protocol:");
                   2270:            } else {
                   2271:                sprintf(Cmd, "%s %s", argv[4], argv[2]);
                   2272:            }
                   2273:        }
                   2274:        return TCL_OK;
                   2275:     default:
                   2276:        Tcl_AppendResult(interp, "wrong # of arguments: must be \"",
                   2277:            argv[0], " protocol window <attribute> [cmd]\"", (char *) NULL);
                   2278:        return TCL_ERROR;
                   2279:     }
                   2280: 
                   2281: #undef Cmd
                   2282: }
                   2283: 
                   2284: 
                   2285: /*
                   2286:  *----------------------------------------------------------------------
                   2287:  *
                   2288:  * Tk_CoordsToWindow --
                   2289:  *
                   2290:  *     Given the root coordinates of a point, this procedure
                   2291:  *     returns the token for the top-most window covering that point,
                   2292:  *     if there exists such a window in this application.
                   2293:  *
                   2294:  * Results:
                   2295:  *     The return result is either a token for the window corresponding
                   2296:  *     to rootX and rootY, or else NULL to indicate that there is no such
                   2297:  *     window.
                   2298:  *
                   2299:  * Side effects:
                   2300:  *     None.
                   2301:  *
                   2302:  *----------------------------------------------------------------------
                   2303:  */
                   2304: 
                   2305: Tk_Window
                   2306: Tk_CoordsToWindow(rootX, rootY, tkwin)
                   2307:     int rootX, rootY;          /* Coordinates of point in root window. */
                   2308:     Tk_Window tkwin;           /* Token for any window in application;
                   2309:                                 * used to identify the application. */
                   2310: {
                   2311:     Window rootChild, dummy3, dummy4;
                   2312:     int i, dummy1, dummy2;
                   2313:     register WmInfo *wmPtr;
                   2314:     register TkWindow *winPtr, *childPtr;
                   2315:     TkWindow *nextPtr;         /* Coordinates of highest child found so
                   2316:                                 * far that contains point. */
                   2317:     int x, y;                  /* Coordinates in winPtr. */
                   2318:     int tmpx, tmpy, bd;
                   2319:     Window *children;          /* Children of winPtr, or NULL. */
                   2320:     unsigned int numChildren;  /* Size of children array. */
                   2321: 
                   2322:     /*
                   2323:      * Step 1:  find the top-level window that contains the desired
                   2324:      * coordinates.
                   2325:      */
                   2326: 
                   2327:     if (XTranslateCoordinates(Tk_Display(tkwin),
                   2328:            RootWindowOfScreen(Tk_Screen(tkwin)),
                   2329:            RootWindowOfScreen(Tk_Screen(tkwin)), rootX, rootY, &dummy1,
                   2330:            &dummy2, &rootChild) == False) {
                   2331:        panic("Tk_CoordsToWindow get False return from XTranslateCoordinates");
                   2332:     }
                   2333:     for (wmPtr = firstWmPtr; ; wmPtr = wmPtr->nextPtr) {
                   2334:        if (wmPtr == NULL) {
                   2335:            return NULL;
                   2336:        }
                   2337:        if ((wmPtr->reparent == rootChild) || ((wmPtr->reparent == None)
                   2338:                && (wmPtr->winPtr->window == rootChild))) {
                   2339:            break;
                   2340:        }
                   2341:     }
                   2342:     winPtr = wmPtr->winPtr;
                   2343:     if (winPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr) {
                   2344:        return NULL;
                   2345:     }
                   2346: 
                   2347:     /*
                   2348:      * Step 2: work down through the hierarchy underneath this window.
                   2349:      * At each level, scan through all the children to see if any contain
                   2350:      * the point.  If none do, then we're done.  If one does, then do the
                   2351:      * same thing on that child.  If two or more do, then fetch enough
                   2352:      * information from the window server to figure out which is on top,
                   2353:      * and repeat on that child.
                   2354:      */
                   2355: 
                   2356:     x = rootX;
                   2357:     y = rootY;
                   2358:     while (1) {
                   2359:        x -= winPtr->changes.x;
                   2360:        y -= winPtr->changes.y;
                   2361:        nextPtr = NULL;
                   2362:        children = NULL;
                   2363:        for (childPtr = winPtr->childList; childPtr != NULL;
                   2364:                childPtr = childPtr->nextPtr) {
                   2365:            if (!Tk_IsMapped(childPtr) || (childPtr->flags & TK_TOP_LEVEL)) {
                   2366:                continue;
                   2367:            }
                   2368:            tmpx = x - childPtr->changes.x;
                   2369:            tmpy = y - childPtr->changes.y;
                   2370:            bd = childPtr->changes.border_width;
                   2371:            if ((tmpx < -bd) || (tmpy < -bd)
                   2372:                    || (tmpx >= (childPtr->changes.width + bd))
                   2373:                    || (tmpy >= (childPtr->changes.height + bd))) {
                   2374:                continue;
                   2375:            }
                   2376:            if (nextPtr == NULL) {
                   2377:                nextPtr = childPtr;
                   2378:                continue;
                   2379:            }
                   2380: 
                   2381:            /*
                   2382:             * More than one child of same parent overlaps point.  Must
                   2383:             * figure out which is on top.  Keep a cache of the stacking
                   2384:             * order for winPtr to help with this, in case there are >2
                   2385:             * children overlapping.
                   2386:             */
                   2387: 
                   2388:            if (children == NULL) {
                   2389:                if (XQueryTree(winPtr->display, winPtr->window, &dummy3,
                   2390:                        &dummy4, &children, &numChildren) == 0) {
                   2391:                    panic("Tk_CoordsToWindow get error return from XQueryTree");
                   2392:                }
                   2393:            }
                   2394:            for (i = 0; i < numChildren; i++) {
                   2395:                if (children[i] == childPtr->window) {
                   2396:                    break;
                   2397:                }
                   2398:                if (children[i] == nextPtr->window) {
                   2399:                    nextPtr = childPtr;
                   2400:                    break;
                   2401:                }
                   2402:            }
                   2403:        }
                   2404:        if (children != NULL) {
                   2405:            XFree((char *) children);
                   2406:        }
                   2407:        if (nextPtr == NULL) {
                   2408:            break;
                   2409:        }
                   2410:        winPtr = nextPtr;
                   2411:     }
                   2412:     return (Tk_Window) winPtr;
                   2413: }
                   2414: 
                   2415: 

unix.superglobalmegacorp.com

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