From f994ad01956aa98c99d6efd85df83fc59493c6ff Mon Sep 17 00:00:00 2001 From: Kaleb Keithley Date: Fri, 14 Nov 2003 16:48:58 +0000 Subject: XFree86 4.3.0.1 --- Clock.c | 1197 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- Clock.h | 39 ++ ClockP.h | 43 +++ xclock.c | 59 +-- xclock.man | 39 +- 5 files changed, 1219 insertions(+), 158 deletions(-) diff --git a/Clock.c b/Clock.c index 1a01b1b..d312871 100644 --- a/Clock.c +++ b/Clock.c @@ -46,34 +46,23 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ +/* $XFree86: xc/programs/xclock/Clock.c,v 3.24 2002/10/21 13:33:07 alanh Exp $ */ #include #include #include #include "ClockP.h" #include +#include +#include -#if defined(__STDC__) && !defined(AIXV3) /* AIX is broken */ -#define Const const -#else -#define Const /**/ -#endif - -#ifdef X_NOT_STDC_ENV -extern struct tm *localtime(); -#define Time_t long -extern Time_t time (); -#else #include #define Time_t time_t -#endif #ifdef XKB #include #endif -static void clock_tic(), DrawHand(), DrawSecond(), SetSeg(), DrawClockFace(); -static erase_hands(), round(); /* Private Definitions */ @@ -81,6 +70,7 @@ static erase_hands(), round(); #define PI 3.14159265358979 #define TWOPI (2. * PI) +#define MINOR_TICK_FRACT 95 #define SECOND_HAND_FRACT 90 #define MINUTE_HAND_FRACT 70 #define HOUR_HAND_FRACT 40 @@ -107,14 +97,24 @@ static XtResource resources[] = { goffset(height), XtRImmediate, (XtPointer) 0}, {XtNupdate, XtCInterval, XtRInt, sizeof(int), offset(update), XtRImmediate, (XtPointer) 60 }, +#ifndef XRENDER {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), offset(fgpixel), XtRString, XtDefaultForeground}, +#endif {XtNhand, XtCForeground, XtRPixel, sizeof(Pixel), offset(Hdpixel), XtRString, XtDefaultForeground}, {XtNhighlight, XtCForeground, XtRPixel, sizeof(Pixel), offset(Hipixel), XtRString, XtDefaultForeground}, + {XtNutime, XtCBoolean, XtRBoolean, sizeof(Boolean), + offset(utime), XtRImmediate, (XtPointer) FALSE}, {XtNanalog, XtCBoolean, XtRBoolean, sizeof(Boolean), offset(analog), XtRImmediate, (XtPointer) TRUE}, + {XtNtwentyfour, XtCBoolean, XtRBoolean, sizeof(Boolean), + offset(twentyfour), XtRImmediate, (XtPointer) TRUE}, + {XtNbrief, XtCBoolean, XtRBoolean, sizeof(Boolean), + offset(brief), XtRImmediate, (XtPointer) FALSE}, + {XtNstrftime, XtCString, XtRString, sizeof(String), + offset(strftime), XtRString, ""}, {XtNchime, XtCBoolean, XtRBoolean, sizeof(Boolean), offset(chime), XtRImmediate, (XtPointer) FALSE }, {XtNpadding, XtCMargin, XtRInt, sizeof(int), @@ -123,14 +123,55 @@ static XtResource resources[] = { offset(font), XtRString, XtDefaultFont}, {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int), offset (backing_store), XtRString, "default"}, +#ifdef XRENDER + {XtNrender, XtCBoolean, XtRBoolean, sizeof(Boolean), + offset(render), XtRImmediate, (XtPointer) TRUE }, + {XtNbuffer, XtCBoolean, XtRBoolean, sizeof(Boolean), + offset(buffer), XtRImmediate, (XtPointer) TRUE }, + {XtNsharp, XtCBoolean, XtRBoolean, sizeof(Boolean), + offset(sharp), XtRImmediate, (XtPointer) FALSE }, + {XtNforeground, XtCForeground, XtRXftColor, sizeof(XftColor), + offset(fg_color), XtRString, XtDefaultForeground}, + {XtNhourColor, XtCForeground, XtRXftColor, sizeof(XftColor), + offset(hour_color), XtRString, "rgba:7f/00/00/c0"}, + {XtNminuteColor, XtCForeground, XtRXftColor, sizeof(XftColor), + offset(min_color), XtRString, "rgba:00/7f/7f/c0"}, + {XtNsecondColor, XtCForeground, XtRXftColor, sizeof(XftColor), + offset(sec_color), XtRString, "rgba:00/00/ff/80"}, + {XtNmajorColor, XtCForeground, XtRXftColor, sizeof(XftColor), + offset(major_color), XtRString, "rgba:7f/00/00/c0"}, + {XtNminorColor, XtCForeground, XtRXftColor, sizeof(XftColor), + offset(minor_color), XtRString, "rgba:00/7f/7f/c0"}, + {XtNface, XtCFace, XtRXftFont, sizeof (XftFont *), + offset (face), XtRString, ""}, +#endif }; #undef offset #undef goffset -static void ClassInitialize(); -static void Initialize(), Realize(), Destroy(), Resize(), Redisplay(); -static Boolean SetValues(); +static void ClassInitialize ( void ); +static void Initialize ( Widget request, Widget new, ArgList args, + Cardinal *num_args ); +static void Realize ( Widget gw, XtValueMask *valueMask, + XSetWindowAttributes *attrs ); +static void Destroy ( Widget gw ); +static void Resize ( Widget gw ); +static void Redisplay ( Widget gw, XEvent *event, Region region ); +static void clock_tic ( XtPointer client_data, XtIntervalId *id ); +static void erase_hands ( ClockWidget w, struct tm *tm ); +static void ClockAngle ( int tick_units, double *sinp, double *cosp ); +static void DrawLine ( ClockWidget w, Dimension blank_length, + Dimension length, int tick_units ); +static void DrawHand ( ClockWidget w, Dimension length, Dimension width, + int tick_units ); +static void DrawSecond ( ClockWidget w, Dimension length, Dimension width, + Dimension offset, int tick_units ); +static void SetSeg ( ClockWidget w, int x1, int y1, int x2, int y2 ); +static void DrawClockFace ( ClockWidget w ); +static int clock_round ( double x ); +static Boolean SetValues ( Widget gcurrent, Widget grequest, Widget gnew, + ArgList args, Cardinal *num_args ); ClockClassRec clockClassRec = { { /* core fields */ @@ -149,7 +190,7 @@ ClockClassRec clockClassRec = { /* resource_count */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, - /* compress_exposure */ TRUE, + /* compress_exposure */ XtExposeCompressMaximal, /* compress_enterleave */ TRUE, /* visible_interest */ FALSE, /* destroy */ Destroy, @@ -183,17 +224,247 @@ WidgetClass clockWidgetClass = (WidgetClass) &clockClassRec; * ****************************************************************/ -static void ClassInitialize() +#ifdef XRENDER +XtConvertArgRec xftColorConvertArgs[] = { + {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), + sizeof(Screen *)}, + {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap), + sizeof(Colormap)} +}; + +#define donestr(type, value, tstr) \ + { \ + if (toVal->addr != NULL) { \ + if (toVal->size < sizeof(type)) { \ + toVal->size = sizeof(type); \ + XtDisplayStringConversionWarning(dpy, \ + (char*) fromVal->addr, tstr); \ + return False; \ + } \ + *(type*)(toVal->addr) = (value); \ + } \ + else { \ + static type static_val; \ + static_val = (value); \ + toVal->addr = (XPointer)&static_val; \ + } \ + toVal->size = sizeof(type); \ + return True; \ + } + +static void +XmuFreeXftColor (XtAppContext app, XrmValuePtr toVal, XtPointer closure, + XrmValuePtr args, Cardinal *num_args) +{ + Screen *screen; + Colormap colormap; + XftColor *color; + + if (*num_args != 2) + { + XtAppErrorMsg (app, + "freeXftColor", "wrongParameters", + "XtToolkitError", + "Freeing an XftColor requires screen and colormap arguments", + (String *) NULL, (Cardinal *)NULL); + return; + } + + screen = *((Screen **) args[0].addr); + colormap = *((Colormap *) args[1].addr); + color = (XftColor *) toVal->addr; + XftColorFree (DisplayOfScreen (screen), + DefaultVisual (DisplayOfScreen (screen), + XScreenNumberOfScreen (screen)), + colormap, color); +} + +static Boolean +XmuCvtStringToXftColor(Display *dpy, + XrmValue *args, Cardinal *num_args, + XrmValue *fromVal, XrmValue *toVal, + XtPointer *converter_data) +{ + char *spec; + XRenderColor renderColor; + XftColor xftColor; + Screen *screen; + Colormap colormap; + + if (*num_args != 2) + { + XtAppErrorMsg (XtDisplayToApplicationContext (dpy), + "cvtStringToXftColor", "wrongParameters", + "XtToolkitError", + "String to render color conversion needs screen and colormap arguments", + (String *) NULL, (Cardinal *)NULL); + return False; + } + + screen = *((Screen **) args[0].addr); + colormap = *((Colormap *) args[1].addr); + + spec = (char *) fromVal->addr; + if (strcasecmp (spec, XtDefaultForeground) == 0) + { + renderColor.red = 0; + renderColor.green = 0; + renderColor.blue = 0; + renderColor.alpha = 0xffff; + } + else if (strcasecmp (spec, XtDefaultBackground) == 0) + { + renderColor.red = 0xffff; + renderColor.green = 0xffff; + renderColor.blue = 0xffff; + renderColor.alpha = 0xffff; + } + else if (!XRenderParseColor (dpy, spec, &renderColor)) + return False; + if (!XftColorAllocValue (dpy, + DefaultVisual (dpy, + XScreenNumberOfScreen (screen)), + colormap, + &renderColor, + &xftColor)) + return False; + + donestr (XftColor, xftColor, XtRXftColor); +} + +static void +XmuFreeXftFont (XtAppContext app, XrmValuePtr toVal, XtPointer closure, + XrmValuePtr args, Cardinal *num_args) +{ + Screen *screen; + XftFont *font; + + if (*num_args != 1) + { + XtAppErrorMsg (app, + "freeXftFont", "wrongParameters", + "XtToolkitError", + "Freeing an XftFont requires screen argument", + (String *) NULL, (Cardinal *)NULL); + return; + } + + screen = *((Screen **) args[0].addr); + font = *((XftFont **) toVal->addr); + if (font) + XftFontClose (DisplayOfScreen (screen), font); +} + +static Boolean +XmuCvtStringToXftFont(Display *dpy, + XrmValue *args, Cardinal *num_args, + XrmValue *fromVal, XrmValue *toVal, + XtPointer *converter_data) +{ + char *name; + XftFont *font; + Screen *screen; + + if (*num_args != 1) + { + XtAppErrorMsg (XtDisplayToApplicationContext (dpy), + "cvtStringToXftFont", "wrongParameters", + "XtToolkitError", + "String to XftFont conversion needs screen argument", + (String *) NULL, (Cardinal *)NULL); + return False; + } + + screen = *((Screen **) args[0].addr); + name = (char *) fromVal->addr; + + font = XftFontOpenName (dpy, + XScreenNumberOfScreen (screen), + name); + if (font) + { + donestr (XftFont *, font, XtRXftFont); + } + XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRXftFont); + return False; +} + +XtConvertArgRec xftFontConvertArgs[] = { + {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), + sizeof(Screen *)}, +}; + +#endif + +static void +ClassInitialize(void) { XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore, NULL, 0 ); +#ifdef XRENDER + XtSetTypeConverter (XtRString, XtRXftColor, + XmuCvtStringToXftColor, + xftColorConvertArgs, XtNumber(xftColorConvertArgs), + XtCacheByDisplay, XmuFreeXftColor); + XtSetTypeConverter (XtRString, XtRXftFont, + XmuCvtStringToXftFont, + xftFontConvertArgs, XtNumber(xftFontConvertArgs), + XtCacheByDisplay, XmuFreeXftFont); +#endif +} + +static char * +TimeString (ClockWidget w, struct tm *tm) +{ + if (w->clock.brief) + { + if (w->clock.twentyfour) + { + static char brief[6]; + sprintf (brief, "%02d:%02d", tm->tm_hour, tm->tm_min); + return brief; + } + else + { + static char brief[9]; + int hour = tm->tm_hour % 12; + if (!hour) hour = 12; + sprintf (brief, "%02d:%02d %cM", hour, tm->tm_min, + tm->tm_hour >= 12 ? 'P' : 'A'); + return brief; + } + } + else if (w->clock.utime) + { + static char utime[35]; + Time_t tsec; + tsec = time(NULL); + sprintf (utime, "%10lu seconds since Epoch", (unsigned long)tsec); + return utime; + } else if (*w->clock.strftime) { + /*Note: this code is probably excessively paranoid + about buffer overflow. The extra size 10 padding + is also meant as a further guard against programmer + error, although it is a little controversial*/ + static char ctime[STRFTIME_BUFF_SIZE+10]; + ctime[0] = ctime[STRFTIME_BUFF_SIZE] = '\0'; + strftime (ctime, STRFTIME_BUFF_SIZE-1,w->clock.strftime, tm); + ctime[STRFTIME_BUFF_SIZE-1] = '\0'; + return ctime; + } + else if (w->clock.twentyfour) + return asctime (tm); + else + { + static char long12[28]; + strftime(long12, sizeof long12, "%a %b %d %I:%M:%S %p %Y", tm); + return long12; + } } /* ARGSUSED */ -static void Initialize (request, new, args, num_args) - Widget request, new; - ArgList args; - Cardinal *num_args; +static void +Initialize (Widget request, Widget new, ArgList args, Cardinal *num_args) { ClockWidget w = (ClockWidget)new; XtGCMask valuemask; @@ -214,22 +485,36 @@ static void Initialize (request, new, args, num_args) (void) time(&time_value); tm = *localtime(&time_value); - str = asctime(&tm); + str = TimeString (w, &tm); if (w->clock.font == NULL) w->clock.font = XQueryFont( XtDisplay(w), XGContextFromGC( DefaultGCOfScreen(XtScreen(w))) ); +#ifdef XRENDER + if (w->clock.render) + { + XGlyphInfo extents; + XftTextExtents8 (XtDisplay (w), w->clock.face, + (FcChar8 *) str, strlen (str), &extents); + min_width = extents.xOff + 2 * w->clock.padding; + min_height = w->clock.face->ascent + w->clock.face->descent + + 2 * w->clock.padding; + } + else +#endif + { min_width = XTextWidth(w->clock.font, str, strlen(str)) + 2 * w->clock.padding; min_height = w->clock.font->ascent + w->clock.font->descent + 2 * w->clock.padding; + } } if (w->core.width == 0) w->core.width = min_width; if (w->core.height == 0) w->core.height = min_height; - myXGCV.foreground = w->clock.fgpixel; + myXGCV.foreground = ClockFgPixel (w); myXGCV.background = w->core.background_pixel; if (w->clock.font != NULL) myXGCV.font = w->clock.font->fid; @@ -238,8 +523,9 @@ static void Initialize (request, new, args, num_args) myXGCV.line_width = 0; w->clock.myGC = XtGetGC((Widget)w, valuemask, &myXGCV); - valuemask = GCForeground | GCLineWidth ; + valuemask = GCForeground | GCLineWidth | GCGraphicsExposures; myXGCV.foreground = w->core.background_pixel; + myXGCV.graphics_exposures = False; w->clock.EraseGC = XtGetGC((Widget)w, valuemask, &myXGCV); myXGCV.foreground = w->clock.Hipixel; @@ -254,12 +540,396 @@ static void Initialize (request, new, args, num_args) w->clock.show_second_hand = (w->clock.update <= SECOND_HAND_TIME); w->clock.numseg = 0; w->clock.interval_id = 0; + memset (&w->clock.otm, '\0', sizeof (w->clock.otm)); +#ifdef XRENDER + { + int major, minor; + + if (XRenderQueryVersion (XtDisplay (w), &major, &minor) && + (major > 0 || + (major == 0 && minor >= 4))) + { + w->clock.can_polygon = True; + } + else + w->clock.can_polygon = False; + } + w->clock.pixmap = 0; + w->clock.draw = 0; + w->clock.damage.x = 0; + w->clock.damage.y = 0; + w->clock.damage.height = 0; + w->clock.damage.width = 0; +#endif +} + +#if XRENDER +static void +RenderPrepare (ClockWidget w, XftColor *color) +{ + if (!w->clock.draw) + { + Drawable d = XtWindow (w); + if (w->clock.buffer) + { + if (!w->clock.pixmap) + { + Arg arg[1]; + w->clock.pixmap = XCreatePixmap (XtDisplay (w), d, + w->core.width, + w->core.height, + w->core.depth); + arg[0].name = XtNbackgroundPixmap; + arg[0].value = 0; + XtSetValues ((Widget) w, arg, 1); + } + d = w->clock.pixmap; + } + + w->clock.draw = XftDrawCreate (XtDisplay (w), d, + DefaultVisual (XtDisplay (w), + DefaultScreen(XtDisplay (w))), + w->core.colormap); + w->clock.picture = XftDrawPicture (w->clock.draw); + } + if (color) + w->clock.fill_picture = XftDrawSrcPicture (w->clock.draw, color); +} + +static void +RenderClip (ClockWidget w) +{ + Region r; + Drawable d; + + RenderPrepare (w, 0); + if (w->clock.buffer) + d = w->clock.pixmap; + else + d = XtWindow (w); + XFillRectangle (XtDisplay (w), d, w->clock.EraseGC, + w->clock.damage.x, + w->clock.damage.y, + w->clock.damage.width, + w->clock.damage.height); + r = XCreateRegion (); + XUnionRectWithRegion (&w->clock.damage, + r, r); + XftDrawSetClip (w->clock.draw, r); + XDestroyRegion (r); +} + +static void +RenderTextBounds (ClockWidget w, char *str, int off, int len, + XRectangle *bounds, int *xp, int *yp) +{ + XGlyphInfo head, tail; + int x, y; + + XftTextExtents8 (XtDisplay (w), w->clock.face, (FcChar8 *) str, + off, &head); + XftTextExtents8 (XtDisplay (w), w->clock.face, (FcChar8 *) str + off, + len - off, &tail); + /* + * Compute position of tail + */ + x = w->clock.padding + head.xOff; + y = w->clock.face->ascent + w->clock.padding + head.yOff; + /* + * Compute bounds of tail, pad a bit as the bounds aren't exact + */ + bounds->x = x - tail.x - 1; + bounds->y = y - tail.y - 1; + bounds->width = tail.width + 2; + bounds->height = tail.height + 2; + if (xp) *xp = x; + if (yp) *yp = y; +} + +static void +RenderUpdateRectBounds (XRectangle *damage, XRectangle *bounds) +{ + int x1 = bounds->x; + int y1 = bounds->y; + int x2 = bounds->x + bounds->width; + int y2 = bounds->y + bounds->height; + int d_x1 = damage->x; + int d_y1 = damage->y; + int d_x2 = damage->x + damage->width; + int d_y2 = damage->y + damage->height; + + if (x1 == x2) + { + x1 = d_x1; + x2 = d_x2; + } + else + { + if (d_x1 < x1) x1 = d_x1; + if (d_x2 > x2) x2 = d_x2; + } + if (y1 == y2) + { + y1 = d_y1; + y2 = d_y2; + } + else + { + if (d_y1 < y1) y1 = d_y1; + if (d_y2 > y2) y2 = d_y2; + } + + bounds->x = x1; + bounds->y = y1; + bounds->width = x2 - x1; + bounds->height = y2 - y1; +} + +static Boolean +RenderRectIn (XRectangle *rect, XRectangle *bounds) +{ + int x1 = bounds->x; + int y1 = bounds->y; + int x2 = bounds->x + bounds->width; + int y2 = bounds->y + bounds->height; + int r_x1 = rect->x; + int r_y1 = rect->y; + int r_x2 = rect->x + rect->width; + int r_y2 = rect->y + rect->height; + + return r_x1 < x2 && x1 < r_x2 && r_y1 < y2 && y1 < r_y2; +} + +#define LINE_WIDTH 0.01 +#include + +#define XCoord(x,w) ((x) * (w)->clock.x_scale + (w)->clock.x_off) +#define YCoord(y,w) ((y) * (w)->clock.y_scale + (w)->clock.y_off) + +static void +RenderUpdateBounds (XPointDouble *points, int npoints, XRectangle *bounds) +{ + int x1 = bounds->x; + int y1 = bounds->y; + int x2 = bounds->x + bounds->width; + int y2 = bounds->y + bounds->height; + + while (npoints--) + { + int r_x1 = points[0].x; + int r_y1 = points[0].y; + int r_x2 = points[0].x + 1; + int r_y2 = points[0].y + 1; + + if (x1 == x2) + x2 = x1 = r_x1; + if (y1 == y2) + y2 = y1 = r_y1; + if (r_x1 < x1) x1 = r_x1; + if (r_y1 < y1) y1 = r_y1; + if (r_x2 > x2) x2 = r_x2; + if (r_y2 > y2) y2 = r_y2; + points++; + } + bounds->x = x1; + bounds->y = y1; + bounds->width = x2 - x1; + bounds->height = y2 - y1; +} + +static Boolean +RenderCheckBounds (XPointDouble *points, int npoints, XRectangle *bounds) +{ + int x1 = bounds->x; + int y1 = bounds->y; + int x2 = bounds->x + bounds->width; + int y2 = bounds->y + bounds->height; + + while (npoints--) + { + if (x1 <= points->x && points->x <= x2 && + y1 <= points->y && points->y <= y2) + return True; + points++; + } + return False; +} + +static void +RenderUpdate (ClockWidget w) +{ + if (w->clock.buffer && w->clock.pixmap) + { + XCopyArea (XtDisplay (w), w->clock.pixmap, + XtWindow (w), w->clock.EraseGC, + w->clock.damage.x, w->clock.damage.y, + w->clock.damage.width, w->clock.damage.height, + w->clock.damage.x, w->clock.damage.y); + } +} + +static void +RenderResetBounds (XRectangle *bounds) +{ + bounds->x = 0; + bounds->y = 0; + bounds->width = 0; + bounds->height = 0; +} + +static void +RenderLine (ClockWidget w, XDouble x1, XDouble y1, XDouble x2, XDouble y2, + XftColor *color, + Boolean draw) +{ + XPointDouble poly[4]; + XDouble dx = (x2 - x1); + XDouble dy = (y2 - y1); + XDouble len = sqrt (dx*dx + dy*dy); + XDouble ldx = (LINE_WIDTH/2.0) * dy / len; + XDouble ldy = (LINE_WIDTH/2.0) * dx / len; + + poly[0].x = XCoord (x1 + ldx, w); + poly[0].y = YCoord (y1 - ldy, w); + + poly[1].x = XCoord (x2 + ldx, w); + poly[1].y = YCoord (y2 - ldy, w); + + poly[2].x = XCoord (x2 - ldx, w); + poly[2].y = YCoord (y2 + ldy, w); + + poly[3].x = XCoord (x1 - ldx, w); + poly[3].y = YCoord (y1 + ldy, w); + + RenderUpdateBounds (poly, 4, &w->clock.damage); + if (draw) + { + if (RenderCheckBounds (poly, 4, &w->clock.damage)) + { + RenderPrepare (w, color); + XRenderCompositeDoublePoly (XtDisplay (w), + PictOpOver, + w->clock.fill_picture, + w->clock.picture, + w->clock.mask_format, + 0, 0, 0, 0, poly, 4, EvenOddRule); + } + } + else + RenderUpdateBounds (poly, 4, &w->clock.damage); +} + +static void +RenderRotate (ClockWidget w, XPointDouble *out, double x, double y, double s, double c) +{ + out->x = XCoord (x * c - y * s, w); + out->y = YCoord (y * c + x * s, w); +} + +static void +RenderHand (ClockWidget w, int tick_units, int size, XftColor *color, + Boolean draw) +{ + double c, s; + XPointDouble poly[3]; + double outer_x; + double inner_y; + + ClockAngle (tick_units, &c, &s); + s = -s; + + /* compute raw positions */ + outer_x = size / 100.0; + inner_y = HAND_WIDTH_FRACT / 100.0; + + /* rotate them into position */ + RenderRotate (w, &poly[0], outer_x, 0.0, s, c); + RenderRotate (w, &poly[1], -inner_y, inner_y, s, c); + RenderRotate (w, &poly[2], -inner_y, -inner_y, s, c); + + if (draw) + { + if (RenderCheckBounds (poly, 3, &w->clock.damage)) + { + RenderPrepare (w, color); + XRenderCompositeDoublePoly (XtDisplay (w), + PictOpOver, + w->clock.fill_picture, + w->clock.picture, + w->clock.mask_format, + 0, 0, 0, 0, poly, 3, EvenOddRule); + } + } + RenderUpdateBounds (poly, 3, &w->clock.damage); +} + +static void +RenderHands (ClockWidget w, struct tm *tm, Boolean draw) +{ + RenderHand (w, tm->tm_hour * 300 + tm->tm_min*5, HOUR_HAND_FRACT, &w->clock.hour_color, draw); + RenderHand (w, tm->tm_min * 60 + tm->tm_sec, MINUTE_HAND_FRACT, &w->clock.min_color, draw); +} + +static void +RenderSec (ClockWidget w, struct tm *tm, Boolean draw) +{ + double c, s; + XPointDouble poly[10]; + double inner_x, middle_x, outer_x, far_x; + double middle_y; + double line_y; + + ClockAngle (tm->tm_sec * 60, &c, &s); + + s = -s; + + /* + * Compute raw positions + */ + line_y = LINE_WIDTH; + inner_x = (MINUTE_HAND_FRACT / 100.0); + middle_x = ((SECOND_HAND_FRACT + MINUTE_HAND_FRACT) / 200.0); + outer_x = (SECOND_HAND_FRACT / 100.0); + far_x = (MINOR_TICK_FRACT / 100.0); + middle_y = (SECOND_WIDTH_FRACT / 100.0); + + /* + * Rotate them into position + */ + RenderRotate (w, &poly[0], -line_y, line_y, s, c); + RenderRotate (w, &poly[1], inner_x, line_y, s, c); + RenderRotate (w, &poly[2], middle_x, middle_y, s, c); + RenderRotate (w, &poly[3], outer_x, line_y, s, c); + RenderRotate (w, &poly[4], far_x, line_y, s, c); + RenderRotate (w, &poly[5], far_x, -line_y, s, c); + RenderRotate (w, &poly[6], outer_x, -line_y, s, c); + RenderRotate (w, &poly[7], middle_x, -middle_y, s, c); + RenderRotate (w, &poly[8], inner_x, -line_y, s, c); + RenderRotate (w, &poly[9], -line_y, -line_y, s, c); + + if (draw) + { + if (RenderCheckBounds (poly, 10, &w->clock.damage)) + { + RenderPrepare (w, &w->clock.sec_color); + XRenderCompositeDoublePoly (XtDisplay (w), + PictOpOver, + w->clock.fill_picture, + w->clock.picture, + w->clock.mask_format, + 0, 0, 0, 0, poly, 10, EvenOddRule); + } + } + else + { + RenderUpdateBounds (poly, 10, &w->clock.damage); + } } -static void Realize (gw, valueMask, attrs) - Widget gw; - XtValueMask *valueMask; - XSetWindowAttributes *attrs; +#endif + +static void +Realize(Widget gw, XtValueMask *valueMask, XSetWindowAttributes *attrs) { ClockWidget w = (ClockWidget) gw; #ifdef notdef @@ -279,19 +949,25 @@ static void Realize (gw, valueMask, attrs) Resize(gw); } -static void Destroy (gw) - Widget gw; +static void +Destroy(Widget gw) { ClockWidget w = (ClockWidget) gw; if (w->clock.interval_id) XtRemoveTimeOut (w->clock.interval_id); +#ifdef RENDER + if (w->clock.picture) + XRenderFreePicture (dpy, w->clock.picture); + if (w->clock.fill_picture) + XRenderFreePicture (dpy, w->clock.fill_picture); +#endif XtReleaseGC (gw, w->clock.myGC); XtReleaseGC (gw, w->clock.HighGC); XtReleaseGC (gw, w->clock.HandGC); XtReleaseGC (gw, w->clock.EraseGC); } -static void Resize (gw) - Widget gw; +static void +Resize(Widget gw) { ClockWidget w = (ClockWidget) gw; /* don't do this computation if window hasn't been realized yet. */ @@ -309,42 +985,69 @@ static void Resize (gw) w->clock.centerX = w->core.width / 2; w->clock.centerY = w->core.height / 2; } +#ifdef XRENDER + w->clock.x_scale = 0.45 * w->core.width; + w->clock.y_scale = 0.45 * w->core.height; + w->clock.x_off = 0.5 * w->core.width; + w->clock.y_off = 0.5 * w->core.height; + if (w->clock.pixmap) + { + XFreePixmap (XtDisplay (w), w->clock.pixmap); + w->clock.pixmap = 0; + if (w->clock.draw) + { + XftDrawDestroy (w->clock.draw); + w->clock.draw = 0; + } + w->clock.picture = 0; + } +#endif } /* ARGSUSED */ -static void Redisplay (gw, event, region) - Widget gw; - XEvent *event; /* unused */ - Region region; /* unused */ +static void +Redisplay(Widget gw, XEvent *event, Region region) { ClockWidget w = (ClockWidget) gw; if (w->clock.analog) { - if (w->clock.numseg != 0) - erase_hands (w, (struct tm *) 0); - DrawClockFace(w); +#ifdef XRENDER + if (w->clock.render && w->clock.can_polygon) + XClipBox (region, &w->clock.damage); + else +#endif + { + if (w->clock.numseg != 0) + erase_hands (w, (struct tm *) 0); + DrawClockFace(w); + } } else { +#ifdef XRENDER + if (w->clock.render) + XClipBox (region, &w->clock.damage); +#endif w->clock.prev_time_string[0] = '\0'; } clock_tic((XtPointer)w, (XtIntervalId)0); } /* ARGSUSED */ -static void clock_tic(client_data, id) - XtPointer client_data; - XtIntervalId *id; +static void +clock_tic(XtPointer client_data, XtIntervalId *id) { ClockWidget w = (ClockWidget)client_data; struct tm tm; Time_t time_value; + struct timeval tv; char *time_ptr; register Display *dpy = XtDisplay(w); register Window win = XtWindow(w); + X_GETTIMEOFDAY (&tv); if (id || !w->clock.interval_id) w->clock.interval_id = XtAppAddTimeOut( XtWidgetToApplicationContext( (Widget) w), - w->clock.update*1000, clock_tic, (XtPointer)w ); - (void) time(&time_value); + (w->clock.update - 1) * 1000 + (1000000 - tv.tv_usec)/1000, clock_tic, (XtPointer)w ); + time_value = tv.tv_sec; tm = *localtime(&time_value); /* * Beep on the half hour; double-beep on the hour. @@ -375,18 +1078,51 @@ static void clock_tic(client_data, id) int clear_from; int i, len, prev_len; - time_ptr = asctime(&tm); + time_ptr = TimeString (w, &tm); len = strlen (time_ptr); if (time_ptr[len - 1] == '\n') time_ptr[--len] = '\0'; prev_len = strlen (w->clock.prev_time_string); for (i = 0; ((i < len) && (i < prev_len) && (w->clock.prev_time_string[i] == time_ptr[i])); i++); - strcpy (w->clock.prev_time_string+i, time_ptr+i); +#ifdef XRENDER + if (w->clock.render) + { + XRectangle old_tail, new_tail, head; + int x, y; + + RenderTextBounds (w, w->clock.prev_time_string, i, prev_len, + &old_tail, 0, 0); + RenderUpdateRectBounds (&old_tail, &w->clock.damage); + RenderTextBounds (w, time_ptr, i, len, + &new_tail, 0, 0); + RenderUpdateRectBounds (&new_tail, &w->clock.damage); + + while (i) + { + RenderTextBounds (w, time_ptr, 0, i, &head, 0, 0); + if (!RenderRectIn (&head, &w->clock.damage)) + break; + i--; + } + RenderTextBounds (w, time_ptr, i, len, &new_tail, &x, &y); + RenderClip (w); + RenderPrepare (w, 0); + XftDrawString8 (w->clock.draw, + &w->clock.fg_color, + w->clock.face, + x, y, + (FcChar8 *) time_ptr + i, len - i); + RenderUpdate (w); + RenderResetBounds (&w->clock.damage); + } + else +#endif + { XDrawImageString (dpy, win, w->clock.myGC, - (2+w->clock.padding + + (1+w->clock.padding + XTextWidth (w->clock.font, time_ptr, i)), - 2+w->clock.font->ascent+w->clock.padding, + w->clock.font->ascent+w->clock.padding, time_ptr + i, len - i); /* * Clear any left over bits @@ -396,6 +1132,8 @@ static void clock_tic(client_data, id) if (clear_from < (int)w->core.width) XFillRectangle (dpy, win, w->clock.EraseGC, clear_from, 0, w->core.width - clear_from, w->core.height); + } + strcpy (w->clock.prev_time_string+i, time_ptr+i); } else { /* * The second (or minute) hand is sec (or min) @@ -411,6 +1149,45 @@ static void clock_tic(client_data, id) if(tm.tm_hour >= 12) tm.tm_hour -= 12; +#ifdef XRENDER + if (w->clock.render && w->clock.can_polygon) + { + w->clock.mask_format = XRenderFindStandardFormat (XtDisplay (w), + w->clock.sharp ? + PictStandardA1 : + PictStandardA8); + /* + * Compute repaint area + */ + if (tm.tm_min != w->clock.otm.tm_min || + tm.tm_hour != w->clock.otm.tm_hour || + tm.tm_sec != w->clock.otm.tm_sec) + { + RenderHands (w, &w->clock.otm, False); + RenderHands (w, &tm, False); + } + if (w->clock.show_second_hand && + tm.tm_sec != w->clock.otm.tm_sec) + { + RenderSec (w, &w->clock.otm, False); + RenderSec (w, &tm, False); + } + if (w->clock.damage.width && + w->clock.damage.height) + { + RenderClip (w); + DrawClockFace (w); + RenderHands (w, &tm, True); + if (w->clock.show_second_hand == TRUE) + RenderSec (w, &tm, True); + } + w->clock.otm = tm; + RenderUpdate (w); + RenderResetBounds (&w->clock.damage); + return; + } +#endif + erase_hands (w, &tm); if (w->clock.numseg == 0 || @@ -426,7 +1203,7 @@ static void clock_tic(client_data, id) */ DrawHand(w, w->clock.minute_hand_length, w->clock.hand_width, - tm.tm_min * 12 + tm.tm_min * 60 ); if(w->clock.Hdpixel != w->core.background_pixel) XFillPolygon( dpy, @@ -441,7 +1218,7 @@ static void clock_tic(client_data, id) w->clock.hour = w->clock.segbuffptr; DrawHand(w, w->clock.hour_hand_length, w->clock.hand_width, - tm.tm_hour * 60 + tm.tm_min + tm.tm_hour * 300 + tm.tm_min * 5 ); if(w->clock.Hdpixel != w->core.background_pixel) { XFillPolygon(dpy, @@ -464,7 +1241,7 @@ static void clock_tic(client_data, id) w->clock.second_hand_length - 2, w->clock.second_hand_width, w->clock.minute_hand_length + 2, - tm.tm_sec * 12 + tm.tm_sec * 60 ); if(w->clock.Hdpixel != w->core.background_pixel) XFillPolygon( dpy, @@ -485,9 +1262,8 @@ static void clock_tic(client_data, id) } } -static erase_hands (w, tm) -ClockWidget w; -struct tm *tm; +static void +erase_hands(ClockWidget w, struct tm *tm) { /* * Erase old hands. @@ -541,46 +1317,134 @@ struct tm *tm; } } -static float Const Sines[] = { -.000000, .008727, .017452, .026177, .034899, .043619, .052336, .061049, -.069756, .078459, .087156, .095846, .104528, .113203, .121869, .130526, -.139173, .147809, .156434, .165048, .173648, .182236, .190809, .199368, -.207912, .216440, .224951, .233445, .241922, .250380, .258819, .267238, -.275637, .284015, .292372, .300706, .309017, .317305, .325568, .333807, -.342020, .350207, .358368, .366501, .374607, .382683, .390731, .398749, -.406737, .414693, .422618, .430511, .438371, .446198, .453990, .461749, -.469472, .477159, .484810, .492424, .500000, .507538, .515038, .522499, -.529919, .537300, .544639, .551937, .559193, .566406, .573576, .580703, -.587785, .594823, .601815, .608761, .615661, .622515, .629320, .636078, -.642788, .649448, .656059, .662620, .669131, .675590, .681998, .688355, -.694658, .700909, .707107 +static float const Sines[] = { +0.000000, 0.001745, 0.003490, 0.005235, 0.006981, 0.008726, 0.010471, 0.012217, +0.013962, 0.015707, 0.017452, 0.019197, 0.020942, 0.022687, 0.024432, 0.026176, +0.027921, 0.029666, 0.031410, 0.033155, 0.034899, 0.036643, 0.038387, 0.040131, +0.041875, 0.043619, 0.045362, 0.047106, 0.048849, 0.050592, 0.052335, 0.054078, +0.055821, 0.057564, 0.059306, 0.061048, 0.062790, 0.064532, 0.066273, 0.068015, +0.069756, 0.071497, 0.073238, 0.074978, 0.076719, 0.078459, 0.080198, 0.081938, +0.083677, 0.085416, 0.087155, 0.088894, 0.090632, 0.092370, 0.094108, 0.095845, +0.097582, 0.099319, 0.101056, 0.102792, 0.104528, 0.106264, 0.107999, 0.109734, +0.111468, 0.113203, 0.114937, 0.116670, 0.118403, 0.120136, 0.121869, 0.123601, +0.125333, 0.127064, 0.128795, 0.130526, 0.132256, 0.133986, 0.135715, 0.137444, +0.139173, 0.140901, 0.142628, 0.144356, 0.146083, 0.147809, 0.149535, 0.151260, +0.152985, 0.154710, 0.156434, 0.158158, 0.159881, 0.161603, 0.163325, 0.165047, +0.166768, 0.168489, 0.170209, 0.171929, 0.173648, 0.175366, 0.177084, 0.178802, +0.180519, 0.182235, 0.183951, 0.185666, 0.187381, 0.189095, 0.190808, 0.192521, +0.194234, 0.195946, 0.197657, 0.199367, 0.201077, 0.202787, 0.204496, 0.206204, +0.207911, 0.209618, 0.211324, 0.213030, 0.214735, 0.216439, 0.218143, 0.219846, +0.221548, 0.223250, 0.224951, 0.226651, 0.228350, 0.230049, 0.231747, 0.233445, +0.235142, 0.236838, 0.238533, 0.240228, 0.241921, 0.243615, 0.245307, 0.246999, +0.248689, 0.250380, 0.252069, 0.253757, 0.255445, 0.257132, 0.258819, 0.260504, +0.262189, 0.263873, 0.265556, 0.267238, 0.268919, 0.270600, 0.272280, 0.273959, +0.275637, 0.277314, 0.278991, 0.280666, 0.282341, 0.284015, 0.285688, 0.287360, +0.289031, 0.290702, 0.292371, 0.294040, 0.295708, 0.297374, 0.299040, 0.300705, +0.302369, 0.304033, 0.305695, 0.307356, 0.309016, 0.310676, 0.312334, 0.313992, +0.315649, 0.317304, 0.318959, 0.320612, 0.322265, 0.323917, 0.325568, 0.327217, +0.328866, 0.330514, 0.332161, 0.333806, 0.335451, 0.337095, 0.338737, 0.340379, +0.342020, 0.343659, 0.345298, 0.346935, 0.348572, 0.350207, 0.351841, 0.353474, +0.355106, 0.356737, 0.358367, 0.359996, 0.361624, 0.363251, 0.364876, 0.366501, +0.368124, 0.369746, 0.371367, 0.372987, 0.374606, 0.376224, 0.377840, 0.379456, +0.381070, 0.382683, 0.384295, 0.385906, 0.387515, 0.389123, 0.390731, 0.392337, +0.393941, 0.395545, 0.397147, 0.398749, 0.400349, 0.401947, 0.403545, 0.405141, +0.406736, 0.408330, 0.409923, 0.411514, 0.413104, 0.414693, 0.416280, 0.417867, +0.419452, 0.421035, 0.422618, 0.424199, 0.425779, 0.427357, 0.428935, 0.430511, +0.432085, 0.433659, 0.435231, 0.436801, 0.438371, 0.439939, 0.441505, 0.443071, +0.444635, 0.446197, 0.447759, 0.449318, 0.450877, 0.452434, 0.453990, 0.455544, +0.457097, 0.458649, 0.460199, 0.461748, 0.463296, 0.464842, 0.466386, 0.467929, +0.469471, 0.471011, 0.472550, 0.474088, 0.475624, 0.477158, 0.478691, 0.480223, +0.481753, 0.483282, 0.484809, 0.486335, 0.487859, 0.489382, 0.490903, 0.492423, +0.493941, 0.495458, 0.496973, 0.498487, 0.499999, 0.501510, 0.503019, 0.504527, +0.506033, 0.507538, 0.509041, 0.510542, 0.512042, 0.513541, 0.515038, 0.516533, +0.518027, 0.519519, 0.521009, 0.522498, 0.523985, 0.525471, 0.526955, 0.528438, +0.529919, 0.531398, 0.532876, 0.534352, 0.535826, 0.537299, 0.538770, 0.540240, +0.541708, 0.543174, 0.544639, 0.546101, 0.547563, 0.549022, 0.550480, 0.551936, +0.553391, 0.554844, 0.556295, 0.557745, 0.559192, 0.560638, 0.562083, 0.563526, +0.564967, 0.566406, 0.567843, 0.569279, 0.570713, 0.572145, 0.573576, 0.575005, +0.576432, 0.577857, 0.579281, 0.580702, 0.582122, 0.583541, 0.584957, 0.586372, +0.587785, 0.589196, 0.590605, 0.592013, 0.593418, 0.594822, 0.596224, 0.597625, +0.599023, 0.600420, 0.601815, 0.603207, 0.604599, 0.605988, 0.607375, 0.608761, +0.610145, 0.611527, 0.612907, 0.614285, 0.615661, 0.617035, 0.618408, 0.619779, +0.621147, 0.622514, 0.623879, 0.625242, 0.626603, 0.627963, 0.629320, 0.630675, +0.632029, 0.633380, 0.634730, 0.636078, 0.637423, 0.638767, 0.640109, 0.641449, +0.642787, 0.644123, 0.645457, 0.646789, 0.648119, 0.649448, 0.650774, 0.652098, +0.653420, 0.654740, 0.656059, 0.657375, 0.658689, 0.660001, 0.661311, 0.662620, +0.663926, 0.665230, 0.666532, 0.667832, 0.669130, 0.670426, 0.671720, 0.673012, +0.674302, 0.675590, 0.676875, 0.678159, 0.679441, 0.680720, 0.681998, 0.683273, +0.684547, 0.685818, 0.687087, 0.688354, 0.689619, 0.690882, 0.692143, 0.693401, +0.694658, 0.695912, 0.697165, 0.698415, 0.699663, 0.700909, 0.702153, 0.703394, +0.704634, 0.705871, 0.707106, }; - -static float Const Cosines[] = { -1.00000, .999962, .999848, .999657, .999391, .999048, .998630, .998135, -.997564, .996917, .996195, .995396, .994522, .993572, .992546, .991445, -.990268, .989016, .987688, .986286, .984808, .983255, .981627, .979925, -.978148, .976296, .974370, .972370, .970296, .968148, .965926, .963630, -.961262, .958820, .956305, .953717, .951057, .948324, .945519, .942641, -.939693, .936672, .933580, .930418, .927184, .923880, .920505, .917060, -.913545, .909961, .906308, .902585, .898794, .894934, .891007, .887011, -.882948, .878817, .874620, .870356, .866025, .861629, .857167, .852640, -.848048, .843391, .838671, .833886, .829038, .824126, .819152, .814116, -.809017, .803857, .798636, .793353, .788011, .782608, .777146, .771625, -.766044, .760406, .754710, .748956, .743145, .737277, .731354, .725374, -.719340, .713250, .707107 +static float const Cosines[] = { +1.000000, 0.999998, 0.999993, 0.999986, 0.999975, 0.999961, 0.999945, 0.999925, +0.999902, 0.999876, 0.999847, 0.999815, 0.999780, 0.999742, 0.999701, 0.999657, +0.999610, 0.999559, 0.999506, 0.999450, 0.999390, 0.999328, 0.999262, 0.999194, +0.999122, 0.999048, 0.998970, 0.998889, 0.998806, 0.998719, 0.998629, 0.998536, +0.998440, 0.998341, 0.998239, 0.998134, 0.998026, 0.997915, 0.997801, 0.997684, +0.997564, 0.997440, 0.997314, 0.997185, 0.997052, 0.996917, 0.996778, 0.996637, +0.996492, 0.996345, 0.996194, 0.996041, 0.995884, 0.995724, 0.995561, 0.995396, +0.995227, 0.995055, 0.994880, 0.994702, 0.994521, 0.994337, 0.994150, 0.993960, +0.993767, 0.993571, 0.993372, 0.993170, 0.992965, 0.992757, 0.992546, 0.992331, +0.992114, 0.991894, 0.991671, 0.991444, 0.991215, 0.990983, 0.990747, 0.990509, +0.990268, 0.990023, 0.989776, 0.989525, 0.989272, 0.989015, 0.988756, 0.988493, +0.988228, 0.987959, 0.987688, 0.987413, 0.987136, 0.986855, 0.986572, 0.986285, +0.985996, 0.985703, 0.985407, 0.985109, 0.984807, 0.984503, 0.984195, 0.983885, +0.983571, 0.983254, 0.982935, 0.982612, 0.982287, 0.981958, 0.981627, 0.981292, +0.980955, 0.980614, 0.980271, 0.979924, 0.979575, 0.979222, 0.978867, 0.978508, +0.978147, 0.977783, 0.977415, 0.977045, 0.976672, 0.976296, 0.975916, 0.975534, +0.975149, 0.974761, 0.974370, 0.973975, 0.973578, 0.973178, 0.972775, 0.972369, +0.971961, 0.971549, 0.971134, 0.970716, 0.970295, 0.969872, 0.969445, 0.969015, +0.968583, 0.968147, 0.967709, 0.967267, 0.966823, 0.966376, 0.965925, 0.965472, +0.965016, 0.964557, 0.964095, 0.963630, 0.963162, 0.962691, 0.962217, 0.961741, +0.961261, 0.960779, 0.960293, 0.959805, 0.959313, 0.958819, 0.958322, 0.957822, +0.957319, 0.956813, 0.956304, 0.955793, 0.955278, 0.954760, 0.954240, 0.953716, +0.953190, 0.952661, 0.952129, 0.951594, 0.951056, 0.950515, 0.949972, 0.949425, +0.948876, 0.948323, 0.947768, 0.947210, 0.946649, 0.946085, 0.945518, 0.944948, +0.944376, 0.943800, 0.943222, 0.942641, 0.942057, 0.941470, 0.940880, 0.940288, +0.939692, 0.939094, 0.938493, 0.937888, 0.937281, 0.936672, 0.936059, 0.935444, +0.934825, 0.934204, 0.933580, 0.932953, 0.932323, 0.931691, 0.931055, 0.930417, +0.929776, 0.929132, 0.928485, 0.927836, 0.927183, 0.926528, 0.925870, 0.925209, +0.924546, 0.923879, 0.923210, 0.922538, 0.921863, 0.921185, 0.920504, 0.919821, +0.919135, 0.918446, 0.917754, 0.917060, 0.916362, 0.915662, 0.914959, 0.914253, +0.913545, 0.912834, 0.912120, 0.911403, 0.910683, 0.909961, 0.909236, 0.908508, +0.907777, 0.907044, 0.906307, 0.905568, 0.904827, 0.904082, 0.903335, 0.902585, +0.901832, 0.901077, 0.900318, 0.899557, 0.898794, 0.898027, 0.897258, 0.896486, +0.895711, 0.894934, 0.894154, 0.893371, 0.892585, 0.891797, 0.891006, 0.890212, +0.889416, 0.888617, 0.887815, 0.887010, 0.886203, 0.885393, 0.884580, 0.883765, +0.882947, 0.882126, 0.881303, 0.880477, 0.879648, 0.878817, 0.877982, 0.877146, +0.876306, 0.875464, 0.874619, 0.873772, 0.872922, 0.872069, 0.871213, 0.870355, +0.869494, 0.868631, 0.867765, 0.866896, 0.866025, 0.865151, 0.864274, 0.863395, +0.862513, 0.861629, 0.860742, 0.859852, 0.858959, 0.858064, 0.857167, 0.856267, +0.855364, 0.854458, 0.853550, 0.852640, 0.851726, 0.850811, 0.849892, 0.848971, +0.848048, 0.847121, 0.846193, 0.845261, 0.844327, 0.843391, 0.842452, 0.841510, +0.840566, 0.839619, 0.838670, 0.837718, 0.836764, 0.835807, 0.834847, 0.833885, +0.832921, 0.831954, 0.830984, 0.830012, 0.829037, 0.828060, 0.827080, 0.826098, +0.825113, 0.824126, 0.823136, 0.822144, 0.821149, 0.820151, 0.819152, 0.818149, +0.817144, 0.816137, 0.815127, 0.814115, 0.813100, 0.812083, 0.811063, 0.810041, +0.809016, 0.807989, 0.806960, 0.805928, 0.804893, 0.803856, 0.802817, 0.801775, +0.800731, 0.799684, 0.798635, 0.797583, 0.796529, 0.795473, 0.794414, 0.793353, +0.792289, 0.791223, 0.790155, 0.789084, 0.788010, 0.786935, 0.785856, 0.784776, +0.783693, 0.782608, 0.781520, 0.780430, 0.779337, 0.778243, 0.777145, 0.776046, +0.774944, 0.773840, 0.772733, 0.771624, 0.770513, 0.769399, 0.768283, 0.767165, +0.766044, 0.764921, 0.763796, 0.762668, 0.761538, 0.760405, 0.759271, 0.758134, +0.756995, 0.755853, 0.754709, 0.753563, 0.752414, 0.751264, 0.750111, 0.748955, +0.747798, 0.746638, 0.745475, 0.744311, 0.743144, 0.741975, 0.740804, 0.739631, +0.738455, 0.737277, 0.736097, 0.734914, 0.733729, 0.732542, 0.731353, 0.730162, +0.728968, 0.727772, 0.726574, 0.725374, 0.724171, 0.722967, 0.721760, 0.720551, +0.719339, 0.718126, 0.716910, 0.715692, 0.714472, 0.713250, 0.712026, 0.710799, +0.709570, 0.708339, 0.707106, }; -static void ClockAngle(tick_units, sinp, cosp) - int tick_units; - double *sinp, *cosp; +static void +ClockAngle(int tick_units, double *sinp, double *cosp) { int reduced, upper; - reduced = tick_units % 90; - upper = tick_units / 90; + reduced = tick_units % 450; + upper = tick_units / 450; if (upper & 1) - reduced = 90 - reduced; + reduced = 450 - reduced; if ((upper + 1) & 2) { *sinp = Cosines[reduced]; *cosp = Sines[reduced]; @@ -607,11 +1471,9 @@ static void ClockAngle(tick_units, sinp, cosp) * to the perimeter, then erasing all but the outside most pixels doesn't * work because of round-off error (sigh). */ -static void DrawLine(w, blank_length, length, tick_units) -ClockWidget w; -Dimension blank_length; -Dimension length; -int tick_units; +static void +DrawLine(ClockWidget w, Dimension blank_length, Dimension length, + int tick_units) { double dblank_length = (double)blank_length, dlength = (double)length; double cosangle, sinangle; @@ -644,10 +1506,8 @@ int tick_units; * how far around the circle (clockwise) from high noon. * */ -static void DrawHand(w, length, width, tick_units) -ClockWidget w; -Dimension length, width; -int tick_units; +static void +DrawHand(ClockWidget w, Dimension length, Dimension width, int tick_units) { double cosangle, sinangle; @@ -675,14 +1535,14 @@ int tick_units; wc = width * cosangle; ws = width * sinangle; SetSeg(w, - x = w->clock.centerX + round(length * sinangle), - y = w->clock.centerY - round(length * cosangle), - x1 = w->clock.centerX - round(ws + wc), - y1 = w->clock.centerY + round(wc - ws)); /* 1 ---- 2 */ + x = w->clock.centerX + clock_round(length * sinangle), + y = w->clock.centerY - clock_round(length * cosangle), + x1 = w->clock.centerX - clock_round(ws + wc), + y1 = w->clock.centerY + clock_round(wc - ws)); /* 1 ---- 2 */ /* 2 */ SetSeg(w, x1, y1, - x2 = w->clock.centerX - round(ws - wc), - y2 = w->clock.centerY + round(wc + ws)); /* 2 ----- 3 */ + x2 = w->clock.centerX - clock_round(ws - wc), + y2 = w->clock.centerY + clock_round(wc + ws)); /* 2 ----- 3 */ SetSeg(w, x2, y2, x, y); /* 3 ----- 1(4) */ } @@ -697,10 +1557,9 @@ int tick_units; * how far around the circle (clockwise) from high noon. * */ -static void DrawSecond(w, length, width, offset, tick_units) -ClockWidget w; -Dimension length, width, offset; -int tick_units; +static void +DrawSecond(ClockWidget w, Dimension length, Dimension width, + Dimension offset, int tick_units) { double cosangle, sinangle; @@ -744,22 +1603,21 @@ int tick_units; ws = width * sinangle; /*1 ---- 2 */ SetSeg(w, - x = w->clock.centerX + round(length * sinangle), - y = w->clock.centerY - round(length * cosangle), - w->clock.centerX + round(ms - wc), - w->clock.centerY - round(mc + ws) ); - SetSeg(w, w->clock.centerX + round(offset *sinangle), - w->clock.centerY - round(offset * cosangle), /* 2-----3 */ - w->clock.centerX + round(ms + wc), - w->clock.centerY - round(mc - ws)); + x = w->clock.centerX + clock_round(length * sinangle), + y = w->clock.centerY - clock_round(length * cosangle), + w->clock.centerX + clock_round(ms - wc), + w->clock.centerY - clock_round(mc + ws) ); + SetSeg(w, w->clock.centerX + clock_round(offset *sinangle), + w->clock.centerY - clock_round(offset * cosangle), /* 2-----3 */ + w->clock.centerX + clock_round(ms + wc), + w->clock.centerY - clock_round(mc - ws)); w->clock.segbuffptr->x = x; w->clock.segbuffptr++->y = y; w->clock.numseg ++; } -static void SetSeg(w, x1, y1, x2, y2) -ClockWidget w; -int x1, y1, x2, y2; +static void +SetSeg(ClockWidget w, int x1, int y1, int x2, int y2) { w->clock.segbuffptr->x = x1; w->clock.segbuffptr++->y = y1; @@ -772,8 +1630,8 @@ int x1, y1, x2, y2; * Draw the clock face (every fifth tick-mark is longer * than the others). */ -static void DrawClockFace(w) -ClockWidget w; +static void +DrawClockFace(ClockWidget w) { register int i; register int delta = (int)(w->clock.radius - w->clock.second_hand_length) / 3; @@ -781,10 +1639,43 @@ ClockWidget w; w->clock.segbuffptr = w->clock.segbuff; w->clock.numseg = 0; for (i = 0; i < 60; i++) + { +#ifdef XRENDER + if (w->clock.render && w->clock.can_polygon) + { + double s, c; + XDouble x1, y1, x2, y2; + XftColor *color; + ClockAngle (i * 60, &s, &c); + x1 = c; + y1 = s; + if (i % 5) + { + x2 = c * (MINOR_TICK_FRACT / 100.0); + y2 = s * (MINOR_TICK_FRACT / 100.0); + color = &w->clock.minor_color; + } + else + { + x2 = c * (SECOND_HAND_FRACT / 100.0); + y2 = s * (SECOND_HAND_FRACT / 100.0); + color = &w->clock.major_color; + } + RenderLine (w, x1, y1, x2, y2, color, True); + } + else +#endif + { DrawLine(w, ( (i % 5) == 0 ? w->clock.second_hand_length : (w->clock.radius - delta) ), - w->clock.radius, i * 12); + w->clock.radius, i * 60); + } + } +#ifdef XRENDER + if (w->clock.render && w->clock.can_polygon) + return; +#endif /* * Go ahead and draw it. */ @@ -796,17 +1687,28 @@ ClockWidget w; w->clock.numseg = 0; } -static int round(x) -double x; +static int +clock_round(double x) { return(x >= 0.0 ? (int)(x + .5) : (int)(x - .5)); } +#ifdef XRENDER +static Boolean +sameColor (XftColor *old, XftColor *new) +{ + if (old->color.red != new->color.red) return False; + if (old->color.green != new->color.green) return False; + if (old->color.blue != new->color.blue) return False; + if (old->color.alpha != new->color.alpha) return False; + return True; +} +#endif + /* ARGSUSED */ -static Boolean SetValues (gcurrent, grequest, gnew, args, num_args) - Widget gcurrent, grequest, gnew; - ArgList args; - Cardinal *num_args; +static Boolean +SetValues(Widget gcurrent, Widget grequest, Widget gnew, + ArgList args, Cardinal *num_args) { ClockWidget current = (ClockWidget) gcurrent; ClockWidget new = (ClockWidget) gnew; @@ -827,6 +1729,8 @@ static Boolean SetValues (gcurrent, grequest, gnew, args, num_args) clock_tic, (XtPointer)gnew); new->clock.show_second_hand =(new->clock.update <= SECOND_HAND_TIME); + if (new->clock.show_second_hand != current->clock.show_second_hand) + redisplay = TRUE; } if (new->clock.padding != current->clock.padding) @@ -838,10 +1742,10 @@ static Boolean SetValues (gcurrent, grequest, gnew, args, num_args) if (new->clock.font != current->clock.font) redisplay = TRUE; - if ((new->clock.fgpixel != current->clock.fgpixel) + if ((ClockFgPixel(new) != ClockFgPixel (current)) || (new->core.background_pixel != current->core.background_pixel)) { valuemask = GCForeground | GCBackground | GCFont | GCLineWidth; - myXGCV.foreground = new->clock.fgpixel; + myXGCV.foreground = ClockFgPixel (new); myXGCV.background = new->core.background_pixel; myXGCV.font = new->clock.font->fid; myXGCV.line_width = 0; @@ -869,14 +1773,43 @@ static Boolean SetValues (gcurrent, grequest, gnew, args, num_args) } if (new->core.background_pixel != current->core.background_pixel) { - valuemask = GCForeground | GCLineWidth; + valuemask = GCForeground | GCLineWidth | GCGraphicsExposures; myXGCV.foreground = new->core.background_pixel; myXGCV.line_width = 0; + myXGCV.graphics_exposures = False; XtReleaseGC (gcurrent, current->clock.EraseGC); new->clock.EraseGC = XtGetGC((Widget)gcurrent, valuemask, &myXGCV); redisplay = TRUE; } - +#ifdef XRENDER + if (new->clock.face != current->clock.face) + redisplay = TRUE; + if (!sameColor (&new->clock.hour_color, ¤t->clock.fg_color) || + !sameColor (&new->clock.hour_color, ¤t->clock.hour_color) || + !sameColor (&new->clock.min_color, ¤t->clock.min_color) || + !sameColor (&new->clock.sec_color, ¤t->clock.sec_color) || + !sameColor (&new->clock.major_color, ¤t->clock.major_color) || + !sameColor (&new->clock.minor_color, ¤t->clock.minor_color)) + redisplay = True; + if (new->clock.sharp != current->clock.sharp) + redisplay = True; + if (new->clock.render != current->clock.render) + redisplay = True; + if (new->clock.buffer != current->clock.buffer) + { + if (new->clock.pixmap) + { + XFreePixmap (XtDisplay (new), new->clock.pixmap); + new->clock.pixmap = 0; + } + if (new->clock.draw) + { + XftDrawDestroy (new->clock.draw); + new->clock.draw = 0; + } + new->clock.picture = 0; + } +#endif return (redisplay); } diff --git a/Clock.h b/Clock.h index a244370..b209994 100644 --- a/Clock.h +++ b/Clock.h @@ -49,6 +49,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ +/* $XFree86: xc/programs/xclock/Clock.h,v 1.12 2002/10/21 13:33:07 alanh Exp $ */ #ifndef _XawClock_h #define _XawClock_h @@ -65,6 +66,7 @@ SOFTWARE. Name Class RepType Default Value ---- ----- ------- ------------- + twentyfour Boolean Boolean True analog Boolean Boolean True background Background Pixel white backingStore BackingStore BackingStore default @@ -79,6 +81,7 @@ SOFTWARE. highlight Foreground Pixel black mappedWhenManaged MappedWhenManaged Boolean True padding Margin int 8 + utime Boolean Boolean False update Interval int 60 (seconds) width Width Dimension 164 x Position Position 0 @@ -92,15 +95,51 @@ SOFTWARE. #define XtNhand "hands" + /* Boolean: 24-hour if TRUE */ +#define XtNtwentyfour "twentyfour" + /* Boolean: digital if FALSE */ #define XtNanalog "analog" + /* Boolean: only hour/minute if TRUE */ +#define XtNbrief "brief" + + /* String: will be used as format arg to + "strftime" if not empty string */ +#define XtNstrftime "strftime" + + /* Boolean: show seconds since Epoch if TRUE */ +#define XtNutime "utime" + /* Boolean: */ #define XtNchime "chime" /* Int: amount of space around outside of clock */ #define XtNpadding "padding" + /* Boolean: use Render extension if TRUE */ +#define XtNrender "render" + + /* Boolean: use backing pixmap for double buffering */ +#define XtNbuffer "buffer" + + /* RenderColor: colors for various clock elements */ +#define XtNhourColor "hourColor" +#define XtNminuteColor "minuteColor" +#define XtNsecondColor "secondColor" +#define XtNmajorColor "majorColor" +#define XtNminorColor "minorColor" + +#define XtRXftColor "XftColor" + +#define XtNface "face" +#define XtCFace "Face" +#define XtRXftFont "XftFont" + + /* Boolean: use sharp rendering for Render polygons */ +#define XtNsharp "sharp" +#define XtCSharp "Sharp" + typedef struct _ClockRec *ClockWidget; /* completely defined in ClockPrivate.h */ typedef struct _ClockClassRec *ClockWidgetClass; /* completely defined in ClockPrivate.h */ diff --git a/ClockP.h b/ClockP.h index 3f677e1..50fba01 100644 --- a/ClockP.h +++ b/ClockP.h @@ -49,6 +49,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ +/* $XFree86: xc/programs/xclock/ClockP.h,v 1.12 2002/10/21 13:33:08 alanh Exp $ */ #ifndef _XawClockP_h #define _XawClockP_h @@ -56,13 +57,21 @@ SOFTWARE. #include /* Needed for struct tm. */ #include "Clock.h" #include +#ifdef XRENDER +#include +#include +#endif #define SEG_BUFF_SIZE 128 #define ASCII_TIME_BUFLEN 32 /* big enough for 26 plus slop */ +#define STRFTIME_BUFF_SIZE 100 /* buffer for "strftime" option */ + /* New fields for the clock widget instance record */ typedef struct { +#ifndef RENDER Pixel fgpixel; /* color index for text */ +#endif Pixel Hipixel; /* color index for Highlighting */ Pixel Hdpixel; /* color index for hands */ XFontStruct *font; /* font for text */ @@ -77,6 +86,10 @@ typedef struct { Boolean chime; Boolean beeped; Boolean analog; + Boolean brief; + Boolean twentyfour; + Boolean utime; + String strftime; Boolean show_second_hand; Dimension second_hand_length; Dimension minute_hand_length; @@ -93,8 +106,38 @@ typedef struct { struct tm otm ; XtIntervalId interval_id; char prev_time_string[ASCII_TIME_BUFLEN]; +#ifdef XRENDER + XftColor fg_color; + XftColor hour_color; + XftColor min_color; + XftColor sec_color; + XftColor major_color; + XftColor minor_color; + XftFont *face; + XRenderPictFormat *mask_format; + + Boolean render; + Boolean sharp; + Boolean can_polygon; + Boolean buffer; + XftDraw *draw; + Picture picture; + Picture fill_picture; + Pixmap pixmap; + XRectangle damage; + XDouble x_scale; + XDouble x_off; + XDouble y_scale; + XDouble y_off; +#endif } ClockPart; +#ifdef XRENDER +#define ClockFgPixel(c) ((c)->clock.fg_color.pixel) +#else +#define ClockFgPixel(c) ((c)->clock.fgpixel) +#endif + /* Full instance record declaration */ typedef struct _ClockRec { CorePart core; diff --git a/xclock.c b/xclock.c index 8ac6723..0ad6917 100644 --- a/xclock.c +++ b/xclock.c @@ -2,6 +2,8 @@ /* * xclock -- Hacked from Tony Della Fera's much hacked clock program. + * + * "-strftime" option added by George Belotsky, Open Light Software Inc. */ /* @@ -27,7 +29,10 @@ Except as contained in this notice, the name of The Open Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The Open Group. */ +/* $XFree86: xc/programs/xclock/xclock.c,v 1.16 2002/10/21 13:33:08 alanh Exp $ */ +#include +#include #include #include #include @@ -41,7 +46,6 @@ in this Software without prior written authorization from The Open Group. #include #endif -extern void exit(); /* Command line options table. Only resources are entered here...there is a pass over the remaining options after XtParseCommand is let loose. */ @@ -57,9 +61,22 @@ static XrmOptionDescRec options[] = { {"-d", "*clock.analog", XrmoptionNoArg, "FALSE"}, {"-digital", "*clock.analog", XrmoptionNoArg, "FALSE"}, {"-analog", "*clock.analog", XrmoptionNoArg, "TRUE"}, +{"-twelve", "*clock.twentyfour", XrmoptionNoArg, "FALSE"}, +{"-twentyfour", "*clock.twentyfour", XrmoptionNoArg, "TRUE"}, +{"-brief", "*clock.brief", XrmoptionNoArg, "TRUE"}, +{"-utime", "*clock.utime", XrmoptionNoArg, "TRUE"}, +{"-strftime", "*clock.strftime", XrmoptionSepArg, NULL}, +#ifdef XRENDER +{"-face", "*clock.face", XrmoptionSepArg, NULL}, +{"-render", "*clock.render", XrmoptionNoArg, "TRUE"}, +{"-norender", "*clock.render", XrmoptionNoArg, "FALSE"}, +{"-sharp", "*clock.sharp", XrmoptionNoArg, "TRUE"}, +#endif }; -static void quit(); +static void quit ( Widget w, XEvent *event, String *params, + Cardinal *num_params ); + static XtActionsRec xclock_actions[] = { { "quit", quit }, }; @@ -69,32 +86,30 @@ static Atom wm_delete_window; /* * Report the syntax for calling xclock. */ -Syntax(call) - char *call; +static void +Syntax(char *call) { - (void) printf ("Usage: %s [-analog] [-bw ] [-digital]\n", call); + (void) printf ("Usage: %s [-analog] [-bw ] [-digital] [-brief] [-utime] [-strftime ]\n", call); (void) printf (" [-fg ] [-bg ] [-hd ]\n"); (void) printf (" [-hl ] [-bd ]\n"); (void) printf (" [-fn ] [-help] [-padding ]\n"); (void) printf (" [-rv] [-update ] [-display displayname]\n"); - (void) printf (" [-geometry geom]\n\n"); +#ifdef XRENDER + (void) printf (" [-render] [-face ] [-sharp]\n"); +#endif + (void) printf (" [-geometry geom] [-twelve] [-twentyfour]\n\n"); exit(1); } -static void die(w, client_data, call_data) - Widget w; - XtPointer client_data; - XtPointer call_data; +static void +die(Widget w, XtPointer client_data, XtPointer call_data) { XCloseDisplay(XtDisplayOfObject(w)); exit(0); } -static void quit (w, event, params, num_params) - Widget w; /* ApplicationShellWidget */ - XEvent *event; - String *params; - Cardinal *num_params; +static void +quit(Widget w, XEvent *event, String *params, Cardinal *num_params) { Arg arg; @@ -113,18 +128,16 @@ static void quit (w, event, params, num_params) } } -static void save(w, client_data, call_data) - Widget w; - XtPointer client_data, call_data; +static void +save(Widget w, XtPointer client_data, XtPointer call_data) { XtCheckpointToken token = (XtCheckpointToken) call_data; /* we have nothing to save */ token->save_success = True; } -void main(argc, argv) - int argc; - char **argv; +int +main(int argc, char *argv[]) { Widget toplevel; Arg arg; @@ -137,7 +150,6 @@ void main(argc, argv) if (argc != 1) Syntax(argv[0]); XtAddCallback(toplevel, XtNdieCallback, die, NULL); XtAddCallback(toplevel, XtNsaveCallback, save, NULL); - XtAppAddActions (app_con, xclock_actions, XtNumber(xclock_actions)); /* @@ -149,12 +161,14 @@ void main(argc, argv) XtSetArg(arg, XtNiconPixmap, &icon_pixmap); XtGetValues(toplevel, &arg, ONE); + if (icon_pixmap == None) { arg.value = (XtArgVal)XCreateBitmapFromData(XtDisplay(toplevel), XtScreen(toplevel)->root, (char *)clock_bits, clock_width, clock_height); XtSetValues (toplevel, &arg, ONE); } + XtSetArg(arg, XtNiconMask, &icon_pixmap); XtGetValues(toplevel, &arg, ONE); if (icon_pixmap == None) { @@ -172,4 +186,5 @@ void main(argc, argv) (void) XSetWMProtocols (XtDisplay(toplevel), XtWindow(toplevel), &wm_delete_window, 1); XtAppMainLoop (app_con); + exit(0); } diff --git a/xclock.man b/xclock.man index 0019d77..56cf640 100644 --- a/xclock.man +++ b/xclock.man @@ -22,14 +22,18 @@ .\" not be used in advertising or otherwise to promote the sale, use or .\" other dealings in this Software without prior written authorization .\" from The Open Group. -.TH XCLOCK 1 "Release 6.4" "X Version 11" +.\" +.\" $XFree86: xc/programs/xclock/xclock.man,v 1.13 2002/10/21 13:33:08 alanh Exp $ +.\" +.TH XCLOCK 1 __xorgversion__ .SH NAME xclock \- analog / digital clock for X .SH SYNOPSIS .ta 8n \fBxclock\fP [ \fB\-help\fP ] [ \fB\-analog\fP ] [ \fB\-digital\fP ] -[ \fB\-chime\fP ] [ \fB\-hd\fP \fIcolor\fP ] +[ \fB\-brief\fP ] [ \fB\-chime\fP ] [ \fB\-hd\fP \fIcolor\fP ] [ \fB\-hl\fP \fIcolor\fP ] [ \fB\-update\fP \fIseconds\fP ] +[ \fB\-strftime\fP \fIformat\fP ] [ \fB\-padding\fP \fInumber\fP ] .SH DESCRIPTION The @@ -52,6 +56,27 @@ and hands should be used. This is the default. \fB\-digital\fP or \fB\-d\fP This option indicates that a 24 hour digital clock should be used. .TP 8 +\fB\-brief\fP +This option indicates that the digital clock should only display the hours +and minutes fields. The default is to show the full time and date information. +.TP 8 +\fB\-utime\fP or \fB\-d\fP +This option indicates that a digital clock should display seconds since +the Epoch (in format '970012340 seconds since Epoch' instead of a standard +24-hour time. +.TP 8 +.B \-strftime \fIformat\fP +This option allows an strftime(3) format string to be specified for the +digital clock's display. +.TP 8 +.B \-twelve +This option indicates that a digital clock should display the time in +twelve hour format. +.TP 8 +.B \-twentyfour +This option indicates that a digital clock should display the time in +twenty-four hour format. This is the default when a digital clock is used. +.TP 8 .B \-chime This option indicates that the clock should chime once on the half hour and twice on the hour. @@ -115,6 +140,10 @@ the default is \fIlwhite\fP, otherwise the default is \fIblack\fP. Specifies whether or not an analog clock should be used instead of a digital one. The default is True. .TP 8 +.B twentyfour (\fPclass\fB Boolean) +Specifies whether or not a digital clock should display the time in +twenty-four hour format. The default is True. +.TP 8 .B chime (\fPclass\fB Boolean) Specifies whether or not a bell should be rung on the hour and half hour. .TP 8 @@ -148,9 +177,11 @@ to get the default host and display number. to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. .SH FILES -/lib/X11/app-defaults/XClock - specifies required resources +.TP +.I __apploaddir__/XClock +specifies required resources .SH "SEE ALSO" -X(1), xrdb(1), time(3C) +X(__miscmansuffix__), xrdb(1), time(3C) .SH BUGS .I Xclock believes the system clock. -- cgit v1.2.3