1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_extensions.hxx"
37 #include <plugin/unx/plugcon.hxx>
40 #include <osl/module.h>
42 PluginConnector
* pConnector
= NULL
;
44 int nAppArguments
= 0;
45 char** pAppArguments
= NULL
;
46 Display
* pAppDisplay
= NULL
;
47 Display
* pXtAppDisplay
= NULL
;
49 extern oslModule pPluginLib
;
50 extern NPError (*pNP_Shutdown
)();
52 void LoadAdditionalLibs(const char*);
54 XtAppContext app_context
;
55 Widget topLevel
= NULL
, topBox
= NULL
;
56 int wakeup_fd
[2] = { 0, 0 };
57 static bool bPluginAppQuit
= false;
59 static long GlobalConnectionLostHdl( void* /*pInst*/, void* /*pArg*/ )
61 medDebug( 1, "pluginapp exiting due to connection lost\n" );
63 write( wakeup_fd
[1], "xxxx", 4 );
69 static int plugin_x_error_handler( Display
*, XErrorEvent
* )
75 static void ThreadEventHandler( XtPointer
/*client_data*/, int* /*source*/, XtInputId
* id
)
81 while( (len
= read( wakeup_fd
[0], buf
, sizeof( buf
) ) ) > 0 )
83 if( ! bPluginAppQuit
)
85 if( ( nLast
== -1 || buf
[nLast
] != 'x' ) && pConnector
)
86 pConnector
->CallWorkHandler();
89 // it seems you can use XtRemoveInput only
90 // safely from within the callback
92 medDebug( 1, "removing wakeup pipe\n" );
94 XtAppSetExitFlag( app_context
);
95 bPluginAppQuit
= true;
106 IMPL_LINK( PluginConnector
, NewMessageHdl
, Mediator
*, /*pMediator*/ )
108 medDebug( 1, "new message handler\n" );
109 write( wakeup_fd
[1], "cccc", 4 );
114 Widget
createSubWidget( char* /*pPluginText*/, Widget shell
, XLIB_Window aParentWindow
)
116 Widget newWidget
= XtVaCreateManagedWidget(
117 #if defined USE_MOTIF
119 xmDrawingAreaWidgetClass
,
122 # if defined DISABLE_XAW
123 compositeWidgetClass
,
132 XtRealizeWidget( shell
);
133 XtRealizeWidget( newWidget
);
135 medDebug( 1, "Reparenting new widget %x to %x\n", XtWindow( newWidget
), aParentWindow
);
136 XReparentWindow( pXtAppDisplay
,
140 XtMapWidget( shell
);
141 XtMapWidget( newWidget
);
142 XRaiseWindow( pXtAppDisplay
, XtWindow( shell
) );
143 XSync( pXtAppDisplay
, False
);
148 void* CreateNewShell( void** pShellReturn
, XLIB_Window aParentWindow
)
151 XtGetApplicationNameAndClass(pXtAppDisplay
, &n
, &c
);
154 XtVaAppCreateShell( "pane", c
,
155 topLevelShellWidgetClass
,
159 XtNoverrideRedirect
, True
,
161 *pShellReturn
= newShell
;
164 sprintf( pText
, "starting plugin %s ...", pAppArguments
[2] );
166 Widget newWidget
= createSubWidget( pText
, newShell
, aParentWindow
);
171 static oslModule
LoadModule( const char* pPath
)
173 ::rtl::OUString
sSystemPath( ::rtl::OUString::createFromAscii( pPath
) );
174 ::rtl::OUString sFileURL
;
175 osl_getFileURLFromSystemPath( sSystemPath
.pData
, &sFileURL
.pData
);
177 oslModule pLib
= osl_loadModule( sFileURL
.pData
, SAL_LOADMODULE_LAZY
);
180 medDebug( 1, "could not open %s: %s\n", pPath
, dlerror() );
185 // Unix specific implementation
186 static void CheckPlugin( const char* pPath
)
188 oslModule pLib
= LoadModule( pPath
);
190 char*(*pNP_GetMIMEDescription
)() = (char*(*)())
191 osl_getAsciiFunctionSymbol( pLib
, "NP_GetMIMEDescription" );
192 if( pNP_GetMIMEDescription
)
193 printf( "%s\n", pNP_GetMIMEDescription() );
195 medDebug( 1, "could not get symbol NP_GetMIMEDescription %s\n", dlerror() );
197 osl_unloadModule( pLib
);
200 #if OSL_DEBUG_LEVEL > 1 && defined LINUX
201 #include <execinfo.h>
206 static void signal_handler( int nSig
)
208 #if OSL_DEBUG_LEVEL > 1
209 fprintf( stderr
, "caught signal %d, exiting\n", nSig
);
212 int nStackLevels
= backtrace( pStack
, sizeof(pStack
)/sizeof(pStack
[0]) );
213 backtrace_symbols_fd( pStack
, nStackLevels
, STDERR_FILENO
);
218 // ensure that a read on the other side will wakeup
228 static gboolean
noClosure( gpointer
)
234 static gboolean
prepareXtEvent( GSource
*, gint
* )
236 int nMask
= XtAppPending( app_context
);
237 return (nMask
& XtIMAll
) != 0;
240 static gboolean
checkXtEvent( GSource
* )
242 int nMask
= XtAppPending( app_context
);
243 return (nMask
& XtIMAll
) != 0;
246 static gboolean
dispatchXtEvent( GSource
*, GSourceFunc
, gpointer
)
248 XtAppProcessEvent( app_context
, XtIMAll
);
252 static GSourceFuncs aXtEventFuncs
=
262 static gboolean
pollXtTimerCallback(gpointer
)
264 for(int i
= 0; i
< 5; i
++)
266 if( (XtAppPending(app_context
) & (XtIMAll
& ~XtIMXEvent
)) == 0 )
268 XtAppProcessEvent(app_context
, XtIMAll
& ~XtIMXEvent
);
273 static gboolean
prepareWakeupEvent( GSource
*, gint
* )
275 struct pollfd aPoll
= { wakeup_fd
[0], POLLIN
, 0 };
276 poll( &aPoll
, 1, 0 );
277 return (aPoll
.revents
& POLLIN
) != 0;
280 static gboolean
checkWakeupEvent( GSource
* pSource
)
283 return prepareWakeupEvent( pSource
, &nDum
);
286 static gboolean
dispatchWakeupEvent( GSource
*, GSourceFunc
, gpointer
)
292 while( (len
= read( wakeup_fd
[0], buf
, sizeof( buf
) ) ) > 0 )
294 if( ( nLast
== -1 || buf
[nLast
] != 'x' ) && pConnector
)
295 pConnector
->CallWorkHandler();
298 XtAppSetExitFlag( app_context
);
299 bPluginAppQuit
= true;
308 static GSourceFuncs aWakeupEventFuncs
= {
321 int main( int argc
, char **argv
)
323 struct sigaction aSigAction
;
324 aSigAction
.sa_handler
= signal_handler
;
325 sigemptyset( &aSigAction
.sa_mask
);
326 aSigAction
.sa_flags
= SA_NOCLDSTOP
;
327 sigaction( SIGSEGV
, &aSigAction
, NULL
);
328 sigaction( SIGBUS
, &aSigAction
, NULL
);
329 sigaction( SIGABRT
, &aSigAction
, NULL
);
330 sigaction( SIGTERM
, &aSigAction
, NULL
);
331 sigaction( SIGILL
, &aSigAction
, NULL
);
333 int nArg
= (argc
< 3) ? 1 : 2;
334 char* pBaseName
= argv
[nArg
] + strlen(argv
[nArg
]);
335 while( pBaseName
> argv
[nArg
] && pBaseName
[-1] != '/' )
337 LoadAdditionalLibs( pBaseName
);
341 CheckPlugin(argv
[1]);
344 nAppArguments
= argc
;
345 pAppArguments
= argv
;
347 XSetErrorHandler( plugin_x_error_handler
);
349 if( pipe( wakeup_fd
) )
351 medDebug( 1, "could not pipe()\n" );
354 // initialize 'wakeup' pipe.
357 // set close-on-exec descriptor flag.
358 if ((flags
= fcntl (wakeup_fd
[0], F_GETFD
)) != -1)
361 fcntl (wakeup_fd
[0], F_SETFD
, flags
);
363 if ((flags
= fcntl (wakeup_fd
[1], F_GETFD
)) != -1)
366 fcntl (wakeup_fd
[1], F_SETFD
, flags
);
369 // set non-blocking I/O flag.
370 if ((flags
= fcntl (wakeup_fd
[0], F_GETFL
)) != -1)
373 fcntl (wakeup_fd
[0], F_SETFL
, flags
);
375 if ((flags
= fcntl (wakeup_fd
[1], F_GETFL
)) != -1)
378 fcntl (wakeup_fd
[1], F_SETFL
, flags
);
381 pPluginLib
= LoadModule( argv
[2] );
386 int nSocket
= atol( argv
[1] );
390 gtk_init(&argc
, &argv
);
393 pConnector
= new PluginConnector( nSocket
);
394 pConnector
->SetConnectionLostHdl( Link( NULL
, GlobalConnectionLostHdl
) );
396 XtSetLanguageProc( NULL
, NULL
, NULL
);
398 XtToolkitInitialize();
399 app_context
= XtCreateApplicationContext();
400 pXtAppDisplay
= XtOpenDisplay( app_context
, NULL
, "SOPlugin", "SOPlugin", NULL
, 0, &argc
, argv
);
404 // integrate Xt events into GTK event loop
405 GPollFD aXtPollDesc
, aWakeupPollDesc
;
407 GSource
* pXTSource
= g_source_new( &aXtEventFuncs
, sizeof(GSource
) );
410 medDebug( 1, "could not get Xt GSource" );
414 g_source_set_priority( pXTSource
, GDK_PRIORITY_EVENTS
);
415 g_source_set_can_recurse( pXTSource
, TRUE
);
416 g_source_attach( pXTSource
, NULL
);
417 aXtPollDesc
.fd
= ConnectionNumber( pXtAppDisplay
);
418 aXtPollDesc
.events
= G_IO_IN
;
419 aXtPollDesc
.revents
= 0;
420 g_source_add_poll( pXTSource
, &aXtPollDesc
);
422 gint xt_polling_timer_id
= g_timeout_add( 25, pollXtTimerCallback
, NULL
);
423 // Initialize wakeup events listener
424 GSource
*pWakeupSource
= g_source_new( &aWakeupEventFuncs
, sizeof(GSource
) );
425 if ( pWakeupSource
== NULL
)
427 medDebug( 1, "could not get wakeup source" );
430 g_source_set_priority( pWakeupSource
, GDK_PRIORITY_EVENTS
);
431 g_source_attach( pWakeupSource
, NULL
);
432 aWakeupPollDesc
.fd
= wakeup_fd
[0];
433 aWakeupPollDesc
.events
= G_IO_IN
;
434 aWakeupPollDesc
.revents
= 0;
435 g_source_add_poll( pWakeupSource
, &aWakeupPollDesc
);
437 pAppDisplay
= gdk_x11_display_get_xdisplay( gdk_display_get_default() );
439 pAppDisplay
= pXtAppDisplay
;
440 XtAppAddInput( app_context
,
442 (XtPointer
)XtInputReadMask
,
443 ThreadEventHandler
, NULL
);
446 // send that we are ready to go
447 MediatorMessage
* pMessage
=
448 pConnector
->Transact( "init req", 8,
452 #if OSL_DEBUG_LEVEL > 3
458 char* pArgs
[] = { "xterm", "-sl", "2000", "-sb", "-e", "gdb", "pluginapp.bin", pidbuf
, NULL
};
459 sprintf( pidbuf
, "%d", nPID
);
460 execvp( pArgs
[0], pArgs
);
470 // for some reason XtAppSetExitFlag won't quit the application
471 // in ThreadEventHandler most of times; Xt will hang in select
472 // (hat is in XtAppNextEvent). Have our own mainloop instead
477 g_main_context_iteration( NULL
, TRUE
);
479 XtAppProcessEvent( app_context
, XtIMAll
);
481 } while( ! XtAppGetExitFlag( app_context
) && ! bPluginAppQuit
);
483 medDebug( 1, "left plugin app main loop\n" );
486 g_source_remove(xt_polling_timer_id
);
490 medDebug( 1, "NP_Shutdown done\n" );
491 osl_unloadModule( pPluginLib
);
492 medDebug( 1, "plugin close\n" );
494 close( wakeup_fd
[0] );
495 close( wakeup_fd
[1] );
502 void __pure_virtual()
505 void* __builtin_new( int nBytes
)
506 { return malloc(nBytes
); }
507 void* __builtin_vec_new( int nBytes
)
508 { return malloc(nBytes
); }
509 void __builtin_delete( char* pMem
)
511 void __builtin_vec_delete( char* pMem
)