|
|
1.1 ! root 1: /* ! 2: * tkFrame.c -- ! 3: * ! 4: * This module implements "frame" widgets for the Tk ! 5: * toolkit. Frames are windows with a background color ! 6: * and possibly a 3-D effect, but no other attributes. ! 7: * ! 8: * Copyright 1990 Regents of the University of California. ! 9: * Permission to use, copy, modify, and distribute this ! 10: * software and its documentation for any purpose and without ! 11: * fee is hereby granted, provided that the above copyright ! 12: * notice appear in all copies. The University of California ! 13: * makes no representations about the suitability of this ! 14: * software for any purpose. It is provided "as is" without ! 15: * express or implied warranty. ! 16: */ ! 17: ! 18: #ifndef lint ! 19: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkFrame.c,v 1.27 92/08/21 16:17:24 ouster Exp $ SPRITE (Berkeley)"; ! 20: #endif ! 21: ! 22: #include "default.h" ! 23: #include "tkconfig.h" ! 24: #include "tk.h" ! 25: ! 26: /* ! 27: * A data structure of the following type is kept for each ! 28: * frame that currently exists for this process: ! 29: */ ! 30: ! 31: typedef struct { ! 32: Tk_Window tkwin; /* Window that embodies the frame. NULL ! 33: * means that the window has been destroyed ! 34: * but the data structures haven't yet been ! 35: * cleaned up.*/ ! 36: Tcl_Interp *interp; /* Interpreter associated with ! 37: * widget. Used to delete widget ! 38: * command. */ ! 39: Tk_Uid screenName; /* If this window isn't a toplevel window ! 40: * then this is NULL; otherwise it gives ! 41: * the name of the screen on which window ! 42: * is displayed. */ ! 43: Tk_3DBorder border; /* Structure used to draw 3-D border and ! 44: * background. */ ! 45: int borderWidth; /* Width of 3-D border (if any). */ ! 46: int relief; /* 3-d effect: TK_RELIEF_RAISED etc. */ ! 47: int width; /* Width to request for window. <= 0 means ! 48: * don't request any size. */ ! 49: int height; /* Height to request for window. <= 0 means ! 50: * don't request any size. */ ! 51: char *geometry; /* Geometry that user requested. NULL ! 52: * means use width and height instead. ! 53: * Malloc'ed. */ ! 54: Cursor cursor; /* Current cursor for window, or None. */ ! 55: int flags; /* Various flags; see below for ! 56: * definitions. */ ! 57: } Frame; ! 58: ! 59: /* ! 60: * Flag bits for frames: ! 61: * ! 62: * REDRAW_PENDING: Non-zero means a DoWhenIdle handler ! 63: * has already been queued to redraw ! 64: * this window. ! 65: * CLEAR_NEEDED; Need to clear the window when redrawing. ! 66: */ ! 67: ! 68: #define REDRAW_PENDING 1 ! 69: #define CLEAR_NEEDED 2 ! 70: ! 71: static Tk_ConfigSpec configSpecs[] = { ! 72: {TK_CONFIG_BORDER, "-background", "background", "Background", ! 73: DEF_FRAME_BG_COLOR, Tk_Offset(Frame, border), TK_CONFIG_COLOR_ONLY}, ! 74: {TK_CONFIG_BORDER, "-background", "background", "Background", ! 75: DEF_FRAME_BG_MONO, Tk_Offset(Frame, border), TK_CONFIG_MONO_ONLY}, ! 76: {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, ! 77: (char *) NULL, 0, 0}, ! 78: {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, ! 79: (char *) NULL, 0, 0}, ! 80: {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", ! 81: DEF_FRAME_BORDER_WIDTH, Tk_Offset(Frame, borderWidth), 0}, ! 82: {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", ! 83: DEF_FRAME_CURSOR, Tk_Offset(Frame, cursor), TK_CONFIG_NULL_OK}, ! 84: {TK_CONFIG_STRING, "-geometry", "geometry", "Geometry", ! 85: DEF_FRAME_GEOMETRY, Tk_Offset(Frame, geometry), TK_CONFIG_NULL_OK}, ! 86: {TK_CONFIG_PIXELS, "-height", "height", "Height", ! 87: DEF_FRAME_HEIGHT, Tk_Offset(Frame, height), 0}, ! 88: {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", ! 89: DEF_FRAME_RELIEF, Tk_Offset(Frame, relief), 0}, ! 90: {TK_CONFIG_PIXELS, "-width", "width", "Width", ! 91: DEF_FRAME_WIDTH, Tk_Offset(Frame, width), 0}, ! 92: {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, ! 93: (char *) NULL, 0, 0} ! 94: }; ! 95: ! 96: /* ! 97: * Forward declarations for procedures defined later in this file: ! 98: */ ! 99: ! 100: static int ConfigureFrame _ANSI_ARGS_((Tcl_Interp *interp, ! 101: Frame *framePtr, int argc, char **argv, int flags)); ! 102: static void DestroyFrame _ANSI_ARGS_((ClientData clientData)); ! 103: static void DisplayFrame _ANSI_ARGS_((ClientData clientData)); ! 104: static void FrameEventProc _ANSI_ARGS_((ClientData clientData, ! 105: XEvent *eventPtr)); ! 106: static int FrameWidgetCmd _ANSI_ARGS_((ClientData clientData, ! 107: Tcl_Interp *interp, int argc, char **argv)); ! 108: static void MapFrame _ANSI_ARGS_((ClientData clientData)); ! 109: ! 110: /* ! 111: *-------------------------------------------------------------- ! 112: * ! 113: * Tk_FrameCmd -- ! 114: * ! 115: * This procedure is invoked to process the "frame" and ! 116: * "toplevel" Tcl commands. See the user documentation for ! 117: * details on what it does. ! 118: * ! 119: * Results: ! 120: * A standard Tcl result. ! 121: * ! 122: * Side effects: ! 123: * See the user documentation. ! 124: * ! 125: *-------------------------------------------------------------- ! 126: */ ! 127: ! 128: int ! 129: Tk_FrameCmd(clientData, interp, argc, argv) ! 130: ClientData clientData; /* Main window associated with ! 131: * interpreter. */ ! 132: Tcl_Interp *interp; /* Current interpreter. */ ! 133: int argc; /* Number of arguments. */ ! 134: char **argv; /* Argument strings. */ ! 135: { ! 136: Tk_Window tkwin = (Tk_Window) clientData; ! 137: Tk_Window new; ! 138: register Frame *framePtr; ! 139: Tk_Uid screenUid; ! 140: char *className, *screen; ! 141: int src, dst; ! 142: ! 143: if (argc < 2) { ! 144: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 145: argv[0], " pathName ?options?\"", (char *) NULL); ! 146: return TCL_ERROR; ! 147: } ! 148: ! 149: /* ! 150: * The code below is a special workaround that extracts a few key ! 151: * options from the argument list now, rather than letting ! 152: * ConfigureFrame do it. This is necessary because we have ! 153: * to know the window's screen (if it's top-level) and its ! 154: * class before creating the window. ! 155: */ ! 156: ! 157: screen = NULL; ! 158: className = (argv[0][0] == 't') ? "Toplevel" : "Frame"; ! 159: for (src = 2, dst = 2; src < argc; src += 2) { ! 160: char c; ! 161: ! 162: c = argv[src][1]; ! 163: if ((c == 'c') ! 164: && (strncmp(argv[src], "-class", strlen(argv[src])) == 0)) { ! 165: className = argv[src+1]; ! 166: } else if ((argv[0][0] == 't') && (c == 's') ! 167: && (strncmp(argv[src], "-screen", strlen(argv[src])) == 0)) { ! 168: screen = argv[src+1]; ! 169: } else { ! 170: argv[dst] = argv[src]; ! 171: argv[dst+1] = argv[src+1]; ! 172: dst += 2; ! 173: } ! 174: } ! 175: argc -= src-dst; ! 176: ! 177: /* ! 178: * Provide a default screen for top-level windows (same as screen ! 179: * of parent window). ! 180: */ ! 181: ! 182: if ((argv[0][0] == 't') && (screen == NULL)) { ! 183: screen = ""; ! 184: } ! 185: if (screen != NULL) { ! 186: screenUid = Tk_GetUid(screen); ! 187: } else { ! 188: screenUid = NULL; ! 189: } ! 190: ! 191: /* ! 192: * Create the window. ! 193: */ ! 194: ! 195: new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], screenUid); ! 196: ! 197: if (new == NULL) { ! 198: return TCL_ERROR; ! 199: } ! 200: ! 201: Tk_SetClass(new, className); ! 202: framePtr = (Frame *) ckalloc(sizeof(Frame)); ! 203: framePtr->tkwin = new; ! 204: framePtr->interp = interp; ! 205: framePtr->screenName = screenUid; ! 206: framePtr->border = NULL; ! 207: framePtr->geometry = NULL; ! 208: framePtr->cursor = None; ! 209: framePtr->flags = 0; ! 210: Tk_CreateEventHandler(framePtr->tkwin, ExposureMask|StructureNotifyMask, ! 211: FrameEventProc, (ClientData) framePtr); ! 212: Tcl_CreateCommand(interp, Tk_PathName(framePtr->tkwin), ! 213: FrameWidgetCmd, (ClientData) framePtr, (void (*)()) NULL); ! 214: ! 215: if (ConfigureFrame(interp, framePtr, argc-2, argv+2, 0) != TCL_OK) { ! 216: Tk_DestroyWindow(framePtr->tkwin); ! 217: return TCL_ERROR; ! 218: } ! 219: if (screenUid != NULL) { ! 220: Tk_DoWhenIdle(MapFrame, (ClientData) framePtr); ! 221: } ! 222: interp->result = Tk_PathName(framePtr->tkwin); ! 223: return TCL_OK; ! 224: } ! 225: ! 226: /* ! 227: *-------------------------------------------------------------- ! 228: * ! 229: * FrameWidgetCmd -- ! 230: * ! 231: * This procedure is invoked to process the Tcl command ! 232: * that corresponds to a frame widget. See the user ! 233: * documentation for details on what it does. ! 234: * ! 235: * Results: ! 236: * A standard Tcl result. ! 237: * ! 238: * Side effects: ! 239: * See the user documentation. ! 240: * ! 241: *-------------------------------------------------------------- ! 242: */ ! 243: ! 244: static int ! 245: FrameWidgetCmd(clientData, interp, argc, argv) ! 246: ClientData clientData; /* Information about frame widget. */ ! 247: Tcl_Interp *interp; /* Current interpreter. */ ! 248: int argc; /* Number of arguments. */ ! 249: char **argv; /* Argument strings. */ ! 250: { ! 251: register Frame *framePtr = (Frame *) clientData; ! 252: int result = TCL_OK; ! 253: int length; ! 254: char c; ! 255: ! 256: if (argc < 2) { ! 257: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 258: argv[0], " option ?arg arg ...?\"", (char *) NULL); ! 259: return TCL_ERROR; ! 260: } ! 261: Tk_Preserve((ClientData) framePtr); ! 262: c = argv[1][0]; ! 263: length = strlen(argv[1]); ! 264: if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) { ! 265: if (argc == 2) { ! 266: result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs, ! 267: (char *) framePtr, (char *) NULL, 0); ! 268: } else if (argc == 3) { ! 269: result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs, ! 270: (char *) framePtr, argv[2], 0); ! 271: } else { ! 272: result = ConfigureFrame(interp, framePtr, argc-2, argv+2, ! 273: TK_CONFIG_ARGV_ONLY); ! 274: } ! 275: } else { ! 276: Tcl_AppendResult(interp, "bad option \"", argv[1], ! 277: "\": must be configure", (char *) NULL); ! 278: result = TCL_ERROR; ! 279: } ! 280: Tk_Release((ClientData) framePtr); ! 281: return result; ! 282: } ! 283: ! 284: /* ! 285: *---------------------------------------------------------------------- ! 286: * ! 287: * DestroyFrame -- ! 288: * ! 289: * This procedure is invoked by Tk_EventuallyFree or Tk_Release ! 290: * to clean up the internal structure of a frame at a safe time ! 291: * (when no-one is using it anymore). ! 292: * ! 293: * Results: ! 294: * None. ! 295: * ! 296: * Side effects: ! 297: * Everything associated with the frame is freed up. ! 298: * ! 299: *---------------------------------------------------------------------- ! 300: */ ! 301: ! 302: static void ! 303: DestroyFrame(clientData) ! 304: ClientData clientData; /* Info about frame widget. */ ! 305: { ! 306: register Frame *framePtr = (Frame *) clientData; ! 307: ! 308: if (framePtr->border != NULL) { ! 309: Tk_Free3DBorder(framePtr->border); ! 310: } ! 311: if (framePtr->geometry != NULL) { ! 312: ckfree(framePtr->geometry); ! 313: } ! 314: if (framePtr->cursor != None) { ! 315: Tk_FreeCursor(framePtr->cursor); ! 316: } ! 317: ckfree((char *) framePtr); ! 318: } ! 319: ! 320: /* ! 321: *---------------------------------------------------------------------- ! 322: * ! 323: * ConfigureFrame -- ! 324: * ! 325: * This procedure is called to process an argv/argc list, plus ! 326: * the Tk option database, in order to configure (or ! 327: * reconfigure) a frame widget. ! 328: * ! 329: * Results: ! 330: * The return value is a standard Tcl result. If TCL_ERROR is ! 331: * returned, then interp->result contains an error message. ! 332: * ! 333: * Side effects: ! 334: * Configuration information, such as text string, colors, font, ! 335: * etc. get set for framePtr; old resources get freed, if there ! 336: * were any. ! 337: * ! 338: *---------------------------------------------------------------------- ! 339: */ ! 340: ! 341: static int ! 342: ConfigureFrame(interp, framePtr, argc, argv, flags) ! 343: Tcl_Interp *interp; /* Used for error reporting. */ ! 344: register Frame *framePtr; /* Information about widget; may or may ! 345: * not already have values for some fields. */ ! 346: int argc; /* Number of valid entries in argv. */ ! 347: char **argv; /* Arguments. */ ! 348: int flags; /* Flags to pass to Tk_ConfigureWidget. */ ! 349: { ! 350: if (Tk_ConfigureWidget(interp, framePtr->tkwin, configSpecs, ! 351: argc, argv, (char *) framePtr, flags) != TCL_OK) { ! 352: return TCL_ERROR; ! 353: } ! 354: ! 355: Tk_SetBackgroundFromBorder(framePtr->tkwin, framePtr->border); ! 356: Tk_SetInternalBorder(framePtr->tkwin, framePtr->borderWidth); ! 357: if (framePtr->geometry != NULL) { ! 358: int height, width; ! 359: if (sscanf(framePtr->geometry, "%dx%d", &width, &height) != 2) { ! 360: Tcl_AppendResult(interp, "bad geometry \"", framePtr->geometry, ! 361: "\": expected widthxheight", (char *) NULL); ! 362: return TCL_ERROR; ! 363: } ! 364: Tk_GeometryRequest(framePtr->tkwin, width, height); ! 365: } else if ((framePtr->width > 0) && (framePtr->height > 0)) { ! 366: Tk_GeometryRequest(framePtr->tkwin, framePtr->width, ! 367: framePtr->height); ! 368: } ! 369: ! 370: if (Tk_IsMapped(framePtr->tkwin) ! 371: && !(framePtr->flags & REDRAW_PENDING)) { ! 372: Tk_DoWhenIdle(DisplayFrame, (ClientData) framePtr); ! 373: framePtr->flags |= REDRAW_PENDING|CLEAR_NEEDED; ! 374: } ! 375: return TCL_OK; ! 376: } ! 377: ! 378: /* ! 379: *---------------------------------------------------------------------- ! 380: * ! 381: * DisplayFrame -- ! 382: * ! 383: * This procedure is invoked to display a frame widget. ! 384: * ! 385: * Results: ! 386: * None. ! 387: * ! 388: * Side effects: ! 389: * Commands are output to X to display the frame in its ! 390: * current mode. ! 391: * ! 392: *---------------------------------------------------------------------- ! 393: */ ! 394: ! 395: static void ! 396: DisplayFrame(clientData) ! 397: ClientData clientData; /* Information about widget. */ ! 398: { ! 399: register Frame *framePtr = (Frame *) clientData; ! 400: register Tk_Window tkwin = framePtr->tkwin; ! 401: ! 402: framePtr->flags &= ~REDRAW_PENDING; ! 403: if ((framePtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { ! 404: return; ! 405: } ! 406: ! 407: if (framePtr->flags & CLEAR_NEEDED) { ! 408: XClearWindow(Tk_Display(tkwin), Tk_WindowId(tkwin)); ! 409: framePtr->flags &= ~CLEAR_NEEDED; ! 410: } ! 411: if ((framePtr->border != NULL) ! 412: && (framePtr->relief != TK_RELIEF_FLAT)) { ! 413: Tk_Draw3DRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), ! 414: framePtr->border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), ! 415: framePtr->borderWidth, framePtr->relief); ! 416: } ! 417: } ! 418: ! 419: /* ! 420: *-------------------------------------------------------------- ! 421: * ! 422: * FrameEventProc -- ! 423: * ! 424: * This procedure is invoked by the Tk dispatcher on ! 425: * structure changes to a frame. For frames with 3D ! 426: * borders, this procedure is also invoked for exposures. ! 427: * ! 428: * Results: ! 429: * None. ! 430: * ! 431: * Side effects: ! 432: * When the window gets deleted, internal structures get ! 433: * cleaned up. When it gets exposed, it is redisplayed. ! 434: * ! 435: *-------------------------------------------------------------- ! 436: */ ! 437: ! 438: static void ! 439: FrameEventProc(clientData, eventPtr) ! 440: ClientData clientData; /* Information about window. */ ! 441: register XEvent *eventPtr; /* Information about event. */ ! 442: { ! 443: register Frame *framePtr = (Frame *) clientData; ! 444: ! 445: if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { ! 446: if ((framePtr->relief != TK_RELIEF_FLAT) && (framePtr->tkwin != NULL) ! 447: && !(framePtr->flags & REDRAW_PENDING)) { ! 448: Tk_DoWhenIdle(DisplayFrame, (ClientData) framePtr); ! 449: framePtr->flags |= REDRAW_PENDING; ! 450: } ! 451: } else if (eventPtr->type == DestroyNotify) { ! 452: Tcl_DeleteCommand(framePtr->interp, Tk_PathName(framePtr->tkwin)); ! 453: framePtr->tkwin = NULL; ! 454: if (framePtr->flags & REDRAW_PENDING) { ! 455: Tk_CancelIdleCall(DisplayFrame, (ClientData) framePtr); ! 456: } ! 457: Tk_CancelIdleCall(MapFrame, (ClientData) framePtr); ! 458: Tk_EventuallyFree((ClientData) framePtr, DestroyFrame); ! 459: } ! 460: } ! 461: ! 462: /* ! 463: *---------------------------------------------------------------------- ! 464: * ! 465: * MapFrame -- ! 466: * ! 467: * This procedure is invoked as a when-idle handler to map a ! 468: * newly-created top-level frame. ! 469: * ! 470: * Results: ! 471: * None. ! 472: * ! 473: * Side effects: ! 474: * The frame given by the clientData argument is mapped. ! 475: * ! 476: *---------------------------------------------------------------------- ! 477: */ ! 478: ! 479: static void ! 480: MapFrame(clientData) ! 481: ClientData clientData; /* Pointer to frame structure. */ ! 482: { ! 483: Frame *framePtr = (Frame *) clientData; ! 484: ! 485: /* ! 486: * Wait for all other background events to be processed before ! 487: * mapping window. This ensures that the window's correct geometry ! 488: * will have been determined before it is first mapped, so that the ! 489: * window manager doesn't get a false idea of its desired geometry. ! 490: */ ! 491: ! 492: do { ! 493: if (Tk_DoOneEvent(TK_IDLE_EVENTS) == 0) { ! 494: break; ! 495: } ! 496: ! 497: /* ! 498: * After each event, make sure that the window still exists, ! 499: * and quit if the window has been destroyed. ! 500: */ ! 501: ! 502: if (framePtr->tkwin == NULL) { ! 503: return; ! 504: } ! 505: } while (1); ! 506: Tk_MapWindow(framePtr->tkwin); ! 507: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.