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