Path: blob/master/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c
41149 views
/*1* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425// copy from awt.h26#ifndef _WIN32_WINNT27#define _WIN32_WINNT 0x060028#endif2930// copy from awt.h31#ifndef _WIN32_IE32#define _WIN32_IE 0x060033#endif3435#include "splashscreen_impl.h"36#include <windowsx.h>37#include <windows.h>38#include <winuser.h>39#include "sizecalc.h"4041#ifndef WS_EX_LAYERED42#define WS_EX_LAYERED 0x8000043#endif4445#ifndef ULW_ALPHA46#define ULW_ALPHA 0x0000000247#endif4849#ifndef AC_SRC_OVER50#define AC_SRC_OVER 0x0051#endif5253#ifndef AC_SRC_ALPHA54#define AC_SRC_ALPHA 0x0155#endif5657#define WM_SPLASHUPDATE WM_USER+158#define WM_SPLASHRECONFIGURE WM_USER+25960#define BUFF_SIZE 10246162/* Could use npt but decided to cut down on linked code size */63char* SplashConvertStringAlloc(const char* in, int *size) {64int len, outChars, rc;65WCHAR* buf;66if (!in) {67return NULL;68}69len = strlen(in);70outChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, in, len,71NULL, 0);72buf = (WCHAR*) SAFE_SIZE_ARRAY_ALLOC(malloc, outChars, sizeof(WCHAR));73if (!buf) {74return NULL;75}76rc = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, in, len,77buf, outChars);78if (rc==0) {79free(buf);80return NULL;81} else {82if (size) {83*size = rc;84}85return (char*)buf;86}87}8889unsigned90SplashTime(void)91{92return GetTickCount();93}9495void96SplashInitFrameShape(Splash * splash, int imageIndex)97{98RGNDATA *pRgnData;99RGNDATAHEADER *pRgnHdr;100ImageRect maskRect;101102if (!splash->maskRequired)103return;104105/* reserving memory for the worst case */106if (!IS_SAFE_SIZE_MUL(splash->width / 2 + 1, splash->height)) {107return;108}109pRgnData = (RGNDATA *) SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(RGNDATAHEADER),110sizeof(RECT), (splash->width / 2 + 1) * splash->height);111if (!pRgnData) {112return;113}114pRgnHdr = (RGNDATAHEADER *) pRgnData;115initRect(&maskRect, 0, 0, splash->width, splash->height, 1,116splash->width * splash->imageFormat.depthBytes,117splash->frames[imageIndex].bitmapBits, &splash->imageFormat);118119pRgnHdr->dwSize = sizeof(RGNDATAHEADER);120pRgnHdr->iType = RDH_RECTANGLES;121pRgnHdr->nRgnSize = 0;122pRgnHdr->rcBound.top = 0;123pRgnHdr->rcBound.left = 0;124pRgnHdr->rcBound.bottom = splash->height;125pRgnHdr->rcBound.right = splash->width;126127pRgnHdr->nCount = BitmapToYXBandedRectangles(&maskRect,128(RECT *) (((BYTE *) pRgnData) + sizeof(RGNDATAHEADER)));129130splash->frames[imageIndex].hRgn = ExtCreateRegion(NULL,131sizeof(RGNDATAHEADER) + sizeof(RECT) * pRgnHdr->nCount, pRgnData);132133free(pRgnData);134}135136/* paint current splash screen frame to hdc137this function is unused in layered window mode */138139void140SplashPaint(Splash * splash, HDC hdc)141{142unsigned numColors = splash->screenFormat.colorMap ?143splash->screenFormat.numColors : 0;144BITMAPV4HEADER *pBmi;145HPALETTE hOldPal = NULL;146147if (!splash->frames)148return;149if (splash->currentFrame < 0 || splash->currentFrame >= splash->frameCount)150return;151pBmi = (BITMAPV4HEADER *) SAFE_SIZE_STRUCT_ALLOC(alloca, sizeof(BITMAPV4HEADER),152sizeof(RGBQUAD), numColors);153if (!pBmi) {154return;155}156memset(pBmi, 0, sizeof(BITMAPV4HEADER));157if (splash->screenFormat.colorMap)158memcpy(((BYTE *) pBmi) + sizeof(BITMAPV4HEADER),159splash->screenFormat.colorMap, sizeof(RGBQUAD) * numColors);160161pBmi->bV4Size = sizeof(BITMAPV4HEADER);162pBmi->bV4Width = splash->width;163pBmi->bV4Height = -splash->height;164pBmi->bV4Planes = 1;165pBmi->bV4BitCount = (WORD) (splash->screenFormat.depthBytes * 8);166/* we're ALWAYS using BGRA in screenFormat */167pBmi->bV4V4Compression = BI_RGB;168pBmi->bV4ClrUsed = numColors;169pBmi->bV4ClrImportant = numColors;170pBmi->bV4AlphaMask = splash->screenFormat.mask[3];171pBmi->bV4RedMask = splash->screenFormat.mask[2];172pBmi->bV4GreenMask = splash->screenFormat.mask[1];173pBmi->bV4BlueMask = splash->screenFormat.mask[0];174175/* creating the palette in SplashInitPlatform does not work, so I'm creating it176here on demand */177if (!splash->hPalette) {178unsigned i;179LOGPALETTE *pLogPal = (LOGPALETTE *) SAFE_SIZE_STRUCT_ALLOC(malloc,180sizeof(LOGPALETTE), sizeof(PALETTEENTRY), numColors);181if (!pLogPal) {182return;183}184185pLogPal->palVersion = 0x300;186pLogPal->palNumEntries = (WORD) numColors;187for (i = 0; i < numColors; i++) {188pLogPal->palPalEntry[i].peRed = (BYTE)189QUAD_RED(splash->colorMap[i]);190pLogPal->palPalEntry[i].peGreen = (BYTE)191QUAD_GREEN(splash->colorMap[i]);192pLogPal->palPalEntry[i].peBlue = (BYTE)193QUAD_BLUE(splash->colorMap[i]);194pLogPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE;195}196splash->hPalette = CreatePalette(pLogPal);197free(pLogPal);198}199if (splash->hPalette) {200hOldPal = SelectPalette(hdc, splash->hPalette, FALSE);201RealizePalette(hdc);202}203204StretchDIBits(hdc, 0, 0, splash->width, splash->height, 0, 0,205splash->width, splash->height, splash->screenData,206(BITMAPINFO *) pBmi, DIB_RGB_COLORS, SRCCOPY);207if (hOldPal)208SelectPalette(hdc, hOldPal, FALSE);209}210211212/* The function makes the window visible if it is hidden213or is not yet shown. */214void215SplashRedrawWindow(Splash * splash)216{217if (!SplashIsStillLooping(splash)) {218KillTimer(splash->hWnd, 0);219}220221if (splash->currentFrame < 0) {222return;223}224225SplashUpdateScreenData(splash);226if (splash->isLayered) {227BLENDFUNCTION bf;228POINT ptSrc;229HDC hdcSrc = CreateCompatibleDC(NULL), hdcDst;230BITMAPINFOHEADER bmi;231void *bitmapBits;232HBITMAP hBitmap, hOldBitmap;233RECT rect;234POINT ptDst;235SIZE size;236237bf.BlendOp = AC_SRC_OVER;238bf.BlendFlags = 0;239bf.AlphaFormat = AC_SRC_ALPHA;240bf.SourceConstantAlpha = 0xFF;241ptSrc.x = ptSrc.y = 0;242243memset(&bmi, 0, sizeof(bmi));244bmi.biSize = sizeof(BITMAPINFOHEADER);245bmi.biWidth = splash->width;246bmi.biHeight = -splash->height;247bmi.biPlanes = 1;248bmi.biBitCount = 32;249bmi.biCompression = BI_RGB;250251// FIXME: this is somewhat ineffective252// maybe if we allocate memory for all frames as DIBSections,253// then we could select the frames into the DC directly254255hBitmap = CreateDIBSection(NULL, (BITMAPINFO *) & bmi, DIB_RGB_COLORS,256&bitmapBits, NULL, 0);257memcpy(bitmapBits, splash->screenData,258splash->screenStride * splash->height);259hOldBitmap = (HBITMAP) SelectObject(hdcSrc, hBitmap);260hdcDst = GetDC(splash->hWnd);261262GetWindowRect(splash->hWnd, &rect);263264ptDst.x = rect.left;265ptDst.y = rect.top;266267size.cx = splash->width;268size.cy = splash->height;269270UpdateLayeredWindow(splash->hWnd, hdcDst, &ptDst, &size,271hdcSrc, &ptSrc, 0, &bf, ULW_ALPHA);272273ReleaseDC(splash->hWnd, hdcDst);274SelectObject(hdcSrc, hOldBitmap);275DeleteObject(hBitmap);276DeleteDC(hdcSrc);277}278else {279InvalidateRect(splash->hWnd, NULL, FALSE);280if (splash->maskRequired) {281HRGN hRgn = CreateRectRgn(0, 0, 0, 0);282283CombineRgn(hRgn, splash->frames[splash->currentFrame].hRgn,284splash->frames[splash->currentFrame].hRgn, RGN_COPY);285SetWindowRgn(splash->hWnd, hRgn, TRUE);286} else {287SetWindowRgn(splash->hWnd, NULL, TRUE);288}289UpdateWindow(splash->hWnd);290}291if (!IsWindowVisible(splash->hWnd)) {292POINT cursorPos;293ShowWindow(splash->hWnd, SW_SHOW);294// Windows won't update the cursor after the window is shown,295// if the cursor is already above the window. need to do this manually.296GetCursorPos(&cursorPos);297if (WindowFromPoint(cursorPos) == splash->hWnd) {298// unfortunately Windows fail to understand that the window299// thread should own the cursor, even though the mouse pointer300// is over the window, until the mouse has been moved.301// we're using SetCursorPos here to fake the mouse movement302// and enable proper update of the cursor.303SetCursorPos(cursorPos.x, cursorPos.y);304SetCursor(LoadCursor(NULL, IDC_WAIT));305}306}307if (SplashIsStillLooping(splash)) {308int time = splash->time +309splash->frames[splash->currentFrame].delay - SplashTime();310311if (time < 0)312time = 0;313SetTimer(splash->hWnd, 0, time, NULL);314}315}316317void SplashReconfigureNow(Splash * splash) {318splash->x = (GetSystemMetrics(SM_CXSCREEN) - splash->width) / 2;319splash->y = (GetSystemMetrics(SM_CYSCREEN) - splash->height) / 2;320if (splash->hWnd) {321//Fixed 6474657: splash screen image jumps towards left while322// setting the new image using setImageURL()323// We may safely hide the splash window because SplashRedrawWindow()324// will show the window again.325ShowWindow(splash->hWnd, SW_HIDE);326MoveWindow(splash->hWnd, splash->x, splash->y, splash->width, splash->height, FALSE);327}328SplashRedrawWindow(splash);329}330331static LRESULT CALLBACK332SplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)333{334PAINTSTRUCT ps;335HDC hdc;336337338switch (message) {339340case WM_ERASEBKGND:341return TRUE; // to avoid flicker342343case WM_SYSCOMMAND:344if (wParam==SC_CLOSE||wParam==SC_DEFAULT||wParam==SC_HOTKEY||345wParam==SC_KEYMENU||wParam==SC_MAXIMIZE||346wParam==SC_MINIMIZE||wParam==SC_MOUSEMENU||wParam==SC_MOVE||347wParam==SC_RESTORE||wParam==SC_SIZE)348{349return 0;350}351352/* double switch to avoid prologue/epilogue duplication */353case WM_TIMER:354case WM_SPLASHUPDATE:355case WM_PAINT:356case WM_SPLASHRECONFIGURE:357{358Splash *splash = (Splash *) GetWindowLongPtr(hWnd, GWLP_USERDATA);359360SplashLock(splash);361if (splash->isVisible>0) {362switch(message) {363case WM_TIMER:364SplashNextFrame(splash);365SplashRedrawWindow(splash);366break;367case WM_SPLASHUPDATE:368SplashRedrawWindow(splash);369break;370case WM_PAINT:371hdc = BeginPaint(hWnd, &ps);372SplashPaint(splash, hdc);373EndPaint(hWnd, &ps);374break;375case WM_SPLASHRECONFIGURE:376SplashReconfigureNow(splash);377break;378}379}380SplashUnlock(splash);381break;382}383case WM_DESTROY:384PostQuitMessage(0);385break;386default:387return DefWindowProc(hWnd, message, wParam, lParam);388389}390return 0;391}392393HWND394SplashCreateWindow(Splash * splash)395{396WNDCLASSEX wcex;397ATOM wndClass;398DWORD style, exStyle;399HWND hWnd;400401ZeroMemory(&wcex, sizeof(WNDCLASSEX));402403wcex.cbSize = sizeof(WNDCLASSEX);404wcex.style = CS_HREDRAW | CS_VREDRAW;405wcex.lpfnWndProc = (WNDPROC) SplashWndProc;406wcex.hInstance = GetModuleHandle(NULL);407wcex.lpszClassName = "JavaSplash";408wcex.hCursor = LoadCursor(NULL, IDC_WAIT);409410wndClass = RegisterClassEx(&wcex);411if (!wndClass) {412return 0;413}414415splash->x = (GetSystemMetrics(SM_CXSCREEN) - splash->width) / 2;416splash->y = (GetSystemMetrics(SM_CYSCREEN) - splash->height) / 2;417exStyle = splash->isLayered ? WS_EX_LAYERED : 0;418exStyle |= WS_EX_TOOLWINDOW; /* don't show the window on taskbar */419style = WS_POPUP;420hWnd = CreateWindowEx(exStyle, (LPCSTR) wndClass, "", style,421splash->x, splash->y, splash->width, splash->height, NULL, NULL,422wcex.hInstance, NULL);423SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) splash);424return hWnd;425}426427void428SplashLock(Splash * splash)429{430EnterCriticalSection(&splash->lock);431}432433void434SplashUnlock(Splash * splash)435{436LeaveCriticalSection(&splash->lock);437}438439int440SplashInitPlatform(Splash * splash)441{442HDC hdc;443int paletteMode;444445InitializeCriticalSection(&splash->lock);446splash->isLayered = FALSE;447hdc = GetDC(NULL);448paletteMode = (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0;449if (UpdateLayeredWindow && !paletteMode) {450splash->isLayered = TRUE;451}452splash->byteAlignment = 4;453if (splash->isLayered) {454initFormat(&splash->screenFormat,4550x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);456splash->screenFormat.premultiplied = 1;457splash->maskRequired = 0;458}459else {460splash->maskRequired = 1;461if (paletteMode) {462int numColors = GetDeviceCaps(hdc, SIZEPALETTE) -463GetDeviceCaps(hdc, NUMRESERVED);464int i;465int numComponents[3];466467initFormat(&splash->screenFormat, 0, 0, 0, 0);468/* FIXME: maybe remapping to non-reserved colors would improve performance */469for (i = 0; i < numColors; i++) {470splash->colorIndex[i] = i;471}472numColors = quantizeColors(numColors, numComponents);473initColorCube(numComponents, splash->colorMap, splash->dithers,474splash->colorIndex);475splash->screenFormat.colorIndex = splash->colorIndex;476splash->screenFormat.depthBytes = 1;477splash->screenFormat.colorMap = splash->colorMap;478splash->screenFormat.dithers = splash->dithers;479splash->screenFormat.numColors = numColors;480splash->hPalette = NULL;481}482else {483initFormat(&splash->screenFormat,4840x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);485}486}487ReleaseDC(NULL, hdc);488return 1;489}490491void492SplashCleanupPlatform(Splash * splash)493{494int i;495496if (splash->frames) {497for (i = 0; i < splash->frameCount; i++) {498if (splash->frames[i].hRgn) {499DeleteObject(splash->frames[i].hRgn);500splash->frames[i].hRgn = NULL;501}502}503}504if (splash->hPalette)505DeleteObject(splash->hPalette);506splash->maskRequired = !splash->isLayered;507}508509void510SplashDonePlatform(Splash * splash)511{512if (splash->hWnd)513DestroyWindow(splash->hWnd);514}515516void517SplashMessagePump()518{519MSG msg;520521while (GetMessage(&msg, NULL, 0, 0)) {522TranslateMessage(&msg);523DispatchMessage(&msg);524}525}526527DWORD WINAPI528SplashScreenThread(LPVOID param)529{530Splash *splash = (Splash *) param;531532splash->currentFrame = 0;533SplashLock(splash);534splash->time = SplashTime();535splash->hWnd = SplashCreateWindow(splash);536if (splash->hWnd) {537SplashRedrawWindow(splash);538//map the splash co-ordinates as per system scale539splash->x /= splash->scaleFactor;540splash->y /= splash->scaleFactor;541SplashUnlock(splash);542SplashMessagePump();543SplashLock(splash);544}545SplashDone(splash);546splash->isVisible = -1;547SplashUnlock(splash);548return 0;549}550551void552SplashCreateThread(Splash * splash)553{554DWORD threadId;555556CreateThread(NULL, 0, SplashScreenThread, (LPVOID) splash, 0, &threadId);557}558559void560SplashClosePlatform(Splash * splash)561{562PostMessage(splash->hWnd, WM_QUIT, 0, 0);563}564565void566SplashUpdate(Splash * splash)567{568PostMessage(splash->hWnd, WM_SPLASHUPDATE, 0, 0);569}570571void572SplashReconfigure(Splash * splash)573{574PostMessage(splash->hWnd, WM_SPLASHRECONFIGURE, 0, 0);575}576577JNIEXPORT jboolean578SplashGetScaledImageName(const char* jarName, const char* fileName,579float *scaleFactor, char *scaleImageName,580const size_t scaledImageLength)581{582float dpiScaleX = -1.0f;583float dpiScaleY = -1.0f;584FILE *fp = NULL;585*scaleFactor = 1.0;586GetScreenDpi(getPrimaryMonitor(), &dpiScaleX, &dpiScaleY);587*scaleFactor = dpiScaleX > 0 ? dpiScaleX / 96 : *scaleFactor;588return GetScaledImageName(fileName, scaleImageName,589scaleFactor, scaledImageLength);590}591592593594