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