gnash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash] Plugin initialization function does not get called and double sh


From: annonygmouse
Subject: [Gnash] Plugin initialization function does not get called and double shutdown?
Date: Thu, 27 Apr 2006 00:35:56 +0200
User-agent: Mozilla/5.0 (X11; U; Linux x86_64; ca-AD; rv:1.7.12) Gecko/20060405 Debian/1.7.12-1.1


Hi, I'm still stuck with my mozilla and gnash don't getting along properly.

I've dugg a bit in it and here are my findings.

I've added some logging in the file plugin.cpp.

NPError
NS_PluginInitialize()
{
dbglogfile << "Initializing the plugin" << endl;


and it does never get called!

There's also a different behaviour whether I call mozilla opening the
swf file directly (case 1) or I open a URL of a web page containing some
flash (case 2).


Here's the gnash-db.log for the cases:

Case 1.- /usr/lib/mozilla/mozilla-bin
file:///home/jo/gnash/testsuite/movies.all/elvis.swf
00:28:10: Entering PluginShutdown
00:28:10: TRACE: void NS_PluginShutdown() enter
00:28:10: Plugin already shut down
00:28:15: Entering PluginShutdown
00:28:15: TRACE: void NS_PluginShutdown() enter
00:28:15: Plugin already shut down

And mozilla shows a blank page.

Case 2.- /usr/lib/mozilla/mozilla-bin www.ono.com
00:26:42: Browser reads values from plugin
00:26:42: TRACE: NPError NS_PluginGetValue(NPPVariable, void*) enter
00:26:42: Browser reads value NPPVpluginNameStringShockwave Flash 8.0
00:26:42: Browser reads values from plugin
00:26:42: TRACE: NPError NS_PluginGetValue(NPPVariable, void*) enter
00:26:42: Browser reads value NPPVpluginDescriptionString Gnash 0.7, the GNU Flash Player. Copyright &copy; 2006 <a href="http://www.fsf.org";>Free Software Foundation</a>, Inc.<br>Gnash comes with NO WARRANTY, to the extent permitted by law. You may redistribute copies of Gnash under the terms of the <a href="http://www.gnu.org/licenses/gpl.html";>GNU General Public License</a>, with an additional special exception allowing linking with Mozilla, or any variant of Mozilla (such as Firefox), so long as the linking is through its standard plug-in interface. For more information about Gnash, see <a href="http://www.gnu.org/software/gnash/";>http://www.gnu.org/software/gnash</a>.
00:27:06: Entering PluginShutdown
00:27:06: TRACE: void NS_PluginShutdown() enter
00:27:06: Plugin already shut down
00:27:17: Entering PluginShutdown
00:27:17: TRACE: void NS_PluginShutdown() enter
00:27:17: Plugin already shut down

Here it seems there's more communication between both, as mozilla reads the gnash info. And draws a jigsaw icon on a gray background.

Note that it also seems that pluginshutdown is called twice... I'm not sure whether this is correct or not...

Any hint?
My machine is a Turion 64 - Debian 64bits - unstable.
Is there anyone with a similar configuration?

Here's the diff against the CVS version:
address@hidden:~/gnash$ export CVS_RSH="ssh" && cvs -z3 -d:pserver:address@hidden:/sources/gnash diff plugin/plugin.cpp cvs diff: CVS password file /home/jo/.cvspass does not exist - creating a new file
Index: plugin/plugin.cpp
===================================================================
RCS file: /sources/gnash/gnash/plugin/plugin.cpp,v
retrieving revision 1.28
diff -r1.28 plugin.cpp
179a180
> dbglogfile << "Initializing the plugin" << endl;
264a266
>       dbglogfile << "Entering PluginShutdown" << endl;
326a329
>      dbglogfile << "Browser reads values from plugin " << endl;
332a336
> dbglogfile << "Browser reads value NPPVpluginNameString" << PLUGIN_NAME << endl;
339a344
> dbglogfile << "Browser reads value NPPVpluginDescriptionString " << description << endl;
352a358
> dbglogfile << "Invalid parameter" << endl;
365a372
> dbglogfile << "Plugin: New instance" << endl;
425a433
> dbglogfile << "Initiating plugin object " << endl;
616c624
<
---
> dbglogfile << "Initiating plugin object " << aVariable << aValue << endl;

Kind regards
SebastiĆ 
// 
//   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

// Linking Gnash statically or dynamically with other modules is making a
// combined work based on Gnash. Thus, the terms and conditions of the GNU
// General Public License cover the whole combination.
//
// As a special exception, the copyright holders of Gnash give you
// permission to combine Gnash with free software programs or libraries
// that are released under the GNU LGPL and with code included in any
// release of Talkback distributed by the Mozilla Foundation. You may
// copy and distribute such a system following the terms of the GNU GPL
// for all but the LGPL-covered parts and Talkback, and following the
// LGPL for the LGPL-covered parts.
//
// Note that people who make modified versions of Gnash are not obligated
// to grant this special exception for their modified versions; it is their
// choice whether to do so. The GNU General Public License gives permission
// to release a modified version without this exception; this exception
// also makes it possible to release a modified version which carries
// forward this exception.
// 
//

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "plugin.h"
#define MIME_TYPES_HANDLED  "application/x-shockwave-flash"
// The name must be this value to get flash movies that check the
// plugin version to load.
#define PLUGIN_NAME     "Shockwave Flash 8.0"
#define MIME_TYPES_DESCRIPTION  MIME_TYPES_HANDLED":swf:"PLUGIN_NAME
// PLUGIN_DESCRIPTION is inline in a function below, since it got very
// long, including copyright info and URLs and such.
#define PLUGIN_DESCRIPTION  SEE-BELOW-SEARCH-FOR-PLUGIN_DESCRIPTION

#include <GL/glx.h>
#include <GL/gl.h>
#include <GL/glu.h>
//#include <X11/extensions/xf86vmode.h>
#ifdef HAVE_GTK2
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#endif
#include <sys/param.h>
#ifdef USE_GTKGLEXT
#include <gtk/gtkgl.h>
#include <gdk/gdkx.h>
#endif
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/XKBlib.h>
#include <X11/keysym.h>
#include <X11/Sunkeysym.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <iostream>
#include <string>

#include "tu_file.h"
#include "tu_types.h"
//#include "player.h"
#include "xmlsocket.h"

// Mozilla SDK headers
#include "prinit.h"
#include "prlock.h"
#include "prcvar.h"
#include "prerr.h"
#include "prerror.h"
#include "prthread.h"

using namespace std;
using namespace gnash;

bool processing;

extern NPNetscapeFuncs NPNFuncs;

NPBool      plugInitialized = FALSE;
Display     *gxDisplay = NULL;
PRLock      *glMutex = NULL;
PRLock      *playerMutex = NULL;
PRCondVar   *playerCond = NULL;

// Static members. We have to share this data amongst all
//Display     *nsPluginInstance::gxDisplay = NULL;
//PRLock      *nsPluginInstance::_playerMutex = NULL;
//PRCondVar   *nsPluginInstance::_playerCond = NULL;
//SDL_cond    *nsPluginInstance::_gCond = NULL;
//SDL_mutex   *nsPluginInstance::_playerMutex = NULL;
//PRLock      *nsPluginInstance::_prlock = NULL;

#ifdef USE_GTK2
GtkWidget   *gtkplug = NULL;
GtkMenu     *popup_menu = NULL;
GtkMenuItem *menuitem_play = NULL;
GtkMenuItem *menuitem_pause = NULL;
#endif

// static int   streamfd = -1;
// static float s_scale = 1.0f;
// static bool  s_verbose = false;
// static int   doneYet = 0;
static bool  waitforgdb = false;

const int INBUFSIZE = 1024;
// static void xt_event_handler(Widget xtwidget, nsPluginInstance *plugin,
//               XEvent *xevent, Boolean *b);


#if 0
static int attributeList_noFSAA[] = { GLX_RGBA, GLX_DOUBLEBUFFER, 
GLX_STENCIL_SIZE, 1, None };
#else
static int attributeList_noFSAA[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None };
#endif
static int attributeList_FSAA[] = { GLX_RGBA, GLX_DOUBLEBUFFER, 
GLX_STENCIL_SIZE, 1, GLX_SAMPLE_BUFFERS_ARB, 1,GLX_SAMPLES_ARB, 1, None };

#ifdef HAVE_LIBXML
extern int xml_fd;              // FIXME: this is the file descriptor
                                // from XMLSocket::connect(). This
                                // needs to be propogated up through
                                // the layers properly, but first I
                                // want to make sure it all works.
#endif // HAVE_LIBXML

void
PR_CALLBACK Destructor(void *data)
{
    GNASH_REPORT_FUNCTION;

    /*
     * We don't actually free the storage since it's actually allocated
     * on the stack. Normally, this would not be the case and this is
     * the opportunity to free whatever.
    PR_Free(data);
     */
}  /* Destructor */


/// \brief Return the MIME Type description for this plugin.
char*
NPP_GetMIMEDescription(void)
{
    return(MIME_TYPES_DESCRIPTION);
}

//
// general initialization and shutdown
//

/// \brief Initialize the plugin
///
/// This C function gets called once when the plugin is loaded,
/// regardless of how many instantiations there is actually playing
/// movies. So this is where all the one time only initialization
/// stuff goes.
NPError
NS_PluginInitialize()
{
dbglogfile << "Initializing the plugin" << endl;
    GNASH_REPORT_FUNCTION;

    NPError err = NPERR_NO_ERROR;
    PRBool supportsXEmbed = PR_TRUE;
    NPNToolkitType toolkit;

    // This mutex is to lock the display before doing any OpenGL or
    // X11 function calls.
    glMutex = PR_NewLock();
    if (glMutex) {
        dbglogfile << "Allocated new GL Mutex" << endl;
    } else {
        dbglogfile << "ERROR: Couldn't allocate new GL Mutex!" << endl;
    }

#ifndef USE_FORK
    // This mutex is only used with the condition variable.
    playerMutex = PR_NewLock();
    if (playerMutex) {
        dbglogfile << "Allocated new X11 Mutex" << endl;
    } else {
        dbglogfile << "ERROR: Couldn't allocate new Player Mutex!" << endl;
    }

    // This is used to signal the player when it should start playing
    // a movie.
    playerCond = PR_NewCondVar(playerMutex);
    if (playerCond) {
        dbglogfile << "Allocated new condition variable" << endl;
    } else {
        dbglogfile << "ERROR: Couldn't allocate new Condition Variable!" << 
endl;
    }    
#endif // end of USE_FORK

    // Open a connection to the X11 server so we can lock the Display
    // when swapping GLX contexts.
    gxDisplay = XOpenDisplay(NULL);
    if (gxDisplay) {
        dbglogfile << "Opened connection to X11 server" << endl;
    } else {
        dbglogfile << "ERROR: Couldn't open a connection to the X11 server!" << 
endl;
    }
    
    dbglogfile.setVerbosity(2);

    // Make sure that the browser supports functionality we need
    err = CallNPN_GetValueProc(NPNFuncs.getvalue, NULL,
                               NPNVSupportsXEmbedBool,
                               (void *)&supportsXEmbed);

    if (err != NPERR_NO_ERROR || supportsXEmbed != PR_TRUE) {
        log_warning("No xEmbed support in this Mozilla version!");
        return NPERR_INCOMPATIBLE_VERSION_ERROR;
    } else {
        dbglogfile << "xEmbed supported in this Mozilla version" << endl;
    }

    err = CallNPN_GetValueProc(NPNFuncs.getvalue, NULL,
                               NPNVToolkit,
                               (void *)&toolkit);
    
    if (err != NPERR_NO_ERROR || toolkit != NPNVGtk2) {
        log_warning("No GTK2 support in this Mozilla version! Have %d",
                    (int)toolkit);
        return NPERR_INCOMPATIBLE_VERSION_ERROR;
    } else {
        dbglogfile << "Gtk2+ supported in this Mozilla version" << endl;
    }

    plugInitialized = TRUE;

    GNASH_REPORT_RETURN;
    
    return NPERR_NO_ERROR;
}

/// \brief Shutdown the plugin
///
/// This C function gets called once when the plugin is being
/// shutdown, regardless of how many instantiations actually are
/// playing movies. So this is where all the one time only
/// shutdown stuff goes.
void
NS_PluginShutdown()
{
        dbglogfile << "Entering PluginShutdown" << endl;
    GNASH_REPORT_FUNCTION;

    if (!plugInitialized) {
        dbglogfile << "Plugin already shut down" << endl;
        return;
    }

    if (glMutex) {
        PR_DestroyLock(glMutex);
        glMutex = NULL;
        dbglogfile << "Destroyed GL Mutex" << endl;
    }

#ifndef USE_FORK
    if (playerMutex) {
        PR_DestroyLock(playerMutex);
        playerMutex = NULL;
        dbglogfile << "Destroyed Player Mutex" << endl;
    }

    if (playerCond) {
        PR_DestroyCondVar(playerCond);
        playerCond = NULL;
        dbglogfile << "Destroyed Player condition variable" << endl;
    }
#endif // end of USE_FORK

    if (gxDisplay) {
        XCloseDisplay(gxDisplay);
        gxDisplay = NULL;
        dbglogfile << "Closed connection to X11 server" << endl;
    }

    GNASH_REPORT_RETURN;
    plugInitialized = FALSE;
}

// HTML description of Gnash, for display in URL "about:plugins" in the browser.
// PLUGIN_DESCRIPTION used to feed in here, but now it's just literal.
static const char description[] = 
"Gnash " VERSION ", the GNU Flash Player.  "
"Copyright &copy; 2006 "
"<a href=\"http://www.fsf.org\";>Free Software Foundation</a>, Inc.<br>"
"Gnash comes with NO WARRANTY, to the extent permitted by law.  "
"You may redistribute copies of Gnash under the terms of the "
"<a href=\"http://www.gnu.org/licenses/gpl.html\";>GNU "
"General Public License</a>, with an additional special exception allowing "
"linking with Mozilla, or any variant of Mozilla (such as Firefox), "
"so long as the linking is "
"through its standard plug-in interface.  For more information about Gnash, "
"see <a href=\"http://www.gnu.org/software/gnash/\";>"
"http://www.gnu.org/software/gnash</a>."
            ;

/// \brief Retrieve values from the plugin for the Browser
///
/// This C function is called by the browser to get certain
/// information is needs from the plugin. This information is the
/// plugin name, a description, etc...
NPError
NS_PluginGetValue(NPPVariable aVariable, void *aValue)
{
     dbglogfile << "Browser reads values from plugin " << endl;
    GNASH_REPORT_FUNCTION;
    
    NPError err = NPERR_NO_ERROR;
    
    switch (aVariable) {
      case NPPVpluginNameString:
dbglogfile << "Browser reads value NPPVpluginNameString" << PLUGIN_NAME << endl;
          *((char **)aValue) = PLUGIN_NAME;
          break;

      // This becomes the description field you see below the opening
      // text when you type about:plugins
      case NPPVpluginDescriptionString:
          *((char **)aValue) = (char *)description;
dbglogfile << "Browser reads value NPPVpluginDescriptionString " << description 
<< endl;
          break;

      case NPPVpluginNeedsXEmbed:
#ifdef HAVE_GTK2
          *((PRBool *)aValue) = PR_TRUE;
#else
          *((PRBool *)aValue) = PR_FALSE;
#endif
          break;
      case NPPVpluginTimerInterval:
      case NPPVpluginKeepLibraryInMemory:
      default:
          err = NPERR_INVALID_PARAM;
dbglogfile << "Invalid parameter" << endl;
          break;
    }
    GNASH_REPORT_RETURN;
    return err;
}

/// \brief construct our plugin instance object
///
/// This instantiates a new object via a C function used by the
/// browser.
nsPluginInstanceBase *
NS_NewPluginInstance(nsPluginCreateData * aCreateDataStruct)
{
dbglogfile << "Plugin: New instance" << endl;
    GNASH_REPORT_FUNCTION;
    
    if(!aCreateDataStruct)
        return NULL;

    nsPluginInstance * plugin = new 
nsPluginInstance(aCreateDataStruct->instance);
    
    GNASH_REPORT_RETURN;
    return plugin;
}

/// \brief destroy our plugin instance object
///
/// This destroys our instantiated object via a C function used by the
/// browser.
void
NS_DestroyPluginInstance(nsPluginInstanceBase * aPlugin)
{
    GNASH_REPORT_FUNCTION;

    if (aPlugin) {
        delete (nsPluginInstance *)aPlugin;
    }
    GNASH_REPORT_RETURN;
}

//
// nsPluginInstance class implementation
//

/// \brief Construct a new nsPluginInstance object
nsPluginInstance::nsPluginInstance(NPP aInstance) : nsPluginInstanceBase(),
                                                    mInstance(aInstance),
                                                    _window(0),
                                                    mXtwidget(0),
                                                    mFontInfo(0),
                                                    _glxContext(NULL),
                                                    _shutdown(FALSE),
                                                    _glInitialized(FALSE),
                                                    _thread(NULL),
                                                    _thread_key(0),
                                                    _childpid(0)
{
    GNASH_REPORT_FUNCTION;
}

/// \brief Destroy a nsPluginInstance object
nsPluginInstance::~nsPluginInstance()
{
    GNASH_REPORT_FUNCTION;
}

/// \brief Initialize an instance of the plugin object
/// 
/// This methods initializes the plugin object, and is called for
/// every movie that gets played. This is where the movie playing
/// specific initialization goes.
NPBool
nsPluginInstance::init(NPWindow* aWindow)
{
dbglogfile << "Initiating plugin object " << endl;
    log_trace("%s: enter for instance %p", __PRETTY_FUNCTION__, this);
    
    if(aWindow == NULL) {
        log_msg("%s: ERROR: Window handle was bogus!", __PRETTY_FUNCTION__);
        return FALSE;
    } else {
        log_msg("%s: X origin = %d, Y Origin = %d, Width = %d,"
               " Height = %d, WindowID = %p, this = %p",
                __FUNCTION__,
               aWindow->x, aWindow->y, aWindow->width, aWindow->height,
               aWindow->window, this);
    }

    // Only for developers. Make the plugin block here so we can
    // attach GDB to it.
    bool gdb = false;
    while (gdb) {
        dbglogfile << "Waiting for GDB for pid " << getpid() << endl;
        sleep(5);
    }
    
    return TRUE;
}

/// \brief Shutdown an instantiated object
///
/// This shuts down an object, and is called for every movie that gets
/// played. This is where the movie playing specific shutdown code
/// goes.
void
nsPluginInstance::shut()
{
    log_trace("%s: enter for instance %p", __PRETTY_FUNCTION__, this);    

#ifndef USE_FORK
    if (_thread) {
        dbglogfile << "Waiting for the thread to terminate..." << endl;
//      PRStatus rv = PR_SetThreadPrivate(_thread_key, (void *)"stop");
        _shutdown = TRUE;
//      PR_Interrupt(_thread);
//      if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) {
//          dbglogfile << "ERROR: Couldn't interupt thread!" << endl;
//      }
        
        PR_JoinThread(_thread);
        _thread = NULL;
    }
    destroyContext();
// end of USE_FORK
#endif
    kill(_childpid, SIGINT);
    _childpid = 0;
}

/// \brief Set the window to be used to render in
///
/// This sets up the window the plugin is supposed to render
/// into. This calls passes in various information used by the plugin
/// to setup the window. This may get called multiple times by each
/// instantiated object, so it can't do much but window specific
/// setup here.
NPError
nsPluginInstance::SetWindow(NPWindow* aWindow)
{
    log_trace("%s: enter for instance %p", __PRETTY_FUNCTION__, this);    
    
    if(aWindow == NULL) {
        dbglogfile << __FUNCTION__ << ": ERROR: Window handle was bogus!" << 
endl;
        return FALSE;
    } else {
        log_msg("%s: X origin = %d, Y Origin = %d, Width = %d,"
               " Height = %d, WindowID = %p, this = %p",
               __FUNCTION__,
               aWindow->x, aWindow->y, aWindow->width, aWindow->height,
               aWindow->window, this);
    }    
    
//     if (_glInitialized) {
//      log_msg("%s Already initialized...", __FUNCTION__);
//      return TRUE;
//     }
//    GdkNativeWindow window;
//    this->window = GdkNativeWindow(ptrdiff_t(window.window));

    
    if (aWindow->x == mX && aWindow->y == mY
        && aWindow->width == mWidth
        && aWindow->height == mHeight
        && (unsigned long)(aWindow->window) == _window) {
        return TRUE;
    }

    lockGL();
    lockX();
    mX = aWindow->x;
    mY = aWindow->y;
    mWidth = aWindow->width;
    mHeight = aWindow->height;
    
    if (_window == (Window) aWindow->window) {
        // The page with the plugin is being resized.
        // Save any UI information because the next time
        // around expect a SetWindow with a new window id.
        dbglogfile << __FUNCTION__ << "Error: Setwindow() called with same 
window handle - but resizing plugin unhandled!" << endl;
    } else {
        _window = (Window) aWindow->window;
        NPSetWindowCallbackStruct *ws_info =
            (NPSetWindowCallbackStruct *)aWindow->ws_info;
        mVisual = ws_info->visual;
        mDepth = ws_info->depth;
        mColormap = ws_info->colormap;
//        gxDisplay = ws_info->display;

        if (!mFontInfo) {
            if (!(mFontInfo = XLoadQueryFont(gxDisplay, "9x15"))) {
                dbglogfile << "ERROR: Cannot open 9X15 font!" << endl;
            }
        }
#if 1
        XVisualInfo *vi = glXChooseVisual(gxDisplay, DefaultScreen(gxDisplay),
                                          attributeList_FSAA);
        if (vi == NULL) {
            vi = glXChooseVisual(gxDisplay, DefaultScreen(gxDisplay),
                                 attributeList_noFSAA);
        } else {
            vi->visual = mVisual;
        }
#else
        XWindowAttributes a;
        XVisualInfo vi_in;
        int out_count;
        XGetWindowAttributes(gxDisplay, _window, &a);
        vi_in.visualid = XVisualIDFromVisual(a.visual);
        XVisualInfo *vi = XGetVisualInfo(gxDisplay,
                                         VisualScreenMask|VisualIDMask,
                                         &vi_in, &out_count);
#endif
        _glxContext = glXCreateContext(gxDisplay, vi, 0, GL_TRUE);
        if (_glxContext) {
            dbglogfile << __FUNCTION__ << ": Got new glxContext "
                       << (void *)_glxContext << endl;
            setGL();
            initGL();
            _glInitialized = TRUE;
        } else {
            dbglogfile << __FUNCTION__ << ": ERROR: Couldn't get new 
glxContext!" << endl;
        }

        // add xt event handler#
//         long event_mask = 
ExposureMask|KeyPress|KeyRelease|ButtonPress|ButtonRelease
//          Widget xtwidget;
        
//         xtwidget =  XtWindowToWidget((Display *) gxdisplay,
//                                      (Window) aWindow->window);
//         XtAddEventHandler(xtwidget, event_mask, FALSE,
//                           (XtEventHandler) xt_event_handler, this);
    }

    resizeWindow(mWidth,mHeight);

    unsetGL();
    freeX();
    freeGL();
    
    return NPERR_NO_ERROR;
}

// void NPN_Version(int * plugin_major,
//                  int * plugin_minor,
//                  int * mozilla_major,
//                  int * mozilla_minor)
// {
//     *plugin_major = NP_VERSION_MAJOR;
//     *plugin_minor = NP_VERSION_MINOR;
//     *mozilla_major = mozillaFuncs.version >> 8;
//     *mozilla_minor = mozillaFuncs.version & 0xff;
// }

const char *
nsPluginInstance::getVersion()
{
    GNASH_REPORT_FUNCTION;
    
    return NPN_UserAgent(mInstance);
}

NPError
nsPluginInstance::GetValue(NPPVariable aVariable, void *aValue)
{
    log_trace("%s: enter for instance %p", __PRETTY_FUNCTION__, this);    
    dbglogfile << "Initiating plugin object " << aVariable << aValue << endl;
    return NS_PluginGetValue(aVariable, aValue) ;
}

/// \brief Write a status message
///
/// This writes a status message to the status line at the bottom of
/// the browser window and the console firefox was started from.
NPError
nsPluginInstance::WriteStatus(char *msg) const
{
    NPN_Status(mInstance, msg);
    log_msg("%s", msg);

    return NPERR_NO_ERROR;
}

/// \brief Open a new data stream
///
/// Opens a new incoming data stream, which is the flash movie we want
/// to play.
/// A URL can be pretty ugly, like in this example:
/// 
http://www.shockwave.com/swf/navbar/navbar_sw.swf?atomfilms=http%3a//www.atomfilms.com/af/home/&shockwave=http%3a//www.shockwave.com&gameblast=http%3a//gameblast.shockwave.com/gb/gbHome.jsp&known=0
/// 
../flash/gui.swf?ip_addr=foobar.com&ip_port=3660&show_cursor=true&path_prefix=../flash/&trapallkeys=true"
///
/// So this is where we parse the URL to get all the options passed in
/// when invoking the plugin.
NPError
nsPluginInstance::NewStream(NPMIMEType type, NPStream * stream,
                            NPBool seekable, uint16 * stype)
{
    log_trace("%s: enter for instance %p", __PRETTY_FUNCTION__, this);    
    
    char tmp[300];
    memset(tmp, 0, 300);
    string url = stream->url;
    string fname, opts;
    size_t start, end, eq;
    bool dumpopts = false;

    log_msg("%s: this = %p, URL is %s", __FUNCTION__,
           (void *)this, stream->url);

    end   = url.find(".swf", 0) + 4;
    start = url.rfind("/", end) + 1;
    fname = "/tmp/";
    fname += url.substr(start, end - start);

    // extract the parameters from the URL
    start = url.find("?", end);
    end = url.size();
    if (start != string::npos) {
        opts = url.substr(start+1, end);
    }

    dbglogfile << __FUNCTION__ << ": The full URL is " << url << endl;
    while (opts.size() > 0) {
        start = 0;
        eq = opts.find("=", 0);
        if (opts[0] == '&') {
            start++;
        }
        end = opts.find("&", start);
        if (end <= 0) {
            end = opts.size();
        }
        if (eq == string::npos) {
            eq = opts.size();
        }
        string name = opts.substr(start, eq);
        string value = opts.substr(eq+1, end-eq-1);
        if (dumpopts) {
            dbglogfile << __FUNCTION__ << "Option " << name << " = "
                       << value << endl;
        }
        // Look for our special debug flags
        if (name == "debug") {
            dbglogfile << __FUNCTION__ << "Debug flag is " << value << endl;
            if (value == "waitforgdb") {
                waitforgdb = true;
            }
            if (value == "dumpopts") {
                dumpopts = true;
            }
        } else {
            _options[name] = value;
        }
        if ((opts.size() > end) && (opts[end] == '&')) {
                end++;
        }
        opts.erase(start, end);
    }
    
    //  log_msg("%s: URL is %s", __PRETTY_FUNCTION__, url.c_str());
    log_msg("%s: Open stream for %s, this = %p", __FUNCTION__,
           fname.c_str(), (void *)this);

    sprintf(tmp, "Loading Flash movie %s", fname.c_str());
    WriteStatus(tmp);
  
    _streamfd = open(fname.c_str(), O_CREAT | O_WRONLY, 
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
    if (_streamfd < 0) {
        sprintf(tmp,"%s can't be opened, check your permissions!\n", 
fname.c_str());
        WriteStatus(tmp);
        _streamfd = open(fname.c_str(), O_TRUNC | O_WRONLY, 
S_IRUSR|S_IRGRP|S_IROTH);
        if (_streamfd < 0) {
            sprintf(tmp,"%s can't be created, check your permissions!\n", 
fname.c_str());
            WriteStatus(tmp);
        }
    }

    _swf_file = fname;
    processing = true;

    return NPERR_NO_ERROR;
}

/// \brief Destroy the data stream we've been reading.
NPError
nsPluginInstance::DestroyStream(NPStream * stream, NPError reason)
{
    log_trace("%s: enter for instance %p", __PRETTY_FUNCTION__, this);    
    
    nsPluginInstance *arg = (nsPluginInstance *)this;
    char tmp[300];
    memset(tmp, 0, 300);
    sprintf(tmp, "Done Flash movie %s", _swf_file.c_str());
    WriteStatus(tmp);

    log_msg("%s: this = %p, URL is %s", __PRETTY_FUNCTION__,
           (void *)arg, stream->url);
    processing = false;

    if (_streamfd) {
        close(_streamfd);
        _streamfd = -1;
    }
    
    // Wait for GDB
    if (waitforgdb) {
        log_msg("Attach GDB to PID %d to debug!", getpid());
        log_msg("This thread will block until then!...");
        log_msg("Once blocked here, you can set other breakpoints.");
        log_msg("do a \"set variable waitforgdb=false\" to continue");
        while (waitforgdb) {
            sleep(1);
        }
    }

    log_msg("%s: Starting player Thread for this = %p",
           __PRETTY_FUNCTION__, (void *)this);

    // PR_USER_THREAD - PR_Cleanup blocks until the last thread of
    //                  type PR_USER_THREAD terminates.
    // PR_SYSTEM_THREAD - NSPR ignores threads of type
    // PR_SYSTEM_THREAD when determining when a call to PR_Cleanup
    // should return.
    //
    // PR_LOCAL_THREAD - A local thread, scheduled locally by NSPR
    // within the process.
    // PR_GLOBAL_THREAD - A global thread, scheduled by the host OS.
    // PR_GLOBAL_BOUND_THREAD - A global bound (kernel) thread,
    // scheduled by the host OS
#ifndef USE_FORK
    _thread = PR_CreateThread(PR_USER_THREAD, playerThread, this,
                              PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
                              PR_JOINABLE_THREAD, 0);
#else
#ifdef HAVE_GTK2
    Window window = GdkNativeWindow(ptrdiff_t(_window));
#else
    Window window = _window;
#endif
    _childpid = startProc(_swf_file.c_str(), window);
#endif

//     sprintf(tmp, "Started thread for Flash movie %s", _swf_file.c_str());
//     WriteStatus(tmp);

    return NPERR_NO_ERROR;
}

void
nsPluginInstance::URLNotify(const char *url, NPReason reason,
                            void *notifyData)
{
    log_trace("%s: enter for instance %p", __PRETTY_FUNCTION__, this);    
    
    log_msg("URL: %s\nReason %i", url, reason);
}

/// \brief Return how many bytes we can read into the buffer
int32
nsPluginInstance::WriteReady(NPStream * stream)
{
//   log_msg("%s(%d): Entering", __PRETTY_FUNCTION__, __LINE__);
//   log_msg("Stream for %s is ready", stream->url);

    return INBUFSIZE;
}

/// \brief Read the data stream from Mozilla/Firefox
///
/// For now we read the bytes and write them to a disk file.
int32
nsPluginInstance::Write(NPStream * stream, int32 offset, int32 len,
                        void *buffer)
{
//   log_msg("%s(%d): Entering", __PRETTY_FUNCTION__, __LINE__);
//   log_msg("Reading Stream %s, offset is %d, length = %d",
//          stream->url, offset, len);

    return write(_streamfd, buffer, len);
}

/// \brief Initialize OpenGL
///
void
nsPluginInstance::initGL()
{
    log_trace("%s: enter for instance %p", __PRETTY_FUNCTION__, this);    
    
    if (_glInitialized) {
        dbglogfile << __FUNCTION__ << ": OpenGL already initialized..."  << 
endl;
        return;
    }

    // Grab control of the display
//    lockDisplay();
    
    dbglogfile << __FUNCTION__ << ": Initializing OpenGL..." << endl;

    // Enable smooth shading 
    glShadeModel(GL_SMOOTH);
  
    // Set the background black 
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  
    // Depth buffer setup 
    glClearDepth(1.0f);
  
    // Enables Depth Testing 
    glEnable(GL_DEPTH_TEST);
  
    // The Type Of Depth Test To Do 
    glDepthFunc(GL_LEQUAL);

    // Really Nice Perspective Calculations 
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    if (_glxContext) {
        _glInitialized = TRUE;
    }
        
    // Release control of the display
//    freeDisplay();
}

/// \brief Shutdown OpenGL
void
nsPluginInstance::destroyContext()
{
    log_trace("%s: enter for instance %p", __PRETTY_FUNCTION__, this);    

    if (!_glInitialized) {
        dbglogfile << __FUNCTION__ << ": OpenGL already killed..." << endl;
        return;
    }

    if (gxDisplay && _glxContext) {
        // Grab control of the display
//      lockDisplay();
//      lockGL();
        lockX();
//      setGL();
        
        dbglogfile << __FUNCTION__ << ": Destroying GLX Context "
                   << (void *)_glxContext << endl;
        glXDestroyContext(gxDisplay, _glxContext);
        _glxContext = NULL;

//      freeDisplay();
        // Release control of the display
//      unsetGL();
        freeX();
//      freeGL();
    }
    _glInitialized = FALSE;
}

/// \brief Resize our viewport after a window resize event
int
nsPluginInstance::resizeWindow( int width, int height )
{
    log_trace("%s: enter for instance %p", __PRETTY_FUNCTION__, this);    

    log_msg("%s: Width = %d, Height = %d",  __FUNCTION__, width, height);

    if (!plugInitialized || !_glxContext) {
        dbglogfile << __FUNCTION__ << ": OpenGL not initialized..." << endl;
        return true;
    }

    // Grab control of the display
//     lockGL();
//     lockX();
//     setGL();
    
    // Height / width ration 
    GLfloat ratio;
  
    // Protect against a divide by zero 
    if (height == 0) {
        height = 1;
    }
  
    ratio = (GLfloat)width / (GLfloat)height;
  
    // Setup our viewport. 
    glViewport(0, 0, (GLint)width, (GLint)height);
  
    // change to the projection matrix and set our viewing volume. 
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
  
    // Set our perspective 
    gluPerspective(45.0f, ratio, 0.1f, 100.0f);
  
    // Make sure we're changing the model view and not the projection 
    glMatrixMode(GL_MODELVIEW);
  
    // Reset The View 
//    glLoadIdentity();
  
    // Release control of the display
//     unsetGL();
//     freeX();
//     freeGL();

    return(true);
}

/// \brief Draw a hardcoded image
///
/// This draws a hardcoded OpenGL graphic into the window, and is only
/// used for testing by developers.
void
nsPluginInstance::drawTestScene( void )
{
    log_trace("%s: enter for instance %p", __PRETTY_FUNCTION__, this);    

    // Grab control of the display
    lockDisplay();
    
    dbglogfile << __FUNCTION__ << ": Drawing graphic..." << endl;

    // Clear The Screen And The Depth Buffer
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    // Move Left 1.5 Units And Into The Screen 6.0
    glLoadIdentity();
    glTranslatef( -1.5f, 0.0f, -6.0f );

    glColor3f(1.0f,1.0f,1.0f);
    
    glBegin( GL_TRIANGLES );            // Drawing Using Triangles
      glVertex3f(  0.0f,  1.0f, 0.0f ); // Top
      glVertex3f( -1.0f, -1.0f, 0.0f ); // Botom Left
      glVertex3f(  1.0f, -1.0f, 0.0f ); // Bottom Rigt
    glEnd( );                           // Finished Drawing The Triangle
    
    /* Move Right 3 Units */
    glTranslatef( 3.0f, 0.0f, 0.0f );
    
    glBegin( GL_QUADS );                // Draw A Quad
      glVertex3f( -1.0f,  1.0f, 0.0f ); // Top Left
      glVertex3f(  1.0f,  1.0f, 0.0f ); // Top Right
      glVertex3f(  1.0f, -1.0f, 0.0f ); // Bottom Right
      glVertex3f( -1.0f, -1.0f, 0.0f ); // Bottom Left
    glEnd();                   // Done Drawing The Quad

    swapBuffers();
    
    // Release control of the display
    freeDisplay();
//    SDL_mutexP(mutant);
}


int
nsPluginInstance::startProc(string filespec)
{
    return startProc(filespec, _window);
}

int
nsPluginInstance::startProc(string filespec, Window win)
{
    GNASH_REPORT_FUNCTION;
    
    struct stat procstats;
    int ret = 0;
    
    char *gnash_env = getenv("GNASH_PLAYER");
    if (!gnash_env) {
        _procname = PREFIX;
        _procname += "/bin/gnash"; 
    } else {
        _procname = gnash_env; 
    }
    
    // See if the file actually exists, otherwise we can't spawn it
    if (stat(_procname.c_str(), &procstats) == -1) {
        dbglogfile << "Invalid filename: " << _procname << endl;
        return -1;
    }
    
    _childpid = fork();
    // childpid is -1, if the fork failed, so print out an error message
    if (_childpid == -1) {
        perror(strerror(errno));
        return -1;
    }
    // childpid is a positive integer, if we are the parent, and
    // fork() worked
    if (_childpid > 0) {
        dbglogfile << "Forked sucessfully, child process PID is " << _childpid 
<< endl;
        return _childpid;
    }
        
    // setup the command line
    char num[30];
    memset(num, 0, 30);
    sprintf(num, "%ld", win);
    char num2[30];
    memset(num2, 0, 30);
    sprintf(num2, "%d", mWidth);
    char num3[30];
    memset(num3, 0, 30);
    sprintf(num3, "%d", mHeight);
    
//     cmd_line[0] = new char(procname.size()+1);
//     strcpy(cmd_line[0], procname.c_str());
//     cmd_line[1] = new char(50);
//     sprintf(cmd_line[1], "-x %d", (int)win);
//     cmd_line[2] = new char(50);
//     sprintf(cmd_line[2], "-v");
//     cmd_line[3] = new char(filespec.size()+1);
//     sprintf(cmd_line[3], "%s", filespec.c_str());
    // This option tells the child process to wait for GDB to connect.

    // This option tells the child process to wait for GDB to connect.
    if (waitforgdb) {
//         cmd_line[4] = new char(4);
//         strcpy(cmd_line[4], "-s");
    }
    char *argv[] = {
        (char *)_procname.c_str(),
        "-x", num,
        (char *)filespec.c_str(),
        "-j", num2,
        "-k", num3,
        0
    };
    
    // If we are the child, exec the new process, then go away
    if (_childpid == 0) {
        // Start the desired executable
        dbglogfile << "Starting " << _procname << " with -x "
                   << (int)win << " " << filespec << endl;
        ret = execv(argv[0], argv);
        perror(strerror(ret));
        exit(ret);
    }
    
    return _childpid;
}

// Local Variables:
// mode: C++
// indent-tabs-mode: t
// End:

reply via email to

[Prev in Thread] Current Thread [Next in Thread]