summaryrefslogtreecommitdiff
path: root/extensions/source/plugin/unx/npwrap.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/source/plugin/unx/npwrap.cxx')
-rw-r--r--extensions/source/plugin/unx/npwrap.cxx515
1 files changed, 515 insertions, 0 deletions
diff --git a/extensions/source/plugin/unx/npwrap.cxx b/extensions/source/plugin/unx/npwrap.cxx
new file mode 100644
index 000000000000..387de8cde24d
--- /dev/null
+++ b/extensions/source/plugin/unx/npwrap.cxx
@@ -0,0 +1,515 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_extensions.hxx"
+#include <errno.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <sys/poll.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <plugin/unx/plugcon.hxx>
+
+#include <osl/file.h>
+#include <osl/module.h>
+
+PluginConnector* pConnector = NULL;
+
+int nAppArguments = 0;
+char** pAppArguments = NULL;
+Display* pAppDisplay = NULL;
+Display* pXtAppDisplay = NULL;
+
+extern oslModule pPluginLib;
+extern NPError (*pNP_Shutdown)();
+
+void LoadAdditionalLibs(const char*);
+
+XtAppContext app_context;
+Widget topLevel = NULL, topBox = NULL;
+int wakeup_fd[2] = { 0, 0 };
+static bool bPluginAppQuit = false;
+
+static long GlobalConnectionLostHdl( void* /*pInst*/, void* /*pArg*/ )
+{
+ medDebug( 1, "pluginapp exiting due to connection lost\n" );
+
+ write( wakeup_fd[1], "xxxx", 4 );
+ return 0;
+}
+
+extern "C"
+{
+ static int plugin_x_error_handler( Display*, XErrorEvent* )
+ {
+ return 0;
+ }
+
+ #ifndef ENABLE_GTK
+ static void ThreadEventHandler( XtPointer /*client_data*/, int* /*source*/, XtInputId* id )
+ {
+ char buf[256];
+ // clear pipe
+ int len, nLast = -1;
+
+ while( (len = read( wakeup_fd[0], buf, sizeof( buf ) ) ) > 0 )
+ nLast = len-1;
+ if( ! bPluginAppQuit )
+ {
+ if( ( nLast == -1 || buf[nLast] != 'x' ) && pConnector )
+ pConnector->CallWorkHandler();
+ else
+ {
+ // it seems you can use XtRemoveInput only
+ // safely from within the callback
+ // why is that ?
+ medDebug( 1, "removing wakeup pipe\n" );
+ XtRemoveInput( *id );
+ XtAppSetExitFlag( app_context );
+ bPluginAppQuit = true;
+
+ delete pConnector;
+ pConnector = NULL;
+ }
+ }
+ }
+ #endif
+}
+
+
+IMPL_LINK( PluginConnector, NewMessageHdl, Mediator*, /*pMediator*/ )
+{
+ medDebug( 1, "new message handler\n" );
+ write( wakeup_fd[1], "cccc", 4 );
+ return 0;
+
+}
+
+Widget createSubWidget( char* /*pPluginText*/, Widget shell, XLIB_Window aParentWindow )
+{
+ Widget newWidget = XtVaCreateManagedWidget(
+#if defined USE_MOTIF
+ "drawingArea",
+ xmDrawingAreaWidgetClass,
+#else
+ "",
+# if defined DISABLE_XAW
+ compositeWidgetClass,
+# else
+ labelWidgetClass,
+# endif
+#endif
+ shell,
+ XtNwidth, 200,
+ XtNheight, 200,
+ (char *)NULL );
+ XtRealizeWidget( shell );
+ XtRealizeWidget( newWidget );
+
+ medDebug( 1, "Reparenting new widget %x to %x\n", XtWindow( newWidget ), aParentWindow );
+ XReparentWindow( pXtAppDisplay,
+ XtWindow( shell ),
+ aParentWindow,
+ 0, 0 );
+ XtMapWidget( shell );
+ XtMapWidget( newWidget );
+ XRaiseWindow( pXtAppDisplay, XtWindow( shell ) );
+ XSync( pXtAppDisplay, False );
+
+ return newWidget;
+}
+
+void* CreateNewShell( void** pShellReturn, XLIB_Window aParentWindow )
+{
+ XLIB_String n, c;
+ XtGetApplicationNameAndClass(pXtAppDisplay, &n, &c);
+
+ Widget newShell =
+ XtVaAppCreateShell( "pane", c,
+ topLevelShellWidgetClass,
+ pXtAppDisplay,
+ XtNwidth, 200,
+ XtNheight, 200,
+ XtNoverrideRedirect, True,
+ (char *)NULL );
+ *pShellReturn = newShell;
+
+ char pText[1024];
+ sprintf( pText, "starting plugin %s ...", pAppArguments[2] );
+
+ Widget newWidget = createSubWidget( pText, newShell, aParentWindow );
+
+ return newWidget;
+}
+
+static oslModule LoadModule( const char* pPath )
+{
+ ::rtl::OUString sSystemPath( ::rtl::OUString::createFromAscii( pPath ) );
+ ::rtl::OUString sFileURL;
+ osl_getFileURLFromSystemPath( sSystemPath.pData, &sFileURL.pData );
+
+ oslModule pLib = osl_loadModule( sFileURL.pData, SAL_LOADMODULE_LAZY );
+ if( ! pLib )
+ {
+ medDebug( 1, "could not open %s: %s\n", pPath, dlerror() );
+ }
+ return pLib;
+}
+
+// Unix specific implementation
+static void CheckPlugin( const char* pPath )
+{
+ oslModule pLib = LoadModule( pPath );
+
+ char*(*pNP_GetMIMEDescription)() = (char*(*)())
+ osl_getAsciiFunctionSymbol( pLib, "NP_GetMIMEDescription" );
+ if( pNP_GetMIMEDescription )
+ printf( "%s\n", pNP_GetMIMEDescription() );
+ else
+ medDebug( 1, "could not get symbol NP_GetMIMEDescription %s\n", dlerror() );
+
+ osl_unloadModule( pLib );
+}
+
+#if OSL_DEBUG_LEVEL > 1 && defined LINUX
+#include <execinfo.h>
+#endif
+
+extern "C" {
+
+static void signal_handler( int nSig )
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "caught signal %d, exiting\n", nSig );
+#ifdef LINUX
+ void* pStack[64];
+ int nStackLevels = backtrace( pStack, sizeof(pStack)/sizeof(pStack[0]) );
+ backtrace_symbols_fd( pStack, nStackLevels, STDERR_FILENO );
+#endif
+#endif
+ if( pConnector )
+ {
+ // ensure that a read on the other side will wakeup
+ delete pConnector;
+ pConnector = NULL;
+ }
+
+ _exit(nSig);
+}
+
+#ifdef ENABLE_GTK
+
+static gboolean noClosure( gpointer )
+{
+ return TRUE;
+}
+
+// Xt events
+static gboolean prepareXtEvent( GSource*, gint* )
+{
+ int nMask = XtAppPending( app_context );
+ return (nMask & XtIMAll) != 0;
+}
+
+static gboolean checkXtEvent( GSource* )
+{
+ int nMask = XtAppPending( app_context );
+ return (nMask & XtIMAll) != 0;
+}
+
+static gboolean dispatchXtEvent( GSource*, GSourceFunc, gpointer )
+{
+ XtAppProcessEvent( app_context, XtIMAll );
+ return TRUE;
+}
+
+static GSourceFuncs aXtEventFuncs =
+{
+ prepareXtEvent,
+ checkXtEvent,
+ dispatchXtEvent,
+ NULL,
+ noClosure,
+ NULL
+};
+
+static gboolean pollXtTimerCallback(gpointer)
+{
+ for(int i = 0; i < 5; i++)
+ {
+ if( (XtAppPending(app_context) & (XtIMAll & ~XtIMXEvent)) == 0 )
+ break;
+ XtAppProcessEvent(app_context, XtIMAll & ~XtIMXEvent);
+ }
+ return TRUE;
+}
+
+static gboolean prepareWakeupEvent( GSource*, gint* )
+{
+ struct pollfd aPoll = { wakeup_fd[0], POLLIN, 0 };
+ poll( &aPoll, 1, 0 );
+ return (aPoll.revents & POLLIN ) != 0;
+}
+
+static gboolean checkWakeupEvent( GSource* pSource )
+{
+ gint nDum = 0;
+ return prepareWakeupEvent( pSource, &nDum );
+}
+
+static gboolean dispatchWakeupEvent( GSource*, GSourceFunc, gpointer )
+{
+ char buf[256];
+ // clear pipe
+ int len, nLast = -1;
+
+ while( (len = read( wakeup_fd[0], buf, sizeof( buf ) ) ) > 0 )
+ nLast = len-1;
+ if( ( nLast == -1 || buf[nLast] != 'x' ) && pConnector )
+ pConnector->CallWorkHandler();
+ else
+ {
+ XtAppSetExitFlag( app_context );
+ bPluginAppQuit = true;
+
+ delete pConnector;
+ pConnector = NULL;
+ }
+
+ return TRUE;
+}
+
+static GSourceFuncs aWakeupEventFuncs = {
+ prepareWakeupEvent,
+ checkWakeupEvent,
+ dispatchWakeupEvent,
+ NULL,
+ noClosure,
+ NULL
+};
+
+#endif // GTK
+
+}
+
+int main( int argc, char **argv)
+{
+ struct sigaction aSigAction;
+ aSigAction.sa_handler = signal_handler;
+ sigemptyset( &aSigAction.sa_mask );
+ aSigAction.sa_flags = SA_NOCLDSTOP;
+ sigaction( SIGSEGV, &aSigAction, NULL );
+ sigaction( SIGBUS, &aSigAction, NULL );
+ sigaction( SIGABRT, &aSigAction, NULL );
+ sigaction( SIGTERM, &aSigAction, NULL );
+ sigaction( SIGILL, &aSigAction, NULL );
+
+ int nArg = (argc < 3) ? 1 : 2;
+ char* pBaseName = argv[nArg] + strlen(argv[nArg]);
+ while( pBaseName > argv[nArg] && pBaseName[-1] != '/' )
+ pBaseName--;
+ LoadAdditionalLibs( pBaseName );
+
+ if( argc == 2 )
+ {
+ CheckPlugin(argv[1]);
+ exit(0);
+ }
+ nAppArguments = argc;
+ pAppArguments = argv;
+
+ XSetErrorHandler( plugin_x_error_handler );
+
+ if( pipe( wakeup_fd ) )
+ {
+ medDebug( 1, "could not pipe()\n" );
+ return 1;
+ }
+ // initialize 'wakeup' pipe.
+ int flags;
+
+ // set close-on-exec descriptor flag.
+ if ((flags = fcntl (wakeup_fd[0], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (wakeup_fd[0], F_SETFD, flags);
+ }
+ if ((flags = fcntl (wakeup_fd[1], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (wakeup_fd[1], F_SETFD, flags);
+ }
+
+ // set non-blocking I/O flag.
+ if ((flags = fcntl (wakeup_fd[0], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (wakeup_fd[0], F_SETFL, flags);
+ }
+ if ((flags = fcntl (wakeup_fd[1], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (wakeup_fd[1], F_SETFL, flags);
+ }
+
+ pPluginLib = LoadModule( argv[2] );
+ if( ! pPluginLib )
+ {
+ exit(255);
+ }
+ int nSocket = atol( argv[1] );
+
+ #ifdef ENABLE_GTK
+ g_thread_init(NULL);
+ gtk_init(&argc, &argv);
+ #endif
+
+ pConnector = new PluginConnector( nSocket );
+ pConnector->SetConnectionLostHdl( Link( NULL, GlobalConnectionLostHdl ) );
+
+ XtSetLanguageProc( NULL, NULL, NULL );
+
+ XtToolkitInitialize();
+ app_context = XtCreateApplicationContext();
+ pXtAppDisplay = XtOpenDisplay( app_context, NULL, "SOPlugin", "SOPlugin", NULL, 0, &argc, argv );
+
+
+ #ifdef ENABLE_GTK
+ // integrate Xt events into GTK event loop
+ GPollFD aXtPollDesc, aWakeupPollDesc;
+
+ GSource* pXTSource = g_source_new( &aXtEventFuncs, sizeof(GSource) );
+ if( !pXTSource )
+ {
+ medDebug( 1, "could not get Xt GSource" );
+ return 1;
+ }
+
+ g_source_set_priority( pXTSource, GDK_PRIORITY_EVENTS );
+ g_source_set_can_recurse( pXTSource, TRUE );
+ g_source_attach( pXTSource, NULL );
+ aXtPollDesc.fd = ConnectionNumber( pXtAppDisplay );
+ aXtPollDesc.events = G_IO_IN;
+ aXtPollDesc.revents = 0;
+ g_source_add_poll( pXTSource, &aXtPollDesc );
+
+ gint xt_polling_timer_id = g_timeout_add( 25, pollXtTimerCallback, NULL);
+ // Initialize wakeup events listener
+ GSource *pWakeupSource = g_source_new( &aWakeupEventFuncs, sizeof(GSource) );
+ if ( pWakeupSource == NULL )
+ {
+ medDebug( 1, "could not get wakeup source" );
+ return 1;
+ }
+ g_source_set_priority( pWakeupSource, GDK_PRIORITY_EVENTS);
+ g_source_attach( pWakeupSource, NULL );
+ aWakeupPollDesc.fd = wakeup_fd[0];
+ aWakeupPollDesc.events = G_IO_IN;
+ aWakeupPollDesc.revents = 0;
+ g_source_add_poll( pWakeupSource, &aWakeupPollDesc );
+
+ pAppDisplay = gdk_x11_display_get_xdisplay( gdk_display_get_default() );
+ #else
+ pAppDisplay = pXtAppDisplay;
+ XtAppAddInput( app_context,
+ wakeup_fd[0],
+ (XtPointer)XtInputReadMask,
+ ThreadEventHandler, NULL );
+ #endif
+
+ // send that we are ready to go
+ MediatorMessage* pMessage =
+ pConnector->Transact( "init req", 8,
+ NULL );
+ delete pMessage;
+
+#if OSL_DEBUG_LEVEL > 3
+ int nPID = getpid();
+ int nChild = fork();
+ if( nChild == 0 )
+ {
+ char pidbuf[16];
+ char* pArgs[] = { "xterm", "-sl", "2000", "-sb", "-e", "gdb", "pluginapp.bin", pidbuf, NULL };
+ sprintf( pidbuf, "%d", nPID );
+ execvp( pArgs[0], pArgs );
+ _exit(255);
+ }
+ else
+ sleep( 10 );
+#endif
+
+ /*
+ * Loop for events.
+ */
+ // for some reason XtAppSetExitFlag won't quit the application
+ // in ThreadEventHandler most of times; Xt will hang in select
+ // (hat is in XtAppNextEvent). Have our own mainloop instead
+ // of XtAppMainLoop
+ do
+ {
+ #ifdef ENABLE_GTK
+ g_main_context_iteration( NULL, TRUE );
+ #else
+ XtAppProcessEvent( app_context, XtIMAll );
+ #endif
+ } while( ! XtAppGetExitFlag( app_context ) && ! bPluginAppQuit );
+
+ medDebug( 1, "left plugin app main loop\n" );
+
+ #ifdef ENABLE_GTK
+ g_source_remove(xt_polling_timer_id);
+ #endif
+
+ pNP_Shutdown();
+ medDebug( 1, "NP_Shutdown done\n" );
+ osl_unloadModule( pPluginLib );
+ medDebug( 1, "plugin close\n" );
+
+ close( wakeup_fd[0] );
+ close( wakeup_fd[1] );
+
+ return 0;
+}
+
+#ifdef GCC
+extern "C" {
+ void __pure_virtual()
+ {}
+
+ void* __builtin_new( int nBytes )
+ { return malloc(nBytes); }
+ void* __builtin_vec_new( int nBytes )
+ { return malloc(nBytes); }
+ void __builtin_delete( char* pMem )
+ { free(pMem); }
+ void __builtin_vec_delete( char* pMem )
+ { free(pMem); }
+}
+#endif
+