LCOV - code coverage report
Current view: top level - extensions/source/plugin/unx - npwrap.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 157 0.0 %
Date: 2014-04-14 Functions: 0 18 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10