//Sample code file: var/ndk/webBuildengine/tmp/viewable_samples/c5607871-120e-404c-9042-2603fb37af10/SCNSAVER/CPP/GWS.CPP

//Warning: This code has been marked up for HTML

/***************************************************************************
$name: MyApp.C
$version: 1.0 
$date_modified: 121498 
$description: GroupWise Screen Saver
$owner: GroupWise SDK Team Lead
Copyright (c) 1998 Novell, Inc. All Rights Reserved.

THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK) THAT CONTAINS THIS WORK.
PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
CUSTOMERS WITH RESPECT TO THIS CODE.
****************************************************************************/

#include <windows.h>
#include <stdlib.h>
#include <tchar.h>
#include <stdio.h>
#include <time.h>
#include <mmsystem.h>
#include <scrnsave.h>
#include "bouncer.h"
#include "ctrace.h"
#include "resource.h"
#include "gwgw.h"


/***********************************************************************
**      defines
*/
#define ID_TIMER      200


/***********************************************************************
**      globals
*/
/* Externals defined in SCRNSAVE.LIB. Required for all screen savers. */

extern HANDLE hMainInstance;
extern HWND   hMainWindow;
extern BOOL   fChildPreview;

TCHAR        szName[TITLEBARNAMELEN] = "GroupWise Screen Saver";
TCHAR        szAppName[APPNAMEBUFFERLEN];
TCHAR        szIniFile[MAXFILELEN];
TCHAR        szScreenSaver[22];
TCHAR        szHelpFile[MAXFILELEN];
TCHAR        szNoHelpMemory[BUFFLEN];
UINT         MyHelpMessage;


/***********************************************************************
**   static globals
*/
static const int   s_iRandomMax = 4;   // can't move more than this pixels at one time

static const int   s_iAbsDelta = 1;   // each move must be at least one pixel


static const DWORD   c_dwStartWait = 1800;   // time before bitmap breaks up

static const DWORD   c_dwDlgDelay = 60000;   // time before closing dialog

static const DWORD   c_dwMessageDelay = 10000;   // time before moving msg wnd

static const DWORD   c_dwFlashDelay = 333;   // time between caption flashes


static const int   HIT_NONE   = 0;
static const int   HIT_LEFT   = 1;
static const int   HIT_RIGHT  = 2;
static const int   HIT_TOP    = 3;
static const int   HIT_BOTTOM = 4;

static const char   c_szMute [] = "Mute";
static const char   c_szSpeed[] = "Speed";
static const char   c_szMessage[] = "Prompt";

static BOOL      s_bIsFull;
static BOOL      s_bMute = TRUE;
static BOOL      s_bMessageUp = FALSE;
static BOOL      s_bTimer = FALSE;

static int      s_iXLimit;
static int      s_iYLimit;
static int      s_iXScreen;
static int      s_iYScreen;
static int      s_iSpeed = 100;
static int      s_iMsgWidth;
static int      s_iMsgHeight;

static UINT      s_wTimer = 0;

static HWND      s_hDlg = NULL;
static HWND      s_hWndMessage = NULL;

static DWORD   s_dwDlgStartTime;

static double   s_dXScale;
static double   s_dYScale;

static CBouncer   s_Bouncer;

static char      s_szDefaultText[500];

extern GWorb   g_gworb;


/***********************************************************************
**      read from the ini file
*/
static void GetIniSettings(void)
{
   char   szText[500];

   s_bMute  = (BOOL) GetPrivateProfileInt (szAppName, c_szMute,
      TRUE, szIniFile);
   s_iSpeed = GetPrivateProfileInt (szAppName, c_szSpeed,
      50, szIniFile);

   LoadString (hMainInstance, IDS_DEFAULTTEXT,
      szText, sizeof (szText));
   GetPrivateProfileString (szAppName, c_szMessage,
      szText, s_szDefaultText, sizeof (s_szDefaultText), szIniFile);
}


/***********************************************************************
**      write a number to the ini file
*/
static void WriteProfileInt (LPSTR szSection, LPSTR szKey, int i)
{
    char achBuf[40];

    /* Write out as unsigned because GetPrivateProfileInt() can't
       cope with signed values! */

    wsprintf(achBuf, "%u", i);
    WritePrivateProfileString (szSection, szKey, achBuf, szIniFile);
}


/***********************************************************************
**      read all the ini file settings
*/
static void GetIniEntries (void)
{
      // Load Common Strings from stringtable...

   LoadString (hMainInstance, idsAppName, szAppName, 40); 
   LoadString (hMainInstance, idsIniFile, szIniFile, MAXFILELEN);
   LoadString (hMainInstance, idsScreenSaver, szScreenSaver, 22);
   LoadString (hMainInstance, idsHelpFile, szHelpFile, MAXFILELEN);
   LoadString (hMainInstance, idsNoHelpMemory, szNoHelpMemory, BUFFLEN);
}


/***********************************************************************
**
*/
static void SetSpeed (HWND hWnd, int nSpeed)
{
   KillTimer (hWnd, ID_TIMER);
   s_wTimer = SetTimer (hWnd, ID_TIMER, 1 + (500 - (nSpeed * 5)), NULL);
   ASSERT (s_wTimer);
}


/***********************************************************************
**      initialize
*/
static void Seed (HWND hWnd)
{
   RECT   rc;
   HDC      hdc;
   BITMAP   bmp;

      // randomize the random number sequence

   srand ((int) (short) time (NULL));

      // screen size

   s_iXScreen = GetSystemMetrics (SM_CXSCREEN);
   s_iYScreen = GetSystemMetrics (SM_CYSCREEN);
   GetWindowRect (hWnd, &rc);
   s_iXLimit = rc.right - rc.left;
   s_iYLimit = rc.bottom - rc.top;

      // is this a sample window or full screen?

   s_bIsFull = FALSE;
   if (GetParent (hWnd) == NULL)
      s_bIsFull = TRUE;         // full screen mode (not sample)

   if (s_bIsFull)
   {
      s_dXScale = 1.0;
      s_dYScale = 1.0;
   }
   else
   {
      s_dXScale = ((double) s_iXLimit) / ((double) s_iXScreen);
        s_dYScale = ((double) s_iYLimit) / ((double) s_iYScreen);
   }

      // get the bitmaps and sizes

   hdc = ::GetDC (hWnd);

   s_Bouncer.m_hmemdc = CreateCompatibleDC (hdc);

   s_Bouncer.m_hbitmap = (HBITMAP) LoadImage (hMainInstance,
      MAKEINTRESOURCE (IDB_BITMAP1), IMAGE_BITMAP, 0, 0, 0);
   GetObject (s_Bouncer.m_hbitmap, sizeof (bmp), &bmp);
   s_Bouncer.m_iXBit = bmp.bmWidth;
   s_Bouncer.m_iYBit = bmp.bmHeight;
   s_Bouncer.m_holdbitmap = SelectObject (s_Bouncer.m_hmemdc,
      s_Bouncer.m_hbitmap);

   ::ReleaseDC (hWnd, hdc);

      // get center of screen

   int      iHeight;
   int      iWidth;
   int      iYPos;
   int      iXPos;

   iWidth  = s_Bouncer.m_iXBit;
   iHeight = s_Bouncer.m_iYBit;

   iXPos = (s_iXScreen / 2) - (iWidth / 2);
   iYPos = (s_iYScreen / 2) - (iHeight / 2);

      // starting position of bitmap

   s_Bouncer.m_iXPosition = iXPos;
   s_Bouncer.m_iYPosition = iYPos;
   s_Bouncer.m_iXDelta = (rand () % s_iRandomMax + s_iAbsDelta);
   s_Bouncer.m_iYDelta = - (rand () % s_iRandomMax + s_iAbsDelta);
   s_Bouncer.m_iXLastPos = iXPos;
   s_Bouncer.m_iYLastPos = iYPos;
}


/***********************************************************************
**      see if we hit an edge of the screen
*/
static int Collision (CBouncer *pMe)
{
   int         iLeft;
   int         iRight;
   int         iTop;
   int         iBottom;

   iLeft   = pMe->m_iXPosition;
   iRight  = iLeft + pMe->m_iXBit;
   iTop    = pMe->m_iYPosition;
   iBottom = iTop + pMe->m_iYBit;

      // left edge of window?

    if (iLeft < 0)
   {
      pMe->m_iXPosition = 0;
      pMe->m_iXDelta = rand () % s_iRandomMax + s_iAbsDelta;
      return (HIT_LEFT);
   }

      // right side of window?

    if (iRight > s_iXScreen)
   {
      pMe->m_iXPosition = s_iXScreen - pMe->m_iXBit;
      pMe->m_iXDelta = - (rand () % s_iRandomMax + s_iAbsDelta);
      return (HIT_RIGHT);
   }

      // top of window?

    if (iTop < 0)
   {
      pMe->m_iYPosition = 0;
      pMe->m_iYDelta = rand () % s_iRandomMax + s_iAbsDelta;
      return (HIT_TOP);
   }

      // bottom of window?

    if (iBottom > s_iYScreen)
   {
      pMe->m_iYPosition = s_iYScreen - pMe->m_iYBit;
      pMe->m_iYDelta = - (rand () % s_iRandomMax + s_iAbsDelta);
      return (HIT_BOTTOM);
   }

   return (HIT_NONE);
}



/***********************************************************************
**      draw after a move
*/
static int Draw (HDC hdc, BOOL bMove)
{
   BOOL      bBounce = FALSE;
   int         iCollision;
   CBouncer   *pBouncer;
   RECT      rc;

   pBouncer = &s_Bouncer;

   if (bMove)
   {
         // if we moved vertically, blank out area we no longer occupy

      if (pBouncer->m_iYLastPos > pBouncer->m_iYPosition)   // moving up

      {
         rc.top    = pBouncer->m_iYPosition + pBouncer->m_iYBit;
         rc.bottom = pBouncer->m_iYLastPos + pBouncer->m_iYBit;
      }
       else   // moving down

       {
         rc.top    = pBouncer->m_iYLastPos;
         rc.bottom = pBouncer->m_iYPosition;
      }
      rc.left  = pBouncer->m_iXLastPos;
      rc.right = rc.left + pBouncer->m_iXBit;

       rc.left   = (int) (s_dXScale * rc.left);
      rc.right  = (int) (s_dXScale * rc.right);
      rc.top    = (int) (s_dYScale * rc.top);
      rc.bottom = (int) (s_dYScale * rc.bottom);

       FillRect (hdc, &rc, (HBRUSH) GetStockObject (BLACK_BRUSH));

         // if we moved horizontally, blank out area we no longer occupy

       if (pBouncer->m_iXLastPos > pBouncer->m_iXPosition)   // moving left

       {
         rc.left  = pBouncer->m_iXPosition + pBouncer->m_iXBit;
         rc.right = pBouncer->m_iXLastPos + pBouncer->m_iXBit;
       }
       else   // moving right

       {
         rc.left  = pBouncer->m_iXLastPos;
         rc.right = pBouncer->m_iXPosition;
       }
       if (pBouncer->m_iYLastPos > pBouncer->m_iYPosition)   // moving up

       {
         rc.top    = pBouncer->m_iYLastPos;
         rc.bottom = pBouncer->m_iYPosition + pBouncer->m_iYBit;
      }
      else   // moving down

       {
         rc.top    = pBouncer->m_iYPosition;
         rc.bottom = pBouncer->m_iYLastPos + pBouncer->m_iYBit;
      }

       rc.left   = (int) (s_dXScale * rc.left);
      rc.right  = (int) (s_dXScale * rc.right);
      rc.top    = (int) (s_dYScale * rc.top);
      rc.bottom = (int) (s_dYScale * rc.bottom);

       FillRect (hdc, &rc, (HBRUSH) GetStockObject (BLACK_BRUSH));
   }

   if (s_bIsFull)
   {
      BitBlt (hdc, pBouncer->m_iXPosition, pBouncer->m_iYPosition,
         pBouncer->m_iXBit, pBouncer->m_iYBit, pBouncer->m_hmemdc, 0, 0, SRCCOPY);
   }
   else
   {
      StretchBlt (hdc, (int) (pBouncer->m_iXPosition * s_dXScale),
         (int) (pBouncer->m_iYPosition * s_dYScale),
         (int) (pBouncer->m_iXBit * s_dXScale),
         (int) (pBouncer->m_iYBit * s_dYScale),
         pBouncer->m_hmemdc, 0, 0, 
         pBouncer->m_iXBit, pBouncer->m_iYBit, SRCCOPY);
   }

   if (bMove)
   {
         // last now equal to current

      pBouncer->m_iXLastPos = pBouncer->m_iXPosition;
      pBouncer->m_iYLastPos = pBouncer->m_iYPosition;

         // set position to where we will next be drawn

       pBouncer->m_iXPosition += pBouncer->m_iXDelta;
       pBouncer->m_iYPosition += pBouncer->m_iYDelta;

         // will that hit something?

      iCollision = Collision (pBouncer);

      if (iCollision != HIT_NONE)
         bBounce = TRUE;
      else
         bBounce = FALSE;

         // play the collision sound if requested

       if (bBounce && !s_bMute)
      {
         PlaySound (MAKEINTRESOURCE (IDR_SOUND1), hMainInstance,
            SND_RESOURCE | SND_ASYNC | SND_NODEFAULT);
      }
   }

   return (-1);
}


/***********************************************************************
**      allow other windows to come on top
*/
static BOOL saverInit (HWND hWnd)
{
      // Note that this causes a double screen clear on certain displays

   SetWindowPos (hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
   return TRUE;
}


/***********************************************************************
**      dialog proc for accepting message text
*/
BOOL WINAPI TakeMessageDialog (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
   int      iLen;
   HWND   hCtrl;
   LPSTR   lpUserName;
   char   *lpText;
   char   *lpFrom;
   char   szSubject[200];
   char   szTitle[256];

    switch (message)
   {
        case WM_INITDIALOG:
         lpUserName = g_gworb.GetUserName ();
         if (lpUserName)
         {
            LoadString (hMainInstance, IDS_MESSAGETITLE,
               szTitle, sizeof (szTitle));
            wsprintf (szSubject, (LPSTR) szTitle, g_gworb.GetUserName ());
            SetWindowText (hDlg, szSubject);
         }

         s_hDlg = hDlg;

         hCtrl = GetDlgItem (hDlg, IDC_FROM);
         ASSERT (hCtrl);
         SetFocus (hCtrl);
         s_dwDlgStartTime = GetTickCount ();
         return (FALSE);

        case WM_COMMAND:
            switch (wParam)
         {
                case IDOK:               // OK

               LoadString (hMainInstance, IDS_SUBJECT,
                  szSubject, sizeof (szSubject));

               hCtrl = GetDlgItem (hDlg, IDC_MESSAGE);
               ASSERT (hCtrl);
               iLen = GetWindowTextLength (hCtrl) + 1;
               lpText = new char [iLen];
               GetWindowText (hCtrl, lpText, iLen);

               hCtrl = GetDlgItem (hDlg, IDC_FROM);
               ASSERT (hCtrl);
               iLen = GetWindowTextLength (hCtrl) + 1;
               lpFrom = new char [iLen];
               GetWindowText (hCtrl, lpFrom, iLen);

                    EndDialog (hDlg, TRUE);      // close now


               g_gworb.SendSelfMessage (szSubject, lpText, lpFrom);

               delete [] lpText;
               delete [] lpFrom;

                    return TRUE;

                case IDCANCEL:            // Cancel

                    EndDialog (hDlg, FALSE);
                    return TRUE;

            default:
               if (HIWORD (wParam) == EN_CHANGE)
               {
                     // reset timer

                  s_dwDlgStartTime = GetTickCount ();
               }
               break;
            }
            break;

      default:
         break;
   }

    return FALSE;
}


/***********************************************************************
**      display the dialog to accept message text
*/
static void
TakeMessage (HWND hWnd)
{
   int      iStatus;
   RECT   rSaveRect;

   if (!s_bIsFull)
      return;

   if (!g_gworb.ReadyToSend ())
   {
      MessageBeep (0);
      return;
   }

      // hide prompt window

   GetWindowRect (s_hWndMessage, &rSaveRect);
   SetWindowPos (s_hWndMessage, NULL, s_iXScreen + 1, s_iYScreen + 1, 0, 0,
      SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);

   s_bMessageUp = TRUE;
   SetCursor (LoadCursor (NULL, IDC_ARROW));

   iStatus = DialogBox (hMainInstance,
      MAKEINTRESOURCE (IDD_TAKEMESSAGE),
      hWnd, (DLGPROC) TakeMessageDialog);
   ASSERT (iStatus != -1);

   SetCursor (NULL);
//   s_bMessageUp = FALSE;      // not here!


   SetWindowPos (s_hWndMessage, NULL, rSaveRect.left, rSaveRect.top, 0, 0,
      SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}


/***********************************************************************
**      draw the text in the prompt window
*/
static void
MessagePaint (HWND hWnd, WPARAM wParam, LPARAM lParam)
{
   RECT      rRect;
   PAINTSTRUCT   stPS;

   BeginPaint (hWnd, &stPS);

   rRect.left   = 0;
   rRect.top    = 0;
   rRect.right  = s_iMsgWidth;
   rRect.bottom = s_iMsgHeight;

   SetBkMode (stPS.hdc, TRANSPARENT);

   DrawText (stPS.hdc, s_szDefaultText, lstrlen (s_szDefaultText),
      &rRect, DT_CENTER | DT_WORDBREAK);

   EndPaint (hWnd, &stPS);
}


/***********************************************************************
**      window proc for prompt window
**      send most messages to parent window
*/
LRESULT FAR PASCAL MessageWndProc
   (HWND    hWnd,
   UINT     wMsg,
   WPARAM   wParam,
   LPARAM   lParam)
{

   switch (wMsg)
   {
      case WM_KEYDOWN:
         PostMessage (hMainWindow, wMsg, wParam, lParam);
         break;

      case WM_KEYUP:
         PostMessage (hMainWindow, wMsg, wParam, lParam);
         break;

      case WM_PAINT:
         MessagePaint (hWnd, wParam, lParam);
         break;

      case WM_SETFOCUS:
         SetFocus (hMainWindow);
         break;

      case WM_MOUSEMOVE:
         PostMessage (hMainWindow, wMsg, wParam, lParam);
         break;

      default:
         break;
   }

   return (DefWindowProc (hWnd, wMsg, wParam, lParam));
}


/***********************************************************************
**      regist the prompt window class
*/
static void
RegisterMessageWindow (void)
{
   WNDCLASS      wc;
   ATOM         aRegisterClass;

   wc.style = 0;
   wc.lpfnWndProc = (WNDPROC) MessageWndProc;
   wc.cbClsExtra = 0;
   wc.cbWndExtra = 0;
   wc.hInstance = hMainInstance;
   wc.hIcon     = NULL;
   wc.hCursor   = NULL;
   wc.hbrBackground   = (HBRUSH) (COLOR_WINDOW + 1);
   wc.lpszMenuName = NULL;
   wc.lpszClassName = "GWSMESSAGE";

   aRegisterClass = RegisterClass (&wc);
   ASSERT (aRegisterClass);

   return;
}


/***********************************************************************
**      create the prompt window
*/
static void
MessageWindow (HWND hWndParent)
{
   HDC      hDC;
   int      iX;
   int      iY;
   BOOL   bStatus;
   LPSTR   lpUserName;
   RECT   rRect;
   SIZE   stSize;

   if (!s_bIsFull)
      return;

      // create the window

   lpUserName = g_gworb.GetUserName ();
   if (!lpUserName)
      return;

   s_iMsgWidth  = s_iXScreen / 3;
   s_iMsgHeight = s_iYScreen / 4;

   iX = 1;
   iY = 1;

   s_hWndMessage = CreateWindow (
      (LPCTSTR) "GWSMESSAGE",   // address of registered class name

      (LPCTSTR) lpUserName,   // address of window name

      WS_BORDER | WS_CAPTION | WS_POPUP,   // window style

      iX,   // horizontal position of window

      iY,   // vertical position of window

      s_iMsgWidth,   // window width

      s_iMsgHeight,   // window height

      hWndParent,   // handle of parent or owner window

      NULL,   // handle of menu or child-window identifier

      hMainInstance,   // handle of application instance

      NULL);    // address of window-creation data

   ASSERT (s_hWndMessage);
   if (s_hWndMessage == NULL)
      return;

   SetActiveWindow (hWndParent);

      // size window

   int      iTextWidth;
   int      iTextHeight;
   int      iNameWidth;

   hDC = GetDC (s_hWndMessage);
   ASSERT (hDC);

   bStatus = GetTextExtentPoint32 (
       hDC,   // handle of device context 

       (LPCTSTR) lpUserName,   // address of text string 

       lstrlen (lpUserName),   // number of characters in string 

       &stSize);    // address of structure for string size  

   ASSERT (bStatus);

   iNameWidth = stSize.cx + 20;

   bStatus = GetTextExtentPoint32 (
       hDC,   // handle of device context 

       (LPCTSTR) s_szDefaultText,   // address of text string 

       lstrlen (s_szDefaultText),   // number of characters in string 

       &stSize);    // address of structure for string size  

   ASSERT (bStatus);

   iTextWidth  = stSize.cx;
   iTextHeight = stSize.cy;

   ReleaseDC (s_hWndMessage, hDC);

      // position window

   s_iMsgWidth  = max (iNameWidth, iTextWidth / 2) + 10;
   s_iMsgHeight = max (100, iTextHeight) + 10;

   iX = rand () % (s_iXScreen - s_iMsgWidth);
   iY = rand () % (s_iYScreen - s_iMsgHeight);

   SetWindowPos (s_hWndMessage, NULL, iX, iY, s_iMsgWidth, s_iMsgHeight,
      SWP_NOZORDER | SWP_NOACTIVATE);

   GetClientRect (s_hWndMessage, &rRect);
   s_iMsgWidth  = rRect.right - rRect.left;
   s_iMsgHeight = rRect.bottom - rRect.top;

      // show the window

   ShowWindow (s_hWndMessage, SW_SHOWNOACTIVATE);

   return;
}


/***********************************************************************
**      move the prompt window every 10 seconds
*/
static void
MoveMessage (void)
{
   static   DWORD   dwNextCount = 0;
   static   DWORD   dwNextFlash = 0;
   static   int      iFlash = 0;
   DWORD   dwNow;

   if (!s_bIsFull)
      return;

   if (s_hWndMessage == NULL)
      return;

   if (s_bMessageUp)
      return;

   dwNow = GetTickCount ();

   if (dwNextCount == 0)
   {
      dwNextCount = dwNow + c_dwMessageDelay;
      return;
   }

   if (dwNow > dwNextCount)
   {
      int      iX;
      int      iY;

      iX = rand () % (s_iXScreen - s_iMsgWidth - 10);
      iY = rand () % (s_iYScreen - s_iMsgHeight - 10);
      SetWindowPos (s_hWndMessage, NULL, iX, iY, 0, 0,
         SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);

      dwNextCount = dwNow + c_dwMessageDelay;
   }

      // flash caption

   if (dwNow > dwNextFlash)
   {
      FlashWindow (s_hWndMessage, TRUE);

      dwNextFlash = dwNow + c_dwFlashDelay;
   }

   return;
}


/***********************************************************************
**      main window
*/
LONG PASCAL
ScreenSaverProc (HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
   static BOOL         bFirstPaint = TRUE;
   static HBRUSH      hBrush = NULL;
    static RECT         rc;
   static DWORD      dwEnd = 0L;
    HDC            hDC;
   BOOL         bStatus;
   PAINTSTRUCT      ps;

    switch (Message)
   {

        case WM_CREATE:
        {
         hMainWindow = hWnd;

         ReleaseCapture ();

            // register the window class for prompt window

         RegisterMessageWindow ();

               // load resources

            GetIniEntries ();
            GetIniSettings ();

         if (s_iSpeed < 0)
            s_iSpeed = 0;

            saverInit (hWnd);   // debug only stuff


         GetWindowRect (hWnd, &rc);

         Seed (hWnd);

         dwEnd = GetTickCount () + c_dwStartWait;
         SetSpeed (hWnd, s_iSpeed);
            break;
        }

        case WM_TIMER:
         if (GetTickCount () > dwEnd)
         {
            if (!s_bTimer)
            {
               s_bTimer = TRUE;
               hDC = GetDC (hWnd);
               ASSERT (hDC);
               Draw (hDC, TRUE);
               ReleaseDC (hWnd, hDC);
               s_bTimer = FALSE;
               MoveMessage ();
            }
         }
         if (s_bMessageUp &&
            GetTickCount () > s_dwDlgStartTime + c_dwDlgDelay &&
            IsWindow (s_hDlg))
         {
               // close dialog

            SendMessage (s_hDlg, WM_COMMAND, IDCANCEL, 0L);
         }
            break;

      case WM_PAINT:
            memset (&ps, 0, sizeof (PAINTSTRUCT));
            hDC = BeginPaint (hWnd, &ps);

         if (hBrush == NULL)
         {
            hBrush = CreateSolidBrush (RGB (0, 0, 0));
            ASSERT (hBrush);
         }

         FillRect (hDC, &rc, hBrush);

         Draw (hDC, FALSE);

            EndPaint(hWnd, &ps);

         if (bFirstPaint)
         {
            bFirstPaint = FALSE;
            if (s_bIsFull)
            {
               bStatus = g_gworb.Init ();
                  // create message dialog window


               if (bStatus)
               {
                  MessageWindow (hWnd);
               }

            }
         }
         break;

      case WM_KEYDOWN:
         if (wParam == VK_SPACE)
         {
            TakeMessage (hWnd);
            return (0);
         }
         break;

      case WM_MOUSEMOVE:
         if (s_bIsFull && s_bMessageUp)
         {
            s_bMessageUp = FALSE;
            return (0);
         }
         break;

      case WM_SETCURSOR:
         if (s_bMessageUp)
         {
            SetCursor (LoadCursor (NULL, IDC_ARROW));
            return (0L);
         }
         break;

      case WM_CLOSE:
         if (s_bMessageUp)
         {
            MessageBeep (MB_ICONASTERISK);
            return (0);
         }
         break;

        case WM_DESTROY:
            if (s_wTimer)
         {
               KillTimer (hWnd, ID_TIMER);
            }
            break;

      default:
         break;
   }
        
    return DefScreenSaverProc(hWnd, Message, wParam, lParam);
}


/***********************************************************************
**      configuration dialog
*/
BOOL WINAPI ScreenSaverConfigureDialog (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
   HWND   hCtrl;
   int      nCurPos;
   char   szText[256];

    switch (message)
   {
        case WM_INITDIALOG:
         GetIniEntries ();
         GetIniSettings ();

         hCtrl = GetDlgItem (hDlg, IDC_SPEED_GRP);
         ASSERT (hCtrl);
         LoadString (hMainInstance, IDS_SPEED_GRP, szText, sizeof (szText));
         SetWindowText (hCtrl, szText);

         hCtrl = GetDlgItem (hDlg, IDC_SOUND_GRP);
         ASSERT (hCtrl);
         LoadString (hMainInstance, IDS_SOUND_GRP, szText, sizeof (szText));
         SetWindowText (hCtrl, szText);

         hCtrl = GetDlgItem (hDlg, IDC_SLOW_TXT);
         ASSERT (hCtrl);
         LoadString (hMainInstance, IDS_SLOW_TXT, szText, sizeof (szText));
         SetWindowText (hCtrl, szText);

         hCtrl = GetDlgItem (hDlg, IDC_FAST_TXT);
         ASSERT (hCtrl);
         LoadString (hMainInstance, IDS_FAST_TXT, szText, sizeof (szText));
         SetWindowText (hCtrl, szText);

         hCtrl = GetDlgItem (hDlg, IDOK);
         ASSERT (hCtrl);
         LoadString (hMainInstance, IDS_OK, szText, sizeof (szText));
         SetWindowText (hCtrl, szText);

         hCtrl = GetDlgItem (hDlg, IDCANCEL);
         ASSERT (hCtrl);
         LoadString (hMainInstance, IDS_CANCEL, szText, sizeof (szText));
         SetWindowText (hCtrl, szText);

         hCtrl = GetDlgItem (hDlg, IDC_MESSAGE_TXT);
         ASSERT (hCtrl);
         LoadString (hMainInstance, IDS_MESSAGE_TXT, szText, sizeof (szText));
         SetWindowText (hCtrl, szText);

         hCtrl = GetDlgItem (hDlg, IDC_MESSAGE);
         ASSERT (hCtrl);
         SetWindowText (hCtrl, s_szDefaultText);

         hCtrl = GetDlgItem (hDlg, IDC_MUTE);
         ASSERT (hCtrl);
         LoadString (hMainInstance, IDS_MUTE_TXT, szText, sizeof (szText));
         SetWindowText (hCtrl, szText);
         CheckDlgButton (hDlg, IDC_MUTE, !s_bMute);

         LoadString (hMainInstance, IDS_CONFIG_CAPTION, szText, sizeof (szText));
         SetWindowText (hDlg, szText);

         hCtrl = GetDlgItem (hDlg, IDC_SCROLLBAR_SPEED);
         ASSERT (hCtrl);
         SetScrollRange (hCtrl, SB_CTL, 1, 100, FALSE);
         SetScrollPos (hCtrl, SB_CTL, s_iSpeed, FALSE);
         return (TRUE);

        case WM_HSCROLL:
         nCurPos = GetScrollPos ((HWND) lParam, SB_CTL);
            switch (LOWORD (wParam)) 
         { 
            case SB_LEFT: //    Scroll to far left.

               nCurPos = 1;
               break;
            case SB_LINELEFT: //    Scroll left.

               nCurPos--;
               break;
            case SB_LINERIGHT: //    Scroll right.

               nCurPos++;
               break;
            case SB_PAGELEFT: //    Scroll one page left.

               nCurPos -= 10;
               break;
            case SB_PAGERIGHT: //    Scroll one page right.

               nCurPos += 10;
               break;
            case SB_RIGHT: //    Scroll to far right.

               nCurPos = 100;
               break;
            case SB_THUMBPOSITION: 
               nCurPos = HIWORD (wParam);
                    break; 
            case SB_ENDSCROLL: 
            case SB_THUMBTRACK: //    Drag scroll box to specified position.

               break;
            default:
               break;
         } 
 
         if (nCurPos < 1)
            nCurPos = 1;
         if (nCurPos > 100)
            nCurPos = 100;

         SetScrollPos ((HWND) lParam, SB_CTL, nCurPos, TRUE);

         s_iSpeed = nCurPos;
         break;

        case WM_COMMAND:
            switch (wParam)
         {
                case IDOK:               // OK

               s_bMute = !IsDlgButtonChecked (hDlg, IDC_MUTE);
               GetDlgItemText (hDlg, IDC_MESSAGE,
                  s_szDefaultText, sizeof (s_szDefaultText));
               WriteProfileInt (szAppName, (LPSTR) c_szMute, (int) s_bMute);
               WriteProfileInt (szAppName, (LPSTR) c_szSpeed, s_iSpeed);
               WritePrivateProfileString (szAppName, (LPSTR) c_szMessage,
                  s_szDefaultText, szIniFile);

                    EndDialog(hDlg, TRUE);
                    return TRUE;

                case IDCANCEL:            // Cancel

                    EndDialog (hDlg, FALSE);
                    return TRUE;
            }
            break;
   }

    return FALSE;
}


/***********************************************************************
**      dummy function expected by scrnsave.lib
*/
BOOL WINAPI RegisterDialogClasses (HANDLE hInst)
{
   return (TRUE);
}