1 | /* $XConsortium: Clock.c,v 1.66 91/10/16 21:30:24 eswu Exp $ */ |
---|
2 | |
---|
3 | /*********************************************************** |
---|
4 | Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, |
---|
5 | and the Massachusetts Institute of Technology, Cambridge, Massachusetts. |
---|
6 | |
---|
7 | All Rights Reserved |
---|
8 | |
---|
9 | Permission to use, copy, modify, and distribute this software and its |
---|
10 | documentation for any purpose and without fee is hereby granted, |
---|
11 | provided that the above copyright notice appear in all copies and that |
---|
12 | both that copyright notice and this permission notice appear in |
---|
13 | supporting documentation, and that the names of Digital or MIT not be |
---|
14 | used in advertising or publicity pertaining to distribution of the |
---|
15 | software without specific, written prior permission. |
---|
16 | |
---|
17 | DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
---|
18 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL |
---|
19 | DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
---|
20 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
---|
21 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
---|
22 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
---|
23 | SOFTWARE. |
---|
24 | |
---|
25 | ******************************************************************/ |
---|
26 | |
---|
27 | #include <X11/Xlib.h> |
---|
28 | #include <X11/StringDefs.h> |
---|
29 | #include <X11/IntrinsicP.h> |
---|
30 | #include <X11/Xaw/XawInit.h> |
---|
31 | #include "ClockP.h" |
---|
32 | #include <X11/Xosdefs.h> |
---|
33 | |
---|
34 | #if __STDC__ |
---|
35 | #define Const const |
---|
36 | #else |
---|
37 | #define Const /**/ |
---|
38 | #endif |
---|
39 | |
---|
40 | #ifdef X_NOT_STDC_ENV |
---|
41 | extern struct tm *localtime(); |
---|
42 | #endif |
---|
43 | |
---|
44 | static void clock_tic(), DrawHand(), DrawSecond(), SetSeg(), DrawClockFace(); |
---|
45 | static erase_hands(), round(); |
---|
46 | |
---|
47 | /* Private Definitions */ |
---|
48 | |
---|
49 | #define VERTICES_IN_HANDS 6 /* to draw triangle */ |
---|
50 | #define PI 3.14159265358979 |
---|
51 | #define TWOPI (2. * PI) |
---|
52 | |
---|
53 | #define SECOND_HAND_FRACT 90 |
---|
54 | #define MINUTE_HAND_FRACT 70 |
---|
55 | #define HOUR_HAND_FRACT 40 |
---|
56 | #define HAND_WIDTH_FRACT 7 |
---|
57 | #define SECOND_WIDTH_FRACT 5 |
---|
58 | #define SECOND_HAND_TIME 30 |
---|
59 | |
---|
60 | #define ANALOG_SIZE_DEFAULT 164 |
---|
61 | |
---|
62 | #define max(a, b) ((a) > (b) ? (a) : (b)) |
---|
63 | #define min(a, b) ((a) < (b) ? (a) : (b)) |
---|
64 | #define abs(a) ((a) < 0 ? -(a) : (a)) |
---|
65 | |
---|
66 | |
---|
67 | /* Initialization of defaults */ |
---|
68 | |
---|
69 | #define offset(field) XtOffsetOf(ClockRec, clock.field) |
---|
70 | #define goffset(field) XtOffsetOf(WidgetRec, core.field) |
---|
71 | |
---|
72 | static XtResource resources[] = { |
---|
73 | {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension), |
---|
74 | goffset(width), XtRImmediate, (XtPointer) 0}, |
---|
75 | {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension), |
---|
76 | goffset(height), XtRImmediate, (XtPointer) 0}, |
---|
77 | {XtNupdate, XtCInterval, XtRInt, sizeof(int), |
---|
78 | offset(update), XtRImmediate, (XtPointer) 60 }, |
---|
79 | {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), |
---|
80 | offset(fgpixel), XtRString, XtDefaultForeground}, |
---|
81 | {XtNhand, XtCForeground, XtRPixel, sizeof(Pixel), |
---|
82 | offset(Hdpixel), XtRString, XtDefaultForeground}, |
---|
83 | {XtNhighlight, XtCForeground, XtRPixel, sizeof(Pixel), |
---|
84 | offset(Hipixel), XtRString, XtDefaultForeground}, |
---|
85 | {XtNanalog, XtCBoolean, XtRBoolean, sizeof(Boolean), |
---|
86 | offset(analog), XtRImmediate, (XtPointer) TRUE}, |
---|
87 | {XtNchime, XtCBoolean, XtRBoolean, sizeof(Boolean), |
---|
88 | offset(chime), XtRImmediate, (XtPointer) FALSE }, |
---|
89 | {XtNpadding, XtCMargin, XtRInt, sizeof(int), |
---|
90 | offset(padding), XtRImmediate, (XtPointer) 8}, |
---|
91 | {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), |
---|
92 | offset(font), XtRString, XtDefaultFont}, |
---|
93 | {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int), |
---|
94 | offset (backing_store), XtRString, "default"}, |
---|
95 | }; |
---|
96 | |
---|
97 | #undef offset |
---|
98 | #undef goffset |
---|
99 | |
---|
100 | static void ClassInitialize(); |
---|
101 | static void Initialize(), Realize(), Destroy(), Resize(), Redisplay(); |
---|
102 | static Boolean SetValues(); |
---|
103 | |
---|
104 | ClockClassRec clockClassRec = { |
---|
105 | { /* core fields */ |
---|
106 | /* superclass */ (WidgetClass) &simpleClassRec, |
---|
107 | /* class_name */ "Clock", |
---|
108 | /* widget_size */ sizeof(ClockRec), |
---|
109 | /* class_initialize */ ClassInitialize, |
---|
110 | /* class_part_initialize */ NULL, |
---|
111 | /* class_inited */ FALSE, |
---|
112 | /* initialize */ Initialize, |
---|
113 | /* initialize_hook */ NULL, |
---|
114 | /* realize */ Realize, |
---|
115 | /* actions */ NULL, |
---|
116 | /* num_actions */ 0, |
---|
117 | /* resources */ resources, |
---|
118 | /* resource_count */ XtNumber(resources), |
---|
119 | /* xrm_class */ NULLQUARK, |
---|
120 | /* compress_motion */ TRUE, |
---|
121 | /* compress_exposure */ TRUE, |
---|
122 | /* compress_enterleave */ TRUE, |
---|
123 | /* visible_interest */ FALSE, |
---|
124 | /* destroy */ Destroy, |
---|
125 | /* resize */ Resize, |
---|
126 | /* expose */ Redisplay, |
---|
127 | /* set_values */ SetValues, |
---|
128 | /* set_values_hook */ NULL, |
---|
129 | /* set_values_almost */ XtInheritSetValuesAlmost, |
---|
130 | /* get_values_hook */ NULL, |
---|
131 | /* accept_focus */ NULL, |
---|
132 | /* version */ XtVersion, |
---|
133 | /* callback_private */ NULL, |
---|
134 | /* tm_table */ NULL, |
---|
135 | /* query_geometry */ XtInheritQueryGeometry, |
---|
136 | /* display_accelerator */ XtInheritDisplayAccelerator, |
---|
137 | /* extension */ NULL |
---|
138 | }, |
---|
139 | { /* simple fields */ |
---|
140 | /* change_sensitive */ XtInheritChangeSensitive |
---|
141 | }, |
---|
142 | { /* clock fields */ |
---|
143 | /* ignore */ 0 |
---|
144 | } |
---|
145 | }; |
---|
146 | |
---|
147 | WidgetClass clockWidgetClass = (WidgetClass) &clockClassRec; |
---|
148 | |
---|
149 | /**************************************************************** |
---|
150 | * |
---|
151 | * Private Procedures |
---|
152 | * |
---|
153 | ****************************************************************/ |
---|
154 | |
---|
155 | static void ClassInitialize() |
---|
156 | { |
---|
157 | XawInitializeWidgetSet(); |
---|
158 | XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore, |
---|
159 | NULL, 0 ); |
---|
160 | } |
---|
161 | |
---|
162 | /* ARGSUSED */ |
---|
163 | static void Initialize (request, new, args, num_args) |
---|
164 | Widget request, new; |
---|
165 | ArgList args; |
---|
166 | Cardinal *num_args; |
---|
167 | { |
---|
168 | ClockWidget w = (ClockWidget)new; |
---|
169 | XtGCMask valuemask; |
---|
170 | XGCValues myXGCV; |
---|
171 | int min_height, min_width; |
---|
172 | |
---|
173 | valuemask = GCForeground | GCBackground | GCFont | GCLineWidth; |
---|
174 | if (w->clock.font != NULL) |
---|
175 | myXGCV.font = w->clock.font->fid; |
---|
176 | else |
---|
177 | valuemask &= ~GCFont; /* use server default font */ |
---|
178 | |
---|
179 | min_width = min_height = ANALOG_SIZE_DEFAULT; |
---|
180 | if(!w->clock.analog) { |
---|
181 | char *str; |
---|
182 | struct tm tm; |
---|
183 | long time_value; |
---|
184 | (void) time(&time_value); |
---|
185 | tm = *localtime(&time_value); |
---|
186 | str = asctime(&tm); |
---|
187 | if (w->clock.font == NULL) |
---|
188 | w->clock.font = XQueryFont( XtDisplay(w), |
---|
189 | XGContextFromGC( |
---|
190 | DefaultGCOfScreen(XtScreen(w))) ); |
---|
191 | min_width = XTextWidth(w->clock.font, str, strlen(str)) + |
---|
192 | 2 * w->clock.padding; |
---|
193 | min_height = w->clock.font->ascent + |
---|
194 | w->clock.font->descent + 2 * w->clock.padding; |
---|
195 | } |
---|
196 | if (w->core.width == 0) |
---|
197 | w->core.width = min_width; |
---|
198 | if (w->core.height == 0) |
---|
199 | w->core.height = min_height; |
---|
200 | |
---|
201 | myXGCV.foreground = w->clock.fgpixel; |
---|
202 | myXGCV.background = w->core.background_pixel; |
---|
203 | if (w->clock.font != NULL) |
---|
204 | myXGCV.font = w->clock.font->fid; |
---|
205 | else |
---|
206 | valuemask &= ~GCFont; /* use server default font */ |
---|
207 | myXGCV.line_width = 0; |
---|
208 | w->clock.myGC = XtGetGC((Widget)w, valuemask, &myXGCV); |
---|
209 | |
---|
210 | valuemask = GCForeground | GCLineWidth ; |
---|
211 | myXGCV.foreground = w->core.background_pixel; |
---|
212 | w->clock.EraseGC = XtGetGC((Widget)w, valuemask, &myXGCV); |
---|
213 | |
---|
214 | myXGCV.foreground = w->clock.Hipixel; |
---|
215 | w->clock.HighGC = XtGetGC((Widget)w, valuemask, &myXGCV); |
---|
216 | |
---|
217 | valuemask = GCForeground; |
---|
218 | myXGCV.foreground = w->clock.Hdpixel; |
---|
219 | w->clock.HandGC = XtGetGC((Widget)w, valuemask, &myXGCV); |
---|
220 | |
---|
221 | if (w->clock.update <= 0) |
---|
222 | w->clock.update = 60; /* make invalid update's use a default */ |
---|
223 | w->clock.show_second_hand = (w->clock.update <= SECOND_HAND_TIME); |
---|
224 | w->clock.numseg = 0; |
---|
225 | w->clock.interval_id = 0; |
---|
226 | } |
---|
227 | |
---|
228 | static void Realize (gw, valueMask, attrs) |
---|
229 | Widget gw; |
---|
230 | XtValueMask *valueMask; |
---|
231 | XSetWindowAttributes *attrs; |
---|
232 | { |
---|
233 | ClockWidget w = (ClockWidget) gw; |
---|
234 | #ifdef notdef |
---|
235 | *valueMask |= CWBitGravity; |
---|
236 | attrs->bit_gravity = ForgetGravity; |
---|
237 | #endif |
---|
238 | switch (w->clock.backing_store) { |
---|
239 | case Always: |
---|
240 | case NotUseful: |
---|
241 | case WhenMapped: |
---|
242 | *valueMask |=CWBackingStore; |
---|
243 | attrs->backing_store = w->clock.backing_store; |
---|
244 | break; |
---|
245 | } |
---|
246 | (*clockWidgetClass->core_class.superclass->core_class.realize) |
---|
247 | (gw, valueMask, attrs); |
---|
248 | Resize(gw); |
---|
249 | } |
---|
250 | |
---|
251 | static void Destroy (gw) |
---|
252 | Widget gw; |
---|
253 | { |
---|
254 | ClockWidget w = (ClockWidget) gw; |
---|
255 | if (w->clock.interval_id) XtRemoveTimeOut (w->clock.interval_id); |
---|
256 | XtReleaseGC (gw, w->clock.myGC); |
---|
257 | XtReleaseGC (gw, w->clock.HighGC); |
---|
258 | XtReleaseGC (gw, w->clock.HandGC); |
---|
259 | XtReleaseGC (gw, w->clock.EraseGC); |
---|
260 | } |
---|
261 | |
---|
262 | static void Resize (gw) |
---|
263 | Widget gw; |
---|
264 | { |
---|
265 | ClockWidget w = (ClockWidget) gw; |
---|
266 | /* don't do this computation if window hasn't been realized yet. */ |
---|
267 | if (XtIsRealized(gw) && w->clock.analog) { |
---|
268 | /* need signed value since Dimension is unsigned */ |
---|
269 | int radius = ((int) min(w->core.width, w->core.height) - (int) (2 * w->clock.padding)) / 2; |
---|
270 | w->clock.radius = (Dimension) max (radius, 1); |
---|
271 | |
---|
272 | w->clock.second_hand_length = (int)(SECOND_HAND_FRACT * w->clock.radius) / 100; |
---|
273 | w->clock.minute_hand_length = (int)(MINUTE_HAND_FRACT * w->clock.radius) / 100; |
---|
274 | w->clock.hour_hand_length = (int)(HOUR_HAND_FRACT * w->clock.radius) / 100; |
---|
275 | w->clock.hand_width = (int)(HAND_WIDTH_FRACT * w->clock.radius) / 100; |
---|
276 | w->clock.second_hand_width = (int)(SECOND_WIDTH_FRACT * w->clock.radius) / 100; |
---|
277 | |
---|
278 | w->clock.centerX = w->core.width / 2; |
---|
279 | w->clock.centerY = w->core.height / 2; |
---|
280 | } |
---|
281 | } |
---|
282 | |
---|
283 | /* ARGSUSED */ |
---|
284 | static void Redisplay (gw, event, region) |
---|
285 | Widget gw; |
---|
286 | XEvent *event; /* unused */ |
---|
287 | Region region; /* unused */ |
---|
288 | { |
---|
289 | ClockWidget w = (ClockWidget) gw; |
---|
290 | if (w->clock.analog) { |
---|
291 | if (w->clock.numseg != 0) |
---|
292 | erase_hands (w, (struct tm *) 0); |
---|
293 | DrawClockFace(w); |
---|
294 | } else { |
---|
295 | w->clock.prev_time_string[0] = '\0'; |
---|
296 | } |
---|
297 | clock_tic((XtPointer)w, (XtIntervalId)0); |
---|
298 | } |
---|
299 | |
---|
300 | /* ARGSUSED */ |
---|
301 | static void clock_tic(client_data, id) |
---|
302 | XtPointer client_data; |
---|
303 | XtIntervalId *id; |
---|
304 | { |
---|
305 | ClockWidget w = (ClockWidget)client_data; |
---|
306 | struct tm tm; |
---|
307 | long time_value; |
---|
308 | char *time_ptr; |
---|
309 | register Display *dpy = XtDisplay(w); |
---|
310 | register Window win = XtWindow(w); |
---|
311 | |
---|
312 | if (id || !w->clock.interval_id) |
---|
313 | w->clock.interval_id = |
---|
314 | XtAppAddTimeOut( XtWidgetToApplicationContext( (Widget) w), |
---|
315 | w->clock.update*1000, clock_tic, (XtPointer)w ); |
---|
316 | (void) time(&time_value); |
---|
317 | tm = *localtime(&time_value); |
---|
318 | /* |
---|
319 | * Beep on the half hour; double-beep on the hour. |
---|
320 | */ |
---|
321 | if (w->clock.chime == TRUE) { |
---|
322 | if (w->clock.beeped && (tm.tm_min != 30) && |
---|
323 | (tm.tm_min != 0)) |
---|
324 | w->clock.beeped = FALSE; |
---|
325 | if (((tm.tm_min == 30) || (tm.tm_min == 0)) |
---|
326 | && (!w->clock.beeped)) { |
---|
327 | w->clock.beeped = TRUE; |
---|
328 | XBell(dpy, 50); |
---|
329 | if (tm.tm_min == 0) |
---|
330 | XBell(dpy, 50); |
---|
331 | } |
---|
332 | } |
---|
333 | if( w->clock.analog == FALSE ) { |
---|
334 | int clear_from; |
---|
335 | int i, len, prev_len; |
---|
336 | |
---|
337 | time_ptr = asctime(&tm); |
---|
338 | len = strlen (time_ptr); |
---|
339 | if (time_ptr[len - 1] == '\n') time_ptr[--len] = '\0'; |
---|
340 | prev_len = strlen (w->clock.prev_time_string); |
---|
341 | for (i = 0; ((i < len) && (i < prev_len) && |
---|
342 | (w->clock.prev_time_string[i] == time_ptr[i])); i++); |
---|
343 | strcpy (w->clock.prev_time_string+i, time_ptr+i); |
---|
344 | |
---|
345 | XDrawImageString (dpy, win, w->clock.myGC, |
---|
346 | (2+w->clock.padding + |
---|
347 | XTextWidth (w->clock.font, time_ptr, i)), |
---|
348 | 2+w->clock.font->ascent+w->clock.padding, |
---|
349 | time_ptr + i, len - i); |
---|
350 | /* |
---|
351 | * Clear any left over bits |
---|
352 | */ |
---|
353 | clear_from = XTextWidth (w->clock.font, time_ptr, len) |
---|
354 | + 2 + w->clock.padding; |
---|
355 | if (clear_from < (int)w->core.width) |
---|
356 | XFillRectangle (dpy, win, w->clock.EraseGC, |
---|
357 | clear_from, 0, w->core.width - clear_from, w->core.height); |
---|
358 | } else { |
---|
359 | /* |
---|
360 | * The second (or minute) hand is sec (or min) |
---|
361 | * sixtieths around the clock face. The hour hand is |
---|
362 | * (hour + min/60) twelfths of the way around the |
---|
363 | * clock-face. The derivation is left as an excercise |
---|
364 | * for the reader. |
---|
365 | */ |
---|
366 | |
---|
367 | /* |
---|
368 | * 12 hour clock. |
---|
369 | */ |
---|
370 | if(tm.tm_hour >= 12) |
---|
371 | tm.tm_hour -= 12; |
---|
372 | |
---|
373 | erase_hands (w, &tm); |
---|
374 | |
---|
375 | if (w->clock.numseg == 0 || |
---|
376 | tm.tm_min != w->clock.otm.tm_min || |
---|
377 | tm.tm_hour != w->clock.otm.tm_hour) { |
---|
378 | w->clock.segbuffptr = w->clock.segbuff; |
---|
379 | w->clock.numseg = 0; |
---|
380 | /* |
---|
381 | * Calculate the hour hand, fill it in with its |
---|
382 | * color and then outline it. Next, do the same |
---|
383 | * with the minute hand. This is a cheap hidden |
---|
384 | * line algorithm. |
---|
385 | */ |
---|
386 | DrawHand(w, |
---|
387 | w->clock.minute_hand_length, w->clock.hand_width, |
---|
388 | tm.tm_min * 12 |
---|
389 | ); |
---|
390 | if(w->clock.Hdpixel != w->core.background_pixel) |
---|
391 | XFillPolygon( dpy, |
---|
392 | win, w->clock.HandGC, |
---|
393 | w->clock.segbuff, VERTICES_IN_HANDS, |
---|
394 | Convex, CoordModeOrigin |
---|
395 | ); |
---|
396 | XDrawLines( dpy, |
---|
397 | win, w->clock.HighGC, |
---|
398 | w->clock.segbuff, VERTICES_IN_HANDS, |
---|
399 | CoordModeOrigin); |
---|
400 | w->clock.hour = w->clock.segbuffptr; |
---|
401 | DrawHand(w, |
---|
402 | w->clock.hour_hand_length, w->clock.hand_width, |
---|
403 | tm.tm_hour * 60 + tm.tm_min |
---|
404 | ); |
---|
405 | if(w->clock.Hdpixel != w->core.background_pixel) { |
---|
406 | XFillPolygon(dpy, |
---|
407 | win, w->clock.HandGC, |
---|
408 | w->clock.hour, |
---|
409 | VERTICES_IN_HANDS, |
---|
410 | Convex, CoordModeOrigin |
---|
411 | ); |
---|
412 | } |
---|
413 | XDrawLines( dpy, |
---|
414 | win, w->clock.HighGC, |
---|
415 | w->clock.hour, VERTICES_IN_HANDS, |
---|
416 | CoordModeOrigin ); |
---|
417 | |
---|
418 | w->clock.sec = w->clock.segbuffptr; |
---|
419 | } |
---|
420 | if (w->clock.show_second_hand == TRUE) { |
---|
421 | w->clock.segbuffptr = w->clock.sec; |
---|
422 | DrawSecond(w, |
---|
423 | w->clock.second_hand_length - 2, |
---|
424 | w->clock.second_hand_width, |
---|
425 | w->clock.minute_hand_length + 2, |
---|
426 | tm.tm_sec * 12 |
---|
427 | ); |
---|
428 | if(w->clock.Hdpixel != w->core.background_pixel) |
---|
429 | XFillPolygon( dpy, |
---|
430 | win, w->clock.HandGC, |
---|
431 | w->clock.sec, |
---|
432 | VERTICES_IN_HANDS -2, |
---|
433 | Convex, CoordModeOrigin |
---|
434 | ); |
---|
435 | XDrawLines( dpy, |
---|
436 | win, w->clock.HighGC, |
---|
437 | w->clock.sec, |
---|
438 | VERTICES_IN_HANDS-1, |
---|
439 | CoordModeOrigin |
---|
440 | ); |
---|
441 | |
---|
442 | } |
---|
443 | w->clock.otm = tm; |
---|
444 | } |
---|
445 | } |
---|
446 | |
---|
447 | static erase_hands (w, tm) |
---|
448 | ClockWidget w; |
---|
449 | struct tm *tm; |
---|
450 | { |
---|
451 | /* |
---|
452 | * Erase old hands. |
---|
453 | */ |
---|
454 | if(w->clock.numseg > 0) { |
---|
455 | Display *dpy; |
---|
456 | Window win; |
---|
457 | |
---|
458 | dpy = XtDisplay (w); |
---|
459 | win = XtWindow (w); |
---|
460 | if (w->clock.show_second_hand == TRUE) { |
---|
461 | XDrawLines(dpy, win, |
---|
462 | w->clock.EraseGC, |
---|
463 | w->clock.sec, |
---|
464 | VERTICES_IN_HANDS-1, |
---|
465 | CoordModeOrigin); |
---|
466 | if(w->clock.Hdpixel != w->core.background_pixel) { |
---|
467 | XFillPolygon(dpy, |
---|
468 | win, w->clock.EraseGC, |
---|
469 | w->clock.sec, |
---|
470 | VERTICES_IN_HANDS-2, |
---|
471 | Convex, CoordModeOrigin |
---|
472 | ); |
---|
473 | } |
---|
474 | } |
---|
475 | if(!tm || tm->tm_min != w->clock.otm.tm_min || |
---|
476 | tm->tm_hour != w->clock.otm.tm_hour) |
---|
477 | { |
---|
478 | XDrawLines( dpy, win, |
---|
479 | w->clock.EraseGC, |
---|
480 | w->clock.segbuff, |
---|
481 | VERTICES_IN_HANDS, |
---|
482 | CoordModeOrigin); |
---|
483 | XDrawLines( dpy, win, |
---|
484 | w->clock.EraseGC, |
---|
485 | w->clock.hour, |
---|
486 | VERTICES_IN_HANDS, |
---|
487 | CoordModeOrigin); |
---|
488 | if(w->clock.Hdpixel != w->core.background_pixel) { |
---|
489 | XFillPolygon( dpy, win, |
---|
490 | w->clock.EraseGC, |
---|
491 | w->clock.segbuff, VERTICES_IN_HANDS, |
---|
492 | Convex, CoordModeOrigin); |
---|
493 | XFillPolygon( dpy, win, |
---|
494 | w->clock.EraseGC, |
---|
495 | w->clock.hour, |
---|
496 | VERTICES_IN_HANDS, |
---|
497 | Convex, CoordModeOrigin); |
---|
498 | } |
---|
499 | } |
---|
500 | } |
---|
501 | } |
---|
502 | |
---|
503 | static float Const Sines[] = { |
---|
504 | .000000, .008727, .017452, .026177, .034899, .043619, .052336, .061049, |
---|
505 | .069756, .078459, .087156, .095846, .104528, .113203, .121869, .130526, |
---|
506 | .139173, .147809, .156434, .165048, .173648, .182236, .190809, .199368, |
---|
507 | .207912, .216440, .224951, .233445, .241922, .250380, .258819, .267238, |
---|
508 | .275637, .284015, .292372, .300706, .309017, .317305, .325568, .333807, |
---|
509 | .342020, .350207, .358368, .366501, .374607, .382683, .390731, .398749, |
---|
510 | .406737, .414693, .422618, .430511, .438371, .446198, .453990, .461749, |
---|
511 | .469472, .477159, .484810, .492424, .500000, .507538, .515038, .522499, |
---|
512 | .529919, .537300, .544639, .551937, .559193, .566406, .573576, .580703, |
---|
513 | .587785, .594823, .601815, .608761, .615661, .622515, .629320, .636078, |
---|
514 | .642788, .649448, .656059, .662620, .669131, .675590, .681998, .688355, |
---|
515 | .694658, .700909, .707107 |
---|
516 | }; |
---|
517 | |
---|
518 | static float Const Cosines[] = { |
---|
519 | 1.00000, .999962, .999848, .999657, .999391, .999048, .998630, .998135, |
---|
520 | .997564, .996917, .996195, .995396, .994522, .993572, .992546, .991445, |
---|
521 | .990268, .989016, .987688, .986286, .984808, .983255, .981627, .979925, |
---|
522 | .978148, .976296, .974370, .972370, .970296, .968148, .965926, .963630, |
---|
523 | .961262, .958820, .956305, .953717, .951057, .948324, .945519, .942641, |
---|
524 | .939693, .936672, .933580, .930418, .927184, .923880, .920505, .917060, |
---|
525 | .913545, .909961, .906308, .902585, .898794, .894934, .891007, .887011, |
---|
526 | .882948, .878817, .874620, .870356, .866025, .861629, .857167, .852640, |
---|
527 | .848048, .843391, .838671, .833886, .829038, .824126, .819152, .814116, |
---|
528 | .809017, .803857, .798636, .793353, .788011, .782608, .777146, .771625, |
---|
529 | .766044, .760406, .754710, .748956, .743145, .737277, .731354, .725374, |
---|
530 | .719340, .713250, .707107 |
---|
531 | }; |
---|
532 | |
---|
533 | static void ClockAngle(tick_units, sinp, cosp) |
---|
534 | int tick_units; |
---|
535 | double *sinp, *cosp; |
---|
536 | { |
---|
537 | int reduced, upper; |
---|
538 | |
---|
539 | reduced = tick_units % 90; |
---|
540 | upper = tick_units / 90; |
---|
541 | if (upper & 1) |
---|
542 | reduced = 90 - reduced; |
---|
543 | if ((upper + 1) & 2) { |
---|
544 | *sinp = Cosines[reduced]; |
---|
545 | *cosp = Sines[reduced]; |
---|
546 | } else { |
---|
547 | *sinp = Sines[reduced]; |
---|
548 | *cosp = Cosines[reduced]; |
---|
549 | } |
---|
550 | if (upper >= 2 && upper < 6) |
---|
551 | *cosp = -*cosp; |
---|
552 | if (upper >= 4) |
---|
553 | *sinp = -*sinp; |
---|
554 | } |
---|
555 | |
---|
556 | /* |
---|
557 | * DrawLine - Draws a line. |
---|
558 | * |
---|
559 | * blank_length is the distance from the center which the line begins. |
---|
560 | * length is the maximum length of the hand. |
---|
561 | * Tick_units is a number between zero and 12*60 indicating |
---|
562 | * how far around the circle (clockwise) from high noon. |
---|
563 | * |
---|
564 | * The blank_length feature is because I wanted to draw tick-marks around the |
---|
565 | * circle (for seconds). The obvious means of drawing lines from the center |
---|
566 | * to the perimeter, then erasing all but the outside most pixels doesn't |
---|
567 | * work because of round-off error (sigh). |
---|
568 | */ |
---|
569 | static void DrawLine(w, blank_length, length, tick_units) |
---|
570 | ClockWidget w; |
---|
571 | Dimension blank_length; |
---|
572 | Dimension length; |
---|
573 | int tick_units; |
---|
574 | { |
---|
575 | double dblank_length = (double)blank_length, dlength = (double)length; |
---|
576 | double cosangle, sinangle; |
---|
577 | int cx = w->clock.centerX, cy = w->clock.centerY, x1, y1, x2, y2; |
---|
578 | |
---|
579 | /* |
---|
580 | * Angles are measured from 12 o'clock, clockwise increasing. |
---|
581 | * Since in X, +x is to the right and +y is downward: |
---|
582 | * |
---|
583 | * x = x0 + r * sin(theta) |
---|
584 | * y = y0 - r * cos(theta) |
---|
585 | * |
---|
586 | */ |
---|
587 | ClockAngle(tick_units, &sinangle, &cosangle); |
---|
588 | |
---|
589 | /* break this out so that stupid compilers can cope */ |
---|
590 | x1 = cx + (int)(dblank_length * sinangle); |
---|
591 | y1 = cy - (int)(dblank_length * cosangle); |
---|
592 | x2 = cx + (int)(dlength * sinangle); |
---|
593 | y2 = cy - (int)(dlength * cosangle); |
---|
594 | SetSeg(w, x1, y1, x2, y2); |
---|
595 | } |
---|
596 | |
---|
597 | /* |
---|
598 | * DrawHand - Draws a hand. |
---|
599 | * |
---|
600 | * length is the maximum length of the hand. |
---|
601 | * width is the half-width of the hand. |
---|
602 | * Tick_units is a number between zero and 12*60 indicating |
---|
603 | * how far around the circle (clockwise) from high noon. |
---|
604 | * |
---|
605 | */ |
---|
606 | static void DrawHand(w, length, width, tick_units) |
---|
607 | ClockWidget w; |
---|
608 | Dimension length, width; |
---|
609 | int tick_units; |
---|
610 | { |
---|
611 | |
---|
612 | double cosangle, sinangle; |
---|
613 | register double ws, wc; |
---|
614 | Position x, y, x1, y1, x2, y2; |
---|
615 | |
---|
616 | /* |
---|
617 | * Angles are measured from 12 o'clock, clockwise increasing. |
---|
618 | * Since in X, +x is to the right and +y is downward: |
---|
619 | * |
---|
620 | * x = x0 + r * sin(theta) |
---|
621 | * y = y0 - r * cos(theta) |
---|
622 | * |
---|
623 | */ |
---|
624 | ClockAngle(tick_units, &sinangle, &cosangle); |
---|
625 | /* |
---|
626 | * Order of points when drawing the hand. |
---|
627 | * |
---|
628 | * 1,4 |
---|
629 | * / \ |
---|
630 | * / \ |
---|
631 | * / \ |
---|
632 | * 2 ------- 3 |
---|
633 | */ |
---|
634 | wc = width * cosangle; |
---|
635 | ws = width * sinangle; |
---|
636 | SetSeg(w, |
---|
637 | x = w->clock.centerX + round(length * sinangle), |
---|
638 | y = w->clock.centerY - round(length * cosangle), |
---|
639 | x1 = w->clock.centerX - round(ws + wc), |
---|
640 | y1 = w->clock.centerY + round(wc - ws)); /* 1 ---- 2 */ |
---|
641 | /* 2 */ |
---|
642 | SetSeg(w, x1, y1, |
---|
643 | x2 = w->clock.centerX - round(ws - wc), |
---|
644 | y2 = w->clock.centerY + round(wc + ws)); /* 2 ----- 3 */ |
---|
645 | |
---|
646 | SetSeg(w, x2, y2, x, y); /* 3 ----- 1(4) */ |
---|
647 | } |
---|
648 | |
---|
649 | /* |
---|
650 | * DrawSecond - Draws the second hand (diamond). |
---|
651 | * |
---|
652 | * length is the maximum length of the hand. |
---|
653 | * width is the half-width of the hand. |
---|
654 | * offset is direct distance from center to tail end. |
---|
655 | * Tick_units is a number between zero and 12*60 indicating |
---|
656 | * how far around the circle (clockwise) from high noon. |
---|
657 | * |
---|
658 | */ |
---|
659 | static void DrawSecond(w, length, width, offset, tick_units) |
---|
660 | ClockWidget w; |
---|
661 | Dimension length, width, offset; |
---|
662 | int tick_units; |
---|
663 | { |
---|
664 | |
---|
665 | double cosangle, sinangle; |
---|
666 | register double ms, mc, ws, wc; |
---|
667 | register int mid; |
---|
668 | Position x, y; |
---|
669 | |
---|
670 | /* |
---|
671 | * Angles are measured from 12 o'clock, clockwise increasing. |
---|
672 | * Since in X, +x is to the right and +y is downward: |
---|
673 | * |
---|
674 | * x = x0 + r * sin(theta) |
---|
675 | * y = y0 - r * cos(theta) |
---|
676 | * |
---|
677 | */ |
---|
678 | ClockAngle(tick_units, &sinangle, &cosangle); |
---|
679 | /* |
---|
680 | * Order of points when drawing the hand. |
---|
681 | * |
---|
682 | * 1,5 |
---|
683 | * / \ |
---|
684 | * / \ |
---|
685 | * / \ |
---|
686 | * 2< >4 |
---|
687 | * \ / |
---|
688 | * \ / |
---|
689 | * \ / |
---|
690 | * - 3 |
---|
691 | * | |
---|
692 | * | |
---|
693 | * offset |
---|
694 | * | |
---|
695 | * | |
---|
696 | * - + center |
---|
697 | */ |
---|
698 | |
---|
699 | mid = (int) (length + offset) / 2; |
---|
700 | mc = mid * cosangle; |
---|
701 | ms = mid * sinangle; |
---|
702 | wc = width * cosangle; |
---|
703 | ws = width * sinangle; |
---|
704 | /*1 ---- 2 */ |
---|
705 | SetSeg(w, |
---|
706 | x = w->clock.centerX + round(length * sinangle), |
---|
707 | y = w->clock.centerY - round(length * cosangle), |
---|
708 | w->clock.centerX + round(ms - wc), |
---|
709 | w->clock.centerY - round(mc + ws) ); |
---|
710 | SetSeg(w, w->clock.centerX + round(offset *sinangle), |
---|
711 | w->clock.centerY - round(offset * cosangle), /* 2-----3 */ |
---|
712 | w->clock.centerX + round(ms + wc), |
---|
713 | w->clock.centerY - round(mc - ws)); |
---|
714 | w->clock.segbuffptr->x = x; |
---|
715 | w->clock.segbuffptr++->y = y; |
---|
716 | w->clock.numseg ++; |
---|
717 | } |
---|
718 | |
---|
719 | static void SetSeg(w, x1, y1, x2, y2) |
---|
720 | ClockWidget w; |
---|
721 | int x1, y1, x2, y2; |
---|
722 | { |
---|
723 | w->clock.segbuffptr->x = x1; |
---|
724 | w->clock.segbuffptr++->y = y1; |
---|
725 | w->clock.segbuffptr->x = x2; |
---|
726 | w->clock.segbuffptr++->y = y2; |
---|
727 | w->clock.numseg += 2; |
---|
728 | } |
---|
729 | |
---|
730 | /* |
---|
731 | * Draw the clock face (every fifth tick-mark is longer |
---|
732 | * than the others). |
---|
733 | */ |
---|
734 | static void DrawClockFace(w) |
---|
735 | ClockWidget w; |
---|
736 | { |
---|
737 | register int i; |
---|
738 | register int delta = (int)(w->clock.radius - w->clock.second_hand_length) / 3; |
---|
739 | |
---|
740 | w->clock.segbuffptr = w->clock.segbuff; |
---|
741 | w->clock.numseg = 0; |
---|
742 | for (i = 0; i < 60; i++) |
---|
743 | DrawLine(w, ( (i % 5) == 0 ? |
---|
744 | w->clock.second_hand_length : |
---|
745 | (w->clock.radius - delta) ), |
---|
746 | w->clock.radius, i * 12); |
---|
747 | /* |
---|
748 | * Go ahead and draw it. |
---|
749 | */ |
---|
750 | XDrawSegments(XtDisplay(w), XtWindow(w), |
---|
751 | w->clock.myGC, (XSegment *) &(w->clock.segbuff[0]), |
---|
752 | w->clock.numseg/2); |
---|
753 | |
---|
754 | w->clock.segbuffptr = w->clock.segbuff; |
---|
755 | w->clock.numseg = 0; |
---|
756 | } |
---|
757 | |
---|
758 | static int round(x) |
---|
759 | double x; |
---|
760 | { |
---|
761 | return(x >= 0.0 ? (int)(x + .5) : (int)(x - .5)); |
---|
762 | } |
---|
763 | |
---|
764 | /* ARGSUSED */ |
---|
765 | static Boolean SetValues (gcurrent, grequest, gnew, args, num_args) |
---|
766 | Widget gcurrent, grequest, gnew; |
---|
767 | ArgList args; |
---|
768 | Cardinal *num_args; |
---|
769 | { |
---|
770 | ClockWidget current = (ClockWidget) gcurrent; |
---|
771 | ClockWidget new = (ClockWidget) gnew; |
---|
772 | Boolean redisplay = FALSE; |
---|
773 | XtGCMask valuemask; |
---|
774 | XGCValues myXGCV; |
---|
775 | |
---|
776 | /* first check for changes to clock-specific resources. We'll accept all |
---|
777 | the changes, but may need to do some computations first. */ |
---|
778 | |
---|
779 | if (new->clock.update != current->clock.update) { |
---|
780 | if (current->clock.interval_id) |
---|
781 | XtRemoveTimeOut (current->clock.interval_id); |
---|
782 | if (XtIsRealized( (Widget) new)) |
---|
783 | new->clock.interval_id = XtAppAddTimeOut( |
---|
784 | XtWidgetToApplicationContext(gnew), |
---|
785 | new->clock.update*1000, |
---|
786 | clock_tic, (XtPointer)gnew); |
---|
787 | |
---|
788 | new->clock.show_second_hand =(new->clock.update <= SECOND_HAND_TIME); |
---|
789 | } |
---|
790 | |
---|
791 | if (new->clock.padding != current->clock.padding) |
---|
792 | redisplay = TRUE; |
---|
793 | |
---|
794 | if (new->clock.analog != current->clock.analog) |
---|
795 | redisplay = TRUE; |
---|
796 | |
---|
797 | if (new->clock.font != current->clock.font) |
---|
798 | redisplay = TRUE; |
---|
799 | |
---|
800 | if ((new->clock.fgpixel != current->clock.fgpixel) |
---|
801 | || (new->core.background_pixel != current->core.background_pixel)) { |
---|
802 | valuemask = GCForeground | GCBackground | GCFont | GCLineWidth; |
---|
803 | myXGCV.foreground = new->clock.fgpixel; |
---|
804 | myXGCV.background = new->core.background_pixel; |
---|
805 | myXGCV.font = new->clock.font->fid; |
---|
806 | myXGCV.line_width = 0; |
---|
807 | XtReleaseGC (gcurrent, current->clock.myGC); |
---|
808 | new->clock.myGC = XtGetGC(gcurrent, valuemask, &myXGCV); |
---|
809 | redisplay = TRUE; |
---|
810 | } |
---|
811 | |
---|
812 | if (new->clock.Hipixel != current->clock.Hipixel) { |
---|
813 | valuemask = GCForeground | GCLineWidth; |
---|
814 | myXGCV.foreground = new->clock.fgpixel; |
---|
815 | myXGCV.font = new->clock.font->fid; |
---|
816 | myXGCV.line_width = 0; |
---|
817 | XtReleaseGC (gcurrent, current->clock.HighGC); |
---|
818 | new->clock.HighGC = XtGetGC((Widget)gcurrent, valuemask, &myXGCV); |
---|
819 | redisplay = TRUE; |
---|
820 | } |
---|
821 | |
---|
822 | if (new->clock.Hdpixel != current->clock.Hdpixel) { |
---|
823 | valuemask = GCForeground; |
---|
824 | myXGCV.foreground = new->clock.fgpixel; |
---|
825 | XtReleaseGC (gcurrent, current->clock.HandGC); |
---|
826 | new->clock.HandGC = XtGetGC((Widget)gcurrent, valuemask, &myXGCV); |
---|
827 | redisplay = TRUE; |
---|
828 | } |
---|
829 | |
---|
830 | if (new->core.background_pixel != current->core.background_pixel) { |
---|
831 | valuemask = GCForeground | GCLineWidth; |
---|
832 | myXGCV.foreground = new->core.background_pixel; |
---|
833 | myXGCV.line_width = 0; |
---|
834 | XtReleaseGC (gcurrent, current->clock.EraseGC); |
---|
835 | new->clock.EraseGC = XtGetGC((Widget)gcurrent, valuemask, &myXGCV); |
---|
836 | redisplay = TRUE; |
---|
837 | } |
---|
838 | |
---|
839 | return (redisplay); |
---|
840 | |
---|
841 | } |
---|