|
|
1.1 ! root 1: /* ! 2: * tkButton.c -- ! 3: * ! 4: * This module implements a collection of button-like ! 5: * widgets for the Tk toolkit. The widgets implemented ! 6: * include labels, buttons, check buttons, and radio ! 7: * buttons. ! 8: * ! 9: * Copyright 1990-1992 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/tkButton.c,v 1.69 92/08/21 11:42:47 ouster Exp $ SPRITE (Berkeley)"; ! 21: #endif ! 22: ! 23: #include "default.h" ! 24: #include "tkconfig.h" ! 25: #include "tkint.h" ! 26: ! 27: #include <assert.h> ! 28: ! 29: /* ! 30: * A data structure of the following type is kept for each ! 31: * widget managed by this file: ! 32: */ ! 33: ! 34: typedef struct { ! 35: Tk_Window tkwin; /* Window that embodies the button. NULL ! 36: * means that the window has been destroyed. */ ! 37: Tcl_Interp *interp; /* Interpreter associated with button. */ ! 38: int type; /* Type of widget: restricts operations ! 39: * that may be performed on widget. See ! 40: * below for possible values. */ ! 41: ! 42: /* ! 43: * Information about what's in the button. ! 44: */ ! 45: ! 46: char *text; /* Text to display in button (malloc'ed) ! 47: * or NULL. */ ! 48: int textLength; /* # of characters in text. */ ! 49: char *textVarName; /* Name of variable (malloc'ed) or NULL. ! 50: * If non-NULL, button displays the contents ! 51: * of this variable. */ ! 52: Pixmap bitmap; /* Bitmap to display or None. If not None ! 53: * then text and textVar are ignored. */ ! 54: ! 55: /* ! 56: * Information used when displaying widget: ! 57: */ ! 58: ! 59: Tk_Uid state; /* State of button for display purposes: ! 60: * normal, active, or disabled. */ ! 61: Tk_3DBorder normalBorder; /* Structure used to draw 3-D ! 62: * border and background when window ! 63: * isn't active. NULL means no such ! 64: * border exists. */ ! 65: Tk_3DBorder activeBorder; /* Structure used to draw 3-D ! 66: * border and background when window ! 67: * is active. NULL means no such ! 68: * border exists. */ ! 69: int borderWidth; /* Width of border. */ ! 70: int relief; /* 3-d effect: TK_RELIEF_RAISED, etc. */ ! 71: XFontStruct *fontPtr; /* Information about text font, or NULL. */ ! 72: XColor *normalFg; /* Foreground color in normal mode. */ ! 73: XColor *activeFg; /* Foreground color in active mode. NULL ! 74: * means use normalFg instead. */ ! 75: XColor *disabledFg; /* Foreground color when disabled. NULL ! 76: * means use normalFg with a 50% stipple ! 77: * instead. */ ! 78: GC normalTextGC; /* GC for drawing text in normal mode. Also ! 79: * used to copy from off-screen pixmap onto ! 80: * screen. */ ! 81: GC activeTextGC; /* GC for drawing text in active mode (NULL ! 82: * means use normalTextGC). */ ! 83: Pixmap gray; /* Pixmap for displaying disabled text if ! 84: * disabledFg is NULL. */ ! 85: GC disabledGC; /* Used to produce disabled effect. If ! 86: * disabledFg isn't NULL, this GC is used to ! 87: * draw button text or icon. Otherwise ! 88: * text or icon is drawn with normalGC and ! 89: * this GC is used to stipple background ! 90: * across it. */ ! 91: int leftBearing; /* Amount text sticks left from its origin, ! 92: * in pixels. */ ! 93: int rightBearing; /* Amount text sticks right from its origin. */ ! 94: int width, height; /* If > 0, these specify dimensions to request ! 95: * for window, in characters for text and in ! 96: * pixels for bitmaps. In this case the actual ! 97: * size of the text string or bitmap is ! 98: * ignored in computing desired window size. */ ! 99: int padX, padY; /* Extra space around text or bitmap (pixels ! 100: * on each side). */ ! 101: Tk_Anchor anchor; /* Where text/bitmap should be displayed ! 102: * inside button region. */ ! 103: XColor *selectorFg; /* Color for selector. */ ! 104: GC selectorGC; /* For drawing highlight when this button ! 105: * is in selected state. */ ! 106: int selectorSpace; /* Horizontal space (in pixels) allocated for ! 107: * display of selector. */ ! 108: int selectorDiameter; /* Diameter of selector, in pixels. */ ! 109: ! 110: /* ! 111: * For check and radio buttons, the fields below are used ! 112: * to manage the variable indicating the button's state. ! 113: */ ! 114: ! 115: char *selVarName; /* Name of variable used to control selected ! 116: * state of button. Malloc'ed (if ! 117: * not NULL). */ ! 118: char *onValue; /* Value to store in variable when ! 119: * this button is selected. Malloc'ed (if ! 120: * not NULL). */ ! 121: char *offValue; /* Value to store in variable when this ! 122: * button isn't selected. Malloc'ed ! 123: * (if not NULL). Valid only for check ! 124: * buttons. */ ! 125: ! 126: /* ! 127: * Miscellaneous information: ! 128: */ ! 129: ! 130: Cursor cursor; /* Current cursor for window, or None. */ ! 131: char *command; /* Command to execute when button is ! 132: * invoked; valid for buttons only. ! 133: * If not NULL, it's malloc-ed. */ ! 134: int flags; /* Various flags; see below for ! 135: * definitions. */ ! 136: Tk_TimerToken updateTimerToken; /* Added by Don to optimize rapid ! 137: * updates. */ ! 138: } Button; ! 139: ! 140: /* ! 141: * Possible "type" values for buttons. These are the kinds of ! 142: * widgets supported by this file. The ordering of the type ! 143: * numbers is significant: greater means more features and is ! 144: * used in the code. ! 145: */ ! 146: ! 147: #define TYPE_LABEL 0 ! 148: #define TYPE_BUTTON 1 ! 149: #define TYPE_CHECK_BUTTON 2 ! 150: #define TYPE_RADIO_BUTTON 3 ! 151: ! 152: /* ! 153: * Class names for buttons, indexed by one of the type values above. ! 154: */ ! 155: ! 156: static char *classNames[] = {"Label", "Button", "CheckButton", "RadioButton"}; ! 157: ! 158: /* ! 159: * Flag bits for buttons: ! 160: * ! 161: * REDRAW_PENDING: Non-zero means a DoWhenIdle handler ! 162: * has already been queued to redraw ! 163: * this window. ! 164: * SELECTED: Non-zero means this button is selected, ! 165: * so special highlight should be drawn. ! 166: */ ! 167: ! 168: #define REDRAW_PENDING 1 ! 169: #define SELECTED 2 ! 170: ! 171: /* ! 172: * Mask values used to selectively enable entries in the ! 173: * configuration specs: ! 174: */ ! 175: ! 176: #define LABEL_MASK TK_CONFIG_USER_BIT ! 177: #define BUTTON_MASK TK_CONFIG_USER_BIT << 1 ! 178: #define CHECK_BUTTON_MASK TK_CONFIG_USER_BIT << 2 ! 179: #define RADIO_BUTTON_MASK TK_CONFIG_USER_BIT << 3 ! 180: #define ALL_MASK (LABEL_MASK | BUTTON_MASK \ ! 181: | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK) ! 182: ! 183: static int configFlags[] = {LABEL_MASK, BUTTON_MASK, ! 184: CHECK_BUTTON_MASK, RADIO_BUTTON_MASK}; ! 185: /* ! 186: * Information used for parsing configuration specs: ! 187: */ ! 188: ! 189: static Tk_ConfigSpec configSpecs[] = { ! 190: {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", ! 191: DEF_BUTTON_ACTIVE_BG_COLOR, Tk_Offset(Button, activeBorder), ! 192: BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK ! 193: |TK_CONFIG_COLOR_ONLY}, ! 194: {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", ! 195: DEF_BUTTON_ACTIVE_BG_MONO, Tk_Offset(Button, activeBorder), ! 196: BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK ! 197: |TK_CONFIG_MONO_ONLY}, ! 198: {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", ! 199: DEF_BUTTON_ACTIVE_FG_COLOR, Tk_Offset(Button, activeFg), ! 200: BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK ! 201: |TK_CONFIG_COLOR_ONLY}, ! 202: {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", ! 203: DEF_BUTTON_ACTIVE_FG_MONO, Tk_Offset(Button, activeFg), ! 204: BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK ! 205: |TK_CONFIG_MONO_ONLY}, ! 206: {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", ! 207: DEF_BUTTON_ANCHOR, Tk_Offset(Button, anchor), ALL_MASK}, ! 208: {TK_CONFIG_BORDER, "-background", "background", "Background", ! 209: DEF_BUTTON_BG_COLOR, Tk_Offset(Button, normalBorder), ! 210: ALL_MASK | TK_CONFIG_COLOR_ONLY}, ! 211: {TK_CONFIG_BORDER, "-background", "background", "Background", ! 212: DEF_BUTTON_BG_MONO, Tk_Offset(Button, normalBorder), ! 213: ALL_MASK | TK_CONFIG_MONO_ONLY}, ! 214: {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, ! 215: (char *) NULL, 0, ALL_MASK}, ! 216: {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, ! 217: (char *) NULL, 0, ALL_MASK}, ! 218: #if defined(USE_XPM3) ! 219: {TK_CONFIG_PIXMAP, "-bitmap", "bitmap", "Bitmap", ! 220: DEF_BUTTON_BITMAP, Tk_Offset(Button, bitmap), ! 221: ALL_MASK|TK_CONFIG_NULL_OK}, ! 222: #else ! 223: {TK_CONFIG_BITMAP, "-bitmap", "bitmap", "Bitmap", ! 224: DEF_BUTTON_BITMAP, Tk_Offset(Button, bitmap), ! 225: ALL_MASK|TK_CONFIG_NULL_OK}, ! 226: #endif ! 227: {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", ! 228: DEF_BUTTON_BORDER_WIDTH, Tk_Offset(Button, borderWidth), ALL_MASK}, ! 229: {TK_CONFIG_STRING, "-command", "command", "Command", ! 230: DEF_BUTTON_COMMAND, Tk_Offset(Button, command), ! 231: BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, ! 232: {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", ! 233: DEF_BUTTON_CURSOR, Tk_Offset(Button, cursor), ! 234: ALL_MASK|TK_CONFIG_NULL_OK}, ! 235: {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", ! 236: "DisabledForeground", DEF_BUTTON_DISABLED_FG_COLOR, ! 237: Tk_Offset(Button, disabledFg), BUTTON_MASK|CHECK_BUTTON_MASK ! 238: |RADIO_BUTTON_MASK|TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK}, ! 239: {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", ! 240: "DisabledForeground", DEF_BUTTON_DISABLED_FG_MONO, ! 241: Tk_Offset(Button, disabledFg), BUTTON_MASK|CHECK_BUTTON_MASK ! 242: |RADIO_BUTTON_MASK|TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK}, ! 243: {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, ! 244: (char *) NULL, 0, ALL_MASK}, ! 245: {TK_CONFIG_FONT, "-font", "font", "Font", ! 246: DEF_BUTTON_FONT, Tk_Offset(Button, fontPtr), ! 247: ALL_MASK}, ! 248: {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", ! 249: DEF_BUTTON_FG, Tk_Offset(Button, normalFg), ALL_MASK}, ! 250: {TK_CONFIG_INT, "-height", "height", "Height", ! 251: DEF_BUTTON_HEIGHT, Tk_Offset(Button, height), ALL_MASK}, ! 252: {TK_CONFIG_STRING, "-offvalue", "offValue", "Value", ! 253: DEF_BUTTON_OFF_VALUE, Tk_Offset(Button, offValue), ! 254: CHECK_BUTTON_MASK}, ! 255: {TK_CONFIG_STRING, "-onvalue", "onValue", "Value", ! 256: DEF_BUTTON_ON_VALUE, Tk_Offset(Button, onValue), ! 257: CHECK_BUTTON_MASK}, ! 258: {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", ! 259: DEF_BUTTON_PADX, Tk_Offset(Button, padX), ALL_MASK}, ! 260: {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", ! 261: DEF_BUTTON_PADY, Tk_Offset(Button, padY), ALL_MASK}, ! 262: {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", ! 263: DEF_BUTTON_RELIEF, Tk_Offset(Button, relief), ! 264: BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, ! 265: {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", ! 266: DEF_LABEL_RELIEF, Tk_Offset(Button, relief), LABEL_MASK}, ! 267: {TK_CONFIG_COLOR, "-selector", "selector", "Foreground", ! 268: DEF_BUTTON_SELECTOR_COLOR, Tk_Offset(Button, selectorFg), ! 269: CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_COLOR_ONLY ! 270: |TK_CONFIG_NULL_OK}, ! 271: {TK_CONFIG_COLOR, "-selector", "selector", "Foreground", ! 272: DEF_BUTTON_SELECTOR_MONO, Tk_Offset(Button, selectorFg), ! 273: CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_MONO_ONLY ! 274: |TK_CONFIG_NULL_OK}, ! 275: {TK_CONFIG_UID, "-state", "state", "State", ! 276: DEF_BUTTON_STATE, Tk_Offset(Button, state), ! 277: BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, ! 278: {TK_CONFIG_STRING, "-text", "text", "Text", ! 279: DEF_BUTTON_TEXT, Tk_Offset(Button, text), ALL_MASK}, ! 280: {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable", ! 281: DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(Button, textVarName), ! 282: ALL_MASK|TK_CONFIG_NULL_OK}, ! 283: {TK_CONFIG_STRING, "-value", "value", "Value", ! 284: DEF_BUTTON_VALUE, Tk_Offset(Button, onValue), ! 285: RADIO_BUTTON_MASK}, ! 286: {TK_CONFIG_STRING, "-variable", "variable", "Variable", ! 287: DEF_RADIOBUTTON_VARIABLE, Tk_Offset(Button, selVarName), ! 288: RADIO_BUTTON_MASK}, ! 289: {TK_CONFIG_STRING, "-variable", "variable", "Variable", ! 290: DEF_CHECKBUTTON_VARIABLE, Tk_Offset(Button, selVarName), ! 291: CHECK_BUTTON_MASK}, ! 292: {TK_CONFIG_INT, "-width", "width", "Width", ! 293: DEF_BUTTON_WIDTH, Tk_Offset(Button, width), ALL_MASK}, ! 294: {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, ! 295: (char *) NULL, 0, 0} ! 296: }; ! 297: ! 298: /* ! 299: * String to print out in error messages, identifying options for ! 300: * widget commands for different types of labels or buttons: ! 301: */ ! 302: ! 303: static char *optionStrings[] = { ! 304: "configure", ! 305: "activate, configure, deactivate, flash, or invoke", ! 306: "activate, configure, deactivate, deselect, flash, invoke, select, or toggle", ! 307: "activate, configure, deactivate, deselect, flash, invoke, or select" ! 308: }; ! 309: ! 310: static int ButtonUpdateTime = 200; // Added by Don. ! 311: ! 312: /* ! 313: * Forward declarations for procedures defined later in this file: ! 314: */ ! 315: ! 316: static void ButtonEventProc _ANSI_ARGS_((ClientData clientData, ! 317: XEvent *eventPtr)); ! 318: static char * ButtonTextVarProc _ANSI_ARGS_((ClientData clientData, ! 319: Tcl_Interp *interp, char *name1, char *name2, ! 320: int flags)); ! 321: static char * ButtonVarProc _ANSI_ARGS_((ClientData clientData, ! 322: Tcl_Interp *interp, char *name1, char *name2, ! 323: int flags)); ! 324: static int ButtonWidgetCmd _ANSI_ARGS_((ClientData clientData, ! 325: Tcl_Interp *interp, int argc, char **argv)); ! 326: static void ComputeButtonGeometry _ANSI_ARGS_((Button *butPtr)); ! 327: static int ConfigureButton _ANSI_ARGS_((Tcl_Interp *interp, ! 328: Button *butPtr, int argc, char **argv, ! 329: int flags)); ! 330: static void DestroyButton _ANSI_ARGS_((ClientData clientData)); ! 331: static void DisplayButton _ANSI_ARGS_((ClientData clientData)); ! 332: static int InvokeButton _ANSI_ARGS_((Button *butPtr)); ! 333: ! 334: /* ! 335: *-------------------------------------------------------------- ! 336: * ! 337: * Tk_ButtonCmd -- ! 338: * ! 339: * This procedure is invoked to process the "button", "label", ! 340: * "radiobutton", and "checkbutton" Tcl commands. See the ! 341: * user documentation for details on what it does. ! 342: * ! 343: * Results: ! 344: * A standard Tcl result. ! 345: * ! 346: * Side effects: ! 347: * See the user documentation. ! 348: * ! 349: *-------------------------------------------------------------- ! 350: */ ! 351: ! 352: int ! 353: Tk_ButtonCmd(clientData, interp, argc, argv) ! 354: ClientData clientData; /* Main window associated with ! 355: * interpreter. */ ! 356: Tcl_Interp *interp; /* Current interpreter. */ ! 357: int argc; /* Number of arguments. */ ! 358: char **argv; /* Argument strings. */ ! 359: { ! 360: register Button *butPtr; ! 361: int type; ! 362: Tk_Window tkwin = (Tk_Window) clientData; ! 363: Tk_Window new; ! 364: ! 365: if (argc < 2) { ! 366: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 367: argv[0], " pathName ?options?\"", (char *) NULL); ! 368: return TCL_ERROR; ! 369: } ! 370: ! 371: switch (argv[0][0]) { ! 372: case 'l': ! 373: type = TYPE_LABEL; ! 374: break; ! 375: case 'b': ! 376: type = TYPE_BUTTON; ! 377: break; ! 378: case 'c': ! 379: type = TYPE_CHECK_BUTTON; ! 380: break; ! 381: case 'r': ! 382: type = TYPE_RADIO_BUTTON; ! 383: break; ! 384: default: ! 385: sprintf(interp->result, ! 386: "unknown button-creation command \"%.50s\""); ! 387: return TCL_ERROR; ! 388: } ! 389: ! 390: /* ! 391: * Create the new window. ! 392: */ ! 393: ! 394: new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); ! 395: if (new == NULL) { ! 396: return TCL_ERROR; ! 397: } ! 398: ! 399: /* ! 400: * Initialize the data structure for the button. ! 401: */ ! 402: ! 403: butPtr = (Button *) ckalloc(sizeof(Button)); ! 404: butPtr->tkwin = new; ! 405: butPtr->interp = interp; ! 406: butPtr->type = type; ! 407: butPtr->text = NULL; ! 408: butPtr->textVarName = NULL; ! 409: butPtr->bitmap = None; ! 410: butPtr->state = tkNormalUid; ! 411: butPtr->normalBorder = NULL; ! 412: butPtr->activeBorder = NULL; ! 413: butPtr->borderWidth = 0; ! 414: butPtr->relief = TK_RELIEF_FLAT; ! 415: butPtr->fontPtr = NULL; ! 416: butPtr->normalFg = NULL; ! 417: butPtr->activeFg = NULL; ! 418: butPtr->disabledFg = NULL; ! 419: butPtr->normalTextGC = None; ! 420: butPtr->activeTextGC = None; ! 421: butPtr->gray = None; ! 422: butPtr->disabledGC = None; ! 423: butPtr->selectorFg = NULL; ! 424: butPtr->selectorGC = None; ! 425: butPtr->selVarName = NULL; ! 426: butPtr->onValue = NULL; ! 427: butPtr->offValue = NULL; ! 428: butPtr->cursor = None; ! 429: butPtr->command = NULL; ! 430: butPtr->flags = 0; ! 431: butPtr->updateTimerToken = 0; ! 432: ! 433: Tk_SetClass(new, classNames[type]); ! 434: //fprintf(stderr, "ButtonWidgetCmd Made %s %s\n", Tk_Class(butPtr->tkwin), Tk_PathName(butPtr->tkwin)); ! 435: Tk_CreateEventHandler(butPtr->tkwin, ExposureMask|StructureNotifyMask, ! 436: ButtonEventProc, (ClientData) butPtr); ! 437: Tcl_CreateCommand(interp, Tk_PathName(butPtr->tkwin), ButtonWidgetCmd, ! 438: (ClientData) butPtr, (void (*)()) NULL); ! 439: if (ConfigureButton(interp, butPtr, argc-2, argv+2, ! 440: configFlags[type]) != TCL_OK) { ! 441: Tk_DestroyWindow(butPtr->tkwin); ! 442: return TCL_ERROR; ! 443: } ! 444: ! 445: interp->result = Tk_PathName(butPtr->tkwin); ! 446: return TCL_OK; ! 447: } ! 448: ! 449: /* ! 450: *-------------------------------------------------------------- ! 451: * ! 452: * ButtonWidgetCmd -- ! 453: * ! 454: * This procedure is invoked to process the Tcl command ! 455: * that corresponds to a widget managed by this module. ! 456: * See the user documentation for details on what it does. ! 457: * ! 458: * Results: ! 459: * A standard Tcl result. ! 460: * ! 461: * Side effects: ! 462: * See the user documentation. ! 463: * ! 464: *-------------------------------------------------------------- ! 465: */ ! 466: ! 467: static int ! 468: ButtonWidgetCmd(clientData, interp, argc, argv) ! 469: ClientData clientData; /* Information about button widget. */ ! 470: Tcl_Interp *interp; /* Current interpreter. */ ! 471: int argc; /* Number of arguments. */ ! 472: char **argv; /* Argument strings. */ ! 473: { ! 474: register Button *butPtr = (Button *) clientData; ! 475: int result = TCL_OK; ! 476: int length; ! 477: char c; ! 478: ! 479: if (argc < 2) { ! 480: sprintf(interp->result, ! 481: "wrong # args: should be \"%.50s option [arg arg ...]\"", ! 482: argv[0]); ! 483: return TCL_ERROR; ! 484: } ! 485: Tk_Preserve((ClientData) butPtr); ! 486: c = argv[1][0]; ! 487: length = strlen(argv[1]); ! 488: if ((c == 'a') && (strncmp(argv[1], "activate", length) == 0) ! 489: && (butPtr->type != TYPE_LABEL)) { ! 490: if (argc > 2) { ! 491: sprintf(interp->result, ! 492: "wrong # args: should be \"%.50s activate\"", ! 493: argv[0]); ! 494: goto error; ! 495: } ! 496: if (butPtr->state != tkDisabledUid) { ! 497: butPtr->state = tkActiveUid; ! 498: Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->activeBorder); ! 499: goto redisplay; ! 500: } ! 501: } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) { ! 502: if (argc == 2) { ! 503: result = Tk_ConfigureInfo(interp, butPtr->tkwin, configSpecs, ! 504: (char *) butPtr, (char *) NULL, configFlags[butPtr->type]); ! 505: } else if (argc == 3) { ! 506: result = Tk_ConfigureInfo(interp, butPtr->tkwin, configSpecs, ! 507: (char *) butPtr, argv[2], ! 508: configFlags[butPtr->type]); ! 509: } else { ! 510: result = ConfigureButton(interp, butPtr, argc-2, argv+2, ! 511: configFlags[butPtr->type] | TK_CONFIG_ARGV_ONLY); ! 512: } ! 513: } else if ((c == 'd') && (strncmp(argv[1], "deactivate", length) == 0) ! 514: && (length > 2) && (butPtr->type != TYPE_LABEL)) { ! 515: if (argc > 2) { ! 516: sprintf(interp->result, ! 517: "wrong # args: should be \"%.50s deactivate\"", ! 518: argv[0]); ! 519: goto error; ! 520: } ! 521: if (butPtr->state != tkDisabledUid) { ! 522: butPtr->state = tkNormalUid; ! 523: Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->normalBorder); ! 524: goto redisplay; ! 525: } ! 526: } else if ((c == 'd') && (strncmp(argv[1], "deselect", length) == 0) ! 527: && (length > 2) && (butPtr->type >= TYPE_CHECK_BUTTON)) { ! 528: if (argc > 2) { ! 529: sprintf(interp->result, ! 530: "wrong # args: should be \"%.50s deselect\"", ! 531: argv[0]); ! 532: goto error; ! 533: } ! 534: if (butPtr->type == TYPE_CHECK_BUTTON) { ! 535: Tcl_SetVar(interp, butPtr->selVarName, butPtr->offValue, ! 536: TCL_GLOBAL_ONLY); ! 537: } else if (butPtr->flags & SELECTED) { ! 538: Tcl_SetVar(interp, butPtr->selVarName, "", TCL_GLOBAL_ONLY); ! 539: } ! 540: } else if ((c == 'f') && (strncmp(argv[1], "flash", length) == 0) ! 541: && (butPtr->type != TYPE_LABEL)) { ! 542: int i; ! 543: ! 544: if (argc > 2) { ! 545: sprintf(interp->result, ! 546: "wrong # args: should be \"%.50s flash\"", ! 547: argv[0]); ! 548: goto error; ! 549: } ! 550: if (butPtr->state != tkDisabledUid) { ! 551: for (i = 0; i < 4; i++) { ! 552: butPtr->state = (butPtr->state == tkNormalUid) ! 553: ? tkActiveUid : tkNormalUid; ! 554: Tk_SetBackgroundFromBorder(butPtr->tkwin, ! 555: (butPtr->state == tkActiveUid) ? butPtr->activeBorder ! 556: : butPtr->normalBorder); ! 557: DisplayButton((ClientData) butPtr); ! 558: XFlush(Tk_Display(butPtr->tkwin)); ! 559: Tk_Sleep(50); ! 560: } ! 561: } ! 562: } else if ((c == 'i') && (strncmp(argv[1], "invoke", length) == 0) ! 563: && (butPtr->type > TYPE_LABEL)) { ! 564: if (argc > 2) { ! 565: sprintf(interp->result, ! 566: "wrong # args: should be \"%.50s invoke\"", ! 567: argv[0]); ! 568: goto error; ! 569: } ! 570: if (butPtr->state != tkDisabledUid) { ! 571: result = InvokeButton(butPtr); ! 572: } ! 573: } else if ((c == 's') && (strncmp(argv[1], "select", length) == 0) ! 574: && (butPtr->type >= TYPE_CHECK_BUTTON)) { ! 575: if (argc > 2) { ! 576: sprintf(interp->result, ! 577: "wrong # args: should be \"%.50s select\"", ! 578: argv[0]); ! 579: goto error; ! 580: } ! 581: Tcl_SetVar(interp, butPtr->selVarName, butPtr->onValue, TCL_GLOBAL_ONLY); ! 582: } else if ((c == 't') && (strncmp(argv[1], "toggle", length) == 0) ! 583: && (length >= 2) && (butPtr->type == TYPE_CHECK_BUTTON)) { ! 584: if (argc > 2) { ! 585: sprintf(interp->result, ! 586: "wrong # args: should be \"%.50s select\"", ! 587: argv[0]); ! 588: goto error; ! 589: } ! 590: if (butPtr->flags & SELECTED) { ! 591: Tcl_SetVar(interp, butPtr->selVarName, butPtr->offValue, TCL_GLOBAL_ONLY); ! 592: } else { ! 593: Tcl_SetVar(interp, butPtr->selVarName, butPtr->onValue, TCL_GLOBAL_ONLY); ! 594: } ! 595: } else { ! 596: sprintf(interp->result, ! 597: "bad option \"%.50s\": must be %s", argv[1], ! 598: optionStrings[butPtr->type]); ! 599: goto error; ! 600: } ! 601: Tk_Release((ClientData) butPtr); ! 602: return result; ! 603: ! 604: redisplay: ! 605: if (Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) { ! 606: //Tk_TimerToken last = butPtr->updateTimerToken; ! 607: butPtr->flags |= REDRAW_PENDING; ! 608: // Tk_DoWhenIdle(DisplayButton, (ClientData) butPtr); ! 609: assert(butPtr->updateTimerToken == 0); ! 610: if (butPtr->updateTimerToken == 0) { ! 611: butPtr->updateTimerToken = ! 612: Tk_CreateTimerHandler( ! 613: ButtonUpdateTime, ! 614: DisplayButton, ! 615: (ClientData) butPtr); ! 616: } ! 617: //fprintf(stderr, "ButtonWidgetCmd Set Timer %s %s was %d now %d\n", Tk_Class(butPtr->tkwin), Tk_PathName(butPtr->tkwin), last, butPtr->updateTimerToken); ! 618: } ! 619: Tk_Release((ClientData) butPtr); ! 620: return TCL_OK; ! 621: ! 622: error: ! 623: Tk_Release((ClientData) butPtr); ! 624: return TCL_ERROR; ! 625: } ! 626: ! 627: /* ! 628: *---------------------------------------------------------------------- ! 629: * ! 630: * DestroyButton -- ! 631: * ! 632: * This procedure is invoked by Tk_EventuallyFree or Tk_Release ! 633: * to clean up the internal structure of a button at a safe time ! 634: * (when no-one is using it anymore). ! 635: * ! 636: * Results: ! 637: * None. ! 638: * ! 639: * Side effects: ! 640: * Everything associated with the widget is freed up. ! 641: * ! 642: *---------------------------------------------------------------------- ! 643: */ ! 644: ! 645: static void ! 646: DestroyButton(clientData) ! 647: ClientData clientData; /* Info about entry widget. */ ! 648: { ! 649: register Button *butPtr = (Button *) clientData; ! 650: ! 651: if (butPtr->text != NULL) { ! 652: ckfree(butPtr->text); ! 653: } ! 654: if (butPtr->textVarName != NULL) { ! 655: Tcl_UntraceVar(butPtr->interp, butPtr->textVarName, ! 656: TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ! 657: ButtonTextVarProc, (ClientData) butPtr); ! 658: ckfree(butPtr->textVarName); ! 659: } ! 660: if (butPtr->bitmap != None) { ! 661: #if defined(USE_XPM3) ! 662: Tk_FreePixmap(butPtr->bitmap); ! 663: #else ! 664: Tk_FreeBitmap(butPtr->bitmap); ! 665: #endif ! 666: } ! 667: if (butPtr->normalBorder != NULL) { ! 668: Tk_Free3DBorder(butPtr->normalBorder); ! 669: } ! 670: if (butPtr->activeBorder != NULL) { ! 671: Tk_Free3DBorder(butPtr->activeBorder); ! 672: } ! 673: if (butPtr->fontPtr != NULL) { ! 674: Tk_FreeFontStruct(butPtr->fontPtr); ! 675: } ! 676: if (butPtr->normalFg != NULL) { ! 677: Tk_FreeColor(butPtr->normalFg); ! 678: } ! 679: if (butPtr->disabledFg != NULL) { ! 680: Tk_FreeColor(butPtr->disabledFg); ! 681: } ! 682: if (butPtr->activeFg != NULL) { ! 683: Tk_FreeColor(butPtr->activeFg); ! 684: } ! 685: if (butPtr->normalTextGC != None) { ! 686: Tk_FreeGC(butPtr->normalTextGC); ! 687: } ! 688: if (butPtr->activeTextGC != None) { ! 689: Tk_FreeGC(butPtr->activeTextGC); ! 690: } ! 691: if (butPtr->gray != None) { ! 692: Tk_FreeBitmap(butPtr->gray); ! 693: } ! 694: if (butPtr->disabledGC != None) { ! 695: Tk_FreeGC(butPtr->disabledGC); ! 696: } ! 697: if (butPtr->selectorFg != NULL) { ! 698: Tk_FreeColor(butPtr->selectorFg); ! 699: } ! 700: if (butPtr->selectorGC != None) { ! 701: Tk_FreeGC(butPtr->selectorGC); ! 702: } ! 703: if (butPtr->selVarName != NULL) { ! 704: Tcl_UntraceVar(butPtr->interp, butPtr->selVarName, ! 705: TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ! 706: ButtonVarProc, (ClientData) butPtr); ! 707: ckfree(butPtr->selVarName); ! 708: } ! 709: if (butPtr->onValue != NULL) { ! 710: ckfree(butPtr->onValue); ! 711: } ! 712: if (butPtr->offValue != NULL) { ! 713: ckfree(butPtr->offValue); ! 714: } ! 715: if (butPtr->cursor != None) { ! 716: Tk_FreeCursor(butPtr->cursor); ! 717: } ! 718: if (butPtr->command != NULL) { ! 719: ckfree(butPtr->command); ! 720: } ! 721: if (butPtr->updateTimerToken != NULL) { ! 722: Tk_DeleteTimerHandler(butPtr->updateTimerToken); ! 723: //fprintf(stderr, "DestroyButton Delete Timer was %d now 0\n", butPtr->updateTimerToken); ! 724: butPtr->updateTimerToken = 0; ! 725: ! 726: } ! 727: ckfree((char *) butPtr); ! 728: } ! 729: ! 730: /* ! 731: *---------------------------------------------------------------------- ! 732: * ! 733: * ConfigureButton -- ! 734: * ! 735: * This procedure is called to process an argv/argc list, plus ! 736: * the Tk option database, in order to configure (or ! 737: * reconfigure) a button widget. ! 738: * ! 739: * Results: ! 740: * The return value is a standard Tcl result. If TCL_ERROR is ! 741: * returned, then interp->result contains an error message. ! 742: * ! 743: * Side effects: ! 744: * Configuration information, such as text string, colors, font, ! 745: * etc. get set for butPtr; old resources get freed, if there ! 746: * were any. The button is redisplayed. ! 747: * ! 748: *---------------------------------------------------------------------- ! 749: */ ! 750: ! 751: static int ! 752: ConfigureButton(interp, butPtr, argc, argv, flags) ! 753: Tcl_Interp *interp; /* Used for error reporting. */ ! 754: register Button *butPtr; /* Information about widget; may or may ! 755: * not already have values for some fields. */ ! 756: int argc; /* Number of valid entries in argv. */ ! 757: char **argv; /* Arguments. */ ! 758: int flags; /* Flags to pass to Tk_ConfigureWidget. */ ! 759: { ! 760: XGCValues gcValues; ! 761: GC newGC; ! 762: unsigned long mask; ! 763: ! 764: /* ! 765: * Eliminate any existing trace on variables monitored by the button. ! 766: */ ! 767: ! 768: if (butPtr->textVarName != NULL) { ! 769: Tcl_UntraceVar(interp, butPtr->textVarName, ! 770: TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ! 771: ButtonTextVarProc, (ClientData) butPtr); ! 772: } ! 773: if (butPtr->selVarName != NULL) { ! 774: Tcl_UntraceVar(interp, butPtr->selVarName, ! 775: TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ! 776: ButtonVarProc, (ClientData) butPtr); ! 777: } ! 778: ! 779: if (Tk_ConfigureWidget(interp, butPtr->tkwin, configSpecs, ! 780: argc, argv, (char *) butPtr, flags) != TCL_OK) { ! 781: return TCL_ERROR; ! 782: } ! 783: ! 784: /* ! 785: * A few options need special processing, such as setting the ! 786: * background from a 3-D border, or filling in complicated ! 787: * defaults that couldn't be specified to Tk_ConfigureWidget. ! 788: */ ! 789: ! 790: if (butPtr->state == tkActiveUid) { ! 791: Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->activeBorder); ! 792: } else { ! 793: Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->normalBorder); ! 794: if ((butPtr->state != tkNormalUid) ! 795: && (butPtr->state != tkDisabledUid)) { ! 796: Tcl_AppendResult(interp, "bad state value \"", butPtr->state, ! 797: "\": must be normal, active, or disabled", (char *) NULL); ! 798: butPtr->state = tkNormalUid; ! 799: return TCL_ERROR; ! 800: } ! 801: } ! 802: ! 803: gcValues.font = butPtr->fontPtr->fid; ! 804: gcValues.foreground = butPtr->normalFg->pixel; ! 805: gcValues.background = Tk_3DBorderColor(butPtr->normalBorder)->pixel; ! 806: ! 807: /* ! 808: * Note: GraphicsExpose events are disabled in normalTextGC because it's ! 809: * used to copy stuff from an off-screen pixmap onto the screen (we know ! 810: * that there's no problem with obscured areas). ! 811: */ ! 812: ! 813: gcValues.graphics_exposures = False; ! 814: newGC = Tk_GetGC(butPtr->tkwin, ! 815: GCForeground|GCBackground|GCFont|GCGraphicsExposures, &gcValues); ! 816: if (butPtr->normalTextGC != None) { ! 817: Tk_FreeGC(butPtr->normalTextGC); ! 818: } ! 819: butPtr->normalTextGC = newGC; ! 820: ! 821: if (butPtr->activeFg != NULL) { ! 822: gcValues.font = butPtr->fontPtr->fid; ! 823: gcValues.foreground = butPtr->activeFg->pixel; ! 824: gcValues.background = Tk_3DBorderColor(butPtr->activeBorder)->pixel; ! 825: newGC = Tk_GetGC(butPtr->tkwin, GCForeground|GCBackground|GCFont, ! 826: &gcValues); ! 827: if (butPtr->activeTextGC != None) { ! 828: Tk_FreeGC(butPtr->activeTextGC); ! 829: } ! 830: butPtr->activeTextGC = newGC; ! 831: } ! 832: ! 833: gcValues.font = butPtr->fontPtr->fid; ! 834: gcValues.background = Tk_3DBorderColor(butPtr->normalBorder)->pixel; ! 835: if (butPtr->disabledFg != NULL) { ! 836: gcValues.foreground = butPtr->disabledFg->pixel; ! 837: mask = GCForeground|GCBackground|GCFont; ! 838: } else { ! 839: gcValues.foreground = gcValues.background; ! 840: if (butPtr->gray == None) { ! 841: butPtr->gray = Tk_GetBitmap(interp, butPtr->tkwin, ! 842: Tk_GetUid("gray50")); ! 843: if (butPtr->gray == None) { ! 844: return TCL_ERROR; ! 845: } ! 846: } ! 847: gcValues.fill_style = FillStippled; ! 848: gcValues.stipple = butPtr->gray; ! 849: mask = GCForeground|GCFillStyle|GCStipple; ! 850: } ! 851: newGC = Tk_GetGC(butPtr->tkwin, mask, &gcValues); ! 852: if (butPtr->disabledGC != None) { ! 853: Tk_FreeGC(butPtr->disabledGC); ! 854: } ! 855: butPtr->disabledGC = newGC; ! 856: ! 857: if (butPtr->padX < 0) { ! 858: butPtr->padX = 0; ! 859: } ! 860: if (butPtr->padY < 0) { ! 861: butPtr->padY = 0; ! 862: } ! 863: ! 864: if (butPtr->type >= TYPE_CHECK_BUTTON) { ! 865: char *value; ! 866: ! 867: if (butPtr->selectorFg != NULL) { ! 868: gcValues.foreground = butPtr->selectorFg->pixel; ! 869: newGC = Tk_GetGC(butPtr->tkwin, GCForeground, &gcValues); ! 870: } else { ! 871: newGC = None; ! 872: } ! 873: if (butPtr->selectorGC != None) { ! 874: Tk_FreeGC(butPtr->selectorGC); ! 875: } ! 876: butPtr->selectorGC = newGC; ! 877: ! 878: if (butPtr->selVarName == NULL) { ! 879: butPtr->selVarName = (char *) ckalloc((unsigned) ! 880: (strlen(Tk_Name(butPtr->tkwin)) + 1)); ! 881: strcpy(butPtr->selVarName, Tk_Name(butPtr->tkwin)); ! 882: } ! 883: if (butPtr->onValue == NULL) { ! 884: butPtr->onValue = (char *) ckalloc((unsigned) ! 885: (strlen(Tk_Name(butPtr->tkwin)) + 1)); ! 886: strcpy(butPtr->onValue, Tk_Name(butPtr->tkwin)); ! 887: } ! 888: ! 889: /* ! 890: * Select the button if the associated variable has the ! 891: * appropriate value, initialize the variable if it doesn't ! 892: * exist, then set a trace on the variable to monitor future ! 893: * changes to its value. ! 894: */ ! 895: ! 896: value = Tcl_GetVar(interp, butPtr->selVarName, TCL_GLOBAL_ONLY); ! 897: butPtr->flags &= ~SELECTED; ! 898: if (value != NULL) { ! 899: if (strcmp(value, butPtr->onValue) == 0) { ! 900: butPtr->flags |= SELECTED; ! 901: } ! 902: } else { ! 903: Tcl_SetVar(interp, butPtr->selVarName, ! 904: (butPtr->type == TYPE_CHECK_BUTTON) ? butPtr->offValue : "", ! 905: TCL_GLOBAL_ONLY); ! 906: } ! 907: Tcl_TraceVar(interp, butPtr->selVarName, ! 908: TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ! 909: ButtonVarProc, (ClientData) butPtr); ! 910: } ! 911: ! 912: /* ! 913: * If the button is to display the value of a variable, then set up ! 914: * a trace on the variable's value, create the variable if it doesn't ! 915: * exist, and fetch its current value. ! 916: */ ! 917: ! 918: if ((butPtr->bitmap == None) && (butPtr->textVarName != NULL)) { ! 919: char *value; ! 920: ! 921: value = Tcl_GetVar(interp, butPtr->textVarName, TCL_GLOBAL_ONLY); ! 922: if (value == NULL) { ! 923: Tcl_SetVar(interp, butPtr->textVarName, butPtr->text, ! 924: TCL_GLOBAL_ONLY); ! 925: } else { ! 926: if (butPtr->text != NULL) { ! 927: ckfree(butPtr->text); ! 928: } ! 929: butPtr->text = ckalloc((unsigned) (strlen(value) + 1)); ! 930: strcpy(butPtr->text, value); ! 931: } ! 932: Tcl_TraceVar(interp, butPtr->textVarName, ! 933: TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ! 934: ButtonTextVarProc, (ClientData) butPtr); ! 935: } ! 936: ! 937: ComputeButtonGeometry(butPtr); ! 938: ! 939: /* ! 940: * Lastly, arrange for the button to be redisplayed. ! 941: */ ! 942: ! 943: if (Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) { ! 944: //Tk_TimerToken last = butPtr->updateTimerToken; ! 945: butPtr->flags |= REDRAW_PENDING; ! 946: // Tk_DoWhenIdle(DisplayButton, (ClientData) butPtr); ! 947: assert(butPtr->updateTimerToken == 0); ! 948: if (butPtr->updateTimerToken == 0) { ! 949: butPtr->updateTimerToken = ! 950: Tk_CreateTimerHandler( ! 951: ButtonUpdateTime, ! 952: DisplayButton, ! 953: (ClientData) butPtr); ! 954: } ! 955: //fprintf(stderr, "ConfigureButton Set Timer %s %s was %d now %d\n", Tk_Class(butPtr->tkwin), Tk_PathName(butPtr->tkwin), last, butPtr->updateTimerToken); ! 956: } ! 957: ! 958: return TCL_OK; ! 959: } ! 960: ! 961: /* ! 962: *---------------------------------------------------------------------- ! 963: * ! 964: * DisplayButton -- ! 965: * ! 966: * This procedure is invoked to display a button widget. ! 967: * ! 968: * Results: ! 969: * None. ! 970: * ! 971: * Side effects: ! 972: * Commands are output to X to display the button in its ! 973: * current mode. ! 974: * ! 975: *---------------------------------------------------------------------- ! 976: */ ! 977: ! 978: static void ! 979: DisplayButton(clientData) ! 980: ClientData clientData; /* Information about widget. */ ! 981: { ! 982: register Button *butPtr = (Button *) clientData; ! 983: GC gc; ! 984: Tk_3DBorder border; ! 985: Pixmap pixmap; ! 986: int x = 0; /* Initialization only needed to stop ! 987: * compiler warning. */ ! 988: int y; ! 989: register Tk_Window tkwin = butPtr->tkwin; ! 990: ! 991: //fprintf(stderr, "DisplayButton Handled Timer %s %s was %d now 0\n", Tk_Class(butPtr->tkwin), Tk_PathName(butPtr->tkwin), butPtr->updateTimerToken); ! 992: ! 993: assert(butPtr->updateTimerToken != 0); ! 994: butPtr->updateTimerToken = 0; ! 995: ! 996: butPtr->flags &= ~REDRAW_PENDING; ! 997: if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { ! 998: return; ! 999: } ! 1000: ! 1001: if ((butPtr->state == tkDisabledUid) && (butPtr->disabledFg != NULL)) { ! 1002: gc = butPtr->disabledGC; ! 1003: border = butPtr->normalBorder; ! 1004: } else if (butPtr->state == tkActiveUid) { ! 1005: gc = butPtr->activeTextGC; ! 1006: border = butPtr->activeBorder; ! 1007: } else { ! 1008: gc = butPtr->normalTextGC; ! 1009: border = butPtr->normalBorder; ! 1010: } ! 1011: ! 1012: /* ! 1013: * In order to avoid screen flashes, this procedure redraws ! 1014: * the button in a pixmap, then copies the pixmap to the ! 1015: * screen in a single operation. This means that there's no ! 1016: * point in time where the on-sreen image has been cleared. ! 1017: */ ! 1018: ! 1019: pixmap = XCreatePixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), ! 1020: Tk_Width(tkwin), Tk_Height(tkwin), ! 1021: Tk_DefaultDepth(Tk_Screen(tkwin))); ! 1022: Tk_Fill3DRectangle(Tk_Display(tkwin), pixmap, border, ! 1023: 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); ! 1024: ! 1025: /* ! 1026: * Display bitmap or text for button. ! 1027: */ ! 1028: ! 1029: if (butPtr->bitmap != None) { ! 1030: unsigned int width, height; ! 1031: ! 1032: #if defined(USE_XPM3) ! 1033: Tk_SizeOfPixmap(butPtr->bitmap, &width, &height); ! 1034: #else ! 1035: Tk_SizeOfBitmap(butPtr->bitmap, &width, &height); ! 1036: #endif ! 1037: switch (butPtr->anchor) { ! 1038: case TK_ANCHOR_NW: case TK_ANCHOR_W: case TK_ANCHOR_SW: ! 1039: x = butPtr->borderWidth + butPtr->selectorSpace ! 1040: + butPtr->padX + 1; ! 1041: break; ! 1042: case TK_ANCHOR_N: case TK_ANCHOR_CENTER: case TK_ANCHOR_S: ! 1043: x = (Tk_Width(tkwin) + butPtr->selectorSpace - width)/2; ! 1044: break; ! 1045: default: ! 1046: x = Tk_Width(tkwin) - butPtr->borderWidth - butPtr->padX ! 1047: - width - 1; ! 1048: break; ! 1049: } ! 1050: switch (butPtr->anchor) { ! 1051: case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE: ! 1052: y = butPtr->borderWidth + butPtr->padY + 1; ! 1053: break; ! 1054: case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E: ! 1055: y = (Tk_Height(tkwin) - height)/2; ! 1056: break; ! 1057: default: ! 1058: y = Tk_Height(tkwin) - butPtr->borderWidth - butPtr->padY ! 1059: - height - 1; ! 1060: break; ! 1061: } ! 1062: if (butPtr->relief == TK_RELIEF_RAISED) { ! 1063: x -= 1; ! 1064: y -= 1; ! 1065: } else if (butPtr->relief == TK_RELIEF_SUNKEN) { ! 1066: x += 1; ! 1067: y += 1; ! 1068: } ! 1069: #if defined(USE_XPM3) ! 1070: XCopyArea(Tk_Display(tkwin), butPtr->bitmap, pixmap, ! 1071: gc, 0, 0, width, height, x, y); ! 1072: #else ! 1073: XCopyPlane(Tk_Display(tkwin), butPtr->bitmap, pixmap, ! 1074: gc, 0, 0, width, height, x, y, 1); ! 1075: #endif ! 1076: y += height/2; ! 1077: } else { ! 1078: switch (butPtr->anchor) { ! 1079: case TK_ANCHOR_NW: case TK_ANCHOR_W: case TK_ANCHOR_SW: ! 1080: x = butPtr->borderWidth + butPtr->padX + butPtr->selectorSpace ! 1081: + butPtr->leftBearing + 1; ! 1082: break; ! 1083: case TK_ANCHOR_N: case TK_ANCHOR_CENTER: case TK_ANCHOR_S: ! 1084: x = (Tk_Width(tkwin) + butPtr->selectorSpace ! 1085: + butPtr->leftBearing - butPtr->rightBearing)/2; ! 1086: break; ! 1087: default: ! 1088: x = Tk_Width(tkwin) - butPtr->borderWidth - butPtr->padX ! 1089: - butPtr->rightBearing - 1; ! 1090: break; ! 1091: } ! 1092: switch (butPtr->anchor) { ! 1093: case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE: ! 1094: y = butPtr->borderWidth + butPtr->fontPtr->ascent ! 1095: + butPtr->padY + 1; ! 1096: break; ! 1097: case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E: ! 1098: y = (Tk_Height(tkwin) + butPtr->fontPtr->ascent ! 1099: - butPtr->fontPtr->descent)/2; ! 1100: break; ! 1101: default: ! 1102: y = Tk_Height(tkwin) - butPtr->borderWidth - butPtr->padY ! 1103: - butPtr->fontPtr->descent - 1; ! 1104: break; ! 1105: } ! 1106: if (butPtr->relief == TK_RELIEF_RAISED) { ! 1107: x -= 1; ! 1108: y -= 1; ! 1109: } else if (butPtr->relief == TK_RELIEF_SUNKEN) { ! 1110: x += 1; ! 1111: y += 1; ! 1112: } ! 1113: XDrawString(Tk_Display(tkwin), pixmap, gc, x, y, ! 1114: butPtr->text, butPtr->textLength); ! 1115: y -= (butPtr->fontPtr->ascent - butPtr->fontPtr->descent)/2; ! 1116: x -= butPtr->leftBearing; ! 1117: } ! 1118: ! 1119: /* ! 1120: * Draw the selector for check buttons and radio buttons. At this ! 1121: * point x and y refer to the top-left corner of the text or bitmap. ! 1122: */ ! 1123: ! 1124: if ((butPtr->type == TYPE_CHECK_BUTTON) && (butPtr->selectorGC != None)) { ! 1125: int dim; ! 1126: ! 1127: dim = butPtr->selectorDiameter; ! 1128: x -= (butPtr->selectorSpace + butPtr->padX + dim)/2; ! 1129: y -= dim/2; ! 1130: Tk_Draw3DRectangle(Tk_Display(tkwin), pixmap, border, x, y, ! 1131: dim, dim, butPtr->borderWidth, TK_RELIEF_SUNKEN); ! 1132: x += butPtr->borderWidth; ! 1133: y += butPtr->borderWidth; ! 1134: dim -= 2*butPtr->borderWidth; ! 1135: if (dim > 0) { ! 1136: if (butPtr->flags & SELECTED) { ! 1137: XFillRectangle(Tk_Display(tkwin), pixmap, butPtr->selectorGC, ! 1138: x, y, (unsigned int) dim, (unsigned int) dim); ! 1139: } else { ! 1140: Tk_Fill3DRectangle(Tk_Display(tkwin), pixmap, ! 1141: butPtr->normalBorder, x, y, dim, dim, ! 1142: butPtr->borderWidth, TK_RELIEF_FLAT); ! 1143: } ! 1144: } ! 1145: } else if ((butPtr->type == TYPE_RADIO_BUTTON) ! 1146: && (butPtr->selectorGC != None)) { ! 1147: XPoint points[4]; ! 1148: int radius; ! 1149: ! 1150: radius = butPtr->selectorDiameter/2; ! 1151: points[0].x = x - (butPtr->selectorSpace + butPtr->padX ! 1152: + butPtr->selectorDiameter)/2; ! 1153: points[0].y = y; ! 1154: points[1].x = points[0].x + radius; ! 1155: points[1].y = points[0].y + radius; ! 1156: points[2].x = points[1].x + radius; ! 1157: points[2].y = points[0].y; ! 1158: points[3].x = points[1].x; ! 1159: points[3].y = points[0].y - radius; ! 1160: if (butPtr->flags & SELECTED) { ! 1161: XFillPolygon(Tk_Display(tkwin), pixmap, butPtr->selectorGC, ! 1162: points, 4, Convex, CoordModeOrigin); ! 1163: } else { ! 1164: Tk_Fill3DPolygon(Tk_Display(tkwin), pixmap, butPtr->normalBorder, ! 1165: points, 4, butPtr->borderWidth, TK_RELIEF_FLAT); ! 1166: } ! 1167: Tk_Draw3DPolygon(Tk_Display(tkwin), pixmap, border, ! 1168: points, 4, butPtr->borderWidth, TK_RELIEF_RAISED); ! 1169: } ! 1170: ! 1171: /* ! 1172: * If the button is disabled with a stipple rather than a special ! 1173: * foreground color, generate the stippled effect. ! 1174: */ ! 1175: ! 1176: if ((butPtr->state == tkDisabledUid) && (butPtr->disabledFg == NULL)) { ! 1177: XFillRectangle(Tk_Display(tkwin), pixmap, butPtr->disabledGC, ! 1178: butPtr->borderWidth, butPtr->borderWidth, ! 1179: (unsigned) (Tk_Width(tkwin) - 2*butPtr->borderWidth), ! 1180: (unsigned) (Tk_Height(tkwin) - 2*butPtr->borderWidth)); ! 1181: } ! 1182: ! 1183: /* ! 1184: * Draw the border last. This way, if the button's contents ! 1185: * overflow onto the border they'll be covered up by the border. ! 1186: */ ! 1187: ! 1188: if (butPtr->relief != TK_RELIEF_FLAT) { ! 1189: Tk_Draw3DRectangle(Tk_Display(tkwin), pixmap, border,0, 0, ! 1190: Tk_Width(tkwin), Tk_Height(tkwin), butPtr->borderWidth, ! 1191: butPtr->relief); ! 1192: } ! 1193: ! 1194: /* ! 1195: * Copy the information from the off-screen pixmap onto the screen, ! 1196: * then delete the pixmap. ! 1197: */ ! 1198: ! 1199: XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin), ! 1200: butPtr->normalTextGC, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, 0); ! 1201: XFreePixmap(Tk_Display(tkwin), pixmap); ! 1202: } ! 1203: ! 1204: /* ! 1205: *-------------------------------------------------------------- ! 1206: * ! 1207: * ButtonEventProc -- ! 1208: * ! 1209: * This procedure is invoked by the Tk dispatcher for various ! 1210: * events on buttons. ! 1211: * ! 1212: * Results: ! 1213: * None. ! 1214: * ! 1215: * Side effects: ! 1216: * When the window gets deleted, internal structures get ! 1217: * cleaned up. When it gets exposed, it is redisplayed. ! 1218: * ! 1219: *-------------------------------------------------------------- ! 1220: */ ! 1221: ! 1222: static void ! 1223: ButtonEventProc(clientData, eventPtr) ! 1224: ClientData clientData; /* Information about window. */ ! 1225: XEvent *eventPtr; /* Information about event. */ ! 1226: { ! 1227: Button *butPtr = (Button *) clientData; ! 1228: if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { ! 1229: if ((butPtr->tkwin != NULL) && !(butPtr->flags & REDRAW_PENDING)) { ! 1230: //Tk_TimerToken last = butPtr->updateTimerToken; ! 1231: butPtr->flags |= REDRAW_PENDING; ! 1232: // Tk_DoWhenIdle(DisplayButton, (ClientData) butPtr); ! 1233: assert(butPtr->updateTimerToken == NULL); ! 1234: if (butPtr->updateTimerToken == NULL) { ! 1235: butPtr->updateTimerToken = ! 1236: Tk_CreateTimerHandler( ! 1237: ButtonUpdateTime, ! 1238: DisplayButton, ! 1239: (ClientData) butPtr); ! 1240: } // if ! 1241: //fprintf(stderr, "ButtonEventProc Expose Set Timer %s %s was %d now %d\n", Tk_Class(butPtr->tkwin), Tk_PathName(butPtr->tkwin), last, butPtr->updateTimerToken); ! 1242: } ! 1243: } else if (eventPtr->type == DestroyNotify) { ! 1244: Tcl_DeleteCommand(butPtr->interp, Tk_PathName(butPtr->tkwin)); ! 1245: butPtr->tkwin = NULL; ! 1246: if (butPtr->flags & REDRAW_PENDING) { ! 1247: //fprintf(stderr, "ButtonEventProc Destroy Timer was %d now 0\n", butPtr->updateTimerToken); ! 1248: // Tk_CancelIdleCall(DisplayButton, (ClientData) butPtr); ! 1249: butPtr->flags &= ~REDRAW_PENDING; ! 1250: assert(butPtr->updateTimerToken != NULL); ! 1251: if (butPtr->updateTimerToken != NULL) { ! 1252: Tk_DeleteTimerHandler(butPtr->updateTimerToken); ! 1253: butPtr->updateTimerToken = 0; ! 1254: } ! 1255: } ! 1256: Tk_EventuallyFree((ClientData) butPtr, DestroyButton); ! 1257: } ! 1258: } ! 1259: ! 1260: /* ! 1261: *---------------------------------------------------------------------- ! 1262: * ! 1263: * ComputeButtonGeometry -- ! 1264: * ! 1265: * After changes in a button's text or bitmap, this procedure ! 1266: * recomputes the button's geometry and passes this information ! 1267: * along to the geometry manager for the window. ! 1268: * ! 1269: * Results: ! 1270: * None. ! 1271: * ! 1272: * Side effects: ! 1273: * The button's window may change size. ! 1274: * ! 1275: *---------------------------------------------------------------------- ! 1276: */ ! 1277: ! 1278: static void ! 1279: ComputeButtonGeometry(butPtr) ! 1280: register Button *butPtr; /* Button whose geometry may have changed. */ ! 1281: { ! 1282: XCharStruct bbox; ! 1283: int dummy; ! 1284: unsigned int width, height; ! 1285: ! 1286: butPtr->selectorSpace = 0; ! 1287: if (butPtr->bitmap != None) { ! 1288: #if defined(USE_XPM3) ! 1289: Tk_SizeOfPixmap(butPtr->bitmap, &width, &height); ! 1290: #else ! 1291: Tk_SizeOfBitmap(butPtr->bitmap, &width, &height); ! 1292: #endif ! 1293: if (butPtr->width > 0) { ! 1294: width = butPtr->width; ! 1295: } ! 1296: if (butPtr->height > 0) { ! 1297: height = butPtr->height; ! 1298: } ! 1299: if ((butPtr->type >= TYPE_CHECK_BUTTON) ! 1300: && (butPtr->selectorGC != None)) { ! 1301: butPtr->selectorSpace = (14*height)/10; ! 1302: if (butPtr->type == TYPE_CHECK_BUTTON) { ! 1303: butPtr->selectorDiameter = (65*height)/100; ! 1304: } else { ! 1305: butPtr->selectorDiameter = (75*height)/100; ! 1306: } ! 1307: } ! 1308: } else { ! 1309: butPtr->textLength = strlen(butPtr->text); ! 1310: XTextExtents(butPtr->fontPtr, butPtr->text, butPtr->textLength, ! 1311: &dummy, &dummy, &dummy, &bbox); ! 1312: butPtr->leftBearing = bbox.lbearing; ! 1313: butPtr->rightBearing = bbox.rbearing; ! 1314: width = bbox.lbearing + bbox.rbearing; ! 1315: height = butPtr->fontPtr->ascent + butPtr->fontPtr->descent; ! 1316: if (butPtr->width > 0) { ! 1317: width = butPtr->width * XTextWidth(butPtr->fontPtr, "0", 1); ! 1318: } ! 1319: if (butPtr->height > 0) { ! 1320: height *= butPtr->height; ! 1321: } ! 1322: if ((butPtr->type >= TYPE_CHECK_BUTTON) ! 1323: && (butPtr->selectorGC != None)) { ! 1324: butPtr->selectorDiameter = butPtr->fontPtr->ascent ! 1325: + butPtr->fontPtr->descent; ! 1326: if (butPtr->type == TYPE_CHECK_BUTTON) { ! 1327: butPtr->selectorDiameter = (80*butPtr->selectorDiameter)/100; ! 1328: } ! 1329: butPtr->selectorSpace = butPtr->selectorDiameter + butPtr->padX; ! 1330: } ! 1331: } ! 1332: ! 1333: /* ! 1334: * When issuing the geometry request, add extra space for the selector, ! 1335: * if any, and for the border and padding, plus two extra pixels so the ! 1336: * display can be offset by 1 pixel in either direction for the raised ! 1337: * or lowered effect. ! 1338: */ ! 1339: ! 1340: width += 2*butPtr->padX; ! 1341: height += 2*butPtr->padY; ! 1342: Tk_GeometryRequest(butPtr->tkwin, (int) (width + butPtr->selectorSpace ! 1343: + 2*butPtr->borderWidth + 2), ! 1344: (int) (height + 2*butPtr->borderWidth + 2)); ! 1345: Tk_SetInternalBorder(butPtr->tkwin, butPtr->borderWidth); ! 1346: } ! 1347: ! 1348: /* ! 1349: *---------------------------------------------------------------------- ! 1350: * ! 1351: * InvokeButton -- ! 1352: * ! 1353: * This procedure is called to carry out the actions associated ! 1354: * with a button, such as invoking a Tcl command or setting a ! 1355: * variable. This procedure is invoked, for example, when the ! 1356: * button is invoked via the mouse. ! 1357: * ! 1358: * Results: ! 1359: * A standard Tcl return value. Information is also left in ! 1360: * interp->result. ! 1361: * ! 1362: * Side effects: ! 1363: * Depends on the button and its associated command. ! 1364: * ! 1365: *---------------------------------------------------------------------- ! 1366: */ ! 1367: ! 1368: static int ! 1369: InvokeButton(butPtr) ! 1370: register Button *butPtr; /* Information about button. */ ! 1371: { ! 1372: if (butPtr->type == TYPE_CHECK_BUTTON) { ! 1373: if (butPtr->flags & SELECTED) { ! 1374: Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->offValue, ! 1375: TCL_GLOBAL_ONLY); ! 1376: } else { ! 1377: Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->onValue, ! 1378: TCL_GLOBAL_ONLY); ! 1379: } ! 1380: } else if (butPtr->type == TYPE_RADIO_BUTTON) { ! 1381: Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->onValue, ! 1382: TCL_GLOBAL_ONLY); ! 1383: } ! 1384: if ((butPtr->type != TYPE_LABEL) && (butPtr->command != NULL)) { ! 1385: return Tcl_GlobalEval(butPtr->interp, butPtr->command); ! 1386: } ! 1387: return TCL_OK; ! 1388: } ! 1389: ! 1390: /* ! 1391: *-------------------------------------------------------------- ! 1392: * ! 1393: * ButtonVarProc -- ! 1394: * ! 1395: * This procedure is invoked when someone changes the ! 1396: * state variable associated with a radio button. Depending ! 1397: * on the new value of the button's variable, the button ! 1398: * may be selected or deselected. ! 1399: * ! 1400: * Results: ! 1401: * NULL is always returned. ! 1402: * ! 1403: * Side effects: ! 1404: * The button may become selected or deselected. ! 1405: * ! 1406: *-------------------------------------------------------------- ! 1407: */ ! 1408: ! 1409: /* ARGSUSED */ ! 1410: static char * ! 1411: ButtonVarProc(clientData, interp, name1, name2, flags) ! 1412: ClientData clientData; /* Information about button. */ ! 1413: Tcl_Interp *interp; /* Interpreter containing variable. */ ! 1414: char *name1; /* Name of variable. */ ! 1415: char *name2; /* Second part of variable name. */ ! 1416: int flags; /* Information about what happened. */ ! 1417: { ! 1418: register Button *butPtr = (Button *) clientData; ! 1419: char *value; ! 1420: ! 1421: /* ! 1422: * If the variable is being unset, then just re-establish the ! 1423: * trace unless the whole interpreter is going away. ! 1424: */ ! 1425: ! 1426: if (flags & TCL_TRACE_UNSETS) { ! 1427: butPtr->flags &= ~SELECTED; ! 1428: if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { ! 1429: Tcl_TraceVar2(interp, name1, name2, ! 1430: TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ! 1431: ButtonVarProc, clientData); ! 1432: } ! 1433: goto redisplay; ! 1434: } ! 1435: ! 1436: /* ! 1437: * Use the value of the variable to update the selected status of ! 1438: * the button. ! 1439: */ ! 1440: ! 1441: value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY); ! 1442: if (strcmp(value, butPtr->onValue) == 0) { ! 1443: if (butPtr->flags & SELECTED) { ! 1444: return (char *) NULL; ! 1445: } ! 1446: butPtr->flags |= SELECTED; ! 1447: } else if (butPtr->flags & SELECTED) { ! 1448: butPtr->flags &= ~SELECTED; ! 1449: } else { ! 1450: return (char *) NULL; ! 1451: } ! 1452: ! 1453: redisplay: ! 1454: if ((butPtr->tkwin != NULL) && Tk_IsMapped(butPtr->tkwin) ! 1455: && !(butPtr->flags & REDRAW_PENDING)) { ! 1456: //Tk_TimerToken last = butPtr->updateTimerToken; ! 1457: butPtr->flags |= REDRAW_PENDING; ! 1458: // Tk_DoWhenIdle(DisplayButton, (ClientData) butPtr); ! 1459: assert(butPtr->updateTimerToken == NULL); ! 1460: if (butPtr->updateTimerToken == NULL) { ! 1461: butPtr->updateTimerToken = ! 1462: Tk_CreateTimerHandler( ! 1463: ButtonUpdateTime, ! 1464: DisplayButton, ! 1465: (ClientData) butPtr); ! 1466: } ! 1467: //fprintf(stderr, "ButtonVarProc Set Timer %s %s was %d now %d\n", Tk_Class(butPtr->tkwin), Tk_PathName(butPtr->tkwin), last, butPtr->updateTimerToken); ! 1468: } ! 1469: return (char *) NULL; ! 1470: } ! 1471: ! 1472: /* ! 1473: *-------------------------------------------------------------- ! 1474: * ! 1475: * ButtonTextVarProc -- ! 1476: * ! 1477: * This procedure is invoked when someone changes the variable ! 1478: * whose contents are to be displayed in a button. ! 1479: * ! 1480: * Results: ! 1481: * NULL is always returned. ! 1482: * ! 1483: * Side effects: ! 1484: * The text displayed in the button will change to match the ! 1485: * variable. ! 1486: * ! 1487: *-------------------------------------------------------------- ! 1488: */ ! 1489: ! 1490: /* ARGSUSED */ ! 1491: static char * ! 1492: ButtonTextVarProc(clientData, interp, name1, name2, flags) ! 1493: ClientData clientData; /* Information about button. */ ! 1494: Tcl_Interp *interp; /* Interpreter containing variable. */ ! 1495: char *name1; /* Name of variable. */ ! 1496: char *name2; /* Second part of variable name. */ ! 1497: int flags; /* Information about what happened. */ ! 1498: { ! 1499: register Button *butPtr = (Button *) clientData; ! 1500: char *value; ! 1501: ! 1502: /* ! 1503: * If the variable is unset, then immediately recreate it unless ! 1504: * the whole interpreter is going away. ! 1505: */ ! 1506: ! 1507: if (flags & TCL_TRACE_UNSETS) { ! 1508: if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { ! 1509: Tcl_SetVar2(interp, name1, name2, butPtr->text, ! 1510: flags & TCL_GLOBAL_ONLY); ! 1511: Tcl_TraceVar2(interp, name1, name2, ! 1512: TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ! 1513: ButtonTextVarProc, clientData); ! 1514: } ! 1515: return (char *) NULL; ! 1516: } ! 1517: ! 1518: value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY); ! 1519: if (value == NULL) { ! 1520: value = ""; ! 1521: } ! 1522: if (butPtr->text != NULL) { ! 1523: ckfree(butPtr->text); ! 1524: } ! 1525: butPtr->text = ckalloc((unsigned) (strlen(value) + 1)); ! 1526: strcpy(butPtr->text, value); ! 1527: ComputeButtonGeometry(butPtr); ! 1528: ! 1529: if ((butPtr->tkwin != NULL) && Tk_IsMapped(butPtr->tkwin) ! 1530: && !(butPtr->flags & REDRAW_PENDING)) { ! 1531: //Tk_TimerToken last = butPtr->updateTimerToken; ! 1532: butPtr->flags |= REDRAW_PENDING; ! 1533: // Tk_DoWhenIdle(DisplayButton, (ClientData) butPtr); ! 1534: assert(butPtr->updateTimerToken == NULL); ! 1535: if (butPtr->updateTimerToken == NULL) { ! 1536: butPtr->updateTimerToken = ! 1537: Tk_CreateTimerHandler( ! 1538: ButtonUpdateTime, ! 1539: DisplayButton, ! 1540: (ClientData) butPtr); ! 1541: } ! 1542: //fprintf(stderr, "ButtonTextVarProc Set Timer %s %s was %d now %d\n", Tk_Class(butPtr->tkwin), Tk_PathName(butPtr->tkwin), last, butPtr->updateTimerToken); ! 1543: } ! 1544: return (char *) NULL; ! 1545: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.