more work on outbound scripting

This commit is contained in:
David Rose 2009-07-07 01:05:41 +00:00
parent b2906cda8b
commit 59210bf718
12 changed files with 214 additions and 111 deletions

View File

@ -173,7 +173,7 @@ set_wparams(const P3DWindowParams &wparams) {
// of the instance, to be used by JavaScript code in the // of the instance, to be used by JavaScript code in the
// browser to control this program. // browser to control this program.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
P3DObject *P3DInstance:: P3D_object *P3DInstance::
get_panda_script_object() const { get_panda_script_object() const {
assert(_session != NULL); assert(_session != NULL);
nout << "Called P3DInstance::get_panda_script_object()\n"; nout << "Called P3DInstance::get_panda_script_object()\n";
@ -188,13 +188,13 @@ get_panda_script_object() const {
TiXmlDocument *response = _session->command_and_response(doc); TiXmlDocument *response = _session->command_and_response(doc);
nout << "response pointer: " << response << "\n" << flush; nout << "response pointer: " << response << "\n" << flush;
P3DObject *result = NULL; P3D_object *result = NULL;
if (response != NULL) { if (response != NULL) {
TiXmlElement *xresponse = response->FirstChildElement("response"); TiXmlElement *xresponse = response->FirstChildElement("response");
if (xresponse != NULL) { if (xresponse != NULL) {
TiXmlElement *xvalue = xresponse->FirstChildElement("value"); TiXmlElement *xvalue = xresponse->FirstChildElement("value");
if (xvalue != NULL) { if (xvalue != NULL) {
result = _session->xml_to_object(xvalue); result = _session->xml_to_p3dobj(xvalue);
} }
} }
delete response; delete response;
@ -464,7 +464,7 @@ send_browser_script_object() {
xcommand->SetAttribute("cmd", "pyobj"); xcommand->SetAttribute("cmd", "pyobj");
xcommand->SetAttribute("op", "set_browser_script_object"); xcommand->SetAttribute("op", "set_browser_script_object");
if (_browser_script_object != NULL) { if (_browser_script_object != NULL) {
xcommand->LinkEndChild(_session->object_to_xml(_browser_script_object)); xcommand->LinkEndChild(_session->p3dobj_to_xml(_browser_script_object));
} }
doc->LinkEndChild(decl); doc->LinkEndChild(decl);
@ -534,7 +534,7 @@ handle_script_request(P3D_request *request) {
doc->LinkEndChild(decl); doc->LinkEndChild(decl);
doc->LinkEndChild(xcommand); doc->LinkEndChild(xcommand);
if (value != NULL) { if (value != NULL) {
xcommand->LinkEndChild(_session->object_to_xml(value)); xcommand->LinkEndChild(_session->p3dobj_to_xml(value));
P3D_OBJECT_FINISH(value); P3D_OBJECT_FINISH(value);
} }

View File

@ -46,7 +46,7 @@ public:
void set_wparams(const P3DWindowParams &wparams); void set_wparams(const P3DWindowParams &wparams);
inline const P3DWindowParams &get_wparams() const; inline const P3DWindowParams &get_wparams() const;
P3DObject *get_panda_script_object() const; P3D_object *get_panda_script_object() const;
void set_browser_script_object(P3D_object *object); void set_browser_script_object(P3D_object *object);
bool has_request(); bool has_request();

View File

@ -194,7 +194,7 @@ call(const string &method_name, P3D_object *params[], int num_params) const {
} }
for (int i = 0; i < num_params; ++i) { for (int i = 0; i < num_params; ++i) {
TiXmlElement *xparams = _session->object_to_xml(params[i]); TiXmlElement *xparams = _session->p3dobj_to_xml(params[i]);
xcommand->LinkEndChild(xparams); xcommand->LinkEndChild(xparams);
// Now we're done with the params object passed in, we can delete // Now we're done with the params object passed in, we can delete
@ -207,13 +207,13 @@ call(const string &method_name, P3D_object *params[], int num_params) const {
TiXmlDocument *response = _session->command_and_response(doc); TiXmlDocument *response = _session->command_and_response(doc);
nout << "call response pointer: " << response << "\n" << flush; nout << "call response pointer: " << response << "\n" << flush;
P3DObject *result = NULL; P3D_object *result = NULL;
if (response != NULL) { if (response != NULL) {
TiXmlElement *xresponse = response->FirstChildElement("response"); TiXmlElement *xresponse = response->FirstChildElement("response");
if (xresponse != NULL) { if (xresponse != NULL) {
TiXmlElement *xvalue = xresponse->FirstChildElement("value"); TiXmlElement *xvalue = xresponse->FirstChildElement("value");
if (xvalue != NULL) { if (xvalue != NULL) {
result = _session->xml_to_object(xvalue); result = _session->xml_to_p3dobj(xvalue);
} }
} }
delete response; delete response;

View File

@ -172,7 +172,7 @@ run_python() {
// Now add check_comm() as a task. // Now add check_comm() as a task.
_check_comm_task = new GenericAsyncTask("check_comm", st_check_comm, this); _check_comm_task = new GenericAsyncTask("check_comm", task_check_comm, this);
AsyncTaskManager *task_mgr = AsyncTaskManager::get_global_ptr(); AsyncTaskManager *task_mgr = AsyncTaskManager::get_global_ptr();
task_mgr->add(_check_comm_task); task_mgr->add(_check_comm_task);
@ -244,7 +244,7 @@ handle_command(TiXmlDocument *doc) {
} else if (strcmp(cmd, "script_response") == 0) { } else if (strcmp(cmd, "script_response") == 0) {
// Response from a script request. // Response from a script request.
assert(!needs_response); assert(!needs_response);
handle_script_response_command(xcommand); nout << "Ignoring unexpected script_response\n";
} else { } else {
nout << "Unhandled command " << cmd << "\n"; nout << "Unhandled command " << cmd << "\n";
@ -408,41 +408,16 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
} }
} }
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::handle_script_response_command
// Access: Private
// Description: Handles the script_response command, a response from
// the browser to a previous script request from this
// process.
////////////////////////////////////////////////////////////////////
void P3DPythonRun::
handle_script_response_command(TiXmlElement *xcommand) {
int unique_id;
if (xcommand->QueryIntAttribute("unique_id", &unique_id) == TIXML_SUCCESS) {
PyObject *value = NULL;
TiXmlElement *xvalue = xcommand->FirstChildElement("value");
if (xvalue != NULL) {
value = xml_to_pyobj(xvalue);
} else {
value = Py_None;
Py_INCREF(value);
}
PyObject *result = PyObject_CallMethod
(_runner, (char *)"scriptResponse", (char *)"iO", unique_id, value);
Py_DECREF(value);
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::check_comm // Function: P3DPythonRun::check_comm
// Access: Private // Access: Private
// Description: This method is added to the Python task manager (via // Description: This method is added to the task manager (via
// py_check_comm, below) so that it gets a call every // task_check_comm, below) so that it gets a call every
// frame. Its job is to check for commands received // frame. Its job is to check for commands received
// from the plugin host in the parent process. // from the plugin host in the parent process.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
AsyncTask::DoneStatus P3DPythonRun:: void P3DPythonRun::
check_comm(GenericAsyncTask *task) { check_comm() {
ACQUIRE_LOCK(_commands_lock); ACQUIRE_LOCK(_commands_lock);
while (!_commands.empty()) { while (!_commands.empty()) {
TiXmlDocument *doc = _commands.front(); TiXmlDocument *doc = _commands.front();
@ -461,21 +436,82 @@ check_comm(GenericAsyncTask *task) {
} }
RELEASE_LOCK(_commands_lock); RELEASE_LOCK(_commands_lock);
return AsyncTask::DS_cont;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::st_check_comm // Function: P3DPythonRun::task_check_comm
// Access: Private, Static // Access: Private, Static
// Description: This static function wrapper around check_comm is // Description: This static function wrapper around check_comm is
// necessary to add the method function to the // necessary to add the method function to the
// GenericAsyncTask object. // GenericAsyncTask object.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
AsyncTask::DoneStatus P3DPythonRun:: AsyncTask::DoneStatus P3DPythonRun::
st_check_comm(GenericAsyncTask *task, void *user_data) { task_check_comm(GenericAsyncTask *task, void *user_data) {
P3DPythonRun *self = (P3DPythonRun *)user_data; P3DPythonRun *self = (P3DPythonRun *)user_data;
return self->check_comm(task); self->check_comm();
return AsyncTask::DS_cont;
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::wait_script_response
// Access: Private
// Description: This method is similar to check_comm(), above, but
// instead of handling all events, it waits for a
// specific script_response ID to come back from the
// browser, and leaves all other events in the queue.
////////////////////////////////////////////////////////////////////
TiXmlDocument *P3DPythonRun::
wait_script_response(int response_id) {
while (true) {
ACQUIRE_LOCK(_commands_lock);
Commands::iterator ci;
for (ci = _commands.begin(); ci != _commands.end(); ++ci) {
TiXmlDocument *doc = (*ci);
TiXmlElement *xcommand = doc->FirstChildElement("command");
if (xcommand != NULL) {
const char *cmd = xcommand->Attribute("cmd");
if (cmd != NULL && strcmp(cmd, "script_response") == 0) {
int unique_id;
if (xcommand->QueryIntAttribute("unique_id", &unique_id) == TIXML_SUCCESS) {
if (unique_id == response_id) {
// This is the response we were waiting for.
_commands.erase(ci);
RELEASE_LOCK(_commands_lock);
return doc;
}
}
}
// It's not the response we're waiting for, but maybe we need
// to handle it anyway.
bool needs_response = false;
int want_response_id;
if (xcommand->QueryIntAttribute("want_response_id", &want_response_id) == TIXML_SUCCESS) {
// This command will be wanting a response. We'd better
// honor it right away, or we risk deadlock with the browser
// process and the Python process waiting for each other.
_commands.erase(ci);
RELEASE_LOCK(_commands_lock);
handle_command(doc);
delete doc;
ACQUIRE_LOCK(_commands_lock);
break;
}
}
}
if (!_program_continue) {
terminate_session();
}
RELEASE_LOCK(_commands_lock);
// It hasn't shown up yet. Give the sub-thread a chance to
// process the input and append it to the queue.
Thread::force_yield();
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -494,6 +530,38 @@ py_request_func(PyObject *args) {
return NULL; return NULL;
} }
if (strcmp(request_type, "wait_script_response") == 0) {
// This is a special case. Instead of generating a new request,
// this means to wait for a particular script_response to come in
// on the wire.
int response_id;
if (!PyArg_ParseTuple(extra_args, "i", &response_id)) {
Py_DECREF(extra_args);
return NULL;
}
nout << "Waiting for script_response " << response_id << "\n";
TiXmlDocument *doc = wait_script_response(response_id);
nout << "got: " << *doc << "\n";
TiXmlElement *xcommand = doc->FirstChildElement("command");
assert(xcommand != NULL);
TiXmlElement *xvalue = xcommand->FirstChildElement("value");
PyObject *value = NULL;
if (xvalue != NULL) {
nout << "Converting xvalue: " << *xvalue << "\n";
value = xml_to_pyobj(xvalue);
} else {
value = Py_None;
Py_INCREF(value);
}
nout << "Got script_response " << response_id << ", xvalue = " << xvalue << "\n";
delete doc;
Py_DECREF(extra_args);
return value;
}
TiXmlDocument doc; TiXmlDocument doc;
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", ""); TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
TiXmlElement *xrequest = new TiXmlElement("request"); TiXmlElement *xrequest = new TiXmlElement("request");
@ -506,6 +574,7 @@ py_request_func(PyObject *args) {
// A general notification to be sent directly to the instance. // A general notification to be sent directly to the instance.
const char *message; const char *message;
if (!PyArg_ParseTuple(extra_args, "s", &message)) { if (!PyArg_ParseTuple(extra_args, "s", &message)) {
Py_DECREF(extra_args);
return NULL; return NULL;
} }
@ -522,8 +591,10 @@ py_request_func(PyObject *args) {
int unique_id; int unique_id;
if (!PyArg_ParseTuple(extra_args, "sOsOi", if (!PyArg_ParseTuple(extra_args, "sOsOi",
&operation, &object, &property_name, &value, &unique_id)) { &operation, &object, &property_name, &value, &unique_id)) {
Py_DECREF(extra_args);
return NULL; return NULL;
} }
xrequest->SetAttribute("operation", operation); xrequest->SetAttribute("operation", operation);
xrequest->SetAttribute("property_name", property_name); xrequest->SetAttribute("property_name", property_name);
xrequest->SetAttribute("unique_id", unique_id); xrequest->SetAttribute("unique_id", unique_id);
@ -542,6 +613,7 @@ py_request_func(PyObject *args) {
const char *expression; const char *expression;
int unique_id; int unique_id;
if (!PyArg_ParseTuple(extra_args, "si", &expression, &unique_id)) { if (!PyArg_ParseTuple(extra_args, "si", &expression, &unique_id)) {
Py_DECREF(extra_args);
return NULL; return NULL;
} }
@ -554,9 +626,11 @@ py_request_func(PyObject *args) {
} else { } else {
string message = string("Unsupported request type: ") + string(request_type); string message = string("Unsupported request type: ") + string(request_type);
PyErr_SetString(PyExc_ValueError, message.c_str()); PyErr_SetString(PyExc_ValueError, message.c_str());
Py_DECREF(extra_args);
return NULL; return NULL;
} }
Py_DECREF(extra_args);
return Py_BuildValue(""); return Py_BuildValue("");
} }
@ -780,6 +854,11 @@ terminate_session() {
} }
Py_DECREF(result); Py_DECREF(result);
nout << "done calling stop()\n"; nout << "done calling stop()\n";
// The task manager is cleaned up. Let's exit immediately here,
// rather than returning all the way up. This just makes it easier
// when we call terminate_session() from a deeply-nested loop.
exit(0);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -921,7 +1000,8 @@ xml_to_pyobj(TiXmlElement *xvalue) {
int object_id; int object_id;
if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) { if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) {
// Construct a new BrowserObject wrapper around this object. // Construct a new BrowserObject wrapper around this object.
return PyObject_CallFunction(_browser_object_class, (char *)"i", object_id); return PyObject_CallFunction(_browser_object_class, (char *)"Oi",
_runner, object_id);
} }
} else if (strcmp(type, "python") == 0) { } else if (strcmp(type, "python") == 0) {

View File

@ -74,8 +74,9 @@ private:
int want_response_id); int want_response_id);
void handle_script_response_command(TiXmlElement *xcommand); void handle_script_response_command(TiXmlElement *xcommand);
AsyncTask::DoneStatus check_comm(GenericAsyncTask *task); void check_comm();
static AsyncTask::DoneStatus st_check_comm(GenericAsyncTask *task, void *user_data); static AsyncTask::DoneStatus task_check_comm(GenericAsyncTask *task, void *user_data);
TiXmlDocument *wait_script_response(int response_id);
PyObject *py_request_func(PyObject *args); PyObject *py_request_func(PyObject *args);
static PyObject *st_request_func(PyObject *, PyObject *args); static PyObject *st_request_func(PyObject *, PyObject *args);

View File

@ -312,14 +312,14 @@ command_and_response(TiXmlDocument *command) {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: P3DSession::xml_to_object // Function: P3DSession::xml_to_p3dobj
// Access: Public // Access: Public
// Description: Converts the XML representation of the particular // Description: Converts the XML representation of the particular
// object value into a corresponding P3DObject object. // object value into a corresponding P3D_object.
// Returns the newly-allocated object. // Returns the newly-allocated object.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
P3DObject *P3DSession:: P3D_object *P3DSession::
xml_to_object(const TiXmlElement *xvalue) { xml_to_p3dobj(const TiXmlElement *xvalue) {
const char *type = xvalue->Attribute("type"); const char *type = xvalue->Attribute("type");
if (strcmp(type, "none") == 0) { if (strcmp(type, "none") == 0) {
return new P3DNoneObject; return new P3DNoneObject;
@ -350,6 +350,15 @@ xml_to_object(const TiXmlElement *xvalue) {
return new P3DStringObject(*value); return new P3DStringObject(*value);
} }
} else if (strcmp(type, "browser") == 0) {
int object_id;
if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) {
P3D_object *obj = (P3D_object *)object_id;
nout << "Found object " << obj << "\n" << flush;
nout << " formatted is " << *obj << "\n" << flush;
return P3D_OBJECT_COPY(obj);
}
} else if (strcmp(type, "python") == 0) { } else if (strcmp(type, "python") == 0) {
int object_id; int object_id;
if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) { if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) {
@ -362,14 +371,14 @@ xml_to_object(const TiXmlElement *xvalue) {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: P3DSession::object_to_xml // Function: P3DSession::p3dobj_to_xml
// Access: Public // Access: Public
// Description: Allocates and returns a new XML structure // Description: Allocates and returns a new XML structure
// corresponding to the indicated value. The supplied // corresponding to the indicated value. The supplied
// P3DObject passed in is *not* deleted. // P3DObject passed in is *not* deleted.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
TiXmlElement *P3DSession:: TiXmlElement *P3DSession::
object_to_xml(const P3D_object *obj) { p3dobj_to_xml(const P3D_object *obj) {
TiXmlElement *xvalue = new TiXmlElement("value"); TiXmlElement *xvalue = new TiXmlElement("value");
switch (P3D_OBJECT_GET_TYPE(obj)) { switch (P3D_OBJECT_GET_TYPE(obj)) {
@ -681,7 +690,11 @@ rt_make_p3d_request(TiXmlElement *xrequest) {
xrequest->Attribute("unique_id", &unique_id); xrequest->Attribute("unique_id", &unique_id);
if (operation != NULL && xobject != NULL) { if (operation != NULL && xobject != NULL) {
P3D_object *object = xml_to_object(xobject); nout << "xobject = " << *xobject << "\n" << flush;
P3D_object *object = xml_to_p3dobj(xobject);
nout << "converted to " << object << "\n" << flush;
nout << "object = " << *object << "\n" << flush;
nout << "operation = " << *operation << "\n" << flush;
if (strcmp(operation, "get_property") == 0 && property_name != NULL) { if (strcmp(operation, "get_property") == 0 && property_name != NULL) {
request = new P3D_request; request = new P3D_request;
request->_request_type = P3D_RT_script; request->_request_type = P3D_RT_script;

View File

@ -49,8 +49,8 @@ public:
void send_command(TiXmlDocument *command); void send_command(TiXmlDocument *command);
TiXmlDocument *command_and_response(TiXmlDocument *command); TiXmlDocument *command_and_response(TiXmlDocument *command);
P3DObject *xml_to_object(const TiXmlElement *xvalue); P3D_object *xml_to_p3dobj(const TiXmlElement *xvalue);
TiXmlElement *object_to_xml(const P3D_object *obj); TiXmlElement *p3dobj_to_xml(const P3D_object *obj);
private: private:
void install_progress(P3DPackage *package, double progress); void install_progress(P3DPackage *package, double progress);

View File

@ -128,7 +128,7 @@ get_property(const string &property) const {
return NULL; return NULL;
} }
P3D_object *object = _instance->variant_to_object(&result); P3D_object *object = _instance->variant_to_p3dobj(&result);
browser->releasevariantvalue(&result); browser->releasevariantvalue(&result);
return object; return object;
} }

View File

@ -499,13 +499,13 @@ get_panda_script_object() {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PPInstance::object_to_variant // Function: PPInstance::p3dobj_to_variant
// Access: Private // Access: Private
// Description: Converts the indicated P3D_object to the equivalent // Description: Converts the indicated P3D_object to the equivalent
// NPVariant, and stores it in result. // NPVariant, and stores it in result.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void PPInstance:: void PPInstance::
object_to_variant(NPVariant *result, const P3D_object *object) { p3dobj_to_variant(NPVariant *result, const P3D_object *object) {
switch (P3D_OBJECT_GET_TYPE(object)) { switch (P3D_OBJECT_GET_TYPE(object)) {
case P3D_OT_none: case P3D_OT_none:
VOID_TO_NPVARIANT(*result); VOID_TO_NPVARIANT(*result);
@ -542,7 +542,7 @@ object_to_variant(NPVariant *result, const P3D_object *object) {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PPInstance::variant_to_object // Function: PPInstance::variant_to_p3dobj
// Access: Private // Access: Private
// Description: Converts the indicated NPVariant to the equivalent // Description: Converts the indicated NPVariant to the equivalent
// P3D_object, and returns it (newly-allocated). The // P3D_object, and returns it (newly-allocated). The
@ -550,7 +550,7 @@ object_to_variant(NPVariant *result, const P3D_object *object) {
// later. // later.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
P3D_object *PPInstance:: P3D_object *PPInstance::
variant_to_object(const NPVariant *variant) { variant_to_p3dobj(const NPVariant *variant) {
if (NPVARIANT_IS_VOID(*variant) || if (NPVARIANT_IS_VOID(*variant) ||
NPVARIANT_IS_NULL(*variant)) { NPVARIANT_IS_NULL(*variant)) {
return P3D_new_none_object(); return P3D_new_none_object();
@ -564,8 +564,7 @@ variant_to_object(const NPVariant *variant) {
NPString str = NPVARIANT_TO_STRING(*variant); NPString str = NPVARIANT_TO_STRING(*variant);
return P3D_new_string_object(str.utf8characters, str.utf8length); return P3D_new_string_object(str.utf8characters, str.utf8length);
} else if (NPVARIANT_IS_OBJECT(*variant)) { } else if (NPVARIANT_IS_OBJECT(*variant)) {
// TODO. return new PPBrowserObject(this, NPVARIANT_TO_OBJECT(*variant));
return P3D_new_none_object();
} }
// Hmm, none of the above? // Hmm, none of the above?
@ -826,37 +825,6 @@ show_np_variant(const NPVariant &result) {
} }
} }
////////////////////////////////////////////////////////////////////
// Function: PPInstance::np_variant_to_object
// Access: Private
// Description: Returns a freshly-allocated P3D_object corresponding
// to the indicated NPVariant.
////////////////////////////////////////////////////////////////////
P3D_object *PPInstance::
np_variant_to_object(const NPVariant &result) {
if (NPVARIANT_IS_NULL(result)) {
return NULL;
} else if (NPVARIANT_IS_VOID(result)) {
return P3D_new_none_object();
} else if (NPVARIANT_IS_BOOLEAN(result)) {
return P3D_new_bool_object(NPVARIANT_TO_BOOLEAN(result));
} else if (NPVARIANT_IS_INT32(result)) {
return P3D_new_int_object(NPVARIANT_TO_INT32(result));
} else if (NPVARIANT_IS_DOUBLE(result)) {
return P3D_new_float_object(NPVARIANT_TO_DOUBLE(result));
} else if (NPVARIANT_IS_STRING(result)) {
NPString str = NPVARIANT_TO_STRING(result);
return P3D_new_string_object(str.utf8characters, str.utf8length);
} else if (NPVARIANT_IS_OBJECT(result)) {
// TODO?
return P3D_new_none_object();
// NPVARIANT_TO_OBJECT(result);
}
// Huh, what is this?
return NULL;
}
#ifdef _WIN32 #ifdef _WIN32
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -52,8 +52,8 @@ public:
NPObject *get_panda_script_object(); NPObject *get_panda_script_object();
void object_to_variant(NPVariant *result, const P3D_object *object); void p3dobj_to_variant(NPVariant *result, const P3D_object *object);
P3D_object *variant_to_object(const NPVariant *variant); P3D_object *variant_to_p3dobj(const NPVariant *variant);
private: private:
bool read_contents_file(const string &filename); bool read_contents_file(const string &filename);
@ -65,7 +65,6 @@ private:
void send_window(); void send_window();
void show_np_variant(const NPVariant &result); void show_np_variant(const NPVariant &result);
P3D_object *np_variant_to_object(const NPVariant &result);
#ifdef _WIN32 #ifdef _WIN32
static LONG static LONG

View File

@ -175,7 +175,7 @@ get_property(NPIdentifier name, NPVariant *result) {
} }
// We have the property, and its value is stored in value. // We have the property, and its value is stored in value.
_instance->object_to_variant(result, value); _instance->p3dobj_to_variant(result, value);
P3D_OBJECT_FINISH(value); P3D_OBJECT_FINISH(value);
return true; return true;
} }
@ -195,7 +195,7 @@ set_property(NPIdentifier name, const NPVariant *value) {
return false; return false;
} }
P3D_object *object = _instance->variant_to_object(value); P3D_object *object = _instance->variant_to_p3dobj(value);
bool result = P3D_OBJECT_SET_PROPERTY(_p3d_object, property_name.c_str(), object); bool result = P3D_OBJECT_SET_PROPERTY(_p3d_object, property_name.c_str(), object);
return result; return result;
} }

View File

@ -22,7 +22,7 @@ See pack3d.py for a script that generates these p3d files.
import sys import sys
from direct.showbase import VFSImporter from direct.showbase import VFSImporter
from direct.showbase.DirectObject import DirectObject from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, unloadPrcFile, getModelPath, HTTPClient from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, unloadPrcFile, getModelPath, HTTPClient, Thread
from direct.stdpy import file from direct.stdpy import file
from direct.task.TaskManagerGlobal import taskMgr from direct.task.TaskManagerGlobal import taskMgr
from direct.showbase import AppRunnerGlobal from direct.showbase import AppRunnerGlobal
@ -155,8 +155,9 @@ class AppRunner(DirectObject):
""" Replaces self.window with the browser's toplevel DOM """ Replaces self.window with the browser's toplevel DOM
object, for controlling the JavaScript and the document in the object, for controlling the JavaScript and the document in the
same page with the Panda3D plugin. """ same page with the Panda3D plugin. """
print "setBrowserScriptObject(%s)" % (window)
self.window = window self.window = window
print "setBrowserScriptObject(%s)" % (window)
def setP3DFilename(self, p3dFilename, tokens = [], def setP3DFilename(self, p3dFilename, tokens = [],
instanceId = None): instanceId = None):
@ -261,7 +262,8 @@ class AppRunner(DirectObject):
self.requestFunc = func self.requestFunc = func
def sendRequest(self, request, *args): def sendRequest(self, request, *args):
self.requestFunc(self.instanceId, request, args) assert self.requestFunc
return self.requestFunc(self.instanceId, request, args)
def windowEvent(self, win): def windowEvent(self, win):
print "Got window event in runp3d" print "Got window event in runp3d"
@ -271,7 +273,9 @@ class AppRunner(DirectObject):
def scriptRequest(self, operation, object, propertyName = None, def scriptRequest(self, operation, object, propertyName = None,
value = None): value = None):
""" Issues a new script request to the browser. This queries """ Issues a new script request to the browser. This queries
or modifies one of the browser's DOM properties. or modifies one of the browser's DOM properties. This method
blocks until the return value is received from the browser,
and then it returns that value.
operation may be one of [ 'get_property', 'set_property', operation may be one of [ 'get_property', 'set_property',
'call', 'evaluate' ]. 'call', 'evaluate' ].
@ -291,10 +295,10 @@ class AppRunner(DirectObject):
self.sendRequest('script', operation, object, self.sendRequest('script', operation, object,
propertyName, value, uniqueId); propertyName, value, uniqueId);
def scriptResponse(self, uniqueId, value): # Now wait for the response to come in.
""" Called by the browser in response to a scriptRequest, result = self.sendRequest('wait_script_response', uniqueId)
above. """ print "result for %s.%s = %s" % (object, propertyName, result,)
print "Got scriptResponse: %s, %s" % (uniqueId, value) return result
def parseSysArgs(self): def parseSysArgs(self):
""" Converts sys.argv into (p3dFilename, tokens). """ """ Converts sys.argv into (p3dFilename, tokens). """
@ -333,9 +337,47 @@ class BrowserObject:
actually exists in the plugin host's namespace, e.g. a JavaScript actually exists in the plugin host's namespace, e.g. a JavaScript
or DOM object. """ or DOM object. """
def __init__(self, objectId): def __init__(self, runner, objectId):
self.__objectId = objectId self.__dict__['_BrowserObject__runner'] = runner
self.__dict__['_BrowserObject__objectId'] = objectId
def __str__(self):
return "BrowserObject(%s)" % (self.__objectId)
def __nonzero__(self):
return True
def __getattr__(self, name):
""" Remaps attempts to query an attribute into the appropriate
calls to query the actual browser object under the hood. """
print "__getattr_(self, %s)" % (name)
print "runner = %s" % (self.__runner)
value = self.__runner.scriptRequest('get_property', self,
propertyName = name)
return value
# raise AttributeError(name)
def __setattr__(self, name, value):
if name in self.__dict__:
self.__dict__[name] = value
return
value = self.__runner.scriptRequest('set_property', self,
propertyName = name,
value = value)
if not value:
raise AttributeError(name)
def __delattr__(self, name):
if name in self.__dict__:
del self.__dict__[name]
return
value = self.__runner.scriptRequest('del_property', self,
propertyName = name)
if not value:
raise AttributeError(name)
if __name__ == '__main__': if __name__ == '__main__':
runner = AppRunner() runner = AppRunner()