[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 */ /*
*/ #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 */ /*
*/ 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 */ /*
*/ 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; /*
*/ #define REDRAW_PENDING 0x1 #define GOT_FOCUS 0x2 #define TICKING 0x4 /*
*/ 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} }; /*
*/ #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} }; /*
*/ 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); /*
*/ 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); /*
*/ 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; } /*
*/ 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; } /*
*/ Tk_SetClass(tkwin, "Clock"); /*
*/ 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; /*
*/ Tk_CreateEventHandler(clockPtr->tkwin, ExposureMask|StructureNotifyMask|FocusChangeMask, ClockEventProc, (ClientData) clockPtr); /*
*/ clockPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(clockPtr->tkwin), ClockInstanceCmd, (ClientData) clockPtr, (void (*)()) NULL); /*
*/ 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; } /*
*/ 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; /*
*/ 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; } /*
*/ Tk_SetClass(tkwin, "Clock"); /*
*/ 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; /*
*/ Tk_CreateEventHandler(clockPtr->tkwin, ExposureMask|StructureNotifyMask|FocusChangeMask, ClockEventProc, (ClientData) clockPtr); /*
*/ clockPtr->widgetCmd = Tcl_CreateObjCommand(interp, Tk_PathName(clockPtr->tkwin), ClockInstanceObjCmd, (ClientData) clockPtr, (void (*)()) NULL); /*
*/ 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; } /*
*/ 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) { /*
*/ result = Tk_ConfigureInfo(interp, clockPtr->tkwin, configSpecs, (char *) clockPtr, (char *) NULL,0); } else if (argc == 3) { /*
*/ result = Tk_ConfigureInfo(interp, clockPtr->tkwin, configSpecs, (char *) clockPtr, argv[2], 0); } else { /*
*/ 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; } /*
*/ 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) { /*
*/ 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 { /*
*/ result = ClockObjConfigure(interp, clockPtr, objc-2, objv+2); } } } return TCL_OK; } /*
*/ 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; /*
*/ if (Tk_ConfigureWidget(interp, clockPtr->tkwin, configSpecs, argc, argv, (char *) clockPtr, flags) != TCL_OK) { return TCL_ERROR; } /*
*/ Tk_SetWindowBackground(clockPtr->tkwin, Tk_3DBorderColor(clockPtr->background)->pixel); /*
*/ 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; /*
*/ ComputeGeometry(clockPtr); /*
*/ if ((clockPtr->tkwin != NULL) && Tk_IsMapped(clockPtr->tkwin) && !(clockPtr->flags & REDRAW_PENDING)) { Tk_DoWhenIdle(ClockDisplay, (ClientData) clockPtr); clockPtr->flags |= REDRAW_PENDING; } return TCL_OK; } /*
*/ 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; /*
*/ for (error = 0 ; error <= 1 ; error++) { if (!error) { /*
*/ if (Tk_SetOptions(interp, (char *) clockPtr, clockPtr->optionTable, objc, objv, clockPtr->tkwin, &savedOptions, &mask) != TCL_OK) { continue; } } else { /*
*/ 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) { /*
*/ Tk_SetBackgroundFromBorder(clockPtr->tkwin, clockPtr->background); /*
*/ 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; } /*
*/ /* MODIFY || clockPtr->numChars == 0) to force a geometry query */ if (mask & GEOMETRY_MASK || clockPtr->numChars == 0) { ComputeGeometry(clockPtr); } /*
*/ if ((clockPtr->tkwin != NULL) && Tk_IsMapped(clockPtr->tkwin) && !(clockPtr->flags & REDRAW_PENDING)) { Tk_DoWhenIdle(ClockDisplay, (ClientData) clockPtr); clockPtr->flags |= REDRAW_PENDING; } /*
*/ break; } if (!error) { Tk_FreeSavedOptions(&savedOptions); return TCL_OK; } else { Tcl_SetObjResult(interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } /*
*/ 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 */ /*
*/ /* 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); } /*
*/ 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 /*
*/ clockPtr->flags &= ~(REDRAW_PENDING|TICKING); if ((clockPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { return; } /*
*/ /* 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); /*
*/ 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); /*
*/ 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); /*
*/ 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) { /*
*/ 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); } /*
*/ XCopyArea(clockPtr->display, pixmap, Tk_WindowId(tkwin), clockPtr->textGC, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, 0); Tk_FreePixmap(clockPtr->display, pixmap); /*
*/ clockPtr->token = Tk_CreateTimerHandler(1000, ClockDisplay, (ClientData)clockPtr); clockPtr->flags |= TICKING; } /*
*/ 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); /*
*/ 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; } /*
*/ 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; } } /*
*/ static void ClockDestroy(clientData) ClientData clientData; /* Info about entry widget. */ { register Clock *clockPtr = (Clock *) clientData; /*
*/ 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); } /*
*/ Tk_FreeOptions(configSpecs, (char *) clockPtr, clockPtr->display, 0); Tcl_Free((char *) clockPtr); } /*
*/ void ClockObjDelete(ClientData clientData) { Tk_OptionTable optionTable = (Tk_OptionTable) clientData; if (optionTable != NULL) { Tk_DeleteOptionTable(optionTable); } }