summaryrefslogtreecommitdiffstats
path: root/desktop/unx/source
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /desktop/unx/source
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'desktop/unx/source')
-rw-r--r--desktop/unx/source/args.c138
-rw-r--r--desktop/unx/source/args.h28
-rw-r--r--desktop/unx/source/file_image.h69
-rw-r--r--desktop/unx/source/file_image_unx.c121
-rw-r--r--desktop/unx/source/pagein.c102
-rw-r--r--desktop/unx/source/pagein.h34
-rw-r--r--desktop/unx/source/splashx.c817
-rw-r--r--desktop/unx/source/splashx.h29
-rw-r--r--desktop/unx/source/start.c878
9 files changed, 2216 insertions, 0 deletions
diff --git a/desktop/unx/source/args.c b/desktop/unx/source/args.c
new file mode 100644
index 000000000..199b58a8e
--- /dev/null
+++ b/desktop/unx/source/args.c
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <osl/process.h>
+
+#include "args.h"
+
+/* do we start -env: */
+static int
+is_env_arg (rtl_uString const *str)
+{
+ return !rtl_ustr_ascii_compare_WithLength (str->buffer, 5, "-env:");
+}
+
+static const struct {
+ const char *name;
+ unsigned int bInhibitSplash : 1;
+ unsigned int bInhibitPagein : 1;
+ unsigned int bInhibitJavaLdx : 1;
+ unsigned int bInhibitPipe : 1;
+ const char *pPageinType;
+} pArgDescr[] = {
+ /* have a trailing argument */
+ { "pt", 1, 0, 0, 0, NULL },
+ { "p", 1, 0, 0, 0, NULL },
+ { "display", 0, 0, 0, 0, NULL },
+
+ /* no splash */
+ { "nologo", 1, 0, 0, 0, NULL },
+ { "headless", 1, 0, 0, 0, NULL },
+ { "invisible", 1, 0, 0, 0, NULL },
+ { "quickstart", 1, 0, 0, 0, NULL },
+ { "minimized", 1, 0, 0, 0, NULL },
+ { "convert-to", 1, 0, 0, 0, NULL },
+ { "cat", 1, 0, 0, 0, NULL },
+
+ /* pagein bits */
+ { "writer", 0, 0, 0, 0, "pagein-writer" },
+ { "calc", 0, 0, 0, 0, "pagein-calc" },
+ { "draw", 0, 0, 0, 0, "pagein-draw" },
+ { "impress", 0, 0, 0, 0, "pagein-impress" },
+
+ /* Do not send --help/--version over the pipe, as their output shall go to
+ the calling process's stdout (ideally, this would also happen in the
+ presence of unknown options); also prevent splash/pagein/javaldx overhead
+ (as these options will be processed early in soffice_main): */
+ { "version", 1, 1, 1, 1, NULL },
+ { "help", 1, 1, 1, 1, NULL },
+ { "h", 1, 1, 1, 1, NULL },
+ { "?", 1, 1, 1, 1, NULL },
+};
+
+Args *args_parse (void)
+{
+ Args *args;
+ sal_uInt32 nArgs, i, j;
+
+ nArgs = osl_getCommandArgCount();
+ i = sizeof (Args) + sizeof (rtl_uString *) * nArgs;
+ args = malloc (i);
+ memset (args, 0, i);
+ args->nArgsTotal = nArgs;
+
+ j = 0;
+
+ /* sort the -env: args to the front */
+ for ( i = 0; i < nArgs; ++i )
+ {
+ rtl_uString *pTmp = NULL;
+ osl_getCommandArg( i, &pTmp );
+ if (is_env_arg (pTmp))
+ args->ppArgs[j++] = pTmp;
+ else
+ rtl_uString_release (pTmp);
+ }
+ args->nArgsEnv = j;
+
+ /* Then the other args */
+ for ( i = 0; i < nArgs; ++i )
+ {
+ rtl_uString *pTmp = NULL;
+
+ osl_getCommandArg( i, &pTmp );
+ if (!is_env_arg (pTmp))
+ args->ppArgs[j++] = pTmp;
+ else
+ rtl_uString_release (pTmp);
+ }
+
+ for ( i = args->nArgsEnv; i < args->nArgsTotal; i++ )
+ {
+ const sal_Unicode *arg = args->ppArgs[i]->buffer;
+ sal_Int32 length = args->ppArgs[i]->length;
+
+ /* grok only parameters */
+ if (arg[0] != '-')
+ continue;
+
+ while (length > 1 && arg[0] == '-') {
+ arg++;
+ length--;
+ }
+
+ for ( j = 0; j < SAL_N_ELEMENTS (pArgDescr); ++j ) {
+ if (rtl_ustr_ascii_compare_WithLength(
+ arg, length, pArgDescr[j].name)
+ == 0)
+ {
+ args->bInhibitSplash |= pArgDescr[j].bInhibitSplash;
+ args->bInhibitPagein |= pArgDescr[j].bInhibitPagein;
+ args->bInhibitJavaLdx |= pArgDescr[j].bInhibitJavaLdx;
+ args->bInhibitPipe |= pArgDescr[j].bInhibitPipe;
+ if (pArgDescr[j].pPageinType)
+ args->pPageinType = pArgDescr[j].pPageinType;
+ break;
+ }
+ }
+ }
+
+ return args;
+}
+
+void
+args_free (Args *args)
+{
+ /* FIXME: free ppArgs */
+ rtl_uString_release( args->pAppPath );
+ free (args);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/unx/source/args.h b/desktop/unx/source/args.h
new file mode 100644
index 000000000..f0fe7ce39
--- /dev/null
+++ b/desktop/unx/source/args.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include <sal/types.h>
+#include <rtl/ustring.h>
+
+typedef struct {
+ rtl_uString *pAppPath;
+ const char *pPageinType; // @pagein-writer for - writer etc. else NULL
+ sal_Bool bInhibitSplash; // should we show a splash screen
+ sal_Bool bInhibitPagein; // should we run pagein ?
+ sal_Bool bInhibitJavaLdx; // should we run javaldx ?
+ sal_Bool bInhibitPipe; // for --help and --version
+
+ sal_uInt32 nArgsEnv; // number of -env: style args
+ sal_uInt32 nArgsTotal; // number of -env: as well as -writer style args
+ rtl_uString *ppArgs[1]; // sorted argument array
+} Args;
+
+Args *args_parse (void);
+void args_free (Args *args);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/unx/source/file_image.h b/desktop/unx/source/file_image.h
new file mode 100644
index 000000000..6f0194d17
--- /dev/null
+++ b/desktop/unx/source/file_image.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#ifndef INCLUDED_STDDEF_H
+#include <stddef.h>
+#define INCLUDED_STDDEF_H
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** file_image.
+ */
+struct file_image_st
+{
+ void * m_base;
+ size_t m_size;
+};
+
+typedef struct file_image_st file_image;
+
+#define FILE_IMAGE_INITIALIZER { NULL, 0 }
+
+
+/** file_image_open.
+ */
+int file_image_open (
+ file_image * image,
+ const char * filename);
+
+
+/** file_image_pagein.
+ */
+int file_image_pagein (
+ file_image * image);
+
+
+/** file_image_close.
+ */
+int file_image_close (
+ file_image * image);
+
+
+/** Epilog.
+ */
+#ifdef __cplusplus
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/unx/source/file_image_unx.c b/desktop/unx/source/file_image_unx.c
new file mode 100644
index 000000000..4294a5761
--- /dev/null
+++ b/desktop/unx/source/file_image_unx.c
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "file_image.h"
+
+#include <unistd.h>
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <string.h>
+
+/*
+ * file_image_open
+ */
+int file_image_open (file_image * image, const char * filename)
+{
+ int result = 0;
+ int fd;
+ struct stat st;
+ void * p;
+
+ if (image == NULL)
+ return EINVAL;
+
+ image->m_base = MAP_FAILED;
+ image->m_size = 0;
+
+ if ((fd = open (filename, O_RDONLY)) == -1)
+ return errno;
+
+ if (fstat (fd, &st) == -1)
+ {
+ result = errno;
+ goto cleanup_and_leave;
+ }
+
+ p = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (p == MAP_FAILED)
+ {
+ result = errno;
+ goto cleanup_and_leave;
+ }
+
+ image->m_base = p;
+ image->m_size = st.st_size;
+
+cleanup_and_leave:
+ close (fd);
+ return result;
+}
+
+/*
+ * file_image_pagein.
+ */
+int file_image_pagein (file_image * image)
+{
+ long s = -1;
+ volatile char c =0;
+ size_t idx;
+
+ if (image == NULL)
+ return EINVAL;
+ if (image->m_base == NULL)
+ return EINVAL;
+ if (image->m_size == 0)
+ return 0;
+
+ if (madvise (image->m_base, image->m_size, MADV_WILLNEED) == -1)
+ return errno;
+
+ s = sysconf (_SC_PAGESIZE);
+ if (s == -1)
+ s = 0x1000;
+ // force touching of each page despite the optimizer
+ for(idx = 0; idx < image->m_size; idx += (size_t)s)
+ {
+ c ^= ((volatile const char*)(image->m_base))[idx];
+ }
+ c ^= ((volatile const char*)(image->m_base))[image->m_size-1];
+ (void)c; // silence Clang 13 trunk -Wunused-but-set-variable
+
+ return 0;
+}
+
+/*
+ * file_image_close
+ */
+int file_image_close (file_image * image)
+{
+ if (image == NULL)
+ return EINVAL;
+
+ if (munmap (image->m_base, image->m_size) == -1)
+ return errno;
+
+ image->m_base = NULL;
+ image->m_size = 0;
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/unx/source/pagein.c b/desktop/unx/source/pagein.c
new file mode 100644
index 000000000..87bbb699f
--- /dev/null
+++ b/desktop/unx/source/pagein.c
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "file_image.h"
+#include "pagein.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#ifdef LINUX
+#include <sys/sysmacros.h>
+#endif
+
+/* do_pagein */
+static void do_pagein (const char * filename)
+{
+ int result;
+ file_image image = FILE_IMAGE_INITIALIZER;
+
+ if (file_image_open (&image, filename) != 0)
+ return;
+
+ if ((result = file_image_pagein (&image)) != 0)
+ {
+ fprintf (stderr, "file_image_pagein %s: %s\n", filename, strerror(result));
+ }
+
+ file_image_close (&image);
+}
+
+static int isRotational(char const * path)
+{
+ int ret = 1;
+#ifdef LINUX
+ FILE * fp = NULL;
+ char fullpath[4096];
+ struct stat out;
+ int major, minor;
+ char type;
+ if (stat(path , &out) == -1)
+ return ret;
+ major = major(out.st_dev);
+ minor = 0; /* minor(out.st_dev); only the device itself has a queue */
+ sprintf(fullpath,"/sys/dev/block/%d:%d/queue/rotational",major,minor);
+ if ((fp = fopen(fullpath, "r")) == NULL)
+ return ret;
+ if (fgets(&type, 1, fp))
+ ret = type == '1';
+ fclose(fp);
+#endif
+ return ret;
+}
+
+void pagein_execute(char const * path, char const * file)
+{
+ char fullpath[4096];
+ char *p = NULL;
+ FILE * fp = NULL;
+ if(!isRotational(path))
+ return;
+ memset(fullpath, 0, sizeof(fullpath));
+ strncpy (fullpath, path, 3000);
+ if (!(p = strrchr (fullpath, '/')))
+ p = fullpath;
+ else
+ p++;
+ strncpy(p, file, 1024);
+ p[strlen(p)] = '\0';
+ if ((fp = fopen (fullpath, "r")) == NULL)
+ {
+
+ fprintf (stderr, "fopen %s: %s\n", fullpath, strerror(errno));
+ return;
+ }
+ while (fgets (p, 1024, fp) != NULL)
+ {
+ p[strlen(p) - 1] = '\0';
+
+ /* paths relative to the location of the pagein file */
+ do_pagein (fullpath);
+ }
+ fclose (fp);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/unx/source/pagein.h b/desktop/unx/source/pagein.h
new file mode 100644
index 000000000..7fb8b6a91
--- /dev/null
+++ b/desktop/unx/source/pagein.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <config_features.h>
+
+#if HAVE_FEATURE_PAGEIN
+void pagein_execute(char const* path, char const* file);
+#else
+inline void pagein_execute(char const* path, char const* file)
+{
+ (void)path;
+ (void)file;
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/unx/source/splashx.c b/desktop/unx/source/splashx.c
new file mode 100644
index 000000000..afd137d06
--- /dev/null
+++ b/desktop/unx/source/splashx.c
@@ -0,0 +1,817 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <config_features.h>
+#include "splashx.h"
+
+#if defined(ENABLE_QUICKSTART_LIBPNG) && HAVE_FEATURE_UI
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+
+#ifdef USE_XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+
+#include <osl/endian.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <png.h>
+
+#include <osl/process.h>
+#include <osl/thread.h>
+#include <rtl/bootstrap.h>
+#include <rtl/ustrbuf.h>
+
+typedef struct {
+ unsigned char b, g, r;
+} color_t;
+
+struct splash
+{
+ Display* display;
+ int screen;
+ int depth;
+ int display_width;
+ int display_height;
+ int display_x_pos;
+ int display_y_pos;
+ Visual* visual;
+
+ int width;
+ int height;
+
+ Colormap color_map;
+ Window win;
+ GC gc;
+ //true when intro-highres loaded successfully
+ sal_Bool bHasHiDpiImage;
+
+// Progress bar values
+// taken from desktop/source/splash/splash.cxx
+ int tlx;
+ int tly;
+ int barwidth;
+ int barheight;
+ int barspace;
+ color_t barcol;
+ color_t framecol;
+
+ XColor barcolor;
+ XColor framecolor;
+
+ unsigned char** bitmap_rows;
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+};
+
+#define WINDOW_WIDTH 440
+#define WINDOW_HEIGHT 299
+
+#define PROGRESS_XOFFSET 12
+#define PROGRESS_YOFFSET 18
+#define PROGRESS_BARSPACE 2
+
+/* libpng-1.2.41 */
+#ifndef PNG_TRANSFORM_GRAY_TO_RGB
+# define PNG_TRANSFORM_GRAY_TO_RGB 0x2000
+#endif
+
+static int splash_load_bmp( struct splash* splash, const char *filename )
+{
+ FILE *file;
+
+ if ( !(file = fopen( filename, "r" ) ) )
+ return 0;
+
+ splash->png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
+ splash->info_ptr = png_create_info_struct(splash->png_ptr);
+ png_init_io( splash->png_ptr, file );
+
+ if( setjmp( png_jmpbuf( splash->png_ptr ) ) )
+ {
+ png_destroy_read_struct( &(splash->png_ptr), &(splash->info_ptr), NULL );
+ fclose( file );
+ return 0;
+ }
+
+ png_read_png( splash->png_ptr, splash->info_ptr,
+ PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_ALPHA |
+ PNG_TRANSFORM_GRAY_TO_RGB | PNG_TRANSFORM_BGR, NULL);
+
+ splash->bitmap_rows = png_get_rows( splash->png_ptr, splash->info_ptr );
+ splash->width = png_get_image_width( splash->png_ptr, splash->info_ptr );
+ splash->height = png_get_image_height( splash->png_ptr, splash->info_ptr );
+
+ fclose( file );
+ return 1;
+}
+
+static void setup_color( int const 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
+}
+
+/* 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;
+
+ /* 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;
+ int i = 0;
+ sal_Int32 nIndex = 0;
+ 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 );
+}
+
+// setup
+static void splash_setup( struct splash* splash, int const barc[3], int const framec[3], int posx, int posy, int w, int h )
+{
+ if ( splash->width <= 500 )
+ {
+ splash->barwidth = splash->width - ( 2 * PROGRESS_XOFFSET );
+ splash->barheight = 6;
+ splash->tlx = PROGRESS_XOFFSET;
+ splash->tly = splash->height - PROGRESS_YOFFSET;
+
+ splash->barcol.r = 0;
+ splash->barcol.g = 0;
+ splash->barcol.b = 128;
+ }
+
+ if ( posx >= 0 )
+ splash->tlx = posx;
+ if ( posy >= 0 )
+ splash->tly = posy;
+ if ( w >= 0 )
+ splash->barwidth = w;
+ if ( h >= 0 )
+ splash->barheight = h;
+
+ setup_color( barc, &(splash->barcol) );
+ setup_color( framec, &(splash->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)
+static int HIGHEST_BIT( unsigned long x )
+{
+ int i = 0;
+ for ( ; x; ++i )
+ x >>= 1;
+
+ return i;
+}
+
+// Number of bits set to 1
+static 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(struct splash* splash)
+{
+ Pixmap pixmap;
+ GC pixmap_gc;
+ XGCValues values;
+
+ if ( !splash->bitmap_rows )
+ {
+ return;
+ }
+ pixmap = XCreatePixmap( splash->display, splash->win, splash->width, splash->height, splash->depth );
+
+ pixmap_gc = XCreateGC( splash->display, pixmap, 0/*value_mask*/, &values );
+
+ if ( splash->visual->class == TrueColor )
+ {
+ const unsigned long red_mask = splash->visual->red_mask;
+ const unsigned long green_mask = splash->visual->green_mask;
+ const unsigned long blue_mask = splash->visual->blue_mask;
+
+ const unsigned long red_delta_mask = ( 1UL << ( 8 - BITS( red_mask ) ) ) - 1;
+ const unsigned long green_delta_mask = ( 1UL << ( 8 - BITS( green_mask ) ) ) - 1;
+ const unsigned long blue_delta_mask = ( 1UL << ( 8 - BITS( blue_mask ) ) ) - 1;
+
+ const int red_shift = HIGHEST_BIT( red_mask ) - 8;
+ const int green_shift = HIGHEST_BIT( green_mask ) - 8;
+ const int blue_shift = HIGHEST_BIT( blue_mask ) - 8;
+
+ XImage* image = XCreateImage( splash->display, splash->visual, splash->depth, ZPixmap,
+ 0, NULL, splash->width, splash->height, 32, 0 );
+
+ const int bytes_per_line = image->bytes_per_line;
+ const int bpp = image->bits_per_pixel;
+ const int byte_order = image->byte_order;
+#if defined OSL_LITENDIAN
+ const int machine_byte_order = LSBFirst;
+#else /* OSL_BIGENDIAN */
+ const int machine_byte_order = MSBFirst;
+#endif
+
+ char *data = malloc( splash->height * bytes_per_line );
+ char *out = data;
+ 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 < splash->height; ++y ) \
+ { \
+ unsigned long red_delta = 0, green_delta = 0, blue_delta = 0; \
+ color_t *in = (color_t *)(splash->bitmap_rows[y]); \
+ out = data + y * bytes_per_line; \
+ for ( x = 0; x < splash->width; ++x, ++in ) \
+ { \
+ unsigned long red = in->r + red_delta; \
+ unsigned long green = in->g + green_delta; \
+ unsigned long blue = in->b + blue_delta; \
+ unsigned long pixel = 0; \
+ uint32_t tmp = 0; \
+ (void) tmp; \
+ 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; \
+ pixel = \
+ ( SHIFT( red, red_shift ) & red_mask ) | \
+ ( SHIFT( green, green_shift ) & green_mask ) | \
+ ( SHIFT( blue, blue_shift ) & blue_mask ); \
+ code \
+ } \
+ } \
+ }
+
+ 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, 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)
+ {
+#if defined OSL_LITENDIAN
+ COPY_IN_OUT( 3, memcpy(out, &pixel, sizeof (color_t)); out += 3; )
+#else /* OSL_BIGENDIAN */
+ COPY_IN_OUT( 3, 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; )
+#endif
+ }
+ else
+ COPY_IN_OUT( 3, 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, 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( splash->display, pixmap_gc );
+ XFreePixmap( splash->display, pixmap );
+ XDestroyImage( image );
+ return;
+ }
+
+#undef COPY_IN_OUT
+
+ XPutImage( splash->display, pixmap, pixmap_gc, image, 0, 0, 0, 0, splash->width, splash->height );
+ XDestroyImage( image );
+ }
+
+ XSetWindowBackgroundPixmap( splash->display, splash->win, pixmap );
+
+ XFreeGC( splash->display, pixmap_gc );
+ XFreePixmap( splash->display, pixmap );
+}
+
+// The old method of hiding the window decorations
+static void suppress_decorations_motif(struct splash* splash)
+{
+ struct
+ {
+ unsigned long flags, functions, decorations;
+ long input_mode;
+ } mwmhints;
+
+ Atom a = XInternAtom( splash->display, "_MOTIF_WM_HINTS", False );
+
+ mwmhints.flags = 15; // functions, decorations, input_mode, status
+ mwmhints.functions = 2; // ?
+ mwmhints.decorations = 0;
+ mwmhints.input_mode = 0;
+
+ XChangeProperty( splash->display, splash->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(struct splash* splash)
+{
+ Atom atom_type = XInternAtom( splash->display, "_NET_WM_WINDOW_TYPE", True );
+ Atom atom_splash = XInternAtom( splash->display, "_NET_WM_WINDOW_TYPE_SPLASH", True );
+
+ if ( atom_type != None && atom_splash != None )
+ XChangeProperty( splash->display, splash->win, atom_type, XA_ATOM, 32,
+ PropModeReplace, (unsigned char*)&atom_splash, 1 );
+ //else
+ suppress_decorations_motif(splash); // FIXME: Unconditional until Metacity/compiz's SPLASH handling is fixed
+}
+
+/**
+ * Connects to the display and initializes splash with the screen details
+ *
+ * @return Success: 1; Failure: 0
+ */
+static int splash_init_display( struct splash* splash, int argc, char** argv )
+{
+ char *display_name = NULL;
+ int i;
+#ifdef USE_XINERAMA
+ int n_xinerama_screens = 1;
+ XineramaScreenInfo* p_screens = NULL;
+#endif
+
+ 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
+ splash->display = XOpenDisplay( display_name );
+ if ( !splash->display )
+ {
+ fprintf( stderr, "Failed to open display\n" );
+ return 0;
+ }
+
+ // create the window
+ splash->screen = DefaultScreen( splash->display );
+ splash->depth = DefaultDepth( splash->display, splash->screen );
+ splash->color_map = DefaultColormap( splash->display, splash->screen );
+ splash->visual = DefaultVisual( splash->display, splash->screen );
+
+ splash->display_width = DisplayWidth( splash->display, splash->screen );
+ splash->display_height = DisplayHeight( splash->display, splash->screen );
+ splash->display_x_pos = 0;
+ splash->display_y_pos = 0;
+
+#ifdef USE_XINERAMA
+ p_screens = XineramaQueryScreens( splash->display, &n_xinerama_screens );
+ if( p_screens )
+ {
+ for( i=0; i < n_xinerama_screens; i++ )
+ {
+ if ( p_screens[i].screen_number == splash->screen )
+ {
+ splash->display_width = p_screens[i].width;
+ splash->display_height = p_screens[i].height;
+ splash->display_x_pos = p_screens[i].x_org;
+ splash->display_y_pos = p_screens[i].y_org;
+ break;
+ }
+ }
+ XFree( p_screens );
+ }
+#endif
+ return 1;
+}
+
+/**
+ * Create the window for the splash screen
+ *
+ * @return Success: 1; Failure: 0
+ */
+static int splash_create_window(struct splash* splash)
+{
+ Window root_win;
+ XGCValues values;
+ const char* name = "LibreOffice";
+ const char* icon = "icon"; // FIXME
+ XSizeHints size_hints;
+
+ root_win = RootWindow( splash->display, splash->screen );
+
+ splash->win = XCreateSimpleWindow( splash->display, root_win,
+ (splash->display_x_pos + (splash->display_width - splash->width)/2),
+ (splash->display_y_pos + (splash->display_height - splash->height)/2),
+ splash->width, splash->height, 0,
+ BlackPixel( splash->display, splash->screen ), BlackPixel( splash->display, splash->screen ) );
+
+ XSetWindowColormap( splash->display, splash->win, splash->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( splash->barcolor, splash->barcol );
+ FILL_COLOR( splash->framecolor, splash->framecol );
+#undef FILL_COLOR
+
+ XAllocColor( splash->display, splash->color_map, &(splash->barcolor) );
+ XAllocColor( splash->display, splash->color_map, &(splash->framecolor) );
+
+ // not resizable, no decorations, etc.
+ splash->gc = XCreateGC( splash->display, splash->win, 0/*value_mask*/, &values );
+
+ size_hints.flags = PPosition | PSize | PMinSize | PMaxSize;
+ size_hints.x = splash->display_x_pos;
+ size_hints.y = splash->display_y_pos;
+ size_hints.width = splash->width;
+ size_hints.height = splash->height;
+ size_hints.min_width = splash->width;
+ size_hints.max_width = splash->width;
+ size_hints.min_height = splash->height;
+ size_hints.max_height = splash->height;
+
+ XSetStandardProperties( splash->display, splash->win, name, icon, None,
+ NULL, 0, &size_hints );
+
+ // the actual work
+ suppress_decorations(splash);
+ create_pixmap(splash);
+
+ // show it
+ XSelectInput( splash->display, splash->win, 0 );
+ XMapWindow( splash->display, splash->win );
+
+ return 1;
+}
+
+// Re-draw & process the events
+// Just throwing them away - we do not need anything more...
+static void process_events(struct splash* splash)
+{
+ XEvent xev;
+ int num_events;
+
+ XFlush( splash->display );
+ num_events = XPending( splash->display );
+ while ( num_events > 0 )
+ {
+ num_events--;
+ XNextEvent( splash->display, &xev );
+ }
+}
+
+
+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;
+}
+
+static sal_Bool isHiDPI(struct splash* splash)
+{
+ const char* pValStr;
+ double nDPI;
+
+ /*
+ * GNOME currently enables HiDPI support when the screen resolution is at least 192 dpi
+ * and the screen height (in device pixels) is at least 1200.
+ */
+
+ if (splash->display_height < 1200)
+ return sal_False;
+
+ pValStr = XGetDefault(splash->display, "Xft", "dpi");
+ /* if it's too old to have this, assume it's not hidpi */
+ if (!pValStr)
+ return sal_False;
+
+ nDPI = strtod(pValStr, NULL);
+ if (nDPI < 192)
+ return sal_False;
+
+ return sal_True;
+}
+
+#define IMG_SUFFIX ".png"
+
+static void splash_load_image( struct splash* splash, rtl_uString* pUAppPath )
+{
+ /* FIXME-BCP47: if we wanted to support language tags here that would get
+ * complicated, this is C-source not C++ so LanguageTag can't be used. For
+ * now the splash screen will have to get along with language-territory. */
+
+ 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) + 3;
+ pLocale = malloc (nLocSize);
+ pLocale[0] = '-';
+ strcpy (pLocale + 1, pLang->buffer);
+ strcat (pLocale, "_");
+ strcat (pLocale, pCountry->buffer);
+
+ rtl_string_release( pCountry );
+ rtl_string_release( pLang );
+
+ pAppPath = ustr_to_str (pUAppPath);
+ pBuffer = malloc (pAppPath->length + nLocSize + 256);
+ strcpy (pBuffer, pAppPath->buffer);
+ pSuffix = pBuffer + pAppPath->length;
+ rtl_string_release( pAppPath );
+
+ strcpy (pSuffix, "intro");
+ strcat (pSuffix, pLocale);
+ strcat (pSuffix, IMG_SUFFIX);
+ if ( splash_load_bmp( splash, pBuffer ) )
+ goto cleanup; /* success */
+
+ /* load high resolution splash image */
+ splash->bHasHiDpiImage = sal_False;
+ if (isHiDPI(splash))
+ {
+ strcpy (pSuffix, "intro-highres" IMG_SUFFIX);
+ if ( splash_load_bmp( splash, pBuffer ) )
+ {
+ splash->bHasHiDpiImage = sal_True;
+ goto cleanup; /* success */
+ }
+ }
+ /* load standard resolution splash image */
+ strcpy (pSuffix, "intro" IMG_SUFFIX);
+ if ( splash_load_bmp( splash, pBuffer ) )
+ goto cleanup; /* success */
+
+ fprintf (stderr, "Failed to find intro image\n");
+
+ cleanup:
+ free (pLocale);
+ free (pBuffer);
+}
+
+/* Load the colors and size of the splash. */
+static void splash_load_defaults( struct splash* splash, rtl_uString* pAppPath, sal_Bool* bNoDefaults )
+{
+ rtl_uString *pSettings = NULL, *pTmp = NULL;
+ rtlBootstrapHandle handle;
+ int logo[1] = { -1 },
+ bar[3] = { -1, -1, -1 },
+ frame[3] = { -1, -1, -1 },
+ pos[2] = { -1, -1 },
+ size[2] = { -1, -1 };
+
+ /* construct the sofficerc file location */
+ rtl_uString_newFromAscii( &pSettings, "file://" );
+ rtl_uString_newConcat( &pSettings, pSettings, pAppPath );
+ 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 );
+
+ /* get the values */
+ get_bootstrap_value( logo, 1, handle, "Logo" );
+ get_bootstrap_value( bar, 3, handle, "ProgressBarColor" );
+ get_bootstrap_value( frame, 3, handle, "ProgressFrameColor" );
+ if (isHiDPI(splash) && splash->bHasHiDpiImage)
+ {
+ get_bootstrap_value( pos, 2, handle, "ProgressPositionHigh" );
+ get_bootstrap_value( size, 2, handle, "ProgressSizeHigh" );
+ }
+ else
+ {
+ get_bootstrap_value( pos, 2, handle, "ProgressPosition" );
+ get_bootstrap_value( size, 2, handle, "ProgressSize" );
+ }
+
+ if ( logo[0] == 0 )
+ {
+ *bNoDefaults = sal_True;
+ }
+
+ splash_setup( splash, bar, frame, pos[0], pos[1], size[0], size[1] );
+
+ /* cleanup */
+ rtl_bootstrap_args_close( handle );
+ rtl_uString_release( pSettings );
+ rtl_uString_release( pTmp );
+}
+
+
+// Draw the progress
+void splash_draw_progress( struct splash* splash, int progress )
+{
+ int length = 0;
+
+ if (!splash)
+ {
+ return;
+ }
+ // sanity
+ if ( progress < 0 )
+ {
+ progress = 0;
+ }
+ if ( progress > 100 )
+ {
+ progress = 100;
+ }
+ // draw progress...
+ length = ( progress * splash->barwidth / 100 ) - ( 2 * splash->barspace );
+ if ( length < 0 )
+ {
+ length = 0;
+ }
+ // border
+ XSetForeground( splash->display, splash->gc, splash->framecolor.pixel );
+ XDrawRectangle( splash->display, splash->win, splash->gc, splash->tlx, splash->tly,
+ splash->barwidth, splash->barheight );
+
+ // progress bar
+ XSetForeground( splash->display, splash->gc, splash->barcolor.pixel );
+ XFillRectangle( splash->display, splash->win, splash->gc,
+ splash->tlx + splash->barspace, splash->tly + splash->barspace,
+ length + 1, splash->barheight - 2 * splash->barspace + 1 );
+
+ // pending events
+ process_events(splash);
+}
+
+void splash_destroy(struct splash* splash)
+{
+ if(!splash)
+ return;
+
+ if(splash->display)
+ {
+ if(splash->gc)
+ {
+ XFreeGC(splash->display, splash->gc);
+ splash->gc = NULL;
+ }
+
+ XCloseDisplay( splash->display );
+ splash->display = NULL;
+ png_destroy_read_struct( &(splash->png_ptr), &(splash->info_ptr), NULL );
+ }
+ free(splash);
+}
+
+struct splash* splash_create(rtl_uString* pAppPath, int argc, char** argv)
+{
+ struct splash* splash;
+ sal_Bool bNoDefaults = sal_False;
+
+ splash = calloc(1, sizeof(struct splash));
+ if (splash && !splash_init_display(splash, argc, argv))
+ {
+ splash_destroy(splash);
+ splash = NULL;
+ }
+
+ if (!splash)
+ return NULL;
+
+ splash->width = WINDOW_WIDTH;
+ splash->height = WINDOW_HEIGHT;
+
+ splash->tlx = 212;
+ splash->tly = 216;
+ splash->barwidth = 263;
+ splash->barheight = 8;
+ splash->barspace = PROGRESS_BARSPACE;
+ splash->barcol.b = 18;
+ splash->barcol.g = 202;
+ splash->barcol.r = 157;
+ splash->framecol.b = 0xD3;
+ splash->framecol.g = 0xD3;
+ splash->framecol.r = 0xD3;
+
+ splash_load_image( splash, pAppPath );
+ splash_load_defaults( splash, pAppPath, &bNoDefaults );
+
+ if (!bNoDefaults && splash_create_window(splash))
+ {
+ splash_draw_progress( splash, 0 );
+ return splash;
+ }
+
+ splash_destroy(splash);
+ return NULL;
+}
+
+#else /* not ENABLE_QUICKSTART_LIBPNG */
+
+struct splash
+{
+};
+
+/* Stubs that will never be called in this case */
+void splash_draw_progress( struct splash* splash, int progress )
+{
+ (void)splash; (void)progress;
+}
+
+void splash_destroy(struct splash* splash)
+{
+ (void)splash;
+}
+
+struct splash* splash_create(rtl_uString* pAppPath, int argc, char** argv)
+{
+ (void)pAppPath; (void)argc; (void)argv;
+ return NULL;
+}
+
+
+#endif // ENABLE_QUICKSTART_LIBPNG
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/unx/source/splashx.h b/desktop/unx/source/splashx.h
new file mode 100644
index 000000000..0ca1ba655
--- /dev/null
+++ b/desktop/unx/source/splashx.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <rtl/ustring.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct splash;
+
+struct splash* splash_create(rtl_uString* pAppPath, int argc, char** argv);
+
+void splash_destroy(struct splash* splash);
+
+void splash_draw_progress(struct splash* splash, int progress);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/unx/source/start.c b/desktop/unx/source/start.c
new file mode 100644
index 000000000..f95956566
--- /dev/null
+++ b/desktop/unx/source/start.c
@@ -0,0 +1,878 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <config_java.h>
+
+#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 <poll.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <libgen.h>
+#include <string.h>
+#include <errno.h>
+
+#include <desktop/exithelper.h>
+#include <osl/process.h>
+#include <osl/thread.h>
+#include <rtl/bootstrap.h>
+#include <rtl/digest.h>
+#include <rtl/process.h>
+#include <rtl/ustrbuf.h>
+#include <sal/main.h>
+
+#include "args.h"
+#include "pagein.h"
+#include "splashx.h"
+
+#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;
+}
+
+typedef struct {
+ int status_fd;
+ oslProcess child;
+} ChildInfo;
+
+static int
+child_info_get_status_fd(ChildInfo const *info)
+{
+ return info->status_fd;
+}
+
+static void
+child_info_destroy(ChildInfo *info)
+{
+ close (info->status_fd);
+ osl_freeProcessHandle (info->child);
+ free (info);
+}
+
+static ChildInfo * child_spawn(Args *args, sal_Bool bAllArgs, sal_Bool bWithStatus)
+{
+ rtl_uString *pApp = NULL, *pTmp = NULL;
+ rtl_uString **ppArgs;
+ sal_uInt32 nArgs, i;
+ ChildInfo *info;
+ int status_pipe[2];
+ oslProcessError nError;
+
+ info = calloc (1, sizeof (ChildInfo));
+
+ /* create pipe */
+ if (pipe(status_pipe) < 0)
+ {
+ fprintf(stderr, "ERROR: no file handles\n");
+ exit(1);
+ }
+ info->status_fd = status_pipe[0];
+
+ /* application name */
+ rtl_uString_newFromAscii(&pApp, "file://");
+ rtl_uString_newConcat(&pApp, pApp, args->pAppPath);
+ rtl_uString_newFromAscii(&pTmp, "soffice.bin");
+ rtl_uString_newConcat(&pApp, pApp, pTmp);
+ rtl_uString_release(pTmp);
+ pTmp = NULL;
+
+ /* copy args */
+ nArgs = bAllArgs ? args->nArgsTotal : args->nArgsEnv;
+ ppArgs = (rtl_uString **)calloc(nArgs + 1, sizeof(rtl_uString*));
+ for (i = 0; i < nArgs; ++i)
+ ppArgs[i] = args->ppArgs[i];
+
+ if(bWithStatus)
+ {
+ char buffer[64];
+
+ /* add the pipe arg */
+ snprintf(buffer, 63, "--splash-pipe=%d", status_pipe[1]);
+ rtl_uString_newFromAscii( &pTmp, buffer );
+ ppArgs[nArgs] = pTmp;
+ ++nArgs;
+ }
+
+ /* start the main process */
+ nError = osl_executeProcess(pApp, ppArgs, nArgs,
+ osl_Process_NORMAL,
+ NULL,
+ NULL,
+ NULL, 0,
+ &info->child );
+
+ if (pTmp)
+ rtl_uString_release(pTmp);
+ free (ppArgs);
+
+ if (nError != osl_Process_E_None)
+ {
+ fprintf(stderr, "ERROR %d forking process\n", nError);
+ rtl_uString_release(pApp);
+ _exit (1);
+ }
+
+ rtl_uString_release(pApp);
+ close( status_pipe[1] );
+
+ return info;
+}
+
+static sal_Bool child_exited_wait(ChildInfo *info, sal_Bool bShortWait)
+{
+ TimeValue t = { 0, 250 /* ms */ * 1000 * 1000 };
+ if (!bShortWait)
+ t.Seconds = 1024;
+
+ return osl_joinProcessWithTimeout(info->child, &t) != osl_Process_E_TimedOut;
+}
+
+static int child_get_exit_code(ChildInfo *info)
+{
+ oslProcessInfo inf;
+
+ inf.Code = -1;
+ inf.Size = sizeof(inf);
+
+ if (osl_getProcessInfo(info->child, osl_Process_EXITCODE, &inf) != osl_Process_E_None)
+ {
+ fprintf(stderr, "Warning: failed to fetch libreoffice exit status\n");
+ return -1;
+ }
+
+ return inf.Code;
+}
+
+typedef enum { ProgressContinue, ProgressRestart, ProgressExit } ProgressStatus;
+
+/* Path of the application, with trailing slash. */
+static rtl_uString *get_app_path(const char *pAppExec)
+{
+ char pRealPath[PATH_MAX];
+ rtl_uString *pResult;
+ sal_Int32 len;
+ char* dummy;
+
+ char *pOrigPath = strdup(pAppExec);
+ char *pPath = dirname(pOrigPath);
+
+ dummy = realpath(pPath, pRealPath);
+ (void)dummy;
+ pResult = charp_to_ustr(pRealPath);
+ free(pOrigPath);
+
+ len = rtl_uString_getLength(pResult);
+ if (len > 0 && rtl_uString_getStr(pResult)[len - 1] != '/')
+ {
+ rtl_uString *pSlash = NULL;
+ rtl_uString_newFromAscii(&pSlash, "/");
+ rtl_uString_newConcat(&pResult, pResult, pSlash);
+ rtl_uString_release(pSlash);
+ }
+
+ 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;
+ unsigned char *pData = NULL;
+ sal_uInt32 nSize = 0;
+ rtlDigest digest;
+ sal_uInt32 md5_key_len = 0;
+ sal_uInt8* md5_buf = NULL;
+ sal_uInt32 i = 0;
+
+ if ( !pText )
+ return NULL;
+
+ pData = (unsigned char *)rtl_uString_getStr(pText);
+ nSize = rtl_uString_getLength(pText) * sizeof(sal_Unicode);
+ if (!pData)
+ return NULL;
+
+ digest = rtl_digest_create(rtl_Digest_AlgorithmMD5);
+ if (!digest)
+ return NULL;
+
+ md5_key_len = rtl_digest_queryLength(digest);
+ 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);
+ 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;
+ rtlBootstrapHandle handle;
+ rtl_uString *pMd5hash = NULL;
+ sal_Unicode pUnicode[RTL_USTR_MAX_VALUEOFINT32];
+
+ /* setup bootstrap filename */
+ rtl_uString_newFromAscii(&pPath, "file://");
+ rtl_uString_newConcat(&pPath, pPath, pAppPath);
+ rtl_uString_newConcat(&pPath, pPath, pTmp);
+ rtl_uString_newFromAscii(&pTmp, SAL_CONFIGFILE("bootstrap"));
+ rtl_uString_newConcat(&pPath, pPath, pTmp);
+
+ /* read userinstallation value */
+ 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 */
+ pMd5hash = get_md5hash(pAbsUserInstallation);
+ if (!pMd5hash)
+ rtl_uString_new(&pMd5hash);
+
+ if (access(PIPEDEFAULTPATH, W_OK) == 0)
+ {
+ rtl_uString_newFromAscii(&pResult, PIPEDEFAULTPATH);
+ }
+ else if (access(PIPEALTERNATEPATH, W_OK) == 0)
+ {
+ rtl_uString_newFromAscii(&pResult, PIPEALTERNATEPATH);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: no valid pipe path found.\n");
+ exit(1);
+ }
+
+ rtl_uString_newFromAscii(&pTmp, "/OSL_PIPE_");
+ rtl_uString_newConcat(&pResult, pResult, pTmp);
+
+ 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);
+
+ /* cleanup */
+ rtl_uString_release(pMd5hash);
+ rtl_uString_release(pPath);
+ rtl_uString_release(pTmp);
+
+ if (pBasePath)
+ 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;
+
+ (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, rtl_string_getStr(pPipeStr), sizeof(addr.sun_path) - 1);
+ 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)
+ {
+ close(fd);
+ fd = -1;
+ }
+ return fd;
+}
+
+/* Escape: "," -> "\\,", "\0" -> "\\0", "\\" -> "\\\\" */
+static rtl_uString *escape_path(rtl_uString const *pToEscape)
+{
+ rtl_uString *pBuffer = NULL;
+ sal_Int32 nCapacity = 1000;
+ sal_Int32 i = 0;
+ sal_Int32 nEscapeLength = rtl_uString_getLength(pToEscape);
+
+ rtl_uString_new_WithLength(&pBuffer, nCapacity);
+
+ for (; i < nEscapeLength; ++i)
+ {
+ sal_Unicode c = pToEscape->buffer[i];
+ switch (c)
+ {
+ case '\0':
+ rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
+ rtl_uString_getLength(pBuffer),
+ RTL_CONSTASCII_STRINGPARAM("\\0"));
+ break;
+ case ',':
+ rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
+ rtl_uString_getLength(pBuffer),
+ RTL_CONSTASCII_STRINGPARAM("\\,"));
+ break;
+ case '\\':
+ 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 LO instance (using the 'fd' file descriptor) */
+static sal_Bool send_args(int fd, rtl_uString const *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);
+ sal_uInt32 nArg = 0;
+ sal_uInt32 nArgCount = rtl_getAppCommandArgCount();
+
+ 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"));
+ }
+
+ for (nArg = 0; nArg < nArgCount; ++nArg)
+ {
+ rtl_uString *pEscapedTmp = NULL;
+ rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
+ rtl_uString_getLength(pBuffer),
+ ",", 1);
+
+ rtl_getAppCommandArg(nArg, &pTmp);
+
+ 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);
+ }
+
+ if (!rtl_convertUStringToString(
+ &pOut, rtl_uString_getStr(pBuffer),
+ rtl_uString_getLength(pBuffer), RTL_TEXTENCODING_UTF8,
+ (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
+ {
+ fprintf(stderr, "ERROR: cannot convert arguments to UTF-8\n");
+ exit(1);
+ }
+
+ nLen = rtl_string_getLength(pOut) + 1;
+ ssize_t n = write(fd, rtl_string_getStr(pOut), nLen);
+ bResult = (n >= 0 && (size_t) n == nLen);
+
+ if ( bResult )
+ {
+ char resp[SAL_N_ELEMENTS("InternalIPC::ProcessingDone")];
+ n = read(fd, resp, SAL_N_ELEMENTS(resp));
+ bResult = n == SAL_N_ELEMENTS(resp)
+ && (memcmp(
+ resp, "InternalIPC::ProcessingDone",
+ SAL_N_ELEMENTS(resp))
+ == 0);
+ }
+
+ /* cleanup */
+ rtl_uString_release(pEscapedCwdPath);
+ rtl_uString_release(pBuffer);
+ rtl_uString_release(pTmp);
+ rtl_string_release(pOut);
+
+ return bResult;
+}
+
+
+#define BUFFER_LEN 255
+
+/* Read the percent to show in splash. */
+static ProgressStatus read_percent(ChildInfo const *info, int *pPercent)
+{
+ static char pBuffer[BUFFER_LEN + 1];
+ static char *pNext = pBuffer;
+ static ssize_t nRead = 0;
+
+ char *pBegin;
+ char *pIter;
+ char c;
+
+ /* from the last call */
+ int nNotProcessed = nRead - (pNext - pBuffer);
+ if (nNotProcessed >= BUFFER_LEN)
+ return ProgressContinue;
+
+ memmove(pBuffer, pNext, nNotProcessed);
+
+ /* read data */
+ nRead = read(child_info_get_status_fd(info),
+ pBuffer + nNotProcessed, BUFFER_LEN - nNotProcessed);
+
+ if (nRead < 0)
+ {
+ if (errno == EINTR)
+ return ProgressContinue;
+
+ return ProgressExit;
+ }
+
+ 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 (!strncasecmp(pBegin, "end", 3))
+ return ProgressExit;
+ else if (!strncasecmp(pBegin, "restart", 7))
+ return ProgressRestart;
+ else if (sscanf(pBegin, "%d%c", pPercent, &c) == 2 && c == '%')
+ return ProgressContinue;
+
+ /* unexpected - let's exit the splash to be safe */
+ return ProgressExit;
+}
+
+/* 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 - LibreOffice is unlikely to work well if at all\n");
+ exit(1);
+ }
+#endif
+}
+
+static void exec_pagein (Args *args)
+{
+ rtl_String * path = ustr_to_str(args->pAppPath);
+ pagein_execute(rtl_string_getStr(path), "pagein-common");
+
+ if (args->pPageinType)
+ pagein_execute(rtl_string_getStr(path), args->pPageinType);
+
+ rtl_string_release(path);
+}
+
+#if HAVE_FEATURE_JAVA
+
+static void extend_library_path(const char *new_element)
+{
+ rtl_uString *pEnvName=NULL, *pOrigEnvVar=NULL, *pNewEnvVar=NULL;
+ const char *pathname;
+#ifdef AIX
+ pathname = "LIBPATH";
+#else
+ pathname = "LD_LIBRARY_PATH";
+#endif
+
+ rtl_uString_newFromAscii(&pEnvName, pathname);
+ rtl_uString_newFromAscii(&pNewEnvVar, new_element);
+
+ osl_getEnvironment(pEnvName, &pOrigEnvVar);
+ if (pOrigEnvVar && pOrigEnvVar->length)
+ {
+ rtl_uString *pDelim = NULL;
+ rtl_uString_newFromAscii(&pDelim, ":");
+ rtl_uString_newConcat(&pNewEnvVar, pNewEnvVar, pDelim);
+ rtl_uString_newConcat(&pNewEnvVar, pNewEnvVar, pOrigEnvVar);
+ rtl_uString_release(pDelim);
+ }
+
+ osl_setEnvironment(pEnvName, pNewEnvVar);
+
+ if (pOrigEnvVar)
+ rtl_uString_release(pOrigEnvVar);
+
+ rtl_uString_release(pNewEnvVar);
+ rtl_uString_release(pEnvName);
+}
+
+static void exec_javaldx(Args *args)
+{
+ char newpath[4096];
+ sal_uInt32 nArgs;
+ rtl_uString *pApp;
+ rtl_uString **ppArgs;
+ rtl_uString *pTmp, *pTmp2;
+
+ oslProcess javaldx = NULL;
+ oslFileHandle fileOut = NULL;
+ oslProcessError err;
+
+ ppArgs = (rtl_uString **)calloc(args->nArgsEnv + 2, sizeof(rtl_uString*));
+
+ for (nArgs = 0; nArgs < args->nArgsEnv; ++nArgs)
+ ppArgs[nArgs] = args->ppArgs[nArgs];
+
+ /* Use absolute path to redirectrc */
+ pTmp = NULL;
+ rtl_uString_newFromAscii(&pTmp, "-env:INIFILENAME=vnd.sun.star.pathname:");
+ rtl_uString_newConcat(&pTmp, pTmp, args->pAppPath);
+ pTmp2 = NULL;
+ rtl_uString_newFromAscii(&pTmp2, "redirectrc");
+ rtl_uString_newConcat(&pTmp, pTmp, pTmp2);
+ ppArgs[nArgs] = pTmp;
+ rtl_uString_release (pTmp2);
+ nArgs++;
+
+ /* And also to javaldx */
+ pApp = NULL;
+ rtl_uString_newFromAscii(&pApp, "file://");
+ rtl_uString_newConcat(&pApp, pApp, args->pAppPath);
+ pTmp = NULL;
+ rtl_uString_newFromAscii(&pTmp, "javaldx");
+ rtl_uString_newConcat(&pApp, pApp, pTmp);
+ rtl_uString_release(pTmp);
+
+ err = osl_executeProcess_WithRedirectedIO(pApp, ppArgs, nArgs,
+ osl_Process_NORMAL,
+ NULL, // security
+ NULL, // work dir
+ NULL, 0,
+ &javaldx, // process handle
+ NULL,
+ &fileOut,
+ NULL);
+
+ rtl_uString_release(ppArgs[nArgs-1]);
+ rtl_uString_release(pApp);
+ free(ppArgs);
+
+ if(err != osl_Process_E_None)
+ {
+ fprintf (stderr, "Warning: failed to launch javaldx - java may not function correctly\n");
+
+ if (javaldx)
+ osl_freeProcessHandle(javaldx);
+ if (fileOut)
+ osl_closeFile(fileOut);
+ return;
+ }
+ else
+ {
+ char *chomp;
+ sal_uInt64 bytes_read;
+
+ /* Magically osl_readLine doesn't work with pipes with E_SPIPE - so be this lame instead: */
+ while (osl_readFile (fileOut, newpath, SAL_N_ELEMENTS (newpath), &bytes_read) == osl_File_E_INTR);
+
+ if (bytes_read <= 0)
+ {
+ fprintf (stderr, "Warning: failed to read path from javaldx\n");
+
+ if (javaldx)
+ osl_freeProcessHandle(javaldx);
+
+ if (fileOut)
+ osl_closeFile(fileOut);
+
+ return;
+ }
+
+ newpath[bytes_read] = '\0';
+
+ if ((chomp = strstr (newpath, "\n")))
+ *chomp = '\0';
+ }
+
+ if (newpath[0] != '\0') {
+ extend_library_path(newpath);
+ }
+
+ if (javaldx)
+ osl_freeProcessHandle(javaldx);
+
+ if (fileOut)
+ osl_closeFile(fileOut);
+}
+
+#endif
+
+// has to be a global :(
+static oslProcess * volatile g_pProcess = NULL;
+
+static void sigterm_handler(int ignored)
+{
+ (void) ignored;
+
+ if (g_pProcess) {
+ osl_terminateProcess(g_pProcess); // forward signal to soffice.bin
+ osl_joinProcess(g_pProcess);
+ }
+
+ _exit(255);
+}
+
+
+SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
+{
+ sal_Bool bSentArgs = sal_False;
+ const char* pUsePlugin;
+ rtl_uString *pPipePath = NULL;
+ Args *args;
+ int status = 0;
+ struct splash* splash = NULL;
+ struct sigaction sigpipe_action;
+ struct sigaction sigterm_action;
+
+ /* turn SIGPIPE into an error */
+ memset(&sigpipe_action, 0, sizeof(struct sigaction));
+ sigpipe_action.sa_handler = SIG_IGN;
+ sigemptyset(&sigpipe_action.sa_mask);
+ sigaction(SIGPIPE, &sigpipe_action, NULL);
+ memset(&sigterm_action, 0, sizeof(struct sigaction));
+ sigterm_action.sa_handler = &sigterm_handler;
+ sigemptyset(&sigterm_action.sa_mask);
+ sigaction(SIGTERM, &sigterm_action, NULL);
+
+ args = args_parse();
+ args->pAppPath = get_app_path(argv[0]);
+ if (!args->pAppPath)
+ {
+ fprintf(stderr, "ERROR: Can't read app link\n");
+ exit(1);
+ }
+
+#ifndef ENABLE_QUICKSTART_LIBPNG
+ /* we can't load and render it anyway */
+ args->bInhibitSplash = sal_True;
+#endif
+
+ pUsePlugin = getenv("SAL_USE_VCLPLUGIN");
+ if (pUsePlugin && !strcmp(pUsePlugin, "svp"))
+ args->bInhibitSplash = sal_True;
+
+ if (!args->bInhibitPipe && !getenv("LIBO_FLATPAK"))
+ {
+ int fd = 0;
+ pPipePath = get_pipe_path(args->pAppPath);
+
+ if ((fd=connect_pipe(pPipePath)) >= 0)
+ {
+ // Wait for answer
+ char resp[strlen("InternalIPC::SendArguments") + 1];
+ ssize_t n = read(fd, resp, SAL_N_ELEMENTS(resp));
+ if (n == (ssize_t) SAL_N_ELEMENTS(resp) &&
+ (memcmp(resp, "InternalIPC::SendArguments",
+ SAL_N_ELEMENTS(resp) - 1) == 0))
+ {
+ rtl_uString *pCwdPath = NULL;
+ osl_getProcessWorkingDir(&pCwdPath);
+
+ // Then send args
+ bSentArgs = send_args(fd, pCwdPath);
+ }
+
+ close(fd);
+ }
+ }
+
+ if (!bSentArgs)
+ {
+ /* we have to prepare for, and exec the binary */
+ int nPercent = 0;
+ ChildInfo *info;
+ sal_Bool bAllArgs = sal_True;
+ sal_Bool bShortWait, bRestart;
+
+ /* sanity check pieces */
+ system_checks();
+
+ /* load splash image and create window */
+ if (!args->bInhibitSplash)
+ splash = splash_create(args->pAppPath, argc, argv);
+
+ /* pagein */
+ if (!args->bInhibitPagein)
+ exec_pagein(args);
+
+ /* javaldx */
+#if HAVE_FEATURE_JAVA
+ if (!args->bInhibitJavaLdx)
+ exec_javaldx (args);
+#endif
+
+ do
+ {
+ bRestart = sal_False;
+
+ /* fast updates if we have somewhere to update it to */
+ bShortWait = splash ? sal_True : sal_False;
+
+ /* Periodically update the splash & the percent according
+ to what status_fd says, poll quickly only while starting */
+ info = child_spawn (args, bAllArgs, bShortWait);
+ g_pProcess = info->child;
+
+ while (!child_exited_wait(info, bShortWait))
+ {
+ ProgressStatus eResult;
+
+ splash_draw_progress(splash, nPercent);
+ eResult = read_percent(info, &nPercent);
+
+ if (eResult != ProgressContinue)
+ {
+ splash_destroy(splash);
+ splash = NULL;
+ bShortWait = sal_False;
+ }
+ }
+
+ status = child_get_exit_code(info);
+ g_pProcess = NULL; // reset
+
+ switch (status)
+ {
+ case EXITHELPER_CRASH_WITH_RESTART: // re-start with just -env: parameters
+ bRestart = sal_True;
+ bAllArgs = sal_False;
+ break;
+ case EXITHELPER_NORMAL_RESTART: // re-start with all arguments
+ bRestart = sal_True;
+ bAllArgs = sal_True;
+ break;
+ default:
+ break;
+ }
+
+ child_info_destroy(info);
+ } while (bRestart);
+ }
+
+ /* cleanup */
+ if (pPipePath)
+ rtl_uString_release(pPipePath);
+
+ args_free(args);
+
+ return status;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */