Clock.c revision e9554658
1/* $Xorg: Clock.c,v 1.4 2001/02/09 02:05:39 xorgcvs Exp $ */ 2/* $XdotOrg: xc/programs/xclock/Clock.c,v 1.3 2004/10/30 20:33:44 alanc Exp $ */ 3 4/*********************************************************** 5 6Copyright 1987, 1988, 1998 The Open Group 7 8Permission to use, copy, modify, distribute, and sell this software and its 9documentation for any purpose is hereby granted without fee, provided that 10the above copyright notice appear in all copies and that both that 11copyright notice and this permission notice appear in supporting 12documentation. 13 14The above copyright notice and this permission notice shall be included in 15all copies or substantial portions of the Software. 16 17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24Except as contained in this notice, the name of The Open Group shall not be 25used in advertising or otherwise to promote the sale, use or other dealings 26in this Software without prior written authorization from The Open Group. 27 28 29Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 30 31 All Rights Reserved 32 33Permission to use, copy, modify, and distribute this software and its 34documentation for any purpose and without fee is hereby granted, 35provided that the above copyright notice appear in all copies and that 36both that copyright notice and this permission notice appear in 37supporting documentation, and that the name of Digital not be 38used in advertising or publicity pertaining to distribution of the 39software without specific, written prior permission. 40 41DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 42ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 43DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 44ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 45WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 46ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 47SOFTWARE. 48 49******************************************************************/ 50/* 51 * Copyright 2004 Sun Microsystems, Inc. 52 * All rights reserved. 53 * 54 * Redistribution and use in source and binary forms, with or without 55 * modification, are permitted provided that the following conditions 56 * are met: 57 * 58 * 1. Redistributions of source code must retain the above copyright 59 * notice, this list of conditions and the following disclaimer. 60 * 61 * 2. Redistributions in binary form must reproduce the above copyright 62 * notice, this list of conditions and the following disclaimer in the 63 * documentation and/or other materials provided with the distribution. 64 * 65 * 3. Neither the name of Sun Microsystems, Inc. nor the names of its 66 * contributors may be used to endorse or promote products derived from 67 * this software without specific prior written permission. 68 * 69 * This software is provided "AS IS," without a warranty of any kind. 70 * 71 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 72 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 73 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. 74 * SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES OR 75 * LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR RELATING TO USE, 76 * MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS DERIVATIVES. 77 * IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, 78 * PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 79 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE 80 * THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE 81 * SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 82 * 83 * Authors: I18N - Steve Swales - March 2000 84 * bgpixmap - Alan Coopersmith (as part of STSF project) - Sept. 2001 85 */ 86/* $XFree86: xc/programs/xclock/Clock.c,v 3.25 2003/07/04 16:24:30 eich Exp $ */ 87 88#ifdef HAVE_CONFIG_H 89# include "config.h" 90#endif 91 92#include <X11/Xlib.h> 93#include <X11/StringDefs.h> 94#include <X11/IntrinsicP.h> 95#include "ClockP.h" 96#include <X11/Xosdefs.h> 97#include <stdio.h> 98#include <X11/Xos.h> 99#include <X11/Xaw/XawInit.h> 100#if !defined(NO_I18N) && defined(HAVE_ICONV) 101#include <iconv.h> 102#include <langinfo.h> 103#include <errno.h> 104#include <limits.h> 105#endif 106 107#if defined(XawVersion) && (XawVersion >= 7000002L) 108#define USE_XAW_PIXMAP_CVT 109#else 110#include <X11/xpm.h> 111#endif 112 113#include <time.h> 114#define Time_t time_t 115 116#ifdef XKB 117#include <X11/extensions/XKBbells.h> 118#endif 119 120#ifndef NO_I18N 121#include <stdlib.h> /* for getenv() */ 122#include <locale.h> 123extern Boolean no_locale; /* if True, use old (unlocalized) behaviour */ 124#endif 125 126 127/* Private Definitions */ 128 129#define VERTICES_IN_HANDS 6 /* to draw triangle */ 130#define PI 3.14159265358979 131#define TWOPI (2. * PI) 132 133#define MINOR_TICK_FRACT 95 134#define SECOND_HAND_FRACT 90 135#define MINUTE_HAND_FRACT 70 136#define HOUR_HAND_FRACT 40 137#define HAND_WIDTH_FRACT 7 138#define SECOND_WIDTH_FRACT 5 139#define SECOND_HAND_TIME 30 140 141#define ANALOG_SIZE_DEFAULT 164 142 143#define max(a, b) ((a) > (b) ? (a) : (b)) 144#define min(a, b) ((a) < (b) ? (a) : (b)) 145/* #define abs(a) ((a) < 0 ? -(a) : (a)) */ 146 147 148/* Initialization of defaults */ 149 150#define offset(field) XtOffsetOf(ClockRec, clock.field) 151#define goffset(field) XtOffsetOf(WidgetRec, core.field) 152 153static XtResource resources[] = { 154 {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension), 155 goffset(width), XtRImmediate, (XtPointer) 0}, 156 {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension), 157 goffset(height), XtRImmediate, (XtPointer) 0}, 158 {XtNupdate, XtCInterval, XtRInt, sizeof(int), 159 offset(update), XtRImmediate, (XtPointer) 60 }, 160#ifndef XRENDER 161 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), 162 offset(fgpixel), XtRString, XtDefaultForeground}, 163#endif 164 {XtNhand, XtCForeground, XtRPixel, sizeof(Pixel), 165 offset(Hdpixel), XtRString, XtDefaultForeground}, 166 {XtNhighlight, XtCForeground, XtRPixel, sizeof(Pixel), 167 offset(Hipixel), XtRString, XtDefaultForeground}, 168 {XtNutime, XtCBoolean, XtRBoolean, sizeof(Boolean), 169 offset(utime), XtRImmediate, (XtPointer) FALSE}, 170 {XtNanalog, XtCBoolean, XtRBoolean, sizeof(Boolean), 171 offset(analog), XtRImmediate, (XtPointer) TRUE}, 172 {XtNtwentyfour, XtCBoolean, XtRBoolean, sizeof(Boolean), 173 offset(twentyfour), XtRImmediate, (XtPointer) TRUE}, 174 {XtNbrief, XtCBoolean, XtRBoolean, sizeof(Boolean), 175 offset(brief), XtRImmediate, (XtPointer) FALSE}, 176 {XtNstrftime, XtCString, XtRString, sizeof(String), 177 offset(strftime), XtRString, ""}, 178 {XtNchime, XtCBoolean, XtRBoolean, sizeof(Boolean), 179 offset(chime), XtRImmediate, (XtPointer) FALSE }, 180 {XtNpadding, XtCMargin, XtRInt, sizeof(int), 181 offset(padding), XtRImmediate, (XtPointer) 8}, 182 {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), 183 offset(font), XtRString, XtDefaultFont}, 184#ifndef NO_I18N 185 {XtNfontSet, XtCFontSet, XtRFontSet, sizeof(XFontSet), 186 offset(fontSet), XtRString, XtDefaultFontSet,}, 187#endif 188 {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int), 189 offset (backing_store), XtRString, "default"}, 190#ifdef XRENDER 191 {XtNrender, XtCBoolean, XtRBoolean, sizeof(Boolean), 192 offset(render), XtRImmediate, (XtPointer) TRUE }, 193 {XtNbuffer, XtCBoolean, XtRBoolean, sizeof(Boolean), 194 offset(buffer), XtRImmediate, (XtPointer) TRUE }, 195 {XtNsharp, XtCBoolean, XtRBoolean, sizeof(Boolean), 196 offset(sharp), XtRImmediate, (XtPointer) FALSE }, 197 {XtNforeground, XtCForeground, XtRXftColor, sizeof(XftColor), 198 offset(fg_color), XtRString, XtDefaultForeground}, 199 {XtNhourColor, XtCForeground, XtRXftColor, sizeof(XftColor), 200 offset(hour_color), XtRString, XtDefaultForeground}, 201 {XtNminuteColor, XtCForeground, XtRXftColor, sizeof(XftColor), 202 offset(min_color), XtRString, XtDefaultForeground}, 203 {XtNsecondColor, XtCForeground, XtRXftColor, sizeof(XftColor), 204 offset(sec_color), XtRString, XtDefaultForeground}, 205 {XtNmajorColor, XtCForeground, XtRXftColor, sizeof(XftColor), 206 offset(major_color), XtRString, XtDefaultForeground}, 207 {XtNminorColor, XtCForeground, XtRXftColor, sizeof(XftColor), 208 offset(minor_color), XtRString, XtDefaultForeground}, 209 {XtNface, XtCFace, XtRXftFont, sizeof (XftFont *), 210 offset (face), XtRString, ""}, 211#endif 212}; 213 214#undef offset 215#undef goffset 216 217static void ClassInitialize ( void ); 218static void Initialize ( Widget request, Widget new, ArgList args, 219 Cardinal *num_args ); 220static void Realize ( Widget gw, XtValueMask *valueMask, 221 XSetWindowAttributes *attrs ); 222static void Destroy ( Widget gw ); 223static void Resize ( Widget gw ); 224static void Redisplay ( Widget gw, XEvent *event, Region region ); 225static void clock_tic ( XtPointer client_data, XtIntervalId *id ); 226static void erase_hands ( ClockWidget w, struct tm *tm ); 227static void ClockAngle ( int tick_units, double *sinp, double *cosp ); 228static void DrawLine ( ClockWidget w, Dimension blank_length, 229 Dimension length, int tick_units ); 230static void DrawHand ( ClockWidget w, Dimension length, Dimension width, 231 int tick_units ); 232static void DrawSecond ( ClockWidget w, Dimension length, Dimension width, 233 Dimension offset, int tick_units ); 234static void SetSeg ( ClockWidget w, int x1, int y1, int x2, int y2 ); 235static void DrawClockFace ( ClockWidget w ); 236static int clock_round ( double x ); 237static Boolean SetValues ( Widget gcurrent, Widget grequest, Widget gnew, 238 ArgList args, Cardinal *num_args ); 239#if !defined(NO_I18N) && defined(HAVE_ICONV) 240static char *clock_to_utf8(const char *); 241#endif 242 243ClockClassRec clockClassRec = { 244 { /* core fields */ 245 /* superclass */ (WidgetClass) &simpleClassRec, 246 /* class_name */ "Clock", 247 /* widget_size */ sizeof(ClockRec), 248 /* class_initialize */ ClassInitialize, 249 /* class_part_initialize */ NULL, 250 /* class_inited */ FALSE, 251 /* initialize */ Initialize, 252 /* initialize_hook */ NULL, 253 /* realize */ Realize, 254 /* actions */ NULL, 255 /* num_actions */ 0, 256 /* resources */ resources, 257 /* resource_count */ XtNumber(resources), 258 /* xrm_class */ NULLQUARK, 259 /* compress_motion */ TRUE, 260 /* compress_exposure */ XtExposeCompressMaximal, 261 /* compress_enterleave */ TRUE, 262 /* visible_interest */ FALSE, 263 /* destroy */ Destroy, 264 /* resize */ Resize, 265 /* expose */ Redisplay, 266 /* set_values */ SetValues, 267 /* set_values_hook */ NULL, 268 /* set_values_almost */ XtInheritSetValuesAlmost, 269 /* get_values_hook */ NULL, 270 /* accept_focus */ NULL, 271 /* version */ XtVersion, 272 /* callback_private */ NULL, 273 /* tm_table */ NULL, 274 /* query_geometry */ XtInheritQueryGeometry, 275 /* display_accelerator */ XtInheritDisplayAccelerator, 276 /* extension */ NULL 277 }, 278 { /* simple fields */ 279 /* change_sensitive */ XtInheritChangeSensitive 280 }, 281 { /* clock fields */ 282 /* ignore */ 0 283 } 284}; 285 286WidgetClass clockWidgetClass = (WidgetClass) &clockClassRec; 287 288/**************************************************************** 289 * 290 * Private Procedures 291 * 292 ****************************************************************/ 293#ifndef USE_XAW_PIXMAP_CVT 294static void CvtStringToPixmap( 295 XrmValue* args, 296 Cardinal* num_args, 297 XrmValuePtr fromVal, 298 XrmValuePtr toVal 299 ) 300{ 301 static Pixmap pmap; 302 Pixmap shapemask; 303 char *name = (char *)fromVal->addr; 304 Screen *screen; 305 Display *dpy; 306 307 if (*num_args != 1) 308 XtErrorMsg("wrongParameters","cvtStringToPixmap","XtToolkitError", 309 "String to pixmap conversion needs screen argument", 310 (String *)NULL, (Cardinal *)NULL); 311 312 if (strcmp(name, "None") == 0) { 313 pmap = None; 314 } else { 315 screen = *((Screen **) args[0].addr); 316 dpy = DisplayOfScreen(screen); 317 318 XpmReadFileToPixmap(dpy, RootWindowOfScreen(screen), name, &pmap, 319 &shapemask, NULL); 320 } 321 322 (*toVal).size = sizeof(Pixmap); 323 (*toVal).addr = (XPointer) &pmap ; 324} 325#endif 326 327#ifdef XRENDER 328XtConvertArgRec xftColorConvertArgs[] = { 329 {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), 330 sizeof(Screen *)}, 331 {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap), 332 sizeof(Colormap)} 333}; 334 335#define donestr(type, value, tstr) \ 336 { \ 337 if (toVal->addr != NULL) { \ 338 if (toVal->size < sizeof(type)) { \ 339 toVal->size = sizeof(type); \ 340 XtDisplayStringConversionWarning(dpy, \ 341 (char*) fromVal->addr, tstr); \ 342 return False; \ 343 } \ 344 *(type*)(toVal->addr) = (value); \ 345 } \ 346 else { \ 347 static type static_val; \ 348 static_val = (value); \ 349 toVal->addr = (XPointer)&static_val; \ 350 } \ 351 toVal->size = sizeof(type); \ 352 return True; \ 353 } 354 355static void 356XmuFreeXftColor (XtAppContext app, XrmValuePtr toVal, XtPointer closure, 357 XrmValuePtr args, Cardinal *num_args) 358{ 359 Screen *screen; 360 Colormap colormap; 361 XftColor *color; 362 363 if (*num_args != 2) 364 { 365 XtAppErrorMsg (app, 366 "freeXftColor", "wrongParameters", 367 "XtToolkitError", 368 "Freeing an XftColor requires screen and colormap arguments", 369 (String *) NULL, (Cardinal *)NULL); 370 return; 371 } 372 373 screen = *((Screen **) args[0].addr); 374 colormap = *((Colormap *) args[1].addr); 375 color = (XftColor *) toVal->addr; 376 XftColorFree (DisplayOfScreen (screen), 377 DefaultVisual (DisplayOfScreen (screen), 378 XScreenNumberOfScreen (screen)), 379 colormap, color); 380} 381 382static Boolean 383XmuCvtStringToXftColor(Display *dpy, 384 XrmValue *args, Cardinal *num_args, 385 XrmValue *fromVal, XrmValue *toVal, 386 XtPointer *converter_data) 387{ 388 char *spec; 389 XRenderColor renderColor; 390 XftColor xftColor; 391 Screen *screen; 392 Colormap colormap; 393 394 if (*num_args != 2) 395 { 396 XtAppErrorMsg (XtDisplayToApplicationContext (dpy), 397 "cvtStringToXftColor", "wrongParameters", 398 "XtToolkitError", 399 "String to render color conversion needs screen and colormap arguments", 400 (String *) NULL, (Cardinal *)NULL); 401 return False; 402 } 403 404 screen = *((Screen **) args[0].addr); 405 colormap = *((Colormap *) args[1].addr); 406 407 spec = (char *) fromVal->addr; 408 if (strcasecmp (spec, XtDefaultForeground) == 0) 409 { 410 renderColor.red = 0; 411 renderColor.green = 0; 412 renderColor.blue = 0; 413 renderColor.alpha = 0xffff; 414 } 415 else if (strcasecmp (spec, XtDefaultBackground) == 0) 416 { 417 renderColor.red = 0xffff; 418 renderColor.green = 0xffff; 419 renderColor.blue = 0xffff; 420 renderColor.alpha = 0xffff; 421 } 422 else if (!XRenderParseColor (dpy, spec, &renderColor)) 423 return False; 424 if (!XftColorAllocValue (dpy, 425 DefaultVisual (dpy, 426 XScreenNumberOfScreen (screen)), 427 colormap, 428 &renderColor, 429 &xftColor)) 430 return False; 431 432 donestr (XftColor, xftColor, XtRXftColor); 433} 434 435static void 436XmuFreeXftFont (XtAppContext app, XrmValuePtr toVal, XtPointer closure, 437 XrmValuePtr args, Cardinal *num_args) 438{ 439 Screen *screen; 440 XftFont *font; 441 442 if (*num_args != 1) 443 { 444 XtAppErrorMsg (app, 445 "freeXftFont", "wrongParameters", 446 "XtToolkitError", 447 "Freeing an XftFont requires screen argument", 448 (String *) NULL, (Cardinal *)NULL); 449 return; 450 } 451 452 screen = *((Screen **) args[0].addr); 453 font = *((XftFont **) toVal->addr); 454 if (font) 455 XftFontClose (DisplayOfScreen (screen), font); 456} 457 458static Boolean 459XmuCvtStringToXftFont(Display *dpy, 460 XrmValue *args, Cardinal *num_args, 461 XrmValue *fromVal, XrmValue *toVal, 462 XtPointer *converter_data) 463{ 464 char *name; 465 XftFont *font; 466 Screen *screen; 467 468 if (*num_args != 1) 469 { 470 XtAppErrorMsg (XtDisplayToApplicationContext (dpy), 471 "cvtStringToXftFont", "wrongParameters", 472 "XtToolkitError", 473 "String to XftFont conversion needs screen argument", 474 (String *) NULL, (Cardinal *)NULL); 475 return False; 476 } 477 478 screen = *((Screen **) args[0].addr); 479 name = (char *) fromVal->addr; 480 481 font = XftFontOpenName (dpy, 482 XScreenNumberOfScreen (screen), 483 name); 484 if (font) 485 { 486 donestr (XftFont *, font, XtRXftFont); 487 } 488 XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRXftFont); 489 return False; 490} 491 492XtConvertArgRec xftFontConvertArgs[] = { 493 {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), 494 sizeof(Screen *)}, 495}; 496 497#endif 498 499static void 500ClassInitialize(void) 501{ 502#ifdef USE_XAW_PIXMAP_CVT 503 XawInitializeWidgetSet(); 504#else 505 static XtConvertArgRec scrnConvertArg[] = { 506 {XtBaseOffset, (XtPointer) XtOffset(Widget, core.screen), 507 sizeof(Screen *)} 508 }; 509 XtAddConverter( XtRString, XtRPixmap, CvtStringToPixmap, 510 scrnConvertArg, XtNumber(scrnConvertArg)); 511#endif 512 XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore, 513 NULL, 0 ); 514#ifdef XRENDER 515 XtSetTypeConverter (XtRString, XtRXftColor, 516 XmuCvtStringToXftColor, 517 xftColorConvertArgs, XtNumber(xftColorConvertArgs), 518 XtCacheByDisplay, XmuFreeXftColor); 519 XtSetTypeConverter (XtRString, XtRXftFont, 520 XmuCvtStringToXftFont, 521 xftFontConvertArgs, XtNumber(xftFontConvertArgs), 522 XtCacheByDisplay, XmuFreeXftFont); 523#endif 524} 525 526static char * 527TimeString (ClockWidget w, struct tm *tm) 528{ 529 if (w->clock.brief) 530 { 531 if (w->clock.twentyfour) 532 { 533 static char brief[6]; 534 sprintf (brief, "%02d:%02d", tm->tm_hour, tm->tm_min); 535 return brief; 536 } 537 else 538 { 539 static char brief[9]; 540 int hour = tm->tm_hour % 12; 541 if (!hour) hour = 12; 542 sprintf (brief, "%02d:%02d %cM", hour, tm->tm_min, 543 tm->tm_hour >= 12 ? 'P' : 'A'); 544 return brief; 545 } 546 } 547 else if (w->clock.utime) 548 { 549 static char utime[35]; 550 Time_t tsec; 551 tsec = time(NULL); 552 sprintf (utime, "%10lu seconds since Epoch", (unsigned long)tsec); 553 return utime; 554 } else if (*w->clock.strftime) { 555 /*Note: this code is probably excessively paranoid 556 about buffer overflow. The extra size 10 padding 557 is also meant as a further guard against programmer 558 error, although it is a little controversial*/ 559 static char ctime[STRFTIME_BUFF_SIZE+10]; 560 ctime[0] = ctime[STRFTIME_BUFF_SIZE] = '\0'; 561 if (0 < strftime (ctime, STRFTIME_BUFF_SIZE-1,w->clock.strftime, tm)) { 562 ctime[STRFTIME_BUFF_SIZE-1] = '\0'; 563 return ctime; 564 } else { 565 return asctime (tm); 566 } 567 } 568 else if (w->clock.twentyfour) 569 return asctime (tm); 570 else 571 { 572 static char long12[28]; 573 strftime(long12, sizeof long12, "%a %b %d %I:%M:%S %p %Y", tm); 574 return long12; 575 } 576} 577 578/* ARGSUSED */ 579static void 580Initialize (Widget request, Widget new, ArgList args, Cardinal *num_args) 581{ 582 ClockWidget w = (ClockWidget)new; 583 XtGCMask valuemask; 584 XGCValues myXGCV; 585 int min_height, min_width; 586 587 valuemask = GCForeground | GCBackground | GCFont | GCLineWidth; 588 if (w->clock.font != NULL) 589 myXGCV.font = w->clock.font->fid; 590 else 591 valuemask &= ~GCFont; /* use server default font */ 592 593 min_width = min_height = ANALOG_SIZE_DEFAULT; 594 if(!w->clock.analog) { 595 char *str; 596 struct tm tm; 597 Time_t time_value; 598 int len; 599 600#ifndef NO_I18N 601 w->clock.utf8 = False; 602 603 if (!no_locale) { 604 char *time_locale = setlocale(LC_TIME, NULL); 605 606 if (strstr(time_locale, "UTF-8") || strstr(time_locale, "utf8")) { 607 w->clock.utf8 = True; 608 } 609 610 /* 611 * initialize time format from CFTIME if set, otherwise 612 * default to "%c". This emulates ascftime, but we use 613 * strftime so we can limit the string buffer size to 614 * avoid possible buffer overflow. 615 */ 616 if ((w->clock.strftime == NULL) || (w->clock.strftime[0] == 0)) { 617 w->clock.strftime = getenv("CFTIME"); 618 if (w->clock.strftime == NULL) { 619 w->clock.strftime = "%c"; 620 } 621 } 622 } 623#endif /* NO_I18N */ 624 625 (void) time(&time_value); 626 tm = *localtime(&time_value); 627 str = TimeString (w, &tm); 628 len = strlen(str); 629 if (str[len - 1] == '\n') 630 str[--len] = '\0'; 631 632#ifdef XRENDER 633 if (w->clock.render) 634 { 635 XGlyphInfo extents; 636#ifndef NO_I18N 637# ifdef HAVE_ICONV 638 char *utf8_str; 639# endif 640 if (w->clock.utf8) 641 XftTextExtentsUtf8 (XtDisplay (w), w->clock.face, 642 (FcChar8 *) str, len, &extents); 643# ifdef HAVE_ICONV 644 else if ((utf8_str = clock_to_utf8(str)) != NULL) { 645 XftTextExtentsUtf8 (XtDisplay (w), w->clock.face, 646 (FcChar8 *)utf8_str, strlen(utf8_str), &extents); 647 free(utf8_str); 648 } 649# endif 650 else 651#endif 652 XftTextExtents8 (XtDisplay (w), w->clock.face, 653 (FcChar8 *) str, len, &extents); 654 min_width = extents.xOff + 2 * w->clock.padding; 655 min_height = w->clock.face->ascent + w->clock.face->descent + 656 2 * w->clock.padding; 657 } 658 else 659#endif 660#ifndef NO_I18N 661 if (!no_locale) { 662 XFontSetExtents *fse; 663 664 if(w->clock.fontSet == NULL) { 665 char **missing, *default_str; 666 int n_missing; 667 w->clock.fontSet = XCreateFontSet( XtDisplay(w), 668 XtDefaultFontSet, 669 &missing, 670 &n_missing, 671 &default_str); 672 } 673 if (w->clock.fontSet != NULL) 674 { 675 /* don't free this... it's freed with the XFontSet. */ 676 fse = XExtentsOfFontSet(w->clock.fontSet); 677 678 min_width = XmbTextEscapement(w->clock.fontSet,str, 679 len) 680 + 2 * w->clock.padding; 681 min_height = fse->max_logical_extent.height + 682 3 * w->clock.padding; 683 } else { 684 no_locale = True; 685 } 686 } 687 688 if (!no_locale) 689#endif /* NO_I18N */ 690 { 691 if (w->clock.font == NULL) 692 w->clock.font = XQueryFont( XtDisplay(w), 693 XGContextFromGC( 694 DefaultGCOfScreen(XtScreen(w))) ); 695 min_width = XTextWidth(w->clock.font, str, len) + 696 2 * w->clock.padding; 697 min_height = w->clock.font->ascent + 698 w->clock.font->descent + 2 * w->clock.padding; 699 } 700 } 701 if (w->core.width == 0) 702 w->core.width = min_width; 703 if (w->core.height == 0) 704 w->core.height = min_height; 705 706 myXGCV.foreground = ClockFgPixel (w); 707 myXGCV.background = w->core.background_pixel; 708 if (w->clock.font != NULL) 709 myXGCV.font = w->clock.font->fid; 710 else 711 valuemask &= ~GCFont; /* use server default font */ 712 myXGCV.line_width = 0; 713 w->clock.myGC = XtGetGC((Widget)w, valuemask, &myXGCV); 714 715 valuemask = GCForeground | GCLineWidth | GCGraphicsExposures; 716 myXGCV.foreground = w->core.background_pixel; 717 if (w->core.background_pixmap != XtUnspecifiedPixmap) { 718 myXGCV.tile = w->core.background_pixmap; 719 myXGCV.fill_style = FillTiled; 720 valuemask |= (GCTile | GCFillStyle); 721 } 722 myXGCV.graphics_exposures = False; 723 w->clock.EraseGC = XtGetGC((Widget)w, valuemask, &myXGCV); 724 valuemask &= ~(GCTile | GCFillStyle); 725 726 myXGCV.foreground = w->clock.Hipixel; 727 w->clock.HighGC = XtGetGC((Widget)w, valuemask, &myXGCV); 728 729 valuemask = GCForeground; 730 myXGCV.foreground = w->clock.Hdpixel; 731 w->clock.HandGC = XtGetGC((Widget)w, valuemask, &myXGCV); 732 733 if (w->clock.update <= 0) 734 w->clock.update = 60; /* make invalid update's use a default */ 735 w->clock.show_second_hand = (w->clock.update <= SECOND_HAND_TIME); 736 w->clock.numseg = 0; 737 w->clock.interval_id = 0; 738 memset (&w->clock.otm, '\0', sizeof (w->clock.otm)); 739#ifdef XRENDER 740 { 741 int major, minor; 742 743 if (XRenderQueryVersion (XtDisplay (w), &major, &minor) && 744 (major > 0 || 745 (major == 0 && minor >= 4))) 746 { 747 w->clock.can_polygon = True; 748 } 749 else 750 w->clock.can_polygon = False; 751 } 752 w->clock.pixmap = 0; 753 w->clock.draw = 0; 754 w->clock.damage.x = 0; 755 w->clock.damage.y = 0; 756 w->clock.damage.height = 0; 757 w->clock.damage.width = 0; 758#endif 759} 760 761#ifdef XRENDER 762static void 763RenderPrepare (ClockWidget w, XftColor *color) 764{ 765 if (!w->clock.draw) 766 { 767 Drawable d = XtWindow (w); 768 if (w->clock.buffer) 769 { 770 if (!w->clock.pixmap) 771 { 772 Arg arg[1]; 773 w->clock.pixmap = XCreatePixmap (XtDisplay (w), d, 774 w->core.width, 775 w->core.height, 776 w->core.depth); 777 arg[0].name = XtNbackgroundPixmap; 778 arg[0].value = 0; 779 XtSetValues ((Widget) w, arg, 1); 780 } 781 d = w->clock.pixmap; 782 } 783 784 w->clock.draw = XftDrawCreate (XtDisplay (w), d, 785 DefaultVisual (XtDisplay (w), 786 DefaultScreen(XtDisplay (w))), 787 w->core.colormap); 788 w->clock.picture = XftDrawPicture (w->clock.draw); 789 } 790 if (color) 791 w->clock.fill_picture = XftDrawSrcPicture (w->clock.draw, color); 792} 793 794static void 795RenderClip (ClockWidget w) 796{ 797 Region r; 798 Drawable d; 799 800 RenderPrepare (w, 0); 801 if (w->clock.buffer) 802 d = w->clock.pixmap; 803 else 804 d = XtWindow (w); 805 XFillRectangle (XtDisplay (w), d, w->clock.EraseGC, 806 w->clock.damage.x, 807 w->clock.damage.y, 808 w->clock.damage.width, 809 w->clock.damage.height); 810 r = XCreateRegion (); 811 XUnionRectWithRegion (&w->clock.damage, 812 r, r); 813 XftDrawSetClip (w->clock.draw, r); 814 XDestroyRegion (r); 815} 816 817static void 818RenderTextBounds (ClockWidget w, char *str, int off, int len, 819 XRectangle *bounds, int *xp, int *yp) 820{ 821 XGlyphInfo head, tail; 822 int x, y; 823 824#ifndef NO_I18N 825# ifdef HAVE_ICONV 826 char *utf8_str; 827# endif 828 if (w->clock.utf8) 829 { 830 XftTextExtentsUtf8 (XtDisplay (w), w->clock.face, 831 (FcChar8 *) str, off, &head); 832 XftTextExtentsUtf8 (XtDisplay (w), w->clock.face, 833 (FcChar8 *) str + off, len - off, &tail); 834 } 835# ifdef HAVE_ICONV 836 else if ((utf8_str = clock_to_utf8(str)) != NULL) 837 { 838 XftTextExtentsUtf8 (XtDisplay (w), w->clock.face, 839 (FcChar8 *)utf8_str, off, &head); 840 XftTextExtentsUtf8 (XtDisplay (w), w->clock.face, 841 (FcChar8 *)utf8_str + off, strlen(utf8_str) - off, &tail); 842 free(utf8_str); 843 } 844# endif 845 else 846#endif 847 { 848 XftTextExtents8 (XtDisplay (w), w->clock.face, (FcChar8 *) str, 849 off, &head); 850 XftTextExtents8 (XtDisplay (w), w->clock.face, (FcChar8 *) str + off, 851 len - off, &tail); 852 } 853 854 /* 855 * Compute position of tail 856 */ 857 x = w->clock.padding + head.xOff; 858 y = w->clock.face->ascent + w->clock.padding + head.yOff; 859 /* 860 * Compute bounds of tail, pad a bit as the bounds aren't exact 861 */ 862 bounds->x = x - tail.x - 1; 863 bounds->y = y - tail.y - 1; 864 bounds->width = tail.width + 2; 865 bounds->height = tail.height + 2; 866 if (xp) *xp = x; 867 if (yp) *yp = y; 868} 869 870static void 871RenderUpdateRectBounds (XRectangle *damage, XRectangle *bounds) 872{ 873 int x1 = bounds->x; 874 int y1 = bounds->y; 875 int x2 = bounds->x + bounds->width; 876 int y2 = bounds->y + bounds->height; 877 int d_x1 = damage->x; 878 int d_y1 = damage->y; 879 int d_x2 = damage->x + damage->width; 880 int d_y2 = damage->y + damage->height; 881 882 if (x1 == x2) 883 { 884 x1 = d_x1; 885 x2 = d_x2; 886 } 887 else 888 { 889 if (d_x1 < x1) x1 = d_x1; 890 if (d_x2 > x2) x2 = d_x2; 891 } 892 if (y1 == y2) 893 { 894 y1 = d_y1; 895 y2 = d_y2; 896 } 897 else 898 { 899 if (d_y1 < y1) y1 = d_y1; 900 if (d_y2 > y2) y2 = d_y2; 901 } 902 903 bounds->x = x1; 904 bounds->y = y1; 905 bounds->width = x2 - x1; 906 bounds->height = y2 - y1; 907} 908 909static Boolean 910RenderRectIn (XRectangle *rect, XRectangle *bounds) 911{ 912 int x1 = bounds->x; 913 int y1 = bounds->y; 914 int x2 = bounds->x + bounds->width; 915 int y2 = bounds->y + bounds->height; 916 int r_x1 = rect->x; 917 int r_y1 = rect->y; 918 int r_x2 = rect->x + rect->width; 919 int r_y2 = rect->y + rect->height; 920 921 return r_x1 < x2 && x1 < r_x2 && r_y1 < y2 && y1 < r_y2; 922} 923 924#define LINE_WIDTH 0.01 925#include <math.h> 926 927#define XCoord(x,w) ((x) * (w)->clock.x_scale + (w)->clock.x_off) 928#define YCoord(y,w) ((y) * (w)->clock.y_scale + (w)->clock.y_off) 929 930static void 931RenderUpdateBounds (XPointDouble *points, int npoints, XRectangle *bounds) 932{ 933 int x1 = bounds->x; 934 int y1 = bounds->y; 935 int x2 = bounds->x + bounds->width; 936 int y2 = bounds->y + bounds->height; 937 938 while (npoints--) 939 { 940 int r_x1 = points[0].x; 941 int r_y1 = points[0].y; 942 int r_x2 = points[0].x + 1; 943 int r_y2 = points[0].y + 1; 944 945 if (x1 == x2) 946 x2 = x1 = r_x1; 947 if (y1 == y2) 948 y2 = y1 = r_y1; 949 if (r_x1 < x1) x1 = r_x1; 950 if (r_y1 < y1) y1 = r_y1; 951 if (r_x2 > x2) x2 = r_x2; 952 if (r_y2 > y2) y2 = r_y2; 953 points++; 954 } 955 bounds->x = x1; 956 bounds->y = y1; 957 bounds->width = x2 - x1; 958 bounds->height = y2 - y1; 959} 960 961static Boolean 962RenderCheckBounds (XPointDouble *points, int npoints, XRectangle *bounds) 963{ 964 int x1 = bounds->x; 965 int y1 = bounds->y; 966 int x2 = bounds->x + bounds->width; 967 int y2 = bounds->y + bounds->height; 968 969 while (npoints--) 970 { 971 if (x1 <= points->x && points->x <= x2 && 972 y1 <= points->y && points->y <= y2) 973 return True; 974 points++; 975 } 976 return False; 977} 978 979static void 980RenderUpdate (ClockWidget w) 981{ 982 if (w->clock.buffer && w->clock.pixmap) 983 { 984 XCopyArea (XtDisplay (w), w->clock.pixmap, 985 XtWindow (w), w->clock.EraseGC, 986 w->clock.damage.x, w->clock.damage.y, 987 w->clock.damage.width, w->clock.damage.height, 988 w->clock.damage.x, w->clock.damage.y); 989 } 990} 991 992static void 993RenderResetBounds (XRectangle *bounds) 994{ 995 bounds->x = 0; 996 bounds->y = 0; 997 bounds->width = 0; 998 bounds->height = 0; 999} 1000 1001static void 1002RenderLine (ClockWidget w, XDouble x1, XDouble y1, XDouble x2, XDouble y2, 1003 XftColor *color, 1004 Boolean draw) 1005{ 1006 XPointDouble poly[4]; 1007 XDouble dx = (x2 - x1); 1008 XDouble dy = (y2 - y1); 1009 XDouble len = sqrt (dx*dx + dy*dy); 1010 XDouble ldx = (LINE_WIDTH/2.0) * dy / len; 1011 XDouble ldy = (LINE_WIDTH/2.0) * dx / len; 1012 1013 poly[0].x = XCoord (x1 + ldx, w); 1014 poly[0].y = YCoord (y1 - ldy, w); 1015 1016 poly[1].x = XCoord (x2 + ldx, w); 1017 poly[1].y = YCoord (y2 - ldy, w); 1018 1019 poly[2].x = XCoord (x2 - ldx, w); 1020 poly[2].y = YCoord (y2 + ldy, w); 1021 1022 poly[3].x = XCoord (x1 - ldx, w); 1023 poly[3].y = YCoord (y1 + ldy, w); 1024 1025 RenderUpdateBounds (poly, 4, &w->clock.damage); 1026 if (draw) 1027 { 1028 if (RenderCheckBounds (poly, 4, &w->clock.damage)) 1029 { 1030 RenderPrepare (w, color); 1031 XRenderCompositeDoublePoly (XtDisplay (w), 1032 PictOpOver, 1033 w->clock.fill_picture, 1034 w->clock.picture, 1035 w->clock.mask_format, 1036 0, 0, 0, 0, poly, 4, EvenOddRule); 1037 } 1038 } 1039 else 1040 RenderUpdateBounds (poly, 4, &w->clock.damage); 1041} 1042 1043static void 1044RenderRotate (ClockWidget w, XPointDouble *out, double x, double y, double s, double c) 1045{ 1046 out->x = XCoord (x * c - y * s, w); 1047 out->y = YCoord (y * c + x * s, w); 1048} 1049 1050static void 1051RenderHand (ClockWidget w, int tick_units, int size, XftColor *color, 1052 Boolean draw) 1053{ 1054 double c, s; 1055 XPointDouble poly[3]; 1056 double outer_x; 1057 double inner_y; 1058 1059 ClockAngle (tick_units, &c, &s); 1060 s = -s; 1061 1062 /* compute raw positions */ 1063 outer_x = size / 100.0; 1064 inner_y = HAND_WIDTH_FRACT / 100.0; 1065 1066 /* rotate them into position */ 1067 RenderRotate (w, &poly[0], outer_x, 0.0, s, c); 1068 RenderRotate (w, &poly[1], -inner_y, inner_y, s, c); 1069 RenderRotate (w, &poly[2], -inner_y, -inner_y, s, c); 1070 1071 if (draw) 1072 { 1073 if (RenderCheckBounds (poly, 3, &w->clock.damage)) 1074 { 1075 RenderPrepare (w, color); 1076 XRenderCompositeDoublePoly (XtDisplay (w), 1077 PictOpOver, 1078 w->clock.fill_picture, 1079 w->clock.picture, 1080 w->clock.mask_format, 1081 0, 0, 0, 0, poly, 3, EvenOddRule); 1082 } 1083 } 1084 RenderUpdateBounds (poly, 3, &w->clock.damage); 1085} 1086 1087static void 1088RenderHands (ClockWidget w, struct tm *tm, Boolean draw) 1089{ 1090 RenderHand (w, tm->tm_hour * 300 + tm->tm_min*5, HOUR_HAND_FRACT, &w->clock.hour_color, draw); 1091 RenderHand (w, tm->tm_min * 60 + tm->tm_sec, MINUTE_HAND_FRACT, &w->clock.min_color, draw); 1092} 1093 1094static void 1095RenderSec (ClockWidget w, struct tm *tm, Boolean draw) 1096{ 1097 double c, s; 1098 XPointDouble poly[10]; 1099 double inner_x, middle_x, outer_x, far_x; 1100 double middle_y; 1101 double line_y; 1102 1103 ClockAngle (tm->tm_sec * 60, &c, &s); 1104 1105 s = -s; 1106 1107 /* 1108 * Compute raw positions 1109 */ 1110 line_y = LINE_WIDTH; 1111 inner_x = (MINUTE_HAND_FRACT / 100.0); 1112 middle_x = ((SECOND_HAND_FRACT + MINUTE_HAND_FRACT) / 200.0); 1113 outer_x = (SECOND_HAND_FRACT / 100.0); 1114 far_x = (MINOR_TICK_FRACT / 100.0); 1115 middle_y = (SECOND_WIDTH_FRACT / 100.0); 1116 1117 /* 1118 * Rotate them into position 1119 */ 1120 RenderRotate (w, &poly[0], -line_y, line_y, s, c); 1121 RenderRotate (w, &poly[1], inner_x, line_y, s, c); 1122 RenderRotate (w, &poly[2], middle_x, middle_y, s, c); 1123 RenderRotate (w, &poly[3], outer_x, line_y, s, c); 1124 RenderRotate (w, &poly[4], far_x, line_y, s, c); 1125 RenderRotate (w, &poly[5], far_x, -line_y, s, c); 1126 RenderRotate (w, &poly[6], outer_x, -line_y, s, c); 1127 RenderRotate (w, &poly[7], middle_x, -middle_y, s, c); 1128 RenderRotate (w, &poly[8], inner_x, -line_y, s, c); 1129 RenderRotate (w, &poly[9], -line_y, -line_y, s, c); 1130 1131 if (draw) 1132 { 1133 if (RenderCheckBounds (poly, 10, &w->clock.damage)) 1134 { 1135 RenderPrepare (w, &w->clock.sec_color); 1136 XRenderCompositeDoublePoly (XtDisplay (w), 1137 PictOpOver, 1138 w->clock.fill_picture, 1139 w->clock.picture, 1140 w->clock.mask_format, 1141 0, 0, 0, 0, poly, 10, EvenOddRule); 1142 } 1143 } 1144 else 1145 { 1146 RenderUpdateBounds (poly, 10, &w->clock.damage); 1147 } 1148} 1149 1150#endif 1151 1152static void 1153Realize(Widget gw, XtValueMask *valueMask, XSetWindowAttributes *attrs) 1154{ 1155 ClockWidget w = (ClockWidget) gw; 1156#ifdef notdef 1157 *valueMask |= CWBitGravity; 1158 attrs->bit_gravity = ForgetGravity; 1159#endif 1160 switch (w->clock.backing_store) { 1161 case Always: 1162 case NotUseful: 1163 case WhenMapped: 1164 *valueMask |=CWBackingStore; 1165 attrs->backing_store = w->clock.backing_store; 1166 break; 1167 } 1168 (*clockWidgetClass->core_class.superclass->core_class.realize) 1169 (gw, valueMask, attrs); 1170 Resize(gw); 1171} 1172 1173static void 1174Destroy(Widget gw) 1175{ 1176 ClockWidget w = (ClockWidget) gw; 1177 if (w->clock.interval_id) XtRemoveTimeOut (w->clock.interval_id); 1178#ifdef XRENDER 1179 if (w->clock.picture) 1180 XRenderFreePicture (XtDisplay(w), w->clock.picture); 1181 if (w->clock.fill_picture) 1182 XRenderFreePicture (XtDisplay(w), w->clock.fill_picture); 1183#endif 1184 XtReleaseGC (gw, w->clock.myGC); 1185 XtReleaseGC (gw, w->clock.HighGC); 1186 XtReleaseGC (gw, w->clock.HandGC); 1187 XtReleaseGC (gw, w->clock.EraseGC); 1188} 1189 1190static void 1191Resize(Widget gw) 1192{ 1193 ClockWidget w = (ClockWidget) gw; 1194 /* don't do this computation if window hasn't been realized yet. */ 1195 if (XtIsRealized(gw) && w->clock.analog) { 1196 /* need signed value since Dimension is unsigned */ 1197 int radius = ((int) min(w->core.width, w->core.height) - (int) (2 * w->clock.padding)) / 2; 1198 w->clock.radius = (Dimension) max (radius, 1); 1199 1200 w->clock.second_hand_length = (int)(SECOND_HAND_FRACT * w->clock.radius) / 100; 1201 w->clock.minute_hand_length = (int)(MINUTE_HAND_FRACT * w->clock.radius) / 100; 1202 w->clock.hour_hand_length = (int)(HOUR_HAND_FRACT * w->clock.radius) / 100; 1203 w->clock.hand_width = (int)(HAND_WIDTH_FRACT * w->clock.radius) / 100; 1204 w->clock.second_hand_width = (int)(SECOND_WIDTH_FRACT * w->clock.radius) / 100; 1205 1206 w->clock.centerX = w->core.width / 2; 1207 w->clock.centerY = w->core.height / 2; 1208 } 1209#ifdef XRENDER 1210 w->clock.x_scale = 0.45 * w->core.width; 1211 w->clock.y_scale = 0.45 * w->core.height; 1212 w->clock.x_off = 0.5 * w->core.width; 1213 w->clock.y_off = 0.5 * w->core.height; 1214 if (w->clock.pixmap) 1215 { 1216 XFreePixmap (XtDisplay (w), w->clock.pixmap); 1217 w->clock.pixmap = 0; 1218 if (w->clock.draw) 1219 { 1220 XftDrawDestroy (w->clock.draw); 1221 w->clock.draw = 0; 1222 } 1223 w->clock.picture = 0; 1224 } 1225#endif 1226} 1227 1228/* ARGSUSED */ 1229static void 1230Redisplay(Widget gw, XEvent *event, Region region) 1231{ 1232 ClockWidget w = (ClockWidget) gw; 1233 if (w->clock.analog) { 1234#ifdef XRENDER 1235 if (w->clock.render && w->clock.can_polygon) 1236 XClipBox (region, &w->clock.damage); 1237 else 1238#endif 1239 { 1240 if (w->clock.numseg != 0) 1241 erase_hands (w, (struct tm *) 0); 1242 DrawClockFace(w); 1243 } 1244 } else { 1245#ifdef XRENDER 1246 if (w->clock.render) 1247 XClipBox (region, &w->clock.damage); 1248#endif 1249 w->clock.prev_time_string[0] = '\0'; 1250 } 1251 clock_tic((XtPointer)w, (XtIntervalId *)NULL); 1252} 1253 1254/* ARGSUSED */ 1255static void 1256clock_tic(XtPointer client_data, XtIntervalId *id) 1257{ 1258 ClockWidget w = (ClockWidget)client_data; 1259 struct tm tm; 1260 Time_t time_value; 1261 struct timeval tv; 1262 char *time_ptr; 1263 register Display *dpy = XtDisplay(w); 1264 register Window win = XtWindow(w); 1265 1266 X_GETTIMEOFDAY (&tv); 1267 if (id || !w->clock.interval_id) 1268 w->clock.interval_id = 1269 XtAppAddTimeOut( XtWidgetToApplicationContext( (Widget) w), 1270 (w->clock.update - 1) * 1000 + (1000000 - tv.tv_usec)/1000, clock_tic, (XtPointer)w ); 1271 time_value = tv.tv_sec; 1272 tm = *localtime(&time_value); 1273 /* 1274 * Beep on the half hour; double-beep on the hour. 1275 */ 1276 if (w->clock.chime == TRUE) { 1277 if (w->clock.beeped && (tm.tm_min != 30) && 1278 (tm.tm_min != 0)) 1279 w->clock.beeped = FALSE; 1280 if (((tm.tm_min == 30) || (tm.tm_min == 0)) 1281 && (!w->clock.beeped)) { 1282 w->clock.beeped = TRUE; 1283#ifdef XKB 1284 if (tm.tm_min==0) { 1285 XkbStdBell(dpy,win,50,XkbBI_ClockChimeHour); 1286 XkbStdBell(dpy,win,50,XkbBI_RepeatingLastBell); 1287 } 1288 else { 1289 XkbStdBell(dpy,win,50,XkbBI_ClockChimeHalf); 1290 } 1291#else 1292 XBell(dpy, 50); 1293 if (tm.tm_min == 0) 1294 XBell(dpy, 50); 1295#endif 1296 } 1297 } 1298 if( w->clock.analog == FALSE ) { 1299 int clear_from = w->core.width; 1300 int i, len, prev_len; 1301 1302 time_ptr = TimeString (w, &tm); 1303 len = strlen (time_ptr); 1304 if (time_ptr[len - 1] == '\n') time_ptr[--len] = '\0'; 1305 prev_len = strlen (w->clock.prev_time_string); 1306 for (i = 0; ((i < len) && (i < prev_len) && 1307 (w->clock.prev_time_string[i] == time_ptr[i])); i++); 1308 1309#ifdef XRENDER 1310 if (w->clock.render) 1311 { 1312 XRectangle old_tail, new_tail, head; 1313 int x, y; 1314#if !defined(NO_I18N) && defined(HAVE_ICONV) 1315 char *utf8_str; 1316#endif 1317 1318 RenderTextBounds (w, w->clock.prev_time_string, i, prev_len, 1319 &old_tail, 0, 0); 1320 RenderUpdateRectBounds (&old_tail, &w->clock.damage); 1321 RenderTextBounds (w, time_ptr, i, len, 1322 &new_tail, 0, 0); 1323 RenderUpdateRectBounds (&new_tail, &w->clock.damage); 1324 1325 while (i) 1326 { 1327 RenderTextBounds (w, time_ptr, 0, i, &head, 0, 0); 1328 if (!RenderRectIn (&head, &w->clock.damage)) 1329 break; 1330 i--; 1331 } 1332 RenderTextBounds (w, time_ptr, i, len, &new_tail, &x, &y); 1333 RenderClip (w); 1334 RenderPrepare (w, 0); 1335#ifndef NO_I18N 1336 if (w->clock.utf8) { 1337 XftDrawStringUtf8 (w->clock.draw, 1338 &w->clock.fg_color, 1339 w->clock.face, 1340 x, y, 1341 (FcChar8 *) time_ptr + i, len - i); 1342 1343 } 1344# ifdef HAVE_ICONV 1345 else if ((utf8_str = 1346 clock_to_utf8(time_ptr + i)) != NULL) { 1347 XftDrawStringUtf8 (w->clock.draw, 1348 &w->clock.fg_color, 1349 w->clock.face, 1350 x, y, 1351 (FcChar8 *)utf8_str, strlen(utf8_str) - i); 1352 free(utf8_str); 1353 } 1354# endif 1355 else 1356#endif 1357 { 1358 XftDrawString8 (w->clock.draw, 1359 &w->clock.fg_color, 1360 w->clock.face, 1361 x, y, 1362 (FcChar8 *) time_ptr + i, len - i); 1363 } 1364 RenderUpdate (w); 1365 RenderResetBounds (&w->clock.damage); 1366 } 1367 else 1368#endif 1369#ifndef NO_I18N 1370 if(!no_locale) { 1371 if(0 < len) { 1372 XFontSetExtents *fse 1373 = XExtentsOfFontSet(w->clock.fontSet); 1374 1375 XmbDrawImageString(dpy,win,w->clock.fontSet,w->clock.myGC, 1376 (2+w->clock.padding + 1377 (i?XmbTextEscapement(w->clock.fontSet, 1378 time_ptr,i):0)), 1379 2+w->clock.padding+fse->max_logical_extent.height, 1380 time_ptr+i,len-i 1381 ); 1382 /* 1383 * Clear any left over bits 1384 */ 1385 clear_from = XmbTextEscapement (w->clock.fontSet,time_ptr, 1386 len) + 2+w->clock.padding; 1387 } 1388 } else 1389#endif /* NO_I18N */ 1390 { 1391 XDrawImageString (dpy, win, w->clock.myGC, 1392 (1+w->clock.padding + 1393 XTextWidth (w->clock.font, time_ptr, i)), 1394 w->clock.font->ascent+w->clock.padding, 1395 time_ptr + i, len - i); 1396 /* 1397 * Clear any left over bits 1398 */ 1399 clear_from = XTextWidth (w->clock.font, time_ptr, len) 1400 + 2 + w->clock.padding; 1401 } 1402 if (clear_from < (int)w->core.width) 1403 XClearArea (dpy, win, 1404 clear_from, 0, w->core.width - clear_from, w->core.height, 1405 False); 1406#if defined(HAS_STRLCAT) || defined(HAVE_STRLCPY) 1407 strlcpy (w->clock.prev_time_string+i, time_ptr+i, 1408 sizeof(w->clock.prev_time_string)-i); 1409#else 1410 strncpy (w->clock.prev_time_string+i, time_ptr+i, 1411 sizeof(w->clock.prev_time_string)-i); 1412 w->clock.prev_time_string[sizeof(w->clock.prev_time_string)-1] = 0; 1413#endif 1414 } else { 1415 /* 1416 * The second (or minute) hand is sec (or min) 1417 * sixtieths around the clock face. The hour hand is 1418 * (hour + min/60) twelfths of the way around the 1419 * clock-face. The derivation is left as an excercise 1420 * for the reader. 1421 */ 1422 1423 /* 1424 * 12 hour clock. 1425 */ 1426 if(tm.tm_hour >= 12) 1427 tm.tm_hour -= 12; 1428 1429#ifdef XRENDER 1430 if (w->clock.render && w->clock.can_polygon) 1431 { 1432 w->clock.mask_format = XRenderFindStandardFormat (XtDisplay (w), 1433 w->clock.sharp ? 1434 PictStandardA1 : 1435 PictStandardA8); 1436 /* 1437 * Compute repaint area 1438 */ 1439 if (tm.tm_min != w->clock.otm.tm_min || 1440 tm.tm_hour != w->clock.otm.tm_hour || 1441 tm.tm_sec != w->clock.otm.tm_sec) 1442 { 1443 RenderHands (w, &w->clock.otm, False); 1444 RenderHands (w, &tm, False); 1445 } 1446 if (w->clock.show_second_hand && 1447 tm.tm_sec != w->clock.otm.tm_sec) 1448 { 1449 RenderSec (w, &w->clock.otm, False); 1450 RenderSec (w, &tm, False); 1451 } 1452 if (w->clock.damage.width && 1453 w->clock.damage.height) 1454 { 1455 RenderClip (w); 1456 DrawClockFace (w); 1457 RenderHands (w, &tm, True); 1458 if (w->clock.show_second_hand == TRUE) 1459 RenderSec (w, &tm, True); 1460 } 1461 w->clock.otm = tm; 1462 RenderUpdate (w); 1463 RenderResetBounds (&w->clock.damage); 1464 return; 1465 } 1466#endif 1467 1468 erase_hands (w, &tm); 1469 1470 if (w->clock.numseg == 0 || 1471 tm.tm_min != w->clock.otm.tm_min || 1472 tm.tm_hour != w->clock.otm.tm_hour) { 1473 w->clock.segbuffptr = w->clock.segbuff; 1474 w->clock.numseg = 0; 1475 /* 1476 * Calculate the hour hand, fill it in with its 1477 * color and then outline it. Next, do the same 1478 * with the minute hand. This is a cheap hidden 1479 * line algorithm. 1480 */ 1481 DrawHand(w, 1482 w->clock.minute_hand_length, w->clock.hand_width, 1483 tm.tm_min * 60 1484 ); 1485 if(w->clock.Hdpixel != w->core.background_pixel) 1486 XFillPolygon( dpy, 1487 win, w->clock.HandGC, 1488 w->clock.segbuff, VERTICES_IN_HANDS, 1489 Convex, CoordModeOrigin 1490 ); 1491 XDrawLines( dpy, 1492 win, w->clock.HighGC, 1493 w->clock.segbuff, VERTICES_IN_HANDS, 1494 CoordModeOrigin); 1495 w->clock.hour = w->clock.segbuffptr; 1496 DrawHand(w, 1497 w->clock.hour_hand_length, w->clock.hand_width, 1498 tm.tm_hour * 300 + tm.tm_min * 5 1499 ); 1500 if(w->clock.Hdpixel != w->core.background_pixel) { 1501 XFillPolygon(dpy, 1502 win, w->clock.HandGC, 1503 w->clock.hour, 1504 VERTICES_IN_HANDS, 1505 Convex, CoordModeOrigin 1506 ); 1507 } 1508 XDrawLines( dpy, 1509 win, w->clock.HighGC, 1510 w->clock.hour, VERTICES_IN_HANDS, 1511 CoordModeOrigin ); 1512 1513 w->clock.sec = w->clock.segbuffptr; 1514 } 1515 if (w->clock.show_second_hand == TRUE) { 1516 w->clock.segbuffptr = w->clock.sec; 1517 DrawSecond(w, 1518 w->clock.second_hand_length - 2, 1519 w->clock.second_hand_width, 1520 w->clock.minute_hand_length + 2, 1521 tm.tm_sec * 60 1522 ); 1523 if(w->clock.Hdpixel != w->core.background_pixel) 1524 XFillPolygon( dpy, 1525 win, w->clock.HandGC, 1526 w->clock.sec, 1527 VERTICES_IN_HANDS -2, 1528 Convex, CoordModeOrigin 1529 ); 1530 XDrawLines( dpy, 1531 win, w->clock.HighGC, 1532 w->clock.sec, 1533 VERTICES_IN_HANDS-1, 1534 CoordModeOrigin 1535 ); 1536 1537 } 1538 w->clock.otm = tm; 1539 } 1540} 1541 1542static void 1543erase_hands(ClockWidget w, struct tm *tm) 1544{ 1545 /* 1546 * Erase old hands. 1547 */ 1548 if(w->clock.numseg > 0) { 1549 Display *dpy; 1550 Window win; 1551 1552 dpy = XtDisplay (w); 1553 win = XtWindow (w); 1554 if (w->clock.show_second_hand == TRUE) { 1555 XDrawLines(dpy, win, 1556 w->clock.EraseGC, 1557 w->clock.sec, 1558 VERTICES_IN_HANDS-1, 1559 CoordModeOrigin); 1560 if(w->clock.Hdpixel != w->core.background_pixel) { 1561 XFillPolygon(dpy, 1562 win, w->clock.EraseGC, 1563 w->clock.sec, 1564 VERTICES_IN_HANDS-2, 1565 Convex, CoordModeOrigin 1566 ); 1567 } 1568 } 1569 if(!tm || tm->tm_min != w->clock.otm.tm_min || 1570 tm->tm_hour != w->clock.otm.tm_hour) 1571 { 1572 XDrawLines( dpy, win, 1573 w->clock.EraseGC, 1574 w->clock.segbuff, 1575 VERTICES_IN_HANDS, 1576 CoordModeOrigin); 1577 XDrawLines( dpy, win, 1578 w->clock.EraseGC, 1579 w->clock.hour, 1580 VERTICES_IN_HANDS, 1581 CoordModeOrigin); 1582 if(w->clock.Hdpixel != w->core.background_pixel) { 1583 XFillPolygon( dpy, win, 1584 w->clock.EraseGC, 1585 w->clock.segbuff, VERTICES_IN_HANDS, 1586 Convex, CoordModeOrigin); 1587 XFillPolygon( dpy, win, 1588 w->clock.EraseGC, 1589 w->clock.hour, 1590 VERTICES_IN_HANDS, 1591 Convex, CoordModeOrigin); 1592 } 1593 } 1594 } 1595} 1596 1597static float const Sines[] = { 15980.000000, 0.001745, 0.003490, 0.005235, 0.006981, 0.008726, 0.010471, 0.012217, 15990.013962, 0.015707, 0.017452, 0.019197, 0.020942, 0.022687, 0.024432, 0.026176, 16000.027921, 0.029666, 0.031410, 0.033155, 0.034899, 0.036643, 0.038387, 0.040131, 16010.041875, 0.043619, 0.045362, 0.047106, 0.048849, 0.050592, 0.052335, 0.054078, 16020.055821, 0.057564, 0.059306, 0.061048, 0.062790, 0.064532, 0.066273, 0.068015, 16030.069756, 0.071497, 0.073238, 0.074978, 0.076719, 0.078459, 0.080198, 0.081938, 16040.083677, 0.085416, 0.087155, 0.088894, 0.090632, 0.092370, 0.094108, 0.095845, 16050.097582, 0.099319, 0.101056, 0.102792, 0.104528, 0.106264, 0.107999, 0.109734, 16060.111468, 0.113203, 0.114937, 0.116670, 0.118403, 0.120136, 0.121869, 0.123601, 16070.125333, 0.127064, 0.128795, 0.130526, 0.132256, 0.133986, 0.135715, 0.137444, 16080.139173, 0.140901, 0.142628, 0.144356, 0.146083, 0.147809, 0.149535, 0.151260, 16090.152985, 0.154710, 0.156434, 0.158158, 0.159881, 0.161603, 0.163325, 0.165047, 16100.166768, 0.168489, 0.170209, 0.171929, 0.173648, 0.175366, 0.177084, 0.178802, 16110.180519, 0.182235, 0.183951, 0.185666, 0.187381, 0.189095, 0.190808, 0.192521, 16120.194234, 0.195946, 0.197657, 0.199367, 0.201077, 0.202787, 0.204496, 0.206204, 16130.207911, 0.209618, 0.211324, 0.213030, 0.214735, 0.216439, 0.218143, 0.219846, 16140.221548, 0.223250, 0.224951, 0.226651, 0.228350, 0.230049, 0.231747, 0.233445, 16150.235142, 0.236838, 0.238533, 0.240228, 0.241921, 0.243615, 0.245307, 0.246999, 16160.248689, 0.250380, 0.252069, 0.253757, 0.255445, 0.257132, 0.258819, 0.260504, 16170.262189, 0.263873, 0.265556, 0.267238, 0.268919, 0.270600, 0.272280, 0.273959, 16180.275637, 0.277314, 0.278991, 0.280666, 0.282341, 0.284015, 0.285688, 0.287360, 16190.289031, 0.290702, 0.292371, 0.294040, 0.295708, 0.297374, 0.299040, 0.300705, 16200.302369, 0.304033, 0.305695, 0.307356, 0.309016, 0.310676, 0.312334, 0.313992, 16210.315649, 0.317304, 0.318959, 0.320612, 0.322265, 0.323917, 0.325568, 0.327217, 16220.328866, 0.330514, 0.332161, 0.333806, 0.335451, 0.337095, 0.338737, 0.340379, 16230.342020, 0.343659, 0.345298, 0.346935, 0.348572, 0.350207, 0.351841, 0.353474, 16240.355106, 0.356737, 0.358367, 0.359996, 0.361624, 0.363251, 0.364876, 0.366501, 16250.368124, 0.369746, 0.371367, 0.372987, 0.374606, 0.376224, 0.377840, 0.379456, 16260.381070, 0.382683, 0.384295, 0.385906, 0.387515, 0.389123, 0.390731, 0.392337, 16270.393941, 0.395545, 0.397147, 0.398749, 0.400349, 0.401947, 0.403545, 0.405141, 16280.406736, 0.408330, 0.409923, 0.411514, 0.413104, 0.414693, 0.416280, 0.417867, 16290.419452, 0.421035, 0.422618, 0.424199, 0.425779, 0.427357, 0.428935, 0.430511, 16300.432085, 0.433659, 0.435231, 0.436801, 0.438371, 0.439939, 0.441505, 0.443071, 16310.444635, 0.446197, 0.447759, 0.449318, 0.450877, 0.452434, 0.453990, 0.455544, 16320.457097, 0.458649, 0.460199, 0.461748, 0.463296, 0.464842, 0.466386, 0.467929, 16330.469471, 0.471011, 0.472550, 0.474088, 0.475624, 0.477158, 0.478691, 0.480223, 16340.481753, 0.483282, 0.484809, 0.486335, 0.487859, 0.489382, 0.490903, 0.492423, 16350.493941, 0.495458, 0.496973, 0.498487, 0.499999, 0.501510, 0.503019, 0.504527, 16360.506033, 0.507538, 0.509041, 0.510542, 0.512042, 0.513541, 0.515038, 0.516533, 16370.518027, 0.519519, 0.521009, 0.522498, 0.523985, 0.525471, 0.526955, 0.528438, 16380.529919, 0.531398, 0.532876, 0.534352, 0.535826, 0.537299, 0.538770, 0.540240, 16390.541708, 0.543174, 0.544639, 0.546101, 0.547563, 0.549022, 0.550480, 0.551936, 16400.553391, 0.554844, 0.556295, 0.557745, 0.559192, 0.560638, 0.562083, 0.563526, 16410.564967, 0.566406, 0.567843, 0.569279, 0.570713, 0.572145, 0.573576, 0.575005, 16420.576432, 0.577857, 0.579281, 0.580702, 0.582122, 0.583541, 0.584957, 0.586372, 16430.587785, 0.589196, 0.590605, 0.592013, 0.593418, 0.594822, 0.596224, 0.597625, 16440.599023, 0.600420, 0.601815, 0.603207, 0.604599, 0.605988, 0.607375, 0.608761, 16450.610145, 0.611527, 0.612907, 0.614285, 0.615661, 0.617035, 0.618408, 0.619779, 16460.621147, 0.622514, 0.623879, 0.625242, 0.626603, 0.627963, 0.629320, 0.630675, 16470.632029, 0.633380, 0.634730, 0.636078, 0.637423, 0.638767, 0.640109, 0.641449, 16480.642787, 0.644123, 0.645457, 0.646789, 0.648119, 0.649448, 0.650774, 0.652098, 16490.653420, 0.654740, 0.656059, 0.657375, 0.658689, 0.660001, 0.661311, 0.662620, 16500.663926, 0.665230, 0.666532, 0.667832, 0.669130, 0.670426, 0.671720, 0.673012, 16510.674302, 0.675590, 0.676875, 0.678159, 0.679441, 0.680720, 0.681998, 0.683273, 16520.684547, 0.685818, 0.687087, 0.688354, 0.689619, 0.690882, 0.692143, 0.693401, 16530.694658, 0.695912, 0.697165, 0.698415, 0.699663, 0.700909, 0.702153, 0.703394, 16540.704634, 0.705871, 0.707106, 1655}; 1656static float const Cosines[] = { 16571.000000, 0.999998, 0.999993, 0.999986, 0.999975, 0.999961, 0.999945, 0.999925, 16580.999902, 0.999876, 0.999847, 0.999815, 0.999780, 0.999742, 0.999701, 0.999657, 16590.999610, 0.999559, 0.999506, 0.999450, 0.999390, 0.999328, 0.999262, 0.999194, 16600.999122, 0.999048, 0.998970, 0.998889, 0.998806, 0.998719, 0.998629, 0.998536, 16610.998440, 0.998341, 0.998239, 0.998134, 0.998026, 0.997915, 0.997801, 0.997684, 16620.997564, 0.997440, 0.997314, 0.997185, 0.997052, 0.996917, 0.996778, 0.996637, 16630.996492, 0.996345, 0.996194, 0.996041, 0.995884, 0.995724, 0.995561, 0.995396, 16640.995227, 0.995055, 0.994880, 0.994702, 0.994521, 0.994337, 0.994150, 0.993960, 16650.993767, 0.993571, 0.993372, 0.993170, 0.992965, 0.992757, 0.992546, 0.992331, 16660.992114, 0.991894, 0.991671, 0.991444, 0.991215, 0.990983, 0.990747, 0.990509, 16670.990268, 0.990023, 0.989776, 0.989525, 0.989272, 0.989015, 0.988756, 0.988493, 16680.988228, 0.987959, 0.987688, 0.987413, 0.987136, 0.986855, 0.986572, 0.986285, 16690.985996, 0.985703, 0.985407, 0.985109, 0.984807, 0.984503, 0.984195, 0.983885, 16700.983571, 0.983254, 0.982935, 0.982612, 0.982287, 0.981958, 0.981627, 0.981292, 16710.980955, 0.980614, 0.980271, 0.979924, 0.979575, 0.979222, 0.978867, 0.978508, 16720.978147, 0.977783, 0.977415, 0.977045, 0.976672, 0.976296, 0.975916, 0.975534, 16730.975149, 0.974761, 0.974370, 0.973975, 0.973578, 0.973178, 0.972775, 0.972369, 16740.971961, 0.971549, 0.971134, 0.970716, 0.970295, 0.969872, 0.969445, 0.969015, 16750.968583, 0.968147, 0.967709, 0.967267, 0.966823, 0.966376, 0.965925, 0.965472, 16760.965016, 0.964557, 0.964095, 0.963630, 0.963162, 0.962691, 0.962217, 0.961741, 16770.961261, 0.960779, 0.960293, 0.959805, 0.959313, 0.958819, 0.958322, 0.957822, 16780.957319, 0.956813, 0.956304, 0.955793, 0.955278, 0.954760, 0.954240, 0.953716, 16790.953190, 0.952661, 0.952129, 0.951594, 0.951056, 0.950515, 0.949972, 0.949425, 16800.948876, 0.948323, 0.947768, 0.947210, 0.946649, 0.946085, 0.945518, 0.944948, 16810.944376, 0.943800, 0.943222, 0.942641, 0.942057, 0.941470, 0.940880, 0.940288, 16820.939692, 0.939094, 0.938493, 0.937888, 0.937281, 0.936672, 0.936059, 0.935444, 16830.934825, 0.934204, 0.933580, 0.932953, 0.932323, 0.931691, 0.931055, 0.930417, 16840.929776, 0.929132, 0.928485, 0.927836, 0.927183, 0.926528, 0.925870, 0.925209, 16850.924546, 0.923879, 0.923210, 0.922538, 0.921863, 0.921185, 0.920504, 0.919821, 16860.919135, 0.918446, 0.917754, 0.917060, 0.916362, 0.915662, 0.914959, 0.914253, 16870.913545, 0.912834, 0.912120, 0.911403, 0.910683, 0.909961, 0.909236, 0.908508, 16880.907777, 0.907044, 0.906307, 0.905568, 0.904827, 0.904082, 0.903335, 0.902585, 16890.901832, 0.901077, 0.900318, 0.899557, 0.898794, 0.898027, 0.897258, 0.896486, 16900.895711, 0.894934, 0.894154, 0.893371, 0.892585, 0.891797, 0.891006, 0.890212, 16910.889416, 0.888617, 0.887815, 0.887010, 0.886203, 0.885393, 0.884580, 0.883765, 16920.882947, 0.882126, 0.881303, 0.880477, 0.879648, 0.878817, 0.877982, 0.877146, 16930.876306, 0.875464, 0.874619, 0.873772, 0.872922, 0.872069, 0.871213, 0.870355, 16940.869494, 0.868631, 0.867765, 0.866896, 0.866025, 0.865151, 0.864274, 0.863395, 16950.862513, 0.861629, 0.860742, 0.859852, 0.858959, 0.858064, 0.857167, 0.856267, 16960.855364, 0.854458, 0.853550, 0.852640, 0.851726, 0.850811, 0.849892, 0.848971, 16970.848048, 0.847121, 0.846193, 0.845261, 0.844327, 0.843391, 0.842452, 0.841510, 16980.840566, 0.839619, 0.838670, 0.837718, 0.836764, 0.835807, 0.834847, 0.833885, 16990.832921, 0.831954, 0.830984, 0.830012, 0.829037, 0.828060, 0.827080, 0.826098, 17000.825113, 0.824126, 0.823136, 0.822144, 0.821149, 0.820151, 0.819152, 0.818149, 17010.817144, 0.816137, 0.815127, 0.814115, 0.813100, 0.812083, 0.811063, 0.810041, 17020.809016, 0.807989, 0.806960, 0.805928, 0.804893, 0.803856, 0.802817, 0.801775, 17030.800731, 0.799684, 0.798635, 0.797583, 0.796529, 0.795473, 0.794414, 0.793353, 17040.792289, 0.791223, 0.790155, 0.789084, 0.788010, 0.786935, 0.785856, 0.784776, 17050.783693, 0.782608, 0.781520, 0.780430, 0.779337, 0.778243, 0.777145, 0.776046, 17060.774944, 0.773840, 0.772733, 0.771624, 0.770513, 0.769399, 0.768283, 0.767165, 17070.766044, 0.764921, 0.763796, 0.762668, 0.761538, 0.760405, 0.759271, 0.758134, 17080.756995, 0.755853, 0.754709, 0.753563, 0.752414, 0.751264, 0.750111, 0.748955, 17090.747798, 0.746638, 0.745475, 0.744311, 0.743144, 0.741975, 0.740804, 0.739631, 17100.738455, 0.737277, 0.736097, 0.734914, 0.733729, 0.732542, 0.731353, 0.730162, 17110.728968, 0.727772, 0.726574, 0.725374, 0.724171, 0.722967, 0.721760, 0.720551, 17120.719339, 0.718126, 0.716910, 0.715692, 0.714472, 0.713250, 0.712026, 0.710799, 17130.709570, 0.708339, 0.707106, 1714}; 1715 1716static void 1717ClockAngle(int tick_units, double *sinp, double *cosp) 1718{ 1719 int reduced, upper; 1720 1721 reduced = tick_units % 450; 1722 upper = tick_units / 450; 1723 if (upper & 1) 1724 reduced = 450 - reduced; 1725 if ((upper + 1) & 2) { 1726 *sinp = Cosines[reduced]; 1727 *cosp = Sines[reduced]; 1728 } else { 1729 *sinp = Sines[reduced]; 1730 *cosp = Cosines[reduced]; 1731 } 1732 if (upper >= 2 && upper < 6) 1733 *cosp = -*cosp; 1734 if (upper >= 4) 1735 *sinp = -*sinp; 1736} 1737 1738/* 1739 * DrawLine - Draws a line. 1740 * 1741 * blank_length is the distance from the center which the line begins. 1742 * length is the maximum length of the hand. 1743 * Tick_units is a number between zero and 12*60 indicating 1744 * how far around the circle (clockwise) from high noon. 1745 * 1746 * The blank_length feature is because I wanted to draw tick-marks around the 1747 * circle (for seconds). The obvious means of drawing lines from the center 1748 * to the perimeter, then erasing all but the outside most pixels doesn't 1749 * work because of round-off error (sigh). 1750 */ 1751static void 1752DrawLine(ClockWidget w, Dimension blank_length, Dimension length, 1753 int tick_units) 1754{ 1755 double dblank_length = (double)blank_length, dlength = (double)length; 1756 double cosangle, sinangle; 1757 int cx = w->clock.centerX, cy = w->clock.centerY, x1, y1, x2, y2; 1758 1759 /* 1760 * Angles are measured from 12 o'clock, clockwise increasing. 1761 * Since in X, +x is to the right and +y is downward: 1762 * 1763 * x = x0 + r * sin(theta) 1764 * y = y0 - r * cos(theta) 1765 * 1766 */ 1767 ClockAngle(tick_units, &sinangle, &cosangle); 1768 1769 /* break this out so that stupid compilers can cope */ 1770 x1 = cx + (int)(dblank_length * sinangle); 1771 y1 = cy - (int)(dblank_length * cosangle); 1772 x2 = cx + (int)(dlength * sinangle); 1773 y2 = cy - (int)(dlength * cosangle); 1774 SetSeg(w, x1, y1, x2, y2); 1775} 1776 1777/* 1778 * DrawHand - Draws a hand. 1779 * 1780 * length is the maximum length of the hand. 1781 * width is the half-width of the hand. 1782 * Tick_units is a number between zero and 12*60 indicating 1783 * how far around the circle (clockwise) from high noon. 1784 * 1785 */ 1786static void 1787DrawHand(ClockWidget w, Dimension length, Dimension width, int tick_units) 1788{ 1789 1790 double cosangle, sinangle; 1791 register double ws, wc; 1792 Position x, y, x1, y1, x2, y2; 1793 1794 /* 1795 * Angles are measured from 12 o'clock, clockwise increasing. 1796 * Since in X, +x is to the right and +y is downward: 1797 * 1798 * x = x0 + r * sin(theta) 1799 * y = y0 - r * cos(theta) 1800 * 1801 */ 1802 ClockAngle(tick_units, &sinangle, &cosangle); 1803 /* 1804 * Order of points when drawing the hand. 1805 * 1806 * 1,4 1807 * / \ 1808 * / \ 1809 * / \ 1810 * 2 ------- 3 1811 */ 1812 wc = width * cosangle; 1813 ws = width * sinangle; 1814 SetSeg(w, 1815 x = w->clock.centerX + clock_round(length * sinangle), 1816 y = w->clock.centerY - clock_round(length * cosangle), 1817 x1 = w->clock.centerX - clock_round(ws + wc), 1818 y1 = w->clock.centerY + clock_round(wc - ws)); /* 1 ---- 2 */ 1819 /* 2 */ 1820 SetSeg(w, x1, y1, 1821 x2 = w->clock.centerX - clock_round(ws - wc), 1822 y2 = w->clock.centerY + clock_round(wc + ws)); /* 2 ----- 3 */ 1823 1824 SetSeg(w, x2, y2, x, y); /* 3 ----- 1(4) */ 1825} 1826 1827/* 1828 * DrawSecond - Draws the second hand (diamond). 1829 * 1830 * length is the maximum length of the hand. 1831 * width is the half-width of the hand. 1832 * offset is direct distance from center to tail end. 1833 * Tick_units is a number between zero and 12*60 indicating 1834 * how far around the circle (clockwise) from high noon. 1835 * 1836 */ 1837static void 1838DrawSecond(ClockWidget w, Dimension length, Dimension width, 1839 Dimension offset, int tick_units) 1840{ 1841 1842 double cosangle, sinangle; 1843 register double ms, mc, ws, wc; 1844 register int mid; 1845 Position x, y; 1846 1847 /* 1848 * Angles are measured from 12 o'clock, clockwise increasing. 1849 * Since in X, +x is to the right and +y is downward: 1850 * 1851 * x = x0 + r * sin(theta) 1852 * y = y0 - r * cos(theta) 1853 * 1854 */ 1855 ClockAngle(tick_units, &sinangle, &cosangle); 1856 /* 1857 * Order of points when drawing the hand. 1858 * 1859 * 1,5 1860 * / \ 1861 * / \ 1862 * / \ 1863 * 2< >4 1864 * \ / 1865 * \ / 1866 * \ / 1867 * - 3 1868 * | 1869 * | 1870 * offset 1871 * | 1872 * | 1873 * - + center 1874 */ 1875 1876 mid = (int) (length + offset) / 2; 1877 mc = mid * cosangle; 1878 ms = mid * sinangle; 1879 wc = width * cosangle; 1880 ws = width * sinangle; 1881 /*1 ---- 2 */ 1882 SetSeg(w, 1883 x = w->clock.centerX + clock_round(length * sinangle), 1884 y = w->clock.centerY - clock_round(length * cosangle), 1885 w->clock.centerX + clock_round(ms - wc), 1886 w->clock.centerY - clock_round(mc + ws) ); 1887 SetSeg(w, w->clock.centerX + clock_round(offset *sinangle), 1888 w->clock.centerY - clock_round(offset * cosangle), /* 2-----3 */ 1889 w->clock.centerX + clock_round(ms + wc), 1890 w->clock.centerY - clock_round(mc - ws)); 1891 w->clock.segbuffptr->x = x; 1892 w->clock.segbuffptr++->y = y; 1893 w->clock.numseg ++; 1894} 1895 1896static void 1897SetSeg(ClockWidget w, int x1, int y1, int x2, int y2) 1898{ 1899 w->clock.segbuffptr->x = x1; 1900 w->clock.segbuffptr++->y = y1; 1901 w->clock.segbuffptr->x = x2; 1902 w->clock.segbuffptr++->y = y2; 1903 w->clock.numseg += 2; 1904} 1905 1906/* 1907 * Draw the clock face (every fifth tick-mark is longer 1908 * than the others). 1909 */ 1910static void 1911DrawClockFace(ClockWidget w) 1912{ 1913 register int i; 1914 register int delta = (int)(w->clock.radius - w->clock.second_hand_length) / 3; 1915 1916 w->clock.segbuffptr = w->clock.segbuff; 1917 w->clock.numseg = 0; 1918 for (i = 0; i < 60; i++) 1919 { 1920#ifdef XRENDER 1921 if (w->clock.render && w->clock.can_polygon) 1922 { 1923 double s, c; 1924 XDouble x1, y1, x2, y2; 1925 XftColor *color; 1926 ClockAngle (i * 60, &s, &c); 1927 x1 = c; 1928 y1 = s; 1929 if (i % 5) 1930 { 1931 x2 = c * (MINOR_TICK_FRACT / 100.0); 1932 y2 = s * (MINOR_TICK_FRACT / 100.0); 1933 color = &w->clock.minor_color; 1934 } 1935 else 1936 { 1937 x2 = c * (SECOND_HAND_FRACT / 100.0); 1938 y2 = s * (SECOND_HAND_FRACT / 100.0); 1939 color = &w->clock.major_color; 1940 } 1941 RenderLine (w, x1, y1, x2, y2, color, True); 1942 } 1943 else 1944#endif 1945 { 1946 DrawLine(w, ( (i % 5) == 0 ? 1947 w->clock.second_hand_length : 1948 (w->clock.radius - delta) ), 1949 w->clock.radius, i * 60); 1950 } 1951 } 1952#ifdef XRENDER 1953 if (w->clock.render && w->clock.can_polygon) 1954 return; 1955#endif 1956 /* 1957 * Go ahead and draw it. 1958 */ 1959 XDrawSegments(XtDisplay(w), XtWindow(w), 1960 w->clock.myGC, (XSegment *) &(w->clock.segbuff[0]), 1961 w->clock.numseg/2); 1962 1963 w->clock.segbuffptr = w->clock.segbuff; 1964 w->clock.numseg = 0; 1965} 1966 1967static int 1968clock_round(double x) 1969{ 1970 return(x >= 0.0 ? (int)(x + .5) : (int)(x - .5)); 1971} 1972 1973#ifdef XRENDER 1974static Boolean 1975sameColor (XftColor *old, XftColor *new) 1976{ 1977 if (old->color.red != new->color.red) return False; 1978 if (old->color.green != new->color.green) return False; 1979 if (old->color.blue != new->color.blue) return False; 1980 if (old->color.alpha != new->color.alpha) return False; 1981 return True; 1982} 1983#endif 1984 1985/* ARGSUSED */ 1986static Boolean 1987SetValues(Widget gcurrent, Widget grequest, Widget gnew, 1988 ArgList args, Cardinal *num_args) 1989{ 1990 ClockWidget current = (ClockWidget) gcurrent; 1991 ClockWidget new = (ClockWidget) gnew; 1992 Boolean redisplay = FALSE; 1993 XtGCMask valuemask; 1994 XGCValues myXGCV; 1995 1996 /* first check for changes to clock-specific resources. We'll accept all 1997 the changes, but may need to do some computations first. */ 1998 1999 if (new->clock.update != current->clock.update) { 2000 if (current->clock.interval_id) 2001 XtRemoveTimeOut (current->clock.interval_id); 2002 if (XtIsRealized( (Widget) new)) 2003 new->clock.interval_id = XtAppAddTimeOut( 2004 XtWidgetToApplicationContext(gnew), 2005 new->clock.update*1000, 2006 clock_tic, (XtPointer)gnew); 2007 2008 new->clock.show_second_hand =(new->clock.update <= SECOND_HAND_TIME); 2009 if (new->clock.show_second_hand != current->clock.show_second_hand) 2010 redisplay = TRUE; 2011 } 2012 2013 if (new->clock.padding != current->clock.padding) 2014 redisplay = TRUE; 2015 2016 if (new->clock.analog != current->clock.analog) 2017 redisplay = TRUE; 2018 2019 if (new->clock.font != current->clock.font) 2020 redisplay = TRUE; 2021 2022#ifndef NO_I18N 2023 if (new->clock.fontSet != current->clock.fontSet) 2024 redisplay = TRUE; 2025#endif 2026 2027 if ((ClockFgPixel(new) != ClockFgPixel (current)) 2028 || (new->core.background_pixel != current->core.background_pixel)) { 2029 valuemask = GCForeground | GCBackground | GCFont | GCLineWidth; 2030 myXGCV.foreground = ClockFgPixel (new); 2031 myXGCV.background = new->core.background_pixel; 2032 myXGCV.font = new->clock.font->fid; 2033 myXGCV.line_width = 0; 2034 XtReleaseGC (gcurrent, current->clock.myGC); 2035 new->clock.myGC = XtGetGC(gcurrent, valuemask, &myXGCV); 2036 redisplay = TRUE; 2037 } 2038 2039 if (new->clock.Hipixel != current->clock.Hipixel) { 2040 valuemask = GCForeground | GCLineWidth; 2041 myXGCV.foreground = new->clock.Hipixel; 2042 myXGCV.font = new->clock.font->fid; 2043 myXGCV.line_width = 0; 2044 XtReleaseGC (gcurrent, current->clock.HighGC); 2045 new->clock.HighGC = XtGetGC((Widget)gcurrent, valuemask, &myXGCV); 2046 redisplay = TRUE; 2047 } 2048 2049 if (new->clock.Hdpixel != current->clock.Hdpixel) { 2050 valuemask = GCForeground; 2051 myXGCV.foreground = new->clock.Hdpixel; 2052 XtReleaseGC (gcurrent, current->clock.HandGC); 2053 new->clock.HandGC = XtGetGC((Widget)gcurrent, valuemask, &myXGCV); 2054 redisplay = TRUE; 2055 } 2056 2057 if (new->core.background_pixel != current->core.background_pixel) { 2058 valuemask = GCForeground | GCLineWidth | GCGraphicsExposures; 2059 myXGCV.foreground = new->core.background_pixel; 2060 myXGCV.line_width = 0; 2061 myXGCV.graphics_exposures = False; 2062 XtReleaseGC (gcurrent, current->clock.EraseGC); 2063 new->clock.EraseGC = XtGetGC((Widget)gcurrent, valuemask, &myXGCV); 2064 redisplay = TRUE; 2065 } 2066#ifdef XRENDER 2067 if (new->clock.face != current->clock.face) 2068 redisplay = TRUE; 2069 if (!sameColor (&new->clock.hour_color, ¤t->clock.fg_color) || 2070 !sameColor (&new->clock.hour_color, ¤t->clock.hour_color) || 2071 !sameColor (&new->clock.min_color, ¤t->clock.min_color) || 2072 !sameColor (&new->clock.sec_color, ¤t->clock.sec_color) || 2073 !sameColor (&new->clock.major_color, ¤t->clock.major_color) || 2074 !sameColor (&new->clock.minor_color, ¤t->clock.minor_color)) 2075 redisplay = True; 2076 if (new->clock.sharp != current->clock.sharp) 2077 redisplay = True; 2078 if (new->clock.render != current->clock.render) 2079 redisplay = True; 2080 if (new->clock.buffer != current->clock.buffer) 2081 { 2082 if (new->clock.pixmap) 2083 { 2084 XFreePixmap (XtDisplay (new), new->clock.pixmap); 2085 new->clock.pixmap = 0; 2086 } 2087 if (new->clock.draw) 2088 { 2089 XftDrawDestroy (new->clock.draw); 2090 new->clock.draw = 0; 2091 } 2092 new->clock.picture = 0; 2093 } 2094#endif 2095 return (redisplay); 2096 2097} 2098 2099#if !defined(NO_I18N) && defined(HAVE_ICONV) 2100static char * 2101clock_to_utf8(const char *str) 2102{ 2103 iconv_t cd; 2104 char *buf; 2105 size_t in_len; 2106 size_t buf_size; 2107 size_t ileft, oleft; 2108 const char *inptr; 2109 char *outptr; 2110 size_t ret; 2111 const char *code_set = nl_langinfo(CODESET); 2112 2113 if (str == NULL ||code_set == NULL || strcasecmp(code_set, "646") == 0) 2114 return NULL; 2115 2116 if (strcasecmp(code_set, "UTF-8") == 0) 2117 return strdup(str); 2118 2119 cd = iconv_open("UTF-8", code_set); 2120 if (cd == (iconv_t)-1) 2121 return NULL; 2122 2123 in_len = strlen(str); 2124 buf_size = MB_LEN_MAX * (in_len + 1); 2125 if ((buf = malloc(buf_size)) == NULL) { 2126 (void) iconv_close(cd); 2127 return NULL; 2128 } 2129 2130 inptr = str; 2131 ileft = in_len; 2132 outptr = buf; 2133 oleft = buf_size; 2134 2135 ret = iconv(cd, &inptr, &ileft, &outptr, &oleft); 2136 if (ret == (size_t)(-1) || oleft == 0 ) { 2137 free(buf); 2138 buf = NULL; 2139 } else 2140 *outptr = '\0'; 2141 2142 (void) iconv_close(cd); 2143 return buf; 2144} 2145#endif 2146