1 /* 2 * Copyright (c) 2005, 2013, 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 SplashUpdateScreenData(splash); 217 if (splash->isLayered) { 218 BLENDFUNCTION bf; 219 POINT ptSrc; 220 HDC hdcSrc = CreateCompatibleDC(NULL), hdcDst; 221 BITMAPINFOHEADER bmi; 222 void *bitmapBits; 223 HBITMAP hBitmap, hOldBitmap; 224 RECT rect; 225 POINT ptDst; 226 SIZE size; 227 228 bf.BlendOp = AC_SRC_OVER; 229 bf.BlendFlags = 0; 230 bf.AlphaFormat = AC_SRC_ALPHA; 231 bf.SourceConstantAlpha = 0xFF; 232 ptSrc.x = ptSrc.y = 0; 233 234 memset(&bmi, 0, sizeof(bmi)); 235 bmi.biSize = sizeof(BITMAPINFOHEADER); 236 bmi.biWidth = splash->width; 237 bmi.biHeight = -splash->height; 238 bmi.biPlanes = 1; 239 bmi.biBitCount = 32; 240 bmi.biCompression = BI_RGB; 241 242 // FIXME: this is somewhat ineffective 243 // maybe if we allocate memory for all frames as DIBSections, 244 // then we could select the frames into the DC directly 245 246 hBitmap = CreateDIBSection(NULL, (BITMAPINFO *) & bmi, DIB_RGB_COLORS, 247 &bitmapBits, NULL, 0); 248 memcpy(bitmapBits, splash->screenData, 249 splash->screenStride * splash->height); 250 hOldBitmap = (HBITMAP) SelectObject(hdcSrc, hBitmap); 251 hdcDst = GetDC(splash->hWnd); 252 253 GetWindowRect(splash->hWnd, &rect); 254 255 ptDst.x = rect.left; 256 ptDst.y = rect.top; 257 258 size.cx = splash->width; 259 size.cy = splash->height; 260 261 UpdateLayeredWindow(splash->hWnd, hdcDst, &ptDst, &size, 262 hdcSrc, &ptSrc, 0, &bf, ULW_ALPHA); 263 264 ReleaseDC(splash->hWnd, hdcDst); 265 SelectObject(hdcSrc, hOldBitmap); 266 DeleteObject(hBitmap); 267 DeleteDC(hdcSrc); 268 } 269 else { 270 InvalidateRect(splash->hWnd, NULL, FALSE); 271 if (splash->maskRequired) { 272 HRGN hRgn = CreateRectRgn(0, 0, 0, 0); 273 274 CombineRgn(hRgn, splash->frames[splash->currentFrame].hRgn, 275 splash->frames[splash->currentFrame].hRgn, RGN_COPY); 276 SetWindowRgn(splash->hWnd, hRgn, TRUE); 277 } else { 278 SetWindowRgn(splash->hWnd, NULL, TRUE); 279 } 280 UpdateWindow(splash->hWnd); 281 } 282 if (!IsWindowVisible(splash->hWnd)) { 283 POINT cursorPos; 284 ShowWindow(splash->hWnd, SW_SHOW); 285 // Windows won't update the cursor after the window is shown, 286 // if the cursor is already above the window. need to do this manually. 287 GetCursorPos(&cursorPos); 288 if (WindowFromPoint(cursorPos) == splash->hWnd) { 289 // unfortunately Windows fail to understand that the window 290 // thread should own the cursor, even though the mouse pointer 291 // is over the window, until the mouse has been moved. 292 // we're using SetCursorPos here to fake the mouse movement 293 // and enable proper update of the cursor. 294 SetCursorPos(cursorPos.x, cursorPos.y); 295 SetCursor(LoadCursor(NULL, IDC_WAIT)); 296 } 297 } 298 if (SplashIsStillLooping(splash)) { 299 int time = splash->time + 300 splash->frames[splash->currentFrame].delay - SplashTime(); 301 302 if (time < 0) 303 time = 0; 304 SetTimer(splash->hWnd, 0, time, NULL); 305 } 306 else { 307 KillTimer(splash->hWnd, 0); 308 } 309 } 310 311 void SplashReconfigureNow(Splash * splash) { 312 splash->x = (GetSystemMetrics(SM_CXSCREEN) - splash->width) / 2; 313 splash->y = (GetSystemMetrics(SM_CYSCREEN) - splash->height) / 2; 314 if (splash->hWnd) { 315 //Fixed 6474657: splash screen image jumps towards left while 316 // setting the new image using setImageURL() 317 // We may safely hide the splash window because SplashRedrawWindow() 318 // will show the window again. 319 ShowWindow(splash->hWnd, SW_HIDE); 320 MoveWindow(splash->hWnd, splash->x, splash->y, splash->width, splash->height, FALSE); 321 } 322 SplashRedrawWindow(splash); 323 } 324 325 static LRESULT CALLBACK 326 SplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 327 { 328 PAINTSTRUCT ps; 329 HDC hdc; 330 331 332 switch (message) { 333 334 case WM_ERASEBKGND: 335 return TRUE; // to avoid flicker 336 337 case WM_SYSCOMMAND: 338 if (wParam==SC_CLOSE||wParam==SC_DEFAULT||wParam==SC_HOTKEY|| 339 wParam==SC_KEYMENU||wParam==SC_MAXIMIZE|| 340 wParam==SC_MINIMIZE||wParam==SC_MOUSEMENU||wParam==SC_MOVE|| 341 wParam==SC_RESTORE||wParam==SC_SIZE) 342 { 343 return 0; 344 } 345 346 /* double switch to avoid prologue/epilogue duplication */ 347 case WM_TIMER: 348 case WM_SPLASHUPDATE: 349 case WM_PAINT: 350 case WM_SPLASHRECONFIGURE: 351 { 352 Splash *splash = (Splash *) GetWindowLongPtr(hWnd, GWLP_USERDATA); 353 354 SplashLock(splash); 355 if (splash->isVisible>0) { 356 switch(message) { 357 case WM_TIMER: 358 SplashNextFrame(splash); 359 SplashRedrawWindow(splash); 360 break; 361 case WM_SPLASHUPDATE: 362 SplashRedrawWindow(splash); 363 break; 364 case WM_PAINT: 365 hdc = BeginPaint(hWnd, &ps); 366 SplashPaint(splash, hdc); 367 EndPaint(hWnd, &ps); 368 break; 369 case WM_SPLASHRECONFIGURE: 370 SplashReconfigureNow(splash); 371 break; 372 } 373 } 374 SplashUnlock(splash); 375 break; 376 } 377 case WM_DESTROY: 378 PostQuitMessage(0); 379 break; 380 default: 381 return DefWindowProc(hWnd, message, wParam, lParam); 382 383 } 384 return 0; 385 } 386 387 HWND 388 SplashCreateWindow(Splash * splash) 389 { 390 WNDCLASSEX wcex; 391 ATOM wndClass; 392 DWORD style, exStyle; 393 HWND hWnd; 394 395 ZeroMemory(&wcex, sizeof(WNDCLASSEX)); 396 397 wcex.cbSize = sizeof(WNDCLASSEX); 398 wcex.style = CS_HREDRAW | CS_VREDRAW; 399 wcex.lpfnWndProc = (WNDPROC) SplashWndProc; 400 wcex.hInstance = GetModuleHandle(NULL); 401 wcex.lpszClassName = "JavaSplash"; 402 wcex.hCursor = LoadCursor(NULL, IDC_WAIT); 403 404 wndClass = RegisterClassEx(&wcex); 405 if (!wndClass) { 406 return 0; 407 } 408 409 splash->x = (GetSystemMetrics(SM_CXSCREEN) - splash->width) / 2; 410 splash->y = (GetSystemMetrics(SM_CYSCREEN) - splash->height) / 2; 411 exStyle = splash->isLayered ? WS_EX_LAYERED : 0; 412 exStyle |= WS_EX_TOOLWINDOW; /* don't show the window on taskbar */ 413 style = WS_POPUP; 414 hWnd = CreateWindowEx(exStyle, (LPCSTR) wndClass, "", style, 415 splash->x, splash->y, splash->width, splash->height, NULL, NULL, 416 wcex.hInstance, NULL); 417 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) splash); 418 return hWnd; 419 } 420 421 void 422 SplashLock(Splash * splash) 423 { 424 EnterCriticalSection(&splash->lock); 425 } 426 427 void 428 SplashUnlock(Splash * splash) 429 { 430 LeaveCriticalSection(&splash->lock); 431 } 432 433 void 434 SplashInitPlatform(Splash * splash) 435 { 436 HDC hdc; 437 int paletteMode; 438 439 InitializeCriticalSection(&splash->lock); 440 splash->isLayered = FALSE; 441 hdc = GetDC(NULL); 442 paletteMode = (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0; 443 if (UpdateLayeredWindow && !paletteMode) { 444 splash->isLayered = TRUE; 445 } 446 splash->byteAlignment = 4; 447 if (splash->isLayered) { 448 initFormat(&splash->screenFormat, 449 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); 450 splash->screenFormat.premultiplied = 1; 451 splash->maskRequired = 0; 452 } 453 else { 454 splash->maskRequired = 1; 455 if (paletteMode) { 456 int numColors = GetDeviceCaps(hdc, SIZEPALETTE) - 457 GetDeviceCaps(hdc, NUMRESERVED); 458 int i; 459 int numComponents[3]; 460 461 initFormat(&splash->screenFormat, 0, 0, 0, 0); 462 /* FIXME: maybe remapping to non-reserved colors would improve performance */ 463 for (i = 0; i < numColors; i++) { 464 splash->colorIndex[i] = i; 465 } 466 numColors = quantizeColors(numColors, numComponents); 467 initColorCube(numComponents, splash->colorMap, splash->dithers, 468 splash->colorIndex); 469 splash->screenFormat.colorIndex = splash->colorIndex; 470 splash->screenFormat.depthBytes = 1; 471 splash->screenFormat.colorMap = splash->colorMap; 472 splash->screenFormat.dithers = splash->dithers; 473 splash->screenFormat.numColors = numColors; 474 splash->hPalette = NULL; 475 } 476 else { 477 initFormat(&splash->screenFormat, 478 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); 479 } 480 } 481 ReleaseDC(NULL, hdc); 482 } 483 484 void 485 SplashCleanupPlatform(Splash * splash) 486 { 487 int i; 488 489 if (splash->frames) { 490 for (i = 0; i < splash->frameCount; i++) { 491 if (splash->frames[i].hRgn) { 492 DeleteObject(splash->frames[i].hRgn); 493 splash->frames[i].hRgn = NULL; 494 } 495 } 496 } 497 if (splash->hPalette) 498 DeleteObject(splash->hPalette); 499 splash->maskRequired = !splash->isLayered; 500 } 501 502 void 503 SplashDonePlatform(Splash * splash) 504 { 505 if (splash->hWnd) 506 DestroyWindow(splash->hWnd); 507 } 508 509 void 510 SplashMessagePump() 511 { 512 MSG msg; 513 514 while (GetMessage(&msg, NULL, 0, 0)) { 515 TranslateMessage(&msg); 516 DispatchMessage(&msg); 517 } 518 } 519 520 DWORD WINAPI 521 SplashScreenThread(LPVOID param) 522 { 523 Splash *splash = (Splash *) param; 524 525 splash->currentFrame = 0; 526 SplashLock(splash); 527 splash->time = SplashTime(); 528 splash->hWnd = SplashCreateWindow(splash); 529 if (splash->hWnd) { 530 SplashRedrawWindow(splash); 531 SplashUnlock(splash); 532 SplashMessagePump(); 533 SplashLock(splash); 534 } 535 SplashDone(splash); 536 splash->isVisible = -1; 537 SplashUnlock(splash); 538 return 0; 539 } 540 541 void 542 SplashCreateThread(Splash * splash) 543 { 544 DWORD threadId; 545 546 CreateThread(NULL, 0, SplashScreenThread, (LPVOID) splash, 0, &threadId); 547 } 548 549 void 550 SplashClosePlatform(Splash * splash) 551 { 552 PostMessage(splash->hWnd, WM_QUIT, 0, 0); 553 } 554 555 void 556 SplashUpdate(Splash * splash) 557 { 558 PostMessage(splash->hWnd, WM_SPLASHUPDATE, 0, 0); 559 } 560 561 void 562 SplashReconfigure(Splash * splash) 563 { 564 PostMessage(splash->hWnd, WM_SPLASHRECONFIGURE, 0, 0); 565 }