mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 17:35:34 -04:00
javascript eval
This commit is contained in:
parent
b4f51d5ca6
commit
aa171dde99
@ -17,5 +17,5 @@ class FileSpec:
|
||||
self.hash = hv.asHex()
|
||||
|
||||
def getParams(self):
|
||||
return 'filename="%s" size=%s timestamp=%s hash="%s"' % (
|
||||
return 'filename="%s" size="%s" timestamp="%s" hash="%s"' % (
|
||||
self.filename, self.size, self.timestamp, self.hash)
|
||||
|
@ -475,7 +475,7 @@ handle_notify_request(P3D_request *request) {
|
||||
const char *message = request->_request._notify._message;
|
||||
if (strcmp(message, "onwindowopen") == 0) {
|
||||
// The process told us that it just succesfully opened its
|
||||
// window.
|
||||
// window. Tear down the splash window.
|
||||
_instance_window_opened = true;
|
||||
if (_splash_window != NULL) {
|
||||
delete _splash_window;
|
||||
@ -495,6 +495,7 @@ handle_script_request(P3D_request *request) {
|
||||
assert(request->_request_type == P3D_RT_script);
|
||||
|
||||
P3D_object *object = request->_request._script._object;
|
||||
bool needs_response = request->_request._script._needs_response;
|
||||
int unique_id = request->_request._script._unique_id;
|
||||
switch (request->_request._script._op) {
|
||||
case P3D_SO_get_property:
|
||||
@ -515,8 +516,12 @@ handle_script_request(P3D_request *request) {
|
||||
xcommand->LinkEndChild(_session->p3dobj_to_xml(result));
|
||||
P3D_OBJECT_FINISH(result);
|
||||
}
|
||||
|
||||
_session->send_command(doc);
|
||||
|
||||
if (needs_response) {
|
||||
_session->send_command(doc);
|
||||
} else {
|
||||
delete doc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -546,7 +551,11 @@ handle_script_request(P3D_request *request) {
|
||||
xvalue->SetAttribute("value", (int)result);
|
||||
xcommand->LinkEndChild(xvalue);
|
||||
|
||||
_session->send_command(doc);
|
||||
if (needs_response) {
|
||||
_session->send_command(doc);
|
||||
} else {
|
||||
delete doc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -570,7 +579,11 @@ handle_script_request(P3D_request *request) {
|
||||
xvalue->SetAttribute("value", (int)result);
|
||||
xcommand->LinkEndChild(xvalue);
|
||||
|
||||
_session->send_command(doc);
|
||||
if (needs_response) {
|
||||
_session->send_command(doc);
|
||||
} else {
|
||||
delete doc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -581,8 +594,8 @@ handle_script_request(P3D_request *request) {
|
||||
request->_request._script._values,
|
||||
request->_request._script._num_values);
|
||||
// Reset the value count to 0 so we won't double-delete the
|
||||
// values when the request is deleted (the above call has
|
||||
// already deleted them).
|
||||
// parameter values when the request is deleted (the above call
|
||||
// has already deleted them).
|
||||
request->_request._script._num_values = 0;
|
||||
|
||||
// Feed the result back down to the subprocess.
|
||||
@ -600,7 +613,52 @@ handle_script_request(P3D_request *request) {
|
||||
P3D_OBJECT_FINISH(result);
|
||||
}
|
||||
|
||||
_session->send_command(doc);
|
||||
if (needs_response) {
|
||||
_session->send_command(doc);
|
||||
} else {
|
||||
delete doc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case P3D_SO_eval:
|
||||
{
|
||||
P3D_object *result;
|
||||
if (request->_request._script._num_values == 1) {
|
||||
P3D_object *expression = request->_request._script._values[0];
|
||||
int size = P3D_OBJECT_GET_STRING(expression, NULL, 0);
|
||||
char *buffer = new char[size + 1];
|
||||
P3D_OBJECT_GET_STRING(expression, buffer, size + 1);
|
||||
result = P3D_OBJECT_EVAL(object, buffer);
|
||||
logfile << " eval " << *object << ": " << buffer << ", result = " << result << "\n";
|
||||
delete[] buffer;
|
||||
} else {
|
||||
// Wrong number of values. Error.
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
// Feed the result back down to the subprocess.
|
||||
TiXmlDocument *doc = new TiXmlDocument;
|
||||
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
|
||||
TiXmlElement *xcommand = new TiXmlElement("command");
|
||||
xcommand->SetAttribute("cmd", "script_response");
|
||||
xcommand->SetAttribute("unique_id", unique_id);
|
||||
|
||||
doc->LinkEndChild(decl);
|
||||
doc->LinkEndChild(xcommand);
|
||||
|
||||
if (result != NULL) {
|
||||
xcommand->LinkEndChild(_session->p3dobj_to_xml(result));
|
||||
P3D_OBJECT_FINISH(result);
|
||||
}
|
||||
|
||||
logfile << "eval response: " << *doc << "\n";
|
||||
|
||||
if (needs_response) {
|
||||
_session->send_command(doc);
|
||||
} else {
|
||||
delete doc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -79,6 +79,11 @@ object_call(const P3D_object *object, const char *method_name,
|
||||
return ((const P3DObject *)object)->call(method_name, params, num_params);
|
||||
}
|
||||
|
||||
static P3D_object *
|
||||
object_eval(const P3D_object *object, const char *expression) {
|
||||
return ((const P3DObject *)object)->eval(expression);
|
||||
}
|
||||
|
||||
P3D_class_definition P3DObject::_object_class = {
|
||||
&object_finish,
|
||||
&object_copy,
|
||||
@ -91,6 +96,7 @@ P3D_class_definition P3DObject::_object_class = {
|
||||
&object_get_property,
|
||||
&object_set_property,
|
||||
&object_call,
|
||||
&object_eval,
|
||||
};
|
||||
|
||||
// The next functions are used to construct the generic
|
||||
@ -166,6 +172,11 @@ generic_call(const P3D_object *object, const char *method_name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static P3D_object *
|
||||
generic_eval(const P3D_object *object, const char *expression) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
P3D_class_definition P3DObject::_generic_class = {
|
||||
&generic_finish,
|
||||
&generic_copy,
|
||||
@ -178,6 +189,7 @@ P3D_class_definition P3DObject::_generic_class = {
|
||||
&generic_get_property,
|
||||
&generic_set_property,
|
||||
&generic_call,
|
||||
&generic_eval,
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -301,6 +313,17 @@ call(const string &method_name, P3D_object *params[], int num_params) const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DObject::eval
|
||||
// Access: Public, Virtual
|
||||
// Description: Evaluates an arbitrary JavaScript expression. None
|
||||
// of the P3DObject classes implement this.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_object *P3DObject::
|
||||
eval(const string &expression) const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DObject::output
|
||||
// Access: Public, Virtual
|
||||
|
@ -48,6 +48,7 @@ public:
|
||||
|
||||
virtual P3D_object *call(const string &method_name,
|
||||
P3D_object *params[], int num_params) const;
|
||||
virtual P3D_object *eval(const string &expression) const;
|
||||
|
||||
virtual void output(ostream &out) const;
|
||||
|
||||
|
@ -598,14 +598,17 @@ py_request_func(PyObject *args) {
|
||||
PyObject *object;
|
||||
const char *property_name;
|
||||
PyObject *value;
|
||||
int needs_response;
|
||||
int unique_id;
|
||||
if (!PyArg_ParseTuple(extra_args, "sOsOi",
|
||||
&operation, &object, &property_name, &value, &unique_id)) {
|
||||
if (!PyArg_ParseTuple(extra_args, "sOsOii",
|
||||
&operation, &object, &property_name, &value,
|
||||
&needs_response, &unique_id)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xrequest->SetAttribute("operation", operation);
|
||||
xrequest->SetAttribute("property_name", property_name);
|
||||
xrequest->SetAttribute("needs_response", (int)(needs_response != 0));
|
||||
xrequest->SetAttribute("unique_id", unique_id);
|
||||
TiXmlElement *xobject = pyobj_to_xml(object);
|
||||
xobject->SetValue("object");
|
||||
|
@ -684,6 +684,8 @@ rt_make_p3d_request(TiXmlElement *xrequest) {
|
||||
const char *operation = xrequest->Attribute("operation");
|
||||
TiXmlElement *xobject = xrequest->FirstChildElement("object");
|
||||
const char *property_name = xrequest->Attribute("property_name");
|
||||
int needs_response = 0;
|
||||
xrequest->Attribute("needs_response", &needs_response);
|
||||
int unique_id = 0;
|
||||
xrequest->Attribute("unique_id", &unique_id);
|
||||
|
||||
@ -697,6 +699,8 @@ rt_make_p3d_request(TiXmlElement *xrequest) {
|
||||
op = P3D_SO_del_property;
|
||||
} else if (strcmp(operation, "call") == 0) {
|
||||
op = P3D_SO_call;
|
||||
} else if (strcmp(operation, "eval") == 0) {
|
||||
op = P3D_SO_eval;
|
||||
} else {
|
||||
// An unexpected operation.
|
||||
return NULL;
|
||||
@ -710,6 +714,7 @@ rt_make_p3d_request(TiXmlElement *xrequest) {
|
||||
if (property_name != NULL) {
|
||||
request->_request._script._property_name = strdup(property_name);
|
||||
}
|
||||
request->_request._script._needs_response = (needs_response != 0);
|
||||
request->_request._script._unique_id = unique_id;
|
||||
|
||||
// Fill in the value(s).
|
||||
|
@ -74,7 +74,7 @@ extern "C" {
|
||||
libraries match. It should be passed to P3D_initialize() (below).
|
||||
This number will be incremented whenever there are changes to any of
|
||||
the interface specifications defined in this header file. */
|
||||
#define P3D_API_VERSION 3
|
||||
#define P3D_API_VERSION 4
|
||||
|
||||
/************************ GLOBAL FUNCTIONS **************************/
|
||||
|
||||
@ -391,6 +391,15 @@ typedef P3D_object *
|
||||
P3D_object_call_method(const P3D_object *object, const char *method_name,
|
||||
P3D_object *params[], int num_params);
|
||||
|
||||
/* Evaluates an arbitrary JavaScript expression in the context of the
|
||||
object.
|
||||
|
||||
The return value is a newly-allocated P3D_object on success, or
|
||||
NULL on failure. Ownership of the return value is transferred to
|
||||
the caller. */
|
||||
typedef P3D_object *
|
||||
P3D_object_eval_method(const P3D_object *object, const char *expression);
|
||||
|
||||
/* This defines the class structure that implements all of the above
|
||||
methods. */
|
||||
typedef struct _P3D_class_definition {
|
||||
@ -408,6 +417,7 @@ typedef struct _P3D_class_definition {
|
||||
P3D_object_set_property_method *_set_property;
|
||||
|
||||
P3D_object_call_method *_call;
|
||||
P3D_object_eval_method *_eval;
|
||||
|
||||
} P3D_class_definition;
|
||||
|
||||
@ -435,6 +445,7 @@ struct _P3D_object {
|
||||
#define P3D_OBJECT_SET_PROPERTY(object, property, value) ((object)->_class->_set_property((object), (property), (value)))
|
||||
|
||||
#define P3D_OBJECT_CALL(object, method_name, params, num_params) ((object)->_class->_call((object), (method_name), (params), (num_params)))
|
||||
#define P3D_OBJECT_EVAL(object, expression) ((object)->_class->_eval((object), (expression)))
|
||||
|
||||
|
||||
/* The following function types are once again meant to define
|
||||
@ -604,6 +615,7 @@ typedef enum {
|
||||
P3D_SO_set_property,
|
||||
P3D_SO_del_property,
|
||||
P3D_SO_call,
|
||||
P3D_SO_eval,
|
||||
} P3D_script_operation;
|
||||
typedef struct {
|
||||
P3D_object *_object;
|
||||
@ -611,6 +623,7 @@ typedef struct {
|
||||
const char *_property_name;
|
||||
P3D_object **_values;
|
||||
int _num_values;
|
||||
bool _needs_response;
|
||||
int _unique_id;
|
||||
} P3D_request_script;
|
||||
|
||||
|
@ -56,6 +56,11 @@ object_call(const P3D_object *object, const char *method_name,
|
||||
return ((const PPBrowserObject *)object)->call(method_name, params, num_params);
|
||||
}
|
||||
|
||||
static P3D_object *
|
||||
object_eval(const P3D_object *object, const char *expression) {
|
||||
return ((const PPBrowserObject *)object)->eval(expression);
|
||||
}
|
||||
|
||||
P3D_class_definition *PPBrowserObject::_browser_object_class;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -184,11 +189,15 @@ set_property(const string &property, P3D_object *value) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_object *PPBrowserObject::
|
||||
call(const string &method_name, P3D_object *params[], int num_params) const {
|
||||
logfile << "call " << method_name << "(";
|
||||
// First, convert all of the parameters.
|
||||
NPVariant *npparams = new NPVariant[num_params];
|
||||
for (int i = 0; i < num_params; ++i) {
|
||||
_instance->p3dobj_to_variant(&npparams[i], params[i]);
|
||||
_instance->output_np_variant(logfile, npparams[i]);
|
||||
logfile << ", ";
|
||||
}
|
||||
logfile << ")\n";
|
||||
|
||||
NPVariant result;
|
||||
if (method_name.empty()) {
|
||||
@ -196,7 +205,7 @@ call(const string &method_name, P3D_object *params[], int num_params) const {
|
||||
if (!browser->invokeDefault(_instance->get_npp_instance(), _npobj,
|
||||
npparams, num_params, &result)) {
|
||||
// Failed to invoke.
|
||||
logfile << "invoke failed\n" << flush;
|
||||
logfile << "invokeDefault failed\n" << flush;
|
||||
delete[] npparams;
|
||||
return NULL;
|
||||
}
|
||||
@ -207,11 +216,14 @@ call(const string &method_name, P3D_object *params[], int num_params) const {
|
||||
if (!browser->invoke(_instance->get_npp_instance(), _npobj, method_id,
|
||||
npparams, num_params, &result)) {
|
||||
// Failed to invoke.
|
||||
logfile << "invoke failed\n" << flush;
|
||||
delete[] npparams;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] npparams;
|
||||
|
||||
logfile << "invoke succeeded\n" << flush;
|
||||
|
||||
P3D_object *object = _instance->variant_to_p3dobj(&result);
|
||||
@ -219,6 +231,35 @@ call(const string &method_name, P3D_object *params[], int num_params) const {
|
||||
return object;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PPBrowserObject::eval
|
||||
// Access: Public
|
||||
// Description: Evaluates the indicated JavaScript expression in the
|
||||
// context of the object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_object *PPBrowserObject::
|
||||
eval(const string &expression) const {
|
||||
logfile << "eval " << expression << "\n";
|
||||
|
||||
NPString npexpr;
|
||||
npexpr.utf8characters = expression.c_str();
|
||||
npexpr.utf8length = expression.length();
|
||||
|
||||
NPVariant result;
|
||||
if (!browser->evaluate(_instance->get_npp_instance(), _npobj,
|
||||
&npexpr, &result)) {
|
||||
// Failed to eval.
|
||||
logfile << "eval failed\n" << flush;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
logfile << "eval succeeded\n" << flush;
|
||||
|
||||
P3D_object *object = _instance->variant_to_p3dobj(&result);
|
||||
browser->releasevariantvalue(&result);
|
||||
return object;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PPBrowserObject::get_class_definition
|
||||
// Access: Private, Static
|
||||
@ -239,6 +280,7 @@ get_class_definition() {
|
||||
_browser_object_class->_get_property = &object_get_property;
|
||||
_browser_object_class->_set_property = &object_set_property;
|
||||
_browser_object_class->_call = &object_call;
|
||||
_browser_object_class->_eval = &object_eval;
|
||||
}
|
||||
|
||||
return _browser_object_class;
|
||||
|
@ -41,6 +41,7 @@ public:
|
||||
|
||||
P3D_object *call(const string &method_name,
|
||||
P3D_object *params[], int num_params) const;
|
||||
P3D_object *eval(const string &expression) const;
|
||||
|
||||
private:
|
||||
static P3D_class_definition *get_class_definition();
|
||||
|
@ -74,13 +74,9 @@ PPInstance::
|
||||
_p3d_inst = NULL;
|
||||
}
|
||||
|
||||
// It's not clear why we shoudn't release this object now, but if we
|
||||
// do we crash (at least on Windows).
|
||||
/*
|
||||
if (_script_object != NULL) {
|
||||
browser->releaseobject(_script_object);
|
||||
}
|
||||
*/
|
||||
|
||||
// Free the tokens we allocated.
|
||||
Tokens::iterator ti;
|
||||
@ -430,14 +426,11 @@ handle_request(P3D_request *request) {
|
||||
// with the proper P3D object pointer.
|
||||
P3D_object *obj = P3D_instance_get_panda_script_object(_p3d_inst);
|
||||
_script_object->set_p3d_object(obj);
|
||||
logfile << "got onpythonload\n";
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case P3D_RT_script:
|
||||
// We're allowed to ignore this.
|
||||
break;
|
||||
|
||||
default:
|
||||
// Some request types are not handled.
|
||||
logfile << "Unhandled request: " << request->_request_type << "\n";
|
||||
@ -481,6 +474,8 @@ handle_request_loop() {
|
||||
NPObject *PPInstance::
|
||||
get_panda_script_object() {
|
||||
if (_script_object != NULL) {
|
||||
// NPRuntime "steals" a reference to this object.
|
||||
browser->retainobject(_script_object);
|
||||
return _script_object;
|
||||
}
|
||||
|
||||
@ -492,10 +487,7 @@ get_panda_script_object() {
|
||||
|
||||
_script_object = PPPandaObject::make_new(this, obj);
|
||||
|
||||
// It's not clear why we need to explicitly retain this object now,
|
||||
// but if we don't we crash.
|
||||
browser->retainobject(_script_object);
|
||||
|
||||
return _script_object;
|
||||
}
|
||||
|
||||
@ -946,28 +938,28 @@ send_window() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PPInstance::show_np_variant
|
||||
// Access: Private
|
||||
// Function: PPInstance::output_np_variant
|
||||
// Access: Public
|
||||
// Description: Outputs the variant value.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PPInstance::
|
||||
show_np_variant(const NPVariant &result) {
|
||||
output_np_variant(ostream &out, const NPVariant &result) {
|
||||
if (NPVARIANT_IS_NULL(result)) {
|
||||
logfile << "null";
|
||||
out << "null";
|
||||
} else if (NPVARIANT_IS_VOID(result)) {
|
||||
logfile << "void";
|
||||
out << "void";
|
||||
} else if (NPVARIANT_IS_BOOLEAN(result)) {
|
||||
logfile << "bool " << NPVARIANT_TO_BOOLEAN(result);
|
||||
out << "bool " << NPVARIANT_TO_BOOLEAN(result);
|
||||
} else if (NPVARIANT_IS_INT32(result)) {
|
||||
logfile << "int " << NPVARIANT_TO_INT32(result);
|
||||
out << "int " << NPVARIANT_TO_INT32(result);
|
||||
} else if (NPVARIANT_IS_DOUBLE(result)) {
|
||||
logfile << "double " << NPVARIANT_TO_DOUBLE(result);
|
||||
out << "double " << NPVARIANT_TO_DOUBLE(result);
|
||||
} else if (NPVARIANT_IS_STRING(result)) {
|
||||
NPString str = NPVARIANT_TO_STRING(result);
|
||||
logfile << "string " << string(str.utf8characters, str.utf8length);
|
||||
out << "string " << string(str.utf8characters, str.utf8length);
|
||||
} else if (NPVARIANT_IS_OBJECT(result)) {
|
||||
NPObject *child = NPVARIANT_TO_OBJECT(result);
|
||||
logfile << "object " << child;
|
||||
out << "object " << child;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,8 @@ public:
|
||||
void p3dobj_to_variant(NPVariant *result, const P3D_object *object);
|
||||
P3D_object *variant_to_p3dobj(const NPVariant *variant);
|
||||
|
||||
static void output_np_variant(ostream &out, const NPVariant &result);
|
||||
|
||||
private:
|
||||
void start_download(const string &url, PPDownloadRequest *req);
|
||||
void downloaded_file(PPDownloadRequest *req, const string &filename);
|
||||
@ -72,8 +74,6 @@ private:
|
||||
void create_instance();
|
||||
void send_window();
|
||||
|
||||
void show_np_variant(const NPVariant &result);
|
||||
|
||||
#ifdef _WIN32
|
||||
static LONG
|
||||
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
|
||||
|
@ -56,6 +56,7 @@ class AppRunner(DirectObject):
|
||||
self.gotWindow = False
|
||||
self.gotP3DFilename = False
|
||||
self.started = False
|
||||
self.windowOpened = False
|
||||
self.windowPrc = None
|
||||
|
||||
# Store this Null instance where the application can easily
|
||||
@ -76,6 +77,10 @@ class AppRunner(DirectObject):
|
||||
# e.g. self.dom.document will be the document.
|
||||
self.dom = None
|
||||
|
||||
# This is the list of expressions we will evaluate when
|
||||
# self.dom gets assigned.
|
||||
self.deferredEvals = []
|
||||
|
||||
# This is the default requestFunc that is installed if we
|
||||
# never call setRequestFunc().
|
||||
def defaultRequestFunc(*args):
|
||||
@ -175,18 +180,27 @@ class AppRunner(DirectObject):
|
||||
self.dom = dom
|
||||
print "setBrowserScriptObject(%s)" % (dom)
|
||||
|
||||
# Now evaluate any deferred expressions.
|
||||
for expression in self.deferredEvals:
|
||||
self.scriptRequest('eval', self.dom, value = expression,
|
||||
needsResponse = False)
|
||||
self.deferredEvals = []
|
||||
|
||||
def setP3DFilename(self, p3dFilename, tokens = [],
|
||||
instanceId = None):
|
||||
# One day we will have support for multiple instances within a
|
||||
# Python session. Against that day, we save the instance ID
|
||||
# for this instance.
|
||||
self.instanceId = instanceId
|
||||
|
||||
# Now that we have an instanceId, we can respond to queries
|
||||
# and such.
|
||||
self.sendRequest('notify', 'onpythonload')
|
||||
|
||||
tokenDict = dict(tokens)
|
||||
self.tokens = tokens
|
||||
self.tokenDict = dict(tokens)
|
||||
|
||||
# Tell the browser that Python is up and running, and ready to
|
||||
# respond to queries.
|
||||
self.notifyRequest('onpythonload')
|
||||
|
||||
# Now go load the applet.
|
||||
fname = Filename.fromOsSpecific(p3dFilename)
|
||||
if not p3dFilename:
|
||||
# If we didn't get a literal filename, we have to download it
|
||||
@ -194,7 +208,7 @@ class AppRunner(DirectObject):
|
||||
fname = Filename.temporary('', 'p3d_')
|
||||
fname.setExtension('p3d')
|
||||
p3dFilename = fname.toOsSpecific()
|
||||
src = tokenDict.get('src', None)
|
||||
src = self.tokenDict.get('src', None)
|
||||
if not src:
|
||||
raise ArgumentError, "No Panda app specified."
|
||||
|
||||
@ -241,6 +255,7 @@ class AppRunner(DirectObject):
|
||||
loadPrcFileData(pathname, data)
|
||||
|
||||
self.gotP3DFilename = True
|
||||
|
||||
self.startIfReady()
|
||||
|
||||
def setupWindow(self, windowType, x, y, width, height, parent):
|
||||
@ -291,14 +306,53 @@ class AppRunner(DirectObject):
|
||||
self.requestFunc = func
|
||||
|
||||
def sendRequest(self, request, *args):
|
||||
""" Delivers a request to the browser via self.requestFunc.
|
||||
This low-level function is not intended to be called directly
|
||||
by user code. """
|
||||
|
||||
assert self.requestFunc
|
||||
return self.requestFunc(self.instanceId, request, args)
|
||||
|
||||
def windowEvent(self, win):
|
||||
self.sendRequest('notify', 'onwindowopen')
|
||||
""" This method is called when we get a window event. We
|
||||
listen for this to detect when the window has been
|
||||
successfully opened. """
|
||||
|
||||
if not self.windowOpened:
|
||||
self.notifyRequest('onwindowopen')
|
||||
self.windowOpened = True
|
||||
|
||||
def notifyRequest(self, message):
|
||||
""" Delivers a notify request to the browser. This is a "this
|
||||
happened" type notification; it optionally triggers some
|
||||
JavaScript code execution, and may also trigger some internal
|
||||
automatic actions. (For instance, the plugin takes down the
|
||||
splash window when it sees the onwindowopen notification. """
|
||||
|
||||
self.sendRequest('notify', message)
|
||||
|
||||
# Now process any JavaScript that might be waiting for the
|
||||
# event as well. These are the JavaScript expressions that
|
||||
# were specified in the HTML embed or object tag.
|
||||
#expression = self.tokenDict.get(message)
|
||||
#if expression:
|
||||
# self.evalScript(expression)
|
||||
|
||||
def evalScript(self, expression):
|
||||
""" Evaluates an arbitrary JavaScript expression in the global
|
||||
DOM space. This may be deferred if necessary if self.dom has
|
||||
not yet been assigned. """
|
||||
|
||||
if not self.dom:
|
||||
# Defer the expression.
|
||||
self.deferredEvals.append(expression)
|
||||
else:
|
||||
# Evaluate it now.
|
||||
self.scriptRequest('eval', self.dom, value = expression,
|
||||
needsResponse = False)
|
||||
|
||||
def scriptRequest(self, operation, object, propertyName = '',
|
||||
value = None):
|
||||
value = None, needsResponse = True):
|
||||
""" Issues a new script request to the browser. This queries
|
||||
or modifies one of the browser's DOM properties. This method
|
||||
blocks until the return value is received from the browser,
|
||||
@ -320,11 +374,12 @@ class AppRunner(DirectObject):
|
||||
uniqueId = self.nextScriptId
|
||||
self.nextScriptId += 1
|
||||
self.sendRequest('script', operation, object,
|
||||
propertyName, value, uniqueId);
|
||||
propertyName, value, needsResponse, uniqueId);
|
||||
|
||||
# Now wait for the response to come in.
|
||||
result = self.sendRequest('wait_script_response', uniqueId)
|
||||
return result
|
||||
if needsResponse:
|
||||
# Now wait for the response to come in.
|
||||
result = self.sendRequest('wait_script_response', uniqueId)
|
||||
return result
|
||||
|
||||
def parseSysArgs(self):
|
||||
""" Converts sys.argv into (p3dFilename, tokens). """
|
||||
@ -397,7 +452,25 @@ class BrowserObject:
|
||||
parentObj, attribName = self.__boundMethod
|
||||
if parentObj:
|
||||
# Call it as a method.
|
||||
result = self.__runner.scriptRequest('call', parentObj, propertyName = attribName, value = args)
|
||||
needsResponse = True
|
||||
if parentObj is self.__runner.dom and attribName == 'alert':
|
||||
# As a special hack, we don't wait for the return
|
||||
# value from the alert() call, since this is a
|
||||
# blocking call, and waiting for this could cause
|
||||
# problems.
|
||||
needsResponse = False
|
||||
|
||||
if parentObj is self.__runner.dom and attribName == 'eval' and len(args) == 1 and isinstance(args[0], types.StringTypes):
|
||||
# As another special hack, we make dom.eval() a
|
||||
# special case, and map it directly into an eval()
|
||||
# call. If the string begins with 'void ', we further
|
||||
# assume we're not waiting for a response.
|
||||
if args[0].startswith('void '):
|
||||
needsResponse = False
|
||||
result = self.__runner.scriptRequest('eval', parentObj, value = args[0], needsResponse = needsResponse)
|
||||
else:
|
||||
# This is a normal method call.
|
||||
result = self.__runner.scriptRequest('call', parentObj, propertyName = attribName, value = args, needsResponse = needsResponse)
|
||||
else:
|
||||
# Call it as a plain function.
|
||||
result = self.__runner.scriptRequest('call', self, value = args)
|
||||
|
Loading…
x
Reference in New Issue
Block a user