Annotation of micropolis/src/tk/tkbutton.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.