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 */
SplashConvertStringAlloc(const char * in,int * 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
SplashInitFrameShape(Splash * splash,int imageIndex)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
SplashTime(void)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
msec2timeval(unsigned time,struct timeval * tv)152 msec2timeval(unsigned time, struct timeval *tv) {
153 tv->tv_sec = time / 1000;
154 tv->tv_usec = (time % 1000) * 1000;
155 }
156
157 int
GetNumAvailableColors(Display * display,Screen * screen,unsigned map_entries)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
AllocColors(Display * display,Screen * screen,int numColors,unsigned long * pr)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
FreeColors(Display * display,Screen * screen,int numColors,unsigned long * pr)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
SplashCenter(Splash * splash)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
SplashUpdateSizeHints(Splash * splash)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
SplashCreateWindow(Splash * splash)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
SplashUpdateShape(Splash * splash)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
SplashRevertShape(Splash * splash)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
ByteOrderToX(int byteOrder)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
SplashRedrawWindow(Splash * splash)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
SplashReconfigureNow(Splash * splash)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
sendctl(Splash * splash,char code)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
HandleError(Display * disp,XErrorEvent * err)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
HandleIOError(Display * display)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
SplashInitPlatform(Splash * splash)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
SplashCleanupPlatform(Splash * splash)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
SplashDonePlatform(Splash * splash)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
SplashEventLoop(Splash * splash)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
SplashRemoveDecoration(Splash * splash)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
SplashPThreadDestructor(void * arg)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 *
SplashScreenThread(void * param)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 SplashEventLoop(splash);
757 }
758 SplashUnlock(splash);
759 SplashDone(splash);
760
761 splash->isVisible=-1;
762 return 0;
763 }
764
765 void
SplashCreateThread(Splash * splash)766 SplashCreateThread(Splash * splash) {
767 pthread_t thr;
768 pthread_attr_t attr;
769 int rc;
770
771 pthread_attr_init(&attr);
772 rc = pthread_create(&thr, &attr, SplashScreenThread, (void *) splash);
773 }
774
775 void
SplashLock(Splash * splash)776 SplashLock(Splash * splash) {
777 pthread_mutex_lock(&splash->lock);
778 }
779
780 void
SplashUnlock(Splash * splash)781 SplashUnlock(Splash * splash) {
782 pthread_mutex_unlock(&splash->lock);
783 }
784
785 void
SplashClosePlatform(Splash * splash)786 SplashClosePlatform(Splash * splash) {
787 sendctl(splash, SPLASHCTL_QUIT);
788 }
789
790 void
SplashUpdate(Splash * splash)791 SplashUpdate(Splash * splash) {
792 sendctl(splash, SPLASHCTL_UPDATE);
793 }
794
795 void
SplashReconfigure(Splash * splash)796 SplashReconfigure(Splash * splash) {
797 sendctl(splash, SPLASHCTL_RECONFIGURE);
798 }
799
800 SPLASHEXPORT char*
SplashGetScaledImageName(const char * jarName,const char * fileName,float * scaleFactor)801 SplashGetScaledImageName(const char* jarName, const char* fileName,
802 float *scaleFactor)
803 {
804 *scaleFactor = 1;
805 return NULL;
806 }
807