home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / os2 / clock / clock.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-08  |  101.6 KB  |  3,105 lines

  1. /******************************************************************* CLOCK.CC
  2.  *                                        *
  3.  *          Analog Clock for Presentation Manager             *
  4.  *                                        *
  5.  *          Original program by Charles Petzold                *
  6.  *                                        *
  7.  ****************************************************************************/
  8.  
  9. #define INCL_BASE
  10. #define INCL_PM
  11. #include <os2.h>
  12.  
  13. #include <process.h>
  14. #include <stdarg.h>
  15. #include <stddef.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19.  
  20. #include "debug.h"
  21. #include "support.h"
  22.  
  23. #include "about.h"
  24. #include "config.h"
  25. #include "process.h"
  26. #include "profile.h"
  27. #include "restring.h"
  28.  
  29. #include "clock.h"
  30.  
  31.  
  32. /****************************************************************************
  33.  *                                        *
  34.  *             Definitions & Declarations                *
  35.  *                                        *
  36.  ****************************************************************************/
  37.  
  38.   // Constants
  39.  
  40. #define PROGRAM_NAME "CLOCK"
  41. #define CLASS_NAME   PROGRAM_NAME
  42.  
  43. #define DATEFMT_MM_DD_YY    (0x0000)
  44. #define DATEFMT_DD_MM_YY    (0x0001)
  45. #define DATEFMT_YY_MM_DD    (0x0002)
  46.  
  47. enum { ALERT_TASKCOUNT, ALERT_LOAD } ;
  48.  
  49. #define WM_REFRESH WM_USER
  50.  
  51.  
  52.   // Type Definitions
  53.  
  54. typedef struct
  55. {
  56.   SHORT cxClient ;
  57.   SHORT cyClient ;
  58.   SHORT cxPixelDiam ;
  59.   SHORT cyPixelDiam ;
  60. }
  61. WINDOWINFO, *PWINDOWINFO ;
  62.  
  63. typedef struct          // Parameters saved to system.
  64. {
  65.   SWP     Position ;        // Window size & location.
  66.   BOOL     fPosition ;
  67.  
  68.   BOOL     Hour24 ;        // User options.
  69.   BOOL     fHour24 ;
  70.  
  71.   BOOL     HideControls ;
  72.   BOOL     fHideControls ;
  73.  
  74.   BOOL     Chime ;
  75.   BOOL     fChime ;
  76.  
  77.   BOOL     Float ;
  78.   BOOL     fFloat ;
  79.  
  80.   BOOL     Analog ;
  81.   BOOL     fAnalog ;
  82.  
  83.   BOOL     AlertType ;
  84.   BOOL     fAlertType ;
  85.  
  86.   USHORT AlertLevels [2] [2] ;
  87.   BOOL     fAlertLevels ;
  88.  
  89.   CHAR     FontNameSize [80] ;    // Presentation Parameters
  90.   BOOL     fFontNameSize ;
  91.  
  92.   COLOR  BackColor ;
  93.   BOOL     fBackColor ;
  94.  
  95.   COLOR  TextColor ;
  96.   BOOL     fTextColor ;
  97. }
  98. PROFILE, *PPROFILE ;
  99.  
  100. typedef struct
  101. {
  102.   HAB         Anchor ;
  103.   HMODULE     Library ;
  104.   HINI           ProfileHandle ;
  105.  
  106.   PROFILE Profile ;
  107.  
  108.   HWND hwndTitleBar ;
  109.   HWND hwndSysMenu ;
  110.   HWND hwndMinMax ;
  111.  
  112.   DATETIME PreviousDateTime ;
  113.   USHORT PreviousHour ;
  114.   LONG xPixelsPerMeter, yPixelsPerMeter ;
  115.   WINDOWINFO wi ;
  116.  
  117.   USHORT Alert ;
  118.  
  119.   ULONG MaxCount ;
  120.   ULONG IdleCounter ;
  121.   ULONG IdleCount ;
  122.   TID    IdleLoopTID ;
  123.   TID    MonitorLoopTID ;
  124.  
  125.   COUNTRYINFO CountryInfo ;
  126. }
  127. DATA, *PDATA ;
  128.  
  129. typedef struct
  130. {
  131.   HAB Anchor ;
  132.   HMODULE Library ;
  133.   HINI ProfileHandle ;
  134.   BOOL Analog ;
  135.   BOOL fAnalog ;
  136. }
  137. PARMS, *PPARMS ;
  138.  
  139. typedef struct
  140. {
  141.   volatile PULONG Counter ;
  142.   HWND Owner ;
  143. }
  144. MONITOR_PARMS, *PMONITOR_PARMS ;
  145.  
  146.  
  147.   // Function Prototypes
  148.  
  149. extern INT main ( int argc, PSZ argv[] ) ;
  150.  
  151. static MRESULT EXPENTRY MessageProcessor
  152. (
  153.   HWND hwnd,
  154.   USHORT msg,
  155.   MPARAM mp1,
  156.   MPARAM mp2
  157. ) ;
  158.  
  159. static METHODFUNCTION Create ;
  160. static METHODFUNCTION Destroy ;
  161. static METHODFUNCTION Size ;
  162. static METHODFUNCTION SaveApplication ;
  163. static METHODFUNCTION Paint ;
  164. static METHODFUNCTION Command ;
  165. static METHODFUNCTION ResetDefaults ;
  166. static METHODFUNCTION HideControlsCmd ;
  167. static METHODFUNCTION Configure ;
  168. static METHODFUNCTION About ;
  169. static METHODFUNCTION ButtonDown ;
  170. static METHODFUNCTION ButtonDblClick ;
  171. static METHODFUNCTION PresParamChanged ;
  172. static METHODFUNCTION SysColorChange ;
  173. static METHODFUNCTION QueryKeysHelp ;
  174. static METHODFUNCTION HelpError ;
  175. static METHODFUNCTION ExtHelpUndefined ;
  176. static METHODFUNCTION HelpSubitemNotFound ;
  177. static METHODFUNCTION Refresh ;
  178.  
  179. static int GetProfile ( HINI ProfileHandle, PPROFILE Profile ) ;
  180. static VOID PutProfile ( HINI ProfileHandle, PPROFILE Profile ) ;
  181.  
  182. static VOID RotatePoint ( POINTL aptl[],  SHORT sNum, SHORT sAngle ) ;
  183. static VOID ScalePoint ( POINTL aptl[], SHORT sNum, PWINDOWINFO pwi ) ;
  184. static VOID TranslatePoint ( POINTL aptl[], SHORT sNum, PWINDOWINFO pwi ) ;
  185. static VOID DrawHand ( HPS hPS, POINTL aptlIn[], SHORT sNum, SHORT sAngle,
  186.   PWINDOWINFO pwi ) ;
  187. static void PaintBackground ( HWND hwnd, HPS hPS, PDATA Data, BOOL MustPaint ) ;
  188. static void PaintBorder ( HWND hwnd, HPS hPS, PDATA Data, BOOL MustPaint ) ;
  189. static void PaintDigitalTime ( HWND hwnd, HPS hPS, PDATA Data, PDATETIME DateTime ) ;
  190.  
  191. static void HideControls
  192. (
  193.   BOOL fHide,
  194.   HWND hwndFrame,
  195.   HWND hwndSysMenu,
  196.   HWND hwndTitleBar,
  197.   HWND hwndMinMax
  198. ) ;
  199.  
  200. static void MonitorLoopThread ( PMONITOR_PARMS Parms ) ;
  201.  
  202. static ULONG CalibrateLoadMeter ( void ) ;
  203.  
  204. static void CounterThread ( PULONG Counter ) ;
  205.  
  206. static HINI OpenProfile ( PSZ Name, HAB Anchor, HMODULE Library, HWND HelpInstance ) ;
  207.  
  208.  
  209. /****************************************************************************
  210.  *                                        *
  211.  *    Program Mainline                            *
  212.  *                                        *
  213.  ****************************************************************************/
  214.  
  215. extern int main ( int argc, PSZ argv[] )
  216. {
  217.  /***************************************************************************
  218.   * Initialize the process.                            *
  219.   ***************************************************************************/
  220.  
  221.   Process Proc ;
  222.  
  223.  /***************************************************************************
  224.   * Now WIN and GPI calls will work.  Open the language DLL.            *
  225.   ***************************************************************************/
  226.  
  227.   HMODULE Library = 0 ;
  228.  
  229.   if ( DosLoadModule ( NULL, 0, (PSZ)PROGRAM_NAME, &Library ) )
  230.   {
  231.     Debug ( HWND_DESKTOP, "ERROR: Unable to load " PROGRAM_NAME ".DLL." ) ;
  232.     DosExit ( EXIT_PROCESS, 1 ) ;
  233.   }
  234.  
  235.  /***************************************************************************
  236.   * Get the program title.                                        *
  237.   ***************************************************************************/
  238.  
  239.   ResourceString Title ( Library, IDS_TITLE ) ;
  240.  
  241.  /***************************************************************************
  242.   * Decipher command-line parameters.                        *
  243.   ***************************************************************************/
  244.  
  245.   ResourceString ResetCommand ( Library, IDS_PARMS_RESET ) ;
  246.   ResourceString AnalogCommand ( Library, IDS_PARMS_ANALOG ) ;
  247.   ResourceString DigitalCommand ( Library, IDS_PARMS_DIGITAL ) ;
  248.  
  249.   BOOL Reset = FALSE ;
  250.   BOOL Analog = TRUE ;
  251.   BOOL fAnalog = FALSE ;
  252.  
  253.   while ( --argc )
  254.   {
  255.     argv ++ ;
  256.  
  257.     WinUpper ( Proc.QueryAnchor(), NULL, NULL, *argv ) ;
  258.  
  259.     if ( *argv[0] == '?' )
  260.     {
  261.       ResourceString Message ( Library, IDS_PARAMETERLIST ) ;
  262.  
  263.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message.Ptr(),
  264.     Title.Ptr(), 0, MB_ENTER | MB_NOICON ) ;
  265.  
  266.       DosExit ( EXIT_PROCESS, 1 ) ;
  267.     }
  268.  
  269.     if ( !strcmp ( PCHAR(*argv), PCHAR(ResetCommand.Ptr()) ) )
  270.     {
  271.       Reset = TRUE ;
  272.       continue ;
  273.     }
  274.  
  275.     if ( !strcmp ( PCHAR(*argv), PCHAR(AnalogCommand.Ptr()) ) )
  276.     {
  277.       Analog = TRUE ;
  278.       fAnalog = TRUE ;
  279.       continue ;
  280.     }
  281.  
  282.     if ( !strcmp ( PCHAR(*argv), PCHAR(DigitalCommand.Ptr()) ) )
  283.     {
  284.       Analog = FALSE ;
  285.       fAnalog = TRUE ;
  286.       continue ;
  287.     }
  288.  
  289.     {
  290.       ResourceString Format ( Library, IDS_ERROR_INVALIDPARM ) ;
  291.  
  292.       BYTE Message [200] ;
  293.       sprintf ( PCHAR(Message), PCHAR(Format.Ptr()), *argv ) ;
  294.  
  295.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message,
  296.     Title.Ptr(), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  297.  
  298.       DosExit ( EXIT_PROCESS, 1 ) ;
  299.     }
  300.   }
  301.  
  302.  /***************************************************************************
  303.   * Create the help instance.                            *
  304.   ***************************************************************************/
  305.  
  306.   HELPINIT HelpInit =
  307.   {
  308.     sizeof ( HELPINIT ),
  309.     0L,
  310.     NULL,
  311.     MAKEP ( 0xFFFF, ID_MAIN ),
  312.     0,
  313.     0,
  314.     0,
  315.     0,
  316.     NULL,
  317.     CMIC_HIDE_PANEL_ID,
  318.     (PSZ) ( PROGRAM_NAME ".HLP" )
  319.   } ;
  320.  
  321.   ResourceString HelpTitle ( Library, IDS_HELPTITLE ) ;
  322.   HelpInit.pszHelpWindowTitle = HelpTitle.Ptr() ;
  323.  
  324.   HWND HelpWindow = WinCreateHelpInstance ( Proc.QueryAnchor(), &HelpInit ) ;
  325.  
  326.   if ( HelpWindow == NULL )
  327.   {
  328.     ResourceString Message ( Library, IDS_ERROR_WINCREATEHELPINSTANCE ) ;
  329.  
  330.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message.Ptr(),
  331.       Title.Ptr(), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  332.   }
  333.  
  334.  /***************************************************************************
  335.   * Open/create the profile file.                                       *
  336.   ***************************************************************************/
  337.  
  338.   HINI ProfileHandle = OpenProfile ( PSZ(PROGRAM_NAME), Proc.QueryAnchor(), Library, HelpWindow ) ;
  339.  
  340.   if ( ProfileHandle == NULL )
  341.   {
  342.     ResourceString Message ( Library, IDS_ERROR_PRFOPENPROFILE ) ;
  343. //  Log ( "%s\r\n", Message.Ptr() ) ;
  344.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message.Ptr(),
  345.       Title.Ptr(), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  346.     DosFreeModule ( Library ) ;
  347.     DosExit ( EXIT_PROCESS, 1 ) ;
  348.   }
  349.  
  350.  /***************************************************************************
  351.   * If we're going to reset the program's profile, do it now.               *
  352.   ***************************************************************************/
  353.  
  354.   if ( Reset )
  355.   {
  356.     PrfWriteProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, NULL, NULL, 0 ) ;
  357.   }
  358.  
  359.  /***************************************************************************
  360.   * Create the frame window.                            *
  361.   ***************************************************************************/
  362.  
  363.   #pragma pack(2)
  364.   struct
  365.   {
  366.     USHORT Filler ;
  367.     USHORT cb ;
  368.     ULONG  flCreateFlags ;
  369.     USHORT hmodResources ;
  370.     USHORT idResources ;
  371.   }
  372.   fcdata ;
  373.   #pragma pack()
  374.  
  375.   fcdata.cb = sizeof(fcdata) - sizeof(fcdata.Filler) ;
  376.   fcdata.flCreateFlags =
  377.     FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER |
  378.     FCF_MINMAX | FCF_NOBYTEALIGN | FCF_ACCELTABLE ;
  379.   fcdata.hmodResources = 0 ;
  380.   fcdata.idResources = ID_MAIN ;
  381.  
  382.   HWND FrameWindow = WinCreateWindow
  383.   (
  384.     HWND_DESKTOP,
  385.     WC_FRAME,
  386.     Title.Ptr(),
  387.     0,
  388.     0, 0, 0, 0,
  389.     HWND_DESKTOP,
  390.     HWND_TOP,
  391.     ID_MAIN,
  392.     &fcdata.cb,
  393.     NULL
  394.   ) ;
  395.  
  396.   if ( FrameWindow == NULL )
  397.   {
  398.     ResourceString Message ( Library, IDS_ERROR_WINCREATEFRAME ) ;
  399.  
  400.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message.Ptr(),
  401.       Title.Ptr(), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  402.  
  403.     PrfCloseProfile ( ProfileHandle ) ;
  404.     DosFreeModule ( Library ) ;
  405.     DosExit ( EXIT_PROCESS, 1 ) ;
  406.   }
  407.  
  408.  /***************************************************************************
  409.   * Associate the help instance with the frame window.                *
  410.   ***************************************************************************/
  411.  
  412.   if ( HelpWindow )
  413.   {
  414.     WinAssociateHelpInstance ( HelpWindow, FrameWindow ) ;
  415.   }
  416.  
  417.  /***************************************************************************
  418.   * Register the window class.                            *
  419.   ***************************************************************************/
  420.  
  421.   if ( NOT WinRegisterClass ( Proc.QueryAnchor(), (PSZ)CLASS_NAME, MessageProcessor,
  422.     CS_MOVENOTIFY | CS_SIZEREDRAW | CS_SYNCPAINT, sizeof(PVOID) ) )
  423.   {
  424.     ResourceString Format ( Library, IDS_ERROR_WINREGISTERCLASS ) ;
  425.  
  426.     BYTE Message [200] ;
  427.     sprintf ( PCHAR(Message), PCHAR(Format.Ptr()), CLASS_NAME ) ;
  428.  
  429.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message,
  430.       Title.Ptr(), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  431.  
  432.     PrfCloseProfile ( ProfileHandle ) ;
  433.     DosFreeModule ( Library ) ;
  434.     DosExit ( EXIT_PROCESS, 1 ) ;
  435.   }
  436.  
  437.  /***************************************************************************
  438.   * Create client window.  If this fails, destroy frame and return.        *
  439.   ***************************************************************************/
  440.  
  441.   PARMS Parms ;
  442.   Parms.Anchor = Proc.QueryAnchor() ;
  443.   Parms.Library = Library ;
  444.   Parms.ProfileHandle = ProfileHandle ;
  445.   Parms.Analog = Analog ;
  446.   Parms.fAnalog = fAnalog ;
  447.  
  448.   HWND ClientWindow = WinCreateWindow
  449.   (
  450.     FrameWindow,
  451.     (PSZ)CLASS_NAME,
  452.     (PSZ)"",
  453.     0,
  454.     0, 0, 0, 0,
  455.     FrameWindow,
  456.     HWND_BOTTOM,
  457.     FID_CLIENT,
  458.     &Parms,
  459.     NULL
  460.   ) ;
  461.  
  462.   if ( ClientWindow == NULL )
  463.   {
  464.     ResourceString Message ( Library, IDS_ERROR_WINCREATEWINDOW ) ;
  465.  
  466.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message.Ptr(),
  467.       Title.Ptr(), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  468.  
  469.     WinDestroyWindow ( FrameWindow ) ;
  470.     if ( HelpWindow )
  471.     {
  472.       WinDestroyHelpInstance ( HelpWindow ) ;
  473.     }
  474.     PrfCloseProfile ( ProfileHandle ) ;
  475.     DosFreeModule ( Library ) ;
  476.     DosExit ( EXIT_PROCESS, 1 ) ;
  477.   }
  478.  
  479.  /***************************************************************************
  480.   * Wait for and process messages to the window's queue.  Terminate         *
  481.   *   when the WM_QUIT message is received.                    *
  482.   ***************************************************************************/
  483.  
  484.   QMSG QueueMessage ;
  485.   while ( WinGetMsg ( Proc.QueryAnchor(), &QueueMessage, NULL, 0, 0 ) )
  486.   {
  487.     WinDispatchMsg ( Proc.QueryAnchor(), &QueueMessage ) ;
  488.   }
  489.  
  490.  /***************************************************************************
  491.   * Discard all that was requested of the system and terminate.         *
  492.   ***************************************************************************/
  493.  
  494.   WinDestroyWindow ( FrameWindow ) ;
  495.  
  496.   if ( HelpWindow )
  497.   {
  498.     WinDestroyHelpInstance ( HelpWindow ) ;
  499.   }
  500.  
  501.   PrfCloseProfile ( ProfileHandle ) ;
  502.  
  503.   DosFreeModule ( Library ) ;
  504.  
  505.   DosExit ( EXIT_PROCESS, 0 ) ;
  506. }
  507.  
  508. /****************************************************************************
  509.  *                                        *
  510.  *    Window Message Processor                        *
  511.  *                                        *
  512.  ****************************************************************************/
  513.  
  514. static MRESULT EXPENTRY MessageProcessor
  515. (
  516.   HWND hwnd,
  517.   USHORT msg,
  518.   MPARAM mp1,
  519.   MPARAM mp2
  520. )
  521. {
  522.  /***************************************************************************
  523.   * Dispatch the message according to the method table and return the        *
  524.   *   result.  Any messages not defined above get handled by the system     *
  525.   *   default window processor.                         *
  526.   ***************************************************************************/
  527.  
  528.   static METHOD Methods [] =
  529.   {
  530.     { WM_CREATE,        Create            },
  531.     { WM_DESTROY,        Destroy         },
  532.     { WM_SIZE,            Size            },
  533.     { WM_MOVE,            Size            },
  534.     { WM_SAVEAPPLICATION,    SaveApplication     },
  535.     { WM_PAINT,         Paint            },
  536.     { WM_COMMAND,        Command         },
  537.     { WM_BUTTON1DOWN,        ButtonDown        },
  538.     { WM_BUTTON2DOWN,        ButtonDown        },
  539.     { WM_BUTTON1DBLCLK,     ButtonDblClick        },
  540.     { WM_BUTTON2DBLCLK,     ButtonDblClick        },
  541.     { WM_PRESPARAMCHANGED,    PresParamChanged    },
  542.     { WM_SYSCOLORCHANGE,    SysColorChange        },
  543.     { HM_QUERY_KEYS_HELP,    QueryKeysHelp        },
  544.     { HM_ERROR,         HelpError        },
  545.     { HM_EXT_HELP_UNDEFINED,    ExtHelpUndefined    },
  546.     { HM_HELPSUBITEM_NOT_FOUND, HelpSubitemNotFound },
  547.     { WM_REFRESH,        Refresh         }
  548.   } ;
  549.  
  550.   return ( DispatchMessage ( hwnd, msg, mp1, mp2, Methods, sizeof(Methods)/sizeof(Methods[0]), WinDefWindowProc ) ) ;
  551. }
  552.  
  553. /****************************************************************************
  554.  *                                        *
  555.  *    Initialize main window.                         *
  556.  *                                        *
  557.  ****************************************************************************/
  558.  
  559. static MRESULT APIENTRY Create
  560.   HWND hwnd, 
  561.   USHORT msg, 
  562.   MPARAM mp1, 
  563.   MPARAM mp2
  564. )
  565. {
  566.  /***************************************************************************
  567.   * Allocate instance data.                            *
  568.   ***************************************************************************/
  569.  
  570.   PDATA Data = PDATA ( malloc ( sizeof(DATA) ) ) ;
  571.  
  572.   memset ( Data, 0, sizeof(DATA) ) ;
  573.  
  574.   WinSetWindowPtr ( hwnd, QWL_USER, Data ) ;
  575.  
  576.  /***************************************************************************
  577.   * Grab any parameters from the WM_CREATE message.                *
  578.   ***************************************************************************/
  579.  
  580.   PPARMS Parms = PPARMS ( PVOIDFROMMP ( mp1 ) ) ;
  581.  
  582.   Data->Anchor = Parms->Anchor ;
  583.   Data->Library = Parms->Library ;
  584.   Data->ProfileHandle = Parms->ProfileHandle ;
  585.  
  586.  /***************************************************************************
  587.   * Get profile data. Try the OS2.INI first, then try for private INI.      *
  588.   *   If obtained from OS2.INI, erase it afterwards.                        *
  589.   ***************************************************************************/
  590.  
  591.   if ( GetProfile ( HINI_USERPROFILE, &Data->Profile ) )
  592.   {
  593.     GetProfile ( Data->ProfileHandle, &Data->Profile ) ;
  594.   }
  595.   else
  596.   {
  597.     PrfWriteProfileData ( HINI_USERPROFILE, (PSZ)PROGRAM_NAME, NULL, NULL, 0 ) ;
  598.   }
  599.  
  600.   if ( Parms->fAnalog )
  601.   {
  602.     Data->Profile.Analog = Parms->Analog ;
  603.     Data->Profile.fAnalog = TRUE ;
  604.   }
  605.  
  606.  /***************************************************************************
  607.   * Get country information.                            *
  608.   ***************************************************************************/
  609.  
  610.   {
  611.     COUNTRYCODE CountryCode ;
  612.     ULONG Count ;
  613.     ULONG Status ;
  614.  
  615.     CountryCode.country = 0 ;
  616.     CountryCode.codepage = 0 ;
  617.  
  618.     Status = DosGetCtryInfo ( sizeof(Data->CountryInfo), &CountryCode,
  619.       &Data->CountryInfo, &Count ) ;
  620.     if ( Status )
  621.     {
  622.       BYTE Message [80] ;
  623.       WinLoadMessage ( Data->Anchor, Data->Library, IDS_ERROR_DOSGETCTRYINFO,
  624.     sizeof(Message), Message ) ;
  625.       Debug ( hwnd, PCHAR(Message), Status ) ;
  626.       Data->CountryInfo.fsDateFmt = DATEFMT_MM_DD_YY ;
  627.       Data->CountryInfo.fsTimeFmt = 0 ;
  628.       Data->CountryInfo.szDateSeparator[0] = '/' ;
  629.       Data->CountryInfo.szDateSeparator[1] = 0 ;
  630.       Data->CountryInfo.szTimeSeparator[0] = ':' ;
  631.       Data->CountryInfo.szTimeSeparator[1] = 0 ;
  632.       Data->CountryInfo.szThousandsSeparator[0] = ',' ;
  633.       Data->CountryInfo.szThousandsSeparator[1] = 0 ;
  634.     }
  635.   }
  636.  
  637.   if ( NOT Data->Profile.fHour24 )
  638.   {
  639.     Data->Profile.Hour24 = Data->CountryInfo.fsTimeFmt ;
  640.   }
  641.  
  642.  /***************************************************************************
  643.   * Get initial time.                                *
  644.   ***************************************************************************/
  645.  
  646.   DosGetDateTime ( &Data->PreviousDateTime ) ;
  647.  
  648.   Data->PreviousHour = ( Data->PreviousDateTime.hours * 5 ) % 60
  649.     + Data->PreviousDateTime.minutes/12 ;
  650.  
  651.  /***************************************************************************
  652.   * Get the frame handle.                            *
  653.   ***************************************************************************/
  654.  
  655.   HWND FrameWindow = WinQueryWindow ( hwnd, QW_PARENT ) ;
  656.  
  657.  /***************************************************************************
  658.   * Get the control window handles.                        *
  659.   ***************************************************************************/
  660.  
  661.   Data->hwndSysMenu  = WinWindowFromID ( FrameWindow, FID_SYSMENU  ) ;
  662.   Data->hwndTitleBar = WinWindowFromID ( FrameWindow, FID_TITLEBAR ) ;
  663.   Data->hwndMinMax   = WinWindowFromID ( FrameWindow, FID_MINMAX   ) ;
  664.  
  665.  /***************************************************************************
  666.   * Add basic extensions to the system menu.                    *
  667.   ***************************************************************************/
  668.  
  669.   static MENUITEM MenuSeparator =
  670.     { MIT_END, MIS_SEPARATOR, 0, 0, NULL, 0 } ;
  671.  
  672.   AddSysMenuItem ( FrameWindow, &MenuSeparator, NULL ) ;
  673.  
  674.   static MENUITEM MenuItems [] =
  675.   {
  676.     { MIT_END, MIS_TEXT,      0, IDM_SAVE_APPLICATION, NULL, 0 },
  677.     { MIT_END, MIS_TEXT,      0, IDM_RESET_DEFAULTS,   NULL, 0 },
  678.     { MIT_END, MIS_TEXT,      0, IDM_HIDE_CONTROLS,    NULL, 0 },
  679.     { MIT_END, MIS_TEXT,      0, IDM_CONFIGURE,        NULL, 0 },
  680.   } ;
  681.  
  682.   for ( int i=0; i<sizeof(MenuItems)/sizeof(MenuItems[0]); i++ )
  683.   {
  684.     ResourceString MenuText ( Data->Library, i+IDS_SAVE_APPLICATION ) ;
  685.     AddSysMenuItem ( FrameWindow, MenuItems+i, MenuText.Ptr() ) ;
  686.   }
  687.  
  688.  /***************************************************************************
  689.   * Add 'About' to the system menu.                        *
  690.   ***************************************************************************/
  691.  
  692.   AddSysMenuItem ( FrameWindow, &MenuSeparator, NULL ) ;
  693.  
  694.   ResourceString AboutText ( Data->Library, IDS_ABOUT ) ;
  695.  
  696.   static MENUITEM MenuAbout =
  697.     { MIT_END, MIS_TEXT, 0, IDM_ABOUT, NULL, 0 } ;
  698.  
  699.   AddSysMenuItem ( FrameWindow, &MenuAbout, AboutText.Ptr() ) ;
  700.  
  701.  /***************************************************************************
  702.   * Add 'Help' to the system menu.                        *
  703.   ***************************************************************************/
  704.  
  705.   ResourceString HelpText ( Data->Library, IDS_HELP ) ;
  706.  
  707.   static MENUITEM MenuHelp =
  708.     { MIT_END, MIS_HELP, 0, 0, NULL, 0 } ;
  709.  
  710.   AddSysMenuItem ( FrameWindow, &MenuHelp, HelpText.Ptr() ) ;
  711.  
  712.  /***************************************************************************
  713.   * Calibrate the old-style load meter, if the high resolution timer's      *
  714.   *   available.                                *
  715.   ***************************************************************************/
  716.  
  717.   Data->MaxCount = (ULONG) max ( 1L, CalibrateLoadMeter ( ) ) ;
  718.  
  719.  /***************************************************************************
  720.   * Start the load meter.  Put it to sleep if we're not using it.           *
  721.   ***************************************************************************/
  722.  
  723.   DosCreateThread ( &Data->IdleLoopTID, CounterThread, (ULONG)&Data->IdleCounter, 0, 4096 ) ;
  724.   DosSetPrty ( PRTYS_THREAD, PRTYC_IDLETIME, PRTYD_MINIMUM, Data->IdleLoopTID ) ;
  725.   DosSuspendThread ( Data->IdleLoopTID ) ;
  726.  
  727.   Data->IdleCount = 0 ;
  728.   Data->IdleCounter = 0 ;
  729.  
  730.   if ( Data->Profile.AlertType == ALERT_LOAD )
  731.   {
  732.     DosResumeThread ( Data->IdleLoopTID ) ;
  733.   }
  734.  
  735.   PMONITOR_PARMS MonitorParms = PMONITOR_PARMS ( malloc ( sizeof(*MonitorParms) ) ) ;
  736.   MonitorParms->Counter = & Data->IdleCounter ;
  737.   MonitorParms->Owner = hwnd ;
  738.   DosCreateThread ( &Data->MonitorLoopTID, MonitorLoopThread, (ULONG)MonitorParms, 2, 8192 ) ;
  739.  
  740.  /***************************************************************************
  741.   * Add the program to the system task list.                    *
  742.   ***************************************************************************/
  743.  
  744.   ResourceString Title ( Data->Library, IDS_TITLE ) ;
  745.   Add2TaskList ( FrameWindow, Title.Ptr() ) ;
  746.  
  747.  /***************************************************************************
  748.   * Get device capabilities before you mess around with resizing.        *
  749.   ***************************************************************************/
  750.  
  751.   HPS hPS = WinGetPS ( hwnd ) ;
  752.   HDC hDC = GpiQueryDevice ( hPS ) ;
  753.   DevQueryCaps ( hDC, CAPS_VERTICAL_RESOLUTION, 1L,
  754.     &Data->yPixelsPerMeter ) ;
  755.   DevQueryCaps ( hDC, CAPS_HORIZONTAL_RESOLUTION, 1L,
  756.     &Data->xPixelsPerMeter ) ;
  757.   WinReleasePS ( hPS ) ;
  758.  
  759.  /***************************************************************************
  760.   * If window hasn't been positioned before, set the default position.      *
  761.   ***************************************************************************/
  762.  
  763.   RECTL Rectangle ;
  764.   if ( NOT Data->Profile.fPosition )
  765.   {
  766.     WinQueryWindowRect ( HWND_DESKTOP, &Rectangle ) ;
  767.  
  768.     Rectangle.xLeft = Rectangle.xRight - Rectangle.xRight / 4 ;
  769.     Rectangle.yBottom = Rectangle.yTop - Rectangle.yTop / 3 ;
  770.  
  771.     Data->Profile.Position.x = (SHORT) Rectangle.xLeft ;
  772.     Data->Profile.Position.y = (SHORT) Rectangle.yBottom ;
  773.  
  774.     Data->Profile.Position.cx = (SHORT) ( Rectangle.xRight - Rectangle.xLeft ) ;
  775.     Data->Profile.Position.cy = (SHORT) ( Rectangle.yTop - Rectangle.yBottom ) ;
  776.   }
  777.  
  778.  /***************************************************************************
  779.   * Position & size the window.                         *
  780.   ***************************************************************************/
  781.  
  782.   Rectangle.xLeft   = Data->Profile.Position.x ;
  783.   Rectangle.xRight  = Data->Profile.Position.x + Data->Profile.Position.cx ;
  784.   Rectangle.yBottom = Data->Profile.Position.y ;
  785.   Rectangle.yTop    = Data->Profile.Position.y + Data->Profile.Position.cy ;
  786.  
  787.   if ( Data->Profile.HideControls )
  788.   {
  789.     WinSetParent ( Data->hwndSysMenu,  HWND_OBJECT, FALSE ) ;
  790.     WinSetParent ( Data->hwndTitleBar, HWND_OBJECT, FALSE ) ;
  791.     WinSetParent ( Data->hwndMinMax,   HWND_OBJECT, FALSE ) ;
  792.  
  793.     WinSendMsg ( FrameWindow, WM_UPDATEFRAME,
  794.       MPFROMSHORT ( FCF_TITLEBAR | FCF_SYSMENU | FCF_MINBUTTON ), 0L ) ;
  795.  
  796.     WinCalcFrameRect ( FrameWindow, &Rectangle, TRUE ) ;
  797.  
  798.     WinSetParent ( Data->hwndSysMenu,  FrameWindow, TRUE ) ;
  799.     WinSetParent ( Data->hwndTitleBar, FrameWindow, TRUE ) ;
  800.     WinSetParent ( Data->hwndMinMax,   FrameWindow, TRUE ) ;
  801.  
  802.     WinSendMsg ( FrameWindow, WM_UPDATEFRAME,
  803.       MPFROMSHORT ( FCF_TITLEBAR | FCF_SYSMENU | FCF_MINBUTTON ), 0L ) ;
  804.  
  805.     WinCalcFrameRect ( FrameWindow, &Rectangle, FALSE ) ;
  806.   }
  807.  
  808.   WinSetWindowPos ( FrameWindow, HWND_BOTTOM,
  809.     (SHORT) Rectangle.xLeft, (SHORT) Rectangle.yBottom,
  810.     (SHORT) ( Rectangle.xRight - Rectangle.xLeft ),
  811.     (SHORT) ( Rectangle.yTop - Rectangle.yBottom ),
  812.     SWP_SIZE | SWP_MOVE | SWP_ZORDER |
  813.     ( Data->Profile.Position.fl & SWP_MINIMIZE ) |
  814.     ( Data->Profile.Position.fl & SWP_MAXIMIZE ) |
  815.     ( Data->Profile.Position.fl & SWP_RESTORE ) ) ;
  816.  
  817.  /***************************************************************************
  818.   * Hide the controls if so configured and not minimized.            *
  819.   ***************************************************************************/
  820.  
  821.   if ( Data->Profile.HideControls
  822.     AND NOT ( Data->Profile.Position.fl & SWP_MINIMIZE ) )
  823.   {
  824.     CheckMenuItem ( FrameWindow, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->Profile.HideControls ) ;
  825.  
  826.     HideControls
  827.     (
  828.       TRUE,
  829.       FrameWindow,
  830.       Data->hwndSysMenu,
  831.       Data->hwndTitleBar,
  832.       Data->hwndMinMax
  833.     ) ;
  834.   }
  835.  
  836.  /***************************************************************************
  837.   * Get the saved presentation parameters and reinstate them.            *
  838.   ***************************************************************************/
  839.  
  840.   if ( Data->Profile.fFontNameSize )
  841.   {
  842.     WinSetPresParam ( hwnd, PP_FONTNAMESIZE,
  843.       strlen(Data->Profile.FontNameSize)+1, Data->Profile.FontNameSize ) ;
  844.   }
  845.  
  846.   if ( Data->Profile.fBackColor )
  847.   {
  848.     WinSetPresParam ( hwnd, PP_BACKGROUNDCOLOR,
  849.       sizeof(Data->Profile.BackColor), &Data->Profile.BackColor ) ;
  850.   }
  851.  
  852.   if ( Data->Profile.fTextColor )
  853.   {
  854.     WinSetPresParam ( hwnd, PP_FOREGROUNDCOLOR,
  855.       sizeof(Data->Profile.TextColor), &Data->Profile.TextColor ) ;
  856.   }
  857.  
  858.  /***************************************************************************
  859.   * Now that the window's in order, make it visible.                        *
  860.   ***************************************************************************/
  861.  
  862.   WinShowWindow ( FrameWindow, TRUE ) ;
  863.  
  864.  /***************************************************************************
  865.   * Success?  Return no error.                            *
  866.   ***************************************************************************/
  867.  
  868.   return ( MRFROMSHORT ( 0 ) ) ;
  869. }
  870.  
  871. /****************************************************************************
  872.  *                                        *
  873.  *    Destroy main window.                            *
  874.  *                                        *
  875.  ****************************************************************************/
  876.  
  877. static MRESULT APIENTRY Destroy
  878.   HWND hwnd, 
  879.   USHORT msg, 
  880.   MPARAM mp1, 
  881.   MPARAM mp2
  882. )
  883. {
  884.  /***************************************************************************
  885.   * Find the instance data.                            *
  886.   ***************************************************************************/
  887.  
  888.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  889.  
  890.  /***************************************************************************
  891.   * Release the instance memory.                        *
  892.   ***************************************************************************/
  893.  
  894.   free ( Data ) ;
  895.  
  896.  /***************************************************************************
  897.   * We're done.                                                             *
  898.   ***************************************************************************/
  899.  
  900.   return ( MRFROMSHORT ( 0 ) ) ;
  901. }
  902.  
  903. /****************************************************************************
  904.  *                                        *
  905.  *    Resize the main window.                         *
  906.  *                                        *
  907.  ****************************************************************************/
  908.  
  909. static MRESULT APIENTRY Size
  910.   HWND hwnd, 
  911.   USHORT msg, 
  912.   MPARAM mp1, 
  913.   MPARAM mp2
  914. )
  915. {
  916.  /***************************************************************************
  917.   * Find the instance data.                            *
  918.   ***************************************************************************/
  919.  
  920.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  921.  
  922.  /***************************************************************************
  923.   * Find out the window's new position and size.                            *
  924.   ***************************************************************************/
  925.  
  926.   HWND FrameWindow = WinQueryWindow ( hwnd, QW_PARENT ) ;
  927.  
  928.   SWP Position ;
  929.   WinQueryWindowPos ( FrameWindow, &Position ) ;
  930.  
  931.   if ( NOT ( Position.fl & SWP_MINIMIZE )
  932.     AND NOT ( Position.fl & SWP_MAXIMIZE ) )
  933.   {
  934.     Data->Profile.Position.x = Position.x ;
  935.     Data->Profile.Position.y = Position.y ;
  936.  
  937.     Data->Profile.Position.cx = Position.cx ;
  938.     Data->Profile.Position.cy = Position.cy ;
  939.   }
  940.  
  941.  /***************************************************************************
  942.   * If the message was a sizing notification, recompute scaling factors.    *
  943.   ***************************************************************************/
  944.  
  945.   if ( msg == WM_SIZE )
  946.   {
  947.     Data->wi.cxClient = SHORT1FROMMP ( mp2 ) ;
  948.     Data->wi.cyClient = SHORT2FROMMP ( mp2 ) ;
  949.  
  950.     SHORT sDiamMM = (SHORT) min ( Data->wi.cxClient*1000L/Data->xPixelsPerMeter,
  951.       Data->wi.cyClient*1000L/Data->yPixelsPerMeter ) ;
  952.  
  953.     Data->wi.cxPixelDiam = (SHORT) ( Data->xPixelsPerMeter * sDiamMM / 1000 ) ;
  954.     Data->wi.cyPixelDiam = (SHORT) ( Data->yPixelsPerMeter * sDiamMM / 1000 ) ;
  955.   }
  956.  
  957.  /***************************************************************************
  958.   * If hiding the controls . . .                        *
  959.   ***************************************************************************/
  960.  
  961.   if ( Data->Profile.HideControls )
  962.   {
  963.  
  964.    /*************************************************************************
  965.     * If changing to or from minimized state . . .                *
  966.     *************************************************************************/
  967.  
  968.     if ( ( Position.fl & SWP_MINIMIZE ) != ( Data->Profile.Position.fl & SWP_MINIMIZE ) )
  969.     {
  970.  
  971.      /***********************************************************************
  972.       * Hide the controls if no longer minimized.                *
  973.       ***********************************************************************/
  974.  
  975.       HideControls
  976.       (
  977.     NOT ( Position.fl & SWP_MINIMIZE ),
  978.     FrameWindow,
  979.     Data->hwndSysMenu,
  980.     Data->hwndTitleBar,
  981.     Data->hwndMinMax
  982.       ) ;
  983.     }
  984.   }
  985.  
  986.   Data->Profile.Position.fl = Position.fl ;
  987.  
  988.  /***************************************************************************
  989.   * We're done.                                                             *
  990.   ***************************************************************************/
  991.  
  992.   return ( 0 ) ;
  993. }
  994.  
  995. /****************************************************************************
  996.  *                                        *
  997.  *    Process SAVE APPLICATION message.                    *
  998.  *                                        *
  999.  ****************************************************************************/
  1000.  
  1001. static MRESULT APIENTRY SaveApplication
  1002.   HWND hwnd, 
  1003.   USHORT msg, 
  1004.   MPARAM mp1, 
  1005.   MPARAM mp2
  1006. )
  1007. {
  1008.  /***************************************************************************
  1009.   * Find the instance data.                            *
  1010.   ***************************************************************************/
  1011.  
  1012.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1013.  
  1014.  /***************************************************************************
  1015.   * Call function to put all profile data out to the system.            *
  1016.   ***************************************************************************/
  1017.  
  1018.   PutProfile ( Data->ProfileHandle, &Data->Profile ) ;
  1019.  
  1020.  /***************************************************************************
  1021.   * We're done.  Let the system complete default processing.                *
  1022.   ***************************************************************************/
  1023.  
  1024.   return ( WinDefWindowProc ( hwnd, WM_SAVEAPPLICATION, 0, 0 ) ) ;
  1025. }
  1026.  
  1027. /****************************************************************************
  1028.  *                                        *
  1029.  *    Process timer message.                            *
  1030.  *                                        *
  1031.  ****************************************************************************/
  1032.  
  1033. static MRESULT APIENTRY Refresh
  1034.   HWND hwnd, 
  1035.   USHORT msg, 
  1036.   MPARAM mp1, 
  1037.   MPARAM mp2
  1038. )
  1039. {
  1040.  /***************************************************************************
  1041.   *                Declarations                    *
  1042.   ***************************************************************************/
  1043.  
  1044.   static POINTL
  1045.     aptlHour[5]   = { 0,-15,  10,0,  0,60,  -10,0,  0,-15 },
  1046.     aptlMinute[5] = { 0,-20,   5,0,  0,80,   -5,0,  0,-20 },
  1047.     aptlSecond[2] = { 0,  0,   0,80 } ;
  1048.  
  1049.  /***************************************************************************
  1050.   * Find the instance data.                            *
  1051.   ***************************************************************************/
  1052.  
  1053.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1054.  
  1055.  /***************************************************************************
  1056.   * If we're supposed to float the window, do so here.                      *
  1057.   ***************************************************************************/
  1058.  
  1059.   if ( Data->Profile.Float )
  1060.     WinSetWindowPos ( WinQueryWindow(hwnd,QW_PARENT), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER ) ;
  1061.  
  1062.  /***************************************************************************
  1063.   * Save the idle counter.                            *
  1064.   ***************************************************************************/
  1065.  
  1066.   Data->IdleCount = LONGFROMMP ( mp1 ) ;
  1067.  
  1068.  /***************************************************************************
  1069.   * Get current time.                                *
  1070.   ***************************************************************************/
  1071.  
  1072.   DATETIME DateTime ;
  1073.   DosGetDateTime ( &DateTime ) ;
  1074.  
  1075.   USHORT Hour = ( ( DateTime.hours * 5 ) % 60 + DateTime.minutes / 12 ) ;
  1076.  
  1077.  /***************************************************************************
  1078.   * Get presentation space.                            *
  1079.   ***************************************************************************/
  1080.  
  1081.   HPS hPS = WinGetPS ( hwnd ) ;
  1082.   GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL ) ;
  1083.  
  1084.  /***************************************************************************
  1085.   * If analog or minimized . . .                        *
  1086.   ***************************************************************************/
  1087.  
  1088.   if ( Data->Profile.Analog OR ( Data->Profile.Position.fl & SWP_MINIMIZE ) )
  1089.   {
  1090.  
  1091.    /*************************************************************************
  1092.     * If a new minute has arrived, and the clock is minimized, clear it.    *
  1093.     *************************************************************************/
  1094.  
  1095.     if ( ( Data->Profile.Position.fl & SWP_MINIMIZE )
  1096.       AND ( DateTime.minutes != Data->PreviousDateTime.minutes ) )
  1097.     {
  1098.       PaintBackground ( hwnd, hPS, Data, TRUE ) ;
  1099.     }
  1100.  
  1101.    /*************************************************************************
  1102.     * Erase the old clock hands.                        *
  1103.     *************************************************************************/
  1104.  
  1105.     GpiSetColor ( hPS, Data->Profile.BackColor ) ;
  1106.     if ( ( Data->wi.cxClient > 50 ) AND ( Data->wi.cyClient > 50 ) )
  1107.     {
  1108.       DrawHand ( hPS, aptlSecond, 2, Data->PreviousDateTime.seconds, &Data->wi ) ;
  1109.     }
  1110.  
  1111.     if ( ( Hour != Data->PreviousHour )
  1112.       OR ( DateTime.minutes != Data->PreviousDateTime.minutes ) )
  1113.     {
  1114.       DrawHand ( hPS, aptlHour,   5, Data->PreviousHour,         &Data->wi ) ;
  1115.       DrawHand ( hPS, aptlMinute, 5, Data->PreviousDateTime.minutes, &Data->wi ) ;
  1116.     }
  1117.  
  1118.    /*************************************************************************
  1119.     * Draw the new clock hands.                         *
  1120.     *************************************************************************/
  1121.  
  1122.     GpiSetColor ( hPS, Data->Profile.TextColor ) ;
  1123.     DrawHand ( hPS, aptlHour,    5, Hour,         &Data->wi ) ;
  1124.     DrawHand ( hPS, aptlMinute, 5, DateTime.minutes, &Data->wi ) ;
  1125.     if ( ( Data->wi.cxClient > 50 ) AND ( Data->wi.cyClient > 50 ) )
  1126.     {
  1127.       DrawHand ( hPS, aptlSecond, 2, DateTime.seconds, &Data->wi ) ;
  1128.     }
  1129.   }
  1130.  
  1131.  /***************************************************************************
  1132.   * Else if digital . . .                            *
  1133.   ***************************************************************************/
  1134.  
  1135.   else
  1136.   {
  1137.  
  1138.    /*************************************************************************
  1139.     * If minute has changed . . .                        *
  1140.     *************************************************************************/
  1141.  
  1142.     if ( DateTime.minutes != Data->PreviousDateTime.minutes )
  1143.     {
  1144.       PaintDigitalTime ( hwnd, hPS, Data, &DateTime ) ;
  1145.     }
  1146.   }
  1147.  
  1148.  /***************************************************************************
  1149.   * Adjust the border color to suit the current alert level.            *
  1150.   ***************************************************************************/
  1151.  
  1152.   PaintBorder ( hwnd, hPS, Data, FALSE ) ;
  1153.  
  1154.  /***************************************************************************
  1155.   * Release presentation space.                         *
  1156.   ***************************************************************************/
  1157.  
  1158.   WinReleasePS ( hPS ) ;
  1159.  
  1160.  /***************************************************************************
  1161.   * Chime if we've passed the top of the hour.  Save time when done.        *
  1162.   ***************************************************************************/
  1163.  
  1164.   if ( Data->Profile.Chime AND ( DateTime.hours != Data->PreviousDateTime.hours ) )
  1165.   {
  1166.     DosBeep  ( 400, 100 ) ;
  1167.     DosSleep (        100 ) ;
  1168.     DosBeep  ( 400, 100 ) ;
  1169.   }
  1170.  
  1171.   Data->PreviousDateTime = DateTime ;
  1172.   Data->PreviousHour = Hour ;
  1173.  
  1174.   return ( 0 ) ;
  1175. }
  1176.  
  1177. /****************************************************************************
  1178.  *                                        *
  1179.  *    Repaint entire window.                            *
  1180.  *                                        *
  1181.  ****************************************************************************/
  1182.  
  1183. static MRESULT APIENTRY Paint
  1184. (
  1185.   HWND hwnd,
  1186.   USHORT msg,
  1187.   MPARAM mp1,
  1188.   MPARAM mp2
  1189. )
  1190. {
  1191.  /***************************************************************************
  1192.   *                Declarations                    *
  1193.   ***************************************************************************/
  1194.  
  1195.   static POINTL
  1196.     aptlHour[5]   = { 0,-15,  10,0,  0,60,  -10,0,  0,-15 },
  1197.     aptlMinute[5] = { 0,-20,   5,0,  0,80,   -5,0,  0,-20 },
  1198.     aptlSecond[2] = { 0,  0,   0,80 } ;
  1199.  
  1200.  /***************************************************************************
  1201.   * Find the instance data.                            *
  1202.   ***************************************************************************/
  1203.  
  1204.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1205.  
  1206.  /***************************************************************************
  1207.   * Get presentation space and make it use RGB colors.                *
  1208.   ***************************************************************************/
  1209.  
  1210.   HPS hPS = WinBeginPaint ( hwnd, NULL, NULL ) ;
  1211.   GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL ) ;
  1212.  
  1213.  /***************************************************************************
  1214.   * Paint the background.                            *
  1215.   ***************************************************************************/
  1216.  
  1217.   PaintBackground ( hwnd, hPS, Data, TRUE ) ;
  1218.  
  1219.  /***************************************************************************
  1220.   * If analog or minimized . . .                        *
  1221.   ***************************************************************************/
  1222.  
  1223.   if ( Data->Profile.Analog OR ( Data->Profile.Position.fl & SWP_MINIMIZE ) )
  1224.   {
  1225.  
  1226.    /*************************************************************************
  1227.     * Draw hour, minute and second hands.                    *
  1228.     *************************************************************************/
  1229.  
  1230.     DrawHand ( hPS, aptlHour,    5, Data->PreviousHour,           &Data->wi ) ;
  1231.     DrawHand ( hPS, aptlMinute, 5, Data->PreviousDateTime.minutes, &Data->wi ) ;
  1232.  
  1233.     if ( ( Data->wi.cxClient > 50 ) AND ( Data->wi.cyClient > 50 ) )
  1234.     {
  1235.       DrawHand ( hPS, aptlSecond, 2, Data->PreviousDateTime.seconds, &Data->wi ) ;
  1236.     }
  1237.   }
  1238.  
  1239.  /***************************************************************************
  1240.   * Else if digital . . .                            *
  1241.   ***************************************************************************/
  1242.  
  1243.   else
  1244.   {
  1245.     PaintDigitalTime ( hwnd, hPS, Data, &Data->PreviousDateTime ) ;
  1246.   }
  1247.  
  1248.  /***************************************************************************
  1249.   * Release presentation space and return.                    *
  1250.   ***************************************************************************/
  1251.  
  1252.   WinEndPaint ( hPS ) ;
  1253.  
  1254.   return ( 0 ) ;
  1255. }
  1256.  
  1257. /****************************************************************************
  1258.  *                                        *
  1259.  *    Process commands received by Main Window                *
  1260.  *                                        *
  1261.  ****************************************************************************/
  1262.  
  1263. static MRESULT APIENTRY Command
  1264. (
  1265.   HWND hwnd,
  1266.   USHORT msg,
  1267.   MPARAM mp1,
  1268.   MPARAM mp2
  1269. )
  1270. {
  1271.  /***************************************************************************
  1272.   * Dispatch the messages.  There is no default message processor.        *
  1273.   ***************************************************************************/
  1274.  
  1275.   static METHOD Methods [] =
  1276.   {
  1277.     { IDM_SAVE_APPLICATION, SaveApplication },
  1278.     { IDM_RESET_DEFAULTS,   ResetDefaults   },
  1279.     { IDM_HIDE_CONTROLS,    HideControlsCmd },
  1280.     { IDM_CONFIGURE,        Configure        },
  1281.     { IDM_EXIT,         Exit        },
  1282.     { IDM_ABOUT,        About        }
  1283.   } ;
  1284.  
  1285.   return ( DispatchMessage ( hwnd, SHORT1FROMMP(mp1), mp1, mp2, Methods, sizeof(Methods)/sizeof(Methods[0]), NULL ) ) ;
  1286. }
  1287.  
  1288. /****************************************************************************
  1289.  *                                        *
  1290.  *    Process Reset Defaults menu command.                    *
  1291.  *                                        *
  1292.  ****************************************************************************/
  1293.  
  1294. static MRESULT APIENTRY ResetDefaults
  1295.   HWND hwnd, 
  1296.   USHORT msg, 
  1297.   MPARAM mp1, 
  1298.   MPARAM mp2
  1299. )
  1300. {
  1301.  /***************************************************************************
  1302.   * Find the instance data.                            *
  1303.   ***************************************************************************/
  1304.  
  1305.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1306.  
  1307.  /***************************************************************************
  1308.   * Reset all profile data for this program.                    *
  1309.   ***************************************************************************/
  1310.  
  1311.   PrfWriteProfileData ( Data->ProfileHandle, PSZ(PROGRAM_NAME), NULL, NULL, 0 ) ;
  1312.  
  1313.  /***************************************************************************
  1314.   * Reset the program's presentation parameters.                            *
  1315.   ***************************************************************************/
  1316.  
  1317.   WinRemovePresParam ( hwnd, PP_FONTNAMESIZE ) ;
  1318.   WinRemovePresParam ( hwnd, PP_FOREGROUNDCOLOR ) ;
  1319.   WinRemovePresParam ( hwnd, PP_BACKGROUNDCOLOR ) ;
  1320.  
  1321.  /***************************************************************************
  1322.   * Done.                                    *
  1323.   ***************************************************************************/
  1324.  
  1325.   return ( MRFROMSHORT ( 0 ) ) ;
  1326. }
  1327.  
  1328. /****************************************************************************
  1329.  *                                        *
  1330.  *    Process Hide Controls menu command.                    *
  1331.  *                                        *
  1332.  ****************************************************************************/
  1333.  
  1334. static MRESULT APIENTRY HideControlsCmd
  1335.   HWND hwnd, 
  1336.   USHORT msg, 
  1337.   MPARAM mp1, 
  1338.   MPARAM mp2
  1339. )
  1340. {
  1341.  /***************************************************************************
  1342.   * Find the instance data.                            *
  1343.   ***************************************************************************/
  1344.  
  1345.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1346.  
  1347.  /***************************************************************************
  1348.   * Get the frame window handle.                        *
  1349.   ***************************************************************************/
  1350.  
  1351.   HWND FrameWindow = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1352.  
  1353.  /***************************************************************************
  1354.   * Toggle the Hide Controls setting.                        *
  1355.   ***************************************************************************/
  1356.  
  1357.   Data->Profile.HideControls = Data->Profile.HideControls ? FALSE : TRUE ;
  1358.   Data->Profile.fHideControls = TRUE ;
  1359.  
  1360.  /***************************************************************************
  1361.   * If controls aren't hidden yet, update the menu check-mark.              *
  1362.   ***************************************************************************/
  1363.  
  1364.   if ( Data->Profile.HideControls )
  1365.     CheckMenuItem ( FrameWindow, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->Profile.HideControls ) ;
  1366.  
  1367.  /***************************************************************************
  1368.   * If not minimized right now, hide or reveal the controls.            *
  1369.   ***************************************************************************/
  1370.  
  1371.   if ( NOT ( Data->Profile.Position.fl & SWP_MINIMIZE ) )
  1372.   {
  1373.     HideControls
  1374.     (
  1375.       Data->Profile.HideControls,
  1376.       FrameWindow,
  1377.       Data->hwndSysMenu,
  1378.       Data->hwndTitleBar,
  1379.       Data->hwndMinMax
  1380.     ) ;
  1381.   }
  1382.  
  1383.  /***************************************************************************
  1384.   * If controls are no longer hidden, update the menu check-mark.        *
  1385.   ***************************************************************************/
  1386.  
  1387.   if ( NOT Data->Profile.HideControls )
  1388.     CheckMenuItem ( FrameWindow, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->Profile.HideControls ) ;
  1389.  
  1390.  /***************************************************************************
  1391.   * Done.                                    *
  1392.   ***************************************************************************/
  1393.  
  1394.   return ( MRFROMSHORT ( 0 ) ) ;
  1395. }
  1396.  
  1397. /****************************************************************************
  1398.  *                                        *
  1399.  *    Process Configure command.                        *
  1400.  *                                        *
  1401.  ****************************************************************************/
  1402.  
  1403. static MRESULT APIENTRY Configure
  1404.   HWND hwnd, 
  1405.   USHORT msg, 
  1406.   MPARAM mp1, 
  1407.   MPARAM mp2
  1408. )
  1409. {
  1410.  /***************************************************************************
  1411.   * Find the instance data.                            *
  1412.   ***************************************************************************/
  1413.  
  1414.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1415.  
  1416.  /***************************************************************************
  1417.   * Invoke the Configure dialog.                        *
  1418.   ***************************************************************************/
  1419.  
  1420.   CONFIG_PARMS Parms ;
  1421.   Parms.id         = IDD_CONFIGURE ;
  1422.   Parms.hwndHelp     = WinQueryHelpInstance ( hwnd ) ;
  1423.   Parms.Analog         = Data->Profile.Analog ;
  1424.   Parms.Hour24         = Data->Profile.Hour24 ;
  1425.   Parms.HideControls = Data->Profile.HideControls ;
  1426.   Parms.Chime         = Data->Profile.Chime ;
  1427.   Parms.Float         = Data->Profile.Float ;
  1428.   Parms.AlertType    = Data->Profile.AlertType ;
  1429.  
  1430.   memcpy ( Parms.AlertLevels, Data->Profile.AlertLevels, sizeof(Parms.AlertLevels) ) ;
  1431.  
  1432.   if ( WinDlgBox ( HWND_DESKTOP, hwnd, ConfigureProcessor,
  1433.     Data->Library, IDD_CONFIGURE, &Parms ) )
  1434.   {
  1435.     Data->Profile.fHour24 = TRUE ;
  1436.     if ( Data->Profile.Hour24 != Parms.Hour24 )
  1437.     {
  1438.       Data->Profile.Hour24 = Parms.Hour24 ;
  1439.       WinInvalidateRect ( hwnd, NULL, FALSE ) ;
  1440.     }
  1441.  
  1442.     Data->Profile.fChime = TRUE ;
  1443.     Data->Profile.Chime = Parms.Chime ;
  1444.  
  1445.     Data->Profile.fFloat = TRUE ;
  1446.     Data->Profile.Float = Parms.Float ;
  1447.  
  1448.     Data->Profile.fAlertType = TRUE ;
  1449.     if ( Data->Profile.AlertType != Parms.AlertType )
  1450.     {
  1451.       Data->Profile.AlertType = Parms.AlertType ;
  1452.       if ( Data->Profile.AlertType == ALERT_LOAD )
  1453.     DosResumeThread ( Data->IdleLoopTID ) ;
  1454.       else
  1455.     DosSuspendThread ( Data->IdleLoopTID ) ;
  1456.     }
  1457.  
  1458.     Data->Profile.fAnalog = TRUE ;
  1459.     if ( Data->Profile.Analog != Parms.Analog )
  1460.     {
  1461.       Data->Profile.Analog = Parms.Analog ;
  1462.       WinInvalidateRect ( hwnd, NULL, FALSE ) ;
  1463.     }
  1464.  
  1465.     Data->Profile.fHideControls = TRUE ;
  1466.     if ( Data->Profile.HideControls != Parms.HideControls )
  1467.     {
  1468.       HWND FrameWindow = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1469.       Data->Profile.HideControls = Parms.HideControls ;
  1470.       if ( Data->Profile.HideControls )
  1471.     CheckMenuItem ( FrameWindow, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->Profile.HideControls ) ;
  1472.       if ( NOT ( Data->Profile.Position.fl & SWP_MINIMIZE ) )
  1473.       {
  1474.     HideControls
  1475.     (
  1476.       Data->Profile.HideControls,
  1477.       FrameWindow,
  1478.       Data->hwndSysMenu,
  1479.       Data->hwndTitleBar,
  1480.       Data->hwndMinMax
  1481.     ) ;
  1482.       }
  1483.       if ( NOT Data->Profile.HideControls )
  1484.     CheckMenuItem ( FrameWindow, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->Profile.HideControls ) ;
  1485.     }
  1486.  
  1487.     Data->Profile.fAlertLevels = TRUE ;
  1488.     memcpy ( Data->Profile.AlertLevels, Parms.AlertLevels, sizeof(Parms.AlertLevels) ) ;
  1489.   }
  1490.  
  1491.  /***************************************************************************
  1492.   * Done.                                    *
  1493.   ***************************************************************************/
  1494.  
  1495.   return ( MRFROMSHORT ( 0 ) ) ;
  1496. }
  1497.  
  1498. /****************************************************************************
  1499.  *                                        *
  1500.  *    Process About menu command.                        *
  1501.  *                                        *
  1502.  ****************************************************************************/
  1503.  
  1504. static MRESULT APIENTRY About
  1505.   HWND hwnd, 
  1506.   USHORT msg, 
  1507.   MPARAM mp1, 
  1508.   MPARAM mp2
  1509. )
  1510. {
  1511.  /***************************************************************************
  1512.   * Find the instance data.                            *
  1513.   ***************************************************************************/
  1514.  
  1515.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1516.  
  1517.  /***************************************************************************
  1518.   * Invoke the About dialog.                            *
  1519.   ***************************************************************************/
  1520.  
  1521.   ABOUT_PARMS Parms ;
  1522.   Parms.id = IDD_ABOUT ;
  1523.   Parms.hwndHelp = WinQueryHelpInstance ( hwnd ) ;
  1524.  
  1525.   WinDlgBox ( HWND_DESKTOP, hwnd, AboutProcessor,
  1526.     Data->Library, IDD_ABOUT, &Parms ) ;
  1527.  
  1528.  /***************************************************************************
  1529.   * Done.                                    *
  1530.   ***************************************************************************/
  1531.  
  1532.   return ( MRFROMSHORT ( 0 ) ) ;
  1533. }
  1534.  
  1535. /****************************************************************************
  1536.  *                                        *
  1537.  *    Process Mouse Button being pressed.                    *
  1538.  *                                        *
  1539.  ****************************************************************************/
  1540.  
  1541. static MRESULT APIENTRY ButtonDown
  1542. (
  1543.   HWND hwnd,
  1544.   USHORT msg,
  1545.   MPARAM mp1,
  1546.   MPARAM mp2
  1547. )
  1548. {
  1549.  /***************************************************************************
  1550.   * Find the instance data.                            *
  1551.   ***************************************************************************/
  1552.  
  1553.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1554.  
  1555.  /***************************************************************************
  1556.   * Determine the new window position.                        *
  1557.   ***************************************************************************/
  1558.  
  1559.   TRACKINFO TrackInfo ;
  1560.   memset ( &TrackInfo, 0, sizeof(TrackInfo) ) ;
  1561.  
  1562.   TrackInfo.cxBorder = 1 ;
  1563.   TrackInfo.cyBorder = 1 ;
  1564.   TrackInfo.cxGrid = 1 ;
  1565.   TrackInfo.cyGrid = 1 ;
  1566.   TrackInfo.cxKeyboard = 8 ;
  1567.   TrackInfo.cyKeyboard = 8 ;
  1568.  
  1569.   HWND FrameWindow = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1570.  
  1571.   SWP Position ;
  1572.   WinQueryWindowPos ( FrameWindow, &Position ) ;
  1573.   TrackInfo.rclTrack.xLeft   = Position.x ;
  1574.   TrackInfo.rclTrack.xRight  = Position.x + Position.cx ;
  1575.   TrackInfo.rclTrack.yBottom = Position.y ;
  1576.   TrackInfo.rclTrack.yTop    = Position.y + Position.cy ;
  1577.  
  1578.   WinQueryWindowPos ( HWND_DESKTOP, &Position ) ;
  1579.   TrackInfo.rclBoundary.xLeft   = Position.x ;
  1580.   TrackInfo.rclBoundary.xRight  = Position.x + Position.cx ;
  1581.   TrackInfo.rclBoundary.yBottom = Position.y ;
  1582.   TrackInfo.rclBoundary.yTop    = Position.y + Position.cy ;
  1583.  
  1584.   TrackInfo.ptlMinTrackSize.x = 0 ;
  1585.   TrackInfo.ptlMinTrackSize.y = 0 ;
  1586.   TrackInfo.ptlMaxTrackSize.x = Position.cx ;
  1587.   TrackInfo.ptlMaxTrackSize.y = Position.cy ;
  1588.  
  1589.   TrackInfo.fs = TF_MOVE | TF_STANDARD | TF_ALLINBOUNDARY ;
  1590.  
  1591.   if ( WinTrackRect ( HWND_DESKTOP, NULL, &TrackInfo ) )
  1592.   {
  1593.     WinSetWindowPos ( FrameWindow, NULL,
  1594.       (SHORT) TrackInfo.rclTrack.xLeft,
  1595.       (SHORT) TrackInfo.rclTrack.yBottom,
  1596.       0, 0, SWP_MOVE ) ;
  1597.   }
  1598.  
  1599.  /***************************************************************************
  1600.   * Return through the default processor, letting window activation        *
  1601.   *   and other system functions occur.                     *
  1602.   ***************************************************************************/
  1603.  
  1604.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1605. }
  1606.  
  1607. /****************************************************************************
  1608.  *                                        *
  1609.  *    Process Mouse Button having been double-clicked.            *
  1610.  *                                        *
  1611.  ****************************************************************************/
  1612.  
  1613. static MRESULT APIENTRY ButtonDblClick
  1614. (
  1615.   HWND hwnd,
  1616.   USHORT msg,
  1617.   MPARAM mp1,
  1618.   MPARAM mp2
  1619. )
  1620. {
  1621.  /***************************************************************************
  1622.   * Send message to self to stop hiding the controls.                *
  1623.   ***************************************************************************/
  1624.  
  1625.   WinPostMsg ( hwnd, WM_COMMAND,
  1626.     MPFROM2SHORT ( IDM_HIDE_CONTROLS, 0 ),
  1627.     MPFROM2SHORT ( CMDSRC_OTHER, TRUE ) ) ;
  1628.  
  1629.  /***************************************************************************
  1630.   * Return through the default processor, letting window activation        *
  1631.   *   and other system functions occur.                     *
  1632.   ***************************************************************************/
  1633.  
  1634.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1635. }
  1636.  
  1637. /****************************************************************************
  1638.  *                                        *
  1639.  *    Process Presentation Parameter Changed notification.            *
  1640.  *                                        *
  1641.  ****************************************************************************/
  1642.  
  1643. static MRESULT APIENTRY PresParamChanged
  1644. (
  1645.   HWND hwnd,
  1646.   USHORT msg,
  1647.   MPARAM mp1,
  1648.   MPARAM mp2
  1649. )
  1650. {
  1651.  /***************************************************************************
  1652.   * Find the instance data.                            *
  1653.   ***************************************************************************/
  1654.  
  1655.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1656.  
  1657.  /***************************************************************************
  1658.   * Get the presentation parameter that changed.                *
  1659.   ***************************************************************************/
  1660.  
  1661.   switch ( LONGFROMMP(mp1) )
  1662.   {
  1663.  
  1664.    /*************************************************************************
  1665.     * If font, note the fact that we now have a font to be saved as        *
  1666.     *    part of the configuration.  Get the font metrics and resize        *
  1667.     *    the window appropriately.                        *
  1668.     *************************************************************************/
  1669.  
  1670.     case PP_FONTNAMESIZE:
  1671.     {
  1672.       ULONG ppid ;
  1673.       if ( WinQueryPresParam ( hwnd, PP_FONTNAMESIZE, 0, &ppid,
  1674.     sizeof(Data->Profile.FontNameSize), &Data->Profile.FontNameSize,
  1675.     0 ) )
  1676.       {
  1677.     Data->Profile.fFontNameSize = TRUE ;
  1678.       }
  1679.       else
  1680.       {
  1681.     strcpy ( (PCHAR)Data->Profile.FontNameSize, "" ) ;
  1682.     Data->Profile.fFontNameSize = FALSE ;
  1683.     PrfWriteProfileData ( Data->ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"FontNameSize", NULL, 0 ) ;
  1684.       }
  1685.       WinInvalidateRect ( hwnd, NULL, TRUE ) ;
  1686.       break ;
  1687.     }
  1688.  
  1689.    /*************************************************************************
  1690.     * If background color, note the fact and repaint the window.        *
  1691.     *************************************************************************/
  1692.  
  1693.     case PP_BACKGROUNDCOLOR:
  1694.     {
  1695.       ULONG ppid ;
  1696.       if ( WinQueryPresParam ( hwnd, PP_BACKGROUNDCOLOR, 0, &ppid,
  1697.     sizeof(Data->Profile.BackColor), &Data->Profile.BackColor, 0 ) )
  1698.       {
  1699.     Data->Profile.fBackColor = TRUE ;
  1700.       }
  1701.       else
  1702.       {
  1703.     Data->Profile.BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0L ) ;
  1704.     Data->Profile.fBackColor = FALSE ;
  1705.     PrfWriteProfileData ( Data->ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"BackgroundColor", NULL, 0 ) ;
  1706.       }
  1707.       WinInvalidateRect ( hwnd, NULL, TRUE ) ;
  1708.       break ;
  1709.     }
  1710.  
  1711.    /*************************************************************************
  1712.     * If foreground color, note the fact and repaint the window.        *
  1713.     *************************************************************************/
  1714.  
  1715.     case PP_FOREGROUNDCOLOR:
  1716.     {
  1717.       ULONG ppid ;
  1718.       if ( WinQueryPresParam ( hwnd, PP_FOREGROUNDCOLOR, 0, &ppid,
  1719.     sizeof(Data->Profile.TextColor), &Data->Profile.TextColor, 0 ) )
  1720.       {
  1721.     Data->Profile.fTextColor = TRUE ;
  1722.       }
  1723.       else
  1724.       {
  1725.     Data->Profile.TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0L ) ;
  1726.     Data->Profile.fTextColor = FALSE ;
  1727.     PrfWriteProfileData ( Data->ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"ForegroundColor", NULL, 0 ) ;
  1728.       }
  1729.       WinInvalidateRect ( hwnd, NULL, TRUE ) ;
  1730.       break ;
  1731.     }
  1732.   }
  1733.  
  1734.  /***************************************************************************
  1735.   * Return through the default processor, letting window activation        *
  1736.   *   and other system functions occur.                     *
  1737.   ***************************************************************************/
  1738.  
  1739.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1740. }
  1741.  
  1742. /****************************************************************************
  1743.  *                                        *
  1744.  *    Process System Color Change notification.                *
  1745.  *                                        *
  1746.  ****************************************************************************/
  1747.  
  1748. static MRESULT APIENTRY SysColorChange
  1749. (
  1750.   HWND hwnd,
  1751.   USHORT msg,
  1752.   MPARAM mp1,
  1753.   MPARAM mp2
  1754. )
  1755. {
  1756.  /***************************************************************************
  1757.   * Find the instance data.                            *
  1758.   ***************************************************************************/
  1759.  
  1760.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1761.  
  1762.  /***************************************************************************
  1763.   * If we aren't using custom colors, then query for the new defaults.      *
  1764.   ***************************************************************************/
  1765.  
  1766.   if ( NOT Data->Profile.fBackColor )
  1767.   {
  1768.     Data->Profile.BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0L ) ;
  1769.   }
  1770.  
  1771.   if ( NOT Data->Profile.fTextColor )
  1772.   {
  1773.     Data->Profile.TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0L ) ;
  1774.   }
  1775.  
  1776.  /***************************************************************************
  1777.   * Return value must be NULL, according to the documentation.            *
  1778.   ***************************************************************************/
  1779.  
  1780.   return ( MRFROMP ( NULL ) ) ;
  1781. }
  1782.  
  1783. /****************************************************************************
  1784.  *                                        *
  1785.  *    Process Query for Keys Help resource id.                *
  1786.  *                                        *
  1787.  ****************************************************************************/
  1788.  
  1789. static MRESULT APIENTRY QueryKeysHelp
  1790. (
  1791.   HWND hwnd,
  1792.   USHORT msg,
  1793.   MPARAM mp1,
  1794.   MPARAM mp2
  1795. )
  1796. {
  1797.  /***************************************************************************
  1798.   * Simply return the ID of the Keys Help panel.                *
  1799.   ***************************************************************************/
  1800.  
  1801.   return ( (MRESULT) IDM_KEYS_HELP ) ;
  1802. }
  1803.  
  1804. /****************************************************************************
  1805.  *                                        *
  1806.  *    Process Help Manager Error                        *
  1807.  *                                        *
  1808.  ****************************************************************************/
  1809.  
  1810. static MRESULT APIENTRY HelpError
  1811.   HWND hwnd, 
  1812.   USHORT msg, 
  1813.   MPARAM mp1, 
  1814.   MPARAM mp2
  1815. )
  1816. {
  1817.  /***************************************************************************
  1818.   * Local Declarations                                *
  1819.   ***************************************************************************/
  1820.  
  1821.   static struct
  1822.   {
  1823.     ULONG Error ;
  1824.     USHORT StringId ;
  1825.   }
  1826.   HelpErrors [] =
  1827.   {
  1828.     { HMERR_NO_FRAME_WND_IN_CHAIN,     IDS_HMERR_NO_FRAME_WND_IN_CHAIN },
  1829.     { HMERR_INVALID_ASSOC_APP_WND,     IDS_HMERR_INVALID_ASSOC_APP_WND },
  1830.     { HMERR_INVALID_ASSOC_HELP_INST,   IDS_HMERR_INVALID_ASSOC_HELP_IN },
  1831.     { HMERR_INVALID_DESTROY_HELP_INST, IDS_HMERR_INVALID_DESTROY_HELP_ },
  1832.     { HMERR_NO_HELP_INST_IN_CHAIN,     IDS_HMERR_NO_HELP_INST_IN_CHAIN },
  1833.     { HMERR_INVALID_HELP_INSTANCE_HDL, IDS_HMERR_INVALID_HELP_INSTANCE },
  1834.     { HMERR_INVALID_QUERY_APP_WND,     IDS_HMERR_INVALID_QUERY_APP_WND },
  1835.     { HMERR_HELP_INST_CALLED_INVALID,  IDS_HMERR_HELP_INST_CALLED_INVA },
  1836.     { HMERR_HELPTABLE_UNDEFINE,        IDS_HMERR_HELPTABLE_UNDEFINE    },
  1837.     { HMERR_HELP_INSTANCE_UNDEFINE,    IDS_HMERR_HELP_INSTANCE_UNDEFIN },
  1838.     { HMERR_HELPITEM_NOT_FOUND,        IDS_HMERR_HELPITEM_NOT_FOUND    },
  1839.     { HMERR_INVALID_HELPSUBITEM_SIZE,  IDS_HMERR_INVALID_HELPSUBITEM_S },
  1840.     { HMERR_HELPSUBITEM_NOT_FOUND,     IDS_HMERR_HELPSUBITEM_NOT_FOUND },
  1841.     { HMERR_INDEX_NOT_FOUND,           IDS_HMERR_INDEX_NOT_FOUND       },
  1842.     { HMERR_CONTENT_NOT_FOUND,           IDS_HMERR_CONTENT_NOT_FOUND     },
  1843.     { HMERR_OPEN_LIB_FILE,           IDS_HMERR_OPEN_LIB_FILE           },
  1844.     { HMERR_READ_LIB_FILE,           IDS_HMERR_READ_LIB_FILE           },
  1845.     { HMERR_CLOSE_LIB_FILE,           IDS_HMERR_CLOSE_LIB_FILE        },
  1846.     { HMERR_INVALID_LIB_FILE,           IDS_HMERR_INVALID_LIB_FILE      },
  1847.     { HMERR_NO_MEMORY,               IDS_HMERR_NO_MEMORY           },
  1848.     { HMERR_ALLOCATE_SEGMENT,           IDS_HMERR_ALLOCATE_SEGMENT      },
  1849.     { HMERR_FREE_MEMORY,           IDS_HMERR_FREE_MEMORY           },
  1850.     { HMERR_PANEL_NOT_FOUND,           IDS_HMERR_PANEL_NOT_FOUND       },
  1851.     { HMERR_DATABASE_NOT_OPEN,           IDS_HMERR_DATABASE_NOT_OPEN     },
  1852.     { 0,                   IDS_HMERR_UNKNOWN           }
  1853.   } ;
  1854.  
  1855.   ULONG ErrorCode = (ULONG) LONGFROMMP ( mp1 ) ;
  1856.  
  1857.  /***************************************************************************
  1858.   * Find the instance data.                            *
  1859.   ***************************************************************************/
  1860.  
  1861.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1862.  
  1863.  /***************************************************************************
  1864.   * Find the error code in the message table.                    *
  1865.   ***************************************************************************/
  1866.  
  1867.   int Index = 0 ;
  1868.   while ( HelpErrors[Index].Error
  1869.     AND ( HelpErrors[Index].Error != ErrorCode ) )
  1870.   {
  1871.     Index ++ ;
  1872.   }
  1873.  
  1874.  /***************************************************************************
  1875.   * Get the message texts.                            *
  1876.   ***************************************************************************/
  1877.  
  1878.   ResourceString Title ( Data->Library, IDS_HMERR ) ;
  1879.  
  1880.   ResourceString Message ( Data->Library, HelpErrors[Index].StringId ) ;
  1881.  
  1882.  /***************************************************************************
  1883.   * Display the error message.                            *
  1884.   ***************************************************************************/
  1885.  
  1886.   WinMessageBox
  1887.   (
  1888.     HWND_DESKTOP,
  1889.     hwnd,
  1890.     Message.Ptr(),
  1891.     Title.Ptr(),
  1892.     0,
  1893.     MB_OK | MB_WARNING
  1894.   ) ;
  1895.  
  1896.  /***************************************************************************
  1897.   * Return zero, indicating that the message was processed.            *
  1898.   ***************************************************************************/
  1899.  
  1900.   return ( MRFROMSHORT ( 0 ) ) ;
  1901. }
  1902.  
  1903. /****************************************************************************
  1904.  *                                        *
  1905.  *    Process "Extended Help Undefined" notification                *
  1906.  *                                        *
  1907.  ****************************************************************************/
  1908.  
  1909. static MRESULT APIENTRY ExtHelpUndefined
  1910.   HWND hwnd, 
  1911.   USHORT msg, 
  1912.   MPARAM mp1, 
  1913.   MPARAM mp2
  1914. )
  1915. {
  1916.  /***************************************************************************
  1917.   * Find the instance data.                            *
  1918.   ***************************************************************************/
  1919.  
  1920.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1921.  
  1922.  /***************************************************************************
  1923.   * Get the message texts.                            *
  1924.   ***************************************************************************/
  1925.  
  1926.   ResourceString Title ( Data->Library, IDS_HMERR ) ;
  1927.  
  1928.   ResourceString Message ( Data->Library, IDS_HMERR_EXTHELPUNDEFINED ) ;
  1929.  
  1930.  /***************************************************************************
  1931.   * Display the error message.                            *
  1932.   ***************************************************************************/
  1933.  
  1934.   WinMessageBox
  1935.   (
  1936.     HWND_DESKTOP,
  1937.     hwnd,
  1938.     Message.Ptr(),
  1939.     Title.Ptr(),
  1940.     0,
  1941.     MB_OK | MB_WARNING
  1942.   ) ;
  1943.  
  1944.  /***************************************************************************
  1945.   * Return zero, indicating that the message was processed.            *
  1946.   ***************************************************************************/
  1947.  
  1948.   return ( MRFROMSHORT ( 0 ) ) ;
  1949. }
  1950.  
  1951. /****************************************************************************
  1952.  *                                        *
  1953.  *    Process "Help Subitem Not Found" notification                *
  1954.  *                                        *
  1955.  ****************************************************************************/
  1956.  
  1957. static MRESULT APIENTRY HelpSubitemNotFound
  1958.   HWND hwnd, 
  1959.   USHORT msg, 
  1960.   MPARAM mp1, 
  1961.   MPARAM mp2
  1962. )
  1963. {
  1964.  /***************************************************************************
  1965.   * Find the instance data.                            *
  1966.   ***************************************************************************/
  1967.  
  1968.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1969.  
  1970.  /***************************************************************************
  1971.   * Get the title text.                             *
  1972.   ***************************************************************************/
  1973.  
  1974.   ResourceString Title ( Data->Library, IDS_HMERR ) ;
  1975.  
  1976.  /***************************************************************************
  1977.   * Format the error message.                            *
  1978.   ***************************************************************************/
  1979.  
  1980.   USHORT Topic = (USHORT) SHORT1FROMMP ( mp2 ) ;
  1981.   USHORT Subtopic = (USHORT) SHORT2FROMMP ( mp2 ) ;
  1982.  
  1983.   ResourceString Frame     ( Data->Library, IDS_HELPMODE_FRAME ) ;
  1984.   ResourceString Menu     ( Data->Library, IDS_HELPMODE_MENU ) ;
  1985.   ResourceString Window  ( Data->Library, IDS_HELPMODE_WINDOW ) ;
  1986.   ResourceString Unknown ( Data->Library, IDS_HELPMODE_UNKNOWN ) ;
  1987.  
  1988.   PBYTE Mode ;
  1989.   switch ( SHORT1FROMMP ( mp1 ) )
  1990.   {
  1991.     case HLPM_FRAME:
  1992.       Mode = Frame.Ptr() ;
  1993.       break ;
  1994.  
  1995.     case HLPM_MENU:
  1996.       Mode = Menu.Ptr() ;
  1997.       break ;
  1998.  
  1999.     case HLPM_WINDOW:
  2000.       Mode = Window.Ptr() ;
  2001.       break ;
  2002.  
  2003.     default:
  2004.       Mode = Unknown.Ptr() ;
  2005.   }
  2006.  
  2007.   ResourceString Format ( Data->Library, IDS_HELPSUBITEMNOTFOUND ) ;
  2008.  
  2009.   BYTE Message [200] ;
  2010.   sprintf ( (PCHAR)Message, PCHAR(Format.Ptr()), Mode, Topic, Subtopic ) ;
  2011.  
  2012.  /***************************************************************************
  2013.   * Display the error message.                            *
  2014.   ***************************************************************************/
  2015.  
  2016.   WinMessageBox
  2017.   (
  2018.     HWND_DESKTOP,
  2019.     hwnd,
  2020.     Message,
  2021.     Title.Ptr(),
  2022.     0,
  2023.     MB_OK | MB_WARNING
  2024.   ) ;
  2025.  
  2026.  /***************************************************************************
  2027.   * Return zero, indicating that the message was processed.            *
  2028.   ***************************************************************************/
  2029.  
  2030.   return ( MRFROMSHORT ( 0 ) ) ;
  2031. }
  2032.  
  2033.  
  2034. /****************************************************************************
  2035.  *                                        *
  2036.  *                 Get Profile Data                    *
  2037.  *                                        *
  2038.  ****************************************************************************/
  2039.  
  2040. static int GetProfile ( HINI ProfileHandle, PPROFILE Profile )
  2041. {
  2042.  /***************************************************************************
  2043.   * Get the window's current size and position.                             *
  2044.   ***************************************************************************/
  2045.  
  2046.   #pragma pack(2)
  2047.   typedef struct {
  2048.     USHORT Filler ;
  2049.     USHORT fs ;
  2050.     USHORT cy, cx, y, x ;
  2051.     HWND hwndInsertBehind ;
  2052.     HWND hwnd ;
  2053.   } OLDSWP ;
  2054.   #pragma pack()
  2055.  
  2056.   ULONG Size ;
  2057.   memset ( &Profile->Position, 0, sizeof(Profile->Position) ) ;
  2058.   Profile->fPosition = FALSE ;
  2059.   if ( PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Position", &Size ) )
  2060.   {
  2061.     if ( Size == sizeof(OLDSWP)-sizeof(USHORT) )
  2062.     {
  2063.       OLDSWP OldPosition ;
  2064.       if ( PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Position", &OldPosition.fs, &Size ) )
  2065.       {
  2066.     Profile->Position.fl = OldPosition.fs ;
  2067.         Profile->Position.cy = OldPosition.cy ;
  2068.         Profile->Position.cx = OldPosition.cx ;
  2069.         Profile->Position.y = OldPosition.y ;
  2070.         Profile->Position.x = OldPosition.x ;
  2071.         Profile->Position.hwndInsertBehind = OldPosition.hwndInsertBehind ;
  2072.         Profile->Position.hwnd = OldPosition.hwnd ;
  2073.         Profile->fPosition = TRUE ;
  2074.       }
  2075.     }
  2076.     else if ( Size == sizeof(Profile->Position) )
  2077.     {
  2078.       if ( PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Position", &Profile->Position, &Size ) )
  2079.       {
  2080.         Profile->fPosition = TRUE ;
  2081.       }
  2082.     }
  2083.   }
  2084.  
  2085.   if ( NOT Profile->fPosition )
  2086.   {
  2087.     if ( ProfileHandle == HINI_USERPROFILE )
  2088.     {
  2089.       return ( 1 ) ;
  2090.     }
  2091.   }
  2092.  
  2093.  /***************************************************************************
  2094.   * Get the program options.                            *
  2095.   ***************************************************************************/
  2096.  
  2097.   Profile->Hour24 = FALSE ;
  2098.   if
  2099.   (
  2100.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Hour24", &Size )
  2101.     AND
  2102.     ( ( Size == sizeof(Profile->Hour24) ) OR ( Size == sizeof(SHORT) ) )
  2103.     AND
  2104.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Hour24", &Profile->Hour24, &Size )
  2105.   )
  2106.   {
  2107.     Profile->fHour24 = TRUE ;
  2108.   }
  2109.  
  2110.   Profile->HideControls = FALSE ;
  2111.   if
  2112.   (
  2113.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"HideControls", &Size )
  2114.     AND
  2115.     ( ( Size == sizeof(Profile->HideControls) ) OR ( Size == sizeof(SHORT) ) )
  2116.     AND
  2117.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"HideControls", &Profile->HideControls, &Size )
  2118.   )
  2119.   {
  2120.     Profile->fHideControls = TRUE ;
  2121.   }
  2122.  
  2123.   Profile->Chime = FALSE ;
  2124.   if
  2125.   (
  2126.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Chime", &Size )
  2127.     AND
  2128.     ( ( Size == sizeof(Profile->Chime) ) OR ( Size == sizeof(SHORT) ) )
  2129.     AND
  2130.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Chime", &Profile->Chime, &Size )
  2131.   )
  2132.   {
  2133.     Profile->fChime = TRUE ;
  2134.   }
  2135.  
  2136.   Profile->Float = FALSE ;
  2137.   if
  2138.   (
  2139.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Float", &Size )
  2140.     AND
  2141.     ( ( Size == sizeof(Profile->Float) ) OR ( Size == sizeof(SHORT) ) )
  2142.     AND
  2143.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Float", &Profile->Float, &Size )
  2144.   )
  2145.   {
  2146.     Profile->fFloat = TRUE ;
  2147.   }
  2148.  
  2149.   Profile->Analog = TRUE ;
  2150.   if
  2151.   (
  2152.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Analog", &Size )
  2153.     AND
  2154.     ( ( Size == sizeof(Profile->Analog) ) OR ( Size == sizeof(SHORT) ) )
  2155.     AND
  2156.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Analog", &Profile->Analog, &Size )
  2157.   )
  2158.   {
  2159.     Profile->fAnalog = TRUE ;
  2160.   }
  2161.  
  2162.   Profile->AlertType = ALERT_TASKCOUNT ;
  2163.   if
  2164.   (
  2165.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"AlertType", &Size )
  2166.     AND
  2167.     ( ( Size == sizeof(Profile->AlertType) ) OR ( Size == sizeof(SHORT) ) )
  2168.     AND
  2169.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"AlertType", &Profile->AlertType, &Size )
  2170.   )
  2171.   {
  2172.     Profile->fAlertType = TRUE ;
  2173.   }
  2174.  
  2175.   Profile->AlertLevels [ALERT_TASKCOUNT] [0] = 8 ;
  2176.   Profile->AlertLevels [ALERT_TASKCOUNT] [1] = 12 ;
  2177.   Profile->AlertLevels [ALERT_LOAD]     [0] = 33 ;
  2178.   Profile->AlertLevels [ALERT_LOAD]     [1] = 67 ;
  2179.  
  2180.   if
  2181.   (
  2182.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"AlertLevels", &Size )
  2183.     AND
  2184.     ( Size == sizeof(Profile->AlertLevels) )
  2185.     AND
  2186.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"AlertLevels", Profile->AlertLevels, &Size )
  2187.   )
  2188.   {
  2189.     Profile->fAlertLevels = TRUE ;
  2190.   }
  2191.  
  2192.  /***************************************************************************
  2193.   * Get the presentation parameters.                        *
  2194.   ***************************************************************************/
  2195.  
  2196.   strcpy ( (PCHAR)Profile->FontNameSize, "" ) ;
  2197.   Profile->fFontNameSize = FALSE ;
  2198.   if
  2199.   (
  2200.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"FontNameSize", &Size )
  2201.     AND
  2202.     ( Size == sizeof(Profile->FontNameSize) )
  2203.     AND
  2204.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"FontNameSize", &Profile->FontNameSize, &Size )
  2205.   )
  2206.   {
  2207.     Profile->fFontNameSize = TRUE ;
  2208.   }
  2209.  
  2210.   Profile->BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0L ) ;
  2211.   Profile->fBackColor = FALSE ;
  2212.   if
  2213.   (
  2214.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"BackgroundColor", &Size )
  2215.     AND
  2216.     ( Size == sizeof(Profile->BackColor) )
  2217.     AND
  2218.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"BackgroundColor", &Profile->BackColor, &Size )
  2219.   )
  2220.   {
  2221.     Profile->fBackColor = TRUE ;
  2222.   }
  2223.  
  2224.   Profile->TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0L ) ;
  2225.   Profile->fTextColor = FALSE ;
  2226.   if
  2227.   (
  2228.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"ForegroundColor", &Size )
  2229.     AND
  2230.     ( Size == sizeof(Profile->TextColor) )
  2231.     AND
  2232.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"ForegroundColor", &Profile->TextColor, &Size )
  2233.   )
  2234.   {
  2235.     Profile->fTextColor = TRUE ;
  2236.   }
  2237.  
  2238.  /***************************************************************************
  2239.   * Return no error.                                *
  2240.   ***************************************************************************/
  2241.  
  2242.   return ( 0 ) ;
  2243. }
  2244.  
  2245. /****************************************************************************
  2246.  *                                        *
  2247.  *                 Put Profile Data                    *
  2248.  *                                        *
  2249.  ****************************************************************************/
  2250.  
  2251. static VOID PutProfile ( HINI ProfileHandle, PPROFILE Profile )
  2252. {
  2253.  /***************************************************************************
  2254.   * Save the window's current size and position.                            *
  2255.   ***************************************************************************/
  2256.  
  2257.   PrfWriteProfileData
  2258.   (
  2259.     ProfileHandle,
  2260.     (PSZ)PROGRAM_NAME,
  2261.     (PSZ)"Position",
  2262.     &Profile->Position,
  2263.     sizeof(Profile->Position)
  2264.   ) ;
  2265.  
  2266.  /***************************************************************************
  2267.   * Save the program options.                            *
  2268.   ***************************************************************************/
  2269.  
  2270.   if ( Profile->fHour24 )
  2271.   {
  2272.     PrfWriteProfileData
  2273.     (
  2274.       ProfileHandle,
  2275.       (PSZ)PROGRAM_NAME,
  2276.       (PSZ)"Hour24",
  2277.       &Profile->Hour24,
  2278.       (ULONG)sizeof(Profile->Hour24)
  2279.     ) ;
  2280.   }
  2281.  
  2282.   if ( Profile->fHideControls )
  2283.   {
  2284.     PrfWriteProfileData
  2285.     (
  2286.       ProfileHandle,
  2287.       (PSZ)PROGRAM_NAME,
  2288.       (PSZ)"HideControls",
  2289.       &Profile->HideControls,
  2290.       (ULONG)sizeof(Profile->HideControls)
  2291.     ) ;
  2292.   }
  2293.  
  2294.   if ( Profile->fChime )
  2295.   {
  2296.     PrfWriteProfileData
  2297.     (
  2298.       ProfileHandle,
  2299.       (PSZ)PROGRAM_NAME,
  2300.       (PSZ)"Chime",
  2301.       &Profile->Chime,
  2302.       (ULONG)sizeof(Profile->Chime)
  2303.     ) ;
  2304.   }
  2305.  
  2306.   if ( Profile->fFloat )
  2307.   {
  2308.     PrfWriteProfileData
  2309.     (
  2310.       ProfileHandle,
  2311.       (PSZ)PROGRAM_NAME,
  2312.       (PSZ)"Float",
  2313.       &Profile->Float,
  2314.       (ULONG)sizeof(Profile->Float)
  2315.     ) ;
  2316.   }
  2317.  
  2318.   if ( Profile->fAnalog )
  2319.   {
  2320.     PrfWriteProfileData
  2321.     (
  2322.       ProfileHandle,
  2323.       (PSZ)PROGRAM_NAME,
  2324.       (PSZ)"Analog",
  2325.       &Profile->Analog,
  2326.       (ULONG)sizeof(Profile->Analog)
  2327.     ) ;
  2328.   }
  2329.  
  2330.   if ( Profile->fAlertType )
  2331.   {
  2332.     PrfWriteProfileData
  2333.     (
  2334.       ProfileHandle,
  2335.       (PSZ)PROGRAM_NAME,
  2336.       (PSZ)"AlertType",
  2337.       &Profile->AlertType,
  2338.       (ULONG)sizeof(Profile->AlertType)
  2339.     ) ;
  2340.   }
  2341.  
  2342.   if ( Profile->fAlertLevels )
  2343.   {
  2344.     PrfWriteProfileData
  2345.     (
  2346.       ProfileHandle,
  2347.       (PSZ)PROGRAM_NAME,
  2348.       (PSZ)"AlertLevels",
  2349.       Profile->AlertLevels,
  2350.       (ULONG)sizeof(Profile->AlertLevels)
  2351.     ) ;
  2352.   }
  2353.  
  2354.  /***************************************************************************
  2355.   * Save the presentation parameters.                        *
  2356.   ***************************************************************************/
  2357.  
  2358.   if ( Profile->fFontNameSize )
  2359.   {
  2360.     PrfWriteProfileData
  2361.     (
  2362.       ProfileHandle,
  2363.       (PSZ)PROGRAM_NAME,
  2364.       (PSZ)"FontNameSize",
  2365.       Profile->FontNameSize,
  2366.       sizeof(Profile->FontNameSize)
  2367.     ) ;
  2368.   }
  2369.  
  2370.   if ( Profile->fBackColor )
  2371.   {
  2372.     PrfWriteProfileData
  2373.     (
  2374.       ProfileHandle,
  2375.       (PSZ)PROGRAM_NAME,
  2376.       (PSZ)"BackgroundColor",
  2377.       &Profile->BackColor,
  2378.       sizeof(Profile->BackColor)
  2379.     ) ;
  2380.   }
  2381.  
  2382.   if ( Profile->fTextColor )
  2383.   {
  2384.     PrfWriteProfileData
  2385.     (
  2386.       ProfileHandle,
  2387.       (PSZ)PROGRAM_NAME,
  2388.       (PSZ)"ForegroundColor",
  2389.       &Profile->TextColor,
  2390.       sizeof(Profile->TextColor)
  2391.     ) ;
  2392.   }
  2393. }
  2394.  
  2395. /****************************************************************************
  2396.  *                                        *
  2397.  *    Perform point coordinate rotation.                    *
  2398.  *                                        *
  2399.  ****************************************************************************/
  2400.  
  2401. static VOID RotatePoint ( POINTL aptl[],  SHORT sNum, SHORT sAngle )
  2402. {
  2403.   static SHORT sSin[60] = {
  2404.       0,  105,  208,  309,  407,  500,  588,  669,  743,  809,
  2405.     866,  914,  951,  978,  995, 1000,  995,  978,  951,  914,
  2406.     866,  809,  743,  669,  588,  500,  407,  309,  208,  105,
  2407.       0, -104, -207, -308, -406, -499, -587, -668, -742, -808,
  2408.    -865, -913, -950, -977, -994, -999, -994, -977, -950, -913,
  2409.    -865, -808, -742, -668, -587, -499, -406, -308, -207, -104 };
  2410.  
  2411.   POINTL ptlTemp ;
  2412.   SHORT sIndex ;
  2413.  
  2414.   for ( sIndex = 0; sIndex < sNum ; sIndex++ )
  2415.   {
  2416.     ptlTemp.x = (aptl[sIndex].x * sSin[(sAngle+15)%60] +
  2417.       aptl[sIndex].y * sSin[sAngle]) / 1000 ;
  2418.     ptlTemp.y = (aptl[sIndex].y * sSin[(sAngle+15)%60] -
  2419.       aptl[sIndex].x * sSin[sAngle]) / 1000 ;
  2420.     aptl[sIndex] = ptlTemp ;
  2421.   }
  2422. }
  2423.  
  2424. /****************************************************************************
  2425.  *                                        *
  2426.  *    Perform point coordinate scaling.                    *
  2427.  *                                        *
  2428.  ****************************************************************************/
  2429.  
  2430. static VOID ScalePoint ( POINTL aptl[], SHORT sNum, PWINDOWINFO pwi )
  2431. {
  2432.   SHORT sIndex ;
  2433.  
  2434.   for ( sIndex=0; sIndex < sNum; sIndex++ )
  2435.   {
  2436.     aptl[sIndex].x = aptl[sIndex].x * pwi->cxPixelDiam / 200 ;
  2437.     aptl[sIndex].y = aptl[sIndex].y * pwi->cyPixelDiam / 200 ;
  2438.   }
  2439. }
  2440.  
  2441. /****************************************************************************
  2442.  *                                        *
  2443.  *    Perform point coordinate translation.                    *
  2444.  *                                        *
  2445.  ****************************************************************************/
  2446.  
  2447. static VOID TranslatePoint ( POINTL aptl[], SHORT sNum, PWINDOWINFO pwi )
  2448. {
  2449.   SHORT sIndex ;
  2450.  
  2451.   for ( sIndex=0; sIndex<sNum; sIndex++ )
  2452.   {
  2453.     aptl[sIndex].x += pwi->cxClient / 2 - 1 ;
  2454.     aptl[sIndex].y += pwi->cyClient / 2 - 1 ;
  2455.   }
  2456. }
  2457.  
  2458. /****************************************************************************
  2459.  *                                        *
  2460.  *    Draw a clock hand.                            *
  2461.  *                                        *
  2462.  ****************************************************************************/
  2463.  
  2464. static VOID DrawHand ( HPS hPS, POINTL aptlIn[], SHORT sNum, SHORT sAngle,
  2465.   PWINDOWINFO pwi )
  2466. {
  2467.   POINTL aptl[5] ;
  2468.   SHORT sIndex ;
  2469.  
  2470.   for ( sIndex=0; sIndex<sNum; sIndex++ )
  2471.   {
  2472.     aptl [ sIndex ] = aptlIn [ sIndex ] ;
  2473.   }
  2474.  
  2475.   RotatePoint ( aptl, sNum, sAngle ) ;
  2476.   ScalePoint ( aptl, sNum, pwi ) ;
  2477.   TranslatePoint ( aptl, sNum, pwi ) ;
  2478.  
  2479.   GpiMove ( hPS, aptl ) ;
  2480.   GpiPolyLine ( hPS, sNum-1L, aptl+1 ) ;
  2481. }
  2482.  
  2483. /****************************************************************************
  2484.  *                                        *
  2485.  *             Paint Background (all but hands)                *
  2486.  *                                        *
  2487.  ****************************************************************************/
  2488.  
  2489. static void PaintBackground ( HWND hwnd, HPS hPS, PDATA Data, BOOL MustPaint )
  2490. {
  2491.  /***************************************************************************
  2492.   * Local Declarations                                *
  2493.   ***************************************************************************/
  2494.  
  2495.   SHORT  Angle ;
  2496.   POINTL Points [3] ;
  2497.   RECTL  Rectangle ;
  2498.  
  2499.  /***************************************************************************
  2500.   * Clear the window.                                *
  2501.   ***************************************************************************/
  2502.  
  2503.   WinQueryWindowRect ( hwnd, &Rectangle ) ;
  2504.  
  2505.   GpiMove ( hPS, (PPOINTL) &Rectangle.xLeft ) ;
  2506.   GpiSetColor ( hPS, Data->Profile.BackColor ) ;
  2507.   GpiBox ( hPS, DRO_FILL, (PPOINTL) &Rectangle.xRight, 0L, 0L ) ;
  2508.  
  2509.  /***************************************************************************
  2510.   * Paint the appropriate border color.                     *
  2511.   ***************************************************************************/
  2512.  
  2513.   PaintBorder ( hwnd, hPS, Data, MustPaint ) ;
  2514.  
  2515.  /***************************************************************************
  2516.   * If analog or minimized . . .                        *
  2517.   ***************************************************************************/
  2518.  
  2519.   if ( Data->Profile.Analog OR ( Data->Profile.Position.fl & SWP_MINIMIZE ) )
  2520.   {
  2521.  
  2522.    /*************************************************************************
  2523.     * Draw hour and minute marks around the dial.                *
  2524.     *************************************************************************/
  2525.  
  2526.     GpiSetColor ( hPS, Data->Profile.TextColor ) ;
  2527.  
  2528.     for ( Angle=0; Angle<60; Angle++ )
  2529.     {
  2530.       Points[0].x = 0 ;
  2531.       Points[0].y = 90 ;
  2532.       RotatePoint ( Points, 1, Angle ) ;
  2533.       ScalePoint ( Points, 1, &Data->wi ) ;
  2534.       TranslatePoint ( Points, 1, &Data->wi ) ;
  2535.       Points[2].x = Points[2].y = Angle % 5 ? 2 : 10 ;
  2536.  
  2537.       ScalePoint ( Points + 2, 1, &Data->wi ) ;
  2538.  
  2539.       Points[0].x -= Points[2].x / 2 ;
  2540.       Points[0].y -= Points[2].y / 2 ;
  2541.  
  2542.       Points[1].x = Points[0].x + Points[2].x ;
  2543.       Points[1].y = Points[0].y + Points[2].y ;
  2544.  
  2545.       GpiMove ( hPS, Points ) ;
  2546.  
  2547.       if ( ( Angle % 5 == 0 ) OR
  2548.     ( ( Data->wi.cxClient ) > 50 ) AND ( Data->wi.cyClient > 50 ) )
  2549.       {
  2550.     GpiBox ( hPS, DRO_OUTLINEFILL, Points+1, Points[2].x, Points[2].y ) ;
  2551.       }
  2552.     }
  2553.   }
  2554. }
  2555.  
  2556. /****************************************************************************
  2557.  *                                        *
  2558.  *                  Paint Border                    *
  2559.  *                                        *
  2560.  ****************************************************************************/
  2561.  
  2562. static void PaintBorder ( HWND hwnd, HPS hPS, PDATA Data, BOOL MustPaint )
  2563. {
  2564.  /***************************************************************************
  2565.   * Local Declarations                                *
  2566.   ***************************************************************************/
  2567.  
  2568.   USHORT Alert ;
  2569.   USHORT Level ;
  2570.   POINTL Point ;
  2571.   RECTL  Rectangle ;
  2572.  
  2573.  /***************************************************************************
  2574.   * Determine level of the current alert type.                    *
  2575.   ***************************************************************************/
  2576.  
  2577.   if ( Data->Profile.AlertType == ALERT_TASKCOUNT )
  2578.   {
  2579.     Level = WinQuerySwitchList ( Data->Anchor, NULL, 0 ) ;
  2580.   }
  2581.   else
  2582.   {
  2583.     Data->MaxCount = (ULONG) max ( Data->MaxCount, Data->IdleCount ) ;
  2584.     Level = (USHORT) ( ( ( Data->MaxCount - Data->IdleCount ) * 100 ) / Data->MaxCount ) ;
  2585.   }
  2586.  
  2587.  /***************************************************************************
  2588.   * Determine alert class.                            *
  2589.   ***************************************************************************/
  2590.  
  2591.   if ( Level < Data->Profile.AlertLevels[Data->Profile.AlertType][0] )
  2592.     Alert = 0 ;
  2593.   else if ( Level < Data->Profile.AlertLevels[Data->Profile.AlertType][1] )
  2594.     Alert = 1 ;
  2595.   else
  2596.     Alert = 2 ;
  2597.  
  2598.  /***************************************************************************
  2599.   * If border must be painted, or the alert level has changed, paint it.    *
  2600.   ***************************************************************************/
  2601.  
  2602.   if ( MustPaint OR ( Alert != Data->Alert ) )
  2603.   {
  2604.     WinQueryWindowRect ( hwnd, &Rectangle ) ;
  2605.  
  2606.     GpiSetColor ( hPS, Alert > 1 ? RGB_RED : ( Alert > 0 ? RGB_YELLOW : RGB_GREEN ) ) ;
  2607.  
  2608.     Point.x = 0 ;
  2609.     Point.y = 0 ;
  2610.     GpiMove ( hPS, &Point ) ;
  2611.  
  2612.     Point.x = Rectangle.xRight - 1 ;
  2613.     Point.y = Rectangle.yTop - 1 ;
  2614.     GpiBox ( hPS, DRO_OUTLINE, &Point, 0L, 0L ) ;
  2615.  
  2616.     Point.x = 1 ;
  2617.     Point.y = 1 ;
  2618.     GpiMove ( hPS, &Point ) ;
  2619.  
  2620.     Point.x = Rectangle.xRight - 2 ;
  2621.     Point.y = Rectangle.yTop - 2 ;
  2622.     GpiBox ( hPS, DRO_OUTLINE, &Point, 0L, 0L ) ;
  2623.  
  2624.     Data->Alert = Alert ;
  2625.   }
  2626. }
  2627.  
  2628. /****************************************************************************
  2629.  *                                        *
  2630.  *                Paint Digital Time                    *
  2631.  *                                        *
  2632.  ****************************************************************************/
  2633.  
  2634. static void PaintDigitalTime ( HWND hwnd, HPS hPS, PDATA Data, PDATETIME DateTime )
  2635. {
  2636.  /***************************************************************************
  2637.   * Local Declarations                                *
  2638.   ***************************************************************************/
  2639.  
  2640.   USHORT Hour ;
  2641.   RECTL Rectangle ;
  2642.   CHAR Text [20] ;
  2643.  
  2644.  /***************************************************************************
  2645.   * Determine the window rectangle, less the border.                *
  2646.   ***************************************************************************/
  2647.  
  2648.   WinQueryWindowRect ( hwnd, &Rectangle ) ;
  2649.  
  2650.   Rectangle.xLeft += 2 ;
  2651.   Rectangle.xRight -= 2 ;
  2652.   Rectangle.yBottom += 2 ;
  2653.   Rectangle.yTop -= 2 ;
  2654.  
  2655.  /***************************************************************************
  2656.   * Draw the new time within the rectangle.                    *
  2657.   ***************************************************************************/
  2658.  
  2659.   if ( ( DateTime->minutes == 0 ) AND ( DateTime->hours % 12 == 0 ) )
  2660.   {
  2661.     if ( DateTime->hours == 0 )
  2662.     {
  2663.       ResourceString Midnight ( Data->Library, IDS_MIDNIGHT ) ;
  2664.       strcpy ( Text, PCHAR(Midnight.Ptr()) ) ;
  2665.     }
  2666.     else if ( DateTime->hours == 12 )
  2667.     {
  2668.       ResourceString Noon ( Data->Library, IDS_NOON ) ;
  2669.       strcpy ( Text, PCHAR(Noon.Ptr()) ) ;
  2670.     }
  2671.   }
  2672.   else
  2673.   {
  2674.     if ( Data->Profile.Hour24 )
  2675.     {
  2676.       sprintf ( Text, "%u%s%02u",
  2677.     DateTime->hours, Data->CountryInfo.szTimeSeparator, DateTime->minutes ) ;
  2678.     }
  2679.     else
  2680.     {
  2681.       ResourceString Am ( Data->Library, IDS_AM ) ;
  2682.       ResourceString Pm ( Data->Library, IDS_PM ) ;
  2683.  
  2684.       Hour = DateTime->hours % 12 ;
  2685.  
  2686.       if ( Hour == 0 )
  2687.     Hour = 12 ;
  2688.  
  2689.       sprintf ( Text, "%u%s%02u%s",
  2690.     Hour, Data->CountryInfo.szTimeSeparator, DateTime->minutes,
  2691.     (DateTime->hours>=12) ? Pm.Ptr() : Am.Ptr() ) ;
  2692.     }
  2693.   }
  2694.  
  2695.   WinDrawText ( hPS, strlen(Text), PSZ(Text), &Rectangle,
  2696.     Data->Profile.TextColor, Data->Profile.BackColor,
  2697.     DT_CENTER | DT_VCENTER | DT_ERASERECT ) ;
  2698. }
  2699.  
  2700. /****************************************************************************
  2701.  *                                        *
  2702.  *            Hide Window Controls                    *
  2703.  *                                        *
  2704.  ****************************************************************************/
  2705.  
  2706. static void HideControls
  2707. (
  2708.   BOOL fHide,
  2709.   HWND FrameWindow,
  2710.   HWND hwndSysMenu,
  2711.   HWND hwndTitleBar,
  2712.   HWND hwndMinMax
  2713. )
  2714. {
  2715.  /***************************************************************************
  2716.   * Local Declarations                                *
  2717.   ***************************************************************************/
  2718.  
  2719.   SWP OldPosition ;
  2720.   SWP Position ;
  2721.   RECTL Rectangle ;
  2722.  
  2723.  /***************************************************************************
  2724.   * Get original window position and state.                    *
  2725.   ***************************************************************************/
  2726.  
  2727.   WinQueryWindowPos ( FrameWindow, &OldPosition ) ;
  2728.  
  2729.  /***************************************************************************
  2730.   * Restore and hide the window.                        *
  2731.   ***************************************************************************/
  2732.  
  2733.   WinSetWindowPos ( FrameWindow, NULL, 0, 0, 0, 0, SWP_RESTORE | SWP_HIDE ) ;
  2734.  
  2735.  /***************************************************************************
  2736.   * Determine client window and location.                    *
  2737.   ***************************************************************************/
  2738.  
  2739.   WinQueryWindowPos ( FrameWindow, &Position ) ;
  2740.  
  2741.   Rectangle.xLeft   = Position.x ;
  2742.   Rectangle.xRight  = Position.x + Position.cx ;
  2743.   Rectangle.yBottom = Position.y ;
  2744.   Rectangle.yTop    = Position.y + Position.cy ;
  2745.  
  2746.   WinCalcFrameRect ( FrameWindow, &Rectangle, TRUE ) ;
  2747.  
  2748.  /***************************************************************************
  2749.   * Hide or reveal the controls windows by changing their parentage.        *
  2750.   ***************************************************************************/
  2751.  
  2752.   if ( fHide )
  2753.   {
  2754.     WinSetParent ( hwndSysMenu,  HWND_OBJECT, FALSE ) ;
  2755.     WinSetParent ( hwndTitleBar, HWND_OBJECT, FALSE ) ;
  2756.     WinSetParent ( hwndMinMax,     HWND_OBJECT, FALSE ) ;
  2757.   }
  2758.   else
  2759.   {
  2760.     WinSetParent ( hwndSysMenu,  FrameWindow, TRUE ) ;
  2761.     WinSetParent ( hwndTitleBar, FrameWindow, TRUE ) ;
  2762.     WinSetParent ( hwndMinMax,     FrameWindow, TRUE ) ;
  2763.   }
  2764.  
  2765.  /***************************************************************************
  2766.   * Tell the frame that things have changed.  Let it update the window.     *
  2767.   ***************************************************************************/
  2768.  
  2769.   WinSendMsg ( FrameWindow, WM_UPDATEFRAME,
  2770.     MPFROMSHORT ( FCF_TITLEBAR | FCF_SYSMENU | FCF_MINBUTTON ), 0L ) ;
  2771.  
  2772.  /***************************************************************************
  2773.   * Reposition the frame around the client window, which is left be.        *
  2774.   ***************************************************************************/
  2775.  
  2776.   WinCalcFrameRect ( FrameWindow, &Rectangle, FALSE ) ;
  2777.  
  2778.   WinSetWindowPos ( FrameWindow, NULL,
  2779.     (SHORT) Rectangle.xLeft,  (SHORT) Rectangle.yBottom,
  2780.     (SHORT) (Rectangle.xRight-Rectangle.xLeft),
  2781.     (SHORT) (Rectangle.yTop-Rectangle.yBottom),
  2782.     SWP_SIZE | SWP_MOVE ) ;
  2783.  
  2784.  /***************************************************************************
  2785.   * If window was maximized, put it back that way.                *
  2786.   ***************************************************************************/
  2787.  
  2788.   if ( OldPosition.fl & SWP_MAXIMIZE )
  2789.   {
  2790.     WinSetWindowPos ( FrameWindow, NULL,
  2791.       (SHORT) Rectangle.xLeft,    (SHORT) Rectangle.yBottom,
  2792.       (SHORT) (Rectangle.xRight-Rectangle.xLeft),
  2793.       (SHORT) (Rectangle.yTop-Rectangle.yBottom),
  2794.       SWP_SIZE | SWP_MOVE |
  2795.       ( OldPosition.fl & SWP_MAXIMIZE ) ) ;
  2796.   }
  2797.  
  2798.  /***************************************************************************
  2799.   * Reveal the window to the curious world.                    *
  2800.   ***************************************************************************/
  2801.  
  2802.   WinShowWindow ( FrameWindow, TRUE ) ;
  2803. }
  2804.  
  2805. /****************************************************************************
  2806.  *                                        *
  2807.  *    Monitor Loop Thread                            *
  2808.  *                                        *
  2809.  ****************************************************************************/
  2810.  
  2811. static VOID MonitorLoopThread ( PMONITOR_PARMS Parms )
  2812. {
  2813.  /***************************************************************************
  2814.   * Set this thread's priority as high as it can go.                        *
  2815.   ***************************************************************************/
  2816.  
  2817.   DosSetPrty ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0 ) ;
  2818.  
  2819.  /***************************************************************************
  2820.   * Start up the high resolution timer, if it is available.            *
  2821.   ***************************************************************************/
  2822.  
  2823.   BOOL HiResTimer = OpenTimer ( ) ;
  2824.  
  2825.  /***************************************************************************
  2826.   * Loop forever . . .                                *
  2827.   ***************************************************************************/
  2828.  
  2829.   while ( 1 )
  2830.   {
  2831.  
  2832.    /*************************************************************************
  2833.     * Reset the last time and count seen.                    *
  2834.     *************************************************************************/
  2835.  
  2836.     ULONG LastMilliseconds ;
  2837.     TIMESTAMP Time [2] ;
  2838.  
  2839.     if ( HiResTimer )
  2840.       GetTime ( &Time[0] ) ;
  2841.     else
  2842.       DosQuerySysInfo ( QSV_MS_COUNT, QSV_MS_COUNT, &LastMilliseconds, sizeof(LastMilliseconds) ) ;
  2843.  
  2844.     ULONG LastCounter = *Parms->Counter ;
  2845.  
  2846.    /*************************************************************************
  2847.     * Sleep for a bit.                                *
  2848.     *************************************************************************/
  2849.  
  2850.     DosSleep ( 1000 ) ;
  2851.  
  2852.    /*************************************************************************
  2853.     * Find out how much time and counts went by.                *
  2854.     *************************************************************************/
  2855.  
  2856.     ULONG CurrentCounter = *Parms->Counter ;
  2857.  
  2858.     ULONG DeltaMilliseconds ;
  2859.  
  2860.     if ( HiResTimer )
  2861.     {
  2862.       GetTime ( &Time[1] ) ;
  2863.  
  2864.       ULONG Nanoseconds ;
  2865.       DeltaMilliseconds = ElapsedTime ( &Time[0], &Time[1], &Nanoseconds ) ;
  2866.  
  2867.       if ( Nanoseconds >= 500000L )
  2868.     DeltaMilliseconds ++ ;
  2869.     }
  2870.     else
  2871.     {
  2872.       ULONG Milliseconds ;
  2873.       DosQuerySysInfo ( QSV_MS_COUNT, QSV_MS_COUNT, &Milliseconds, sizeof(Milliseconds) ) ;
  2874.       DeltaMilliseconds = Milliseconds - LastMilliseconds ;
  2875.     }
  2876.  
  2877.    /*************************************************************************
  2878.     * Find out how much idle time was counted.    Adjust it to persecond.     *
  2879.     *************************************************************************/
  2880.  
  2881.     ULONG Counter = (ULONG) ( ( (double)(CurrentCounter-LastCounter) * 1000L ) / (double)DeltaMilliseconds ) ;
  2882.  
  2883.    /*************************************************************************
  2884.     * Tell the owner window to refresh its statistics.                *
  2885.     *************************************************************************/
  2886.  
  2887.     WinPostMsg ( Parms->Owner, WM_REFRESH, MPFROMLONG(Counter), 0L ) ;
  2888.   }
  2889. }
  2890.  
  2891. /****************************************************************************
  2892.  *                                        *
  2893.  *             Calibrate the Load Meter                *
  2894.  *                                        *
  2895.  ****************************************************************************/
  2896.  
  2897. static ULONG CalibrateLoadMeter ( void )
  2898. {
  2899.  /***************************************************************************
  2900.   * Set result to zero as a default.                        *
  2901.   ***************************************************************************/
  2902.  
  2903.   double AdjustedMaxLoad = 0.0 ;
  2904.  
  2905.  /***************************************************************************
  2906.   * If HRTIMER.SYS has been installed . . .                    *
  2907.   ***************************************************************************/
  2908.  
  2909.   if ( OpenTimer ( ) )
  2910.   {
  2911.    /*************************************************************************
  2912.     * Increase this thread's priority to the maximum.                       *
  2913.     *************************************************************************/
  2914.  
  2915.     DosSetPrty ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0 ) ;
  2916.  
  2917.    /*************************************************************************
  2918.     * Create the calibration thread and set its priority next highest.        *
  2919.     *************************************************************************/
  2920.  
  2921.     TID tidCalibrate ;
  2922.     ULONG MaxLoad ;
  2923.     DosCreateThread ( &tidCalibrate, CounterThread, (ULONG)&MaxLoad, 0, 4096 ) ;
  2924.     DosSetPrty ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM-1, tidCalibrate ) ;
  2925.     DosSuspendThread ( tidCalibrate ) ;
  2926.  
  2927.    /*************************************************************************
  2928.     * Reset the calibration count, get the time, and let the counter go.    *
  2929.     *************************************************************************/
  2930.  
  2931.     MaxLoad = 0 ;
  2932.     TIMESTAMP Time[2] ;
  2933.     GetTime ( &Time[0] ) ;
  2934.     DosResumeThread ( tidCalibrate ) ;
  2935.  
  2936.    /*************************************************************************
  2937.     * Sleep for one second.                            *
  2938.     *************************************************************************/
  2939.  
  2940.     DosSleep ( 1000 ) ;
  2941.  
  2942.    /*************************************************************************
  2943.     * Suspend the calibration counter and get the time.             *
  2944.     *************************************************************************/
  2945.  
  2946.     DosSuspendThread ( tidCalibrate ) ;
  2947.     GetTime ( &Time[1] ) ;
  2948.  
  2949.    /*************************************************************************
  2950.     * Return priorities to normal.                        *
  2951.     *************************************************************************/
  2952.  
  2953.     DosSetPrty ( PRTYS_THREAD, PRTYC_REGULAR, 0, 0 ) ;
  2954.  
  2955.    /*************************************************************************
  2956.     * Get the elapsed time and adjust the calibration count.            *
  2957.     *************************************************************************/
  2958.  
  2959.     ULONG Milliseconds ;
  2960.     ULONG Nanoseconds ;
  2961.     Milliseconds = ElapsedTime ( &Time[0], &Time[1], &Nanoseconds ) ;
  2962.  
  2963.     AdjustedMaxLoad = (double)MaxLoad * 1.0E9 ;
  2964.     AdjustedMaxLoad /= (double)Milliseconds*1.0E6L + (double)Nanoseconds ;
  2965.  
  2966.    /*************************************************************************
  2967.     * Close down the connection to HRTIMER.SYS.                 *
  2968.     *************************************************************************/
  2969.  
  2970.     CloseTimer ( ) ;
  2971.   }
  2972.  
  2973.  /***************************************************************************
  2974.   * Return the adjusted calibration count.  If HRTIMER was not there, it    *
  2975.   *   will be zero.                                *
  2976.   ***************************************************************************/
  2977.  
  2978.   return ( (ULONG)AdjustedMaxLoad ) ;
  2979. }
  2980.  
  2981. /****************************************************************************
  2982.  *                                        *
  2983.  *              General Purpose Counter Thread                *
  2984.  *                                        *
  2985.  ****************************************************************************/
  2986.  
  2987. static VOID CounterThread ( PULONG Counter )
  2988. {
  2989.   while ( 1 )
  2990.   {
  2991.     (*Counter) ++ ;
  2992.   }
  2993. }
  2994.  
  2995. /****************************************************************************
  2996.  *                                        *
  2997.  *    Open the Profile                            *
  2998.  *                                        *
  2999.  ****************************************************************************/
  3000.  
  3001. static HINI OpenProfile ( PSZ Name, HAB Anchor, HMODULE Library, HWND HelpInstance )
  3002. {
  3003.  /***************************************************************************
  3004.   * Query the system INI for the profile file's path.                       *
  3005.   ***************************************************************************/
  3006.  
  3007.   PSZ ProfilePath = NULL ;
  3008.   ULONG Size ;
  3009.  
  3010.   if ( PrfQueryProfileSize ( HINI_USERPROFILE, PSZ(PROGRAM_NAME), PSZ("INIPATH"), &Size ) )
  3011.   {
  3012.     // The info exists.  Fetch it.
  3013.     ProfilePath = PSZ ( AllocateMemory ( Size ) ) ;
  3014.     PrfQueryProfileData ( HINI_USERPROFILE, PSZ(PROGRAM_NAME), PSZ("INIPATH"),
  3015.       ProfilePath, &Size ) ;
  3016.  
  3017.     // Build the profile file name.
  3018.     BYTE FullPath [_MAX_PATH] ;
  3019.     strcpy ( PCHAR(FullPath), PCHAR(ProfilePath) ) ;
  3020.     strcat ( PCHAR(FullPath), "\\" ) ;
  3021.     strcat ( PCHAR(FullPath), PCHAR(Name) ) ;
  3022.     strcat ( PCHAR(FullPath), ".INI" ) ;
  3023.  
  3024.     // Clean the name up and expand it to a full path.
  3025.     BYTE Path [256] ;
  3026.     DosQueryPathInfo ( FullPath, FIL_QUERYFULLNAME, Path, sizeof(Path) ) ;
  3027.  
  3028.     // Does the file exist?  If not, discard the name.
  3029.     FILESTATUS3 Status ;
  3030.     if ( DosQueryPathInfo ( Path, FIL_STANDARD, &Status, sizeof(Status) ) )
  3031.     {
  3032.       FreeMemory ( ProfilePath ) ;
  3033.       ProfilePath = NULL ;
  3034.     }
  3035.   }
  3036.  
  3037.  /***************************************************************************
  3038.   * If the profile file couldn't be found, ask the user for a path.         *
  3039.   ***************************************************************************/
  3040.  
  3041.   if ( ProfilePath == NULL )
  3042.   {
  3043.     // Set the default path.
  3044.     BYTE Path [256] ;
  3045.     DosQueryPathInfo ( PSZ("."), FIL_QUERYFULLNAME, Path, sizeof(Path) ) ;
  3046.  
  3047.     // Call up the entry dialog.
  3048.     PROFILE_PARMS Parms ;
  3049.     Parms.id = IDD_PROFILE_PATH ;
  3050.     Parms.hwndHelp = HelpInstance ;
  3051.     Parms.Path = Path ;
  3052.     Parms.PathSize = sizeof(Path) ;
  3053.     if ( WinDlgBox ( HWND_DESKTOP, HWND_DESKTOP, ProfileProcessor,
  3054.       Library, IDD_PROFILE_PATH, &Parms ) )
  3055.     {
  3056.       // If OK, save the approved path in the system profile.
  3057.       ProfilePath = PSZ ( AllocateMemory ( strlen(PCHAR(Path)) + 1 ) ) ;
  3058.       strcpy ( PCHAR(ProfilePath), PCHAR(Path) ) ;
  3059.  
  3060.       PrfWriteProfileData ( HINI_USERPROFILE, PSZ(PROGRAM_NAME), PSZ("INIPATH"),
  3061.     ProfilePath, strlen(PCHAR(ProfilePath))+1 ) ;
  3062.     }
  3063.     else
  3064.     {
  3065.       // If not, return an error.
  3066.       return ( NULL ) ;
  3067.     }
  3068.   }
  3069.  
  3070.  /***************************************************************************
  3071.   * Build the full profile file name.                        *
  3072.   ***************************************************************************/
  3073.  
  3074.   BYTE ProfileName [_MAX_PATH] ;
  3075.   strcpy ( PCHAR(ProfileName), PCHAR(ProfilePath) ) ;
  3076.   strcat ( PCHAR(ProfileName), "\\" PROGRAM_NAME ".INI" ) ;
  3077.  
  3078.  /***************************************************************************
  3079.   * Release the memory previously allocated to store the path.            *
  3080.   ***************************************************************************/
  3081.  
  3082.   if ( ProfilePath )
  3083.   {
  3084.     FreeMemory ( ProfilePath ) ;
  3085.   }
  3086.  
  3087.  /***************************************************************************
  3088.   * Open/Create the profile file and return the resultant handle.        *
  3089.   ***************************************************************************/
  3090.  
  3091.   return ( PrfOpenProfile ( Anchor, ProfileName ) ) ;
  3092. }
  3093.