home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / d / d020_1_4 / 5.ddi / CLOCK / CLOCK.C next >
Encoding:
C/C++ Source or Header  |  1990-06-01  |  33.1 KB  |  838 lines

  1. /***************************************************************************
  2.  *                                                                         *
  3.  *  PROGRAM   : Clock.c                                                    *
  4.  *                                                                         *
  5.  *  PURPOSE   : To give a demonstration on the use of a timer in a windows *
  6.  *              application.                                               *
  7.  *                                                                         *
  8.  *  MACROS    : HourHandPos  - Computes the hour hand position based on    *
  9.  *                             both the hour and minute values.            *
  10.  *                                                                         *
  11.  *              VertEquiv    - Computes the raster line equivalent to the  *
  12.  *                             given pixel value.                          *
  13.  *                                                                         *
  14.  *              HorzEquiv    - Computes the pixel equivalent to the given  *
  15.  *                             raster line value.                          *
  16.  *                                                                         *
  17.  *  FUNCTIONS : About        - Dialog function for the About Dialog.       *
  18.  *                                                                         *
  19.  *              ClockWndProc - Window function for the application.        *
  20.  *                                                                         *
  21.  *              CreateTools  - Creates brushes and pens to coincide with   *
  22.  *                             the current system colors.                  *
  23.  *                                                                         *
  24.  *              DeleteTools  - Destroys the brushes and pens created by    *
  25.  *                             CreateTools.                                *
  26.  *                                                                         *
  27.  *              ClockCreate  - Performs the necessary initialization for   *
  28.  *                             drawing the clock correctly and gets the    *
  29.  *                             initial time to be displayed by the clock.  *
  30.  *                                                                         *
  31.  *              ClockSize    - Resize the clock to the largest possible    *
  32.  *                             circle that will fit in the client area.    *
  33.  *                                                                         *
  34.  *              ClockTimer   - Update the clock to reflect the most recent *
  35.  *                             time.                                       *
  36.  *                                                                         *
  37.  *              ClockPaint   - Paint the clock to display the most recent  *
  38.  *                             time.                                       *
  39.  *                                                                         *
  40.  *              DrawFace     - Draws the clock face.                       *
  41.  *                                                                         *
  42.  *              DrawHand     - Draws a thin hand with the specified brush  *
  43.  *                             in the specified hand position.             *
  44.  *                                                                         *
  45.  *              DrawFatHand  - Draws a fat hand with the specified brush   *
  46.  *                             in the specified hand position.             *
  47.  *                                                                         *
  48.  *              CircleClock  - Resizes clock rectangle to keep clock       *
  49.  *                             circular.                                   *
  50.  *                                                                         *
  51.  *              WinMain      - Calls the initialization function, creates  *
  52.  *                             the main application window, and enters the *
  53.  *                             message loop.                               *
  54.  *                                                                         *
  55.  *              ClockInit    - Registers the application window class and  *
  56.  *                             initializes the circle values for the clock *
  57.  *                             face.                                       *
  58.  *                                                                         *
  59.  ***************************************************************************/
  60.  
  61. #include "windows.h"
  62. #include "clock.h"
  63.  
  64. /* Structure for holding time (in hours, minutes, and seconds) */
  65. typedef struct
  66. {
  67.     int hour;
  68.     int minute;
  69.     int second;
  70. } TIME;
  71.  
  72. extern void GetTime(TIME *); /* asm function to get current time */
  73.  
  74. TIME oTime;             /* the time currently displayed on the clock          */
  75.  
  76. HBRUSH hbrForegnd;      /* foreground brush -- system window text color       */
  77. HBRUSH hbrBackgnd;      /* background brush -- system window backbround color */
  78. HPEN   hpenForegnd;     /* foreground pen   -- system window text color       */
  79. HPEN   hpenBackgnd;     /* background pen   -- system window background color */
  80.  
  81. HANDLE hInst;           /* instance of the CLOCK program being executed       */
  82. BOOL   bFirst = TRUE;   /* TRUE if this is the 1st instance; FALSE otherwise  */
  83.  
  84. HANDLE    hCirTab;      /* Circle table for the circular clock face positions */
  85. POINT FAR *lpCirTab;    /* Pointer to the circle table                        */
  86.  
  87. int   TimerID = 1;      /* number used for timer-id                           */
  88. char  szBuffer[BUFLEN]; /* buffer for stringtable data                        */
  89. RECT  ClockRect;        /* rectangle that EXACTLY bounds the clock face       */
  90. long  ClockRadius;      /* clock face radius                                  */
  91. POINT ClockCenter;      /* clock face center                                  */
  92. BOOL  bIconic = FALSE;  /* TRUE if clock is currently iconic; FALSE otherwise */
  93.  
  94. int   HorzRes;          /* width of the display (in pixels)                   */
  95. int   VertRes;          /* height of the display (in raster lines)            */
  96. long  AspectH;          /* number of pixels per decimeter on the display      */
  97. long  AspectV;          /* number of raster lines per decimeter on the display*/
  98.  
  99.  
  100. /***************************************************************************
  101.  *                                                                         *
  102.  *  MACRO    : HourHandPos (TIME)                                          *
  103.  *                                                                         *
  104.  *  PURPOSE  : Computes the hour hand position based on both the hour and  *
  105.  *             minute values in the given time record.                     *
  106.  *                                                                         *
  107.  ***************************************************************************/
  108.  
  109. #define HourHandPos(time)  (time.hour * 5) + (time.minute /12)
  110.  
  111.  
  112. /***************************************************************************
  113.  *                                                                         *
  114.  *  MACRO    : VertEquiv (int)                                             *
  115.  *                                                                         *
  116.  *  PURPOSE  : Computes the raster line (vertical) equivalent to the given *
  117.  *             pixel (horizontal) value.                                   *
  118.  *                                                                         *
  119.  ***************************************************************************/
  120.  
  121. #define VertEquiv(lengthH) ((lengthH * AspectV) / AspectH)
  122.  
  123.  
  124. /***************************************************************************
  125.  *                                                                         *
  126.  *  MACRO    : HorzEquiv (int)                                             *
  127.  *                                                                         *
  128.  *  PURPOSE  : Computes the pixel (horizontal) equivalent to the given     *
  129.  *             raster line (vertical) value.                               *
  130.  *                                                                         *
  131.  ***************************************************************************/
  132.  
  133. #define HorzEquiv(lengthV) ((lengthV * AspectH) / AspectV)
  134.  
  135.  
  136. /***************************************************************************
  137.  *                                                                         *
  138.  *  FUNCTION : About (HWND, unsigned, WORD, LONG)                          *
  139.  *                                                                         *
  140.  *  PURPOSE  : Dialog function for the "About..." menu item dialog.        *
  141.  *                                                                         *
  142.  ***************************************************************************/
  143.  
  144. BOOL FAR PASCAL About(hDlg, message, wParam, lParam)
  145.     HWND     hDlg;
  146.     unsigned message;
  147.     WORD     wParam;
  148.     LONG     lParam;
  149. {
  150.     switch (message)
  151.     {
  152.         case WM_COMMAND:
  153.             EndDialog(hDlg, TRUE);
  154.             /* fall through */
  155.  
  156.         case WM_INITDIALOG:
  157.             return(TRUE);
  158.  
  159.         default:
  160.             return(FALSE);
  161.     }
  162. }
  163.  
  164.  
  165. /***************************************************************************
  166.  *                                                                         *
  167.  *  FUNCTION : ClockWndProc (HWND, unsigned, WORD, LONG)                   *
  168.  *                                                                         *
  169.  *  PURPOSE  : Window function for the application.                        *
  170.  *                                                                         *
  171.  ***************************************************************************/
  172.  
  173. long FAR PASCAL ClockWndProc(hWnd, message, wParam, lParam)
  174.     HWND     hWnd;
  175.     unsigned message;
  176.     WORD     wParam;
  177.     LONG     lParam;
  178. {
  179.     switch (message)
  180.     {
  181.         case WM_SYSCOMMAND:
  182.             if (wParam == IDM_ABOUT)
  183.             {
  184.                 /* Draw and handle messages for the "About..." Dialog */
  185.                 DialogBox(hInst,
  186.                       MAKEINTRESOURCE(1),
  187.                       hWnd,
  188.                       MakeProcInstance((FARPROC) About, hInst));
  189.             }
  190.             else
  191.             {
  192.                 /* Perform the default window processing */
  193.                 return(DefWindowProc(hWnd, message, wParam, lParam));
  194.             }
  195.             break;
  196.  
  197.         case WM_SIZE:
  198.             /* Resize clock based on window size and redraw */
  199.             ClockSize(hWnd, LOWORD(lParam), HIWORD(lParam), wParam);
  200.             UpdateWindow(hWnd);
  201.             break;
  202.  
  203.         case WM_DESTROY:
  204.             /* Destroy clock's timer and tools before exiting */
  205.             KillTimer(hWnd, TimerID);
  206.             DeleteTools();
  207.             PostQuitMessage(0);
  208.             break;
  209.  
  210.         case WM_PAINT:
  211.             {
  212.                 PAINTSTRUCT ps;
  213.  
  214.                 /* Paint clock displaying current time */
  215.                 InvalidateRect(hWnd, (LPRECT) NULL, TRUE);
  216.                 BeginPaint(hWnd, (LPPAINTSTRUCT) &ps);
  217.                 ClockPaint(hWnd, ps.hdc, PAINTALL);
  218.                 EndPaint(hWnd, (LPPAINTSTRUCT) &ps);
  219.             }
  220.             break;
  221.  
  222.         case WM_TIMECHANGE:
  223.         case WM_TIMER:
  224.             /* Update clock to display new time */
  225.             ClockTimer(hWnd);
  226.             break;
  227.  
  228.         case WM_SYSCOLORCHANGE:
  229.             /* Change tools to coincide with system window colors */
  230.             DeleteTools();
  231.             CreateTools();
  232.             break;
  233.  
  234.         case WM_ERASEBKGND:
  235.             {
  236.                 RECT rc;
  237.  
  238.                 /* Paint over the entire client area */
  239.                 GetClientRect(hWnd, (LPRECT) &rc);
  240.                 FillRect((HDC) wParam, (LPRECT) &rc, hbrBackgnd);
  241.             }
  242.             break;
  243.  
  244.         default:
  245.             /* Perform the default window processing */
  246.             return(DefWindowProc(hWnd, message, wParam, lParam));
  247.     }
  248.     return(0L);
  249. }
  250.  
  251.  
  252. /***************************************************************************
  253.  *                                                                         *
  254.  *  FUNCTION : CreateTools ()                                              *
  255.  *                                                                         *
  256.  *  PURPOSE  : Creates brushes and pens to coincide with the current       *
  257.  *             system colors.                                              *
  258.  *                                                                         *
  259.  ***************************************************************************/
  260.  
  261. int CreateTools()
  262. {
  263.     hbrForegnd  = CreateSolidBrush(GetSysColor(COLOR_WINDOWTEXT));
  264.     hbrBackgnd  = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  265.     hpenForegnd = CreatePen(0, 1, GetSysColor(COLOR_WINDOWTEXT));
  266.     hpenBackgnd = CreatePen(0, 1, GetSysColor(COLOR_WINDOW));
  267. }
  268.  
  269.  
  270. /***************************************************************************
  271.  *                                                                         *
  272.  *  FUNCTION : DeleteTools ()                                              *
  273.  *                                                                         *
  274.  *  PURPOSE  : Destroys the brushes and pens created by CreateTools.       *
  275.  *                                                                         *
  276.  ***************************************************************************/
  277.  
  278. int DeleteTools()
  279. {
  280.     DeleteObject(hbrForegnd);
  281.     DeleteObject(hbrBackgnd);
  282.     DeleteObject(hpenForegnd);
  283.     DeleteObject(hpenBackgnd);
  284. }
  285.  
  286.  
  287. /***************************************************************************
  288.  *                                                                         *
  289.  *  FUNCTION : ClockCreate ()                                              *
  290.  *                                                                         *
  291.  *  PURPOSE  : First, for drawing the clock, ClockCreate computes the      *
  292.  *             aspect ratio and creates the necessary pens and brushes.    *
  293.  *             Then, if this is the first instance of the app running,     *
  294.  *             ClockCreate scales the circle table values according to the *
  295.  *             aspect ratio. Finally, ClockCreate gets the initial time.   *
  296.  *                                                                         *
  297.  ***************************************************************************/
  298.  
  299. int ClockCreate()
  300. {
  301.     int  pos;      /* hand position index into the circle table */
  302.     int  vertSize; /* height of the display in millimeters      */
  303.     int  horzSize; /* width of the display in millimeters       */
  304.     HDC  hDC;
  305.     RECT rc;
  306.  
  307.     /* Get display size in (pixels X raster lines) */
  308.     /* and in (millimeters X millimeters)          */
  309.     hDC = GetDC(NULL);
  310.     VertRes = GetDeviceCaps(hDC, VERTRES);
  311.     HorzRes = GetDeviceCaps(hDC, HORZRES);
  312.     vertSize= GetDeviceCaps(hDC, VERTSIZE);
  313.     horzSize= GetDeviceCaps(hDC, HORZSIZE);
  314.     ReleaseDC(NULL, hDC);
  315.  
  316.     /* Compute (raster lines / decimeter) and (pixels / decimeter) */
  317.     AspectV = ((long) VertRes * MMPERDM) / (long) vertSize;
  318.     AspectH = ((long) HorzRes * MMPERDM) / (long) horzSize;
  319.  
  320.     CreateTools();
  321.  
  322.     /* Scale cosines for aspect ratio if this is the first instance */
  323.     if (bFirst)
  324.     {
  325.         lpCirTab = (POINT far *) GlobalLock(hCirTab);
  326.         for (pos = 0; pos < HANDPOSITIONS; pos++)
  327.         {
  328.             lpCirTab[pos].y = VertEquiv(lpCirTab[pos].y);
  329.         }
  330.         GlobalUnlock(hCirTab);
  331.         }
  332.  
  333.     GetTime(&oTime);
  334. }
  335.  
  336.  
  337. /***************************************************************************
  338.  *                                                                         *
  339.  *  FUNCTION : ClockSize (HWND, int, int, WORD)                            *
  340.  *                                                                         *
  341.  *  PURPOSE  : Resize the clock to the largest possible circle that will   *
  342.  *             fit in the client area. If switching from not iconic to     *
  343.  *             iconic, alter the timer to update every minute.  And if     *
  344.  *             switching back to non iconic, restore the timer to update   *
  345.  *             every second.                                               *
  346.  *                                                                         *
  347.  ***************************************************************************/
  348.  
  349. int ClockSize(hWnd, newWidth, newHeight, sizeType)
  350.     HWND hWnd;
  351.     int  newWidth;
  352.     int  newHeight;
  353.     WORD sizeType;
  354. {
  355.     /* Set ClockRect to bound the largest possible circle in the window */
  356.     SetRect((LPRECT) &(ClockRect), 0, 0, newWidth, newHeight);
  357.     CircleClock(newWidth, newHeight);
  358.  
  359.     if(sizeType == SIZEICONIC)
  360.     {
  361.         /* Update once every minute in the iconic state */
  362.         KillTimer(hWnd, TimerID);
  363.         SetTimer(hWnd, TimerID, (unsigned) ICON_TLEN, 0L);
  364.         bIconic = TRUE;
  365.     }
  366.     else if (bIconic)
  367.     {
  368.         /* Update every second in the opened state (ignore tiling) */
  369.         KillTimer(hWnd, TimerID);
  370.         SetTimer(hWnd, TimerID, OPEN_TLEN, 0L);
  371.         bIconic = FALSE;
  372.     }
  373. }
  374.  
  375.  
  376. /***************************************************************************
  377.  *                                                                         *
  378.  *  FUNCTION : ClockTimer (HWND)                                           *
  379.  *                                                                         *
  380.  *  PURPOSE  : Update the clock to reflect the most recent time.           *
  381.  *                                                                         *
  382.  ***************************************************************************/
  383.  
  384. int ClockTimer(hWnd)
  385.     HWND hWnd;
  386. {
  387.     TIME nTime;
  388.     HDC  hDC;
  389.  
  390.     GetTime(&nTime);
  391.  
  392.     /* It's possible to change any part of the system at any time through */
  393.     /* the Control Panel. Check for any change in second, minute, or hour */
  394.     if ((nTime.second != oTime.second) ||
  395.         (nTime.minute != oTime.minute) ||
  396.         (nTime.hour   != oTime.hour))
  397.     {
  398.         /* The time has changed -- update the clock */
  399.         hDC = GetDC(hWnd);
  400.         ClockPaint(hWnd, hDC, HANDPAINT);
  401.         ReleaseDC(hWnd, hDC);
  402.     }
  403. }
  404.  
  405.  
  406. /***************************************************************************
  407.  *                                                                         *
  408.  *  FUNCTION : ClockPaint (HWND, HDC, int)                                 *
  409.  *                                                                         *
  410.  *  PURPOSE  : Paint the clock to display the most recent time.            *
  411.  *                                                                         *
  412.  ***************************************************************************/
  413.  
  414. int ClockPaint(hWnd, hDC, paintType)
  415.     HWND hWnd;
  416.     HDC  hDC;
  417.     int  paintType;
  418. {
  419.     TIME nTime;
  420.  
  421.     SetBkMode(hDC, TRANSPARENT);
  422.  
  423.     lpCirTab = (POINT far *) GlobalLock(hCirTab);
  424.  
  425.     if (paintType == PAINTALL)
  426.     {
  427.         /* Paint entire clock -- face and hands */
  428.         FillRect(hDC, (LPRECT) &ClockRect, hbrBackgnd);
  429.         DrawFace(hDC);
  430.         DrawFatHand(hDC, HourHandPos(oTime), hpenForegnd, HHAND);
  431.         DrawFatHand(hDC, oTime.minute, hpenForegnd, MHAND);
  432.         if (!bIconic)
  433.         {
  434.             /* Erase old second hand */
  435.             DrawHand(hDC, oTime.second, hpenBackgnd, SECONDTIP, R2_NOT);
  436.         }
  437.         }
  438.     else if (paintType == HANDPAINT)
  439.     {
  440.         GetTime(&nTime);
  441.  
  442.         if ((!bIconic) && (nTime.second != oTime.second))
  443.         {
  444.             /* Second has changed -- erase old second hand */
  445.             DrawHand(hDC, oTime.second, hpenBackgnd, SECONDTIP, R2_NOT);
  446.         }
  447.  
  448.         if ((nTime.minute != oTime.minute) || (nTime.hour != oTime.hour))
  449.         {
  450.             /* Hour and/or minute have changed -- update hands */
  451.             if (bIconic)
  452.             {
  453.                 /* Erase old minute and hour hands */
  454.                 DrawHand(hDC, oTime.minute,
  455.                          hpenBackgnd, MINUTETIP, R2_COPYPEN);
  456.                 DrawHand(hDC, HourHandPos(oTime),
  457.                          hpenBackgnd, HOURTIP, R2_COPYPEN);
  458.  
  459.                 /* Draw new minute and hour hands */
  460.                 DrawHand(hDC, nTime.minute,
  461.                          hpenForegnd, MINUTETIP, R2_COPYPEN);
  462.                 DrawHand(hDC, HourHandPos(nTime),
  463.                          hpenForegnd, HOURTIP, R2_COPYPEN);
  464.                     
  465.             }
  466.             else
  467.             {
  468.                 /* Erase old minute and hour fat hands */
  469.                 DrawFatHand(hDC, oTime.minute,
  470.                         hpenBackgnd, MHAND);
  471.                 DrawFatHand(hDC, HourHandPos(oTime),
  472.                         hpenBackgnd, HHAND);
  473.  
  474.                 /* Draw new minute and hour fat hands */
  475.                 DrawFatHand(hDC, nTime.minute,
  476.                         hpenForegnd, MHAND);
  477.                 DrawFatHand(hDC, HourHandPos(nTime),
  478.                             hpenForegnd, HHAND);
  479.             }
  480.         }
  481.  
  482.         if ((!bIconic) && (nTime.second != oTime.second))
  483.         {
  484.             /* second has changed -- draw new second hand */
  485.             DrawHand(hDC, nTime.second,
  486.                      hpenBackgnd, SECONDTIP, R2_NOT);
  487.         }
  488.  
  489.         /* Store most recent time */
  490.         oTime.minute = nTime.minute;
  491.         oTime.hour   = nTime.hour;
  492.         oTime.second = nTime.second;
  493.     }
  494.     GlobalUnlock(hCirTab);
  495. }
  496.  
  497.  
  498. /***************************************************************************
  499.  *                                                                         *
  500.  *  FUNCTION : DrawFace (HDC)                                              *
  501.  *                                                                         *
  502.  *  PURPOSE  : Draws the clock face.                                       *
  503.  *                                                                         *
  504.  ***************************************************************************/
  505.  
  506. DrawFace(hDC)
  507.     HDC hDC; /* device context to be used when drawing face */
  508. {
  509.     int    pos;       /* hand position index into the circle table */
  510.     int    dotHeight; /* height of the hour-marking dot            */
  511.     int    dotWidth;  /* width of the hour-marking dot             */
  512.     POINT  dotCenter; /* center point of the hour-marking dot      */
  513.     RECT   rc;
  514.  
  515.     /* Compute hour-marking dot width, height, and center point */
  516.     dotWidth = (MAXDOTWIDTH * (long) (ClockRect.right - ClockRect.left)) / HorzRes;
  517.     dotHeight = VertEquiv(dotWidth);
  518.  
  519.     if (dotHeight < MINDOTHEIGHT)
  520.     {
  521.         dotHeight = MINDOTHEIGHT;
  522.     }
  523.  
  524.     if (dotWidth < MINDOTWIDTH)
  525.     {
  526.         dotWidth = MINDOTWIDTH;
  527.     }
  528.  
  529.     dotCenter.x = dotWidth >> 1;
  530.     dotCenter.y = dotHeight >> 1;
  531.  
  532.     /* Compute the clock center and radius */
  533.     InflateRect((LPRECT) &ClockRect, -dotCenter.y, -dotCenter.x);
  534.     ClockRadius = (long) ((ClockRect.right - ClockRect.left) >> 1);
  535.     ClockCenter.x = ClockRect.left + ClockRadius;
  536.     ClockCenter.y = ClockRect.top + ((ClockRect.bottom - ClockRect.top) >> 1);
  537.     InflateRect((LPRECT) &ClockRect, dotCenter.y, dotCenter.x);
  538.  
  539.     /* Draw the large hour-marking dots and small minute-marking dots */
  540.     for(pos = 0; pos < HANDPOSITIONS; pos++)
  541.     {
  542.         rc.top = (lpCirTab[pos].y * ClockRadius) / CIRTABSCALE + ClockCenter.y;
  543.         rc.left = (lpCirTab[pos].x * ClockRadius) / CIRTABSCALE + ClockCenter.x;
  544.         if (pos % 5)
  545.         {
  546.             if ((dotWidth > MINDOTWIDTH) && (dotHeight > MINDOTHEIGHT))
  547.             {
  548.                 /* Draw small minute-marking dot */
  549.                 rc.right = rc.left + 1;
  550.                 rc.bottom = rc.top + 1;
  551.                 FillRect(hDC, (LPRECT) &rc, hbrForegnd);
  552.             }
  553.         }
  554.         else
  555.         {
  556.             /* Draw large hour-marking dot */
  557.             rc.right = rc.left + dotWidth;
  558.             rc.bottom = rc.top + dotHeight;
  559.             OffsetRect((LPRECT) &rc, -dotCenter.x, -dotCenter.y);
  560.             FillRect(hDC, (LPRECT) &rc, hbrForegnd);
  561.         }
  562.     }
  563. }
  564.  
  565.  
  566. /***************************************************************************
  567.  *                                                                         *
  568.  *  FUNCTION : DrawHand (HDC, int, HPEN, int, int)                         *
  569.  *                                                                         *
  570.  *  PURPOSE  : Draws a thin hand with the specified pen in the specified   *
  571.  *             hand position.                                              *
  572.  *                                                                         *
  573.  ***************************************************************************/
  574.  
  575. DrawHand(hDC, pos, hPen, scale, patMode)
  576.     HDC  hDC;     /* device context to be used when drawing hand */
  577.     int  pos;     /* hand position index into the circle table   */
  578.     HPEN hPen;    /* pen to be used when drawing hand            */
  579.     int  scale;   /* ClockRadius percentage to scale drawing to  */
  580.     int  patMode; /* pattern mode to be used when drawing hand   */
  581. {
  582.     long radius;
  583.  
  584.     /* scale length of hand */
  585.     radius = (ClockRadius * scale) / 100;
  586.  
  587.     /* set pattern mode for hand */
  588.     SetROP2(hDC, patMode);
  589.  
  590.     /* select pen for hand */
  591.     SelectObject(hDC, hPen);
  592.  
  593.     /* Draw thin hand */
  594.     MoveTo(hDC, ClockCenter.x, ClockCenter.y);
  595.     LineTo(hDC, ClockCenter.x + (int)((lpCirTab[pos].x * radius) / CIRTABSCALE),
  596.             ClockCenter.y + (int)((lpCirTab[pos].y * radius) / CIRTABSCALE));
  597. }
  598.  
  599.  
  600. /***************************************************************************
  601.  *                                                                         *
  602.  *  FUNCTION : DrawFatHand (HDC, int, HPEN, BOOL)                          *
  603.  *                                                                         *
  604.  *  PURPOSE  : Draws a fat hand with the specified pen in the specified    *
  605.  *             hand position.                                              *
  606.  *                                                                         *
  607.  ***************************************************************************/
  608.  
  609. DrawFatHand(hDC, pos, hPen, hHand)
  610.     HDC  hDC;     /* device context to be used when drawing hand */
  611.     int  pos;     /* hand position index into the circle table   */
  612.     HPEN hPen;    /* pen to be used when drawing hand            */
  613.     BOOL hHand;   /* TRUE if drawing hour hand; FALSE otherwise  */
  614. {
  615.     POINT ptTip;  /* coordinates for the tip of the hand        */
  616.     POINT ptTail; /* coordinates for the tail of the hand       */
  617.     POINT ptSide; /* coordinates for the side of the hand       */
  618.     int   index;  /* position index into the circle table       */
  619.     long  scale;  /* ClockRadius percentage to scale drawing to */
  620.  
  621.     /* set pattern mode for hand */
  622.     SetROP2(hDC, 13);
  623.  
  624.     /* select pen for hand */
  625.     SelectObject(hDC, hPen);
  626.  
  627.     /* compute coordinates for the side of the hand */
  628.     scale = (ClockRadius * (hHand ? HOURSIDE : MINUTESIDE)) / 100;
  629.     index = (pos + SIDESHIFT) % HANDPOSITIONS;
  630.     ptSide.y = (lpCirTab[index].y * scale) / CIRTABSCALE;
  631.     ptSide.x = (lpCirTab[index].x * scale) / CIRTABSCALE;
  632.  
  633.     /* compute coordinates for the tip of the hand */
  634.     scale = (ClockRadius * (hHand ? HOURTIP : MINUTETIP)) / 100;
  635.     ptTip.y = (lpCirTab[pos].y * scale) / CIRTABSCALE;
  636.     ptTip.x = (lpCirTab[pos].x * scale) / CIRTABSCALE;
  637.  
  638.     /* compute coordinates for the tail of the hand */
  639.     scale = (ClockRadius * (hHand ? HOURTAIL : MINUTETAIL)) / 100;
  640.     index = (pos + TAILSHIFT) % HANDPOSITIONS;
  641.     ptTail.y = (lpCirTab[index].y * scale) / CIRTABSCALE;
  642.     ptTail.x = (lpCirTab[index].x * scale) / CIRTABSCALE;
  643.  
  644.     /* Draw tip of hand */
  645.     MoveTo(hDC, ClockCenter.x + ptSide.x, ClockCenter.y + ptSide.y);
  646.     LineTo(hDC, ClockCenter.x +  ptTip.x, ClockCenter.y +  ptTip.y);
  647.     MoveTo(hDC, ClockCenter.x - ptSide.x, ClockCenter.y - ptSide.y);
  648.     LineTo(hDC, ClockCenter.x +  ptTip.x, ClockCenter.y +  ptTip.y);
  649.  
  650.     /* Draw tail of hand */
  651.     MoveTo(hDC, ClockCenter.x + ptSide.x, ClockCenter.y + ptSide.y);
  652.     LineTo(hDC, ClockCenter.x + ptTail.x, ClockCenter.y + ptTail.y);
  653.     MoveTo(hDC, ClockCenter.x - ptSide.x, ClockCenter.y - ptSide.y);
  654.     LineTo(hDC, ClockCenter.x + ptTail.x, ClockCenter.y + ptTail.y);
  655. }
  656.  
  657.  
  658. /***************************************************************************
  659.  *                                                                         *
  660.  *  FUNCTION : CircleClock (int, int)                                      *
  661.  *                                                                         *
  662.  *  PURPOSE  : Resizes the clock rectangle to keep the face circular.      *
  663.  *                                                                         *
  664.  ***************************************************************************/
  665.  
  666. CircleClock(maxWidth, maxHeight)
  667.     int maxWidth;    /* the maximum width of the clock face         */
  668.     int maxHeight;   /* the maximum height of the clock face        */
  669. {
  670.     int clockHeight; /* tallest height that will keep face circular */
  671.     int clockWidth;  /* widest width that will keep face circular   */
  672.  
  673.     if (maxWidth > HorzEquiv(maxHeight))
  674.     {
  675.         /* too wide -- decrease width to keep face circular */
  676.         clockWidth = HorzEquiv(maxHeight);
  677.         ClockRect.left += (maxWidth - clockWidth) >> 1;
  678.         ClockRect.right = ClockRect.left + clockWidth;
  679.     }
  680.     else
  681.     {
  682.         /* too tall -- decrease height to keep face circular */
  683.         clockHeight = VertEquiv(maxWidth);
  684.         ClockRect.top += (maxHeight - clockHeight) >> 1;
  685.         ClockRect.bottom = ClockRect.top + clockHeight;
  686.     }
  687. }
  688.  
  689.  
  690. /***************************************************************************
  691.  *                                                                         *
  692.  *  FUNCTION : WinMain (HANDLE, HANDLE, LPSTR, int)                        *
  693.  *                                                                         *
  694.  *  PURPOSE  : Calls the initialization function, creates the main appli-  *
  695.  *             cation window, and enters the message loop.                 *
  696.  *                                                                         *
  697.  ***************************************************************************/
  698.  
  699. int PASCAL WinMain(hInstance, hPrev, lpszCmdLine, cmdShow)
  700.     HANDLE hInstance;
  701.     HANDLE hPrev;
  702.     LPSTR  lpszCmdLine;
  703.     int    cmdShow;
  704. {
  705.     HWND  hWnd;
  706.     MSG   msg;
  707.     HMENU hMenu;
  708.     TIME  nTime;
  709.     int   sysWidth;  /* width of left and right frames                  */
  710.     int   sysHeight; /* height of caption bar and top and bottom frames */
  711.     int   width;     /* width of entire clock window                    */
  712.     int   height;    /* height of entire clock window                   */
  713.  
  714.     hInst = hInstance;
  715.  
  716.     LoadString(hInst, IDS_APPNAME, (LPSTR) szBuffer, BUFLEN);
  717.  
  718.     if (!hPrev)
  719.     {
  720.         /* First instance -- register window class */
  721.         if (!ClockInit())
  722.             return(FALSE);
  723.         }
  724.     else
  725.     {
  726.         /* Not first instance -- get circle table and reset bFirst flag */
  727.         GetInstanceData(hPrev, (PSTR) &hCirTab, sizeof(HANDLE));
  728.         bFirst = FALSE;
  729.         }
  730.  
  731.     ClockCreate();
  732.  
  733.     /* compute window height and width */
  734.     sysWidth  = GetSystemMetrics(SM_CXFRAME) * 2;
  735.     sysHeight = GetSystemMetrics(SM_CYCAPTION) + (GetSystemMetrics(SM_CYFRAME) * 2);
  736.     width = (HorzRes / 3) + sysWidth;
  737.     height = VertEquiv(width) + sysHeight;
  738.  
  739.     hWnd = CreateWindow( (LPSTR) szBuffer, /* class name              */
  740.                              (LPSTR) szBuffer, /* The window name         */
  741.                              WS_TILEDWINDOW,   /* window style            */
  742.                              CW_USEDEFAULT,    /* use default positioning */
  743.                              0,                /* y not used              */
  744.                              width,            /* window width            */
  745.                  height,           /* window height           */
  746.                              NULL,             /* NULL parent handle      */
  747.                              NULL,             /* NULL menu/child handle  */
  748.                              hInst,            /* program instance        */
  749.                              NULL              /* NULL data structure ref.*/
  750.                );
  751.  
  752.     GetTime(&nTime);
  753.     GetTime(&oTime);
  754.     while ((nTime.second == oTime.second) &&
  755.                (nTime.minute == oTime.minute) &&
  756.                (nTime.hour   == oTime.hour)     )
  757.     {
  758.         GetTime(&oTime);
  759.     }
  760.  
  761.     if (!SetTimer(hWnd, TimerID, OPEN_TLEN, 0L))
  762.     {
  763.         LPSTR szTooMany;
  764.  
  765.         /* 16 public timers already in use -- post error and exit */
  766.         szTooMany = (LPSTR)(unsigned long) LocalAlloc(LPTR, 40);
  767.         LoadString(hInst, IDS_TOOMANY, szTooMany, 40);
  768.         MessageBox((HWND) NULL, szTooMany, (LPSTR) szBuffer,
  769.                MB_OK | MB_ICONHAND | MB_SYSTEMMODAL);
  770.         DeleteTools();
  771.         return(FALSE);
  772.     }
  773.  
  774.     /* Add the "About..." menu item to the bottom of the system menu */
  775.     LoadString(hInst, IDS_ABOUTMENU, (LPSTR) szBuffer, BUFLEN);
  776.     hMenu = GetSystemMenu(hWnd, FALSE);
  777.     ChangeMenu(hMenu, 0, (LPSTR) szBuffer, IDM_ABOUT, MF_APPEND | MF_STRING);
  778.  
  779.     ShowWindow(hWnd, cmdShow);
  780.  
  781.     /* Process messages until program termination */
  782.     while (GetMessage((LPMSG) &msg, NULL, 0, 0))
  783.     {
  784.         TranslateMessage((LPMSG) &msg);
  785.         DispatchMessage((LPMSG) &msg);
  786.     }
  787.     return(msg.wParam);
  788. }
  789.  
  790.  
  791. /***************************************************************************
  792.  *                                                                         *
  793.  *  FUNCTION : ClockInit ()                                                *
  794.  *                                                                         *
  795.  *  PURPOSE  : Registers the applicatoin windwo class and initializes the  *
  796.  *             circle values for the clock face.                           *
  797.  *                                                                         *
  798.  ***************************************************************************/
  799.  
  800. ClockInit()
  801. {
  802.     PWNDCLASS pClockClass;
  803.     HANDLE    hRes;
  804.     char      szData[5];
  805.  
  806.     pClockClass = (PWNDCLASS) LocalAlloc(LPTR, sizeof(WNDCLASS));
  807.  
  808.     pClockClass->lpszClassName = (LPSTR) szBuffer;
  809.     pClockClass->hbrBackground = (HBRUSH) NULL;
  810.     pClockClass->style         = CS_VREDRAW | CS_HREDRAW | CS_BYTEALIGNCLIENT;
  811.     pClockClass->hInstance     = hInst;
  812.     pClockClass->lpfnWndProc   = ClockWndProc;
  813.     pClockClass->hCursor       = LoadCursor(NULL, IDC_ARROW);
  814.     pClockClass->hIcon         = NULL;
  815.  
  816.     if (!RegisterClass((LPWNDCLASS) pClockClass))
  817.     {
  818.         /* Error registering class -- return */
  819.         return(FALSE);
  820.     }
  821.  
  822.     LocalFree((HANDLE) pClockClass);
  823.  
  824.     /* Load in pre-computed circle table cosine values from resource file */
  825.     LoadString(hInst, IDS_DATA, (LPSTR) szData, 5);
  826.     hRes = FindResource(hInst, (LPSTR) szBuffer, (LPSTR) szData);
  827.     if (!hRes)
  828.     {
  829.         /* Could not find circle table resource data -- return */
  830.         return(FALSE);
  831.     }
  832.  
  833.     hCirTab = LoadResource(hInst, hRes);
  834.     LockResource(hCirTab);
  835.  
  836.     return(TRUE);
  837. }
  838.