home *** CD-ROM | disk | FTP | other *** search
/ Freelog 54 / Freelog054.iso / Bas / Détente / WinPenguins / MainWnd.cpp < prev    next >
C/C++ Source or Header  |  2001-04-18  |  23KB  |  881 lines

  1. /**
  2.  * $Id: MainWnd.cpp,v 1.7 2001/04/18 14:46:56 mvines Exp $
  3.  *
  4.  *  Copyright (C) 2000  Michael Vines
  5.  *
  6.  *  This file contains code from XPenguins 1.1
  7.  *        Copyright (C) 1999,2000  Robin Hogan
  8.  *
  9.  *  This program is free software; you can redistribute it and/or modify
  10.  *  it under the terms of the GNU General Public License as published by
  11.  *  the Free Software Foundation; either version 2 of the License, or
  12.  *  (at your option) any later version.
  13.  *
  14.  *  This program is distributed in the hope that it will be useful,
  15.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  *  GNU General Public License for more details.
  18.  *
  19.  *  You should have received a copy of the GNU General Public License
  20.  *  along with this program; if not, write to the Free Software
  21.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  22.  *
  23.  *  As a special exception, Michael Vines gives permission to link this program
  24.  *  with the Microsoft Visual C++ Runtime/MFC Environment, and distribute the
  25.  *  resulting executable, without including the source code for the Microsoft 
  26.  *  Visual C++ Runtime/MFC Environment in the source distribution
  27.  */
  28.  
  29.  
  30. #include "stdafx.h"
  31. #include "winpenguins.h"
  32. #include "winpenguinsDlg.h"
  33. #include "MainWnd.h"
  34. #include "def.h"
  35. #include "screen_capture.h"
  36.  
  37. #ifdef _DEBUG
  38. #define new DEBUG_NEW
  39. #undef THIS_FILE
  40. static char THIS_FILE[] = __FILE__;
  41. #endif
  42.  
  43.  
  44. /////////////////////////////////////////////////////////////////////////////
  45. // Globals defined by CMainWnd
  46. void (WINAPI *transparentblt) (HDC,int,int,int,int,HDC,int,int,int,int,UINT);
  47. void (WINAPI *alphablend)(HDC,int,int,int,int,HDC,int,int,int,int,BLENDFUNCTION);
  48.  
  49. /////////////////////////////////////////////////////////////////////////////
  50. // Locals used by CMainWnd
  51.  
  52. #include "winmon/winmon_ptr.h"
  53.  
  54. static BOOL CALLBACK EnumWindowCallback(HWND hWnd, LPARAM lParam)
  55. {
  56.     RECT rt;
  57.     CRgn rgn;
  58.  
  59.     if (!IsWindowVisible(hWnd)) return TRUE;
  60.  
  61.     // Ignore windows in our process
  62.     DWORD pid;
  63.     GetWindowThreadProcessId(hWnd, &pid);
  64.     if (pid == GetCurrentProcessId()) return TRUE;
  65.  
  66.     // Ignore the "Program Manager" window
  67.     char title[256];
  68.     ::GetWindowText(hWnd, title, 256);
  69.     if (!stricmp(title, "Program Manager")) return TRUE;
  70.  
  71.     // All good, add this window to the region
  72.     if (!GetWindowRect(hWnd, &rt)) return TRUE;
  73.  
  74.     if (rt.right < 0 && rt.bottom < 0) return TRUE;
  75.  
  76.     if (CMainWnd::wndRgn != NULL) {
  77.         if (!rgn.CreateRectRgnIndirect(&rt)) return TRUE;
  78.  
  79.         CMainWnd::wndRgn->CombineRgn(CMainWnd::wndRgn, &rgn, RGN_OR);
  80.     } else {
  81.         CMainWnd::wndRgn = new CRgn();
  82.  
  83.         if (!CMainWnd::wndRgn->CreateRectRgnIndirect(&rt)) return TRUE;
  84.     }
  85.     return TRUE;
  86. }
  87.  
  88.  
  89. static HWND foundWnd;
  90. static BOOL CALLBACK FindWndWithClass(HWND hwnd, LPARAM lParam)
  91. {
  92.     char *className = (char*)lParam;
  93.     char thisClass[256];
  94.  
  95.     GetClassName(hwnd, thisClass, sizeof(thisClass));
  96.  
  97.     foundWnd = NULL;
  98.     if (!strcmp(className, thisClass)) {
  99.         foundWnd = hwnd;
  100.         return FALSE;
  101.     }
  102.     return TRUE;
  103. }
  104.  
  105.  
  106. /////////////////////////////////////////////////////////////////////////////
  107. // CMainWnd
  108.  
  109. CWnd CMainWnd::dskWnd;  // desktop window that is drawn on
  110.  
  111. // The region that covers all top level windows
  112. CRgn *CMainWnd::wndRgn = NULL;
  113.  
  114. // alpha blending level (0-255)
  115. unsigned char CMainWnd::blendLevel = 255;
  116.  
  117. int CMainWnd::soundEnabled = 0;
  118.  
  119. int CMainWnd::santaPercent = 0;
  120.  
  121.  
  122. CMainWnd::CMainWnd()
  123. {
  124.   activeDlg = 0;
  125.  
  126.     // Check if another instance of WinPenguins is already running
  127.     hInstanceMutex = ::CreateMutex(NULL, FALSE, "WinPenguinsInstanceMutex");
  128.     if (NULL == hInstanceMutex) {
  129.         MessageBox("Unable to create instance mutex", "Internal Error", MB_ICONERROR);
  130.         ::ExitProcess(1);
  131.     }
  132.     if (::GetLastError() == ERROR_ALREADY_EXISTS) {
  133.         ::ExitProcess(0);      // Exit quitely if the mutex already exists
  134.     }
  135.  
  136.     srand(time(NULL));
  137.  
  138.     // Check OS version.  Windows 2000 has a TranparentBlt() function
  139.     // which makes things much cleaner, otherwise we have to fake it. 
  140.     // 
  141.     // NOTE: Win98 supposedly also has this function, however it seems
  142.     // to leak GDI resources whenever I use it.  
  143.     bool enableAlpha = false;
  144.     bool transInternal = true;
  145.  
  146.  
  147.     OSVERSIONINFO vi;
  148.     vi.dwOSVersionInfoSize = sizeof(vi);
  149.     GetVersionEx(&vi);
  150.     if (vi.dwMajorVersion >= 5) {
  151.         transInternal = false;
  152.            enableAlpha = true;
  153.     } else {
  154.         if ((4 == vi.dwMajorVersion) && (vi.dwMinorVersion > 0)) {
  155.           enableAlpha = true;
  156.         } 
  157.     }
  158.  
  159.     // Find the desktop window 
  160.     //   this is kindof kludgy and I'm not sure if it'll work in all cases!
  161.     CWnd *progMan = CWnd::FindWindow("Progman", "Program Manager");
  162.  
  163.     ASSERT(progMan != NULL);
  164.     EnumChildWindows(*progMan, FindWndWithClass, (LPARAM)"SHELLDLL_DefView");
  165.     ASSERT(foundWnd != NULL);
  166.     EnumChildWindows(foundWnd, FindWndWithClass, (LPARAM)"SysListView32");
  167.     ASSERT(foundWnd != NULL);
  168.  
  169.     dskWnd.Attach(foundWnd);
  170.  
  171.     
  172.     transparentblt = NULL;
  173.     alphablend = NULL;
  174.  
  175.     msimg32 = ::LoadLibrary("msimg32.dll");
  176.     if (msimg32 != NULL) {
  177.         if (!transInternal) { 
  178.           (FARPROC &)transparentblt = GetProcAddress(msimg32, "TransparentBlt");
  179.         }
  180.  
  181.         if (enableAlpha) {
  182.             (FARPROC &)alphablend = GetProcAddress(msimg32, "AlphaBlend");
  183.         }
  184.     }
  185.  
  186.     
  187.     // Load the Winmon DLL. First just try to load it (ie. if it is already 
  188.     // in the path).  If that failes, then load the copy that is in the EXE 
  189.     // resources.  
  190.     //
  191.     // The reason this is done is so that people can simply distribute the 
  192.     // winpenguins executable without worrying about the additional DLL
  193.  
  194.     winmonFileName[0] = '\0';
  195.     //winmon = ::LoadLibrary("winmon.dll");
  196.     winmon = NULL;
  197.     if (NULL == winmon) {
  198.         HRSRC hRes;
  199.         HGLOBAL hGlobal;
  200.         LPVOID winmonPtr;
  201.         DWORD winmonSize;
  202.         DWORD bytesWritten;
  203.  
  204.         // find winmon.dll in the exe resources
  205.         hRes = ::FindResource(NULL, MAKEINTRESOURCE(IDR_WINMONDLL), "Binary");
  206.         hGlobal = ::LoadResource(NULL, hRes);
  207.  
  208.         winmonPtr = ::LockResource(hGlobal);
  209.         if (NULL == winmonPtr) {
  210.             MessageBox("Unable to load 'winmon.dll'", "Error", MB_ICONERROR);
  211.             ExitProcess(0);
  212.         }
  213.         winmonSize = ::SizeofResource(NULL, hRes);
  214.  
  215.         GetTempPath(MAX_PATH, winmonFileName);
  216.         strncat(winmonFileName, "winmon.dll", MAX_PATH);
  217.         winmonFileName[MAX_PATH] = '\0';
  218.  
  219.         // write winmon.dll and load it
  220.         HANDLE hFile = CreateFile(winmonFileName, GENERIC_WRITE, 0, NULL, 
  221.                                   CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  222.         WriteFile(hFile, winmonPtr, winmonSize, &bytesWritten, NULL);
  223.         CloseHandle(hFile);
  224.         winmon = ::LoadLibrary(winmonFileName);
  225.  
  226.         if (NULL == winmon) {
  227.             MessageBox("Unable to load 'winmon.dll'", "Error", MB_ICONERROR);
  228.             ::ExitProcess(0);
  229.         }
  230.     }
  231.     LoadWinmonFunctions(winmon);
  232.  
  233.     // Load the penguin bitmap resources
  234.     for (int i = 0; i < PENGUIN_COUNT; i++) {
  235.         penguin_data[i].bmp = new CBitmap();
  236.         penguin_data[i].bmp->LoadBitmap(MAKEINTRESOURCE(penguin_data[i].resId));
  237.         penguin_data[i].mskBmp = new CBitmap();
  238.         penguin_data[i].mskBmp->LoadBitmap(MAKEINTRESOURCE(penguin_data[i].mskResId));
  239.     }
  240.  
  241.     Create(NULL, "MainWnd", WS_OVERLAPPEDWINDOW);
  242.  
  243.     // Monitor window activity...
  244.     Winmon_LoadHook(GetCurrentProcessId(), dskWnd.m_hWnd);
  245. }
  246.  
  247.  
  248. CMainWnd::~CMainWnd()
  249. {
  250.     (void) dskWnd.Detach();
  251.  
  252.     Winmon_UnloadHook();
  253.  
  254.     ::FreeLibrary(winmon);
  255.  
  256.     // XXX: this api call fails with an access denied error!
  257.     ::DeleteFile(winmonFileName);
  258.     
  259.     if (msimg32 != NULL) {
  260.         ::FreeLibrary(msimg32);
  261.     } 
  262.  
  263.     ::CloseHandle(hInstanceMutex);
  264. }
  265.  
  266.  
  267.  
  268. BEGIN_MESSAGE_MAP(CMainWnd, CWnd)
  269.     //{{AFX_MSG_MAP(CMainWnd)
  270.     ON_WM_CREATE()
  271.     ON_MESSAGE(UWM_SYSTRAY, OnSysTray)
  272.     ON_WM_CLOSE()
  273.     ON_WM_TIMER()
  274.     ON_COMMAND(ID_ABOUT, OnAbout)
  275.     ON_COMMAND(ID_EXIT, OnExit)
  276.     ON_COMMAND(ID_OPTIONS, OnOptions)
  277.     ON_COMMAND(ID_SCREENCAP, OnScreenCapture)
  278.     ON_WM_LBUTTONDBLCLK()
  279.     //}}AFX_MSG_MAP
  280. END_MESSAGE_MAP()
  281.  
  282.  
  283. /////////////////////////////////////////////////////////////////////////////
  284. // CMainWnd message handlers
  285.  
  286. int CMainWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  287. {
  288.     if (CWnd::OnCreate(lpCreateStruct) == -1)
  289.         return -1;
  290.  
  291.     // Load config options from registry 
  292.     m_numPenguins = theApp.GetProfileInt("Options", "PenguinCount", 5);
  293.     m_moveDelay = theApp.GetProfileInt("Options", "MoveDelay", 50);
  294.     m_splatDist = theApp.GetProfileInt("Options", "SplatDistance", 2000);
  295.   blendLevel = theApp.GetProfileInt("Options", "BlendLevel", 255);
  296.   santaPercent = theApp.GetProfileInt("Options", "SantaPercent", 0);
  297.     soundEnabled = theApp.GetProfileInt("Options", "SoundEnabled", 0);
  298.         
  299.  
  300.     SetToonCountTo(m_numPenguins);
  301.  
  302.     // Create the systray icon
  303.     NOTIFYICONDATA ni;
  304.  
  305.     ni.cbSize = sizeof(ni);
  306.     ni.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  307.     ni.hWnd = m_hWnd;
  308.     ni.uID = 0;
  309.     ni.uCallbackMessage = UWM_SYSTRAY;
  310.     strcpy(ni.szTip, "WinPenguins");
  311.     trayIcon = theApp.LoadIcon(IDR_ICON);
  312.     ni.hIcon = trayIcon;
  313.  
  314.     Shell_NotifyIcon(NIM_ADD, &ni);    
  315.  
  316.     // Movement timer 
  317.     SetTimer(0, m_moveDelay, 0);
  318.  
  319.     return 0;
  320. }
  321.  
  322.  
  323. void CMainWnd::OnSysTray(WPARAM wParam, LPARAM lParam) 
  324. {
  325.     switch (lParam) {
  326.   case WM_LBUTTONUP:
  327.     if (activeDlg != 0) {
  328.       activeDlg->SetForegroundWindow();
  329.       break;
  330.     }
  331.   
  332.     OnOptions();
  333.     break;
  334.     
  335.     case WM_RBUTTONDOWN:
  336.     if (activeDlg != 0) {
  337.       activeDlg->SetForegroundWindow();
  338.       break;
  339.     }
  340.  
  341.     {
  342.         POINT pt;
  343.         ::GetCursorPos(&pt);
  344.  
  345.         CMenu menu;
  346.         CMenu *sysMenu;
  347.  
  348.         menu.LoadMenu(MAKEINTRESOURCE(IDR_SYSTRAY));
  349.  
  350.         sysMenu = menu.GetSubMenu(0);
  351.         sysMenu->SetDefaultItem(1, TRUE);
  352.         sysMenu->TrackPopupMenu(TPM_RIGHTALIGN | TPM_RIGHTBUTTON,
  353.                                 pt.x, pt.y, this, NULL);
  354.         }
  355.         break;
  356.  
  357.     case WM_LBUTTONDBLCLK:
  358.     if (activeDlg != 0) {
  359.       activeDlg->SetForegroundWindow();
  360.       break;
  361.     }
  362.  
  363.         PostMessage(WM_COMMAND, ID_OPTIONS, 0);  
  364.         break;
  365.  
  366.     default:
  367.         break;
  368.     }
  369. }
  370.  
  371.  
  372. void CMainWnd::OnClose() 
  373. {
  374.     if (m_numPenguins > 0 || toonList.GetSize() > 0) {
  375.         m_numPenguins = 0;
  376.         SetToonCountTo(m_numPenguins);
  377.         return;
  378.     }  
  379.  
  380.     CWnd::OnClose();
  381. }
  382.  
  383.  
  384. void CMainWnd::OnTimer(UINT nIDEvent) 
  385. {
  386.     switch (nIDEvent) {
  387.     case 0:
  388.         {
  389.             // Update the WindowRegion if any windows have moved...
  390.             UpdateWndRgn();
  391.  
  392.             // recreate the screen bitmaps when the desktop window is 
  393.             // changed, ie. resizing the taskbar
  394.             if (Winmon_DesktopChanged()) {
  395.                 CreateScreenBitmaps();            
  396.             }
  397.  
  398.             // desktop window has been painted on, flush the penguins
  399.             // and recapture the bitmap
  400.             RECT dskRt;
  401.             if (Winmon_DeskWndPainted(&dskRt)) {
  402.                 // Clear all the penguins 
  403.                 for (int i = 0; i < toonList.GetSize(); i++) {
  404.                     toonList[i]->Erase(dskWnd, &dskRt);
  405.                 }
  406.                 ::SendMessage(dskWnd, WM_PAINT, 0, 0);
  407.  
  408.                 UpdateBgBitmap(&dskRt);
  409.  
  410.                 // Ignore the WM_PAINT message we just sent to 
  411.                 // the desktop window
  412.                 (void)Winmon_DeskWndPainted(NULL);
  413.             }
  414.  
  415.             // Do any required processing...
  416.             for (int i = 0; i < toonList.GetSize(); i++) {
  417.                 int status;
  418.                 bool startingAndBlocked = false;
  419.                 
  420.                 // check if the toon is inside a window...
  421.                 if (toonList[i]->IsBlocked(TOON_HERE)) {
  422.                     if (!toonList[i]->m_startingUp) {
  423.                         toonList[i]->ExplodeAni();
  424.                     } else {
  425.                         startingAndBlocked = true;
  426.                     }
  427.                 } else {
  428.                     toonList[i]->m_startingUp = false;
  429.                 }
  430.  
  431.  
  432.                 status = toonList[i]->AdvanceToon(startingAndBlocked);
  433.  
  434.                 switch (toonList[i]->m_bmpIndex) {
  435.                 case PENGUIN_FALLER:
  436.                     if (startingAndBlocked) break;
  437.  
  438.                     if (status != TOON_OK) {
  439.                         if (toonList[i]->IsBlocked(TOON_DOWN)) {
  440.                             int direction;
  441.  
  442.                             if (toonList[i]->m_prefd > -1) {
  443.                                 direction = toonList[i]->m_prefd;
  444.                             } else {
  445.                                 direction = rand() %2;
  446.                             }
  447.  
  448.                             CheckSubType( toonList[i] );
  449.  
  450.                             if( toonList[i]->GetSubType() == TST_NORMAL_PENGUIN ) {
  451.                                 toonList[i]->SetType( PENGUIN_WALKER, direction );
  452.  
  453.               } else if( toonList[i]->GetSubType() == TST_SANTA_PENGUIN ) {
  454.                                 toonList[i]->SetType( PENGUIN_SANTA_WALKER, direction );
  455.  
  456.               } else    {
  457.                 // this shouldn't happen, but all the same...
  458.                                 toonList[i]->SetType( PENGUIN_WALKER, direction );
  459.                             }
  460.  
  461.                             toonList[i]->SetVelocity(4 *((2*direction)-1), 0);
  462.                             toonList[i]->m_prefd = -1;
  463.                         } else {
  464.                             if (rand() % 10 > 5) {
  465.                                 toonList[i]->SetVelocity(-toonList[i]->m_u, 3);
  466.                             }
  467.  
  468.                             CheckSubType( toonList[i] );
  469.  
  470.                             if( toonList[i]->GetSubType() == TST_NORMAL_PENGUIN )
  471.                             {
  472.                                 toonList[i]->SetType( PENGUIN_CLIMBER, toonList[i]->m_u > 0 );
  473.                             }
  474.                             else if( toonList[i]->GetSubType() == TST_SANTA_PENGUIN )
  475.                             {
  476.                                 toonList[i]->SetType( PENGUIN_SANTA_CLIMBER, toonList[i]->m_u > 0 );
  477.                             }
  478.                             else
  479.                             {
  480.                                 toonList[i]->SetType( PENGUIN_CLIMBER, toonList[i]->m_u > 0 );
  481.                             }
  482.  
  483.                             toonList[i]->SetVelocity(0, -4);
  484.                         }
  485.                     }
  486.                     break;
  487.                 case PENGUIN_TUMBLER:
  488.                     if (status != TOON_OK) {
  489.                         int direction;
  490.  
  491.                         if (toonList[i]->m_prefd > -1) {
  492.                             direction = toonList[i]->m_prefd;
  493.                         } else {
  494.                             direction = rand() %2;
  495.                         }
  496.  
  497.                         CheckSubType( toonList[i] );
  498.  
  499.                         if( toonList[i]->GetSubType() == TST_NORMAL_PENGUIN )
  500.                         {
  501.                             toonList[i]->SetType( PENGUIN_WALKER, direction );
  502.                         }
  503.                         else if( toonList[i]->GetSubType() == TST_SANTA_PENGUIN )
  504.                         {
  505.                             toonList[i]->SetType( PENGUIN_SANTA_WALKER, direction );
  506.                         }
  507.                         else    // this shouldn't happen, but all the same...
  508.                         {
  509.                             toonList[i]->SetType( PENGUIN_WALKER, direction );
  510.                         }
  511.  
  512.                         toonList[i]->SetVelocity(4 *((2*direction)-1), 0);
  513.                         toonList[i]->m_prefd = -1;
  514.  
  515.                         if (toonList[i]->m_y - toonList[i]->m_tumbleStartY > m_splatDist) {
  516.                             toonList[i]->ExplodeAni();
  517.                         }
  518.  
  519.                     }
  520.                     break;
  521.                 case PENGUIN_WALKER:
  522.                 case PENGUIN_SANTA_WALKER:
  523.                     if (!toonList[i]->IsBlocked(TOON_DOWN)) {
  524.                         toonList[i]->m_prefd = toonList[i]->m_directionIndex;
  525.                         toonList[i]->SetType(PENGUIN_TUMBLER, PENGUIN_FOREWARD);
  526.                         toonList[i]->SetVelocity(0, 6);
  527.                         toonList[i]->m_tumbleStartY = toonList[i]->m_y;
  528.                     } else if (status != TOON_OK) {
  529.                         /* Blocked!  We can turn around, fly or climb */
  530.                         switch (rand() % 8) {
  531.                         case 0:
  532.                         case 1:
  533.                             toonList[i]->SetType(PENGUIN_FLOATER, PENGUIN_FOREWARD);
  534.                             toonList[i]->SetVelocity(rand()%5*(-toonList[i]->m_u/4),-3);
  535.                             break;
  536.                         case 2:
  537.                         case 3:
  538.  
  539.                             CheckSubType( toonList[i] );
  540.  
  541.                             if (toonList[i]->GetSubType() == TST_NORMAL_PENGUIN) {
  542.                   toonList[i]->SetType( PENGUIN_CLIMBER, toonList[i]->m_directionIndex );
  543.               } else if( toonList[i]->GetSubType() == TST_SANTA_PENGUIN ) {
  544.                                 toonList[i]->SetType( PENGUIN_SANTA_CLIMBER, toonList[i]->m_directionIndex );
  545.               } else {
  546.                                 toonList[i]->SetType( PENGUIN_CLIMBER, toonList[i]->m_directionIndex );
  547.                             }
  548.  
  549.                             toonList[i]->SetVelocity(0,-4);
  550.                             break;
  551.                         default:
  552.  
  553.                             CheckSubType( toonList[i] );
  554.  
  555.                             if( toonList[i]->GetSubType() == TST_NORMAL_PENGUIN ) {
  556.                                 toonList[i]->SetType(PENGUIN_WALKER, !toonList[i]->m_directionIndex);
  557.               } else if( toonList[i]->GetSubType() == TST_SANTA_PENGUIN ) {
  558.                                 toonList[i]->SetType( PENGUIN_SANTA_WALKER, !toonList[i]->m_directionIndex );
  559.                             }
  560.  
  561.                             toonList[i]->SetVelocity(-toonList[i]->m_u, 0);
  562.  
  563.                             break;
  564.                         }
  565.                     }
  566.                     break;
  567.                 case PENGUIN_CLIMBER:
  568.                 case PENGUIN_SANTA_CLIMBER:
  569.                     if (!toonList[i]->IsBlocked(toonList[i]->m_directionIndex)) {
  570.  
  571.                         CheckSubType( toonList[i] );
  572.  
  573.                         if( toonList[i]->GetSubType() == TST_NORMAL_PENGUIN )
  574.                         {
  575.                             toonList[i]->SetType(PENGUIN_WALKER, toonList[i]->m_directionIndex);
  576.                         }
  577.                         else if( toonList[i]->GetSubType() == TST_SANTA_PENGUIN )
  578.                         {
  579.                             toonList[i]->SetType( PENGUIN_SANTA_WALKER, toonList[i]->m_directionIndex );
  580.                         }
  581.                         else    // again, should never happen... but...
  582.                         {
  583.                             toonList[i]->SetType( PENGUIN_WALKER, toonList[i]->m_directionIndex );
  584.                         }
  585.  
  586.                         toonList[i]->SetVelocity(4*((2*toonList[i]->m_directionIndex)-1), 0);
  587.                         toonList[i]->SetPosition(toonList[i]->m_x+
  588.                                                  (2*toonList[i]->m_directionIndex)-1,
  589.                                                  toonList[i]->m_y);
  590.                         toonList[i]->m_prefd = toonList[i]->m_directionIndex;
  591.                     } else if (status != TOON_OK) {
  592.                         toonList[i]->SetType(PENGUIN_FALLER, PENGUIN_FOREWARD);
  593.                         toonList[i]->SetVelocity(1-toonList[i]->m_directionIndex*2, 3);
  594.                     }
  595.                     break;
  596.                 case PENGUIN_FLOATER:
  597.                     if (status != TOON_OK) {
  598.                         if (toonList[i]->IsBlocked(TOON_UP)) {
  599.                             toonList[i]->SetType(PENGUIN_FALLER, PENGUIN_FOREWARD);
  600.                             toonList[i]->SetVelocity(((toonList[i]->m_u > 0)*2-1), 3);
  601.                         } else {
  602.                             toonList[i]->SetVelocity(-toonList[i]->m_u, -3);
  603.                         }
  604.                     }
  605.                     break;
  606.                 default:
  607.                     break;
  608.                 }
  609.  
  610.             }
  611.  
  612.             CDC *dc = dskWnd.GetDC();
  613.             CDC bgBitmapDC, activeBmpDC, tmpDC;
  614.             
  615.             bgBitmapDC.CreateCompatibleDC(dc);
  616.             activeBmpDC.CreateCompatibleDC(dc);
  617.             tmpDC.CreateCompatibleDC(dc);
  618.             
  619.             CBitmap *oldBgBmp, *oldActiveBmp;
  620.  
  621.             oldBgBmp = bgBitmapDC.SelectObject(&bgBitmap);
  622.             oldActiveBmp = activeBmpDC.SelectObject(&activeBmp);
  623.  
  624.             for (i = 0; i < toonList.GetSize(); i++) {
  625.                 toonList[i]->PaintBackground(&bgBitmapDC, &activeBmpDC);
  626.             }
  627.  
  628.             for (i = 0; i < toonList.GetSize(); i++) {
  629.                 toonList[i]->Paint(&activeBmpDC, &tmpDC);
  630.             }
  631.  
  632.             BOOL deadToons = FALSE;
  633.             // Finally output to the desktop window
  634.             for (i = 0; i < toonList.GetSize(); i++) {
  635.                 if (!toonList[i]->m_active) deadToons = TRUE;
  636.  
  637.                 toonList[i]->PaintToDesktop(dc, &activeBmpDC);
  638.             }
  639.             
  640.             bgBitmapDC.SelectObject(oldBgBmp);
  641.             activeBmpDC.SelectObject(oldActiveBmp);
  642.  
  643.             tmpDC.DeleteDC();
  644.  
  645.             if (deadToons) {
  646.                 for (i = toonList.GetSize()-1; i >= 0; i--) {
  647.                     if (!toonList[i]->m_active) {
  648.                         toonList.RemoveAt(i);
  649.                     }
  650.                 }
  651.  
  652.             }
  653.             
  654.             dskWnd.ReleaseDC(dc);
  655.             SetToonCountTo(m_numPenguins);
  656.         }
  657.  
  658.         break;
  659.  
  660.     default:
  661.         break;
  662.     }
  663.  
  664.     CWnd::OnTimer(nIDEvent);
  665. }
  666.  
  667.  
  668. void CMainWnd::OnAbout() 
  669. {
  670.     CAboutDlg dlg;
  671.  
  672.   activeDlg = &dlg;
  673.  
  674.     (void) dlg.DoModal();    
  675.  
  676.   activeDlg = 0;
  677. }
  678.  
  679. // <TL> Thought some people might find this nice...
  680.  
  681. void CMainWnd::OnScreenCapture()
  682. {
  683.     CFileDialog dlg( FALSE, "BMP", NULL, OFN_OVERWRITEPROMPT, "Bitmap Files (*.bmp)|*.bmp||", this );
  684.  
  685.   activeDlg = &dlg;
  686.  
  687.     if( dlg.DoModal() == IDOK )    {
  688.         RECTCAPINFO rci;
  689.  
  690.         CMainWnd::OnTimer(0);    // step forward a frame to avoid messing
  691.                                 // up our pretty scenery
  692.  
  693.         ResetCaptureInfo( &rci, FALSE );
  694.  
  695.         FullScreenCapture( &rci );
  696.         SaveCaptureToFile( &rci, LPCTSTR( dlg.GetPathName() ) );
  697.         ResetCaptureInfo( &rci, TRUE );
  698.     }
  699.  
  700.   activeDlg = 0;
  701. }
  702.  
  703. // </TL>
  704.  
  705. void CMainWnd::OnExit() 
  706. {
  707.   // Remove the systray icon
  708.     NOTIFYICONDATA ni;
  709.     
  710.     ni.cbSize = sizeof(ni);
  711.     ni.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  712.     ni.uID = 0;
  713.     ni.hWnd = m_hWnd;
  714.     ni.uCallbackMessage = UWM_SYSTRAY;
  715.     strcpy(ni.szTip, "WinPenguins");
  716.     ni.hIcon = trayIcon;
  717.  
  718.     Shell_NotifyIcon(NIM_DELETE, &ni);    
  719.  
  720.     PostMessage(WM_CLOSE, 0, 0);
  721. }
  722.  
  723.  
  724. void CMainWnd::OnOptions() 
  725. {
  726.   
  727.   CWinpenguinsDlg optiondlg;
  728.  
  729.   activeDlg = &optiondlg;
  730.  
  731.      optiondlg.m_pcount = m_numPenguins;
  732.     optiondlg.m_delay = MAX_MOVE_DELAY - m_moveDelay;
  733.     optiondlg.m_splat = m_splatDist;
  734.   optiondlg.m_alpha = blendLevel;
  735.     optiondlg.m_santa = santaPercent;
  736.     optiondlg.m_soundenabled = soundEnabled;
  737.  
  738.     if (optiondlg.DoModal() == IDOK)    {
  739.         ApplyOptions(&optiondlg);
  740.  
  741.         theApp.WriteProfileInt("Options", "PenguinCount", m_numPenguins);
  742.         theApp.WriteProfileInt("Options", "MoveDelay", m_moveDelay);
  743.         theApp.WriteProfileInt("Options", "SplatDistance", m_splatDist);
  744.         theApp.WriteProfileInt("Options", "BlendLevel", blendLevel);
  745.         theApp.WriteProfileInt("Options", "SantaPercent", santaPercent);
  746.         theApp.WriteProfileInt("Options", "SoundEnabled", soundEnabled);
  747.     } else {
  748.         /* restore original values  */
  749.         m_numPenguins = theApp.GetProfileInt("Options", "PenguinCount", 5);
  750.         m_moveDelay = theApp.GetProfileInt("Options", "MoveDelay", 50);
  751.         m_splatDist = theApp.GetProfileInt("Options", "SplatDistance", 2000);
  752.         blendLevel = theApp.GetProfileInt("Options", "BlendLevel", 255);
  753.         santaPercent = theApp.GetProfileInt("Options", "SantaPercent", 0);
  754.         soundEnabled = theApp.GetProfileInt("Options", "SoundEnabled", 0);
  755.         
  756.         optiondlg.m_pcount = m_numPenguins;
  757.         optiondlg.m_delay = MAX_MOVE_DELAY - m_moveDelay;
  758.         optiondlg.m_splat = m_splatDist;
  759.     optiondlg.m_alpha = blendLevel;
  760.     optiondlg.m_santa = santaPercent;
  761.         optiondlg.m_soundenabled = soundEnabled;
  762.  
  763.         ApplyOptions(&optiondlg);
  764.     }
  765.  
  766.   activeDlg = 0;
  767. }
  768.  
  769.  
  770. void CMainWnd::SetToonCountTo(int count)
  771. {
  772.     for (int i = count - toonList.GetSize(); i > 0; i--) {
  773.         CToon *toon = new CToon();
  774.         toonList.Add(toon);
  775.     }
  776.  
  777.     if (count < toonList.GetSize()) {
  778.         for (int i = count; i < toonList.GetSize(); i++) {
  779.             toonList[i]->DeleteAni();
  780.         }
  781.     }
  782.  
  783.     if (toonList.GetSize() == 0) {
  784.         PostMessage(WM_CLOSE, 0, 0);
  785.     }
  786. }
  787.  
  788.  
  789. void CMainWnd::ApplyOptions(CWinpenguinsDlg *const dlg)
  790. {
  791.     m_numPenguins = dlg->m_pcount;
  792.     m_moveDelay = MAX_MOVE_DELAY - dlg->m_delay;
  793.     m_splatDist = dlg->m_splat;
  794.   blendLevel = dlg->m_alpha;
  795.     soundEnabled = dlg->m_soundenabled;
  796.   santaPercent = dlg->m_santa;
  797.  
  798.     // Movement timer 
  799.     KillTimer(0);
  800.     SetTimer(0, m_moveDelay, 0);
  801.  
  802.     SetToonCountTo(m_numPenguins);
  803. }
  804.  
  805.  
  806.  
  807. void CMainWnd::UpdateWndRgn()
  808. {
  809.     if (Winmon_Moved()) {
  810.         delete wndRgn;
  811.         wndRgn = NULL;
  812.  
  813.         // First find all the top level windows
  814.         ::EnumWindows(EnumWindowCallback, 0);
  815.     }
  816. }
  817.  
  818.  
  819.  
  820. void CMainWnd::UpdateBgBitmap(RECT *updateRect)
  821. {
  822.     CDC *dc = dskWnd.GetDC();
  823.     CDC bmpDc;
  824.     CBitmap *oldBmp;
  825.     
  826.     bmpDc.CreateCompatibleDC(dc);
  827.     oldBmp = bmpDc.SelectObject(&bgBitmap);
  828.  
  829.  
  830.     bmpDc.BitBlt(updateRect->left, updateRect->top, 
  831.                  updateRect->right - updateRect->left,
  832.                  updateRect->bottom - updateRect->top,
  833.                  dc, updateRect->left, updateRect->top, SRCCOPY);
  834. /*
  835.     RECT rt;
  836.     ::GetClientRect(dskWnd, &rt);
  837.     bmpDc.BitBlt(0, 0, rt.right - rt.left, rt.bottom - rt.top, dc, 0, 0, SRCCOPY);
  838. */
  839.  
  840.     bmpDc.SelectObject(oldBmp);
  841.  
  842.     dskWnd.ReleaseDC(dc);
  843. }
  844.  
  845.  
  846.  
  847.  
  848.  
  849. void CMainWnd::CreateScreenBitmaps()
  850. {
  851.     RECT rt;
  852.     CDC *dc = dskWnd.GetDC();
  853.     CDC bmpDc;
  854.  
  855.     ::GetWindowRect(dskWnd, &rt);
  856.     
  857.     bgBitmap.DeleteObject();
  858.     bgBitmap.CreateCompatibleBitmap(dc, rt.right - rt.left, rt.bottom - rt.top);
  859.  
  860.     activeBmp.DeleteObject();
  861.     activeBmp.CreateCompatibleBitmap(dc, rt.right - rt.left, rt.bottom - rt.top);
  862.  
  863.     dskWnd.ReleaseDC(dc);
  864. }
  865.  
  866.  
  867. bool CMainWnd::CheckSubType( CToon *pToon)
  868. {
  869.     if (pToon->GetSubType() == TST_UNSPECIFIED) {
  870.         if ((rand() % 100) > santaPercent) {
  871.             pToon->SetSubType(TST_NORMAL_PENGUIN);
  872.         }    else {
  873.             pToon->SetSubType(TST_SANTA_PENGUIN);
  874.         }
  875.  
  876.         return true;
  877.     }
  878.     
  879.   return false;
  880. }
  881.