diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-17 19:03:47 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-17 19:03:47 +0000 |
commit | e87aea23d80c4519a1e2ab97582cfdce6729dbdb (patch) | |
tree | 425895187659ae880f42110fcc9f404ba6200cba /Clock.c | |
parent | 7fa20e0899cf53cbb6d386d0688127df8b6fb0c7 (diff) |
merge XFree86 4.3.0.1 to -CURRENT
Diffstat (limited to 'Clock.c')
-rw-r--r-- | Clock.c | 1197 |
1 files changed, 1065 insertions, 132 deletions
@@ -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 <X11/Xlib.h> #include <X11/StringDefs.h> #include <X11/IntrinsicP.h> #include "ClockP.h" #include <X11/Xosdefs.h> +#include <stdio.h> +#include <X11/Xos.h> -#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 <time.h> #define Time_t time_t -#endif #ifdef XKB #include <X11/extensions/XKBbells.h> #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 <math.h> + +#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); } |