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. 
   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. 
  20 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkWm.c,v 1.32 92/08/21 16:26:31 ouster Exp $ SPRITE (Berkeley)"; 
  28  * The definitions below compensate for the lack of some definitions 
  33 #define PBaseSize       (1L<<8) 
  37  * A data structure of the following type holds window-manager-related 
  38  * information for each top-level window in an application. 
  41 typedef struct TkWmInfo 
{ 
  42     TkWindow 
*winPtr
;           /* Pointer to main Tk information for 
  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 
  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, 
  55     XWMHints hints
;             /* Various pieces of information for 
  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. */ 
  71      * Information used to construct an XSizeHints structure for 
  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 
  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 
  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. */ 
  96      * Information used to manage the size and location of a window. 
  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 
 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 
 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. */ 
 139     int flags
;                  /* Miscellaneous flags, defined below. */ 
 141     char *deleteCmd
;            /* Command to execute when a WM_DELETE_WINDOW 
 142                                  * ICCCM ClientMessage arrives for this window. 
 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. 
 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.  
 154     struct TkWmInfo 
*nextPtr
;   /* Next in list of all top-level windows. */ 
 158  * Flag values for WmInfo structures: 
 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 
 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 
 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 
 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 
 186  * WM_FULL_SCREEN -             non-zero means that the window is in full screen mode. 
 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 
 200  * This module keeps a list of all top-level windows, primarily to 
 201  * simplify the job of Tk_CoordsToWindow. 
 204 static WmInfo 
*firstWmPtr 
= NULL
;       /* Points to first top-level window. */ 
 206 #define IS_GRIDDED(wmPtr) ((wmPtr)->sizeHintsFlags & PBaseSize) 
 209  * Forward declarations for procedures defined in this file: 
 212 static int              ParseGeometry 
_ANSI_ARGS_ ((Tcl_Interp 
*interp
, 
 213                             char *string
, TkWindow 
*winPtr
)); 
 214 static void             TopLevelEventProc 
_ANSI_ARGS_((ClientData clientData
, 
 216 static void             TopLevelReqProc 
_ANSI_ARGS_((ClientData dummy
, 
 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
)); 
 224  *-------------------------------------------------------------- 
 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. 
 236  *      A WmInfo structure gets allocated and initialized. 
 238  *-------------------------------------------------------------- 
 242 TkWmNewWindow(winPtr
) 
 243     TkWindow 
*winPtr
;           /* Newly-created top-level window. */ 
 245     register WmInfo 
*wmPtr
; 
 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
; 
 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
; 
 289     winPtr
->wmInfoPtr 
= wmPtr
; 
 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. 
 298     Tk_CreateEventHandler((Tk_Window
) winPtr
, 
 299             StructureNotifyMask
|EnterWindowMask
|LeaveWindowMask
, 
 300             TopLevelEventProc
, (ClientData
) winPtr
); 
 303      * Arrange for geometry requests to be reflected from the window 
 304      * to the window manager. 
 307     Tk_ManageGeometry((Tk_Window
) winPtr
, TopLevelReqProc
, (ClientData
) 0); 
 311  *-------------------------------------------------------------- 
 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 
 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). 
 327  *      Properties of winPtr may get updated to provide up-to-date 
 328  *      information to the window manager. 
 330  *-------------------------------------------------------------- 
 334 TkWmMapWindow(winPtr
) 
 335     TkWindow 
*winPtr
;           /* Top-level window that's about to 
 338     register WmInfo 
*wmPtr 
= winPtr
->wmInfoPtr
; 
 340     XTextProperty textProp
; 
 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 
 349     if (wmPtr
->hints
.initial_state 
== NormalState
) { 
 350         winPtr
->flags 
|= TK_MAPPED
; 
 352     if (!(wmPtr
->flags 
& WM_NEVER_MAPPED
)) { 
 355     wmPtr
->flags 
&= ~WM_NEVER_MAPPED
; 
 358      * This is the first time this window has ever been mapped. 
 359      * Store all the window-manager-related information for the 
 364     if (wmPtr
->titleUid 
== NULL
) { 
 365         wmPtr
->titleUid 
= winPtr
->nameUid
; 
 367     if (XStringListToTextProperty(&wmPtr
->titleUid
, 1, &textProp
)  != 0) { 
 368         XSetWMName(winPtr
->display
, winPtr
->window
, &textProp
); 
 369         XFree((char *) textProp
.value
); 
 373     TkWmSetClass(winPtr
); 
 374     TkWmSetWmProtocols(winPtr
); 
 376     if (wmPtr
->iconName 
!= NULL
) { 
 377         XSetIconName(winPtr
->display
, winPtr
->window
, wmPtr
->iconName
); 
 380     if (wmPtr
->master 
!= None
) { 
 381         XSetTransientForHint(winPtr
->display
, winPtr
->window
, wmPtr
->master
); 
 384     wmPtr
->flags 
|= WM_UPDATE_SIZE_HINTS
; 
 385     UpdateGeometryInfo((ClientData
) winPtr
); 
 387     if (wmPtr
->hints
.initial_state 
== WithdrawnState
) { 
 394  *-------------------------------------------------------------- 
 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. 
 406  *      The WmInfo structure for winPtr gets freed up. 
 408  *-------------------------------------------------------------- 
 412 TkWmDeadWindow(winPtr
) 
 413     TkWindow 
*winPtr
;           /* Newly-created top-level window. */ 
 415     register WmInfo 
*wmPtr 
= winPtr
->wmInfoPtr
; 
 420     if (firstWmPtr 
== wmPtr
) { 
 421         firstWmPtr 
= wmPtr
->nextPtr
; 
 423         register WmInfo 
*prevPtr
; 
 425         for (prevPtr 
= firstWmPtr
; ; prevPtr 
= prevPtr
->nextPtr
) { 
 426             if (prevPtr 
== NULL
) { 
 427                 panic("couldn't unlink window in TkWmDeadWindow"); 
 429             if (prevPtr
->nextPtr 
== wmPtr
) { 
 430                 prevPtr
->nextPtr 
= wmPtr
->nextPtr
; 
 435     if (wmPtr
->hints
.flags 
& IconPixmapHint
) { 
 436         Tk_FreeBitmap(wmPtr
->hints
.icon_pixmap
); 
 438     if (wmPtr
->hints
.flags 
& IconMaskHint
) { 
 439         Tk_FreeBitmap(wmPtr
->hints
.icon_mask
); 
 441     if (wmPtr
->flags 
& WM_UPDATE_PENDING
) { 
 442         Tk_CancelIdleCall(UpdateGeometryInfo
, (ClientData
) winPtr
); 
 444     if (wmPtr
->deleteCmd
) { 
 445         ckfree(wmPtr
->deleteCmd
); 
 447     ckfree((char *) wmPtr
); 
 448     winPtr
->wmInfoPtr 
= NULL
; 
 452  *-------------------------------------------------------------- 
 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. 
 466  *      A window property may get updated. 
 468  *-------------------------------------------------------------- 
 473     TkWindow 
*winPtr
;           /* Newly-created top-level window. */ 
 475     if (winPtr
->wmInfoPtr
->flags 
& WM_NEVER_MAPPED
) { 
 480     if (winPtr
->classUid 
!= NULL
) { 
 481         XClassHint 
*classPtr
; 
 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
); 
 493  *---------------------------------------------------------------------- 
 497  *      This procedure is invoked to process the "wm" Tcl command. 
 498  *      See the user documentation for details on what it does. 
 501  *      A standard Tcl result. 
 504  *      See the user documentation. 
 506  *---------------------------------------------------------------------- 
 511 Tk_WmCmd(clientData
, interp
, argc
, argv
) 
 512     ClientData clientData
;      /* Main window associated with 
 514     Tcl_Interp 
*interp
;         /* Current interpreter. */ 
 515     int argc
;                   /* Number of arguments. */ 
 516     char **argv
;                /* Argument strings. */ 
 518     Tk_Window tkwin 
= (Tk_Window
) clientData
; 
 520     register WmInfo 
*wmPtr
; 
 525         Tcl_AppendResult(interp
, "wrong # args: should be \"", 
 526                 argv
[0], " option window ?arg ...?\"", (char *) NULL
); 
 529     winPtr 
= (TkWindow 
*) Tk_NameToWindow(interp
, argv
[2], tkwin
); 
 530     if (winPtr 
== NULL
) { 
 533     if (!(winPtr
->flags 
& TK_TOP_LEVEL
)) { 
 534         Tcl_AppendResult(interp
, "window \"", winPtr
->pathName
, 
 535                 "\" isn't a top-level window", (char *) NULL
); 
 538     wmPtr 
= winPtr
->wmInfoPtr
; 
 540     length 
= strlen(argv
[1]); 
 541     if ((c 
== 'a') && (strncmp(argv
[1], "aspect", length
) == 0)) { 
 542         int numer1
, denom1
, numer2
, denom2
; 
 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
); 
 551             if (wmPtr
->sizeHintsFlags 
& PAspect
) { 
 552                 sprintf(interp
->result
, "%d %d %d %d", wmPtr
->minAspect
.x
, 
 553                         wmPtr
->minAspect
.y
, wmPtr
->maxAspect
.x
, 
 558         if (*argv
[3] == '\0') { 
 559             wmPtr
->sizeHintsFlags 
&= ~PAspect
; 
 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
)) { 
 567             if ((numer1 
<= 0) || (denom1 
<= 0) || (numer2 
<= 0) || 
 569                 interp
->result 
= "aspect number can't be <= 0"; 
 572             wmPtr
->minAspect
.x 
= numer1
; 
 573             wmPtr
->minAspect
.y 
= denom1
; 
 574             wmPtr
->maxAspect
.x 
= numer2
; 
 575             wmPtr
->maxAspect
.y 
= denom2
; 
 576             wmPtr
->sizeHintsFlags 
|= PAspect
; 
 578         wmPtr
->flags 
|= WM_UPDATE_SIZE_HINTS
; 
 580     } else if ((c 
== 'd') && (strncmp(argv
[1], "deiconify", length
) == 0)) { 
 582             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
 583                     argv
[0], " deiconify window\"", (char *) NULL
); 
 586         wmPtr
->hints
.initial_state 
= NormalState
; 
 587         if (wmPtr
->flags 
& WM_NEVER_MAPPED
) { 
 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?\"", 
 599             interp
->result 
= wmPtr
->hints
.input 
? "passive" : "active"; 
 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
; 
 609             Tcl_AppendResult(interp
, "bad argument \"", argv
[3], 
 610                     "\": must be active or passive", (char *) NULL
); 
 614     } else if ((c 
== 'f') && (strncmp(argv
[1], "fullscreen", length
) == 0)) { 
 616             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
 617                     argv
[0], " fullscreen window on|off\"", 
 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
; 
 628             Tcl_AppendResult(interp
, "bad argument \"", argv
[3], 
 629                     "\": must be on or off", (char *) NULL
); 
 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
; 
 638         if (!_NET_WM_STATE
) { 
 640           Atom 
*atom_ptr
[MAX_ATOMS
]; 
 641           char *names
[MAX_ATOMS
]; 
 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"); 
 649           Atom atoms
[MAX_ATOMS
]; 
 650           XInternAtoms(winPtr
->display
, names
, i
, 0, atoms
); 
 652             *atom_ptr
[i
] = atoms
[i
]; 
 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
) 
 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
); 
 672     } else if ((c 
== 'g') && (strncmp(argv
[1], "geometry", length
) == 0) 
 677         if ((argc 
!= 3) && (argc 
!= 4)) { 
 678             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
 679                     argv
[0], " geometry window ?newGeometry?\"", 
 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
; 
 693                 width 
= winPtr
->reqWidth
; 
 694                 height 
= winPtr
->reqHeight
; 
 696             sprintf(interp
->result
, "%dx%d%c%d%c%d", width
, height
, 
 697                     xSign
, wmPtr
->x
, ySign
, wmPtr
->y
); 
 700         if (*argv
[3] == '\0') { 
 705         return ParseGeometry(interp
, argv
[3], winPtr
); 
 706     } else if ((c 
== 'g') && (strncmp(argv
[1], "grid", length
) == 0) 
 708         int reqWidth
, reqHeight
, widthInc
, heightInc
; 
 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
); 
 717             if (wmPtr
->sizeHintsFlags 
& PBaseSize
) { 
 718                 sprintf(interp
->result
, "%d %d %d %d", wmPtr
->reqGridWidth
, 
 719                         wmPtr
->reqGridHeight
, wmPtr
->widthInc
, 
 724         if (*argv
[3] == '\0') { 
 726              * Turn off gridding and reset the width and height 
 727              * to make sense as ungridded numbers. 
 730             wmPtr
->sizeHintsFlags 
&= ~(PBaseSize
|PResizeInc
); 
 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
; 
 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
)) { 
 747                 interp
->result 
= "baseWidth can't be < 0"; 
 751                 interp
->result 
= "baseHeight can't be < 0"; 
 755                 interp
->result 
= "widthInc can't be < 0"; 
 759                 interp
->result 
= "heightInc can't be < 0"; 
 762             Tk_SetGrid((Tk_Window
) tkwin
, reqWidth
, reqHeight
, widthInc
, 
 765         wmPtr
->flags 
|= WM_UPDATE_SIZE_HINTS
; 
 767     } else if ((c 
== 'g') && (strncmp(argv
[1], "group", length
) == 0) 
 771         if ((argc 
!= 3) && (argc 
!= 4)) { 
 772             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
 773                     argv
[0], " group window ?pathName?\"", 
 778             if (wmPtr
->hints
.flags 
& WindowGroupHint
) { 
 779                 interp
->result 
= wmPtr
->leaderName
; 
 783         if (*argv
[3] == '\0') { 
 784             wmPtr
->hints
.flags 
&= ~WindowGroupHint
; 
 785             wmPtr
->leaderName 
= NULL
; 
 787             tkwin2 
= Tk_NameToWindow(interp
, argv
[3], tkwin
); 
 788             if (tkwin2 
== NULL
) { 
 791             Tk_MakeWindowExist(tkwin2
); 
 792             wmPtr
->hints
.window_group 
= Tk_WindowId(tkwin2
); 
 793             wmPtr
->hints
.flags 
|= WindowGroupHint
; 
 794             wmPtr
->leaderName 
= Tk_PathName(tkwin2
); 
 797     } else if ((c 
== 'i') && (strncmp(argv
[1], "iconbitmap", length
) == 0) 
 801         if ((argc 
!= 3) && (argc 
!= 4)) { 
 802             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
 803                     argv
[0], " iconbitmap window ?bitmap?\"", 
 808             if (wmPtr
->hints
.flags 
& IconPixmapHint
) { 
 809                 interp
->result 
= Tk_NameOfBitmap(wmPtr
->hints
.icon_pixmap
); 
 813         if (*argv
[3] == '\0') { 
 814             if (wmPtr
->hints
.icon_pixmap 
!= None
) { 
 815                 Tk_FreeBitmap(wmPtr
->hints
.icon_pixmap
); 
 817             wmPtr
->hints
.flags 
&= ~IconPixmapHint
; 
 819             pixmap 
= Tk_GetBitmap(interp
, tkwin
, Tk_GetUid(argv
[3])); 
 820             if (pixmap 
== None
) { 
 823             wmPtr
->hints
.icon_pixmap 
= pixmap
; 
 824             wmPtr
->hints
.flags 
|= IconPixmapHint
; 
 827     } else if ((c 
== 'i') && (strncmp(argv
[1], "iconify", length
) == 0) 
 830             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
 831                     argv
[0], " iconify window\"", (char *) NULL
); 
 834         wmPtr
->hints
.initial_state 
= IconicState
; 
 835         if (wmPtr
->flags 
& WM_NEVER_MAPPED
) { 
 839         if (XIconifyWindow(winPtr
->display
, winPtr
->window
, 
 840                 winPtr
->screenNum
) == 0) { 
 842                     "couldn't send iconify message to window manager"; 
 846         interp
->result 
= "can't iconify under X11R3"; 
 849     } else if ((c 
== 'i') && (strncmp(argv
[1], "iconmask", length
) == 0) 
 853         if ((argc 
!= 3) && (argc 
!= 4)) { 
 854             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
 855                     argv
[0], " iconmask window ?bitmap?\"", 
 860             if (wmPtr
->hints
.flags 
& IconMaskHint
) { 
 861                 interp
->result 
= Tk_NameOfBitmap(wmPtr
->hints
.icon_mask
); 
 865         if (*argv
[3] == '\0') { 
 866             if (wmPtr
->hints
.icon_mask 
!= None
) { 
 867                 Tk_FreeBitmap(wmPtr
->hints
.icon_mask
); 
 869             wmPtr
->hints
.flags 
&= ~IconMaskHint
; 
 871             pixmap 
= Tk_GetBitmap(interp
, tkwin
, Tk_GetUid(argv
[3])); 
 872             if (pixmap 
== None
) { 
 875             wmPtr
->hints
.icon_mask 
= pixmap
; 
 876             wmPtr
->hints
.flags 
|= IconMaskHint
; 
 879     } else if ((c 
== 'i') && (strncmp(argv
[1], "iconname", length
) == 0) 
 882             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
 883                     argv
[0], " iconname window ?newName?\"", (char *) NULL
); 
 887             interp
->result 
= (wmPtr
->iconName 
!= NULL
) ? wmPtr
->iconName 
: ""; 
 890             wmPtr
->iconName 
= Tk_GetUid(argv
[3]); 
 891             if (!(wmPtr
->flags 
& WM_NEVER_MAPPED
)) { 
 892                 XSetIconName(winPtr
->display
, winPtr
->window
, wmPtr
->iconName
); 
 895     } else if ((c 
== 'i') && (strncmp(argv
[1], "iconposition", length
) == 0) 
 899         if ((argc 
!= 3) && (argc 
!= 5)) { 
 900             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
 901                     argv
[0], " iconposition window ?x y?\"", 
 906             if (wmPtr
->hints
.flags 
& IconPositionHint
) { 
 907                 sprintf(interp
->result
, "%d %d", wmPtr
->hints
.icon_x
, 
 908                         wmPtr
->hints
.icon_y
); 
 912         if (*argv
[3] == '\0') { 
 913             wmPtr
->hints
.flags 
&= ~IconPositionHint
; 
 915             if ((Tcl_GetInt(interp
, argv
[3], &x
) != TCL_OK
) 
 916                     || (Tcl_GetInt(interp
, argv
[4], &y
) != TCL_OK
)){ 
 919             wmPtr
->hints
.icon_x 
= x
; 
 920             wmPtr
->hints
.icon_y 
= y
; 
 921             wmPtr
->hints
.flags 
|= IconPositionHint
; 
 924     } else if ((c 
== 'i') && (strncmp(argv
[1], "iconwindow", length
) == 0) 
 928         if ((argc 
!= 3) && (argc 
!= 4)) { 
 929             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
 930                     argv
[0], " iconwindow window ?pathName?\"", 
 935             if (wmPtr
->hints
.flags 
& IconWindowHint
) { 
 936                 interp
->result 
= wmPtr
->iconWindowName
; 
 940         if (*argv
[3] == '\0') { 
 941             wmPtr
->hints
.flags 
&= ~IconWindowHint
; 
 942             wmPtr
->iconWindowName 
= NULL
; 
 944             tkwin2 
= Tk_NameToWindow(interp
, argv
[3], tkwin
); 
 945             if (tkwin2 
== NULL
) { 
 948             Tk_MakeWindowExist(tkwin2
); 
 949             wmPtr
->hints
.icon_window 
= Tk_WindowId(tkwin2
); 
 950             wmPtr
->hints
.flags 
|= IconWindowHint
; 
 951             wmPtr
->iconWindowName 
= Tk_PathName(tkwin2
); 
 954     } else if ((c 
== 'm') && (strncmp(argv
[1], "maxsize", length
) == 0) 
 957         if ((argc 
!= 3) && (argc 
!= 5)) { 
 958             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
 959                     argv
[0], " maxsize window ?width height?\"", (char *) NULL
); 
 963             if (wmPtr
->sizeHintsFlags 
& PMaxSize
) { 
 964                 sprintf(interp
->result
, "%d %d", wmPtr
->maxWidth
, 
 969         if (*argv
[3] == '\0') { 
 970             wmPtr
->sizeHintsFlags 
&= ~PMaxSize
; 
 972             if ((Tcl_GetInt(interp
, argv
[3], &width
) != TCL_OK
) 
 973                     || (Tcl_GetInt(interp
, argv
[4], &height
) != TCL_OK
)) { 
 976             wmPtr
->maxWidth 
= width
; 
 977             wmPtr
->maxHeight 
= height
; 
 978             wmPtr
->sizeHintsFlags 
|= PMaxSize
; 
 980         wmPtr
->flags 
|= WM_UPDATE_SIZE_HINTS
; 
 982     } else if ((c 
== 'm') && (strncmp(argv
[1], "minsize", length
) == 0) 
 985         if ((argc 
!= 3) && (argc 
!= 5)) { 
 986             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
 987                     argv
[0], " minsize window ?width height?\"", (char *) NULL
); 
 991             if (wmPtr
->sizeHintsFlags 
& PMinSize
) { 
 992                 sprintf(interp
->result
, "%d %d", wmPtr
->minWidth
, 
 997         if (*argv
[3] == '\0') { 
 998             wmPtr
->sizeHintsFlags 
&= ~PMinSize
; 
1000             if ((Tcl_GetInt(interp
, argv
[3], &width
) != TCL_OK
) 
1001                     || (Tcl_GetInt(interp
, argv
[4], &height
) != TCL_OK
)) { 
1004             wmPtr
->minWidth 
= width
; 
1005             wmPtr
->minHeight 
= height
; 
1006             wmPtr
->sizeHintsFlags 
|= PMinSize
; 
1008         wmPtr
->flags 
|= WM_UPDATE_SIZE_HINTS
; 
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?\"", 
1018             if (wmPtr
->sizeHintsFlags 
& USPosition
) { 
1019                 interp
->result 
= "user"; 
1020             } else if (wmPtr
->sizeHintsFlags 
& PPosition
) { 
1021                 interp
->result 
= "program"; 
1025         if (*argv
[3] == '\0') { 
1026             wmPtr
->sizeHintsFlags 
&= ~(USPosition
|PPosition
); 
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
; 
1037                 Tcl_AppendResult(interp
, "bad argument \"", argv
[3], 
1038                         "\": must be program or user", (char *) NULL
); 
1042         wmPtr
->flags 
|= WM_UPDATE_SIZE_HINTS
; 
1044     } else if ((c 
== 'r') && (strncmp(argv
[1], "raise", length
) == 0)) { 
1046             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
1047                     argv
[0], " raise window\"", (char *) NULL
); 
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?\"", 
1060             if (wmPtr
->sizeHintsFlags 
& USSize
) { 
1061                 interp
->result 
= "user"; 
1062             } else if (wmPtr
->sizeHintsFlags 
& PSize
) { 
1063                 interp
->result 
= "program"; 
1067         if (*argv
[3] == '\0') { 
1068             wmPtr
->sizeHintsFlags 
&= ~(USSize
|PSize
); 
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
; 
1080                 Tcl_AppendResult(interp
, "bad argument \"", argv
[3], 
1081                         "\": must be program or user", (char *) NULL
); 
1085         wmPtr
->flags 
|= WM_UPDATE_SIZE_HINTS
; 
1087     } else if ((c 
== 't') && (strncmp(argv
[1], "title", length
) == 0) 
1090             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
1091                     argv
[0], " title window ?newTitle?\"", (char *) NULL
); 
1095             interp
->result 
= (wmPtr
->titleUid 
!= NULL
) ? wmPtr
->titleUid
 
1099             wmPtr
->titleUid 
= Tk_GetUid(argv
[3]); 
1101             if (!(wmPtr
->flags 
& WM_NEVER_MAPPED
)) { 
1102                 XTextProperty textProp
; 
1104                 if (XStringListToTextProperty(&wmPtr
->titleUid
, 1, 
1106                     XSetWMName(winPtr
->display
, winPtr
->window
, &textProp
); 
1107                     XFree((char *) textProp
.value
); 
1113     } else if ((c 
== 't') && (strncmp(argv
[1], "transient", length
) == 0) 
1117         if ((argc 
!= 3) && (argc 
!= 4)) { 
1118             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
1119                     argv
[0], " transient window ?master?\"", (char *) NULL
); 
1123             if (wmPtr
->master 
!= None
) { 
1124                 interp
->result 
= wmPtr
->masterWindowName
; 
1128         if (argv
[3][0] == '\0') { 
1129             wmPtr
->master 
= None
; 
1130             wmPtr
->masterWindowName 
= NULL
; 
1132             master 
= Tk_NameToWindow(interp
, argv
[3], tkwin
); 
1133             if (master 
== NULL
) { 
1136             Tk_MakeWindowExist(master
); 
1137             wmPtr
->master 
= Tk_WindowId(master
); 
1138             wmPtr
->masterWindowName 
= Tk_PathName(master
); 
1140         if (!(wmPtr
->flags 
& WM_NEVER_MAPPED
)) { 
1141             XSetTransientForHint(winPtr
->display
, winPtr
->window
, 
1144     } else if ((c 
== 'w') && (strncmp(argv
[1], "withdraw", length
) == 0)) { 
1146             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
1147                     argv
[0], " withdraw window\"", (char *) NULL
); 
1150         wmPtr
->hints
.initial_state 
= WithdrawnState
; 
1151         if (wmPtr
->flags 
& WM_NEVER_MAPPED
) { 
1154         if (XWithdrawWindow(winPtr
->display
, winPtr
->window
, 
1155                 winPtr
->screenNum
) == 0) { 
1157                     "couldn't send withdraw message to window manager"; 
1160         winPtr
->flags 
&= ~TK_MAPPED
; 
1161     } else if ((c 
== 'p') && (strncmp(argv
[1], "protocol", length
) == 0)) { 
1163          * handle various ICCCM WM_PROTOCOL attributes 
1166             Tcl_AppendResult(interp
, "wrong # arguments: must be \"", 
1167                     argv
[0], " protocol window type..\"", (char *) NULL
); 
1170         if (!strcmp(argv
[3], "delete")) { 
1171             return WmProtocolCmd(interp
, &(wmPtr
->deleteCmd
), argc
, argv
); 
1173             Tcl_AppendResult(interp
,  argv
[0],  
1174                 ": bad argument ", argv
[3], " must be: ",  
1175                 "delete", (char *) NULL
); 
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", 
1192     if (!(wmPtr
->flags 
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) { 
1193         Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
); 
1194         wmPtr
->flags 
|= WM_UPDATE_PENDING
; 
1200  *---------------------------------------------------------------------- 
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. 
1213  *      Grid-related information will be passed to the window manager, so 
1214  *      that the top-level window associated with tkwin will resize on 
1217  *---------------------------------------------------------------------- 
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. */ 
1232     TkWindow 
*winPtr 
= (TkWindow 
*) tkwin
; 
1233     register WmInfo 
*wmPtr
; 
1236      * Find the top-level window for tkwin, plus the window manager 
1240     while (!(winPtr
->flags 
& TK_TOP_LEVEL
)) { 
1241         winPtr 
= winPtr
->parentPtr
; 
1243     wmPtr 
= winPtr
->wmInfoPtr
; 
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
)) { 
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). 
1263     if (!(wmPtr
->sizeHintsFlags 
& PBaseSize
)) { 
1269      * Set the new gridding information, and start the process of passing 
1270      * all of this information to the window manager. 
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
; 
1286  *---------------------------------------------------------------------- 
1288  * TopLevelEventProc -- 
1290  *      This procedure is invoked when a top-level (or other externally- 
1291  *      managed window) is restructured in any way. 
1297  *      Tk's internal data structures for the window get modified to 
1298  *      reflect the structural change. 
1300  *---------------------------------------------------------------------- 
1304 TopLevelEventProc(clientData
, eventPtr
) 
1305     ClientData clientData
;              /* Window for which event occurred. */ 
1306     XEvent 
*eventPtr
;                   /* Event that just happened. */ 
1308     register TkWindow 
*winPtr 
= (TkWindow 
*) clientData
; 
1310     if (eventPtr
->type 
== DestroyNotify
) { 
1311         if (!(winPtr
->flags 
& TK_ALREADY_DEAD
)) { 
1312             Tk_DestroyWindow((Tk_Window
) winPtr
); 
1314     } else if (eventPtr
->type 
== ConfigureNotify
) { 
1315         register WmInfo 
*wmPtr 
= winPtr
->wmInfoPtr
; 
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 
1329         diff 
= eventPtr
->xconfigure
.serial 
- wmPtr
->configRequest
; 
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. 
1350         if (wmPtr
->reparent 
== None
) { 
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
; 
1359             unsigned int width
, height
, bd
, dummy
; 
1362             Tk_ErrorHandler handler
; 
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
); 
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 
1376                 wmPtr
->reparent 
= None
; 
1377                 wmPtr
->flags 
&= ~WM_NESTED_REPARENT
; 
1378                 wmPtr
->xInParent 
= wmPtr
->yInParent 
= 0; 
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
; 
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
; 
1393                 if (!eventPtr
->xconfigure
.send_event
) { 
1394                     wmPtr
->xInParent 
= eventPtr
->xconfigure
.x 
+ bd
; 
1395                     wmPtr
->yInParent 
= eventPtr
->xconfigure
.y 
+ bd
; 
1398             winPtr
->changes
.x 
= x 
+ wmPtr
->xInParent
; 
1399             winPtr
->changes
.y 
= y 
+ wmPtr
->yInParent
; 
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 
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 
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 
1424         if (wmPtr
->flags 
& WM_CONFIG_PENDING
) { 
1427              * Size change is just a reflection of something coming from 
1431             diff 
= eventPtr
->xconfigure
.serial 
- wmPtr
->configRequest
; 
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
; 
1439                 wmPtr
->flags 
&= ~(WM_CONFIG_PENDING
|WM_CONFIG_AGAIN
); 
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) { 
1452                 wmPtr
->height 
= wmPtr
->reqGridHeight
 
1453                         + (eventPtr
->xconfigure
.height
 
1454                         - winPtr
->reqHeight
)/wmPtr
->heightInc
; 
1455                 if (wmPtr
->height 
< 0) { 
1458             } else if ((eventPtr
->xconfigure
.width 
!= winPtr
->changes
.width
) 
1459                     || (eventPtr
->xconfigure
.height
 
1460                             != winPtr
->changes
.height
)) { 
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 
1467                 wmPtr
->width 
= eventPtr
->xconfigure
.width
; 
1468                 wmPtr
->height 
= eventPtr
->xconfigure
.height
; 
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
; 
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
); 
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
); 
1488         if ((x 
!= wmPtr
->x
) || (y 
!= wmPtr
->y
)) { 
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
; 
1501         unsigned long numItems
, bytesAfter
; 
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. 
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
; 
1520             virtualRootPtr 
= NULL
; 
1523               Tk_CreateErrorHandler(winPtr
->display
, BadDrawable
, 
1524                                     -1, -1, (Tk_ErrorProc 
*) NULL
, 
1527               Tk_CreateErrorHandler(winPtr
->display
, BadWindow
, 
1528                                     -1, -1, (Tk_ErrorProc 
*) NULL
, 
1531             status 
= XGetWindowProperty(winPtr
->display
, root
, 
1533                                         0, (long) 1, False
, XA_WINDOW
, 
1534                                         &actualType
, &actualFormat
, 
1535                                         &numItems
, &bytesAfter
, 
1536                                         (unsigned char **) &virtualRootPtr
); 
1538             Tk_DeleteErrorHandler(handler1
); 
1539             Tk_DeleteErrorHandler(handler2
); 
1541             if (status 
== Success
) { 
1542                 if (virtualRootPtr 
!= NULL
) { 
1543                     if (*virtualRootPtr 
!= root
) { 
1544                         panic("TopLevelEventProc confused over virtual root"); 
1546                     XFree((char *) virtualRootPtr
); 
1550             wmPtr
->reparent 
= root
; 
1551             (void) XQueryTree(winPtr
->display
, root
, &dummy2
, &root
, 
1553             XFree((char *) children
); 
1557          * The ancestor just below the (virtual) root is in wmPtr->reparent 
1558          * now, and the (virtual) root is in root. 
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
; 
1573             int x
, y
, xOffset
, yOffset
; 
1574             unsigned int width
, height
, bd
; 
1576             if (wmPtr
->reparent 
!= eventPtr
->xreparent
.parent
) { 
1577                 wmPtr
->flags 
|= WM_NESTED_REPARENT
; 
1579                 wmPtr
->flags 
&= ~WM_NESTED_REPARENT
; 
1583              * Compute and save information about reparent and about 
1584              * the window's position in reparent. 
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
; 
1598     } else if ((eventPtr
->type 
== EnterNotify
) 
1599             || (eventPtr
->type 
== LeaveNotify
)) { 
1600         TkFocusEventProc(winPtr
, eventPtr
); 
1605  *---------------------------------------------------------------------- 
1607  * TopLevelReqProc -- 
1609  *      This procedure is invoked by the geometry manager whenever 
1610  *      the requested size for a top-level window is changed. 
1616  *      Arrange for the window to be resized to satisfy the request 
1617  *      (this happens as a when-idle action). 
1619  *---------------------------------------------------------------------- 
1624 TopLevelReqProc(dummy
, tkwin
) 
1625     ClientData dummy
;                   /* Not used. */ 
1626     Tk_Window tkwin
;                    /* Information about window. */ 
1628     TkWindow 
*winPtr 
= (TkWindow 
*) tkwin
; 
1631     wmPtr 
= winPtr
->wmInfoPtr
; 
1632     if ((wmPtr
->prevReqWidth 
== winPtr
->reqWidth
) 
1633             && (wmPtr
->prevReqHeight 
== winPtr
->reqHeight
)) { 
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
; 
1646  *---------------------------------------------------------------------- 
1648  * UpdateGeometryInfo -- 
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. 
1659  *      The window's size and location may change, unless the WM prevents 
1660  *      that from happening. 
1662  *---------------------------------------------------------------------- 
1666 UpdateGeometryInfo(clientData
) 
1667     ClientData clientData
;              /* Pointer to the window's record. */ 
1669     register TkWindow 
*winPtr 
= (TkWindow 
*) clientData
; 
1670     register WmInfo 
*wmPtr 
= winPtr
->wmInfoPtr
; 
1671     int x
, y
, width
, height
; 
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. 
1680     wmPtr
->flags 
&= ~WM_UPDATE_PENDING
; 
1681     if (wmPtr
->flags 
& WM_CONFIG_PENDING
) { 
1682         wmPtr
->flags 
|= WM_CONFIG_AGAIN
; 
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 
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
; 
1706         width 
= wmPtr
->width
; 
1707         height 
= wmPtr
->height
; 
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. 
1723     if (wmPtr
->flags 
& WM_NEGATIVE_X
) { 
1724         x 
= DisplayWidth(winPtr
->display
, winPtr
->screenNum
) - wmPtr
->x
 
1725                 - (width 
+ (wmPtr
->parentWidth 
- winPtr
->changes
.width
)) 
1728         x 
=  wmPtr
->x 
+ wmPtr
->xInParent
; 
1730     if (wmPtr
->flags 
& WM_NEGATIVE_Y
) { 
1731         y 
= DisplayHeight(winPtr
->display
, winPtr
->screenNum
) - wmPtr
->y
 
1732                 - (height 
+ (wmPtr
->parentHeight 
- winPtr
->changes
.height
)) 
1735         y 
=  wmPtr
->y 
+ wmPtr
->yInParent
; 
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. 
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
; 
1750     if (wmPtr
->flags 
& WM_UPDATE_SIZE_HINTS
) { 
1751         UpdateSizeHints(winPtr
); 
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. 
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
, 
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
, 
1775         wmPtr
->flags 
|= WM_CONFIG_PENDING
; 
1780  *-------------------------------------------------------------- 
1782  * UpdateSizeHints -- 
1784  *      This procedure is called to update the window manager's 
1785  *      size hints information from the information in a WmInfo 
1792  *      Properties get changed for winPtr. 
1794  *-------------------------------------------------------------- 
1798 UpdateSizeHints(winPtr
) 
1801     register WmInfo 
*wmPtr 
= winPtr
->wmInfoPtr
; 
1802     XSizeHints 
*hintsPtr
; 
1804     wmPtr
->flags 
&= ~WM_UPDATE_SIZE_HINTS
; 
1807     hintsPtr 
= XAllocSizeHints(); 
1808     if (hintsPtr 
== NULL
) { 
1813      * Compute the pixel-based sizes for the various fields in the 
1814      * size hints structure, based on the grid-based sizes in 
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; 
1824         hintsPtr
->base_height 
= winPtr
->reqHeight
 
1825                 - (wmPtr
->reqGridHeight 
* wmPtr
->heightInc
); 
1826         if (hintsPtr
->base_height 
< 0) { 
1827             hintsPtr
->base_height 
= 0; 
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
); 
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; 
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
; 
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. 
1859     if (!IS_GRIDDED(wmPtr
) 
1860             && ((wmPtr
->sizeHintsFlags 
& (PMinSize
|PMaxSize
)) == 0)) { 
1863         width 
= wmPtr
->width
; 
1864         height 
= wmPtr
->height
; 
1866             width 
= winPtr
->reqWidth
; 
1867             height 
= winPtr
->reqHeight
; 
1869         hintsPtr
->min_width 
= hintsPtr
->max_width 
= width
; 
1870         hintsPtr
->min_height 
= hintsPtr
->max_height 
= height
; 
1871         hintsPtr
->flags 
|= PMinSize
|PMaxSize
; 
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. 
1880     if (!(hintsPtr
->flags 
& PMinSize
)) { 
1881         hintsPtr
->min_width 
= hintsPtr
->min_height 
= 0; 
1882         hintsPtr
->flags 
|= PMinSize
; 
1884     if (!(hintsPtr
->flags 
& PMaxSize
)) { 
1885         hintsPtr
->max_width 
= hintsPtr
->max_height 
= 1000000; 
1886         hintsPtr
->flags 
|= PMaxSize
; 
1889     XSetWMNormalHints(winPtr
->display
, winPtr
->window
, hintsPtr
); 
1891     XFree((char *) hintsPtr
); 
1896  *-------------------------------------------------------------- 
1900  *      This procedure is called to update the window manager's 
1901  *      hints information from the information in a WmInfo 
1908  *      Properties get changed for winPtr. 
1910  *-------------------------------------------------------------- 
1917     WmInfo 
*wmPtr 
= winPtr
->wmInfoPtr
; 
1919     if (wmPtr
->flags 
& WM_NEVER_MAPPED
) { 
1922     XSetWMHints(winPtr
->display
, winPtr
->window
, &wmPtr
->hints
); 
1926  *-------------------------------------------------------------- 
1930  *      This procedure parses a geometry string and updates 
1931  *      information used to control the geometry of a top-level 
1935  *      A standard Tcl return value, plus an error message in 
1936  *      interp->result if an error occurs. 
1939  *      The size and/or location of winPtr may change. 
1941  *-------------------------------------------------------------- 
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. */ 
1952     register WmInfo 
*wmPtr 
= winPtr
->wmInfoPtr
; 
1953     int x
, y
, width
, height
, flags
; 
1955     register char *p 
= string
; 
1958      * The leading "=" is optional. 
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. 
1971     width 
= wmPtr
->width
; 
1972     height 
= wmPtr
->height
; 
1975     flags 
= wmPtr
->flags
; 
1977         width 
= strtoul(p
, &end
, 10); 
1986         height 
= strtoul(p
, &end
, 10); 
1991      * Parse the X and Y coordinates, if they are present. 
1995         flags 
&= ~(WM_NEGATIVE_X 
| WM_NEGATIVE_Y
); 
1997             flags 
|= WM_NEGATIVE_X
; 
1998         } else if (*p 
!= '+') { 
2001         x 
= strtol(p
+1, &end
, 10); 
2004             flags 
|= WM_NEGATIVE_Y
; 
2005         } else if (*p 
!= '+') { 
2008         y 
= strtol(p
+1, &end
, 10); 
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. 
2020         if ((wmPtr
->sizeHintsFlags 
& (USPosition
|PPosition
)) == 0) { 
2021             wmPtr
->sizeHintsFlags 
|= USPosition
; 
2022             wmPtr
->flags 
|= WM_UPDATE_SIZE_HINTS
; 
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. 
2032     wmPtr
->width 
= width
; 
2033     wmPtr
->height 
= height
; 
2036     wmPtr
->flags 
= flags
; 
2038     if (!(wmPtr
->flags 
& (WM_UPDATE_PENDING
|WM_NEVER_MAPPED
))) { 
2039         Tk_DoWhenIdle(UpdateGeometryInfo
, (ClientData
) winPtr
); 
2040         wmPtr
->flags 
|= WM_UPDATE_PENDING
; 
2045     Tcl_AppendResult(interp
, "bad geometry specifier \"", 
2046             string
, "\"", (char *) NULL
); 
2051  *---------------------------------------------------------------------- 
2053  * Tk_GetRootCoords -- 
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. 
2060  *      The locations pointed to by xPtr and yPtr are filled in with 
2061  *      the root coordinates of the (0,0) point in tkwin. 
2066  *---------------------------------------------------------------------- 
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). */ 
2076     register TkWindow 
*winPtr 
= (TkWindow 
*) tkwin
; 
2079      * Search back through this window's parents all the way to a 
2080      * top-level window, combining the offsets of each window within 
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
) { 
2091         winPtr 
= winPtr
->parentPtr
; 
2100  *-------------------------------------------------------------- 
2102  * TkWmSetWmProtocols -- 
2103  *      Set the ICCCM WM_PROTOCOLS to be honored by this window. 
2104  *      Currently, it is just WM_DELETE_WINDOW. 
2110  *      A window property may get updated. 
2112  *-------------------------------------------------------------- 
2116 TkWmSetWmProtocols(winPtr
) 
2117     TkWindow 
*winPtr
;           /* Newly-created top-level window. */ 
2119     if (winPtr
->wmInfoPtr
->flags 
& WM_NEVER_MAPPED
) { 
2124         /* assemble the WM_PROTOCOLS that we honor */ 
2127         atomlist
[count
++] = Tk_InternAtom((Tk_Window
) winPtr
, 
2128                                           "WM_DELETE_WINDOW"); 
2130  *      other WM_PROTOCOLS go here -- e.g... 
2131  *      atomlist[count++] = Tk_InternAtom((Tk_Window) winPtr, 
2132  *                                        "WM_SAVE_YOURSELF"); 
2136          * assign the honor list to the window not all X11R4's have  
2137          * XSetWmProtocols() so use XChangeProperty()  
2140         /* XSetWmProtocols(winPtr->display, winPtr->window, atomlist, count); */ 
2142         XChangeProperty(winPtr
->display
,  
2144                         Tk_InternAtom((Tk_Window
) winPtr
, "WM_PROTOCOLS"), 
2147                         (unsigned char *)atomlist
,  
2158  *---------------------------------------------------------------------- 
2160  * TkWmProtocolEventProc -- 
2162  *      Handle a WM_PROTOCOL ICCCM event sent by the window manager to 
2165  *      The WM_PROTOCOL's currently handled are: 
2167  *              WM_DELETE_PROTOCOL: 
2172  *      for WM_DELETE_WINDOW: 
2173  *              - window may be deleted if specified earlier by a  
2175  *              - a tcl command may be executed if sepcified earlier by a 
2181 TkWmProtocolEventProc(winPtr
, eventPtr
) 
2185     if ((Atom
)(eventPtr
->xclient
.data
.l
)[0] == 
2186         Tk_InternAtom((Tk_Window
) winPtr
, "WM_DELETE_WINDOW")) { 
2188         WmInfo 
*wmPtr 
= winPtr
->wmInfoPtr
; 
2190         if (wmPtr
->deleteCmd
) { 
2191             if (*(wmPtr
->deleteCmd
) == '\0') { 
2192                 /* callback is empty, just delete the window */ 
2193                 Tk_DestroyWindow((Tk_Window
) winPtr
); 
2195                 /* there is a callback so run it */ 
2196                 (void) Tcl_Eval(winPtr
->mainPtr
->interp
,  
2197                                 wmPtr
->deleteCmd
, 0, (char **)0); 
2200             Tk_DestroyWindow((Tk_Window
) winPtr
); 
2204      * else { .. other WM_<ETC> cases go here ... } 
2211  *---------------------------------------------------------------------- 
2217  *      wm protocol <window> delete [command_str]  
2219  * right now just delete is supported for OPTION 
2221  * Kind of artificial, But makes it easier to merge into new 
2222  * versions of Stock Tk. 
2225 WmProtocolCmd(interp
, CmdPtr
, argc
, argv
) 
2231 #define Cmd (*CmdPtr) 
2236          * return current command  
2238         if (!Cmd 
|| *Cmd 
== '\0') { 
2242              * chop off the <blank><window_name> 
2243              * and return just the cmd  
2245             int x 
= strlen(Cmd
) - strlen(argv
[2]) - 1; 
2249                 /* maybe should just have them put the window in the cmd */ 
2250                 Tcl_AppendResult(interp
, Cmd
, (char *)NULL
); 
2253              * tack the blank and window name back on  
2266         if (*argv
[4] != '\0') { 
2267             int x 
= strlen(argv
[4]) + strlen(argv
[2]) + 2; 
2268             if (!(Cmd 
= ckalloc(x
))) { 
2269                 perror("wm protocol:"); 
2271                 sprintf(Cmd
, "%s %s", argv
[4], argv
[2]); 
2276         Tcl_AppendResult(interp
, "wrong # of arguments: must be \"", 
2277             argv
[0], " protocol window <attribute> [cmd]\"", (char *) NULL
); 
2286  *---------------------------------------------------------------------- 
2288  * Tk_CoordsToWindow -- 
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. 
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 
2302  *---------------------------------------------------------------------- 
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. */ 
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. */ 
2319     Window 
*children
;           /* Children of winPtr, or NULL. */ 
2320     unsigned int numChildren
;   /* Size of children array. */ 
2323      * Step 1:  find the top-level window that contains the desired 
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"); 
2333     for (wmPtr 
= firstWmPtr
; ; wmPtr 
= wmPtr
->nextPtr
) { 
2334         if (wmPtr 
== NULL
) { 
2337         if ((wmPtr
->reparent 
== rootChild
) || ((wmPtr
->reparent 
== None
) 
2338                 && (wmPtr
->winPtr
->window 
== rootChild
))) { 
2342     winPtr 
= wmPtr
->winPtr
; 
2343     if (winPtr
->mainPtr 
!= ((TkWindow 
*) tkwin
)->mainPtr
) { 
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. 
2359         x 
-= winPtr
->changes
.x
; 
2360         y 
-= winPtr
->changes
.y
; 
2363         for (childPtr 
= winPtr
->childList
; childPtr 
!= NULL
; 
2364                 childPtr 
= childPtr
->nextPtr
) { 
2365             if (!Tk_IsMapped(childPtr
) || (childPtr
->flags 
& TK_TOP_LEVEL
)) { 
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
))) { 
2376             if (nextPtr 
== NULL
) { 
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. 
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"); 
2394             for (i 
= 0; i 
< numChildren
; i
++) { 
2395                 if (children
[i
] == childPtr
->window
) { 
2398                 if (children
[i
] == nextPtr
->window
) { 
2404         if (children 
!= NULL
) { 
2405             XFree((char *) children
); 
2407         if (nextPtr 
== NULL
) { 
2412     return (Tk_Window
) winPtr
;