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