Added
Link Here
|
1 |
/************************************************************************* |
2 |
* |
3 |
* OpenOffice.org - a multi-platform office productivity suite |
4 |
* |
5 |
* $RCSfile$ |
6 |
* |
7 |
* $Revision$ |
8 |
* |
9 |
* last change: $Author$ $Date$ |
10 |
* |
11 |
* The Contents of this file are made available subject to |
12 |
* the terms of GNU Lesser General Public License Version 2.1. |
13 |
* |
14 |
* |
15 |
* GNU Lesser General Public License Version 2.1 |
16 |
* ============================================= |
17 |
* Copyright 2005 by Sun Microsystems, Inc. |
18 |
* 901 San Antonio Road, Palo Alto, CA 94303, USA |
19 |
* |
20 |
* This library is free software; you can redistribute it and/or |
21 |
* modify it under the terms of the GNU Lesser General Public |
22 |
* License version 2.1, as published by the Free Software Foundation. |
23 |
* |
24 |
* This library is distributed in the hope that it will be useful, |
25 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
26 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
27 |
* Lesser General Public License for more details. |
28 |
* |
29 |
* You should have received a copy of the GNU Lesser General Public |
30 |
* License along with this library; if not, write to the Free Software |
31 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
32 |
* MA 02111-1307 USA |
33 |
* |
34 |
************************************************************************/ |
35 |
|
36 |
#include <X11/Xlib.h> |
37 |
#include <X11/Xatom.h> |
38 |
#include <X11/Xutil.h> |
39 |
|
40 |
#include <endian.h> |
41 |
#include <fcntl.h> |
42 |
#include <stdint.h> |
43 |
#include <stdio.h> |
44 |
#include <stdlib.h> |
45 |
#include <string.h> |
46 |
#include <unistd.h> |
47 |
|
48 |
#include "splashx.h" |
49 |
|
50 |
#define WINDOW_WIDTH 440 |
51 |
#define WINDOW_HEIGHT 299 |
52 |
|
53 |
#define PROGRESS_XOFFSET 12 |
54 |
#define PROGRESS_YOFFSET 18 |
55 |
#define PROGRESS_BARSPACE 2 |
56 |
|
57 |
static Display *display = NULL; |
58 |
static int screen; |
59 |
static int depth; |
60 |
static Visual *visual = NULL; |
61 |
|
62 |
static int width = WINDOW_WIDTH; |
63 |
static int height = WINDOW_HEIGHT; |
64 |
|
65 |
static Colormap color_map; |
66 |
static Window win; |
67 |
static GC gc; |
68 |
|
69 |
typedef struct { |
70 |
unsigned char b, g, r; |
71 |
} color_t; |
72 |
static color_t *bitmap = NULL; |
73 |
|
74 |
#define BMP_HEADER_LEN 14 |
75 |
#define WIN_INFO_LEN 40 |
76 |
|
77 |
#define UINT8( x ) ( (unsigned int)( ( (uint8_t *)( x ) )[0] ) ) |
78 |
|
79 |
#define UINT16( x ) ( ( (unsigned int)( ( (uint8_t *)( x ) )[0] ) ) + \ |
80 |
( ( (unsigned int)( ( (uint8_t *)( x ) )[1] ) ) << 8 ) ) |
81 |
|
82 |
#define UINT32( x ) ( ( (unsigned int)( ( (uint8_t *)( x ) )[0] ) ) + \ |
83 |
( ( (unsigned int)( ( (uint8_t *)( x ) )[1] ) ) << 8 ) + \ |
84 |
( ( (unsigned int)( ( (uint8_t *)( x ) )[2] ) ) << 16 ) + \ |
85 |
( ( (unsigned int)( ( (uint8_t *)( x ) )[3] ) ) << 24 ) ) |
86 |
|
87 |
#define MAX( x, y ) ( ( (x) > (y) )? (x): (y) ) |
88 |
|
89 |
#define LOAD_FAILURE( msg ) \ |
90 |
{ \ |
91 |
fprintf( stderr, "%s: " msg, filename ); \ |
92 |
close( fd ); \ |
93 |
return 0; \ |
94 |
} |
95 |
|
96 |
// Load the specified Windows 24bit BMP to 'bitmap' |
97 |
// Return: 1 - success, 0 - failure |
98 |
int splash_load_bmp( char *filename ) |
99 |
{ |
100 |
int fd = open( filename, O_RDONLY ); |
101 |
if ( fd < 0 ) |
102 |
return 0; |
103 |
|
104 |
char file_header[ BMP_HEADER_LEN ]; |
105 |
|
106 |
if ( read( fd, file_header, BMP_HEADER_LEN ) != BMP_HEADER_LEN || file_header[0] != 'B' || file_header[1] != 'M' ) |
107 |
LOAD_FAILURE( "Not a bitmap.\n" ); |
108 |
|
109 |
int file_size = UINT32( file_header + 2 ); |
110 |
|
111 |
char info_header[ WIN_INFO_LEN ]; |
112 |
if ( read( fd, info_header, 4 ) != 4 ) |
113 |
LOAD_FAILURE( "Unable to read the header.\n" ); |
114 |
|
115 |
int header_size = UINT32( info_header ); |
116 |
if ( header_size != WIN_INFO_LEN ) |
117 |
LOAD_FAILURE( "Not a Windows bitmap.\n" ); |
118 |
|
119 |
if ( read( fd, info_header + 4, WIN_INFO_LEN - 4 ) != WIN_INFO_LEN - 4 ) |
120 |
LOAD_FAILURE( "The header ended too early.\n" ); |
121 |
|
122 |
width = UINT32( info_header + 4 ); |
123 |
height = UINT32( info_header + 8 ); |
124 |
|
125 |
int bits = UINT16( info_header + 14 ); |
126 |
int compression = UINT16( info_header + 16 ); |
127 |
|
128 |
if ( bits != 24 ) |
129 |
LOAD_FAILURE( "Just 24 bpp bitmaps are supported.\n" ); |
130 |
|
131 |
if ( compression != 0 ) |
132 |
LOAD_FAILURE( "Just uncompressed bitmaps are supported.\n" ); |
133 |
|
134 |
size_t bitmap_size = width * height * 3; |
135 |
bitmap = malloc( bitmap_size ); |
136 |
if ( bitmap == NULL ) |
137 |
LOAD_FAILURE( "Cannot allocate memory for the data.\n" ); |
138 |
|
139 |
int y; |
140 |
size_t line_size = width * 3; |
141 |
color_t *line = bitmap + ( height - 1 ) * width; |
142 |
for ( y = height; y > 0; --y, line -= width ) |
143 |
{ |
144 |
if ( read( fd, line, line_size ) != line_size ) |
145 |
LOAD_FAILURE( "Cannot read the bitmap data.\n" ); |
146 |
} |
147 |
|
148 |
close( fd ); |
149 |
return 1; |
150 |
} |
151 |
|
152 |
// Universal shift: bits >= 0 - left, otherwise right |
153 |
#define SHIFT( x, bits ) ( ( (bits) >= 0 )? ( (x) << (bits) ): ( (x) >> -(bits) ) ) |
154 |
|
155 |
// Position of the highest bit (more or less integer log2) |
156 |
inline int HIGHEST_BIT( unsigned long x ) |
157 |
{ |
158 |
int i = 0; |
159 |
for ( ; x; ++i ) |
160 |
x >>= 1; |
161 |
|
162 |
return i; |
163 |
} |
164 |
|
165 |
// Number of bits set to 1 |
166 |
inline int BITS( unsigned long x ) |
167 |
{ |
168 |
int i = 0; |
169 |
for ( ; x; x >>= 1 ) |
170 |
if ( x & 1UL ) |
171 |
++i; |
172 |
|
173 |
return i; |
174 |
} |
175 |
|
176 |
// Set 'bitmap' as the background of our 'win' window |
177 |
static void create_pixmap() |
178 |
{ |
179 |
if ( !bitmap ) |
180 |
return; |
181 |
|
182 |
Pixmap pixmap = XCreatePixmap( display, win, width, height, depth ); |
183 |
|
184 |
unsigned long value_mask = 0; |
185 |
XGCValues values; |
186 |
GC pixmap_gc = XCreateGC( display, pixmap, value_mask, &values ); |
187 |
|
188 |
if ( visual->class == TrueColor ) |
189 |
{ |
190 |
unsigned long red_mask = visual->red_mask; |
191 |
unsigned long green_mask = visual->green_mask; |
192 |
unsigned long blue_mask = visual->blue_mask; |
193 |
|
194 |
unsigned long red_delta_mask = ( 1UL << ( 8 - BITS( red_mask ) ) ) - 1; |
195 |
unsigned long green_delta_mask = ( 1UL << ( 8 - BITS( green_mask ) ) ) - 1; |
196 |
unsigned long blue_delta_mask = ( 1UL << ( 8 - BITS( blue_mask ) ) ) - 1; |
197 |
|
198 |
int red_shift = HIGHEST_BIT( red_mask ) - 8; |
199 |
int green_shift = HIGHEST_BIT( green_mask ) - 8; |
200 |
int blue_shift = HIGHEST_BIT( blue_mask ) - 8; |
201 |
|
202 |
XImage *image = XCreateImage( display, visual, depth, ZPixmap, |
203 |
0, NULL, width, height, 32, 0 ); |
204 |
|
205 |
int bytes_per_line = image->bytes_per_line; |
206 |
int bpp = image->bits_per_pixel; |
207 |
int byte_order = image->byte_order; |
208 |
int machine_byte_order = ( __BYTE_ORDER == __LITTLE_ENDIAN )? LSBFirst: MSBFirst; |
209 |
|
210 |
if ( __BYTE_ORDER != __LITTLE_ENDIAN && __BYTE_ORDER != __BIG_ENDIAN ) |
211 |
{ |
212 |
fprintf( stderr, "Unsupported machine endianity.\n" ); |
213 |
XFreeGC( display, pixmap_gc ); |
214 |
XFreePixmap( display, pixmap ); |
215 |
XDestroyImage( image ); |
216 |
return; |
217 |
} |
218 |
|
219 |
char *data = malloc( height * bytes_per_line ); |
220 |
image->data = data; |
221 |
|
222 |
// The following dithers & converts the color_t color to one |
223 |
// acceptable for the visual |
224 |
#define COPY_IN_OUT( code ) \ |
225 |
{ \ |
226 |
int x, y; \ |
227 |
for ( y = 0; y < height; ++y ) \ |
228 |
{ \ |
229 |
unsigned long red_delta = 0, green_delta = 0, blue_delta = 0; \ |
230 |
for ( x = 0; x < width; ++x, ++in ) \ |
231 |
{ \ |
232 |
unsigned long red = in->r + red_delta; \ |
233 |
unsigned long green = in->g + green_delta; \ |
234 |
unsigned long blue = in->b + blue_delta; \ |
235 |
red_delta = red & red_delta_mask; \ |
236 |
green_delta = green & green_delta_mask; \ |
237 |
blue_delta = blue & blue_delta_mask; \ |
238 |
if ( red > 255 ) \ |
239 |
red = 255; \ |
240 |
if ( green > 255 ) \ |
241 |
green = 255; \ |
242 |
if ( blue > 255 ) \ |
243 |
blue = 255; \ |
244 |
unsigned long pixel = \ |
245 |
( SHIFT( red, red_shift ) & red_mask ) | \ |
246 |
( SHIFT( green, green_shift ) & green_mask ) | \ |
247 |
( SHIFT( blue, blue_shift ) & blue_mask ); \ |
248 |
code \ |
249 |
} \ |
250 |
} \ |
251 |
} |
252 |
|
253 |
color_t *in = bitmap; |
254 |
char *out = data; |
255 |
|
256 |
if ( bpp == 32 ) |
257 |
{ |
258 |
if ( machine_byte_order == byte_order ) |
259 |
COPY_IN_OUT( *( (uint32_t *)out ) = (uint32_t)pixel; out += 4; ) |
260 |
else |
261 |
COPY_IN_OUT( uint32_t tmp = pixel; |
262 |
*( (uint8_t *)out ) = *( (uint8_t *)(&tmp) + 3 ); |
263 |
*( (uint8_t *)out + 1 ) = *( (uint8_t *)(&tmp) + 2 ); |
264 |
*( (uint8_t *)out + 2 ) = *( (uint8_t *)(&tmp) + 1 ); |
265 |
*( (uint8_t *)out + 3 ) = *( (uint8_t *)(&tmp) ); |
266 |
out += 4; ) |
267 |
} |
268 |
else if ( bpp == 24 ) |
269 |
{ |
270 |
if ( machine_byte_order == byte_order && byte_order == LSBFirst ) |
271 |
COPY_IN_OUT( *( (color_t *)out ) = *( (color_t *)( &pixel ) ); out += 3; ) |
272 |
if ( machine_byte_order == byte_order && byte_order == MSBFirst ) |
273 |
COPY_IN_OUT( uint32_t tmp = pixel; |
274 |
*( (uint8_t *)out ) = *( (uint8_t *)(&tmp) + 1 ); |
275 |
*( (uint8_t *)out + 1 ) = *( (uint8_t *)(&tmp) + 2 ); |
276 |
*( (uint8_t *)out + 2 ) = *( (uint8_t *)(&tmp) + 3 ); |
277 |
out += 3; ) |
278 |
else |
279 |
COPY_IN_OUT( uint32_t tmp = pixel; |
280 |
*( (uint8_t *)out ) = *( (uint8_t *)(&tmp) + 3 ); |
281 |
*( (uint8_t *)out + 1 ) = *( (uint8_t *)(&tmp) + 2 ); |
282 |
*( (uint8_t *)out + 2 ) = *( (uint8_t *)(&tmp) + 1 ); |
283 |
out += 3; ) |
284 |
} |
285 |
else if ( bpp == 16 ) |
286 |
{ |
287 |
if ( machine_byte_order == byte_order ) |
288 |
COPY_IN_OUT( *( (uint16_t *)out ) = (uint16_t)pixel; out += 2; ) |
289 |
else |
290 |
COPY_IN_OUT( uint16_t tmp = pixel; |
291 |
*( (uint8_t *)out ) = *( (uint8_t *)(&tmp) + 1 ); |
292 |
*( (uint8_t *)out + 1 ) = *( (uint8_t *)(&tmp) ); |
293 |
out += 2; ); |
294 |
} |
295 |
else if ( bpp == 8 ) |
296 |
{ |
297 |
COPY_IN_OUT( *( (uint8_t *)out ) = (uint8_t)pixel; ++out; ) |
298 |
} |
299 |
else |
300 |
{ |
301 |
fprintf( stderr, "Unsupported depth: %d bits per pixel.\n", bpp ); |
302 |
XFreeGC( display, pixmap_gc ); |
303 |
XFreePixmap( display, pixmap ); |
304 |
XDestroyImage( image ); |
305 |
return; |
306 |
} |
307 |
|
308 |
#undef COPY_IN_OUT |
309 |
|
310 |
XPutImage( display, pixmap, pixmap_gc, image, 0, 0, 0, 0, width, height ); |
311 |
XDestroyImage( image ); |
312 |
} |
313 |
else //if ( depth == 1 || visual->class == DirectColor ) |
314 |
{ |
315 |
// FIXME Something like the following, but faster ;-) - XDrawPoint is not |
316 |
// a good idea... |
317 |
int x, y; |
318 |
for ( y = 0; y < height; ++y ) |
319 |
{ |
320 |
color_t *color = bitmap + y * width; |
321 |
|
322 |
int delta = 0; |
323 |
for ( x = 0; x < width; ++x, ++color ) |
324 |
{ |
325 |
int rnd = (int)( ( (long)( random() - RAND_MAX/2 ) * 32000 )/RAND_MAX ); |
326 |
int luminance = delta + rnd + 299 * (int)color->r + 587 * (int)color->g + 114 * (int)color->b; |
327 |
|
328 |
if ( luminance < 128000 ) |
329 |
{ |
330 |
XSetForeground( display, pixmap_gc, BlackPixel( display, screen ) ); |
331 |
delta = luminance; |
332 |
} |
333 |
else |
334 |
{ |
335 |
XSetForeground( display, pixmap_gc, WhitePixel( display, screen ) ); |
336 |
delta = luminance - 255000; |
337 |
} |
338 |
|
339 |
XDrawPoint( display, pixmap, pixmap_gc, x, y ); |
340 |
} |
341 |
} |
342 |
} |
343 |
|
344 |
XSetWindowBackgroundPixmap( display, win, pixmap ); |
345 |
|
346 |
XFreeGC( display, pixmap_gc ); |
347 |
XFreePixmap( display, pixmap ); |
348 |
} |
349 |
|
350 |
// The old method of hiding the window decorations |
351 |
static void suppress_decorations_motif() |
352 |
{ |
353 |
struct { |
354 |
unsigned long flags, functions, decorations; |
355 |
long input_mode; |
356 |
unsigned long status; |
357 |
} mwmhints; |
358 |
|
359 |
Atom a = XInternAtom( display, "_MOTIF_WM_HINTS", False ); |
360 |
|
361 |
mwmhints.flags = 15; // functions, decorations, input_mode, status |
362 |
mwmhints.functions = 2; // ? |
363 |
mwmhints.decorations = 0; |
364 |
mwmhints.input_mode = 0; |
365 |
|
366 |
XChangeProperty( display, win, a, a, 32, |
367 |
PropModeReplace, (unsigned char*)&mwmhints, 5 ); |
368 |
} |
369 |
|
370 |
// This is a splash, set it as such. |
371 |
// If it fails, just hide the decorations... |
372 |
static void suppress_decorations() |
373 |
{ |
374 |
Atom atom_type = XInternAtom( display, "_NET_WM_WINDOW_TYPE", True ); |
375 |
Atom atom_splash = XInternAtom( display, "_NET_WM_WINDOW_TYPE_SPLASH", True ); |
376 |
|
377 |
if ( atom_type != None && atom_splash != None ) |
378 |
XChangeProperty( display, win, atom_type, XA_ATOM, 32, |
379 |
PropModeReplace, (unsigned char*)&atom_splash, 1 ); |
380 |
//else |
381 |
suppress_decorations_motif(); // FIXME: Unconditional until Metacity/compiz's SPLASH handling is fixed |
382 |
} |
383 |
|
384 |
// Create the window |
385 |
// Return: 1 - success, 0 - failure |
386 |
int splash_create_window( int argc, char** argv ) |
387 |
{ |
388 |
char *display_name = NULL; |
389 |
int i; |
390 |
for ( i = 0; i < argc; i++ ) |
391 |
{ |
392 |
if ( !strcmp( argv[i], "-display" ) || !strcmp( argv[i], "--display" ) ) |
393 |
display_name = ( i + 1 < argc )? argv[i+1]: NULL; |
394 |
} |
395 |
|
396 |
if ( !display_name ) |
397 |
display_name = getenv( "DISPLAY" ); |
398 |
|
399 |
// init display |
400 |
display = XOpenDisplay( display_name ); |
401 |
if ( !display ) |
402 |
{ |
403 |
fprintf( stderr, "Failed to open display\n" ); |
404 |
return 0; |
405 |
} |
406 |
|
407 |
// create the window |
408 |
screen = DefaultScreen( display ); |
409 |
depth = DefaultDepth( display, screen ); |
410 |
color_map = DefaultColormap( display, screen ); |
411 |
visual = DefaultVisual( display, screen ); |
412 |
|
413 |
Window root_win = RootWindow( display, screen ); |
414 |
int display_width = DisplayWidth( display, screen ); |
415 |
int display_height = DisplayHeight( display, screen ); |
416 |
|
417 |
win = XCreateSimpleWindow( display, root_win, |
418 |
( display_width - width ) / 2, ( display_height - height ) / 2, |
419 |
width, height, 0, |
420 |
BlackPixel( display, screen ), BlackPixel( display, screen ) ); |
421 |
|
422 |
XSetWindowColormap( display, win, color_map ); |
423 |
|
424 |
// FIXME Do we want an own colormap for 8bpp displays? |
425 |
|
426 |
// not resizable, no decorations, etc. |
427 |
unsigned long value_mask = 0; |
428 |
XGCValues values; |
429 |
gc = XCreateGC( display, win, value_mask, &values ); |
430 |
|
431 |
XSizeHints size_hints; |
432 |
size_hints.flags = PPosition | PSize | PMinSize | PMaxSize; |
433 |
size_hints.min_width = width; |
434 |
size_hints.max_width = width; |
435 |
size_hints.min_height = height; |
436 |
size_hints.max_height = height; |
437 |
|
438 |
char *name = "OpenOffice.org"; |
439 |
char *icon = "icon"; // FIXME |
440 |
|
441 |
XSetStandardProperties( display, win, name, icon, None, |
442 |
0, 0, &size_hints ); |
443 |
|
444 |
// the actual work |
445 |
suppress_decorations(); |
446 |
create_pixmap(); |
447 |
|
448 |
// show it |
449 |
XSelectInput( display, win, 0 ); |
450 |
XMapWindow( display, win ); |
451 |
|
452 |
return 1; |
453 |
} |
454 |
|
455 |
// Re-draw & rocess the events |
456 |
// Just throwing them away - we do not need anything more... |
457 |
static void process_events() |
458 |
{ |
459 |
XEvent xev; |
460 |
int num_events; |
461 |
|
462 |
XFlush( display ); |
463 |
num_events = XPending( display ); |
464 |
while ( num_events > 0 ) |
465 |
{ |
466 |
num_events--; |
467 |
XNextEvent( display, &xev ); |
468 |
//process_event(xev); |
469 |
} |
470 |
} |
471 |
|
472 |
// Draw the progress |
473 |
void splash_draw_progress( int progress ) |
474 |
{ |
475 |
// values taken from desktop/source/splash/splash.cxx |
476 |
static int tlx = 212; |
477 |
static int tly = 216; |
478 |
static int barwidth = 263; |
479 |
static int barheight = 8; |
480 |
static int barspace = PROGRESS_BARSPACE; |
481 |
static int initialized = 0; |
482 |
if ( !initialized ) |
483 |
{ |
484 |
if ( width <= 500) |
485 |
{ |
486 |
barwidth = width - (2 * PROGRESS_XOFFSET); |
487 |
barheight = 6; |
488 |
tlx = PROGRESS_XOFFSET; |
489 |
tly = height - PROGRESS_YOFFSET; |
490 |
} |
491 |
initialized = 1; |
492 |
} |
493 |
|
494 |
// sanity |
495 |
if ( progress < 0 ) |
496 |
progress = 0; |
497 |
if ( progress > 100 ) |
498 |
progress = 100; |
499 |
|
500 |
// draw progress... |
501 |
int length = ( progress * barwidth / 100 ) - ( 2 * barspace ); |
502 |
if (length < 0) |
503 |
length = 0; |
504 |
|
505 |
// border |
506 |
XSetForeground( display, gc, WhitePixel( display, screen ) ); |
507 |
XDrawRectangle( display, win, gc, |
508 |
tlx, tly, |
509 |
barwidth, barheight ); |
510 |
|
511 |
// progress bar |
512 |
XSetForeground( display, gc, WhitePixel( display, screen ) ); |
513 |
XFillRectangle( display, win, gc, |
514 |
tlx + barspace, tly + barspace, |
515 |
length + 1, barheight - 2*barspace + 1 ); |
516 |
|
517 |
// pending events |
518 |
process_events(); |
519 |
} |
520 |
|
521 |
// Close the window & cleanup |
522 |
void splash_close_window() |
523 |
{ |
524 |
XCloseDisplay( display ); |
525 |
|
526 |
free( bitmap ); |
527 |
bitmap = NULL; |
528 |
} |