summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Holesovsky <kendy@suse.cz>2010-10-12 15:32:09 +0100
committerMichael Meeks <michael.meeks@novell.com>2010-10-12 15:40:42 +0100
commitd2b113ec937d709e45ed1bd278a074f26529d295 (patch)
tree46a8f8c1afee536d74d4c7df7211a210eb870856
parenta4d7dbf897e41a1afda6c2b6f0e5cc35920a1cf3 (diff)
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
-rw-r--r--desktop/inc/app.hxx1
-rw-r--r--desktop/prj/build.lst4
-rw-r--r--desktop/prj/d.lst1
-rw-r--r--desktop/scripts/soffice.sh20
-rw-r--r--desktop/source/app/app.cxx36
-rw-r--r--desktop/source/app/cmdlineargs.cxx16
-rw-r--r--desktop/source/app/cmdlineargs.hxx3
-rw-r--r--desktop/source/app/officeipcthread.cxx9
-rw-r--r--desktop/unx/source/makefile.mk62
-rw-r--r--desktop/unx/source/splashx.c622
-rw-r--r--desktop/unx/source/splashx.h62
-rw-r--r--desktop/unx/source/start.c841
-rw-r--r--desktop/unx/splash/exports.map10
-rw-r--r--desktop/unx/splash/makefile.mk72
-rw-r--r--desktop/unx/splash/services_unxsplash.cxx156
-rw-r--r--desktop/unx/splash/unxsplash.cxx173
-rw-r--r--desktop/unx/splash/unxsplash.hxx90
17 files changed, 2161 insertions, 17 deletions
diff --git a/desktop/inc/app.hxx b/desktop/inc/app.hxx
index 442c9eeb23..499cda2ebd 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 dc5d7a99b2..162c43b38f 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 cda9361d69..6251de274a 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 53c39d4d28..fdd8077105 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 36d5d203de..1a1afcc298 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 7f3d141f85..9552c843b8 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 f357dad523..4ef302e12f 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 854646ef4d..059e594943 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 0000000000..bd8eb75f7d
--- /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@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 0000000000..ee36b7a915
--- /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@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 0000000000..3b923e541b
--- /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@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 0000000000..fe94e904f6
--- /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@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 0000000000..ba501f9ae0
--- /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 0000000000..7466a6d143
--- /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@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 0000000000..03715cc2f8
--- /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@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 0000000000..edb3603d8c
--- /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@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 0000000000..0914ccce27
--- /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@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 );
+};
+
+}