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