Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

winsplash.cpp

Go to the documentation of this file.
00001 // winsplash.cpp
00002 //
00003 // Copyright (C) 2005, Chris Laurel <claurel@shatters.net>
00004 //
00005 // Win32 splash window
00006 //
00007 // This program is free software; you can redistribute it and/or
00008 // modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2
00010 // of the License, or (at your option) any later version.
00011 
00012 #include "winsplash.h"
00013 #include <string>
00014 #include <winuser.h>
00015 #include <commctrl.h>
00016 #include "res/resource.h"
00017 #include <iostream>
00018 
00019 using namespace std;
00020 
00021 
00022 // Required for transparent Windows, but not present in VC6 headers. Only present
00023 // on Win2k or later.
00024 typedef BOOL (WINAPI *lpfnSetLayeredWindowAttributes)
00025         (HWND hWnd, COLORREF cr, BYTE bAlpha, DWORD dwFlags);
00026 typedef BOOL (WINAPI *lpfnUpdateLayeredWindow)
00027         (HWND hwnd, HDC hdcDst, POINT* pptDst, SIZE* psize,
00028          HDC hdcSrc, POINT* pptSrc, COLORREF crKey, BLENDFUNCTION* pblend,
00029          DWORD dwFlags);
00030 
00031 lpfnSetLayeredWindowAttributes winSetLayeredWindowAttributes = NULL;
00032 lpfnUpdateLayeredWindow        winUpdateLayeredWindow = NULL;
00033 
00034 #define WS_EX_LAYERED 0x00080000 
00035 #define LWA_COLORKEY  1
00036 #define LWA_ALPHA     2
00037 
00038 #define ULW_COLORKEY  1
00039 #define ULW_ALPHA     2
00040 #define ULW_OPAQUE    4
00041 
00042 
00043 static LRESULT CALLBACK SplashWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
00044 {
00045     static SplashWindow *splash = NULL;
00046     
00047     if (uMsg == WM_CREATE)
00048     {
00049         splash = reinterpret_cast<SplashWindow*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
00050     }
00051     
00052     if (splash)
00053         return splash->windowProc(hwnd, uMsg, wParam, lParam);
00054     else
00055         return DefWindowProc(hwnd, uMsg, wParam, lParam);
00056 }
00057 
00058 
00059 SplashWindow::SplashWindow(const string& _imageFileName) :
00060     hwnd(NULL),
00061     className(NULL),
00062     imageFileName(_imageFileName),
00063     image(NULL),
00064     hBitmap(0),
00065     hCompositionBitmap(0),
00066     useLayeredWindow(false),
00067     winWidth(640),
00068     winHeight(480)
00069 {
00070     init();
00071 }
00072 
00073 
00074 SplashWindow::~SplashWindow()
00075 {
00076     if (hBitmap)
00077         ::DeleteObject(hBitmap);
00078     if (hCompositionBitmap)
00079         ::DeleteObject(hCompositionBitmap);
00080 }
00081 
00082 
00083 LRESULT CALLBACK
00084 SplashWindow::windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
00085 {
00086     switch (uMsg)
00087     {
00088         case WM_PAINT:
00089             if (!useLayeredWindow)
00090             {
00091                 PAINTSTRUCT ps;
00092                 HDC hDC = BeginPaint(hwnd, &ps);
00093                 paint(hDC);
00094                 EndPaint(hwnd, &ps);
00095             }
00096             return TRUE;            
00097     }
00098 
00099     return DefWindowProc (hwnd, uMsg, wParam, lParam) ;
00100 }
00101 
00102 
00103 void
00104 SplashWindow::paint(HDC hDC)
00105 {
00106     RECT rect;
00107     ::GetClientRect(hwnd, &rect);
00108 
00109     if (hBitmap)
00110     {
00111         // Display the splash image
00112         HDC hMemDC      = ::CreateCompatibleDC(hDC);   
00113         HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(hMemDC, hBitmap);
00114     
00115         BitBlt(hDC, 0, 0, winWidth, winHeight, hMemDC, 0, 0, SRCCOPY);
00116         
00117         ::SelectObject(hMemDC, hOldBitmap);
00118         ::DeleteDC(hMemDC);
00119         
00120         SetTextColor(hDC, RGB(255, 255, 255));
00121         SetBkMode(hDC, TRANSPARENT);        
00122     }
00123     else
00124     {
00125         // If the splash image couldn't be loaded, just paint a black background
00126         HBRUSH hbrush = CreateSolidBrush(RGB(0, 0, 0));
00127         FillRect(hDC, &rect, hbrush);
00128         DeleteObject(hbrush);        
00129     }
00130     
00131     // Show the message text
00132     RECT r;
00133     r.left   = rect.right - 250;
00134     r.top    = rect.bottom - 70;
00135     r.right  = rect.right;
00136     r.bottom = r.top + 30;
00137         
00138     HFONT hFont = reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
00139     SelectObject(hDC, hFont);
00140     
00141     string text = string("Version " VERSION_STRING "\n") + message;
00142     DrawText(hDC, text.c_str(), text.length(), &r, DT_LEFT | DT_VCENTER);
00143 }
00144 
00145 
00146 void
00147 SplashWindow::init()
00148 {
00149     hwnd = NULL;
00150     className = TEXT("CELSPLASH");
00151 
00152     //  Get the function pointer for SetLayeredWindowAttributes
00153     HMODULE user32 = GetModuleHandle(TEXT("USER32.DLL"));
00154 
00155     winSetLayeredWindowAttributes = (lpfnSetLayeredWindowAttributes) GetProcAddress(user32, "SetLayeredWindowAttributes");
00156     winUpdateLayeredWindow = (lpfnUpdateLayeredWindow) GetProcAddress(user32, "UpdateLayeredWindow");
00157     
00158     if (winSetLayeredWindowAttributes != NULL && winUpdateLayeredWindow != NULL)
00159         useLayeredWindow = true;
00160         
00161     image = LoadImageFromFile(imageFileName);    
00162 }
00163 
00164 
00165 void
00166 SplashWindow::updateWindow()
00167 {
00168     // If we're using layered windows, draw into the compositing bitmap and use it to
00169     // as the source for UpdateLayeredWindow. Otherwise, we use the traditional approach
00170     // and send a paint message to the window.
00171     if (useLayeredWindow)
00172     {
00173         HDC hwndDC = GetDC(hwnd);
00174         HDC hDC = CreateCompatibleDC(hwndDC);
00175         
00176         HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(hDC, hCompositionBitmap);
00177         paint(hDC);
00178         
00179         SIZE size;
00180         POINT origin = { 0, 0 };
00181         size.cx = winWidth;
00182         size.cy = winHeight;
00183         BLENDFUNCTION blend;
00184         blend.BlendOp = AC_SRC_OVER;
00185         blend.BlendFlags = 0;
00186         blend.AlphaFormat = AC_SRC_ALPHA;
00187         blend.SourceConstantAlpha = 0xff;
00188         winUpdateLayeredWindow(hwnd, hwndDC, NULL, &size, hDC, &origin, 0, &blend, ULW_ALPHA);
00189 
00190         ::SelectObject(hDC, hOldBitmap);
00191         ::DeleteDC(hDC);
00192     }
00193     
00194     ::UpdateWindow(hwnd);
00195 }
00196 
00197 
00198 HWND
00199 SplashWindow::createWindow()
00200 {
00201     WNDCLASSEX wndclass;
00202     wndclass.cbSize         = sizeof (wndclass);
00203     wndclass.style          = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW;
00204     wndclass.lpfnWndProc    = SplashWndProc;
00205     wndclass.cbClsExtra     = 0;
00206     wndclass.cbWndExtra     = DLGWINDOWEXTRA;
00207     wndclass.hInstance      = ::GetModuleHandle(NULL);
00208     wndclass.hIcon          = NULL;
00209     wndclass.hCursor        = ::LoadCursor( NULL, IDC_WAIT );
00210     wndclass.hbrBackground  = (HBRUSH)::GetStockObject(LTGRAY_BRUSH);
00211     wndclass.lpszMenuName   = NULL;
00212     wndclass.lpszClassName  = className;
00213     wndclass.hIconSm        = NULL;
00214 
00215     if (!RegisterClassEx(&wndclass))
00216         return NULL;
00217 
00218     if (image != NULL)
00219     {
00220         winWidth = image->getWidth();
00221         winHeight = image->getHeight();
00222     }
00223 
00224     // Create the application window centered in the middle of the screen
00225     DWORD nScrWidth  = ::GetSystemMetrics(SM_CXFULLSCREEN);
00226     DWORD nScrHeight = ::GetSystemMetrics(SM_CYFULLSCREEN);
00227 
00228     int x = (nScrWidth  - winWidth) / 2;
00229     int y = (nScrHeight - winHeight) / 2;
00230     hwnd = ::CreateWindowEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW, className, 
00231                             TEXT("Banner"), WS_POPUP, x, y, 
00232                             winWidth, winHeight, NULL, NULL, NULL, this);
00233 
00234     if (hwnd)
00235     {
00236         createBitmap();
00237         
00238         // If this version of Windows supports layered windows, set the window
00239         // style to layered.
00240         if (useLayeredWindow)
00241         {
00242             SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
00243         }
00244         
00245         ShowWindow(hwnd, SW_SHOW);
00246         updateWindow();
00247     }
00248  
00249     delete image;
00250     image = NULL;
00251  
00252     return hwnd;
00253 }
00254 
00255 
00256 bool
00257 SplashWindow::createBitmap()
00258 {
00259     if (image != NULL)
00260     {
00261         BITMAPINFO bmi;
00262         ZeroMemory(&bmi, sizeof(bmi));
00263         bmi.bmiHeader.biSize     = sizeof(BITMAPINFOHEADER);
00264         bmi.bmiHeader.biWidth    = image->getWidth();
00265         bmi.bmiHeader.biHeight   = image->getHeight();
00266         bmi.bmiHeader.biPlanes   = 1;
00267         bmi.bmiHeader.biBitCount = 32;
00268         bmi.bmiHeader.biCompression = BI_RGB;
00269         bmi.bmiHeader.biSizeImage = image->getWidth() * image->getHeight() * 4;
00270 
00271         HDC hwndDC = GetDC(hwnd);
00272         HDC hDC = CreateCompatibleDC(hwndDC);
00273         
00274         void* bmPixels = NULL;
00275         
00276         // create our DIB section and select the bitmap into the dc
00277         hBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, &bmPixels, NULL, 0x0);
00278         
00279         // Windows bitmaps are upside-down and the order of the color channels is different
00280         // than for a PNG. When copying pixels to the bitmap, we remap the color channels and
00281         // flip the image vertically.
00282         if (bmPixels != NULL)
00283         {
00284             unsigned char* src = image->getPixels();
00285             unsigned char* dst = reinterpret_cast<unsigned char*>(bmPixels);
00286             
00287             for (unsigned int i = 0; i < (unsigned int) image->getHeight(); i++)
00288             {
00289                 for (unsigned int j = 0; j < (unsigned int) image->getWidth(); j++)
00290                 {
00291                     unsigned char* srcPix = &src[4 * (image->getWidth() * (image->getHeight() - i - 1) + j)];
00292                     unsigned char* dstPix = &dst[4 * (image->getWidth() * i + j)];
00293                     
00294                     // Windows requires that we premultiply by alpha
00295                     unsigned int alpha = srcPix[3];
00296                     dstPix[0] = (unsigned char) ((srcPix[2] * alpha) / 255);
00297                     dstPix[1] = (unsigned char) ((srcPix[1] * alpha) / 255);
00298                     dstPix[2] = (unsigned char) ((srcPix[0] * alpha) / 255);
00299                     dstPix[3] = srcPix[3];
00300                 }
00301             }
00302         }
00303         
00304         DeleteDC(hDC);
00305         
00306         // Create the composition bitmap (always created, though it's only used when we've got
00307         // layered window support.)
00308         if (hBitmap)
00309         {
00310             hCompositionBitmap = CreateCompatibleBitmap(hwndDC, image->getWidth(), image->getHeight());
00311         }
00312     }
00313     
00314     return hBitmap != 0 && hCompositionBitmap != 0;
00315 }
00316 
00317 
00318 int SplashWindow::messageLoop()
00319 {
00320     if (!hwnd)
00321         showSplash();
00322 
00323     MSG msg;
00324     while (GetMessage(&msg, NULL, 0, 0))
00325     {
00326         TranslateMessage(&msg);
00327         DispatchMessage(&msg);
00328     }
00329 
00330     return msg.wParam ;
00331 }
00332 
00333 
00334 // Redraw the window with a new text message
00335 void SplashWindow::setMessage(const string& msg)
00336 {
00337     message = msg;
00338     InvalidateRect(hwnd, NULL, FALSE);
00339     updateWindow();
00340 }
00341 
00342 
00343 void SplashWindow::showSplash()
00344 {
00345     close();
00346     createWindow();
00347 }
00348 
00349 
00350 int SplashWindow::close()
00351 {
00352     
00353     if (hwnd)
00354     {
00355         DestroyWindow(hwnd);
00356         hwnd = 0;
00357         UnregisterClass(className, ::GetModuleHandle(NULL));
00358         return 1;
00359     }
00360     
00361     return 0;
00362 }

Generated on Sat Jan 14 22:30:32 2006 for Celestia by  doxygen 1.4.1