Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*************************************************************************
3 : *
4 : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : *
6 : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : *
8 : * OpenOffice.org - a multi-platform office productivity suite
9 : *
10 : * This file is part of OpenOffice.org.
11 : *
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.
15 : *
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).
21 : *
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.
26 : *
27 : ************************************************************************/
28 :
29 : #ifdef AIX
30 : #define _LINUX_SOURCE_COMPAT
31 : #include <sys/timer.h>
32 : #undef _LINUX_SOURCE_COMPAT
33 : #endif
34 : #include <errno.h>
35 : #include <dlfcn.h>
36 : #include <unistd.h>
37 : #include <sys/poll.h>
38 : #include <fcntl.h>
39 : #include <signal.h>
40 :
41 : #define GLIB_DISABLE_DEPRECATION_WARNINGS
42 : #include <plugin/unx/plugcon.hxx>
43 :
44 : #include <osl/file.h>
45 : #include <osl/module.h>
46 :
47 : #include <config_vclplug.h>
48 :
49 : PluginConnector* pConnector = NULL;
50 :
51 : int nAppArguments = 0;
52 : char** pAppArguments = NULL;
53 : Display* pAppDisplay = NULL;
54 : Display* pXtAppDisplay = NULL;
55 :
56 : extern oslModule pPluginLib;
57 : extern NPError (*pNP_Shutdown)();
58 :
59 : void LoadAdditionalLibs(const char*);
60 :
61 : XtAppContext app_context;
62 : Widget topLevel = NULL, topBox = NULL;
63 : int wakeup_fd[2] = { 0, 0 };
64 : static bool bPluginAppQuit = false;
65 :
66 0 : static long GlobalConnectionLostHdl( void* /*pInst*/, void* /*pArg*/ )
67 : {
68 : SAL_WARN("extensions.plugin", "pluginapp exiting due to connection lost");
69 :
70 0 : bool bSuccess = (4 == write(wakeup_fd[1], "xxxx", 4 ));
71 : SAL_WARN_IF(!bSuccess, "extensions.plugin", "short write");
72 0 : return 0;
73 : }
74 :
75 : extern "C"
76 : {
77 0 : static int plugin_x_error_handler( Display*, XErrorEvent* )
78 : {
79 0 : return 0;
80 : }
81 :
82 : #ifndef ENABLE_GTK
83 : static void ThreadEventHandler( XtPointer /*client_data*/, int* /*source*/, XtInputId* id )
84 : {
85 : char buf[256];
86 : // clear pipe
87 : int len, nLast = -1;
88 :
89 : while( (len = read( wakeup_fd[0], buf, sizeof( buf ) ) ) > 0 )
90 : nLast = len-1;
91 : if( ! bPluginAppQuit )
92 : {
93 : if( ( nLast == -1 || buf[nLast] != 'x' ) && pConnector )
94 : pConnector->CallWorkHandler();
95 : else
96 : {
97 : // it seems you can use XtRemoveInput only
98 : // safely from within the callback
99 : // why is that ?
100 : SAL_INFO("extensions.plugin", "removing wakeup pipe");
101 : XtRemoveInput( *id );
102 : XtAppSetExitFlag( app_context );
103 : bPluginAppQuit = true;
104 :
105 : delete pConnector;
106 : pConnector = NULL;
107 : }
108 : }
109 : }
110 : #endif
111 : }
112 :
113 :
114 0 : IMPL_LINK( PluginConnector, NewMessageHdl, Mediator*, /*pMediator*/ )
115 : {
116 : SAL_INFO("extensions.plugin", "new message handler");
117 0 : bool bSuccess = (4 == write(wakeup_fd[1], "cccc", 4));
118 : SAL_WARN_IF(!bSuccess, "extensions.plugin", "short write");
119 0 : return 0;
120 :
121 : }
122 :
123 0 : Widget createSubWidget( char* /*pPluginText*/, Widget shell, XLIB_Window aParentWindow )
124 : {
125 : Widget newWidget = XtVaCreateManagedWidget(
126 : #if defined USE_MOTIF
127 : "drawingArea",
128 : xmDrawingAreaWidgetClass,
129 : #else
130 : "",
131 : compositeWidgetClass,
132 : #endif
133 : shell,
134 : XtNwidth, 200,
135 : XtNheight, 200,
136 0 : (char *)NULL );
137 0 : XtRealizeWidget( shell );
138 0 : XtRealizeWidget( newWidget );
139 :
140 : SAL_INFO(
141 : "extensions.plugin",
142 : "reparenting new widget " << XtWindow( newWidget ) << " to "
143 : << aParentWindow);
144 : XReparentWindow( pXtAppDisplay,
145 : XtWindow( shell ),
146 : aParentWindow,
147 0 : 0, 0 );
148 0 : XtMapWidget( shell );
149 0 : XtMapWidget( newWidget );
150 0 : XRaiseWindow( pXtAppDisplay, XtWindow( shell ) );
151 0 : XSync( pXtAppDisplay, False );
152 :
153 0 : return newWidget;
154 : }
155 :
156 0 : void* CreateNewShell( void** pShellReturn, XLIB_Window aParentWindow )
157 : {
158 : XLIB_String n, c;
159 0 : XtGetApplicationNameAndClass(pXtAppDisplay, &n, &c);
160 :
161 : Widget newShell =
162 : XtVaAppCreateShell( "pane", c,
163 : topLevelShellWidgetClass,
164 : pXtAppDisplay,
165 : XtNwidth, 200,
166 : XtNheight, 200,
167 : XtNoverrideRedirect, True,
168 0 : (char *)NULL );
169 0 : *pShellReturn = newShell;
170 :
171 : char pText[1024];
172 0 : sprintf( pText, "starting plugin %s ...", pAppArguments[2] );
173 :
174 0 : Widget newWidget = createSubWidget( pText, newShell, aParentWindow );
175 :
176 0 : return newWidget;
177 : }
178 :
179 0 : static oslModule LoadModule( const char* pPath )
180 : {
181 0 : ::rtl::OUString sSystemPath( ::rtl::OUString::createFromAscii( pPath ) );
182 0 : ::rtl::OUString sFileURL;
183 0 : osl_getFileURLFromSystemPath( sSystemPath.pData, &sFileURL.pData );
184 :
185 0 : oslModule pLib = osl_loadModule( sFileURL.pData, SAL_LOADMODULE_LAZY );
186 : SAL_INFO_IF(!pLib, "extensions.plugin", "could not open " << pPath);
187 0 : return pLib;
188 : }
189 :
190 : // Unix specific implementation
191 0 : static void CheckPlugin( const char* pPath )
192 : {
193 0 : oslModule pLib = LoadModule( pPath );
194 0 : if (pLib != 0)
195 : {
196 : char*(*pNP_GetMIMEDescription)() = (char*(*)())
197 0 : osl_getAsciiFunctionSymbol( pLib, "NP_GetMIMEDescription" );
198 0 : if( pNP_GetMIMEDescription )
199 0 : printf( "%s\n", pNP_GetMIMEDescription() );
200 : else
201 : SAL_WARN(
202 : "extensions.plugin",
203 : "could not get symbol NP_GetMIMEDescription " << dlerror());
204 0 : osl_unloadModule( pLib );
205 : }
206 0 : }
207 :
208 : #if OSL_DEBUG_LEVEL > 1 && defined LINUX
209 : #include <execinfo.h>
210 : #endif
211 :
212 : extern "C" {
213 :
214 0 : static void signal_handler( int nSig )
215 : {
216 : #if OSL_DEBUG_LEVEL > 1
217 : fprintf( stderr, "caught signal %d, exiting\n", nSig );
218 : #ifdef LINUX
219 : void* pStack[64];
220 : int nStackLevels = backtrace( pStack, SAL_N_ELEMENTS(pStack) );
221 : backtrace_symbols_fd( pStack, nStackLevels, STDERR_FILENO );
222 : #endif
223 : #endif
224 0 : if( pConnector )
225 : {
226 : // ensure that a read on the other side will wakeup
227 0 : delete pConnector;
228 0 : pConnector = NULL;
229 : }
230 :
231 0 : _exit(nSig);
232 : }
233 :
234 : #ifdef ENABLE_GTK
235 :
236 0 : static gboolean noClosure( gpointer )
237 : {
238 0 : return sal_True;
239 : }
240 :
241 : // Xt events
242 0 : static gboolean prepareXtEvent( GSource*, gint* )
243 : {
244 0 : int nMask = XtAppPending( app_context );
245 0 : return (nMask & XtIMAll) != 0;
246 : }
247 :
248 0 : static gboolean checkXtEvent( GSource* )
249 : {
250 0 : int nMask = XtAppPending( app_context );
251 0 : return (nMask & XtIMAll) != 0;
252 : }
253 :
254 0 : static gboolean dispatchXtEvent( GSource*, GSourceFunc, gpointer )
255 : {
256 0 : XtAppProcessEvent( app_context, XtIMAll );
257 0 : return sal_True;
258 : }
259 :
260 : static GSourceFuncs aXtEventFuncs =
261 : {
262 : prepareXtEvent,
263 : checkXtEvent,
264 : dispatchXtEvent,
265 : NULL,
266 : noClosure,
267 : NULL
268 : };
269 :
270 0 : static gboolean pollXtTimerCallback(gpointer)
271 : {
272 0 : for(int i = 0; i < 5; i++)
273 : {
274 0 : if( (XtAppPending(app_context) & (XtIMAll & ~XtIMXEvent)) == 0 )
275 0 : break;
276 0 : XtAppProcessEvent(app_context, XtIMAll & ~XtIMXEvent);
277 : }
278 0 : return sal_True;
279 : }
280 :
281 0 : static gboolean prepareWakeupEvent( GSource*, gint* )
282 : {
283 0 : struct pollfd aPoll = { wakeup_fd[0], POLLIN, 0 };
284 0 : poll( &aPoll, 1, 0 );
285 0 : return (aPoll.revents & POLLIN ) != 0;
286 : }
287 :
288 0 : static gboolean checkWakeupEvent( GSource* pSource )
289 : {
290 0 : gint nDum = 0;
291 0 : return prepareWakeupEvent( pSource, &nDum );
292 : }
293 :
294 0 : static gboolean dispatchWakeupEvent( GSource*, GSourceFunc, gpointer )
295 : {
296 : char buf[256];
297 : // clear pipe
298 0 : int len, nLast = -1;
299 :
300 0 : while( (len = read( wakeup_fd[0], buf, sizeof( buf ) ) ) > 0 )
301 0 : nLast = len-1;
302 0 : if( ( nLast == -1 || buf[nLast] != 'x' ) && pConnector )
303 0 : pConnector->CallWorkHandler();
304 : else
305 : {
306 0 : XtAppSetExitFlag( app_context );
307 0 : bPluginAppQuit = true;
308 :
309 0 : delete pConnector;
310 0 : pConnector = NULL;
311 : }
312 :
313 0 : return sal_True;
314 : }
315 :
316 : static GSourceFuncs aWakeupEventFuncs = {
317 : prepareWakeupEvent,
318 : checkWakeupEvent,
319 : dispatchWakeupEvent,
320 : NULL,
321 : noClosure,
322 : NULL
323 : };
324 :
325 : #endif // GTK
326 :
327 : }
328 :
329 0 : int main( int argc, char **argv)
330 : {
331 : struct sigaction aSigAction;
332 0 : aSigAction.sa_handler = signal_handler;
333 0 : sigemptyset( &aSigAction.sa_mask );
334 0 : aSigAction.sa_flags = SA_NOCLDSTOP;
335 0 : sigaction( SIGSEGV, &aSigAction, NULL );
336 0 : sigaction( SIGBUS, &aSigAction, NULL );
337 0 : sigaction( SIGABRT, &aSigAction, NULL );
338 0 : sigaction( SIGTERM, &aSigAction, NULL );
339 0 : sigaction( SIGILL, &aSigAction, NULL );
340 :
341 0 : int nArg = (argc < 3) ? 1 : 2;
342 0 : char* pBaseName = argv[nArg] + strlen(argv[nArg]);
343 0 : while( pBaseName > argv[nArg] && pBaseName[-1] != '/' )
344 0 : pBaseName--;
345 0 : LoadAdditionalLibs( pBaseName );
346 :
347 0 : if( argc == 2 )
348 : {
349 0 : CheckPlugin(argv[1]);
350 0 : exit(0);
351 : }
352 0 : nAppArguments = argc;
353 0 : pAppArguments = argv;
354 :
355 0 : XSetErrorHandler( plugin_x_error_handler );
356 :
357 0 : if( pipe( wakeup_fd ) )
358 : {
359 : SAL_WARN("extensions.plugin", "could not pipe()");
360 0 : return 1;
361 : }
362 : // initialize 'wakeup' pipe.
363 : int flags;
364 :
365 : // set close-on-exec descriptor flag.
366 0 : if ((flags = fcntl (wakeup_fd[0], F_GETFD)) != -1)
367 : {
368 0 : flags |= FD_CLOEXEC;
369 0 : fcntl (wakeup_fd[0], F_SETFD, flags);
370 : }
371 0 : if ((flags = fcntl (wakeup_fd[1], F_GETFD)) != -1)
372 : {
373 0 : flags |= FD_CLOEXEC;
374 0 : fcntl (wakeup_fd[1], F_SETFD, flags);
375 : }
376 :
377 : // set non-blocking I/O flag.
378 0 : if ((flags = fcntl (wakeup_fd[0], F_GETFL)) != -1)
379 : {
380 0 : flags |= O_NONBLOCK;
381 0 : fcntl (wakeup_fd[0], F_SETFL, flags);
382 : }
383 0 : if ((flags = fcntl (wakeup_fd[1], F_GETFL)) != -1)
384 : {
385 0 : flags |= O_NONBLOCK;
386 0 : fcntl (wakeup_fd[1], F_SETFL, flags);
387 : }
388 :
389 0 : pPluginLib = LoadModule( argv[2] );
390 0 : if( ! pPluginLib )
391 : {
392 0 : exit(255);
393 : }
394 0 : int nSocket = atol( argv[1] );
395 :
396 : #ifdef ENABLE_GTK
397 0 : g_thread_init(NULL);
398 0 : gtk_init(&argc, &argv);
399 : #endif
400 :
401 0 : pConnector = new PluginConnector( nSocket );
402 0 : pConnector->SetConnectionLostHdl( Link( NULL, GlobalConnectionLostHdl ) );
403 :
404 0 : XtSetLanguageProc( NULL, NULL, NULL );
405 :
406 0 : XtToolkitInitialize();
407 0 : app_context = XtCreateApplicationContext();
408 0 : pXtAppDisplay = XtOpenDisplay( app_context, NULL, "SOPlugin", "SOPlugin", NULL, 0, &argc, argv );
409 :
410 :
411 : #ifdef ENABLE_GTK
412 : // integrate Xt events into GTK event loop
413 : GPollFD aXtPollDesc, aWakeupPollDesc;
414 :
415 0 : GSource* pXTSource = g_source_new( &aXtEventFuncs, sizeof(GSource) );
416 0 : if( !pXTSource )
417 : {
418 : SAL_WARN("extensions.plugin", "could not get Xt GSource");
419 0 : return 1;
420 : }
421 :
422 0 : g_source_set_priority( pXTSource, GDK_PRIORITY_EVENTS );
423 0 : g_source_set_can_recurse( pXTSource, sal_True );
424 0 : g_source_attach( pXTSource, NULL );
425 0 : aXtPollDesc.fd = ConnectionNumber( pXtAppDisplay );
426 0 : aXtPollDesc.events = G_IO_IN;
427 0 : aXtPollDesc.revents = 0;
428 0 : g_source_add_poll( pXTSource, &aXtPollDesc );
429 :
430 0 : gint xt_polling_timer_id = g_timeout_add( 25, pollXtTimerCallback, NULL);
431 : // Initialize wakeup events listener
432 0 : GSource *pWakeupSource = g_source_new( &aWakeupEventFuncs, sizeof(GSource) );
433 0 : if ( pWakeupSource == NULL )
434 : {
435 : SAL_WARN("extensions.plugin", "could not get wakeup source");
436 0 : return 1;
437 : }
438 0 : g_source_set_priority( pWakeupSource, GDK_PRIORITY_EVENTS);
439 0 : g_source_attach( pWakeupSource, NULL );
440 0 : aWakeupPollDesc.fd = wakeup_fd[0];
441 0 : aWakeupPollDesc.events = G_IO_IN;
442 0 : aWakeupPollDesc.revents = 0;
443 0 : g_source_add_poll( pWakeupSource, &aWakeupPollDesc );
444 :
445 0 : pAppDisplay = gdk_x11_display_get_xdisplay( gdk_display_get_default() );
446 : #else
447 : pAppDisplay = pXtAppDisplay;
448 : XtAppAddInput( app_context,
449 : wakeup_fd[0],
450 : (XtPointer)XtInputReadMask,
451 : ThreadEventHandler, NULL );
452 : #endif
453 :
454 : // send that we are ready to go
455 : MediatorMessage* pMessage =
456 : pConnector->Transact( "init req", 8,
457 0 : NULL );
458 0 : delete pMessage;
459 :
460 : #if OSL_DEBUG_LEVEL > 3
461 : int nPID = getpid();
462 : int nChild = fork();
463 : if( nChild == 0 )
464 : {
465 : char pidbuf[16];
466 : char* pArgs[] = { "xterm", "-sl", "2000", "-sb", "-e", "gdb", "pluginapp.bin", pidbuf, NULL };
467 : sprintf( pidbuf, "%d", nPID );
468 : execvp( pArgs[0], pArgs );
469 : _exit(255);
470 : }
471 : else
472 : sleep( 10 );
473 : #endif
474 :
475 : /*
476 : * Loop for events.
477 : */
478 : // for some reason XtAppSetExitFlag won't quit the application
479 : // in ThreadEventHandler most of times; Xt will hang in select
480 : // (hat is in XtAppNextEvent). Have our own mainloop instead
481 : // of XtAppMainLoop
482 0 : do
483 : {
484 : #ifdef ENABLE_GTK
485 0 : g_main_context_iteration( NULL, sal_True );
486 : #else
487 : XtAppProcessEvent( app_context, XtIMAll );
488 : #endif
489 0 : } while( ! XtAppGetExitFlag( app_context ) && ! bPluginAppQuit );
490 :
491 : SAL_INFO("extensions.plugin", "left plugin app main loop");
492 :
493 : #ifdef ENABLE_GTK
494 0 : g_source_remove(xt_polling_timer_id);
495 : #endif
496 :
497 0 : pNP_Shutdown();
498 : SAL_INFO("extensions.plugin", "NP_Shutdown done");
499 0 : osl_unloadModule( pPluginLib );
500 : SAL_INFO("extensions.plugin", "plugin close");
501 :
502 0 : close( wakeup_fd[0] );
503 0 : close( wakeup_fd[1] );
504 :
505 0 : return 0;
506 : }
507 :
508 : #ifdef GCC
509 : extern "C" {
510 0 : void __pure_virtual()
511 0 : {}
512 :
513 0 : void* __builtin_new( int nBytes )
514 0 : { return malloc(nBytes); }
515 0 : void* __builtin_vec_new( int nBytes )
516 0 : { return malloc(nBytes); }
517 0 : void __builtin_delete( char* pMem )
518 0 : { free(pMem); }
519 0 : void __builtin_vec_delete( char* pMem )
520 0 : { free(pMem); }
521 : }
522 : #endif
523 :
524 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|