--- /dev/null	2006-06-16 15:54:00.000000000 +0200
+++ desktop/unx/source/makefile.mk	2006-08-18 16:31:10.000000000 +0200
@@ -0,0 +1,32 @@
+PRJ=..$/..
+PRJNAME=desktop
+TARGET=ooqstart
+
+NO_DEFAULT_STL=TRUE
+
+.INCLUDE :  settings.mk
+
+.IF "$(ENABLE_GTK)" != "TRUE"
+dummy:
+	@echo "Nothing to build. GUIBASE == $(GUIBASE)"
+
+.ELSE # we need glib...
+
+PKGCONFIG_MODULES=glib-2.0
+.INCLUDE: pkg_config.mk
+
+CFLAGS+= $(PKGCONFIG_CFLAGS)
+STDLIB=
+
+APP1TARGET = $(TARGET)
+APP1OBJS   = $(OBJ)$/splashx.obj $(OBJ)$/start.obj
+APP1NOSAL  = TRUE
+APP1LIBSALCPPRT=
+APP1CODETYPE = C
+APP1STDLIBS = $(PKGCONFIG_LIBS) -lX11 -lsal$(DLLPOSTFIX)
+
+.ENDIF
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE :	target.mk
--- /dev/null	2006-06-16 15:54:00.000000000 +0200
+++ desktop/unx/source/splashx.c	2006-08-18 16:12:34.000000000 +0200
@@ -0,0 +1,570 @@
+/*************************************************************************
+ *
+ *  OpenOffice.org - a multi-platform office productivity suite
+ *
+ *  $RCSfile: unxsplash-desktop-unx-source.diff,v $
+ *
+ *  $Revision: 1.3 $
+ *
+ *  last change: $Author: jholesovsky $ $Date: 2006/08/18 14:53:25 $
+ *
+ *  The Contents of this file are made available subject to
+ *  the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ *    GNU Lesser General Public License Version 2.1
+ *    =============================================
+ *    Copyright 2005 by Sun Microsystems, Inc.
+ *    901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ *    This library is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU Lesser General Public
+ *    License version 2.1, as published by the Free Software Foundation.
+ *
+ *    This library is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *    Lesser General Public License for more details.
+ *
+ *    You should have received a copy of the GNU Lesser General Public
+ *    License along with this library; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *    MA  02111-1307  USA
+ *
+ ************************************************************************/
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+
+#include "osl/endian.h"
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "splashx.h"
+
+typedef struct {
+	unsigned char b, g, r;
+} color_t;
+
+#define WINDOW_WIDTH  440
+#define WINDOW_HEIGHT 299
+
+#define PROGRESS_XOFFSET 12
+#define PROGRESS_YOFFSET 18
+#define PROGRESS_BARSPACE 2
+
+static Display *display = NULL;
+static int screen;
+static int depth;
+static Visual *visual = NULL;
+
+static int width = WINDOW_WIDTH;
+static int height = WINDOW_HEIGHT;
+
+static Colormap color_map;
+static Window win;
+static GC gc;
+
+// Progress bar values
+// taken from desktop/source/splash/splash.cxx
+static int tlx = 212;
+static int tly = 216;
+static int barwidth = 263;
+static int barheight = 8;
+static int barspace = PROGRESS_BARSPACE;
+static color_t barcol = { 18, 202, 157 };
+static color_t framecol = { 0xD3, 0xD3, 0xD3 };
+
+static XColor barcolor;
+static XColor framecolor;
+
+static color_t *bitmap = NULL;
+
+#define BMP_HEADER_LEN 14
+#define WIN_INFO_LEN 40
+
+#define UINT8( x )      ( (unsigned int)( ( (uint8_t *)( x ) )[0] ) )
+
+#define UINT16( x ) (   ( (unsigned int)( ( (uint8_t *)( x ) )[0] ) ) + \
+                      ( ( (unsigned int)( ( (uint8_t *)( x ) )[1] ) ) << 8 ) )
+
+#define UINT32( x ) (   ( (unsigned int)( ( (uint8_t *)( x ) )[0] ) ) + \
+                      ( ( (unsigned int)( ( (uint8_t *)( x ) )[1] ) ) << 8  ) + \
+                      ( ( (unsigned int)( ( (uint8_t *)( x ) )[2] ) ) << 16 ) + \
+                      ( ( (unsigned int)( ( (uint8_t *)( x ) )[3] ) ) << 24 ) )
+
+#define MAX( x, y ) ( ( (x) > (y) )? (x): (y) )
+
+#define LOAD_FAILURE( msg ) \
+	{ \
+		fprintf( stderr, "%s: " msg, filename ); \
+		close( fd ); \
+		return 0; \
+	}
+
+// Load the specified Windows 24bit BMP to 'bitmap'
+// Return: 1 - success, 0 - failure
+int splash_load_bmp( char *filename )
+{
+	int fd = open( filename, O_RDONLY );
+	if ( fd < 0 )
+		return 0;
+
+	char file_header[ BMP_HEADER_LEN ];
+	
+	if ( read( fd, file_header, BMP_HEADER_LEN ) != BMP_HEADER_LEN || file_header[0] != 'B' || file_header[1] != 'M' )
+		LOAD_FAILURE( "Not a bitmap.\n" );
+
+	int file_size = UINT32( file_header + 2 );
+	
+	char info_header[ WIN_INFO_LEN ];
+	if ( read( fd, info_header, 4 ) != 4 )
+		LOAD_FAILURE( "Unable to read the header.\n" );
+
+	int header_size = UINT32( info_header );
+	if ( header_size != WIN_INFO_LEN )
+		LOAD_FAILURE( "Not a Windows bitmap.\n" );
+
+	if ( read( fd, info_header + 4, WIN_INFO_LEN - 4 ) != WIN_INFO_LEN - 4 )
+		LOAD_FAILURE( "The header ended too early.\n" );
+
+	width = UINT32( info_header + 4 );
+	height = UINT32( info_header + 8 );
+
+	int bits = UINT16( info_header + 14 );
+	int compression = UINT16( info_header + 16 );
+
+	if ( bits != 24 )
+		LOAD_FAILURE( "Just 24 bpp bitmaps are supported.\n" );
+
+	if ( compression != 0 )
+		LOAD_FAILURE( "Just uncompressed bitmaps are supported.\n" );
+
+	size_t bitmap_size = width * height * 3;
+	bitmap = malloc( bitmap_size );
+	if ( bitmap == NULL )
+		LOAD_FAILURE( "Cannot allocate memory for the data.\n" );
+
+	if ( read( fd, bitmap, bitmap_size ) != bitmap_size )
+		LOAD_FAILURE( "Cannot read the bitmap data.\n" );
+
+	close( fd );
+	return 1;
+}
+
+static void setup_color( int val[3], color_t *col )
+{
+	if ( val[0] < 0 || val[1] < 0 || val[2] < 0 )
+		return;
+
+#define CONVERT_COLOR(from,to) if (from < 0) to = 0; else if (from > 255) to = 255; else to = from;
+	CONVERT_COLOR (val[0], col->r);
+	CONVERT_COLOR (val[1], col->g);
+	CONVERT_COLOR (val[2], col->b);
+#undef CONVERT_COLOR
+}
+
+// setup
+void splash_setup( int barc[3], int framec[3], int posx, int posy, int w, int h )
+{
+	if ( width <= 500)
+	{
+		barwidth  = width - (2 * PROGRESS_XOFFSET);
+		barheight = 6;
+		tlx = PROGRESS_XOFFSET;
+		tly = height - PROGRESS_YOFFSET;
+
+		barcol.r = 0;
+		barcol.g = 0;
+		barcol.b = 128;
+	}
+
+	if ( posx >= 0 )
+		tlx = posx;
+	if ( posy >= 0 )
+		tly = posy;
+	if ( w >= 0 )
+		barwidth = w;
+	if ( h >= 0 )
+		barheight = h;
+
+	setup_color( barc, &barcol );
+	setup_color( framec, &framecol );
+}
+
+// Universal shift: bits >= 0 - left, otherwise right
+#define SHIFT( x, bits ) ( ( (bits) >= 0 )? ( (x) << (bits) ): ( (x) >> -(bits) ) )
+
+// Position of the highest bit (more or less integer log2)
+inline int HIGHEST_BIT( unsigned long x )
+{
+	int i = 0;
+	for ( ; x; ++i )
+		x >>= 1;
+
+	return i;
+}
+
+// Number of bits set to 1
+inline int BITS( unsigned long x )
+{
+	int i = 0;
+	for ( ; x; x >>= 1 )
+		if ( x & 1UL )
+			++i;
+
+	return i;
+}
+
+// Set 'bitmap' as the background of our 'win' window
+static void create_pixmap()
+{
+	if ( !bitmap )
+		return;
+
+	Pixmap pixmap = XCreatePixmap( display, win, width, height, depth );
+
+	unsigned long value_mask = 0;
+	XGCValues values;
+	GC pixmap_gc = XCreateGC( display, pixmap, value_mask, &values );
+
+	if ( visual->class == TrueColor )
+	{
+		unsigned long red_mask   = visual->red_mask;
+		unsigned long green_mask = visual->green_mask;
+		unsigned long blue_mask  = visual->blue_mask;
+
+		unsigned long red_delta_mask   = ( 1UL << ( 8 - BITS( red_mask ) ) ) - 1;
+		unsigned long green_delta_mask = ( 1UL << ( 8 - BITS( green_mask ) ) ) - 1;
+		unsigned long blue_delta_mask  = ( 1UL << ( 8 - BITS( blue_mask ) ) ) - 1;
+
+		int red_shift   = HIGHEST_BIT( red_mask ) - 8;
+		int green_shift = HIGHEST_BIT( green_mask ) - 8;
+		int blue_shift  = HIGHEST_BIT( blue_mask ) - 8;
+
+		XImage *image = XCreateImage( display, visual, depth, ZPixmap,
+				0, NULL, width, height, 32, 0 );
+
+		int bytes_per_line = image->bytes_per_line;
+		int bpp = image->bits_per_pixel;
+		int byte_order = image->byte_order; 
+		int machine_byte_order;
+#if defined( _LITTLE_ENDIAN )
+		machine_byte_order = LSBFirst;
+#elif defined( _BIG_ENDIAN )
+		machine_byte_order = MSBFirst;
+#else
+		{
+			fprintf( stderr, "Unsupported machine endianity.\n" );
+			XFreeGC( display, pixmap_gc );
+			XFreePixmap( display, pixmap );
+			XDestroyImage( image );
+			return;
+		}
+#endif
+
+		char *data = malloc( height * bytes_per_line );
+		image->data = data;
+
+		// The following dithers & converts the color_t color to one
+		// acceptable for the visual
+#define COPY_IN_OUT( pix_size, code ) \
+		{ \
+			out += pix_size * width * ( height - 1 ); \
+			int x, y; \
+			for ( y = 0; y < height; ++y ) \
+			{ \
+				unsigned long red_delta = 0, green_delta = 0, blue_delta = 0; \
+				for ( x = 0; x < width; ++x, ++in  ) \
+				{ \
+					unsigned long red   = in->r + red_delta; \
+					unsigned long green = in->g + green_delta; \
+					unsigned long blue  = in->b + blue_delta; \
+					red_delta = red & red_delta_mask; \
+					green_delta = green & green_delta_mask; \
+					blue_delta = blue & blue_delta_mask; \
+					if ( red > 255 ) \
+						red = 255; \
+					if ( green > 255 ) \
+						green = 255; \
+					if ( blue > 255 ) \
+						blue = 255; \
+					unsigned long pixel = \
+						( SHIFT( red, red_shift ) & red_mask ) | \
+						( SHIFT( green, green_shift ) & green_mask ) | \
+						( SHIFT( blue, blue_shift ) & blue_mask ); \
+					code \
+				} \
+				out -= 2 * pix_size * width; \
+			} \
+		}
+
+		color_t *in = bitmap;
+		char *out = data;
+
+		if ( bpp == 32 )
+		{
+			if ( machine_byte_order == byte_order )
+				COPY_IN_OUT( 4, *( (uint32_t *)out ) = (uint32_t)pixel; out += 4; )
+			else
+				COPY_IN_OUT( 4, uint32_t tmp = pixel;
+							 *( (uint8_t *)out     ) = *( (uint8_t *)(&tmp) + 3 );
+							 *( (uint8_t *)out + 1 ) = *( (uint8_t *)(&tmp) + 2 );
+							 *( (uint8_t *)out + 2 ) = *( (uint8_t *)(&tmp) + 1 );
+							 *( (uint8_t *)out + 3 ) = *( (uint8_t *)(&tmp)     );
+							 out += 4; )
+		}
+		else if ( bpp == 24 )
+		{
+			if ( machine_byte_order == byte_order && byte_order == LSBFirst )
+				COPY_IN_OUT( 3, *( (color_t *)out ) = *( (color_t *)( &pixel ) ); out += 3; )
+			if ( machine_byte_order == byte_order && byte_order == MSBFirst )
+				COPY_IN_OUT( 3, uint32_t tmp = pixel;
+							 *( (uint8_t *)out     ) = *( (uint8_t *)(&tmp) + 1 );
+							 *( (uint8_t *)out + 1 ) = *( (uint8_t *)(&tmp) + 2 );
+							 *( (uint8_t *)out + 2 ) = *( (uint8_t *)(&tmp) + 3 );
+							 out += 3; )
+			else
+				COPY_IN_OUT( 3, uint32_t tmp = pixel;
+							 *( (uint8_t *)out     ) = *( (uint8_t *)(&tmp) + 3 );
+							 *( (uint8_t *)out + 1 ) = *( (uint8_t *)(&tmp) + 2 );
+							 *( (uint8_t *)out + 2 ) = *( (uint8_t *)(&tmp) + 1 );
+							 out += 3; )
+		}
+		else if ( bpp == 16 )
+		{
+			if ( machine_byte_order == byte_order )
+				COPY_IN_OUT( 2, *( (uint16_t *)out ) = (uint16_t)pixel; out += 2; )
+			else
+				COPY_IN_OUT( 2, uint16_t tmp = pixel;
+							 *( (uint8_t *)out     ) = *( (uint8_t *)(&tmp) + 1 );
+							 *( (uint8_t *)out + 1 ) = *( (uint8_t *)(&tmp)     );
+							 out += 2; );
+		}
+		else if ( bpp == 8 )
+		{
+			COPY_IN_OUT( 1, *( (uint8_t *)out ) = (uint8_t)pixel; ++out; )
+		}
+		else
+		{
+			fprintf( stderr, "Unsupported depth: %d bits per pixel.\n", bpp );
+			XFreeGC( display, pixmap_gc );
+			XFreePixmap( display, pixmap );
+			XDestroyImage( image );
+			return;
+		}
+
+#undef COPY_IN_OUT
+
+		XPutImage( display, pixmap, pixmap_gc, image, 0, 0, 0, 0, width, height );
+		XDestroyImage( image );
+	}
+	else //if ( depth == 1 || visual->class == DirectColor )
+	{
+		// FIXME Something like the following, but faster ;-) - XDrawPoint is not
+		// a good idea...
+		int x, y;
+		for ( y = 0; y < height; ++y )
+		{
+			color_t *color = bitmap + y * width;
+
+			int delta = 0;
+			for ( x = 0; x < width; ++x, ++color )
+			{
+				int rnd = (int)( ( (long)( random() - RAND_MAX/2 ) * 32000 )/RAND_MAX );
+				int luminance = delta + rnd + 299 * (int)color->r + 587 * (int)color->g + 114 * (int)color->b;
+
+				if ( luminance < 128000 )
+				{
+					XSetForeground( display, pixmap_gc, BlackPixel( display, screen ) );
+					delta = luminance;
+				}
+				else
+				{
+					XSetForeground( display, pixmap_gc, WhitePixel( display, screen ) );
+					delta = luminance - 255000;
+				}
+
+				XDrawPoint( display, pixmap, pixmap_gc, x, y );
+			}
+		}
+	}
+
+	XSetWindowBackgroundPixmap( display, win, pixmap );
+
+	XFreeGC( display, pixmap_gc );
+	XFreePixmap( display, pixmap );
+}
+
+// The old method of hiding the window decorations
+static void suppress_decorations_motif()
+{
+	struct {
+		unsigned long flags, functions, decorations;
+		long input_mode;
+		unsigned long status;
+	} mwmhints;
+
+	Atom a = XInternAtom( display, "_MOTIF_WM_HINTS", False );
+
+	mwmhints.flags = 15; // functions, decorations, input_mode, status
+	mwmhints.functions = 2; // ?
+	mwmhints.decorations = 0;
+	mwmhints.input_mode = 0;
+
+	XChangeProperty( display, win, a, a, 32,
+			PropModeReplace, (unsigned char*)&mwmhints, 5 );
+}
+
+// This is a splash, set it as such.
+// If it fails, just hide the decorations...
+static void suppress_decorations()
+{
+	Atom atom_type = XInternAtom( display, "_NET_WM_WINDOW_TYPE", True );
+	Atom atom_splash = XInternAtom( display, "_NET_WM_WINDOW_TYPE_SPLASH", True );
+
+	if ( atom_type != None && atom_splash != None )
+		XChangeProperty( display, win, atom_type, XA_ATOM, 32,
+				PropModeReplace, (unsigned char*)&atom_splash, 1 );
+	//else
+		suppress_decorations_motif(); // FIXME: Unconditional until Metacity/compiz's SPLASH handling is fixed
+}
+
+// Create the window
+// Return: 1 - success, 0 - failure
+int splash_create_window( int argc, char** argv )
+{
+	char *display_name = NULL;
+	int i;
+	for ( i = 0; i < argc; i++ )
+	{
+		if ( !strcmp( argv[i], "-display" )  || !strcmp( argv[i], "--display" ) )
+			display_name = ( i + 1 < argc )? argv[i+1]: NULL;
+	}
+
+	if ( !display_name )
+		display_name = getenv( "DISPLAY" );
+
+	// init display
+	display = XOpenDisplay( display_name );
+	if ( !display )
+	{
+		fprintf( stderr, "Failed to open display\n" );
+		return 0;
+	}
+
+	// create the window
+	screen = DefaultScreen( display );
+	depth = DefaultDepth( display, screen );
+	color_map = DefaultColormap( display, screen );
+	visual = DefaultVisual( display, screen );
+
+	Window root_win = RootWindow( display, screen );
+	int display_width = DisplayWidth( display, screen );
+	int display_height = DisplayHeight( display, screen );
+
+	win = XCreateSimpleWindow( display, root_win,
+			( display_width - width ) / 2, ( display_height - height ) / 2,
+			width, height, 0,
+			BlackPixel( display, screen ), BlackPixel( display, screen ) );
+
+	XSetWindowColormap( display, win, color_map );
+
+	// setup colors
+#define FILL_COLOR(xcol,col) xcol.red = 256*col.r; xcol.green = 256*col.g; xcol.blue = 256*col.b;
+	FILL_COLOR( barcolor, barcol );
+	FILL_COLOR( framecolor, framecol );
+#undef FILL_COLOR
+
+	XAllocColor( display, color_map, &barcolor);
+	XAllocColor( display, color_map, &framecolor);
+
+	// not resizable, no decorations, etc.
+	unsigned long value_mask = 0;
+	XGCValues values;
+	gc = XCreateGC( display, win, value_mask, &values );
+
+	XSizeHints size_hints;
+	size_hints.flags = PPosition | PSize | PMinSize | PMaxSize;
+	size_hints.min_width = width;
+	size_hints.max_width = width;
+	size_hints.min_height = height;
+	size_hints.max_height = height;
+
+	char *name = "OpenOffice.org";
+	char *icon = "icon"; // FIXME
+
+	XSetStandardProperties( display, win, name, icon, None,
+			0, 0, &size_hints ); 
+
+	// the actual work
+	suppress_decorations();
+	create_pixmap();
+
+	// show it
+	XSelectInput( display, win, 0 );
+	XMapWindow( display, win );
+
+	return 1;
+}
+
+// Re-draw & rocess the events
+// Just throwing them away - we do not need anything more...
+static void process_events()
+{
+	XEvent xev;
+	int num_events;
+
+	XFlush( display );
+	num_events = XPending( display );
+	while ( num_events > 0 )
+	{
+		num_events--;
+		XNextEvent( display, &xev );
+		//process_event(xev);
+	}
+}
+
+// Draw the progress
+void splash_draw_progress( int progress )
+{
+	// sanity
+	if ( progress < 0 )
+		progress = 0;
+	if ( progress > 100 )
+		progress = 100;
+	
+	// draw progress...
+	int length = ( progress * barwidth / 100 ) - ( 2 * barspace );
+	if (length < 0)
+		length = 0;
+
+	// border
+	XSetForeground( display, gc, framecolor.pixel );
+	XDrawRectangle( display, win, gc,
+			tlx, tly,
+			barwidth, barheight );
+
+	// progress bar
+	XSetForeground( display, gc, barcolor.pixel );
+	XFillRectangle( display, win, gc,
+			tlx + barspace, tly + barspace,
+			length + 1, barheight - 2*barspace + 1 );
+
+	// pending events
+	process_events();
+}
+
+// Close the window & cleanup
+void splash_close_window()
+{
+	XCloseDisplay( display );
+
+	free( bitmap );
+	bitmap = NULL;
+}
--- /dev/null	2006-06-16 15:54:00.000000000 +0200
+++ desktop/unx/source/splashx.h	2006-08-18 16:39:42.000000000 +0200
@@ -0,0 +1,71 @@
+/*************************************************************************
+ *
+ *  OpenOffice.org - a multi-platform office productivity suite
+ *
+ *  $RCSfile: unxsplash-desktop-unx-source.diff,v $
+ *
+ *  $Revision: 1.3 $
+ *
+ *  last change: $Author: jholesovsky $ $Date: 2006/08/18 14:53:25 $
+ *
+ *  The Contents of this file are made available subject to
+ *  the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ *    GNU Lesser General Public License Version 2.1
+ *    =============================================
+ *    Copyright 2005 by Sun Microsystems, Inc.
+ *    901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ *    This library is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU Lesser General Public
+ *    License version 2.1, as published by the Free Software Foundation.
+ *
+ *    This library is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *    Lesser General Public License for more details.
+ *
+ *    You should have received a copy of the GNU Lesser General Public
+ *    License along with this library; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *    MA  02111-1307  USA
+ *
+ ************************************************************************/
+
+#ifndef _SPLASHX_H
+#define _SPLASHX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Load the specified Windows 24bit BMP we can have as a background of the
+// splash.
+// 
+// Note: Must be called before the create_window(), otherwise there will be no
+// image in the splash, just black rectangle.
+// 
+// Return: 1 - success, 0 - failure (non-existing, etc.)
+int splash_load_bmp( char *filename );
+
+// Init some of the values
+// If not called, the defaults are used
+// barc, framec - colors, posx, posy - position, w, h - size
+void splash_setup( int barc[3], int framec[3], int posx, int posy, int w, int h );
+
+// Create the splash window
+// Return: 1 - success, 0 - failure
+int splash_create_window( int argc, char** argv );
+
+// Destroy the splash window
+void splash_close_window();
+
+// Update the progress bar
+void splash_draw_progress( int progress );
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _SPLASHX_H
--- /dev/null	2006-06-16 15:54:00.000000000 +0200
+++ desktop/unx/source/start.c	2006-08-18 16:31:10.000000000 +0200
@@ -0,0 +1,641 @@
+/*************************************************************************
+ *
+ *  OpenOffice.org - a multi-platform office productivity suite
+ *
+ *  $RCSfile: unxsplash-desktop-unx-source.diff,v $
+ *
+ *  $Revision: 1.3 $
+ *
+ *  last change: $Author: jholesovsky $ $Date: 2006/08/18 14:53:25 $
+ *
+ *  The Contents of this file are made available subject to
+ *  the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ *    GNU Lesser General Public License Version 2.1
+ *    =============================================
+ *    Copyright 2005 by Sun Microsystems, Inc.
+ *    901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ *    This library is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU Lesser General Public
+ *    License version 2.1, as published by the Free Software Foundation.
+ *
+ *    This library is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *    Lesser General Public License for more details.
+ *
+ *    You should have received a copy of the GNU Lesser General Public
+ *    License along with this library; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ *    MA  02111-1307  USA
+ *
+ ************************************************************************/
+
+#include <signal.h>
+#include <unistd.h>
+#include <glib.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <rtl/digest.h>
+
+#include "splashx.h"
+
+#define PIPEDEFAULTPATH		"/tmp"
+#define PIPEALTERNATEPATH	"/var/tmp"
+
+static char *
+read_path_and_chomp (const char *app)
+{
+	int len;
+	char buffer[PATH_MAX];
+
+	/* Readlink on argv[0] to point to the install path */
+	if ((len = readlink (app, buffer, sizeof(buffer))) < 0)
+		return NULL;
+	buffer[MIN(len, 4095)] = '\0';
+
+	return g_path_get_dirname (buffer);
+}
+
+static char *
+get_app_path (const char *app_exec)
+{
+	if (app_exec[0] != '/')
+		g_error ("%s must be called with an absolute path\n", app_exec);
+
+	return g_path_get_dirname (app_exec);
+}
+
+/* OO.o likes to find real paths, unwinding symlinks etc. */
+static char *
+get_real_app_path (const char *app_path)
+{
+	char *path, *bin_path;
+
+	path = g_strdup (app_path);
+
+	/* Hack for use with linkoo: follow soffice.bin
+	   if it is a symlink */
+	bin_path = g_strconcat (app_path, "/soffice.bin", NULL);
+	if (g_file_test (bin_path, G_FILE_TEST_IS_SYMLINK)) 
+	{
+		g_free (path);
+		path = read_path_and_chomp (bin_path);
+	}
+	g_free (bin_path);
+
+	/* Nasty - but OO.o likes to call realpath too ... */
+	char *real_path = (char *)g_malloc (PATH_MAX + 1);
+	realpath (path, real_path);
+	real_path[PATH_MAX] = '\0';
+	g_free (path);
+
+	return real_path;
+}
+
+static char *
+get_user_installation (const char *bootstraprc)
+{
+	char *value;
+	char *user_installation = NULL;
+	GKeyFile* key_file = g_key_file_new();
+
+	// get the value of [Bootstrap]:UserInstalation 
+	if (!g_key_file_load_from_file (key_file, bootstraprc, G_KEY_FILE_NONE, NULL))
+		g_error ("unable to open %s\n", bootstraprc);
+	value = g_key_file_get_value (key_file, "Bootstrap", "UserInstallation", NULL);
+	g_key_file_free (key_file);
+
+	if (!value)
+		return NULL;
+
+	// replace $SYSUSERCONFIG with home path
+	char **split = g_strsplit (value, "$SYSUSERCONFIG", -1);
+	user_installation = g_strjoinv (getenv ("HOME"), split);
+
+	g_strfreev (split);
+	g_free (value);
+
+	// begin with file://
+	if (!g_str_has_prefix (user_installation, "file:"))
+	{
+		char *tmp = g_strconcat ("file://", user_installation, NULL);
+		g_free (user_installation);
+		user_installation = tmp;
+	}
+	
+	return user_installation;
+}
+
+static char *
+get_md5hash (const char *text)
+{
+	if (!text)
+		return NULL;
+
+	size_t length = strlen (text);
+	sal_uInt32 size = length * sizeof (gunichar2);
+	gunichar2 *uni_string = g_utf8_to_utf16 (text, strlen (text), NULL, NULL, NULL);
+
+	unsigned char *data = (unsigned char*)uni_string;
+	if (!data)
+		return NULL;
+
+	rtlDigest digest = rtl_digest_create( rtl_Digest_AlgorithmMD5 );
+	if (digest <= 0)
+		return NULL;
+
+	sal_uInt32 md5_key_len = rtl_digest_queryLength( digest );
+	sal_uInt8 *md5_buf = (sal_uInt8 *)g_new (sal_uInt8, md5_key_len);
+
+	rtl_digest_init( digest, data, size );
+	rtl_digest_update( digest, data, size );
+	rtl_digest_get( digest, md5_buf, md5_key_len );
+	rtl_digest_destroy( digest );
+
+	// create hex-value string from the MD5 value to keep
+	// the string size minimal
+	GString *str = g_string_new ("");
+	sal_uInt32 i = 0;
+	for (; i < md5_key_len; ++i)
+	{
+		char val[3];
+		snprintf (val, 3, "%x", md5_buf[i]); // sic! we ignore some of the 0's
+		g_string_append (str, val);
+	}
+
+	g_free (uni_string);
+
+	return str->str;
+}
+
+static char *
+get_pipe_path (const char *app_path)
+{
+	char *pipe_path;
+	char *real_app_path;
+	char *bootstraprc;
+	char *user_installation;
+	char *md5hash;
+	const char *base_path;
+
+	real_app_path = get_real_app_path (app_path);
+	bootstraprc = g_strconcat (real_app_path, "/bootstraprc", NULL);
+
+	user_installation = get_user_installation (bootstraprc);
+	md5hash = get_md5hash (user_installation);
+	if (!md5hash)
+		md5hash = g_strdup ("");
+
+	if (access(PIPEDEFAULTPATH, R_OK|W_OK) == 0)
+		base_path = PIPEDEFAULTPATH;
+	else
+		base_path = PIPEALTERNATEPATH;
+
+	pipe_path = g_strdup_printf (
+			"%s/OSL_PIPE_%u_SingleOfficeIPC_%s", base_path, (int)getuid(),
+			md5hash);
+
+/*	fprintf (stderr, "pipe path is '%s' from '%s'\n", pipe_path, user_installation);*/
+
+	g_free (md5hash);
+	g_free (user_installation);
+	g_free (bootstraprc);
+	g_free (real_app_path);
+
+	return pipe_path;
+}
+
+static int
+connect_pipe (const char *pipe_path)
+{
+	int fd;
+	size_t len;
+	struct sockaddr_un addr;
+
+	memset(&addr, 0, sizeof(addr));
+
+	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+		return fd;
+
+	fcntl (fd, F_SETFD, FD_CLOEXEC);
+
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, pipe_path, sizeof(addr.sun_path));
+
+/* cut / paste from osl's pipe.c */
+#if defined(FREEBSD)
+	len = SUN_LEN(&addr);
+#else
+	len = sizeof(addr);
+#endif
+
+	if (connect (fd, (struct sockaddr *)&addr, len) < 0)
+		return -1;
+
+	return fd;
+}
+
+static gboolean
+send_args (int fd, GPtrArray *args, const char *cwd)
+{
+	int i, len;
+	GString *arg_str = g_string_new ("");
+
+	for (i = 1; i < args->len; i++)
+	{
+		g_string_append (arg_str, (char *)args->pdata[i]);
+		g_string_append_c (arg_str, '|');
+	}
+
+#ifdef DEBUG		
+	fprintf (stderr, "Pass args: '%s'\n", arg_str->str); 
+#endif
+	len = arg_str->len + 1;
+
+	return write (fd, arg_str->str, len) == len;
+}
+
+typedef struct {
+	gboolean finish;
+	gboolean error;
+	int percent;
+}  StatusClosure;
+
+static gboolean
+status_pipe_update (GIOChannel * source,
+                    GIOCondition condition, 
+                    StatusClosure *cl)
+{
+	gboolean retval = TRUE;
+
+#ifdef DEBUG
+	fprintf (stderr, "Status pipe update (0x%x)\n", (int) condition);
+#endif
+
+	if ((int)condition & (G_IO_IN | G_IO_PRI))
+	{
+		int percent;
+		GString *str = g_string_new ("");
+		switch (g_io_channel_read_line_string (source, str, NULL, NULL)) {
+			case G_IO_STATUS_ERROR:
+				cl->error = TRUE;
+				/* drop through */
+			case G_IO_STATUS_EOF:
+				retval = FALSE;
+				break;
+			default:
+				/* pipe lifecycle is odd - HUP only for remote process death */
+				if (!g_ascii_strncasecmp (str->str, "end", 3))
+					retval = FALSE;
+				if (sscanf (str->str, "%d%%", &percent))
+					cl->percent = percent;
+				break;
+		}
+		g_string_free (str, TRUE);
+	}
+
+	if ((int)condition & (G_IO_HUP | G_IO_NVAL | G_IO_ERR))
+	{
+		cl->error = TRUE;
+		retval = FALSE;
+	}
+
+	if (!retval)
+		cl->finish = TRUE;
+
+	return retval;
+}
+
+static void
+load_splash_image (const char *image_path)
+{
+	char *path;
+	int success;
+
+	path = g_strconcat (image_path, "/intro.bmp", NULL);
+	success = splash_load_bmp (path);
+	g_free (path);
+}
+
+static void
+get_key_file_value (int *array, int size, GKeyFile *key_file, const char *key)
+{
+	char *value = g_key_file_get_value (key_file, "Bootstrap", key, NULL);
+	if (!value)
+		return;
+	
+	char **valuev = g_strsplit (value, ",", 0);
+	if (!valuev)
+	{
+		g_free (value);
+		return;
+	}
+
+	int i = 0;
+	gboolean finish = FALSE;
+	for (; i < size; ++i)
+	{
+		if (!finish && valuev[i])
+			array[i] = atoi (valuev[i]);
+		else
+		{
+			finish = TRUE;
+			array[i] = -1;
+		}
+	}
+
+	g_free (valuev);
+	g_free (value);
+}
+
+static void
+load_splash_defaults (const char *path, gboolean *inhibit_splash)
+{
+	char *settings = g_strconcat (path, "/sofficerc", NULL);
+	GKeyFile* key_file = g_key_file_new();
+
+	// get the value of [Bootstrap]:UserInstalation 
+	if (!g_key_file_load_from_file (key_file, settings, G_KEY_FILE_NONE, NULL))
+		return;
+
+	int logo[1] = {-1},
+	    bar[3] = {-1, -1, -1},
+	    frame[3] = {-1, -1, -1},
+	    pos[2] = {-1, -1},
+	    size[2] = {-1, -1};
+
+	get_key_file_value (logo, 1, key_file, "Logo");
+	get_key_file_value (bar, 3, key_file, "ProgressBarColor");
+	get_key_file_value (frame, 3, key_file, "ProgressFrameColor");
+	get_key_file_value (pos, 2, key_file, "ProgressPosition");
+	get_key_file_value (size, 2, key_file, "ProgressSize");
+
+	if (logo[0] == 0)
+		*inhibit_splash = TRUE;
+
+	splash_setup (bar, frame, pos[0], pos[1], size[0], size[1] );
+
+	g_key_file_free (key_file);
+	g_free (settings);
+}
+
+static void
+show_splash (GIOChannel *status_channel)
+{
+	StatusClosure cl;
+
+	/* setup closure */
+	cl.finish = FALSE;
+	cl.error = FALSE;
+	cl.percent = 0;
+
+	/* setup status listener ... */
+	g_io_add_watch (status_channel, 
+			(GIOCondition)(G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_NVAL | G_IO_ERR),
+			(GIOFunc) status_pipe_update, (gpointer) &cl);
+
+#ifdef DEBUG
+	g_warning ("Start main loop...\n");
+#endif
+	while (!cl.finish)
+	{
+		splash_draw_progress (cl.percent);
+		if ( g_main_context_pending (g_main_context_default ()) )
+			g_main_context_iteration (g_main_context_default (), TRUE);
+		else
+			usleep (20000);
+	}
+
+	if (cl.error)
+		g_warning ("Unknown error forking main binary / abnormal early exit ...");
+
+	g_io_channel_shutdown (status_channel, FALSE, NULL);
+	g_io_channel_unref (status_channel);
+}
+
+typedef struct {
+	int pipe_fd;
+	int clone_fd;
+} ChildClosure;
+
+static void
+child_setup (gpointer user_data)
+{
+	ChildClosure *cl = (ChildClosure *)user_data;
+	if (cl->pipe_fd >= 0)
+		close (cl->pipe_fd);
+	close (cl->clone_fd);
+}
+
+static void
+system_checks (void)
+{
+#ifdef LINUX
+	/* check proc is mounted - lots of things fail otherwise */
+	if (!g_file_test ("/proc/version", G_FILE_TEST_EXISTS))
+		g_warning ("/proc not mounted - OO.o is unlikely to work well if at all");
+#endif
+}
+
+static gboolean
+fork_app (const char *app_path, GPtrArray *args, int pipe_fd,
+          GIOChannel **status_channel)
+{
+	int status_pipe[2];
+	gboolean spawn_success;
+	GError *error = NULL;
+	char *splash_pipe_arg;
+	ChildClosure *cl = g_new (ChildClosure, 1);
+	GIOChannel *status;
+
+	system_checks ();
+
+	args->pdata[0] = (gpointer)g_strconcat (app_path, "/soffice", NULL);
+
+	/* create pipe */
+	if (pipe (status_pipe) < 0)
+		g_error ("no file handles\n");
+
+	status = g_io_channel_unix_new (status_pipe[0]);
+	g_io_channel_set_encoding (status, NULL, NULL);
+
+	splash_pipe_arg = g_strdup_printf ("-splash-pipe=%d", status_pipe[1]);
+#ifdef DEBUG
+	fprintf ( stderr, "Pass splash pipe arg: '%s'\n", splash_pipe_arg);
+#endif
+	g_ptr_array_add (args, splash_pipe_arg);
+
+#ifdef DEBUG
+	fprintf (stderr, "Fork app '%s' in '%s'\n", (char *)args->pdata[0], app_path);
+#endif
+	cl->pipe_fd = pipe_fd;
+	cl->clone_fd = status_pipe[0];
+	spawn_success = g_spawn_async
+		(app_path, (char **)args->pdata, NULL,
+		 G_SPAWN_LEAVE_DESCRIPTORS_OPEN,
+		 (GSpawnChildSetupFunc) child_setup,
+		 (gpointer) cl,
+		 NULL, /* child_pid */
+		 &error);
+	close (status_pipe[1]);
+
+	if (!spawn_success)
+		fprintf (stderr, "Error forking '%s/%s': '%s'\n",
+				app_path, "/soffice",
+				error ? error->message : "<no message>");
+
+	*status_channel = status;
+
+	return spawn_success;
+}
+
+static char *
+convert_path (const char *arg, const char *cwd_str, gboolean not_filename)
+{
+	if (arg[0] == '-' || not_filename)
+		return g_strdup (arg);
+
+	if (strstr (arg, "://")) /* is URI */
+		return g_strdup (arg);
+
+	if (arg[0] == '/') /* absolute path */
+		return g_strdup (arg);
+
+	if (!strncmp (arg, "slot:", 5)) /* a slot */
+		return g_strdup (arg);
+
+	/* prepend cwd ... */
+	return g_strconcat (cwd_str, "/", arg, NULL);
+}
+
+static gboolean
+arg_check (const char *arg, const char *cmp_with)
+{
+	if (arg[0] == '-')
+		arg++;
+	else
+		return FALSE;
+	if (arg[0] == '-') /* tolerate -- prefixes etc. */
+		arg++;
+	return !g_ascii_strcasecmp (arg, cmp_with);
+}
+
+static GPtrArray *
+setup_args (int argc, char **argv, const char *cwd_str,
+            gboolean *inhibit_splash)
+{
+	int i;
+	gboolean have_non_option = FALSE;
+	gboolean next_arg_not_filename = FALSE;
+	GPtrArray *args = g_ptr_array_sized_new (argc + 8);
+
+	*inhibit_splash = FALSE;
+
+	for (i = 0; i < argc; i++)
+	{
+		char *converted;
+
+		if (i)
+			converted = convert_path (argv[i], cwd_str, next_arg_not_filename);
+		else
+			converted = g_strdup (argv[i]);
+		g_ptr_array_add (args, converted);
+
+		if (!i)
+			continue;
+
+		if (argv[i][0] != '-')
+			have_non_option = TRUE;
+
+		else if (arg_check (argv[i], "nologo") ||
+				 arg_check (argv[i], "headless") ||
+				 arg_check (argv[i], "invisible") ||
+				 arg_check (argv[i], "help") || arg_check (argv[i], "h") || arg_check (argv[i], "?") ||
+				 arg_check (argv[i], "minimized"))
+			*inhibit_splash = TRUE;
+
+		else if (arg_check (argv[i], "pt") ||
+				 arg_check (argv[i], "display"))
+			next_arg_not_filename = TRUE;
+	}
+
+	/* It's necessary to append eg. -writer for writer. */
+	if (!have_non_option)
+	{
+		const char *extra_arg = g_getenv ("OOO_EXTRA_ARG");
+		if (!extra_arg)
+			g_error ("Missing default argument in OOO_EXTRA_ARG");
+		if (extra_arg[0] != '\0')
+			g_ptr_array_add (args, g_strdup (extra_arg));
+	}
+
+	return args;
+}
+
+int main (int argc, char **argv)
+{
+	int fd;
+	gboolean inhibit_splash;
+	GIOChannel *status_channel = NULL;
+	gboolean sent_args = FALSE;
+	char *app_path, *pipe_path;
+	GPtrArray *args;
+	char cwd_str[PATH_MAX];
+
+	/* turn SIGPIPE into an error */
+	signal (SIGPIPE, SIG_IGN);
+	if (!getcwd (cwd_str, sizeof (cwd_str)))
+		g_error ("can't get cwd");
+	cwd_str[sizeof(cwd_str)-1] = '\0';
+
+	args = setup_args (argc, argv, cwd_str, &inhibit_splash);
+
+	app_path = get_app_path (argv[0]);
+	if (!app_path)
+		g_error ("Pathalogical failure: can't read app link\n");
+
+	pipe_path = get_pipe_path (app_path);
+
+	if ((fd = connect_pipe (pipe_path)) >= 0)
+		sent_args = send_args (fd, args, cwd_str);
+#ifdef DEBUG
+	else
+		fprintf (stderr, "Failed to connect to pipe '%s'\n", pipe_path);
+#endif
+
+	if (!sent_args)
+	{
+		if (! fork_app (app_path, args, fd, &status_channel))
+			return 1;
+
+		if (!inhibit_splash)
+		{
+			load_splash_image (app_path);
+			load_splash_defaults (app_path, &inhibit_splash);
+		}
+
+		if (!inhibit_splash && splash_create_window (argc, argv))
+		{
+			splash_draw_progress (0);
+			show_splash (status_channel);
+			splash_close_window ();
+		}
+	}
+
+	g_ptr_array_foreach (args, (GFunc)g_free, NULL);
+	g_ptr_array_free (args, TRUE);
+	g_free (app_path);
+
+	return 0;
+}
