merged tag ooo/OOO330_m14
[LibreOffice.git] / extensions / source / plugin / unx / npwrap.cxx
blob387de8cde24df2776abfbb4b1b4b68a68aea15bd
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"
30 #include <errno.h>
31 #include <dlfcn.h>
32 #include <unistd.h>
33 #include <sys/poll.h>
34 #include <fcntl.h>
35 #include <signal.h>
37 #include <plugin/unx/plugcon.hxx>
39 #include <osl/file.h>
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 );
64 return 0;
67 extern "C"
69 static int plugin_x_error_handler( Display*, XErrorEvent* )
71 return 0;
74 #ifndef ENABLE_GTK
75 static void ThreadEventHandler( XtPointer /*client_data*/, int* /*source*/, XtInputId* id )
77 char buf[256];
78 // clear pipe
79 int len, nLast = -1;
81 while( (len = read( wakeup_fd[0], buf, sizeof( buf ) ) ) > 0 )
82 nLast = len-1;
83 if( ! bPluginAppQuit )
85 if( ( nLast == -1 || buf[nLast] != 'x' ) && pConnector )
86 pConnector->CallWorkHandler();
87 else
89 // it seems you can use XtRemoveInput only
90 // safely from within the callback
91 // why is that ?
92 medDebug( 1, "removing wakeup pipe\n" );
93 XtRemoveInput( *id );
94 XtAppSetExitFlag( app_context );
95 bPluginAppQuit = true;
97 delete pConnector;
98 pConnector = NULL;
102 #endif
106 IMPL_LINK( PluginConnector, NewMessageHdl, Mediator*, /*pMediator*/ )
108 medDebug( 1, "new message handler\n" );
109 write( wakeup_fd[1], "cccc", 4 );
110 return 0;
114 Widget createSubWidget( char* /*pPluginText*/, Widget shell, XLIB_Window aParentWindow )
116 Widget newWidget = XtVaCreateManagedWidget(
117 #if defined USE_MOTIF
118 "drawingArea",
119 xmDrawingAreaWidgetClass,
120 #else
122 # if defined DISABLE_XAW
123 compositeWidgetClass,
124 # else
125 labelWidgetClass,
126 # endif
127 #endif
128 shell,
129 XtNwidth, 200,
130 XtNheight, 200,
131 (char *)NULL );
132 XtRealizeWidget( shell );
133 XtRealizeWidget( newWidget );
135 medDebug( 1, "Reparenting new widget %x to %x\n", XtWindow( newWidget ), aParentWindow );
136 XReparentWindow( pXtAppDisplay,
137 XtWindow( shell ),
138 aParentWindow,
139 0, 0 );
140 XtMapWidget( shell );
141 XtMapWidget( newWidget );
142 XRaiseWindow( pXtAppDisplay, XtWindow( shell ) );
143 XSync( pXtAppDisplay, False );
145 return newWidget;
148 void* CreateNewShell( void** pShellReturn, XLIB_Window aParentWindow )
150 XLIB_String n, c;
151 XtGetApplicationNameAndClass(pXtAppDisplay, &n, &c);
153 Widget newShell =
154 XtVaAppCreateShell( "pane", c,
155 topLevelShellWidgetClass,
156 pXtAppDisplay,
157 XtNwidth, 200,
158 XtNheight, 200,
159 XtNoverrideRedirect, True,
160 (char *)NULL );
161 *pShellReturn = newShell;
163 char pText[1024];
164 sprintf( pText, "starting plugin %s ...", pAppArguments[2] );
166 Widget newWidget = createSubWidget( pText, newShell, aParentWindow );
168 return newWidget;
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 );
178 if( ! pLib )
180 medDebug( 1, "could not open %s: %s\n", pPath, dlerror() );
182 return pLib;
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() );
194 else
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>
202 #endif
204 extern "C" {
206 static void signal_handler( int nSig )
208 #if OSL_DEBUG_LEVEL > 1
209 fprintf( stderr, "caught signal %d, exiting\n", nSig );
210 #ifdef LINUX
211 void* pStack[64];
212 int nStackLevels = backtrace( pStack, sizeof(pStack)/sizeof(pStack[0]) );
213 backtrace_symbols_fd( pStack, nStackLevels, STDERR_FILENO );
214 #endif
215 #endif
216 if( pConnector )
218 // ensure that a read on the other side will wakeup
219 delete pConnector;
220 pConnector = NULL;
223 _exit(nSig);
226 #ifdef ENABLE_GTK
228 static gboolean noClosure( gpointer )
230 return TRUE;
233 // Xt events
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 );
249 return TRUE;
252 static GSourceFuncs aXtEventFuncs =
254 prepareXtEvent,
255 checkXtEvent,
256 dispatchXtEvent,
257 NULL,
258 noClosure,
259 NULL
262 static gboolean pollXtTimerCallback(gpointer)
264 for(int i = 0; i < 5; i++)
266 if( (XtAppPending(app_context) & (XtIMAll & ~XtIMXEvent)) == 0 )
267 break;
268 XtAppProcessEvent(app_context, XtIMAll & ~XtIMXEvent);
270 return TRUE;
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 )
282 gint nDum = 0;
283 return prepareWakeupEvent( pSource, &nDum );
286 static gboolean dispatchWakeupEvent( GSource*, GSourceFunc, gpointer )
288 char buf[256];
289 // clear pipe
290 int len, nLast = -1;
292 while( (len = read( wakeup_fd[0], buf, sizeof( buf ) ) ) > 0 )
293 nLast = len-1;
294 if( ( nLast == -1 || buf[nLast] != 'x' ) && pConnector )
295 pConnector->CallWorkHandler();
296 else
298 XtAppSetExitFlag( app_context );
299 bPluginAppQuit = true;
301 delete pConnector;
302 pConnector = NULL;
305 return TRUE;
308 static GSourceFuncs aWakeupEventFuncs = {
309 prepareWakeupEvent,
310 checkWakeupEvent,
311 dispatchWakeupEvent,
312 NULL,
313 noClosure,
314 NULL
317 #endif // GTK
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] != '/' )
336 pBaseName--;
337 LoadAdditionalLibs( pBaseName );
339 if( argc == 2 )
341 CheckPlugin(argv[1]);
342 exit(0);
344 nAppArguments = argc;
345 pAppArguments = argv;
347 XSetErrorHandler( plugin_x_error_handler );
349 if( pipe( wakeup_fd ) )
351 medDebug( 1, "could not pipe()\n" );
352 return 1;
354 // initialize 'wakeup' pipe.
355 int flags;
357 // set close-on-exec descriptor flag.
358 if ((flags = fcntl (wakeup_fd[0], F_GETFD)) != -1)
360 flags |= FD_CLOEXEC;
361 fcntl (wakeup_fd[0], F_SETFD, flags);
363 if ((flags = fcntl (wakeup_fd[1], F_GETFD)) != -1)
365 flags |= FD_CLOEXEC;
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)
372 flags |= O_NONBLOCK;
373 fcntl (wakeup_fd[0], F_SETFL, flags);
375 if ((flags = fcntl (wakeup_fd[1], F_GETFL)) != -1)
377 flags |= O_NONBLOCK;
378 fcntl (wakeup_fd[1], F_SETFL, flags);
381 pPluginLib = LoadModule( argv[2] );
382 if( ! pPluginLib )
384 exit(255);
386 int nSocket = atol( argv[1] );
388 #ifdef ENABLE_GTK
389 g_thread_init(NULL);
390 gtk_init(&argc, &argv);
391 #endif
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 );
403 #ifdef ENABLE_GTK
404 // integrate Xt events into GTK event loop
405 GPollFD aXtPollDesc, aWakeupPollDesc;
407 GSource* pXTSource = g_source_new( &aXtEventFuncs, sizeof(GSource) );
408 if( !pXTSource )
410 medDebug( 1, "could not get Xt GSource" );
411 return 1;
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" );
428 return 1;
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() );
438 #else
439 pAppDisplay = pXtAppDisplay;
440 XtAppAddInput( app_context,
441 wakeup_fd[0],
442 (XtPointer)XtInputReadMask,
443 ThreadEventHandler, NULL );
444 #endif
446 // send that we are ready to go
447 MediatorMessage* pMessage =
448 pConnector->Transact( "init req", 8,
449 NULL );
450 delete pMessage;
452 #if OSL_DEBUG_LEVEL > 3
453 int nPID = getpid();
454 int nChild = fork();
455 if( nChild == 0 )
457 char pidbuf[16];
458 char* pArgs[] = { "xterm", "-sl", "2000", "-sb", "-e", "gdb", "pluginapp.bin", pidbuf, NULL };
459 sprintf( pidbuf, "%d", nPID );
460 execvp( pArgs[0], pArgs );
461 _exit(255);
463 else
464 sleep( 10 );
465 #endif
468 * Loop for events.
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
473 // of XtAppMainLoop
476 #ifdef ENABLE_GTK
477 g_main_context_iteration( NULL, TRUE );
478 #else
479 XtAppProcessEvent( app_context, XtIMAll );
480 #endif
481 } while( ! XtAppGetExitFlag( app_context ) && ! bPluginAppQuit );
483 medDebug( 1, "left plugin app main loop\n" );
485 #ifdef ENABLE_GTK
486 g_source_remove(xt_polling_timer_id);
487 #endif
489 pNP_Shutdown();
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] );
497 return 0;
500 #ifdef GCC
501 extern "C" {
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 )
510 { free(pMem); }
511 void __builtin_vec_delete( char* pMem )
512 { free(pMem); }
514 #endif