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