1/*
2 * Copyright (c) 2005, 2019, 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#include "splashscreen_impl.h"
27#include <X11/Xlib.h>
28#include <X11/Xutil.h>
29#include <X11/extensions/shape.h>
30#include <X11/Xmd.h>
31#include <X11/Xatom.h>
32#include <X11/cursorfont.h>
33#include <sys/types.h>
34#include <pthread.h>
35#include <signal.h>
36#include <unistd.h>
37#include <sys/time.h>
38#include <errno.h>
39#include <iconv.h>
40#include <langinfo.h>
41#include <locale.h>
42#include <fcntl.h>
43#include <poll.h>
44#include <sizecalc.h>
45#include "jni.h"
46
47static Bool shapeSupported;
48static int shapeEventBase, shapeErrorBase;
49
50void SplashRemoveDecoration(Splash * splash);
51
52
53/* Could use npt but decided to cut down on linked code size */
54char* SplashConvertStringAlloc(const char* in, int* size) {
55 const char *codeset;
56 const char *codeset_out;
57 iconv_t cd;
58 size_t rc;
59 char *buf = NULL, *out;
60 size_t bufSize, inSize, outSize;
61 const char* old_locale;
62
63 if (!in) {
64 return NULL;
65 }
66 old_locale = setlocale(LC_ALL, "");
67
68 codeset = nl_langinfo(CODESET);
69 if ( codeset == NULL || codeset[0] == 0 ) {
70 goto done;
71 }
72 /* we don't need BOM in output so we choose native BE or LE encoding here */
73 codeset_out = (platformByteOrder()==BYTE_ORDER_MSBFIRST) ?
74 "UCS-2BE" : "UCS-2LE";
75
76 cd = iconv_open(codeset_out, codeset);
77 if (cd == (iconv_t)-1 ) {
78 goto done;
79 }
80 inSize = strlen(in);
81 buf = SAFE_SIZE_ARRAY_ALLOC(malloc, inSize, 2);
82 if (!buf) {
83 return NULL;
84 }
85 bufSize = inSize*2; // need 2 bytes per char for UCS-2, this is
86 // 2 bytes per source byte max
87 out = buf; outSize = bufSize;
88 /* linux iconv wants char** source and solaris wants const char**...
89 cast to void* */
90 rc = iconv(cd, (void*)&in, &inSize, &out, &outSize);
91 iconv_close(cd);
92
93 if (rc == (size_t)-1) {
94 free(buf);
95 buf = NULL;
96 } else {
97 if (size) {
98 *size = (bufSize-outSize)/2; /* bytes to wchars */
99 }
100 }
101done:
102 setlocale(LC_ALL, old_locale);
103 return buf;
104}
105
106void
107SplashInitFrameShape(Splash * splash, int imageIndex) {
108 ImageRect maskRect;
109 XRectangle *rects;
110 SplashImage *frame = splash->frames + imageIndex;
111
112 frame->rects = NULL;
113 frame->numRects = 0;
114
115 if (!splash->maskRequired)
116 return;
117 if (!shapeSupported)
118 return;
119 initRect(&maskRect, 0, 0, splash->width, splash->height, 1,
120 splash->width * splash->imageFormat.depthBytes,
121 splash->frames[imageIndex].bitmapBits, &splash->imageFormat);
122 if (!IS_SAFE_SIZE_MUL(splash->width / 2 + 1, splash->height)) {
123 return;
124 }
125 rects = SAFE_SIZE_ARRAY_ALLOC(malloc,
126 sizeof(XRectangle), (splash->width / 2 + 1) * splash->height);
127 if (!rects) {
128 return;
129 }
130
131 frame->numRects = BitmapToYXBandedRectangles(&maskRect, rects);
132 frame->rects = SAFE_SIZE_ARRAY_ALLOC(malloc, frame->numRects, sizeof(XRectangle));
133 if (frame->rects) { // handle the error after the if(){}
134 memcpy(frame->rects, rects, frame->numRects * sizeof(XRectangle));
135 }
136 free(rects);
137}
138
139unsigned
140SplashTime(void) {
141 struct timeval tv;
142 struct timezone tz;
143 unsigned long long msec;
144
145 gettimeofday(&tv, &tz);
146 msec = (unsigned long long) tv.tv_sec * 1000 +
147 (unsigned long long) tv.tv_usec / 1000;
148
149 return (unsigned) msec;
150}
151
152void
153msec2timeval(unsigned time, struct timeval *tv) {
154 tv->tv_sec = time / 1000;
155 tv->tv_usec = (time % 1000) * 1000;
156}
157
158int
159GetNumAvailableColors(Display * display, Screen * screen, unsigned map_entries) {
160 unsigned long pmr[1];
161 unsigned long pr[SPLASH_COLOR_MAP_SIZE];
162 unsigned nFailed, nAllocated, done = 0, nPlanes = 0;
163 Colormap cmap;
164 unsigned numColors = SPLASH_COLOR_MAP_SIZE; // never try allocating more than that
165
166 if (numColors > map_entries) {
167 numColors = map_entries;
168 }
169 cmap = XDefaultColormapOfScreen(screen);
170 nAllocated = 0; /* lower bound */
171 nFailed = numColors + 1; /* upper bound */
172
173 /* Binary search to determine the number of available cells */
174 for (done = 0; !done;) {
175 if (XAllocColorCells(display, cmap, 0, pmr, nPlanes, pr, numColors)) {
176 nAllocated = numColors;
177 XFreeColors(display, cmap, pr, numColors, 0);
178 if (nAllocated < (nFailed - 1)) {
179 numColors = (nAllocated + nFailed) / 2;
180 } else
181 done = 1;
182 } else {
183 nFailed = numColors;
184 if (nFailed > (nAllocated + 1))
185 numColors = (nAllocated + nFailed) / 2;
186 else
187 done = 1;
188 }
189 }
190 return nAllocated;
191}
192
193Colormap
194AllocColors(Display * display, Screen * screen, int numColors,
195 unsigned long *pr) {
196 unsigned long pmr[1];
197 Colormap cmap = XDefaultColormapOfScreen(screen);
198
199 XAllocColorCells(display, cmap, 0, pmr, 0, pr, numColors);
200 return cmap;
201}
202
203void
204FreeColors(Display * display, Screen * screen, int numColors,
205 unsigned long *pr) {
206 Colormap cmap = XDefaultColormapOfScreen(screen);
207
208 XFreeColors(display, cmap, pr, numColors, 0);
209}
210
211static void SplashCenter(Splash * splash) {
212 Atom type, atom, actual_type;
213 int status, actual_format;
214 unsigned long nitems, bytes_after;
215 CARD16 *prop = NULL;
216
217 /* try centering using Xinerama hint
218 if there's no hint, use the center of the screen */
219 atom = XInternAtom(splash->display, "XINERAMA_CENTER_HINT", True);
220 if (atom != None) {
221 status = XGetWindowProperty(splash->display,
222 XRootWindowOfScreen(splash->screen), atom, 0, 1, False, XA_INTEGER,
223 &actual_type, &actual_format, &nitems,
224 &bytes_after, (unsigned char**)(&prop));
225 if (status == Success && actual_type != None && prop != NULL) {
226 splash->x = prop[0] - splash->width/2;
227 splash->y = prop[1] - splash->height/2;
228 XFree(prop);
229 return;
230 }
231 if (prop != NULL) {
232 XFree(prop);
233 }
234 }
235 splash->x = (XWidthOfScreen(splash->screen) - splash->width) / 2;
236 splash->y = (XHeightOfScreen(splash->screen) - splash->height) / 2;
237}
238
239static void SplashUpdateSizeHints(Splash * splash) {
240 if (splash->window) {
241 XSizeHints sizeHints;
242
243 sizeHints.flags = USPosition | PPosition | USSize | PSize | PMinSize | PMaxSize | PWinGravity;
244 sizeHints.width = sizeHints.base_width = sizeHints.min_width = sizeHints.max_width = splash->width;
245 sizeHints.height = sizeHints.base_height = sizeHints.min_height = sizeHints.max_height = splash->height;
246 sizeHints.win_gravity = NorthWestGravity;
247
248 XSetWMNormalHints(splash->display, splash->window, &sizeHints);
249 }
250}
251
252void
253SplashCreateWindow(Splash * splash) {
254 XSizeHints sizeHints;
255
256 XSetWindowAttributes attr;
257
258 attr.backing_store = NotUseful;
259 attr.colormap = XDefaultColormapOfScreen(splash->screen);
260 attr.save_under = True;
261 attr.cursor = splash->cursor = XCreateFontCursor(splash->display, XC_watch);
262 attr.event_mask = ExposureMask;
263
264 SplashCenter(splash);
265
266 splash->window = XCreateWindow(splash->display, XRootWindowOfScreen(splash->screen),
267 splash->x, splash->y, splash->width, splash->height, 0, CopyFromParent,
268 InputOutput, CopyFromParent, CWColormap | CWBackingStore | CWSaveUnder | CWCursor | CWEventMask,
269 &attr);
270 SplashUpdateSizeHints(splash);
271
272
273 splash->wmHints = XAllocWMHints();
274 if (splash->wmHints) {
275 splash->wmHints->flags = InputHint | StateHint;
276 splash->wmHints->input = False;
277 splash->wmHints->initial_state = NormalState;
278 XSetWMHints(splash->display, splash->window, splash->wmHints);
279 }
280}
281
282/* for changing the visible shape of a window to an nonrectangular form */
283void
284SplashUpdateShape(Splash * splash) {
285 if (splash->currentFrame < 0 || !shapeSupported || !splash->maskRequired) {
286 return;
287 }
288 XShapeCombineRectangles(splash->display, splash->window, ShapeClip, 0, 0,
289 splash->frames[splash->currentFrame].rects,
290 splash->frames[splash->currentFrame].numRects, ShapeSet, YXBanded);
291 XShapeCombineRectangles(splash->display, splash->window, ShapeBounding,
292 0, 0, splash->frames[splash->currentFrame].rects,
293 splash->frames[splash->currentFrame].numRects, ShapeSet, YXBanded);
294}
295
296/* for reverting the visible shape of a window to an rectangular form */
297void
298SplashRevertShape(Splash * splash) {
299 if (!shapeSupported)
300 return;
301 if (splash->maskRequired)
302 return;
303
304 XShapeCombineMask (splash->display, splash->window, ShapeClip,
305 0, 0, None, ShapeSet);
306 XShapeCombineMask (splash->display, splash->window , ShapeBounding,
307 0, 0, None, ShapeSet);
308}
309
310int
311ByteOrderToX(int byteOrder) {
312 if (byteOrder == BYTE_ORDER_NATIVE)
313 byteOrder = platformByteOrder();
314 switch (byteOrder) {
315 case BYTE_ORDER_LSBFIRST:
316 return LSBFirst;
317 case BYTE_ORDER_MSBFIRST:
318 return MSBFirst;
319 default:
320 return -1;
321 }
322}
323
324void
325SplashRedrawWindow(Splash * splash) {
326 if (splash->currentFrame < 0) {
327 return;
328 }
329
330 XImage *ximage;
331
332 // making this method redraw a part of the image does not make
333 // much sense as SplashUpdateScreenData always re-generates
334 // the image completely, so whole window is always redrawn
335
336 SplashUpdateScreenData(splash);
337 ximage = XCreateImage(splash->display, splash->visual,
338 splash->screenFormat.depthBytes * 8, ZPixmap, 0, (char *) NULL,
339 splash->width, splash->height, 8, 0);
340 ximage->data = (char *) splash->screenData;
341 ximage->bits_per_pixel = ximage->depth;
342 ximage->bytes_per_line = ximage->depth * ximage->width / 8;
343 ximage->byte_order = ByteOrderToX(splash->screenFormat.byteOrder);
344 ximage->bitmap_unit = 8;
345 XPutImage(splash->display, splash->window,
346 XDefaultGCOfScreen(splash->screen), ximage, 0, 0, 0, 0,
347 splash->width, splash->height);
348 ximage->data = NULL;
349 XDestroyImage(ximage);
350 SplashRemoveDecoration(splash);
351 XMapWindow(splash->display, splash->window);
352 XFlush(splash->display);
353}
354
355void SplashReconfigureNow(Splash * splash) {
356 SplashCenter(splash);
357 if (splash->window) {
358 XUnmapWindow(splash->display, splash->window);
359 XMoveResizeWindow(splash->display, splash->window,
360 splash->x, splash->y,
361 splash->width, splash->height);
362 SplashUpdateSizeHints(splash);
363 }
364 if (splash->maskRequired) {
365 SplashUpdateShape(splash);
366 } else {
367 SplashRevertShape(splash);
368 }
369 SplashRedrawWindow(splash);
370}
371
372
373void
374sendctl(Splash * splash, char code) {
375// if (splash->isVisible>0) {
376 if (splash && splash->controlpipe[1]) {
377 write(splash->controlpipe[1], &code, 1);
378 }
379}
380
381int
382HandleError(Display * disp, XErrorEvent * err) {
383 // silently ignore non-fatal errors
384 /*
385 char msg[0x1000];
386 char buf[0x1000];
387 XGetErrorText(disp, err->error_code, msg, sizeof(msg));
388 fprintf(stderr, "Xerror %s, XID %x, ser# %d\n", msg, err->resourceid,
389 err->serial);
390 sprintf(buf, "%d", err->request_code);
391 XGetErrorDatabaseText(disp, "XRequest", buf, "Unknown", msg, sizeof(msg));
392 fprintf(stderr, "Major opcode %d (%s)\n", err->request_code, msg);
393 if (err->request_code > 128) {
394 fprintf(stderr, "Minor opcode %d\n", err->minor_code);
395 }
396 */
397 return 0;
398}
399
400int
401HandleIOError(Display * display) {
402 // for really bad errors, we should exit the thread we're on
403 SplashCleanup(SplashGetInstance());
404 pthread_exit(NULL);
405 return 0;
406}
407
408int
409SplashInitPlatform(Splash * splash) {
410 int shapeVersionMajor, shapeVersionMinor;
411
412 // This setting enables the synchronous Xlib mode!
413 // Don't use it == 1 in production builds!
414#if (defined DEBUG)
415 _Xdebug = 1;
416#endif
417
418 pthread_mutex_init(&splash->lock, NULL);
419
420 // We should not ignore any errors.
421 //XSetErrorHandler(HandleError);
422// XSetIOErrorHandler(HandleIOError);
423 XSetIOErrorHandler(NULL);
424 splash->display = XOpenDisplay(NULL);
425 if (!splash->display) {
426 splash->isVisible = -1;
427 return 0;
428 }
429
430 shapeSupported = XShapeQueryExtension(splash->display, &shapeEventBase,
431 &shapeErrorBase);
432 if (shapeSupported) {
433 XShapeQueryVersion(splash->display, &shapeVersionMajor,
434 &shapeVersionMinor);
435 }
436
437 splash->screen = XDefaultScreenOfDisplay(splash->display);
438 splash->visual = XDefaultVisualOfScreen(splash->screen);
439 switch (splash->visual->class) {
440 case TrueColor: {
441 int depth = XDefaultDepthOfScreen(splash->screen);
442
443 splash->byteAlignment = 1;
444 splash->maskRequired = shapeSupported;
445 initFormat(&splash->screenFormat, splash->visual->red_mask,
446 splash->visual->green_mask, splash->visual->blue_mask, 0);
447 splash->screenFormat.byteOrder =
448 (XImageByteOrder(splash->display) == LSBFirst ?
449 BYTE_ORDER_LSBFIRST : BYTE_ORDER_MSBFIRST);
450 splash->screenFormat.depthBytes = (depth + 7) / 8;
451 // TrueColor depth probably can't be less
452 // than 8 bits, and it's always byte padded
453 break;
454 }
455 case PseudoColor: {
456 int availableColors;
457 int numColors;
458 int numComponents[3];
459 unsigned long colorIndex[SPLASH_COLOR_MAP_SIZE];
460 XColor xColors[SPLASH_COLOR_MAP_SIZE];
461 int i;
462 int depth = XDefaultDepthOfScreen(splash->screen);
463 int scale = 65535 / MAX_COLOR_VALUE;
464
465 availableColors = GetNumAvailableColors(splash->display, splash->screen,
466 splash->visual->map_entries);
467 numColors = quantizeColors(availableColors, numComponents);
468 if (numColors > availableColors) {
469 // Could not allocate the color cells. Most probably
470 // the pool got exhausted. Disable the splash screen.
471 XCloseDisplay(splash->display);
472 splash->isVisible = -1;
473 splash->display = NULL;
474 splash->screen = NULL;
475 splash->visual = NULL;
476 fprintf(stderr, "Warning: unable to initialize the splashscreen. Not enough available color cells.\n");
477 return 0;
478 }
479 splash->cmap = AllocColors(splash->display, splash->screen,
480 numColors, colorIndex);
481 for (i = 0; i < numColors; i++) {
482 splash->colorIndex[i] = colorIndex[i];
483 }
484 initColorCube(numComponents, splash->colorMap, splash->dithers,
485 splash->colorIndex);
486 for (i = 0; i < numColors; i++) {
487 xColors[i].pixel = colorIndex[i];
488 xColors[i].red = (unsigned short)
489 QUAD_RED(splash->colorMap[colorIndex[i]]) * scale;
490 xColors[i].green = (unsigned short)
491 QUAD_GREEN(splash->colorMap[colorIndex[i]]) * scale;
492 xColors[i].blue = (unsigned short)
493 QUAD_BLUE(splash->colorMap[colorIndex[i]]) * scale;
494 xColors[i].flags = DoRed | DoGreen | DoBlue;
495 }
496 XStoreColors(splash->display, splash->cmap, xColors, numColors);
497 initFormat(&splash->screenFormat, 0, 0, 0, 0);
498 splash->screenFormat.colorIndex = splash->colorIndex;
499 splash->screenFormat.depthBytes = (depth + 7) / 8; // or always 8?
500 splash->screenFormat.colorMap = splash->colorMap;
501 splash->screenFormat.dithers = splash->dithers;
502 splash->screenFormat.numColors = numColors;
503 splash->screenFormat.byteOrder = BYTE_ORDER_NATIVE;
504 break;
505 }
506 default:
507 ; /* FIXME: should probably be fixed, but javaws splash screen doesn't support other visuals either */
508 }
509 return 1;
510}
511
512
513void
514SplashCleanupPlatform(Splash * splash) {
515 int i;
516
517 if (splash->frames) {
518 for (i = 0; i < splash->frameCount; i++) {
519 if (splash->frames[i].rects) {
520 free(splash->frames[i].rects);
521 splash->frames[i].rects = NULL;
522 }
523 }
524 }
525 splash->maskRequired = shapeSupported;
526}
527
528void
529SplashDonePlatform(Splash * splash) {
530 pthread_mutex_destroy(&splash->lock);
531 if (splash->cmap) {
532 unsigned long colorIndex[SPLASH_COLOR_MAP_SIZE];
533 int i;
534
535 for (i = 0; i < splash->screenFormat.numColors; i++) {
536 colorIndex[i] = splash->colorIndex[i];
537 }
538 FreeColors(splash->display, splash->screen,
539 splash->screenFormat.numColors, colorIndex);
540 }
541 if (splash->window)
542 XDestroyWindow(splash->display, splash->window);
543 if (splash->wmHints)
544 XFree(splash->wmHints);
545 if (splash->cursor)
546 XFreeCursor(splash->display, splash->cursor);
547 if (splash->display)
548 XCloseDisplay(splash->display);
549}
550
551void
552SplashEventLoop(Splash * splash) {
553
554 /* Different from win32 implementation - this loop
555 uses poll timeouts instead of a timer */
556 /* we should have splash _locked_ on entry!!! */
557
558 int xconn = XConnectionNumber(splash->display);
559
560 while (1) {
561 struct pollfd pfd[2];
562 int timeout = -1;
563 int ctl = splash->controlpipe[0];
564 int rc;
565 int pipes_empty;
566
567 pfd[0].fd = xconn;
568 pfd[0].events = POLLIN | POLLPRI;
569
570 pfd[1].fd = ctl;
571 pfd[1].events = POLLIN | POLLPRI;
572
573 errno = 0;
574 if (splash->isVisible>0 && SplashIsStillLooping(splash)) {
575 timeout = splash->time + splash->frames[splash->currentFrame].delay
576 - SplashTime();
577 if (timeout < 0) {
578 timeout = 0;
579 }
580 }
581 SplashUnlock(splash);
582 rc = poll(pfd, 2, timeout);
583 SplashLock(splash);
584 if (splash->isVisible > 0 && splash->currentFrame >= 0 &&
585 SplashTime() >= splash->time + splash->frames[splash->currentFrame].delay) {
586 SplashNextFrame(splash);
587 SplashUpdateShape(splash);
588 SplashRedrawWindow(splash);
589 }
590 if (rc <= 0) {
591 errno = 0;
592 continue;
593 }
594 pipes_empty = 0;
595 while(!pipes_empty) {
596 char buf;
597
598 pipes_empty = 1;
599 if (read(ctl, &buf, sizeof(buf)) > 0) {
600 pipes_empty = 0;
601 switch (buf) {
602 case SPLASHCTL_UPDATE:
603 if (splash->isVisible>0) {
604 SplashRedrawWindow(splash);
605 }
606 break;
607 case SPLASHCTL_RECONFIGURE:
608 if (splash->isVisible>0) {
609 SplashReconfigureNow(splash);
610 }
611 break;
612 case SPLASHCTL_QUIT:
613 return;
614 }
615 }
616 // we're not using "while(XPending)", processing one event
617 // at a time to avoid control pipe starvation
618 if (XPending(splash->display)) {
619 XEvent evt;
620
621 pipes_empty = 0;
622 XNextEvent(splash->display, &evt);
623 switch (evt.type) {
624 case Expose:
625 if (splash->isVisible>0) {
626 // we're doing full redraw so we just
627 // skip the remaining painting events in the queue
628 while(XCheckTypedEvent(splash->display, Expose,
629 &evt));
630 SplashRedrawWindow(splash);
631 }
632 break;
633 /* ... */
634 }
635 }
636 }
637 }
638}
639
640/* we can't use OverrideRedirect for the window as the window should not be
641 always-on-top, so we must set appropriate wm hints
642
643 this functions sets olwm, mwm and EWMH hints for undecorated window at once
644
645 It works for: mwm, openbox, wmaker, metacity, KWin (FIXME: test more wm's)
646 Should work for: fvwm2.5.x, blackbox, olwm
647 Maybe works for: enlightenment, icewm
648 Does not work for: twm, fvwm2.4.7
649
650*/
651
652void
653SplashRemoveDecoration(Splash * splash) {
654 Atom atom_set;
655 Atom atom_list[4];
656
657 /* the struct below was copied from MwmUtil.h */
658
659 struct PROPMOTIFWMHINTS {
660 /* 32-bit property items are stored as long on the client (whether
661 * that means 32 bits or 64). XChangeProperty handles the conversion
662 * to the actual 32-bit quantities sent to the server.
663 */
664 unsigned long flags;
665 unsigned long functions;
666 unsigned long decorations;
667 long inputMode;
668 unsigned long status;
669 }
670 mwm_hints;
671
672 /* WM_TAKE_FOCUS hint to avoid wm's transfer of focus to this window */
673 /* WM_DELETE_WINDOW hint to avoid closing this window with Alt-F4. See bug 6474035 */
674 atom_set = XInternAtom(splash->display, "WM_PROTOCOLS", True);
675 if (atom_set != None) {
676 atom_list[0] = XInternAtom(splash->display, "WM_TAKE_FOCUS", True);
677 atom_list[1] = XInternAtom(splash->display, "WM_DELETE_WINDOW", True);
678
679 XChangeProperty(splash->display, splash->window, atom_set, XA_ATOM, 32,
680 PropModeReplace, (unsigned char *) atom_list, 2);
681 }
682
683 /* mwm hints */
684 atom_set = XInternAtom(splash->display, "_MOTIF_WM_HINTS", True);
685 if (atom_set != None) {
686 /* flags for decoration and functions */
687 mwm_hints.flags = (1L << 1) | (1L << 0);
688 mwm_hints.decorations = 0;
689 mwm_hints.functions = 0;
690 XChangeProperty(splash->display, splash->window, atom_set, atom_set,
691 32, PropModeReplace, (unsigned char *) &mwm_hints, 5);
692 }
693
694 /* olwm hints */
695 atom_set = XInternAtom(splash->display, "_OL_DECOR_DEL", True);
696 if (atom_set != None) {
697 atom_list[0] = XInternAtom(splash->display, "_OL_DECOR_RESIZE", True);
698 atom_list[1] = XInternAtom(splash->display, "_OL_DECOR_HEADER", True);
699 atom_list[2] = XInternAtom(splash->display, "_OL_DECOR_PIN", True);
700 atom_list[3] = XInternAtom(splash->display, "_OL_DECOR_CLOSE", True);
701 XChangeProperty(splash->display, splash->window, atom_set, XA_ATOM, 32,
702 PropModeReplace, (unsigned char *) atom_list, 4);
703 }
704
705 /* generic EMWH hints
706 we do not set _NET_WM_WINDOW_TYPE to _NET_WM_WINDOW_TYPE_SPLASH
707 hint support due to gnome making this window always-on-top
708 so we have to set _NET_WM_STATE and _NET_WM_ALLOWED_ACTIONS correctly
709 _NET_WM_STATE: SKIP_TASKBAR and SKIP_PAGER
710 _NET_WM_ALLOWED_ACTIONS: disable all actions */
711 atom_set = XInternAtom(splash->display, "_NET_WM_STATE", True);
712 if (atom_set != None) {
713 atom_list[0] = XInternAtom(splash->display,
714 "_NET_WM_STATE_SKIP_TASKBAR", True);
715 atom_list[1] = XInternAtom(splash->display,
716 "_NET_WM_STATE_SKIP_PAGER", True);
717 XChangeProperty(splash->display, splash->window, atom_set, XA_ATOM, 32,
718 PropModeReplace, (unsigned char *) atom_list, 2);
719 }
720 atom_set = XInternAtom(splash->display, "_NET_WM_ALLOWED_ACTIONS", True);
721 if (atom_set != None) {
722 XChangeProperty(splash->display, splash->window, atom_set, XA_ATOM, 32,
723 PropModeReplace, (unsigned char *) atom_list, 0);
724 }
725}
726
727void
728SplashPThreadDestructor(void *arg) {
729 /* this will be used in case of emergency thread exit on xlib error */
730 Splash *splash = (Splash *) arg;
731
732 if (splash) {
733 SplashCleanup(splash);
734 }
735}
736
737void *
738SplashScreenThread(void *param) {
739 Splash *splash = (Splash *) param;
740// pthread_key_t key;
741
742// pthread_key_create(&key, SplashPThreadDestructor);
743// pthread_setspecific(key, splash);
744
745 SplashLock(splash);
746 pipe(splash->controlpipe);
747 fcntl(splash->controlpipe[0], F_SETFL,
748 fcntl(splash->controlpipe[0], F_GETFL, 0) | O_NONBLOCK);
749 splash->time = SplashTime();
750 SplashCreateWindow(splash);
751 fflush(stdout);
752 if (splash->window) {
753 SplashRemoveDecoration(splash);
754 XStoreName(splash->display, splash->window, "Java");
755 XMapRaised(splash->display, splash->window);
756 SplashUpdateShape(splash);
757 SplashRedrawWindow(splash);
758 //map the splash co-ordinates as per system scale
759 splash->x /= splash->scaleFactor;
760 splash->y /= splash->scaleFactor;
761 SplashEventLoop(splash);
762 }
763 SplashUnlock(splash);
764 SplashDone(splash);
765
766 splash->isVisible=-1;
767 return 0;
768}
769
770void
771SplashCreateThread(Splash * splash) {
772 pthread_t thr;
773 pthread_attr_t attr;
774 int rc;
775
776 pthread_attr_init(&attr);
777 rc = pthread_create(&thr, &attr, SplashScreenThread, (void *) splash);
778}
779
780void
781SplashLock(Splash * splash) {
782 pthread_mutex_lock(&splash->lock);
783}
784
785void
786SplashUnlock(Splash * splash) {
787 pthread_mutex_unlock(&splash->lock);
788}
789
790void
791SplashClosePlatform(Splash * splash) {
792 sendctl(splash, SPLASHCTL_QUIT);
793}
794
795void
796SplashUpdate(Splash * splash) {
797 sendctl(splash, SPLASHCTL_UPDATE);
798}
799
800void
801SplashReconfigure(Splash * splash) {
802 sendctl(splash, SPLASHCTL_RECONFIGURE);
803}
804
805JNIEXPORT jboolean
806SplashGetScaledImageName(const char* jarName, const char* fileName,
807 float *scaleFactor, char *scaledImgName,
808 const size_t scaledImageNameLength)
809{
810 *scaleFactor = 1;
811#ifndef __linux__
812 return JNI_FALSE;
813#endif
814 *scaleFactor = (float)getNativeScaleFactor(NULL);
815 return GetScaledImageName(fileName, scaledImgName, scaleFactor, scaledImageNameLength);
816}
817
818