Logo ROOT   6.14/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 
26 static const char *gConception[] = {
27  "Rene Brun",
28  "Fons Rademakers",
29  0
30 };
31 
32 const 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:
58 static HINSTANCE gInst = 0; // Current instance
59 static HWND gSplashWnd = 0; // Splash screen
60 static bool gShow = FALSE;
61 static DWORD gDelayVal = 0;
62 static bool gAbout = false;
63 static RECT gCreditsRect = { 115, 0, 580, 80 }; // clip rect in logo
64 static unsigned int gCreditsWidth = gCreditsRect.right - gCreditsRect.left; // credits pixmap size
65 
66 ///////////////////////////////////////////////////////////////////////////
67 /// Create a bitmap and draw alpha blended text on it.
68 
69 HBITMAP 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 
135 void 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 
169 static 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 
181 static 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 
210 void 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 
225 IStream *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 
256 IWICBitmapSource *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 
311 HBITMAP 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 
358 HBITMAP 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 
386 void DestroySplashScreen()
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 
398 LRESULT 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 
425 void 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 
439 HWND 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 
450 void 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 
502 bool 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 
525 void 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
image html pict1_TGaxis_012 png width
Define new text attributes for the label number "labNum".
Definition: TGaxis.cxx:2551
pt SetTextColor(4)
void DestroySplashScreen()
static constexpr double L
void CreateSplash(DWORD time, bool extended)
you should not use this method at all Int_t Int_t Double_t bm
Definition: TRolke.cxx:630
#define CALLBACK
Definition: TGLFaceSet.cxx:30
TText * text
#define TRUE
Double_t y[n]
Definition: legend1.C:17
#define FALSE
#define ROOT_RELEASE
Definition: RVersion.h:17