1 /* 2 * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 // copy from awt.h 27 #ifndef _WIN32_WINNT 28 #define _WIN32_WINNT 0x0600 29 #endif 30 31 // copy from awt.h 32 #ifndef _WIN32_IE 33 #define _WIN32_IE 0x0600 34 #endif 35 36 #include "splashscreen_impl.h" 37 #include <windowsx.h> 38 #include <windows.h> 39 #include <winuser.h> 40 #include "sizecalc.h" 41 42 #ifndef WS_EX_LAYERED 43 #define WS_EX_LAYERED 0x80000 44 #endif 45 46 #ifndef ULW_ALPHA 47 #define ULW_ALPHA 0x00000002 48 #endif 49 50 #ifndef AC_SRC_OVER 51 #define AC_SRC_OVER 0x00 52 #endif 53 54 #ifndef AC_SRC_ALPHA 55 #define AC_SRC_ALPHA 0x01 56 #endif 57 58 #define WM_SPLASHUPDATE WM_USER+1 59 #define WM_SPLASHRECONFIGURE WM_USER+2 60 61 #define BUFF_SIZE 1024 62 63 /* Could use npt but decided to cut down on linked code size */ 64 char* SplashConvertStringAlloc(const char* in, int *size) { 65 int len, outChars, rc; 66 WCHAR* buf; 67 if (!in) { 68 return NULL; 69 } 70 len = strlen(in); 71 outChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, in, len, 72 NULL, 0); 73 buf = (WCHAR*) SAFE_SIZE_ARRAY_ALLOC(malloc, outChars, sizeof(WCHAR)); 74 if (!buf) { 75 return NULL; 76 } 77 rc = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, in, len, 78 buf, outChars); 79 if (rc==0) { 80 free(buf); 81 return NULL; 82 } else { 83 if (size) { 84 *size = rc; 85 } 86 return (char*)buf; 87 } 88 } 89 90 unsigned 91 SplashTime(void) 92 { 93 return GetTickCount(); 94 } 95 96 void 97 SplashInitFrameShape(Splash * splash, int imageIndex) 98 { 99 RGNDATA *pRgnData; 100 RGNDATAHEADER *pRgnHdr; 101 ImageRect maskRect; 102 103 if (!splash->maskRequired) 104 return; 105 106 /* reserving memory for the worst case */ 107 if (!IS_SAFE_SIZE_MUL(splash->width / 2 + 1, splash->height)) { 108 return; 109 } 110 pRgnData = (RGNDATA *) SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(RGNDATAHEADER), 111 sizeof(RECT), (splash->width / 2 + 1) * splash->height); 112 if (!pRgnData) { 113 return; 114 } 115 pRgnHdr = (RGNDATAHEADER *) pRgnData; 116 initRect(&maskRect, 0, 0, splash->width, splash->height, 1, 117 splash->width * splash->imageFormat.depthBytes, 118 splash->frames[imageIndex].bitmapBits, &splash->imageFormat); 119 120 pRgnHdr->dwSize = sizeof(RGNDATAHEADER); 121 pRgnHdr->iType = RDH_RECTANGLES; 122 pRgnHdr->nRgnSize = 0; 123 pRgnHdr->rcBound.top = 0; 124 pRgnHdr->rcBound.left = 0; 125 pRgnHdr->rcBound.bottom = splash->height; 126 pRgnHdr->rcBound.right = splash->width; 127 128 pRgnHdr->nCount = BitmapToYXBandedRectangles(&maskRect, 129 (RECT *) (((BYTE *) pRgnData) + sizeof(RGNDATAHEADER))); 130 131 splash->frames[imageIndex].hRgn = ExtCreateRegion(NULL, 132 sizeof(RGNDATAHEADER) + sizeof(RECT) * pRgnHdr->nCount, pRgnData); 133 134 free(pRgnData); 135 } 136 137 /* paint current splash screen frame to hdc 138 this function is unused in layered window mode */ 139 140 void 141 SplashPaint(Splash * splash, HDC hdc) 142 { 143 unsigned numColors = splash->screenFormat.colorMap ? 144 splash->screenFormat.numColors : 0; 145 BITMAPV4HEADER *pBmi; 146 HPALETTE hOldPal = NULL; 147 148 if (!splash->frames) 149 return; 150 if (splash->currentFrame < 0 || splash->currentFrame >= splash->frameCount) 151 return; 152 pBmi = (BITMAPV4HEADER *) SAFE_SIZE_STRUCT_ALLOC(alloca, sizeof(BITMAPV4HEADER), 153 sizeof(RGBQUAD), numColors); 154 if (!pBmi) { 155 return; 156 } 157 memset(pBmi, 0, sizeof(BITMAPV4HEADER)); 158 if (splash->screenFormat.colorMap) 159 memcpy(((BYTE *) pBmi) + sizeof(BITMAPV4HEADER), 160 splash->screenFormat.colorMap, sizeof(RGBQUAD) * numColors); 161 162 pBmi->bV4Size = sizeof(BITMAPV4HEADER); 163 pBmi->bV4Width = splash->width; 164 pBmi->bV4Height = -splash->height; 165 pBmi->bV4Planes = 1; 166 pBmi->bV4BitCount = (WORD) (splash->screenFormat.depthBytes * 8); 167 /* we're ALWAYS using BGRA in screenFormat */ 168 pBmi->bV4V4Compression = BI_RGB; 169 pBmi->bV4ClrUsed = numColors; 170 pBmi->bV4ClrImportant = numColors; 171 pBmi->bV4AlphaMask = splash->screenFormat.mask[3]; 172 pBmi->bV4RedMask = splash->screenFormat.mask[2]; 173 pBmi->bV4GreenMask = splash->screenFormat.mask[1]; 174 pBmi->bV4BlueMask = splash->screenFormat.mask[0]; 175 176 /* creating the palette in SplashInitPlatform does not work, so I'm creating it 177 here on demand */ 178 if (!splash->hPalette) { 179 unsigned i; 180 LOGPALETTE *pLogPal = (LOGPALETTE *) SAFE_SIZE_STRUCT_ALLOC(malloc, 181 sizeof(LOGPALETTE), sizeof(PALETTEENTRY), numColors); 182 if (!pLogPal) { 183 return; 184 } 185 186 pLogPal->palVersion = 0x300; 187 pLogPal->palNumEntries = (WORD) numColors; 188 for (i = 0; i < numColors; i++) { 189 pLogPal->palPalEntry[i].peRed = (BYTE) 190 QUAD_RED(splash->colorMap[i]); 191 pLogPal->palPalEntry[i].peGreen = (BYTE) 192 QUAD_GREEN(splash->colorMap[i]); 193 pLogPal->palPalEntry[i].peBlue = (BYTE) 194 QUAD_BLUE(splash->colorMap[i]); 195 pLogPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE; 196 } 197 splash->hPalette = CreatePalette(pLogPal); 198 free(pLogPal); 199 } 200 if (splash->hPalette) { 201 hOldPal = SelectPalette(hdc, splash->hPalette, FALSE); 202 RealizePalette(hdc); 203 } 204 205 StretchDIBits(hdc, 0, 0, splash->width, splash->height, 0, 0, 206 splash->width, splash->height, splash->screenData, 207 (BITMAPINFO *) pBmi, DIB_RGB_COLORS, SRCCOPY); 208 if (hOldPal) 209 SelectPalette(hdc, hOldPal, FALSE); 210 } 211 212 213 /* The function makes the window visible if it is hidden 214 or is not yet shown. */ 215 void 216 SplashRedrawWindow(Splash * splash) 217 { 218 if (!SplashIsStillLooping(splash)) { 219 KillTimer(splash->hWnd, 0); 220 } 221 222 if (splash->currentFrame < 0) { 223 return; 224 } 225 226 SplashUpdateScreenData(splash); 227 if (splash->isLayered) { 228 BLENDFUNCTION bf; 229 POINT ptSrc; 230 HDC hdcSrc = CreateCompatibleDC(NULL), hdcDst; 231 BITMAPINFOHEADER bmi; 232 void *bitmapBits; 233 HBITMAP hBitmap, hOldBitmap; 234 RECT rect; 235 POINT ptDst; 236 SIZE size; 237 238 bf.BlendOp = AC_SRC_OVER; 239 bf.BlendFlags = 0; 240 bf.AlphaFormat = AC_SRC_ALPHA; 241 bf.SourceConstantAlpha = 0xFF; 242 ptSrc.x = ptSrc.y = 0; 243 244 memset(&bmi, 0, sizeof(bmi)); 245 bmi.biSize = sizeof(BITMAPINFOHEADER); 246 bmi.biWidth = splash->width; 247 bmi.biHeight = -splash->height; 248 bmi.biPlanes = 1; 249 bmi.biBitCount = 32; 250 bmi.biCompression = BI_RGB; 251 252 // FIXME: this is somewhat ineffective 253 // maybe if we allocate memory for all frames as DIBSections, 254 // then we could select the frames into the DC directly 255 256 hBitmap = CreateDIBSection(NULL, (BITMAPINFO *) & bmi, DIB_RGB_COLORS, 257 &bitmapBits, NULL, 0); 258 memcpy(bitmapBits, splash->screenData, 259 splash->screenStride * splash->height); 260 hOldBitmap = (HBITMAP) SelectObject(hdcSrc, hBitmap); 261 hdcDst = GetDC(splash->hWnd); 262 263 GetWindowRect(splash->hWnd, &rect); 264 265 ptDst.x = rect.left; 266 ptDst.y = rect.top; 267 268 size.cx = splash->width; 269 size.cy = splash->height; 270 271 UpdateLayeredWindow(splash->hWnd, hdcDst, &ptDst, &size, 272 hdcSrc, &ptSrc, 0, &bf, ULW_ALPHA); 273 274 ReleaseDC(splash->hWnd, hdcDst); 275 SelectObject(hdcSrc, hOldBitmap); 276 DeleteObject(hBitmap); 277 DeleteDC(hdcSrc); 278 } 279 else { 280 InvalidateRect(splash->hWnd, NULL, FALSE); 281 if (splash->maskRequired) { 282 HRGN hRgn = CreateRectRgn(0, 0, 0, 0); 283 284 CombineRgn(hRgn, splash->frames[splash->currentFrame].hRgn, 285 splash->frames[splash->currentFrame].hRgn, RGN_COPY); 286 SetWindowRgn(splash->hWnd, hRgn, TRUE); 287 } else { 288 SetWindowRgn(splash->hWnd, NULL, TRUE); 289 } 290 UpdateWindow(splash->hWnd); 291 } 292 if (!IsWindowVisible(splash->hWnd)) { 293 POINT cursorPos; 294 ShowWindow(splash->hWnd, SW_SHOW); 295 // Windows won't update the cursor after the window is shown, 296 // if the cursor is already above the window. need to do this manually. 297 GetCursorPos(&cursorPos); 298 if (WindowFromPoint(cursorPos) == splash->hWnd) { 299 // unfortunately Windows fail to understand that the window 300 // thread should own the cursor, even though the mouse pointer 301 // is over the window, until the mouse has been moved. 302 // we're using SetCursorPos here to fake the mouse movement 303 // and enable proper update of the cursor. 304 SetCursorPos(cursorPos.x, cursorPos.y); 305 SetCursor(LoadCursor(NULL, IDC_WAIT)); 306 } 307 } 308 if (SplashIsStillLooping(splash)) { 309 int time = splash->time + 310 splash->frames[splash->currentFrame].delay - SplashTime(); 311 312 if (time < 0) 313 time = 0; 314 SetTimer(splash->hWnd, 0, time, NULL); 315 } 316 } 317 318 void SplashReconfigureNow(Splash * splash) { 319 splash->x = (GetSystemMetrics(SM_CXSCREEN) - splash->width) / 2; 320 splash->y = (GetSystemMetrics(SM_CYSCREEN) - splash->height) / 2; 321 if (splash->hWnd) { 322 //Fixed 6474657: splash screen image jumps towards left while 323 // setting the new image using setImageURL() 324 // We may safely hide the splash window because SplashRedrawWindow() 325 // will show the window again. 326 ShowWindow(splash->hWnd, SW_HIDE); 327 MoveWindow(splash->hWnd, splash->x, splash->y, splash->width, splash->height, FALSE); 328 } 329 SplashRedrawWindow(splash); 330 } 331 332 static LRESULT CALLBACK 333 SplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 334 { 335 PAINTSTRUCT ps; 336 HDC hdc; 337 338 339 switch (message) { 340 341 case WM_ERASEBKGND: 342 return TRUE; // to avoid flicker 343 344 case WM_SYSCOMMAND: 345 if (wParam==SC_CLOSE||wParam==SC_DEFAULT||wParam==SC_HOTKEY|| 346 wParam==SC_KEYMENU||wParam==SC_MAXIMIZE|| 347 wParam==SC_MINIMIZE||wParam==SC_MOUSEMENU||wParam==SC_MOVE|| 348 wParam==SC_RESTORE||wParam==SC_SIZE) 349 { 350 return 0; 351 } 352 353 /* double switch to avoid prologue/epilogue duplication */ 354 case WM_TIMER: 355 case WM_SPLASHUPDATE: 356 case WM_PAINT: 357 case WM_SPLASHRECONFIGURE: 358 { 359 Splash *splash = (Splash *) GetWindowLongPtr(hWnd, GWLP_USERDATA); 360 361 SplashLock(splash); 362 if (splash->isVisible>0) { 363 switch(message) { 364 case WM_TIMER: 365 SplashNextFrame(splash); 366 SplashRedrawWindow(splash); 367 break; 368 case WM_SPLASHUPDATE: 369 SplashRedrawWindow(splash); 370 break; 371 case WM_PAINT: 372 hdc = BeginPaint(hWnd, &ps); 373 SplashPaint(splash, hdc); 374 EndPaint(hWnd, &ps); 375 break; 376 case WM_SPLASHRECONFIGURE: 377 SplashReconfigureNow(splash); 378 break; 379 } 380 } 381 SplashUnlock(splash); 382 break; 383 } 384 case WM_DESTROY: 385 PostQuitMessage(0); 386 break; 387 default: 388 return DefWindowProc(hWnd, message, wParam, lParam); 389 390 } 391 return 0; 392 } 393 394 HWND 395 SplashCreateWindow(Splash * splash) 396 { 397 WNDCLASSEX wcex; 398 ATOM wndClass; 399 DWORD style, exStyle; 400 HWND hWnd; 401 402 ZeroMemory(&wcex, sizeof(WNDCLASSEX)); 403 404 wcex.cbSize = sizeof(WNDCLASSEX); 405 wcex.style = CS_HREDRAW | CS_VREDRAW; 406 wcex.lpfnWndProc = (WNDPROC) SplashWndProc; 407 wcex.hInstance = GetModuleHandle(NULL); 408 wcex.lpszClassName = "JavaSplash"; 409 wcex.hCursor = LoadCursor(NULL, IDC_WAIT); 410 411 wndClass = RegisterClassEx(&wcex); 412 if (!wndClass) { 413 return 0; 414 } 415 416 splash->x = (GetSystemMetrics(SM_CXSCREEN) - splash->width) / 2; 417 splash->y = (GetSystemMetrics(SM_CYSCREEN) - splash->height) / 2; 418 exStyle = splash->isLayered ? WS_EX_LAYERED : 0; 419 exStyle |= WS_EX_TOOLWINDOW; /* don't show the window on taskbar */ 420 style = WS_POPUP; 421 hWnd = CreateWindowEx(exStyle, (LPCSTR) wndClass, "", style, 422 splash->x, splash->y, splash->width, splash->height, NULL, NULL, 423 wcex.hInstance, NULL); 424 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) splash); 425 return hWnd; 426 } 427 428 void 429 SplashLock(Splash * splash) 430 { 431 EnterCriticalSection(&splash->lock); 432 } 433 434 void 435 SplashUnlock(Splash * splash) 436 { 437 LeaveCriticalSection(&splash->lock); 438 } 439 440 void 441 SplashInitPlatform(Splash * splash) 442 { 443 HDC hdc; 444 int paletteMode; 445 446 InitializeCriticalSection(&splash->lock); 447 splash->isLayered = FALSE; 448 hdc = GetDC(NULL); 449 paletteMode = (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0; 450 if (UpdateLayeredWindow && !paletteMode) { 451 splash->isLayered = TRUE; 452 } 453 splash->byteAlignment = 4; 454 if (splash->isLayered) { 455 initFormat(&splash->screenFormat, 456 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); 457 splash->screenFormat.premultiplied = 1; 458 splash->maskRequired = 0; 459 } 460 else { 461 splash->maskRequired = 1; 462 if (paletteMode) { 463 int numColors = GetDeviceCaps(hdc, SIZEPALETTE) - 464 GetDeviceCaps(hdc, NUMRESERVED); 465 int i; 466 int numComponents[3]; 467 468 initFormat(&splash->screenFormat, 0, 0, 0, 0); 469 /* FIXME: maybe remapping to non-reserved colors would improve performance */ 470 for (i = 0; i < numColors; i++) { 471 splash->colorIndex[i] = i; 472 } 473 numColors = quantizeColors(numColors, numComponents); 474 initColorCube(numComponents, splash->colorMap, splash->dithers, 475 splash->colorIndex); 476 splash->screenFormat.colorIndex = splash->colorIndex; 477 splash->screenFormat.depthBytes = 1; 478 splash->screenFormat.colorMap = splash->colorMap; 479 splash->screenFormat.dithers = splash->dithers; 480 splash->screenFormat.numColors = numColors; 481 splash->hPalette = NULL; 482 } 483 else { 484 initFormat(&splash->screenFormat, 485 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); 486 } 487 } 488 ReleaseDC(NULL, hdc); 489 } 490 491 void 492 SplashCleanupPlatform(Splash * splash) 493 { 494 int i; 495 496 if (splash->frames) { 497 for (i = 0; i < splash->frameCount; i++) { 498 if (splash->frames[i].hRgn) { 499 DeleteObject(splash->frames[i].hRgn); 500 splash->frames[i].hRgn = NULL; 501 } 502 } 503 } 504 if (splash->hPalette) 505 DeleteObject(splash->hPalette); 506 splash->maskRequired = !splash->isLayered; 507 } 508 509 void 510 SplashDonePlatform(Splash * splash) 511 { 512 if (splash->hWnd) 513 DestroyWindow(splash->hWnd); 514 } 515 516 void 517 SplashMessagePump() 518 { 519 MSG msg; 520 521 while (GetMessage(&msg, NULL, 0, 0)) { 522 TranslateMessage(&msg); 523 DispatchMessage(&msg); 524 } 525 } 526 527 DWORD WINAPI 528 SplashScreenThread(LPVOID param) 529 { 530 Splash *splash = (Splash *) param; 531 532 splash->currentFrame = 0; 533 SplashLock(splash); 534 splash->time = SplashTime(); 535 splash->hWnd = SplashCreateWindow(splash); 536 if (splash->hWnd) { 537 SplashRedrawWindow(splash); 538 //map the splash co-ordinates as per system scale 539 splash->x /= splash->scaleFactor; 540 splash->y /= splash->scaleFactor; 541 SplashUnlock(splash); 542 SplashMessagePump(); 543 SplashLock(splash); 544 } 545 SplashDone(splash); 546 splash->isVisible = -1; 547 SplashUnlock(splash); 548 return 0; 549 } 550 551 void 552 SplashCreateThread(Splash * splash) 553 { 554 DWORD threadId; 555 556 CreateThread(NULL, 0, SplashScreenThread, (LPVOID) splash, 0, &threadId); 557 } 558 559 void 560 SplashClosePlatform(Splash * splash) 561 { 562 PostMessage(splash->hWnd, WM_QUIT, 0, 0); 563 } 564 565 void 566 SplashUpdate(Splash * splash) 567 { 568 PostMessage(splash->hWnd, WM_SPLASHUPDATE, 0, 0); 569 } 570 571 void 572 SplashReconfigure(Splash * splash) 573 { 574 PostMessage(splash->hWnd, WM_SPLASHRECONFIGURE, 0, 0); 575 } 576 577 jboolean 578 SplashGetScaledImageName(const char* jarName, const char* fileName, 579 float *scaleFactor, char *scaleImageName, 580 const size_t scaledImageLength) 581 { 582 float dpiScaleX = -1.0f; 583 float dpiScaleY = -1.0f; 584 FILE *fp = NULL; 585 *scaleFactor = 1.0; 586 GetScreenDpi(getPrimaryMonitor(), &dpiScaleX, &dpiScaleY); 587 *scaleFactor = dpiScaleX > 0 ? dpiScaleX / 96 : *scaleFactor; 588 return GetScaledImageName(fileName, scaleImageName, 589 scaleFactor, scaledImageLength); 590 591 } 592 --- EOF ---