home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / XAP / XFILEMAN / XFILEMAN.TAR / xfilemanager / Clock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-22  |  12.0 KB  |  445 lines

  1. /*
  2.  * $XConsortium: Clock.c,v 1.24 91/05/22 17:20:31 converse Exp $
  3.  *
  4.  * Copyright 1989 Massachusetts Institute of Technology
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of M.I.T. not be used in advertising or
  11.  * publicity pertaining to distribution of the software without specific,
  12.  * written prior permission.  M.I.T. makes no representations about the
  13.  * suitability of this software for any purpose.  It is provided "as is"
  14.  * without express or implied warranty.
  15.  *
  16.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  18.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  21.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  */
  23.  
  24. /*
  25.  * Clock.c
  26.  *
  27.  * a NeWS clone clock
  28.  */
  29.  
  30. #include <X11/IntrinsicP.h>
  31. #include <X11/StringDefs.h>
  32. #include <X11/Xmu/Converters.h>
  33. #include "ClockP.h"
  34. #include <X11/Xos.h>
  35. #include <stdio.h>
  36. #include <math.h>
  37. #include <X11/extensions/shape.h>
  38.  
  39. #ifdef AIXV3
  40. #include <time.h>
  41. #endif
  42.  
  43. #ifdef X_NOT_STDC_ENV
  44. extern struct tm *localtime();
  45. #endif
  46.  
  47. #define offset(field) XtOffsetOf(ClockRec, clock.field)
  48. #define goffset(field) XtOffsetOf(WidgetRec, core.field)
  49.  
  50. static XtResource resources[] = {
  51.     {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  52.         goffset(width), XtRImmediate, (XtPointer) 120},
  53.     {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  54.     goffset(height), XtRImmediate, (XtPointer) 120},
  55.     {XtNminute, XtCForeground, XtRPixel, sizeof (Pixel),
  56.     offset(minute), XtRString, XtDefaultForeground},
  57.     {XtNhour, XtCForeground, XtRPixel, sizeof (Pixel),
  58.     offset(hour), XtRString, XtDefaultForeground},
  59.     {XtNjewel, XtCForeground, XtRPixel, sizeof (Pixel),
  60.     offset(jewel), XtRString, XtDefaultForeground},
  61.     {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
  62.         offset (backing_store), XtRString, "default"},
  63.     {XtNborderSize, XtCBorderSize, XtRFloat, sizeof (float),
  64.     offset (border_size), XtRString, "0.1"},
  65.     {XtNjewelSize, XtCBorderSize, XtRFloat, sizeof (float),
  66.     offset (jewel_size), XtRString, "0.075"},
  67.     {XtNshapeWindow, XtCShapeWindow, XtRBoolean, sizeof (Boolean),
  68.     offset (shape_window), XtRImmediate, (XtPointer) True},
  69.     {XtNtransparent, XtCTransparent, XtRBoolean, sizeof (Boolean),
  70.     offset (transparent), XtRImmediate, (XtPointer) False},
  71. };
  72.  
  73. #undef offset
  74. #undef goffset
  75.  
  76. static void     new_time();
  77.  
  78. static void Initialize(), Realize(), Destroy(), Redisplay(), Resize();
  79.  
  80. # define BORDER_SIZE(w)    ((w)->clock.border_size)
  81. # define WINDOW_WIDTH(w)    (2.0 - BORDER_SIZE(w)*2)
  82. # define WINDOW_HEIGHT(w)   (2.0 - BORDER_SIZE(w)*2)
  83. # define MINUTE_WIDTH(w)    (0.05)
  84. # define HOUR_WIDTH(w)        (0.05)
  85. # define JEWEL_SIZE(w)        ((w)->clock.jewel_size)
  86. # define MINUTE_LENGTH(w)   (JEWEL_Y(w) - JEWEL_SIZE(w) / 2.0)
  87. # define HOUR_LENGTH(w)        (MINUTE_LENGTH(w) * 0.6)
  88. # define JEWEL_X(w)        (0.0)
  89. # define JEWEL_Y(w)        (1.0 - (BORDER_SIZE(w) + JEWEL_SIZE(w)))
  90.  
  91. static void ClassInitialize();
  92.  
  93. ClockClassRec clockClassRec = {
  94.     { /* core fields */
  95.     /* superclass        */    &widgetClassRec,
  96.     /* class_name        */    "Clock",
  97.     /* size            */    sizeof(ClockRec),
  98.     /* class_initialize        */    ClassInitialize,
  99.     /* class_part_initialize    */    NULL,
  100.     /* class_inited        */    FALSE,
  101.     /* initialize        */    Initialize,
  102.     /* initialize_hook        */    NULL,
  103.     /* realize            */    Realize,
  104.     /* actions            */    NULL,
  105.     /* num_actions        */    0,
  106.     /* resources        */    resources,
  107.     /* num_resources        */    XtNumber(resources),
  108.     /* xrm_class        */    NULLQUARK,
  109.     /* compress_motion        */    TRUE,
  110.     /* compress_exposure    */    TRUE,
  111.     /* compress_enterleave    */    TRUE,
  112.     /* visible_interest        */    FALSE,
  113.     /* destroy            */    Destroy,
  114.     /* resize            */    Resize,
  115.     /* expose            */    Redisplay,
  116.     /* set_values        */    NULL,
  117.     /* set_values_hook        */    NULL,
  118.     /* set_values_almost    */    NULL,
  119.     /* get_values_hook        */    NULL,
  120.     /* accept_focus        */    NULL,
  121.     /* version            */    XtVersion,
  122.     /* callback_private        */    NULL,
  123.     /* tm_table            */    NULL,
  124.     /* query_geometry        */    XtInheritQueryGeometry,
  125.     }
  126. };
  127.  
  128. static void ClassInitialize()
  129. {
  130.     XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
  131.             NULL, 0 );
  132. }
  133.  
  134. WidgetClass clockWidgetClass = (WidgetClass) &clockClassRec;
  135.  
  136. /* ARGSUSED */
  137. static void Initialize (greq, gnew)
  138.     Widget greq, gnew;
  139. {
  140.     ClockWidget w = (ClockWidget)gnew;
  141.     XtGCMask    valuemask;
  142.     XGCValues    myXGCV;
  143.     int shape_event_base, shape_error_base;
  144.  
  145.     valuemask = GCForeground;
  146.  
  147.     myXGCV.foreground = w->clock.minute;
  148.     w->clock.minuteGC = XtGetGC(gnew, valuemask, &myXGCV);
  149.  
  150.     myXGCV.foreground = w->clock.hour;
  151.     w->clock.hourGC = XtGetGC(gnew, valuemask, &myXGCV);
  152.  
  153.     myXGCV.foreground = w->clock.jewel;
  154.     w->clock.jewelGC = XtGetGC(gnew, valuemask, &myXGCV);
  155.  
  156.     myXGCV.foreground = w->core.background_pixel;
  157.     w->clock.eraseGC = XtGetGC(gnew, valuemask, &myXGCV);
  158.  
  159.     /* wait for Realize to add the timeout */
  160.     w->clock.interval_id = 0;
  161.  
  162.     w->clock.shape_window = False;
  163.     w->clock.shape_mask = 0;
  164.     w->clock.shapeGC = 0;
  165.     w->clock.shape_width = 0;
  166.     w->clock.shape_height = 0;
  167.     w->clock.polys_valid = 0;
  168. }
  169.  
  170. static void Resize (w)
  171.     ClockWidget    w;
  172. {
  173.     XGCValues    xgcv;
  174.     Widget    parent;
  175.     XWindowChanges    xwc;
  176.     int        face_width, face_height;
  177.     int        x, y;
  178.     Pixmap    shape_mask;
  179.  
  180.     if (XtIsRealized((Widget) w) == FALSE)
  181.     return;
  182.  
  183.     /*
  184.      * compute desired border size
  185.      */
  186.  
  187.     SetTransform (&w->clock.maskt,
  188.           0, w->core.width,
  189.           w->core.height, 0,
  190.           -1.0, 1.0,
  191.            -1.0, 1.0);
  192.  
  193.     face_width = abs (Xwidth (BORDER_SIZE(w), BORDER_SIZE(w), &w->clock.maskt));
  194.     face_height = abs (Xheight (BORDER_SIZE(w), BORDER_SIZE(w), &w->clock.maskt));
  195.  
  196.     /*
  197.      *  shape the windows and borders
  198.      */
  199.  
  200.     /*
  201.      * reconfigure the widget to split the availible
  202.      * space between the window and the border
  203.      */
  204.  
  205.     if (face_width > face_height)
  206.     xwc.border_width = face_height;
  207.     else
  208.     xwc.border_width = face_width;
  209.     xwc.width = w->core.width - xwc.border_width * 2;
  210.     xwc.height = w->core.height - xwc.border_width * 2;
  211.     XConfigureWindow (XtDisplay (w), XtWindow (w),
  212.             CWWidth|CWHeight|CWBorderWidth,
  213.             &xwc);
  214.  
  215.     SetTransform (&w->clock.t, 0, xwc.width,
  216.                 xwc.height, 0,
  217.                 -WINDOW_WIDTH(w)/2, WINDOW_WIDTH(w)/2,
  218.                 -WINDOW_HEIGHT(w)/2, WINDOW_HEIGHT(w)/2);
  219. }
  220.  
  221. static void Realize (gw, valueMask, attrs)
  222.      Widget gw;
  223.      XtValueMask *valueMask;
  224.      XSetWindowAttributes *attrs;
  225. {
  226.      ClockWidget    w = (ClockWidget)gw;
  227.  
  228.     if (w->clock.backing_store != Always + WhenMapped + NotUseful) {
  229.          attrs->backing_store = w->clock.backing_store;
  230.     *valueMask |= CWBackingStore;
  231.     }
  232.     XtCreateWindow( gw, (unsigned)InputOutput, (Visual *)CopyFromParent,
  233.              *valueMask, attrs );
  234.     Resize (w);
  235.     new_time ((XtPointer) gw, 0);
  236. }
  237.  
  238. static void Destroy (gw)
  239.      Widget gw;
  240. {
  241.      ClockWidget w = (ClockWidget)gw;
  242.      if (w->clock.interval_id) XtRemoveTimeOut (w->clock.interval_id);
  243.      if (w->clock.shapeGC)
  244.     XFreeGC(XtDisplay(gw), w->clock.shapeGC);
  245.      if (w->clock.shape_mask)
  246.     XFreePixmap (XtDisplay (w), w->clock.shape_mask);
  247. }
  248.  
  249. /* ARGSUSED */
  250. static void Redisplay(gw, event, region)
  251.      Widget gw;
  252.      XEvent *event;
  253.      Region region;
  254. {
  255.     ClockWidget    w;
  256.  
  257.     w = (ClockWidget) gw;
  258.     paint_jewel (w, XtWindow (w), w->clock.jewelGC);
  259.     paint_hands (w, XtWindow (w), w->clock.minuteGC, w->clock.hourGC);
  260. }
  261.  
  262. /*
  263.  * routines to draw the hands and jewel
  264.  */
  265.  
  266. #ifndef PI    /* may be found in <math.h> */
  267. # define PI (3.14159265358979323846)
  268. #endif
  269.  
  270. /*
  271.  * converts a number from 0..1 representing a clockwise radial distance
  272.  * from the 12 oclock position to a radian measure of the counter-clockwise
  273.  * distance from the 3 oclock position
  274.  */
  275.  
  276. static double
  277. clock_to_angle (clock)
  278. double    clock;
  279. {
  280.     if (clock >= .75)
  281.         clock -= 1.0;
  282.     return -2.0 * PI * clock + PI / 2.0;
  283. }
  284.  
  285. /* ARGSUSED */
  286. static void new_time (client_data, id)
  287.      XtPointer client_data;
  288.      XtIntervalId *id;        /* unused */
  289. {
  290.         ClockWidget    w = (ClockWidget)client_data;
  291.     long        now;
  292.     struct tm    *tm;
  293.     
  294.     if (w->clock.polys_valid) {
  295.         paint_hands (w, XtWindow (w), w->clock.eraseGC, w->clock.eraseGC);
  296.         check_jewel (w, XtWindow (w), w->clock.jewelGC);
  297.     }
  298.     (void) time (&now);
  299.     tm = localtime (&now);
  300.     if (tm->tm_hour >= 12)
  301.         tm->tm_hour -= 12;
  302.     w->clock.hour_angle = clock_to_angle ((((double) tm->tm_hour) +
  303.                 ((double) tm->tm_min) / 60.0) / 12.0);
  304.     w->clock.minute_angle =
  305.         clock_to_angle (((double) tm->tm_min) / 60.0);
  306.     /*
  307.      * add the timeout before painting the hands, that may
  308.      * take a while and we'd like the clock to keep up
  309.      * with time changes.
  310.      */
  311.     w->clock.interval_id = 
  312.         XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w),
  313.                  (60 - tm->tm_sec) * 1000, new_time, client_data);
  314.     compute_hands (w);
  315.     paint_hands (w, XtWindow (w), w->clock.minuteGC, w->clock.hourGC);
  316. } /* new_time */
  317.  
  318. paint_jewel (w, d, gc)
  319. ClockWidget w;
  320. Drawable    d;
  321. GC        gc;
  322. {
  323.     if (JEWEL_SIZE(w) > 0.0)
  324.     {
  325.     TFillArc (XtDisplay (w), d, gc, &w->clock.t,
  326.             JEWEL_X(w) - JEWEL_SIZE(w) / 2.0,
  327.              JEWEL_Y(w) - JEWEL_SIZE(w) / 2.0,
  328.              JEWEL_SIZE(w), JEWEL_SIZE(w), 0, 360 * 64);
  329.     }
  330. }
  331.  
  332. #define sqr(x)    ((x)*(x))
  333.  
  334. /*
  335.  * check to see if the polygon intersects the circular jewel
  336.  */
  337.  
  338. check_jewel_poly (w, poly)
  339. ClockWidget    w;
  340. TPoint        poly[POLY_SIZE];
  341. {
  342.     double    a2, b2, c2, d2;
  343.     double    x, y, size;
  344.     int    i;
  345.  
  346.     if (JEWEL_SIZE(w) > 0.0)
  347.     {
  348.     x = JEWEL_X(w);
  349.     y = JEWEL_Y(w);
  350.     size = JEWEL_SIZE(w);
  351.     /*
  352.      * check each side of the polygon to see if the
  353.      * distance from the line to the center of the
  354.      * circular jewel is less than the radius.
  355.      */
  356.     for (i = 0; i < POLY_SIZE-1; i++) {
  357.         a2 = sqr (poly[i].x - x) + sqr (poly[i].y - y);
  358.         b2 = sqr (poly[i+1].x - x) + sqr (poly[i+1].y - y);
  359.         c2 = sqr (poly[i].x - poly[i+1].x) + sqr (poly[i].y - poly[i+1].y);
  360.         d2 = a2 + b2 - c2;
  361.         if (d2 <= sqr (size) &&
  362.             a2 <= 2 * c2 && b2 <= 2 * c2 ||
  363.              a2 <= sqr (size) ||
  364.             b2 <= sqr (size))
  365.             return 1;
  366.     }
  367.     }
  368.     return 0;
  369. }
  370.  
  371. check_jewel (w, d, gc)
  372. ClockWidget    w;
  373. Drawable    d;
  374. GC        gc;
  375. {
  376.     if (!w->clock.polys_valid || JEWEL_SIZE(w) <= 0.0)
  377.         return;
  378.     if ((MINUTE_LENGTH(w) >= (JEWEL_Y(w) - JEWEL_SIZE(w)/2.0) &&
  379.          check_jewel_poly (w, w->clock.minute_poly)) ||
  380.         (HOUR_LENGTH(w) >= (JEWEL_Y(w) - JEWEL_SIZE(w)/2.0) &&
  381.          check_jewel_poly (w, w->clock.minute_poly)))
  382.     {
  383.         paint_jewel (w, d, gc);
  384.     }
  385. }
  386.  
  387. /*
  388.  * A hand is a rectangle with a triangular cap at the far end.
  389.  * This is represented with a five sided polygon.
  390.  */
  391.  
  392. compute_hand (w, a, l, width, poly)
  393. ClockWidget    w;
  394. double        a, l, width;
  395. TPoint        poly[POLY_SIZE];
  396. {
  397.     double    c, s;
  398.  
  399.     c = cos(a);
  400.     s = sin(a);
  401.     poly[0].x = c * l;    
  402.     poly[0].y = s * l;
  403.     poly[1].x = (l - width) * c - s * width;
  404.     poly[1].y = (l - width) * s + c * width;
  405.     poly[2].x = (-width) * c - s * width;
  406.     poly[2].y = (-width) * s + c * width;
  407.     poly[3].x = (-width) * c + s * width;
  408.     poly[3].y = (-width) * s - c * width;
  409.     poly[4].x = (l - width) * c + s * width;
  410.     poly[4].y = (l - width) * s - c * width;
  411.     poly[5].x = poly[0].x;
  412.     poly[5].y = poly[0].y;
  413. }
  414.  
  415. compute_hands (w)
  416. ClockWidget    w;
  417. {
  418.     compute_hand (w, w->clock.minute_angle,
  419.         MINUTE_LENGTH(w), MINUTE_WIDTH(w), w->clock.minute_poly);
  420.     compute_hand (w, w->clock.hour_angle,
  421.         HOUR_LENGTH(w), HOUR_WIDTH(w), w->clock.hour_poly);
  422.     w->clock.polys_valid = 1;
  423. }
  424.  
  425. paint_hand (w, d, gc, poly)
  426. ClockWidget    w;
  427. Drawable    d;
  428. GC        gc;
  429. TPoint        poly[POLY_SIZE];
  430. {
  431.     TFillPolygon (XtDisplay (w), d, gc, &w->clock.t, poly, POLY_SIZE,
  432.             Convex, CoordModeOrigin);
  433. }
  434.  
  435. paint_hands (w, d, minute_gc, hour_gc)
  436. ClockWidget    w;
  437. Drawable    d;
  438. GC        minute_gc, hour_gc;
  439. {
  440.     if (w->clock.polys_valid) {
  441.     paint_hand (w, d, hour_gc, w->clock.hour_poly);
  442.     paint_hand (w, d, minute_gc, w->clock.minute_poly);
  443.     }
  444. }
  445.