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