Use C++ linker
[oweals/cde.git] / cde / programs / dtwm / Clock.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* static char rcsid[] = 
24         "$XConsortium: Clock.c /main/8 1996/10/14 10:58:15 pascale $";
25 */
26 /**---------------------------------------------------------------------
27 ***     
28 ***     file:           Clock.c
29 ***
30 ***     project:        MotifPlus Widgets
31 ***
32 ***     description:    Source code for DtClock class.
33 ***                     Portions adapted from the Xaw Clock widget.
34 ***     
35 ***
36 ***                     (c) Copyright 1990 by Hewlett-Packard Company.
37 ***
38 ***
39 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
40 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
41
42                         All Rights Reserved
43
44 Permission to use, copy, modify, and distribute this software and its 
45 documentation for any purpose and without fee is hereby granted, 
46 provided that the above copyright notice appear in all copies and that
47 both that copyright notice and this permission notice appear in 
48 supporting documentation, and that the names of Digital or MIT not be
49 used in advertising or publicity pertaining to distribution of the
50 software without specific, written prior permission.  
51
52 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
53 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
54 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
55 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
56 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
57 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
58 SOFTWARE.
59 ***
60 ***
61 ***-------------------------------------------------------------------*/
62
63
64 \f
65 /*-------------------------------------------------------------
66 **      Include Files
67 */
68
69 #include <stdio.h>
70 #ifdef __apollo
71 #include <sys/types.h>
72 #endif
73 #include <sys/stat.h>
74 #include <time.h>
75 #include <Xm/GadgetP.h>
76 #include <Xm/ManagerP.h>
77 #include "ClockP.h"
78 #include <Dt/Control.h>
79
80
81 /*-------------------------------------------------------------
82 **      Public Interface
83 **-------------------------------------------------------------
84 */
85
86 WidgetClass     dtClockGadgetClass;
87
88 \f
89 /*-------------------------------------------------------------
90 */
91
92 #define SIZE_DEFAULT            32
93 #define DELAY_DEFAULT           250
94 #define VERTICES_IN_HANDS       6       /* to draw triangle */
95 #define PI                      3.14159265358979
96 #define TWOPI                   (2. * PI)
97
98 #define SMALL_TICK_FRACT        100
99 #define SMALL_MINUTE_HAND_FRACT 95
100 #define SMALL_HOUR_HAND_FRACT   68
101 #define SMALL_HAND_WIDTH_FRACT  12
102
103 #define TICK_FRACT              90
104 #define MINUTE_HAND_FRACT       70
105 #define HOUR_HAND_FRACT         40
106 #define HAND_WIDTH_FRACT        7
107
108 #define max(a,b)        ((a) > (b) ? (a) : (b))
109 #define min(a,b)        ((a) < (b) ? (a) : (b))
110 #define abs(a)          ((a) < 0 ? - (a) : (a))
111
112 #define G_Width(r)              (r -> rectangle.width)
113 #define G_Height(r)             (r -> rectangle.height)
114 #define M_BackgroundGC(m)       (m -> manager.background_GC)
115 #define G_X(r)                  (r -> rectangle.x)
116 #define G_Y(r)                  (r -> rectangle.y)
117
118
119 /* Is this still needed, or does <time.h> always declare time()? */
120 extern time_t           time ( time_t * );
121
122
123 /********    Public Function Declarations    ********/
124
125 extern Widget DtCreateClock( 
126                         Widget parent,
127                         String name,
128                         ArgList arglist,
129                         Cardinal argcount) ;
130
131 /********    End Public Function Declarations    ********/
132
133 /********    Static Function Declarations    ********/
134
135 static void ClockTick( 
136                         XtPointer client_data,
137                         XtIntervalId *id) ;
138 static void DrawLine( 
139                         DtClockGadget w,
140                         Dimension blank_length,
141                         Dimension length,
142                         double fraction_of_a_circle) ;
143 static void DrawHand( 
144                         DtClockGadget w,
145                         Dimension length,
146                         Dimension width,
147                         double fraction_of_a_circle) ;
148 static void SetSegment( 
149                         DtClockGadget w,
150                         int x1,
151                         int y1,
152                         int x2,
153                         int y2) ;
154 static int round( 
155                         double x) ;
156 static void DrawClockFace( 
157                         DtClockGadget g) ;
158 static void Initialize( 
159                         Widget request_w,
160                         Widget new_w) ;
161 static void Destroy( 
162                         Widget w) ;
163 static void Resize( 
164                         Widget widget) ;
165 static void Draw( 
166                         DtClockGadget g,
167                         Drawable drawable,
168                         Position x,
169                         Position y,
170                         Dimension w,
171                         Dimension h,
172                         Dimension h_t,
173                         Dimension s_t,
174                         unsigned char s_type,
175                         unsigned char fill_mode) ;
176 static void UpdateGCs( 
177                         DtClockGadget g) ;
178 static void EraseHands ( DtClockGadget  w, struct tm *  tm );
179
180 /********    End Static Function Declarations    ********/
181
182 \f
183 /*-------------------------------------------------------------
184 **      Resource List
185 */
186 #define R_Offset(field) \
187         XtOffset (DtClockGadget, clock.field)
188
189 static XtResource resources[] = 
190 {
191         {
192                 XmNclockInterval,
193                 XmCInterval, XmRInt, sizeof (int),
194                 R_Offset (clock_interval), XmRImmediate, (XtPointer) 60
195         },
196         {
197                 XmNchime,
198                 XmCBoolean, XmRBoolean, sizeof (Boolean),
199                 R_Offset (chime), XmRImmediate, (XtPointer) FALSE
200         },
201         {
202                 XmNleftInset,
203                 XmCSpacing, XmRHorizontalDimension, sizeof (Dimension),
204                 R_Offset (left_inset), XmRImmediate, (caddr_t) 2
205         },
206         {
207                 XmNrightInset,
208                 XmCSpacing, XmRHorizontalDimension, sizeof (Dimension),
209                 R_Offset (right_inset), XmRImmediate, (caddr_t) 2
210         },
211         {
212                 XmNtopInset,
213                 XmCSpacing, XmRVerticalDimension, sizeof (Dimension),
214                 R_Offset (top_inset), XmRImmediate, (caddr_t) 2
215         },
216         {
217                 XmNbottomInset,
218                 XmCSpacing, XmRVerticalDimension, sizeof (Dimension),
219                 R_Offset (bottom_inset), XmRImmediate, (caddr_t) 2
220         }
221 };
222 #undef  R_Offset
223
224
225 \f
226 /*-------------------------------------------------------------
227 **      Class Record
228 */
229 DtClockClassRec dtClockClassRec =
230 {
231         /*      Core Part
232         */
233         {       
234                 (WidgetClass) &dtControlClassRec, /* superclass */
235                 "Clock",                        /* class_name           */
236                 sizeof (DtClockRec),            /* widget_size          */
237                 NULL,                           /* class_initialize     */
238                 NULL,                           /* class_part_initialize*/
239                 False,                          /* class_inited         */
240                 (XtInitProc) Initialize,        /* initialize           */
241                 NULL,                           /* initialize_hook      */
242                 NULL,                           /* realize              */
243                 NULL,                           /* actions              */
244                 0,                              /* num_actions          */
245                 resources,                      /* resources            */
246                 XtNumber (resources),           /* num_resources        */
247                 NULLQUARK,                      /* xrm_class            */
248                 True,                           /* compress_motion      */
249                 True,                           /* compress_exposure    */
250                 True,                           /* compress_enterleave  */
251                 False,                          /* visible_interest     */      
252                 Destroy,                        /* destroy              */      
253                 Resize,                         /* resize               */
254                 XtInheritExpose,                /* expose               */      
255                 NULL,                           /* set_values           */      
256                 NULL,                           /* set_values_hook      */
257                 XtInheritSetValuesAlmost,       /* set_values_almost    */
258                 NULL,                           /* get_values_hook      */
259                 NULL,                           /* accept_focus         */      
260                 XtVersion,                      /* version              */
261                 NULL,                           /* callback private     */
262                 NULL,                           /* tm_table             */
263                 NULL,                           /* query_geometry       */
264                 NULL,                           /* display_accelerator  */
265                 NULL,                           /* extension            */
266         },
267
268         /*      XmGadget Part
269         */
270         {
271                 XmInheritBorderHighlight,       /* border_highlight     */
272                 XmInheritBorderUnhighlight,     /* border_unhighlight   */
273 (XtActionProc)  XmInheritArmAndActivate,        /* arm_and_activate     */
274 (XmWidgetDispatchProc)  XmInheritInputDispatch, /* input_dispatch       */
275                 XmInheritVisualChange,          /* visual_change        */
276                 NULL,                           /* get_resources        */
277                 0,                              /* num_get_resources    */
278                 XmInheritCachePart,             /* class_cache_part     */
279                 NULL,                           /* extension            */
280         },
281
282         /*      DtIcon Part
283         */
284         {
285                 DtInheritGetSize,               /* get_size             */
286                 DtInheritGetPositions,          /* get_positions        */
287                 (DrawProc) Draw,                /* draw                 */
288                 DtInheritCallCallback,          /* call_callback        */
289 (UpdateGCsProc) UpdateGCs,                      /* update_gcs           */
290                 False,                          /* optimize_redraw      */
291                 NULL,                           /* class_cache_part     */
292                 NULL,                           /* extension            */
293         },
294
295         /*      DtClock Part
296         */
297         {
298                 NULL,                           /* class_cache_part     */
299                 NULL,                           /* extension            */
300         },
301
302         /*      DtControl Part
303         */
304         {
305                 NULL,                           /* class_cache_part     */
306                 NULL,                           /* extension            */
307         }
308 };
309
310
311 WidgetClass dtClockGadgetClass = (WidgetClass) &dtClockClassRec;
312
313
314 \f
315 /*-------------------------------------------------------------
316 **      Private Functions
317 **-------------------------------------------------------------
318 */
319
320 /*-------------------------------------------------------------
321 **      ClockTick
322 **              Clock timeout.
323 */
324 static void 
325 ClockTick(
326         XtPointer client_data,
327         XtIntervalId *id )
328 {
329         DtClockGadget           w =     (DtClockGadget)client_data;     
330         struct tm *     localtime ();
331         struct tm       tm; 
332         time_t          time_value;
333         char *          time_ptr;
334         register Display *      dpy = XtDisplay (w);
335         register Window         win = XtWindow (w);
336
337         if (id || !w->clock.interval_id)
338                 w->clock.interval_id =
339                         XtAppAddTimeOut (
340                                 XtWidgetToApplicationContext ((Widget) w),
341                                 G_ClockInterval (w)*1000, ClockTick,
342                                 (XtPointer)w );
343         (void) time (&time_value);
344         tm = *localtime (&time_value);
345
346         if (! XtIsManaged ((Widget)w))
347         {
348                 w->clock.otm = tm;
349                 return;
350         }
351
352 /*      Beep on the half hour; double-beep on the hour.
353 */
354         if (w->clock.chime == TRUE)
355         {
356                 if (w->clock.beeped && (tm.tm_min != 30) &&
357                     (tm.tm_min != 0))
358                         w->clock.beeped = FALSE;
359                 if (((tm.tm_min == 30) || (tm.tm_min == 0)) 
360                     && (!w->clock.beeped))
361                 {
362                         w->clock.beeped = TRUE;
363                         XBell (dpy, 50);        
364                         if (tm.tm_min == 0)
365                                 XBell (dpy, 50);
366                 }
367         }
368
369 /* remove this when clipping added to gcs */
370         if ((G_Width (w) <
371                    (Dimension)((G_ClockWidth (w) / 2) + w->clock.centerX)) ||
372             (G_Height (w) <
373                    (Dimension)((G_ClockHeight (w) / 2) + w->clock.centerY)))
374                 return;
375
376 /*      The second (or minute) hand is sec (or min) sixtieths around the
377 *       clock face. The hour hand is (hour + min/60) twelfths of the way
378 *       around the clock-face.
379 */
380         if (tm.tm_hour > 12)
381                 tm.tm_hour -= 12;
382
383         EraseHands (w, &tm);
384
385         w->clock.segbuffptr = w->clock.segbuff;
386         w->clock.numseg = 0;
387
388 /*      Calculate the hour hand, fill it in with its color.
389 */
390         DrawHand (w, w->clock.minute_hand_length, w->clock.hand_width,
391                                 ((double) tm.tm_min)/60.0);
392         XDrawLines (dpy, win, G_ClockHandGC (w), w->clock.segbuff,
393                         VERTICES_IN_HANDS, CoordModeOrigin);
394         XFillPolygon (dpy, win, G_ClockHandGC (w), w->clock.segbuff,
395                         VERTICES_IN_HANDS, Convex, CoordModeOrigin);
396
397         w->clock.hour = w->clock.segbuffptr;
398
399         DrawHand (w, w->clock.hour_hand_length, w->clock.hand_width,
400                          ((((double)tm.tm_hour) + 
401                                 (((double)tm.tm_min)/60.0)) / 12.0));
402         XFillPolygon (dpy, win, G_ClockHandGC (w), w->clock.hour,
403                         VERTICES_IN_HANDS, Convex, CoordModeOrigin);
404         XDrawLines (dpy, win, G_ClockHandGC (w), w->clock.hour,
405                         VERTICES_IN_HANDS, CoordModeOrigin);
406
407         w->clock.sec = w->clock.segbuffptr;
408         w->clock.otm = tm;
409 }
410         
411
412 \f
413 /*-------------------------------------------------------------
414 **      EraseHands
415 **              Erase clock hands.
416 */
417 static void
418 EraseHands (
419         DtClockGadget   w,
420         struct tm *     tm )
421 {
422         XmManagerWidget mgr =   (XmManagerWidget) XtParent (w);
423         Display *       dpy =           XtDisplay (w);
424         Window          win =           XtWindow (w);
425         unsigned char   behavior =      G_Behavior (w);
426         GC              gc;
427
428         if (! XtIsManaged ((Widget)w) || w->clock.numseg <= 0)
429                 return;
430
431         gc = G_ClockBackgroundGC (w);
432
433 /*      Erase old hands.
434 */
435         if (!tm || tm->tm_min != w->clock.otm.tm_min ||
436                   tm->tm_hour != w->clock.otm.tm_hour)
437         { 
438                 XDrawLines (dpy, win, gc, w->clock.segbuff,
439                                 VERTICES_IN_HANDS, CoordModeOrigin);
440                 XDrawLines (dpy, win, gc, w->clock.hour,
441                                 VERTICES_IN_HANDS, CoordModeOrigin);
442                 XFillPolygon (dpy, win, gc, w->clock.segbuff,
443                                 VERTICES_IN_HANDS, Convex, CoordModeOrigin);
444                 XFillPolygon (dpy, win, gc, w->clock.hour,
445                                 VERTICES_IN_HANDS, Convex, CoordModeOrigin);
446         }
447 }
448
449
450 \f
451 /*-------------------------------------------------------------
452 **      DrawLine
453 **              Draw a line.
454  * blank_length is the distance from the center which the line begins.
455  * length is the maximum length of the hand.
456  * Fraction_of_a_circle is a fraction between 0 and 1 (inclusive) indicating
457  * how far around the circle (clockwise) from high noon.
458  *
459  * The blank_length feature is because I wanted to draw tick-marks around the
460  * circle (for seconds).  The obvious means of drawing lines from the center
461  * to the perimeter, then erasing all but the outside most pixels doesn't
462  * work because of round-off error (sigh).
463  */
464 static void
465 DrawLine (
466         DtClockGadget w,
467         Dimension blank_length,
468         Dimension length,
469         double fraction_of_a_circle )
470 {
471         double dblank_length = (double)blank_length, dlength = (double)length;
472         double angle, cosangle, sinangle;
473         double cos ();
474         double sin ();
475         int cx = w->clock.centerX, cy = w->clock.centerY, x1, y1, x2, y2;
476
477         /*
478          *  A full circle is 2 PI radians.
479          *  Angles are measured from 12 o'clock, clockwise increasing.
480          *  Since in X, +x is to the right and +y is downward:
481          *
482          *      x = x0 + r * sin (theta)
483          *      y = y0 - r * cos (theta)
484          *
485          */
486         angle = TWOPI * fraction_of_a_circle;
487         cosangle = cos (angle);
488         sinangle = sin (angle);
489
490         /* break this out so that stupid compilers can cope */
491         x1 = cx + (int) (dblank_length * sinangle);
492         y1 = cy - (int) (dblank_length * cosangle);
493         x2 = cx + (int) (dlength * sinangle);
494         y2 = cy - (int) (dlength * cosangle);
495         SetSegment (w, x1, y1, x2, y2);
496 }
497
498
499 \f
500 /*-------------------------------------------------------------
501 **      DrawHand
502 **              Draw a hand.
503  *
504  * length is the maximum length of the hand.
505  * width is the half-width of the hand.
506  * Fraction_of_a_circle is a fraction between 0 and 1 (inclusive) indicating
507  * how far around the circle (clockwise) from high noon.
508  *
509  */
510 static void 
511 DrawHand(
512         DtClockGadget w,
513         Dimension length,
514         Dimension width,
515         double fraction_of_a_circle )
516 {
517         register double angle, cosangle, sinangle;
518         register double ws, wc;
519         Position x, y, x1, y1, x2, y2;
520         double cos ();
521         double sin ();
522
523         /*  A full circle is 2 PI radians.
524          *  Angles are measured from 12 o'clock, clockwise increasing.
525          *  Since in X, +x is to the right and +y is downward:
526          *
527          *      x = x0 + r * sin (theta)
528          *      y = y0 - r * cos (theta)
529          */
530         angle = TWOPI * fraction_of_a_circle;
531         cosangle = cos (angle);
532         sinangle = sin (angle);
533
534         /* Order of points when drawing the hand.
535          *                  1,4
536          *                  / \
537          *                 /   \
538          *                /      \
539          *              2 ------- 3
540          */
541         wc = width * cosangle;
542         ws = width * sinangle;
543         SetSegment (w,
544                    x = w->clock.centerX + round (length * sinangle),
545                    y = w->clock.centerY - round (length * cosangle),
546                    x1 = w->clock.centerX - round (ws + wc), 
547                    y1 = w->clock.centerY + round (wc - ws));  /* 1 ---- 2 */
548         SetSegment (w, x1, y1, 
549                    x2 = w->clock.centerX - round (ws - wc), 
550                    y2 = w->clock.centerY + round (wc + ws));  /* 2 ----- 3 */
551         SetSegment (w, x2, y2, x, y);   /* 3 ----- 1 (4) */
552 }
553
554
555 \f
556 /*-------------------------------------------------------------
557 **      SetSegment
558 **              Set segment values.
559 */
560 static void 
561 SetSegment(
562         DtClockGadget w,
563         int x1,
564         int y1,
565         int x2,
566         int y2 )
567 {
568         w->clock.segbuffptr->x = x1 + G_X (w);
569         w->clock.segbuffptr++->y = y1 + G_Y (w);
570         w->clock.segbuffptr->x = x2 + G_X (w);
571         w->clock.segbuffptr++->y = y2 + G_Y (w);
572         w->clock.numseg += 2;
573 }
574
575
576 /*-------------------------------------------------------------
577 **      round
578 **              round integer.
579 */
580 static int 
581 round(
582         double x )
583 {
584         return (x >= 0.0 ? (int) (x + .5) : (int) (x - .5));
585 }
586
587
588 \f
589 /*-------------------------------------------------------------
590 **      DrawClockFace
591  *
592  *      Draw the clock face (every fifth tick-mark is longer
593  *      than the others).
594  */
595 static void 
596 DrawClockFace(
597         DtClockGadget g )
598 {
599         Boolean draw_minute_ticks =
600                          ((G_ClockWidth (g) > (Dimension) (2 * SIZE_DEFAULT)) &&
601                           (G_ClockHeight (g) > (Dimension) (2 * SIZE_DEFAULT)));
602         register int i;
603         register int delta =
604                         (int)(g->clock.radius - g->clock.tick_spacing) / 3;
605
606         if (! XtIsManaged ((Widget)g))
607                 return;
608
609         g->clock.segbuffptr = g->clock.segbuff;
610         g->clock.numseg = 0;
611
612 /*      Set segments.
613 */
614         for (i = 0; i < 60; i++)
615         {
616                 if (draw_minute_ticks)
617                 {
618                         if ((i % 5) == 0)
619                                 DrawLine (g, g->clock.tick_spacing,
620                                          g->clock.radius, ((double) i)/60.);
621                         else
622                                 DrawLine (g, g->clock.radius - delta,
623                                          g->clock.radius, ((double) i)/60.);
624                 }
625                 else
626                         if ((i % 15) == 0)
627                                 DrawLine (g, g->clock.radius - 1,
628                                          g->clock.radius, ((double) i)/60.);
629         }
630
631 /*      Draw clock face.
632 */
633         XDrawSegments (XtDisplay (g), XtWindow (g), G_ClockHandGC (g),
634                         (XSegment *) & (g->clock.segbuff[0]),
635                         g->clock.numseg/2);
636         
637         g->clock.segbuffptr = g->clock.segbuff;
638         g->clock.numseg = 0;
639 }
640
641
642 \f
643 /*-------------------------------------------------------------
644 **      Action Procs
645 **-------------------------------------------------------------
646 */
647
648 /*-------------------------------------------------------------
649 **      Core Procs
650 **-------------------------------------------------------------
651 */
652
653 \f
654 /*-------------------------------------------------------------
655 **      Initialize
656 **              Initialize a new gadget instance.
657 */
658 /* ARGSUSED */
659 static void 
660 Initialize(
661         Widget request_w,
662         Widget new_w )
663 {
664         DtClockGadget   request =        (DtClockGadget) request_w,
665                         new =            (DtClockGadget) new_w;
666         Dimension       w, h,
667                         h_t =           G_HighlightThickness (new),
668                         s_t =           G_ShadowThickness (new);
669         XmManagerWidget mw = (XmManagerWidget) XtParent (new);
670         EventMask       mask;
671         String          name = NULL;
672
673 /*      Set width and height.
674 */
675         if ((G_Width (request) == 0) ||
676             (G_Height (request) == 0))
677         {
678                 G_ClockWidth (new) = SIZE_DEFAULT;
679                 G_ClockHeight (new) = SIZE_DEFAULT;
680                 G_GetSize ((DtIconGadget)new, &w, &h);
681                 if (G_Width (request) == 0)
682                         G_Width (new) = w;
683                 if (G_Height (request) == 0)
684                         G_Height (new) = h;
685         }
686
687         Resize ((Widget)new);
688
689         if (G_ClockInterval (new) <= 0)
690                 G_ClockInterval (new) = 60;     /* make invalid update's use a default */
691         new->clock.interval_id = 0;
692         new->clock.numseg = 0;
693 }
694
695
696 \f
697 /*-------------------------------------------------------------
698 **      Destroy
699 **              Release resources allocated for gadget.
700 */
701 static void 
702 Destroy(
703         Widget w )
704 {
705         DtClockGadget   g =      (DtClockGadget) w;
706         XmManagerWidget mw = (XmManagerWidget) XtParent (g);
707
708         if (g->clock.interval_id) XtRemoveTimeOut (g->clock.interval_id);
709
710         XtReleaseGC ((Widget) mw, G_ClockHandGC (g));
711 }
712
713
714 \f
715 /*-------------------------------------------------------------
716 **      Resize
717 **              Set positions of string and pixmap.
718 */
719 static void 
720 Resize(
721         Widget widget )
722 {
723         DtClockGadget   g =      (DtClockGadget) widget;
724         Position        pix_x, pix_y, str_x, str_y;
725         Dimension       s_t = G_ShadowThickness (g),
726                         h_t = G_HighlightThickness (g),
727                         p_w = G_PixmapWidth (g),
728                         p_h = G_PixmapHeight (g),
729                         m_w = G_MarginWidth (g),
730                         m_h = G_MarginHeight (g),
731                         s_w = G_StringWidth (g),
732                         s_h = G_StringHeight (g),
733                         v_pad = 2 * (s_t + h_t + m_h),
734                         h_pad = 2 * (s_t + h_t + m_w),
735                         spacing = G_Spacing (g),
736                         w = G_Width (g),
737                         h = G_Height (g);
738         int             radius;
739
740         G_ClockWidth (g) = p_w - G_LeftInset (g) - G_RightInset (g);
741         G_ClockHeight (g) = p_h - G_TopInset (g) - G_BottomInset (g);
742         
743         G_ClockWidth (g) = min (G_ClockWidth (g), G_ClockHeight (g));
744         G_ClockHeight (g) = G_ClockWidth (g);
745
746         G_GetPositions ((DtIconGadget)g, w, h, h_t, s_t,
747                          &pix_x, &pix_y, &str_x, &str_y);
748
749 /*      Compute clock size factors.
750 *       (need signed radius value since Dimension is unsigned)
751 */
752         radius = ((int) min (G_ClockWidth (g), G_ClockHeight (g))/2);
753         g->clock.radius = (Dimension) max (radius, 1);
754
755         if (G_ClockWidth (g) < (Dimension)(SIZE_DEFAULT / 2))
756         {
757                 g->clock.tick_spacing =
758                    ((Dimension)(TICK_FRACT * g->clock.radius)/100);
759                 g->clock.minute_hand_length =
760                    ((Dimension)(MINUTE_HAND_FRACT * g->clock.radius)/100);
761                 g->clock.hour_hand_length =
762                    ((Dimension)(HOUR_HAND_FRACT * g->clock.radius)/100);
763                 g->clock.hand_width =
764                    ((Dimension)(HAND_WIDTH_FRACT * g->clock.radius)/100);
765         }
766         else
767         {
768                 g->clock.tick_spacing =
769                    ((Dimension)(SMALL_TICK_FRACT * g->clock.radius)/100);
770                 g->clock.minute_hand_length =
771                    ((Dimension)(SMALL_MINUTE_HAND_FRACT * g->clock.radius)/100);
772                 g->clock.hour_hand_length =
773                    ((Dimension)(SMALL_HOUR_HAND_FRACT * g->clock.radius)/100);
774                 g->clock.hand_width =
775                    ((Dimension)(SMALL_HAND_WIDTH_FRACT * g->clock.radius)/100);
776         }
777
778 /*      Compute clock position factors.
779 */
780         g->clock.centerX = pix_x + (p_w / 2);
781         g->clock.centerY = pix_y + (p_h / 2);
782 }
783
784
785 \f
786 /*-------------------------------------------------------------
787 **      SetValues
788 **              
789 */
790 #if 0
791 /* ARGSUSED */
792 static Boolean 
793 SetValues(
794         Widget current_w,
795         Widget request_w,
796         Widget new_w )
797 {
798         DtClockGadget   request =        (DtClockGadget) request_w,
799                         current =        (DtClockGadget) current_w,
800                         new =            (DtClockGadget) new_w;
801         Boolean         redraw_flag = False;
802
803         if (G_ClockInterval (new) != current->clock.update)
804         {
805                 if (current->clock.interval_id)
806                         XtRemoveTimeOut (current->clock.interval_id);
807                 if (XtIsRealized (new))
808                         new->clock.interval_id =
809                                 XtAppAddTimeOut (
810                                         XtWidgetToApplicationContext (new_w),
811                                         G_ClockInterval (new)*1000,
812                                         (XtTimerCallbackProc) ClockTick, 
813                                         (XtPointer)new_w);
814         }
815
816 /*      Update clock face and hand color.
817 */
818         if ((G_ClockBackground (new) != G_ClockBackground (current)) ||
819             (G_ClockHandPixel (new) != G_ClockHandPixel (current)))
820         {
821                 G_UpdateGCs ((DtIconGadget)new);
822                 redraw_flag = True;
823         }
824
825 /*      Update size factors if no resize.
826 */
827         if ((G_Width (new) == G_Width (current) &&
828              G_Height (new) == G_Height (current)) &&
829             (G_MarginWidth (new) != G_MarginWidth (current) ||
830              G_MarginHeight (new) != G_MarginHeight (current) ||
831              G_Spacing (new) != G_Spacing (current) ||
832              G_ShadowThickness (new) != G_ShadowThickness (current) ||
833              G_HighlightThickness (new) != G_HighlightThickness (current)))
834                 Resize (new_w);
835
836         return (redraw_flag);
837 }
838 #endif /* 0 */
839
840
841 /*-------------------------------------------------------------
842 **      Gadget Procs
843 **-------------------------------------------------------------
844 */
845
846 \f
847 /*-------------------------------------------------------------
848 **      Icon Procs
849 **-------------------------------------------------------------
850 */
851
852 /*-------------------------------------------------------------
853 **      Draw
854 **              Draw gadget to drawable.
855 */
856 static void 
857 Draw(
858         DtClockGadget g,
859         Drawable drawable,
860         Position x,
861         Position y,
862         Dimension w,
863         Dimension h,
864         Dimension h_t,
865         Dimension s_t,
866         unsigned char s_type,
867         unsigned char fill_mode )
868 {
869    XmManagerWidget mgr = (XmManagerWidget) XtParent (g);
870    Display * d = XtDisplay (g);
871    GC gc;
872    XRectangle clip;
873    Position p_x, p_y, s_x, s_y;
874    unsigned char behavior =     G_Behavior (g);
875    Dimension m_w = G_MarginWidth (g);
876    Dimension m_h = G_MarginHeight (g);
877    Dimension h_pad = h_t + s_t + m_w;
878    Dimension v_pad = h_t + s_t + m_h;
879    Dimension width, height;
880    Pixmap pix;
881    Pixmap mask;
882    Boolean bMono;
883
884    bMono = ( ((G_Foreground (g) == BlackPixelOfScreen (XtScreen (g))) ||
885               (G_Foreground (g) == WhitePixelOfScreen (XtScreen (g)))) &&
886              ((G_Background (g) == BlackPixelOfScreen (XtScreen (g))) ||
887               (G_Background (g) == WhitePixelOfScreen (XtScreen (g)))) );
888
889    if ((G_Armed (g)) && (fill_mode != XmFILL_PARENT))
890        gc = G_ArmedBackgroundGC (g);
891    else
892        gc = M_BackgroundGC (mgr);
893
894    if ((fill_mode != XmFILL_NONE) && (fill_mode != XmFILL_TRANSPARENT))
895        XFillRectangle (d, drawable, gc, x + h_t, y + h_t,
896                                    w - 2 * h_t, h - 2 * h_t);
897
898    G_GetPositions ((DtIconGadget)g, w, h, h_t, s_t, &p_x, &p_y, &s_x, &s_y);
899
900    if (G_Pixmap (g))
901        {
902        width = ((Dimension)(p_x + s_t + h_t) >= G_Width (g))
903                            ? 0 : min (G_PixmapWidth (g),
904                                    (Dimension)(G_Width (g) - p_x - s_t - h_t));
905        height = ((Dimension)(p_y + s_t + h_t) >= G_Height (g))
906                            ? 0 : min (G_PixmapHeight (g),
907                                    (Dimension)(G_Height (g) - p_y - s_t - h_t));
908    /*   Use normal image.
909     */
910        pix = G_Pixmap (g);
911        mask = G_Mask (g);
912
913    /*   Update clip gc.
914     */
915        if (mask != XmUNSPECIFIED_PIXMAP)
916            {
917            gc = G_ClipGC (g);
918            XSetClipMask (XtDisplay(g), gc, mask);
919            XSetClipOrigin (XtDisplay(g), gc, x + p_x, y + p_y);
920            }
921        else
922            gc = G_NormalGC (g);
923            
924    /*   Paint pixmap.
925     */
926        if ((gc != NULL) && (pix != XmUNSPECIFIED_PIXMAP))
927            XCopyArea (d, pix, drawable, gc, 0, 0,
928                            width, height, x + p_x, y + p_y);
929        }
930
931    /*   Fill clock face region and draw clock.
932    */
933            if (g->clock.numseg != 0)
934                    EraseHands (g, (struct tm *) 0);
935
936            ClockTick ((XtPointer)g, (XtIntervalId)0);
937
938    /*   Draw shadow.
939    */
940            if ((behavior == XmICON_BUTTON || behavior == XmICON_DRAG) &&
941                 G_FillOnArm (g) && G_Armed (g))
942                    gc = G_ArmedGC (g);
943            else if (behavior == XmICON_TOGGLE && G_FillOnArm (g) &&
944                     ((G_Armed (g) && !G_Set (g)) ||
945                      (!G_Armed (g) && G_Set (g))))
946                    gc = G_ArmedGC (g);
947            else
948                    gc = G_NormalGC (g);
949
950    /*   Draw string.
951    */
952            if (G_String (g))
953            {
954                    clip.x = x + h_t + s_x;
955                    clip.y = y + h_t + s_y;
956                    clip.width = G_Width (g) - (2 * (h_t + s_t));
957                    clip.height = G_Height (g) - (2 * (h_t + s_t));
958                    if (clip.width > 0 && clip.height > 0)
959                    {
960                       if (bMono)
961                       {
962                          if ((s_x - 2) >= (Position)(h_t + s_t))
963                             XFillRectangle (d, drawable,
964                                             G_ArmedBackgroundGC (g),
965                                             x + s_x - 2, y + s_y,
966                                             2, G_StringHeight (g));
967                          XmStringDrawImage (d, drawable, G_FontList (g),
968                                             G_String (g), G_NormalGC (g),
969                                             x + s_x, y + s_y,
970                                             clip.width, XmALIGNMENT_BEGINNING,
971                                             XmSTRING_DIRECTION_L_TO_R, &clip);
972                          if ((s_x + (Position)(G_StringWidth (g) + 2))
973                              <= (Position)(G_Width (g) - h_t - s_t))
974                             XFillRectangle (d, drawable,
975                                             G_ArmedBackgroundGC (g),
976                                             x + s_x + G_StringWidth (g),
977                                             y + s_y, 2, G_StringHeight (g));
978                       }
979                       else
980                       {
981                          if (G_UseEmbossedText (g))
982                             XmStringDraw (d, drawable, G_FontList (g),
983                                           G_String (g), G_BottomShadowGC (g),
984                                           x + s_x + 1, y + s_y + 1,
985                                           clip.width, XmALIGNMENT_BEGINNING,
986                                           XmSTRING_DIRECTION_L_TO_R, &clip);
987                          XmStringDraw (d, drawable, G_FontList (g),
988                                        G_String (g), G_NormalGC (g),
989                                        x + s_x, y + s_y,
990                                        clip.width, XmALIGNMENT_BEGINNING,
991                                        XmSTRING_DIRECTION_L_TO_R, &clip);
992
993                       }
994                    }
995            }
996
997 }
998
999
1000 \f
1001 /*-------------------------------------------------------------
1002 **      UpdateGCs
1003 **              Get normal and background graphics contexts.
1004 **              Use standard mask to maximize caching opportunities.
1005 */
1006 static void 
1007 UpdateGCs(
1008         DtClockGadget g )
1009 {
1010 XGCValues       values;
1011 XtGCMask        value_mask;
1012 XmManagerWidget mw = (XmManagerWidget) XtParent(g);
1013 XFontStruct *   font;
1014 Boolean         font_rtn;
1015 DtIconGadgetClass
1016                 super = (DtIconGadgetClass) XtSuperclass (g);
1017 static Boolean  first = True;
1018
1019 /*      Let superclass do most of the work.
1020 */
1021 (* C_UpdateGCs (super)) ((DtIconGadget)g);
1022
1023 if (first)
1024         first = False;
1025 else if (G_ClockHandGC (g))
1026         XtReleaseGC ((Widget)mw, G_ClockHandGC (g));
1027
1028 /*      Get clock hand GC.
1029 */
1030 font_rtn = XmeRenderTableGetDefaultFont (G_FontList (g), &font);
1031 value_mask = GCForeground | GCFont | GCFillStyle;
1032
1033 if (((G_PixmapForeground (g) == WhitePixelOfScreen (XtScreen (g))) &&
1034      (G_PixmapBackground (g) == BlackPixelOfScreen (XtScreen (g)))) ||
1035     ((G_PixmapForeground (g) == BlackPixelOfScreen (XtScreen (g))) &&
1036      (G_PixmapBackground (g) == WhitePixelOfScreen (XtScreen (g)))))
1037     values.foreground = G_PixmapBackground (g);
1038 else
1039     values.foreground = mw->manager.top_shadow_color;
1040 values.fill_style = FillSolid;
1041 values.font = font->fid;
1042
1043 G_ClockHandGC (g) = XtGetGC ((Widget) mw, value_mask, &values);
1044
1045 /*      Get clock background GC
1046 */
1047
1048 value_mask |= GCBackground;
1049
1050 if (((G_PixmapForeground (g) == WhitePixelOfScreen (XtScreen (g))) &&
1051      (G_PixmapBackground (g) == BlackPixelOfScreen (XtScreen (g)))) ||
1052     ((G_PixmapForeground (g) == BlackPixelOfScreen (XtScreen (g))) &&
1053      (G_PixmapBackground (g) == WhitePixelOfScreen (XtScreen (g)))))
1054     values.foreground = G_PixmapForeground (g);
1055 else
1056     values.foreground = G_ArmColor (g);
1057 values.background = G_PixmapBackground (g);
1058
1059 G_ClockBackgroundGC (g) = XtGetGC ((Widget) mw, value_mask, &values);
1060 }
1061
1062
1063 \f
1064 /*-------------------------------------------------------------
1065 **      Public Entry Points
1066 **-------------------------------------------------------------
1067 */
1068
1069 /*-------------------------------------------------------------
1070 **      DtCreateClock
1071 **              Create a new gadget instance.
1072 **-------------------------------------------------------------
1073 */
1074 Widget 
1075 DtCreateClock(
1076         Widget parent,
1077         String name,
1078         ArgList arglist,
1079         Cardinal argcount )
1080 {
1081         return (XtCreateWidget (name, dtClockGadgetClass, 
1082                         parent, arglist, argcount));
1083 }