1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #define _LINUX_SOURCE_COMPAT
31 #include <sys/timer.h>
32 #undef _LINUX_SOURCE_COMPAT
41 #include <plugin/unx/plugcon.hxx>
44 #include <osl/module.h>
45 #include <sal/log.hxx>
47 #include <config_vclplug.h>
51 PluginConnector
* pConnector
= NULL
;
53 int nAppArguments
= 0;
54 char** pAppArguments
= NULL
;
55 Display
* pAppDisplay
= NULL
;
56 Display
* pXtAppDisplay
= NULL
;
58 extern oslModule pPluginLib
;
59 extern NPError (*pNP_Shutdown
)();
61 XtAppContext app_context
;
62 Widget topLevel
= NULL
, topBox
= NULL
;
63 int wakeup_fd
[2] = { 0, 0 };
64 static bool bPluginAppQuit
= false;
66 static long GlobalConnectionLostHdl( void* /*pInst*/, void* /*pArg*/ )
68 SAL_WARN("extensions.plugin", "pluginapp exiting due to connection lost");
70 bool bSuccess
= (4 == write(wakeup_fd
[1], "xxxx", 4 ));
71 SAL_WARN_IF(!bSuccess
, "extensions.plugin", "short write");
77 static int plugin_x_error_handler( Display
*, XErrorEvent
* )
83 static void ThreadEventHandler( XtPointer
/*client_data*/, int* /*source*/, XtInputId
* id
)
89 while( (len
= read( wakeup_fd
[0], buf
, sizeof( buf
) ) ) > 0 )
91 if( ! bPluginAppQuit
)
93 if( ( nLast
== -1 || buf
[nLast
] != 'x' ) && pConnector
)
94 pConnector
->CallWorkHandler();
97 // it seems you can use XtRemoveInput only
98 // safely from within the callback
100 SAL_INFO("extensions.plugin", "removing wakeup pipe");
101 XtRemoveInput( *id
);
102 XtAppSetExitFlag( app_context
);
103 bPluginAppQuit
= true;
114 IMPL_LINK( PluginConnector
, NewMessageHdl
, Mediator
*, /*pMediator*/ )
116 (void) this; // loplugin:staticmethods
117 SAL_INFO("extensions.plugin", "new message handler");
118 bool bSuccess
= (4 == write(wakeup_fd
[1], "cccc", 4));
119 SAL_WARN_IF(!bSuccess
, "extensions.plugin", "short write");
124 Widget
createSubWidget( char* /*pPluginText*/, Widget shell
, Window aParentWindow
)
126 Widget newWidget
= XtVaCreateManagedWidget(
127 #if defined USE_MOTIF
129 xmDrawingAreaWidgetClass
,
132 compositeWidgetClass
,
138 XtRealizeWidget( shell
);
139 XtRealizeWidget( newWidget
);
143 "reparenting new widget " << XtWindow( newWidget
) << " to "
145 XReparentWindow( pXtAppDisplay
,
149 XtMapWidget( shell
);
150 XtMapWidget( newWidget
);
151 XRaiseWindow( pXtAppDisplay
, XtWindow( shell
) );
152 XSync( pXtAppDisplay
, False
);
157 void* CreateNewShell( void** pShellReturn
, Window aParentWindow
)
160 XtGetApplicationNameAndClass(pXtAppDisplay
, &n
, &c
);
163 XtVaAppCreateShell( "pane", c
,
164 topLevelShellWidgetClass
,
168 XtNoverrideRedirect
, True
,
170 *pShellReturn
= newShell
;
173 sprintf( pText
, "starting plugin %s ...", pAppArguments
[2] );
175 Widget newWidget
= createSubWidget( pText
, newShell
, aParentWindow
);
180 static oslModule
LoadModule( const char* pPath
)
182 OUString
sSystemPath( OUString::createFromAscii( pPath
) );
184 osl_getFileURLFromSystemPath( sSystemPath
.pData
, &sFileURL
.pData
);
186 oslModule pLib
= osl_loadModule( sFileURL
.pData
, SAL_LOADMODULE_LAZY
);
187 SAL_INFO_IF(!pLib
, "extensions.plugin", "could not open " << pPath
);
191 // Unix specific implementation
192 static void CheckPlugin( const char* pPath
)
194 oslModule pLib
= LoadModule( pPath
);
197 char*(*pNP_GetMIMEDescription
)() = reinterpret_cast<char*(*)()>(
198 osl_getAsciiFunctionSymbol( pLib
, "NP_GetMIMEDescription" ));
199 if( pNP_GetMIMEDescription
)
200 printf( "%s\n", pNP_GetMIMEDescription() );
204 "could not get symbol NP_GetMIMEDescription " << dlerror());
205 osl_unloadModule( pLib
);
209 #if OSL_DEBUG_LEVEL > 1 && defined LINUX
210 #include <execinfo.h>
215 static void signal_handler( int nSig
)
217 #if OSL_DEBUG_LEVEL > 1
218 fprintf( stderr
, "caught signal %d, exiting\n", nSig
);
221 int nStackLevels
= backtrace( pStack
, SAL_N_ELEMENTS(pStack
) );
222 backtrace_symbols_fd( pStack
, nStackLevels
, STDERR_FILENO
);
227 // ensure that a read on the other side will wakeup
237 static gboolean
noClosure( gpointer
)
243 static gboolean
prepareXtEvent( GSource
*, gint
* )
245 int nMask
= XtAppPending( app_context
);
246 return (nMask
& XtIMAll
) != 0;
249 static gboolean
checkXtEvent( GSource
* )
251 int nMask
= XtAppPending( app_context
);
252 return (nMask
& XtIMAll
) != 0;
255 static gboolean
dispatchXtEvent( GSource
*, GSourceFunc
, gpointer
)
257 XtAppProcessEvent( app_context
, XtIMAll
);
261 static GSourceFuncs aXtEventFuncs
=
271 static gboolean
pollXtTimerCallback(gpointer
)
273 for(int i
= 0; i
< 5; i
++)
275 if( (XtAppPending(app_context
) & (XtIMAll
& ~XtIMXEvent
)) == 0 )
277 XtAppProcessEvent(app_context
, XtIMAll
& ~XtIMXEvent
);
282 static gboolean
prepareWakeupEvent( GSource
*, gint
* )
284 struct pollfd aPoll
= { wakeup_fd
[0], POLLIN
, 0 };
285 (void)poll(&aPoll
, 1, 0);
286 return (aPoll
.revents
& POLLIN
) != 0;
289 static gboolean
checkWakeupEvent( GSource
* pSource
)
292 return prepareWakeupEvent( pSource
, &nDum
);
295 static gboolean
dispatchWakeupEvent( GSource
*, GSourceFunc
, gpointer
)
301 while( (len
= read( wakeup_fd
[0], buf
, sizeof( buf
) ) ) > 0 )
303 if( ( nLast
== -1 || buf
[nLast
] != 'x' ) && pConnector
)
304 pConnector
->CallWorkHandler();
307 XtAppSetExitFlag( app_context
);
308 bPluginAppQuit
= true;
317 static GSourceFuncs aWakeupEventFuncs
= {
330 int main( int argc
, char **argv
)
332 struct sigaction aSigAction
;
333 aSigAction
.sa_handler
= signal_handler
;
334 sigemptyset( &aSigAction
.sa_mask
);
335 aSigAction
.sa_flags
= SA_NOCLDSTOP
;
336 sigaction( SIGSEGV
, &aSigAction
, NULL
);
337 sigaction( SIGBUS
, &aSigAction
, NULL
);
338 sigaction( SIGABRT
, &aSigAction
, NULL
);
339 sigaction( SIGTERM
, &aSigAction
, NULL
);
340 sigaction( SIGILL
, &aSigAction
, NULL
);
342 int nArg
= (argc
< 3) ? 1 : 2;
343 char* pBaseName
= argv
[nArg
] + strlen(argv
[nArg
]);
344 while( pBaseName
> argv
[nArg
] && pBaseName
[-1] != '/' )
346 LoadAdditionalLibs( pBaseName
);
350 CheckPlugin(argv
[1]);
353 nAppArguments
= argc
;
354 pAppArguments
= argv
;
356 XSetErrorHandler( plugin_x_error_handler
);
358 if( pipe( wakeup_fd
) )
360 SAL_WARN("extensions.plugin", "could not pipe()");
363 // initialize 'wakeup' pipe.
366 // set close-on-exec descriptor flag.
367 if ((flags
= fcntl (wakeup_fd
[0], F_GETFD
)) != -1)
370 (void)fcntl(wakeup_fd
[0], F_SETFD
, flags
);
372 if ((flags
= fcntl (wakeup_fd
[1], F_GETFD
)) != -1)
375 (void)fcntl(wakeup_fd
[1], F_SETFD
, flags
);
378 // set non-blocking I/O flag.
379 if ((flags
= fcntl (wakeup_fd
[0], F_GETFL
)) != -1)
382 (void)fcntl(wakeup_fd
[0], F_SETFL
, flags
);
384 if ((flags
= fcntl (wakeup_fd
[1], F_GETFL
)) != -1)
387 (void)fcntl(wakeup_fd
[1], F_SETFL
, flags
);
390 pPluginLib
= LoadModule( argv
[2] );
395 int nSocket
= atol( argv
[1] );
399 gtk_init(&argc
, &argv
);
402 pConnector
= new PluginConnector( nSocket
);
403 pConnector
->SetConnectionLostHdl( Link
<>( NULL
, GlobalConnectionLostHdl
) );
405 XtSetLanguageProc( NULL
, NULL
, NULL
);
407 XtToolkitInitialize();
408 app_context
= XtCreateApplicationContext();
409 pXtAppDisplay
= XtOpenDisplay( app_context
, NULL
, "SOPlugin", "SOPlugin", NULL
, 0, &argc
, argv
);
413 // integrate Xt events into GTK event loop
414 GPollFD aXtPollDesc
, aWakeupPollDesc
;
416 GSource
* pXTSource
= g_source_new( &aXtEventFuncs
, sizeof(GSource
) );
419 SAL_WARN("extensions.plugin", "could not get Xt GSource");
423 g_source_set_priority( pXTSource
, GDK_PRIORITY_EVENTS
);
424 g_source_set_can_recurse( pXTSource
, sal_True
);
425 g_source_attach( pXTSource
, NULL
);
426 aXtPollDesc
.fd
= ConnectionNumber( pXtAppDisplay
);
427 aXtPollDesc
.events
= G_IO_IN
;
428 aXtPollDesc
.revents
= 0;
429 g_source_add_poll( pXTSource
, &aXtPollDesc
);
431 gint xt_polling_timer_id
= g_timeout_add( 25, pollXtTimerCallback
, NULL
);
432 // Initialize wakeup events listener
433 GSource
*pWakeupSource
= g_source_new( &aWakeupEventFuncs
, sizeof(GSource
) );
434 if ( pWakeupSource
== NULL
)
436 SAL_WARN("extensions.plugin", "could not get wakeup source");
439 g_source_set_priority( pWakeupSource
, GDK_PRIORITY_EVENTS
);
440 g_source_attach( pWakeupSource
, NULL
);
441 aWakeupPollDesc
.fd
= wakeup_fd
[0];
442 aWakeupPollDesc
.events
= G_IO_IN
;
443 aWakeupPollDesc
.revents
= 0;
444 g_source_add_poll( pWakeupSource
, &aWakeupPollDesc
);
446 pAppDisplay
= gdk_x11_display_get_xdisplay( gdk_display_get_default() );
448 pAppDisplay
= pXtAppDisplay
;
449 XtAppAddInput( app_context
,
451 (XtPointer
)XtInputReadMask
,
452 ThreadEventHandler
, NULL
);
455 // send that we are ready to go
456 MediatorMessage
* pMessage
=
457 pConnector
->Transact( "init req", 8,
461 #if OSL_DEBUG_LEVEL > 3
467 char* pArgs
[] = { "xterm", "-sl", "2000", "-sb", "-e", "gdb", "pluginapp.bin", pidbuf
, NULL
};
468 sprintf( pidbuf
, "%d", nPID
);
469 execvp( pArgs
[0], pArgs
);
479 // for some reason XtAppSetExitFlag won't quit the application
480 // in ThreadEventHandler most of times; Xt will hang in select
481 // (hat is in XtAppNextEvent). Have our own mainloop instead
486 g_main_context_iteration( NULL
, sal_True
);
488 XtAppProcessEvent( app_context
, XtIMAll
);
490 } while( ! XtAppGetExitFlag( app_context
) && ! bPluginAppQuit
);
492 SAL_INFO("extensions.plugin", "left plugin app main loop");
495 g_source_remove(xt_polling_timer_id
);
499 SAL_INFO("extensions.plugin", "NP_Shutdown done");
500 osl_unloadModule( pPluginLib
);
501 SAL_INFO("extensions.plugin", "plugin close");
503 close( wakeup_fd
[0] );
504 close( wakeup_fd
[1] );
509 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */