home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / os2 / life2 / life.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-14  |  44.6 KB  |  1,148 lines

  1. //-------------------------------------------------------------------------
  2. // The Game of Life - A Screen Saver
  3. //
  4. // Written by Larry Salomon, Jr. with the intent of disseminating yet more
  5. // PM source for the purpose of teaching those who are still struggling
  6. // and need a bit of guidance.
  7. //
  8. // The link step of the build process requires the library CMN32.LIB,
  9. // which can be found in the common.zip package also on cdrom.com
  10. // (in the /pub/os2/all/program directory, I believe).  For more inform-
  11. // ation on the common.zip package, see the Programming Reference (.INF
  12. // format) contained in that ZIP file.
  13. //
  14. // Any questions, comments, or concerns can be sent via email to me.  My
  15. // address is os2man@panix.com
  16. //-------------------------------------------------------------------------
  17. #define INCL_DOSMISC
  18. #define INCL_GPIBITMAPS
  19. #define INCL_GPILOGCOLORTABLE
  20. #define INCL_GPIPRIMITIVES
  21. #define INCL_WINBUTTONS
  22. #define INCL_WINDIALOGS
  23. #define INCL_WINENTRYFIELDS
  24. #define INCL_WINHELP
  25. #define INCL_WININPUT
  26. #define INCL_WINPALETTE
  27. #define INCL_WINPOINTERS
  28. #define INCL_WINSHELLDATA
  29. #define INCL_WINSTDSLIDER
  30. #define INCL_WINSYS
  31. #define INCL_WINTIMER
  32. #define INCL_WINWINDOWMGR
  33. #include <os2.h>
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <time.h>
  38. #define INCL_CMNLIB
  39. #include <common.h>
  40. #include "rc.h"
  41. #include "help.h"
  42. #include "life.h"
  43.  
  44. //-------------------------------------------------------------------------
  45. // Beginning of 16-bit declarations
  46. //-------------------------------------------------------------------------
  47. //-------------------------------------------------------------------------
  48. // We need access to the 16-bit API DosGetInfoSeg() so that we can determine
  49. // the id of the current session.  Though the documentation for
  50. // DosQuerySysInfo() says that you can specify the QSV_FOREGROUND_FS_SESSION
  51. // parameter to get this, that constant is not defined in the 2.0 toolkit
  52. // and hard-coding its value - 24 - returns an error.
  53. //
  54. // Why do we need to know the session id?  See the notes below.  :)
  55. //-------------------------------------------------------------------------
  56. typedef struct _GINFOSEG {
  57.     ULONG   time;               /* time in seconds                           */
  58.     ULONG   msecs;              /* milliseconds                              */
  59.     UCHAR   hour;               /* hours                                     */
  60.     UCHAR   minutes;            /* minutes                                   */
  61.     UCHAR   seconds;            /* seconds                                   */
  62.     UCHAR   hundredths;         /* hundredths                                */
  63.     USHORT  timezone;           /* minutes from UTC                          */
  64.     USHORT  cusecTimerInterval; /* timer interval (units = 0.0001 seconds)   */
  65.     UCHAR   day;                /* day                                       */
  66.     UCHAR   month;              /* month                                     */
  67.     USHORT  year;               /* year                                      */
  68.     UCHAR   weekday;            /* day of week                               */
  69.     UCHAR   uchMajorVersion;    /* major version number                      */
  70.     UCHAR   uchMinorVersion;    /* minor version number                      */
  71.     UCHAR   chRevisionLetter;   /* revision letter                           */
  72.     UCHAR   sgCurrent;          /* current foreground session                */
  73.     UCHAR   sgMax;              /* maximum number of sessions                */
  74.     UCHAR   cHugeShift;         /* shift count for huge elements             */
  75.     UCHAR   fProtectModeOnly;   /* protect mode only indicator               */
  76.     USHORT  pidForeground;      /* pid of last process in forground session  */
  77.     UCHAR   fDynamicSched;      /* dynamic variation flag                    */
  78.     UCHAR   csecMaxWait;        /* max wait in seconds                       */
  79.     USHORT  cmsecMinSlice;      /* minimum timeslice (milliseconds)          */
  80.     USHORT  cmsecMaxSlice;      /* maximum timeslice (milliseconds)          */
  81.     USHORT  bootdrive;          /* drive from which the system was booted    */
  82.     UCHAR   amecRAS[32];        /* system trace major code flag bits         */
  83.     UCHAR   csgWindowableVioMax;/* maximum number of VIO windowable sessions */
  84.     UCHAR   csgPMMax;           /* maximum number of pres. services sessions */
  85. } GINFOSEG;
  86. typedef GINFOSEG FAR *PGINFOSEG;
  87.  
  88. USHORT APIENTRY16 DOS16GETINFOSEG(PSEL _Seg16 pselGlobal,PSEL _Seg16 pselLocal);
  89. //-------------------------------------------------------------------------
  90. // End of 16-bit declarations
  91. //-------------------------------------------------------------------------
  92.  
  93. //-------------------------------------------------------------------------
  94. // CLS_SAVER - class of the screen saver window.  The Settings window is a
  95. //             dialog, so it has no class.  :)
  96. // PRF_APPNAME - application name for the Prf*() functions.
  97. // PRF_SETTINGS - key name for the settings info.
  98. // COORD(pcdData,usX,usY) - converts a 2-d coordinate in a 1-d array index.
  99. // TID_LIFECLICKS - timer id for the screen saver.
  100. // TID_SECONDS - timer id for the inactivity timer.
  101. // TM_TIMEOUT - timeout value for TID_LIFECLICKS.
  102. // MAX_COLORS - number of colors in aulColors[].
  103. // MAX_MARGIN - defines the boundaries of the centers of the patterns that
  104. //              are generated.  Used to avoid boundary checks when gen'ing
  105. //              the universe.
  106. // MAX_TICKS - modulus factor when calculating the number of ticks for the
  107. //             current universe.
  108. // BASE_TICKS - base number of ticks for every universe.  A random number
  109. //              from 0-(MAX_TICKS-1) is added to this to get the lifetime of
  110. //              each universe.
  111. //-------------------------------------------------------------------------
  112. #define CLS_SAVER                "LifeSaver"
  113.  
  114. #define PRF_APPNAME              "Life Saver"
  115. #define PRF_SETTINGS             "Settings"
  116.  
  117. #define COORD(pcdData,usX,usY) (((usY)*pcdData->szlBoard.cx)+(usX))
  118.  
  119. #define TID_LIFECLICKS           1
  120. #define TID_SECONDS              2
  121.  
  122. #define TM_TIMEOUT               750
  123.  
  124. #define MAX_COLORS               16
  125. #define MAX_MARGIN               3
  126.  
  127. #define MAX_TICKS                25
  128. #define BASE_TICKS               25
  129.  
  130. //-------------------------------------------------------------------------
  131. // The colors to be used.  The age of a square (in ticks) is mod'd with
  132. // the maximum number of colors to get an index into the palette, which
  133. // is based on this array.
  134. //-------------------------------------------------------------------------
  135. ULONG aulColors[MAX_COLORS]={
  136.    0x00FFFF00L,
  137.    0x00CCFF33L,
  138.    0x0099FF66L,
  139.    0x0066FF99L,
  140.    0x0033FFCCL,
  141.    0x0000FFFFL,
  142.    0x0033CCFFL,
  143.    0x006699FFL,
  144.    0x009966FFL,
  145.    0x00CC33FFL,
  146.    0x00FF00FFL,
  147.    0x00FF33CCL,
  148.    0x00FF6699L,
  149.    0x00FF9966L,
  150.    0x00FFCC33L,
  151.    0x00000000L
  152. };
  153.  
  154. //-------------------------------------------------------------------------
  155. // Settings information
  156. //-------------------------------------------------------------------------
  157. typedef struct _SETTINGS {
  158.    USHORT usSzStruct;
  159.    ULONG ulSaveTime;
  160.    BOOL bDisable;
  161. } SETTINGS, *PSETTINGS;
  162.  
  163. //-------------------------------------------------------------------------
  164. // Instance data for the saver window
  165. //-------------------------------------------------------------------------
  166. typedef struct _SAVERDATA {
  167.    USHORT usSzStruct;
  168.    HAB habAnchor;
  169.    HWND hwndOwner;
  170.  
  171.    SETTINGS sSettings;
  172.    ULONG ulSeconds;
  173.    HWND hwndFocus;
  174.    PHOOKDATA phdHook;
  175.  
  176.    HPS hpsPaint;
  177.    HPAL hpPalette;
  178.    HBITMAP hbmSpace;
  179.    SIZEL szlSpace;
  180.    SIZEL szlBoard;
  181.    PSHORT psBoard;
  182.    PSHORT psNew;
  183.    ULONG ulMaxTicks;
  184.    ULONG ulRoamer;
  185.    ULONG ulNumTicks;
  186. } SAVERDATA, *PSAVERDATA;
  187.  
  188. //-------------------------------------------------------------------------
  189. // Instance data for the client window
  190. //-------------------------------------------------------------------------
  191. typedef struct _CLIENTDATA {
  192.    USHORT usSzStruct;
  193.    HAB habAnchor;
  194.    HWND hwndSaver;
  195.    HWND hwndHelp;
  196.    PSAVERDATA psdData;
  197. } CLIENTDATA, *PCLIENTDATA;
  198.  
  199. #include "proto.h"
  200.  
  201. VOID querySpaceRect(HWND hwndWnd,USHORT usX,USHORT usY,PRECTL prclSpace)
  202. //-------------------------------------------------------------------------
  203. // This function returns the rectangle for the coordinates (usX,usY).
  204. //
  205. // Input:  hwndWnd - specifies the saver window
  206. //         usX, usY - specifies the coordinates
  207. // Output:  prclSpace - points to the rectangle for the space
  208. //-------------------------------------------------------------------------
  209. {
  210.    PSAVERDATA psdData;
  211.    RECTL rclWnd;
  212.  
  213.    psdData=WinQueryWindowPtr(hwndWnd,0);
  214.    WinQueryWindowRect(hwndWnd,&rclWnd);
  215.    prclSpace->xLeft=rclWnd.xLeft+usX*psdData->szlSpace.cx;
  216.    prclSpace->yBottom=rclWnd.yTop-(usY+1)*psdData->szlSpace.cy;
  217.    prclSpace->xRight=prclSpace->xLeft+psdData->szlSpace.cx;
  218.    prclSpace->yTop=prclSpace->yBottom+psdData->szlSpace.cy;
  219.    return;                       // Avoid the "implicit return" warning.  Ugh!
  220. }
  221.  
  222. USHORT queryNumNeighbors(PSAVERDATA psdData,USHORT usX,USHORT usY)
  223. //-------------------------------------------------------------------------
  224. // This function returns the number of neighbors of the space (usX,usY)
  225. //
  226. // Input:  psdData - points to the saver window instance data.  We pass this
  227. //                   instead of the pointer to the board buffer because we
  228. //                   also need the size of the board.  A better solution
  229. //                   would be to typedef a BOARD datatype which includes
  230. //                   the size...Nah...Too easy.  :)
  231. //         usX, usY - coordinates of the space to check
  232. // Returns:  number of neighbors
  233. //
  234. // In the notes below, 'X' is the space to be checked and the neighbors
  235. // are number thusly:
  236. //
  237. // 1 2 3
  238. // 4 X 6
  239. // 7 8 9
  240. //-------------------------------------------------------------------------
  241. {
  242.    USHORT usNum;
  243.  
  244.    usNum=0;
  245.  
  246.    if (usX>0) {
  247.       //-------------------------------------------------------------------
  248.       // Check neighbors 1, 4, and 7
  249.       //-------------------------------------------------------------------
  250.       if (psdData->psBoard[COORD(psdData,usX-1,usY)]!=-1) {
  251.          usNum++;
  252.       } /* endif */
  253.  
  254.       if ((usY>0) && (psdData->psBoard[COORD(psdData,usX-1,usY-1)]!=-1)) {
  255.          usNum++;
  256.       } /* endif */
  257.  
  258.       if ((usY<psdData->szlBoard.cy-1) &&
  259.           (psdData->psBoard[COORD(psdData,usX-1,usY+1)]!=-1)) {
  260.          usNum++;
  261.       } /* endif */
  262.    } /* endif */
  263.  
  264.    if (usX<psdData->szlBoard.cx-1) {
  265.       //-------------------------------------------------------------------
  266.       // Check neighbors 3, 6, and 9
  267.       //-------------------------------------------------------------------
  268.       if (psdData->psBoard[COORD(psdData,usX+1,usY)]!=-1) {
  269.          usNum++;
  270.       } /* endif */
  271.  
  272.       if ((usY>0) && (psdData->psBoard[COORD(psdData,usX+1,usY-1)]!=-1)) {
  273.          usNum++;
  274.       } /* endif */
  275.  
  276.       if ((usY<psdData->szlBoard.cy-1) &&
  277.           (psdData->psBoard[COORD(psdData,usX+1,usY+1)]!=-1)) {
  278.          usNum++;
  279.       } /* endif */
  280.    } /* endif */
  281.  
  282.    //----------------------------------------------------------------------
  283.    // Check neighbors 2 and 8
  284.    //----------------------------------------------------------------------
  285.    if ((usY>0) && (psdData->psBoard[COORD(psdData,usX,usY-1)]!=-1)) {
  286.       usNum++;
  287.    } /* endif */
  288.  
  289.    if ((usY<psdData->szlBoard.cy-1) &&
  290.        (psdData->psBoard[COORD(psdData,usX,usY+1)]!=-1)) {
  291.       usNum++;
  292.    } /* endif */
  293.  
  294.    return usNum;
  295. }
  296.  
  297. VOID initBoard(PSAVERDATA psdData)
  298. //-------------------------------------------------------------------------
  299. // This function reinitializes the universe.
  300. //
  301. // Input:  psdData - points to the saver window instance data
  302. //-------------------------------------------------------------------------
  303. {
  304.    USHORT usX;
  305.    USHORT usY;
  306.    ULONG ulNumPtrns;
  307.    ULONG ulIndex;
  308.  
  309.    psdData->ulMaxTicks=rand()%MAX_TICKS+BASE_TICKS;
  310.    psdData->ulRoamer=psdData->ulMaxTicks/4;
  311.    psdData->ulNumTicks=0;
  312.  
  313.    for (usX=0; usX<psdData->szlBoard.cx; usX++) {
  314.       for (usY=0; usY<psdData->szlBoard.cy; usY++) {
  315.          psdData->psBoard[COORD(psdData,usX,usY)]=-1;
  316.          psdData->psNew[COORD(psdData,usX,usY)]=-1;
  317.       } /* endfor */
  318.    } /* endfor */
  319.  
  320.    //----------------------------------------------------------------------
  321.    // Generate a random number (1-3) of patterns.  In the patters below,
  322.    // 'x' indicates a filled space, 'X' indicates the filled center of the
  323.    // pattern, and '.' indicates the empty center of the pattern
  324.    //----------------------------------------------------------------------
  325.    ulNumPtrns=rand()%3+1;
  326.  
  327.    for (ulIndex=0; ulIndex<ulNumPtrns; ulIndex++) {
  328.       usX=(USHORT)(rand()%(psdData->szlBoard.cx-MAX_MARGIN*4))+MAX_MARGIN*2;
  329.       usY=(USHORT)(rand()%(psdData->szlBoard.cy-MAX_MARGIN*4))+MAX_MARGIN*2;
  330.  
  331.       switch (rand()%8) {
  332.       case 0:
  333.          //----------------------------------------------------------------
  334.          // Pattern:
  335.          //
  336.          //     x
  337.          //   x X x
  338.          //     x
  339.          //----------------------------------------------------------------
  340.          psdData->psBoard[COORD(psdData,usX,usY)]=0;
  341.          psdData->psBoard[COORD(psdData,usX-1,usY)]=0;
  342.          psdData->psBoard[COORD(psdData,usX+1,usY)]=0;
  343.          psdData->psBoard[COORD(psdData,usX,usY-1)]=0;
  344.          psdData->psBoard[COORD(psdData,usX,usY+1)]=0;
  345.          break;
  346.       case 1:
  347.          //----------------------------------------------------------------
  348.          // Pattern:
  349.          //
  350.          //   x     x
  351.          //   x .   x
  352.          //   x     x
  353.          //----------------------------------------------------------------
  354.          psdData->psBoard[COORD(psdData,usX-1,usY-1)]=0;
  355.          psdData->psBoard[COORD(psdData,usX-1,usY)]=0;
  356.          psdData->psBoard[COORD(psdData,usX-1,usY+1)]=0;
  357.          psdData->psBoard[COORD(psdData,usX+2,usY-1)]=0;
  358.          psdData->psBoard[COORD(psdData,usX+2,usY)]=0;
  359.          psdData->psBoard[COORD(psdData,usX+2,usY+1)]=0;
  360.          break;
  361.       case 2:
  362.          //----------------------------------------------------------------
  363.          // Pattern:
  364.          //
  365.          //     x x
  366.          //       x
  367.          //   x X x
  368.          //   x
  369.          //   x x
  370.          //----------------------------------------------------------------
  371.          psdData->psBoard[COORD(psdData,usX,usY)]=0;
  372.          psdData->psBoard[COORD(psdData,usX-1,usY)]=0;
  373.          psdData->psBoard[COORD(psdData,usX-1,usY+1)]=0;
  374.          psdData->psBoard[COORD(psdData,usX-1,usY+2)]=0;
  375.          psdData->psBoard[COORD(psdData,usX,usY+2)]=0;
  376.          psdData->psBoard[COORD(psdData,usX+1,usY)]=0;
  377.          psdData->psBoard[COORD(psdData,usX+1,usY-1)]=0;
  378.          psdData->psBoard[COORD(psdData,usX+1,usY-2)]=0;
  379.          psdData->psBoard[COORD(psdData,usX,usY-2)]=0;
  380.          break;
  381.       case 3:
  382.          //----------------------------------------------------------------
  383.          // Pattern:
  384.          //
  385.          //   x
  386.          //     x
  387.          // x x . x x
  388.          //     x
  389.          //       x
  390.          //----------------------------------------------------------------
  391.          psdData->psBoard[COORD(psdData,usX-2,usY)]=0;
  392.          psdData->psBoard[COORD(psdData,usX-1,usY)]=0;
  393.          psdData->psBoard[COORD(psdData,usX+1,usY)]=0;
  394.          psdData->psBoard[COORD(psdData,usX+2,usY)]=0;
  395.          psdData->psBoard[COORD(psdData,usX,usY-1)]=0;
  396.          psdData->psBoard[COORD(psdData,usX-1,usY-2)]=0;
  397.          psdData->psBoard[COORD(psdData,usX,usY+1)]=0;
  398.          psdData->psBoard[COORD(psdData,usX+1,usY+2)]=0;
  399.          break;
  400.       case 4:
  401.          //----------------------------------------------------------------
  402.          // Pattern:
  403.          //
  404.          //     x x
  405.          //   x X   x
  406.          //   x     x
  407.          //     x x
  408.          //----------------------------------------------------------------
  409.          psdData->psBoard[COORD(psdData,usX-1,usY)]=0;
  410.          psdData->psBoard[COORD(psdData,usX-1,usY+1)]=0;
  411.          psdData->psBoard[COORD(psdData,usX,usY+2)]=0;
  412.          psdData->psBoard[COORD(psdData,usX+1,usY+2)]=0;
  413.          psdData->psBoard[COORD(psdData,usX+2,usY+1)]=0;
  414.          psdData->psBoard[COORD(psdData,usX+2,usY)]=0;
  415.          psdData->psBoard[COORD(psdData,usX+1,usY-1)]=0;
  416.          psdData->psBoard[COORD(psdData,usX,usY-1)]=0;
  417.  
  418.          psdData->psBoard[COORD(psdData,usX,usY)]=0;
  419.          break;
  420.       case 5:
  421.          //----------------------------------------------------------------
  422.          // Pattern:
  423.          //
  424.          //     x x
  425.          //   x . x x
  426.          //   x     x
  427.          //     x x
  428.          //----------------------------------------------------------------
  429.          psdData->psBoard[COORD(psdData,usX-1,usY)]=0;
  430.          psdData->psBoard[COORD(psdData,usX-1,usY+1)]=0;
  431.          psdData->psBoard[COORD(psdData,usX,usY+2)]=0;
  432.          psdData->psBoard[COORD(psdData,usX+1,usY+2)]=0;
  433.          psdData->psBoard[COORD(psdData,usX+2,usY+1)]=0;
  434.          psdData->psBoard[COORD(psdData,usX+2,usY)]=0;
  435.          psdData->psBoard[COORD(psdData,usX+1,usY-1)]=0;
  436.          psdData->psBoard[COORD(psdData,usX,usY-1)]=0;
  437.  
  438.          psdData->psBoard[COORD(psdData,usX+1,usY)]=0;
  439.          break;
  440.       case 6:
  441.          //----------------------------------------------------------------
  442.          // Pattern:
  443.          //
  444.          //     x x
  445.          //   x .   x
  446.          //   x   x x
  447.          //     x x
  448.          //----------------------------------------------------------------
  449.          psdData->psBoard[COORD(psdData,usX-1,usY)]=0;
  450.          psdData->psBoard[COORD(psdData,usX-1,usY+1)]=0;
  451.          psdData->psBoard[COORD(psdData,usX,usY+2)]=0;
  452.          psdData->psBoard[COORD(psdData,usX+1,usY+2)]=0;
  453.          psdData->psBoard[COORD(psdData,usX+2,usY+1)]=0;
  454.          psdData->psBoard[COORD(psdData,usX+2,usY)]=0;
  455.          psdData->psBoard[COORD(psdData,usX+1,usY-1)]=0;
  456.          psdData->psBoard[COORD(psdData,usX,usY-1)]=0;
  457.  
  458.          psdData->psBoard[COORD(psdData,usX+1,usY+1)]=0;
  459.          break;
  460.       case 7:
  461.          //----------------------------------------------------------------
  462.          // Pattern:
  463.          //
  464.          //     x x
  465.          //   x .   x
  466.          //   x x   x
  467.          //     x x
  468.          //----------------------------------------------------------------
  469.          psdData->psBoard[COORD(psdData,usX-1,usY)]=0;
  470.          psdData->psBoard[COORD(psdData,usX-1,usY+1)]=0;
  471.          psdData->psBoard[COORD(psdData,usX,usY+2)]=0;
  472.          psdData->psBoard[COORD(psdData,usX+1,usY+2)]=0;
  473.          psdData->psBoard[COORD(psdData,usX+2,usY+1)]=0;
  474.          psdData->psBoard[COORD(psdData,usX+2,usY)]=0;
  475.          psdData->psBoard[COORD(psdData,usX+1,usY-1)]=0;
  476.          psdData->psBoard[COORD(psdData,usX,usY-1)]=0;
  477.  
  478.          psdData->psBoard[COORD(psdData,usX,usY+1)]=0;
  479.          break;
  480.       default:
  481.          break;
  482.       } /* endswitch */
  483.    } /* endfor */
  484.  
  485.    return;
  486. }
  487.  
  488. VOID initRoamer(PSAVERDATA psdData)
  489. //-------------------------------------------------------------------------
  490. // This function creates a roamer.
  491. //
  492. // Input:  psdData - points to the saver window instance data
  493. //-------------------------------------------------------------------------
  494. {
  495.    USHORT usDelta;
  496.  
  497.    usDelta=rand()%5;
  498.  
  499.    psdData->psBoard[COORD(psdData,3+usDelta,2)]=0;
  500.    psdData->psBoard[COORD(psdData,4+usDelta,3)]=0;
  501.    psdData->psBoard[COORD(psdData,4+usDelta,4)]=0;
  502.    psdData->psBoard[COORD(psdData,3+usDelta,4)]=0;
  503.    psdData->psBoard[COORD(psdData,2+usDelta,4)]=0;
  504.    return;
  505. }
  506.  
  507. MRESULT EXPENTRY saverWndProc(HWND hwndWnd,
  508.                               ULONG ulMsg,
  509.                               MPARAM mpParm1,
  510.                               MPARAM mpParm2)
  511. //-------------------------------------------------------------------------
  512. // Saver window procedure
  513. //-------------------------------------------------------------------------
  514. {
  515.    PSAVERDATA psdData;
  516.  
  517.    psdData=WinQueryWindowPtr(hwndWnd,0);
  518.  
  519.    switch (ulMsg) {
  520.    case WM_CREATE:
  521.       {
  522.          SIZEL szlPaint;
  523.          BITMAPINFOHEADER bmihInfo;
  524.          ULONG ulChanged;
  525.          ULONG ulSzBuf;
  526.  
  527.          //----------------------------------------------------------------
  528.          // Allocate and initialize the instance data
  529.          //----------------------------------------------------------------
  530.          psdData=calloc(1,sizeof(SAVERDATA));
  531.          if (psdData==NULL) {
  532.             return MRFROMSHORT(TRUE);
  533.          } /* endif */
  534.  
  535.          WinSetWindowPtr(hwndWnd,0,psdData);
  536.  
  537.          psdData->usSzStruct=sizeof(SAVERDATA);
  538.          psdData->habAnchor=WinQueryAnchorBlock(hwndWnd);
  539.          psdData->hwndOwner=WinQueryWindow(hwndWnd,QW_OWNER);
  540.  
  541.          szlPaint.cx=0;
  542.          szlPaint.cy=0;
  543.  
  544.          psdData->hpsPaint=GpiCreatePS(psdData->habAnchor,
  545.                                        WinOpenWindowDC(hwndWnd),
  546.                                        &szlPaint,
  547.                                        PU_PELS|GPIT_NORMAL|GPIA_ASSOC);
  548.          if (psdData->hpsPaint==NULLHANDLE) {
  549.             free(psdData);
  550.             return MRFROMSHORT(TRUE);
  551.          } /* endif */
  552.  
  553.          psdData->hpPalette=GpiCreatePalette(psdData->habAnchor,
  554.                                              0,
  555.                                              LCOLF_CONSECRGB,
  556.                                              MAX_COLORS,
  557.                                              aulColors);
  558.          if (psdData->hpPalette==NULLHANDLE) {
  559.             GpiDestroyPS(psdData->hpsPaint);
  560.             free(psdData);
  561.             return MRFROMSHORT(TRUE);
  562.          } /* endif */
  563.  
  564.          GpiSelectPalette(psdData->hpsPaint,psdData->hpPalette);
  565.          WinRealizePalette(hwndWnd,psdData->hpsPaint,&ulChanged);
  566.  
  567.          psdData->hbmSpace=GpiLoadBitmap(psdData->hpsPaint,
  568.                                          NULLHANDLE,
  569.                                          BMP_SPACE,
  570.                                          0,
  571.                                          0);
  572.  
  573.          GpiQueryBitmapParameters(psdData->hbmSpace,&bmihInfo);
  574.          psdData->szlSpace.cx=bmihInfo.cx;
  575.          psdData->szlSpace.cy=bmihInfo.cy;
  576.  
  577.          psdData->szlBoard.cx=WinQuerySysValue(HWND_DESKTOP,SV_CXSCREEN)/
  578.                                  psdData->szlSpace.cx;
  579.          psdData->szlBoard.cy=WinQuerySysValue(HWND_DESKTOP,SV_CYSCREEN)/
  580.                                  psdData->szlSpace.cy;
  581.  
  582.          psdData->psBoard=calloc(psdData->szlBoard.cx*psdData->szlBoard.cy,
  583.                                  sizeof(SHORT));
  584.          if (psdData->psBoard==NULL) {
  585.             GpiDeleteBitmap(psdData->hbmSpace);
  586.             GpiDeletePalette(psdData->hpPalette);
  587.             GpiDestroyPS(psdData->hpsPaint);
  588.             free(psdData);
  589.             return MRFROMSHORT(TRUE);
  590.          } /* endif */
  591.  
  592.          psdData->psNew=calloc(psdData->szlBoard.cx*psdData->szlBoard.cy,
  593.                                sizeof(SHORT));
  594.          if (psdData->psNew==NULL) {
  595.             GpiDeleteBitmap(psdData->hbmSpace);
  596.             GpiDeletePalette(psdData->hpPalette);
  597.             GpiDestroyPS(psdData->hpsPaint);
  598.             free(psdData->psBoard);
  599.             free(psdData);
  600.             return MRFROMSHORT(TRUE);
  601.          } /* endif */
  602.  
  603.          //----------------------------------------------------------------
  604.          // If we can't find the settings info in the .INI file, initialize
  605.          // them to the defaults
  606.          //----------------------------------------------------------------
  607.          ulSzBuf=sizeof(SETTINGS);
  608.  
  609.          if (!PrfQueryProfileData(HINI_USERPROFILE,
  610.                                   PRF_APPNAME,
  611.                                   PRF_SETTINGS,
  612.                                   &psdData->sSettings,
  613.                                   &ulSzBuf) ||
  614.              (psdData->sSettings.usSzStruct!=sizeof(SETTINGS))) {
  615.             psdData->sSettings.usSzStruct=sizeof(SETTINGS);
  616.             psdData->sSettings.ulSaveTime=60;
  617.             psdData->sSettings.bDisable=FALSE;
  618.          } /* endif */
  619.  
  620.          psdData->ulSeconds=0;
  621.  
  622.          WinStartTimer(psdData->habAnchor,
  623.                        hwndWnd,
  624.                        TID_SECONDS,
  625.                        1000);
  626.  
  627.          //----------------------------------------------------------------
  628.          // Tell the DLL to install itself
  629.          //----------------------------------------------------------------
  630.          LifeInit(hwndWnd,&psdData->phdHook);
  631.       }
  632.       break;
  633.    case WM_DESTROY:
  634.       LifeTerm();
  635.       WinStopTimer(psdData->habAnchor,hwndWnd,TID_SECONDS);
  636.       WinStopTimer(psdData->habAnchor,hwndWnd,TID_LIFECLICKS);
  637.       GpiDeletePalette(psdData->hpPalette);
  638.       GpiDeleteBitmap(psdData->hbmSpace);
  639.       GpiDestroyPS(psdData->hpsPaint);
  640.       free(psdData->psBoard);
  641.       free(psdData->psNew);
  642.       free(psdData);
  643.       break;
  644.    case WM_SIZE:
  645.       psdData->szlBoard.cx=SHORT1FROMMP(mpParm2)/psdData->szlSpace.cx;
  646.       psdData->szlBoard.cy=SHORT2FROMMP(mpParm2)/psdData->szlSpace.cy;
  647.       break;
  648.    case WM_TIMER:
  649.       switch (SHORT1FROMMP(mpParm1)) {
  650.       case TID_LIFECLICKS:
  651.          {
  652.             USHORT usX;
  653.             USHORT usY;
  654.             USHORT usNum;
  655.  
  656.             psdData->ulNumTicks++;
  657.  
  658.             //-------------------------------------------------------------
  659.             // If we've exceeded the lifespan of this universe, create a
  660.             // new one, else if it's time for the roamer to appear, create
  661.             // it.
  662.             //-------------------------------------------------------------
  663.             if (psdData->ulNumTicks==psdData->ulMaxTicks) {
  664.                initBoard(psdData);
  665.             } else
  666.             if (psdData->ulNumTicks==psdData->ulRoamer) {
  667.                initRoamer(psdData);
  668.             } /* endif */
  669.  
  670.             //-------------------------------------------------------------
  671.             // For every space in the universe, check the number of neighbors
  672.             // and update it accordingly.
  673.             //-------------------------------------------------------------
  674.             for (usX=0; usX<psdData->szlBoard.cx; usX++) {
  675.                for (usY=0; usY<psdData->szlBoard.cy; usY++) {
  676.                   usNum=queryNumNeighbors(psdData,usX,usY);
  677.  
  678.                   switch (usNum) {
  679.                   case 0:
  680.                   case 1:
  681.                   case 4:
  682.                   case 5:
  683.                   case 6:
  684.                   case 7:
  685.                   case 8:
  686.                      psdData->psNew[COORD(psdData,usX,usY)]=-1;
  687.                      break;
  688.                   case 2:
  689.                      if (psdData->psBoard[COORD(psdData,usX,usY)]!=-1) {
  690.                         psdData->psNew[COORD(psdData,usX,usY)]=
  691.                            psdData->psBoard[COORD(psdData,usX,usY)]+1;
  692.                      } else {
  693.                         psdData->psNew[COORD(psdData,usX,usY)]=-1;
  694.                      } /* endif */
  695.                      break;
  696.                   case 3:
  697.                      psdData->psNew[COORD(psdData,usX,usY)]=
  698.                         psdData->psBoard[COORD(psdData,usX,usY)]+1;
  699.                      break;
  700.                   default:
  701.                      break;
  702.                   } /* endswitch */
  703.                } /* endfor */
  704.             } /* endfor */
  705.  
  706.             memcpy(psdData->psBoard,
  707.                    psdData->psNew,
  708.                    psdData->szlBoard.cx*psdData->szlBoard.cy*sizeof(SHORT));
  709.  
  710.             WinInvalidateRect(hwndWnd,NULL,FALSE);
  711.             WinUpdateWindow(hwndWnd);
  712.          }
  713.          break;
  714.       case TID_SECONDS:
  715.          {
  716.             USHORT usSelGlobal;
  717.             USHORT usSelLocal;
  718.             PGINFOSEG _Seg16 pgisGlobal;
  719.             ULONG ulCx;
  720.             ULONG ulCy;
  721.  
  722.             //-------------------------------------------------------------
  723.             // Talk about some hocus-pocus to call a 16-bit routine!!!
  724.             // Get the current session id and if it is not PM (id==1),
  725.             // don't monitor the inactivity.
  726.             //-------------------------------------------------------------
  727.             DOS16GETINFOSEG((PSEL _Seg16)&usSelGlobal,(PSEL _Seg16)&usSelLocal);
  728.             pgisGlobal=(PGINFOSEG _Seg16)MAKEULONG(0,usSelGlobal);
  729.  
  730.             if ((pgisGlobal->sgCurrent==1) && (!psdData->sSettings.bDisable)) {
  731.                psdData->ulSeconds++;
  732.             } else {
  733.                psdData->ulSeconds=0;
  734.             } /* endif */
  735.  
  736.             //-------------------------------------------------------------
  737.             // If you've been inactive for too long, check your heart. :)
  738.             // Seriously, if the number of seconds of inactivity has
  739.             // elapsed, start the saver.
  740.             //-------------------------------------------------------------
  741.             if (psdData->ulSeconds>=psdData->sSettings.ulSaveTime) {
  742.                initBoard(psdData);
  743.  
  744.                WinShowPointer(HWND_DESKTOP,FALSE);
  745.  
  746.                ulCx=WinQuerySysValue(HWND_DESKTOP,SV_CXSCREEN);
  747.                ulCy=WinQuerySysValue(HWND_DESKTOP,SV_CYSCREEN);
  748.  
  749.                //----------------------------------------------------------
  750.                // What a kludge!  If we don't set the focus to ourselves,
  751.                // certain applications might paint over us (i.e. the
  752.                // system clock).
  753.                //----------------------------------------------------------
  754.                psdData->hwndFocus=WinQueryFocus(HWND_DESKTOP);
  755.                WinSetFocus(HWND_DESKTOP,psdData->hwndOwner);
  756.  
  757.                WinSetWindowPos(hwndWnd,
  758.                                NULLHANDLE,
  759.                                0,
  760.                                0,
  761.                                ulCx,
  762.                                ulCy,
  763.                                SWP_MOVE|SWP_SIZE|SWP_SHOW);
  764.  
  765.                //----------------------------------------------------------
  766.                // Stop the inactivity timer and start the universe timer
  767.                //----------------------------------------------------------
  768.                WinStopTimer(psdData->habAnchor,
  769.                             hwndWnd,
  770.                             TID_SECONDS);
  771.  
  772.                WinStartTimer(psdData->habAnchor,
  773.                              hwndWnd,
  774.                              TID_LIFECLICKS,
  775.                              TM_TIMEOUT);
  776.  
  777.                //----------------------------------------------------------
  778.                // The usMouseKludge field is used because if you are a
  779.                // hidden window and then you show yourself, if the mouse
  780.                // is over you when you appear you get a pair of WM_MOUSEMOVE
  781.                // messages.  We don't want the saver to appear and then
  782.                // disappear again, so set this to the number of WM_MOUSEMOVEs
  783.                // to ignore so the hook doesn't notify us.
  784.                //----------------------------------------------------------
  785.                psdData->phdHook->usMouseKludge=2;
  786.                psdData->phdHook->bSaving=TRUE;
  787.             } /* endif */
  788.          }
  789.          break;
  790.       default:
  791.          return WinDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  792.       } /* endswitch */
  793.       break;
  794.    case WM_PAINT:
  795.       {
  796.          RECTL rclPaint;
  797.          RECTL rclWnd;
  798.          USHORT usX;
  799.          USHORT usY;
  800.          RECTL rclSpace;
  801.  
  802.          WinBeginPaint(hwndWnd,psdData->hpsPaint,&rclPaint);
  803.  
  804.          //----------------------------------------------------------------
  805.          // Paint the sections of the window that are not covered by a
  806.          // space black (aulColors[MAX_COLORS-1]==0x00000000, RGB).
  807.          //----------------------------------------------------------------
  808.          WinQueryWindowRect(hwndWnd,&rclWnd);
  809.          rclWnd.xLeft=psdData->szlBoard.cx*psdData->szlSpace.cx;
  810.          WinFillRect(psdData->hpsPaint,&rclWnd,MAX_COLORS-1);
  811.  
  812.          WinQueryWindowRect(hwndWnd,&rclWnd);
  813.          rclWnd.yTop-=psdData->szlBoard.cy*psdData->szlSpace.cy;
  814.          WinFillRect(psdData->hpsPaint,&rclWnd,MAX_COLORS-1);
  815.  
  816.          rclPaint.xLeft=rclPaint.xLeft/psdData->szlSpace.cx;
  817.          rclPaint.xRight=rclPaint.xRight/psdData->szlSpace.cx+1;
  818.          rclPaint.yBottom=(rclWnd.yTop-rclPaint.yBottom)/psdData->szlSpace.cy;
  819.          rclPaint.yTop=(rclWnd.yTop-rclPaint.yTop)/psdData->szlSpace.cy+1;
  820.  
  821.          for (usX=0; usX<psdData->szlBoard.cx; usX++) {
  822.             for (usY=0; usY<psdData->szlBoard.cy; usY++) {
  823.                querySpaceRect(hwndWnd,usX,usY,&rclSpace);
  824.  
  825.                if ((psdData->psBoard[COORD(psdData,usX,usY)])==-1) {
  826.                   WinFillRect(psdData->hpsPaint,&rclSpace,MAX_COLORS-1);
  827.                } else {
  828.                   WinDrawBitmap(psdData->hpsPaint,
  829.                                 psdData->hbmSpace,
  830.                                 NULL,
  831.                                 (PPOINTL)&rclSpace.xLeft,
  832.                                 psdData->psBoard[COORD(psdData,usX,usY)]%(MAX_COLORS-1),
  833.                                 MAX_COLORS-1,
  834.                                 DBM_NORMAL);
  835.                } /* endif */
  836.             } /* endfor */
  837.          } /* endfor */
  838.  
  839.          WinEndPaint(psdData->hpsPaint);
  840.       }
  841.       break;
  842.    case LFM_INPUT:
  843.       if (psdData->phdHook->bSaving) {
  844.          //----------------------------------------------------------------
  845.          // If we're in saver mode, stop it.
  846.          //----------------------------------------------------------------
  847.          WinStopTimer(psdData->habAnchor,
  848.                       hwndWnd,
  849.                       TID_LIFECLICKS);
  850.          psdData->phdHook->bSaving=FALSE;
  851.  
  852.          WinSetFocus(HWND_DESKTOP,psdData->hwndFocus);
  853.  
  854.          WinSetWindowPos(hwndWnd,
  855.                          NULLHANDLE,
  856.                          0,
  857.                          0,
  858.                          0,
  859.                          0,
  860.                          SWP_HIDE);
  861.  
  862.          WinShowPointer(HWND_DESKTOP,TRUE);
  863.       } /* endif */
  864.  
  865.       //-------------------------------------------------------------------
  866.       // Reset the inactivity count and restart the timer.
  867.       //-------------------------------------------------------------------
  868.       psdData->ulSeconds=0;
  869.       WinStartTimer(psdData->habAnchor,
  870.                     hwndWnd,
  871.                     TID_SECONDS,
  872.                     1000);
  873.       break;
  874.    default:
  875.       return WinDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  876.    } /* endswitch */
  877.  
  878.    return MRFROMSHORT(FALSE);
  879. }
  880.  
  881. MRESULT EXPENTRY settingsDlgProc(HWND hwndWnd,
  882.                                  ULONG ulMsg,
  883.                                  MPARAM mpParm1,
  884.                                  MPARAM mpParm2)
  885. {
  886.    PCLIENTDATA pcdData;
  887.  
  888.    pcdData=WinQueryWindowPtr(hwndWnd,0);
  889.  
  890.    switch (ulMsg) {
  891.    case WM_INITDLG:
  892.       {
  893.          HELPINIT hiInit;
  894.          CHAR achBuf[256];
  895.  
  896.          srand(time(NULL));
  897.  
  898.          //----------------------------------------------------------------
  899.          // Allocate and initialize the instance data
  900.          //----------------------------------------------------------------
  901.          pcdData=calloc(1,sizeof(CLIENTDATA));
  902.          if (pcdData==NULL) {
  903.             WinAlarm(HWND_DESKTOP,WA_ERROR);
  904.             WinDismissDlg(hwndWnd,FALSE);
  905.             return MRFROMSHORT(FALSE);
  906.          } /* endif */
  907.  
  908.          WinSetWindowPtr(hwndWnd,0,pcdData);
  909.  
  910.          pcdData->usSzStruct=sizeof(CLIENTDATA);
  911.          pcdData->habAnchor=WinQueryAnchorBlock(hwndWnd);
  912.  
  913.          pcdData->hwndSaver=WinCreateWindow(HWND_DESKTOP,
  914.                                             CLS_SAVER,
  915.                                             "",
  916.                                             0,
  917.                                             0,
  918.                                             0,
  919.                                             0,
  920.                                             0,
  921.                                             hwndWnd,
  922.                                             HWND_TOP,
  923.                                             WND_SAVER,
  924.                                             NULL,
  925.                                             NULL);
  926.          if (pcdData->hwndSaver==NULLHANDLE) {
  927.             free(pcdData);
  928.             WinAlarm(HWND_DESKTOP,WA_ERROR);
  929.             WinDismissDlg(hwndWnd,FALSE);
  930.             return MRFROMSHORT(FALSE);
  931.          } /* endif */
  932.  
  933.          pcdData->psdData=WinQueryWindowPtr(pcdData->hwndSaver,0);
  934.  
  935.          //----------------------------------------------------------------
  936.          // Create the help instance
  937.          //----------------------------------------------------------------
  938.          hiInit.cb=sizeof(HELPINIT);
  939.          hiInit.ulReturnCode=0L;
  940.          hiInit.pszTutorialName=NULL;
  941.          hiInit.phtHelpTable=(PHELPTABLE)MAKEULONG(HELP_SETTINGS,0xFFFF);
  942.          hiInit.hmodHelpTableModule=NULLHANDLE;
  943.          hiInit.hmodAccelActionBarModule=NULLHANDLE;
  944.          hiInit.idAccelTable=0;
  945.          hiInit.idActionBar=0;
  946.  
  947.          WinLoadString(pcdData->habAnchor,
  948.                        NULLHANDLE,
  949.                        STR_HELPTITLE,
  950.                        sizeof(achBuf),
  951.                        achBuf);
  952.          hiInit.pszHelpWindowTitle=achBuf;
  953.  
  954.          hiInit.fShowPanelId=CMIC_HIDE_PANEL_ID;
  955.          hiInit.pszHelpLibraryName="LIFE.HLP";
  956.  
  957.          pcdData->hwndHelp=WinCreateHelpInstance(pcdData->habAnchor,&hiInit);
  958.          if (pcdData->hwndHelp!=NULLHANDLE) {
  959.             if (hiInit.ulReturnCode==0) {
  960.                WinAssociateHelpInstance(pcdData->hwndHelp,hwndWnd);
  961.             } else {
  962.                WinDestroyHelpInstance(pcdData->hwndHelp);
  963.                pcdData->hwndHelp=NULLHANDLE;
  964.             } /* endif */
  965.          } /* endif */
  966.  
  967.          if (pcdData->hwndHelp==NULLHANDLE) {
  968.             WinEnableWindow(WinWindowFromID(hwndWnd,DST_PB_HELP),FALSE);
  969.          } /* endif */
  970.  
  971.          WinSendDlgItemMsg(hwndWnd,
  972.                            DST_SL_TIMEOUT,
  973.                            SLM_SETTICKSIZE,
  974.                            MPFROM2SHORT(SMA_SETALLTICKS,5),
  975.                            0);
  976.  
  977.          WinSendMsg(hwndWnd,WM_COMMAND,MPFROMSHORT(DST_PB_UNDO),0);
  978.  
  979.          //----------------------------------------------------------------
  980.          // Since the initial position of any slider is 0, if the current
  981.          // setting also evaluates to position 0, the slider will not
  982.          // change the value and thus we will not get a WM_CONTROL message.
  983.          // So, send the message anyways so that the entryfield will get
  984.          // updated.  Also, since no changes have been made, disable the
  985.          // Undo button.
  986.          //----------------------------------------------------------------
  987.          WinSendMsg(hwndWnd,
  988.                     WM_CONTROL,
  989.                     MPFROM2SHORT(DST_SL_TIMEOUT,SLN_CHANGE),
  990.                     0);
  991.          WinEnableWindow(WinWindowFromID(hwndWnd,DST_PB_UNDO),FALSE);
  992.  
  993.          CmnWinCenterWindow(hwndWnd);
  994.       }
  995.       break;
  996.    case WM_DESTROY:
  997.       WinDestroyWindow(pcdData->hwndSaver);
  998.       WinDestroyHelpInstance(pcdData->hwndHelp);
  999.       free(pcdData);
  1000.       break;
  1001.    case WM_CONTROL:
  1002.       switch (SHORT1FROMMP(mpParm1)) {
  1003.       case DST_CB_DISABLE:
  1004.          switch (SHORT2FROMMP(mpParm1)) {
  1005.          case BN_CLICKED:
  1006.          case BN_DBLCLICKED:
  1007.             WinEnableWindow(WinWindowFromID(hwndWnd,DST_PB_UNDO),TRUE);
  1008.             break;
  1009.          default:
  1010.             return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1011.          } /* endswitch */
  1012.          break;
  1013.       case DST_SL_TIMEOUT:
  1014.          switch (SHORT2FROMMP(mpParm1)) {
  1015.          case SLN_CHANGE:
  1016.          case SLN_SLIDERTRACK:
  1017.             {
  1018.                ULONG ulPos;
  1019.                CHAR achText[32];
  1020.  
  1021.                //----------------------------------------------------------
  1022.                // The user has changed the slider position, so update the
  1023.                // entryfield to reflect the current value
  1024.                //----------------------------------------------------------
  1025.                ulPos=LONGFROMMR(WinSendDlgItemMsg(hwndWnd,
  1026.                                                   DST_SL_TIMEOUT,
  1027.                                                   SLM_QUERYSLIDERINFO,
  1028.                                                   MPFROM2SHORT(SMA_SLIDERARMPOSITION,
  1029.                                                                SMA_INCREMENTVALUE),
  1030.                                                   0));
  1031.                ulPos=ulPos*15+30;
  1032.  
  1033.                sprintf(achText,"%ld:%02ld",ulPos/60,ulPos%60);
  1034.                WinSetDlgItemText(hwndWnd,DST_EF_TIMEOUT,achText);
  1035.  
  1036.                WinEnableWindow(WinWindowFromID(hwndWnd,DST_PB_UNDO),TRUE);
  1037.             }
  1038.             break;
  1039.          default:
  1040.             return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1041.          } /* endswitch */
  1042.          break;
  1043.       default:
  1044.          return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1045.       } /* endswitch */
  1046.       break;
  1047.    case WM_COMMAND:
  1048.       switch (SHORT1FROMMP(mpParm1)) {
  1049.       case DST_PB_SET:
  1050.       case DID_OK:
  1051.       case DST_PB_APPLY:
  1052.          {
  1053.             ULONG ulPos;
  1054.  
  1055.             //-------------------------------------------------------------
  1056.             // Query the values and update the saver instance data.  If
  1057.             // "Set" was specified, write to the .INI file.
  1058.             //-------------------------------------------------------------
  1059.             ulPos=LONGFROMMR(WinSendDlgItemMsg(hwndWnd,
  1060.                                                DST_SL_TIMEOUT,
  1061.                                                SLM_QUERYSLIDERINFO,
  1062.                                                MPFROM2SHORT(SMA_SLIDERARMPOSITION,
  1063.                                                             SMA_INCREMENTVALUE),
  1064.                                                0));
  1065.             ulPos=ulPos*15+30;
  1066.  
  1067.             pcdData->psdData->sSettings.ulSaveTime=ulPos;
  1068.             pcdData->psdData->ulSeconds=0;
  1069.  
  1070.             pcdData->psdData->sSettings.bDisable=
  1071.                SHORT1FROMMR(WinSendDlgItemMsg(hwndWnd,
  1072.                                               DST_CB_DISABLE,
  1073.                                               BM_QUERYCHECK,
  1074.                                               0,
  1075.                                               0));
  1076.  
  1077.             if (SHORT1FROMMP(mpParm1)!=DST_PB_APPLY) {
  1078.                PrfWriteProfileData(HINI_USERPROFILE,
  1079.                                    PRF_APPNAME,
  1080.                                    PRF_SETTINGS,
  1081.                                    &pcdData->psdData->sSettings,
  1082.                                    (ULONG)pcdData->psdData->usSzStruct);
  1083.             } /* endif */
  1084.  
  1085.             WinEnableWindow(WinWindowFromID(hwndWnd,DST_PB_UNDO),FALSE);
  1086.          }
  1087.          break;
  1088.       case DST_PB_UNDO:
  1089.          //----------------------------------------------------------------
  1090.          // Revert back to the last "Set" or "Apply"
  1091.          //----------------------------------------------------------------
  1092.          WinSendDlgItemMsg(hwndWnd,
  1093.                            DST_SL_TIMEOUT,
  1094.                            SLM_SETSLIDERINFO,
  1095.                            MPFROM2SHORT(SMA_SLIDERARMPOSITION,
  1096.                                            SMA_INCREMENTVALUE),
  1097.                            MPFROMLONG((pcdData->psdData->sSettings.ulSaveTime-
  1098.                                         30)/15));
  1099.          WinSendDlgItemMsg(hwndWnd,
  1100.                            DST_CB_DISABLE,
  1101.                            BM_SETCHECK,
  1102.                            MPFROMSHORT(pcdData->psdData->sSettings.bDisable),
  1103.                            0);
  1104.          WinEnableWindow(WinWindowFromID(hwndWnd,DST_PB_UNDO),FALSE);
  1105.          break;
  1106.       case DST_PB_HELP:
  1107.          WinSendMsg(pcdData->hwndHelp,HM_EXT_HELP,0,0);
  1108.          break;
  1109.       default:
  1110.          break;
  1111.       } /* endswitch */
  1112.       break;
  1113.    default:
  1114.       return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1115.    } /* endswitch */
  1116.  
  1117.    return MRFROMSHORT(FALSE);
  1118. }
  1119.  
  1120. INT main(VOID)
  1121. {
  1122.    HAB habAnchor;
  1123.    HMQ hmqQueue;
  1124.  
  1125.    habAnchor=WinInitialize(0);
  1126.    hmqQueue=WinCreateMsgQueue(habAnchor,0);
  1127.  
  1128.    //----------------------------------------------------------------------
  1129.    // Register the classes of the various types of windows we use
  1130.    //----------------------------------------------------------------------
  1131.    WinRegisterClass(habAnchor,
  1132.                     CLS_SAVER,
  1133.                     saverWndProc,
  1134.                     CS_SIZEREDRAW,
  1135.                     sizeof(PVOID));
  1136.  
  1137.    WinDlgBox(HWND_DESKTOP,
  1138.              HWND_DESKTOP,
  1139.              settingsDlgProc,
  1140.              NULLHANDLE,
  1141.              DLG_SETTINGS,
  1142.              NULL);
  1143.  
  1144.    WinDestroyMsgQueue(hmqQueue);
  1145.    WinTerminate(habAnchor);
  1146.    return 0;
  1147. }
  1148.