diff options
-rw-r--r-- | desktop/inc/app.hxx | 1 | ||||
-rw-r--r-- | desktop/prj/build.lst | 4 | ||||
-rw-r--r-- | desktop/prj/d.lst | 1 | ||||
-rw-r--r-- | desktop/scripts/soffice.sh | 20 | ||||
-rw-r--r-- | desktop/source/app/app.cxx | 36 | ||||
-rw-r--r-- | desktop/source/app/cmdlineargs.cxx | 14 | ||||
-rw-r--r-- | desktop/source/app/cmdlineargs.hxx | 3 | ||||
-rw-r--r-- | desktop/source/app/officeipcthread.cxx | 9 | ||||
-rw-r--r-- | desktop/unx/source/makefile.mk | 62 | ||||
-rw-r--r-- | desktop/unx/source/splashx.c | 622 | ||||
-rw-r--r-- | desktop/unx/source/splashx.h | 62 | ||||
-rw-r--r-- | desktop/unx/source/start.c | 841 | ||||
-rw-r--r-- | desktop/unx/splash/exports.map | 10 | ||||
-rw-r--r-- | desktop/unx/splash/makefile.mk | 72 | ||||
-rw-r--r-- | desktop/unx/splash/services_unxsplash.cxx | 156 | ||||
-rw-r--r-- | desktop/unx/splash/unxsplash.cxx | 173 | ||||
-rw-r--r-- | desktop/unx/splash/unxsplash.hxx | 90 |
17 files changed, 2160 insertions, 16 deletions
diff --git a/desktop/inc/app.hxx b/desktop/inc/app.hxx index c5cb6aa1e789..0690828081c5 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 dc5d7a99b2d6..162c43b38f15 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 cda9361d6933..6251de274a69 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 2c14f12a8e09..df11ec5c13e3 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 fe9be77b4ab4..920676f6c8f1 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 b915c938c1b6..a02c25c9b6d4 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 ); @@ -981,6 +994,7 @@ sal_Bool CommandLineArgs::IsEmptyOrAcceptOnly() const osl::MutexGuard aMutexGuard( m_aMutex ); 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 fecd38302639..c14106907cac 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 ca750817fa60..7aeaa57da64f 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 000000000000..bd8eb75f7dc0 --- /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 000000000000..ee36b7a91568 --- /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 000000000000..3b923e541b51 --- /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 000000000000..834564b1010f --- /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 000000000000..ba501f9ae076 --- /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 000000000000..7466a6d143c5 --- /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 000000000000..03715cc2f88b --- /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 000000000000..edb3603d8c39 --- /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 000000000000..0914ccce2791 --- /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 ); +}; + +} |