diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index 652cf04ce6..3871dfa622 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/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(); } diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index 149adfe43c..c4e661aa32 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/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(); diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index 5249dbde49..77067b7150 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/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); diff --git a/direct/src/plugin/p3dInstanceManager.h b/direct/src/plugin/p3dInstanceManager.h index edf6f63556..5e375500ab 100644 --- a/direct/src/plugin/p3dInstanceManager.h +++ b/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); diff --git a/direct/src/plugin/p3d_plugin.cxx b/direct/src/plugin/p3d_plugin.cxx index 81ef9faa66..cb4e239641 100644 --- a/direct/src/plugin/p3d_plugin.cxx +++ b/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; } diff --git a/direct/src/plugin/p3d_plugin.h b/direct/src/plugin/p3d_plugin.h index dc2bc5faa0..83dc2059d0 100644 --- a/direct/src/plugin/p3d_plugin.h +++ b/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); diff --git a/direct/src/plugin_npapi/Sources.pp b/direct/src/plugin_npapi/Sources.pp index e86e40f7b6..c45fe5fa1c 100644 --- a/direct/src/plugin_npapi/Sources.pp +++ b/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. diff --git a/direct/src/plugin_npapi/ppDownloadRequest.I b/direct/src/plugin_npapi/ppDownloadRequest.I index 662da114f0..2ac0da3b5c 100644 --- a/direct/src/plugin_npapi/ppDownloadRequest.I +++ b/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) { } diff --git a/direct/src/plugin_npapi/ppDownloadRequest.cxx b/direct/src/plugin_npapi/ppDownloadRequest.cxx index e7e4b60d97..8b64e4fd62 100644 --- a/direct/src/plugin_npapi/ppDownloadRequest.cxx +++ b/direct/src/plugin_npapi/ppDownloadRequest.cxx @@ -13,3 +13,4 @@ //////////////////////////////////////////////////////////////////// #include "ppDownloadRequest.h" + diff --git a/direct/src/plugin_npapi/ppDownloadRequest.h b/direct/src/plugin_npapi/ppDownloadRequest.h index d2e8a96888..0886cdfc4f 100644 --- a/direct/src/plugin_npapi/ppDownloadRequest.h +++ b/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" diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx index 408c0a0dab..fc9909c104 100644 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ b/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); } diff --git a/direct/src/plugin_npapi/ppInstance.h b/direct/src/plugin_npapi/ppInstance.h index bf491ba7cd..387f080413 100644 --- a/direct/src/plugin_npapi/ppInstance.h +++ b/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" diff --git a/direct/src/plugin_npapi/startup.cxx b/direct/src/plugin_npapi/startup.cxx index 4039c7e4f1..dda0f0b997 100644 --- a/direct/src/plugin_npapi/startup.cxx +++ b/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 @@ -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); } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/plugin_npapi/startup.h b/direct/src/plugin_npapi/startup.h index d212b43b13..d08eec1ddf 100644 --- a/direct/src/plugin_npapi/startup.h +++ b/direct/src/plugin_npapi/startup.h @@ -29,4 +29,6 @@ extern "C" { NPError OSCALL NP_Shutdown(void); } +void request_ready(P3D_instance *instance); + #endif diff --git a/direct/src/plugin_standalone/panda3d.cxx b/direct/src/plugin_standalone/panda3d.cxx index 41fa89a007..8ab6182fd8 100644 --- a/direct/src/plugin_standalone/panda3d.cxx +++ b/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);