mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
onPluginFail
This commit is contained in:
parent
d60e61993e
commit
f5e2e89d18
@ -38,6 +38,7 @@ extern ostream *nout_stream;
|
|||||||
#define nout (*nout_stream)
|
#define nout (*nout_stream)
|
||||||
|
|
||||||
extern string global_root_dir;
|
extern string global_root_dir;
|
||||||
|
extern bool has_plugin_thread_async_call;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "p3d_plugin_config.h"
|
#include "p3d_plugin_config.h"
|
||||||
#include "find_root_dir.h"
|
#include "find_root_dir.h"
|
||||||
#include "mkdir_complete.h"
|
#include "mkdir_complete.h"
|
||||||
|
#include "nppanda3d_common.h"
|
||||||
|
|
||||||
// We can include this header file to get the DTOOL_PLATFORM
|
// We can include this header file to get the DTOOL_PLATFORM
|
||||||
// definition, even though we don't link with dtool.
|
// definition, even though we don't link with dtool.
|
||||||
@ -53,6 +54,7 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16_t mode,
|
|||||||
_npp_instance = instance;
|
_npp_instance = instance;
|
||||||
_npp_mode = mode;
|
_npp_mode = mode;
|
||||||
_script_object = NULL;
|
_script_object = NULL;
|
||||||
|
_failed = false;
|
||||||
|
|
||||||
// Copy the tokens and save them within this object.
|
// Copy the tokens and save them within this object.
|
||||||
_tokens.reserve(argc);
|
_tokens.reserve(argc);
|
||||||
@ -93,6 +95,7 @@ PPInstance::
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(_streams.empty());
|
assert(_streams.empty());
|
||||||
|
assert(_file_datas.empty());
|
||||||
|
|
||||||
if (_script_object != NULL) {
|
if (_script_object != NULL) {
|
||||||
browser->releaseobject(_script_object);
|
browser->releaseobject(_script_object);
|
||||||
@ -119,7 +122,17 @@ PPInstance::
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void PPInstance::
|
void PPInstance::
|
||||||
begin() {
|
begin() {
|
||||||
if (!is_plugin_loaded()) {
|
// On Windows and Linux, we must insist on having this call. OSX
|
||||||
|
// doesn't necessarily require it.
|
||||||
|
#ifndef __APPLE__
|
||||||
|
if (!has_plugin_thread_async_call) {
|
||||||
|
nout << "Browser version insufficient: we require at least NPAPI version 0.19.\n";
|
||||||
|
set_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
|
if (!is_plugin_loaded() && !_failed) {
|
||||||
// Go download the contents file, so we can download the core DLL.
|
// Go download the contents file, so we can download the core DLL.
|
||||||
string url = PANDA_PACKAGE_HOST_URL;
|
string url = PANDA_PACKAGE_HOST_URL;
|
||||||
if (!url.empty() && url[url.length() - 1] != '/') {
|
if (!url.empty() && url[url.length() - 1] != '/') {
|
||||||
@ -149,6 +162,10 @@ begin() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void PPInstance::
|
void PPInstance::
|
||||||
set_window(NPWindow *window) {
|
set_window(NPWindow *window) {
|
||||||
|
if (_failed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_got_window &&
|
if (_got_window &&
|
||||||
window->x == _window.x &&
|
window->x == _window.x &&
|
||||||
window->y == _window.y &&
|
window->y == _window.y &&
|
||||||
@ -200,6 +217,9 @@ set_window(NPWindow *window) {
|
|||||||
NPError PPInstance::
|
NPError PPInstance::
|
||||||
new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16_t *stype) {
|
new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16_t *stype) {
|
||||||
assert(find(_streams.begin(), _streams.end(), stream) == _streams.end());
|
assert(find(_streams.begin(), _streams.end(), stream) == _streams.end());
|
||||||
|
if (_failed) {
|
||||||
|
return NPERR_GENERIC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (stream->notifyData == NULL) {
|
if (stream->notifyData == NULL) {
|
||||||
// This is an unsolicited stream. Assume the first unsolicited
|
// This is an unsolicited stream. Assume the first unsolicited
|
||||||
@ -272,6 +292,14 @@ stop_outstanding_streams() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(_streams.empty());
|
assert(_streams.empty());
|
||||||
|
|
||||||
|
// Also stop any currently pending _file_datas; these are
|
||||||
|
// locally-implemented streams.
|
||||||
|
FileDatas::iterator fi;
|
||||||
|
for (fi = _file_datas.begin(); fi != _file_datas.end(); ++fi) {
|
||||||
|
delete (*fi);
|
||||||
|
}
|
||||||
|
_file_datas.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -282,7 +310,7 @@ stop_outstanding_streams() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int32_t PPInstance::
|
int32_t PPInstance::
|
||||||
write_ready(NPStream *stream) {
|
write_ready(NPStream *stream) {
|
||||||
if (stream->notifyData != NULL) {
|
if (stream->notifyData != NULL && !_failed) {
|
||||||
PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
|
PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
|
||||||
if (req->_rtype == PPDownloadRequest::RT_instance_data) {
|
if (req->_rtype == PPDownloadRequest::RT_instance_data) {
|
||||||
// There's a special case for the RT_instance_data stream. This
|
// There's a special case for the RT_instance_data stream. This
|
||||||
@ -325,6 +353,12 @@ write_stream(NPStream *stream, int offset, int len, void *buffer) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_failed) {
|
||||||
|
// We're done; stop this.
|
||||||
|
browser->destroystream(_npp_instance, stream, NPRES_USER_BREAK);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
|
PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
|
||||||
switch (req->_rtype) {
|
switch (req->_rtype) {
|
||||||
case PPDownloadRequest::RT_user:
|
case PPDownloadRequest::RT_user:
|
||||||
@ -411,6 +445,12 @@ url_notify(const char *url, NPReason reason, void *notifyData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PPDownloadRequest *req = (PPDownloadRequest *)notifyData;
|
PPDownloadRequest *req = (PPDownloadRequest *)notifyData;
|
||||||
|
if (_failed) {
|
||||||
|
// We're done; ignore this.
|
||||||
|
delete req;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (req->_rtype) {
|
switch (req->_rtype) {
|
||||||
case PPDownloadRequest::RT_user:
|
case PPDownloadRequest::RT_user:
|
||||||
if (!req->_notified_done) {
|
if (!req->_notified_done) {
|
||||||
@ -546,6 +586,9 @@ stream_as_file(NPStream *stream, const char *fname) {
|
|||||||
void PPInstance::
|
void PPInstance::
|
||||||
handle_request(P3D_request *request) {
|
handle_request(P3D_request *request) {
|
||||||
assert(request->_instance == _p3d_inst);
|
assert(request->_instance == _p3d_inst);
|
||||||
|
if (_failed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
|
|
||||||
@ -609,12 +652,12 @@ handle_request(P3D_request *request) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void PPInstance::
|
void PPInstance::
|
||||||
generic_browser_call() {
|
generic_browser_call() {
|
||||||
//#ifndef HAS_PLUGIN_THREAD_ASYNC_CALL
|
if (!has_plugin_thread_async_call) {
|
||||||
// If we can't ask Mozilla to call us back using
|
// If we can't ask Mozilla to call us back using
|
||||||
// NPN_PluginThreadAsyncCall(), then we'll do it explicitly now,
|
// NPN_PluginThreadAsyncCall(), then we'll do it explicitly now,
|
||||||
// since we know we're in the main thread here.
|
// since we know we're in the main thread here.
|
||||||
handle_request_loop();
|
handle_request_loop();
|
||||||
//#endif
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -763,6 +806,33 @@ variant_to_p3dobj(const NPVariant *variant) {
|
|||||||
return P3D_new_none_object();
|
return P3D_new_none_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PPInstance::output_np_variant
|
||||||
|
// Access: Public
|
||||||
|
// Description: Outputs the variant value.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PPInstance::
|
||||||
|
output_np_variant(ostream &out, const NPVariant &result) {
|
||||||
|
if (NPVARIANT_IS_NULL(result)) {
|
||||||
|
out << "null";
|
||||||
|
} else if (NPVARIANT_IS_VOID(result)) {
|
||||||
|
out << "void";
|
||||||
|
} else if (NPVARIANT_IS_BOOLEAN(result)) {
|
||||||
|
out << "bool " << NPVARIANT_TO_BOOLEAN(result);
|
||||||
|
} else if (NPVARIANT_IS_INT32(result)) {
|
||||||
|
out << "int " << NPVARIANT_TO_INT32(result);
|
||||||
|
} else if (NPVARIANT_IS_DOUBLE(result)) {
|
||||||
|
out << "double " << NPVARIANT_TO_DOUBLE(result);
|
||||||
|
} else if (NPVARIANT_IS_STRING(result)) {
|
||||||
|
NPString str = NPVARIANT_TO_STRING(result);
|
||||||
|
const UC_NPString &uc_str = *(UC_NPString *)(&str);
|
||||||
|
out << "string " << string(uc_str.UTF8Characters, uc_str.UTF8Length);
|
||||||
|
} else if (NPVARIANT_IS_OBJECT(result)) {
|
||||||
|
NPObject *child = NPVARIANT_TO_OBJECT(result);
|
||||||
|
out << "object " << child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: PPInstance::find_host
|
// Function: PPInstance::find_host
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -891,18 +961,19 @@ request_ready(P3D_instance *instance) {
|
|||||||
PPInstance *inst = (PPInstance *)(instance->_user_data);
|
PPInstance *inst = (PPInstance *)(instance->_user_data);
|
||||||
assert(inst != NULL);
|
assert(inst != NULL);
|
||||||
|
|
||||||
|
if (has_plugin_thread_async_call) {
|
||||||
#ifdef HAS_PLUGIN_THREAD_ASYNC_CALL
|
#ifdef HAS_PLUGIN_THREAD_ASYNC_CALL
|
||||||
// Since we are running at least Gecko 1.9, and we have this very
|
// Since we are running at least Gecko 1.9, and we have this very
|
||||||
// useful function, let's use it to ask the browser to call us back
|
// useful function, let's use it to ask the browser to call us back
|
||||||
// in the main thread.
|
// in the main thread.
|
||||||
// nout << "async: " << (void *)browser->pluginthreadasynccall << "\n";
|
|
||||||
if ((void *)browser->pluginthreadasynccall != (void *)NULL) {
|
if ((void *)browser->pluginthreadasynccall != (void *)NULL) {
|
||||||
browser->pluginthreadasynccall(inst->_npp_instance, browser_sync_callback, NULL);
|
browser->pluginthreadasynccall(inst->_npp_instance, browser_sync_callback, NULL);
|
||||||
}
|
}
|
||||||
#else // HAS_PLUGIN_THREAD_ASYNC_CALL
|
#endif // HAS_PLUGIN_THREAD_ASYNC_CALL
|
||||||
|
|
||||||
// If we're using an older version of Gecko, we have to do this some
|
} else {
|
||||||
// other, OS-dependent way.
|
// If we're using an older version of Gecko, we have to do this
|
||||||
|
// some other, OS-dependent way.
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Use a Windows message to forward this event to the main thread.
|
// Use a Windows message to forward this event to the main thread.
|
||||||
@ -913,14 +984,10 @@ request_ready(P3D_instance *instance) {
|
|||||||
if (win != NULL && win->type == NPWindowTypeWindow) {
|
if (win != NULL && win->type == NPWindowTypeWindow) {
|
||||||
PostMessage((HWND)(win->window), WM_USER, 0, 0);
|
PostMessage((HWND)(win->window), WM_USER, 0, 0);
|
||||||
}
|
}
|
||||||
|
#endif // _WIN32
|
||||||
#else
|
|
||||||
// On Mac and Linux, we ignore this asynchronous event, and rely on
|
// On Mac and Linux, we ignore this asynchronous event, and rely on
|
||||||
// detecting it within HandleEvent() and similar callbacks.
|
// detecting it within HandleEvent() and similar callbacks.
|
||||||
|
}
|
||||||
#endif // _WIN32
|
|
||||||
|
|
||||||
#endif // HAS_PLUGIN_THREAD_ASYNC_CALL
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -1211,6 +1278,7 @@ do_load_plugin() {
|
|||||||
nout << "Attempting to load core API from " << pathname << "\n";
|
nout << "Attempting to load core API from " << pathname << "\n";
|
||||||
if (!load_plugin(pathname, "", "", true, "", "", "", false, false, nout)) {
|
if (!load_plugin(pathname, "", "", true, "", "", "", false, false, nout)) {
|
||||||
nout << "Unable to launch core API in " << pathname << "\n";
|
nout << "Unable to launch core API in " << pathname << "\n";
|
||||||
|
set_failed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1436,29 +1504,62 @@ copy_file(const string &from_filename, const string &to_filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: PPInstance::output_np_variant
|
// Function: PPInstance::set_failed
|
||||||
// Access: Public
|
// Access: Private
|
||||||
// Description: Outputs the variant value.
|
// Description: Called when something has gone wrong that prevents
|
||||||
|
// the plugin instance from running. Specifically, this
|
||||||
|
// means it failed to load the core API.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void PPInstance::
|
void PPInstance::
|
||||||
output_np_variant(ostream &out, const NPVariant &result) {
|
set_failed() {
|
||||||
if (NPVARIANT_IS_NULL(result)) {
|
if (!_failed) {
|
||||||
out << "null";
|
_failed = true;
|
||||||
} else if (NPVARIANT_IS_VOID(result)) {
|
|
||||||
out << "void";
|
nout << "Plugin failed.\n";
|
||||||
} else if (NPVARIANT_IS_BOOLEAN(result)) {
|
stop_outstanding_streams();
|
||||||
out << "bool " << NPVARIANT_TO_BOOLEAN(result);
|
|
||||||
} else if (NPVARIANT_IS_INT32(result)) {
|
string expression;
|
||||||
out << "int " << NPVARIANT_TO_INT32(result);
|
// Look for the "onpluginfail" token.
|
||||||
} else if (NPVARIANT_IS_DOUBLE(result)) {
|
Tokens::iterator ti;
|
||||||
out << "double " << NPVARIANT_TO_DOUBLE(result);
|
for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) {
|
||||||
} else if (NPVARIANT_IS_STRING(result)) {
|
if ((*ti)._keyword != NULL && (*ti)._value != NULL) {
|
||||||
NPString str = NPVARIANT_TO_STRING(result);
|
// Make the token lowercase, since HTML is case-insensitive but
|
||||||
const UC_NPString &uc_str = *(UC_NPString *)(&str);
|
// we're not.
|
||||||
out << "string " << string(uc_str.UTF8Characters, uc_str.UTF8Length);
|
string keyword;
|
||||||
} else if (NPVARIANT_IS_OBJECT(result)) {
|
for (const char *p = (*ti)._keyword; *p; ++p) {
|
||||||
NPObject *child = NPVARIANT_TO_OBJECT(result);
|
keyword += tolower(*p);
|
||||||
out << "object " << child;
|
}
|
||||||
|
if (keyword == "onpluginfail") {
|
||||||
|
expression = (*ti)._value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expression.empty()) {
|
||||||
|
// Now attempt to evaluate the expression.
|
||||||
|
NPObject *window_object = NULL;
|
||||||
|
if (browser->getvalue(_npp_instance, NPNVWindowNPObject,
|
||||||
|
&window_object) == NPERR_NO_ERROR) {
|
||||||
|
NPString npexpr = { expression.c_str(), expression.length() };
|
||||||
|
NPVariant result;
|
||||||
|
if (browser->evaluate(_npp_instance, window_object,
|
||||||
|
&npexpr, &result)) {
|
||||||
|
nout << "Eval " << expression << "\n";
|
||||||
|
browser->releasevariantvalue(&result);
|
||||||
|
} else {
|
||||||
|
nout << "Unable to eval " << expression << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
browser->releaseobject(window_object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_p3d_inst != NULL) {
|
||||||
|
P3D_instance_finish(_p3d_inst);
|
||||||
|
_p3d_inst = NULL;
|
||||||
|
}
|
||||||
|
cleanup_window();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1528,12 +1629,12 @@ browser_sync_callback(void *) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
LONG PPInstance::
|
LONG PPInstance::
|
||||||
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||||
#ifndef HAS_PLUGIN_THREAD_ASYNC_CALL
|
if (!has_plugin_thread_async_call) {
|
||||||
// Since we're here in the main thread, call handle_request_loop()
|
// Since we're here in the main thread, call handle_request_loop()
|
||||||
// to see if there are any new requests to be serviced by the main
|
// to see if there are any new requests to be serviced by the main
|
||||||
// thread.
|
// thread.
|
||||||
handle_request_loop();
|
handle_request_loop();
|
||||||
#endif
|
}
|
||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case WM_ERASEBKGND:
|
case WM_ERASEBKGND:
|
||||||
|
@ -89,6 +89,8 @@ private:
|
|||||||
void cleanup_window();
|
void cleanup_window();
|
||||||
bool copy_file(const string &from_filename, const string &to_filename);
|
bool copy_file(const string &from_filename, const string &to_filename);
|
||||||
|
|
||||||
|
void set_failed();
|
||||||
|
|
||||||
static void handle_request_loop();
|
static void handle_request_loop();
|
||||||
static void browser_sync_callback(void *);
|
static void browser_sync_callback(void *);
|
||||||
|
|
||||||
@ -114,6 +116,7 @@ private:
|
|||||||
CoreUrls _core_urls;
|
CoreUrls _core_urls;
|
||||||
|
|
||||||
FileSpec _core_api_dll;
|
FileSpec _core_api_dll;
|
||||||
|
bool _failed;
|
||||||
|
|
||||||
bool _got_instance_url;
|
bool _got_instance_url;
|
||||||
string _instance_url;
|
string _instance_url;
|
||||||
|
@ -26,6 +26,7 @@ static ofstream logfile;
|
|||||||
ostream *nout_stream = &logfile;
|
ostream *nout_stream = &logfile;
|
||||||
|
|
||||||
string global_root_dir;
|
string global_root_dir;
|
||||||
|
bool has_plugin_thread_async_call;
|
||||||
|
|
||||||
NPNetscapeFuncs *browser;
|
NPNetscapeFuncs *browser;
|
||||||
|
|
||||||
@ -186,11 +187,11 @@ NP_Initialize(NPNetscapeFuncs *browserFuncs,
|
|||||||
nout << "Plugin compiled with version "
|
nout << "Plugin compiled with version "
|
||||||
<< expected_major << "." << expected_minor << "\n";
|
<< expected_major << "." << expected_minor << "\n";
|
||||||
|
|
||||||
|
has_plugin_thread_async_call = false;
|
||||||
#ifdef HAS_PLUGIN_THREAD_ASYNC_CALL
|
#ifdef HAS_PLUGIN_THREAD_ASYNC_CALL
|
||||||
// We expect to find at least version NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL.
|
// Check if the browser offers this very useful call.
|
||||||
if (browser_major == 0 && browser_minor < NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL) {
|
if (browser_major > 0 || browser_minor >= NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL) {
|
||||||
nout << "Cannot run: unsupported version of NPAPI detected.\n";
|
has_plugin_thread_async_call = true;
|
||||||
return NPERR_GENERIC_ERROR;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user