source: trunk/athena/lib/Xj/AClock.c @ 12350

Revision 12350, 15.7 KB checked in by ghudson, 26 years ago (diff)
Some RCS ID cleanup: delete $Log$ and replace other RCS keywords with $Id$.
Line 
1/*
2 * $Id: AClock.c,v 1.2 1999-01-22 23:16:45 ghudson Exp $
3 *
4 * Copyright 1990, 1991 by the Massachusetts Institute of Technology.
5 *
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 *
9 */
10
11#if  (!defined(lint))  &&  (!defined(SABER))
12static char *rcsid =
13"$Id: AClock.c,v 1.2 1999-01-22 23:16:45 ghudson Exp $";
14#endif
15
16#include "mit-copyright.h"
17#include <stdio.h>
18#include <X11/Xos.h>            /* needed for <time.h> or <sys/time.h> */
19#include <math.h>
20#include "Jets.h"
21#include "AClock.h"
22
23#ifdef SHAPE
24#include <X11/extensions/shape.h>
25#endif
26
27#include "sintable.h"
28
29extern int DEBUG;
30
31#define offset(field) XjOffset(AClockJet,field)
32
33static XjResource resources[] = {
34  { XjNx, XjCX, XjRInt, sizeof(int),
35     offset(core.x), XjRString, XjInheritValue },
36  { XjNy, XjCY, XjRInt, sizeof(int),
37     offset(core.y), XjRString, XjInheritValue },
38  { XjNwidth, XjCWidth, XjRInt, sizeof(int),
39     offset(core.width), XjRString, XjInheritValue },
40  { XjNheight, XjCHeight, XjRInt, sizeof(int),
41     offset(core.height), XjRString, XjInheritValue },
42  { XjNpadding, XjCPadding, XjRInt, sizeof(int),
43      offset(aClock.padding), XjRString, "7" }, 
44  { XjNminorTick, XjCTick, XjRInt, sizeof(int),
45      offset(aClock.minorTick), XjRString, "1" },
46  { XjNmajorTick, XjCTick, XjRInt, sizeof(int),
47      offset(aClock.majorTick), XjRString, "5" },
48  { XjNminorStart, XjCTick, XjRInt, sizeof(int),
49      offset(aClock.minorStart), XjRString, "97" },
50  { XjNminorEnd, XjCTick, XjRInt, sizeof(int),
51      offset(aClock.minorEnd), XjRString, "99" },
52  { XjNmajorStart, XjCTick, XjRInt, sizeof(int),
53      offset(aClock.majorStart), XjRString, "90" },
54  { XjNmajorEnd, XjCTick, XjRInt, sizeof(int),
55      offset(aClock.majorEnd), XjRString, "100" },
56  { XjNsecondStart, XjCHand, XjRInt, sizeof(int),
57      offset(aClock.secondStart), XjRString, "73" },
58  { XjNsecondEnd, XjCHand, XjRInt, sizeof(int),
59      offset(aClock.secondEnd), XjRString, "88" },
60  { XjNsecondArc, XjCArc, XjRInt, sizeof(int),
61      offset(aClock.secondArc), XjRString, "6" },
62  { XjNminuteStart, XjCHand, XjRInt, sizeof(int),
63      offset(aClock.minuteStart), XjRString, "71" },
64  { XjNminuteEnd, XjCHand, XjRInt, sizeof(int),
65      offset(aClock.minuteEnd), XjRString, "-10" },
66  { XjNminuteArc, XjCArc, XjRInt, sizeof(int),
67      offset(aClock.minuteArc), XjRString, "100" },
68  { XjNhourStart, XjCHand, XjRInt, sizeof(int),
69      offset(aClock.hourStart), XjRString, "45" },
70  { XjNhourEnd, XjCHand, XjRInt, sizeof(int),
71      offset(aClock.hourEnd), XjRString, "-10" },
72  { XjNhourArc, XjCArc, XjRInt, sizeof(int),
73      offset(aClock.hourArc), XjRString, "100" },
74  { XjNforeground, XjCForeground, XjRColor, sizeof(int),
75      offset(aClock.foreground), XjRString, XjDefaultForeground },
76  { XjNbackground, XjCBackground, XjRColor, sizeof(int),
77      offset(aClock.background), XjRString, XjDefaultBackground },
78  { XjNhands, XjCForeground, XjRColor, sizeof(int),
79      offset(aClock.hands), XjRString, XjDefaultForeground },
80  { XjNhighlight, XjCForeground, XjRColor, sizeof(int),
81      offset(aClock.highlight), XjRString, XjDefaultForeground },
82  { XjNreverseVideo, XjCReverseVideo, XjRBoolean, sizeof(Boolean),
83      offset(aClock.reverseVideo), XjRBoolean, (caddr_t) False },
84  { XjNupdate, XjCInterval, XjRInt, sizeof(int),
85      offset(aClock.update), XjRString, "1" },
86  { XjNkeepRound, XjCKeepRound, XjRBoolean, sizeof(Boolean),
87      offset(aClock.keepRound), XjRBoolean, (caddr_t) False },
88#ifdef SHAPE
89  { XjNround, XjCRound, XjRBoolean, sizeof(Boolean),
90      offset(aClock.round), XjRBoolean, (caddr_t) False },
91#endif
92};
93
94#undef offset
95
96static void wakeup(), expose(), realize(), querySize(), move(),
97  resize(), initialize(), destroy();
98
99AClockClassRec aClockClassRec = {
100  {
101    /* class name */            "AnalogClock",
102    /* jet size   */            sizeof(AClockRec),
103    /* classInitialize */       NULL,
104    /* classInitialized? */     1,
105    /* initialize */            initialize,
106    /* prerealize */            NULL,
107    /* realize */               realize,
108    /* event */                 NULL,
109    /* expose */                expose,
110    /* querySize */             querySize,
111    /* move */                  move,
112    /* resize */                resize,
113    /* destroy */               destroy,
114    /* resources */             resources,
115    /* number of 'em */         XjNumber(resources)
116  }
117};
118
119JetClass aClockJetClass = (JetClass)&aClockClassRec;
120
121
122static void initialize(me)
123     AClockJet me;
124{
125#ifdef SHAPE
126  int shape_event_base, shape_error_base;
127
128  if (me->aClock.round && !XShapeQueryExtension (XjDisplay(me),
129                                                 &shape_event_base,
130                                                 &shape_error_base))
131    me->aClock.round = False;
132
133  me->aClock.mask = 0;
134#endif
135
136  me->aClock.realized = 0;
137}
138
139static int intsin(angle)
140     int angle;
141{
142  int quadr; /* used to be quad; conflicts with Ultrix. grrrr. */
143
144  if (angle >= 0)
145    {
146      quadr = (angle%CIRCLE) / ANGLES;
147      angle = angle%ANGLES;
148    }
149  else
150    {
151      quadr = (3 - ((-angle)%CIRCLE) / ANGLES);
152      angle = ANGLES - ((-angle)%ANGLES);
153    }
154
155  switch(quadr)
156    {
157    case 0:
158      return sinTable[angle];
159    case 1:
160      return sinTable[(ANGLES - 1) - angle];
161    case 2:
162      return -sinTable[angle];
163    case 3:
164      return -sinTable[(ANGLES - 1 ) - angle];
165    default:
166      fprintf(stdout, "sin broken (%d)\n", angle);
167      XjExit(-1);
168    }
169  return 0;               /* just to make saber happy... look up 2 lines... */
170}
171
172#define intcos(angle) intsin(angle + ANGLES)
173
174/*
175 * Things are currently broken screenwise.
176 * It will be fun to fix later. :)
177 */
178static void realize(me)
179     AClockJet me;
180{
181  unsigned long valuemask;
182  XGCValues values;
183  Pixmap tmp;
184
185  me->aClock.realized = 1;
186
187  if (me->aClock.reverseVideo)
188    {
189      int temp;
190
191      temp = me->aClock.foreground;
192      if (me->aClock.hands == me->aClock.foreground)
193        me->aClock.hands = me->aClock.background;
194      if (me->aClock.highlight == me->aClock.foreground)
195        me->aClock.highlight = me->aClock.background;
196      me->aClock.foreground = me->aClock.background;
197      me->aClock.background = temp;
198    }
199
200  valuemask = ( GCForeground | GCBackground
201               | GCFunction | GCGraphicsExposures );
202  values.graphics_exposures = False;
203  values.function = GXcopy;
204  values.background = me->aClock.background;
205
206#ifdef SHAPE
207  tmp = XjCreatePixmap (XjDisplay(me), XjWindow(me), 1, 1, 1);
208  values.foreground = 0;
209  me->aClock.eraseGC = XjCreateGC(XjDisplay(me), tmp, valuemask, &values);
210  values.foreground = 1;
211  me->aClock.setGC = XjCreateGC(XjDisplay(me), tmp, valuemask, &values);
212  XjFreePixmap(XjDisplay(me), tmp);
213#endif
214
215  values.foreground = me->aClock.foreground;
216  me->aClock.handsGC = me->aClock.highlightGC = me->aClock.foregroundGC
217                        = XjCreateGC(me->core.display,
218                                     me->core.window,
219                                     valuemask,
220                                     &values);
221
222  if (me->aClock.hands != me->aClock.foreground)
223    {
224      values.foreground = me->aClock.hands;
225      me->aClock.handsGC = XjCreateGC(me->core.display,
226                                      me->core.window,
227                                      valuemask,
228                                      &values);
229    }
230
231  if (me->aClock.highlight != me->aClock.foreground)
232    {
233      values.foreground = me->aClock.highlight;
234      me->aClock.highlightGC = XjCreateGC(me->core.display,
235                                          me->core.window,
236                                          valuemask,
237                                          &values);
238    }
239
240  values.foreground = me->aClock.background;
241  me->aClock.backgroundGC = XjCreateGC(me->core.display,
242                                       me->core.window,
243                                       valuemask,
244                                       &values);
245
246  me->aClock.h = me->aClock.m = me->aClock.s = -1;
247  me->aClock.timerid = XjAddWakeup(wakeup, me, 1000 * me->aClock.update);
248
249#ifdef SHAPE
250  if (me->aClock.round)
251    {
252      XjSize size;
253
254      size.width = me->core.width;
255      size.height = me->core.height;
256      resize(me, &size);
257    }
258#endif /* SHAPE */
259}
260
261static void querySize(me, size)
262     AClockJet me;
263     XjSize *size;
264{
265  size->width = 50;
266  size->height = 50;
267}
268
269static void move(me, x, y)
270     AClockJet me;
271     int x, y;
272{
273  if (DEBUG)
274    printf ("MV(aClock) '%s' x=%d,y=%d\n", me->core.name, x, y);
275
276  me->core.x = x;
277  me->core.y = y;
278  me->aClock.centerx = me->core.width / 2 + me->core.x;
279  me->aClock.centery = me->core.height / 2 + me->core.y;
280}
281
282static void resize(me, size)
283     AClockJet me;
284     XjSize *size;
285{
286  int width, height;
287
288  if (DEBUG)
289    printf ("RS(aClock) '%s' w=%d,h=%d\n", me->core.name,
290            size->width, size->height);
291
292  if (me->aClock.keepRound)
293    width = height = MIN(size->width, size->height);
294  else
295    {
296      width = size->width;
297      height = size->height;
298    }
299
300  me->aClock.centerx = size->width / 2 + me->core.x;
301  me->aClock.centery = size->height / 2 + me->core.y;
302  me->aClock.xradius = width / 2 + me->core.x - me->aClock.padding;
303  me->aClock.yradius = height / 2 + me->core.y - me->aClock.padding;
304
305  if (me->aClock.realized == 1)
306    {
307      XFillRectangle(me->core.display, me->core.window,
308                     me->aClock.backgroundGC,
309                     me->core.x, me->core.y,
310                     me->core.width, me->core.height);
311#ifdef SHAPE
312      if (me->aClock.round)
313        {
314          Jet parent;
315          int x, y, bw = 0;
316
317          /*
318           * allocate a pixmap to draw shapes in
319           */
320          if (me->aClock.mask)
321            XjFreePixmap(XjDisplay(me), me->aClock.mask);
322
323          me->aClock.mask = XjCreatePixmap (XjDisplay(me), XjWindow(me),
324                                            size->width, size->height, 1);
325
326          /* erase the pixmap */
327          XFillRectangle (XjDisplay(me), me->aClock.mask, me->aClock.eraseGC,
328                          0, 0, size->width, size->height);
329
330          /*
331           * draw the bounding shape.  Doing this first
332           * eliminates extra exposure events.
333           */
334
335          x = me->aClock.centerx - width/2 - me->core.x;
336          y = me->aClock.centery - height/2 - me->core.y;
337
338          XFillArc (XjDisplay(me), me->aClock.mask,
339                    me->aClock.setGC, x, y, width, height,
340                    0, 360 * 64);
341          XShapeCombineMask (XjDisplay(me), XjWindow(me), ShapeBounding,
342                             0, 0, me->aClock.mask, ShapeSet);
343
344          /*
345           * Find the highest enclosing widget (a window) to get borderwidth.
346           */
347          for (parent = (Jet) me; XjParent(parent) && !bw;
348               parent = XjParent(parent))
349            if (!strcmp(parent->core.classRec->core_class.className, "Window"))
350              bw = parent->core.borderWidth;
351
352          /* erase the pixmap */
353          XFillRectangle (XjDisplay (me), me->aClock.mask, me->aClock.eraseGC,
354                          0, 0, size->width, size->height);
355
356          /*
357           * draw the clip shape
358           */
359
360          XFillArc (XjDisplay(me), me->aClock.mask,
361                    me->aClock.setGC, x + bw, y + bw,
362                    width - 2 * bw, height - 2 * bw,
363                    0, 360 * 64);
364          XShapeCombineMask(XjDisplay(me), XjWindow(me), ShapeClip,
365                            0, 0, me->aClock.mask, ShapeSet);
366        }
367#endif /* SHAPE */
368    }
369
370  me->core.width = size->width;         /* These sizes must be set AFTER */
371  me->core.height = size->height;       /* the FillRectangle above... */
372}
373
374
375
376static void drawHand(me, drawable, gc_fill, gc_hilite, angle, start, end, arc)
377     AClockJet me;
378     Drawable drawable;
379     GC gc_fill, gc_hilite;
380     int angle;
381     int start, end, arc;
382{
383  int offset = arc * CIRCLE / (360 * 2);
384
385  XPoint p[4];
386
387  p[0].x = (end * me->aClock.xradius / 100) * intsin(angle - offset) /
388    SCALE + me->aClock.centerx;
389  p[0].y = (-(end * me->aClock.yradius / 100) * intcos(angle - offset) /
390    SCALE) + me->aClock.centery;
391  p[1].x = (start * me->aClock.xradius / 100) * intsin(angle) /
392    SCALE + me->aClock.centerx;
393  p[1].y = (-(start * me->aClock.yradius / 100) * intcos(angle) /
394    SCALE) + me->aClock.centery;
395  p[2].x = (end * me->aClock.xradius / 100) * intsin(angle + offset) /
396    SCALE + me->aClock.centerx;
397  p[2].y = (-(end * me->aClock.yradius / 100) * intcos(angle + offset) /
398    SCALE) + me->aClock.centery;
399  p[3] = p[0];
400
401  XFillPolygon(me->core.display, drawable,
402               gc_fill, p, 3, Convex, CoordModeOrigin);
403
404  XDrawLines(me->core.display, drawable,
405             gc_hilite, p, 4, CoordModeOrigin);
406}
407
408
409static void drawSecond(me, drawable, gc_fill, gc_hilite, angle)
410     AClockJet me;
411     Drawable drawable;
412     GC gc_fill, gc_hilite;
413     int angle;
414{
415  int offset = me->aClock.secondArc * CIRCLE / (360 * 2);
416  int ssx = me->aClock.secondStart * me->aClock.xradius / 100;
417  int ssy = me->aClock.secondStart * me->aClock.yradius / 100;
418  int sex = me->aClock.secondEnd * me->aClock.xradius / 100;
419  int sey = me->aClock.secondEnd * me->aClock.yradius / 100;
420  int mx = (ssx + sex) / 2;
421  int my = (ssy + sey) / 2;
422
423  XPoint p[5];
424
425  p[0].x = intsin(angle) * ssx / SCALE + me->aClock.centerx;
426  p[0].y = -(intcos(angle) * ssy / SCALE) + me->aClock.centery;
427  p[2].x = intsin(angle) * sex / SCALE + me->aClock.centerx;
428  p[2].y = -(intcos(angle) * sey / SCALE) + me->aClock.centery;
429
430  p[1].x = intsin(angle - offset) * mx / SCALE + me->aClock.centerx;
431  p[1].y = -(intcos(angle - offset) * my / SCALE) + me->aClock.centery;
432  p[3].x = intsin(angle + offset) * mx / SCALE + me->aClock.centerx;
433  p[3].y = -(intcos(angle + offset) * my / SCALE) + me->aClock.centery;
434  p[4] = p[0];
435
436  XFillPolygon(me->core.display, drawable,
437               gc_fill, p, 4, Convex, CoordModeOrigin);
438
439  XDrawLines(me->core.display, drawable,
440             gc_hilite, p, 5, CoordModeOrigin);
441}
442
443
444static int update(me, expose)
445     AClockJet me;
446     int expose;
447{
448  struct timeval now;
449  struct tm *t;
450  int oh = me->aClock.h, om = me->aClock.m, os = me->aClock.s;
451  int h, m, s;
452
453  gettimeofday(&now, NULL);
454  t = localtime((time_t *) &now.tv_sec);
455
456  h = t->tm_hour%12;
457  m = t->tm_min;
458  s = t->tm_sec;
459
460  if ((s != os || expose) && (me->aClock.update < 31))
461    {
462      if (s != os)
463        drawSecond(me, me->core.window,
464                   me->aClock.backgroundGC, me->aClock.backgroundGC,
465                   os * CIRCLE / 60);
466
467      drawSecond(me, me->core.window,
468                 me->aClock.handsGC, me->aClock.highlightGC,
469                 s * CIRCLE / 60);
470    }
471
472  if (m != om || expose)
473    {
474      if (m != om)
475        {
476          drawHand(me, me->core.window,
477                   me->aClock.backgroundGC, me->aClock.backgroundGC,
478                   om * CIRCLE / 60,
479                   me->aClock.minuteStart, me->aClock.minuteEnd,
480                   me->aClock.minuteArc);
481
482          drawHand(me, me->core.window,
483                   me->aClock.backgroundGC, me->aClock.backgroundGC,
484                   (60 * oh + om) * CIRCLE / 720,
485                   me->aClock.hourStart, me->aClock.hourEnd,
486                   me->aClock.hourArc);
487        }
488
489      drawHand(me, me->core.window,
490               me->aClock.handsGC, me->aClock.highlightGC,
491               m * CIRCLE / 60,
492               me->aClock.minuteStart, me->aClock.minuteEnd,
493               me->aClock.minuteArc);
494
495      drawHand(me, me->core.window,
496               me->aClock.handsGC, me->aClock.highlightGC,
497               (60 * h + m) * CIRCLE / 720,
498               me->aClock.hourStart, me->aClock.hourEnd,
499               me->aClock.hourArc);
500    }
501
502  me->aClock.h = h; me->aClock.m = m; me->aClock.s = s; 
503
504/*  if (me->aClock.update > 1) */
505    return(1000 * me->aClock.update);
506
507/*  return(1000 - (now.tv_usec / 1000)); */
508}
509
510static void drawTicks(me)
511     AClockJet me;
512{
513  int ticks;
514  int start, end;
515  int x1, y1, x2, y2;
516
517  for (ticks = 0; ticks < 60; ticks++)
518    {
519
520      if (me->aClock.majorTick != 0
521          && ticks % me->aClock.majorTick == 0)
522        {
523          start = me->aClock.majorStart;
524          end = me->aClock.majorEnd;
525        }
526      else if (me->aClock.minorTick != 0
527               && ticks % me->aClock.minorTick == 0)
528        {
529          start = me->aClock.minorStart;
530          end = me->aClock.minorEnd;
531        }
532      else continue;
533
534      x1 = me->aClock.centerx +
535        (me->aClock.xradius * start) / 100
536          * intsin(ticks * CIRCLE / 60) / SCALE;
537
538      y1 = me->aClock.centery +
539        (me->aClock.yradius * start) / 100
540          * -(intcos(ticks * CIRCLE / 60)) / SCALE;
541
542      x2 = me->aClock.centerx +
543        (me->aClock.xradius * end) / 100
544          * intsin(ticks * CIRCLE / 60) / SCALE;
545
546      y2 = me->aClock.centery +
547        (me->aClock.yradius * end) / 100
548          * -(intcos(ticks * CIRCLE / 60)) / SCALE;
549
550      XDrawLine(me->core.display,
551                me->core.window,
552                me->aClock.foregroundGC,
553                x1, y1, x2, y2);
554    }
555}
556
557static void wakeup(me, id)
558     AClockJet me;
559     int id;
560{
561  me->aClock.timerid = XjAddWakeup(wakeup, me, update(me, 0));
562}
563
564static void expose(me, event)
565     AClockJet me;
566     XEvent *event;
567{
568  drawTicks(me);
569  (void) update(me, 1);
570}
571
572static void destroy(me)
573     AClockJet me;
574{
575  XjFreeGC(me->core.display, me->aClock.backgroundGC);
576  XjFreeGC(me->core.display, me->aClock.foregroundGC);
577
578  (void)XjRemoveWakeup(me->aClock.timerid);
579}
Note: See TracBrowser for help on using the repository browser.