Update ooo320-m1
[ooovba.git] / extensions / source / plugin / unx / npwrap.cxx
blob0500ea0272366c6655359e9a00520616f2f6edbf
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: npwrap.cxx,v $
10 * $Revision: 1.16.90.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_extensions.hxx"
33 #include <errno.h>
34 #include <dlfcn.h>
35 #include <unistd.h>
36 #include <sys/poll.h>
37 #include <fcntl.h>
38 #include <signal.h>
40 #include <plugin/unx/plugcon.hxx>
42 #include <osl/file.h>
43 #include <osl/module.h>
45 PluginConnector* pConnector = NULL;
47 int nAppArguments = 0;
48 char** pAppArguments = NULL;
49 Display* pAppDisplay = NULL;
50 Display* pXtAppDisplay = NULL;
52 extern oslModule pPluginLib;
53 extern NPError (*pNP_Shutdown)();
55 void LoadAdditionalLibs(const char*);
57 XtAppContext app_context;
58 Widget topLevel = NULL, topBox = NULL;
59 int wakeup_fd[2] = { 0, 0 };
60 static bool bPluginAppQuit = false;
62 static long GlobalConnectionLostHdl( void* /*pInst*/, void* /*pArg*/ )
64 medDebug( 1, "pluginapp exiting due to connection lost\n" );
66 write( wakeup_fd[1], "xxxx", 4 );
67 return 0;
70 extern "C"
72 static int plugin_x_error_handler( Display*, XErrorEvent* )
74 return 0;
77 #ifndef ENABLE_GTK
78 static void ThreadEventHandler( XtPointer /*client_data*/, int* /*source*/, XtInputId* id )
80 char buf[256];
81 // clear pipe
82 int len, nLast = -1;
84 while( (len = read( wakeup_fd[0], buf, sizeof( buf ) ) ) > 0 )
85 nLast = len-1;
86 if( ! bPluginAppQuit )
88 if( ( nLast == -1 || buf[nLast] != 'x' ) && pConnector )
89 pConnector->CallWorkHandler();
90 else
92 // it seems you can use XtRemoveInput only
93 // safely from within the callback
94 // why is that ?
95 medDebug( 1, "removing wakeup pipe\n" );
96 XtRemoveInput( *id );
97 XtAppSetExitFlag( app_context );
98 bPluginAppQuit = true;
100 delete pConnector;
101 pConnector = NULL;
105 #endif
109 IMPL_LINK( PluginConnector, NewMessageHdl, Mediator*, /*pMediator*/ )
111 medDebug( 1, "new message handler\n" );
112 write( wakeup_fd[1], "cccc", 4 );
113 return 0;
117 Widget createSubWidget( char* /*pPluginText*/, Widget shell, XLIB_Window aParentWindow )
119 Widget newWidget = XtVaCreateManagedWidget(
120 #if defined USE_MOTIF
121 "drawingArea",
122 xmDrawingAreaWidgetClass,
123 #else
125 # if defined DISABLE_XAW
126 compositeWidgetClass,
127 # else
128 labelWidgetClass,
129 # endif
130 #endif
131 shell,
132 XtNwidth, 200,
133 XtNheight, 200,
134 (char *)NULL );
135 XtRealizeWidget( shell );
136 XtRealizeWidget( newWidget );
138 medDebug( 1, "Reparenting new widget %x to %x\n", XtWindow( newWidget ), aParentWindow );
139 XReparentWindow( pXtAppDisplay,
140 XtWindow( shell ),
141 aParentWindow,
142 0, 0 );
143 XtMapWidget( shell );
144 XtMapWidget( newWidget );
145 XRaiseWindow( pXtAppDisplay, XtWindow( shell ) );
146 XSync( pXtAppDisplay, False );
148 return newWidget;
151 void* CreateNewShell( void** pShellReturn, XLIB_Window aParentWindow )
153 XLIB_String n, c;
154 XtGetApplicationNameAndClass(pXtAppDisplay, &n, &c);
156 Widget newShell =
157 XtVaAppCreateShell( "pane", c,
158 topLevelShellWidgetClass,
159 pXtAppDisplay,
160 XtNwidth, 200,
161 XtNheight, 200,
162 XtNoverrideRedirect, True,
163 (char *)NULL );
164 *pShellReturn = newShell;
166 char pText[1024];
167 sprintf( pText, "starting plugin %s ...", pAppArguments[2] );
169 Widget newWidget = createSubWidget( pText, newShell, aParentWindow );
171 return newWidget;
174 static oslModule LoadModule( const char* pPath )
176 ::rtl::OUString sSystemPath( ::rtl::OUString::createFromAscii( pPath ) );
177 ::rtl::OUString sFileURL;
178 osl_getFileURLFromSystemPath( sSystemPath.pData, &sFileURL.pData );
180 oslModule pLib = osl_loadModule( sFileURL.pData, SAL_LOADMODULE_LAZY );
181 if( ! pLib )
183 medDebug( 1, "could not open %s: %s\n", pPath, dlerror() );
185 return pLib;
188 // Unix specific implementation
189 static void CheckPlugin( const char* pPath )
191 oslModule pLib = LoadModule( pPath );
193 char*(*pNP_GetMIMEDescription)() = (char*(*)())
194 osl_getAsciiFunctionSymbol( pLib, "NP_GetMIMEDescription" );
195 if( pNP_GetMIMEDescription )
196 printf( "%s\n", pNP_GetMIMEDescription() );
197 else
198 medDebug( 1, "could not get symbol NP_GetMIMEDescription %s\n", dlerror() );
200 osl_unloadModule( pLib );
203 #if OSL_DEBUG_LEVEL > 1 && defined LINUX
204 #include <execinfo.h>
205 #endif
207 extern "C" {
209 static void signal_handler( int nSig )
211 #if OSL_DEBUG_LEVEL > 1
212 fprintf( stderr, "caught signal %d, exiting\n", nSig );
213 #ifdef LINUX
214 void* pStack[64];
215 int nStackLevels = backtrace( pStack, sizeof(pStack)/sizeof(pStack[0]) );
216 backtrace_symbols_fd( pStack, nStackLevels, STDERR_FILENO );
217 #endif
218 #endif
219 if( pConnector )
221 // ensure that a read on the other side will wakeup
222 delete pConnector;
223 pConnector = NULL;
226 _exit(nSig);
229 #ifdef ENABLE_GTK
231 static gboolean noClosure( gpointer )
233 return TRUE;
236 // Xt events
237 static gboolean prepareXtEvent( GSource*, gint* )
239 int nMask = XtAppPending( app_context );
240 return (nMask & XtIMAll) != 0;
243 static gboolean checkXtEvent( GSource* )
245 int nMask = XtAppPending( app_context );
246 return (nMask & XtIMAll) != 0;
249 static gboolean dispatchXtEvent( GSource*, GSourceFunc, gpointer )
251 XtAppProcessEvent( app_context, XtIMAll );
252 return TRUE;
255 static GSourceFuncs aXtEventFuncs =
257 prepareXtEvent,
258 checkXtEvent,
259 dispatchXtEvent,
260 NULL,
261 noClosure,
262 NULL
265 static gboolean pollXtTimerCallback(gpointer)
267 for(int i = 0; i < 5; i++)
269 if( (XtAppPending(app_context) & (XtIMAll & ~XtIMXEvent)) == 0 )
270 break;
271 XtAppProcessEvent(app_context, XtIMAll & ~XtIMXEvent);
273 return TRUE;
276 static gboolean prepareWakeupEvent( GSource*, gint* )
278 struct pollfd aPoll = { wakeup_fd[0], POLLIN, 0 };
279 poll( &aPoll, 1, 0 );
280 return (aPoll.revents & POLLIN ) != 0;
283 static gboolean checkWakeupEvent( GSource* pSource )
285 gint nDum = 0;
286 return prepareWakeupEvent( pSource, &nDum );
289 static gboolean dispatchWakeupEvent( GSource*, GSourceFunc, gpointer )
291 char buf[256];
292 // clear pipe
293 int len, nLast = -1;
295 while( (len = read( wakeup_fd[0], buf, sizeof( buf ) ) ) > 0 )
296 nLast = len-1;
297 if( ( nLast == -1 || buf[nLast] != 'x' ) && pConnector )
298 pConnector->CallWorkHandler();
299 else
301 XtAppSetExitFlag( app_context );
302 bPluginAppQuit = true;
304 delete pConnector;
305 pConnector = NULL;
308 return TRUE;
311 static GSourceFuncs aWakeupEventFuncs = {
312 prepareWakeupEvent,
313 checkWakeupEvent,
314 dispatchWakeupEvent,
315 NULL,
316 noClosure,
317 NULL
320 #endif // GTK
324 int main( int argc, char **argv)
326 struct sigaction aSigAction;
327 aSigAction.sa_handler = signal_handler;
328 sigemptyset( &aSigAction.sa_mask );
329 aSigAction.sa_flags = SA_NOCLDSTOP;
330 sigaction( SIGSEGV, &aSigAction, NULL );
331 sigaction( SIGBUS, &aSigAction, NULL );
332 sigaction( SIGABRT, &aSigAction, NULL );
333 sigaction( SIGTERM, &aSigAction, NULL );
334 sigaction( SIGILL, &aSigAction, NULL );
336 int nArg = (argc < 3) ? 1 : 2;
337 char* pBaseName = argv[nArg] + strlen(argv[nArg]);
338 while( pBaseName > argv[nArg] && pBaseName[-1] != '/' )
339 pBaseName--;
340 LoadAdditionalLibs( pBaseName );
342 if( argc == 2 )
344 CheckPlugin(argv[1]);
345 exit(0);
347 nAppArguments = argc;
348 pAppArguments = argv;
350 XSetErrorHandler( plugin_x_error_handler );
352 if( pipe( wakeup_fd ) )
354 medDebug( 1, "could not pipe()\n" );
355 return 1;
357 // initialize 'wakeup' pipe.
358 int flags;
360 // set close-on-exec descriptor flag.
361 if ((flags = fcntl (wakeup_fd[0], F_GETFD)) != -1)
363 flags |= FD_CLOEXEC;
364 fcntl (wakeup_fd[0], F_SETFD, flags);
366 if ((flags = fcntl (wakeup_fd[1], F_GETFD)) != -1)
368 flags |= FD_CLOEXEC;
369 fcntl (wakeup_fd[1], F_SETFD, flags);
372 // set non-blocking I/O flag.
373 if ((flags = fcntl (wakeup_fd[0], F_GETFL)) != -1)
375 flags |= O_NONBLOCK;
376 fcntl (wakeup_fd[0], F_SETFL, flags);
378 if ((flags = fcntl (wakeup_fd[1], F_GETFL)) != -1)
380 flags |= O_NONBLOCK;
381 fcntl (wakeup_fd[1], F_SETFL, flags);
384 pPluginLib = LoadModule( argv[2] );
385 if( ! pPluginLib )
387 exit(255);
389 int nSocket = atol( argv[1] );
391 #ifdef ENABLE_GTK
392 g_thread_init(NULL);
393 gtk_init(&argc, &argv);
394 #endif
396 pConnector = new PluginConnector( nSocket );
397 pConnector->SetConnectionLostHdl( Link( NULL, GlobalConnectionLostHdl ) );
399 XtSetLanguageProc( NULL, NULL, NULL );
401 XtToolkitInitialize();
402 app_context = XtCreateApplicationContext();
403 pXtAppDisplay = XtOpenDisplay( app_context, NULL, "SOPlugin", "SOPlugin", NULL, 0, &argc, argv );
406 #ifdef ENABLE_GTK
407 // integrate Xt events into GTK event loop
408 GPollFD aXtPollDesc, aWakeupPollDesc;
410 GSource* pXTSource = g_source_new( &aXtEventFuncs, sizeof(GSource) );
411 if( !pXTSource )
413 medDebug( 1, "could not get Xt GSource" );
414 return 1;
417 g_source_set_priority( pXTSource, GDK_PRIORITY_EVENTS );
418 g_source_set_can_recurse( pXTSource, TRUE );
419 g_source_attach( pXTSource, NULL );
420 aXtPollDesc.fd = ConnectionNumber( pXtAppDisplay );
421 aXtPollDesc.events = G_IO_IN;
422 aXtPollDesc.revents = 0;
423 g_source_add_poll( pXTSource, &aXtPollDesc );
425 gint xt_polling_timer_id = g_timeout_add( 25, pollXtTimerCallback, NULL);
426 // Initialize wakeup events listener
427 GSource *pWakeupSource = g_source_new( &aWakeupEventFuncs, sizeof(GSource) );
428 if ( pWakeupSource == NULL )
430 medDebug( 1, "could not get wakeup source" );
431 return 1;
433 g_source_set_priority( pWakeupSource, GDK_PRIORITY_EVENTS);
434 g_source_attach( pWakeupSource, NULL );
435 aWakeupPollDesc.fd = wakeup_fd[0];
436 aWakeupPollDesc.events = G_IO_IN;
437 aWakeupPollDesc.revents = 0;
438 g_source_add_poll( pWakeupSource, &aWakeupPollDesc );
440 pAppDisplay = gdk_x11_display_get_xdisplay( gdk_display_get_default() );
441 #else
442 pAppDisplay = pXtAppDisplay;
443 XtAppAddInput( app_context,
444 wakeup_fd[0],
445 (XtPointer)XtInputReadMask,
446 ThreadEventHandler, NULL );
447 #endif
449 // send that we are ready to go
450 MediatorMessage* pMessage =
451 pConnector->Transact( "init req", 8,
452 NULL );
453 delete pMessage;
455 #if OSL_DEBUG_LEVEL > 3
456 int nPID = getpid();
457 int nChild = fork();
458 if( nChild == 0 )
460 char pidbuf[16];
461 char* pArgs[] = { "xterm", "-sl", "2000", "-sb", "-e", "gdb", "pluginapp.bin", pidbuf, NULL };
462 sprintf( pidbuf, "%d", nPID );
463 execvp( pArgs[0], pArgs );
464 _exit(255);
466 else
467 sleep( 10 );
468 #endif
471 * Loop for events.
473 // for some reason XtAppSetExitFlag won't quit the application
474 // in ThreadEventHandler most of times; Xt will hang in select
475 // (hat is in XtAppNextEvent). Have our own mainloop instead
476 // of XtAppMainLoop
479 #ifdef ENABLE_GTK
480 g_main_context_iteration( NULL, TRUE );
481 #else
482 XtAppProcessEvent( app_context, XtIMAll );
483 #endif
484 } while( ! XtAppGetExitFlag( app_context ) && ! bPluginAppQuit );
486 medDebug( 1, "left plugin app main loop\n" );
488 g_source_remove(xt_polling_timer_id);
490 pNP_Shutdown();
491 medDebug( 1, "NP_Shutdown done\n" );
492 osl_unloadModule( pPluginLib );
493 medDebug( 1, "plugin close\n" );
495 close( wakeup_fd[0] );
496 close( wakeup_fd[1] );
498 return 0;
501 #ifdef GCC
502 extern "C" {
503 void __pure_virtual()
506 void* __builtin_new( int nBytes )
507 { return malloc(nBytes); }
508 void* __builtin_vec_new( int nBytes )
509 { return malloc(nBytes); }
510 void __builtin_delete( char* pMem )
511 { free(pMem); }
512 void __builtin_vec_delete( char* pMem )
513 { free(pMem); }
515 #endif