浏览代码

it continues

David Rose 16 年之前
父节点
当前提交
8a48e4593e

+ 17 - 2
direct/src/plugin/p3dInstance.cxx

@@ -29,12 +29,15 @@ int P3DInstance::_next_instance_id = 0;
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 P3DInstance::
-P3DInstance(P3D_request_ready_func *func,
+P3DInstance(P3D_request_ready_func *func, void *user_data,
             const string &p3d_filename, 
             const P3D_token tokens[], size_t num_tokens) :
   _func(func),
   _fparams(p3d_filename, tokens, num_tokens)
 {
+  _user_data = user_data;
+  _request_pending = false;
+
   _instance_id = _next_instance_id;
   ++_next_instance_id;
 
@@ -169,9 +172,13 @@ P3D_request *P3DInstance::
 get_request() {
   P3D_request *result = NULL;
   ACQUIRE_LOCK(_request_lock);
+  nout << "P3DInstance::get_request() called on " << this
+       << ", " << _pending_requests.size() << " requests in queue\n";
   if (!_pending_requests.empty()) {
     result = _pending_requests.front();
+    nout << "popped request " << result << "\n";
     _pending_requests.pop_front();
+    _request_pending = !_pending_requests.empty();
   }
   RELEASE_LOCK(_request_lock);
 
@@ -186,13 +193,21 @@ get_request() {
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 add_request(P3D_request *request) {
-  nout << "adding a request\n";
+  nout << "adding request " << request << " in " << this << "\n";
   assert(request->_instance == this);
 
   ACQUIRE_LOCK(_request_lock);
   _pending_requests.push_back(request);
+  _request_pending = true;
   RELEASE_LOCK(_request_lock);
 
+  // Asynchronous notification for anyone who cares.
+  nout << "request_ready, calling " << _func << "\n" << flush;
+  if (_func != NULL) {
+    _func(this);
+  }
+
+  // Synchronous notification for pollers.
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   inst_mgr->signal_request_ready();
 }

+ 1 - 1
direct/src/plugin/p3dInstance.h

@@ -35,7 +35,7 @@ class P3DPackage;
 ////////////////////////////////////////////////////////////////////
 class P3DInstance : public P3D_instance {
 public:
-  P3DInstance(P3D_request_ready_func *func,
+  P3DInstance(P3D_request_ready_func *func, void *user_data,
               const string &p3d_filename, 
               const P3D_token tokens[], size_t num_tokens);
   ~P3DInstance();

+ 2 - 1
direct/src/plugin/p3dInstanceManager.cxx

@@ -112,9 +112,10 @@ initialize() {
 ////////////////////////////////////////////////////////////////////
 P3DInstance *P3DInstanceManager::
 create_instance(P3D_request_ready_func *func,
+                void *user_data,
                 const string &p3d_filename, 
                 const P3D_token tokens[], size_t num_tokens) {
-  P3DInstance *inst = new P3DInstance(func, p3d_filename, 
+  P3DInstance *inst = new P3DInstance(func, user_data, p3d_filename, 
                                       tokens, num_tokens);
   _instances.insert(inst);
 

+ 1 - 0
direct/src/plugin/p3dInstanceManager.h

@@ -45,6 +45,7 @@ public:
 
   P3DInstance *
   create_instance(P3D_request_ready_func *func,
+                  void *user_data,
                   const string &p3d_filename, 
                   const P3D_token tokens[], size_t num_tokens);
 

+ 9 - 3
direct/src/plugin/p3d_plugin.cxx

@@ -70,6 +70,7 @@ P3D_free_string(char *string) {
 
 P3D_instance *
 P3D_create_instance(P3D_request_ready_func *func,
+                    void *user_data,
                     const char *p3d_filename, 
                     const P3D_token tokens[], size_t num_tokens) {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
@@ -80,7 +81,7 @@ P3D_create_instance(P3D_request_ready_func *func,
   }
 
   P3DInstance *result = 
-    inst_mgr->create_instance(func, p3d_filename, tokens, num_tokens);
+    inst_mgr->create_instance(func, user_data, p3d_filename, tokens, num_tokens);
   RELEASE_LOCK(_lock);
   return result;
 }
@@ -148,7 +149,9 @@ P3D_request *
 P3D_instance_get_request(P3D_instance *instance) {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_lock);
+  nout << "P3D_instance_get_request(" << instance << ")\n";
   P3D_request *result = ((P3DInstance *)instance)->get_request();
+  nout << "  result = " << result << "\n" << flush;
   RELEASE_LOCK(_lock);
   return result;
 }
@@ -160,6 +163,8 @@ P3D_check_request(bool wait) {
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   P3D_instance *inst = inst_mgr->check_request();
 
+  nout << "P3D_instance_check_request, inst = " << inst << "\n";
+
   if (inst != NULL || !wait) {
     RELEASE_LOCK(_lock);
     return inst;
@@ -192,13 +197,14 @@ P3D_instance_feed_url_stream(P3D_instance *instance, int unique_id,
                              P3D_result_code result_code,
                              int http_status_code, 
                              size_t total_expected_data,
-                             const unsigned char *this_data, 
+                             const void *this_data, 
                              size_t this_data_size) {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_lock);
   bool result = ((P3DInstance *)instance)->
     feed_url_stream(unique_id, result_code, http_status_code,
-                    total_expected_data, this_data, this_data_size);
+                    total_expected_data, 
+                    (const unsigned char *)this_data, this_data_size);
   RELEASE_LOCK(_lock);
   return result;
 }

+ 15 - 3
direct/src/plugin/p3d_plugin.h

@@ -111,11 +111,16 @@ P3D_free_string_func(char *string);
    instances operate generally independently of each other. */
 
 /* This structure defines the handle to a single instance.  The host
-   may access the _request_pending member, which will be true if the
-   host should call P3D_instance_get_request(). */
+   may access any members appearing here. */
 typedef struct {
+  /* true if the host should call P3D_instance_get_request().*/
   bool _request_pending;
 
+  /* an opaque pointer the host may use to store private data that the
+     plugin does not interpret.  This pointer can be directly set, or
+     it can be initialized in the P3D_create_instance() call. */
+  void *_user_data;
+
   /* Additional opaque data may be stored here. */
 } P3D_instance;
 
@@ -199,6 +204,12 @@ typedef struct {
    instance.  If this is empty or NULL, the "src" token (below) will
    be downloaded instead.
 
+   The user_data pointer is any arbitrary pointer value; it will be
+   copied into the _user_data member of the new P3D_instance object.
+   This pointer is intended for the host to use to store private data
+   associated with each instance; the plugin will not do anything with
+   this data.
+
    For tokens, pass an array of P3D_token elements (above), which
    correspond to the user-supplied keyword/value pairs that may appear
    in the embed token within the HTML syntax; the host is responsible
@@ -222,6 +233,7 @@ typedef struct {
 
 typedef P3D_instance *
 P3D_create_instance_func(P3D_request_ready_func *func,
+                         void *user_data,
                          const char *p3d_filename, 
                          const P3D_token tokens[], size_t num_tokens);
 
@@ -446,7 +458,7 @@ P3D_instance_feed_url_stream_func(P3D_instance *instance, int unique_id,
                                   P3D_result_code result_code,
                                   int http_status_code, 
                                   size_t total_expected_data,
-                                  const unsigned char *this_data, 
+                                  const void *this_data, 
                                   size_t this_data_size);
 
 

+ 1 - 0
direct/src/plugin_npapi/Sources.pp

@@ -30,6 +30,7 @@
   #if $[WINDOWS_PLATFORM]
     #define WIN_RESOURCE_FILE nppanda3d.rc
     #define LINKER_DEF_FILE nppanda3d.def
+    #define WIN_SYS_LIBS user32.lib
   #endif
 
   // Mac-specific options.

+ 2 - 1
direct/src/plugin_npapi/ppDownloadRequest.I

@@ -21,7 +21,8 @@
 inline PPDownloadRequest::
 PPDownloadRequest(RequestType rtype, int user_id) :
   _rtype(rtype),
-  _user_id(user_id)
+  _user_id(user_id),
+  _notified_done(false)
 {
 }
 

+ 1 - 0
direct/src/plugin_npapi/ppDownloadRequest.cxx

@@ -13,3 +13,4 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "ppDownloadRequest.h"
+

+ 4 - 0
direct/src/plugin_npapi/ppDownloadRequest.h

@@ -36,6 +36,10 @@ public:
 public:
   RequestType _rtype;
   int _user_id;
+
+  // This is sent true when we have notified the plugin that the
+  // stream is done.
+  bool _notified_done;
 };
 
 #include "ppDownloadRequest.I"

+ 159 - 11
direct/src/plugin_npapi/ppInstance.cxx

@@ -13,6 +13,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "ppInstance.h"
+#include "startup.h"
 #include "p3d_plugin_config.h"
 
 ////////////////////////////////////////////////////////////////////
@@ -27,7 +28,7 @@ PPInstance::
 PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode, 
            int16 argc, char *argn[], char *argv[], NPSavedData *saved) {
   logfile << "constructing " << this << "\n" << flush;
-  _inst = NULL;
+  _p3d_inst = NULL;
 
   _npp_instance = instance;
   _npp_mode = mode;
@@ -69,9 +70,9 @@ PPInstance::
   logfile
     << "destructing " << this << "\n" << flush;
 
-  if (_inst != NULL) {
-    P3D_instance_finish(_inst);
-    _inst = NULL;
+  if (_p3d_inst != NULL) {
+    P3D_instance_finish(_p3d_inst);
+    _p3d_inst = NULL;
   }
 
   // Free the tokens we allocated.
@@ -101,7 +102,7 @@ set_window(NPWindow *window) {
   _window = *window;
   _got_window = true;
   
-  if (_inst == NULL) {
+  if (_p3d_inst == NULL) {
     create_instance();
   } else {
     send_window();
@@ -139,6 +140,12 @@ new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16 *stype) {
     *stype = NP_ASFILEONLY;
     return NPERR_NO_ERROR;
 
+  case PPDownloadRequest::RT_user:
+    // This is a request from the plugin.  We'll receive this as a
+    // stream.
+    *stype = NP_NORMAL;
+    return NPERR_NO_ERROR;
+
   default:
     // Don't know what this is.
     logfile << "Unexpected request " << (int)req->_rtype << "\n";
@@ -147,6 +154,35 @@ new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16 *stype) {
   return NPERR_GENERIC_ERROR;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::write_stream
+//       Access: Public
+//  Description: Called by the browser to feed data read from a URL or
+//               whatever.
+////////////////////////////////////////////////////////////////////
+int PPInstance::
+write_stream(NPStream *stream, int offset, int len, void *buffer) {
+  if (stream->notifyData == NULL) {
+    logfile << "Unexpected write_stream on " << stream->url << "\n";
+    return 0;
+  }
+
+  PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
+  switch (req->_rtype) {
+  case PPDownloadRequest::RT_user:
+    P3D_instance_feed_url_stream(_p3d_inst, req->_user_id,
+                                 P3D_RC_in_progress, 0,
+                                 stream->end, buffer, len);
+    return len;
+    
+  default:
+    logfile << "Unexpected write_stream on " << stream->url << "\n";
+    break;
+  }
+
+  return 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PPInstance::destroy_stream
 //       Access: Public
@@ -156,6 +192,37 @@ new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16 *stype) {
 ////////////////////////////////////////////////////////////////////
 NPError PPInstance::
 destroy_stream(NPStream *stream, NPReason reason) {
+  if (stream->notifyData == NULL) {
+    logfile << "Unexpected destroy_stream on " << stream->url << "\n";
+    return NPERR_GENERIC_ERROR;
+  }
+
+  PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
+  switch (req->_rtype) {
+  case PPDownloadRequest::RT_user:
+    {
+      P3D_result_code result_code = P3D_RC_done;
+      if (reason != NPRES_DONE) {
+        result_code = P3D_RC_generic_error;
+      }
+      assert(!req->_notified_done);
+      P3D_instance_feed_url_stream(_p3d_inst, req->_user_id,
+                                   result_code, 0, stream->end, NULL, 0);
+      req->_notified_done = true;
+    }
+    break;
+
+  case PPDownloadRequest::RT_core_dll:
+    // This is the one case we don't start with GetUrlNotify, so we'll
+    // never get a url_notify call on this one.  So, we have to delete
+    // the PPDownloadRequest object here.
+    delete req;
+    break;
+
+  default:
+    break;
+  }
+  
   return NPERR_NO_ERROR;
 }
 
@@ -169,6 +236,36 @@ destroy_stream(NPStream *stream, NPReason reason) {
 ////////////////////////////////////////////////////////////////////
 void PPInstance::
 url_notify(const char *url, NPReason reason, void *notifyData) {
+  if (notifyData == NULL) {
+    return;
+  }
+  
+  PPDownloadRequest *req = (PPDownloadRequest *)notifyData;
+  switch (req->_rtype) {
+  case PPDownloadRequest::RT_user:
+    if (!req->_notified_done) {
+      // We shouldn't have gotten here without notifying the stream
+      // unless the stream never got started (and hence we never
+      // called destroy_stream().
+      logfile << "Failure starting stream\n" << flush;
+      assert(reason != NPRES_DONE);
+
+      P3D_instance_feed_url_stream(_p3d_inst, req->_user_id,
+                                   P3D_RC_generic_error, 0, 0, NULL, 0);
+      req->_notified_done = true;
+    }
+    break;
+
+  case PPDownloadRequest::RT_core_dll:
+    // Shouldn't be possible to get here.
+    assert(false);
+    break;
+    
+  default:
+    break;
+  }
+  
+  delete req;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -189,6 +286,8 @@ stream_as_file(NPStream *stream, const char *fname) {
   // Safari seems to want to report the filename in the old-style form
   // "Macintosh HD:blah:blah:blah" instead of the new-style form
   // "/blah/blah/blah".  How annoying.
+
+  // TODO: Is "Macintosh HD:" the only possible prefix?
   if (filename.substr(0, 13) == "Macintosh HD:") {
     string fname2;
     for (size_t p = 12; p < filename.size(); ++p) {
@@ -212,6 +311,7 @@ stream_as_file(NPStream *stream, const char *fname) {
     logfile << "got plugin\n";
     if (!load_plugin(filename)) {
       logfile << "Unable to launch core API.\n";
+      break;
     }
     create_instance();
     break;
@@ -230,6 +330,54 @@ stream_as_file(NPStream *stream, const char *fname) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::handle_request
+//       Access: Public
+//  Description: Handles a request from the plugin, forwarding
+//               it to the browser as appropriate.
+////////////////////////////////////////////////////////////////////
+void PPInstance::
+handle_request(P3D_request *request) {
+  logfile << "handle_request: " << request << "\n";
+  assert(request->_instance == _p3d_inst);
+
+  bool handled = false;
+
+  switch (request->_request_type) {
+  case P3D_RT_stop:
+    logfile << "Got P3D_RT_stop\n";
+    if (_p3d_inst != NULL) {
+      P3D_instance_finish(_p3d_inst);
+      _p3d_inst = NULL;
+    }
+    // Guess the browser doesn't really care.
+    handled = true;
+    break;
+
+  case P3D_RT_get_url:
+    {
+      logfile << "Got P3D_RT_get_url: " << request->_request._get_url._url
+              << "\n";
+      
+      PPDownloadRequest *req = 
+        new PPDownloadRequest(PPDownloadRequest::RT_user, 
+                              request->_request._get_url._unique_id);
+      browser->geturlnotify(_npp_instance, request->_request._get_url._url,
+                            NULL, req);
+    }
+    
+    break;
+
+  default:
+    // Some request types are not handled.
+    logfile << "Unhandled request: " << request->_request_type << "\n";
+    break;
+  };
+
+  P3D_request_finish(request, handled);
+}
+
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PPInstance::create_instance
 //       Access: Private
@@ -238,7 +386,7 @@ stream_as_file(NPStream *stream, const char *fname) {
 ////////////////////////////////////////////////////////////////////
 void PPInstance::
 create_instance() {
-  if (_inst != NULL) {
+  if (_p3d_inst != NULL) {
     // Already created.
     return;
   }
@@ -263,10 +411,10 @@ create_instance() {
     tokens = &_tokens[0];
   }
 
-  _inst = P3D_create_instance
-    (NULL, _p3d_filename.c_str(), tokens, _tokens.size());
+  _p3d_inst = P3D_create_instance
+    (request_ready, this, _p3d_filename.c_str(), tokens, _tokens.size());
 
-  if (_inst != NULL) {
+  if (_p3d_inst != NULL) {
     send_window();
   }
 }
@@ -280,7 +428,7 @@ create_instance() {
 ////////////////////////////////////////////////////////////////////
 void PPInstance::
 send_window() {
-  assert(_inst != NULL);
+  assert(_p3d_inst != NULL);
 
   P3D_window_handle parent_window;
 #ifdef _WIN32
@@ -288,7 +436,7 @@ send_window() {
 #endif
 
   P3D_instance_setup_window
-    (_inst, P3D_WT_embedded,
+    (_p3d_inst, P3D_WT_toplevel,
      _window.x, _window.y, _window.width, _window.height,
      parent_window);
 }

+ 4 - 1
direct/src/plugin_npapi/ppInstance.h

@@ -35,10 +35,13 @@ public:
   void set_window(NPWindow *window);
   NPError new_stream(NPMIMEType type, NPStream *stream, 
                      bool seekable, uint16 *stype);
+  int write_stream(NPStream *stream, int offset, int len, void *buffer);
   NPError destroy_stream(NPStream *stream, NPReason reason);
   void url_notify(const char *url, NPReason reason, void *notifyData);
   void stream_as_file(NPStream *stream, const char *fname);
 
+  void handle_request(P3D_request *request);
+
 private:
   void create_instance();
   void send_window();
@@ -56,7 +59,7 @@ private:
   bool _got_window;
   NPWindow _window;
 
-  P3D_instance *_inst;
+  P3D_instance *_p3d_inst;
 };
 
 #include "ppInstance.I"

+ 105 - 4
direct/src/plugin_npapi/startup.cxx

@@ -14,6 +14,7 @@
 
 #include "startup.h"
 #include "p3d_plugin_config.h"
+#include "p3d_lock.h"
 
 #ifdef _WIN32
 #include <malloc.h>
@@ -31,7 +32,85 @@ open_logfile() {
     logfile_is_open = true;
   }
 }
-  
+
+#ifdef _WIN32
+UINT _timer = 0;
+#endif
+LOCK _timer_lock;
+
+////////////////////////////////////////////////////////////////////
+//     Function: handle_request_loop
+//  Description: Checks for any new requests from the plugin.  This
+//               function is called only in the main thread.
+////////////////////////////////////////////////////////////////////
+static void
+handle_request_loop() {
+  assert(is_plugin_loaded());
+
+  P3D_instance *p3d_inst = P3D_check_request(false);
+  logfile << "P3D_check_request() returns " << p3d_inst << "\n" << flush;
+  while (p3d_inst != (P3D_instance *)NULL) {
+    P3D_request *request = P3D_instance_get_request(p3d_inst);
+    logfile << "got request " << request << "\n";
+    if (request != (P3D_request *)NULL) {
+      PPInstance *inst = (PPInstance *)(p3d_inst->_user_data);
+      assert(inst != NULL);
+      inst->handle_request(request);
+    }
+    p3d_inst = P3D_check_request(false);
+    logfile << "P3D_check_request() returns " << p3d_inst << "\n" << flush;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: win_timer_func
+//  Description: The Windows flavor of the timer callback function.
+////////////////////////////////////////////////////////////////////
+#ifdef _WIN32
+static VOID CALLBACK
+win_timer_func(HWND hwnd, UINT msg, UINT_PTR event, DWORD time) {
+  ACQUIRE_LOCK(_timer_lock);
+  logfile
+    << "win_timer_func " << hwnd << ", " << msg << ", " << event
+    << ", " << time << "\n"
+    << "timer thread = " << GetCurrentThreadId() << "\n"
+    << flush;
+  KillTimer(NULL, _timer);
+  _timer = 0;
+  RELEASE_LOCK(_timer_lock);
+
+  handle_request_loop();
+}
+#endif // _WIN32
+
+////////////////////////////////////////////////////////////////////
+//     Function: request_ready
+//  Description: This function is attached as an asyncronous callback
+//               to each instance; it will be notified when the
+//               instance has a request ready.  This function may be
+//               called in a sub-thread.
+////////////////////////////////////////////////////////////////////
+void
+request_ready(P3D_instance *instance) {
+  logfile
+    << "request_ready"
+    //    << " thread = " << GetCurrentThreadId()
+    << "\n" << flush;
+
+  // Since we might be in a sub-thread at this point, use a timer to
+  // forward this event to the main thread.
+
+  ACQUIRE_LOCK(_timer_lock);
+#ifdef _WIN32
+  if (_timer == 0) {
+    _timer = SetTimer(NULL, 0, 0, win_timer_func);
+    logfile << "_timer = " << _timer << "\n" << flush;
+  }
+#endif
+  RELEASE_LOCK(_timer_lock);
+}
+
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NP_Initialize
 //  Description: This function is called (almost) before any other
@@ -56,9 +135,12 @@ NP_Initialize(NPNetscapeFuncs *browserFuncs,
 
   open_logfile();
   logfile << "initializing\n" << flush;
+  //  logfile << "main thread = " << GetCurrentThreadId() << "\n";
 
   logfile << "browserFuncs = " << browserFuncs << "\n" << flush;
 
+  INIT_LOCK(_timer_lock);
+
   /*
 #ifdef _WIN32
   string plugin_location = "c:/cygwin/home/drose/player/direct/built/lib/p3d_plugin.dll";
@@ -116,6 +198,17 @@ NP_GetEntryPoints(NPPluginFuncs *pluginFuncs) {
 NPError OSCALL
 NP_Shutdown(void) {
   logfile << "shutdown\n" << flush;
+
+  ACQUIRE_LOCK(_timer_lock);
+#ifdef _WIN32
+  if (_timer != 0) {
+    KillTimer(NULL, _timer);
+    _timer = 0;
+  }
+#endif
+  RELEASE_LOCK(_timer_lock);
+  DESTROY_LOCK(_timer_lock);
+
   unload_plugin();
 
   // Not clear whether there's a return value or not.  Some versions
@@ -224,7 +317,10 @@ NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) {
 int32
 NPP_WriteReady(NPP instance, NPStream *stream) {
   logfile << "WriteReady\n";
-  return 0;
+  // We're supposed to return the maximum amount of data the plugin is
+  // prepared to handle.  Gee, I don't know.  As much as you can give
+  // me, I guess.
+  return 0x7fffffff;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -236,8 +332,13 @@ NPP_WriteReady(NPP instance, NPStream *stream) {
 int32
 NPP_Write(NPP instance, NPStream *stream, int32 offset, 
           int32 len, void *buffer) {
-  logfile << "Write\n";
-  return 0;
+  logfile << "Write " << stream->url 
+          << ", " << len << "\n" << flush;
+
+  PPInstance *inst = (PPInstance *)(instance->pdata);
+  assert(inst != NULL);
+
+  return inst->write_stream(stream, offset, len, buffer);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 0
direct/src/plugin_npapi/startup.h

@@ -29,4 +29,6 @@ extern "C" {
   NPError OSCALL NP_Shutdown(void);
 }
 
+void request_ready(P3D_instance *instance);
+
 #endif

+ 1 - 1
direct/src/plugin_standalone/panda3d.cxx

@@ -262,7 +262,7 @@ create_instance(const string &arg, P3D_window_type window_type,
   } 
 
   P3D_instance *inst = P3D_create_instance
-    (NULL, os_p3d_filename.c_str(), tokens, num_tokens);
+    (NULL, NULL, os_p3d_filename.c_str(), tokens, num_tokens);
 
   P3D_instance_setup_window
     (inst, window_type, win_x, win_y, win_width, win_height, parent_window);