Clock Widget in C

http://www.tfh-berlin.de/~sleuthold/files/tcl/clock.jpg [May 06]


The source of Clock Widget in C is from:

Practical Programming in Tcl and Tk (fourth edition) written by Brent B. Welch, Ken Jones and Jeffrey Hobbs (Chapter 49, Writing a Tk Widget in C).

I was trying to build the extension just for fun and education. And I wanted to see how it looks like. Here are some pictures (WinXP and Linux).

    package require Tkclock

    oclock .oc
    pack .oc

    # wclock .wc
    # pack .wc

Some changes to the code where necessary to build and run it. I'm not sure if this is because of 8.x or real bugs. Search for MODIFY to see what I had to change.

        /* Tkclock.cpp */

        /*
         * Example 49-2
         * The Clock widget data structure.
         */

        #include "tk.h"

        #include <string.h>
        /* MODIFY */
        #ifndef __WIN32__
                #include <sys/time.h>
        #else
                #include <time.h>
                #define TCL_STORAGE_CLASS DLLEXPORT
        #endif


        typedef struct {
                Tk_Window tkwin;                                                        /* The window for the widget */
                Display *display;                                                        /* Tk's handle on the display */
                Tcl_Interp *interp;                                                        /* Interpreter of the widget */
                Tcl_Command widgetCmd;                                                        /* clock instance command. */
                Tk_OptionTable optionTable; /* Used to parse options */
                /*
                 * Clock-specific attributes.
                 */
                int borderWidth;                                                        /* Size of 3-D border */
                Tcl_Obj *borderWidthPtr;        /* Original string value */
                int relief;                                                        /* Style of 3-D border */
                Tk_3DBorder background;                                                        /* Color for border & background */
                XColor *foreground;                                                        /* Color for the text */
                XColor *highlight;                                                        /* Color for active highlight */
                XColor *highlightBg;                                                        /* Color for neutral highlight */
                int highlightWidth;                                                        /* Thickness of highlight rim */
                Tcl_Obj *highlightWidthPtr; /* Original string value */
                Tk_Font tkfont;                                                        /* Font info for the text */
                char *format;                                                        /* Format for time string */
                /*
                 * Graphic contexts and other support.
                 */
                GC textGC;                                                        /* Text graphics context */
                Tk_TimerToken token;                                                        /* Periodic callback handle*/
                char *clock;                                                        /* Pointer to the clock string */
                int numChars;                                                        /* length of the text */
                int textWidth;                                                        /* in pixels */
                Tcl_Obj *widthPtr;                                                        /* The original width string value*/
                int textHeight;                                                        /* in pixels */
                Tcl_Obj *heightPtr;                                                        /* The original height string value*/
                int padX;                                                        /* Horizontal padding */
                Tcl_Obj *padXPtr;                                                        /* The original padX string value*/
                int padY;                                                        /* Vertical padding */
                Tcl_Obj *padYPtr;                                                        /* The original padY string value */
                int flags;                                                        /* Flags defined below */
        } Clock;
        /*
        * Flag bit definitions.
        */
        #define REDRAW_PENDING                                                        0x1
        #define GOT_FOCUS                                                        0x2
        #define TICKING                                                        0x4


        /*
         * Example 49-10
         * Configuration specs for the clock widget.
         */

        static Tk_ConfigSpec configSpecs[] = {
                {TK_CONFIG_BORDER, "-background", "background",
                        "Background", "light blue",
                        Tk_Offset(Clock, background), TK_CONFIG_COLOR_ONLY},
                {TK_CONFIG_BORDER, "-background", "background",
                        "Background", "white", Tk_Offset(Clock, background),
                        TK_CONFIG_MONO_ONLY},
                {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
                        (char *) NULL, 0, 0},
                {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
                        (char *) NULL, 0, 0},
                {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth",
                        "BorderWidth","2", Tk_Offset(Clock, borderWidth), 0},
                {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
                        "ridge", Tk_Offset(Clock, relief), 0},
                {TK_CONFIG_COLOR, "-foreground", "foreground",
                        "Foreground", "black", Tk_Offset(Clock, foreground),0},
                {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
                        (char *) NULL, 0, 0},
                {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor",
                        "HighlightColor", "red", Tk_Offset(Clock, highlight),
                        TK_CONFIG_COLOR_ONLY},
                {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor",
                         "HighlightColor", "black", 
                        Tk_Offset(Clock, highlight),TK_CONFIG_MONO_ONLY},
                {TK_CONFIG_COLOR, "-highlightbackground", 
                        "highlightBackground", "HighlightBackground",
                        "light blue", Tk_Offset(Clock, highlightBg),
                        TK_CONFIG_COLOR_ONLY},
                {TK_CONFIG_COLOR, "-highlightbackground", 
                        "highlightBackground", "HighlightBackground",
                        "black", Tk_Offset(Clock, highlightBg),
                        TK_CONFIG_MONO_ONLY},
                {TK_CONFIG_PIXELS, "-highlightthickness",
                        "highlightThickness","HighlightThickness",
                        "2", Tk_Offset(Clock, highlightWidth), 0},
                {TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
                        "2", Tk_Offset(Clock, padX), 0},
                {TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
                        "2", Tk_Offset(Clock, padY), 0},
                {TK_CONFIG_STRING, "-format", "format", "Format",
                        "%H:%M:%S", Tk_Offset(Clock, format), 0},
                {TK_CONFIG_FONT, "-font", "font", "Font",
                        "Courier 18",
                         Tk_Offset(Clock, tkfont), 0},
                {TK_CONFIG_END, (char *) NULL, (char *) NULL,
                         (char *) NULL, (char *) NULL, 0, 0}
        };


        /*
         * Example 49-12
         * The Tk_OptionSpec structure for the clock widget.
         */

        #define GEOMETRY_MASK 0X1
        #define GRAPHICS_MASK 0X2

        static Tk_OptionSpec optionSpecs[] = {
                {TK_OPTION_BORDER, "-background", "background",
                        "Background", "light blue", -1,
                        Tk_Offset(Clock, background), 0, 
                        (ClientData) "white", GRAPHICS_MASK},
        /* MOFIFY */
                {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL,
                        (char *) NULL, -1, 0, 0, (ClientData) "-background", 0},
                {TK_OPTION_PIXELS, "-borderwidth", "borderWidth",
                        "BorderWidth", "2", Tk_Offset(Clock, borderWidthPtr),
                        Tk_Offset(Clock, borderWidth), 
                        0, 0, GEOMETRY_MASK},
        /* MOFIFY */
                {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
                        (char *) NULL, -1, 0, 0, (ClientData) "-borderwidth", 0},
                {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
                        "ridge", -1, Tk_Offset(Clock, relief), 0, 0, 0},
                {TK_OPTION_COLOR, "-foreground", "foreground",
                        "Foreground", "black",-1, Tk_Offset(Clock, foreground),
                        0, (ClientData) "black", GRAPHICS_MASK},
        /* MOFIFY */
                {TK_OPTION_SYNONYM, "-fg", (char *) NULL, (char *) NULL,
                        (char *) NULL, -1, 0, 0, (ClientData) "-foreground", 0},
                {TK_OPTION_COLOR, "-highlightcolor", "highlightColor",
                        "HighlightColor", "red",-1, Tk_Offset(Clock, highlight),
                        0, (ClientData) "black", GRAPHICS_MASK},
                {TK_OPTION_COLOR, "-highlightbackground", 
                        "highlightBackground", "HighlightBackground",
                        "light blue",-1, Tk_Offset(Clock, highlightBg),
                        0, (ClientData) "white", GRAPHICS_MASK},
                {TK_OPTION_PIXELS, "-highlightthickness",
                        "highlightThickness","HighlightThickness",
                        "2", Tk_Offset(Clock, highlightWidthPtr),
                        Tk_Offset(Clock, highlightWidth), 0, 0,
                        GEOMETRY_MASK},
                {TK_OPTION_PIXELS, "-padx", "padX", "Pad",
                        "2", Tk_Offset(Clock, padXPtr),
                        Tk_Offset(Clock, padX), 0, 0, GEOMETRY_MASK},
                {TK_OPTION_PIXELS, "-pady", "padY", "Pad",
                        "2", Tk_Offset(Clock, padYPtr),
                        Tk_Offset(Clock, padY), 0, 0, GEOMETRY_MASK},
                {TK_OPTION_STRING, "-format", "format", "Format",
                        "%H:%M:%S",-1, Tk_Offset(Clock, format), 0, 0,
                        GEOMETRY_MASK},
                {TK_OPTION_FONT, "-font", "font", "Font",
                        "Courier 18",
                        -1, Tk_Offset(Clock, tkfont), 0, 0, 
                        (GRAPHICS_MASK|GEOMETRY_MASK)},
                {TK_OPTION_END, (char *) NULL, (char *) NULL,
                         (char *) NULL, (char *) NULL, -1, 0, 0, 0, 0}
        };

        /*
         * Example 49-1
         * The Clock_Init procedure.
         */

        int ClockCmd(ClientData clientData,
                                        Tcl_Interp *interp,
                                        int argc, CONST char *argv[]);
        int ClockObjCmd(ClientData clientData,
                                        Tcl_Interp *interp,
                                        int objc, Tcl_Obj *CONST objv[]);
        void ClockObjDelete(ClientData clientData);


        /*
         * forward all procedures
         */

        static int
        ClockInstanceCmd(ClientData clientData, 
                                         Tcl_Interp *interp, 
                                         int argc, 
                                         CONST char *argv[]);
        static int
        ClockInstanceObjCmd(ClientData clientData, 
                                                Tcl_Interp *interp, 
                                                int objc, 
                                                Tcl_Obj *CONST objv[]);
        static int
        ClockConfigure(Tcl_Interp *interp, 
                                   Clock *clockPtr, 
                                   int argc, 
                                   CONST char *argv[], 
                                   int flags);
        static int
        ClockObjConfigure(Tcl_Interp *interp, 
                                          Clock *clockPtr, 
                                          int objc, 
                                          Tcl_Obj *CONST objv[]);
        static void
        ComputeGeometry(Clock *clockPtr);

        static void
        ClockDisplay(ClientData clientData);

        static void
        ClockEventProc(ClientData clientData, 
                                   XEvent *eventPtr);
        static void
        ClockDestroy(ClientData clientData);

        void
        ClockObjDelete(ClientData clientData);


        /*
        * Clock_Init is called when the package is loaded.
        */
        EXTERN int Tkclock_Init(Tcl_Interp *interp) {
                if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
                        return TCL_ERROR;
                }
        /* MODIFY */
                if (Tk_InitStubs(interp, "8.1", 0) == NULL) {
                        return TCL_ERROR;
                }
                Tcl_CreateCommand(interp, "wclock", ClockCmd,
                                (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
                Tcl_CreateObjCommand(interp, "oclock", ClockObjCmd,
                                (ClientData)NULL, ClockObjDelete);
                Tcl_PkgRequire(interp, "Tk", "8.1",0);
                Tcl_PkgProvide(interp, "Tkclock", "1.0");
                return TCL_OK;
        }

        /*
         * Example 49-3
         * The ClockCmd command procedure.
         */

        int
        ClockCmd(clientData, interp, argc, argv)
                ClientData clientData;                                                /* Main window of the app */
                Tcl_Interp *interp;                                                /* Current interpreter. */
                int argc;                                                /* Number of arguments. */
                CONST char **argv;                                                /* Argument strings. */
        {
        /* MODIFY */
                /* Tk_Window main_tk = (Tk_Window) clientData; */
                Clock *clockPtr;
                Tk_Window tkwin;
         
                if (argc < 2) {
                        Tcl_AppendResult(interp, "wrong # args: should be \"",
                                 argv[0], " pathName ?options?\"", (char *) NULL);
                        return TCL_ERROR;
                }
        /* MODIFY */
                tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp),
                                 argv[1], (char *) NULL);
                if (tkwin == NULL) {
                        return TCL_ERROR;
                }
                /*
                 * Set resource class.
                 */
                Tk_SetClass(tkwin, "Clock");
                /*
                 * Allocate and initialize the widget record.
                 */
                clockPtr = (Clock *) Tcl_Alloc(sizeof(Clock));
                clockPtr->tkwin = tkwin;
                clockPtr->display = Tk_Display(tkwin);
                clockPtr->interp = interp;
                clockPtr->borderWidth = 0;
                clockPtr->highlightWidth = 0;
                clockPtr->relief = TK_RELIEF_FLAT;
                clockPtr->background = NULL;
                clockPtr->foreground = NULL;
                clockPtr->highlight = NULL;
                clockPtr->highlightBg = NULL;
                clockPtr->tkfont = NULL;
                clockPtr->textGC = None;
                clockPtr->token = NULL;
                clockPtr->clock = NULL;
                clockPtr->format = NULL;
                clockPtr->numChars = 0;
                clockPtr->textWidth = 0;
                clockPtr->textHeight = 0;
                clockPtr->padX = 0;
                clockPtr->padY = 0;
                clockPtr->flags = 0;
                /*
                 * Register a handler for when the window is
                 * exposed or resized.
                 */
                Tk_CreateEventHandler(clockPtr->tkwin,
                        ExposureMask|StructureNotifyMask|FocusChangeMask,
                        ClockEventProc, (ClientData) clockPtr);
                /*
                 * Create a Tcl command that operates on the widget.
                 */
                clockPtr->widgetCmd = Tcl_CreateCommand(interp,
                        Tk_PathName(clockPtr->tkwin),
                        ClockInstanceCmd,
                        (ClientData) clockPtr, (void (*)()) NULL);
                /*
                 * Parse the command line arguments.
                 */
                if (ClockConfigure(interp, clockPtr,
                                 argc-2, argv+2, 0) != TCL_OK) {
                        Tk_DestroyWindow(clockPtr->tkwin);
                        return TCL_ERROR;
                }
                interp->result = Tk_PathName(clockPtr->tkwin);
                return TCL_OK;
        }


        /*
         * Example 49-4
         * The ClockObjCmd command procedure.
         */

        int
        ClockObjCmd(clientData, interp, objc, objv)
                ClientData clientData;                                                /* Main window of the app */
                Tcl_Interp *interp;                                                /* Current interpreter. */
                int objc;                                                /* Number of arguments. */
                Tcl_Obj *CONST objv[];                                                /* Argument values. */
        {
                Tk_OptionTable optionTable;
                Clock *clockPtr;
                Tk_Window tkwin;
         
                if (objc < 2) {
                        Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?");
                        return TCL_ERROR;
                }
                optionTable = (Tk_OptionTable) clientData;
                if (optionTable == NULL) {
                        Tcl_CmdInfo info;
                        char *name;

                        /*
                         * Initialize the option table for this widget the
                         * first time a clock widget is created. The option
                         * table is saved as our client data.
                         */
                        
                        optionTable = Tk_CreateOptionTable(interp, optionSpecs);
                        name = Tcl_GetString(objv[0]);
                        Tcl_GetCommandInfo(interp, name, &info);
                        info.objClientData = (ClientData) optionTable;
                        Tcl_SetCommandInfo(interp, name, &info);
                }
                tkwin = Tk_CreateWindowFromPath(interp,
                                Tk_MainWindow(interp),
                                Tcl_GetString(objv[1]), (char *) NULL);
                if (tkwin == NULL) {
                        return TCL_ERROR;
                }
                /*
                 * Set resource class.
                 */
                Tk_SetClass(tkwin, "Clock");
                /*
                 * Allocate and initialize the widget record.
                 */
                clockPtr = (Clock *) ckalloc(sizeof(Clock));
                clockPtr->tkwin = tkwin;
                clockPtr->display = Tk_Display(tkwin);
                clockPtr->interp = interp;
                clockPtr->optionTable = optionTable;
                clockPtr->borderWidth = 0;
                clockPtr->borderWidthPtr = NULL;
                clockPtr->highlightWidth = 0;
                clockPtr->highlightWidthPtr = NULL;
                clockPtr->relief = TK_RELIEF_FLAT;
                clockPtr->background = NULL;
                clockPtr->foreground = NULL;
                clockPtr->highlight = NULL;
                clockPtr->highlightBg = NULL;
                clockPtr->tkfont = NULL;
                clockPtr->textGC = None;
                clockPtr->token = NULL;
                clockPtr->clock = NULL;
                clockPtr->format = NULL;
                clockPtr->numChars = 0;
                clockPtr->textWidth = 0;
                clockPtr->widthPtr = NULL;
                clockPtr->textHeight = 0;
                clockPtr->heightPtr = NULL;
                clockPtr->padX = 0;
                clockPtr->padXPtr = NULL;
                clockPtr->padY = 0;
                clockPtr->padYPtr = NULL;
                clockPtr->flags = 0;
                /*
                 * Register a handler for when the window is
                 * exposed or resized.
                 */
                Tk_CreateEventHandler(clockPtr->tkwin,
                        ExposureMask|StructureNotifyMask|FocusChangeMask,
                        ClockEventProc, (ClientData) clockPtr);
                /*
                 * Create a Tcl command that operates on the widget.
                 */
                clockPtr->widgetCmd = Tcl_CreateObjCommand(interp,
                        Tk_PathName(clockPtr->tkwin),
                        ClockInstanceObjCmd,
                        (ClientData) clockPtr, (void (*)()) NULL);
                /*
                 * Parse the command line arguments.
                 */
                if ((Tk_InitOptions(interp, (char *)clockPtr, 
                                optionTable, tkwin) != TCL_OK) ||
                        (ClockObjConfigure(interp, clockPtr,
                                 objc-2, objv+2) != TCL_OK)) {
                        Tk_DestroyWindow(clockPtr->tkwin);
                        return TCL_ERROR;
                }
                Tcl_SetStringObj(Tcl_GetObjResult(interp),
                        Tk_PathName(clockPtr->tkwin), -1);
                return TCL_OK;
        }


        /*
         * Example 49-5
         * The ClockInstanceCmd command procedure.
         */

        static int
        ClockInstanceCmd(clientData, interp, argc, argv)
                ClientData clientData;                                                /* A pointer to a Clock struct */
                Tcl_Interp *interp;                                                /* The interpreter */
                int argc;                                                /* The number of arguments */
                CONST char *argv[];                                                /* The command line arguments */
        {
                Clock *clockPtr = (Clock *)clientData;
                int result = TCL_OK;
                char c;
                int len;
                if (argc < 2) {
                        Tcl_AppendResult(interp, "wrong # args: should be \"",
                                argv[0], " option ?arg arg ...?\"", (char *) NULL);
                        return TCL_ERROR;
                }
                c = argv[1][0];
                len = strlen(argv[1]);
                if ((c == 'c') && (strncmp(argv[1], "cget", len) == 0)
                                && (len >= 2)) {
                        if (argc != 3) {
                                Tcl_AppendResult(interp,
                                         "wrong # args: should be \"",
                                        argv[0], " cget option\"",
                                        (char *) NULL);
                                return TCL_ERROR;
                        }
                        result = Tk_ConfigureValue(interp, clockPtr->tkwin,
                                 configSpecs, (char *) clockPtr, argv[2], 0);
                } else if ((c == 'c') && (strncmp(argv[1], "configure", len) 
                                        == 0) && (len >= 2)) {
                        if (argc == 2) {
                                /*
                                 * Return all configuration information.
                                 */
                                result = Tk_ConfigureInfo(interp, clockPtr->tkwin,
                                        configSpecs, (char *) clockPtr,
                                        (char *) NULL,0);
                        } else if (argc == 3) {
                                /*
                                 * Return info about one attribute, like cget.
                                 */
                                result = Tk_ConfigureInfo(interp, clockPtr->tkwin,
                                        configSpecs, (char *) clockPtr, argv[2], 0);
                        } else {
                                /*
                                 * Change one or more attributes.
                                 */
                                result = ClockConfigure(interp, clockPtr, argc-2,
                                        argv+2,TK_CONFIG_ARGV_ONLY);
                        }
                } else {
                        Tcl_AppendResult(interp, "bad option \"", argv[1],
                                "\": must be cget, configure, position, or size",
                                (char *) NULL);
                        return TCL_ERROR;
                }
                return result;
        }

        /*
         * Example 49-6
         * The ClockInstanceObjCmd command procedure.
         */

        static int
        ClockInstanceObjCmd(clientData, interp, objc, objv)
                ClientData clientData;                                                /* A pointer to a Clock struct */
                Tcl_Interp *interp;                                                /* The interpreter */
                int objc;                                                /* The number of arguments */
                Tcl_Obj *CONST objv[];                                                /* The command line arguments */
        {
                Clock *clockPtr = (Clock *)clientData;
                CONST char *commands[] = {"cget", "configure", NULL};
                enum command {CLOCK_CGET, CLOCK_CONFIGURE};
                int result;
                Tcl_Obj *objPtr;
                int index;

                if (objc < 2) {
                        Tcl_WrongNumArgs(interp, 1, objv, 
                                "option ?arg arg ...?");
                        return TCL_ERROR;
                }
                result = Tcl_GetIndexFromObj(interp, objv[1], commands,
                                "option", 0, &index);
                if (result != TCL_OK) {
                        return result;
                }
                switch (index) {
                        case CLOCK_CGET: {
                                if (objc != 3) {
                                        Tcl_WrongNumArgs(interp, 1, objv, 
                                                "cget option");
                                        return TCL_ERROR;
                                }
                                objPtr = Tk_GetOptionValue(interp, 
                                                (char *)clockPtr,
                                                clockPtr->optionTable,
                                                (objc == 3) ? objv[2] : NULL,
                                                clockPtr->tkwin);
                                if (objPtr == NULL) {
                                        return TCL_ERROR;
                                } else {
                                        Tcl_SetObjResult(interp, objPtr);
                                }
                                break;
                        }
                        case CLOCK_CONFIGURE: {
                                if (objc <= 3) {
                                        /*
                                         * Return one item if the option is given,
                                         * or return all configuration information.
                                         */
                                        objPtr = Tk_GetOptionInfo(interp,
                                                        (char *) clockPtr,
                                                        clockPtr->optionTable,
                                                        (objc == 3) ? objv[2] : NULL,
                                                        clockPtr->tkwin);
                                        if (objPtr == NULL) {
                                                return TCL_ERROR;
                                        } else {
                                                Tcl_SetObjResult(interp, objPtr);
                                        }
                                } else {
                                        /*
                                         * Change one or more attributes.
                                         */
                                        result = ClockObjConfigure(interp, clockPtr, 
                                                objc-2, objv+2);
                                }
                        }
                }
                return TCL_OK;
        }


        /*
         * Example 49-7
         * ClockConfigure allocates resources for the widget.
         */

        static int
        ClockConfigure(interp, clockPtr, argc, argv, flags)
                Tcl_Interp *interp;        /* For return values and errors */
                Clock *clockPtr;                                        /* The per-instance data structure */
                int argc;                                        /* Number of valid entries in argv */
                CONST char *argv[];                                        /* The command line arguments */
                int flags;                                        /* Tk_ConfigureWidget flags */
        {
                XGCValues gcValues;
                GC newGC;

                /*
                 * Tk_ConfigureWidget parses the command line arguments
                 * and looks for defaults in the resource database.
                 */
                if (Tk_ConfigureWidget(interp, clockPtr->tkwin,
                                configSpecs, argc, argv, (char *) clockPtr, flags)
                                        != TCL_OK) {
                        return TCL_ERROR;
                }
                /*
                 * Give the widget a default background so it doesn\" t get
                 * a random background between the time it is initially
                 * displayed by the X server and we paint it
                 */
                Tk_SetWindowBackground(clockPtr->tkwin,
                        Tk_3DBorderColor(clockPtr->background)->pixel);
                /*
                 * Set up the graphics contexts to display the widget.
                 * The context is used to draw off-screen pixmaps,
                 * so turn off exposure notifications.
                 */
                gcValues.background = 
                        Tk_3DBorderColor(clockPtr->background)->pixel;
                gcValues.foreground = clockPtr->foreground->pixel;
                gcValues.font = Tk_FontId(clockPtr->tkfont);
                gcValues.graphics_exposures = False;
                newGC = Tk_GetGC(clockPtr->tkwin,
                        GCBackground|GCForeground|GCFont|GCGraphicsExposures,
                        &gcValues);
                if (clockPtr->textGC != None) {
                        Tk_FreeGC(clockPtr->display, clockPtr->textGC);
                }
                clockPtr->textGC = newGC;
                /*
                 * Determine how big the widget wants to be.
                 */
                ComputeGeometry(clockPtr);
                /*
                 * Set up a call to display ourself.
                 */
                if ((clockPtr->tkwin != NULL) &&
                                  Tk_IsMapped(clockPtr->tkwin)
                                 && !(clockPtr->flags & REDRAW_PENDING)) {
                        Tk_DoWhenIdle(ClockDisplay, (ClientData) clockPtr);
                        clockPtr->flags |= REDRAW_PENDING;
                }
                return TCL_OK;
        }


        /*
         * Example 49-8
         * ClockObjConfigure allocates resources for the widget.
         */

        static int
        ClockObjConfigure(interp, clockPtr, objc, objv)
                Tcl_Interp *interp;        /* For return values and errors */
                Clock *clockPtr;                                        /* The per-instance data structure */
                int objc;                                        /* Number of valid entries in argv */
                Tcl_Obj *CONST objv[];                                        /* The command line arguments */
        {
                XGCValues gcValues;
                GC newGC;
                Tk_SavedOptions savedOptions;
                int mask, error;
                Tcl_Obj *errorResult;

                /*
                 * The first time through this loop we set the 
                 * configuration from the command line inputs. The second
                 * pass is used to restore the configuration in case of
                 * errors
                 */
                for (error = 0 ; error <= 1 ; error++) {
                        if (!error) {
                                /*
                                 * Tk_SetOptions parses the command arguments
                                 * and looks for defaults in the resource
                                 * database.
                                 */
                                if (Tk_SetOptions(interp, (char *) clockPtr,
                                                clockPtr->optionTable, objc, objv,
                                                clockPtr->tkwin, &savedOptions,
                                                &mask) != TCL_OK) {
                                        continue;
                                }
                        } else {
                                /*
                                 * Restore options from saved values
                                 */
                                errorResult = Tcl_GetObjResult(interp);
                                Tcl_IncrRefCount(errorResult);
                                Tk_RestoreSavedOptions(&savedOptions);
                        }

        /* MODIFY || clockPtr->textGC == None''' to force correct graphics context initialisation */
                        if (mask & GRAPHICS_MASK || clockPtr->textGC == None) {
                                /*
                                 * Give the widget a default background so it doesn\" t
                                 * get a random background between the time it is 
                                 * initially displayed by the system and we paint it
                                 */
                                Tk_SetBackgroundFromBorder(clockPtr->tkwin, 
                                                clockPtr->background);
                                /*
                                 * Set up the graphics contexts to display the widget.
                                 * The context is used to draw off-screen pixmaps,
                                 * so turn off exposure notifications.
                                 */
                                gcValues.background = 
                                        Tk_3DBorderColor(clockPtr->background)->pixel;
                                gcValues.foreground = clockPtr->foreground->pixel;
                                gcValues.font = Tk_FontId(clockPtr->tkfont);
                                gcValues.graphics_exposures = False;
                                newGC = Tk_GetGC(clockPtr->tkwin,
                                GCBackground|GCForeground|GCFont|GCGraphicsExposures,
                                        &gcValues);
                                if (clockPtr->textGC != None) {
                                        Tk_FreeGC(clockPtr->display, clockPtr->textGC);
                                }
                                clockPtr->textGC = newGC;
                        }
                        /*
                         * Determine how big the widget wants to be.
                         */
        /* MODIFY  || clockPtr->numChars == 0) to force a geometry query */
                        if (mask & GEOMETRY_MASK || clockPtr->numChars == 0) {
                                ComputeGeometry(clockPtr);
                        }
                        /*
                         * Set up a call to display ourself.
                         */
                        if ((clockPtr->tkwin != NULL) &&
                                          Tk_IsMapped(clockPtr->tkwin)
                                         && !(clockPtr->flags & REDRAW_PENDING)) {
                                Tk_DoWhenIdle(ClockDisplay,
                                        (ClientData) clockPtr);
                                clockPtr->flags |= REDRAW_PENDING;
                        }
                        /*
                         * All OK, break out and avoid error rollback.
                         */
                        break;
                }
                if (!error) {
                        Tk_FreeSavedOptions(&savedOptions);
                        return TCL_OK;
                } else {
                        Tcl_SetObjResult(interp, errorResult);
                        Tcl_DecrRefCount(errorResult);
                        return TCL_ERROR;
                }
        }

        /*
         * Example 49-13
         * ComputeGeometry computes the widget\" s size.
         */

        static void
        ComputeGeometry(Clock *clockPtr)
        {
                int width, height;
                Tk_FontMetrics fm;                                                        /* Font size information */
                struct tm *tmPtr;                                                        /* Time info split into fields */
        /* MODIFY */
                /* struct timeval tv; */                                                        /* BSD-style time value */
                int bd;                                                        /* Padding from borders */
                char clock[1000];                                                        /* Displayed time */

                /*
                 * Get the time and format it to see how big it will be.
                 */
        /* MODIFY */
        #ifdef __WIN32__
                time_t aclock;
                time( &aclock );   /* Get time in seconds */
                tmPtr = localtime( &aclock );   /* Convert time to struct tm form */
        #else
                struct timeval tv;        /* BSD-style time value */
                gettimeofday(&tv, NULL);
                tmPtr = localtime(&tv.tv_sec);
        #endif

                strftime(clock, 1000, clockPtr->format, tmPtr);
                if (clockPtr->clock != NULL) {
                        ckfree(clockPtr->clock);
                }
                clockPtr->clock = ckalloc(1+strlen(clock));
                clockPtr->numChars = strlen(clock);

                bd = clockPtr->highlightWidth + clockPtr->borderWidth;
                Tk_GetFontMetrics(clockPtr->tkfont, &fm);
                height = fm.linespace + 2*(bd + clockPtr->padY);
        /* MODIFY (-1, TK_PARTIAL_OK) to force unbounded linelength */
                Tk_MeasureChars(clockPtr->tkfont, clock,
                        clockPtr->numChars, -1, TK_PARTIAL_OK, &clockPtr->textWidth);
                width = clockPtr->textWidth + 2*(bd + clockPtr->padX);

                Tk_GeometryRequest(clockPtr->tkwin, width, height);
                Tk_SetInternalBorder(clockPtr->tkwin, bd);
        }


        /*
         * Example 49-14
         * The ClockDisplay procedure.
         */

        static void
        ClockDisplay(ClientData clientData)
        {
                Clock *clockPtr = (Clock *)clientData;
                Tk_Window tkwin = clockPtr->tkwin;
                GC gc;                                                         /* Graphics Context for highlight */
                Tk_TextLayout layout;                                                        /* Text measurement state */
                Pixmap pixmap;                                                        /* Temporary drawing area */
                int /* offset,*/ x, y;                                                        /* Coordinates */
                int width, height;                                                        /* Size */
                struct tm *tmPtr;                                                        /* Time info split into fields */

        /* MODIFY */
        #ifdef __WIN32__
                time_t aclock;
        #else
                struct timeval tv;        /* BSD-style time value */
        #endif

                /*
                 * Make sure the clock still exists
                 * and is mapped onto the display before painting.
                 */
                clockPtr->flags &= ~(REDRAW_PENDING|TICKING);
                if ((clockPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
                        return;
                }

                /*
                 * Format the time into a string.
                 * localtime chops up the time into fields.
                 * strftime formats the fields into a string.
                 */
        /* MODIFY */
        #ifdef __WIN32__
                /* time_t aclock; */
                time( &aclock );   /* Get time in seconds */
                tmPtr = localtime( &aclock );   /* Convert time to struct tm form */
        #else
                struct timeval tv;        /* BSD-style time value */
                gettimeofday(&tv, NULL);
                tmPtr = localtime(&tv.tv_sec);
        #endif

                strftime(clockPtr->clock, clockPtr->numChars+1, 
                        clockPtr->format, tmPtr);
                /*
                 * To avoid flicker when the display is updated, the new
                 * image is painted in an offscreen pixmap and then 
                 * copied onto the display in one operation. Allocate the
                 * pixmap and paint its background.
                 */
                pixmap = Tk_GetPixmap(clockPtr->display,
                        Tk_WindowId(tkwin), Tk_Width(tkwin),
                        Tk_Height(tkwin), Tk_Depth(tkwin));
                Tk_Fill3DRectangle(tkwin, pixmap, 
                        clockPtr->background, 0, 0, Tk_Width(tkwin),
                        Tk_Height(tkwin), 0, TK_RELIEF_FLAT);

                /*
                 * Paint the text first.
                 */
                layout = Tk_ComputeTextLayout(clockPtr->tkfont, 
                        clockPtr->clock, clockPtr->numChars, 0,
                        TK_JUSTIFY_CENTER, 0, &width, &height);
                x = (Tk_Width(tkwin) - width)/2;
                y = (Tk_Height(tkwin) - height)/2;
                Tk_DrawTextLayout(clockPtr->display, pixmap,
                        clockPtr->textGC, layout, x, y, 0, -1);

                /*
                 * Display the borders, so they overwrite any of the
                 * text that extends to the edge of the display.
                 */
                if (clockPtr->relief != TK_RELIEF_FLAT) {
                        Tk_Draw3DRectangle(tkwin, pixmap,
                                clockPtr->background,
                                clockPtr->highlightWidth,
                                clockPtr->highlightWidth,
                                Tk_Width(tkwin) - 2*clockPtr->highlightWidth,
                                Tk_Height(tkwin) - 2*clockPtr->highlightWidth,
                                clockPtr->borderWidth, clockPtr->relief);
                }
                if (clockPtr->highlightWidth != 0) {
                        /*
                         * This GC is associated with the color, and Tk caches
                         * the GC until the color is freed. Hence no freeGC.
                         */

                        if (clockPtr->flags & GOT_FOCUS) {
                                gc = Tk_GCForColor(clockPtr->highlight, pixmap);
                        } else {
                                gc = Tk_GCForColor(clockPtr->highlightBg, pixmap);
                        }
                        Tk_DrawFocusHighlight(tkwin, gc, 
                                clockPtr->highlightWidth, pixmap);
                }
                /*
                 * Copy the information from the off-screen pixmap onto
                 * the screen, then delete the pixmap.
                 */
            
                XCopyArea(clockPtr->display, pixmap, Tk_WindowId(tkwin),
                        clockPtr->textGC, 0, 0, Tk_Width(tkwin),
                        Tk_Height(tkwin), 0, 0);
                Tk_FreePixmap(clockPtr->display, pixmap);

                /*
                 * Queue another call to ourselves. The rate at which
                 * this is done could be optimized.
                 */
                clockPtr->token = Tk_CreateTimerHandler(1000, 
                        ClockDisplay, (ClientData)clockPtr);
                clockPtr->flags |= TICKING;
        }


        /*
         * Example 49-15
         * The ClockEventProc handles window events.
         */

        static void
        ClockEventProc(ClientData clientData, XEvent *eventPtr)
        {
                Clock *clockPtr = (Clock *) clientData;
                if ((eventPtr->type == Expose) &&
                        (eventPtr->xexpose.count == 0)) {
                                goto redraw;
                } else if (eventPtr->type == DestroyNotify) {
                        Tcl_DeleteCommandFromToken(clockPtr->interp, 
                                        clockPtr->widgetCmd);
                        /*
                         * Zapping the tkwin lets the other procedures
                         * know we are being destroyed.
                         */
                        clockPtr->tkwin = NULL;

                        if (clockPtr->flags & REDRAW_PENDING) {
                                Tk_CancelIdleCall(ClockDisplay,
                                        (ClientData) clockPtr);
                                clockPtr->flags &= ~REDRAW_PENDING;
                        }
                        if (clockPtr->flags & TICKING) {
                                Tk_DeleteTimerHandler(clockPtr->token);
                                clockPtr->flags &= ~TICKING;
                        }
                        /*
                         * This results in a call to ClockDestroy.
                         */
                        Tk_EventuallyFree((ClientData) clockPtr,
                                ClockDestroy);
                } else if (eventPtr->type == FocusIn) {
                        if (eventPtr->xfocus.detail != NotifyPointer) {
                                clockPtr->flags |= GOT_FOCUS;
                                if (clockPtr->highlightWidth > 0) {
                                        goto redraw;
                                }
                        }
                } else if (eventPtr->type == FocusOut) {
                        if (eventPtr->xfocus.detail != NotifyPointer) {
                                clockPtr->flags &= ~GOT_FOCUS;
                                if (clockPtr->highlightWidth > 0) {
                                        goto redraw;
                                }
                        }
                }
                return;
        redraw:
                if ((clockPtr->tkwin != NULL) &&
                                !(clockPtr->flags & REDRAW_PENDING)) {
                        Tk_DoWhenIdle(ClockDisplay, (ClientData) clockPtr);
                        clockPtr->flags |= REDRAW_PENDING;
                }
        }


        /*
         * Example 49-16
         * The ClockDestroy cleanup procedure.
         */

        static void
        ClockDestroy(clientData)
                ClientData clientData;                /* Info about entry widget. */
        {
                register Clock *clockPtr = (Clock *) clientData;
         
                /*
                 * Free up all the stuff that requires special handling,
                 * then let Tk_FreeOptions handle resources associated
                 * with the widget attributes.
                 */
                if (clockPtr->textGC != None) {
                        Tk_FreeGC(clockPtr->display, clockPtr->textGC);
                }
                if (clockPtr->clock != NULL) {
                        Tcl_Free(clockPtr->clock);
                }
                if (clockPtr->flags & TICKING) {
                        Tk_DeleteTimerHandler(clockPtr->token);
                }
                if (clockPtr->flags & REDRAW_PENDING) {
                        Tk_CancelIdleCall(ClockDisplay,
                                (ClientData) clockPtr);
                }
                /*
                 * This frees up colors and fonts and any allocated
                 * storage associated with the widget attributes.
                 */
                Tk_FreeOptions(configSpecs, (char *) clockPtr,
                        clockPtr->display, 0);
                Tcl_Free((char *) clockPtr);
        }


        /*
         * Example 49-17
         * The ClockObjDelete command.
         */

        void
        ClockObjDelete(ClientData clientData)
        {
                Tk_OptionTable optionTable = (Tk_OptionTable) clientData;
                if (optionTable != NULL) {
                        Tk_DeleteOptionTable(optionTable);
                }
        }

nueq - 2015-11-03 14:33:23

Please give me compiled dll file of this code. Im cant compile it =( I have next errors: error C2065: 'clientData' : undeclared identifier error C2065: 'interp' : undeclared identifier error C2065: 'argc' : undeclared identifier error C2065: 'argv' : undeclared identifier error C2373: 'ClockCmd' : redefinition; different type modifiers