|
|
1.1 root 1: /* $Header: Clock.c,v 1.3 87/09/12 12:42:42 swick Exp $ */
2: #ifndef lint
3: static char *sccsid = "@(#)Clock.c 1.0 2/25/87";
4: #endif lint
5:
6: /*
7: * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
8: *
9: * All Rights Reserved
10: *
11: * Permission to use, copy, modify, and distribute this software and its
12: * documentation for any purpose and without fee is hereby granted,
13: * provided that the above copyright notice appear in all copies and that
14: * both that copyright notice and this permission notice appear in
15: * supporting documentation, and that the name of Digital Equipment
16: * Corporation not be used in advertising or publicity pertaining to
17: * distribution of the software without specific, written prior permission.
18: *
19: * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
20: * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
21: * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
22: * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23: * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24: * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
25: * SOFTWARE.
26: */
27:
28:
29: #include <stdio.h>
30: #include <strings.h>
31: #include "Xlib.h"
32: #include "Xutil.h"
33: #include "Intrinsic.h"
34: #include "Clock.h"
35: #include "Atoms.h"
36: #include <sys/time.h>
37: #include <sys/file.h>
38: #include <sys/param.h>
39: #include <math.h>
40:
41: extern long time();
42:
43: /* Private Definitions */
44:
45:
46: #define VERTICES_IN_HANDS 6 /* to draw triangle */
47: #define PHI (PI / 16.) /* half angle of hand tip */
48: #define PI 3.14159265358979
49: #define PI4 (PI / 4.)
50: #define SINPHI 0.19509032201613
51: #define TWOPI (2. * PI)
52:
53: #define SEG_BUFF_SIZE 128
54:
55: #define SECOND_HAND_FRACT 90
56: #define MINUTE_HAND_FRACT 70
57: #define HOUR_HAND_FRACT 40
58: #define HAND_WIDTH_FRACT 7
59: #define SECOND_WIDTH_FRACT 5
60: #define SECOND_HAND_TIME 30
61:
62: #define DEF_UPDATE 60
63:
64: #define DEF_BORDER 2
65: #define DEF_VECTOR_HEIGHT 1
66: #define DEF_VECTOR_WIDTH 1
67:
68: #define DEF_DIGITAL_PADDING 10
69: #define DEF_DIGITAL_FONT "6x10"
70: #define DEF_ANALOG_PADDING 8
71: #define DEF_ANALOG_WIDTH 164
72: #define DEF_ANALOG_HEIGHT 164
73:
74: #define UNINIT -1
75: #define FAILURE 0
76:
77: #define max(a, b) ((a) > (b) ? (a) : (b))
78: #define min(a, b) ((a) < (b) ? (a) : (b))
79: #define abs(a) ((a) < 0 ? -(a) : (a))
80:
81:
82: typedef struct WidgetDataRec {
83: Display *dpy; /* widget display connection */
84: Window mywin; /* widget window */
85: Dimension brwidth; /* border width in pixels */
86: Dimension width, height; /* width/height in pixels */
87: Position x, y;
88: Pixel fgpixel; /* color index for text */
89: Pixel bgpixel; /* color index for background */
90: Pixel Hipixel; /* color index for Highlighting */
91: Pixel Hdpixel; /* color index for hands */
92: Pixel brpixel; /* pixel for border */
93: XFontStruct *fontstruct; /* font for text */
94: GC myGC; /* pointer to GraphicsContext */
95: GC EraseGC; /* eraser GC */
96: GC HandGC; /* Hand GC */
97: GC HighGC; /* Highlighting GC */
98: /* start of graph stuff */
99: int update; /* update frequence */
100: Dimension radius; /* radius factor */
101: int chime;
102: int beeped;
103: int analog;
104: int show_second_hand;
105: Dimension second_hand_length;
106: Dimension minute_hand_length;
107: Dimension hour_hand_length;
108: Dimension hand_width;
109: Dimension second_hand_width;
110: Position centerX;
111: Position centerY;
112: int numseg;
113: int mapped; /* is exposed */
114: int padding;
115: XPoint segbuff[SEG_BUFF_SIZE];
116: XPoint *segbuffptr;
117: XPoint *hour, *sec;
118: struct tm otm ;
119: caddr_t cookie;
120: } WidgetDataRec, *WidgetData;
121:
122:
123: /* Private Data */
124:
125: static WidgetDataRec globaldata;
126:
127: /* !!! STATIC !!! */
128: static int initDone = 0; /* initialization flag */
129:
130: static XContext widgetContext;
131:
132: /* bogus static's */
133: static int def_brwidth = DEF_BORDER;
134: static int def_width = 164;
135: static int def_height = 164;
136: static int def_x = 0;
137: static int def_y = 0;
138: static int def_update = DEF_UPDATE;
139: static int def_analog = 1;
140: static int def_chime = 0;
141: static int def_padding = DEF_ANALOG_PADDING;
142:
143: static Resource resourcelist[] = {
144: {XtNwindow, XtCWindow, XrmRWindow,
145: sizeof(Window), (caddr_t)&globaldata.mywin, (caddr_t)NULL},
146: {XtNborderWidth, XtCBorderWidth, XrmRInt,
147: sizeof(int), (caddr_t)&globaldata.brwidth, (caddr_t) &def_brwidth},
148: {XtNwidth, XtCWidth, XrmRInt,
149: sizeof(int), (caddr_t)&globaldata.width, (caddr_t) &def_width},
150: {XtNheight, XtCHeight, XrmRInt,
151: sizeof(int), (caddr_t)&globaldata.height, (caddr_t) &def_height },
152: {XtNx, XtCX, XrmRInt,
153: sizeof(int), (caddr_t)&globaldata.x, (caddr_t) &def_x },
154: {XtNy, XtCY, XrmRInt,
155: sizeof(int), (caddr_t)&globaldata.y, (caddr_t) &def_y },
156: {XtNupdate, XtCInterval, XrmRInt,
157: sizeof(int), (caddr_t)&globaldata.update, (caddr_t) &def_update },
158: {XtNchime, XtCChime, XrmRInt,
159: sizeof(int), (caddr_t)&globaldata.chime, (caddr_t) &def_chime },
160: {XtNhand, XtCColor, XrmRPixel,
161: sizeof(int), (caddr_t)&globaldata.Hdpixel, (caddr_t)&XtDefaultFGPixel},
162: {XtNhigh, XtCColor, XrmRPixel,
163: sizeof(int), (caddr_t)&globaldata.Hipixel, (caddr_t)&XtDefaultFGPixel},
164: {XtNforeground, XtCColor, XrmRPixel,
165: sizeof(int), (caddr_t)&globaldata.fgpixel, (caddr_t)&XtDefaultFGPixel},
166: {XtNbackground, XtCColor, XrmRPixel,
167: sizeof(int), (caddr_t)&globaldata.bgpixel, (caddr_t)&XtDefaultBGPixel},
168: {XtNpadding, XtCPadding, XrmRInt,
169: sizeof(int), (caddr_t)&globaldata.padding, (caddr_t) &def_padding },
170: {XtNborder, XtCColor, XrmRPixel,
171: sizeof(int),(caddr_t)&globaldata.brpixel, (caddr_t)&XtDefaultFGPixel}
172: };
173:
174: static Resource resourcelist1[] = {
175: {XtNfont, XtCFont, XrmRFontStruct,
176: sizeof(XFontStruct *), (caddr_t)&globaldata.fontstruct, (caddr_t)NULL},
177: {XtNanalog, XtCAnalog, XrmRInt,
178: sizeof(int), (caddr_t) &globaldata.analog, (caddr_t) &def_analog }
179: };
180:
181: /****************************************************************
182: *
183: * Private Procedures
184: *
185: ****************************************************************/
186:
187: static void ClockInitialize (dpy)
188: Display *dpy;
189: {
190: if (initDone) return;
191:
192: widgetContext = XUniqueContext();
193: globaldata.fontstruct = XLoadQueryFont(dpy,"fixed");
194:
195: initDone = 1;
196: }
197:
198: /*
199: * Given a display and window, get the widget data.
200: */
201:
202: static WidgetData DataFromWindow(dpy, window)
203: Display *dpy;
204: Window window;
205: {
206: WidgetData result;
207: if (XFindContext(dpy, window, widgetContext, (caddr_t *)&result))
208: return NULL;
209: return result;
210: }
211:
212: static void Destroy();
213:
214: /*
215: *
216: * Generic widget event handler
217: *
218: */
219:
220: static XtEventReturnCode EventHandler(event, eventdata)
221: XEvent *event;
222: caddr_t eventdata;
223: {
224: WidgetData data = (WidgetData ) eventdata;
225: void clock_tic();
226:
227: switch (event->type) {
228: case ConfigureNotify:
229: data->height = event->xconfigure.height;
230: data->width = event->xconfigure.width;
231: break;
232:
233: case DestroyNotify:
234: Destroy(data);
235: break;
236:
237: case ClientMessage:
238: if (((XClientMessageEvent *)event)->message_type ==
239: (unsigned long) XtTimerExpired)
240: clock_tic(data);
241: break;
242:
243: case Expose:
244: data->mapped = 1;
245: if( ((XExposeEvent *)event)->count == 0)
246: redisplay_clock(data);
247: break;
248:
249: case NoExpose:
250: data->mapped = 0;
251: break;
252: }
253:
254: return (XteventHandled);
255: }
256:
257: static redisplay_clock(data)
258: WidgetData data;
259: {
260: if(data->analog) {
261: data->radius = (min(data->width, data->height)-(2 * data->padding)) / 2;
262: data->second_hand_length = ((SECOND_HAND_FRACT * data->radius) / 100);
263: data->minute_hand_length = ((MINUTE_HAND_FRACT * data->radius) / 100);
264: data->hour_hand_length = ((HOUR_HAND_FRACT * data->radius) / 100);
265: data->hand_width = ((HAND_WIDTH_FRACT * data->radius) / 100);
266: data->second_hand_width = ((SECOND_WIDTH_FRACT * data->radius) / 100);
267: data->centerX = data->width / 2;
268: data->centerY = data->height / 2;
269: DrawClockFace(data, data->second_hand_length, data->radius);
270: }
271: clock_tic(data);
272: }
273:
274: /*
275: *
276: * Destroy the widget
277: *
278: */
279:
280: static void Destroy(data)
281: WidgetData data;
282: {
283:
284: XtClearEventHandlers(data->dpy, data->mywin);
285: (void) XtClearTimeOut(data->mywin, data->cookie);
286: XtFree ((char *) data);
287: }
288:
289: /****************************************************************
290: *
291: * Public Procedures
292: *
293: ****************************************************************/
294:
295: Window XtCreateClock(dpy, pw, arglist, argCount)
296: Display *dpy;
297: Window pw; /* parent window */
298: ArgList arglist;
299: int argCount;
300: {
301: WidgetData data;
302: unsigned long eventmask;
303: GCMask valuemask;
304: XrmNameList names;
305: XrmClassList classes;
306: XGCValues myXGCV;
307: char *str;
308: struct tm tm, *localtime();
309: long time_value;
310:
311: if (!initDone)ClockInitialize (dpy);
312:
313: data = (WidgetData ) XtMalloc (sizeof (WidgetDataRec));
314: globaldata.dpy = dpy;
315:
316: /* Set Some Default Values */
317: XtGetResources(dpy, resourcelist1, XtNumber(resourcelist1), arglist,
318: argCount, pw, "clock", "Clock", &names, &classes);
319: if(!globaldata.analog) {
320: (void) time(&time_value);
321: tm = *localtime(&time_value);
322: str = asctime(&tm);
323: def_width = XTextWidth( globaldata.fontstruct, str, strlen(str)) +
324: 2 * 10;
325: def_height = globaldata.fontstruct->ascent +
326: globaldata.fontstruct->descent + 2 * 10;
327: def_padding = 10;
328: }
329: /* Set Default Values */
330: XtGetResources(dpy, resourcelist, XtNumber(resourcelist), arglist,
331: argCount, pw, "clock", "Clock", &names, &classes);
332: if(!globaldata.analog && globaldata.padding != def_padding) {
333: def_width = XTextWidth( globaldata.fontstruct, str, strlen(str)) +
334: 2 * globaldata.padding;
335: def_height = globaldata.fontstruct->ascent +
336: globaldata.fontstruct->descent + 2 * globaldata.padding;
337: XtGetResources(dpy, resourcelist, XtNumber(resourcelist), arglist,
338: argCount, pw, "clock", "Clock", &names, &classes);
339: }
340: *data = globaldata;
341: valuemask = GCForeground | GCFont | GCBackground | GCLineWidth;
342: myXGCV.foreground = (*data).fgpixel;
343: myXGCV.font = (*data).fontstruct->fid;
344: myXGCV.background = data->bgpixel;
345: myXGCV.line_width = 0;
346: (*data).myGC = XtGetGC(dpy, (XContext) XtNclock, pw, valuemask, &myXGCV);
347: valuemask = GCForeground | GCLineWidth ;
348: myXGCV.foreground = (*data).bgpixel;
349: (*data).EraseGC = XtGetGC(dpy, (XContext) XtNclock, pw, valuemask, &myXGCV);
350: myXGCV.foreground = (*data).Hdpixel;
351: (*data).HandGC = XtGetGC(dpy, (XContext) XtNclock, pw, valuemask, &myXGCV);
352: valuemask = GCForeground | GCLineWidth ;
353: myXGCV.foreground = (*data).Hipixel;
354: (*data).HighGC = XtGetGC(dpy, (XContext) XtNclock, pw, valuemask, &myXGCV);
355:
356: if (data->mywin != NULL) {
357: XWindowAttributes wi;
358: /* set global data from window parameters */
359: if (! XGetWindowAttributes(data->dpy,data->mywin, &wi)) {
360: data->mywin = NULL;
361: } else {
362: data->brwidth = wi.border_width;
363: data->width = wi.width;
364: data->height = wi.height;
365: }
366: }
367: if (data->mywin == NULL) {
368: /* create the Clock window */
369: data->mywin = XCreateSimpleWindow(data->dpy, pw, data->x, data->y,
370: data->width, data->height,
371: data->brwidth, data->brpixel, data->bgpixel);
372: }
373:
374: XtSetNameAndClass(data->dpy, data->mywin, names, classes);
375: XrmFreeNameList(names);
376: XrmFreeClassList(classes);
377:
378: /* set handler for expose, resize, and message events */
379:
380: eventmask = ExposureMask+StructureNotifyMask;
381: XtSetEventHandler (
382: data->dpy, data->mywin,
383: (XtEventHandler)EventHandler, eventmask, (caddr_t)data);
384:
385: XtSetTimeOut(data->mywin, XtNclock, data->update*1000);
386: if (data->update <= SECOND_HAND_TIME)
387: data->show_second_hand = TRUE;
388: return (data->mywin);
389: }
390:
391:
392: static void clock_tic(data)
393: WidgetData data;
394: {
395:
396: struct tm *localtime();
397: struct tm tm;
398: long time_value;
399: char time_string[28];
400: char *time_ptr = time_string;
401:
402: (void) time(&time_value);
403: tm = *localtime(&time_value);
404: /*
405: * Beep on the half hour; double-beep on the hour.
406: */
407: if (data->chime == TRUE) {
408: if (data->beeped && (tm.tm_min != 30) &&
409: (tm.tm_min != 0))
410: data->beeped = 0;
411: if (((tm.tm_min == 30) || (tm.tm_min == 0))
412: && (!data->beeped)) {
413: data->beeped = 1;
414: XBell(data->dpy, 50);
415: if (tm.tm_min == 0)
416: XBell(data->dpy, 50);
417: }
418: }
419: if( data->analog == FALSE ) {
420: time_ptr = asctime(&tm);
421: time_ptr[strlen(time_ptr) - 1] = 0;
422: XDrawImageString(data->dpy, data->mywin, data->myGC,
423: 2+data->padding
424: , 2+data->fontstruct->ascent+data->padding,
425: time_ptr, strlen(time_ptr));
426: } else {
427: /*
428: * The second (or minute) hand is sec (or min)
429: * sixtieths around the clock face. The hour hand is
430: * (hour + min/60) twelfths of the way around the
431: * clock-face. The derivation is left as an excercise
432: * for the reader.
433: */
434:
435: /*
436: * 12 hour clock.
437: */
438: if(tm.tm_hour > 12)
439: tm.tm_hour -= 12;
440:
441: /*
442: * Erase old hands.
443: */
444: if(data->numseg > 0) {
445: if (data->show_second_hand == TRUE) {
446: XDrawLines(data->dpy, data->mywin,
447: data->EraseGC,
448: data->sec,
449: VERTICES_IN_HANDS-1,
450: CoordModeOrigin);
451: if(data->Hdpixel != data->bgpixel) {
452: XFillPolygon(data->dpy,
453: data->mywin, data->EraseGC,
454: data->sec,
455: VERTICES_IN_HANDS-2,
456: Convex, CoordModeOrigin
457: );
458: }
459: }
460: if( tm.tm_min != data->otm.tm_min ||
461: tm.tm_hour != data->otm.tm_hour ) {
462: XDrawLines( data->dpy,
463: data->mywin,
464: data->EraseGC,
465: data->segbuff,
466: VERTICES_IN_HANDS,
467: CoordModeOrigin);
468: XDrawLines( data->dpy,
469: data->mywin,
470: data->EraseGC,
471: data->hour,
472: VERTICES_IN_HANDS,
473: CoordModeOrigin);
474: if(data->Hdpixel != data->bgpixel) {
475: XFillPolygon( data->dpy,
476: data->mywin, data->EraseGC,
477: data->segbuff, VERTICES_IN_HANDS,
478: Convex, CoordModeOrigin
479: );
480: XFillPolygon(data->dpy,
481: data->mywin, data->EraseGC,
482: data->hour,
483: VERTICES_IN_HANDS,
484: Convex, CoordModeOrigin
485: );
486: }
487: }
488: }
489:
490: if (data->numseg == 0 ||
491: tm.tm_min != data->otm.tm_min ||
492: tm.tm_hour != data->otm.tm_hour) {
493: data->segbuffptr = data->segbuff;
494: data->numseg = 0;
495: /*
496: * Calculate the hour hand, fill it in with its
497: * color and then outline it. Next, do the same
498: * with the minute hand. This is a cheap hidden
499: * line algorithm.
500: */
501: DrawHand(data,
502: data->minute_hand_length, data->hand_width,
503: ((double) tm.tm_min)/60.0
504: );
505: if(data->Hdpixel != data->bgpixel)
506: XFillPolygon( data->dpy,
507: data->mywin, data->HandGC,
508: data->segbuff, VERTICES_IN_HANDS,
509: Convex, CoordModeOrigin
510: );
511: XDrawLines( data->dpy,
512: data->mywin, data->HighGC,
513: data->segbuff, VERTICES_IN_HANDS,
514: CoordModeOrigin);
515: data->hour = data->segbuffptr;
516: DrawHand(data,
517: data->hour_hand_length, data->hand_width,
518: ((((double)tm.tm_hour) +
519: (((double)tm.tm_min)/60.0)) / 12.0)
520: );
521: if(data->Hdpixel != data->bgpixel) {
522: XFillPolygon( data->dpy,
523: data->mywin, data->HandGC,
524: data->hour,
525: VERTICES_IN_HANDS,
526: Convex, CoordModeOrigin
527: );
528: }
529: XDrawLines( data->dpy,
530: data->mywin, data->HighGC,
531: data->hour, VERTICES_IN_HANDS,
532: CoordModeOrigin );
533:
534: data->sec = data->segbuffptr;
535: }
536: if (data->show_second_hand == TRUE) {
537: data->segbuffptr = data->sec;
538: DrawSecond(data,
539: data->second_hand_length - 2,
540: data->second_hand_width,
541: data->minute_hand_length + 2,
542: ((double) tm.tm_sec)/60.0
543: );
544: if(data->Hdpixel != data->bgpixel)
545: XFillPolygon( data->dpy,
546: data->mywin, data->HandGC,
547: data->sec,
548: VERTICES_IN_HANDS -2,
549: Convex, CoordModeOrigin
550: );
551: XDrawLines( data->dpy,
552: data->mywin, data->HighGC,
553: data->sec,
554: VERTICES_IN_HANDS-1,
555: CoordModeOrigin
556: );
557: /*
558: * keep the pointer from walking too far.
559: */
560: data->segbuffptr = data->sec;
561: data->numseg = data->segbuffptr-data->segbuff;
562: }
563: data->otm = tm;
564:
565: }
566: }
567:
568: /*
569: * DrawLine - Draws a line.
570: *
571: * blank_length is the distance from the center which the line begins.
572: * length is the maximum length of the hand.
573: * Fraction_of_a_circle is a fraction between 0 and 1 (inclusive) indicating
574: * how far around the circle (clockwise) from high noon.
575: *
576: * The blank_length feature is because I wanted to draw tick-marks around the
577: * circle (for seconds). The obvious means of drawing lines from the center
578: * to the perimeter, then erasing all but the outside most pixels doesn't
579: * work because of round-off error (sigh).
580: */
581: static DrawLine(data, blank_length, length, fraction_of_a_circle)
582: WidgetData data;
583: Dimension blank_length;
584: Dimension length;
585: double fraction_of_a_circle;
586: {
587: register double angle, cosangle, sinangle;
588: double cos();
589: double sin();
590:
591: /*
592: * A full circle is 2 PI radians.
593: * Angles are measured from 12 o'clock, clockwise increasing.
594: * Since in X, +x is to the right and +y is downward:
595: *
596: * x = x0 + r * sin(theta)
597: * y = y0 - r * cos(theta)
598: *
599: */
600: angle = TWOPI * fraction_of_a_circle;
601: cosangle = cos(angle);
602: sinangle = sin(angle);
603:
604: SetSeg( data,
605: data->centerX + (int)(blank_length * sinangle),
606: data->centerY - (int)(blank_length * cosangle),
607: data->centerX + (int)(length * sinangle),
608: data->centerY - (int)(length * cosangle));
609: }
610:
611: /*
612: * DrawHand - Draws a hand.
613: *
614: * length is the maximum length of the hand.
615: * width is the half-width of the hand.
616: * Fraction_of_a_circle is a fraction between 0 and 1 (inclusive) indicating
617: * how far around the circle (clockwise) from high noon.
618: *
619: */
620: static DrawHand(data, length, width, fraction_of_a_circle)
621: WidgetData data;
622: Dimension length, width;
623: double fraction_of_a_circle;
624: {
625:
626: register double angle, cosangle, sinangle;
627: register double ws, wc;
628: Position x, y, x1, y1, x2, y2;
629: double cos();
630: double sin();
631:
632: /*
633: * A full circle is 2 PI radians.
634: * Angles are measured from 12 o'clock, clockwise increasing.
635: * Since in X, +x is to the right and +y is downward:
636: *
637: * x = x0 + r * sin(theta)
638: * y = y0 - r * cos(theta)
639: *
640: */
641: angle = TWOPI * fraction_of_a_circle;
642: cosangle = cos(angle);
643: sinangle = sin(angle);
644: /*
645: * Order of points when drawing the hand.
646: *
647: * 1,4
648: * / \
649: * / \
650: * / \
651: * 2 ------- 3
652: */
653: wc = width * cosangle;
654: ws = width * sinangle;
655: SetSeg( data,
656: x = data->centerX + round(length * sinangle),
657: y = data->centerY - round(length * cosangle),
658: x1 = data->centerX - round(ws + wc),
659: y1 = data->centerY + round(wc - ws)); /* 1 ---- 2 */
660: /* 2 */
661: SetSeg( data, x1, y1,
662: x2 = data->centerX - round(ws - wc),
663: y2 = data->centerY + round(wc + ws)); /* 2 ----- 3 */
664:
665: SetSeg( data, x2, y2, x, y); /* 3 ----- 1(4) */
666: }
667:
668: /*
669: * DrawSecond - Draws the second hand (diamond).
670: *
671: * length is the maximum length of the hand.
672: * width is the half-width of the hand.
673: * offset is direct distance from center to tail end.
674: * Fraction_of_a_circle is a fraction between 0 and 1 (inclusive) indicating
675: * how far around the circle (clockwise) from high noon.
676: *
677: */
678: static DrawSecond(data, length, width, offset, fraction_of_a_circle)
679: WidgetData data;
680: Dimension length, width, offset;
681: double fraction_of_a_circle;
682: {
683:
684: register double angle, cosangle, sinangle;
685: register double ms, mc, ws, wc;
686: register int mid;
687: Position x, y;
688: double cos();
689: double sin();
690:
691: /*
692: * A full circle is 2 PI radians.
693: * Angles are measured from 12 o'clock, clockwise increasing.
694: * Since in X, +x is to the right and +y is downward:
695: *
696: * x = x0 + r * sin(theta)
697: * y = y0 - r * cos(theta)
698: *
699: */
700: angle = TWOPI * fraction_of_a_circle;
701: cosangle = cos(angle);
702: sinangle = sin(angle);
703: /*
704: * Order of points when drawing the hand.
705: *
706: * 1,5
707: * / \
708: * / \
709: * / \
710: * 2< >4
711: * \ /
712: * \ /
713: * \ /
714: * - 3
715: * |
716: * |
717: * offset
718: * |
719: * |
720: * - + center
721: */
722:
723: mid = (length + offset) / 2;
724: mc = mid * cosangle;
725: ms = mid * sinangle;
726: wc = width * cosangle;
727: ws = width * sinangle;
728: /*1 ---- 2 */
729: SetSeg( data,
730: x = data->centerX + round(length * sinangle),
731: y = data->centerY - round(length * cosangle),
732: data->centerX + round(ms - wc),
733: data->centerY - round(mc + ws) );
734: SetSeg( data, data->centerX + round(offset *sinangle),
735: data->centerY - round(offset * cosangle), /* 2-----3 */
736: data->centerX + round(ms + wc),
737: data->centerY - round(mc - ws));
738: data->segbuffptr->x = x;
739: data->segbuffptr++->y = y;
740: data->numseg ++;
741: }
742:
743: static SetSeg( data, x1, y1, x2, y2)
744: WidgetData data;
745: int x1, y1, x2, y2;
746: {
747: data->segbuffptr->x = x1;
748: data->segbuffptr++->y = y1;
749: data->segbuffptr->x = x2;
750: data->segbuffptr++->y = y2;
751: data->numseg += 2;
752: }
753:
754: /*
755: * Draw the clock face (every fifth tick-mark is longer
756: * than the others).
757: */
758: static DrawClockFace(data, second_hand, radius)
759: WidgetData data;
760: Dimension second_hand;
761: Dimension radius;
762: {
763: register int i;
764: register int delta = (radius - second_hand) / 3;
765:
766: XClearWindow(data->dpy, data->mywin);
767: data->segbuffptr = data->segbuff;
768: data->numseg = 0;
769: for (i = 0; i < 60; i++)
770: DrawLine(data, (i % 5) == 0 ? second_hand : (radius - delta), radius,
771: ((double) i)/60.);
772: /*
773: * Go ahead and draw it.
774: */
775: XDrawSegments(data->dpy, data->mywin,
776: data->myGC, (XSegment *) &(data->segbuff[0]),
777: data->numseg/2);
778:
779: data->segbuffptr = data->segbuff;
780: data->numseg = 0;
781: }
782:
783: static round(x)
784: double x;
785: {
786: return(x >= 0 ? (int)(x + .5) : (int)(x - .5));
787: }
788:
789:
790: /*
791: *
792: * Get Attributes
793: *
794: */
795:
796: void XtClockGetValues (dpy, window, arglist, argCount)
797: Display *dpy;
798: Window window;
799: ArgList arglist;
800: int argCount;
801: {
802: WidgetData data;
803: data = DataFromWindow(dpy, window);
804: if (data == NULL) return;
805: globaldata = *data;
806: XtGetValues(resourcelist, XtNumber(resourcelist), arglist, argCount);
807: }
808:
809: /*
810: *
811: * Set Attributes
812: *
813: */
814:
815: void XtClockSetValues (dpy, window, arglist, argCount)
816: Display *dpy;
817: Window window;
818: ArgList arglist;
819: int argCount;
820: {
821: WidgetData data;
822: int redisplay = FALSE;
823: GCMask valuemask;
824: XGCValues myXGCV;
825:
826:
827: data = DataFromWindow(dpy, window);
828: if (data == NULL) return;
829: globaldata = *data;
830: XtSetValues(resourcelist, XtNumber(resourcelist), arglist, argCount);
831:
832: if(globaldata.update != data->update) {
833: (void) XtClearTimeOut(data->mywin, data->cookie);
834: XtSetTimeOut(data->mywin, data->cookie, globaldata.update*1000);
835: data->update = globaldata.update;
836: if (data->update <= SECOND_HAND_TIME)
837: data->show_second_hand = TRUE;
838:
839: }
840: if (globaldata.brpixel != data->brpixel) {
841: data->brpixel = globaldata.brpixel;
842: if (data->brwidth != 0)
843: XSetWindowBorder(data->dpy, data->mywin, data->brpixel);
844: redisplay = TRUE;
845: }
846: if ((globaldata.bgpixel != data->bgpixel) ||
847: (globaldata.fgpixel != data->fgpixel) ||
848: (globaldata.Hdpixel != data->Hdpixel) ||
849: (globaldata.Hipixel != data->Hipixel)) {
850: redisplay = TRUE;
851: if((globaldata.bgpixel != data->bgpixel) ||
852: (globaldata.fgpixel != data->fgpixel)) {
853: valuemask = GCForeground | GCFont | GCBackground | GCLineWidth;
854: myXGCV.foreground = (*data).fgpixel;
855: myXGCV.font = (*data).fontstruct->fid;
856: myXGCV.background = data->bgpixel;
857: data->myGC = XtGetGC(
858: data->dpy, (XContext) XtNclock, data->mywin, valuemask, &myXGCV);
859: }
860: if (globaldata.bgpixel != data->bgpixel) {
861: valuemask = GCForeground | GCLineWidth;
862: myXGCV.foreground = (*data).bgpixel;
863: data->EraseGC = XtGetGC(
864: data->dpy, (XContext) XtNclock, data->mywin, valuemask, &myXGCV);
865: }
866: if (globaldata.Hdpixel != data->Hdpixel) {
867: valuemask = GCForeground | GCLineWidth;
868: myXGCV.foreground = (*data).Hdpixel;
869: data->HandGC = XtGetGC(
870: data->dpy, (XContext) XtNclock, data->mywin, valuemask, &myXGCV);
871: }
872: if (globaldata.Hipixel != data->Hipixel) {
873: valuemask = GCForeground | GCLineWidth;
874: myXGCV.foreground = (*data).Hipixel;
875: data->HighGC = XtGetGC(
876: data->dpy, (XContext) XtNclock, data->mywin, valuemask, &myXGCV);
877: }
878: }
879: *data = globaldata;
880: if(redisplay == TRUE) {
881: XClearWindow(data->dpy, data->mywin);
882: redisplay_clock(data);
883: }
884: }
885:
886:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.