home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: WPS_PM / WPS_PM.zip / DESKEXT.ZIP / BOUNCE.C < prev    next >
C/C++ Source or Header  |  1990-05-12  |  8KB  |  284 lines

  1. /***************************************************************************\
  2. * BOUNCE.C - An example Desktop Screen Saver extension by John Ridges
  3. \***************************************************************************/
  4.  
  5. #define MAXBITMAPS 25   /* How many happy faces can be on the screen */
  6.  
  7. #define INCL_DOSMEMMGR
  8. #define INCL_DOSPROCESS
  9. #define INCL_DOSSEMAPHORES
  10. #define INCL_GPIBITMAPS
  11. #define INCL_WINBUTTONS
  12. #define INCL_WINDIALOGS
  13. #define INCL_WINENTRYFIELDS
  14. #define INCL_WININPUT
  15. #define INCL_WINMESSAGEMGR
  16. #define INCL_WINSHELLDATA
  17. #define INCL_WINTIMER
  18. #define INCL_WINWINDOWMGR
  19.  
  20. #include <os2.h>
  21. #include <stdlib.h>   /* Needed because SRAND and RAND are called */
  22.  
  23. typedef struct {
  24.     HAB deskpichab;
  25.     HWND screenhwnd;
  26.     RECTL screenrectl;
  27.     ULONG volatile closesemaphore;
  28.     HMODULE thismodule;
  29. } SAVERBLOCK;
  30.  
  31. char far * far pascal _loadds saverstatus(SAVERBLOCK far *, BOOL far *);
  32. MRESULT CALLBACK saverdialog(HWND, USHORT, MPARAM, MPARAM);
  33. void far pascal _loadds saverthread(void);
  34.  
  35. static SAVERBLOCK far *saverinfo;
  36.  
  37. /*
  38.    This is the record that describes the position and velocity of
  39.    a happy face
  40. */
  41. typedef struct {
  42.     FIXED xvelocity,yvelocity;
  43.     FIXED xposition,yposition;
  44. } BITMAPREC;
  45.  
  46. /*
  47.     This is the record that contains the options of the screen saver.
  48.     These options are kept in the OS2.INI profile file.
  49. */
  50. typedef struct {
  51.     BOOL enabled;   /* The screen saver enabled status */
  52.     int numbitmaps;   /* The number of happy faces on the screen */
  53. } PROFILEREC;
  54.  
  55. static char name[] = "Bounce";  /* The name of this screen saver */
  56. static BOOL gotprofile = FALSE;  /* Indicates that we've read the profile */
  57. static PROFILEREC profile = { TRUE, 4 };   /* Default values */
  58.  
  59. char far * far pascal _loadds saverstatus(initptr,enabledptr)
  60. SAVERBLOCK far *initptr;
  61. BOOL far *enabledptr;
  62. {
  63.     SHORT i;
  64.     
  65.     /* Save the SAVERBLOCK address locally */
  66.     saverinfo = initptr;
  67.  
  68.     /* Read the profile (but only once!) */
  69.     if (!gotprofile) {
  70.         i = sizeof(PROFILEREC);
  71.         WinQueryProfileData(saverinfo->deskpichab,"Deskpic",name,&profile,&i);
  72.         gotprofile = TRUE;
  73.     }
  74.     
  75.     /* Return the enabled status */
  76.     *enabledptr = profile.enabled;
  77.     
  78.     /* Return the screen saver name */
  79.     return name;
  80. }
  81.  
  82. MRESULT CALLBACK saverdialog(hwnd,message,mp1,mp2)
  83. HWND hwnd;
  84. USHORT message;
  85. MPARAM mp1,mp2;
  86. {
  87.     SHORT i;
  88.     RECTL ourrect,desktoprect;
  89.  
  90.     switch(message) {
  91.     case WM_INITDLG:
  92.  
  93.         /* Center the dialog inside of the desktop */
  94.         WinQueryWindowRect(hwnd,&ourrect);
  95.         WinQueryWindowRect(HWND_DESKTOP,&desktoprect);
  96.         WinSetWindowPos(hwnd,NULL,
  97.             (int)(desktoprect.xRight-ourrect.xRight+ourrect.xLeft)/2,
  98.             (int)(desktoprect.yTop-ourrect.yTop+ourrect.yBottom)/2,
  99.             0,0,SWP_MOVE);
  100.  
  101.         /* Check the enabled button if enabled */
  102.         if (profile.enabled)
  103.             WinSendDlgItemMsg(hwnd,3,BM_SETCHECK,MPFROMSHORT(1),0);
  104.  
  105.         /* Set the Quantity field */
  106.         WinSetDlgItemShort(hwnd,4,profile.numbitmaps,TRUE);
  107.  
  108.         /* Bring up the dialog */
  109.         WinShowWindow(hwnd,TRUE);
  110.         return FALSE;
  111.     case WM_COMMAND:
  112.  
  113.         /* If OK is pushed */
  114.         if (SHORT1FROMMP(mp1) == 1) {
  115.  
  116.             /* Get the value of the Quantity field */
  117.             WinQueryDlgItemShort(hwnd,4,&i,TRUE);
  118.  
  119.             /* Check to see if the Quantity is in bounds */
  120.             if (i < 1 || i > MAXBITMAPS) {
  121.  
  122.                 /* Bring up an error message box */
  123.                 WinMessageBox(HWND_DESKTOP,hwnd,"The number of happy faces must "
  124.                     "be between 1 and 25",NULL,0,MB_OK|MB_ICONHAND);
  125.  
  126.                 /* Hilight the Quantity field */
  127.                 WinSendDlgItemMsg(hwnd,4,EM_SETSEL,MPFROM2SHORT(0,
  128.                     WinQueryDlgItemTextLength(hwnd,4)),0);
  129.  
  130.                 /* Give the Quantity field the focus */
  131.                 WinSetFocus(HWND_DESKTOP,WinWindowFromID(hwnd,4));
  132.  
  133.                 /* Don't exit the dialog */
  134.                 return FALSE;
  135.             }
  136.             /* Save the number of happy faces */
  137.             profile.numbitmaps = i;
  138.  
  139.             /* Get the enabled status */
  140.             profile.enabled =
  141.                 SHORT1FROMMR(WinSendDlgItemMsg(hwnd,3,BM_QUERYCHECK,0,0));
  142.  
  143.             /* Write the profile data */
  144.             WinWriteProfileData(saverinfo->deskpichab,"Deskpic",name,&profile,
  145.                 sizeof(PROFILEREC));
  146.         }
  147.     }
  148.     return WinDefDlgProc(hwnd,message,mp1,mp2);
  149. }
  150.  
  151. void far pascal _loadds saverthread()
  152. {
  153.     HAB hab;
  154.     HPS hps;
  155.     int i;
  156.     FIXED tempx,tempy;
  157.     ULONG sqrt;
  158.     POINTL aptl[4];
  159.     SEL bitmapsel;
  160.     BITMAPREC far *bitmaps;
  161.     HBITMAP hbmp;
  162.  
  163.     /* Get an HAB for this thread (since we make PM calls) */
  164.     hab = WinInitialize(0);
  165.  
  166.     /* Get an HPS of the screen */
  167.     hps = WinGetPS(saverinfo->screenhwnd);
  168.  
  169.     /* Paint the screen black */
  170.     WinFillRect(hps,&saverinfo->screenrectl,CLR_BLACK);
  171.  
  172.     /* Get memory for the array of BITMAPRECs */
  173.     DosAllocSeg(sizeof(BITMAPREC)*profile.numbitmaps,&bitmapsel,SEG_NONSHARED);
  174.     bitmaps = MAKEP(bitmapsel,0);
  175.  
  176.     /* Flag all the happy faces as 'position unknown' */
  177.     for (i = 0; i < profile.numbitmaps; i++) bitmaps[i].xposition = -1L;
  178.  
  179.     /* Get the handle to the happy face and its dimensions */
  180.     hbmp = GpiLoadBitmap(hps,saverinfo->thismodule,1,0L,0L);
  181.     aptl[2].x = aptl[2].y = 0;
  182.     aptl[3].x = aptl[3].y = 34;
  183.  
  184.     /* Randomize RAND using the time */
  185.     srand((unsigned int)WinGetCurrentTime(hab));
  186.  
  187.     /* Loop until DESKPIC tells us to stop */
  188.     while (!saverinfo->closesemaphore)
  189.  
  190.         /* Process for each happy face */
  191.         for (i = 0; i < profile.numbitmaps; i++) {
  192.  
  193.         /* If the happy face's position is unknown, initialize it */
  194.         if (bitmaps[i].xposition < 0) {
  195.  
  196.             /* Pick a random x velocity between -1 and 1 (fixed) */
  197.             tempx = (long)rand()<<1;
  198.             bitmaps[i].xvelocity = rand()&1 ? tempx : -tempx;
  199.  
  200.             /*
  201.                 Make the total velocity 1 by computing:
  202.                 yvelocity = sqrt(1 - xvelocity * xvelocity)
  203.             */
  204.             tempy = MAKEFIXED(0,65535)-((ULONG)tempx*(ULONG)tempx>>16);
  205.  
  206.             /* Cheesy sqrt routine to avoid linking in floating point */
  207.             sqrt = 0;
  208.             tempx = 1L<<15;
  209.             do {
  210.                 sqrt ^= tempx;
  211.                 if (sqrt*sqrt>>16 > (ULONG)tempy) sqrt ^= tempx;
  212.                 tempx >>= 1;
  213.             } while (tempx);
  214.  
  215.             /* Randomly set y velocity sign */
  216.             bitmaps[i].yvelocity = rand()&1 ? sqrt : -sqrt;
  217.  
  218.             /* Randomly choose the x and y position of the happy face */
  219.             tempx = MAKEFIXED(saverinfo->screenrectl.xLeft,0)+(rand()*
  220.                 (saverinfo->screenrectl.xRight-saverinfo->screenrectl.xLeft-32)<<1);
  221.             tempy = MAKEFIXED(saverinfo->screenrectl.yBottom,0)+(rand()*
  222.                 (saverinfo->screenrectl.yTop-saverinfo->screenrectl.yBottom-32)<<1);
  223.         }
  224.         else {
  225.             /* Find the new position of the happy face */
  226.             tempx = bitmaps[i].xposition+bitmaps[i].xvelocity;
  227.             tempy = bitmaps[i].yposition+bitmaps[i].yvelocity;
  228.  
  229.             /* See if the happy face has hit an edge of the screen */
  230.             if (FIXEDINT(tempx) < (int)saverinfo->screenrectl.xLeft) {
  231.  
  232.                 /* Bounced off the left edge */
  233.                 tempx = (saverinfo->screenrectl.xLeft<<17)-tempx;
  234.                 bitmaps[i].xvelocity = -bitmaps[i].xvelocity;
  235.             }
  236.             else if (FIXEDINT(tempx) >= (int)saverinfo->screenrectl.xRight-32) {
  237.  
  238.                 /* Bounced off the right edge */
  239.                 tempx = (saverinfo->screenrectl.xRight-32<<17)-tempx;
  240.                 bitmaps[i].xvelocity = -bitmaps[i].xvelocity;
  241.             }
  242.             if (FIXEDINT(tempy) < (int)saverinfo->screenrectl.yBottom) {
  243.  
  244.                 /* Bounced off the bottom edge */
  245.                 tempy = (saverinfo->screenrectl.yBottom<<17)-tempy;
  246.                 bitmaps[i].yvelocity = -bitmaps[i].yvelocity;
  247.             }
  248.             else if (FIXEDINT(tempy) >= (int)saverinfo->screenrectl.yTop-32) {
  249.  
  250.                 /* Bounced off the top edge */
  251.                 tempy = (saverinfo->screenrectl.yTop-32<<17)-tempy;
  252.                 bitmaps[i].yvelocity = -bitmaps[i].yvelocity;
  253.             }
  254.         }
  255.         /* Draw the happy face in the new position */
  256.         aptl[0].x = FIXEDINT(tempx)-1;
  257.         aptl[0].y = FIXEDINT(tempy)-1;
  258.         aptl[1].x = FIXEDINT(tempx)+32;
  259.         aptl[1].y = FIXEDINT(tempy)+32;
  260.         GpiWCBitBlt(hps,hbmp,4L,aptl,ROP_SRCCOPY,BBO_IGNORE);
  261.  
  262.         /* Save the position of the happy face */
  263.         bitmaps[i].xposition = tempx;
  264.         bitmaps[i].yposition = tempy;
  265.     }
  266.     /* Release the happy face bitmap */
  267.     GpiDeleteBitmap(hbmp);
  268.  
  269.     /* Release the memory for the array of BITMAPRECs */
  270.     DosFreeSeg(bitmapsel);
  271.  
  272.     /* Release the HPS of the screen */
  273.     WinReleasePS(hps);
  274.  
  275.     /* Get rid of the HAB */
  276.     WinTerminate(hab);
  277.  
  278.     /* Make sure the stack doesn't vanish before we're completely gone */
  279.     DosEnterCritSec();
  280.  
  281.     /* Tell DESKPIC that we're gone */
  282.     DosSemClear((HSEM)&saverinfo->closesemaphore);
  283. }
  284.