1/* 2 * tkUnixWm.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 (c) 1991-1994 The Regents of the University of California. 10 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 11 * 12 * See the file "license.terms" for information on usage and redistribution 13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 14 * 15 * RCS: @(#) $Id: tkUnixWm.c,v 1.36.2.7 2006/04/11 20:23:45 hobbs Exp $ 16 */ 17 18#include "tkPort.h" 19#include "tkInt.h" 20#include "tkUnixInt.h" 21 22/* 23 * A data structure of the following type holds information for 24 * each window manager protocol (such as WM_DELETE_WINDOW) for 25 * which a handler (i.e. a Tcl command) has been defined for a 26 * particular top-level window. 27 */ 28 29typedef struct ProtocolHandler { 30 Atom protocol; /* Identifies the protocol. */ 31 struct ProtocolHandler *nextPtr; 32 /* Next in list of protocol handlers for 33 * the same top-level window, or NULL for 34 * end of list. */ 35 Tcl_Interp *interp; /* Interpreter in which to invoke command. */ 36 char command[4]; /* Tcl command to invoke when a client 37 * message for this protocol arrives. 38 * The actual size of the structure varies 39 * to accommodate the needs of the actual 40 * command. THIS MUST BE THE LAST FIELD OF 41 * THE STRUCTURE. */ 42} ProtocolHandler; 43 44#define HANDLER_SIZE(cmdLength) \ 45 ((unsigned) (sizeof(ProtocolHandler) - 3 + cmdLength)) 46 47/* 48 * A data structure of the following type holds window-manager-related 49 * information for each top-level window in an application. 50 */ 51 52typedef struct TkWmInfo { 53 TkWindow *winPtr; /* Pointer to main Tk information for 54 * this window. */ 55 Window reparent; /* If the window has been reparented, this 56 * gives the ID of the ancestor of the window 57 * that is a child of the root window (may 58 * not be window's immediate parent). If 59 * the window isn't reparented, this has the 60 * value None. */ 61 char *title; /* Title to display in window caption. If 62 * NULL, use name of widget. Malloced. */ 63 char *iconName; /* Name to display in icon. Malloced. */ 64 XWMHints hints; /* Various pieces of information for 65 * window manager. */ 66 char *leaderName; /* Path name of leader of window group 67 * (corresponds to hints.window_group). 68 * Malloc-ed. Note: this field doesn't 69 * get updated if leader is destroyed. */ 70 TkWindow *masterPtr; /* Master window for TRANSIENT_FOR property, 71 * or NULL. */ 72 Tk_Window icon; /* Window to use as icon for this window, 73 * or NULL. */ 74 Tk_Window iconFor; /* Window for which this window is icon, or 75 * NULL if this isn't an icon for anyone. */ 76 int withdrawn; /* Non-zero means window has been withdrawn. */ 77 78 /* 79 * In order to support menubars transparently under X, each toplevel 80 * window is encased in an additional window, called the wrapper, 81 * that holds the toplevel and the menubar, if any. The information 82 * below is used to keep track of the wrapper and the menubar. 83 */ 84 85 TkWindow *wrapperPtr; /* Pointer to information about the wrapper. 86 * This is the "real" toplevel window as 87 * seen by the window manager. Although 88 * this is an official Tk window, it 89 * doesn't appear in the application's 90 * window hierarchy. NULL means that 91 * the wrapper hasn't been created yet. */ 92 Tk_Window menubar; /* Pointer to information about the 93 * menubar, or NULL if there is no 94 * menubar for this toplevel. */ 95 int menuHeight; /* Amount of vertical space needed for 96 * menubar, measured in pixels. If 97 * menubar is non-NULL, this is >= 1 (X 98 * servers don't like dimensions of 0). */ 99 100 /* 101 * Information used to construct an XSizeHints structure for 102 * the window manager: 103 */ 104 105 int sizeHintsFlags; /* Flags word for XSizeHints structure. 106 * If the PBaseSize flag is set then the 107 * window is gridded; otherwise it isn't 108 * gridded. */ 109 int minWidth, minHeight; /* Minimum dimensions of window, in 110 * pixels or grid units. */ 111 int maxWidth, maxHeight; /* Maximum dimensions of window, in 112 * pixels or grid units. 0 to default.*/ 113 Tk_Window gridWin; /* Identifies the window that controls 114 * gridding for this top-level, or NULL if 115 * the top-level isn't currently gridded. */ 116 int widthInc, heightInc; /* Increments for size changes (# pixels 117 * per step). */ 118 struct { 119 int x; /* numerator */ 120 int y; /* denominator */ 121 } minAspect, maxAspect; /* Min/max aspect ratios for window. */ 122 int reqGridWidth, reqGridHeight; 123 /* The dimensions of the window (in 124 * grid units) requested through 125 * the geometry manager. */ 126 int gravity; /* Desired window gravity. */ 127 128 /* 129 * Information used to manage the size and location of a window. 130 */ 131 132 int width, height; /* Desired dimensions of window, specified 133 * in pixels or grid units. These values are 134 * set by the "wm geometry" command and by 135 * ConfigureNotify events (for when wm 136 * resizes window). -1 means user hasn't 137 * requested dimensions. */ 138 int x, y; /* Desired X and Y coordinates for window. 139 * These values are set by "wm geometry", 140 * plus by ConfigureNotify events (when wm 141 * moves window). These numbers are 142 * different than the numbers stored in 143 * winPtr->changes because (a) they could be 144 * measured from the right or bottom edge 145 * of the screen (see WM_NEGATIVE_X and 146 * WM_NEGATIVE_Y flags) and (b) if the window 147 * has been reparented then they refer to the 148 * parent rather than the window itself. */ 149 int parentWidth, parentHeight; 150 /* Width and height of reparent, in pixels 151 * *including border*. If window hasn't been 152 * reparented then these will be the outer 153 * dimensions of the window, including 154 * border. */ 155 int xInParent, yInParent; /* Offset of wrapperPtr within reparent, 156 * measured in pixels from upper-left outer 157 * corner of reparent's border to upper-left 158 * outer corner of wrapperPtr's border. If 159 * not reparented then these are zero. */ 160 int configWidth, configHeight; 161 /* Dimensions passed to last request that we 162 * issued to change geometry of the wrapper. 163 * Used to eliminate redundant resize 164 * operations. */ 165 166 /* 167 * Information about the virtual root window for this top-level, 168 * if there is one. 169 */ 170 171 Window vRoot; /* Virtual root window for this top-level, 172 * or None if there is no virtual root 173 * window (i.e. just use the screen's root). */ 174 int vRootX, vRootY; /* Position of the virtual root inside the 175 * root window. If the WM_VROOT_OFFSET_STALE 176 * flag is set then this information may be 177 * incorrect and needs to be refreshed from 178 * the X server. If vRoot is None then these 179 * values are both 0. */ 180 int vRootWidth, vRootHeight;/* Dimensions of the virtual root window. 181 * If vRoot is None, gives the dimensions 182 * of the containing screen. This information 183 * is never stale, even though vRootX and 184 * vRootY can be. */ 185 186 /* 187 * Miscellaneous information. 188 */ 189 190 ProtocolHandler *protPtr; /* First in list of protocol handlers for 191 * this window (NULL means none). */ 192 int cmdArgc; /* Number of elements in cmdArgv below. */ 193 CONST char **cmdArgv; /* Array of strings to store in the 194 * WM_COMMAND property. NULL means nothing 195 * available. */ 196 char *clientMachine; /* String to store in WM_CLIENT_MACHINE 197 * property, or NULL. */ 198 int flags; /* Miscellaneous flags, defined below. */ 199 int numTransients; /* number of transients on this window */ 200 int iconDataSize; /* size of iconphoto image data */ 201 unsigned char *iconDataPtr; /* iconphoto image data, if set */ 202 struct TkWmInfo *nextPtr; /* Next in list of all top-level windows. */ 203} WmInfo; 204 205/* 206 * Flag values for WmInfo structures: 207 * 208 * WM_NEVER_MAPPED - non-zero means window has never been 209 * mapped; need to update all info when 210 * window is first mapped. 211 * WM_UPDATE_PENDING - non-zero means a call to UpdateGeometryInfo 212 * has already been scheduled for this 213 * window; no need to schedule another one. 214 * WM_NEGATIVE_X - non-zero means x-coordinate is measured in 215 * pixels from right edge of screen, rather 216 * than from left edge. 217 * WM_NEGATIVE_Y - non-zero means y-coordinate is measured in 218 * pixels up from bottom of screen, rather than 219 * down from top. 220 * WM_UPDATE_SIZE_HINTS - non-zero means that new size hints need to be 221 * propagated to window manager. 222 * WM_SYNC_PENDING - set to non-zero while waiting for the window 223 * manager to respond to some state change. 224 * WM_VROOT_OFFSET_STALE - non-zero means that (x,y) offset information 225 * about the virtual root window is stale and 226 * needs to be fetched fresh from the X server. 227 * WM_ABOUT_TO_MAP - non-zero means that the window is about to 228 * be mapped by TkWmMapWindow. This is used 229 * by UpdateGeometryInfo to modify its behavior. 230 * WM_MOVE_PENDING - non-zero means the application has requested 231 * a new position for the window, but it hasn't 232 * been reflected through the window manager 233 * yet. 234 * WM_COLORMAPS_EXPLICIT - non-zero means the colormap windows were 235 * set explicitly via "wm colormapwindows". 236 * WM_ADDED_TOPLEVEL_COLORMAP - non-zero means that when "wm colormapwindows" 237 * was called the top-level itself wasn't 238 * specified, so we added it implicitly at 239 * the end of the list. 240 * WM_WIDTH_NOT_RESIZABLE - non-zero means that we're not supposed to 241 * allow the user to change the width of the 242 * window (controlled by "wm resizable" 243 * command). 244 * WM_HEIGHT_NOT_RESIZABLE - non-zero means that we're not supposed to 245 * allow the user to change the height of the 246 * window (controlled by "wm resizable" 247 * command). 248 * WM_WITHDRAWN - non-zero means that this window has explicitly 249 * been withdrawn. If it's a transient, it should 250 * not mirror state changes in the master. 251 */ 252 253#define WM_NEVER_MAPPED 1 254#define WM_UPDATE_PENDING 2 255#define WM_NEGATIVE_X 4 256#define WM_NEGATIVE_Y 8 257#define WM_UPDATE_SIZE_HINTS 0x10 258#define WM_SYNC_PENDING 0x20 259#define WM_VROOT_OFFSET_STALE 0x40 260#define WM_ABOUT_TO_MAP 0x100 261#define WM_MOVE_PENDING 0x200 262#define WM_COLORMAPS_EXPLICIT 0x400 263#define WM_ADDED_TOPLEVEL_COLORMAP 0x800 264#define WM_WIDTH_NOT_RESIZABLE 0x1000 265#define WM_HEIGHT_NOT_RESIZABLE 0x2000 266#define WM_WITHDRAWN 0x4000 267 268/* 269 * This module keeps a list of all top-level windows, primarily to 270 * simplify the job of Tk_CoordsToWindow. The list is called 271 * firstWmPtr and is stored in the TkDisplay structure. 272 */ 273 274/* 275 * The following structures are the official type records for geometry 276 * management of top-level and menubar windows. 277 */ 278 279static void TopLevelReqProc _ANSI_ARGS_((ClientData dummy, 280 Tk_Window tkwin)); 281 282static Tk_GeomMgr wmMgrType = { 283 "wm", /* name */ 284 TopLevelReqProc, /* requestProc */ 285 (Tk_GeomLostSlaveProc *) NULL, /* lostSlaveProc */ 286}; 287 288static void MenubarReqProc _ANSI_ARGS_((ClientData clientData, 289 Tk_Window tkwin)); 290 291static Tk_GeomMgr menubarMgrType = { 292 "menubar", /* name */ 293 MenubarReqProc, /* requestProc */ 294 (Tk_GeomLostSlaveProc *) NULL, /* lostSlaveProc */ 295}; 296 297/* 298 * Structures of the following type are used for communication between 299 * WaitForEvent, WaitRestrictProc, and WaitTimeoutProc. 300 */ 301 302typedef struct WaitRestrictInfo { 303 Display *display; /* Window belongs to this display. */ 304 WmInfo *wmInfoPtr; 305 int type; /* We only care about this type of event. */ 306 XEvent *eventPtr; /* Where to store the event when it's found. */ 307 int foundEvent; /* Non-zero means that an event of the 308 * desired type has been found. */ 309} WaitRestrictInfo; 310 311/* 312 * Forward declarations for procedures defined in this file: 313 */ 314 315static int ComputeReparentGeometry _ANSI_ARGS_((WmInfo *wmPtr)); 316static void ConfigureEvent _ANSI_ARGS_((WmInfo *wmPtr, 317 XConfigureEvent *eventPtr)); 318static void CreateWrapper _ANSI_ARGS_((WmInfo *wmPtr)); 319static void GetMaxSize _ANSI_ARGS_((WmInfo *wmPtr, 320 int *maxWidthPtr, int *maxHeightPtr)); 321static void MenubarDestroyProc _ANSI_ARGS_((ClientData clientData, 322 XEvent *eventPtr)); 323static int ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp, 324 char *string, TkWindow *winPtr)); 325static void ReparentEvent _ANSI_ARGS_((WmInfo *wmPtr, 326 XReparentEvent *eventPtr)); 327static int SetNetWmType _ANSI_ARGS_((TkWindow *winPtr, 328 Tcl_Obj *typePtr)); 329static Tcl_Obj * GetNetWmType _ANSI_ARGS_((TkWindow *winPtr)); 330static void TkSetTransientFor _ANSI_ARGS_((Tk_Window tkwin, 331 Tk_Window parent)); 332static void TkWmStackorderToplevelWrapperMap _ANSI_ARGS_(( 333 TkWindow *winPtr, 334 Display *display, 335 Tcl_HashTable *reparentTable)); 336static void TopLevelReqProc _ANSI_ARGS_((ClientData dummy, 337 Tk_Window tkwin)); 338static void UpdateCommand _ANSI_ARGS_((TkWindow *winPtr)); 339static void UpdateGeometryInfo _ANSI_ARGS_(( 340 ClientData clientData)); 341static void UpdateHints _ANSI_ARGS_((TkWindow *winPtr)); 342static void UpdateSizeHints _ANSI_ARGS_((TkWindow *winPtr, 343 int newWidth, int newHeight)); 344static void UpdateTitle _ANSI_ARGS_((TkWindow *winPtr)); 345static void UpdatePhotoIcon _ANSI_ARGS_((TkWindow *winPtr)); 346static void UpdateVRootGeometry _ANSI_ARGS_((WmInfo *wmPtr)); 347static void UpdateWmProtocols _ANSI_ARGS_((WmInfo *wmPtr)); 348static void WaitForConfigureNotify _ANSI_ARGS_((TkWindow *winPtr, 349 unsigned long serial)); 350static int WaitForEvent _ANSI_ARGS_((Display *display, 351 WmInfo *wmInfoPtr, int type, XEvent *eventPtr)); 352static void WaitForMapNotify _ANSI_ARGS_((TkWindow *winPtr, 353 int mapped)); 354static Tk_RestrictAction 355 WaitRestrictProc _ANSI_ARGS_((ClientData clientData, 356 XEvent *eventPtr)); 357static void WrapperEventProc _ANSI_ARGS_((ClientData clientData, 358 XEvent *eventPtr)); 359static void WmWaitMapProc _ANSI_ARGS_(( 360 ClientData clientData, XEvent *eventPtr)); 361 362static int WmAspectCmd _ANSI_ARGS_((Tk_Window tkwin, 363 TkWindow *winPtr, Tcl_Interp *interp, int objc, 364 Tcl_Obj *CONST objv[])); 365static int WmAttributesCmd _ANSI_ARGS_((Tk_Window tkwin, 366 TkWindow *winPtr, Tcl_Interp *interp, int objc, 367 Tcl_Obj *CONST objv[])); 368static int WmClientCmd _ANSI_ARGS_((Tk_Window tkwin, 369 TkWindow *winPtr, Tcl_Interp *interp, int objc, 370 Tcl_Obj *CONST objv[])); 371static int WmColormapwindowsCmd _ANSI_ARGS_((Tk_Window tkwin, 372 TkWindow *winPtr, Tcl_Interp *interp, int objc, 373 Tcl_Obj *CONST objv[])); 374static int WmCommandCmd _ANSI_ARGS_((Tk_Window tkwin, 375 TkWindow *winPtr, Tcl_Interp *interp, int objc, 376 Tcl_Obj *CONST objv[])); 377static int WmDeiconifyCmd _ANSI_ARGS_((Tk_Window tkwin, 378 TkWindow *winPtr, Tcl_Interp *interp, int objc, 379 Tcl_Obj *CONST objv[])); 380static int WmFocusmodelCmd _ANSI_ARGS_((Tk_Window tkwin, 381 TkWindow *winPtr, Tcl_Interp *interp, int objc, 382 Tcl_Obj *CONST objv[])); 383static int WmFrameCmd _ANSI_ARGS_((Tk_Window tkwin, 384 TkWindow *winPtr, Tcl_Interp *interp, int objc, 385 Tcl_Obj *CONST objv[])); 386static int WmGeometryCmd _ANSI_ARGS_((Tk_Window tkwin, 387 TkWindow *winPtr, Tcl_Interp *interp, int objc, 388 Tcl_Obj *CONST objv[])); 389static int WmGridCmd _ANSI_ARGS_((Tk_Window tkwin, 390 TkWindow *winPtr, Tcl_Interp *interp, int objc, 391 Tcl_Obj *CONST objv[])); 392static int WmGroupCmd _ANSI_ARGS_((Tk_Window tkwin, 393 TkWindow *winPtr, Tcl_Interp *interp, int objc, 394 Tcl_Obj *CONST objv[])); 395static int WmIconbitmapCmd _ANSI_ARGS_((Tk_Window tkwin, 396 TkWindow *winPtr, Tcl_Interp *interp, int objc, 397 Tcl_Obj *CONST objv[])); 398static int WmIconifyCmd _ANSI_ARGS_((Tk_Window tkwin, 399 TkWindow *winPtr, Tcl_Interp *interp, int objc, 400 Tcl_Obj *CONST objv[])); 401static int WmIconmaskCmd _ANSI_ARGS_((Tk_Window tkwin, 402 TkWindow *winPtr, Tcl_Interp *interp, int objc, 403 Tcl_Obj *CONST objv[])); 404static int WmIconnameCmd _ANSI_ARGS_((Tk_Window tkwin, 405 TkWindow *winPtr, Tcl_Interp *interp, int objc, 406 Tcl_Obj *CONST objv[])); 407static int WmIconphotoCmd _ANSI_ARGS_((Tk_Window tkwin, 408 TkWindow *winPtr, Tcl_Interp *interp, int objc, 409 Tcl_Obj *CONST objv[])); 410static int WmIconpositionCmd _ANSI_ARGS_((Tk_Window tkwin, 411 TkWindow *winPtr, Tcl_Interp *interp, int objc, 412 Tcl_Obj *CONST objv[])); 413static int WmIconwindowCmd _ANSI_ARGS_((Tk_Window tkwin, 414 TkWindow *winPtr, Tcl_Interp *interp, int objc, 415 Tcl_Obj *CONST objv[])); 416static int WmMaxsizeCmd _ANSI_ARGS_((Tk_Window tkwin, 417 TkWindow *winPtr, Tcl_Interp *interp, int objc, 418 Tcl_Obj *CONST objv[])); 419static int WmMinsizeCmd _ANSI_ARGS_((Tk_Window tkwin, 420 TkWindow *winPtr, Tcl_Interp *interp, int objc, 421 Tcl_Obj *CONST objv[])); 422static int WmOverrideredirectCmd _ANSI_ARGS_((Tk_Window tkwin, 423 TkWindow *winPtr, Tcl_Interp *interp, int objc, 424 Tcl_Obj *CONST objv[])); 425static int WmPositionfromCmd _ANSI_ARGS_((Tk_Window tkwin, 426 TkWindow *winPtr, Tcl_Interp *interp, int objc, 427 Tcl_Obj *CONST objv[])); 428static int WmProtocolCmd _ANSI_ARGS_((Tk_Window tkwin, 429 TkWindow *winPtr, Tcl_Interp *interp, int objc, 430 Tcl_Obj *CONST objv[])); 431static int WmResizableCmd _ANSI_ARGS_((Tk_Window tkwin, 432 TkWindow *winPtr, Tcl_Interp *interp, int objc, 433 Tcl_Obj *CONST objv[])); 434static int WmSizefromCmd _ANSI_ARGS_((Tk_Window tkwin, 435 TkWindow *winPtr, Tcl_Interp *interp, int objc, 436 Tcl_Obj *CONST objv[])); 437static int WmStackorderCmd _ANSI_ARGS_((Tk_Window tkwin, 438 TkWindow *winPtr, Tcl_Interp *interp, int objc, 439 Tcl_Obj *CONST objv[])); 440static int WmStateCmd _ANSI_ARGS_((Tk_Window tkwin, 441 TkWindow *winPtr, Tcl_Interp *interp, int objc, 442 Tcl_Obj *CONST objv[])); 443static int WmTitleCmd _ANSI_ARGS_((Tk_Window tkwin, 444 TkWindow *winPtr, Tcl_Interp *interp, int objc, 445 Tcl_Obj *CONST objv[])); 446static int WmTransientCmd _ANSI_ARGS_((Tk_Window tkwin, 447 TkWindow *winPtr, Tcl_Interp *interp, int objc, 448 Tcl_Obj *CONST objv[])); 449static int WmWithdrawCmd _ANSI_ARGS_((Tk_Window tkwin, 450 TkWindow *winPtr, Tcl_Interp *interp, int objc, 451 Tcl_Obj *CONST objv[])); 452static void WmUpdateGeom _ANSI_ARGS_((WmInfo *wmPtr, 453 TkWindow *winPtr)); 454 455/* 456 *-------------------------------------------------------------- 457 * 458 * TkWmCleanup -- 459 * 460 * This procedure is invoked to cleanup remaining wm resources 461 * associated with a display. 462 * 463 * Results: 464 * None. 465 * 466 * Side effects: 467 * All WmInfo structure resources are freed and invalidated. 468 * 469 *-------------------------------------------------------------- 470 */ 471 472void TkWmCleanup(dispPtr) 473 TkDisplay *dispPtr; 474{ 475 WmInfo *wmPtr, *nextPtr; 476 for (wmPtr = dispPtr->firstWmPtr; wmPtr != NULL; wmPtr = nextPtr) { 477 /* 478 * We can't assume we have access to winPtr's anymore, so some 479 * cleanup requiring winPtr data is avoided. 480 */ 481 nextPtr = wmPtr->nextPtr; 482 if (wmPtr->title != NULL) { 483 ckfree(wmPtr->title); 484 } 485 if (wmPtr->iconName != NULL) { 486 ckfree(wmPtr->iconName); 487 } 488 if (wmPtr->iconDataPtr != NULL) { 489 ckfree((char *)wmPtr->iconDataPtr); 490 } 491 if (wmPtr->leaderName != NULL) { 492 ckfree(wmPtr->leaderName); 493 } 494 if (wmPtr->menubar != NULL) { 495 Tk_DestroyWindow(wmPtr->menubar); 496 } 497 if (wmPtr->wrapperPtr != NULL) { 498 Tk_DestroyWindow((Tk_Window) wmPtr->wrapperPtr); 499 } 500 while (wmPtr->protPtr != NULL) { 501 ProtocolHandler *protPtr; 502 503 protPtr = wmPtr->protPtr; 504 wmPtr->protPtr = protPtr->nextPtr; 505 Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC); 506 } 507 if (wmPtr->cmdArgv != NULL) { 508 ckfree((char *) wmPtr->cmdArgv); 509 } 510 if (wmPtr->clientMachine != NULL) { 511 ckfree((char *) wmPtr->clientMachine); 512 } 513 ckfree((char *) wmPtr); 514 } 515 if (dispPtr->iconDataPtr != NULL) { 516 ckfree((char *)dispPtr->iconDataPtr); 517 dispPtr->iconDataPtr = NULL; 518 } 519} 520 521/* 522 *-------------------------------------------------------------- 523 * 524 * TkWmNewWindow -- 525 * 526 * This procedure is invoked whenever a new top-level 527 * window is created. Its job is to initialize the WmInfo 528 * structure for the window. 529 * 530 * Results: 531 * None. 532 * 533 * Side effects: 534 * A WmInfo structure gets allocated and initialized. 535 * 536 *-------------------------------------------------------------- 537 */ 538 539void 540TkWmNewWindow(winPtr) 541 TkWindow *winPtr; /* Newly-created top-level window. */ 542{ 543 register WmInfo *wmPtr; 544 TkDisplay *dispPtr = winPtr->dispPtr; 545 546 wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo)); 547 memset(wmPtr, 0, sizeof(WmInfo)); 548 wmPtr->winPtr = winPtr; 549 wmPtr->reparent = None; 550 wmPtr->masterPtr = NULL; 551 wmPtr->numTransients = 0; 552 wmPtr->hints.flags = InputHint | StateHint; 553 wmPtr->hints.input = True; 554 wmPtr->hints.initial_state = NormalState; 555 wmPtr->hints.icon_pixmap = None; 556 wmPtr->hints.icon_window = None; 557 wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0; 558 wmPtr->hints.icon_mask = None; 559 wmPtr->hints.window_group = None; 560 561 /* 562 * Default the maximum dimensions to the size of the display, minus 563 * a guess about how space is needed for window manager decorations. 564 */ 565 566 wmPtr->gridWin = NULL; 567 wmPtr->minWidth = wmPtr->minHeight = 1; 568 wmPtr->maxWidth = wmPtr->maxHeight = 0; 569 wmPtr->widthInc = wmPtr->heightInc = 1; 570 wmPtr->minAspect.x = wmPtr->minAspect.y = 1; 571 wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1; 572 wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1; 573 wmPtr->gravity = NorthWestGravity; 574 wmPtr->width = -1; 575 wmPtr->height = -1; 576 wmPtr->x = winPtr->changes.x; 577 wmPtr->y = winPtr->changes.y; 578 wmPtr->parentWidth = winPtr->changes.width 579 + 2*winPtr->changes.border_width; 580 wmPtr->parentHeight = winPtr->changes.height 581 + 2*winPtr->changes.border_width; 582 wmPtr->configWidth = -1; 583 wmPtr->configHeight = -1; 584 wmPtr->vRoot = None; 585 wmPtr->flags = WM_NEVER_MAPPED; 586 wmPtr->nextPtr = (WmInfo *) dispPtr->firstWmPtr; 587 dispPtr->firstWmPtr = wmPtr; 588 winPtr->wmInfoPtr = wmPtr; 589 590 UpdateVRootGeometry(wmPtr); 591 592 /* 593 * Arrange for geometry requests to be reflected from the window 594 * to the window manager. 595 */ 596 597 Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0); 598} 599 600/* 601 *-------------------------------------------------------------- 602 * 603 * TkWmMapWindow -- 604 * 605 * This procedure is invoked to map a top-level window. This 606 * module gets a chance to update all window-manager-related 607 * information in properties before the window manager sees 608 * the map event and checks the properties. It also gets to 609 * decide whether or not to even map the window after all. 610 * 611 * Results: 612 * None. 613 * 614 * Side effects: 615 * Properties of winPtr may get updated to provide up-to-date 616 * information to the window manager. The window may also get 617 * mapped, but it may not be if this procedure decides that 618 * isn't appropriate (e.g. because the window is withdrawn). 619 * 620 *-------------------------------------------------------------- 621 */ 622 623void 624TkWmMapWindow(winPtr) 625 TkWindow *winPtr; /* Top-level window that's about to 626 * be mapped. */ 627{ 628 register WmInfo *wmPtr = winPtr->wmInfoPtr; 629 XTextProperty textProp; 630 631 if (wmPtr->flags & WM_NEVER_MAPPED) { 632 Tcl_DString ds; 633 634 wmPtr->flags &= ~WM_NEVER_MAPPED; 635 636 /* 637 * This is the first time this window has ever been mapped. 638 * First create the wrapper window that provides space for a 639 * menubar. 640 */ 641 642 if (wmPtr->wrapperPtr == NULL) { 643 CreateWrapper(wmPtr); 644 } 645 646 /* 647 * Store all the window-manager-related information for the 648 * window. 649 */ 650 651 TkWmSetClass(winPtr); 652 UpdateTitle(winPtr); 653 UpdatePhotoIcon(winPtr); 654 655 if (wmPtr->masterPtr != NULL) { 656 /* 657 * Don't map a transient if the master is not mapped. 658 */ 659 660 if (!Tk_IsMapped(wmPtr->masterPtr)) { 661 wmPtr->withdrawn = 1; 662 wmPtr->hints.initial_state = WithdrawnState; 663 } else { 664 XSetTransientForHint(winPtr->display, wmPtr->wrapperPtr->window, 665 wmPtr->masterPtr->wmInfoPtr->wrapperPtr->window); 666 } 667 } 668 669 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 670 UpdateHints(winPtr); 671 UpdateWmProtocols(wmPtr); 672 if (wmPtr->cmdArgv != NULL) { 673 UpdateCommand(winPtr); 674 } 675 if (wmPtr->clientMachine != NULL) { 676 Tcl_UtfToExternalDString(NULL, wmPtr->clientMachine, -1, &ds); 677 if (XStringListToTextProperty(&(Tcl_DStringValue(&ds)), 1, 678 &textProp) != 0) { 679 XSetWMClientMachine(winPtr->display, wmPtr->wrapperPtr->window, 680 &textProp); 681 XFree((char *) textProp.value); 682 } 683 Tcl_DStringFree(&ds); 684 } 685 } 686 if (wmPtr->hints.initial_state == WithdrawnState) { 687 return; 688 } 689 if (wmPtr->iconFor != NULL) { 690 /* 691 * This window is an icon for somebody else. Make sure that 692 * the geometry is up-to-date, then return without mapping 693 * the window. 694 */ 695 696 if (wmPtr->flags & WM_UPDATE_PENDING) { 697 Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr); 698 } 699 UpdateGeometryInfo((ClientData) winPtr); 700 return; 701 } 702 wmPtr->flags |= WM_ABOUT_TO_MAP; 703 if (wmPtr->flags & WM_UPDATE_PENDING) { 704 Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr); 705 } 706 UpdateGeometryInfo((ClientData) winPtr); 707 wmPtr->flags &= ~WM_ABOUT_TO_MAP; 708 709 /* 710 * Map the window, then wait to be sure that the window manager has 711 * processed the map operation. 712 */ 713 714 XMapWindow(winPtr->display, wmPtr->wrapperPtr->window); 715 if (wmPtr->hints.initial_state == NormalState) { 716 WaitForMapNotify(winPtr, 1); 717 } 718} 719 720/* 721 *-------------------------------------------------------------- 722 * 723 * TkWmUnmapWindow -- 724 * 725 * This procedure is invoked to unmap a top-level window. The 726 * only thing it does special is to wait for the window actually 727 * to be unmapped. 728 * 729 * Results: 730 * None. 731 * 732 * Side effects: 733 * Unmaps the window. 734 * 735 *-------------------------------------------------------------- 736 */ 737 738void 739TkWmUnmapWindow(winPtr) 740 TkWindow *winPtr; /* Top-level window that's about to 741 * be mapped. */ 742{ 743 /* 744 * It seems to be important to wait after unmapping a top-level 745 * window until the window really gets unmapped. I don't completely 746 * understand all the interactions with the window manager, but if 747 * we go on without waiting, and if the window is then mapped again 748 * quickly, events seem to get lost so that we think the window isn't 749 * mapped when in fact it is mapped. I suspect that this has something 750 * to do with the window manager filtering Map events (and possily not 751 * filtering Unmap events?). 752 */ 753 XUnmapWindow(winPtr->display, winPtr->wmInfoPtr->wrapperPtr->window); 754 WaitForMapNotify(winPtr, 0); 755} 756 757/* 758 *-------------------------------------------------------------- 759 * 760 * TkWmDeadWindow -- 761 * 762 * This procedure is invoked when a top-level window is 763 * about to be deleted. It cleans up the wm-related data 764 * structures for the window. 765 * 766 * Results: 767 * None. 768 * 769 * Side effects: 770 * The WmInfo structure for winPtr gets freed up. 771 * 772 *-------------------------------------------------------------- 773 */ 774 775void 776TkWmDeadWindow(winPtr) 777 TkWindow *winPtr; /* Top-level window that's being deleted. */ 778{ 779 register WmInfo *wmPtr = winPtr->wmInfoPtr; 780 WmInfo *wmPtr2; 781 782 if (wmPtr == NULL) { 783 return; 784 } 785 if ((WmInfo *) winPtr->dispPtr->firstWmPtr == wmPtr) { 786 winPtr->dispPtr->firstWmPtr = wmPtr->nextPtr; 787 } else { 788 register WmInfo *prevPtr; 789 790 for (prevPtr = (WmInfo *) winPtr->dispPtr->firstWmPtr; ; 791 prevPtr = prevPtr->nextPtr) { 792 if (prevPtr == NULL) { 793 Tcl_Panic("couldn't unlink window in TkWmDeadWindow"); 794 } 795 if (prevPtr->nextPtr == wmPtr) { 796 prevPtr->nextPtr = wmPtr->nextPtr; 797 break; 798 } 799 } 800 } 801 if (wmPtr->title != NULL) { 802 ckfree(wmPtr->title); 803 } 804 if (wmPtr->iconName != NULL) { 805 ckfree(wmPtr->iconName); 806 } 807 if (wmPtr->iconDataPtr != NULL) { 808 ckfree((char *)wmPtr->iconDataPtr); 809 } 810 if (wmPtr->hints.flags & IconPixmapHint) { 811 Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap); 812 } 813 if (wmPtr->hints.flags & IconMaskHint) { 814 Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask); 815 } 816 if (wmPtr->leaderName != NULL) { 817 ckfree(wmPtr->leaderName); 818 } 819 if (wmPtr->icon != NULL) { 820 wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr; 821 wmPtr2->iconFor = NULL; 822 wmPtr2->withdrawn = 1; 823 } 824 if (wmPtr->iconFor != NULL) { 825 wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr; 826 wmPtr2->icon = NULL; 827 wmPtr2->hints.flags &= ~IconWindowHint; 828 UpdateHints((TkWindow *) wmPtr->iconFor); 829 } 830 if (wmPtr->menubar != NULL) { 831 Tk_DestroyWindow(wmPtr->menubar); 832 } 833 if (wmPtr->wrapperPtr != NULL) { 834 /* 835 * The rest of Tk doesn't know that we reparent the toplevel 836 * inside the wrapper, so reparent it back out again before 837 * deleting the wrapper; otherwise the toplevel will get deleted 838 * twice (once implicitly by the deletion of the wrapper). 839 */ 840 841 XUnmapWindow(winPtr->display, winPtr->window); 842 XReparentWindow(winPtr->display, winPtr->window, 843 XRootWindow(winPtr->display, winPtr->screenNum), 0, 0); 844 Tk_DestroyWindow((Tk_Window) wmPtr->wrapperPtr); 845 } 846 while (wmPtr->protPtr != NULL) { 847 ProtocolHandler *protPtr; 848 849 protPtr = wmPtr->protPtr; 850 wmPtr->protPtr = protPtr->nextPtr; 851 Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC); 852 } 853 if (wmPtr->cmdArgv != NULL) { 854 ckfree((char *) wmPtr->cmdArgv); 855 } 856 if (wmPtr->clientMachine != NULL) { 857 ckfree((char *) wmPtr->clientMachine); 858 } 859 if (wmPtr->flags & WM_UPDATE_PENDING) { 860 Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr); 861 } 862 /* 863 * Reset all transient windows whose master is the dead window. 864 */ 865 866 for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL; 867 wmPtr2 = wmPtr2->nextPtr) { 868 if (wmPtr2->masterPtr == winPtr) { 869 wmPtr->numTransients--; 870 Tk_DeleteEventHandler((Tk_Window) wmPtr2->masterPtr, 871 StructureNotifyMask, 872 WmWaitMapProc, (ClientData) wmPtr2->winPtr); 873 wmPtr2->masterPtr = NULL; 874 if (!(wmPtr2->flags & WM_NEVER_MAPPED)) { 875 XDeleteProperty(winPtr->display, wmPtr2->wrapperPtr->window, 876 Tk_InternAtom((Tk_Window) winPtr, "WM_TRANSIENT_FOR")); 877 /* FIXME: Need a call like Win32's UpdateWrapper() so 878 we can recreate the wrapper and get rid of the 879 transient window decorations. */ 880 } 881 } 882 } 883 if (wmPtr->numTransients != 0) 884 Tcl_Panic("numTransients should be 0"); 885 886 if (wmPtr->masterPtr != NULL) { 887 wmPtr2 = wmPtr->masterPtr->wmInfoPtr; 888 /* 889 * If we had a master, tell them that we aren't tied 890 * to them anymore 891 */ 892 if (wmPtr2 != NULL) { 893 wmPtr2->numTransients--; 894 } 895 Tk_DeleteEventHandler((Tk_Window) wmPtr->masterPtr, 896 StructureNotifyMask, 897 WmWaitMapProc, (ClientData) winPtr); 898 wmPtr->masterPtr = NULL; 899 } 900 ckfree((char *) wmPtr); 901 winPtr->wmInfoPtr = NULL; 902} 903 904/* 905 *-------------------------------------------------------------- 906 * 907 * TkWmSetClass -- 908 * 909 * This procedure is invoked whenever a top-level window's 910 * class is changed. If the window has been mapped then this 911 * procedure updates the window manager property for the 912 * class. If the window hasn't been mapped, the update is 913 * deferred until just before the first mapping. 914 * 915 * Results: 916 * None. 917 * 918 * Side effects: 919 * A window property may get updated. 920 * 921 *-------------------------------------------------------------- 922 */ 923 924void 925TkWmSetClass(winPtr) 926 TkWindow *winPtr; /* Newly-created top-level window. */ 927{ 928 if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) { 929 return; 930 } 931 932 if (winPtr->classUid != NULL) { 933 XClassHint *classPtr; 934 Tcl_DString name, class; 935 936 Tcl_UtfToExternalDString(NULL, winPtr->nameUid, -1, &name); 937 Tcl_UtfToExternalDString(NULL, winPtr->classUid, -1, &class); 938 classPtr = XAllocClassHint(); 939 classPtr->res_name = Tcl_DStringValue(&name); 940 classPtr->res_class = Tcl_DStringValue(&class); 941 XSetClassHint(winPtr->display, winPtr->wmInfoPtr->wrapperPtr->window, 942 classPtr); 943 XFree((char *) classPtr); 944 Tcl_DStringFree(&name); 945 Tcl_DStringFree(&class); 946 } 947} 948 949/* 950 *---------------------------------------------------------------------- 951 * 952 * Tk_WmObjCmd -- 953 * 954 * This procedure is invoked to process the "wm" Tcl command. 955 * See the user documentation for details on what it does. 956 * 957 * Results: 958 * A standard Tcl result. 959 * 960 * Side effects: 961 * See the user documentation. 962 * 963 *---------------------------------------------------------------------- 964 */ 965 966 /* ARGSUSED */ 967int 968Tk_WmObjCmd(clientData, interp, objc, objv) 969 ClientData clientData; /* Main window associated with 970 * interpreter. */ 971 Tcl_Interp *interp; /* Current interpreter. */ 972 int objc; /* Number of arguments. */ 973 Tcl_Obj *CONST objv[]; /* Argument objects. */ 974{ 975 Tk_Window tkwin = (Tk_Window) clientData; 976 static CONST char *optionStrings[] = { 977 "aspect", "attributes", "client", "colormapwindows", 978 "command", "deiconify", "focusmodel", "frame", 979 "geometry", "grid", "group", "iconbitmap", 980 "iconify", "iconmask", "iconname", 981 "iconphoto", "iconposition", 982 "iconwindow", "maxsize", "minsize", "overrideredirect", 983 "positionfrom", "protocol", "resizable", "sizefrom", 984 "stackorder", "state", "title", "transient", 985 "withdraw", (char *) NULL }; 986 enum options { 987 WMOPT_ASPECT, WMOPT_ATTRIBUTES, WMOPT_CLIENT, WMOPT_COLORMAPWINDOWS, 988 WMOPT_COMMAND, WMOPT_DEICONIFY, WMOPT_FOCUSMODEL, WMOPT_FRAME, 989 WMOPT_GEOMETRY, WMOPT_GRID, WMOPT_GROUP, WMOPT_ICONBITMAP, 990 WMOPT_ICONIFY, WMOPT_ICONMASK, WMOPT_ICONNAME, 991 WMOPT_ICONPHOTO, WMOPT_ICONPOSITION, 992 WMOPT_ICONWINDOW, WMOPT_MAXSIZE, WMOPT_MINSIZE, WMOPT_OVERRIDEREDIRECT, 993 WMOPT_POSITIONFROM, WMOPT_PROTOCOL, WMOPT_RESIZABLE, WMOPT_SIZEFROM, 994 WMOPT_STACKORDER, WMOPT_STATE, WMOPT_TITLE, WMOPT_TRANSIENT, 995 WMOPT_WITHDRAW }; 996 int index; 997 int length; 998 char *argv1; 999 TkWindow *winPtr; 1000 TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; 1001 1002 if (objc < 2) { 1003 wrongNumArgs: 1004 Tcl_WrongNumArgs(interp, 1, objv, "option window ?arg ...?"); 1005 return TCL_ERROR; 1006 } 1007 1008 argv1 = Tcl_GetStringFromObj(objv[1], &length); 1009 if ((argv1[0] == 't') && (strncmp(argv1, "tracing", (size_t) length) == 0) 1010 && (length >= 3)) { 1011 int wmTracing; 1012 if ((objc != 2) && (objc != 3)) { 1013 Tcl_WrongNumArgs(interp, 2, objv, "?boolean?"); 1014 return TCL_ERROR; 1015 } 1016 if (objc == 2) { 1017 Tcl_SetResult(interp, 1018 ((dispPtr->flags & TK_DISPLAY_WM_TRACING) ? "on" : "off"), 1019 TCL_STATIC); 1020 return TCL_OK; 1021 } 1022 if (Tcl_GetBooleanFromObj(interp, objv[2], &wmTracing) != TCL_OK) { 1023 return TCL_ERROR; 1024 } 1025 if (wmTracing) { 1026 dispPtr->flags |= TK_DISPLAY_WM_TRACING; 1027 } else { 1028 dispPtr->flags &= ~TK_DISPLAY_WM_TRACING; 1029 } 1030 return TCL_OK; 1031 } 1032 1033 if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, 1034 &index) != TCL_OK) { 1035 return TCL_ERROR; 1036 } 1037 1038 if (objc < 3) { 1039 goto wrongNumArgs; 1040 } 1041 1042 if (TkGetWindowFromObj(interp, tkwin, objv[2], (Tk_Window *) &winPtr) 1043 != TCL_OK) { 1044 return TCL_ERROR; 1045 } 1046 if (!Tk_IsTopLevel(winPtr)) { 1047 Tcl_AppendResult(interp, "window \"", winPtr->pathName, 1048 "\" isn't a top-level window", (char *) NULL); 1049 return TCL_ERROR; 1050 } 1051 1052 switch ((enum options) index) { 1053 case WMOPT_ASPECT: 1054 return WmAspectCmd(tkwin, winPtr, interp, objc, objv); 1055 case WMOPT_ATTRIBUTES: 1056 return WmAttributesCmd(tkwin, winPtr, interp, objc, objv); 1057 case WMOPT_CLIENT: 1058 return WmClientCmd(tkwin, winPtr, interp, objc, objv); 1059 case WMOPT_COLORMAPWINDOWS: 1060 return WmColormapwindowsCmd(tkwin, winPtr, interp, objc, objv); 1061 case WMOPT_COMMAND: 1062 return WmCommandCmd(tkwin, winPtr, interp, objc, objv); 1063 case WMOPT_DEICONIFY: 1064 return WmDeiconifyCmd(tkwin, winPtr, interp, objc, objv); 1065 case WMOPT_FOCUSMODEL: 1066 return WmFocusmodelCmd(tkwin, winPtr, interp, objc, objv); 1067 case WMOPT_FRAME: 1068 return WmFrameCmd(tkwin, winPtr, interp, objc, objv); 1069 case WMOPT_GEOMETRY: 1070 return WmGeometryCmd(tkwin, winPtr, interp, objc, objv); 1071 case WMOPT_GRID: 1072 return WmGridCmd(tkwin, winPtr, interp, objc, objv); 1073 case WMOPT_GROUP: 1074 return WmGroupCmd(tkwin, winPtr, interp, objc, objv); 1075 case WMOPT_ICONBITMAP: 1076 return WmIconbitmapCmd(tkwin, winPtr, interp, objc, objv); 1077 case WMOPT_ICONIFY: 1078 return WmIconifyCmd(tkwin, winPtr, interp, objc, objv); 1079 case WMOPT_ICONMASK: 1080 return WmIconmaskCmd(tkwin, winPtr, interp, objc, objv); 1081 case WMOPT_ICONNAME: 1082 return WmIconnameCmd(tkwin, winPtr, interp, objc, objv); 1083 case WMOPT_ICONPHOTO: 1084 return WmIconphotoCmd(tkwin, winPtr, interp, objc, objv); 1085 case WMOPT_ICONPOSITION: 1086 return WmIconpositionCmd(tkwin, winPtr, interp, objc, objv); 1087 case WMOPT_ICONWINDOW: 1088 return WmIconwindowCmd(tkwin, winPtr, interp, objc, objv); 1089 case WMOPT_MAXSIZE: 1090 return WmMaxsizeCmd(tkwin, winPtr, interp, objc, objv); 1091 case WMOPT_MINSIZE: 1092 return WmMinsizeCmd(tkwin, winPtr, interp, objc, objv); 1093 case WMOPT_OVERRIDEREDIRECT: 1094 return WmOverrideredirectCmd(tkwin, winPtr, interp, objc, objv); 1095 case WMOPT_POSITIONFROM: 1096 return WmPositionfromCmd(tkwin, winPtr, interp, objc, objv); 1097 case WMOPT_PROTOCOL: 1098 return WmProtocolCmd(tkwin, winPtr, interp, objc, objv); 1099 case WMOPT_RESIZABLE: 1100 return WmResizableCmd(tkwin, winPtr, interp, objc, objv); 1101 case WMOPT_SIZEFROM: 1102 return WmSizefromCmd(tkwin, winPtr, interp, objc, objv); 1103 case WMOPT_STACKORDER: 1104 return WmStackorderCmd(tkwin, winPtr, interp, objc, objv); 1105 case WMOPT_STATE: 1106 return WmStateCmd(tkwin, winPtr, interp, objc, objv); 1107 case WMOPT_TITLE: 1108 return WmTitleCmd(tkwin, winPtr, interp, objc, objv); 1109 case WMOPT_TRANSIENT: 1110 return WmTransientCmd(tkwin, winPtr, interp, objc, objv); 1111 case WMOPT_WITHDRAW: 1112 return WmWithdrawCmd(tkwin, winPtr, interp, objc, objv); 1113 } 1114 1115 /* This should not happen */ 1116 return TCL_ERROR; 1117} 1118 1119/* 1120 *---------------------------------------------------------------------- 1121 * 1122 * WmAspectCmd -- 1123 * 1124 * This procedure is invoked to process the "wm aspect" Tcl command. 1125 * See the user documentation for details on what it does. 1126 * 1127 * Results: 1128 * A standard Tcl result. 1129 * 1130 * Side effects: 1131 * See the user documentation. 1132 * 1133 *---------------------------------------------------------------------- 1134 */ 1135 1136static int 1137WmAspectCmd(tkwin, winPtr, interp, objc, objv) 1138 Tk_Window tkwin; /* Main window of the application. */ 1139 TkWindow *winPtr; /* Toplevel to work with */ 1140 Tcl_Interp *interp; /* Current interpreter. */ 1141 int objc; /* Number of arguments. */ 1142 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1143{ 1144 register WmInfo *wmPtr = winPtr->wmInfoPtr; 1145 int numer1, denom1, numer2, denom2; 1146 1147 if ((objc != 3) && (objc != 7)) { 1148 Tcl_WrongNumArgs(interp, 2, objv, 1149 "window ?minNumer minDenom maxNumer maxDenom?"); 1150 return TCL_ERROR; 1151 } 1152 if (objc == 3) { 1153 if (wmPtr->sizeHintsFlags & PAspect) { 1154 char buf[TCL_INTEGER_SPACE * 4]; 1155 1156 sprintf(buf, "%d %d %d %d", wmPtr->minAspect.x, 1157 wmPtr->minAspect.y, wmPtr->maxAspect.x, 1158 wmPtr->maxAspect.y); 1159 Tcl_SetResult(interp, buf, TCL_VOLATILE); 1160 } 1161 return TCL_OK; 1162 } 1163 if (*Tcl_GetString(objv[3]) == '\0') { 1164 wmPtr->sizeHintsFlags &= ~PAspect; 1165 } else { 1166 if ((Tcl_GetIntFromObj(interp, objv[3], &numer1) != TCL_OK) 1167 || (Tcl_GetIntFromObj(interp, objv[4], &denom1) != TCL_OK) 1168 || (Tcl_GetIntFromObj(interp, objv[5], &numer2) != TCL_OK) 1169 || (Tcl_GetIntFromObj(interp, objv[6], &denom2) != TCL_OK)) { 1170 return TCL_ERROR; 1171 } 1172 if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) || 1173 (denom2 <= 0)) { 1174 Tcl_SetResult(interp, "aspect number can't be <= 0", 1175 TCL_STATIC); 1176 return TCL_ERROR; 1177 } 1178 wmPtr->minAspect.x = numer1; 1179 wmPtr->minAspect.y = denom1; 1180 wmPtr->maxAspect.x = numer2; 1181 wmPtr->maxAspect.y = denom2; 1182 wmPtr->sizeHintsFlags |= PAspect; 1183 } 1184 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 1185 WmUpdateGeom(wmPtr, winPtr); 1186 return TCL_OK; 1187} 1188 1189/* 1190 *---------------------------------------------------------------------- 1191 * 1192 * WmAttributesCmd -- 1193 * 1194 * This procedure is invoked to process the "wm attributes" Tcl command. 1195 * See the user documentation for details on what it does. 1196 * 1197 * Results: 1198 * A standard Tcl result. 1199 * 1200 * Side effects: 1201 * See the user documentation. 1202 * 1203 *---------------------------------------------------------------------- 1204 */ 1205 1206static int 1207WmAttributesCmd(tkwin, winPtr, interp, objc, objv) 1208 Tk_Window tkwin; /* Main window of the application. */ 1209 TkWindow *winPtr; /* Toplevel to work with */ 1210 Tcl_Interp *interp; /* Current interpreter. */ 1211 int objc; /* Number of arguments. */ 1212 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1213{ 1214 if (objc < 4) { 1215 Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); 1216 Tcl_ListObjAppendElement(interp, listObj, 1217 Tcl_NewStringObj("-type", -1)); 1218 Tcl_ListObjAppendElement(interp, listObj, GetNetWmType(winPtr)); 1219 Tcl_SetObjResult(interp, listObj); 1220 return TCL_OK; 1221 } 1222 if (objc > 5 || strcmp("-type", Tcl_GetString(objv[3]))) { 1223 Tcl_WrongNumArgs(interp, 2, objv, "window ?-type list?"); 1224 return TCL_ERROR; 1225 } 1226 if (objc == 4) { 1227 Tcl_SetObjResult(interp, GetNetWmType(winPtr)); 1228 return TCL_OK; 1229 } 1230 return SetNetWmType(winPtr, objv[4]); 1231} 1232 1233/* 1234 *---------------------------------------------------------------------- 1235 * 1236 * WmClientCmd -- 1237 * 1238 * This procedure is invoked to process the "wm client" Tcl command. 1239 * See the user documentation for details on what it does. 1240 * 1241 * Results: 1242 * A standard Tcl result. 1243 * 1244 * Side effects: 1245 * See the user documentation. 1246 * 1247 *---------------------------------------------------------------------- 1248 */ 1249 1250static int 1251WmClientCmd(tkwin, winPtr, interp, objc, objv) 1252 Tk_Window tkwin; /* Main window of the application. */ 1253 TkWindow *winPtr; /* Toplevel to work with */ 1254 Tcl_Interp *interp; /* Current interpreter. */ 1255 int objc; /* Number of arguments. */ 1256 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1257{ 1258 register WmInfo *wmPtr = winPtr->wmInfoPtr; 1259 char *argv3; 1260 int length; 1261 1262 if ((objc != 3) && (objc != 4)) { 1263 Tcl_WrongNumArgs(interp, 2, objv, "window ?name?"); 1264 return TCL_ERROR; 1265 } 1266 if (objc == 3) { 1267 if (wmPtr->clientMachine != NULL) { 1268 Tcl_SetResult(interp, wmPtr->clientMachine, TCL_STATIC); 1269 } 1270 return TCL_OK; 1271 } 1272 argv3 = Tcl_GetStringFromObj(objv[3], &length); 1273 if (argv3[0] == 0) { 1274 if (wmPtr->clientMachine != NULL) { 1275 ckfree((char *) wmPtr->clientMachine); 1276 wmPtr->clientMachine = NULL; 1277 if (!(wmPtr->flags & WM_NEVER_MAPPED)) { 1278 XDeleteProperty(winPtr->display, wmPtr->wrapperPtr->window, 1279 Tk_InternAtom((Tk_Window) winPtr, 1280 "WM_CLIENT_MACHINE")); 1281 } 1282 } 1283 return TCL_OK; 1284 } 1285 if (wmPtr->clientMachine != NULL) { 1286 ckfree((char *) wmPtr->clientMachine); 1287 } 1288 wmPtr->clientMachine = (char *) 1289 ckalloc((unsigned) (length + 1)); 1290 strcpy(wmPtr->clientMachine, argv3); 1291 if (!(wmPtr->flags & WM_NEVER_MAPPED)) { 1292 XTextProperty textProp; 1293 Tcl_DString ds; 1294 1295 Tcl_UtfToExternalDString(NULL, wmPtr->clientMachine, -1, &ds); 1296 if (XStringListToTextProperty(&(Tcl_DStringValue(&ds)), 1, 1297 &textProp) != 0) { 1298 XSetWMClientMachine(winPtr->display, wmPtr->wrapperPtr->window, 1299 &textProp); 1300 XFree((char *) textProp.value); 1301 } 1302 Tcl_DStringFree(&ds); 1303 } 1304 return TCL_OK; 1305} 1306 1307/* 1308 *---------------------------------------------------------------------- 1309 * 1310 * WmColormapwindowsCmd -- 1311 * 1312 * This procedure is invoked to process the "wm colormapwindows" 1313 * Tcl command. 1314 * See the user documentation for details on what it does. 1315 * 1316 * Results: 1317 * A standard Tcl result. 1318 * 1319 * Side effects: 1320 * See the user documentation. 1321 * 1322 *---------------------------------------------------------------------- 1323 */ 1324 1325static int 1326WmColormapwindowsCmd(tkwin, winPtr, interp, objc, objv) 1327 Tk_Window tkwin; /* Main window of the application. */ 1328 TkWindow *winPtr; /* Toplevel to work with */ 1329 Tcl_Interp *interp; /* Current interpreter. */ 1330 int objc; /* Number of arguments. */ 1331 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1332{ 1333 register WmInfo *wmPtr = winPtr->wmInfoPtr; 1334 Window *cmapList; 1335 TkWindow *winPtr2; 1336 int count, i, windowObjc, gotToplevel; 1337 Tcl_Obj **windowObjv; 1338 char buffer[20]; 1339 1340 if ((objc != 3) && (objc != 4)) { 1341 Tcl_WrongNumArgs(interp, 2, objv, "window ?windowList?"); 1342 return TCL_ERROR; 1343 } 1344 Tk_MakeWindowExist((Tk_Window) winPtr); 1345 if (wmPtr->wrapperPtr == NULL) { 1346 CreateWrapper(wmPtr); 1347 } 1348 if (objc == 3) { 1349 if (XGetWMColormapWindows(winPtr->display, 1350 wmPtr->wrapperPtr->window, &cmapList, &count) == 0) { 1351 return TCL_OK; 1352 } 1353 for (i = 0; i < count; i++) { 1354 if ((i == (count-1)) 1355 && (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) { 1356 break; 1357 } 1358 winPtr2 = (TkWindow *) Tk_IdToWindow(winPtr->display, 1359 cmapList[i]); 1360 if (winPtr2 == NULL) { 1361 sprintf(buffer, "0x%lx", cmapList[i]); 1362 Tcl_AppendElement(interp, buffer); 1363 } else { 1364 Tcl_AppendElement(interp, winPtr2->pathName); 1365 } 1366 } 1367 XFree((char *) cmapList); 1368 return TCL_OK; 1369 } 1370 if (Tcl_ListObjGetElements(interp, objv[3], &windowObjc, &windowObjv) 1371 != TCL_OK) { 1372 return TCL_ERROR; 1373 } 1374 cmapList = (Window *) ckalloc((unsigned) 1375 ((windowObjc+1)*sizeof(Window))); 1376 gotToplevel = 0; 1377 for (i = 0; i < windowObjc; i++) { 1378 if (TkGetWindowFromObj(interp, tkwin, windowObjv[i], 1379 (Tk_Window *) &winPtr2) != TCL_OK) 1380 { 1381 ckfree((char *) cmapList); 1382 return TCL_ERROR; 1383 } 1384 if (winPtr2 == winPtr) { 1385 gotToplevel = 1; 1386 } 1387 if (winPtr2->window == None) { 1388 Tk_MakeWindowExist((Tk_Window) winPtr2); 1389 } 1390 cmapList[i] = winPtr2->window; 1391 } 1392 if (!gotToplevel) { 1393 wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP; 1394 cmapList[windowObjc] = wmPtr->wrapperPtr->window; 1395 windowObjc++; 1396 } else { 1397 wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP; 1398 } 1399 wmPtr->flags |= WM_COLORMAPS_EXPLICIT; 1400 XSetWMColormapWindows(winPtr->display, wmPtr->wrapperPtr->window, 1401 cmapList, windowObjc); 1402 ckfree((char *) cmapList); 1403 return TCL_OK; 1404} 1405 1406/* 1407 *---------------------------------------------------------------------- 1408 * 1409 * WmCommandCmd -- 1410 * 1411 * This procedure is invoked to process the "wm command" Tcl command. 1412 * See the user documentation for details on what it does. 1413 * 1414 * Results: 1415 * A standard Tcl result. 1416 * 1417 * Side effects: 1418 * See the user documentation. 1419 * 1420 *---------------------------------------------------------------------- 1421 */ 1422 1423static int 1424WmCommandCmd(tkwin, winPtr, interp, objc, objv) 1425 Tk_Window tkwin; /* Main window of the application. */ 1426 TkWindow *winPtr; /* Toplevel to work with */ 1427 Tcl_Interp *interp; /* Current interpreter. */ 1428 int objc; /* Number of arguments. */ 1429 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1430{ 1431 register WmInfo *wmPtr = winPtr->wmInfoPtr; 1432 char *argv3; 1433 int cmdArgc; 1434 CONST char **cmdArgv; 1435 1436 if ((objc != 3) && (objc != 4)) { 1437 Tcl_WrongNumArgs(interp, 2, objv, "window ?value?"); 1438 return TCL_ERROR; 1439 } 1440 if (objc == 3) { 1441 if (wmPtr->cmdArgv != NULL) { 1442 Tcl_SetResult(interp, 1443 Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv), 1444 TCL_DYNAMIC); 1445 } 1446 return TCL_OK; 1447 } 1448 argv3 = Tcl_GetString(objv[3]); 1449 if (argv3[0] == 0) { 1450 if (wmPtr->cmdArgv != NULL) { 1451 ckfree((char *) wmPtr->cmdArgv); 1452 wmPtr->cmdArgv = NULL; 1453 if (!(wmPtr->flags & WM_NEVER_MAPPED)) { 1454 XDeleteProperty(winPtr->display, wmPtr->wrapperPtr->window, 1455 Tk_InternAtom((Tk_Window) winPtr, "WM_COMMAND")); 1456 } 1457 } 1458 return TCL_OK; 1459 } 1460 if (Tcl_SplitList(interp, argv3, &cmdArgc, &cmdArgv) != TCL_OK) { 1461 return TCL_ERROR; 1462 } 1463 if (wmPtr->cmdArgv != NULL) { 1464 ckfree((char *) wmPtr->cmdArgv); 1465 } 1466 wmPtr->cmdArgc = cmdArgc; 1467 wmPtr->cmdArgv = cmdArgv; 1468 if (!(wmPtr->flags & WM_NEVER_MAPPED)) { 1469 UpdateCommand(winPtr); 1470 } 1471 return TCL_OK; 1472} 1473 1474/* 1475 *---------------------------------------------------------------------- 1476 * 1477 * WmDeiconifyCmd -- 1478 * 1479 * This procedure is invoked to process the "wm deiconify" Tcl command. 1480 * See the user documentation for details on what it does. 1481 * 1482 * Results: 1483 * A standard Tcl result. 1484 * 1485 * Side effects: 1486 * See the user documentation. 1487 * 1488 *---------------------------------------------------------------------- 1489 */ 1490 1491static int 1492WmDeiconifyCmd(tkwin, winPtr, interp, objc, objv) 1493 Tk_Window tkwin; /* Main window of the application. */ 1494 TkWindow *winPtr; /* Toplevel to work with */ 1495 Tcl_Interp *interp; /* Current interpreter. */ 1496 int objc; /* Number of arguments. */ 1497 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1498{ 1499 register WmInfo *wmPtr = winPtr->wmInfoPtr; 1500 1501 if (objc != 3) { 1502 Tcl_WrongNumArgs(interp, 2, objv, "window"); 1503 return TCL_ERROR; 1504 } 1505 if (wmPtr->iconFor != NULL) { 1506 Tcl_AppendResult(interp, "can't deiconify ", Tcl_GetString(objv[2]), 1507 ": it is an icon for ", Tk_PathName(wmPtr->iconFor), 1508 (char *) NULL); 1509 return TCL_ERROR; 1510 } 1511 if (winPtr->flags & TK_EMBEDDED) { 1512 Tcl_AppendResult(interp, "can't deiconify ", winPtr->pathName, 1513 ": it is an embedded window", (char *) NULL); 1514 return TCL_ERROR; 1515 } 1516 wmPtr->flags &= ~WM_WITHDRAWN; 1517 TkpWmSetState(winPtr, NormalState); 1518 return TCL_OK; 1519} 1520 1521/* 1522 *---------------------------------------------------------------------- 1523 * 1524 * WmFocusmodelCmd -- 1525 * 1526 * This procedure is invoked to process the "wm focusmodel" Tcl command. 1527 * See the user documentation for details on what it does. 1528 * 1529 * Results: 1530 * A standard Tcl result. 1531 * 1532 * Side effects: 1533 * See the user documentation. 1534 * 1535 *---------------------------------------------------------------------- 1536 */ 1537 1538static int 1539WmFocusmodelCmd(tkwin, winPtr, interp, objc, objv) 1540 Tk_Window tkwin; /* Main window of the application. */ 1541 TkWindow *winPtr; /* Toplevel to work with */ 1542 Tcl_Interp *interp; /* Current interpreter. */ 1543 int objc; /* Number of arguments. */ 1544 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1545{ 1546 register WmInfo *wmPtr = winPtr->wmInfoPtr; 1547 static CONST char *optionStrings[] = { 1548 "active", "passive", (char *) NULL }; 1549 enum options { 1550 OPT_ACTIVE, OPT_PASSIVE }; 1551 int index; 1552 1553 if ((objc != 3) && (objc != 4)) { 1554 Tcl_WrongNumArgs(interp, 2, objv, "window ?active|passive?"); 1555 return TCL_ERROR; 1556 } 1557 if (objc == 3) { 1558 Tcl_SetResult(interp, (wmPtr->hints.input ? "passive" : "active"), 1559 TCL_STATIC); 1560 return TCL_OK; 1561 } 1562 1563 if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0, 1564 &index) != TCL_OK) { 1565 return TCL_ERROR; 1566 } 1567 if (index == OPT_ACTIVE) { 1568 wmPtr->hints.input = False; 1569 } else { /* OPT_PASSIVE */ 1570 wmPtr->hints.input = True; 1571 } 1572 UpdateHints(winPtr); 1573 return TCL_OK; 1574} 1575 1576/* 1577 *---------------------------------------------------------------------- 1578 * 1579 * WmFrameCmd -- 1580 * 1581 * This procedure is invoked to process the "wm frame" Tcl command. 1582 * See the user documentation for details on what it does. 1583 * 1584 * Results: 1585 * A standard Tcl result. 1586 * 1587 * Side effects: 1588 * See the user documentation. 1589 * 1590 *---------------------------------------------------------------------- 1591 */ 1592 1593static int 1594WmFrameCmd(tkwin, winPtr, interp, objc, objv) 1595 Tk_Window tkwin; /* Main window of the application. */ 1596 TkWindow *winPtr; /* Toplevel to work with */ 1597 Tcl_Interp *interp; /* Current interpreter. */ 1598 int objc; /* Number of arguments. */ 1599 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1600{ 1601 register WmInfo *wmPtr = winPtr->wmInfoPtr; 1602 Window window; 1603 char buf[TCL_INTEGER_SPACE]; 1604 1605 if (objc != 3) { 1606 Tcl_WrongNumArgs(interp, 2, objv, "window"); 1607 return TCL_ERROR; 1608 } 1609 window = wmPtr->reparent; 1610 if (window == None) { 1611 window = Tk_WindowId((Tk_Window) winPtr); 1612 } 1613 sprintf(buf, "0x%x", (unsigned int) window); 1614 Tcl_SetResult(interp, buf, TCL_VOLATILE); 1615 return TCL_OK; 1616} 1617 1618/* 1619 *---------------------------------------------------------------------- 1620 * 1621 * WmGeometryCmd -- 1622 * 1623 * This procedure is invoked to process the "wm geometry" Tcl command. 1624 * See the user documentation for details on what it does. 1625 * 1626 * Results: 1627 * A standard Tcl result. 1628 * 1629 * Side effects: 1630 * See the user documentation. 1631 * 1632 *---------------------------------------------------------------------- 1633 */ 1634 1635static int 1636WmGeometryCmd(tkwin, winPtr, interp, objc, objv) 1637 Tk_Window tkwin; /* Main window of the application. */ 1638 TkWindow *winPtr; /* Toplevel to work with */ 1639 Tcl_Interp *interp; /* Current interpreter. */ 1640 int objc; /* Number of arguments. */ 1641 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1642{ 1643 register WmInfo *wmPtr = winPtr->wmInfoPtr; 1644 char xSign, ySign; 1645 int width, height; 1646 char *argv3; 1647 1648 if ((objc != 3) && (objc != 4)) { 1649 Tcl_WrongNumArgs(interp, 2, objv, "window ?newGeometry?"); 1650 return TCL_ERROR; 1651 } 1652 if (objc == 3) { 1653 char buf[16 + TCL_INTEGER_SPACE * 4]; 1654 1655 xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+'; 1656 ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+'; 1657 if (wmPtr->gridWin != NULL) { 1658 width = wmPtr->reqGridWidth + (winPtr->changes.width 1659 - winPtr->reqWidth)/wmPtr->widthInc; 1660 height = wmPtr->reqGridHeight + (winPtr->changes.height 1661 - winPtr->reqHeight)/wmPtr->heightInc; 1662 } else { 1663 width = winPtr->changes.width; 1664 height = winPtr->changes.height; 1665 } 1666 sprintf(buf, "%dx%d%c%d%c%d", width, height, xSign, wmPtr->x, 1667 ySign, wmPtr->y); 1668 Tcl_SetResult(interp, buf, TCL_VOLATILE); 1669 return TCL_OK; 1670 } 1671 argv3 = Tcl_GetString(objv[3]); 1672 if (*argv3 == '\0') { 1673 wmPtr->width = -1; 1674 wmPtr->height = -1; 1675 WmUpdateGeom(wmPtr, winPtr); 1676 return TCL_OK; 1677 } 1678 return ParseGeometry(interp, argv3, winPtr); 1679} 1680 1681/* 1682 *---------------------------------------------------------------------- 1683 * 1684 * WmGridCmd -- 1685 * 1686 * This procedure is invoked to process the "wm grid" Tcl command. 1687 * See the user documentation for details on what it does. 1688 * 1689 * Results: 1690 * A standard Tcl result. 1691 * 1692 * Side effects: 1693 * See the user documentation. 1694 * 1695 *---------------------------------------------------------------------- 1696 */ 1697 1698static int 1699WmGridCmd(tkwin, winPtr, interp, objc, objv) 1700 Tk_Window tkwin; /* Main window of the application. */ 1701 TkWindow *winPtr; /* Toplevel to work with */ 1702 Tcl_Interp *interp; /* Current interpreter. */ 1703 int objc; /* Number of arguments. */ 1704 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1705{ 1706 register WmInfo *wmPtr = winPtr->wmInfoPtr; 1707 int reqWidth, reqHeight, widthInc, heightInc; 1708 1709 if ((objc != 3) && (objc != 7)) { 1710 Tcl_WrongNumArgs(interp, 2, objv, 1711 "window ?baseWidth baseHeight widthInc heightInc?"); 1712 return TCL_ERROR; 1713 } 1714 if (objc == 3) { 1715 if (wmPtr->sizeHintsFlags & PBaseSize) { 1716 char buf[TCL_INTEGER_SPACE * 4]; 1717 1718 sprintf(buf, "%d %d %d %d", wmPtr->reqGridWidth, 1719 wmPtr->reqGridHeight, wmPtr->widthInc, 1720 wmPtr->heightInc); 1721 Tcl_SetResult(interp, buf, TCL_VOLATILE); 1722 } 1723 return TCL_OK; 1724 } 1725 if (*Tcl_GetString(objv[3]) == '\0') { 1726 /* 1727 * Turn off gridding and reset the width and height 1728 * to make sense as ungridded numbers. 1729 */ 1730 1731 wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc); 1732 if (wmPtr->width != -1) { 1733 wmPtr->width = winPtr->reqWidth + (wmPtr->width 1734 - wmPtr->reqGridWidth)*wmPtr->widthInc; 1735 wmPtr->height = winPtr->reqHeight + (wmPtr->height 1736 - wmPtr->reqGridHeight)*wmPtr->heightInc; 1737 } 1738 wmPtr->widthInc = 1; 1739 wmPtr->heightInc = 1; 1740 } else { 1741 if ((Tcl_GetIntFromObj(interp, objv[3], &reqWidth) != TCL_OK) 1742 || (Tcl_GetIntFromObj(interp, objv[4], &reqHeight) != TCL_OK) 1743 || (Tcl_GetIntFromObj(interp, objv[5], &widthInc) != TCL_OK) 1744 || (Tcl_GetIntFromObj(interp, objv[6], &heightInc) != TCL_OK)) { 1745 return TCL_ERROR; 1746 } 1747 if (reqWidth < 0) { 1748 Tcl_SetResult(interp, "baseWidth can't be < 0", TCL_STATIC); 1749 return TCL_ERROR; 1750 } 1751 if (reqHeight < 0) { 1752 Tcl_SetResult(interp, "baseHeight can't be < 0", TCL_STATIC); 1753 return TCL_ERROR; 1754 } 1755 if (widthInc <= 0) { 1756 Tcl_SetResult(interp, "widthInc can't be <= 0", TCL_STATIC); 1757 return TCL_ERROR; 1758 } 1759 if (heightInc <= 0) { 1760 Tcl_SetResult(interp, "heightInc can't be <= 0", TCL_STATIC); 1761 return TCL_ERROR; 1762 } 1763 Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc, 1764 heightInc); 1765 } 1766 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 1767 WmUpdateGeom(wmPtr, winPtr); 1768 return TCL_OK; 1769} 1770 1771/* 1772 *---------------------------------------------------------------------- 1773 * 1774 * WmGroupCmd -- 1775 * 1776 * This procedure is invoked to process the "wm group" Tcl command. 1777 * See the user documentation for details on what it does. 1778 * 1779 * Results: 1780 * A standard Tcl result. 1781 * 1782 * Side effects: 1783 * See the user documentation. 1784 * 1785 *---------------------------------------------------------------------- 1786 */ 1787 1788static int 1789WmGroupCmd(tkwin, winPtr, interp, objc, objv) 1790 Tk_Window tkwin; /* Main window of the application. */ 1791 TkWindow *winPtr; /* Toplevel to work with */ 1792 Tcl_Interp *interp; /* Current interpreter. */ 1793 int objc; /* Number of arguments. */ 1794 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1795{ 1796 register WmInfo *wmPtr = winPtr->wmInfoPtr; 1797 Tk_Window tkwin2; 1798 WmInfo *wmPtr2; 1799 char *argv3; 1800 int length; 1801 1802 if ((objc != 3) && (objc != 4)) { 1803 Tcl_WrongNumArgs(interp, 2, objv, "window ?pathName?"); 1804 return TCL_ERROR; 1805 } 1806 if (objc == 3) { 1807 if (wmPtr->hints.flags & WindowGroupHint) { 1808 Tcl_SetResult(interp, wmPtr->leaderName, TCL_STATIC); 1809 } 1810 return TCL_OK; 1811 } 1812 argv3 = Tcl_GetStringFromObj(objv[3], &length); 1813 if (*argv3 == '\0') { 1814 wmPtr->hints.flags &= ~WindowGroupHint; 1815 if (wmPtr->leaderName != NULL) { 1816 ckfree(wmPtr->leaderName); 1817 } 1818 wmPtr->leaderName = NULL; 1819 } else { 1820 if (TkGetWindowFromObj(interp, tkwin, objv[3], &tkwin2) != TCL_OK) { 1821 return TCL_ERROR; 1822 } 1823 while (!Tk_TopWinHierarchy(tkwin2)) { 1824 /* 1825 * Ensure that the group leader is actually a Tk toplevel. 1826 */ 1827 1828 tkwin2 = Tk_Parent(tkwin2); 1829 } 1830 Tk_MakeWindowExist(tkwin2); 1831 wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr; 1832 if (wmPtr2->wrapperPtr == NULL) { 1833 CreateWrapper(wmPtr2); 1834 } 1835 if (wmPtr->leaderName != NULL) { 1836 ckfree(wmPtr->leaderName); 1837 } 1838 wmPtr->hints.window_group = Tk_WindowId(wmPtr2->wrapperPtr); 1839 wmPtr->hints.flags |= WindowGroupHint; 1840 wmPtr->leaderName = ckalloc((unsigned) (length + 1)); 1841 strcpy(wmPtr->leaderName, argv3); 1842 } 1843 UpdateHints(winPtr); 1844 return TCL_OK; 1845} 1846 1847/* 1848 *---------------------------------------------------------------------- 1849 * 1850 * WmIconbitmapCmd -- 1851 * 1852 * This procedure is invoked to process the "wm iconbitmap" Tcl command. 1853 * See the user documentation for details on what it does. 1854 * 1855 * Results: 1856 * A standard Tcl result. 1857 * 1858 * Side effects: 1859 * See the user documentation. 1860 * 1861 *---------------------------------------------------------------------- 1862 */ 1863 1864static int 1865WmIconbitmapCmd(tkwin, winPtr, interp, objc, objv) 1866 Tk_Window tkwin; /* Main window of the application. */ 1867 TkWindow *winPtr; /* Toplevel to work with */ 1868 Tcl_Interp *interp; /* Current interpreter. */ 1869 int objc; /* Number of arguments. */ 1870 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1871{ 1872 register WmInfo *wmPtr = winPtr->wmInfoPtr; 1873 Pixmap pixmap; 1874 char *argv3; 1875 1876 if ((objc < 3) || (objc > 4)) { 1877 Tcl_WrongNumArgs(interp, 2, objv, "window ?bitmap?"); 1878 return TCL_ERROR; 1879 } 1880 if (objc == 3) { 1881 if (wmPtr->hints.flags & IconPixmapHint) { 1882 Tcl_SetResult(interp, (char *) 1883 Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_pixmap), 1884 TCL_STATIC); 1885 } 1886 return TCL_OK; 1887 } 1888 argv3 = Tcl_GetString(objv[3]); 1889 if (*argv3 == '\0') { 1890 if (wmPtr->hints.icon_pixmap != None) { 1891 Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap); 1892 wmPtr->hints.icon_pixmap = None; 1893 } 1894 wmPtr->hints.flags &= ~IconPixmapHint; 1895 } else { 1896 pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr, argv3); 1897 if (pixmap == None) { 1898 return TCL_ERROR; 1899 } 1900 wmPtr->hints.icon_pixmap = pixmap; 1901 wmPtr->hints.flags |= IconPixmapHint; 1902 } 1903 UpdateHints(winPtr); 1904 return TCL_OK; 1905} 1906 1907/* 1908 *---------------------------------------------------------------------- 1909 * 1910 * WmIconifyCmd -- 1911 * 1912 * This procedure is invoked to process the "wm iconify" Tcl command. 1913 * See the user documentation for details on what it does. 1914 * 1915 * Results: 1916 * A standard Tcl result. 1917 * 1918 * Side effects: 1919 * See the user documentation. 1920 * 1921 *---------------------------------------------------------------------- 1922 */ 1923 1924static int 1925WmIconifyCmd(tkwin, winPtr, interp, objc, objv) 1926 Tk_Window tkwin; /* Main window of the application. */ 1927 TkWindow *winPtr; /* Toplevel to work with */ 1928 Tcl_Interp *interp; /* Current interpreter. */ 1929 int objc; /* Number of arguments. */ 1930 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1931{ 1932 register WmInfo *wmPtr = winPtr->wmInfoPtr; 1933 if (objc != 3) { 1934 Tcl_WrongNumArgs(interp, 2, objv, "window"); 1935 return TCL_ERROR; 1936 } 1937 if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) { 1938 Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName, 1939 "\": override-redirect flag is set", (char *) NULL); 1940 return TCL_ERROR; 1941 } 1942 if (wmPtr->masterPtr != NULL) { 1943 Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName, 1944 "\": it is a transient", (char *) NULL); 1945 return TCL_ERROR; 1946 } 1947 if (wmPtr->iconFor != NULL) { 1948 Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName, 1949 ": it is an icon for ", Tk_PathName(wmPtr->iconFor), 1950 (char *) NULL); 1951 return TCL_ERROR; 1952 } 1953 if (winPtr->flags & TK_EMBEDDED) { 1954 Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName, 1955 ": it is an embedded window", (char *) NULL); 1956 return TCL_ERROR; 1957 } 1958 if (TkpWmSetState(winPtr, IconicState) == 0) { 1959 Tcl_SetResult(interp, 1960 "couldn't send iconify message to window manager", 1961 TCL_STATIC); 1962 return TCL_ERROR; 1963 } 1964 return TCL_OK; 1965} 1966 1967/* 1968 *---------------------------------------------------------------------- 1969 * 1970 * WmIconmaskCmd -- 1971 * 1972 * This procedure is invoked to process the "wm iconmask" Tcl command. 1973 * See the user documentation for details on what it does. 1974 * 1975 * Results: 1976 * A standard Tcl result. 1977 * 1978 * Side effects: 1979 * See the user documentation. 1980 * 1981 *---------------------------------------------------------------------- 1982 */ 1983 1984static int 1985WmIconmaskCmd(tkwin, winPtr, interp, objc, objv) 1986 Tk_Window tkwin; /* Main window of the application. */ 1987 TkWindow *winPtr; /* Toplevel to work with */ 1988 Tcl_Interp *interp; /* Current interpreter. */ 1989 int objc; /* Number of arguments. */ 1990 Tcl_Obj *CONST objv[]; /* Argument objects. */ 1991{ 1992 register WmInfo *wmPtr = winPtr->wmInfoPtr; 1993 Pixmap pixmap; 1994 char *argv3; 1995 1996 if ((objc != 3) && (objc != 4)) { 1997 Tcl_WrongNumArgs(interp, 2, objv, "window ?bitmap?"); 1998 return TCL_ERROR; 1999 } 2000 if (objc == 3) { 2001 if (wmPtr->hints.flags & IconMaskHint) { 2002 Tcl_SetResult(interp, (char *) 2003 Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_mask), 2004 TCL_STATIC); 2005 } 2006 return TCL_OK; 2007 } 2008 argv3 = Tcl_GetString(objv[3]); 2009 if (*argv3 == '\0') { 2010 if (wmPtr->hints.icon_mask != None) { 2011 Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask); 2012 } 2013 wmPtr->hints.flags &= ~IconMaskHint; 2014 } else { 2015 pixmap = Tk_GetBitmap(interp, tkwin, argv3); 2016 if (pixmap == None) { 2017 return TCL_ERROR; 2018 } 2019 wmPtr->hints.icon_mask = pixmap; 2020 wmPtr->hints.flags |= IconMaskHint; 2021 } 2022 UpdateHints(winPtr); 2023 return TCL_OK; 2024} 2025 2026/* 2027 *---------------------------------------------------------------------- 2028 * 2029 * WmIconnameCmd -- 2030 * 2031 * This procedure is invoked to process the "wm iconname" Tcl command. 2032 * See the user documentation for details on what it does. 2033 * 2034 * Results: 2035 * A standard Tcl result. 2036 * 2037 * Side effects: 2038 * See the user documentation. 2039 * 2040 *---------------------------------------------------------------------- 2041 */ 2042 2043static int 2044WmIconnameCmd(tkwin, winPtr, interp, objc, objv) 2045 Tk_Window tkwin; /* Main window of the application. */ 2046 TkWindow *winPtr; /* Toplevel to work with */ 2047 Tcl_Interp *interp; /* Current interpreter. */ 2048 int objc; /* Number of arguments. */ 2049 Tcl_Obj *CONST objv[]; /* Argument objects. */ 2050{ 2051 register WmInfo *wmPtr = winPtr->wmInfoPtr; 2052 char *argv3; 2053 int length; 2054 2055 if (objc > 4) { 2056 Tcl_WrongNumArgs(interp, 2, objv, "window ?newName?"); 2057 return TCL_ERROR; 2058 } 2059 if (objc == 3) { 2060 Tcl_SetResult(interp, 2061 ((wmPtr->iconName != NULL) ? wmPtr->iconName : ""), 2062 TCL_STATIC); 2063 return TCL_OK; 2064 } else { 2065 if (wmPtr->iconName != NULL) { 2066 ckfree((char *) wmPtr->iconName); 2067 } 2068 argv3 = Tcl_GetStringFromObj(objv[3], &length); 2069 wmPtr->iconName = ckalloc((unsigned) (length + 1)); 2070 strcpy(wmPtr->iconName, argv3); 2071 if (!(wmPtr->flags & WM_NEVER_MAPPED)) { 2072 UpdateTitle(winPtr); 2073 } 2074 } 2075 return TCL_OK; 2076} 2077 2078/* 2079 *---------------------------------------------------------------------- 2080 * 2081 * WmIconphotoCmd -- 2082 * 2083 * This procedure is invoked to process the "wm iconphoto" 2084 * Tcl command. 2085 * See the user documentation for details on what it does. 2086 * 2087 * Results: 2088 * A standard Tcl result. 2089 * 2090 * Side effects: 2091 * See the user documentation. 2092 * 2093 *---------------------------------------------------------------------- 2094 */ 2095 2096static int 2097WmIconphotoCmd(tkwin, winPtr, interp, objc, objv) 2098 Tk_Window tkwin; /* Main window of the application. */ 2099 TkWindow *winPtr; /* Toplevel to work with */ 2100 Tcl_Interp *interp; /* Current interpreter. */ 2101 int objc; /* Number of arguments. */ 2102 Tcl_Obj *CONST objv[]; /* Argument objects. */ 2103{ 2104 register WmInfo *wmPtr = winPtr->wmInfoPtr; 2105 Tk_PhotoHandle photo; 2106 Tk_PhotoImageBlock block; 2107 int i, size = 0, width, height, index = 0, x, y, isDefault = 0; 2108 long R, G, B, A; 2109 long *iconPropertyData; 2110 unsigned char *pixelByte; 2111 2112 if (objc < 4) { 2113 Tcl_WrongNumArgs(interp, 2, objv, 2114 "window ?-default? image1 ?image2 ...?"); 2115 return TCL_ERROR; 2116 } 2117 if (strcmp(Tcl_GetString(objv[3]), "-default") == 0) { 2118 isDefault = 1; 2119 if (objc == 4) { 2120 Tcl_WrongNumArgs(interp, 2, objv, 2121 "window ?-default? image1 ?image2 ...?"); 2122 return TCL_ERROR; 2123 } 2124 } 2125 /* 2126 * Iterate over all images to retrieve their sizes, in order to allocate a 2127 * buffer large enough to hold all images. 2128 */ 2129 for (i = 3 + isDefault; i < objc; i++) { 2130 photo = Tk_FindPhoto(interp, Tcl_GetString(objv[i])); 2131 if (photo == NULL) { 2132 Tcl_AppendResult(interp, "can't use \"", Tcl_GetString(objv[i]), 2133 "\" as iconphoto: not a photo image", (char *) NULL); 2134 return TCL_ERROR; 2135 } 2136 Tk_PhotoGetSize(photo, &width, &height); 2137 /* We need to cardinals for width & height and one cardinal for each 2138 * image pixel. */ 2139 size += 2 + width * height; 2140 } 2141 /* We have calculated the size of the data. Try to allocate the needed 2142 * memory space. */ 2143 iconPropertyData = (long *) Tcl_AttemptAlloc(sizeof(long)*size); 2144 if (iconPropertyData == NULL) { 2145 return TCL_ERROR; 2146 } 2147 memset(iconPropertyData, 0, sizeof(long)*size); 2148 2149 for (i = 3 + isDefault; i < objc; i++) { 2150 photo = Tk_FindPhoto(interp, Tcl_GetString(objv[i])); 2151 if (photo == NULL) { 2152 Tcl_Free((char *) iconPropertyData); 2153 return TCL_ERROR; 2154 } 2155 Tk_PhotoGetSize(photo, &width, &height); 2156 Tk_PhotoGetImage(photo, &block); 2157 /* 2158 * Each image data will be placed as an array of 32bit packed 2159 * CARDINAL, in a window property named "_NET_WM_ICON": 2160 * _NET_WM_ICON 2161 * 2162 * _NET_WM_ICON CARDINAL[][2+n]/32 2163 * 2164 * This is an array of possible icons for the client. 2165 * This specification does not stipulate what size these icons should 2166 * be, but individual desktop environments or toolkits may do so. 2167 * The Window Manager MAY scale any of these icons to an appropriate 2168 * size. 2169 * 2170 * This is an array of 32bit packed CARDINAL ARGB with high byte being 2171 * A, low byte being B. The first two cardinals are width, height. 2172 * Data is in rows, left to right and top to bottom. 2173 */ 2174 2175 /* 2176 * Encode the image data in the iconPropertyData array. 2177 */ 2178 iconPropertyData[index++] = width; 2179 iconPropertyData[index++] = height; 2180 for (y = 0; y < height; y++) { 2181 for (x = 0; x < width; x++) { 2182 R = *(block.pixelPtr + x*block.pixelSize + 2183 y*block.pitch + block.offset[0]); 2184 G = *(block.pixelPtr + x*block.pixelSize + 2185 y*block.pitch + block.offset[1]); 2186 B = *(block.pixelPtr + x*block.pixelSize + 2187 y*block.pitch + block.offset[2]); 2188 A = *(block.pixelPtr + x*block.pixelSize + 2189 y*block.pitch + block.offset[3]); 2190 pixelByte = (unsigned char *) &iconPropertyData[index]; 2191 pixelByte[3] = A; 2192 pixelByte[2] = R; 2193 pixelByte[1] = G; 2194 pixelByte[0] = B; 2195 index++; 2196 } 2197 } 2198 } 2199 if (wmPtr->iconDataPtr != NULL) { 2200 ckfree((char *)wmPtr->iconDataPtr); 2201 wmPtr->iconDataPtr = NULL; 2202 } 2203 if (isDefault) { 2204 if (winPtr->dispPtr->iconDataPtr != NULL) { 2205 ckfree((char *) winPtr->dispPtr->iconDataPtr); 2206 } 2207 winPtr->dispPtr->iconDataPtr = (unsigned char *) iconPropertyData; 2208 winPtr->dispPtr->iconDataSize = size; 2209 } else { 2210 wmPtr->iconDataPtr = (unsigned char *) iconPropertyData; 2211 wmPtr->iconDataSize = size; 2212 } 2213 if (!(wmPtr->flags & WM_NEVER_MAPPED)) { 2214 UpdatePhotoIcon(winPtr); 2215 } 2216 return TCL_OK; 2217} 2218 2219/* 2220 *---------------------------------------------------------------------- 2221 * 2222 * WmIconpositionCmd -- 2223 * 2224 * This procedure is invoked to process the "wm iconposition" 2225 * Tcl command. 2226 * See the user documentation for details on what it does. 2227 * 2228 * Results: 2229 * A standard Tcl result. 2230 * 2231 * Side effects: 2232 * See the user documentation. 2233 * 2234 *---------------------------------------------------------------------- 2235 */ 2236 2237static int 2238WmIconpositionCmd(tkwin, winPtr, interp, objc, objv) 2239 Tk_Window tkwin; /* Main window of the application. */ 2240 TkWindow *winPtr; /* Toplevel to work with */ 2241 Tcl_Interp *interp; /* Current interpreter. */ 2242 int objc; /* Number of arguments. */ 2243 Tcl_Obj *CONST objv[]; /* Argument objects. */ 2244{ 2245 register WmInfo *wmPtr = winPtr->wmInfoPtr; 2246 int x, y; 2247 2248 if ((objc != 3) && (objc != 5)) { 2249 Tcl_WrongNumArgs(interp, 2, objv, "window ?x y?"); 2250 return TCL_ERROR; 2251 } 2252 if (objc == 3) { 2253 if (wmPtr->hints.flags & IconPositionHint) { 2254 char buf[TCL_INTEGER_SPACE * 2]; 2255 2256 sprintf(buf, "%d %d", wmPtr->hints.icon_x, 2257 wmPtr->hints.icon_y); 2258 Tcl_SetResult(interp, buf, TCL_VOLATILE); 2259 } 2260 return TCL_OK; 2261 } 2262 if (*Tcl_GetString(objv[3]) == '\0') { 2263 wmPtr->hints.flags &= ~IconPositionHint; 2264 } else { 2265 if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) 2266 || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)){ 2267 return TCL_ERROR; 2268 } 2269 wmPtr->hints.icon_x = x; 2270 wmPtr->hints.icon_y = y; 2271 wmPtr->hints.flags |= IconPositionHint; 2272 } 2273 UpdateHints(winPtr); 2274 return TCL_OK; 2275} 2276 2277/* 2278 *---------------------------------------------------------------------- 2279 * 2280 * WmIconwindowCmd -- 2281 * 2282 * This procedure is invoked to process the "wm iconwindow" Tcl command. 2283 * See the user documentation for details on what it does. 2284 * 2285 * Results: 2286 * A standard Tcl result. 2287 * 2288 * Side effects: 2289 * See the user documentation. 2290 * 2291 *---------------------------------------------------------------------- 2292 */ 2293 2294static int 2295WmIconwindowCmd(tkwin, winPtr, interp, objc, objv) 2296 Tk_Window tkwin; /* Main window of the application. */ 2297 TkWindow *winPtr; /* Toplevel to work with */ 2298 Tcl_Interp *interp; /* Current interpreter. */ 2299 int objc; /* Number of arguments. */ 2300 Tcl_Obj *CONST objv[]; /* Argument objects. */ 2301{ 2302 register WmInfo *wmPtr = winPtr->wmInfoPtr; 2303 Tk_Window tkwin2; 2304 WmInfo *wmPtr2; 2305 XSetWindowAttributes atts; 2306 2307 if ((objc != 3) && (objc != 4)) { 2308 Tcl_WrongNumArgs(interp, 2, objv, "window ?pathName?"); 2309 return TCL_ERROR; 2310 } 2311 if (objc == 3) { 2312 if (wmPtr->icon != NULL) { 2313 Tcl_SetResult(interp, Tk_PathName(wmPtr->icon), TCL_STATIC); 2314 } 2315 return TCL_OK; 2316 } 2317 if (*Tcl_GetString(objv[3]) == '\0') { 2318 wmPtr->hints.flags &= ~IconWindowHint; 2319 if (wmPtr->icon != NULL) { 2320 /* 2321 * Remove the icon window relationship. In principle we 2322 * should also re-enable button events for the window, but 2323 * this doesn't work in general because the window manager 2324 * is probably selecting on them (we'll get an error if 2325 * we try to re-enable the events). So, just leave the 2326 * icon window event-challenged; the user will have to 2327 * recreate it if they want button events. 2328 */ 2329 2330 wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr; 2331 wmPtr2->iconFor = NULL; 2332 wmPtr2->withdrawn = 1; 2333 wmPtr2->hints.initial_state = WithdrawnState; 2334 } 2335 wmPtr->icon = NULL; 2336 } else { 2337 if (TkGetWindowFromObj(interp, tkwin, objv[3], &tkwin2) != TCL_OK) { 2338 return TCL_ERROR; 2339 } 2340 if (!Tk_IsTopLevel(tkwin2)) { 2341 Tcl_AppendResult(interp, "can't use ", Tcl_GetString(objv[3]), 2342 " as icon window: not at top level", (char *) NULL); 2343 return TCL_ERROR; 2344 } 2345 wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr; 2346 if (wmPtr2->iconFor != NULL) { 2347 Tcl_AppendResult(interp, Tcl_GetString(objv[3]), 2348 " is already an icon for ", 2349 Tk_PathName(wmPtr2->iconFor), (char *) NULL); 2350 return TCL_ERROR; 2351 } 2352 if (wmPtr->icon != NULL) { 2353 WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr; 2354 wmPtr3->iconFor = NULL; 2355 wmPtr3->withdrawn = 1; 2356 wmPtr3->hints.initial_state = WithdrawnState; 2357 } 2358 2359 /* 2360 * Disable button events in the icon window: some window 2361 * managers (like olvwm) want to get the events themselves, 2362 * but X only allows one application at a time to receive 2363 * button events for a window. 2364 */ 2365 2366 atts.event_mask = Tk_Attributes(tkwin2)->event_mask 2367 & ~ButtonPressMask; 2368 Tk_ChangeWindowAttributes(tkwin2, CWEventMask, &atts); 2369 Tk_MakeWindowExist(tkwin2); 2370 if (wmPtr2->wrapperPtr == NULL) { 2371 CreateWrapper(wmPtr2); 2372 } 2373 wmPtr->hints.icon_window = Tk_WindowId(wmPtr2->wrapperPtr); 2374 wmPtr->hints.flags |= IconWindowHint; 2375 wmPtr->icon = tkwin2; 2376 wmPtr2->iconFor = (Tk_Window) winPtr; 2377 if (!wmPtr2->withdrawn && !(wmPtr2->flags & WM_NEVER_MAPPED)) { 2378 wmPtr2->withdrawn = 0; 2379 if (XWithdrawWindow(Tk_Display(tkwin2), 2380 Tk_WindowId(wmPtr2->wrapperPtr), 2381 Tk_ScreenNumber(tkwin2)) == 0) { 2382 Tcl_SetResult(interp, 2383 "couldn't send withdraw message to window manager", 2384 TCL_STATIC); 2385 return TCL_ERROR; 2386 } 2387 WaitForMapNotify((TkWindow *) tkwin2, 0); 2388 } 2389 } 2390 UpdateHints(winPtr); 2391 return TCL_OK; 2392} 2393 2394/* 2395 *---------------------------------------------------------------------- 2396 * 2397 * WmMaxsizeCmd -- 2398 * 2399 * This procedure is invoked to process the "wm maxsize" Tcl command. 2400 * See the user documentation for details on what it does. 2401 * 2402 * Results: 2403 * A standard Tcl result. 2404 * 2405 * Side effects: 2406 * See the user documentation. 2407 * 2408 *---------------------------------------------------------------------- 2409 */ 2410 2411static int 2412WmMaxsizeCmd(tkwin, winPtr, interp, objc, objv) 2413 Tk_Window tkwin; /* Main window of the application. */ 2414 TkWindow *winPtr; /* Toplevel to work with */ 2415 Tcl_Interp *interp; /* Current interpreter. */ 2416 int objc; /* Number of arguments. */ 2417 Tcl_Obj *CONST objv[]; /* Argument objects. */ 2418{ 2419 register WmInfo *wmPtr = winPtr->wmInfoPtr; 2420 int width, height; 2421 2422 if ((objc != 3) && (objc != 5)) { 2423 Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?"); 2424 return TCL_ERROR; 2425 } 2426 if (objc == 3) { 2427 char buf[TCL_INTEGER_SPACE * 2]; 2428 2429 GetMaxSize(wmPtr, &width, &height); 2430 sprintf(buf, "%d %d", width, height); 2431 Tcl_SetResult(interp, buf, TCL_VOLATILE); 2432 return TCL_OK; 2433 } 2434 if ((Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK) 2435 || (Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK)) { 2436 return TCL_ERROR; 2437 } 2438 wmPtr->maxWidth = width; 2439 wmPtr->maxHeight = height; 2440 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 2441 2442 if (width <= 0 && height <= 0) { 2443 wmPtr->sizeHintsFlags &= ~PMaxSize; 2444 } else { 2445 wmPtr->sizeHintsFlags |= PMaxSize; 2446 } 2447 2448 WmUpdateGeom(wmPtr, winPtr); 2449 return TCL_OK; 2450} 2451 2452/* 2453 *---------------------------------------------------------------------- 2454 * 2455 * WmMinsizeCmd -- 2456 * 2457 * This procedure is invoked to process the "wm minsize" Tcl command. 2458 * See the user documentation for details on what it does. 2459 * 2460 * Results: 2461 * A standard Tcl result. 2462 * 2463 * Side effects: 2464 * See the user documentation. 2465 * 2466 *---------------------------------------------------------------------- 2467 */ 2468 2469static int 2470WmMinsizeCmd(tkwin, winPtr, interp, objc, objv) 2471 Tk_Window tkwin; /* Main window of the application. */ 2472 TkWindow *winPtr; /* Toplevel to work with */ 2473 Tcl_Interp *interp; /* Current interpreter. */ 2474 int objc; /* Number of arguments. */ 2475 Tcl_Obj *CONST objv[]; /* Argument objects. */ 2476{ 2477 register WmInfo *wmPtr = winPtr->wmInfoPtr; 2478 int width, height; 2479 2480 if ((objc != 3) && (objc != 5)) { 2481 Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?"); 2482 return TCL_ERROR; 2483 } 2484 if (objc == 3) { 2485 char buf[TCL_INTEGER_SPACE * 2]; 2486 2487 sprintf(buf, "%d %d", wmPtr->minWidth, wmPtr->minHeight); 2488 Tcl_SetResult(interp, buf, TCL_VOLATILE); 2489 return TCL_OK; 2490 } 2491 if ((Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK) 2492 || (Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK)) { 2493 return TCL_ERROR; 2494 } 2495 wmPtr->minWidth = width; 2496 wmPtr->minHeight = height; 2497 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 2498 WmUpdateGeom(wmPtr, winPtr); 2499 return TCL_OK; 2500} 2501 2502/* 2503 *---------------------------------------------------------------------- 2504 * 2505 * WmOverrideredirectCmd -- 2506 * 2507 * This procedure is invoked to process the "wm overrideredirect" 2508 * Tcl command. 2509 * See the user documentation for details on what it does. 2510 * 2511 * Results: 2512 * A standard Tcl result. 2513 * 2514 * Side effects: 2515 * See the user documentation. 2516 * 2517 *---------------------------------------------------------------------- 2518 */ 2519 2520static int 2521WmOverrideredirectCmd(tkwin, winPtr, interp, objc, objv) 2522 Tk_Window tkwin; /* Main window of the application. */ 2523 TkWindow *winPtr; /* Toplevel to work with */ 2524 Tcl_Interp *interp; /* Current interpreter. */ 2525 int objc; /* Number of arguments. */ 2526 Tcl_Obj *CONST objv[]; /* Argument objects. */ 2527{ 2528 int boolean, curValue; 2529 XSetWindowAttributes atts; 2530 2531 if ((objc != 3) && (objc != 4)) { 2532 Tcl_WrongNumArgs(interp, 2, objv, "window ?boolean?"); 2533 return TCL_ERROR; 2534 } 2535 curValue = Tk_Attributes((Tk_Window) winPtr)->override_redirect; 2536 if (objc == 3) { 2537 Tcl_SetBooleanObj(Tcl_GetObjResult(interp), curValue); 2538 return TCL_OK; 2539 } 2540 if (Tcl_GetBooleanFromObj(interp, objv[3], &boolean) != TCL_OK) { 2541 return TCL_ERROR; 2542 } 2543 if (curValue != boolean) { 2544 /* 2545 * Only do this if we are really changing value, because it 2546 * causes some funky stuff to occur 2547 */ 2548 atts.override_redirect = (boolean) ? True : False; 2549 Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect, 2550 &atts); 2551 if (winPtr->wmInfoPtr->wrapperPtr != NULL) { 2552 Tk_ChangeWindowAttributes( 2553 (Tk_Window) winPtr->wmInfoPtr->wrapperPtr, 2554 CWOverrideRedirect, &atts); 2555 } 2556 } 2557 return TCL_OK; 2558} 2559 2560/* 2561 *---------------------------------------------------------------------- 2562 * 2563 * WmPositionfromCmd -- 2564 * 2565 * This procedure is invoked to process the "wm positionfrom" 2566 * Tcl command. 2567 * See the user documentation for details on what it does. 2568 * 2569 * Results: 2570 * A standard Tcl result. 2571 * 2572 * Side effects: 2573 * See the user documentation. 2574 * 2575 *---------------------------------------------------------------------- 2576 */ 2577 2578static int 2579WmPositionfromCmd(tkwin, winPtr, interp, objc, objv) 2580 Tk_Window tkwin; /* Main window of the application. */ 2581 TkWindow *winPtr; /* Toplevel to work with */ 2582 Tcl_Interp *interp; /* Current interpreter. */ 2583 int objc; /* Number of arguments. */ 2584 Tcl_Obj *CONST objv[]; /* Argument objects. */ 2585{ 2586 register WmInfo *wmPtr = winPtr->wmInfoPtr; 2587 static CONST char *optionStrings[] = { 2588 "program", "user", (char *) NULL }; 2589 enum options { 2590 OPT_PROGRAM, OPT_USER }; 2591 int index; 2592 2593 if ((objc != 3) && (objc != 4)) { 2594 Tcl_WrongNumArgs(interp, 2, objv, "window ?user/program?"); 2595 return TCL_ERROR; 2596 } 2597 if (objc == 3) { 2598 if (wmPtr->sizeHintsFlags & USPosition) { 2599 Tcl_SetResult(interp, "user", TCL_STATIC); 2600 } else if (wmPtr->sizeHintsFlags & PPosition) { 2601 Tcl_SetResult(interp, "program", TCL_STATIC); 2602 } 2603 return TCL_OK; 2604 } 2605 if (*Tcl_GetString(objv[3]) == '\0') { 2606 wmPtr->sizeHintsFlags &= ~(USPosition|PPosition); 2607 } else { 2608 if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0, 2609 &index) != TCL_OK) { 2610 return TCL_ERROR; 2611 } 2612 if (index == OPT_USER) { 2613 wmPtr->sizeHintsFlags &= ~PPosition; 2614 wmPtr->sizeHintsFlags |= USPosition; 2615 } else { 2616 wmPtr->sizeHintsFlags &= ~USPosition; 2617 wmPtr->sizeHintsFlags |= PPosition; 2618 } 2619 } 2620 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 2621 WmUpdateGeom(wmPtr, winPtr); 2622 return TCL_OK; 2623} 2624 2625/* 2626 *---------------------------------------------------------------------- 2627 * 2628 * WmProtocolCmd -- 2629 * 2630 * This procedure is invoked to process the "wm protocol" Tcl command. 2631 * See the user documentation for details on what it does. 2632 * 2633 * Results: 2634 * A standard Tcl result. 2635 * 2636 * Side effects: 2637 * See the user documentation. 2638 * 2639 *---------------------------------------------------------------------- 2640 */ 2641 2642static int 2643WmProtocolCmd(tkwin, winPtr, interp, objc, objv) 2644 Tk_Window tkwin; /* Main window of the application. */ 2645 TkWindow *winPtr; /* Toplevel to work with */ 2646 Tcl_Interp *interp; /* Current interpreter. */ 2647 int objc; /* Number of arguments. */ 2648 Tcl_Obj *CONST objv[]; /* Argument objects. */ 2649{ 2650 register WmInfo *wmPtr = winPtr->wmInfoPtr; 2651 register ProtocolHandler *protPtr, *prevPtr; 2652 Atom protocol; 2653 char *cmd; 2654 int cmdLength; 2655 2656 if ((objc < 3) || (objc > 5)) { 2657 Tcl_WrongNumArgs(interp, 2, objv, "window ?name? ?command?"); 2658 return TCL_ERROR; 2659 } 2660 if (objc == 3) { 2661 /* 2662 * Return a list of all defined protocols for the window. 2663 */ 2664 for (protPtr = wmPtr->protPtr; protPtr != NULL; 2665 protPtr = protPtr->nextPtr) { 2666 Tcl_AppendElement(interp, 2667 Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol)); 2668 } 2669 return TCL_OK; 2670 } 2671 protocol = Tk_InternAtom((Tk_Window) winPtr, Tcl_GetString(objv[3])); 2672 if (objc == 4) { 2673 /* 2674 * Return the command to handle a given protocol. 2675 */ 2676 for (protPtr = wmPtr->protPtr; protPtr != NULL; 2677 protPtr = protPtr->nextPtr) { 2678 if (protPtr->protocol == protocol) { 2679 Tcl_SetResult(interp, protPtr->command, TCL_STATIC); 2680 return TCL_OK; 2681 } 2682 } 2683 return TCL_OK; 2684 } 2685 2686 /* 2687 * Delete any current protocol handler, then create a new 2688 * one with the specified command, unless the command is 2689 * empty. 2690 */ 2691 2692 for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL; 2693 prevPtr = protPtr, protPtr = protPtr->nextPtr) { 2694 if (protPtr->protocol == protocol) { 2695 if (prevPtr == NULL) { 2696 wmPtr->protPtr = protPtr->nextPtr; 2697 } else { 2698 prevPtr->nextPtr = protPtr->nextPtr; 2699 } 2700 Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC); 2701 break; 2702 } 2703 } 2704 cmd = Tcl_GetStringFromObj(objv[4], &cmdLength); 2705 if (cmdLength > 0) { 2706 protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength)); 2707 protPtr->protocol = protocol; 2708 protPtr->nextPtr = wmPtr->protPtr; 2709 wmPtr->protPtr = protPtr; 2710 protPtr->interp = interp; 2711 strcpy(protPtr->command, cmd); 2712 } 2713 if (!(wmPtr->flags & WM_NEVER_MAPPED)) { 2714 UpdateWmProtocols(wmPtr); 2715 } 2716 return TCL_OK; 2717} 2718 2719/* 2720 *---------------------------------------------------------------------- 2721 * 2722 * WmResizableCmd -- 2723 * 2724 * This procedure is invoked to process the "wm resizable" Tcl command. 2725 * See the user documentation for details on what it does. 2726 * 2727 * Results: 2728 * A standard Tcl result. 2729 * 2730 * Side effects: 2731 * See the user documentation. 2732 * 2733 *---------------------------------------------------------------------- 2734 */ 2735 2736static int 2737WmResizableCmd(tkwin, winPtr, interp, objc, objv) 2738 Tk_Window tkwin; /* Main window of the application. */ 2739 TkWindow *winPtr; /* Toplevel to work with */ 2740 Tcl_Interp *interp; /* Current interpreter. */ 2741 int objc; /* Number of arguments. */ 2742 Tcl_Obj *CONST objv[]; /* Argument objects. */ 2743{ 2744 register WmInfo *wmPtr = winPtr->wmInfoPtr; 2745 int width, height; 2746 2747 if ((objc != 3) && (objc != 5)) { 2748 Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?"); 2749 return TCL_ERROR; 2750 } 2751 if (objc == 3) { 2752 char buf[TCL_INTEGER_SPACE * 2]; 2753 2754 sprintf(buf, "%d %d", 2755 (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1, 2756 (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1); 2757 Tcl_SetResult(interp, buf, TCL_VOLATILE); 2758 return TCL_OK; 2759 } 2760 if ((Tcl_GetBooleanFromObj(interp, objv[3], &width) != TCL_OK) 2761 || (Tcl_GetBooleanFromObj(interp, objv[4], &height) != TCL_OK)) { 2762 return TCL_ERROR; 2763 } 2764 if (width) { 2765 wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE; 2766 } else { 2767 wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE; 2768 } 2769 if (height) { 2770 wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE; 2771 } else { 2772 wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE; 2773 } 2774 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 2775 WmUpdateGeom(wmPtr, winPtr); 2776 return TCL_OK; 2777} 2778 2779/* 2780 *---------------------------------------------------------------------- 2781 * 2782 * WmSizefromCmd -- 2783 * 2784 * This procedure is invoked to process the "wm sizefrom" Tcl command. 2785 * See the user documentation for details on what it does. 2786 * 2787 * Results: 2788 * A standard Tcl result. 2789 * 2790 * Side effects: 2791 * See the user documentation. 2792 * 2793 *---------------------------------------------------------------------- 2794 */ 2795 2796static int 2797WmSizefromCmd(tkwin, winPtr, interp, objc, objv) 2798 Tk_Window tkwin; /* Main window of the application. */ 2799 TkWindow *winPtr; /* Toplevel to work with */ 2800 Tcl_Interp *interp; /* Current interpreter. */ 2801 int objc; /* Number of arguments. */ 2802 Tcl_Obj *CONST objv[]; /* Argument objects. */ 2803{ 2804 register WmInfo *wmPtr = winPtr->wmInfoPtr; 2805 static CONST char *optionStrings[] = { 2806 "program", "user", (char *) NULL }; 2807 enum options { 2808 OPT_PROGRAM, OPT_USER }; 2809 int index; 2810 2811 if ((objc != 3) && (objc != 4)) { 2812 Tcl_WrongNumArgs(interp, 2, objv, "window ?user|program?"); 2813 return TCL_ERROR; 2814 } 2815 if (objc == 3) { 2816 if (wmPtr->sizeHintsFlags & USSize) { 2817 Tcl_SetResult(interp, "user", TCL_STATIC); 2818 } else if (wmPtr->sizeHintsFlags & PSize) { 2819 Tcl_SetResult(interp, "program", TCL_STATIC); 2820 } 2821 return TCL_OK; 2822 } 2823 2824 if (*Tcl_GetString(objv[3]) == '\0') { 2825 wmPtr->sizeHintsFlags &= ~(USSize|PSize); 2826 } else { 2827 if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0, 2828 &index) != TCL_OK) { 2829 return TCL_ERROR; 2830 } 2831 if (index == OPT_USER) { 2832 wmPtr->sizeHintsFlags &= ~PSize; 2833 wmPtr->sizeHintsFlags |= USSize; 2834 } else { /* OPT_PROGRAM */ 2835 wmPtr->sizeHintsFlags &= ~USSize; 2836 wmPtr->sizeHintsFlags |= PSize; 2837 } 2838 } 2839 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 2840 WmUpdateGeom(wmPtr, winPtr); 2841 return TCL_OK; 2842} 2843 2844/* 2845 *---------------------------------------------------------------------- 2846 * 2847 * WmStackorderCmd -- 2848 * 2849 * This procedure is invoked to process the "wm stackorder" Tcl command. 2850 * See the user documentation for details on what it does. 2851 * 2852 * Results: 2853 * A standard Tcl result. 2854 * 2855 * Side effects: 2856 * See the user documentation. 2857 * 2858 *---------------------------------------------------------------------- 2859 */ 2860 2861static int 2862WmStackorderCmd(tkwin, winPtr, interp, objc, objv) 2863 Tk_Window tkwin; /* Main window of the application. */ 2864 TkWindow *winPtr; /* Toplevel to work with */ 2865 Tcl_Interp *interp; /* Current interpreter. */ 2866 int objc; /* Number of arguments. */ 2867 Tcl_Obj *CONST objv[]; /* Argument objects. */ 2868{ 2869 TkWindow **windows, **window_ptr; 2870 static CONST char *optionStrings[] = { 2871 "isabove", "isbelow", (char *) NULL }; 2872 enum options { 2873 OPT_ISABOVE, OPT_ISBELOW }; 2874 int index; 2875 2876 if ((objc != 3) && (objc != 5)) { 2877 Tcl_WrongNumArgs(interp, 2, objv, "window ?isabove|isbelow window?"); 2878 return TCL_ERROR; 2879 } 2880 2881 if (objc == 3) { 2882 windows = TkWmStackorderToplevel(winPtr); 2883 if (windows == NULL) { 2884 Tcl_Panic("TkWmStackorderToplevel failed"); 2885 } else { 2886 for (window_ptr = windows; *window_ptr ; window_ptr++) { 2887 Tcl_AppendElement(interp, (*window_ptr)->pathName); 2888 } 2889 ckfree((char *) windows); 2890 return TCL_OK; 2891 } 2892 } else { 2893 TkWindow *winPtr2; 2894 int index1=-1, index2=-1, result; 2895 2896 if (TkGetWindowFromObj(interp, tkwin, objv[4], (Tk_Window *) &winPtr2) 2897 != TCL_OK) { 2898 return TCL_ERROR; 2899 } 2900 2901 if (!Tk_IsTopLevel(winPtr2)) { 2902 Tcl_AppendResult(interp, "window \"", winPtr2->pathName, 2903 "\" isn't a top-level window", (char *) NULL); 2904 return TCL_ERROR; 2905 } 2906 2907 if (!Tk_IsMapped(winPtr)) { 2908 Tcl_AppendResult(interp, "window \"", winPtr->pathName, 2909 "\" isn't mapped", (char *) NULL); 2910 return TCL_ERROR; 2911 } 2912 2913 if (!Tk_IsMapped(winPtr2)) { 2914 Tcl_AppendResult(interp, "window \"", winPtr2->pathName, 2915 "\" isn't mapped", (char *) NULL); 2916 return TCL_ERROR; 2917 } 2918 2919 /* 2920 * Lookup stacking order of all toplevels that are children 2921 * of "." and find the position of winPtr and winPtr2 2922 * in the stacking order. 2923 */ 2924 2925 windows = TkWmStackorderToplevel(winPtr->mainPtr->winPtr); 2926 2927 if (windows == NULL) { 2928 Tcl_AppendResult(interp, "TkWmStackorderToplevel failed", 2929 (char *) NULL); 2930 return TCL_ERROR; 2931 } else { 2932 for (window_ptr = windows; *window_ptr ; window_ptr++) { 2933 if (*window_ptr == winPtr) 2934 index1 = (window_ptr - windows); 2935 if (*window_ptr == winPtr2) 2936 index2 = (window_ptr - windows); 2937 } 2938 if (index1 == -1) 2939 Tcl_Panic("winPtr window not found"); 2940 if (index2 == -1) 2941 Tcl_Panic("winPtr2 window not found"); 2942 2943 ckfree((char *) windows); 2944 } 2945 2946 if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0, 2947 &index) != TCL_OK) { 2948 return TCL_ERROR; 2949 } 2950 if (index == OPT_ISABOVE) { 2951 result = index1 > index2; 2952 } else { /* OPT_ISBELOW */ 2953 result = index1 < index2; 2954 } 2955 Tcl_SetIntObj(Tcl_GetObjResult(interp), result); 2956 return TCL_OK; 2957 } 2958 return TCL_OK; 2959} 2960 2961/* 2962 *---------------------------------------------------------------------- 2963 * 2964 * WmStateCmd -- 2965 * 2966 * This procedure is invoked to process the "wm state" Tcl command. 2967 * See the user documentation for details on what it does. 2968 * 2969 * Results: 2970 * A standard Tcl result. 2971 * 2972 * Side effects: 2973 * See the user documentation. 2974 * 2975 *---------------------------------------------------------------------- 2976 */ 2977 2978static int 2979WmStateCmd(tkwin, winPtr, interp, objc, objv) 2980 Tk_Window tkwin; /* Main window of the application. */ 2981 TkWindow *winPtr; /* Toplevel to work with */ 2982 Tcl_Interp *interp; /* Current interpreter. */ 2983 int objc; /* Number of arguments. */ 2984 Tcl_Obj *CONST objv[]; /* Argument objects. */ 2985{ 2986 register WmInfo *wmPtr = winPtr->wmInfoPtr; 2987 static CONST char *optionStrings[] = { 2988 "normal", "iconic", "withdrawn", (char *) NULL }; 2989 enum options { 2990 OPT_NORMAL, OPT_ICONIC, OPT_WITHDRAWN }; 2991 int index; 2992 2993 if ((objc < 3) || (objc > 4)) { 2994 Tcl_WrongNumArgs(interp, 2, objv, "window ?state?"); 2995 return TCL_ERROR; 2996 } 2997 if (objc == 4) { 2998 if (wmPtr->iconFor != NULL) { 2999 Tcl_AppendResult(interp, "can't change state of ", 3000 Tcl_GetString(objv[2]), 3001 ": it is an icon for ", Tk_PathName(wmPtr->iconFor), 3002 (char *) NULL); 3003 return TCL_ERROR; 3004 } 3005 3006 if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0, 3007 &index) != TCL_OK) { 3008 return TCL_ERROR; 3009 } 3010 3011 if (index == OPT_NORMAL) { 3012 wmPtr->flags &= ~WM_WITHDRAWN; 3013 (void) TkpWmSetState(winPtr, NormalState); 3014 } else if (index == OPT_ICONIC) { 3015 if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) { 3016 Tcl_AppendResult(interp, "can't iconify \"", 3017 winPtr->pathName, 3018 "\": override-redirect flag is set", 3019 (char *) NULL); 3020 return TCL_ERROR; 3021 } 3022 if (wmPtr->masterPtr != NULL) { 3023 Tcl_AppendResult(interp, "can't iconify \"", 3024 winPtr->pathName, 3025 "\": it is a transient", (char *) NULL); 3026 return TCL_ERROR; 3027 } 3028 if (TkpWmSetState(winPtr, IconicState) == 0) { 3029 Tcl_SetResult(interp, 3030 "couldn't send iconify message to window manager", 3031 TCL_STATIC); 3032 return TCL_ERROR; 3033 } 3034 } else { /* OPT_WITHDRAWN */ 3035 wmPtr->flags |= WM_WITHDRAWN; 3036 if (TkpWmSetState(winPtr, WithdrawnState) == 0) { 3037 Tcl_SetResult(interp, 3038 "couldn't send withdraw message to window manager", 3039 TCL_STATIC); 3040 return TCL_ERROR; 3041 } 3042 } 3043 } else { 3044 if (wmPtr->iconFor != NULL) { 3045 Tcl_SetResult(interp, "icon", TCL_STATIC); 3046 } else if (wmPtr->withdrawn) { 3047 Tcl_SetResult(interp, "withdrawn", TCL_STATIC); 3048 } else if (Tk_IsMapped((Tk_Window) winPtr) 3049 || ((wmPtr->flags & WM_NEVER_MAPPED) 3050 && (wmPtr->hints.initial_state == NormalState))) { 3051 Tcl_SetResult(interp, "normal", TCL_STATIC); 3052 } else { 3053 Tcl_SetResult(interp, "iconic", TCL_STATIC); 3054 } 3055 } 3056 return TCL_OK; 3057} 3058 3059/* 3060 *---------------------------------------------------------------------- 3061 * 3062 * WmTitleCmd -- 3063 * 3064 * This procedure is invoked to process the "wm title" Tcl command. 3065 * See the user documentation for details on what it does. 3066 * 3067 * Results: 3068 * A standard Tcl result. 3069 * 3070 * Side effects: 3071 * See the user documentation. 3072 * 3073 *---------------------------------------------------------------------- 3074 */ 3075 3076static int 3077WmTitleCmd(tkwin, winPtr, interp, objc, objv) 3078 Tk_Window tkwin; /* Main window of the application. */ 3079 TkWindow *winPtr; /* Toplevel to work with */ 3080 Tcl_Interp *interp; /* Current interpreter. */ 3081 int objc; /* Number of arguments. */ 3082 Tcl_Obj *CONST objv[]; /* Argument objects. */ 3083{ 3084 register WmInfo *wmPtr = winPtr->wmInfoPtr; 3085 char *argv3; 3086 int length; 3087 3088 if (objc > 4) { 3089 Tcl_WrongNumArgs(interp, 2, objv, "window ?newTitle?"); 3090 return TCL_ERROR; 3091 } 3092 if (objc == 3) { 3093 Tcl_SetResult(interp, (char *) 3094 ((wmPtr->title != NULL) ? wmPtr->title : winPtr->nameUid), 3095 TCL_STATIC); 3096 return TCL_OK; 3097 } else { 3098 if (wmPtr->title != NULL) { 3099 ckfree((char *) wmPtr->title); 3100 } 3101 argv3 = Tcl_GetStringFromObj(objv[3], &length); 3102 wmPtr->title = ckalloc((unsigned) (length + 1)); 3103 strcpy(wmPtr->title, argv3); 3104 3105 if (!(wmPtr->flags & WM_NEVER_MAPPED)) { 3106 UpdateTitle(winPtr); 3107 } 3108 } 3109 return TCL_OK; 3110} 3111 3112/* 3113 *---------------------------------------------------------------------- 3114 * 3115 * WmTransientCmd -- 3116 * 3117 * This procedure is invoked to process the "wm transient" Tcl command. 3118 * See the user documentation for details on what it does. 3119 * 3120 * Results: 3121 * A standard Tcl result. 3122 * 3123 * Side effects: 3124 * See the user documentation. 3125 * 3126 *---------------------------------------------------------------------- 3127 */ 3128 3129static int 3130WmTransientCmd(tkwin, winPtr, interp, objc, objv) 3131 Tk_Window tkwin; /* Main window of the application. */ 3132 TkWindow *winPtr; /* Toplevel to work with */ 3133 Tcl_Interp *interp; /* Current interpreter. */ 3134 int objc; /* Number of arguments. */ 3135 Tcl_Obj *CONST objv[]; /* Argument objects. */ 3136{ 3137 register WmInfo *wmPtr = winPtr->wmInfoPtr; 3138 TkWindow *masterPtr = wmPtr->masterPtr; 3139 WmInfo *wmPtr2; 3140 3141 if ((objc != 3) && (objc != 4)) { 3142 Tcl_WrongNumArgs(interp, 2, objv, "window ?master?"); 3143 return TCL_ERROR; 3144 } 3145 if (objc == 3) { 3146 if (masterPtr != NULL) { 3147 Tcl_SetResult(interp, Tk_PathName(masterPtr), TCL_STATIC); 3148 } 3149 return TCL_OK; 3150 } 3151 if (Tcl_GetString(objv[3])[0] == '\0') { 3152 if (masterPtr != NULL) { 3153 /* 3154 * If we had a master, tell them that we aren't tied 3155 * to them anymore 3156 */ 3157 3158 masterPtr->wmInfoPtr->numTransients--; 3159 Tk_DeleteEventHandler((Tk_Window) masterPtr, 3160 StructureNotifyMask, 3161 WmWaitMapProc, (ClientData) winPtr); 3162 3163 /* FIXME: Need a call like Win32's UpdateWrapper() so 3164 we can recreate the wrapper and get rid of the 3165 transient window decorations. */ 3166 } 3167 3168 wmPtr->masterPtr = NULL; 3169 } else { 3170 if (TkGetWindowFromObj(interp, tkwin, objv[3], 3171 (Tk_Window *) &masterPtr) != TCL_OK) { 3172 return TCL_ERROR; 3173 } 3174 while (!Tk_TopWinHierarchy(masterPtr)) { 3175 /* 3176 * Ensure that the master window is actually a Tk toplevel. 3177 */ 3178 3179 masterPtr = masterPtr->parentPtr; 3180 } 3181 Tk_MakeWindowExist((Tk_Window) masterPtr); 3182 3183 if (wmPtr->iconFor != NULL) { 3184 Tcl_AppendResult(interp, "can't make \"", 3185 Tcl_GetString(objv[2]), 3186 "\" a transient: it is an icon for ", 3187 Tk_PathName(wmPtr->iconFor), 3188 (char *) NULL); 3189 return TCL_ERROR; 3190 } 3191 3192 wmPtr2 = masterPtr->wmInfoPtr; 3193 if (wmPtr2->wrapperPtr == NULL) { 3194 CreateWrapper(wmPtr2); 3195 } 3196 3197 if (wmPtr2->iconFor != NULL) { 3198 Tcl_AppendResult(interp, "can't make \"", 3199 Tcl_GetString(objv[3]), 3200 "\" a master: it is an icon for ", 3201 Tk_PathName(wmPtr2->iconFor), 3202 (char *) NULL); 3203 return TCL_ERROR; 3204 } 3205 3206 if (masterPtr == winPtr) { 3207 Tcl_AppendResult(interp, "can't make \"", Tk_PathName(winPtr), 3208 "\" its own master", 3209 (char *) NULL); 3210 return TCL_ERROR; 3211 } else if (masterPtr != wmPtr->masterPtr) { 3212 /* 3213 * Remove old master map/unmap binding before setting 3214 * the new master. The event handler will ensure that 3215 * transient states reflect the state of the master. 3216 */ 3217 3218 if (wmPtr->masterPtr != NULL) { 3219 wmPtr->masterPtr->wmInfoPtr->numTransients--; 3220 Tk_DeleteEventHandler((Tk_Window) wmPtr->masterPtr, 3221 StructureNotifyMask, 3222 WmWaitMapProc, (ClientData) winPtr); 3223 } 3224 3225 masterPtr->wmInfoPtr->numTransients++; 3226 Tk_CreateEventHandler((Tk_Window) masterPtr, 3227 StructureNotifyMask, 3228 WmWaitMapProc, (ClientData) winPtr); 3229 3230 wmPtr->masterPtr = masterPtr; 3231 } 3232 } 3233 if (!(wmPtr->flags & WM_NEVER_MAPPED)) { 3234 if (wmPtr->masterPtr != NULL && !Tk_IsMapped(wmPtr->masterPtr)) { 3235 if (TkpWmSetState(winPtr, WithdrawnState) == 0) { 3236 Tcl_SetResult(interp, 3237 "couldn't send withdraw message to window manager", 3238 TCL_STATIC); 3239 return TCL_ERROR; 3240 } 3241 } else { 3242 if (wmPtr->masterPtr != NULL) { 3243 XSetTransientForHint(winPtr->display, wmPtr->wrapperPtr->window, 3244 wmPtr->masterPtr->wmInfoPtr->wrapperPtr->window); 3245 } else { 3246 XDeleteProperty(winPtr->display, wmPtr->wrapperPtr->window, 3247 Tk_InternAtom((Tk_Window)winPtr, "WM_TRANSIENT_FOR")); 3248 } 3249 } 3250 } 3251 return TCL_OK; 3252} 3253 3254/* 3255 *---------------------------------------------------------------------- 3256 * 3257 * WmWithdrawCmd -- 3258 * 3259 * This procedure is invoked to process the "wm withdraw" Tcl command. 3260 * See the user documentation for details on what it does. 3261 * 3262 * Results: 3263 * A standard Tcl result. 3264 * 3265 * Side effects: 3266 * See the user documentation. 3267 * 3268 *---------------------------------------------------------------------- 3269 */ 3270 3271static int 3272WmWithdrawCmd(tkwin, winPtr, interp, objc, objv) 3273 Tk_Window tkwin; /* Main window of the application. */ 3274 TkWindow *winPtr; /* Toplevel to work with */ 3275 Tcl_Interp *interp; /* Current interpreter. */ 3276 int objc; /* Number of arguments. */ 3277 Tcl_Obj *CONST objv[]; /* Argument objects. */ 3278{ 3279 register WmInfo *wmPtr = winPtr->wmInfoPtr; 3280 3281 if (objc != 3) { 3282 Tcl_WrongNumArgs(interp, 2, objv, "window"); 3283 return TCL_ERROR; 3284 } 3285 if (wmPtr->iconFor != NULL) { 3286 Tcl_AppendResult(interp, "can't withdraw ", Tcl_GetString(objv[2]), 3287 ": it is an icon for ", Tk_PathName(wmPtr->iconFor), 3288 (char *) NULL); 3289 return TCL_ERROR; 3290 } 3291 wmPtr->flags |= WM_WITHDRAWN; 3292 if (TkpWmSetState(winPtr, WithdrawnState) == 0) { 3293 Tcl_SetResult(interp, 3294 "couldn't send withdraw message to window manager", 3295 TCL_STATIC); 3296 return TCL_ERROR; 3297 } 3298 return TCL_OK; 3299} 3300 3301/* 3302 * Invoked by those wm subcommands that affect geometry. 3303 * Schedules a geometry update. 3304 */ 3305static void 3306WmUpdateGeom(wmPtr, winPtr) 3307 WmInfo *wmPtr; 3308 TkWindow *winPtr; 3309{ 3310 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { 3311 Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr); 3312 wmPtr->flags |= WM_UPDATE_PENDING; 3313 } 3314} 3315 3316/* 3317 * Invoked when a MapNotify or UnmapNotify event is delivered for a 3318 * toplevel that is the master of a transient toplevel. 3319 */ 3320static void 3321WmWaitMapProc(clientData, eventPtr) 3322 ClientData clientData; /* Pointer to window. */ 3323 XEvent *eventPtr; /* Information about event. */ 3324{ 3325 TkWindow *winPtr = (TkWindow *) clientData; 3326 TkWindow *masterPtr = winPtr->wmInfoPtr->masterPtr; 3327 3328 if (masterPtr == NULL) 3329 return; 3330 3331 if (eventPtr->type == MapNotify) { 3332 if (!(winPtr->wmInfoPtr->flags & WM_WITHDRAWN)) 3333 (void) TkpWmSetState(winPtr, NormalState); 3334 } else if (eventPtr->type == UnmapNotify) { 3335 (void) TkpWmSetState(winPtr, WithdrawnState); 3336 } 3337} 3338 3339/* 3340 *---------------------------------------------------------------------- 3341 * 3342 * Tk_SetGrid -- 3343 * 3344 * This procedure is invoked by a widget when it wishes to set a grid 3345 * coordinate system that controls the size of a top-level window. 3346 * It provides a C interface equivalent to the "wm grid" command and 3347 * is usually asscoiated with the -setgrid option. 3348 * 3349 * Results: 3350 * None. 3351 * 3352 * Side effects: 3353 * Grid-related information will be passed to the window manager, so 3354 * that the top-level window associated with tkwin will resize on 3355 * even grid units. If some other window already controls gridding 3356 * for the top-level window then this procedure call has no effect. 3357 * 3358 *---------------------------------------------------------------------- 3359 */ 3360 3361void 3362Tk_SetGrid(tkwin, reqWidth, reqHeight, widthInc, heightInc) 3363 Tk_Window tkwin; /* Token for window. New window mgr info 3364 * will be posted for the top-level window 3365 * associated with this window. */ 3366 int reqWidth; /* Width (in grid units) corresponding to 3367 * the requested geometry for tkwin. */ 3368 int reqHeight; /* Height (in grid units) corresponding to 3369 * the requested geometry for tkwin. */ 3370 int widthInc, heightInc; /* Pixel increments corresponding to a 3371 * change of one grid unit. */ 3372{ 3373 TkWindow *winPtr = (TkWindow *) tkwin; 3374 register WmInfo *wmPtr; 3375 3376 /* 3377 * Ensure widthInc and heightInc are greater than 0 3378 */ 3379 if (widthInc <= 0) { 3380 widthInc = 1; 3381 } 3382 if (heightInc <= 0) { 3383 heightInc = 1; 3384 } 3385 3386 /* 3387 * Find the top-level window for tkwin, plus the window manager 3388 * information. 3389 */ 3390 3391 while (!(winPtr->flags & TK_TOP_HIERARCHY)) { 3392 winPtr = winPtr->parentPtr; 3393 if (winPtr == NULL) { 3394 /* 3395 * The window is being deleted... just skip this operation. 3396 */ 3397 3398 return; 3399 } 3400 } 3401 wmPtr = winPtr->wmInfoPtr; 3402 if (wmPtr == NULL) { 3403 return; 3404 } 3405 3406 if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) { 3407 return; 3408 } 3409 3410 if ((wmPtr->reqGridWidth == reqWidth) 3411 && (wmPtr->reqGridHeight == reqHeight) 3412 && (wmPtr->widthInc == widthInc) 3413 && (wmPtr->heightInc == heightInc) 3414 && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc)) 3415 == (PBaseSize|PResizeInc))) { 3416 return; 3417 } 3418 3419 /* 3420 * If gridding was previously off, then forget about any window 3421 * size requests made by the user or via "wm geometry": these are 3422 * in pixel units and there's no easy way to translate them to 3423 * grid units since the new requested size of the top-level window in 3424 * pixels may not yet have been registered yet (it may filter up 3425 * the hierarchy in DoWhenIdle handlers). However, if the window 3426 * has never been mapped yet then just leave the window size alone: 3427 * assume that it is intended to be in grid units but just happened 3428 * to have been specified before this procedure was called. 3429 */ 3430 3431 if ((wmPtr->gridWin == NULL) && !(wmPtr->flags & WM_NEVER_MAPPED)) { 3432 wmPtr->width = -1; 3433 wmPtr->height = -1; 3434 } 3435 3436 /* 3437 * Set the new gridding information, and start the process of passing 3438 * all of this information to the window manager. 3439 */ 3440 3441 wmPtr->gridWin = tkwin; 3442 wmPtr->reqGridWidth = reqWidth; 3443 wmPtr->reqGridHeight = reqHeight; 3444 wmPtr->widthInc = widthInc; 3445 wmPtr->heightInc = heightInc; 3446 wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc; 3447 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 3448 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { 3449 Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr); 3450 wmPtr->flags |= WM_UPDATE_PENDING; 3451 } 3452} 3453 3454/* 3455 *---------------------------------------------------------------------- 3456 * 3457 * Tk_UnsetGrid -- 3458 * 3459 * This procedure cancels the effect of a previous call 3460 * to Tk_SetGrid. 3461 * 3462 * Results: 3463 * None. 3464 * 3465 * Side effects: 3466 * If tkwin currently controls gridding for its top-level window, 3467 * gridding is cancelled for that top-level window; if some other 3468 * window controls gridding then this procedure has no effect. 3469 * 3470 *---------------------------------------------------------------------- 3471 */ 3472 3473void 3474Tk_UnsetGrid(tkwin) 3475 Tk_Window tkwin; /* Token for window that is currently 3476 * controlling gridding. */ 3477{ 3478 TkWindow *winPtr = (TkWindow *) tkwin; 3479 register WmInfo *wmPtr; 3480 3481 /* 3482 * Find the top-level window for tkwin, plus the window manager 3483 * information. 3484 */ 3485 3486 while (!(winPtr->flags & TK_TOP_HIERARCHY)) { 3487 winPtr = winPtr->parentPtr; 3488 if (winPtr == NULL) { 3489 /* 3490 * The window is being deleted... just skip this operation. 3491 */ 3492 3493 return; 3494 } 3495 } 3496 wmPtr = winPtr->wmInfoPtr; 3497 if (wmPtr == NULL) { 3498 return; 3499 } 3500 3501 if (tkwin != wmPtr->gridWin) { 3502 return; 3503 } 3504 3505 wmPtr->gridWin = NULL; 3506 wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc); 3507 if (wmPtr->width != -1) { 3508 wmPtr->width = winPtr->reqWidth + (wmPtr->width 3509 - wmPtr->reqGridWidth)*wmPtr->widthInc; 3510 wmPtr->height = winPtr->reqHeight + (wmPtr->height 3511 - wmPtr->reqGridHeight)*wmPtr->heightInc; 3512 } 3513 wmPtr->widthInc = 1; 3514 wmPtr->heightInc = 1; 3515 3516 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 3517 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { 3518 Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr); 3519 wmPtr->flags |= WM_UPDATE_PENDING; 3520 } 3521} 3522 3523/* 3524 *---------------------------------------------------------------------- 3525 * 3526 * ConfigureEvent -- 3527 * 3528 * This procedure is called to handle ConfigureNotify events on 3529 * wrapper windows. 3530 * 3531 * Results: 3532 * None. 3533 * 3534 * Side effects: 3535 * Information gets updated in the WmInfo structure for the window 3536 * and the toplevel itself gets repositioned within the wrapper. 3537 * 3538 *---------------------------------------------------------------------- 3539 */ 3540 3541static void 3542ConfigureEvent(wmPtr, configEventPtr) 3543 WmInfo *wmPtr; /* Information about toplevel window. */ 3544 XConfigureEvent *configEventPtr; /* Event that just occurred for 3545 * wmPtr->wrapperPtr. */ 3546{ 3547 TkWindow *wrapperPtr = wmPtr->wrapperPtr; 3548 TkWindow *winPtr = wmPtr->winPtr; 3549 TkDisplay *dispPtr = wmPtr->winPtr->dispPtr; 3550 Tk_ErrorHandler handler; 3551 3552 /* 3553 * Update size information from the event. There are a couple of 3554 * tricky points here: 3555 * 3556 * 1. If the user changed the size externally then set wmPtr->width 3557 * and wmPtr->height just as if a "wm geometry" command had been 3558 * invoked with the same information. 3559 * 2. However, if the size is changing in response to a request 3560 * coming from us (WM_SYNC_PENDING is set), then don't set wmPtr->width 3561 * or wmPtr->height if they were previously -1 (otherwise the 3562 * window will stop tracking geometry manager requests). 3563 */ 3564 3565 if (((wrapperPtr->changes.width != configEventPtr->width) 3566 || (wrapperPtr->changes.height != configEventPtr->height)) 3567 && !(wmPtr->flags & WM_SYNC_PENDING)){ 3568 if (dispPtr->flags & TK_DISPLAY_WM_TRACING) { 3569 printf("TopLevelEventProc: user changed %s size to %dx%d\n", 3570 winPtr->pathName, configEventPtr->width, 3571 configEventPtr->height); 3572 } 3573 if ((wmPtr->width == -1) 3574 && (configEventPtr->width == winPtr->reqWidth)) { 3575 /* 3576 * Don't set external width, since the user didn't change it 3577 * from what the widgets asked for. 3578 */ 3579 } else { 3580 /* 3581 * Note: if this window is embedded then don't set the external 3582 * size, since it came from the containing application, not the 3583 * user. In this case we want to keep sending our size requests 3584 * to the containing application; if the user fixes the size 3585 * of that application then it will still percolate down to us 3586 * in the right way. 3587 */ 3588 3589 if (!(winPtr->flags & TK_EMBEDDED)) { 3590 if (wmPtr->gridWin != NULL) { 3591 wmPtr->width = wmPtr->reqGridWidth 3592 + (configEventPtr->width 3593 - winPtr->reqWidth)/wmPtr->widthInc; 3594 if (wmPtr->width < 0) { 3595 wmPtr->width = 0; 3596 } 3597 } else { 3598 wmPtr->width = configEventPtr->width; 3599 } 3600 } 3601 } 3602 if ((wmPtr->height == -1) 3603 && (configEventPtr->height == 3604 (winPtr->reqHeight + wmPtr->menuHeight))) { 3605 /* 3606 * Don't set external height, since the user didn't change it 3607 * from what the widgets asked for. 3608 */ 3609 } else { 3610 /* 3611 * See note for wmPtr->width about not setting external size 3612 * for embedded windows. 3613 */ 3614 3615 if (!(winPtr->flags & TK_EMBEDDED)) { 3616 if (wmPtr->gridWin != NULL) { 3617 wmPtr->height = wmPtr->reqGridHeight 3618 + (configEventPtr->height - wmPtr->menuHeight 3619 - winPtr->reqHeight)/wmPtr->heightInc; 3620 if (wmPtr->height < 0) { 3621 wmPtr->height = 0; 3622 } 3623 } else { 3624 wmPtr->height = configEventPtr->height - wmPtr->menuHeight; 3625 } 3626 } 3627 } 3628 wmPtr->configWidth = configEventPtr->width; 3629 wmPtr->configHeight = configEventPtr->height; 3630 } 3631 3632 if (dispPtr->flags & TK_DISPLAY_WM_TRACING) { 3633 printf("ConfigureEvent: %s x = %d y = %d, width = %d, height = %d\n", 3634 winPtr->pathName, configEventPtr->x, configEventPtr->y, 3635 configEventPtr->width, configEventPtr->height); 3636 printf(" send_event = %d, serial = %ld (win %p, wrapper %p)\n", 3637 configEventPtr->send_event, configEventPtr->serial, 3638 winPtr, wrapperPtr); 3639 } 3640 wrapperPtr->changes.width = configEventPtr->width; 3641 wrapperPtr->changes.height = configEventPtr->height; 3642 wrapperPtr->changes.border_width = configEventPtr->border_width; 3643 wrapperPtr->changes.sibling = configEventPtr->above; 3644 wrapperPtr->changes.stack_mode = Above; 3645 3646 /* 3647 * Reparenting window managers make life difficult. If the 3648 * window manager reparents a top-level window then the x and y 3649 * information that comes in events for the window is wrong: 3650 * it gives the location of the window inside its decorative 3651 * parent, rather than the location of the window in root 3652 * coordinates, which is what we want. Window managers 3653 * are supposed to send synthetic events with the correct 3654 * information, but ICCCM doesn't require them to do this 3655 * under all conditions, and the information provided doesn't 3656 * include everything we need here. So, the code below 3657 * maintains a bunch of information about the parent window. 3658 * If the window hasn't been reparented, we pretend that 3659 * there is a parent shrink-wrapped around the window. 3660 */ 3661 3662 if (dispPtr->flags & TK_DISPLAY_WM_TRACING) { 3663 printf(" %s parent == %p, above %p\n", 3664 winPtr->pathName, (void *) wmPtr->reparent, 3665 (void *) configEventPtr->above); 3666 } 3667 3668 if ((wmPtr->reparent == None) || !ComputeReparentGeometry(wmPtr)) { 3669 wmPtr->parentWidth = configEventPtr->width 3670 + 2*configEventPtr->border_width; 3671 wmPtr->parentHeight = configEventPtr->height 3672 + 2*configEventPtr->border_width; 3673 wrapperPtr->changes.x = wmPtr->x = configEventPtr->x; 3674 wrapperPtr->changes.y = wmPtr->y = configEventPtr->y; 3675 if (wmPtr->flags & WM_NEGATIVE_X) { 3676 wmPtr->x = wmPtr->vRootWidth - (wmPtr->x + wmPtr->parentWidth); 3677 } 3678 if (wmPtr->flags & WM_NEGATIVE_Y) { 3679 wmPtr->y = wmPtr->vRootHeight - (wmPtr->y + wmPtr->parentHeight); 3680 } 3681 } 3682 3683 /* 3684 * Make sure that the toplevel and menubar are properly positioned within 3685 * the wrapper. If the menuHeight happens to be zero, we'll get a 3686 * BadValue X error that we want to ignore [Bug: 3377] 3687 */ 3688 handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1, 3689 (Tk_ErrorProc *) NULL, (ClientData) NULL); 3690 XMoveResizeWindow(winPtr->display, winPtr->window, 0, 3691 wmPtr->menuHeight, (unsigned) wrapperPtr->changes.width, 3692 (unsigned) (wrapperPtr->changes.height - wmPtr->menuHeight)); 3693 Tk_DeleteErrorHandler(handler); 3694 if ((wmPtr->menubar != NULL) 3695 && ((Tk_Width(wmPtr->menubar) != wrapperPtr->changes.width) 3696 || (Tk_Height(wmPtr->menubar) != wmPtr->menuHeight))) { 3697 Tk_MoveResizeWindow(wmPtr->menubar, 0, 0, wrapperPtr->changes.width, 3698 wmPtr->menuHeight); 3699 } 3700 3701 /* 3702 * Update the coordinates in the toplevel (they should refer to the 3703 * position in root window coordinates, not the coordinates of the 3704 * wrapper window). Then synthesize a ConfigureNotify event to tell 3705 * the application about the change. 3706 */ 3707 3708 winPtr->changes.x = wrapperPtr->changes.x; 3709 winPtr->changes.y = wrapperPtr->changes.y + wmPtr->menuHeight; 3710 winPtr->changes.width = wrapperPtr->changes.width; 3711 winPtr->changes.height = wrapperPtr->changes.height - wmPtr->menuHeight; 3712 TkDoConfigureNotify(winPtr); 3713} 3714 3715/* 3716 *---------------------------------------------------------------------- 3717 * 3718 * ReparentEvent -- 3719 * 3720 * This procedure is called to handle ReparentNotify events on 3721 * wrapper windows. 3722 * 3723 * Results: 3724 * None. 3725 * 3726 * Side effects: 3727 * Information gets updated in the WmInfo structure for the window. 3728 * 3729 *---------------------------------------------------------------------- 3730 */ 3731 3732static void 3733ReparentEvent(wmPtr, reparentEventPtr) 3734 WmInfo *wmPtr; /* Information about toplevel window. */ 3735 XReparentEvent *reparentEventPtr; /* Event that just occurred for 3736 * wmPtr->wrapperPtr. */ 3737{ 3738 TkWindow *wrapperPtr = wmPtr->wrapperPtr; 3739 Window vRoot, ancestor, *children, dummy2, *virtualRootPtr; 3740 Atom actualType; 3741 int actualFormat; 3742 unsigned long numItems, bytesAfter; 3743 unsigned int dummy; 3744 Tk_ErrorHandler handler; 3745 TkDisplay *dispPtr = wmPtr->winPtr->dispPtr; 3746 3747 /* 3748 * Identify the root window for wrapperPtr. This is tricky because of 3749 * virtual root window managers like tvtwm. If the window has a 3750 * property named __SWM_ROOT or __WM_ROOT then this property gives 3751 * the id for a virtual root window that should be used instead of 3752 * the root window of the screen. 3753 */ 3754 3755 vRoot = RootWindow(wrapperPtr->display, wrapperPtr->screenNum); 3756 wmPtr->vRoot = None; 3757 handler = Tk_CreateErrorHandler(wrapperPtr->display, -1, -1, -1, 3758 (Tk_ErrorProc *) NULL, (ClientData) NULL); 3759 if (((XGetWindowProperty(wrapperPtr->display, wrapperPtr->window, 3760 Tk_InternAtom((Tk_Window) wrapperPtr, "__WM_ROOT"), 0, (long) 1, 3761 False, XA_WINDOW, &actualType, &actualFormat, &numItems, 3762 &bytesAfter, (unsigned char **) &virtualRootPtr) == Success) 3763 && (actualType == XA_WINDOW)) 3764 || ((XGetWindowProperty(wrapperPtr->display, wrapperPtr->window, 3765 Tk_InternAtom((Tk_Window) wrapperPtr, "__SWM_ROOT"), 0, (long) 1, 3766 False, XA_WINDOW, &actualType, &actualFormat, &numItems, 3767 &bytesAfter, (unsigned char **) &virtualRootPtr) == Success) 3768 && (actualType == XA_WINDOW))) { 3769 if ((actualFormat == 32) && (numItems == 1)) { 3770 vRoot = wmPtr->vRoot = *virtualRootPtr; 3771 } else if (dispPtr->flags & TK_DISPLAY_WM_TRACING) { 3772 printf("%s format %d numItems %ld\n", 3773 "ReparentEvent got bogus VROOT property:", actualFormat, 3774 numItems); 3775 } 3776 XFree((char *) virtualRootPtr); 3777 } 3778 Tk_DeleteErrorHandler(handler); 3779 3780 if (dispPtr->flags & TK_DISPLAY_WM_TRACING) { 3781 printf("ReparentEvent: %s (%p) reparented to 0x%x, vRoot = 0x%x\n", 3782 wmPtr->winPtr->pathName, wmPtr->winPtr, 3783 (unsigned int) reparentEventPtr->parent, (unsigned int) vRoot); 3784 } 3785 3786 /* 3787 * Fetch correct geometry information for the new virtual root. 3788 */ 3789 3790 UpdateVRootGeometry(wmPtr); 3791 3792 /* 3793 * If the window's new parent is the root window, then mark it as 3794 * no longer reparented. 3795 */ 3796 3797 if (reparentEventPtr->parent == vRoot) { 3798 noReparent: 3799 wmPtr->reparent = None; 3800 wmPtr->parentWidth = wrapperPtr->changes.width; 3801 wmPtr->parentHeight = wrapperPtr->changes.height; 3802 wmPtr->xInParent = wmPtr->yInParent = 0; 3803 wrapperPtr->changes.x = reparentEventPtr->x; 3804 wrapperPtr->changes.y = reparentEventPtr->y; 3805 wmPtr->winPtr->changes.x = reparentEventPtr->x; 3806 wmPtr->winPtr->changes.y = reparentEventPtr->y + wmPtr->menuHeight; 3807 return; 3808 } 3809 3810 /* 3811 * Search up the window hierarchy to find the ancestor of this 3812 * window that is just below the (virtual) root. This is tricky 3813 * because it's possible that things have changed since the event 3814 * was generated so that the ancestry indicated by the event no 3815 * longer exists. If this happens then an error will occur and 3816 * we just discard the event (there will be a more up-to-date 3817 * ReparentNotify event coming later). 3818 */ 3819 3820 handler = Tk_CreateErrorHandler(wrapperPtr->display, -1, -1, -1, 3821 (Tk_ErrorProc *) NULL, (ClientData) NULL); 3822 wmPtr->reparent = reparentEventPtr->parent; 3823 while (1) { 3824 if (XQueryTree(wrapperPtr->display, wmPtr->reparent, &dummy2, 3825 &ancestor, &children, &dummy) == 0) { 3826 Tk_DeleteErrorHandler(handler); 3827 goto noReparent; 3828 } 3829 XFree((char *) children); 3830 if ((ancestor == vRoot) || 3831 (ancestor == RootWindow(wrapperPtr->display, 3832 wrapperPtr->screenNum))) { 3833 break; 3834 } 3835 wmPtr->reparent = ancestor; 3836 } 3837 Tk_DeleteErrorHandler(handler); 3838 3839 if (!ComputeReparentGeometry(wmPtr)) { 3840 goto noReparent; 3841 } 3842} 3843 3844/* 3845 *---------------------------------------------------------------------- 3846 * 3847 * ComputeReparentGeometry -- 3848 * 3849 * This procedure is invoked to recompute geometry information 3850 * related to a reparented top-level window, such as the position 3851 * and total size of the parent and the position within it of 3852 * the top-level window. 3853 * 3854 * Results: 3855 * The return value is 1 if everything completed successfully 3856 * and 0 if an error occurred while querying information about 3857 * winPtr's parents. In this case winPtr is marked as no longer 3858 * being reparented. 3859 * 3860 * Side effects: 3861 * Geometry information in wmPtr, wmPtr->winPtr, and 3862 * wmPtr->wrapperPtr gets updated. 3863 * 3864 *---------------------------------------------------------------------- 3865 */ 3866 3867static int 3868ComputeReparentGeometry(wmPtr) 3869 WmInfo *wmPtr; /* Information about toplevel window 3870 * whose reparent info is to be recomputed. */ 3871{ 3872 TkWindow *wrapperPtr = wmPtr->wrapperPtr; 3873 int width, height, bd; 3874 unsigned int dummy; 3875 int xOffset, yOffset, x, y; 3876 Window dummy2; 3877 Status status; 3878 Tk_ErrorHandler handler; 3879 TkDisplay *dispPtr = wmPtr->winPtr->dispPtr; 3880 3881 handler = Tk_CreateErrorHandler(wrapperPtr->display, -1, -1, -1, 3882 (Tk_ErrorProc *) NULL, (ClientData) NULL); 3883 (void) XTranslateCoordinates(wrapperPtr->display, wrapperPtr->window, 3884 wmPtr->reparent, 0, 0, &xOffset, &yOffset, &dummy2); 3885 status = XGetGeometry(wrapperPtr->display, wmPtr->reparent, 3886 &dummy2, &x, &y, (unsigned int *) &width, 3887 (unsigned int *) &height, (unsigned int *) &bd, &dummy); 3888 Tk_DeleteErrorHandler(handler); 3889 if (status == 0) { 3890 /* 3891 * It appears that the reparented parent went away and 3892 * no-one told us. Reset the window to indicate that 3893 * it's not reparented. 3894 */ 3895 wmPtr->reparent = None; 3896 wmPtr->xInParent = wmPtr->yInParent = 0; 3897 return 0; 3898 } 3899 wmPtr->xInParent = xOffset + bd; 3900 wmPtr->yInParent = yOffset + bd; 3901 wmPtr->parentWidth = width + 2*bd; 3902 wmPtr->parentHeight = height + 2*bd; 3903 3904 /* 3905 * Some tricky issues in updating wmPtr->x and wmPtr->y: 3906 * 3907 * 1. Don't update them if the event occurred because of something 3908 * we did (i.e. WM_SYNC_PENDING and WM_MOVE_PENDING are both set). 3909 * This is because window managers treat coords differently than Tk, 3910 * and no two window managers are alike. If the window manager moved 3911 * the window because we told it to, remember the coordinates we told 3912 * it, not the ones it actually moved it to. This allows us to move 3913 * the window back to the same coordinates later and get the same 3914 * result. Without this check, windows can "walk" across the screen 3915 * under some conditions. 3916 * 3917 * 2. Don't update wmPtr->x and wmPtr->y unless wrapperPtr->changes.x 3918 * or wrapperPtr->changes.y has changed (otherwise a size change can 3919 * spoof us into thinking that the position changed too and defeat 3920 * the intent of (1) above. 3921 * 3922 * (As of 9/96 the above 2 comments appear to be stale. They're 3923 * being left in place as a reminder of what was once true (and 3924 * perhaps should still be true?)). 3925 * 3926 * 3. Ignore size changes coming from the window system if we're 3927 * about to change the size ourselves but haven't seen the event for 3928 * it yet: our size change is supposed to take priority. 3929 */ 3930 3931 if (!(wmPtr->flags & WM_MOVE_PENDING) 3932 && ((wrapperPtr->changes.x != (x + wmPtr->xInParent)) 3933 || (wrapperPtr->changes.y != (y + wmPtr->yInParent)))) { 3934 wmPtr->x = x; 3935 if (wmPtr->flags & WM_NEGATIVE_X) { 3936 wmPtr->x = wmPtr->vRootWidth - (wmPtr->x + wmPtr->parentWidth); 3937 } 3938 wmPtr->y = y; 3939 if (wmPtr->flags & WM_NEGATIVE_Y) { 3940 wmPtr->y = wmPtr->vRootHeight - (wmPtr->y + wmPtr->parentHeight); 3941 } 3942 } 3943 3944 wrapperPtr->changes.x = x + wmPtr->xInParent; 3945 wrapperPtr->changes.y = y + wmPtr->yInParent; 3946 if (dispPtr->flags & TK_DISPLAY_WM_TRACING) { 3947 printf("wrapperPtr %p coords %d,%d\n", 3948 wrapperPtr, wrapperPtr->changes.x, wrapperPtr->changes.y); 3949 printf(" wmPtr %p coords %d,%d, offsets %d %d\n", 3950 wmPtr, wmPtr->x, wmPtr->y, wmPtr->xInParent, wmPtr->yInParent); 3951 } 3952 return 1; 3953} 3954 3955/* 3956 *---------------------------------------------------------------------- 3957 * 3958 * WrapperEventProc -- 3959 * 3960 * This procedure is invoked by the event loop when a wrapper window 3961 * is restructured. 3962 * 3963 * Results: 3964 * None. 3965 * 3966 * Side effects: 3967 * Tk's internal data structures for the window get modified to 3968 * reflect the structural change. 3969 * 3970 *---------------------------------------------------------------------- 3971 */ 3972 3973static void 3974WrapperEventProc(clientData, eventPtr) 3975 ClientData clientData; /* Information about toplevel window. */ 3976 XEvent *eventPtr; /* Event that just happened. */ 3977{ 3978 WmInfo *wmPtr = (WmInfo *) clientData; 3979 XEvent mapEvent; 3980 TkDisplay *dispPtr = wmPtr->winPtr->dispPtr; 3981 3982 wmPtr->flags |= WM_VROOT_OFFSET_STALE; 3983 if (eventPtr->type == DestroyNotify) { 3984 Tk_ErrorHandler handler; 3985 3986 if (!(wmPtr->wrapperPtr->flags & TK_ALREADY_DEAD)) { 3987 /* 3988 * A top-level window was deleted externally (e.g., by the window 3989 * manager). This is probably not a good thing, but cleanup as 3990 * best we can. The error handler is needed because 3991 * Tk_DestroyWindow will try to destroy the window, but of course 3992 * it's already gone. 3993 */ 3994 3995 handler = Tk_CreateErrorHandler(wmPtr->winPtr->display, -1, -1, -1, 3996 (Tk_ErrorProc *) NULL, (ClientData) NULL); 3997 Tk_DestroyWindow((Tk_Window) wmPtr->winPtr); 3998 Tk_DeleteErrorHandler(handler); 3999 } 4000 if (dispPtr->flags & TK_DISPLAY_WM_TRACING) { 4001 printf("TopLevelEventProc: %s deleted\n", wmPtr->winPtr->pathName); 4002 } 4003 } else if (eventPtr->type == ConfigureNotify) { 4004 /* 4005 * Ignore the event if the window has never been mapped yet. 4006 * Such an event occurs only in weird cases like changing the 4007 * internal border width of a top-level window, which results 4008 * in a synthetic Configure event. These events are not relevant 4009 * to us, and if we process them confusion may result (e.g. we 4010 * may conclude erroneously that the user repositioned or resized 4011 * the window). 4012 */ 4013 4014 if (!(wmPtr->flags & WM_NEVER_MAPPED)) { 4015 ConfigureEvent(wmPtr, &eventPtr->xconfigure); 4016 } 4017 } else if (eventPtr->type == MapNotify) { 4018 wmPtr->wrapperPtr->flags |= TK_MAPPED; 4019 wmPtr->winPtr->flags |= TK_MAPPED; 4020 XMapWindow(wmPtr->winPtr->display, wmPtr->winPtr->window); 4021 goto doMapEvent; 4022 } else if (eventPtr->type == UnmapNotify) { 4023 wmPtr->wrapperPtr->flags &= ~TK_MAPPED; 4024 wmPtr->winPtr->flags &= ~TK_MAPPED; 4025 XUnmapWindow(wmPtr->winPtr->display, wmPtr->winPtr->window); 4026 goto doMapEvent; 4027 } else if (eventPtr->type == ReparentNotify) { 4028 ReparentEvent(wmPtr, &eventPtr->xreparent); 4029 } 4030 return; 4031 4032 doMapEvent: 4033 mapEvent = *eventPtr; 4034 mapEvent.xmap.event = wmPtr->winPtr->window; 4035 mapEvent.xmap.window = wmPtr->winPtr->window; 4036 Tk_HandleEvent(&mapEvent); 4037} 4038 4039/* 4040 *---------------------------------------------------------------------- 4041 * 4042 * TopLevelReqProc -- 4043 * 4044 * This procedure is invoked by the geometry manager whenever 4045 * the requested size for a top-level window is changed. 4046 * 4047 * Results: 4048 * None. 4049 * 4050 * Side effects: 4051 * Arrange for the window to be resized to satisfy the request 4052 * (this happens as a when-idle action). 4053 * 4054 *---------------------------------------------------------------------- 4055 */ 4056 4057 /* ARGSUSED */ 4058static void 4059TopLevelReqProc(dummy, tkwin) 4060 ClientData dummy; /* Not used. */ 4061 Tk_Window tkwin; /* Information about window. */ 4062{ 4063 TkWindow *winPtr = (TkWindow *) tkwin; 4064 WmInfo *wmPtr; 4065 4066 wmPtr = winPtr->wmInfoPtr; 4067 4068 if ((wmPtr->width >= 0) && (wmPtr->height >= 0)) { 4069 /* 4070 * Explicit dimensions have been set for this window, so we 4071 * should ignore the geometry request. It's actually important 4072 * to ignore the geometry request because, due to quirks in 4073 * window managers, invoking UpdateGeometryInfo may cause the 4074 * window to move. For example, if "wm geometry -10-20" was 4075 * invoked, the window may be positioned incorrectly the first 4076 * time it appears (because we didn't know the proper width of 4077 * the window manager borders); if we invoke UpdateGeometryInfo 4078 * again, the window will be positioned correctly, which may 4079 * cause it to jump on the screen. 4080 */ 4081 4082 return; 4083 } 4084 4085 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 4086 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { 4087 Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr); 4088 wmPtr->flags |= WM_UPDATE_PENDING; 4089 } 4090 4091 /* 4092 * If the window isn't being positioned by its upper left corner 4093 * then we have to move it as well. 4094 */ 4095 4096 if (wmPtr->flags & (WM_NEGATIVE_X | WM_NEGATIVE_Y)) { 4097 wmPtr->flags |= WM_MOVE_PENDING; 4098 } 4099} 4100 4101/* 4102 *---------------------------------------------------------------------- 4103 * 4104 * UpdateGeometryInfo -- 4105 * 4106 * This procedure is invoked when a top-level window is first 4107 * mapped, and also as a when-idle procedure, to bring the 4108 * geometry and/or position of a top-level window back into 4109 * line with what has been requested by the user and/or widgets. 4110 * This procedure doesn't return until the window manager has 4111 * responded to the geometry change. 4112 * 4113 * Results: 4114 * None. 4115 * 4116 * Side effects: 4117 * The size and location of both the toplevel window and its wrapper 4118 * may change, unless the WM prevents that from happening. 4119 * 4120 *---------------------------------------------------------------------- 4121 */ 4122 4123static void 4124UpdateGeometryInfo(clientData) 4125 ClientData clientData; /* Pointer to the window's record. */ 4126{ 4127 register TkWindow *winPtr = (TkWindow *) clientData; 4128 register WmInfo *wmPtr = winPtr->wmInfoPtr; 4129 int x, y, width, height, min, max; 4130 unsigned long serial; 4131 4132 wmPtr->flags &= ~WM_UPDATE_PENDING; 4133 4134 /* 4135 * Compute the new size for the top-level window. See the 4136 * user documentation for details on this, but the size 4137 * requested depends on (a) the size requested internally 4138 * by the window's widgets, (b) the size requested by the 4139 * user in a "wm geometry" command or via wm-based interactive 4140 * resizing (if any), (c) whether or not the window is 4141 * gridded, and (d) the current min or max size for 4142 * the toplevel. Don't permit sizes <= 0 because this 4143 * upsets the X server. 4144 */ 4145 4146 if (wmPtr->width == -1) { 4147 width = winPtr->reqWidth; 4148 } else if (wmPtr->gridWin != NULL) { 4149 width = winPtr->reqWidth 4150 + (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc; 4151 } else { 4152 width = wmPtr->width; 4153 } 4154 if (width <= 0) { 4155 width = 1; 4156 } 4157 /* 4158 * Account for window max/min width 4159 */ 4160 if (wmPtr->gridWin != NULL) { 4161 min = winPtr->reqWidth 4162 + (wmPtr->minWidth - wmPtr->reqGridWidth)*wmPtr->widthInc; 4163 if (wmPtr->maxWidth > 0) { 4164 max = winPtr->reqWidth 4165 + (wmPtr->maxWidth - wmPtr->reqGridWidth)*wmPtr->widthInc; 4166 } else { 4167 max = 0; 4168 } 4169 } else { 4170 min = wmPtr->minWidth; 4171 max = wmPtr->maxWidth; 4172 } 4173 if (width < min) { 4174 width = min; 4175 } else if ((max > 0) && (width > max)) { 4176 width = max; 4177 } 4178 4179 if (wmPtr->height == -1) { 4180 height = winPtr->reqHeight; 4181 } else if (wmPtr->gridWin != NULL) { 4182 height = winPtr->reqHeight 4183 + (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc; 4184 } else { 4185 height = wmPtr->height; 4186 } 4187 if (height <= 0) { 4188 height = 1; 4189 } 4190 /* 4191 * Account for window max/min height 4192 */ 4193 if (wmPtr->gridWin != NULL) { 4194 min = winPtr->reqHeight 4195 + (wmPtr->minHeight - wmPtr->reqGridHeight)*wmPtr->heightInc; 4196 if (wmPtr->maxHeight > 0) { 4197 max = winPtr->reqHeight 4198 + (wmPtr->maxHeight - wmPtr->reqGridHeight)*wmPtr->heightInc; 4199 } else { 4200 max = 0; 4201 } 4202 } else { 4203 min = wmPtr->minHeight; 4204 max = wmPtr->maxHeight; 4205 } 4206 if (height < min) { 4207 height = min; 4208 } else if ((max > 0) && (height > max)) { 4209 height = max; 4210 } 4211 4212 /* 4213 * Compute the new position for the upper-left pixel of the window's 4214 * decorative frame. This is tricky, because we need to include the 4215 * border widths supplied by a reparented parent in this calculation, 4216 * but can't use the parent's current overall size since that may 4217 * change as a result of this code. 4218 */ 4219 4220 if (wmPtr->flags & WM_NEGATIVE_X) { 4221 x = wmPtr->vRootWidth - wmPtr->x 4222 - (width + (wmPtr->parentWidth - winPtr->changes.width)); 4223 } else { 4224 x = wmPtr->x; 4225 } 4226 if (wmPtr->flags & WM_NEGATIVE_Y) { 4227 y = wmPtr->vRootHeight - wmPtr->y 4228 - (height + (wmPtr->parentHeight - winPtr->changes.height)); 4229 } else { 4230 y = wmPtr->y; 4231 } 4232 4233 /* 4234 * If the window's size is going to change and the window is 4235 * supposed to not be resizable by the user, then we have to 4236 * update the size hints. There may also be a size-hint-update 4237 * request pending from somewhere else, too. 4238 */ 4239 4240 if (((width != winPtr->changes.width) 4241 || (height != winPtr->changes.height)) 4242 && (wmPtr->gridWin == NULL) 4243 && ((wmPtr->sizeHintsFlags & (PMinSize|PMaxSize)) == 0)) { 4244 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 4245 } 4246 if (wmPtr->flags & WM_UPDATE_SIZE_HINTS) { 4247 UpdateSizeHints(winPtr, width, height); 4248 } 4249 4250 /* 4251 * Reconfigure the wrapper if it isn't already configured correctly. 4252 * A few tricky points: 4253 * 4254 * 1. If the window is embeddedand the container is also in this 4255 * process, don't actually reconfigure the window; just pass the 4256 * desired size on to the container. Also, zero out any position 4257 * information, since embedded windows are not allowed to move. 4258 * 2. Sometimes the window manager will give us a different size 4259 * than we asked for (e.g. mwm has a minimum size for windows), so 4260 * base the size check on what we *asked for* last time, not what we 4261 * got. 4262 * 3. Can't just reconfigure always, because we may not get a 4263 * ConfigureNotify event back if nothing changed, so 4264 * WaitForConfigureNotify will hang a long time. 4265 * 4. Don't move window unless a new position has been requested for 4266 * it. This is because of "features" in some window managers (e.g. 4267 * twm, as of 4/24/91) where they don't interpret coordinates 4268 * according to ICCCM. Moving a window to its current location may 4269 * cause it to shift position on the screen. 4270 */ 4271 4272 if ((winPtr->flags & (TK_EMBEDDED|TK_BOTH_HALVES)) 4273 == (TK_EMBEDDED|TK_BOTH_HALVES)) { 4274 TkWindow *childPtr = TkpGetOtherWindow(winPtr); 4275 /* 4276 * This window is embedded and the container is also in this 4277 * process, so we don't need to do anything special about the 4278 * geometry, except to make sure that the desired size is known 4279 * by the container. Also, zero out any position information, 4280 * since embedded windows are not allowed to move. 4281 */ 4282 4283 wmPtr->x = wmPtr->y = 0; 4284 wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y); 4285 if (childPtr != NULL) { 4286 height += wmPtr->menuHeight; 4287 Tk_GeometryRequest((Tk_Window) childPtr, width, height); 4288 } 4289 return; 4290 } 4291 4292 serial = NextRequest(winPtr->display); 4293 height += wmPtr->menuHeight; 4294 if (wmPtr->flags & WM_MOVE_PENDING) { 4295 if ((x + wmPtr->xInParent == winPtr->changes.x) && 4296 (y + wmPtr->yInParent + wmPtr->menuHeight == winPtr->changes.y) 4297 && (width == wmPtr->wrapperPtr->changes.width) 4298 && (height == wmPtr->wrapperPtr->changes.height)) { 4299 /* 4300 * The window already has the correct geometry, so don't bother 4301 * to configure it; the X server appears to ignore these 4302 * requests, so we won't get back a ConfigureNotify and the 4303 * WaitForConfigureNotify call below will hang for a while. 4304 */ 4305 4306 wmPtr->flags &= ~WM_MOVE_PENDING; 4307 return; 4308 } 4309 wmPtr->configWidth = width; 4310 wmPtr->configHeight = height; 4311 if (winPtr->dispPtr->flags & TK_DISPLAY_WM_TRACING) { 4312 printf("UpdateGeometryInfo moving to %d %d, resizing to %d x %d,\n", 4313 x, y, width, height); 4314 } 4315 XMoveResizeWindow(winPtr->display, wmPtr->wrapperPtr->window, x, y, 4316 (unsigned) width, (unsigned) height); 4317 } else if ((width != wmPtr->configWidth) 4318 || (height != wmPtr->configHeight)) { 4319 if ((width == wmPtr->wrapperPtr->changes.width) 4320 && (height == wmPtr->wrapperPtr->changes.height)) { 4321 /* 4322 * The window is already just the size we want, so don't bother 4323 * to configure it; the X server appears to ignore these 4324 * requests, so we won't get back a ConfigureNotify and the 4325 * WaitForConfigureNotify call below will hang for a while. 4326 */ 4327 4328 return; 4329 } 4330 wmPtr->configWidth = width; 4331 wmPtr->configHeight = height; 4332 if (winPtr->dispPtr->flags & TK_DISPLAY_WM_TRACING) { 4333 printf("UpdateGeometryInfo resizing %p to %d x %d\n", 4334 (void *)wmPtr->wrapperPtr->window, width, height); 4335 } 4336 XResizeWindow(winPtr->display, wmPtr->wrapperPtr->window, 4337 (unsigned) width, (unsigned) height); 4338 } else if ((wmPtr->menubar != NULL) 4339 && ((Tk_Width(wmPtr->menubar) != wmPtr->wrapperPtr->changes.width) 4340 || (Tk_Height(wmPtr->menubar) != wmPtr->menuHeight))) { 4341 /* 4342 * It is possible that the window's overall size has not changed 4343 * but the menu size has. 4344 */ 4345 4346 Tk_MoveResizeWindow(wmPtr->menubar, 0, 0, 4347 wmPtr->wrapperPtr->changes.width, wmPtr->menuHeight); 4348 XResizeWindow(winPtr->display, wmPtr->wrapperPtr->window, 4349 (unsigned) width, (unsigned) height); 4350 } else { 4351 return; 4352 } 4353 4354 /* 4355 * Wait for the configure operation to complete. Don't need to do 4356 * this, however, if the window is about to be mapped: it will be 4357 * taken care of elsewhere. 4358 */ 4359 4360 if (!(wmPtr->flags & WM_ABOUT_TO_MAP)) { 4361 WaitForConfigureNotify(winPtr, serial); 4362 } 4363} 4364 4365/* 4366 *-------------------------------------------------------------- 4367 * 4368 * UpdateSizeHints -- 4369 * 4370 * This procedure is called to update the window manager's 4371 * size hints information from the information in a WmInfo 4372 * structure. 4373 * 4374 * Results: 4375 * None. 4376 * 4377 * Side effects: 4378 * Properties get changed for winPtr. 4379 * 4380 *-------------------------------------------------------------- 4381 */ 4382 4383static void 4384UpdateSizeHints(winPtr, newWidth, newHeight) 4385 TkWindow *winPtr; 4386 int newWidth; 4387 int newHeight; 4388{ 4389 register WmInfo *wmPtr = winPtr->wmInfoPtr; 4390 XSizeHints *hintsPtr; 4391 int maxWidth, maxHeight; 4392 4393 wmPtr->flags &= ~WM_UPDATE_SIZE_HINTS; 4394 4395 hintsPtr = XAllocSizeHints(); 4396 if (hintsPtr == NULL) { 4397 return; 4398 } 4399 4400 /* 4401 * Compute the pixel-based sizes for the various fields in the 4402 * size hints structure, based on the grid-based sizes in 4403 * our structure. 4404 */ 4405 4406 GetMaxSize(wmPtr, &maxWidth, &maxHeight); 4407 if (wmPtr->gridWin != NULL) { 4408 hintsPtr->base_width = winPtr->reqWidth 4409 - (wmPtr->reqGridWidth * wmPtr->widthInc); 4410 if (hintsPtr->base_width < 0) { 4411 hintsPtr->base_width = 0; 4412 } 4413 hintsPtr->base_height = winPtr->reqHeight + wmPtr->menuHeight 4414 - (wmPtr->reqGridHeight * wmPtr->heightInc); 4415 if (hintsPtr->base_height < 0) { 4416 hintsPtr->base_height = 0; 4417 } 4418 hintsPtr->min_width = hintsPtr->base_width 4419 + (wmPtr->minWidth * wmPtr->widthInc); 4420 hintsPtr->min_height = hintsPtr->base_height 4421 + (wmPtr->minHeight * wmPtr->heightInc); 4422 hintsPtr->max_width = hintsPtr->base_width 4423 + (maxWidth * wmPtr->widthInc); 4424 hintsPtr->max_height = hintsPtr->base_height 4425 + (maxHeight * wmPtr->heightInc); 4426 } else { 4427 hintsPtr->min_width = wmPtr->minWidth; 4428 hintsPtr->min_height = wmPtr->minHeight; 4429 hintsPtr->max_width = maxWidth; 4430 hintsPtr->max_height = maxHeight; 4431 hintsPtr->base_width = 0; 4432 hintsPtr->base_height = 0; 4433 } 4434 hintsPtr->width_inc = wmPtr->widthInc; 4435 hintsPtr->height_inc = wmPtr->heightInc; 4436 hintsPtr->min_aspect.x = wmPtr->minAspect.x; 4437 hintsPtr->min_aspect.y = wmPtr->minAspect.y; 4438 hintsPtr->max_aspect.x = wmPtr->maxAspect.x; 4439 hintsPtr->max_aspect.y = wmPtr->maxAspect.y; 4440 hintsPtr->win_gravity = wmPtr->gravity; 4441 hintsPtr->flags = wmPtr->sizeHintsFlags | PMinSize; 4442 4443 /* 4444 * If the window isn't supposed to be resizable, then set the 4445 * minimum and maximum dimensions to be the same. 4446 */ 4447 4448 if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) { 4449 hintsPtr->max_width = hintsPtr->min_width = newWidth; 4450 hintsPtr->flags |= PMaxSize; 4451 } 4452 if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) { 4453 hintsPtr->max_height = hintsPtr->min_height = 4454 newHeight + wmPtr->menuHeight; 4455 hintsPtr->flags |= PMaxSize; 4456 } 4457 4458 XSetWMNormalHints(winPtr->display, wmPtr->wrapperPtr->window, hintsPtr); 4459 4460 XFree((char *) hintsPtr); 4461} 4462 4463/* 4464 *-------------------------------------------------------------- 4465 * 4466 * UpdateTitle -- 4467 * 4468 * This procedure is called to update the window title and 4469 * icon name. It sets the ICCCM-defined properties WM_NAME 4470 * and WM_ICON_NAME for older window managers, and the 4471 * freedesktop.org-defined _NET_WM_NAME and _NET_WM_ICON_NAME 4472 * properties for newer ones. The ICCCM properties are 4473 * stored in the system encoding, the newer properties 4474 * are stored in UTF-8. 4475 * 4476 * NOTE: the ICCCM specifies that WM_NAME and WM_ICON_NAME are 4477 * stored in ISO-Latin-1. Tk has historically used the default 4478 * system encoding (since 8.1). It's not clear whether this is 4479 * correct or not. 4480 * 4481 * Side effects: 4482 * Properties get changed for winPtr. 4483 * 4484 *-------------------------------------------------------------- 4485 */ 4486static void 4487UpdateTitle(winPtr) 4488 TkWindow *winPtr; 4489{ 4490 WmInfo *wmPtr = winPtr->wmInfoPtr; 4491 Atom XA_UTF8_STRING = Tk_InternAtom((Tk_Window) winPtr, "UTF8_STRING"); 4492 const char *string; 4493 Tcl_DString ds; 4494 4495 /* 4496 * Set window title: 4497 */ 4498 string = (wmPtr->title != NULL) ? wmPtr->title : winPtr->nameUid; 4499 Tcl_UtfToExternalDString(NULL, string, -1, &ds); 4500 XStoreName(winPtr->display, wmPtr->wrapperPtr->window, 4501 Tcl_DStringValue(&ds)); 4502 Tcl_DStringFree(&ds); 4503 4504 XChangeProperty(winPtr->display, wmPtr->wrapperPtr->window, 4505 Tk_InternAtom((Tk_Window) winPtr, "_NET_WM_NAME"), 4506 XA_UTF8_STRING, 8, PropModeReplace, 4507 (const unsigned char*)string, (signed int)strlen(string)); 4508 4509 /* 4510 * Set icon name: 4511 */ 4512 if (wmPtr->iconName != NULL) { 4513 Tcl_UtfToExternalDString(NULL, wmPtr->iconName, -1, &ds); 4514 XSetIconName(winPtr->display, wmPtr->wrapperPtr->window, 4515 Tcl_DStringValue(&ds)); 4516 Tcl_DStringFree(&ds); 4517 4518 XChangeProperty(winPtr->display, wmPtr->wrapperPtr->window, 4519 Tk_InternAtom((Tk_Window) winPtr, "_NET_WM_ICON_NAME"), 4520 XA_UTF8_STRING, 8, PropModeReplace, 4521 (const unsigned char*)wmPtr->iconName, 4522 (signed int)strlen(wmPtr->iconName)); 4523 } 4524} 4525 4526/* 4527 *-------------------------------------------------------------- 4528 * 4529 * UpdatePhotoIcon -- 4530 * 4531 * This procedure is called to update the window ohoto icon. 4532 * It sets the EWMH-defined properties _NET_WM_ICON. 4533 * 4534 * Side effects: 4535 * Properties get changed for winPtr. 4536 * 4537 *-------------------------------------------------------------- 4538 */ 4539static void 4540UpdatePhotoIcon(winPtr) 4541 TkWindow *winPtr; 4542{ 4543 WmInfo *wmPtr = winPtr->wmInfoPtr; 4544 unsigned char *data = wmPtr->iconDataPtr; 4545 int size = wmPtr->iconDataSize; 4546 4547 if (data == NULL) { 4548 data = winPtr->dispPtr->iconDataPtr; 4549 size = winPtr->dispPtr->iconDataSize; 4550 } 4551 if (data != NULL) { 4552 /* 4553 * Set icon: 4554 */ 4555 XChangeProperty(winPtr->display, wmPtr->wrapperPtr->window, 4556 Tk_InternAtom((Tk_Window) winPtr, "_NET_WM_ICON"), 4557 XA_CARDINAL, 32, PropModeReplace, 4558 (unsigned char *) data, size); 4559 } 4560} 4561 4562/* 4563 *---------------------------------------------------------------------- 4564 * 4565 * WaitForConfigureNotify -- 4566 * 4567 * This procedure is invoked in order to synchronize with the 4568 * window manager. It waits for a ConfigureNotify event to 4569 * arrive, signalling that the window manager has seen an attempt 4570 * on our part to move or resize a top-level window. 4571 * 4572 * Results: 4573 * None. 4574 * 4575 * Side effects: 4576 * Delays the execution of the process until a ConfigureNotify event 4577 * arrives with serial number at least as great as serial. This 4578 * is useful for two reasons: 4579 * 4580 * 1. It's important to distinguish ConfigureNotify events that are 4581 * coming in response to a request we've made from those generated 4582 * spontaneously by the user. The reason for this is that if the 4583 * user resizes the window we take that as an order to ignore 4584 * geometry requests coming from inside the window hierarchy. If 4585 * we accidentally interpret a response to our request as a 4586 * user-initiated action, the window will stop responding to 4587 * new geometry requests. To make this distinction, (a) this 4588 * procedure sets a flag for TopLevelEventProc to indicate that 4589 * we're waiting to sync with the wm, and (b) all changes to 4590 * the size of a top-level window are followed by calls to this 4591 * procedure. 4592 * 2. Races and confusion can come about if there are multiple 4593 * operations outstanding at a time (e.g. two different resizes 4594 * of the top-level window: it's hard to tell which of the 4595 * ConfigureNotify events coming back is for which request). 4596 * While waiting, some events covered by StructureNotifyMask are 4597 * processed (ConfigureNotify, MapNotify, and UnmapNotify) 4598 * and all others are deferred. 4599 * 4600 *---------------------------------------------------------------------- 4601 */ 4602 4603static void 4604WaitForConfigureNotify(winPtr, serial) 4605 TkWindow *winPtr; /* Top-level window for which we want 4606 * to see a ConfigureNotify. */ 4607 unsigned long serial; /* Serial number of resize request. Want to 4608 * be sure wm has seen this. */ 4609{ 4610 WmInfo *wmPtr = winPtr->wmInfoPtr; 4611 XEvent event; 4612 int diff, code; 4613 int gotConfig = 0; 4614 4615 /* 4616 * One more tricky detail about this procedure. In some cases the 4617 * window manager will decide to ignore a configure request (e.g. 4618 * because it thinks the window is already in the right place). 4619 * To avoid hanging in this situation, only wait for a few seconds, 4620 * then give up. 4621 */ 4622 4623 while (!gotConfig) { 4624 wmPtr->flags |= WM_SYNC_PENDING; 4625 code = WaitForEvent(winPtr->display, wmPtr, ConfigureNotify, &event); 4626 wmPtr->flags &= ~WM_SYNC_PENDING; 4627 if (code != TCL_OK) { 4628 if (winPtr->dispPtr->flags & TK_DISPLAY_WM_TRACING) { 4629 printf("WaitForConfigureNotify giving up on %s\n", 4630 winPtr->pathName); 4631 } 4632 break; 4633 } 4634 diff = event.xconfigure.serial - serial; 4635 if (diff >= 0) { 4636 gotConfig = 1; 4637 } 4638 } 4639 wmPtr->flags &= ~WM_MOVE_PENDING; 4640 if (winPtr->dispPtr->flags & TK_DISPLAY_WM_TRACING) { 4641 printf("WaitForConfigureNotify finished with %s, serial %ld\n", 4642 winPtr->pathName, serial); 4643 } 4644} 4645 4646/* 4647 *---------------------------------------------------------------------- 4648 * 4649 * WaitForEvent -- 4650 * 4651 * This procedure is used by WaitForConfigureNotify and 4652 * WaitForMapNotify to wait for an event of a certain type 4653 * to arrive. 4654 * 4655 * Results: 4656 * Under normal conditions, TCL_OK is returned and an event for 4657 * display and window that matches "mask" is stored in *eventPtr. 4658 * This event has already been processed by Tk before this procedure 4659 * returns. If a long time goes by with no event of the right type 4660 * arriving, or if an error occurs while waiting for the event to 4661 * arrive, then TCL_ERROR is returned. 4662 * 4663 * Side effects: 4664 * While waiting for the desired event to occur, Configurenotify, 4665 * MapNotify, and UnmapNotify events for window are processed, 4666 * as are all ReparentNotify events. 4667 * 4668 *---------------------------------------------------------------------- 4669 */ 4670 4671static int 4672WaitForEvent(display, wmInfoPtr, type, eventPtr) 4673 Display *display; /* Display event is coming from. */ 4674 WmInfo *wmInfoPtr; /* Window for which event is desired. */ 4675 int type; /* Type of event that is wanted. */ 4676 XEvent *eventPtr; /* Place to store event. */ 4677{ 4678 WaitRestrictInfo info; 4679 Tk_RestrictProc *oldRestrictProc; 4680 ClientData oldRestrictData; 4681 Tcl_Time timeout; 4682 4683 /* 4684 * Set up an event filter to select just the events we want, and 4685 * a timer handler, then wait for events until we get the event 4686 * we want or a timeout happens. 4687 */ 4688 4689 info.display = display; 4690 info.wmInfoPtr = wmInfoPtr; 4691 info.type = type; 4692 info.eventPtr = eventPtr; 4693 info.foundEvent = 0; 4694 oldRestrictProc = Tk_RestrictEvents(WaitRestrictProc, (ClientData) &info, 4695 &oldRestrictData); 4696 4697 Tcl_GetTime(&timeout); 4698 timeout.sec += 2; 4699 4700 while (!info.foundEvent) { 4701 if (!TkUnixDoOneXEvent(&timeout)) { 4702 break; 4703 } 4704 } 4705 (void) Tk_RestrictEvents(oldRestrictProc, oldRestrictData, 4706 &oldRestrictData); 4707 if (info.foundEvent) { 4708 return TCL_OK; 4709 } 4710 return TCL_ERROR; 4711} 4712 4713/* 4714 *---------------------------------------------------------------------- 4715 * 4716 * WaitRestrictProc -- 4717 * 4718 * This procedure is a Tk_RestrictProc that is used to filter 4719 * events while WaitForEvent is active. 4720 * 4721 * Results: 4722 * Returns TK_PROCESS_EVENT if the right event is found. Also 4723 * returns TK_PROCESS_EVENT if any ReparentNotify event is found 4724 * or if the event is a ConfigureNotify, MapNotify, or UnmapNotify 4725 * for window. Otherwise returns TK_DEFER_EVENT. 4726 * 4727 * Side effects: 4728 * An event may get stored in the area indicated by the caller 4729 * of WaitForEvent. 4730 * 4731 *---------------------------------------------------------------------- 4732 */ 4733 4734static Tk_RestrictAction 4735WaitRestrictProc(clientData, eventPtr) 4736 ClientData clientData; /* Pointer to WaitRestrictInfo structure. */ 4737 XEvent *eventPtr; /* Event that is about to be handled. */ 4738{ 4739 WaitRestrictInfo *infoPtr = (WaitRestrictInfo *) clientData; 4740 4741 if (eventPtr->type == ReparentNotify) { 4742 return TK_PROCESS_EVENT; 4743 } 4744 if (((eventPtr->xany.window != infoPtr->wmInfoPtr->wrapperPtr->window) 4745 && (eventPtr->xany.window != infoPtr->wmInfoPtr->reparent)) 4746 || (eventPtr->xany.display != infoPtr->display)) { 4747 return TK_DEFER_EVENT; 4748 } 4749 if (eventPtr->type == infoPtr->type) { 4750 *infoPtr->eventPtr = *eventPtr; 4751 infoPtr->foundEvent = 1; 4752 return TK_PROCESS_EVENT; 4753 } 4754 if (eventPtr->type == ConfigureNotify 4755 || eventPtr->type == MapNotify 4756 || eventPtr->type == UnmapNotify) { 4757 return TK_PROCESS_EVENT; 4758 } 4759 return TK_DEFER_EVENT; 4760} 4761 4762/* 4763 *---------------------------------------------------------------------- 4764 * 4765 * WaitForMapNotify -- 4766 * 4767 * This procedure is invoked in order to synchronize with the 4768 * window manager. It waits for the window's mapped state to 4769 * reach the value given by mapped. 4770 * 4771 * Results: 4772 * None. 4773 * 4774 * Side effects: 4775 * Delays the execution of the process until winPtr becomes mapped 4776 * or unmapped, depending on the "mapped" argument. This allows us 4777 * to synchronize with the window manager, and allows us to 4778 * identify changes in window size that come about when the window 4779 * manager first starts managing the window (as opposed to those 4780 * requested interactively by the user later). See the comments 4781 * for WaitForConfigureNotify and WM_SYNC_PENDING. While waiting, 4782 * some events covered by StructureNotifyMask are processed and all 4783 * others are deferred. 4784 * 4785 *---------------------------------------------------------------------- 4786 */ 4787 4788static void 4789WaitForMapNotify(winPtr, mapped) 4790 TkWindow *winPtr; /* Top-level window for which we want 4791 * to see a particular mapping state. */ 4792 int mapped; /* If non-zero, wait for window to become 4793 * mapped, otherwise wait for it to become 4794 * unmapped. */ 4795{ 4796 WmInfo *wmPtr = winPtr->wmInfoPtr; 4797 XEvent event; 4798 int code; 4799 4800 while (1) { 4801 if (mapped) { 4802 if (winPtr->flags & TK_MAPPED) { 4803 break; 4804 } 4805 } else if (!(winPtr->flags & TK_MAPPED)) { 4806 break; 4807 } 4808 wmPtr->flags |= WM_SYNC_PENDING; 4809 code = WaitForEvent(winPtr->display, wmPtr, 4810 mapped ? MapNotify : UnmapNotify, &event); 4811 wmPtr->flags &= ~WM_SYNC_PENDING; 4812 if (code != TCL_OK) { 4813 /* 4814 * There are some bizarre situations in which the window 4815 * manager can't respond or chooses not to (e.g. if we've 4816 * got a grab set it can't respond). If this happens then 4817 * just quit. 4818 */ 4819 4820 if (winPtr->dispPtr->flags & TK_DISPLAY_WM_TRACING) { 4821 printf("WaitForMapNotify giving up on %s\n", winPtr->pathName); 4822 } 4823 break; 4824 } 4825 } 4826 wmPtr->flags &= ~WM_MOVE_PENDING; 4827 if (winPtr->dispPtr->flags & TK_DISPLAY_WM_TRACING) { 4828 printf("WaitForMapNotify finished with %s (winPtr %p, wmPtr %p)\n", 4829 winPtr->pathName, winPtr, wmPtr); 4830 } 4831} 4832 4833/* 4834 *-------------------------------------------------------------- 4835 * 4836 * UpdateHints -- 4837 * 4838 * This procedure is called to update the window manager's 4839 * hints information from the information in a WmInfo 4840 * structure. 4841 * 4842 * Results: 4843 * None. 4844 * 4845 * Side effects: 4846 * Properties get changed for winPtr. 4847 * 4848 *-------------------------------------------------------------- 4849 */ 4850 4851static void 4852UpdateHints(winPtr) 4853 TkWindow *winPtr; 4854{ 4855 WmInfo *wmPtr = winPtr->wmInfoPtr; 4856 4857 if (wmPtr->flags & WM_NEVER_MAPPED) { 4858 return; 4859 } 4860 XSetWMHints(winPtr->display, wmPtr->wrapperPtr->window, &wmPtr->hints); 4861} 4862 4863/* 4864 *---------------------------------------------------------------------- 4865 * 4866 * SetNetWmType -- 4867 * 4868 * Set the extended window manager hints for a toplevel window 4869 * to the types provided. The specification states that this 4870 * may be a list of window types in preferred order. To permit 4871 * for future type definitions, the set of names is unconstrained 4872 * and names are converted to upper-case and appended to 4873 * "_NET_WM_WINDOW_TYPE_" before being converted to an Atom. 4874 * 4875 *---------------------------------------------------------------------- 4876 */ 4877 4878static int 4879SetNetWmType(winPtr, typePtr) 4880 TkWindow *winPtr; 4881 Tcl_Obj *typePtr; 4882{ 4883 Atom typeAtom, *atoms = NULL; 4884 WmInfo *wmPtr; 4885 TkWindow *wrapperPtr; 4886 Tcl_Obj **objv; 4887 int objc, n; 4888 Tk_Window tkwin = (Tk_Window)winPtr; 4889 Tcl_Interp *interp = winPtr->mainPtr->interp; 4890 4891 if (TCL_OK != Tcl_ListObjGetElements(interp, typePtr, &objc, &objv)) { 4892 return TCL_ERROR; 4893 } 4894 4895 if (!Tk_HasWrapper(tkwin)) { 4896 return TCL_OK; /* error?? */ 4897 } 4898 4899 if (objc > 0) { 4900 atoms = (Atom *)ckalloc(sizeof(Atom) * objc); 4901 } 4902 4903 for (n = 0; n < objc; ++n) { 4904 Tcl_DString ds, dsName; 4905 int len; 4906 char *name = Tcl_GetStringFromObj(objv[n], &len); 4907 Tcl_UtfToUpper(name); 4908 Tcl_UtfToExternalDString(NULL, name, len, &dsName); 4909 Tcl_DStringInit(&ds); 4910 Tcl_DStringAppend(&ds, "_NET_WM_WINDOW_TYPE_", 20); 4911 Tcl_DStringAppend(&ds, Tcl_DStringValue(&dsName), 4912 Tcl_DStringLength(&dsName)); 4913 Tcl_DStringFree(&dsName); 4914 atoms[n] = Tk_InternAtom(tkwin, Tcl_DStringValue(&ds)); 4915 Tcl_DStringFree(&ds); 4916 } 4917 4918 wmPtr = winPtr->wmInfoPtr; 4919 if (wmPtr->wrapperPtr == NULL) { 4920 CreateWrapper(wmPtr); 4921 } 4922 wrapperPtr = wmPtr->wrapperPtr; 4923 4924 typeAtom = Tk_InternAtom(tkwin, "_NET_WM_WINDOW_TYPE"); 4925 XChangeProperty(Tk_Display(tkwin), wrapperPtr->window, typeAtom, 4926 XA_ATOM, 32, PropModeReplace, (unsigned char *) atoms, objc); 4927 4928 ckfree((char *)atoms); 4929 return TCL_OK; 4930} 4931 4932/* 4933 *---------------------------------------------------------------------- 4934 * 4935 * GetNetWmType -- 4936 * 4937 * Read the extended window manager type hint from a window 4938 * and return as a list of names suitable for use with 4939 * SetNetWmType. 4940 * 4941 *---------------------------------------------------------------------- 4942 */ 4943 4944static Tcl_Obj * 4945GetNetWmType(winPtr) 4946 TkWindow *winPtr; 4947{ 4948 Atom typeAtom, actualType, *atoms; 4949 int actualFormat; 4950 unsigned long n, count, bytesAfter; 4951 unsigned char *propertyValue = NULL; 4952 long maxLength = 1024; 4953 Tk_Window tkwin = (Tk_Window)winPtr; 4954 TkWindow *wrapperPtr; 4955 Tcl_Obj *typePtr; 4956 Tcl_Interp *interp; 4957 Tcl_DString ds; 4958 4959 interp = winPtr->mainPtr->interp; 4960 typePtr = Tcl_NewListObj(0, NULL); 4961 4962 if (winPtr->wmInfoPtr->wrapperPtr == NULL) { 4963 CreateWrapper(winPtr->wmInfoPtr); 4964 } 4965 wrapperPtr = winPtr->wmInfoPtr->wrapperPtr; 4966 4967 typeAtom = Tk_InternAtom(tkwin, "_NET_WM_WINDOW_TYPE"); 4968 if (Success == XGetWindowProperty(wrapperPtr->display, 4969 wrapperPtr->window, typeAtom, 0L, maxLength, False, 4970 XA_ATOM, &actualType, &actualFormat, &count, 4971 &bytesAfter, &propertyValue)) { 4972 atoms = (Atom *)propertyValue; 4973 for (n = 0; n < count; ++n) { 4974 const char *name = Tk_GetAtomName(tkwin, atoms[n]); 4975 if (strncmp("_NET_WM_WINDOW_TYPE_", name, 20) == 0) { 4976 Tcl_ExternalToUtfDString(NULL, name+20, -1, &ds); 4977 Tcl_UtfToLower(Tcl_DStringValue(&ds)); 4978 Tcl_ListObjAppendElement(interp, typePtr, 4979 Tcl_NewStringObj(Tcl_DStringValue(&ds), 4980 Tcl_DStringLength(&ds))); 4981 Tcl_DStringFree(&ds); 4982 } 4983 } 4984 XFree(propertyValue); 4985 } 4986 4987 return typePtr; 4988} 4989 4990/* 4991 *-------------------------------------------------------------- 4992 * 4993 * ParseGeometry -- 4994 * 4995 * This procedure parses a geometry string and updates 4996 * information used to control the geometry of a top-level 4997 * window. 4998 * 4999 * Results: 5000 * A standard Tcl return value, plus an error message in 5001 * the interp's result if an error occurs. 5002 * 5003 * Side effects: 5004 * The size and/or location of winPtr may change. 5005 * 5006 *-------------------------------------------------------------- 5007 */ 5008 5009static int 5010ParseGeometry(interp, string, winPtr) 5011 Tcl_Interp *interp; /* Used for error reporting. */ 5012 char *string; /* String containing new geometry. Has the 5013 * standard form "=wxh+x+y". */ 5014 TkWindow *winPtr; /* Pointer to top-level window whose 5015 * geometry is to be changed. */ 5016{ 5017 register WmInfo *wmPtr = winPtr->wmInfoPtr; 5018 int x, y, width, height, flags; 5019 char *end; 5020 register char *p = string; 5021 5022 /* 5023 * The leading "=" is optional. 5024 */ 5025 5026 if (*p == '=') { 5027 p++; 5028 } 5029 5030 /* 5031 * Parse the width and height, if they are present. Don't 5032 * actually update any of the fields of wmPtr until we've 5033 * successfully parsed the entire geometry string. 5034 */ 5035 5036 width = wmPtr->width; 5037 height = wmPtr->height; 5038 x = wmPtr->x; 5039 y = wmPtr->y; 5040 flags = wmPtr->flags; 5041 if (isdigit(UCHAR(*p))) { 5042 width = strtoul(p, &end, 10); 5043 p = end; 5044 if (*p != 'x') { 5045 goto error; 5046 } 5047 p++; 5048 if (!isdigit(UCHAR(*p))) { 5049 goto error; 5050 } 5051 height = strtoul(p, &end, 10); 5052 p = end; 5053 } 5054 5055 /* 5056 * Parse the X and Y coordinates, if they are present. 5057 */ 5058 5059 if (*p != '\0') { 5060 flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y); 5061 if (*p == '-') { 5062 flags |= WM_NEGATIVE_X; 5063 } else if (*p != '+') { 5064 goto error; 5065 } 5066 p++; 5067 if (!isdigit(UCHAR(*p)) && (*p != '-')) { 5068 goto error; 5069 } 5070 x = strtol(p, &end, 10); 5071 p = end; 5072 if (*p == '-') { 5073 flags |= WM_NEGATIVE_Y; 5074 } else if (*p != '+') { 5075 goto error; 5076 } 5077 p++; 5078 if (!isdigit(UCHAR(*p)) && (*p != '-')) { 5079 goto error; 5080 } 5081 y = strtol(p, &end, 10); 5082 if (*end != '\0') { 5083 goto error; 5084 } 5085 5086 /* 5087 * Assume that the geometry information came from the user, 5088 * unless an explicit source has been specified. Otherwise 5089 * most window managers assume that the size hints were 5090 * program-specified and they ignore them. 5091 */ 5092 5093 if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) { 5094 wmPtr->sizeHintsFlags |= USPosition; 5095 flags |= WM_UPDATE_SIZE_HINTS; 5096 } 5097 } 5098 5099 /* 5100 * Everything was parsed OK. Update the fields of *wmPtr and 5101 * arrange for the appropriate information to be percolated out 5102 * to the window manager at the next idle moment. 5103 */ 5104 5105 wmPtr->width = width; 5106 wmPtr->height = height; 5107 wmPtr->x = x; 5108 wmPtr->y = y; 5109 flags |= WM_MOVE_PENDING; 5110 wmPtr->flags = flags; 5111 5112 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { 5113 Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr); 5114 wmPtr->flags |= WM_UPDATE_PENDING; 5115 } 5116 return TCL_OK; 5117 5118 error: 5119 Tcl_AppendResult(interp, "bad geometry specifier \"", 5120 string, "\"", (char *) NULL); 5121 return TCL_ERROR; 5122} 5123 5124/* 5125 *---------------------------------------------------------------------- 5126 * 5127 * Tk_GetRootCoords -- 5128 * 5129 * Given a token for a window, this procedure traces through the 5130 * window's lineage to find the (virtual) root-window coordinates 5131 * corresponding to point (0,0) in the window. 5132 * 5133 * Results: 5134 * The locations pointed to by xPtr and yPtr are filled in with 5135 * the root coordinates of the (0,0) point in tkwin. If a virtual 5136 * root window is in effect for the window, then the coordinates 5137 * in the virtual root are returned. 5138 * 5139 * Side effects: 5140 * None. 5141 * 5142 *---------------------------------------------------------------------- 5143 */ 5144 5145void 5146Tk_GetRootCoords(tkwin, xPtr, yPtr) 5147 Tk_Window tkwin; /* Token for window. */ 5148 int *xPtr; /* Where to store x-displacement of (0,0). */ 5149 int *yPtr; /* Where to store y-displacement of (0,0). */ 5150{ 5151 int x, y; 5152 register TkWindow *winPtr = (TkWindow *) tkwin; 5153 5154 /* 5155 * Search back through this window's parents all the way to a 5156 * top-level window, combining the offsets of each window within 5157 * its parent. 5158 */ 5159 5160 x = y = 0; 5161 while (1) { 5162 x += winPtr->changes.x + winPtr->changes.border_width; 5163 y += winPtr->changes.y + winPtr->changes.border_width; 5164 if ((winPtr->wmInfoPtr != NULL) 5165 && (winPtr->wmInfoPtr->menubar == (Tk_Window) winPtr)) { 5166 /* 5167 * This window is a special menubar; switch over to its 5168 * associated toplevel, compensate for their differences in 5169 * y coordinates, then continue with the toplevel (in case 5170 * it's embedded). 5171 */ 5172 5173 y -= winPtr->wmInfoPtr->menuHeight; 5174 winPtr = winPtr->wmInfoPtr->winPtr; 5175 continue; 5176 } 5177 if (winPtr->flags & TK_TOP_LEVEL) { 5178 TkWindow *otherPtr; 5179 5180 if (!(winPtr->flags & TK_EMBEDDED)) { 5181 break; 5182 } 5183 otherPtr = TkpGetOtherWindow(winPtr); 5184 if (otherPtr == NULL) { 5185 /* 5186 * The container window is not in the same application. 5187 * Query the X server. 5188 */ 5189 5190 Window root, dummyChild; 5191 int rootX, rootY; 5192 5193 root = winPtr->wmInfoPtr->vRoot; 5194 if (root == None) { 5195 root = RootWindowOfScreen(Tk_Screen((Tk_Window)winPtr)); 5196 } 5197 XTranslateCoordinates(winPtr->display, winPtr->window, 5198 root, 0, 0, &rootX, &rootY, &dummyChild); 5199 x += rootX; 5200 y += rootY; 5201 break; 5202 } else { 5203 /* 5204 * The container window is in the same application. 5205 * Let's query its coordinates. 5206 */ 5207 5208 winPtr = otherPtr; 5209 continue; 5210 } 5211 } 5212 winPtr = winPtr->parentPtr; 5213 if (winPtr == NULL) { 5214 break; 5215 } 5216 } 5217 *xPtr = x; 5218 *yPtr = y; 5219} 5220 5221/* 5222 *---------------------------------------------------------------------- 5223 * 5224 * Tk_CoordsToWindow -- 5225 * 5226 * Given the (virtual) root coordinates of a point, this procedure 5227 * returns the token for the top-most window covering that point, 5228 * if there exists such a window in this application. 5229 * 5230 * Results: 5231 * The return result is either a token for the window corresponding 5232 * to rootX and rootY, or else NULL to indicate that there is no such 5233 * window. 5234 * 5235 * Side effects: 5236 * None. 5237 * 5238 *---------------------------------------------------------------------- 5239 */ 5240 5241Tk_Window 5242Tk_CoordsToWindow(rootX, rootY, tkwin) 5243 int rootX, rootY; /* Coordinates of point in root window. If 5244 * a virtual-root window manager is in use, 5245 * these coordinates refer to the virtual 5246 * root, not the real root. */ 5247 Tk_Window tkwin; /* Token for any window in application; 5248 * used to identify the display. */ 5249{ 5250 Window window, parent, child; 5251 int x, y, childX, childY, tmpx, tmpy, bd; 5252 WmInfo *wmPtr; 5253 TkWindow *winPtr, *childPtr, *nextPtr; 5254 TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; 5255 Tk_ErrorHandler handler = NULL; 5256 5257 /* 5258 * Step 1: scan the list of toplevel windows to see if there is a 5259 * virtual root for the screen we're interested in. If so, we have 5260 * to translate the coordinates from virtual root to root 5261 * coordinates. 5262 */ 5263 5264 parent = window = RootWindowOfScreen(Tk_Screen(tkwin)); 5265 x = rootX; 5266 y = rootY; 5267 for (wmPtr = (WmInfo *) dispPtr->firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) { 5268 if (Tk_Screen(wmPtr->winPtr) != Tk_Screen(tkwin)) { 5269 continue; 5270 } 5271 if (wmPtr->vRoot == None) { 5272 continue; 5273 } 5274 UpdateVRootGeometry(wmPtr); 5275 parent = wmPtr->vRoot; 5276 break; 5277 } 5278 5279 /* 5280 * Step 2: work down through the window hierarchy starting at the 5281 * root. For each window, find the child that contains the given 5282 * point and then see if this child is either a wrapper for one of 5283 * our toplevel windows or a window manager decoration window for 5284 * one of our toplevels. This approach handles several tricky 5285 * cases: 5286 * 5287 * 1. There may be a virtual root window between the root and one of 5288 * our toplevels. 5289 * 2. If a toplevel is embedded, we may have to search through the 5290 * windows of the container application(s) before getting to 5291 * the toplevel. 5292 */ 5293 5294 handler = Tk_CreateErrorHandler(Tk_Display(tkwin), -1, -1, -1, 5295 (Tk_ErrorProc *) NULL, (ClientData) NULL); 5296 while (1) { 5297 if (XTranslateCoordinates(Tk_Display(tkwin), parent, window, 5298 x, y, &childX, &childY, &child) == False) { 5299 /* 5300 * We can end up here when the window is in the middle of 5301 * being deleted 5302 */ 5303 Tk_DeleteErrorHandler(handler); 5304 return NULL; 5305 } 5306 if (child == None) { 5307 Tk_DeleteErrorHandler(handler); 5308 return NULL; 5309 } 5310 for (wmPtr = (WmInfo *) dispPtr->firstWmPtr; wmPtr != NULL; 5311 wmPtr = wmPtr->nextPtr) { 5312 if (wmPtr->reparent == child) { 5313 goto gotToplevel; 5314 } 5315 if (wmPtr->wrapperPtr != NULL) { 5316 if (child == wmPtr->wrapperPtr->window) { 5317 goto gotToplevel; 5318 } 5319 } else if (child == wmPtr->winPtr->window) { 5320 goto gotToplevel; 5321 } 5322 } 5323 x = childX; 5324 y = childY; 5325 parent = window; 5326 window = child; 5327 } 5328 5329 gotToplevel: 5330 if (handler) { 5331 /* 5332 * Check value of handler, because we can reach this label 5333 * from above or below 5334 */ 5335 Tk_DeleteErrorHandler(handler); 5336 handler = NULL; 5337 } 5338 winPtr = wmPtr->winPtr; 5339 if (winPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr) { 5340 return NULL; 5341 } 5342 5343 /* 5344 * Step 3: at this point winPtr and wmPtr refer to the toplevel that 5345 * contains the given coordinates, and childX and childY give the 5346 * translated coordinates in the *parent* of the toplevel. Now 5347 * decide whether the coordinates are in the menubar or the actual 5348 * toplevel, and translate the coordinates into the coordinate 5349 * system of that window. 5350 */ 5351 5352 x = childX - winPtr->changes.x; 5353 y = childY - winPtr->changes.y; 5354 if ((x < 0) || (x >= winPtr->changes.width) 5355 || (y >= winPtr->changes.height)) { 5356 return NULL; 5357 } 5358 if (y < 0) { 5359 winPtr = (TkWindow *) wmPtr->menubar; 5360 if (winPtr == NULL) { 5361 return NULL; 5362 } 5363 y += wmPtr->menuHeight; 5364 if (y < 0) { 5365 return NULL; 5366 } 5367 } 5368 5369 /* 5370 * Step 4: work down through the hierarchy underneath the current 5371 * window. At each level, scan through all the children to find the 5372 * highest one in the stacking order that contains the point. Then 5373 * repeat the whole process on that child. 5374 */ 5375 5376 while (1) { 5377 nextPtr = NULL; 5378 for (childPtr = winPtr->childList; childPtr != NULL; 5379 childPtr = childPtr->nextPtr) { 5380 if (!Tk_IsMapped(childPtr) || (childPtr->flags & TK_TOP_HIERARCHY)) { 5381 continue; 5382 } 5383 if (childPtr->flags & TK_REPARENTED) { 5384 continue; 5385 } 5386 tmpx = x - childPtr->changes.x; 5387 tmpy = y - childPtr->changes.y; 5388 bd = childPtr->changes.border_width; 5389 if ((tmpx >= -bd) && (tmpy >= -bd) 5390 && (tmpx < (childPtr->changes.width + bd)) 5391 && (tmpy < (childPtr->changes.height + bd))) { 5392 nextPtr = childPtr; 5393 } 5394 } 5395 if (nextPtr == NULL) { 5396 break; 5397 } 5398 winPtr = nextPtr; 5399 x -= winPtr->changes.x; 5400 y -= winPtr->changes.y; 5401 if ((winPtr->flags & TK_CONTAINER) 5402 && (winPtr->flags & TK_BOTH_HALVES)) { 5403 /* 5404 * The window containing the point is a container, and the 5405 * embedded application is in this same process. Switch 5406 * over to the toplevel for the embedded application and 5407 * start processing that toplevel from scratch. 5408 */ 5409 5410 winPtr = TkpGetOtherWindow(winPtr); 5411 if (winPtr == NULL) { 5412 return NULL; 5413 } 5414 wmPtr = winPtr->wmInfoPtr; 5415 childX = x; 5416 childY = y; 5417 goto gotToplevel; 5418 } 5419 } 5420 return (Tk_Window) winPtr; 5421} 5422 5423/* 5424 *---------------------------------------------------------------------- 5425 * 5426 * UpdateVRootGeometry -- 5427 * 5428 * This procedure is called to update all the virtual root 5429 * geometry information in wmPtr. 5430 * 5431 * Results: 5432 * None. 5433 * 5434 * Side effects: 5435 * The vRootX, vRootY, vRootWidth, and vRootHeight fields in 5436 * wmPtr are filled with the most up-to-date information. 5437 * 5438 *---------------------------------------------------------------------- 5439 */ 5440 5441static void 5442UpdateVRootGeometry(wmPtr) 5443 WmInfo *wmPtr; /* Window manager information to be 5444 * updated. The wmPtr->vRoot field must 5445 * be valid. */ 5446{ 5447 TkWindow *winPtr = wmPtr->winPtr; 5448 int bd; 5449 unsigned int dummy; 5450 Window dummy2; 5451 Status status; 5452 Tk_ErrorHandler handler; 5453 5454 /* 5455 * If this isn't a virtual-root window manager, just return information 5456 * about the screen. 5457 */ 5458 5459 wmPtr->flags &= ~WM_VROOT_OFFSET_STALE; 5460 if (wmPtr->vRoot == None) { 5461 noVRoot: 5462 wmPtr->vRootX = wmPtr->vRootY = 0; 5463 wmPtr->vRootWidth = DisplayWidth(winPtr->display, winPtr->screenNum); 5464 wmPtr->vRootHeight = DisplayHeight(winPtr->display, winPtr->screenNum); 5465 return; 5466 } 5467 5468 /* 5469 * Refresh the virtual root information if it's out of date. 5470 */ 5471 5472 handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1, 5473 (Tk_ErrorProc *) NULL, (ClientData) NULL); 5474 status = XGetGeometry(winPtr->display, wmPtr->vRoot, 5475 &dummy2, &wmPtr->vRootX, &wmPtr->vRootY, 5476 (unsigned int *) &wmPtr->vRootWidth, 5477 (unsigned int *) &wmPtr->vRootHeight, (unsigned int *) &bd, 5478 &dummy); 5479 if (winPtr->dispPtr->flags & TK_DISPLAY_WM_TRACING) { 5480 printf("UpdateVRootGeometry: x = %d, y = %d, width = %d, ", 5481 wmPtr->vRootX, wmPtr->vRootY, wmPtr->vRootWidth); 5482 printf("height = %d, status = %d\n", wmPtr->vRootHeight, status); 5483 } 5484 Tk_DeleteErrorHandler(handler); 5485 if (status == 0) { 5486 /* 5487 * The virtual root is gone! Pretend that it never existed. 5488 */ 5489 5490 wmPtr->vRoot = None; 5491 goto noVRoot; 5492 } 5493} 5494 5495/* 5496 *---------------------------------------------------------------------- 5497 * 5498 * Tk_GetVRootGeometry -- 5499 * 5500 * This procedure returns information about the virtual root 5501 * window corresponding to a particular Tk window. 5502 * 5503 * Results: 5504 * The values at xPtr, yPtr, widthPtr, and heightPtr are set 5505 * with the offset and dimensions of the root window corresponding 5506 * to tkwin. If tkwin is being managed by a virtual root window 5507 * manager these values correspond to the virtual root window being 5508 * used for tkwin; otherwise the offsets will be 0 and the 5509 * dimensions will be those of the screen. 5510 * 5511 * Side effects: 5512 * Vroot window information is refreshed if it is out of date. 5513 * 5514 *---------------------------------------------------------------------- 5515 */ 5516 5517void 5518Tk_GetVRootGeometry(tkwin, xPtr, yPtr, widthPtr, heightPtr) 5519 Tk_Window tkwin; /* Window whose virtual root is to be 5520 * queried. */ 5521 int *xPtr, *yPtr; /* Store x and y offsets of virtual root 5522 * here. */ 5523 int *widthPtr, *heightPtr; /* Store dimensions of virtual root here. */ 5524{ 5525 WmInfo *wmPtr; 5526 TkWindow *winPtr = (TkWindow *) tkwin; 5527 5528 /* 5529 * Find the top-level window for tkwin, and locate the window manager 5530 * information for that window. 5531 */ 5532 5533 while (!(winPtr->flags & TK_TOP_HIERARCHY) && (winPtr->parentPtr != NULL)) { 5534 winPtr = winPtr->parentPtr; 5535 } 5536 wmPtr = winPtr->wmInfoPtr; 5537 if (wmPtr == NULL) { 5538 /* Punt. */ 5539 *xPtr = 0; 5540 *yPtr = 0; 5541 *widthPtr = 0; 5542 *heightPtr = 0; 5543 } 5544 5545 5546 /* 5547 * Make sure that the geometry information is up-to-date, then copy 5548 * it out to the caller. 5549 */ 5550 5551 if (wmPtr->flags & WM_VROOT_OFFSET_STALE) { 5552 UpdateVRootGeometry(wmPtr); 5553 } 5554 *xPtr = wmPtr->vRootX; 5555 *yPtr = wmPtr->vRootY; 5556 *widthPtr = wmPtr->vRootWidth; 5557 *heightPtr = wmPtr->vRootHeight; 5558} 5559 5560/* 5561 *---------------------------------------------------------------------- 5562 * 5563 * Tk_MoveToplevelWindow -- 5564 * 5565 * This procedure is called instead of Tk_MoveWindow to adjust 5566 * the x-y location of a top-level window. It delays the actual 5567 * move to a later time and keeps window-manager information 5568 * up-to-date with the move 5569 * 5570 * Results: 5571 * None. 5572 * 5573 * Side effects: 5574 * The window is eventually moved so that its upper-left corner 5575 * (actually, the upper-left corner of the window's decorative 5576 * frame, if there is one) is at (x,y). 5577 * 5578 *---------------------------------------------------------------------- 5579 */ 5580 5581void 5582Tk_MoveToplevelWindow(tkwin, x, y) 5583 Tk_Window tkwin; /* Window to move. */ 5584 int x, y; /* New location for window (within 5585 * parent). */ 5586{ 5587 TkWindow *winPtr = (TkWindow *) tkwin; 5588 register WmInfo *wmPtr = winPtr->wmInfoPtr; 5589 5590 if (!(winPtr->flags & TK_TOP_LEVEL)) { 5591 Tcl_Panic("Tk_MoveToplevelWindow called with non-toplevel window"); 5592 } 5593 wmPtr->x = x; 5594 wmPtr->y = y; 5595 wmPtr->flags |= WM_MOVE_PENDING; 5596 wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y); 5597 if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) { 5598 wmPtr->sizeHintsFlags |= USPosition; 5599 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 5600 } 5601 5602 /* 5603 * If the window has already been mapped, must bring its geometry 5604 * up-to-date immediately, otherwise an event might arrive from the 5605 * server that would overwrite wmPtr->x and wmPtr->y and lose the 5606 * new position. 5607 */ 5608 5609 if (!(wmPtr->flags & WM_NEVER_MAPPED)) { 5610 if (wmPtr->flags & WM_UPDATE_PENDING) { 5611 Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr); 5612 } 5613 UpdateGeometryInfo((ClientData) winPtr); 5614 } 5615} 5616 5617/* 5618 *---------------------------------------------------------------------- 5619 * 5620 * UpdateWmProtocols -- 5621 * 5622 * This procedure transfers the most up-to-date information about 5623 * window manager protocols from the WmInfo structure to the actual 5624 * property on the top-level window. 5625 * 5626 * Results: 5627 * None. 5628 * 5629 * Side effects: 5630 * The WM_PROTOCOLS property gets changed for wmPtr's window. 5631 * 5632 *---------------------------------------------------------------------- 5633 */ 5634 5635static void 5636UpdateWmProtocols(wmPtr) 5637 register WmInfo *wmPtr; /* Information about top-level window. */ 5638{ 5639 register ProtocolHandler *protPtr; 5640 Atom deleteWindowAtom; 5641 int count; 5642 Atom *arrayPtr, *atomPtr; 5643 5644 /* 5645 * There are only two tricky parts here. First, there could be any 5646 * number of atoms for the window, so count them and malloc an array 5647 * to hold all of their atoms. Second, we *always* want to respond 5648 * to the WM_DELETE_WINDOW protocol, even if no-one's officially asked. 5649 */ 5650 5651 for (protPtr = wmPtr->protPtr, count = 1; protPtr != NULL; 5652 protPtr = protPtr->nextPtr, count++) { 5653 /* Empty loop body; we're just counting the handlers. */ 5654 } 5655 arrayPtr = (Atom *) ckalloc((unsigned) (count * sizeof(Atom))); 5656 deleteWindowAtom = Tk_InternAtom((Tk_Window) wmPtr->winPtr, 5657 "WM_DELETE_WINDOW"); 5658 arrayPtr[0] = deleteWindowAtom; 5659 for (protPtr = wmPtr->protPtr, atomPtr = &arrayPtr[1]; 5660 protPtr != NULL; protPtr = protPtr->nextPtr) { 5661 if (protPtr->protocol != deleteWindowAtom) { 5662 *atomPtr = protPtr->protocol; 5663 atomPtr++; 5664 } 5665 } 5666 XChangeProperty(wmPtr->winPtr->display, wmPtr->wrapperPtr->window, 5667 Tk_InternAtom((Tk_Window) wmPtr->winPtr, "WM_PROTOCOLS"), 5668 XA_ATOM, 32, PropModeReplace, (unsigned char *) arrayPtr, 5669 atomPtr-arrayPtr); 5670 ckfree((char *) arrayPtr); 5671} 5672 5673/* 5674 *---------------------------------------------------------------------- 5675 * 5676 * TkWmProtocolEventProc -- 5677 * 5678 * This procedure is called by the Tk_HandleEvent whenever a 5679 * ClientMessage event arrives whose type is "WM_PROTOCOLS". 5680 * This procedure handles the message from the window manager 5681 * in an appropriate fashion. 5682 * 5683 * Results: 5684 * None. 5685 * 5686 * Side effects: 5687 * Depends on what sort of handler, if any, was set up for the 5688 * protocol. 5689 * 5690 *---------------------------------------------------------------------- 5691 */ 5692 5693void 5694TkWmProtocolEventProc(winPtr, eventPtr) 5695 TkWindow *winPtr; /* Window to which the event was sent. */ 5696 XEvent *eventPtr; /* X event. */ 5697{ 5698 WmInfo *wmPtr; 5699 register ProtocolHandler *protPtr; 5700 Atom protocol; 5701 int result; 5702 CONST char *protocolName; 5703 Tcl_Interp *interp; 5704 5705 wmPtr = winPtr->wmInfoPtr; 5706 if (wmPtr == NULL) { 5707 return; 5708 } 5709 protocol = (Atom) eventPtr->xclient.data.l[0]; 5710 5711 /* 5712 * Note: it's very important to retrieve the protocol name now, 5713 * before invoking the command, even though the name won't be used 5714 * until after the command returns. This is because the command 5715 * could delete winPtr, making it impossible for us to use it 5716 * later in the call to Tk_GetAtomName. 5717 */ 5718 5719 protocolName = Tk_GetAtomName((Tk_Window) winPtr, protocol); 5720 for (protPtr = wmPtr->protPtr; protPtr != NULL; 5721 protPtr = protPtr->nextPtr) { 5722 if (protocol == protPtr->protocol) { 5723 Tcl_Preserve((ClientData) protPtr); 5724 interp = protPtr->interp; 5725 Tcl_Preserve((ClientData) interp); 5726 result = Tcl_GlobalEval(interp, protPtr->command); 5727 if (result != TCL_OK) { 5728 Tcl_AddErrorInfo(interp, "\n (command for \""); 5729 Tcl_AddErrorInfo(interp, protocolName); 5730 Tcl_AddErrorInfo(interp, 5731 "\" window manager protocol)"); 5732 Tcl_BackgroundError(interp); 5733 } 5734 Tcl_Release((ClientData) interp); 5735 Tcl_Release((ClientData) protPtr); 5736 return; 5737 } 5738 } 5739 5740 /* 5741 * No handler was present for this protocol. If this is a 5742 * WM_DELETE_WINDOW message then just destroy the window. 5743 */ 5744 5745 if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) { 5746 Tk_DestroyWindow((Tk_Window) wmPtr->winPtr); 5747 } 5748} 5749 5750/* 5751 *---------------------------------------------------------------------- 5752 * 5753 * TkWmStackorderToplevelWrapperMap -- 5754 * 5755 * This procedure will create a table that maps the reparent wrapper 5756 * X id for a toplevel to the TkWindow structure that is wraps. 5757 * Tk keeps track of a mapping from the window X id to the TkWindow 5758 * structure but that does us no good here since we only get the X 5759 * id of the wrapper window. Only those toplevel windows that are 5760 * mapped have a position in the stacking order. 5761 * 5762 * Results: 5763 * None. 5764 * 5765 * Side effects: 5766 * Adds entries to the passed hashtable. 5767 * 5768 *---------------------------------------------------------------------- 5769 */ 5770 5771static void 5772TkWmStackorderToplevelWrapperMap(winPtr, display, table) 5773 TkWindow *winPtr; /* TkWindow to recurse on */ 5774 Display *display; /* X display of parent window */ 5775 Tcl_HashTable *table; /* Maps X id to TkWindow */ 5776{ 5777 TkWindow *childPtr; 5778 Tcl_HashEntry *hPtr; 5779 Window wrapper; 5780 int newEntry; 5781 5782 if (Tk_IsMapped(winPtr) && Tk_IsTopLevel(winPtr) && 5783 !Tk_IsEmbedded(winPtr) && (winPtr->display == display)) { 5784 wrapper = (winPtr->wmInfoPtr->reparent != None) 5785 ? winPtr->wmInfoPtr->reparent 5786 : winPtr->wmInfoPtr->wrapperPtr->window; 5787 5788 hPtr = Tcl_CreateHashEntry(table, 5789 (char *) wrapper, &newEntry); 5790 Tcl_SetHashValue(hPtr, winPtr); 5791 } 5792 5793 for (childPtr = winPtr->childList; childPtr != NULL; 5794 childPtr = childPtr->nextPtr) { 5795 TkWmStackorderToplevelWrapperMap(childPtr, display, table); 5796 } 5797} 5798 5799/* 5800 *---------------------------------------------------------------------- 5801 * 5802 * TkWmStackorderToplevel -- 5803 * 5804 * This procedure returns the stack order of toplevel windows. 5805 * 5806 * Results: 5807 * An array of pointers to tk window objects in stacking order 5808 * or else NULL if there was an error. 5809 * 5810 * Side effects: 5811 * None. 5812 * 5813 *---------------------------------------------------------------------- 5814 */ 5815 5816TkWindow ** 5817TkWmStackorderToplevel(parentPtr) 5818 TkWindow *parentPtr; /* Parent toplevel window. */ 5819{ 5820 Window dummy1, dummy2, vRoot; 5821 Window *children; 5822 unsigned int numChildren, i; 5823 TkWindow *childWinPtr, **windows, **window_ptr; 5824 Tcl_HashTable table; 5825 Tcl_HashEntry *hPtr; 5826 Tcl_HashSearch search; 5827 5828 /* 5829 * Map X Window ids to a TkWindow of the wrapped toplevel. 5830 */ 5831 5832 Tcl_InitHashTable(&table, TCL_ONE_WORD_KEYS); 5833 TkWmStackorderToplevelWrapperMap(parentPtr, parentPtr->display, &table); 5834 5835 window_ptr = windows = (TkWindow **) ckalloc((table.numEntries+1) 5836 * sizeof(TkWindow *)); 5837 5838 /* 5839 * Special cases: If zero or one toplevels were mapped 5840 * there is no need to call XQueryTree. 5841 */ 5842 5843 switch (table.numEntries) { 5844 case 0: 5845 windows[0] = NULL; 5846 goto done; 5847 case 1: 5848 hPtr = Tcl_FirstHashEntry(&table, &search); 5849 windows[0] = (TkWindow *) Tcl_GetHashValue(hPtr); 5850 windows[1] = NULL; 5851 goto done; 5852 } 5853 5854 vRoot = parentPtr->wmInfoPtr->vRoot; 5855 if (vRoot == None) { 5856 vRoot = RootWindowOfScreen(Tk_Screen((Tk_Window) parentPtr)); 5857 } 5858 5859 if (XQueryTree(parentPtr->display, vRoot, &dummy1, &dummy2, 5860 &children, &numChildren) == 0) { 5861 ckfree((char *) windows); 5862 windows = NULL; 5863 } else { 5864 for (i = 0; i < numChildren; i++) { 5865 hPtr = Tcl_FindHashEntry(&table, (char *) children[i]); 5866 if (hPtr != NULL) { 5867 childWinPtr = (TkWindow *) Tcl_GetHashValue(hPtr); 5868 *window_ptr++ = childWinPtr; 5869 } 5870 } 5871 if ((window_ptr - windows) != table.numEntries) 5872 Tcl_Panic("num matched toplevel windows does not equal num children"); 5873 *window_ptr = NULL; 5874 if (numChildren) { 5875 XFree((char *) children); 5876 } 5877 } 5878 5879 done: 5880 Tcl_DeleteHashTable(&table); 5881 return windows; 5882} 5883 5884/* 5885 *---------------------------------------------------------------------- 5886 * 5887 * TkWmRestackToplevel -- 5888 * 5889 * This procedure restacks a top-level window. 5890 * 5891 * Results: 5892 * None. 5893 * 5894 * Side effects: 5895 * WinPtr gets restacked as specified by aboveBelow and otherPtr. 5896 * 5897 *---------------------------------------------------------------------- 5898 */ 5899 5900void 5901TkWmRestackToplevel(winPtr, aboveBelow, otherPtr) 5902 TkWindow *winPtr; /* Window to restack. */ 5903 int aboveBelow; /* Gives relative position for restacking; 5904 * must be Above or Below. */ 5905 TkWindow *otherPtr; /* Window relative to which to restack; 5906 * if NULL, then winPtr gets restacked 5907 * above or below *all* siblings. */ 5908{ 5909 XWindowChanges changes; 5910 unsigned int mask; 5911 TkWindow *wrapperPtr; 5912 5913 memset(&changes, 0, sizeof(XWindowChanges)); 5914 changes.stack_mode = aboveBelow; 5915 mask = CWStackMode; 5916 5917 /* 5918 * Make sure that winPtr and its wrapper window have been created. 5919 */ 5920 if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) { 5921 TkWmMapWindow(winPtr); 5922 } 5923 wrapperPtr = winPtr->wmInfoPtr->wrapperPtr; 5924 5925 if (otherPtr != NULL) { 5926 /* 5927 * The window is to be restacked with respect to another toplevel. 5928 * Make sure it has been created as well. 5929 */ 5930 if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) { 5931 TkWmMapWindow(otherPtr); 5932 } 5933 changes.sibling = otherPtr->wmInfoPtr->wrapperPtr->window; 5934 mask |= CWSibling; 5935 } 5936 5937 /* 5938 * Reconfigure the window. Note that we use XReconfigureWMWindow 5939 * instead of XConfigureWindow, in order to handle the case 5940 * where the window is to be restacked with respect to another toplevel. 5941 * See [ICCCM] 4.1.5 "Configuring the Window" and XReconfigureWMWindow(3) 5942 * for details. 5943 */ 5944 5945 XReconfigureWMWindow(winPtr->display, wrapperPtr->window, 5946 Tk_ScreenNumber((Tk_Window) winPtr), mask, &changes); 5947} 5948 5949 5950/* 5951 *---------------------------------------------------------------------- 5952 * 5953 * TkWmAddToColormapWindows -- 5954 * 5955 * This procedure is called to add a given window to the 5956 * WM_COLORMAP_WINDOWS property for its top-level, if it 5957 * isn't already there. It is invoked by the Tk code that 5958 * creates a new colormap, in order to make sure that colormap 5959 * information is propagated to the window manager by default. 5960 * 5961 * Results: 5962 * None. 5963 * 5964 * Side effects: 5965 * WinPtr's window gets added to the WM_COLORMAP_WINDOWS 5966 * property of its nearest top-level ancestor, unless the 5967 * colormaps have been set explicitly with the 5968 * "wm colormapwindows" command. 5969 * 5970 *---------------------------------------------------------------------- 5971 */ 5972 5973void 5974TkWmAddToColormapWindows(winPtr) 5975 TkWindow *winPtr; /* Window with a non-default colormap. 5976 * Should not be a top-level window. */ 5977{ 5978 TkWindow *wrapperPtr; 5979 TkWindow *topPtr; 5980 Window *oldPtr, *newPtr; 5981 int count, i; 5982 5983 if (winPtr->window == None) { 5984 return; 5985 } 5986 5987 for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) { 5988 if (topPtr == NULL) { 5989 /* 5990 * Window is being deleted. Skip the whole operation. 5991 */ 5992 5993 return; 5994 } 5995 if (topPtr->flags & TK_TOP_HIERARCHY) { 5996 break; 5997 } 5998 } 5999 if (topPtr->wmInfoPtr == NULL) { 6000 return; 6001 } 6002 6003 if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) { 6004 return; 6005 } 6006 if (topPtr->wmInfoPtr->wrapperPtr == NULL) { 6007 CreateWrapper(topPtr->wmInfoPtr); 6008 } 6009 wrapperPtr = topPtr->wmInfoPtr->wrapperPtr; 6010 6011 /* 6012 * Fetch the old value of the property. 6013 */ 6014 6015 if (XGetWMColormapWindows(topPtr->display, wrapperPtr->window, 6016 &oldPtr, &count) == 0) { 6017 oldPtr = NULL; 6018 count = 0; 6019 } 6020 6021 /* 6022 * Make sure that the window isn't already in the list. 6023 */ 6024 6025 for (i = 0; i < count; i++) { 6026 if (oldPtr[i] == winPtr->window) { 6027 return; 6028 } 6029 } 6030 6031 /* 6032 * Make a new bigger array and use it to reset the property. 6033 * Automatically add the toplevel itself as the last element 6034 * of the list. 6035 */ 6036 6037 newPtr = (Window *) ckalloc((unsigned) ((count+2)*sizeof(Window))); 6038 for (i = 0; i < count; i++) { 6039 newPtr[i] = oldPtr[i]; 6040 } 6041 if (count == 0) { 6042 count++; 6043 } 6044 newPtr[count-1] = winPtr->window; 6045 newPtr[count] = topPtr->window; 6046 XSetWMColormapWindows(topPtr->display, wrapperPtr->window, newPtr, 6047 count+1); 6048 ckfree((char *) newPtr); 6049 if (oldPtr != NULL) { 6050 XFree((char *) oldPtr); 6051 } 6052} 6053 6054/* 6055 *---------------------------------------------------------------------- 6056 * 6057 * TkWmRemoveFromColormapWindows -- 6058 * 6059 * This procedure is called to remove a given window from the 6060 * WM_COLORMAP_WINDOWS property for its top-level. It is invoked 6061 * when windows are deleted. 6062 * 6063 * Results: 6064 * None. 6065 * 6066 * Side effects: 6067 * WinPtr's window gets removed from the WM_COLORMAP_WINDOWS 6068 * property of its nearest top-level ancestor, unless the 6069 * top-level itself is being deleted too. 6070 * 6071 *---------------------------------------------------------------------- 6072 */ 6073 6074void 6075TkWmRemoveFromColormapWindows(winPtr) 6076 TkWindow *winPtr; /* Window that may be present in 6077 * WM_COLORMAP_WINDOWS property for its 6078 * top-level. Should not be a top-level 6079 * window. */ 6080{ 6081 TkWindow *wrapperPtr; 6082 TkWindow *topPtr; 6083 Window *oldPtr; 6084 int count, i, j; 6085 6086 if (winPtr->window == None) { 6087 return; 6088 } 6089 6090 for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) { 6091 if (topPtr == NULL) { 6092 /* 6093 * Ancestors have been deleted, so skip the whole operation. 6094 * Seems like this can't ever happen? 6095 */ 6096 6097 return; 6098 } 6099 if (topPtr->flags & TK_TOP_HIERARCHY) { 6100 break; 6101 } 6102 } 6103 if (topPtr->flags & TK_ALREADY_DEAD) { 6104 /* 6105 * Top-level is being deleted, so there's no need to cleanup 6106 * the WM_COLORMAP_WINDOWS property. 6107 */ 6108 6109 return; 6110 } 6111 if (topPtr->wmInfoPtr == NULL) { 6112 return; 6113 } 6114 6115 if (topPtr->wmInfoPtr->wrapperPtr == NULL) { 6116 CreateWrapper(topPtr->wmInfoPtr); 6117 } 6118 wrapperPtr = topPtr->wmInfoPtr->wrapperPtr; 6119 if (wrapperPtr == NULL) { 6120 return; 6121 } 6122 6123 /* 6124 * Fetch the old value of the property. 6125 */ 6126 6127 if (XGetWMColormapWindows(topPtr->display, wrapperPtr->window, 6128 &oldPtr, &count) == 0) { 6129 return; 6130 } 6131 6132 /* 6133 * Find the window and slide the following ones down to cover 6134 * it up. 6135 */ 6136 6137 for (i = 0; i < count; i++) { 6138 if (oldPtr[i] == winPtr->window) { 6139 for (j = i ; j < count-1; j++) { 6140 oldPtr[j] = oldPtr[j+1]; 6141 } 6142 XSetWMColormapWindows(topPtr->display, wrapperPtr->window, 6143 oldPtr, count-1); 6144 break; 6145 } 6146 } 6147 XFree((char *) oldPtr); 6148} 6149 6150/* 6151 *---------------------------------------------------------------------- 6152 * 6153 * TkGetPointerCoords -- 6154 * 6155 * Fetch the position of the mouse pointer. 6156 * 6157 * Results: 6158 * *xPtr and *yPtr are filled in with the (virtual) root coordinates 6159 * of the mouse pointer for tkwin's display. If the pointer isn't 6160 * on tkwin's screen, then -1 values are returned for both 6161 * coordinates. The argument tkwin must be a toplevel window. 6162 * 6163 * Side effects: 6164 * None. 6165 * 6166 *---------------------------------------------------------------------- 6167 */ 6168 6169void 6170TkGetPointerCoords(tkwin, xPtr, yPtr) 6171 Tk_Window tkwin; /* Toplevel window that identifies screen 6172 * on which lookup is to be done. */ 6173 int *xPtr, *yPtr; /* Store pointer coordinates here. */ 6174{ 6175 TkWindow *winPtr = (TkWindow *) tkwin; 6176 WmInfo *wmPtr; 6177 Window w, root, child; 6178 int rootX, rootY; 6179 unsigned int mask; 6180 6181 wmPtr = winPtr->wmInfoPtr; 6182 6183 w = wmPtr->vRoot; 6184 if (w == None) { 6185 w = RootWindow(winPtr->display, winPtr->screenNum); 6186 } 6187 if (XQueryPointer(winPtr->display, w, &root, &child, &rootX, &rootY, 6188 xPtr, yPtr, &mask) != True) { 6189 *xPtr = -1; 6190 *yPtr = -1; 6191 } 6192} 6193 6194/* 6195 *---------------------------------------------------------------------- 6196 * 6197 * GetMaxSize -- 6198 * 6199 * This procedure computes the current maxWidth and maxHeight 6200 * values for a window, taking into account the possibility 6201 * that they may be defaulted. 6202 * 6203 * Results: 6204 * The values at *maxWidthPtr and *maxHeightPtr are filled 6205 * in with the maximum allowable dimensions of wmPtr's window, 6206 * in grid units. If no maximum has been specified for the 6207 * window, then this procedure computes the largest sizes that 6208 * will fit on the screen. 6209 * 6210 * Side effects: 6211 * None. 6212 * 6213 *---------------------------------------------------------------------- 6214 */ 6215 6216static void 6217GetMaxSize(wmPtr, maxWidthPtr, maxHeightPtr) 6218 WmInfo *wmPtr; /* Window manager information for the 6219 * window. */ 6220 int *maxWidthPtr; /* Where to store the current maximum 6221 * width of the window. */ 6222 int *maxHeightPtr; /* Where to store the current maximum 6223 * height of the window. */ 6224{ 6225 int tmp; 6226 6227 if (wmPtr->maxWidth > 0) { 6228 *maxWidthPtr = wmPtr->maxWidth; 6229 } else { 6230 /* 6231 * Must compute a default width. Fill up the display, leaving a 6232 * bit of extra space for the window manager's borders. 6233 */ 6234 6235 tmp = DisplayWidth(wmPtr->winPtr->display, wmPtr->winPtr->screenNum) 6236 - 15; 6237 if (wmPtr->gridWin != NULL) { 6238 /* 6239 * Gridding is turned on; convert from pixels to grid units. 6240 */ 6241 6242 tmp = wmPtr->reqGridWidth 6243 + (tmp - wmPtr->winPtr->reqWidth)/wmPtr->widthInc; 6244 } 6245 *maxWidthPtr = tmp; 6246 } 6247 if (wmPtr->maxHeight > 0) { 6248 *maxHeightPtr = wmPtr->maxHeight; 6249 } else { 6250 tmp = DisplayHeight(wmPtr->winPtr->display, wmPtr->winPtr->screenNum) 6251 - 30; 6252 if (wmPtr->gridWin != NULL) { 6253 tmp = wmPtr->reqGridHeight 6254 + (tmp - wmPtr->winPtr->reqHeight)/wmPtr->heightInc; 6255 } 6256 *maxHeightPtr = tmp; 6257 } 6258} 6259 6260/* 6261 *---------------------------------------------------------------------- 6262 * 6263 * TkSetTransientFor -- 6264 * 6265 * Set a Tk window to be transient with reference to a specified 6266 * parent or the toplevel ancestor if None is passed as parent. 6267 * 6268 *---------------------------------------------------------------------- 6269 */ 6270 6271static void 6272TkSetTransientFor(tkwin, parent) 6273 Tk_Window tkwin; 6274 Tk_Window parent; 6275{ 6276 if (parent == None) { 6277 parent = Tk_Parent(tkwin); 6278 while (!Tk_IsTopLevel(parent)) 6279 parent = Tk_Parent(tkwin); 6280 } 6281 XSetTransientForHint(Tk_Display(tkwin), 6282 ((TkWindow *)tkwin)->wmInfoPtr->wrapperPtr->window, 6283 ((TkWindow *)parent)->wmInfoPtr->wrapperPtr->window); 6284} 6285 6286/* 6287 *---------------------------------------------------------------------- 6288 * 6289 * TkpMakeMenuWindow -- 6290 * 6291 * Configure the window to be either a pull-down (or pop-up) 6292 * menu, or as a toplevel (torn-off) menu or palette. 6293 * 6294 * Results: 6295 * None. 6296 * 6297 * Side effects: 6298 * Changes the style bit used to create a new Mac toplevel. 6299 * 6300 *---------------------------------------------------------------------- 6301 */ 6302 6303void 6304TkpMakeMenuWindow(tkwin, transient) 6305 Tk_Window tkwin; /* New window. */ 6306 int transient; /* 1 means menu is only posted briefly as 6307 * a popup or pulldown or cascade. 0 means 6308 * menu is always visible, e.g. as a torn-off 6309 * menu. Determines whether save_under and 6310 * override_redirect should be set. */ 6311{ 6312 WmInfo *wmPtr; 6313 XSetWindowAttributes atts; 6314 TkWindow *wrapperPtr; 6315 Tcl_Obj *typeObj; 6316 6317 if (!Tk_HasWrapper(tkwin)) { 6318 return; 6319 } 6320 wmPtr = ((TkWindow *) tkwin)->wmInfoPtr; 6321 if (wmPtr->wrapperPtr == NULL) { 6322 CreateWrapper(wmPtr); 6323 } 6324 wrapperPtr = wmPtr->wrapperPtr; 6325 if (transient) { 6326 atts.override_redirect = True; 6327 atts.save_under = True; 6328 typeObj = Tcl_NewStringObj("dropdown_menu", -1); 6329 } else { 6330 atts.override_redirect = False; 6331 atts.save_under = False; 6332 typeObj = Tcl_NewStringObj("menu", -1); 6333 TkSetTransientFor(tkwin, None); 6334 } 6335 SetNetWmType((TkWindow *)tkwin, typeObj); 6336 6337 /* 6338 * The override-redirect and save-under bits must be set on the 6339 * wrapper window in order to have the desired effect. However, 6340 * also set the override-redirect bit on the window itself, so 6341 * that the "wm overrideredirect" command will see it. 6342 */ 6343 6344 if ((atts.override_redirect != Tk_Attributes(wrapperPtr)->override_redirect) 6345 || (atts.save_under != Tk_Attributes(wrapperPtr)->save_under)) { 6346 Tk_ChangeWindowAttributes((Tk_Window) wrapperPtr, 6347 CWOverrideRedirect|CWSaveUnder, &atts); 6348 } 6349 if (atts.override_redirect != Tk_Attributes(tkwin)->override_redirect) { 6350 Tk_ChangeWindowAttributes(tkwin, CWOverrideRedirect, &atts); 6351 } 6352} 6353 6354/* 6355 *---------------------------------------------------------------------- 6356 * 6357 * CreateWrapper -- 6358 * 6359 * This procedure is invoked to create the wrapper window for a 6360 * toplevel window. It is called just before a toplevel is mapped 6361 * for the first time. 6362 * 6363 * Results: 6364 * None. 6365 * 6366 * Side effects: 6367 * The wrapper is created and the toplevel is reparented inside it. 6368 * 6369 *---------------------------------------------------------------------- 6370 */ 6371 6372static void 6373CreateWrapper(wmPtr) 6374 WmInfo *wmPtr; /* Window manager information for the 6375 * window. */ 6376{ 6377 TkWindow *winPtr, *wrapperPtr; 6378 Window parent; 6379 Tcl_HashEntry *hPtr; 6380 int new; 6381 6382 winPtr = wmPtr->winPtr; 6383 if (winPtr->window == None) { 6384 Tk_MakeWindowExist((Tk_Window) winPtr); 6385 } 6386 6387 /* 6388 * The code below is copied from CreateTopLevelWindow, 6389 * Tk_MakeWindowExist, and TkpMakeWindow; The idea is to create an 6390 * "official" Tk window (so that we can get events on it), but to 6391 * hide the window outside the official Tk hierarchy so that it 6392 * isn't visible to the application. See the comments for the other 6393 * procedures if you have questions about this code. 6394 */ 6395 6396 wmPtr->wrapperPtr = wrapperPtr = TkAllocWindow(winPtr->dispPtr, 6397 Tk_ScreenNumber((Tk_Window) winPtr), winPtr); 6398 wrapperPtr->dirtyAtts |= CWBorderPixel; 6399 6400 /* 6401 * Tk doesn't normally select for StructureNotifyMask events because 6402 * the events are synthesized internally. However, for wrapper 6403 * windows we need to know when the window manager modifies the 6404 * window configuration. We also need to select on focus change 6405 * events; these are the only windows for which we care about focus 6406 * changes. 6407 */ 6408 6409 wrapperPtr->flags |= TK_WRAPPER; 6410 wrapperPtr->atts.event_mask |= StructureNotifyMask|FocusChangeMask; 6411 wrapperPtr->atts.override_redirect = winPtr->atts.override_redirect; 6412 if (winPtr->flags & TK_EMBEDDED) { 6413 parent = TkUnixContainerId(winPtr); 6414 } else { 6415 parent = XRootWindow(wrapperPtr->display, wrapperPtr->screenNum); 6416 } 6417 wrapperPtr->window = XCreateWindow(wrapperPtr->display, 6418 parent, wrapperPtr->changes.x, wrapperPtr->changes.y, 6419 (unsigned) wrapperPtr->changes.width, 6420 (unsigned) wrapperPtr->changes.height, 6421 (unsigned) wrapperPtr->changes.border_width, wrapperPtr->depth, 6422 InputOutput, wrapperPtr->visual, 6423 wrapperPtr->dirtyAtts|CWOverrideRedirect, &wrapperPtr->atts); 6424 hPtr = Tcl_CreateHashEntry(&wrapperPtr->dispPtr->winTable, 6425 (char *) wrapperPtr->window, &new); 6426 Tcl_SetHashValue(hPtr, wrapperPtr); 6427 wrapperPtr->mainPtr = winPtr->mainPtr; 6428 wrapperPtr->mainPtr->refCount++; 6429 wrapperPtr->dirtyAtts = 0; 6430 wrapperPtr->dirtyChanges = 0; 6431 wrapperPtr->wmInfoPtr = wmPtr; 6432 6433 /* 6434 * Reparent the toplevel window inside the wrapper. 6435 */ 6436 6437 XReparentWindow(wrapperPtr->display, winPtr->window, wrapperPtr->window, 6438 0, 0); 6439 6440 /* 6441 * Tk must monitor structure events for wrapper windows in order 6442 * to detect changes made by window managers such as resizing, 6443 * mapping, unmapping, etc.. 6444 */ 6445 6446 Tk_CreateEventHandler((Tk_Window) wmPtr->wrapperPtr, StructureNotifyMask, 6447 WrapperEventProc, (ClientData) wmPtr); 6448} 6449 6450/* 6451 *---------------------------------------------------------------------- 6452 * 6453 * TkWmFocusToplevel -- 6454 * 6455 * This is a utility procedure invoked by focus-management code. 6456 * The focus code responds to externally generated focus-related 6457 * events on wrapper windows but ignores those events for any other 6458 * windows. This procedure determines whether a given window is a 6459 * wrapper window and, if so, returns the toplevel window 6460 * corresponding to the wrapper. 6461 * 6462 * Results: 6463 * If winPtr is a wrapper window, returns a pointer to the 6464 * corresponding toplevel window; otherwise returns NULL. 6465 * 6466 * Side effects: 6467 * None. 6468 * 6469 *---------------------------------------------------------------------- 6470 */ 6471 6472TkWindow * 6473TkWmFocusToplevel(winPtr) 6474 TkWindow *winPtr; /* Window that received a focus-related 6475 * event. */ 6476{ 6477 if (!(winPtr->flags & TK_WRAPPER)) { 6478 return NULL; 6479 } 6480 return winPtr->wmInfoPtr->winPtr; 6481} 6482 6483/* 6484 *---------------------------------------------------------------------- 6485 * 6486 * TkUnixSetMenubar -- 6487 * 6488 * This procedure is invoked by menu management code to specify the 6489 * window to use as a menubar for a given toplevel window. 6490 * 6491 * Results: 6492 * None. 6493 * 6494 * Side effects: 6495 * The window given by menubar will be mapped and positioned inside 6496 * the wrapper for tkwin and above tkwin. Menubar will 6497 * automatically be resized to maintain the height specified by 6498 * TkUnixSetMenuHeight the same width as tkwin. Any previous 6499 * menubar specified for tkwin will be unmapped and ignored from 6500 * now on. 6501 * 6502 *---------------------------------------------------------------------- 6503 */ 6504 6505void 6506TkUnixSetMenubar(tkwin, menubar) 6507 Tk_Window tkwin; /* Token for toplevel window. */ 6508 Tk_Window menubar; /* Token for window that is to serve as 6509 * menubar for tkwin. Must not be a 6510 * toplevel window. If NULL, any 6511 * existing menubar is canceled and the 6512 * menu height is reset to 0. */ 6513{ 6514 WmInfo *wmPtr = ((TkWindow *) tkwin)->wmInfoPtr; 6515 Tk_Window parent; 6516 TkWindow *menubarPtr = (TkWindow *) menubar; 6517 6518 if (wmPtr->menubar != NULL) { 6519 /* 6520 * There's already a menubar for this toplevel. If it isn't the 6521 * same as the new menubar, unmap it so that it is out of the 6522 * way, and reparent it back to its original parent. 6523 */ 6524 6525 if (wmPtr->menubar == menubar) { 6526 return; 6527 } 6528 ((TkWindow *) wmPtr->menubar)->wmInfoPtr = NULL; 6529 ((TkWindow *) wmPtr->menubar)->flags &= ~TK_REPARENTED; 6530 Tk_UnmapWindow(wmPtr->menubar); 6531 parent = Tk_Parent(wmPtr->menubar); 6532 if (parent != NULL) { 6533 Tk_MakeWindowExist(parent); 6534 XReparentWindow(Tk_Display(wmPtr->menubar), 6535 Tk_WindowId(wmPtr->menubar), Tk_WindowId(parent), 0, 0); 6536 } 6537 Tk_DeleteEventHandler(wmPtr->menubar, StructureNotifyMask, 6538 MenubarDestroyProc, (ClientData) wmPtr->menubar); 6539 Tk_ManageGeometry(wmPtr->menubar, NULL, (ClientData) NULL); 6540 } 6541 6542 wmPtr->menubar = menubar; 6543 if (menubar == NULL) { 6544 wmPtr->menuHeight = 0; 6545 } else { 6546 if ((menubarPtr->flags & TK_TOP_LEVEL) 6547 || (Tk_Screen(menubar) != Tk_Screen(tkwin))) { 6548 Tcl_Panic("TkUnixSetMenubar got bad menubar"); 6549 } 6550 wmPtr->menuHeight = Tk_ReqHeight(menubar); 6551 if (wmPtr->menuHeight == 0) { 6552 wmPtr->menuHeight = 1; 6553 } 6554 Tk_MakeWindowExist(tkwin); 6555 Tk_MakeWindowExist(menubar); 6556 if (wmPtr->wrapperPtr == NULL) { 6557 CreateWrapper(wmPtr); 6558 } 6559 XReparentWindow(Tk_Display(menubar), Tk_WindowId(menubar), 6560 wmPtr->wrapperPtr->window, 0, 0); 6561 menubarPtr->wmInfoPtr = wmPtr; 6562 Tk_MoveResizeWindow(menubar, 0, 0, Tk_Width(tkwin), wmPtr->menuHeight); 6563 Tk_MapWindow(menubar); 6564 Tk_CreateEventHandler(menubar, StructureNotifyMask, MenubarDestroyProc, 6565 (ClientData) menubar); 6566 Tk_ManageGeometry(menubar, &menubarMgrType, (ClientData) wmPtr); 6567 menubarPtr->flags |= TK_REPARENTED; 6568 } 6569 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 6570 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { 6571 Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) tkwin); 6572 wmPtr->flags |= WM_UPDATE_PENDING; 6573 } 6574} 6575 6576/* 6577 *---------------------------------------------------------------------- 6578 * 6579 * MenubarDestroyProc -- 6580 * 6581 * This procedure is invoked by the event dispatcher whenever a 6582 * menubar window is destroyed (it's also invoked for a few other 6583 * kinds of events, but we ignore those). 6584 * 6585 * Results: 6586 * None. 6587 * 6588 * Side effects: 6589 * The association between the window and its toplevel is broken, 6590 * so that the window is no longer considered to be a menubar. 6591 * 6592 *---------------------------------------------------------------------- 6593 */ 6594 6595static void 6596MenubarDestroyProc(clientData, eventPtr) 6597 ClientData clientData; /* TkWindow pointer for menubar. */ 6598 XEvent *eventPtr; /* Describes what just happened. */ 6599{ 6600 WmInfo *wmPtr; 6601 6602 if (eventPtr->type != DestroyNotify) { 6603 return; 6604 } 6605 wmPtr = ((TkWindow *) clientData)->wmInfoPtr; 6606 wmPtr->menubar = NULL; 6607 wmPtr->menuHeight = 0; 6608 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 6609 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { 6610 Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) wmPtr->winPtr); 6611 wmPtr->flags |= WM_UPDATE_PENDING; 6612 } 6613} 6614 6615/* 6616 *---------------------------------------------------------------------- 6617 * 6618 * MenubarReqProc -- 6619 * 6620 * This procedure is invoked by the Tk geometry management code 6621 * whenever a menubar calls Tk_GeometryRequest to request a new 6622 * size. 6623 * 6624 * Results: 6625 * None. 6626 * 6627 * Side effects: 6628 * None. 6629 * 6630 *---------------------------------------------------------------------- 6631 */ 6632 6633static void 6634MenubarReqProc(clientData, tkwin) 6635 ClientData clientData; /* Pointer to the window manager 6636 * information for tkwin's toplevel. */ 6637 Tk_Window tkwin; /* Handle for menubar window. */ 6638{ 6639 WmInfo *wmPtr = (WmInfo *) clientData; 6640 6641 wmPtr->menuHeight = Tk_ReqHeight(tkwin); 6642 if (wmPtr->menuHeight <= 0) { 6643 wmPtr->menuHeight = 1; 6644 } 6645 wmPtr->flags |= WM_UPDATE_SIZE_HINTS; 6646 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { 6647 Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) wmPtr->winPtr); 6648 wmPtr->flags |= WM_UPDATE_PENDING; 6649 } 6650} 6651 6652/* 6653 *---------------------------------------------------------------------- 6654 * 6655 * TkpGetWrapperWindow -- 6656 * 6657 * Given a toplevel window return the hidden wrapper window for 6658 * the toplevel window if available. 6659 * 6660 * Results: 6661 * The wrapper window. NULL is we were not passed a toplevel 6662 * window or the wrapper has yet to be created. 6663 * 6664 * Side effects: 6665 * None. 6666 * 6667 *---------------------------------------------------------------------- 6668 */ 6669 6670TkWindow * 6671TkpGetWrapperWindow(winPtr) 6672 TkWindow *winPtr; /* A toplevel window pointer. */ 6673{ 6674 register WmInfo *wmPtr = winPtr->wmInfoPtr; 6675 6676 if ((winPtr == NULL) || (wmPtr == NULL)) { 6677 return NULL; 6678 } 6679 6680 return wmPtr->wrapperPtr; 6681} 6682 6683/* 6684 *---------------------------------------------------------------------- 6685 * 6686 * UpdateCommand -- 6687 * 6688 * Update the WM_COMMAND property, taking care to translate 6689 * the command strings into the external encoding. 6690 * 6691 * Results: 6692 * None. 6693 * 6694 * Side effects: 6695 * None. 6696 * 6697 *---------------------------------------------------------------------- 6698 */ 6699 6700static void 6701UpdateCommand(winPtr) 6702 TkWindow *winPtr; 6703{ 6704 register WmInfo *wmPtr = winPtr->wmInfoPtr; 6705 Tcl_DString cmds, ds; 6706 int i, *offsets; 6707 char **cmdArgv; 6708 6709 /* 6710 * Translate the argv strings into the external encoding. To avoid 6711 * allocating lots of memory, the strings are appended to a buffer 6712 * with nulls between each string. 6713 * 6714 * This code is tricky because we need to pass and array of pointers 6715 * to XSetCommand. However, we can't compute the pointers as we go 6716 * because the DString buffer space could get reallocated. So, store 6717 * offsets for each element as we go, then compute pointers from the 6718 * offsets once the entire DString is done. 6719 */ 6720 6721 cmdArgv = (char **) ckalloc(sizeof(char *) * wmPtr->cmdArgc); 6722 offsets = (int *) ckalloc( sizeof(int) * wmPtr->cmdArgc); 6723 Tcl_DStringInit(&cmds); 6724 for (i = 0; i < wmPtr->cmdArgc; i++) { 6725 Tcl_UtfToExternalDString(NULL, wmPtr->cmdArgv[i], -1, &ds); 6726 offsets[i] = Tcl_DStringLength(&cmds); 6727 Tcl_DStringAppend(&cmds, Tcl_DStringValue(&ds), 6728 Tcl_DStringLength(&ds)+1); 6729 Tcl_DStringFree(&ds); 6730 } 6731 cmdArgv[0] = Tcl_DStringValue(&cmds); 6732 for (i = 1; i < wmPtr->cmdArgc; i++) { 6733 cmdArgv[i] = cmdArgv[0] + offsets[i]; 6734 } 6735 6736 XSetCommand(winPtr->display, wmPtr->wrapperPtr->window, 6737 cmdArgv, wmPtr->cmdArgc); 6738 Tcl_DStringFree(&cmds); 6739 ckfree((char *) cmdArgv); 6740 ckfree((char *) offsets); 6741} 6742 6743/* 6744 *---------------------------------------------------------------------- 6745 * 6746 * TkpWmSetState -- 6747 * 6748 * Sets the window manager state for the wrapper window of a 6749 * given toplevel window. 6750 * 6751 * Results: 6752 * 0 on error, 1 otherwise 6753 * 6754 * Side effects: 6755 * May minimize, restore, or withdraw a window. 6756 * 6757 *---------------------------------------------------------------------- 6758 */ 6759 6760int 6761TkpWmSetState(winPtr, state) 6762 TkWindow *winPtr; /* Toplevel window to operate on. */ 6763 int state; /* One of IconicState, NormalState, 6764 * or WithdrawnState. */ 6765{ 6766 WmInfo *wmPtr = winPtr->wmInfoPtr; 6767 6768 if (state == WithdrawnState) { 6769 wmPtr->hints.initial_state = WithdrawnState; 6770 wmPtr->withdrawn = 1; 6771 if (wmPtr->flags & WM_NEVER_MAPPED) { 6772 return 1; 6773 } 6774 if (XWithdrawWindow(winPtr->display, wmPtr->wrapperPtr->window, 6775 winPtr->screenNum) == 0) { 6776 return 0; 6777 } 6778 WaitForMapNotify(winPtr, 0); 6779 } else if (state == NormalState) { 6780 wmPtr->hints.initial_state = NormalState; 6781 wmPtr->withdrawn = 0; 6782 if (wmPtr->flags & WM_NEVER_MAPPED) { 6783 return 1; 6784 } 6785 UpdateHints(winPtr); 6786 Tk_MapWindow((Tk_Window) winPtr); 6787 } else if (state == IconicState) { 6788 wmPtr->hints.initial_state = IconicState; 6789 if (wmPtr->flags & WM_NEVER_MAPPED) { 6790 return 1; 6791 } 6792 if (wmPtr->withdrawn) { 6793 UpdateHints(winPtr); 6794 Tk_MapWindow((Tk_Window) winPtr); 6795 wmPtr->withdrawn = 0; 6796 } else { 6797 if (XIconifyWindow(winPtr->display, wmPtr->wrapperPtr->window, 6798 winPtr->screenNum) == 0) { 6799 return 0; 6800 } 6801 WaitForMapNotify(winPtr, 0); 6802 } 6803 } 6804 6805 return 1; 6806} 6807