fs/rap/fsWinApp.cpp

Go to the documentation of this file.
00001 /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
00002 /*                          _______      ______    ______          __      */
00003 /*  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~    / ____(_)___ / ___ /)  / ____/___  ____/ /__    */
00004 /*     [fsWinApp]         / /_  / / __ \\__ \|/  / /   / __ \/ __  / _ \   */
00005 /*       rev. 4          / __/ / / /_/ /__/ /   / /___/ /_/ / /_/ /  __/   */
00006 /*    9th Feb 2007      /_/   /_/ ,___/____/    \____/\____/\__,_/\___/    */
00007 /*     [ ] stable              /_/ (c) 2006-7 Filip STOKLAS (FipS)         */
00008 /*  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~       http://HOLE.4FipS.com/fips_code.php          */
00009 /*                                                                         */
00010 /* This code is free for personal and commercial use. You may redistribute */
00011 /* it by any means. If you use the code for your own projects please give  */
00012 /* me credit. Please send a bug report. Don't alter or remove this header! */
00013 /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
00018 //---------------------------------------------------------------------------
00034 //---------------------------------------------------------------------------
00035 #include <fs/rap/fsWinApp.h>
00036 
00037 // >>> COMMON SUPPORT BLOCK (rev. 6)
00038 #if defined(FS_HAS_FSASSERT)
00039 #   include <fs/sys/fsAssert.h>
00040 #else
00041 #   include <cassert>
00042 #   if !defined(FS_ASSERT)
00043 #       define FS_ASSERT(exp) assert(exp)
00044 #   endif
00045 #   if !defined(FS_ASSERT_MSG)
00046 #       define FS_ASSERT_MSG(exp, msg) assert(exp && msg)
00047 #   endif
00048 #   if !defined(FS_VERIFY)
00049 #       define FS_VERIFY(exp) \
00050         { bool bExp = !!(exp); assert(bExp && #exp); bExp; }
00051 #   endif
00052 #   if !defined(FS_VERIFY_MSG)
00053 #       define FS_VERIFY_MSG(exp, msg) \
00054         { bool bExp = !!(exp); assert(bExp && #exp && msg); bExp; }
00055 #   endif
00056 #   if !defined(FS_STATIC_ASSERT)
00057 #       define FS_STATIC_ASSERT(exp) { char error[(exp) ? 1 : 0]; error; }
00058 #   endif
00059 #endif
00060 #if !defined(FS_VERIFY_RETURN)
00061 #   define FS_VERIFY_RETURN(exp) \
00062     if(!(exp)) { FS_ASSERT_MSG(0, #exp "<return>"); return; }
00063 #endif
00064 #if !defined(FS_VERIFY_RETURN_VAL)
00065 #   define FS_VERIFY_RETURN_VAL(exp, ret) \
00066     if(!(exp)) { FS_ASSERT_MSG(0, #exp "<returns:>" #ret); return (ret); }
00067 #endif
00068 // <<< COMMON SUPPORT BLOCK (rev. 6)
00069 
00070 #include <vector>
00071 #include <windows.h>
00072 
00073 // provide detailed memory tracking information
00074 #if defined(FS_HAS_FSMEMMGR)
00075 #   include <fs/sys/fsMemMgr.h>
00076 #endif
00077 //---------------------------------------------------------------------------
00078 using namespace fs::rap;
00079 //---------------------------------------------------------------------------
00080 namespace fs { namespace rap {
00081 //---------------------------------------------------------------------------
00082 WinApp_t & WinAppInst()
00083 {
00084     static WinApp_t Inst;
00085     return Inst;
00086 }
00087 //---------------------------------------------------------------------------
00088 }} // namespace fs::rap
00089 //---------------------------------------------------------------------------
00090 //--- ANONYMOUS NAMESPACE >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
00091 //---------------------------------------------------------------------------
00092 namespace {
00093 //---------------------------------------------------------------------------
00094 WinApp_t::InitCfg_t g_Cfg;
00095 const char *g_pszCmdLine = 0;
00096 HWND g_hWnd = 0; 
00097 int g_nMouseX = 0, g_nMouseY = 0;
00098 typedef std::vector<WinApp_t::EvRcvr_i *> TEvRcvrs;
00099 TEvRcvrs g_EvRcvrs; 
00100 bool g_bIgnSysEvs = true; 
00101 //---------------------------------------------------------------------------
00102 template <typename T>
00103 void Send(T &Event)
00104 {
00105     for(size_t i = 0; i < g_EvRcvrs.size(); ++i)
00106         g_EvRcvrs[i]->OnEvent(Event, WinAppInst());
00107 }
00108 //---------------------------------------------------------------------------
00109 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
00110 {
00111     if(g_bIgnSysEvs)
00112         return ::DefWindowProc(hWnd, msg, wParam, lParam);
00113 
00114     switch(msg)
00115     {
00116         case WM_MOUSEMOVE:
00117         {
00118             g_nMouseX = LOWORD(lParam);
00119             g_nMouseY = HIWORD(lParam);
00120             const WinApp_t::MouseEv_t MouseEv(g_nMouseX, g_nMouseY);
00121             
00122             Send(MouseEv);
00123             
00124             break;
00125         }
00126         case WM_PAINT:
00127         {
00128             const WinApp_t::DrawEv_t DrawEv;
00129             Send(DrawEv);
00130             
00131             // validate the whole cl. rect, prevent from recur. WM_PAINT
00132             ::ValidateRect(hWnd, 0);
00133             
00134             break;
00135         }
00136         case WM_KEYDOWN:
00137         {
00138             const WinApp_t::KeyEv_t KeyEv
00139              (static_cast<int>(wParam), true, g_nMouseX, g_nMouseY);
00140              
00141             Send(KeyEv);
00142                 
00143             break;
00144         }
00145         case WM_KEYUP:
00146         {
00147             const WinApp_t::KeyEv_t KeyEv
00148              (static_cast<int>(wParam), false, g_nMouseX, g_nMouseY);
00149              
00150             Send(KeyEv);
00151                 
00152             break;
00153         }
00154         case WM_LBUTTONDOWN:
00155         {
00156             const WinApp_t::KeyEv_t KeyEv
00157              (WinApp_t::KeyEv_t::KEY_LMBTN, true, g_nMouseX, g_nMouseY);
00158              
00159             Send(KeyEv);
00160                 
00161             break;
00162         }
00163         case WM_LBUTTONUP:
00164         {
00165             const WinApp_t::KeyEv_t KeyEv
00166              (WinApp_t::KeyEv_t::KEY_LMBTN, false, g_nMouseX, g_nMouseY);
00167              
00168             Send(KeyEv);
00169                 
00170             break;
00171         }
00172         case WM_SYSCHAR: // Alt + KEY
00173         {
00174             if(wParam == VK_RETURN)
00175             {
00176                 WinAppInst().Fscrn(!g_Cfg.m_bFscrn);
00177             }
00178             break;
00179         }
00180         case WM_SIZE:
00181         {
00182             if(!g_Cfg.m_bFscrn)
00183             {
00184                 g_Cfg.m_nClW = LOWORD(lParam);
00185                 g_Cfg.m_nClH = HIWORD(lParam);
00186             }
00187         
00188             const WinApp_t::SizeEv_t SizeEv(LOWORD(lParam), HIWORD(lParam));
00189              
00190             Send(SizeEv);
00191                 
00192             break;
00193         }
00194         case WM_CLOSE:
00195         {
00196             WinAppInst().Quit();
00197             
00198             break;
00199         }
00200             
00201         default:
00202             return ::DefWindowProc(hWnd, msg, wParam, lParam);
00203     };
00204 
00205     return 0;
00206 }
00207 //---------------------------------------------------------------------------
00208 void GetWinStyles(const WinApp_t::InitCfg_t &Cfg, DWORD &dwStyle, DWORD
00209  &dwExStyle)
00210 {
00211     if(Cfg.m_bFscrn)
00212     {
00213         dwStyle = WS_POPUP;
00214         dwExStyle = WS_EX_APPWINDOW;
00215     }
00216     else
00217     {
00218         dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
00219                                 
00220         if(!Cfg.m_bSzbl)
00221         {
00222             dwStyle &= ~WS_MAXIMIZEBOX;
00223             dwStyle &= ~WS_SIZEBOX;
00224         }
00225         
00226         dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
00227     }
00228 }
00229 //---------------------------------------------------------------------------
00231 void GetDeskSize(int &nDeskW, int &nDeskH)
00232 {
00233     const HWND hWnd = ::GetDesktopWindow();
00234     FS_ASSERT(hWnd);
00235     
00236     RECT rc;
00237     ::GetWindowRect(hWnd, &rc);
00238     
00239     nDeskW = rc.right - rc.left;
00240     nDeskH = rc.bottom - rc.top;
00241 }
00242 //---------------------------------------------------------------------------
00243 void CalcClientRect(const WinApp_t::InitCfg_t &Cfg, RECT &rcCl)
00244 {
00245     // full-screen mode - fill the screen
00246     if(Cfg.m_bFscrn)
00247     {
00248         rcCl.left = 0;
00249         rcCl.top = 0;
00250     
00251         // user - change of the screen resolution is assumed
00252         if(Cfg.m_nFscrnW > 0 && Cfg.m_nFscrnH)
00253         {
00254             rcCl.right = Cfg.m_nFscrnW;
00255             rcCl.bottom = Cfg.m_nFscrnH;
00256         }
00257         // same as the desktop
00258         else
00259         {
00260             int nDeskW, nDeskH;
00261             GetDeskSize(nDeskW, nDeskH);
00262         
00263             rcCl.right = nDeskW;
00264             rcCl.bottom = nDeskH;
00265         }
00266     }
00267     // window mode - center the window
00268     else
00269     {
00270         int nDeskW, nDeskH;
00271         GetDeskSize(nDeskW, nDeskH);
00272         
00273         rcCl.left = nDeskW / 2 - Cfg.m_nClW / 2;
00274         rcCl.top = nDeskH / 2 - Cfg.m_nClH / 2;
00275         rcCl.right = rcCl.left + Cfg.m_nClW;
00276         rcCl.bottom = rcCl.top + Cfg.m_nClH;
00277     }
00278 }
00279 //---------------------------------------------------------------------------
00280 void CalcWinRect(const WinApp_t::InitCfg_t &Cfg, RECT &rcWin)
00281 {
00282     // get the styles
00283     DWORD dwStyle, dwExStyle;
00284     GetWinStyles(Cfg, dwStyle, dwExStyle);
00285     
00286     // get the client rectangle
00287     CalcClientRect(Cfg, rcWin);
00288     
00289     // convert client to window rectangle
00290     ::AdjustWindowRectEx(&rcWin, dwStyle, FALSE, dwExStyle);
00291 }
00292 //---------------------------------------------------------------------------
00293 HWND CreateWin(const WinApp_t::InitCfg_t &Cfg)
00294 {
00295     //---
00296 
00297     // get the window styles based on the config
00298     DWORD dwStyle, dwExStyle;
00299     GetWinStyles(Cfg, dwStyle, dwExStyle);
00300     
00301     // get the window rectangle based on the config
00302     RECT rcWin;
00303     CalcWinRect(Cfg, rcWin);
00304 
00305     //---
00306     
00307     const HINSTANCE hInst = ::GetModuleHandle(0);
00308     FS_ASSERT(hInst);
00309             
00310     WNDCLASS wc;
00311 
00312     wc.style         = CS_HREDRAW | CS_VREDRAW;
00313     wc.lpfnWndProc   = (WNDPROC)WndProc;
00314     wc.cbClsExtra    = 0;
00315     wc.cbWndExtra    = 0;
00316     wc.hInstance     = hInst;
00317     wc.hIcon         = 0;
00318     wc.hCursor       = 0;
00319     wc.hbrBackground = Cfg.m_bClrBgr?(HBRUSH)::GetStockObject(BLACK_BRUSH):0;
00320     wc.lpszMenuName  = 0;
00321     wc.lpszClassName = TEXT("FS_RAP_WINAPP");
00322     
00323     if(!::RegisterClass(&wc))
00324     {
00325         FS_ASSERT_MSG(0, "Could not register application window class!");
00326         return false;
00327     }
00328     
00329     //---
00330 
00331     HWND hWnd = ::CreateWindowEx(
00332      dwExStyle,
00333      TEXT("FS_RAP_WINAPP"),
00334      TEXT("FS_RAP_WINAPP"),
00335      dwStyle,
00336      rcWin.left,
00337      rcWin.top,
00338      rcWin.right - rcWin.left,
00339      rcWin.bottom - rcWin.top,
00340      0,
00341      0,
00342      hInst,
00343      0
00344     );
00345 
00346     if(!hWnd)
00347     {
00348         FS_ASSERT_MSG(g_hWnd, "Could not create application window!");
00349         return false;
00350     }
00351     
00352     //---
00353     
00354     return hWnd;
00355 }
00356 //---------------------------------------------------------------------------
00357 } // anonymous namespace
00358 //---------------------------------------------------------------------------
00359 //--- GLOBAL NAMESPACE >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
00360 //---------------------------------------------------------------------------
00361 int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR pszCmdLine, int)
00362 {
00363     g_pszCmdLine = pszCmdLine;
00364     FS_ASSERT(g_pszCmdLine);
00365     
00366     //---
00367         
00368     // user initialization
00369     if(!WinAppInit(WinAppInst(), g_Cfg))
00370         return 0;
00371     
00372     // system initialization
00373     g_hWnd = CreateWin(g_Cfg);
00374     if(!g_hWnd)
00375         return 0;
00376     
00377     //--- INIT SEQUENCE --- title -> INIT -> SIZE -> show -> (DRAW)
00378     
00379     // set the title of the window
00380     WinAppInst().SetTitle(g_Cfg.m_pszTitle);
00381         
00382     // send the 'Init' event
00383     const WinApp_t::InitEv_t InitEv;
00384     Send(InitEv);
00385     
00386     // send the 'Size' event
00387     RECT rcCl;
00388     ::GetClientRect(g_hWnd, &rcCl);
00389     const WinApp_t::SizeEv_t SizeEv
00390      (rcCl.right - rcCl.left, rcCl.bottom - rcCl.top);
00391     Send(SizeEv);
00392                             
00393     // show the window (invokes the 'Draw' event)
00394     ::ShowWindow(g_hWnd, SW_SHOW);
00395         
00396     g_bIgnSysEvs = false;
00397     
00398     //---
00399             
00400     if(g_Cfg.m_bRtm)
00401     {
00402         for(;;)
00403         {
00404             MSG msg;
00405             // note: WM_PAINT is not removed from the queue!
00406             while(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
00407             {
00408                 if(msg.message == WM_QUIT)
00409                     return static_cast<int>(msg.wParam);
00410 
00411                 ::TranslateMessage(&msg);
00412                 ::DispatchMessage(&msg);
00413             }
00414             
00415             // do the real-time stuff here...
00416             const WinApp_t::RunEv_t RunEv;
00417             Send(RunEv);
00418         }
00419     }
00420     else
00421     {
00422         MSG msg;    
00423         while(::GetMessage(&msg, 0, 0, 0))
00424         {
00425             ::TranslateMessage(&msg);
00426             ::DispatchMessage(&msg);
00427         }
00428         
00429         // ::GetMessage has reached WM_QUIT message
00430         return static_cast<int>(msg.wParam);
00431     }
00432 }
00433 //---------------------------------------------------------------------------
00434 //--- CLASS WinApp_t >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
00435 //---------------------------------------------------------------------------
00436 bool WinApp_t::IsValid() const
00437 {
00438     return g_hWnd ? true : false;
00439 }
00440 //---------------------------------------------------------------------------
00441 const char * WinApp_t::GetCmdLine() const
00442 {
00443     FS_ASSERT(g_pszCmdLine);
00444     
00445     return g_pszCmdLine;
00446 }
00447 //---------------------------------------------------------------------------
00448 void WinApp_t::SetTitle(const char *pszTitle)
00449 {
00450     FS_VERIFY_RETURN(IsValid());
00451     FS_VERIFY_RETURN(pszTitle);
00452     FS_ASSERT(g_hWnd);
00453     
00454     ::SetWindowTextA(g_hWnd, pszTitle);
00455 }
00456 //---------------------------------------------------------------------------
00457 void WinApp_t::Redraw()
00458 {
00459     FS_VERIFY_RETURN(IsValid());
00460 
00461     // invalidate the whole client rect, invokes WM_PAINT in the future
00462     FS_ASSERT(g_hWnd);
00463     ::InvalidateRect(g_hWnd, 0, true);
00464 }
00465 //---------------------------------------------------------------------------
00466 void WinApp_t::Fscrn(bool bOn)
00467 {
00468     FS_VERIFY_RETURN(IsValid());
00469 
00470     // modify the global config
00471     g_Cfg.m_bFscrn = bOn;
00472     
00473     //---
00474     
00475     // get the window styles based on the config
00476     DWORD dwStyle, dwExStyle;
00477     GetWinStyles(g_Cfg, dwStyle, dwExStyle);
00478     
00479     // get the window rectangle based on the config
00480     RECT rcWin;
00481     CalcWinRect(g_Cfg, rcWin);
00482     
00483     //---
00484     
00485     FS_ASSERT(g_hWnd);
00486     
00487     // modify window styles (is it safe to overwrite the states completely?)
00488     FS_VERIFY(::SetWindowLongPtr(g_hWnd, GWL_STYLE, dwStyle));
00489     FS_VERIFY(::SetWindowLongPtr(g_hWnd, GWL_EXSTYLE, dwExStyle));
00490         
00491     // modify window rectangle
00492     FS_VERIFY(::SetWindowPos(
00493      g_hWnd,
00494      0,
00495      rcWin.left, rcWin.top,
00496      rcWin.right - rcWin.left, rcWin.bottom - rcWin.top,
00497      SWP_SHOWWINDOW
00498     ));
00499             
00500     // redraw the desktop (it seems to be necessary)
00501     if(!g_Cfg.m_bFscrn) // return from the full-screen
00502     {
00503         const HWND hDeskWnd = ::GetDesktopWindow();
00504         FS_ASSERT(hDeskWnd);
00505         ::RedrawWindow(
00506          hDeskWnd, 0, 0,
00507          RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN
00508         );
00509     }
00510 }
00511 //---------------------------------------------------------------------------
00512 void WinApp_t::Quit()
00513 {
00514     FS_VERIFY_RETURN(IsValid());
00515 
00516     const WinApp_t::QuitEv_t QuitEv;
00517     Send(QuitEv);
00518 
00519     ::PostQuitMessage(0);
00520 }
00521 //---------------------------------------------------------------------------
00522 void * WinApp_t::GetWinHdle() const
00523 {
00524     FS_VERIFY_RETURN_VAL(IsValid(), 0);
00525     FS_ASSERT(g_hWnd);
00526     
00527     return g_hWnd;
00528 }
00529 //---------------------------------------------------------------------------
00530 void WinApp_t::RegEvRcvr(EvRcvr_i *pEvRcvr)
00531 {
00532     FS_VERIFY_RETURN(pEvRcvr);
00533     
00534     g_EvRcvrs.push_back(pEvRcvr);
00535 }
00536 //---------------------------------------------------------------------------

FipS' Code (Thu Feb 15 22:43:35 2007) - (c) Filip STOKLAS (FipS) - [ www ] [ Guest Book ]