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 47 static Bool shapeSupported; 48 static int shapeEventBase, shapeErrorBase; 49 50 void SplashRemoveDecoration(Splash * splash); 51 52 53 /* Could use npt but decided to cut down on linked code size */ 54 char* 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 } 101 done: 102 setlocale(LC_ALL, old_locale); 103 return buf; 104 } 105 106 void 107 SplashInitFrameShape(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 139 unsigned 140 SplashTime(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 152 void 153 msec2timeval(unsigned time, struct timeval *tv) { 154 tv->tv_sec = time / 1000; 155 tv->tv_usec = (time % 1000) * 1000; 156 } 157 158 int 159 GetNumAvailableColors(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 193 Colormap 194 AllocColors(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 203 void 204 FreeColors(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 211 static 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 239 static 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 252 void 253 SplashCreateWindow(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 */ 283 void 284 SplashUpdateShape(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 */ 297 void 298 SplashRevertShape(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 310 int 311 ByteOrderToX(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 324 void 325 SplashRedrawWindow(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 355 void 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 373 void 374 sendctl(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 381 int 382 HandleError(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 400 int 401 HandleIOError(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 408 int 409 SplashInitPlatform(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 513 void 514 SplashCleanupPlatform(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 528 void 529 SplashDonePlatform(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 551 void 552 SplashEventLoop(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 652 void 653 SplashRemoveDecoration(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 727 void 728 SplashPThreadDestructor(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 737 void * 738 SplashScreenThread(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 770 void 771 SplashCreateThread(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 780 void 781 SplashLock(Splash * splash) { 782 pthread_mutex_lock(&splash->lock); 783 } 784 785 void 786 SplashUnlock(Splash * splash) { 787 pthread_mutex_unlock(&splash->lock); 788 } 789 790 void 791 SplashClosePlatform(Splash * splash) { 792 sendctl(splash, SPLASHCTL_QUIT); 793 } 794 795 void 796 SplashUpdate(Splash * splash) { 797 sendctl(splash, SPLASHCTL_UPDATE); 798 } 799 800 void 801 SplashReconfigure(Splash * splash) { 802 sendctl(splash, SPLASHCTL_RECONFIGURE); 803 } 804 805 JNIEXPORT jboolean 806 SplashGetScaledImageName(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