|
|
1.1 ! root 1: /* ! 2: * tkPlace.c -- ! 3: * ! 4: * This file contains code to implement a simple geometry manager ! 5: * for Tk based on absolute placement or "rubber-sheet" placement. ! 6: * ! 7: * Copyright 1992 Regents of the University of California ! 8: * Permission to use, copy, modify, and distribute this ! 9: * software and its documentation for any purpose and without ! 10: * fee is hereby granted, provided that this copyright ! 11: * notice appears in all copies. The University of California ! 12: * makes no representations about the suitability of this ! 13: * software for any purpose. It is provided "as is" without ! 14: * express or implied warranty. ! 15: */ ! 16: ! 17: #ifndef lint ! 18: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkPlace.c,v 1.6 92/06/10 08:59:28 ouster Exp $ SPRITE (Berkeley)"; ! 19: #endif /* not lint */ ! 20: ! 21: #include "tkconfig.h" ! 22: #include "tkint.h" ! 23: ! 24: /* ! 25: * Border modes for relative placement: ! 26: * ! 27: * BM_INSIDE: relative distances computed using area inside ! 28: * all borders of master window. ! 29: * BM_OUTSIDE: relative distances computed using outside area ! 30: * that includes all borders of master. ! 31: * BM_IGNORE: border issues are ignored: place relative to ! 32: * master's actual window size. ! 33: */ ! 34: ! 35: typedef enum {BM_INSIDE, BM_OUTSIDE, BM_IGNORE} BorderMode; ! 36: ! 37: /* ! 38: * For each window whose geometry is managed by the placer there is ! 39: * a structure of the following type: ! 40: */ ! 41: ! 42: typedef struct Slave { ! 43: Tk_Window tkwin; /* Tk's token for window. */ ! 44: struct Master *masterPtr; /* Pointer to information for window ! 45: * relative to which tkwin is placed. ! 46: * This isn't necessarily the logical ! 47: * parent of tkwin. NULL means the ! 48: * master was deleted or never assigned. */ ! 49: struct Slave *nextPtr; /* Next in list of windows placed relative ! 50: * to same master (NULL for end of list). */ ! 51: ! 52: /* ! 53: * Geometry information for window; where there are both relative ! 54: * and absolute values for the same attribute (e.g. x and relX) only ! 55: * one of them is actually used, depending on flags. ! 56: */ ! 57: ! 58: int x, y; /* X and Y pixel coordinates for tkwin. */ ! 59: float relX, relY; /* X and Y coordinates relative to size of ! 60: * master. */ ! 61: int width, height; /* Absolute dimensions for tkwin. */ ! 62: float relWidth, relHeight; /* Dimensions for tkwin relative to size of ! 63: * master. */ ! 64: Tk_Anchor anchor; /* Which point on tkwin is placed at the ! 65: * given position. */ ! 66: BorderMode borderMode; /* How to treat borders of master window. */ ! 67: int flags; /* Various flags; see below for bit ! 68: * definitions. */ ! 69: } Slave; ! 70: ! 71: /* ! 72: * Flag definitions for Slave structures: ! 73: * ! 74: * CHILD_REL_X - 1 means use relX field; 0 means use x. ! 75: * CHILD_REL_Y - 1 means use relY field; 0 means use y; ! 76: * CHILD_WIDTH - 1 means use width field; ! 77: * CHILD_REL_WIDTH - 1 means use relWidth; if neither this nor ! 78: * CHILD_WIDTH is 1, use window's requested ! 79: * width. ! 80: * CHILD_HEIGHT - 1 means use height field; ! 81: * CHILD_REL_HEIGHT - 1 means use relHeight; if neither this nor ! 82: * CHILD_HEIGHT is 1, use window's requested ! 83: * height. ! 84: */ ! 85: ! 86: #define CHILD_REL_X 1 ! 87: #define CHILD_REL_Y 2 ! 88: #define CHILD_WIDTH 4 ! 89: #define CHILD_REL_WIDTH 8 ! 90: #define CHILD_HEIGHT 0x10 ! 91: #define CHILD_REL_HEIGHT 0x20 ! 92: ! 93: /* ! 94: * For each master window that has a slave managed by the placer there ! 95: * is a structure of the following form: ! 96: */ ! 97: ! 98: typedef struct Master { ! 99: Tk_Window tkwin; /* Tk's token for master window. */ ! 100: struct Slave *slavePtr; /* First in linked list of slaves ! 101: * placed relative to this master. */ ! 102: int flags; /* See below for bit definitions. */ ! 103: } Master; ! 104: ! 105: /* ! 106: * Flag definitions for masters: ! 107: * ! 108: * PARENT_RECONFIG_PENDING - 1 means that a call to RecomputePlacement ! 109: * is already pending via a Do_When_Idle handler. ! 110: */ ! 111: ! 112: #define PARENT_RECONFIG_PENDING 1 ! 113: ! 114: /* ! 115: * The hash tables below both use Tk_Window tokens as keys. They map ! 116: * from Tk_Windows to Slave and Master structures for windows, if they ! 117: * exist. ! 118: */ ! 119: ! 120: static int initialized = 0; ! 121: static Tcl_HashTable masterTable; ! 122: static Tcl_HashTable slaveTable; ! 123: ! 124: /* ! 125: * Forward declarations for procedures defined later in this file: ! 126: */ ! 127: ! 128: static void SlaveStructureProc _ANSI_ARGS_((ClientData clientData, ! 129: XEvent *eventPtr)); ! 130: static int ConfigureSlave _ANSI_ARGS_((Tcl_Interp *interp, ! 131: Slave *slavePtr, int argc, char **argv)); ! 132: static Slave * FindSlave _ANSI_ARGS_((Tk_Window tkwin)); ! 133: static Master * FindMaster _ANSI_ARGS_((Tk_Window tkwin)); ! 134: static void MasterStructureProc _ANSI_ARGS_((ClientData clientData, ! 135: XEvent *eventPtr)); ! 136: static void PlaceRequestProc _ANSI_ARGS_((ClientData clientData, ! 137: Tk_Window tkwin)); ! 138: static void RecomputePlacement _ANSI_ARGS_((ClientData clientData)); ! 139: static void UnlinkSlave _ANSI_ARGS_((Slave *slavePtr)); ! 140: ! 141: /* ! 142: *-------------------------------------------------------------- ! 143: * ! 144: * Tk_PlaceCmd -- ! 145: * ! 146: * This procedure is invoked to process the "place" Tcl ! 147: * commands. See the user documentation for details on ! 148: * what it does. ! 149: * ! 150: * Results: ! 151: * A standard Tcl result. ! 152: * ! 153: * Side effects: ! 154: * See the user documentation. ! 155: * ! 156: *-------------------------------------------------------------- ! 157: */ ! 158: ! 159: int ! 160: Tk_PlaceCmd(clientData, interp, argc, argv) ! 161: ClientData clientData; /* Main window associated with interpreter. */ ! 162: Tcl_Interp *interp; /* Current interpreter. */ ! 163: int argc; /* Number of arguments. */ ! 164: char **argv; /* Argument strings. */ ! 165: { ! 166: Tk_Window tkwin; ! 167: Slave *slavePtr; ! 168: Tcl_HashEntry *hPtr; ! 169: int length; ! 170: char c; ! 171: ! 172: /* ! 173: * Initialize, if that hasn't been done yet. ! 174: */ ! 175: ! 176: if (!initialized) { ! 177: Tcl_InitHashTable(&masterTable, TCL_ONE_WORD_KEYS); ! 178: Tcl_InitHashTable(&slaveTable, TCL_ONE_WORD_KEYS); ! 179: initialized = 1; ! 180: } ! 181: ! 182: if (argc < 3) { ! 183: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 184: argv[0], " option|pathName args", (char *) NULL); ! 185: return TCL_ERROR; ! 186: } ! 187: c = argv[1][0]; ! 188: length = strlen(argv[1]); ! 189: ! 190: /* ! 191: * Handle special shortcut where window name is first argument. ! 192: */ ! 193: ! 194: if (c == '.') { ! 195: tkwin = Tk_NameToWindow(interp, argv[1], (Tk_Window) clientData); ! 196: if (tkwin == NULL) { ! 197: return TCL_ERROR; ! 198: } ! 199: slavePtr = FindSlave(tkwin); ! 200: return ConfigureSlave(interp, slavePtr, argc-2, argv+2); ! 201: } ! 202: ! 203: /* ! 204: * Handle more general case of option followed by window name followed ! 205: * by possible additional arguments. ! 206: */ ! 207: ! 208: tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData); ! 209: if (tkwin == NULL) { ! 210: return TCL_ERROR; ! 211: } ! 212: if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) { ! 213: if (argc < 5) { ! 214: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 215: argv[0], ! 216: " configure pathName option value ?option value ...?\"", ! 217: (char *) NULL); ! 218: return TCL_ERROR; ! 219: } ! 220: slavePtr = FindSlave(tkwin); ! 221: return ConfigureSlave(interp, slavePtr, argc-3, argv+3); ! 222: } else if ((c == 'd') && (strncmp(argv[1], "dependents", length) == 0)) { ! 223: if (argc != 3) { ! 224: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 225: argv[0], " dependents pathName\"", (char *) NULL); ! 226: return TCL_ERROR; ! 227: } ! 228: hPtr = Tcl_FindHashEntry(&masterTable, (char *) tkwin); ! 229: if (hPtr != NULL) { ! 230: Master *masterPtr; ! 231: masterPtr = (Master *) Tcl_GetHashValue(hPtr); ! 232: for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; ! 233: slavePtr = slavePtr->nextPtr) { ! 234: Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin), 0); ! 235: } ! 236: } ! 237: } else if ((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) { ! 238: if (argc != 3) { ! 239: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 240: argv[0], " forget pathName\"", (char *) NULL); ! 241: return TCL_ERROR; ! 242: } ! 243: hPtr = Tcl_FindHashEntry(&slaveTable, (char *) tkwin); ! 244: if (hPtr == NULL) { ! 245: return TCL_OK; ! 246: } ! 247: slavePtr = (Slave *) Tcl_GetHashValue(hPtr); ! 248: UnlinkSlave(slavePtr); ! 249: Tcl_DeleteHashEntry(hPtr); ! 250: Tk_DeleteEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc, ! 251: (ClientData) slavePtr); ! 252: Tk_ManageGeometry(tkwin, (Tk_GeometryProc *) NULL, (ClientData) NULL); ! 253: Tk_UnmapWindow(tkwin); ! 254: ckfree((char *) slavePtr); ! 255: } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) { ! 256: char buffer[50]; ! 257: ! 258: if (argc != 3) { ! 259: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 260: argv[0], " info pathName\"", (char *) NULL); ! 261: return TCL_ERROR; ! 262: } ! 263: hPtr = Tcl_FindHashEntry(&slaveTable, (char *) tkwin); ! 264: if (hPtr == NULL) { ! 265: return TCL_OK; ! 266: } ! 267: slavePtr = (Slave *) Tcl_GetHashValue(hPtr); ! 268: if (slavePtr->flags & CHILD_REL_X) { ! 269: sprintf(buffer, "-relx %.4g", slavePtr->relX); ! 270: } else { ! 271: sprintf(buffer, "-x %d", slavePtr->x); ! 272: } ! 273: Tcl_AppendResult(interp, buffer, (char *) NULL); ! 274: if (slavePtr->flags & CHILD_REL_Y) { ! 275: sprintf(buffer, " -rely %.4g", slavePtr->relY); ! 276: } else { ! 277: sprintf(buffer, " -y %d", slavePtr->y); ! 278: } ! 279: Tcl_AppendResult(interp, buffer, (char *) NULL); ! 280: if (slavePtr->flags & CHILD_REL_WIDTH) { ! 281: sprintf(buffer, " -relwidth %.4g", slavePtr->relWidth); ! 282: Tcl_AppendResult(interp, buffer, (char *) NULL); ! 283: } else if (slavePtr->flags & CHILD_WIDTH) { ! 284: sprintf(buffer, " -width %d", slavePtr->width); ! 285: Tcl_AppendResult(interp, buffer, (char *) NULL); ! 286: } ! 287: if (slavePtr->flags & CHILD_REL_HEIGHT) { ! 288: sprintf(buffer, " -relheight %.4g", slavePtr->relHeight); ! 289: Tcl_AppendResult(interp, buffer, (char *) NULL); ! 290: } else if (slavePtr->flags & CHILD_HEIGHT) { ! 291: sprintf(buffer, " -height %d", slavePtr->height); ! 292: Tcl_AppendResult(interp, buffer, (char *) NULL); ! 293: } ! 294: Tcl_AppendResult(interp, " -anchor ", Tk_NameOfAnchor(slavePtr->anchor), ! 295: (char *) NULL); ! 296: if (slavePtr->borderMode == BM_OUTSIDE) { ! 297: Tcl_AppendResult(interp, " -bordermode outside", (char *) NULL); ! 298: } else if (slavePtr->borderMode == BM_IGNORE) { ! 299: Tcl_AppendResult(interp, " -bordermode ignore", (char *) NULL); ! 300: } ! 301: if ((slavePtr->masterPtr != NULL) ! 302: && (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin))) { ! 303: Tcl_AppendResult(interp, " -in ", ! 304: Tk_PathName(slavePtr->masterPtr->tkwin), (char *) NULL); ! 305: } ! 306: } else { ! 307: Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1], ! 308: "\": must be configure, dependents, forget, or info", ! 309: (char *) NULL); ! 310: return TCL_ERROR; ! 311: } ! 312: return TCL_OK; ! 313: } ! 314: ! 315: /* ! 316: *---------------------------------------------------------------------- ! 317: * ! 318: * FindSlave -- ! 319: * ! 320: * Given a Tk_Window token, find the Slave structure corresponding ! 321: * to that token (making a new one if necessary). ! 322: * ! 323: * Results: ! 324: * None. ! 325: * ! 326: * Side effects: ! 327: * A new Slave structure may be created. ! 328: * ! 329: *---------------------------------------------------------------------- ! 330: */ ! 331: ! 332: static Slave * ! 333: FindSlave(tkwin) ! 334: Tk_Window tkwin; /* Token for desired slave. */ ! 335: { ! 336: Tcl_HashEntry *hPtr; ! 337: register Slave *slavePtr; ! 338: int new; ! 339: ! 340: hPtr = Tcl_CreateHashEntry(&slaveTable, (char *) tkwin, &new); ! 341: if (new) { ! 342: slavePtr = (Slave *) ckalloc(sizeof(Slave)); ! 343: slavePtr->tkwin = tkwin; ! 344: slavePtr->masterPtr = NULL; ! 345: slavePtr->nextPtr = NULL; ! 346: slavePtr->x = slavePtr->y = 0; ! 347: slavePtr->relX = slavePtr->relY = 0.0; ! 348: slavePtr->width = slavePtr->height = 0; ! 349: slavePtr->relWidth = slavePtr->relHeight = 0.0; ! 350: slavePtr->anchor = TK_ANCHOR_NW; ! 351: slavePtr->borderMode = BM_INSIDE; ! 352: slavePtr->flags = 0; ! 353: Tcl_SetHashValue(hPtr, slavePtr); ! 354: Tk_CreateEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc, ! 355: (ClientData) slavePtr); ! 356: Tk_ManageGeometry(tkwin, PlaceRequestProc, (ClientData) slavePtr); ! 357: } else { ! 358: slavePtr = (Slave *) Tcl_GetHashValue(hPtr); ! 359: } ! 360: return slavePtr; ! 361: } ! 362: ! 363: /* ! 364: *---------------------------------------------------------------------- ! 365: * ! 366: * UnlinkSlave -- ! 367: * ! 368: * This procedure removes a slave window from the chain of slaves ! 369: * in its master. ! 370: * ! 371: * Results: ! 372: * None. ! 373: * ! 374: * Side effects: ! 375: * The slave list of slavePtr's master changes. ! 376: * ! 377: *---------------------------------------------------------------------- ! 378: */ ! 379: ! 380: static void ! 381: UnlinkSlave(slavePtr) ! 382: Slave *slavePtr; /* Slave structure to be unlinked. */ ! 383: { ! 384: register Master *masterPtr; ! 385: register Slave *prevPtr; ! 386: ! 387: masterPtr = slavePtr->masterPtr; ! 388: if (masterPtr == NULL) { ! 389: return; ! 390: } ! 391: if (masterPtr->slavePtr == slavePtr) { ! 392: masterPtr->slavePtr = slavePtr->nextPtr; ! 393: } else { ! 394: for (prevPtr = masterPtr->slavePtr; ; ! 395: prevPtr = prevPtr->nextPtr) { ! 396: if (prevPtr == NULL) { ! 397: panic("UnlinkSlave couldn't find slave to unlink"); ! 398: } ! 399: if (prevPtr->nextPtr == slavePtr) { ! 400: prevPtr->nextPtr = slavePtr->nextPtr; ! 401: break; ! 402: } ! 403: } ! 404: } ! 405: slavePtr->masterPtr = NULL; ! 406: } ! 407: ! 408: /* ! 409: *---------------------------------------------------------------------- ! 410: * ! 411: * FindMaster -- ! 412: * ! 413: * Given a Tk_Window token, find the Master structure corresponding ! 414: * to that token (making a new one if necessary). ! 415: * ! 416: * Results: ! 417: * None. ! 418: * ! 419: * Side effects: ! 420: * A new Master structure may be created. ! 421: * ! 422: *---------------------------------------------------------------------- ! 423: */ ! 424: ! 425: static Master * ! 426: FindMaster(tkwin) ! 427: Tk_Window tkwin; /* Token for desired master. */ ! 428: { ! 429: Tcl_HashEntry *hPtr; ! 430: register Master *masterPtr; ! 431: int new; ! 432: ! 433: hPtr = Tcl_CreateHashEntry(&masterTable, (char *) tkwin, &new); ! 434: if (new) { ! 435: masterPtr = (Master *) ckalloc(sizeof(Master)); ! 436: masterPtr->tkwin = tkwin; ! 437: masterPtr->slavePtr = NULL; ! 438: masterPtr->flags = 0; ! 439: Tcl_SetHashValue(hPtr, masterPtr); ! 440: Tk_CreateEventHandler(masterPtr->tkwin, StructureNotifyMask, ! 441: MasterStructureProc, (ClientData) masterPtr); ! 442: } else { ! 443: masterPtr = (Master *) Tcl_GetHashValue(hPtr); ! 444: } ! 445: return masterPtr; ! 446: } ! 447: ! 448: /* ! 449: *---------------------------------------------------------------------- ! 450: * ! 451: * ConfigureSlave -- ! 452: * ! 453: * This procedure is called to process an argv/argc list to ! 454: * reconfigure the placement of a window. ! 455: * ! 456: * Results: ! 457: * A standard Tcl result. If an error occurs then a message is ! 458: * left in interp->result. ! 459: * ! 460: * Side effects: ! 461: * Information in slavePtr may change, and slavePtr's master is ! 462: * scheduled for reconfiguration. ! 463: * ! 464: *---------------------------------------------------------------------- ! 465: */ ! 466: ! 467: static int ! 468: ConfigureSlave(interp, slavePtr, argc, argv) ! 469: Tcl_Interp *interp; /* Used for error reporting. */ ! 470: Slave *slavePtr; /* Pointer to current information ! 471: * about slave. */ ! 472: int argc; /* Number of config arguments. */ ! 473: char **argv; /* String values for arguments. */ ! 474: { ! 475: register Master *masterPtr; ! 476: int c, length, result; ! 477: double d; ! 478: ! 479: result = TCL_OK; ! 480: for ( ; argc > 0; argc -= 2, argv += 2) { ! 481: if (argc < 2) { ! 482: Tcl_AppendResult(interp, "extra option \"", argv[0], ! 483: "\" (option with no value?)", (char *) NULL); ! 484: result = TCL_ERROR; ! 485: goto done; ! 486: } ! 487: length = strlen(argv[0]); ! 488: c = argv[0][1]; ! 489: if ((c == 'a') && (strncmp(argv[0], "-anchor", length) == 0)) { ! 490: if (Tk_GetAnchor(interp, argv[1], &slavePtr->anchor) != TCL_OK) { ! 491: result = TCL_ERROR; ! 492: goto done; ! 493: } ! 494: } else if ((c == 'b') ! 495: && (strncmp(argv[0], "-bordermode", length) == 0)) { ! 496: c = argv[1][0]; ! 497: length = strlen(argv[1]); ! 498: if ((c == 'i') && (strncmp(argv[1], "ignore", length) == 0) ! 499: && (length >= 2)) { ! 500: slavePtr->borderMode = BM_IGNORE; ! 501: } else if ((c == 'i') && (strncmp(argv[1], "inside", length) == 0) ! 502: && (length >= 2)) { ! 503: slavePtr->borderMode = BM_INSIDE; ! 504: } else if ((c == 'o') ! 505: && (strncmp(argv[1], "outside", length) == 0)) { ! 506: slavePtr->borderMode = BM_OUTSIDE; ! 507: } else { ! 508: Tcl_AppendResult(interp, "bad border mode \"", argv[1], ! 509: "\": must be ignore, inside, or outside", ! 510: (char *) NULL); ! 511: result = TCL_ERROR; ! 512: goto done; ! 513: } ! 514: } else if ((c == 'h') && (strncmp(argv[0], "-height", length) == 0)) { ! 515: if (argv[1][0] == 0) { ! 516: slavePtr->flags &= ~(CHILD_REL_HEIGHT|CHILD_HEIGHT); ! 517: } else { ! 518: if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1], ! 519: &slavePtr->height) != TCL_OK) { ! 520: result = TCL_ERROR; ! 521: goto done; ! 522: } ! 523: slavePtr->flags &= ~CHILD_REL_HEIGHT; ! 524: slavePtr->flags |= CHILD_HEIGHT; ! 525: } ! 526: } else if ((c == 'i') && (strncmp(argv[0], "-in", length) == 0)) { ! 527: Tk_Window tkwin; ! 528: Tk_Window ancestor; ! 529: ! 530: tkwin = Tk_NameToWindow(interp, argv[1], slavePtr->tkwin); ! 531: if (tkwin == NULL) { ! 532: result = TCL_ERROR; ! 533: goto done; ! 534: } ! 535: ! 536: /* ! 537: * Make sure that the new master is either the logical parent ! 538: * of the slave or a descendant of that window. ! 539: */ ! 540: ! 541: for (ancestor = tkwin; ; ancestor = Tk_Parent(ancestor)) { ! 542: if (ancestor == Tk_Parent(slavePtr->tkwin)) { ! 543: break; ! 544: } ! 545: if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_LEVEL) { ! 546: Tcl_AppendResult(interp, "can't place ", ! 547: Tk_PathName(slavePtr->tkwin), " relative to ", ! 548: Tk_PathName(tkwin), (char *) NULL); ! 549: result = TCL_ERROR; ! 550: goto done; ! 551: } ! 552: } ! 553: UnlinkSlave(slavePtr); ! 554: slavePtr->masterPtr = FindMaster(tkwin); ! 555: slavePtr->nextPtr = slavePtr->masterPtr->slavePtr; ! 556: slavePtr->masterPtr->slavePtr = slavePtr; ! 557: } else if ((c == 'r') && (strncmp(argv[0], "-relheight", length) == 0) ! 558: && (length >= 5)) { ! 559: if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) { ! 560: result = TCL_ERROR; ! 561: goto done; ! 562: } ! 563: slavePtr->relHeight = d; ! 564: slavePtr->flags |= CHILD_REL_HEIGHT; ! 565: slavePtr->flags &= ~CHILD_HEIGHT; ! 566: } else if ((c == 'r') && (strncmp(argv[0], "-relwidth", length) == 0) ! 567: && (length >= 5)) { ! 568: if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) { ! 569: result = TCL_ERROR; ! 570: goto done; ! 571: } ! 572: slavePtr->relWidth = d; ! 573: slavePtr->flags |= CHILD_REL_WIDTH; ! 574: slavePtr->flags &= ~CHILD_WIDTH; ! 575: } else if ((c == 'r') && (strncmp(argv[0], "-relx", length) == 0) ! 576: && (length >= 5)) { ! 577: if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) { ! 578: result = TCL_ERROR; ! 579: goto done; ! 580: } ! 581: slavePtr->relX = d; ! 582: slavePtr->flags |= CHILD_REL_X; ! 583: } else if ((c == 'r') && (strncmp(argv[0], "-rely", length) == 0) ! 584: && (length >= 5)) { ! 585: if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) { ! 586: result = TCL_ERROR; ! 587: goto done; ! 588: } ! 589: slavePtr->relY = d; ! 590: slavePtr->flags |= CHILD_REL_Y; ! 591: } else if ((c == 'w') && (strncmp(argv[0], "-width", length) == 0)) { ! 592: if (argv[1][0] == 0) { ! 593: slavePtr->flags &= ~(CHILD_REL_WIDTH|CHILD_WIDTH); ! 594: } else { ! 595: if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1], ! 596: &slavePtr->width) != TCL_OK) { ! 597: result = TCL_ERROR; ! 598: goto done; ! 599: } ! 600: slavePtr->flags &= ~CHILD_REL_WIDTH; ! 601: slavePtr->flags |= CHILD_WIDTH; ! 602: } ! 603: } else if ((c == 'x') && (strncmp(argv[0], "-x", length) == 0)) { ! 604: if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1], ! 605: &slavePtr->x) != TCL_OK) { ! 606: result = TCL_ERROR; ! 607: goto done; ! 608: } ! 609: slavePtr->flags &= ~CHILD_REL_X; ! 610: } else if ((c == 'y') && (strncmp(argv[0], "-y", length) == 0)) { ! 611: if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1], ! 612: &slavePtr->y) != TCL_OK) { ! 613: result = TCL_ERROR; ! 614: goto done; ! 615: } ! 616: slavePtr->flags &= ~CHILD_REL_Y; ! 617: } else { ! 618: Tcl_AppendResult(interp, "unknown or ambiguous option \"", ! 619: argv[0], "\": must be -anchor, -bordermode, -height, ", ! 620: "-in, -relheight, -relwidth, -relx, -rely, -width, ", ! 621: "-x, or -y", (char *) NULL); ! 622: result = TCL_ERROR; ! 623: goto done; ! 624: } ! 625: } ! 626: ! 627: /* ! 628: * If there's no master specified for this slave, use its Tk_Parent. ! 629: * Then arrange for a placement recalculation in the master. ! 630: */ ! 631: ! 632: done: ! 633: masterPtr = slavePtr->masterPtr; ! 634: if (masterPtr == NULL) { ! 635: masterPtr = FindMaster(Tk_Parent(slavePtr->tkwin)); ! 636: slavePtr->masterPtr = masterPtr; ! 637: slavePtr->nextPtr = masterPtr->slavePtr; ! 638: masterPtr->slavePtr = slavePtr; ! 639: } ! 640: if (!(masterPtr->flags & PARENT_RECONFIG_PENDING)) { ! 641: masterPtr->flags |= PARENT_RECONFIG_PENDING; ! 642: Tk_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr); ! 643: } ! 644: return result; ! 645: } ! 646: ! 647: /* ! 648: *---------------------------------------------------------------------- ! 649: * ! 650: * RecomputePlacement -- ! 651: * ! 652: * This procedure is called as a when-idle handler. It recomputes ! 653: * the geometries of all the slaves of a given master. ! 654: * ! 655: * Results: ! 656: * None. ! 657: * ! 658: * Side effects: ! 659: * Windows may change size or shape. ! 660: * ! 661: *---------------------------------------------------------------------- ! 662: */ ! 663: ! 664: static void ! 665: RecomputePlacement(clientData) ! 666: ClientData clientData; /* Pointer to Master record. */ ! 667: { ! 668: register Master *masterPtr = (Master *) clientData; ! 669: register Slave *slavePtr; ! 670: Tk_Window ancestor, realMaster; ! 671: int x, y, width, height; ! 672: int masterWidth, masterHeight, masterBW; ! 673: ! 674: masterPtr->flags &= ~PARENT_RECONFIG_PENDING; ! 675: ! 676: /* ! 677: * Iterate over all the slaves for the master. Each slave's ! 678: * geometry can be computed independently of the other slaves. ! 679: */ ! 680: ! 681: for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; ! 682: slavePtr = slavePtr->nextPtr) { ! 683: /* ! 684: * Step 1: compute size and borderwidth of master, taking into ! 685: * account desired border mode. ! 686: */ ! 687: ! 688: masterBW = 0; ! 689: masterWidth = Tk_Width(masterPtr->tkwin); ! 690: masterHeight = Tk_Height(masterPtr->tkwin); ! 691: if (slavePtr->borderMode == BM_INSIDE) { ! 692: masterBW = Tk_InternalBorderWidth(masterPtr->tkwin); ! 693: } else if (slavePtr->borderMode == BM_OUTSIDE) { ! 694: masterBW = -Tk_Changes(masterPtr->tkwin)->border_width; ! 695: } ! 696: masterWidth -= 2*masterBW; ! 697: masterHeight -= 2*masterBW; ! 698: ! 699: /* ! 700: * Step 2: compute size of slave (outside dimensions including ! 701: * border) and location of anchor point within master. ! 702: */ ! 703: ! 704: x = slavePtr->x; ! 705: if (slavePtr->flags & CHILD_REL_X) { ! 706: x = (slavePtr->relX*masterWidth) + ! 707: ((slavePtr->relX > 0) ? 0.5 : -0.5); ! 708: } ! 709: x += masterBW; ! 710: y = slavePtr->y; ! 711: if (slavePtr->flags & CHILD_REL_Y) { ! 712: y = (slavePtr->relY*masterHeight) + ! 713: ((slavePtr->relY > 0) ? 0.5 : -0.5); ! 714: } ! 715: y += masterBW; ! 716: if (slavePtr->flags & CHILD_REL_WIDTH) { ! 717: width = (slavePtr->relWidth*masterWidth) + 0.5; ! 718: } else if (slavePtr->flags & CHILD_WIDTH) { ! 719: width = slavePtr->width; ! 720: } else { ! 721: width = Tk_ReqWidth(slavePtr->tkwin) ! 722: + 2*Tk_Changes(slavePtr->tkwin)->border_width; ! 723: } ! 724: if (slavePtr->flags & CHILD_REL_HEIGHT) { ! 725: height = (slavePtr->relHeight*masterHeight) + 0.5; ! 726: } else if (slavePtr->flags & CHILD_HEIGHT) { ! 727: height = slavePtr->height; ! 728: } else { ! 729: height = Tk_ReqHeight(slavePtr->tkwin) ! 730: + 2*Tk_Changes(slavePtr->tkwin)->border_width; ! 731: } ! 732: ! 733: /* ! 734: * Step 3: adjust the x and y positions so that the desired ! 735: * anchor point on the slave appears at that position. Also ! 736: * adjust for the border mode and master's border. ! 737: */ ! 738: ! 739: switch (slavePtr->anchor) { ! 740: case TK_ANCHOR_N: ! 741: x -= width/2; ! 742: break; ! 743: case TK_ANCHOR_NE: ! 744: x -= width; ! 745: break; ! 746: case TK_ANCHOR_E: ! 747: x -= width; ! 748: y -= height/2; ! 749: break; ! 750: case TK_ANCHOR_SE: ! 751: x -= width; ! 752: y -= height; ! 753: break; ! 754: case TK_ANCHOR_S: ! 755: x -= width/2; ! 756: y -= height; ! 757: break; ! 758: case TK_ANCHOR_SW: ! 759: y -= height; ! 760: break; ! 761: case TK_ANCHOR_W: ! 762: y -= height/2; ! 763: break; ! 764: case TK_ANCHOR_NW: ! 765: break; ! 766: case TK_ANCHOR_CENTER: ! 767: x -= width/2; ! 768: y -= height/2; ! 769: break; ! 770: } ! 771: ! 772: /* ! 773: * Step 4: if masterPtr isn't actually the X master of slavePtr, ! 774: * then translate the x and y coordinates back into the coordinate ! 775: * system of masterPtr. ! 776: */ ! 777: ! 778: for (ancestor = masterPtr->tkwin, ! 779: realMaster = Tk_Parent(slavePtr->tkwin); ! 780: ancestor != realMaster; ancestor = Tk_Parent(ancestor)) { ! 781: x += Tk_X(ancestor) + Tk_Changes(ancestor)->border_width; ! 782: y += Tk_Y(ancestor) + Tk_Changes(ancestor)->border_width; ! 783: } ! 784: ! 785: /* ! 786: * Step 5: adjust width and height again to reflect inside dimensions ! 787: * of window rather than outside. Also make sure that the width and ! 788: * height aren't zero. ! 789: */ ! 790: ! 791: width -= 2*Tk_Changes(slavePtr->tkwin)->border_width; ! 792: height -= 2*Tk_Changes(slavePtr->tkwin)->border_width; ! 793: if (width <= 0) { ! 794: width = 1; ! 795: } ! 796: if (height <= 0) { ! 797: height = 1; ! 798: } ! 799: ! 800: /* ! 801: * Step 6: see if the window's size or location has changed; if ! 802: * so then tell X to reconfigure it. ! 803: */ ! 804: ! 805: if ((x != Tk_X(slavePtr->tkwin)) ! 806: || (y != Tk_Y(slavePtr->tkwin)) ! 807: || (width != Tk_Width(slavePtr->tkwin)) ! 808: || (height != Tk_Height(slavePtr->tkwin))) { ! 809: Tk_MoveResizeWindow(slavePtr->tkwin, x, y, ! 810: (unsigned int) width, (unsigned int) height); ! 811: } ! 812: Tk_MapWindow(slavePtr->tkwin); ! 813: } ! 814: } ! 815: ! 816: /* ! 817: *---------------------------------------------------------------------- ! 818: * ! 819: * MasterStructureProc -- ! 820: * ! 821: * This procedure is invoked by the Tk event handler when ! 822: * StructureNotify events occur for a master window. ! 823: * ! 824: * Results: ! 825: * None. ! 826: * ! 827: * Side effects: ! 828: * Structures get cleaned up if the window was deleted. If the ! 829: * window was resized then slave geometries get recomputed. ! 830: * ! 831: *---------------------------------------------------------------------- ! 832: */ ! 833: ! 834: static void ! 835: MasterStructureProc(clientData, eventPtr) ! 836: ClientData clientData; /* Pointer to Master structure for window ! 837: * referred to by eventPtr. */ ! 838: XEvent *eventPtr; /* Describes what just happened. */ ! 839: { ! 840: register Master *masterPtr = (Master *) clientData; ! 841: register Slave *slavePtr, *nextPtr; ! 842: ! 843: if (eventPtr->type == ConfigureNotify) { ! 844: if ((masterPtr->slavePtr != NULL) ! 845: && !(masterPtr->flags & PARENT_RECONFIG_PENDING)) { ! 846: masterPtr->flags |= PARENT_RECONFIG_PENDING; ! 847: Tk_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr); ! 848: } ! 849: } else if (eventPtr->type == DestroyNotify) { ! 850: for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; ! 851: slavePtr = nextPtr) { ! 852: slavePtr->masterPtr = NULL; ! 853: nextPtr = slavePtr->nextPtr; ! 854: slavePtr->nextPtr = NULL; ! 855: } ! 856: Tcl_DeleteHashEntry(Tcl_FindHashEntry(&masterTable, ! 857: (char *) masterPtr->tkwin)); ! 858: if (masterPtr->flags & PARENT_RECONFIG_PENDING) { ! 859: Tk_CancelIdleCall(RecomputePlacement, (ClientData) masterPtr); ! 860: } ! 861: masterPtr->tkwin = NULL; ! 862: ckfree((char *) masterPtr); ! 863: } ! 864: } ! 865: ! 866: /* ! 867: *---------------------------------------------------------------------- ! 868: * ! 869: * SlaveStructureProc -- ! 870: * ! 871: * This procedure is invoked by the Tk event handler when ! 872: * StructureNotify events occur for a slave window. ! 873: * ! 874: * Results: ! 875: * None. ! 876: * ! 877: * Side effects: ! 878: * Structures get cleaned up if the window was deleted. ! 879: * ! 880: *---------------------------------------------------------------------- ! 881: */ ! 882: ! 883: static void ! 884: SlaveStructureProc(clientData, eventPtr) ! 885: ClientData clientData; /* Pointer to Slave structure for window ! 886: * referred to by eventPtr. */ ! 887: XEvent *eventPtr; /* Describes what just happened. */ ! 888: { ! 889: register Slave *slavePtr = (Slave *) clientData; ! 890: ! 891: if (eventPtr->type == DestroyNotify) { ! 892: UnlinkSlave(slavePtr); ! 893: Tcl_DeleteHashEntry(Tcl_FindHashEntry(&slaveTable, ! 894: (char *) slavePtr->tkwin)); ! 895: ckfree((char *) slavePtr); ! 896: } ! 897: } ! 898: ! 899: /* ! 900: *---------------------------------------------------------------------- ! 901: * ! 902: * PlaceRequestProc -- ! 903: * ! 904: * This procedure is invoked by Tk whenever a slave managed by us ! 905: * changes its requested geometry. ! 906: * ! 907: * Results: ! 908: * None. ! 909: * ! 910: * Side effects: ! 911: * The window will get relayed out, if its requested size has ! 912: * anything to do with its actual size. ! 913: * ! 914: *---------------------------------------------------------------------- ! 915: */ ! 916: ! 917: /* ARGSUSED */ ! 918: static void ! 919: PlaceRequestProc(clientData, tkwin) ! 920: ClientData clientData; /* Pointer to our record for slave. */ ! 921: Tk_Window tkwin; /* Window that changed its desired ! 922: * size. */ ! 923: { ! 924: Slave *slavePtr = (Slave *) clientData; ! 925: Master *masterPtr; ! 926: ! 927: if (((slavePtr->flags & (CHILD_WIDTH|CHILD_REL_WIDTH)) != 0) ! 928: && ((slavePtr->flags & (CHILD_HEIGHT|CHILD_REL_HEIGHT)) != 0)) { ! 929: return; ! 930: } ! 931: masterPtr = slavePtr->masterPtr; ! 932: if (masterPtr == NULL) { ! 933: return; ! 934: } ! 935: if (!(masterPtr->flags & PARENT_RECONFIG_PENDING)) { ! 936: masterPtr->flags |= PARENT_RECONFIG_PENDING; ! 937: Tk_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr); ! 938: } ! 939: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.