/***************************************************************************\ * BOUNCE.C - An example Desktop Screen Saver extension by John Ridges * Converted to a 32-Bit Screen Blanker module by Peter Wansch \***************************************************************************/ #define MAXBITMAPS 25 /* How many happy faces can be on the screen */ #define INCL_DOSMEMMGR #define INCL_DOSPROCESS #define INCL_GPIBITMAPS #define INCL_WINBUTTONS #define INCL_WINDIALOGS #define INCL_WINENTRYFIELDS #define INCL_WININPUT #define INCL_WINMESSAGEMGR #define INCL_WINTIMER #define INCL_WINWINDOWMGR #define INCL_WINSHELLDATA #include typedef struct { HAB habBlanker; HWND hwndScreen; RECTL rclScreen; BOOL fClose; HMODULE hmodBlanker; } BLANKERBLOCK; typedef BLANKERBLOCK *PBLANKERBLOCK; int rand(); void srand(unsigned int seed); PCHAR pchStatus(PBLANKERBLOCK, PBOOL); MRESULT EXPENTRY dpBlanker(HWND, ULONG, MPARAM, MPARAM); VOID vdBlankerThread(VOID); static PBLANKERBLOCK pBlankerBlock; /* This is the record that describes the position and velocity of a happy face */ typedef struct { FIXED xvelocity,yvelocity; FIXED xposition,yposition; } BITMAPREC; /* This is the record that contains the options of the screen saver. These options are kept in the OS2.INI profile file. */ typedef struct { BOOL enabled; /* The screen saver enabled status */ int numbitmaps; /* The number of happy faces on the screen */ } PROFILEREC; static char name[] = "Bounce"; /* The name of this screen saver */ static BOOL gotprofile = FALSE; /* Indicates that we've read the profile */ static PROFILEREC profile = {TRUE, 4}; /* Default values */ static unsigned int __rand = 1; int rand() { __rand = __rand * 69069 + 5; return ((__rand >> 16) & 0x7fff); } void srand(unsigned int seed) { __rand = seed; } PCHAR pchStatus(PBLANKERBLOCK initptr, PBOOL enabledptr) { ULONG i; /* Save the SAVERBLOCK address locally */ pBlankerBlock = initptr; /* Read the profile (but only once!) */ if (!gotprofile) { i = sizeof(PROFILEREC); PrfQueryProfileData(HINI_PROFILE,"Blanker",name,&profile,&i); gotprofile = TRUE; } /* Return the enabled status */ *enabledptr = profile.enabled; /* Return the screen saver name */ return name; } MRESULT EXPENTRY dpBlanker(HWND hwnd, ULONG message, MPARAM mp1, MPARAM mp2) { SHORT i; switch(message) { case WM_INITDLG: /* Check the enabled button if enabled */ if (profile.enabled) WinSendDlgItemMsg(hwnd,3,BM_SETCHECK,MPFROMSHORT(1),0); /* Set the Quantity field */ WinSetDlgItemShort(hwnd,4,profile.numbitmaps,TRUE); /* Bring up the dialog */ WinShowWindow(hwnd,TRUE); return FALSE; case WM_COMMAND: /* If OK is pushed */ if (SHORT1FROMMP(mp1) == 1) { /* Get the value of the Quantity field */ WinQueryDlgItemShort(hwnd,4,&i,TRUE); /* Check to see if the Quantity is in bounds */ if (i < 1 || i > MAXBITMAPS) { /* Bring up an error message box */ WinMessageBox(HWND_DESKTOP,hwnd,"The number of happy faces must " "be between 1 and 25",NULL,0,MB_OK|MB_ICONHAND); /* Hilight the Quantity field */ WinSendDlgItemMsg(hwnd,4,EM_SETSEL,MPFROM2SHORT(0, WinQueryDlgItemTextLength(hwnd,4)),0); /* Give the Quantity field the focus */ WinSetFocus(HWND_DESKTOP,WinWindowFromID(hwnd,4)); /* Don't exit the dialog */ return FALSE; } /* Save the number of happy faces */ profile.numbitmaps = i; /* Get the enabled status */ profile.enabled = SHORT1FROMMR(WinSendDlgItemMsg(hwnd,3,BM_QUERYCHECK,0,0)); /* Write the profile data */ PrfWriteProfileData(HINI_PROFILE,"Blanker",name,&profile, sizeof(PROFILEREC)); } } return WinDefDlgProc(hwnd,message,mp1,mp2); } VOID vdBlankerThread(VOID) { HAB hab; HPS hps; int i; FIXED tempx,tempy; ULONG sqrt; POINTL aptl[4]; BITMAPREC *bitmaps; HBITMAP hbmp; /* Get an HAB for this thread (since we make PM calls) */ hab = WinInitialize(0); /* Get an HPS of the screen */ hps = WinGetPS(pBlankerBlock->hwndScreen); /* Paint the screen black */ WinFillRect(hps,&pBlankerBlock->rclScreen,CLR_BLACK); /* Get memory for the array of BITMAPRECs */ bitmaps = NULL; DosAllocMem((PPVOID)&bitmaps, sizeof(BITMAPREC)*profile.numbitmaps, PAG_READ | PAG_WRITE | PAG_COMMIT); /* Flag all the happy faces as 'position unknown' */ for (i = 0; i < profile.numbitmaps; i++) bitmaps[i].xposition = -1L; /* Get the handle to the happy face and its dimensions */ hbmp = GpiLoadBitmap(hps,pBlankerBlock->hmodBlanker,1,0L,0L); aptl[2].x = aptl[2].y = 0; aptl[3].x = aptl[3].y = 34; /* Randomize RAND using the time */ srand((unsigned int)WinGetCurrentTime(hab)); /* Loop until Screen Blanker tells us to stop */ while (!pBlankerBlock->fClose) /* Process for each happy face */ for (i = 0; i < profile.numbitmaps; i++) { /* If the happy face's position is unknown, initialize it */ if (bitmaps[i].xposition < 0) { /* Pick a random x velocity between -1 and 1 (fixed) */ tempx = (long)rand()<<1; bitmaps[i].xvelocity = rand()&1 ? tempx : -tempx; /* Make the total velocity 1 by computing: yvelocity = sqrt(1 - xvelocity * xvelocity) */ tempy = MAKEFIXED(0,65535)-((ULONG)tempx*(ULONG)tempx>>16); /* Cheesy sqrt routine to avoid linking in floating point */ sqrt = 0; tempx = 1L<<15; do { sqrt ^= tempx; if (sqrt*sqrt>>16 > (ULONG)tempy) sqrt ^= tempx; tempx >>= 1; } while (tempx); /* Randomly set y velocity sign */ bitmaps[i].yvelocity = rand()&1 ? sqrt : -sqrt; /* Randomly choose the x and y position of the happy face */ tempx = MAKEFIXED(pBlankerBlock->rclScreen.xLeft,0)+(rand()* (pBlankerBlock->rclScreen.xRight-pBlankerBlock->rclScreen.xLeft-32)<<1); tempy = MAKEFIXED(pBlankerBlock->rclScreen.yBottom,0)+(rand()* (pBlankerBlock->rclScreen.yTop-pBlankerBlock->rclScreen.yBottom-32)<<1); } else { /* Find the new position of the happy face */ tempx = bitmaps[i].xposition+bitmaps[i].xvelocity; tempy = bitmaps[i].yposition+bitmaps[i].yvelocity; /* See if the happy face has hit an edge of the screen */ if (FIXEDINT(tempx) < (int)pBlankerBlock->rclScreen.xLeft) { /* Bounced off the left edge */ tempx = (pBlankerBlock->rclScreen.xLeft<<17)-tempx; bitmaps[i].xvelocity = -bitmaps[i].xvelocity; } else if (FIXEDINT(tempx) >= (int)pBlankerBlock->rclScreen.xRight-32) { /* Bounced off the right edge */ tempx = (pBlankerBlock->rclScreen.xRight-32<<17)-tempx; bitmaps[i].xvelocity = -bitmaps[i].xvelocity; } if (FIXEDINT(tempy) < (int)pBlankerBlock->rclScreen.yBottom) { /* Bounced off the bottom edge */ tempy = (pBlankerBlock->rclScreen.yBottom<<17)-tempy; bitmaps[i].yvelocity = -bitmaps[i].yvelocity; } else if (FIXEDINT(tempy) >= (int)pBlankerBlock->rclScreen.yTop-32) { /* Bounced off the top edge */ tempy = (pBlankerBlock->rclScreen.yTop-32<<17)-tempy; bitmaps[i].yvelocity = -bitmaps[i].yvelocity; } } /* Draw the happy face in the new position */ aptl[0].x = FIXEDINT(tempx)-1; aptl[0].y = FIXEDINT(tempy)-1; aptl[1].x = FIXEDINT(tempx)+32; aptl[1].y = FIXEDINT(tempy)+32; GpiWCBitBlt(hps,hbmp,4L,aptl,ROP_SRCCOPY,BBO_IGNORE); /* Save the position of the happy face */ bitmaps[i].xposition = tempx; bitmaps[i].yposition = tempy; } /* Release the happy face bitmap */ GpiDeleteBitmap(hbmp); /* Release the memory for the array of BITMAPRECs */ DosFreeMem(bitmaps); /* Release the HPS of the screen */ WinReleasePS(hps); /* Get rid of the HAB */ WinTerminate(hab); /* Make sure the stack doesn't vanish before we're completely gone */ DosEnterCritSec(); /* Tell Screen Blanker that we're gone */ pBlankerBlock->fClose = FALSE; }