Logo ROOT   6.18/05
Reference Guide
Win32Splash.cxx
Go to the documentation of this file.
1// @(#)root/winnt:$Id$
2// Author: Bertrand Bellenot 30/07/02
3
4/*************************************************************************
5 * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#ifdef WIN32
13#include "RVersion.h"
14#include "strlcpy.h"
15#include <wincodec.h>
16#include <tchar.h>
17#include <iostream>
18#include <string>
19#define WIN32_LEAN_AND_MEAN
20#include <windows.h>
21#pragma comment(lib, "windowscodecs.lib")
22#pragma comment(lib, "msimg32.lib")
23
24#define ID_SPLASHSCREEN 25
25
26static const char *gConception[] = {
27 "Rene Brun",
28 "Fons Rademakers",
29 0
30};
31
32const char * gROOTCoreTeam[] = {
33 "Rene Brun",
34 "Fons Rademakers",
35 "Philippe Canal",
36 "Axel Naumann",
37 "Olivier Couet",
38 "Lorenzo Moneta",
39 "Vassil Vassilev",
40 "Gerardo Ganis",
41 "Bertrand Bellenot",
42 "Danilo Piparo",
43 "Wouter Verkerke",
44 "Timur Pocheptsov",
45 "Matevz Tadel",
46 "Pere Mato",
47 "Wim Lavrijsen",
48 "Ilka Antcheva",
49 "Paul Russo",
50 "Andrei Gheata",
51 "Anirudha Bose",
52 "Valeri Onuchine",
53 0
54};
55
56///////////////////////////////////////////////////////////////////////////////
57// Global Variables:
58static HINSTANCE gInst = 0; // Current instance
59static HWND gSplashWnd = 0; // Splash screen
60static bool gShow = FALSE;
61static DWORD gDelayVal = 0;
62static bool gAbout = false;
63static RECT gCreditsRect = { 115, 0, 580, 80 }; // clip rect in logo
64static unsigned int gCreditsWidth = gCreditsRect.right - gCreditsRect.left; // credits pixmap size
65
66///////////////////////////////////////////////////////////////////////////
67/// Create a bitmap and draw alpha blended text on it.
68
69HBITMAP CreateAlphaTextBitmap(LPCSTR inText, HFONT inFont, COLORREF inColour)
70{
71 int TextLength = (int)strlen(inText);
72 if (TextLength <= 0) return NULL;
73
74 // Create DC and select font into it
75 HDC hTextDC = CreateCompatibleDC(NULL);
76 HFONT hOldFont = (HFONT)SelectObject(hTextDC, inFont);
77 HBITMAP hMyDIB = NULL;
78
79 // Get text area
80 RECT TextArea = {0, 0, 0, 0};
81 DrawText(hTextDC, inText, TextLength, &TextArea, DT_CALCRECT);
82 if ((TextArea.right > TextArea.left) && (TextArea.bottom > TextArea.top)) {
83 BITMAPINFOHEADER BMIH;
84 memset(&BMIH, 0x0, sizeof(BITMAPINFOHEADER));
85 void *pvBits = NULL;
86
87 // Specify DIB setup
88 BMIH.biSize = sizeof(BMIH);
89 BMIH.biWidth = TextArea.right - TextArea.left;
90 BMIH.biHeight = TextArea.bottom - TextArea.top;
91 BMIH.biPlanes = 1;
92 BMIH.biBitCount = 32;
93 BMIH.biCompression = BI_RGB;
94
95 // Create and select DIB into DC
96 hMyDIB = CreateDIBSection(hTextDC, (LPBITMAPINFO)&BMIH, 0,
97 (LPVOID*)&pvBits, NULL, 0);
98 HBITMAP hOldBMP = (HBITMAP)SelectObject(hTextDC, hMyDIB);
99 if (hOldBMP != NULL) {
100 // Set up DC properties
101 SetTextColor(hTextDC, 0x00FFFFFF);
102 SetBkColor(hTextDC, 0x00000000);
103 SetBkMode(hTextDC, OPAQUE);
104
105 // Draw text to buffer
106 DrawText(hTextDC, inText, TextLength, &TextArea, DT_NOCLIP);
107 BYTE* DataPtr = (BYTE*)pvBits;
108 BYTE FillR = GetRValue(inColour);
109 BYTE FillG = GetGValue(inColour);
110 BYTE FillB = GetBValue(inColour);
111 BYTE ThisA;
112 for (int LoopY = 0; LoopY < BMIH.biHeight; LoopY++) {
113 for (int LoopX = 0; LoopX < BMIH.biWidth; LoopX++) {
114 ThisA = *DataPtr; // Move alpha and pre-multiply with RGB
115 *DataPtr++ = (FillB * ThisA) >> 8;
116 *DataPtr++ = (FillG * ThisA) >> 8;
117 *DataPtr++ = (FillR * ThisA) >> 8;
118 *DataPtr++ = ThisA; // Set Alpha
119 }
120 }
121 // De-select bitmap
122 SelectObject(hTextDC, hOldBMP);
123 }
124 }
125 // De-select font and destroy temp DC
126 SelectObject(hTextDC, hOldFont);
127 DeleteDC(hTextDC);
128
129 // Return DIBSection
130 return hMyDIB;
131}
132///////////////////////////////////////////////////////////////////////////
133/// Draw alpha blended text on the splash screen.
134
135void DrawAlphaText(HDC inDC, HFONT inFont, COLORREF inColor,
136 const char *text, int inX, int inY)
137{
138 RECT TextArea = {0, 0, 0, 0};
139 HBITMAP MyBMP = CreateAlphaTextBitmap(text, inFont, inColor);
140 if (MyBMP) {
141 // Create temporary DC and select new Bitmap into it
142 HDC hTempDC = CreateCompatibleDC(inDC);
143 HBITMAP hOldBMP = (HBITMAP)SelectObject(hTempDC, MyBMP);
144 if (hOldBMP) {
145 // Get Bitmap image size
146 BITMAP BMInf;
147 GetObject(MyBMP, sizeof(BITMAP), &BMInf);
148
149 // Fill blend function and blend new text to window
150 BLENDFUNCTION bf;
151 bf.BlendOp = AC_SRC_OVER;
152 bf.BlendFlags = 0;
153 bf.SourceConstantAlpha = 0xFF;
154 bf.AlphaFormat = AC_SRC_ALPHA;
155 AlphaBlend(inDC, inX, inY, BMInf.bmWidth, BMInf.bmHeight, hTempDC,
156 0, 0, BMInf.bmWidth, BMInf.bmHeight, bf);
157
158 // Clean up
159 SelectObject(hTempDC, hOldBMP);
160 DeleteObject(MyBMP);
161 DeleteDC(hTempDC);
162 }
163 }
164}
165
166////////////////////////////////////////////////////////////////////////////////
167/// Draw the ROOT version on the bottom right of the splash screen.
168
169static void DrawVersion(HDC hDC, HFONT inFont, COLORREF inColor)
170{
171 SIZE lpSize;
172 char version[256];
173 sprintf(version, "Version %s", ROOT_RELEASE);
174 GetTextExtentPoint32(hDC, version, strlen(version), &lpSize);
175 DrawAlphaText(hDC, inFont, inColor, version, 580-lpSize.cx, 400);
176}
177
178////////////////////////////////////////////////////////////////////////////////
179/// Draw credit item.
180
181static int DrawCreditItem(HDC hDC, HFONT inFont, COLORREF inColor,
182 const char *creditItem, const char **members, int y)
183{
184 char credit[1024];
185 SIZE lpSize1, lpSize2;
186 TEXTMETRIC lptm;
187 int i;
188 int lineSpacing;
189 GetTextMetrics(hDC, &lptm);
190 lineSpacing = lptm.tmAscent + lptm.tmDescent;
191 strcpy(credit, creditItem);
192 for (i = 0; members && members[i]; i++) {
193 if (i) strcat(credit, ", ");
194 GetTextExtentPoint32(hDC, credit, strlen(credit), &lpSize1);
195 GetTextExtentPoint32(hDC, members[i], strlen(members[i]), &lpSize2);
196 if((lpSize1.cx + lpSize2.cx) > (int) gCreditsWidth) {
197 DrawAlphaText(hDC, inFont, inColor, credit, gCreditsRect.left, y);
198 y += lineSpacing;
199 strcpy(credit, " ");
200 }
201 strcat(credit, members[i]);
202 }
203 DrawAlphaText(hDC, inFont, inColor, credit, gCreditsRect.left, y);
204 return y;
205}
206
207////////////////////////////////////////////////////////////////////////////////
208/// Draw the credits on the splah window.
209
210void DrawCredits(HDC hDC, HFONT inFont, COLORREF inColor)
211{
212 TEXTMETRIC lptm;
213 int lineSpacing, y;
214 GetTextMetrics(hDC, &lptm);
215 lineSpacing = lptm.tmAscent + lptm.tmDescent;
216 y = 305;
217 y = DrawCreditItem(hDC, inFont, inColor, "Conception: ", gConception, y);
218 y += 2 * lineSpacing - 4;
219 y = DrawCreditItem(hDC, inFont, inColor, "Core Engineering: ", gROOTCoreTeam, y);
220}
221
222////////////////////////////////////////////////////////////////////////////////
223/// Get a stream from the specified file name (using Windows Imaging Component).
224
225IStream *FromFile(LPCWSTR Filename)
226{
227 IWICStream *Stream = 0;
228 IWICImagingFactory *Factory = 0;
229
230#if(_WIN32_WINNT >= 0x0602) || defined(_WIN7_PLATFORM_UPDATE)
231 // WIC2 is available on Windows 8 and Windows 7 SP1 with KB 2670838 installed
232 HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory2, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&Factory));
233 if (FAILED(hr)) {
234 hr = CoCreateInstance(CLSID_WICImagingFactory1, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&Factory));
235 if (FAILED(hr)) {
236 return NULL;
237 }
238 }
239#else
240 HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&Factory));
241 if (FAILED(hr)) {
242 return NULL;
243 }
244#endif
245 if (SUCCEEDED(Factory->CreateStream(&Stream))) {
246 Stream->InitializeFromFilename(Filename, GENERIC_READ);
247 }
248 Factory->Release();
249 return Stream;
250}
251
252////////////////////////////////////////////////////////////////////////////////
253/// Loads a PNG image from the specified stream (using Windows Imaging
254/// Component).
255
256IWICBitmapSource *LoadBitmapFromStream(IStream *ipImageStream)
257{
258 // initialize return value
259 IWICBitmapSource *ipBitmap = NULL;
260
261 // load WIC's PNG decoder
262 IWICBitmapDecoder *ipDecoder = NULL;
263
264#if(_WIN32_WINNT >= 0x0602) || defined(_WIN7_PLATFORM_UPDATE)
265 // WIC2 is available on Windows 8 and Windows 7 SP1 with KB 2670838 installed
266 HRESULT hr = CoCreateInstance(CLSID_WICPngDecoder2, NULL, CLSCTX_INPROC_SERVER, __uuidof(ipDecoder), reinterpret_cast<void **>(&ipDecoder));
267 if (FAILED(hr)) {
268 hr = CoCreateInstance(CLSID_WICPngDecoder1, NULL, CLSCTX_INPROC_SERVER, __uuidof(ipDecoder), reinterpret_cast<void **>(&ipDecoder));
269 if (FAILED(hr)) {
270 return NULL;
271 }
272 }
273#else
274 HRESULT hr = CoCreateInstance(CLSID_WICPngDecoder, NULL, CLSCTX_INPROC_SERVER, __uuidof(ipDecoder), reinterpret_cast<void **>(&ipDecoder));
275 if (FAILED(hr)) {
276 return NULL;
277 }
278#endif
279 // load the PNG
280 if (FAILED(ipDecoder->Initialize(ipImageStream, WICDecodeMetadataCacheOnLoad))) {
281 ipDecoder->Release();
282 return NULL;
283 }
284 // check for the presence of the first frame in the bitmap
285 UINT nFrameCount = 0;
286
287 if (FAILED(ipDecoder->GetFrameCount(&nFrameCount)) || nFrameCount != 1) {
288 ipDecoder->Release();
289 return NULL;
290 }
291 // load the first frame (i.e., the image)
292 IWICBitmapFrameDecode *ipFrame = NULL;
293
294 if (FAILED(ipDecoder->GetFrame(0, &ipFrame))) {
295 ipDecoder->Release();
296 return NULL;
297 }
298 // convert the image to 32bpp BGRA format with pre-multiplied alpha
299 // (it may not be stored in that format natively in the PNG resource,
300 // but we need this format to create the DIB to use on-screen)
301 WICConvertBitmapSource(GUID_WICPixelFormat32bppPBGRA, ipFrame, &ipBitmap);
302 ipFrame->Release();
303
304 ipDecoder->Release();
305 return ipBitmap;
306}
307
308////////////////////////////////////////////////////////////////////////////////
309/// Create a 32-bit DIB from the specified WIC bitmap.
310
311HBITMAP CreateHBITMAP(IWICBitmapSource *ipBitmap)
312{
313 // initialize return value
314 HBITMAP hbmp = NULL;
315
316 // get image attributes and check for valid image
317 UINT width = 0;
318 UINT height = 0;
319
320 if (FAILED(ipBitmap->GetSize(&width, &height)) || width == 0 || height == 0) {
321 return hbmp;
322 }
323
324 // prepare structure giving bitmap information (negative height indicates a top-down DIB)
325 BITMAPINFO bminfo;
326 ZeroMemory(&bminfo, sizeof(bminfo));
327 bminfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
328 bminfo.bmiHeader.biWidth = width;
329 bminfo.bmiHeader.biHeight = -((LONG) height);
330 bminfo.bmiHeader.biPlanes = 1;
331 bminfo.bmiHeader.biBitCount = 32;
332 bminfo.bmiHeader.biCompression = BI_RGB;
333
334 // create a DIB section that can hold the image
335 void *pvImageBits = NULL;
336 HDC hdcScreen = GetDC(NULL);
337 hbmp = CreateDIBSection(hdcScreen, &bminfo, DIB_RGB_COLORS, &pvImageBits, NULL, 0);
338 ReleaseDC(NULL, hdcScreen);
339
340 if (hbmp == NULL) {
341 return NULL;
342 }
343 // extract the image into the HBITMAP
344 const UINT cbStride = width * 4;
345 const UINT cbImage = cbStride * height;
346
347 if (FAILED(ipBitmap->CopyPixels(NULL, cbStride, cbImage, static_cast<BYTE *>(pvImageBits)))) {
348 // couldn't extract image; delete HBITMAP
349 DeleteObject(hbmp);
350 hbmp = NULL;
351 }
352 return hbmp;
353}
354
355////////////////////////////////////////////////////////////////////////////////
356/// Loads the PNG containing the splash image into a HBITMAP.
357
358HBITMAP LoadSplashImage(LPCWSTR file_name)
359{
360 HBITMAP hbmpSplash = NULL;
361
362 // load the PNG image data into a stream
363 IStream *ipImageStream = FromFile(file_name);
364
365 if (ipImageStream == NULL) {
366 return hbmpSplash;
367 }
368 // load the bitmap with WIC
369 IWICBitmapSource *ipBitmap = LoadBitmapFromStream(ipImageStream);
370
371 if (ipBitmap == NULL) {
372 ipImageStream->Release();
373 return NULL;
374 }
375 // create a HBITMAP containing the image
376 hbmpSplash = CreateHBITMAP(ipBitmap);
377 ipBitmap->Release();
378
379 ipImageStream->Release();
380 return hbmpSplash;
381}
382
383////////////////////////////////////////////////////////////////////////////////
384/// Destroy our splash screen window.
385
387{
388 if (IsWindow(gSplashWnd)) {
389 DestroyWindow(gSplashWnd);
390 gSplashWnd = 0;
391 UnregisterClass("SplashWindow", gInst);
392 }
393}
394
395///////////////////////////////////////////////////////////////////////////
396/// Message handler for the splash screen window.
397
398LRESULT CALLBACK SplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
399{
400 switch (message) {
401 case WM_CREATE:
402 if(!gAbout)
403 SetTimer(hWnd, ID_SPLASHSCREEN, gDelayVal, 0);
404 break;
405
406 case WM_TIMER:
407 if (wParam == ID_SPLASHSCREEN) {
408 KillTimer (hWnd, ID_SPLASHSCREEN);
410 }
411 break;
412
413 case WM_DESTROY:
414 PostQuitMessage(0);
415
416 default:
417 return DefWindowProc(hWnd, message, wParam, lParam);
418 }
419 return 0;
420}
421
422///////////////////////////////////////////////////////////////////////////
423/// Registers a window class for the splash and splash owner windows.
424
425void RegisterWindowClass(HINSTANCE g_hInstance)
426{
427 WNDCLASS wc = { 0 };
428 wc.lpfnWndProc = (WNDPROC)SplashWndProc;//DefWindowProc;
429 wc.hInstance = g_hInstance;
430 //wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(_T("SPLASH")));
431 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
432 wc.lpszClassName = _T("SplashWindow");
433 RegisterClass(&wc);
434}
435
436///////////////////////////////////////////////////////////////////////////
437/// Create the splash owner window and the splash window.
438
439HWND CreateSplashWindow(HINSTANCE g_hInstance)
440{
441 return CreateWindowEx(WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
442 _T("SplashWindow"), NULL, WS_POPUP | WS_VISIBLE,
443 0, 0, 0, 0, NULL, NULL, g_hInstance, NULL);
444}
445
446///////////////////////////////////////////////////////////////////////////
447/// Call UpdateLayeredWindow to set a bitmap (with alpha) as the content of
448/// the splash window.
449
450void SetSplashImage(HWND hwndSplash, HBITMAP hbmpSplash)
451{
452 // get the size of the bitmap
453 BITMAP bm;
454 GetObject(hbmpSplash, sizeof(bm), &bm);
455 SIZE sizeSplash = { bm.bmWidth, bm.bmHeight };
456
457 // get the primary monitor's info
458 POINT ptZero = { 0 };
459 HMONITOR hmonPrimary = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
460 MONITORINFO monitorinfo = { 0 };
461 monitorinfo.cbSize = sizeof(monitorinfo);
462 GetMonitorInfo(hmonPrimary, &monitorinfo);
463
464 // center the splash screen in the middle of the primary work area
465 const RECT &rcWork = monitorinfo.rcWork;
466 POINT ptOrigin;
467 ptOrigin.x = rcWork.left + (rcWork.right - rcWork.left - sizeSplash.cx - 93) / 2;
468 ptOrigin.y = rcWork.top + (rcWork.bottom - rcWork.top - sizeSplash.cy - 104) / 2;
469
470 // create a memory DC holding the splash bitmap
471 HDC hdcScreen = GetDC(NULL);
472 HDC hdcMem = CreateCompatibleDC(hdcScreen);
473 HBITMAP hbmpOld = (HBITMAP) SelectObject(hdcMem, hbmpSplash);
474
475 // use the source image's alpha channel for blending
476 BLENDFUNCTION blend = { 0 };
477 blend.BlendOp = AC_SRC_OVER;
478 blend.SourceConstantAlpha = 255;
479 blend.AlphaFormat = AC_SRC_ALPHA;
480
481 SetBkMode(hdcMem, TRANSPARENT);
482 HFONT hFont = CreateFont(14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Arial\0");
483 HFONT hOldFont = (HFONT)SelectObject(hdcMem, hFont);
484 DrawVersion(hdcMem, hFont, RGB(255,255,255));
485 DrawCredits(hdcMem, hFont, RGB(176,210,249));
486 SelectObject(hdcMem, hOldFont);
487 DeleteObject(hFont);
488
489 // paint the window (in the right location) with the alpha-blended bitmap
490 UpdateLayeredWindow(hwndSplash, hdcScreen, &ptOrigin, &sizeSplash,
491 hdcMem, &ptZero, RGB(0, 0, 0), &blend, ULW_ALPHA);
492
493 // delete temporary objects
494 SelectObject(hdcMem, hbmpOld);
495 DeleteDC(hdcMem);
496 ReleaseDC(NULL, hdcScreen);
497}
498
499////////////////////////////////////////////////////////////////////////////////
500/// check for keybord or mouse event and destroy the splash screen accordingly.
501
502bool PreTranslateMessage(MSG* pMsg)
503{
504 if (!IsWindow(gSplashWnd))
505 return FALSE;
506
507 // If we get a keyboard or mouse message, hide the splash screen.
508 if (pMsg->message == WM_KEYDOWN ||
509 pMsg->message == WM_SYSKEYDOWN ||
510 pMsg->message == WM_LBUTTONDOWN ||
511 pMsg->message == WM_RBUTTONDOWN ||
512 pMsg->message == WM_MBUTTONDOWN ||
513 pMsg->message == WM_NCLBUTTONDOWN ||
514 pMsg->message == WM_NCRBUTTONDOWN ||
515 pMsg->message == WM_NCMBUTTONDOWN) {
517 return TRUE; // message handled here
518 }
519 return FALSE; // message not handled
520}
521
522////////////////////////////////////////////////////////////////////////////////
523/// Create our splash screen.
524
525void CreateSplash(DWORD time, bool extended)
526{
527 MSG msg;
528 gShow = FALSE;
529 if (extended) gAbout = true;
530 if (time > 0) gDelayVal = time * 1000;
531 else return;
532
533 RegisterWindowClass(gInst);
534
535 if (!_wgetenv(L"ROOTSYS")) return;
536 std::wstring RootSysDir = _wgetenv(L"ROOTSYS");
537 std::wstring splash_picture = RootSysDir + L"\\icons\\Root6Splash.png";
538 CoInitialize(0);
539 HBITMAP bkg_img = LoadSplashImage(splash_picture.c_str());
540 gSplashWnd = CreateSplashWindow(gInst);
541 SetSplashImage(gSplashWnd, bkg_img);
542 DeleteObject(bkg_img);
543 CoUninitialize();
544 // Main message loop:
545 while (GetMessage(&msg, 0, 0, 0)) {
546 PreTranslateMessage(&msg);
547 TranslateMessage(&msg);
548 DispatchMessage(&msg);
549 }
551}
552
553#endif
#define ROOT_RELEASE
Definition: RVersion.h:17
include TDocParser_001 C image html pict1_TDocParser_001 png width
Definition: TDocParser.cxx:121
#define CALLBACK
Definition: TGLFaceSet.cxx:30
void DestroySplashScreen()
void CreateSplash(DWORD time, bool extended)
#define TRUE
#define FALSE
pt SetTextColor(4)
TText * text
Double_t y[n]
Definition: legend1.C:17
static constexpr double L