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