[Libreoffice-commits] .: desktop/inc desktop/prj desktop/scripts desktop/source desktop/unx

Michael Meeks mmeeks at kemper.freedesktop.org
Tue Oct 12 07:41:59 PDT 2010


 desktop/inc/app.hxx                       |    1 
 desktop/prj/build.lst                     |    4 
 desktop/prj/d.lst                         |    1 
 desktop/scripts/soffice.sh                |   20 
 desktop/source/app/app.cxx                |   36 -
 desktop/source/app/cmdlineargs.cxx        |   16 
 desktop/source/app/cmdlineargs.hxx        |    3 
 desktop/source/app/officeipcthread.cxx    |    9 
 desktop/unx/source/makefile.mk            |   62 ++
 desktop/unx/source/splashx.c              |  622 ++++++++++++++++++++++
 desktop/unx/source/splashx.h              |   62 ++
 desktop/unx/source/start.c                |  841 ++++++++++++++++++++++++++++++
 desktop/unx/splash/exports.map            |   10 
 desktop/unx/splash/makefile.mk            |   72 ++
 desktop/unx/splash/services_unxsplash.cxx |  156 +++++
 desktop/unx/splash/unxsplash.cxx          |  173 ++++++
 desktop/unx/splash/unxsplash.hxx          |   90 +++
 17 files changed, 2161 insertions(+), 17 deletions(-)

New commits:
commit d2b113ec937d709e45ed1bd278a074f26529d295
Author: Jan Holesovsky <kendy at suse.cz>
Date:   Tue Oct 12 15:32:09 2010 +0100

    Implement unix quick-starter
    
    Kendy's standalone unix-quick-starter, with tweaks to make it
    conditionally compiled, and load png images with the new
    branding layout from Michael.
    Fixes to the soffice shell-script to not run pagein for a 2nd start

diff --git a/desktop/inc/app.hxx b/desktop/inc/app.hxx
index 442c9ee..499cda2 100644
--- a/desktop/inc/app.hxx
+++ b/desktop/inc/app.hxx
@@ -86,6 +86,7 @@ class Desktop : public Application
                                 ~Desktop();
         virtual void			Main( );
         virtual void			Init();
+        virtual void			InitFinished();
         virtual void			DeInit();
         virtual BOOL			QueryExit();
         virtual USHORT			Exception(USHORT nError);
diff --git a/desktop/prj/build.lst b/desktop/prj/build.lst
index dc5d7a9..162c43b 100644
--- a/desktop/prj/build.lst
+++ b/desktop/prj/build.lst
@@ -19,6 +19,8 @@ dt	desktop\win32\source\applauncher\ooo	nmake	-	w	dt_applauncher_ooo dt_applaunc
 dt	desktop\win32\source\rebase				nmake	-	w	dt_rebase dt_inc NULL
 dt	desktop\os2\source\applauncher			nmake	-	p	dt_applauncher dt_inc NULL
 dt	desktop\unx\source\officeloader		nmake	-	u	dt_officeloader_unx dt_inc NULL
+dt     desktop\unx\source                      nmake   -       u       dt_uwrapper     dt_inc NULL
+dt     desktop\unx\splash                      nmake   -       u       dt_usplash      dt_inc NULL
 dt	desktop\source\pagein					nmake	-	u	dt_pagein dt_inc NULL
 dt	desktop\source\pkgchk\unopkg			nmake	-	all	dt_unopkg dt_dp_misc dt_app dt_inc dt_guiloader.w NULL
 dt	desktop\source\deployment				nmake	-	all	dt_deployment dt_dp_manager dt_dp_registry dt_dp_registry_package dt_dp_registry_executable dt_dp_registry_help dt_dp_registry_script dt_dp_registry_sfwk dt_dp_registry_component dt_dp_registry_configuration dt_dp_unopkg dt_inc dt_dp_misc NULL
@@ -35,7 +37,7 @@ dt	desktop\source\deployment\registry\configuration	nmake	-	all	dt_dp_registry_c
 dt	desktop\source\deployment\registry\help			nmake	-	all	dt_dp_registry_help dt_inc NULL
 dt	desktop\source\deployment\registry\executable		nmake	-	all	dt_dp_registry_executable dt_inc NULL
 dt	desktop\scripts 						nmake	-	u	dt_scripts dt_inc NULL
-dt	desktop\util							nmake	-	all	dt_util dt_app dt_pagein.u dt_so_comp dt_spl dt_wrapper.w dt_officeloader.w dt_officeloader_unx.u dt_migr dt_rebase.w NULL
+dt	desktop\util							nmake	-	all	dt_util dt_app dt_pagein.u dt_so_comp dt_spl dt_uwrapper.u dt_usplash.u dt_wrapper.w dt_officeloader.w dt_officeloader_unx.u dt_migr dt_rebase.w NULL
 dt	desktop\zipintro							nmake	-	all	dt_zipintro NULL
 dt  desktop\registry\data\org\openoffice\Office                     nmake   -  all sn_regconfig NULL
 dt  desktop\source\registration\com\sun\star\servicetag\resources   get     -  all sn_svctagres NULL
diff --git a/desktop/prj/d.lst b/desktop/prj/d.lst
index cda9361..6251de2 100644
--- a/desktop/prj/d.lst
+++ b/desktop/prj/d.lst
@@ -10,6 +10,7 @@ mkdir: %_DEST%\bin%_EXT%\odf4ms
 ..\%__SRC%\bin\officeloader.exe %_DEST%\bin%_EXT%\soffice.exe
 ..\%__SRC%\bin\soffice %_DEST%\bin%_EXT%\soffice.bin
 ..\%__SRC%\bin\soffice_mac %_DEST%\bin%_EXT%\soffice
+..\%__SRC%\bin\oosplash %_DEST%\bin%_EXT%\oosplash.bin
 ..\%__SRC%\bin\so\soffice.bin %_DEST%\bin%_EXT%\so\soffice.bin
 ..\%__SRC%\bin\so\officeloader.exe %_DEST%\bin%_EXT%\so\soffice.exe
 ..\%__SRC%\bin\so\soffice %_DEST%\bin%_EXT%\so\soffice.bin
diff --git a/desktop/scripts/soffice.sh b/desktop/scripts/soffice.sh
index 53c39d4..fdd8077 100644
--- a/desktop/scripts/soffice.sh
+++ b/desktop/scripts/soffice.sh
@@ -71,6 +71,26 @@ do
   esac
 done
 
+# test for availability of the fast external splash
+for arg in $@; do
+    if [ "$arg" = "-nologo" -o "$arg" = "-no-oosplash" ]; then
+       no_oosplash=y
+    fi
+done
+
+# Setup our app as oosplash, but try to avoid executing pagein,
+# and other expensive environment setup pieces wherever possible
+# for a second started office
+if [ "$sd_binary" = "soffice.bin" -a -x "$sd_prog/oosplash.bin" ] && [ "$no_oosplash" != "y" ] ; then
+    sd_binary="oosplash.bin"
+
+    export QSTART_CHECK_ONLY=1
+    if "$sd_prog/$sd_binary" -qsend-and-report $*; then
+        exit 0
+    fi
+    unset QSTART_CHECK_ONLY
+fi
+
 # pagein
 sd_pagein_args=@pagein-common
 for sd_arg in "$@"; do
diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index 36d5d20..1a1afcc 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -740,6 +740,13 @@ void Desktop::Init()
     }
 }
 
+void Desktop::InitFinished()
+{
+    RTL_LOGFILE_CONTEXT( aLog, "desktop (cd100003) ::Desktop::InitFinished" );
+
+    CloseSplashScreen();
+}
+
 void Desktop::DeInit()
 {
     RTL_LOGFILE_CONTEXT( aLog, "desktop (cd100003) ::Desktop::DeInit" );
@@ -1546,6 +1553,7 @@ void Desktop::Main()
     OpenSplashScreen();
     RTL_LOGFILE_CONTEXT_TRACE( aLog, "desktop (lo119109) Desktop::Main } OpenSplashScreen" );
 
+    SetSplashScreenProgress(10);
     {
         UserInstall::UserInstallError instErr_fin = UserInstall::finalize();
         if ( instErr_fin != UserInstall::E_None)
@@ -1561,7 +1569,7 @@ void Desktop::Main()
         }
         // refresh path information
         utl::Bootstrap::reloadData();
-        SetSplashScreenProgress(25);
+        SetSplashScreenProgress(20);
     }
 
     Reference< XMultiServiceFactory > xSMgr =
@@ -1579,7 +1587,7 @@ void Desktop::Main()
     {
         RegisterServices( xSMgr );
 
-        //SetSplashScreenProgress(15);
+        SetSplashScreenProgress(25);
 
 #ifndef UNX
         if ( pCmdLineArgs->IsHelp() ) {
@@ -1617,7 +1625,7 @@ void Desktop::Main()
         //  Read the common configuration items for optimization purpose
         if ( !InitializeConfiguration() ) return;
 
-        //SetSplashScreenProgress(20);
+        SetSplashScreenProgress(30);
 
         // set static variable to enabled/disable crash reporter
         retrieveCrashReporterState();
@@ -1678,10 +1686,10 @@ void Desktop::Main()
 #endif
 
         SetDisplayName( aTitle );
-//        SetSplashScreenProgress(30);
+        SetSplashScreenProgress(35);
         RTL_LOGFILE_CONTEXT_TRACE( aLog, "{ create SvtPathOptions and SvtLanguageOptions" );
         pPathOptions.reset( new SvtPathOptions);
-//        SetSplashScreenProgress(40);
+        SetSplashScreenProgress(40);
 //        pLanguageOptions = new SvtLanguageOptions(sal_True);
 //        SetSplashScreenProgress(45);
         RTL_LOGFILE_CONTEXT_TRACE( aLog, "} create SvtPathOptions and SvtLanguageOptions" );
@@ -1779,7 +1787,7 @@ void Desktop::Main()
                     OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.Desktop" ))), UNO_QUERY );
                 if (xDesktopFrame.is())
                 {
-    //                SetSplashScreenProgress(60);
+                    SetSplashScreenProgress(60);
                     Reference< XFrame > xBackingFrame;
                     Reference< ::com::sun::star::awt::XWindow > xContainerWindow;
 
@@ -1796,7 +1804,7 @@ void Desktop::Main()
                         Reference< XController > xBackingComp(
                             xSMgr->createInstanceWithArguments(OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.StartModule") ), lArgs),
                             UNO_QUERY);
-    //                    SetSplashScreenProgress(80);
+                        SetSplashScreenProgress(80);
                         if (xBackingComp.is())
                         {
                             Reference< ::com::sun::star::awt::XWindow > xBackingWin(xBackingComp, UNO_QUERY);
@@ -1836,7 +1844,7 @@ void Desktop::Main()
         return;
     }
     */
-//    SetSplashScreenProgress(55);
+    SetSplashScreenProgress(55);
 
     SvtFontSubstConfig().Apply();
 
@@ -1845,7 +1853,7 @@ void Desktop::Main()
     aAppearanceCfg.SetApplicationDefaults( this );
     SvtAccessibilityOptions aOptions;
     aOptions.SetVCLSettings();
-//    SetSplashScreenProgress(60);
+    SetSplashScreenProgress(60);
 
     if ( !bRestartRequested )
     {
@@ -1859,7 +1867,7 @@ void Desktop::Main()
         // use system window dialogs
         Application::SetSystemWindowMode( SYSTEMWINDOW_MODE_DIALOG );
 
-    //    SetSplashScreenProgress(80);
+        SetSplashScreenProgress(80);
 
         if ( !bTerminateRequested && !pCmdLineArgs->IsInvisible() &&
              !pCmdLineArgs->IsNoQuickstart() )
@@ -3196,14 +3204,18 @@ void Desktop::OpenSplashScreen()
         else if ( pCmdLine->IsWeb() )
             aAppName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "web" ));
 
+        // Which splash to use
+        OUString aSplashService( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.office.SplashScreen" ));
+        if ( pCmdLine->GetStringParam( CommandLineArgs::CMD_STRINGPARAM_SPLASHPIPE ).getLength() )
+            aSplashService = OUString::createFromAscii("com.sun.star.office.PipeSplashScreen");
+
         bVisible = sal_True;
         Sequence< Any > aSeq( 2 );
         aSeq[0] <<= bVisible;
         aSeq[1] <<= aAppName;
         m_rSplashScreen = Reference<XStatusIndicator>(
             comphelper::getProcessServiceFactory()->createInstanceWithArguments(
-            OUString::createFromAscii("com.sun.star.office.SplashScreen"),
-            aSeq), UNO_QUERY);
+            aSplashService, aSeq), UNO_QUERY);
 
         if(m_rSplashScreen.is())
                 m_rSplashScreen->start(OUString::createFromAscii("SplashScreen"), 100);
diff --git a/desktop/source/app/cmdlineargs.cxx b/desktop/source/app/cmdlineargs.cxx
index 7f3d141..9552c84 100644
--- a/desktop/source/app/cmdlineargs.cxx
+++ b/desktop/source/app/cmdlineargs.cxx
@@ -527,6 +527,11 @@ sal_Bool CommandLineArgs::InterpretCommandLineParameter( const ::rtl::OUString&
         SetBoolParam_Impl( CMD_BOOLPARAM_HELPMATH, sal_True );
         return sal_True;
     }
+    else if ( aArgStr.Copy(0, 13).EqualsIgnoreCaseAscii( "-splash-pipe=" ))
+    {
+        AddStringListParam_Impl( CMD_STRINGPARAM_SPLASHPIPE, aArgStr.Copy( 13 ) );
+        return sal_True;
+    }
     #ifdef MACOSX
     /* #i84053# ignore -psn on Mac
        Platform dependent #ifdef here is ugly, however this is currently
@@ -680,6 +685,14 @@ void CommandLineArgs::SetBoolParam( BoolParam eParam, sal_Bool bNewValue )
     m_aBoolParams[eParam] = bNewValue;
 }
 
+const rtl::OUString& CommandLineArgs::GetStringParam( StringParam eParam ) const
+{
+       osl::MutexGuard  aMutexGuard( m_aMutex );
+
+       OSL_ASSERT( ( eParam >= 0 && eParam < CMD_STRINGPARAM_COUNT ) );
+       return m_aStrParams[eParam];
+}
+
 sal_Bool CommandLineArgs::IsMinimized() const
 {
     osl::MutexGuard  aMutexGuard( m_aMutex );
@@ -980,7 +993,8 @@ sal_Bool CommandLineArgs::IsEmptyOrAcceptOnly() const
 {
     osl::MutexGuard  aMutexGuard( m_aMutex );
 
-    return m_eArgumentCount == NONE || 
+    return m_eArgumentCount == NONE ||
+           ( ( m_eArgumentCount == ONE ) && ( m_aStrParams[ CMD_STRINGPARAM_SPLASHPIPE ].getLength() )) ||
            ( ( m_eArgumentCount == ONE ) && ( m_aStrParams[ CMD_STRINGPARAM_ACCEPT ].getLength() )) ||
            ( ( m_eArgumentCount == ONE ) && m_aBoolParams[ CMD_BOOLPARAM_PSN ] );
 }
diff --git a/desktop/source/app/cmdlineargs.hxx b/desktop/source/app/cmdlineargs.hxx
index f357dad..4ef302e 100644
--- a/desktop/source/app/cmdlineargs.hxx
+++ b/desktop/source/app/cmdlineargs.hxx
@@ -77,6 +77,7 @@ class CommandLineArgs
         enum StringParam // must be zero based!
         {
             CMD_STRINGPARAM_PORTAL,
+            CMD_STRINGPARAM_SPLASHPIPE,
             CMD_STRINGPARAM_ACCEPT,
             CMD_STRINGPARAM_UNACCEPT,
             CMD_STRINGPARAM_USERDIR,
@@ -128,6 +129,8 @@ class CommandLineArgs
         // generic methods to access parameter
         void					SetBoolParam( BoolParam eParam, sal_Bool bNewValue );
 
+        const rtl::OUString&    GetStringParam( StringParam eParam ) const;
+
         // Access to bool parameters
         sal_Bool				IsMinimized() const;
         sal_Bool				IsInvisible() const;
diff --git a/desktop/source/app/officeipcthread.cxx b/desktop/source/app/officeipcthread.cxx
index 854646e..059e594 100644
--- a/desktop/source/app/officeipcthread.cxx
+++ b/desktop/source/app/officeipcthread.cxx
@@ -223,11 +223,14 @@ OfficeIPCThread*	OfficeIPCThread::pGlobalOfficeIPCThread = 0;
 namespace { struct Security : public rtl::Static<OSecurity, Security> {}; }
 ::osl::Mutex*		OfficeIPCThread::pOfficeIPCThreadMutex = 0;
 
-
+// Turns a string in aMsg such as file://home/foo/.libreoffice/3
+// Into a hex string of well known length ff132a86...
 String CreateMD5FromString( const OUString& aMsg )
 {
-    // PRE: aStr "file"
-    // BACK: Str "ababab....0f" Hexcode String
+#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
+    fprintf (stderr, "create md5 frim '%s'\n",
+             (const sal_Char *)rtl::OUStringToOString (aMsg, RTL_TEXTENCODING_UTF8));
+#endif
 
     rtlDigest handle = rtl_digest_create( rtl_Digest_AlgorithmMD5 );
     if ( handle > 0 )
diff --git a/desktop/unx/source/makefile.mk b/desktop/unx/source/makefile.mk
new file mode 100644
index 0000000..bd8eb75
--- /dev/null
+++ b/desktop/unx/source/makefile.mk
@@ -0,0 +1,62 @@
+#
+# Version: MPL 1.1 / GPLv3+ / LGPLv3+
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Initial Developer of the Original Code is
+#               Novell, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s): Jan Holesovsky <kendy at novell.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+# the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+# in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+# instead of those above.
+#
+PRJ=..$/..
+PRJNAME=desktop
+TARGET=oosplash
+
+NO_DEFAULT_STL=TRUE
+
+.INCLUDE :  settings.mk
+
+.IF "$(ENABLE_UNIX_QUICKSTARTER)"!="TRUE"
+
+dummy:
+    @echo "Unix quickstarter disabled"
+
+.ELSE
+
+STDLIB=
+
+OBJFILES= \
+    $(OBJ)$/splashx.obj \
+    $(OBJ)$/start.obj
+
+APP1TARGET = $(TARGET)
+APP1RPATH  = BRAND
+APP1OBJS   = $(OBJFILES)
+APP1LIBSALCPPRT=
+APP1CODETYPE = C
+APP1STDLIBS = $(SALLIB) -lX11 `pkg-config --libs libpng`
+.IF "$(OS)"=="SOLARIS"
+APP1STDLIBS+= -lsocket
+.ENDIF
+
+.ENDIF # ENABLE_UNIX_QUICKSTARTER
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE :	target.mk
diff --git a/desktop/unx/source/splashx.c b/desktop/unx/source/splashx.c
new file mode 100644
index 0000000..ee36b7a
--- /dev/null
+++ b/desktop/unx/source/splashx.c
@@ -0,0 +1,622 @@
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Initial Developer of the Original Code is
+ *               Novell, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2010 the
+ * Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): Jan Holesovsky <kendy at novell.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+
+#define USE_LIBPNG
+
+#include "osl/endian.h"
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef USE_LIBPNG
+#  include <png.h>
+#endif
+
+#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 unsigned char **bitmap_rows = 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; \
+    }
+
+#ifdef USE_LIBPNG
+
+/* libpng-1.2.41 */
+#ifndef PNG_TRANSFORM_GRAY_TO_RGB
+#  define PNG_TRANSFORM_GRAY_TO_RGB   0x2000
+#endif
+
+int splash_load_bmp( const char *filename )
+{
+    FILE *file;
+    png_structp png_ptr;
+    png_infop info_ptr;
+
+    if ( !(file = fopen( filename, "r" ) ) )
+        return 0;
+
+    png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
+    info_ptr = png_create_info_struct(png_ptr);
+    png_init_io( png_ptr, file );
+
+    if( setjmp( png_jmpbuf( png_ptr ) ) )
+    {
+        png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
+        fclose( file );
+        return 0;
+    }
+
+    png_read_png( png_ptr, info_ptr,
+                  PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_ALPHA |
+                  PNG_TRANSFORM_GRAY_TO_RGB | PNG_TRANSFORM_BGR, NULL);
+
+    bitmap_rows = png_get_rows( png_ptr, info_ptr );
+    width = info_ptr->width;
+    height = info_ptr->height;
+
+#if 0
+    {
+      int i,j;
+      for (j = 0; j < height; j++) {
+        for (i = 0; i < width*3; i++) {
+          fprintf (stderr, "%.2x", bitmap_rows[j][i]);
+        }
+        fprintf (stderr, "\n");
+      }
+    }
+#endif
+
+    return 1;
+}
+#else
+
+/* Load the specified Windows 24bit BMP to 'bitmap'
+ * Return: 1 - success, 0 - failure */
+int splash_load_bmp( const 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;
+    unsigned char *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" );
+
+    bitmap_rows = malloc (sizeof (unsigned char*) * height);
+    int i;
+    for (i = 0; i < height; i++)
+        bitmap_rows[i] = bitmap + (width * height * 3) - width * 3 * (i + 1);
+
+    close( fd );
+    return 1;
+}
+#endif
+
+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_rows )
+        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 ) \
+        { \
+            int x, y; \
+            for ( y = 0; y < height; ++y ) \
+            { \
+                unsigned long red_delta = 0, green_delta = 0, blue_delta = 0; \
+                color_t *in = (color_t *)bitmap_rows[y]; \
+                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 \
+                } \
+            } \
+        }
+
+        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 = (color_t *)&bitmap_rows[y];
+
+            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 & process 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 );
+
+    // leak it is faster
+    bitmap_rows = NULL;
+}
diff --git a/desktop/unx/source/splashx.h b/desktop/unx/source/splashx.h
new file mode 100644
index 0000000..3b923e5
--- /dev/null
+++ b/desktop/unx/source/splashx.h
@@ -0,0 +1,62 @@
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Initial Developer of the Original Code is
+ *               Novell, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2010 the
+ * Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): Jan Holesovsky <kendy at novell.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+#ifndef _SPLASHX_H
+#define _SPLASHX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Load the specified bitmap so 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( const 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
diff --git a/desktop/unx/source/start.c b/desktop/unx/source/start.c
new file mode 100644
index 0000000..fe94e90
--- /dev/null
+++ b/desktop/unx/source/start.c
@@ -0,0 +1,841 @@
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Initial Developer of the Original Code is
+ *               Novell, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2010 the
+ * Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): Jan Holesovsky <kendy at novell.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+#include <signal.h>
+#include <unistd.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 <sys/poll.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <libgen.h>
+
+#include <osl/nlsupport.h>
+#include <osl/process.h>
+#include <osl/thread.h>
+#include <rtl/bootstrap.h>
+#include <rtl/digest.h>
+#include <rtl/ustrbuf.h>
+#include <sal/main.h>
+
+#include "splashx.h"
+
+/*
+ * magic argument - if passed, not passed onto soffice.bin but we exit
+ * immediately if we fail to control the process. Used to avoid doing
+ * an un-conditional pagein
+ */
+#define QSEND_AND_REPORT "-qsend-and-report"
+
+#define IMG_SUFFIX	     ".bmp"
+#define PIPEDEFAULTPATH      "/tmp"
+#define PIPEALTERNATEPATH    "/var/tmp"
+
+/* Easier conversions: rtl_uString to rtl_String */
+static rtl_String *
+ustr_to_str( rtl_uString *pStr )
+{
+    rtl_String *pOut = NULL;
+
+    rtl_uString2String( &pOut, rtl_uString_getStr( pStr ),
+            rtl_uString_getLength( pStr ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
+
+    return pOut;
+}
+
+/* Easier conversions: char * to rtl_uString */
+static rtl_uString *
+charp_to_ustr( const char *pStr )
+{
+    rtl_uString *pOut = NULL;
+
+    rtl_string2UString( &pOut, pStr, strlen( pStr ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
+
+    return pOut;
+}
+
+/* Easier debugging of rtl_uString values. */
+#if OSL_DEBUG_LEVEL > 0
+static void
+ustr_debug( const char *pMessage, rtl_uString *pStr )
+{
+    rtl_String *pOut = ustr_to_str( pStr );
+
+    fprintf( stderr, "%s: %s\n", pMessage, rtl_string_getStr( pOut ) );
+
+    rtl_string_release( pOut );
+    return;
+}
+#else
+#define ustr_debug( a, b ) {}
+#endif
+
+/* Path of the application. */
+static rtl_uString *
+get_app_path( const char *pAppExec )
+{
+    char pRealPath[PATH_MAX];
+    rtl_uString *pResult;
+
+    char *pPath = strdup( pAppExec );
+    pPath = dirname( pPath );
+
+    realpath( pPath, pRealPath );
+    pResult = charp_to_ustr( pRealPath );
+    free( pPath );
+
+    return pResult;
+}
+
+/* Compute the OOo md5 hash from 'pText' */
+static rtl_uString *
+get_md5hash( rtl_uString *pText )
+{
+    rtl_uString *pResult = NULL;
+    sal_Int32 nCapacity = 100;
+
+#if OSL_DEBUG_LEVEL > 0
+    fprintf (stderr, "Generate pipe md5 for '%s'\n", ustr_to_str (pText)->buffer);
+#endif
+
+    if ( !pText )
+        return NULL;
+
+    unsigned char *pData = (unsigned char *)rtl_uString_getStr( pText );
+    sal_uInt32   nSize = rtl_uString_getLength( pText ) * sizeof( sal_Unicode );
+    if ( !pData )
+        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 *)calloc( md5_key_len, sizeof( sal_uInt8 ) );
+
+    rtl_digest_init( digest, pData , nSize );
+    rtl_digest_update( digest, pData, nSize );
+    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 */
+    rtl_uString_new_WithLength( &pResult, nCapacity );
+    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 */
+
+        rtl_uStringbuffer_insert_ascii( &pResult, &nCapacity, rtl_uString_getLength( pResult ),
+                val, strlen( val ) );
+    }
+
+    /* cleanup */
+    free( md5_buf );
+
+    return pResult;
+}
+
+/* Construct the pipe name */
+static rtl_uString *
+get_pipe_path( rtl_uString *pAppPath )
+{
+    rtl_uString *pPath = NULL, *pTmp = NULL, *pUserInstallation = NULL;
+    rtl_uString *pResult = NULL, *pBasePath = NULL, *pAbsUserInstallation = NULL;
+
+    /* setup bootstrap filename */
+    rtl_uString_newFromAscii( &pPath, "file://" );
+    rtl_uString_newConcat( &pPath, pPath, pAppPath );
+    rtl_uString_newFromAscii( &pTmp, "/" );
+    rtl_uString_newConcat( &pPath, pPath, pTmp );
+    rtl_uString_newFromAscii( &pTmp, SAL_CONFIGFILE( "bootstrap" ) );
+    rtl_uString_newConcat( &pPath, pPath, pTmp );
+
+    ustr_debug( "bootstap", pPath );
+
+    /* read userinstallation value */
+    rtlBootstrapHandle handle = rtl_bootstrap_args_open( pPath );
+
+    rtl_uString_newFromAscii( &pTmp, "UserInstallation" );
+    rtl_bootstrap_get_from_handle( handle, pTmp, &pUserInstallation, NULL );
+
+    rtl_bootstrap_args_close( handle );
+
+    /* turn it into an absolute path - unwinding symlinks etc. */
+    if ( osl_getProcessWorkingDir (&pBasePath) ||
+         osl_getAbsoluteFileURL( pBasePath, pUserInstallation, &pAbsUserInstallation ) )
+        rtl_uString_newFromString (&pAbsUserInstallation, pUserInstallation);
+
+    /* create the pipe name */
+    ustr_debug( "user installation", pAbsUserInstallation );
+    rtl_uString *pMd5hash = get_md5hash( pAbsUserInstallation );
+    if ( !pMd5hash )
+        rtl_uString_new( &pMd5hash );
+
+    if ( access( PIPEDEFAULTPATH, R_OK|W_OK ) == 0 )
+        rtl_uString_newFromAscii( &pResult, PIPEDEFAULTPATH );
+    else
+        rtl_uString_newFromAscii( &pResult, PIPEALTERNATEPATH );
+
+    rtl_uString_newFromAscii( &pTmp, "/OSL_PIPE_" );
+    rtl_uString_newConcat( &pResult, pResult, pTmp );
+
+    sal_Unicode pUnicode[RTL_USTR_MAX_VALUEOFINT32];
+    rtl_ustr_valueOfInt32( pUnicode, (int)getuid(), 10 );
+    rtl_uString_newFromStr( &pTmp, pUnicode );
+    rtl_uString_newConcat( &pResult, pResult, pTmp );
+
+    rtl_uString_newFromAscii( &pTmp, "_SingleOfficeIPC_" );
+    rtl_uString_newConcat( &pResult, pResult, pTmp );
+
+    rtl_uString_newConcat( &pResult, pResult, pMd5hash );
+
+    ustr_debug( "result", pResult );
+
+    /* cleanup */
+    rtl_uString_release( pPath );
+    rtl_uString_release( pTmp );
+    rtl_uString_release( pBasePath );
+    rtl_uString_release( pUserInstallation );
+    rtl_uString_release( pAbsUserInstallation );
+
+    return pResult;
+}
+
+/* Get fd of the pipe of the already running OOo. */
+static int
+connect_pipe( rtl_uString *pPipePath )
+{
+    int fd;
+    size_t len;
+    struct sockaddr_un addr;
+
+    rtl_String *pPipeStr = ustr_to_str( pPipePath );
+
+    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, rtl_string_getStr( pPipeStr ), sizeof( addr.sun_path ) );
+    rtl_string_release( pPipeStr );
+
+/* 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;
+}
+
+/* Escape: "," -> "\\,", "\0" -> "\\0", "\\" -> "\\\\" */
+static rtl_uString *
+escape_path( rtl_uString *pToEscape )
+{
+    rtl_uString *pBuffer = NULL;
+    sal_Int32 nCapacity = 1000;
+
+    rtl_uString_new_WithLength( &pBuffer, nCapacity );
+
+    sal_Int32 i = 0;
+    sal_Int32 nEscapeLength = rtl_uString_getLength( pToEscape );
+    for ( ; i < nEscapeLength; ++i )
+    {
+        sal_Unicode c = pToEscape->buffer[i];
+        switch ( c )
+        {
+            case (sal_Unicode)'\0':
+                rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
+                        rtl_uString_getLength( pBuffer ),
+                        RTL_CONSTASCII_STRINGPARAM( "\\0" ) );
+                break;
+            case (sal_Unicode)',':
+                rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
+                        rtl_uString_getLength( pBuffer ),
+                        RTL_CONSTASCII_STRINGPARAM( "\\," ) );
+                break;
+            case (sal_Unicode)'\\':
+                rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
+                        rtl_uString_getLength( pBuffer ),
+                        RTL_CONSTASCII_STRINGPARAM( "\\\\" ) );
+                break;
+            default:
+                rtl_uStringbuffer_insert( &pBuffer, &nCapacity,
+                        rtl_uString_getLength( pBuffer ),
+                        &c, 1 );
+        }
+    }
+
+    return pBuffer;
+}
+
+/* Send args to the OOo instance (using the 'fd' file descriptor) */
+static sal_Bool
+send_args( int fd, rtl_uString *pCwdPath )
+{
+    rtl_uString *pBuffer = NULL, *pTmp = NULL;
+    sal_Int32 nCapacity = 1000;
+    rtl_String *pOut = NULL;
+    sal_Bool bResult;
+    size_t nLen;
+    rtl_uString *pEscapedCwdPath = escape_path( pCwdPath );
+
+    rtl_uString_new_WithLength( &pBuffer, nCapacity );
+    rtl_uString_new( &pTmp );
+
+    rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
+            rtl_uString_getLength( pBuffer ),
+            RTL_CONSTASCII_STRINGPARAM( "InternalIPC::Arguments" ) );
+
+    if ( rtl_uString_getLength( pEscapedCwdPath ) )
+    {
+    rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
+        rtl_uString_getLength( pBuffer ),
+        RTL_CONSTASCII_STRINGPARAM( "1" ) );
+    rtl_uStringbuffer_insert( &pBuffer, &nCapacity,
+                rtl_uString_getLength( pBuffer ),
+                rtl_uString_getStr( pEscapedCwdPath ),
+                rtl_uString_getLength( pEscapedCwdPath ) );
+    }
+    else
+    rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
+        rtl_uString_getLength( pBuffer ),
+        RTL_CONSTASCII_STRINGPARAM( "0" ) );
+
+    sal_Bool bDontConvertNext = sal_False;
+    sal_uInt32 nArg;
+    sal_uInt32 nArgCount = osl_getCommandArgCount();
+    for ( nArg = 0; nArg < nArgCount; ++nArg )
+    {
+        rtl_uStringbuffer_insert_ascii( &pBuffer, &nCapacity,
+                rtl_uString_getLength( pBuffer ),
+                ",", 1 );
+
+        osl_getCommandArg( nArg, &pTmp );
+
+        if ( rtl_uString_getLength( pTmp ) == 0 ||
+             !rtl_ustr_ascii_compare( pTmp->buffer, QSEND_AND_REPORT ) )
+            continue;
+
+        // this is not a param, we have to prepend filenames with file://
+        // FIXME: improve the check
+        if ( ( pTmp->buffer[0] != (sal_Unicode)'-' ) &&
+             ( rtl_ustr_indexOfAscii_WithLength( pTmp->buffer, pTmp->length, "slot:", 5 /* length */ ) ) )
+        {
+            sal_Int32 nFirstColon = rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, ':' );
+            sal_Int32 nFirstSlash = rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, '/' );
+
+            // check that pTmp is not an URI yet
+            if ( nFirstColon < 1 || ( nFirstSlash != nFirstColon + 1 ) )
+            {
+                // some of the switches (currently just -pt) don't want to
+                // have the filenames as URIs
+                if ( !bDontConvertNext )
+                    osl_getAbsoluteFileURL( pCwdPath, pTmp, &pTmp );
+            }
+        }
+
+        // don't convert filenames with some of the switches
+        // (currently just -pt)
+        bDontConvertNext = !rtl_ustr_ascii_compareIgnoreAsciiCase( pTmp->buffer, "-pt" );
+
+        rtl_uString *pEscapedTmp = escape_path( pTmp );
+
+        rtl_uStringbuffer_insert( &pBuffer, &nCapacity,
+                rtl_uString_getLength( pBuffer ),
+                rtl_uString_getStr( pEscapedTmp ),
+                rtl_uString_getLength( pEscapedTmp ) );
+
+        rtl_uString_release( pEscapedTmp );
+    }
+
+    ustr_debug( "Pass args", pBuffer );
+
+    pOut = ustr_to_str( pBuffer );
+
+    nLen = rtl_string_getLength( pOut ) + 1;
+    bResult = ( write( fd, rtl_string_getStr( pOut ), nLen ) == (ssize_t) nLen );
+
+    /* cleanup */
+    rtl_uString_release( pEscapedCwdPath );
+    rtl_uString_release( pBuffer );
+    rtl_uString_release( pTmp );
+    rtl_string_release( pOut );
+
+    return bResult;
+}
+
+static void
+load_splash_image( rtl_uString *pUAppPath )
+{
+    char *pBuffer, *pSuffix, *pLocale;
+    int nLocSize;
+    rtl_Locale *pLoc = NULL;
+    rtl_String *pLang, *pCountry, *pAppPath;
+
+    osl_getProcessLocale (&pLoc);
+    pLang = ustr_to_str (pLoc->Language);
+    pCountry = ustr_to_str (pLoc->Country);
+
+    nLocSize = strlen (pLang->buffer) + strlen (pCountry->buffer) + 8;
+    pLocale = malloc (nLocSize);
+    pLocale[0] = '-';
+    strcpy (pLocale + 1, pLang->buffer);
+    strcat (pLocale, "_");
+    strcat (pLocale, pCountry->buffer);
+
+    pAppPath = ustr_to_str (pUAppPath);
+    pBuffer = malloc (pAppPath->length + nLocSize + 256);
+    strcpy (pBuffer, pAppPath->buffer);
+    pSuffix = pBuffer + pAppPath->length;
+
+    strcpy (pSuffix, "/edition/intro");
+    strcat (pSuffix, pLocale);
+    strcat (pSuffix, IMG_SUFFIX);
+    if ( splash_load_bmp( pBuffer ) )
+        goto cleanup;
+
+    strcpy (pSuffix, "/edition/intro" IMG_SUFFIX);
+    if ( splash_load_bmp( pBuffer ) )
+        goto cleanup;
+
+    strcpy (pSuffix, "/intro");
+    strcat (pSuffix, pLocale);
+    strcat (pSuffix, IMG_SUFFIX);
+    if ( splash_load_bmp( pBuffer ) )
+        goto cleanup;
+
+    strcpy (pSuffix, "/intro" IMG_SUFFIX);
+    if ( splash_load_bmp( pBuffer ) )
+        goto cleanup;
+
+    fprintf (stderr, "Failed to find intro image\n");
+
+ cleanup:
+    free (pLocale);
+    free (pBuffer);
+}
+
+/* Fill 'array' with values of the key 'name'.
+   Its value is a comma delimited list of integers */
+static void
+get_bootstrap_value( int *array, int size, rtlBootstrapHandle handle, const char *name )
+{
+    rtl_uString *pKey = NULL, *pValue = NULL;
+    sal_Int32 nIndex = 0;
+    int i = 0;
+
+    /* get the value from the ini file */
+    rtl_uString_newFromAscii( &pKey, name );
+    rtl_bootstrap_get_from_handle( handle, pKey, &pValue, NULL );
+
+    /* the value is several numbers delimited by ',' - parse it */
+    if ( rtl_uString_getLength( pValue ) > 0 )
+    {
+        rtl_uString *pToken = NULL;
+
+        for ( ; ( nIndex >= 0 ) && ( i < size ); ++i )
+        {
+            nIndex = rtl_uString_getToken( &pToken, pValue, 0, ',', nIndex );
+            array[i] = rtl_ustr_toInt32( rtl_uString_getStr( pToken ), 10 );
+        }
+
+        rtl_uString_release( pToken );
+    }
+
+    /* cleanup */
+    rtl_uString_release( pKey );
+    rtl_uString_release( pValue );
+}
+
+/* Load the colors and size of the splash. */
+static void
+load_splash_defaults( rtl_uString *pAppPath, sal_Bool *pInhibitSplash )
+{
+    rtl_uString *pSettings = NULL, *pTmp = NULL;
+    rtlBootstrapHandle handle;
+
+    /* costruct the sofficerc file location */
+    rtl_uString_newFromAscii( &pSettings, "file://" );
+    rtl_uString_newConcat( &pSettings, pSettings, pAppPath );
+    rtl_uString_newFromAscii( &pTmp, "/" );
+    rtl_uString_newConcat( &pSettings, pSettings, pTmp );
+    rtl_uString_newFromAscii( &pTmp, SAL_CONFIGFILE( "soffice" ) );
+    rtl_uString_newConcat( &pSettings, pSettings, pTmp );
+
+    /* use it as the bootstrap file */
+    handle = rtl_bootstrap_args_open( pSettings );
+
+    int logo[1] =  { -1 },
+        bar[3] =   { -1, -1, -1 },
+        frame[3] = { -1, -1, -1 },
+        pos[2] =   { -1, -1 },
+        size[2] =  { -1, -1 };
+
+    /* get the values */
+    get_bootstrap_value( logo,  1, handle, "Logo" );
+    get_bootstrap_value( bar,   3, handle, "ProgressBarColor" );
+    get_bootstrap_value( frame, 3, handle, "ProgressFrameColor" );
+    get_bootstrap_value( pos,   2, handle, "ProgressPosition" );
+    get_bootstrap_value( size,  2, handle, "ProgressSize" );
+
+    if ( logo[0] == 0 )
+        *pInhibitSplash = sal_True;
+
+    splash_setup( bar, frame, pos[0], pos[1], size[0], size[1] );
+
+    /* cleanup */
+    rtl_bootstrap_args_close( handle );
+    rtl_uString_release( pSettings );
+    rtl_uString_release( pTmp );
+}
+
+#define BUFFER_LEN 255
+
+/* Read the percent to show in splash. */
+static sal_Bool
+read_percent( int status_fd, int *pPercent )
+{
+    static char pBuffer[BUFFER_LEN + 1];
+    static char *pNext = pBuffer;
+    static ssize_t nRead = 0;
+
+    char *pBegin;
+    char *pIter;
+
+    /* from the last call */
+    int nNotProcessed = nRead - ( pNext - pBuffer );
+    if ( nNotProcessed >= BUFFER_LEN )
+        return sal_False;
+
+    memmove( pBuffer, pNext, nNotProcessed );
+
+    /* read data */
+    nRead = read( status_fd, pBuffer + nNotProcessed, BUFFER_LEN - nNotProcessed );
+    if ( nRead < 0 )
+        return sal_False;
+
+    nRead += nNotProcessed;
+    pBuffer[nRead] = '\0';
+
+    /* skip old data */
+    pBegin = pBuffer;
+    pNext = pBuffer;
+    for ( pIter = pBuffer; *pIter; ++pIter )
+        if ( *pIter == '\n' )
+        {
+            pBegin = pNext;
+            pNext = pIter + 1;
+        }
+
+#if OSL_DEBUG_LEVEL > 0
+    fprintf( stderr, "Got status: %s\n", pBegin );
+#endif
+    if ( !strncasecmp( pBegin, "end", 3 ) )
+        return sal_False;
+    else if ( sscanf( pBegin, "%d%%", pPercent ) )
+        return sal_True;
+
+    return sal_False;
+}
+
+/* Periodically update the splash & the percent acconding to what
+   status_fd says */
+static void
+show_splash( int status_fd )
+{
+    int nRetval;
+    struct pollfd aPfd;
+
+    int nPercent = 0;
+    sal_Bool bFinish = sal_False;
+
+    /* we want to watch status_fd */
+    aPfd.fd = status_fd;
+    aPfd.events = POLLIN;
+
+#if OSL_DEBUG_LEVEL > 0
+    fprintf( stderr, "Starting main loop, status fd: %d\n", status_fd );
+#endif
+
+    /* main loop */
+    do {
+        splash_draw_progress( nPercent );
+
+        /* read from pipe if data available */
+        nRetval = poll( &aPfd, 1, 50 );
+        if ( aPfd.revents & ( POLLERR | POLLHUP | POLLNVAL ) )
+            bFinish = sal_True;
+        else if ( nRetval > 0 )
+            bFinish = !read_percent( status_fd, &nPercent );
+        else if ( nRetval < 0 )
+            bFinish = sal_True;
+    } while ( !bFinish );
+}
+
+/* Simple system check. */
+static void
+system_checks( void )
+{
+#ifdef LINUX
+    struct stat buf;
+
+    /* check proc is mounted - lots of things fail otherwise */
+    if ( stat( "/proc/version", &buf ) != 0 )
+    {
+        fprintf( stderr, "ERROR: /proc not mounted - OO.o is unlikely to work well if at all" );
+        exit( 1 );
+    }
+#endif
+}
+
+/* Start the OOo application */
+static sal_Bool
+fork_app( rtl_uString *pAppPath, int *status_fd )
+{
+    rtl_uString *pApp = NULL, *pTmp = NULL, *pArg = NULL;
+    rtl_uString **ppArgs;
+    sal_uInt32 nArgs, i;
+
+    oslProcess aProcess;
+    oslProcessError nError;
+    int status_pipe[2];
+
+    system_checks();
+
+    /* application name */
+    rtl_uString_newFromAscii( &pApp, "file://" );
+    rtl_uString_newConcat( &pApp, pApp, pAppPath );
+    rtl_uString_newFromAscii( &pTmp, "/soffice.bin" );
+    rtl_uString_newConcat( &pApp, pApp, pTmp );
+
+    rtl_uString_new( &pTmp );
+
+    /* copy args */
+    nArgs = osl_getCommandArgCount();
+    ppArgs = (rtl_uString **)calloc( nArgs + 1, sizeof( rtl_uString* ) );
+    for ( i = 0; i < nArgs; ++i )
+    {
+        ppArgs[i] = NULL;
+        osl_getCommandArg( i, &pTmp );
+        rtl_uString_newFromString( &(ppArgs[i]), pTmp );
+    }
+
+    /* create pipe */
+    if ( pipe( status_pipe ) < 0 )
+    {
+        fprintf( stderr, "ERROR: no file handles\n");
+        exit( 1 );
+    }
+
+    /* add the pipe arg */
+    sal_Unicode pUnicode[RTL_USTR_MAX_VALUEOFINT32];
+    rtl_ustr_valueOfInt32( pUnicode, status_pipe[1], 10 );
+
+    rtl_uString_newFromAscii( &pArg, "-splash-pipe=" );
+    rtl_uString_newFromStr( &pTmp, pUnicode );
+    rtl_uString_newConcat( &pArg, pArg, pTmp );
+
+    ppArgs[nArgs] = NULL;
+    rtl_uString_newFromString( &(ppArgs[nArgs]), pArg );
+    ++nArgs;
+
+    /* start the OOo process */
+    nError = osl_executeProcess( pApp, ppArgs, nArgs,
+            osl_Process_DETACHED | osl_Process_NORMAL,
+            NULL,
+            NULL,
+            NULL, 0,
+            &aProcess );
+
+    *status_fd = status_pipe[0];
+    close( status_pipe[1] );
+
+    if ( nError != osl_Process_E_None )
+    {
+        fprintf( stderr, "ERROR %d forking process", nError );
+        ustr_debug( "", pApp );
+        return sal_False;
+    }
+
+    return sal_True;
+}
+
+/* Check if 'pArg' is -pCmpWith or --pCmpWith */
+static sal_Bool
+arg_check( rtl_uString *pArg, const char *pCmpWith )
+{
+    sal_Unicode *pUnicode = rtl_uString_getStr( pArg );
+
+    if ( pUnicode[0] == (sal_Unicode)'-' )
+        pUnicode++;
+    else
+        return sal_False;
+
+    /* tolerate -- prefixes etc. */
+    if ( pUnicode[0] == (sal_Unicode)'-' )
+        pUnicode++;
+
+    return !rtl_ustr_ascii_compare( pUnicode, pCmpWith );
+}
+
+static const char *ppInhibit[] = {
+    "nologo", "headless", "invisible", "help", "h", "?", "minimized",
+    NULL };
+static const char *ppTwoArgs[] = {
+    "pt", "display",
+    NULL };
+
+/* Read command line parameters and return whether we display the splash. */
+static sal_Bool
+get_inhibit_splash()
+{
+    rtl_uString *pTmp = NULL;
+    sal_Bool bSkipNextArg = sal_False;
+    const char **ppIter;
+
+    rtl_uString_new( &pTmp );
+
+    sal_uInt32 nArg;
+    sal_uInt32 nArgCount = osl_getCommandArgCount();
+    for ( nArg = 0; nArg < nArgCount; ++nArg )
+    {
+        if ( bSkipNextArg )
+        {
+            bSkipNextArg = sal_False;
+            continue;
+        }
+
+        osl_getCommandArg( nArg, &pTmp );
+
+        /* check for inhibit splash params */
+        for ( ppIter = ppInhibit; *ppIter; ++ppIter )
+        {
+            if ( arg_check( pTmp, *ppIter ) )
+            {
+                rtl_uString_release( pTmp );
+                return sal_True;
+            }
+        }
+        /* check for 2 arguments params */
+        for ( ppIter = ppTwoArgs; *ppIter; ++ppIter )
+        {
+            if ( arg_check( pTmp, *ppIter ) )
+            {
+                bSkipNextArg = sal_True;
+                break;
+            }
+        }
+    }
+
+    /* cleanup */
+    rtl_uString_release( pTmp );
+
+    return sal_False;
+}
+
+SAL_IMPLEMENT_MAIN_WITH_ARGS( argc, argv )
+{
+    int fd = 0, status_fd = 0;
+    sal_Bool bInhibitSplash, bSendAndReport;
+    sal_Bool bSentArgs = sal_False;
+    rtl_uString *pAppPath = NULL;
+    rtl_uString *pPipePath = NULL;
+
+    /* turn SIGPIPE into an error */
+    signal( SIGPIPE, SIG_IGN );
+
+    bInhibitSplash = get_inhibit_splash();
+
+    pAppPath = get_app_path( argv[0] );
+    if ( !pAppPath )
+    {
+        fprintf( stderr, "ERROR: Can't read app link\n" );
+        exit( 1 );
+    }
+    ustr_debug( "App path", pAppPath );
+
+    bSendAndReport = argc > 1 && !strcmp (argv[1], "-qsend-and-report");
+
+    pPipePath = get_pipe_path( pAppPath );
+
+    if ( ( fd = connect_pipe( pPipePath ) ) >= 0 )
+    {
+        rtl_uString *pCwdPath = NULL;
+        osl_getProcessWorkingDir( &pCwdPath );
+
+        bSentArgs = send_args( fd, pCwdPath );
+    }
+#if OSL_DEBUG_LEVEL > 0
+    else
+        ustr_debug( "Failed to connect to pipe", pPipePath );
+#endif
+
+    if (bSendAndReport)
+        return !bSentArgs;
+
+    if ( !bSentArgs )
+    {
+        if ( !fork_app( pAppPath, &status_fd ) )
+            return 1;
+
+        if ( !bInhibitSplash )
+        {
+            load_splash_image( pAppPath );
+            load_splash_defaults( pAppPath, &bInhibitSplash );
+        }
+
+        if ( !bInhibitSplash && splash_create_window( argc, argv ) )
+        {
+            splash_draw_progress( 0 );
+            show_splash( status_fd );
+            splash_close_window();
+        }
+    }
+
+    /* cleanup */
+    rtl_uString_release( pAppPath );
+    rtl_uString_release( pPipePath );
+
+    close( fd );
+    close( status_fd );
+
+    return 0;
+}
diff --git a/desktop/unx/splash/exports.map b/desktop/unx/splash/exports.map
new file mode 100644
index 0000000..ba501f9
--- /dev/null
+++ b/desktop/unx/splash/exports.map
@@ -0,0 +1,10 @@
+UDK_3_0_0 {
+    global:
+        GetVersionInfo;
+        component_getImplementationEnvironment;
+        component_getFactory;
+        component_writeInfo;
+
+    local:
+        *;
+};
diff --git a/desktop/unx/splash/makefile.mk b/desktop/unx/splash/makefile.mk
new file mode 100644
index 0000000..7466a6d
--- /dev/null
+++ b/desktop/unx/splash/makefile.mk
@@ -0,0 +1,72 @@
+#
+# Version: MPL 1.1 / GPLv3+ / LGPLv3+
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Initial Developer of the Original Code is
+#               Novell, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s): Jan Holesovsky <kendy at novell.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+# the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+# in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+# instead of those above.
+#
+PRJ=..$/..
+
+PRJNAME=desktop
+TARGET=spl_unx
+LIBTARGET=NO
+
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE :  settings.mk
+
+.IF "$(ENABLE_UNIX_QUICKSTARTER)"!="TRUE"
+
+dummy:
+    @echo "Unix quickstarter disabled"
+
+.ELSE
+
+# --- Files --------------------------------------------------------
+
+SLOFILES =  $(SLO)$/unxsplash.obj \
+            $(SLO)$/services_unxsplash.obj
+
+SHL1DEPN=   makefile.mk
+SHL1OBJS=   $(SLOFILES)
+
+
+SHL1TARGET=$(TARGET)$(DLLPOSTFIX)
+SHL1IMPLIB=i$(TARGET)
+
+SHL1VERSIONMAP=exports.map
+SHL1DEF=$(MISC)$/$(SHL1TARGET).def
+DEF1NAME=$(SHL1TARGET)
+
+SHL1STDLIBS= \
+    $(VOSLIB)			\
+    $(CPPUHELPERLIB)	\
+    $(CPPULIB)			\
+    $(SALLIB)
+
+.ENDIF # ENABLE_UNIX_QUICKSTARTER
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE :  target.mk
diff --git a/desktop/unx/splash/services_unxsplash.cxx b/desktop/unx/splash/services_unxsplash.cxx
new file mode 100644
index 0000000..03715cc
--- /dev/null
+++ b/desktop/unx/splash/services_unxsplash.cxx
@@ -0,0 +1,156 @@
+/*************************************************************************
+ *
+ * Copyright 2010, Novell Inc.
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org.  If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ * Contributor(s): Jan Holesovsky <kendy at novell.com>
+ *
+ ************************************************************************/
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <uno/environment.h>
+#include <cppuhelper/factory.hxx>
+#include <unotools/configmgr.hxx>
+
+#include <string.h>
+
+#include "unxsplash.hxx"
+
+using namespace rtl;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::registry;
+using namespace ::desktop;
+
+static const char* pServices[] =
+{
+    UnxSplashScreen::serviceName,
+    NULL
+};
+
+static const char* pImplementations[] =
+{
+    UnxSplashScreen::implementationName,
+    NULL
+};
+
+typedef Reference<XInterface>(* fProvider)( const Reference<XMultiServiceFactory>& );
+
+static const fProvider pInstanceProviders[] =
+{
+    UnxSplashScreen::getInstance,
+    NULL
+};
+
+
+static const char** pSupportedServices[] =
+{
+    UnxSplashScreen::interfaces,
+    NULL
+};
+
+static Sequence<OUString>
+getSupportedServiceNames( int p ) {
+    const char **names = pSupportedServices[p];
+    Sequence<OUString> aSeq;
+    for ( int i = 0; names[i] != NULL; i++ )
+    {
+        aSeq.realloc( i+1 );
+        aSeq[i] = OUString::createFromAscii( names[i] );
+    }
+    return aSeq;
+}
+
+extern "C"
+{
+void SAL_CALL
+component_getImplementationEnvironment(
+    const sal_Char** ppEnvironmentTypeName,
+    uno_Environment** ppEnvironment )
+{
+    *ppEnvironmentTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME ;
+}
+
+sal_Bool SAL_CALL
+component_writeInfo(
+    void* pServiceManager,
+    void* pRegistryKey )
+{
+    Reference<XMultiServiceFactory> xMan(
+        reinterpret_cast< XMultiServiceFactory* >( pServiceManager ) ) ;
+    Reference<XRegistryKey> xKey(
+        reinterpret_cast< XRegistryKey* >( pRegistryKey ) ) ;
+
+    // iterate over service names and register them...
+    OUString aImpl;
+    const char* pServiceName = NULL;
+    const char* pImplName = NULL;
+    for ( int i = 0; ( pServices[i] != NULL ) && ( pImplementations[i] != NULL ); i++ )
+    {
+        pServiceName= pServices[i];
+        pImplName = pImplementations[i];
+        aImpl = OUString::createFromAscii( "/" )
+              + OUString::createFromAscii( pImplName )
+              + OUString::createFromAscii( "/UNO/SERVICES" );
+        Reference<XRegistryKey> xNewKey = xKey->createKey( aImpl );
+        xNewKey->createKey( OUString::createFromAscii( pServiceName ) );
+    }
+    return sal_True;
+}
+
+void* SAL_CALL
+component_getFactory(
+    const sal_Char* pImplementationName,
+    void* pServiceManager,
+    void* pRegistryKey )
+{
+    // Set default return value for this operation - if it failed.
+    if ( pImplementationName && pServiceManager )
+    {
+        Reference< XSingleServiceFactory > xFactory;
+        Reference< XMultiServiceFactory > xServiceManager(
+            reinterpret_cast< XMultiServiceFactory* >( pServiceManager ) ) ;
+
+        // search implementation
+        for ( int i = 0; ( pImplementations[i] != NULL ); i++ )
+        {
+            if ( strcmp( pImplementations[i], pImplementationName ) == 0 )
+            {
+                // found implementation
+                xFactory = Reference<XSingleServiceFactory>( cppu::createSingleFactory(
+                    xServiceManager, OUString::createFromAscii( pImplementationName ),
+                    pInstanceProviders[i], getSupportedServiceNames( i ) ) );
+                if ( xFactory.is() )
+                {
+                    // Factory is valid - service was found.
+                    xFactory->acquire();
+                    return xFactory.get();
+                }
+            }
+        }
+    }
+
+    return NULL;
+}
+} // extern "C"
diff --git a/desktop/unx/splash/unxsplash.cxx b/desktop/unx/splash/unxsplash.cxx
new file mode 100644
index 0000000..edb3603
--- /dev/null
+++ b/desktop/unx/splash/unxsplash.cxx
@@ -0,0 +1,173 @@
+/*************************************************************************
+ *
+ * Copyright 2010, Novell Inc.
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org.  If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ * Contributor(s): Jan Holesovsky <kendy at novell.com>
+ *
+ ************************************************************************/
+#include "unxsplash.hxx"
+#include <stdio.h>
+#include <unotools/bootstrap.hxx>
+#include <vos/process.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/stream.hxx>
+#include <sfx2/sfx.hrc>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <rtl/logfile.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/math.hxx>
+
+#define PIPE_ARG "-splash-pipe="
+
+using namespace ::rtl;
+using namespace ::com::sun::star::registry;
+
+namespace desktop
+{
+
+UnxSplashScreen::UnxSplashScreen( const Reference< XMultiServiceFactory >& rSMgr )
+    : m_rFactory( rSMgr ),
+      m_pOutFd( NULL )
+{
+}
+
+UnxSplashScreen::~UnxSplashScreen()
+{
+#if OSL_DEBUG_LEVEL > 1
+    fprintf( stderr, "UnxSplashScreen::~UnxSplashScreen()\n" );
+#endif
+
+    if ( m_pOutFd )
+    {
+        fclose( m_pOutFd );
+        m_pOutFd = NULL;
+    }
+}
+
+void SAL_CALL UnxSplashScreen::start( const OUString& /*aText*/, sal_Int32 /*nRange*/ )
+    throw ( RuntimeException )
+{
+}
+
+void SAL_CALL UnxSplashScreen::end()
+    throw ( RuntimeException )
+{
+#if OSL_DEBUG_LEVEL > 1
+    fprintf( stderr, "UnxSplashScreen::end()\n" );
+#endif
+
+    fprintf( m_pOutFd, "end\n" );
+    fflush( m_pOutFd );
+}
+
+void SAL_CALL UnxSplashScreen::reset()
+    throw ( RuntimeException )
+{
+    // TODO?
+}
+
+void SAL_CALL UnxSplashScreen::setText( const OUString& /*aText*/ )
+    throw ( RuntimeException )
+{
+    // TODO?
+}
+
+void SAL_CALL UnxSplashScreen::setValue( sal_Int32 nValue )
+    throw ( RuntimeException )
+{
+    if ( m_pOutFd )
+    {
+        fprintf( m_pOutFd, "%d%%\n", nValue );
+        fflush( m_pOutFd );
+    }
+}
+
+// XInitialize
+void SAL_CALL
+UnxSplashScreen::initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any>& aArguments )
+    throw ( RuntimeException )
+{
+    ::vos::OStartupInfo aInfo;
+    for ( sal_uInt32 i = 0; i < aInfo.getCommandArgCount(); i++ )
+    {
+        rtl::OUString aArg;
+        if ( aInfo.getCommandArg( i, aArg ) )
+            break;
+        if ( aArg.matchIgnoreAsciiCaseAsciiL( PIPE_ARG, sizeof( PIPE_ARG ) - 1, 0 ) )
+        {
+            OUString aNum = aArg.copy( sizeof( PIPE_ARG ) - 1 );
+            int fd = aNum.toInt32();
+            m_pOutFd = fdopen( fd, "w" );
+#if OSL_DEBUG_LEVEL > 1
+            fprintf( stderr, "Got argument '-splash-pipe=%d ('%s') (%p)\n",
+                     fd, (const sal_Char *)rtl::OUStringToOString( aNum, RTL_TEXTENCODING_UTF8 ),
+                     m_pOutFd );
+#endif
+        }
+    }
+}
+
+// get service instance...
+UnxSplashScreen *UnxSplashScreen::m_pINSTANCE = NULL;
+osl::Mutex UnxSplashScreen::m_aMutex;
+
+Reference< XInterface > UnxSplashScreen::getInstance( const Reference< XMultiServiceFactory >& rSMgr )
+{
+    if ( m_pINSTANCE == NULL )
+    {
+        osl::MutexGuard guard( m_aMutex );
+        if ( m_pINSTANCE == NULL )
+            return (XComponent*) new UnxSplashScreen( rSMgr );
+    }
+
+    return (XComponent*)NULL;
+}
+
+// static service info...
+const char* UnxSplashScreen::interfaces[] =
+{
+    "com.sun.star.task.XStartusIndicator",
+    "com.sun.star.lang.XInitialization",
+    NULL,
+};
+const sal_Char *UnxSplashScreen::serviceName = "com.sun.star.office.PipeSplashScreen";
+const sal_Char *UnxSplashScreen::implementationName = "com.sun.star.office.comp.PipeSplashScreen";
+const sal_Char *UnxSplashScreen::supportedServiceNames[] = { "com.sun.star.office.PipeSplashScreen", NULL };
+
+OUString UnxSplashScreen::impl_getImplementationName()
+{
+    return OUString::createFromAscii( implementationName );
+}
+
+Sequence<OUString> UnxSplashScreen::impl_getSupportedServiceNames()
+{
+    Sequence<OUString> aSequence;
+    for ( int i = 0; supportedServiceNames[i] != NULL; i++ )
+    {
+        aSequence.realloc( i+1 );
+        aSequence[i] = OUString::createFromAscii( supportedServiceNames[i] );
+    }
+    return aSequence;
+}
+
+}
diff --git a/desktop/unx/splash/unxsplash.hxx b/desktop/unx/splash/unxsplash.hxx
new file mode 100644
index 0000000..0914ccc
--- /dev/null
+++ b/desktop/unx/splash/unxsplash.hxx
@@ -0,0 +1,90 @@
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Initial Developer of the Original Code is
+ *               Novell, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2010 the
+ * Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): Jan Holesovsky <kendy at novell.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+#include <stdio.h>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <cppuhelper/implbase2.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <osl/mutex.hxx>
+#include <rtl/bootstrap.hxx>
+
+using namespace ::rtl;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::task;
+
+namespace desktop {
+
+class  UnxSplashScreen : public ::cppu::WeakImplHelper2< XStatusIndicator, XInitialization >
+{
+private:
+    // don't allow anybody but ourselves to create instances of this class
+    UnxSplashScreen( const UnxSplashScreen& );
+    UnxSplashScreen( void );
+    UnxSplashScreen operator =( const UnxSplashScreen& );
+
+    UnxSplashScreen( const Reference< XMultiServiceFactory >& xFactory );
+
+    virtual ~UnxSplashScreen();
+
+    static  UnxSplashScreen *m_pINSTANCE;
+
+    static osl::Mutex m_aMutex;
+    Reference< XMultiServiceFactory > m_rFactory;
+
+    FILE *m_pOutFd;
+
+public:
+    static const char* interfaces[];
+    static const sal_Char *serviceName;
+    static const sal_Char *implementationName;
+    static const sal_Char *supportedServiceNames[];
+
+    static Reference< XInterface > getInstance( const Reference < XMultiServiceFactory >& xFactory );
+
+    // static service info
+    static OUString  impl_getImplementationName();
+    static Sequence<OUString> impl_getSupportedServiceNames();
+
+    // XStatusIndicator
+    virtual void SAL_CALL start( const OUString& aText, sal_Int32 nRange ) throw ( RuntimeException );
+    virtual void SAL_CALL end() throw ( RuntimeException );
+    virtual void SAL_CALL reset() throw ( RuntimeException );
+    virtual void SAL_CALL setText( const OUString& aText ) throw ( RuntimeException );
+    virtual void SAL_CALL setValue( sal_Int32 nValue ) throw ( RuntimeException );
+
+    // XInitialize
+    virtual void SAL_CALL initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any>& aArguments ) throw ( RuntimeException );
+};
+
+}


More information about the Libreoffice-commits mailing list