From 13552a7041ddfdc5f57757040c3fc707809f6fc9 Mon Sep 17 00:00:00 2001 From: David Rose Date: Mon, 6 Jul 2009 17:38:41 +0000 Subject: [PATCH] working on inbound scripting controls --- direct/src/plugin/load_plugin.cxx | 20 +- direct/src/plugin/load_plugin.h | 4 +- direct/src/plugin/p3dBoolObject.cxx | 14 -- direct/src/plugin/p3dBoolObject.h | 2 - direct/src/plugin/p3dFloatObject.cxx | 15 -- direct/src/plugin/p3dFloatObject.h | 2 - direct/src/plugin/p3dInstance.cxx | 160 +++++++++++++-- direct/src/plugin/p3dInstance.h | 7 +- direct/src/plugin/p3dInstanceManager.cxx | 5 +- direct/src/plugin/p3dIntObject.cxx | 14 -- direct/src/plugin/p3dIntObject.h | 2 - direct/src/plugin/p3dNoneObject.cxx | 13 -- direct/src/plugin/p3dNoneObject.h | 2 - direct/src/plugin/p3dObject.cxx | 89 ++++++++- direct/src/plugin/p3dObject.h | 19 +- direct/src/plugin/p3dPythonObject.cxx | 23 +-- direct/src/plugin/p3dPythonObject.h | 3 +- direct/src/plugin/p3dPythonRun.cxx | 141 +++++++++++-- direct/src/plugin/p3dPythonRun.h | 5 +- direct/src/plugin/p3dSession.cxx | 99 ++++++++- direct/src/plugin/p3dSession.h | 3 +- direct/src/plugin/p3dStringObject.cxx | 14 -- direct/src/plugin/p3dStringObject.h | 2 - direct/src/plugin/p3d_plugin.cxx | 8 +- direct/src/plugin/p3d_plugin.h | 39 +++- direct/src/plugin/p3d_plugin_common.h | 13 ++ direct/src/plugin_npapi/Sources.pp | 2 + .../src/plugin_npapi/nppanda3d_composite1.cxx | 1 + direct/src/plugin_npapi/ppBrowserObject.I | 14 ++ direct/src/plugin_npapi/ppBrowserObject.cxx | 188 ++++++++++++++++++ direct/src/plugin_npapi/ppBrowserObject.h | 57 ++++++ direct/src/plugin_npapi/ppInstance.cxx | 97 ++++++++- direct/src/plugin_npapi/ppInstance.h | 5 +- direct/src/plugin_npapi/ppPandaObject.cxx | 78 +------- direct/src/plugin_npapi/ppPandaObject.h | 5 +- direct/src/plugin_npapi/startup.cxx | 2 +- direct/src/plugin_standalone/panda3d.cxx | 2 +- direct/src/showutil/runp3d.py | 48 +++++ 38 files changed, 947 insertions(+), 270 deletions(-) create mode 100644 direct/src/plugin_npapi/ppBrowserObject.I create mode 100644 direct/src/plugin_npapi/ppBrowserObject.cxx create mode 100644 direct/src/plugin_npapi/ppBrowserObject.h diff --git a/direct/src/plugin/load_plugin.cxx b/direct/src/plugin/load_plugin.cxx index 1bb601bfd5..9bfa9b2baf 100755 --- a/direct/src/plugin/load_plugin.cxx +++ b/direct/src/plugin/load_plugin.cxx @@ -46,8 +46,8 @@ P3D_new_bool_object_func *P3D_new_bool_object; P3D_new_int_object_func *P3D_new_int_object; P3D_new_float_object_func *P3D_new_float_object; P3D_new_string_object_func *P3D_new_string_object; -P3D_instance_get_script_object_func *P3D_instance_get_script_object; -P3D_instance_set_script_object_func *P3D_instance_set_script_object; +P3D_instance_get_panda_script_object_func *P3D_instance_get_panda_script_object; +P3D_instance_set_browser_script_object_func *P3D_instance_set_browser_script_object; P3D_instance_get_request_func *P3D_instance_get_request; P3D_check_request_func *P3D_check_request; @@ -188,8 +188,8 @@ load_plugin(const string &p3d_plugin_filename) { P3D_new_int_object = (P3D_new_int_object_func *)get_func(module, "P3D_new_int_object"); P3D_new_float_object = (P3D_new_float_object_func *)get_func(module, "P3D_new_float_object"); P3D_new_string_object = (P3D_new_string_object_func *)get_func(module, "P3D_new_string_object"); - P3D_instance_get_script_object = (P3D_instance_get_script_object_func *)get_func(module, "P3D_instance_get_script_object"); - P3D_instance_set_script_object = (P3D_instance_set_script_object_func *)get_func(module, "P3D_instance_set_script_object"); + P3D_instance_get_panda_script_object = (P3D_instance_get_panda_script_object_func *)get_func(module, "P3D_instance_get_panda_script_object"); + P3D_instance_set_browser_script_object = (P3D_instance_set_browser_script_object_func *)get_func(module, "P3D_instance_set_browser_script_object"); P3D_instance_get_request = (P3D_instance_get_request_func *)get_func(module, "P3D_instance_get_request"); P3D_check_request = (P3D_check_request_func *)get_func(module, "P3D_check_request"); @@ -212,8 +212,8 @@ load_plugin(const string &p3d_plugin_filename) { P3D_new_int_object == NULL || P3D_new_float_object == NULL || P3D_new_string_object == NULL || - P3D_instance_get_script_object == NULL || - P3D_instance_set_script_object == NULL || + P3D_instance_get_panda_script_object == NULL || + P3D_instance_set_browser_script_object == NULL || P3D_instance_get_request == NULL || P3D_check_request == NULL || @@ -235,8 +235,8 @@ load_plugin(const string &p3d_plugin_filename) { << "\nP3D_new_int_object = " << P3D_new_int_object << "\nP3D_new_float_object = " << P3D_new_float_object << "\nP3D_new_string_object = " << P3D_new_string_object - << "\nP3D_instance_get_script_object = " << P3D_instance_get_script_object - << "\nP3D_instance_set_script_object = " << P3D_instance_set_script_object + << "\nP3D_instance_get_panda_script_object = " << P3D_instance_get_panda_script_object + << "\nP3D_instance_set_browser_script_object = " << P3D_instance_set_browser_script_object << "\nP3D_instance_get_request = " << P3D_instance_get_request << "\nP3D_check_request = " << P3D_check_request @@ -313,8 +313,8 @@ unload_dso() { P3D_new_int_object = NULL; P3D_new_float_object = NULL; P3D_new_string_object = NULL; - P3D_instance_get_script_object = NULL; - P3D_instance_set_script_object = NULL; + P3D_instance_get_panda_script_object = NULL; + P3D_instance_set_browser_script_object = NULL; P3D_instance_get_request = NULL; P3D_check_request = NULL; diff --git a/direct/src/plugin/load_plugin.h b/direct/src/plugin/load_plugin.h index e5fd1dc4b6..4eacb1c468 100755 --- a/direct/src/plugin/load_plugin.h +++ b/direct/src/plugin/load_plugin.h @@ -33,8 +33,8 @@ extern P3D_new_bool_object_func *P3D_new_bool_object; extern P3D_new_int_object_func *P3D_new_int_object; extern P3D_new_float_object_func *P3D_new_float_object; extern P3D_new_string_object_func *P3D_new_string_object; -extern P3D_instance_get_script_object_func *P3D_instance_get_script_object; -extern P3D_instance_set_script_object_func *P3D_instance_set_script_object; +extern P3D_instance_get_panda_script_object_func *P3D_instance_get_panda_script_object; +extern P3D_instance_set_browser_script_object_func *P3D_instance_set_browser_script_object; extern P3D_instance_get_request_func *P3D_instance_get_request; extern P3D_check_request_func *P3D_check_request; diff --git a/direct/src/plugin/p3dBoolObject.cxx b/direct/src/plugin/p3dBoolObject.cxx index ebc40a5bb0..979cf4345f 100644 --- a/direct/src/plugin/p3dBoolObject.cxx +++ b/direct/src/plugin/p3dBoolObject.cxx @@ -81,17 +81,3 @@ make_string(string &value) const { value = "False"; } } - -//////////////////////////////////////////////////////////////////// -// Function: P3DBoolObject::make_xml -// Access: Public, Virtual -// Description: Allocates and returns a new XML structure -// corresponding to this value. -//////////////////////////////////////////////////////////////////// -TiXmlElement *P3DBoolObject:: -make_xml() const { - TiXmlElement *xvalue = new TiXmlElement("value"); - xvalue->SetAttribute("type", "bool"); - xvalue->SetAttribute("value", (int)_value); - return xvalue; -} diff --git a/direct/src/plugin/p3dBoolObject.h b/direct/src/plugin/p3dBoolObject.h index aae4980b0d..eff3eb1cc1 100644 --- a/direct/src/plugin/p3dBoolObject.h +++ b/direct/src/plugin/p3dBoolObject.h @@ -33,8 +33,6 @@ public: virtual int get_int() const; virtual void make_string(string &value) const; - virtual TiXmlElement *make_xml() const; - private: bool _value; }; diff --git a/direct/src/plugin/p3dFloatObject.cxx b/direct/src/plugin/p3dFloatObject.cxx index 5ff1f7eb82..5bb08042ca 100644 --- a/direct/src/plugin/p3dFloatObject.cxx +++ b/direct/src/plugin/p3dFloatObject.cxx @@ -90,18 +90,3 @@ make_string(string &value) const { strm << _value; value = strm.str(); } - - -//////////////////////////////////////////////////////////////////// -// Function: P3DFloatObject::make_xml -// Access: Public, Virtual -// Description: Allocates and returns a new XML structure -// corresponding to this value. -//////////////////////////////////////////////////////////////////// -TiXmlElement *P3DFloatObject:: -make_xml() const { - TiXmlElement *xvalue = new TiXmlElement("value"); - xvalue->SetAttribute("type", "float"); - xvalue->SetDoubleAttribute("value", _value); - return xvalue; -} diff --git a/direct/src/plugin/p3dFloatObject.h b/direct/src/plugin/p3dFloatObject.h index 5660f97a5e..9be4927af0 100644 --- a/direct/src/plugin/p3dFloatObject.h +++ b/direct/src/plugin/p3dFloatObject.h @@ -34,8 +34,6 @@ public: virtual double get_float() const; virtual void make_string(string &value) const; - virtual TiXmlElement *make_xml() const; - private: double _value; }; diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index 751a50f11c..08d6f50a9e 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -43,6 +43,7 @@ P3DInstance:: P3DInstance(P3D_request_ready_func *func, void *user_data) : _func(func) { + _browser_script_object = NULL; _user_data = user_data; _request_pending = false; _got_fparams = false; @@ -68,6 +69,10 @@ P3DInstance:: ~P3DInstance() { assert(_session == NULL); + if (_browser_script_object != NULL) { + P3D_OBJECT_FINISH(_browser_script_object); + } + DESTROY_LOCK(_request_lock); // Tell all of the packages that we're no longer in business for @@ -162,22 +167,22 @@ set_wparams(const P3DWindowParams &wparams) { } //////////////////////////////////////////////////////////////////// -// Function: P3DInstance::get_script_object +// Function: P3DInstance::get_panda_script_object // Access: Public // Description: Returns a pointer to the top-level scriptable object // of the instance, to be used by JavaScript code in the // browser to control this program. //////////////////////////////////////////////////////////////////// P3DObject *P3DInstance:: -get_script_object() const { +get_panda_script_object() const { assert(_session != NULL); - nout << "Called P3DInstance::get_script_object()\n"; + nout << "Called P3DInstance::get_panda_script_object()\n"; TiXmlDocument *doc = new TiXmlDocument; TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", ""); TiXmlElement *xcommand = new TiXmlElement("command"); xcommand->SetAttribute("cmd", "pyobj"); - xcommand->SetAttribute("op", "get_script_object"); + xcommand->SetAttribute("op", "get_panda_script_object"); doc->LinkEndChild(decl); doc->LinkEndChild(xcommand); TiXmlDocument *response = _session->command_and_response(doc); @@ -202,6 +207,29 @@ get_script_object() const { return result; } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::set_browser_script_object +// Access: Public +// Description: Stores a pointer to the top-level window object +// of the browser, to be used by Panda code to control +// JavaScript. Ownership of this object is passed into +// the instance. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +set_browser_script_object(P3D_object *browser_script_object) { + nout << "Called P3DInstance::set_browser_script_object()\n"; + if (browser_script_object != _browser_script_object) { + if (_browser_script_object != NULL) { + P3D_OBJECT_FINISH(_browser_script_object); + } + _browser_script_object = browser_script_object; + + if (_session != NULL) { + send_browser_script_object(); + } + } +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::has_request @@ -237,22 +265,22 @@ get_request() { } RELEASE_LOCK(_request_lock); + nout << "get_request: " << result << "\n" << flush; + if (result != NULL) { - if (result->_request_type == P3D_RT_notify) { - // If we received a notify request, process the notification - // immediately--it might be interesting to this instance. - const char *message = result->_request._notify._message; - if (strcmp(message, "onwindowopen") == 0) { - // The process told us that it just succesfully opened its - // window. - nout << "Instance " << this << " got onwindowopen\n" << flush; - _instance_window_opened = true; - if (_splash_window != NULL) { - nout << "Deleting splash window\n" << flush; - delete _splash_window; - _splash_window = NULL; - } - } + switch (result->_request_type) { + case P3D_RT_notify: + handle_notify_request(result); + break; + + case P3D_RT_script: + handle_script_request(result); + break; + + default: + // Other kinds of requests don't require special handling at + // this level; pass it up unmolested. + break; } } @@ -422,6 +450,100 @@ make_xml() { return xinstance; } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::send_browser_script_object +// Access: Private +// Description: Sends the XML sequence to inform the session of our +// browser's toplevel window object. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +send_browser_script_object() { + TiXmlDocument *doc = new TiXmlDocument; + TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", ""); + TiXmlElement *xcommand = new TiXmlElement("command"); + xcommand->SetAttribute("cmd", "pyobj"); + xcommand->SetAttribute("op", "set_browser_script_object"); + if (_browser_script_object != NULL) { + xcommand->LinkEndChild(_session->object_to_xml(_browser_script_object)); + } + + doc->LinkEndChild(decl); + doc->LinkEndChild(xcommand); + + _session->send_command(doc); +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::handle_notify_request +// Access: Private +// Description: Called (in the main thread) when a notify request is +// received from the subprocess. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +handle_notify_request(P3D_request *request) { + assert(request->_request_type == P3D_RT_notify); + + // We look for certain notify events that have particular meaning + // to this instance. + const char *message = request->_request._notify._message; + if (strcmp(message, "onwindowopen") == 0) { + // The process told us that it just succesfully opened its + // window. + nout << "Instance " << this << " got onwindowopen\n" << flush; + _instance_window_opened = true; + if (_splash_window != NULL) { + nout << "Deleting splash window\n" << flush; + delete _splash_window; + _splash_window = NULL; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::handle_script_request +// Access: Private +// Description: Called (in the main thread) when a script request is +// received from the subprocess. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +handle_script_request(P3D_request *request) { + assert(request->_request_type == P3D_RT_script); + + P3D_object *object = request->_request._script._object; + int unique_id = request->_request._script._unique_id; + switch (request->_request._script._op) { + case P3D_SO_get_property: + { + P3D_object *value = P3D_OBJECT_GET_PROPERTY(object, request->_request._script._property_name); + nout << "get_property, object = " << object << "\n"; + if (object != NULL) { + nout << " *object = " << *object << "\n" << flush; + } + nout << "value = " << value << "\n" << flush; + if (value != NULL) { + nout << " *value = " << *value << "\n" << flush; + } + // We've got the property value; feed it 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 (value != NULL) { + xcommand->LinkEndChild(_session->object_to_xml(value)); + P3D_OBJECT_FINISH(value); + } + + _session->send_command(doc); + } + break; + } +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::make_splash_window // Access: Private diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index 81ecbf4977..1799feb5a7 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -46,7 +46,8 @@ public: void set_wparams(const P3DWindowParams &wparams); inline const P3DWindowParams &get_wparams() const; - P3DObject *get_script_object() const; + P3DObject *get_panda_script_object() const; + void set_browser_script_object(P3D_object *object); bool has_request(); P3D_request *get_request(); @@ -86,10 +87,14 @@ private: P3DInstance *_inst; }; + void send_browser_script_object(); + void handle_notify_request(P3D_request *request); + void handle_script_request(P3D_request *request); void make_splash_window(); void install_progress(P3DPackage *package, double progress); P3D_request_ready_func *_func; + P3D_object *_browser_script_object; bool _got_fparams; P3DFileParams _fparams; diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index d3d43331bd..5aec8115be 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -301,8 +301,9 @@ signal_request_ready(P3DInstance *inst) { //////////////////////////////////////////////////////////////////// P3D_class_definition *P3DInstanceManager:: make_class_definition() const { - // TODO. - return NULL; + P3D_class_definition *new_class = new P3D_class_definition(P3DObject::_generic_class); + // TODO: save this pointer so we can delete it on destruction. + return new_class; } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/plugin/p3dIntObject.cxx b/direct/src/plugin/p3dIntObject.cxx index b20b6f6a50..7334613a92 100644 --- a/direct/src/plugin/p3dIntObject.cxx +++ b/direct/src/plugin/p3dIntObject.cxx @@ -80,17 +80,3 @@ make_string(string &value) const { value = strm.str(); } - -//////////////////////////////////////////////////////////////////// -// Function: P3DIntObject::make_xml -// Access: Public, Virtual -// Description: Allocates and returns a new XML structure -// corresponding to this value. -//////////////////////////////////////////////////////////////////// -TiXmlElement *P3DIntObject:: -make_xml() const { - TiXmlElement *xvalue = new TiXmlElement("value"); - xvalue->SetAttribute("type", "int"); - xvalue->SetAttribute("value", _value); - return xvalue; -} diff --git a/direct/src/plugin/p3dIntObject.h b/direct/src/plugin/p3dIntObject.h index 37b6a52ead..75c62e8e46 100644 --- a/direct/src/plugin/p3dIntObject.h +++ b/direct/src/plugin/p3dIntObject.h @@ -33,8 +33,6 @@ public: virtual int get_int() const; virtual void make_string(string &value) const; - virtual TiXmlElement *make_xml() const; - private: int _value; }; diff --git a/direct/src/plugin/p3dNoneObject.cxx b/direct/src/plugin/p3dNoneObject.cxx index 56340d0418..c1305d5a60 100644 --- a/direct/src/plugin/p3dNoneObject.cxx +++ b/direct/src/plugin/p3dNoneObject.cxx @@ -54,16 +54,3 @@ void P3DNoneObject:: make_string(string &value) const { value = "None"; } - -//////////////////////////////////////////////////////////////////// -// Function: P3DNoneObject::make_xml -// Access: Public, Virtual -// Description: Allocates and returns a new XML structure -// corresponding to this value. -//////////////////////////////////////////////////////////////////// -TiXmlElement *P3DNoneObject:: -make_xml() const { - TiXmlElement *xvalue = new TiXmlElement("value"); - xvalue->SetAttribute("type", "none"); - return xvalue; -} diff --git a/direct/src/plugin/p3dNoneObject.h b/direct/src/plugin/p3dNoneObject.h index 9f08662f53..5bddac51e5 100644 --- a/direct/src/plugin/p3dNoneObject.h +++ b/direct/src/plugin/p3dNoneObject.h @@ -31,8 +31,6 @@ public: virtual P3D_object_type get_type() const; virtual bool get_bool() const; virtual void make_string(string &value) const; - - virtual TiXmlElement *make_xml() const; }; #endif diff --git a/direct/src/plugin/p3dObject.cxx b/direct/src/plugin/p3dObject.cxx index d859562c85..4e2bd849c3 100644 --- a/direct/src/plugin/p3dObject.cxx +++ b/direct/src/plugin/p3dObject.cxx @@ -15,7 +15,7 @@ #include "p3dObject.h" #include // strncpy -// The following functions are C-style wrappers around the above +// The following functions are C-style wrappers around the below // P3DObject virtual methods; they are defined to allow us to create // the C-style P3D_class_definition method table to store in the // P3D_object structure. @@ -93,6 +93,93 @@ P3D_class_definition P3DObject::_object_class = { &object_call, }; +// The next functions are used to construct the generic +// P3D_class_definition class returned by P3D_make_class_definition(). +// These are pointers to no-op functions, which the host may or may +// not choose to override. +static void +generic_finish(P3D_object *object) { + // You must override finish(), though, otherwise it's a leak. The + // core API has no idea how to delete your object. + nout << "Warning! default object_finish() method does nothing; object will leak.\n" << flush; +} + +static P3D_object * +generic_copy(const P3D_object *object) { + nout << "Warning! default object_copy() method does nothing; object pointer will be shared.\n" << flush; + return (P3D_object *)object; +} + +static P3D_object_type +generic_get_type(const P3D_object *object) { + // We assume anyone going through the trouble of subclassing this + // will want to return an object, not one of the other fundamental + // types. + return P3D_OT_object; +} + +static bool +generic_get_bool(const P3D_object *object) { + return false; +} + +static int +generic_get_int(const P3D_object *object) { + return 0; +} + +static double +generic_get_float(const P3D_object *object) { + return 0.0; +} + +static int +generic_get_string(const P3D_object *object, char *buffer, int buffer_length) { + return 0; +} + +static int +generic_get_repr(const P3D_object *object, char *buffer, int buffer_length) { + return 0; +} + +static P3D_object * +generic_get_property(const P3D_object *object, const char *property) { + return NULL; +} + +static bool +generic_set_property(P3D_object *object, const char *property, + P3D_object *value) { + if (value != NULL) { + P3D_OBJECT_FINISH(value); + } + return false; +} + +static P3D_object * +generic_call(const P3D_object *object, const char *method_name, + P3D_object *params[], int num_params) { + for (int i = 0; i < num_params; ++i) { + P3D_OBJECT_FINISH(params[i]); + } + return NULL; +} + +P3D_class_definition P3DObject::_generic_class = { + &generic_finish, + &generic_copy, + &generic_get_type, + &generic_get_bool, + &generic_get_int, + &generic_get_float, + &generic_get_string, + &generic_get_repr, + &generic_get_property, + &generic_set_property, + &generic_call, +}; + //////////////////////////////////////////////////////////////////// // Function: P3DObject::Destructor // Access: Public, Virtual diff --git a/direct/src/plugin/p3dObject.h b/direct/src/plugin/p3dObject.h index 963d05d5c7..efbecd9a23 100644 --- a/direct/src/plugin/p3dObject.h +++ b/direct/src/plugin/p3dObject.h @@ -49,8 +49,6 @@ public: virtual P3D_object *call(const string &method_name, P3D_object *params[], int num_params) const; - virtual TiXmlElement *make_xml() const=0; - virtual void output(ostream &out) const; inline void ref() const; @@ -62,28 +60,19 @@ private: public: static P3D_class_definition _object_class; + static P3D_class_definition _generic_class; }; #include "p3dObject.I" // For classes that inherit from P3DObject, above, we can use the -// virtual method to write the output simply. +// virtual method to write the output simply. (For classes that +// inherit only from P3D_object, we have to use the generic C method +// defined in p3d_plugin_common.h, a little clumsier.) inline ostream &operator << (ostream &out, const P3DObject &value) { value.output(out); return out; } -// For classes that inherit only from P3D_object, we have to use the -// generic C method, a little clumsier. -inline ostream &operator << (ostream &out, const P3D_object &value) { - int size = P3D_OBJECT_GET_REPR(&value, NULL, 0); - char *buffer = new char[size]; - P3D_OBJECT_GET_REPR(&value, buffer, size); - out.write(buffer, size); - delete[] buffer; - - return out; -} - #endif diff --git a/direct/src/plugin/p3dPythonObject.cxx b/direct/src/plugin/p3dPythonObject.cxx index 75c15c9c39..07c8039f08 100644 --- a/direct/src/plugin/p3dPythonObject.cxx +++ b/direct/src/plugin/p3dPythonObject.cxx @@ -194,8 +194,7 @@ call(const string &method_name, P3D_object *params[], int num_params) const { } for (int i = 0; i < num_params; ++i) { - assert(params[i]->_class == &P3DObject::_object_class); - TiXmlElement *xparams = ((P3DObject *)params[i])->make_xml(); + TiXmlElement *xparams = _session->object_to_xml(params[i]); xcommand->LinkEndChild(xparams); // Now we're done with the params object passed in, we can delete @@ -244,18 +243,14 @@ output(ostream &out) const { } } - //////////////////////////////////////////////////////////////////// -// Function: P3DPythonObject::make_xml -// Access: Public, Virtual -// Description: Allocates and returns a new XML structure -// corresponding to this value. +// Function: P3DPythonObject::get_object_id +// Access: Public +// Description: Returns the object_id number that is used to uniquely +// identify this object in the XML stream. //////////////////////////////////////////////////////////////////// -TiXmlElement *P3DPythonObject:: -make_xml() const { - TiXmlElement *xvalue = new TiXmlElement("value"); - xvalue->SetAttribute("type", "python"); - xvalue->SetAttribute("object_id", _object_id); - - return xvalue; +int P3DPythonObject:: +get_object_id() const { + return _object_id; } + diff --git a/direct/src/plugin/p3dPythonObject.h b/direct/src/plugin/p3dPythonObject.h index e0f92c6d08..129ff1bf4f 100644 --- a/direct/src/plugin/p3dPythonObject.h +++ b/direct/src/plugin/p3dPythonObject.h @@ -47,9 +47,8 @@ public: virtual P3D_object *call(const string &method_name, P3D_object *params[], int num_params) const; - virtual TiXmlElement *make_xml() const; - virtual void output(ostream &out) const; + int get_object_id() const; private: P3DSession *_session; diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx index 8eeea79df4..7bff32a930 100755 --- a/direct/src/plugin/p3dPythonRun.cxx +++ b/direct/src/plugin/p3dPythonRun.cxx @@ -112,19 +112,26 @@ run_python() { } // Get the pointers to the objects needed within the module. - PyObject *AppRunner = PyObject_GetAttrString(runp3d, "AppRunner"); - if (AppRunner == NULL) { + PyObject *app_runner_class = PyObject_GetAttrString(runp3d, "AppRunner"); + if (app_runner_class == NULL) { PyErr_Print(); return false; } // Construct an instance of AppRunner. - _runner = PyObject_CallFunction(AppRunner, (char*) ""); + _runner = PyObject_CallFunction(app_runner_class, (char *)""); if (_runner == NULL) { PyErr_Print(); return false; } - Py_DECREF(AppRunner); + Py_DECREF(app_runner_class); + + // Get the BrowserObject class. + _browser_object_class = PyObject_GetAttrString(runp3d, "BrowserObject"); + if (_browser_object_class == NULL) { + PyErr_Print(); + return false; + } // Get the global TaskManager. _taskMgr = PyObject_GetAttrString(runp3d, "taskMgr"); @@ -139,7 +146,7 @@ run_python() { // Construct a Python wrapper around our request_func() method. static PyMethodDef p3dpython_methods[] = { {"request_func", P3DPythonRun::st_request_func, METH_VARARGS, - "Check for communications to and from the plugin host."}, + "Send an asynchronous request to the plugin host"}, {NULL, NULL, 0, NULL} /* Sentinel */ }; PyObject *p3dpython = Py_InitModule("p3dpython", p3dpython_methods); @@ -155,7 +162,7 @@ run_python() { // Now pass that func pointer back to our AppRunner instance, so it // can call up to us. - PyObject *result = PyObject_CallMethod(_runner, (char*) "setRequestFunc", (char*) "O", request_func); + PyObject *result = PyObject_CallMethod(_runner, (char *)"setRequestFunc", (char *)"O", request_func); if (result == NULL) { PyErr_Print(); return false; @@ -171,7 +178,7 @@ run_python() { // Finally, get lost in taskMgr.run(). nout << "calling run()\n"; - PyObject *done = PyObject_CallMethod(_taskMgr, (char*) "run", (char*) ""); + PyObject *done = PyObject_CallMethod(_taskMgr, (char *)"run", (char *)""); if (done == NULL) { PyErr_Print(); return false; @@ -231,11 +238,13 @@ handle_command(TiXmlDocument *doc) { terminate_session(); } else if (strcmp(cmd, "pyobj") == 0) { - // Manipulate or query a python object. Presumably this - // command will want a response. - assert(needs_response); + // Manipulate or query a python object. + handle_pyobj_command(xcommand, needs_response, want_response_id); - handle_pyobj_command(xcommand, want_response_id); + } else if (strcmp(cmd, "script_response") == 0) { + // Response from a script request. + assert(!needs_response); + handle_script_response_command(xcommand); } else { nout << "Unhandled command " << cmd << "\n"; @@ -262,7 +271,8 @@ handle_command(TiXmlDocument *doc) { // a Python object from the browser scripts. //////////////////////////////////////////////////////////////////// void P3DPythonRun:: -handle_pyobj_command(TiXmlElement *xcommand, int want_response_id) { +handle_pyobj_command(TiXmlElement *xcommand, bool needs_response, + int want_response_id) { TiXmlDocument doc; TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", ""); TiXmlElement *xresponse = new TiXmlElement("response"); @@ -272,13 +282,30 @@ handle_pyobj_command(TiXmlElement *xcommand, int want_response_id) { const char *op = xcommand->Attribute("op"); if (op != NULL) { - if (strcmp(op, "get_script_object") == 0) { - // Get the toplevel Python object. + if (strcmp(op, "get_panda_script_object") == 0) { + // Get Panda's toplevel Python object. PyObject *obj = PyObject_GetAttrString(_runner, "scriptRoot"); if (obj != NULL) { xresponse->LinkEndChild(pyobj_to_xml(obj)); Py_DECREF(obj); } + + } else if (strcmp(op, "set_browser_script_object") == 0) { + // Set the Browser's toplevel window object. + PyObject *obj; + TiXmlElement *xvalue = xcommand->FirstChildElement("value"); + if (xvalue != NULL) { + obj = xml_to_pyobj(xvalue); + } else { + obj = Py_None; + Py_INCREF(obj); + } + + PyObject *result = PyObject_CallMethod + (_runner, (char *)"setBrowserScriptObject", (char *)"O", obj); + Py_DECREF(obj); + Py_XDECREF(result); + } else if (strcmp(op, "call") == 0) { // Call the named method on the indicated object, or the object // itself if method_name isn't given. @@ -375,8 +402,35 @@ handle_pyobj_command(TiXmlElement *xcommand, int want_response_id) { } } - nout << "sending " << doc << "\n" << flush; - _pipe_write << doc << flush; + if (needs_response) { + nout << "sending " << doc << "\n" << flush; + _pipe_write << doc << flush; + } +} + +//////////////////////////////////////////////////////////////////// +// 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); + } } //////////////////////////////////////////////////////////////////// @@ -459,6 +513,30 @@ py_request_func(PyObject *args) { nout << "sending " << doc << "\n" << flush; _pipe_write << doc << flush; + } else if (strcmp(request_type, "script") == 0) { + // Meddling with a scripting variable on the browser side. + const char *operation; + PyObject *object; + const char *property_name; + PyObject *value; + int unique_id; + if (!PyArg_ParseTuple(extra_args, "sOsOi", + &operation, &object, &property_name, &value, &unique_id)) { + return NULL; + } + xrequest->SetAttribute("operation", operation); + xrequest->SetAttribute("property_name", property_name); + xrequest->SetAttribute("unique_id", unique_id); + TiXmlElement *xobject = pyobj_to_xml(object); + xobject->SetValue("object"); + xrequest->LinkEndChild(xobject); + TiXmlElement *xvalue = pyobj_to_xml(value); + xrequest->LinkEndChild(xvalue); + + nout << "sending " << doc << "\n" << flush; + _pipe_write << doc << flush; + + /* } else if (strcmp(request_type, "evaluate") == 0) { // An evaluate request. const char *expression; @@ -471,6 +549,7 @@ py_request_func(PyObject *args) { xrequest->SetAttribute("unique_id", unique_id); nout << "sending " << doc << "\n" << flush; _pipe_write << doc << flush; + */ } else { string message = string("Unsupported request type: ") + string(request_type); @@ -610,7 +689,7 @@ set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams) { } PyObject *result = PyObject_CallMethod - (_runner, (char*) "setP3DFilename", (char*) "sOi", p3d_filename.c_str(), + (_runner, (char *)"setP3DFilename", (char *)"sOi", p3d_filename.c_str(), token_list, inst->get_instance_id()); Py_DECREF(token_list); @@ -669,7 +748,7 @@ setup_window(P3DCInstance *inst, TiXmlElement *xwparams) { // TODO: direct this into the particular instance. This will // require a specialized ShowBase replacement. PyObject *result = PyObject_CallMethod - (_runner, (char*)"setupWindow", (char*)"siiiii", window_type.c_str(), + (_runner, (char *)"setupWindow", (char *)"siiiii", window_type.c_str(), win_x, win_y, win_width, win_height, parent_window_handle); if (result == NULL) { @@ -694,7 +773,7 @@ terminate_session() { _instances.clear(); nout << "calling stop()\n"; - PyObject *result = PyObject_CallMethod(_taskMgr, (char*) "stop", (char*) ""); + PyObject *result = PyObject_CallMethod(_taskMgr, (char *)"stop", (char *)""); if (result == NULL) { PyErr_Print(); return; @@ -772,15 +851,28 @@ pyobj_to_xml(PyObject *value) { xvalue->SetAttribute("value", str); } + } else if (PyObject_IsInstance(value, _browser_object_class)) { + // This is a BrowserObject, a reference to an object that actually + // exists in the host namespace. So, pass up the appropriate + // object ID. + PyObject *objectId = PyObject_GetAttrString(value, (char *)"_BrowserObject__objectId"); + if (objectId != NULL) { + int object_id = PyInt_AsLong(objectId); + xvalue->SetAttribute("type", "browser"); + xvalue->SetAttribute("object_id", object_id); + Py_DECREF(objectId); + } + } else { // Some other kind of object. Make it a generic Python object. // This is more expensive for the caller to deal with--it requires // a back-and-forth across the XML pipe--but it's much more // general. + // TODO: pass pointers better. xvalue->SetAttribute("type", "python"); - xvalue->SetAttribute("object_id", (long)value); + xvalue->SetAttribute("object_id", (int)value); - // Temporary hack. + // TODO: fix this hack, properly manage these reference counts. Py_INCREF(value); } @@ -825,6 +917,13 @@ xml_to_pyobj(TiXmlElement *xvalue) { return PyString_FromStringAndSize(value->data(), value->length()); } + } else if (strcmp(type, "browser") == 0) { + int object_id; + if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) { + // Construct a new BrowserObject wrapper around this object. + return PyObject_CallFunction(_browser_object_class, (char *)"i", object_id); + } + } else if (strcmp(type, "python") == 0) { int object_id; if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) { diff --git a/direct/src/plugin/p3dPythonRun.h b/direct/src/plugin/p3dPythonRun.h index ff539231f1..89596d08f6 100755 --- a/direct/src/plugin/p3dPythonRun.h +++ b/direct/src/plugin/p3dPythonRun.h @@ -70,7 +70,9 @@ public: private: void handle_command(TiXmlDocument *doc); - void handle_pyobj_command(TiXmlElement *xcommand, int want_response_id); + void handle_pyobj_command(TiXmlElement *xcommand, bool needs_response, + int want_response_id); + void handle_script_response_command(TiXmlElement *xcommand); AsyncTask::DoneStatus check_comm(GenericAsyncTask *task); static AsyncTask::DoneStatus st_check_comm(GenericAsyncTask *task, void *user_data); @@ -107,6 +109,7 @@ private: char **_py_argv; PyObject *_runner; + PyObject *_browser_object_class; PyObject *_taskMgr; PT(GenericAsyncTask) _check_comm_task; diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index 82c5791a0e..01a55b2fe4 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -156,6 +156,7 @@ start_instance(P3DInstance *inst) { xcommand->LinkEndChild(xinstance); send_command(doc); + inst->send_browser_script_object(); if (_panda3d->get_ready()) { // If it's ready immediately, go ahead and start. @@ -212,6 +213,7 @@ void P3DSession:: send_command(TiXmlDocument *command) { if (_p3dpython_running) { // Python is running. Send the command. + nout << "Sending " << *command << "\n" << flush; _pipe_write << *command << flush; delete command; } else { @@ -300,7 +302,7 @@ command_and_response(TiXmlDocument *command) { // Returns the newly-allocated object. //////////////////////////////////////////////////////////////////// P3DObject *P3DSession:: -xml_to_object(TiXmlElement *xvalue) { +xml_to_object(const TiXmlElement *xvalue) { const char *type = xvalue->Attribute("type"); if (strcmp(type, "none") == 0) { return new P3DNoneObject; @@ -342,6 +344,75 @@ xml_to_object(TiXmlElement *xvalue) { return new P3DNoneObject; } +//////////////////////////////////////////////////////////////////// +// Function: P3DSession::object_to_xml +// Access: Public +// Description: Allocates and returns a new XML structure +// corresponding to the indicated value. The supplied +// P3DObject passed in is *not* deleted. +//////////////////////////////////////////////////////////////////// +TiXmlElement *P3DSession:: +object_to_xml(const P3D_object *obj) { + TiXmlElement *xvalue = new TiXmlElement("value"); + + switch (P3D_OBJECT_GET_TYPE(obj)) { + case P3D_OT_none: + xvalue->SetAttribute("type", "none"); + break; + + case P3D_OT_bool: + xvalue->SetAttribute("type", "bool"); + xvalue->SetAttribute("value", (int)P3D_OBJECT_GET_BOOL(obj)); + break; + + case P3D_OT_int: + xvalue->SetAttribute("type", "int"); + xvalue->SetAttribute("value", P3D_OBJECT_GET_INT(obj)); + break; + + case P3D_OT_float: + xvalue->SetAttribute("type", "float"); + xvalue->SetDoubleAttribute("value", P3D_OBJECT_GET_FLOAT(obj)); + break; + + case P3D_OT_string: + { + xvalue->SetAttribute("type", "string"); + int size = P3D_OBJECT_GET_STRING(obj, NULL, 0); + char *buffer = new char[size]; + P3D_OBJECT_GET_STRING(obj, buffer, size); + xvalue->SetAttribute("value", string(buffer, size)); + delete [] buffer; + } + break; + + case P3D_OT_object: + if (obj->_class == &P3DObject::_object_class) { + // If it's one of our kind of objects, it must be a + // P3DPythonObject. In this case, just send the object_id down, + // since the actual implementation of this object exists (as a + // Python object) in the sub-process space. + int object_id = ((P3DPythonObject *)obj)->get_object_id(); + xvalue->SetAttribute("type", "python"); + xvalue->SetAttribute("object_id", object_id); + + } else { + // Otherwise, it must a host-provided object, which means we + // should pass a reference down to this particular object, so + // the Python process knows to call back up to here to query it. + // TODO: pass pointers better. + int object_id = (int)obj; + xvalue->SetAttribute("type", "browser"); + xvalue->SetAttribute("object_id", object_id); + + // TODO: manage this reference count somehow. + } + break; + } + + return xvalue; +} + //////////////////////////////////////////////////////////////////// // Function: P3DSession::install_progress // Access: Private @@ -584,6 +655,32 @@ rt_make_p3d_request(TiXmlElement *xrequest) { request->_request._notify._message = strdup(message); } + } else if (strcmp(rtype, "script") == 0) { + const char *operation = xrequest->Attribute("operation"); + TiXmlElement *xobject = xrequest->FirstChildElement("object"); + const char *property_name = xrequest->Attribute("property_name"); + TiXmlElement *xvalue = xrequest->FirstChildElement("value"); + int unique_id = 0; + xrequest->Attribute("unique_id", &unique_id); + + if (operation != NULL && xobject != NULL) { + P3D_object *object = xml_to_object(xobject); + if (strcmp(operation, "get_property") == 0 && property_name != NULL) { + request = new P3D_request; + request->_request_type = P3D_RT_script; + request->_request._script._object = object; + request->_request._script._op = P3D_SO_get_property; + request->_request._script._property_name = strdup(property_name); + request->_request._script._value = NULL; + request->_request._script._unique_id = unique_id; + } + if (request == NULL) { + // If we haven't dispatched a request yet, we didn't use the + // object, so delete it. + P3D_OBJECT_FINISH(object); + } + } + } else { nout << "ignoring request of type " << rtype << "\n"; } diff --git a/direct/src/plugin/p3dSession.h b/direct/src/plugin/p3dSession.h index 936c439c2d..4e93e04a17 100644 --- a/direct/src/plugin/p3dSession.h +++ b/direct/src/plugin/p3dSession.h @@ -49,7 +49,8 @@ public: void send_command(TiXmlDocument *command); TiXmlDocument *command_and_response(TiXmlDocument *command); - P3DObject *xml_to_object(TiXmlElement *xvalue); + P3DObject *xml_to_object(const TiXmlElement *xvalue); + TiXmlElement *object_to_xml(const P3D_object *obj); private: void install_progress(P3DPackage *package, double progress); diff --git a/direct/src/plugin/p3dStringObject.cxx b/direct/src/plugin/p3dStringObject.cxx index de35e1552c..167dff5db2 100644 --- a/direct/src/plugin/p3dStringObject.cxx +++ b/direct/src/plugin/p3dStringObject.cxx @@ -76,20 +76,6 @@ make_string(string &value) const { value = _value; } -//////////////////////////////////////////////////////////////////// -// Function: P3DStringObject::make_xml -// Access: Public, Virtual -// Description: Allocates and returns a new XML structure -// corresponding to this value. -//////////////////////////////////////////////////////////////////// -TiXmlElement *P3DStringObject:: -make_xml() const { - TiXmlElement *xvalue = new TiXmlElement("value"); - xvalue->SetAttribute("type", "string"); - xvalue->SetAttribute("value", _value); - return xvalue; -} - //////////////////////////////////////////////////////////////////// // Function: P3DStringObject::output // Access: Public, Virtual diff --git a/direct/src/plugin/p3dStringObject.h b/direct/src/plugin/p3dStringObject.h index 41582ae6d8..825bfe6220 100644 --- a/direct/src/plugin/p3dStringObject.h +++ b/direct/src/plugin/p3dStringObject.h @@ -34,8 +34,6 @@ public: virtual bool get_bool() const; virtual void make_string(string &value) const; - virtual TiXmlElement *make_xml() const; - virtual void output(ostream &out) const; private: diff --git a/direct/src/plugin/p3d_plugin.cxx b/direct/src/plugin/p3d_plugin.cxx index da06a168a9..2b371ddd16 100644 --- a/direct/src/plugin/p3d_plugin.cxx +++ b/direct/src/plugin/p3d_plugin.cxx @@ -188,23 +188,23 @@ P3D_new_string_object(const char *str, int length) { } P3D_object * -P3D_instance_get_script_object(P3D_instance *instance) { +P3D_instance_get_panda_script_object(P3D_instance *instance) { assert(P3DInstanceManager::get_global_ptr()->is_initialized()); ACQUIRE_LOCK(_api_lock); - P3D_object *result = ((P3DInstance *)instance)->get_script_object(); + P3D_object *result = ((P3DInstance *)instance)->get_panda_script_object(); RELEASE_LOCK(_api_lock); return result; } void -P3D_instance_set_script_object(P3D_instance *instance, +P3D_instance_set_browser_script_object(P3D_instance *instance, P3D_object *object) { assert(P3DInstanceManager::get_global_ptr()->is_initialized()); ACQUIRE_LOCK(_api_lock); - // TODO. + ((P3DInstance *)instance)->set_browser_script_object(object); RELEASE_LOCK(_api_lock); } diff --git a/direct/src/plugin/p3d_plugin.h b/direct/src/plugin/p3d_plugin.h index a5fdb05881..9ec276eeab 100644 --- a/direct/src/plugin/p3d_plugin.h +++ b/direct/src/plugin/p3d_plugin.h @@ -443,7 +443,7 @@ struct _P3D_object { generic function pointers that have reasonable default behavior for all methods. The host should use this function to get a clean P3D_class_definition object before calling - P3D_instance_set_script_object() (see below). Note that this + P3D_instance_set_browser_script_object() (see below). Note that this pointer will automatically be freed when P3D_finalize() is called. */ typedef P3D_class_definition * @@ -481,7 +481,7 @@ P3D_new_string_object_func(const char *string, int length); ownership of the object is passed to the caller, who should be responsible for deleting it eventually. */ typedef P3D_object * -P3D_instance_get_script_object_func(P3D_instance *instance); +P3D_instance_get_panda_script_object_func(P3D_instance *instance); /* The inverse functionality: this supplies an object pointer to the instance to allow the Panda instance to control the browser. In @@ -493,14 +493,14 @@ P3D_instance_get_script_object_func(P3D_instance *instance); have a custom P3D_class_definition pointer, which also must have been created by the host. The best way to create an appropriate class definition is call P3D_make_class_definition(), and then - replace the function pointers for at least _finish, _get_property, - _set_property, and _call. Set these pointers to the host's own - functions that make the appropriate changes in the DOM, or invoke - the appropriate JavaScript functions. + replace the function pointers for at least _finish, _copy, + _get_property, _set_property, and _call. Set these pointers to the + host's own functions that make the appropriate changes in the DOM, + or invoke the appropriate JavaScript functions. If this function is never called, the instance will not be able to make outcalls to the DOM or to JavaScript, but scripts may still be - able to control the instance via P3D_instance_get_script_object(), + able to control the instance via P3D_instance_get_panda_script_object(), above. Ownership of the object is passed into the instance. The caller @@ -508,7 +508,7 @@ P3D_instance_get_script_object_func(P3D_instance *instance); or delete it. The instance will eventually delete it by calling its _finish method. */ typedef void -P3D_instance_set_script_object_func(P3D_instance *instance, +P3D_instance_set_browser_script_object_func(P3D_instance *instance, P3D_object *object); @@ -543,6 +543,7 @@ typedef enum { P3D_RT_get_url, P3D_RT_post_url, P3D_RT_notify, + P3D_RT_script, } P3D_request_type; /* Structures corresponding to the request types in the above enum. */ @@ -586,6 +587,23 @@ typedef struct { const char *_message; } P3D_request_notify; +/* A script object request. This is used to call out into the + browser_script_object (above). This request is handled internally + by the core API, and may safely be ignored by the host. +*/ +typedef enum { + P3D_SO_get_property, + P3D_SO_set_property, + P3D_SO_call, +} P3D_script_operation; +typedef struct { + P3D_object *_object; + P3D_script_operation _op; + const char *_property_name; + P3D_object *_value; + int _unique_id; +} P3D_request_script; + /* This is the overall structure that represents a single request. It is returned by P3D_instance_get_request(). */ typedef struct { @@ -596,6 +614,7 @@ typedef struct { P3D_request_get_url _get_url; P3D_request_post_url _post_url; P3D_request_notify _notify; + P3D_request_script _script; } _request; } P3D_request; @@ -715,8 +734,8 @@ EXPCL_P3D_PLUGIN P3D_new_bool_object_func P3D_new_bool_object; EXPCL_P3D_PLUGIN P3D_new_int_object_func P3D_new_int_object; EXPCL_P3D_PLUGIN P3D_new_float_object_func P3D_new_float_object; EXPCL_P3D_PLUGIN P3D_new_string_object_func P3D_new_string_object; -EXPCL_P3D_PLUGIN P3D_instance_get_script_object_func P3D_instance_get_script_object; -EXPCL_P3D_PLUGIN P3D_instance_set_script_object_func P3D_instance_set_script_object; +EXPCL_P3D_PLUGIN P3D_instance_get_panda_script_object_func P3D_instance_get_panda_script_object; +EXPCL_P3D_PLUGIN P3D_instance_set_browser_script_object_func P3D_instance_set_browser_script_object; EXPCL_P3D_PLUGIN P3D_instance_get_request_func P3D_instance_get_request; EXPCL_P3D_PLUGIN P3D_check_request_func P3D_check_request; diff --git a/direct/src/plugin/p3d_plugin_common.h b/direct/src/plugin/p3d_plugin_common.h index 118b3fd453..d9e049bc3d 100644 --- a/direct/src/plugin/p3d_plugin_common.h +++ b/direct/src/plugin/p3d_plugin_common.h @@ -39,5 +39,18 @@ extern string plugin_output_filename; extern ostream *nout_stream; #define nout (*nout_stream) +// A convenience function for formatting a generic P3D_object to an +// ostream. +inline ostream & +operator << (ostream &out, const P3D_object &value) { + int size = P3D_OBJECT_GET_REPR(&value, NULL, 0); + char *buffer = new char[size]; + P3D_OBJECT_GET_REPR(&value, buffer, size); + out.write(buffer, size); + delete[] buffer; + + return out; +} + #endif diff --git a/direct/src/plugin_npapi/Sources.pp b/direct/src/plugin_npapi/Sources.pp index 74aa017a08..0f96875163 100644 --- a/direct/src/plugin_npapi/Sources.pp +++ b/direct/src/plugin_npapi/Sources.pp @@ -17,12 +17,14 @@ #define SOURCES \ nppanda3d_common.h \ + ppBrowserObject.h ppBrowserObject.I \ ppDownloadRequest.h ppDownloadRequest.I \ ppInstance.h ppInstance.I \ ppPandaObject.h ppPandaObject.I \ startup.h #define INCLUDED_SOURCES \ + ppBrowserObject.cxx \ ppDownloadRequest.cxx \ ppInstance.cxx \ ppPandaObject.cxx \ diff --git a/direct/src/plugin_npapi/nppanda3d_composite1.cxx b/direct/src/plugin_npapi/nppanda3d_composite1.cxx index f456c3f385..bcb17da76f 100644 --- a/direct/src/plugin_npapi/nppanda3d_composite1.cxx +++ b/direct/src/plugin_npapi/nppanda3d_composite1.cxx @@ -1,3 +1,4 @@ +#include "ppBrowserObject.cxx" #include "ppDownloadRequest.cxx" #include "ppInstance.cxx" #include "ppPandaObject.cxx" diff --git a/direct/src/plugin_npapi/ppBrowserObject.I b/direct/src/plugin_npapi/ppBrowserObject.I new file mode 100644 index 0000000000..208450532b --- /dev/null +++ b/direct/src/plugin_npapi/ppBrowserObject.I @@ -0,0 +1,14 @@ +// Filename: ppBrowserObject.I +// Created by: drose (05Jul09) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + diff --git a/direct/src/plugin_npapi/ppBrowserObject.cxx b/direct/src/plugin_npapi/ppBrowserObject.cxx new file mode 100644 index 0000000000..2ee8d94aae --- /dev/null +++ b/direct/src/plugin_npapi/ppBrowserObject.cxx @@ -0,0 +1,188 @@ +// Filename: ppBrowserObject.cxx +// Created by: drose (05Jul09) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "ppBrowserObject.h" +#include "ppInstance.h" +#include +#include // strncpy + +// The following functions are C-style wrappers around the above +// PPBrowserObject methods; they are defined to allow us to create the +// C-style P3D_class_definition method table to store in the +// P3D_object structure. +static void +object_finish(P3D_object *object) { + delete ((PPBrowserObject *)object); +} + +static P3D_object * +object_copy(const P3D_object *object) { + return new PPBrowserObject(*(const PPBrowserObject *)object); +} + +static int +object_get_repr(const P3D_object *object, char *buffer, int buffer_length) { + return ((const PPBrowserObject *)object)->get_repr(buffer, buffer_length); +} + +static P3D_object * +object_get_property(const P3D_object *object, const char *property) { + return ((const PPBrowserObject *)object)->get_property(property); +} + +static bool +object_set_property(P3D_object *object, const char *property, + P3D_object *value) { + return ((PPBrowserObject *)object)->set_property(property, value); +} + +static P3D_object * +object_call(const P3D_object *object, const char *method_name, + P3D_object *params[], int num_params) { + if (method_name == NULL) { + method_name = ""; + } + return ((const PPBrowserObject *)object)->call(method_name, params, num_params); +} + +P3D_class_definition *PPBrowserObject::_browser_object_class; + +//////////////////////////////////////////////////////////////////// +// Function: PPBrowserObject::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PPBrowserObject:: +PPBrowserObject(PPInstance *inst, NPObject *npobj) : + _instance(inst), + _npobj(npobj) +{ + _class = get_class_definition(); + browser->retainobject(_npobj); +} + +//////////////////////////////////////////////////////////////////// +// Function: PPBrowserObject::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PPBrowserObject:: +PPBrowserObject(const PPBrowserObject ©) : + _instance(copy._instance), + _npobj(copy._npobj) +{ + _class = get_class_definition(); + browser->retainobject(_npobj); +} + +//////////////////////////////////////////////////////////////////// +// Function: PPBrowserObject::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PPBrowserObject:: +~PPBrowserObject() { + browser->releaseobject(_npobj); +} + +//////////////////////////////////////////////////////////////////// +// Function: PPBrowserObject::get_repr +// Access: Public +// Description: Returns a user-friendly representation of the object, +// similar to get_string(), above. +//////////////////////////////////////////////////////////////////// +int PPBrowserObject:: +get_repr(char *buffer, int buffer_length) const { + ostringstream strm; + strm << "NPObject " << _npobj; + string result = strm.str(); + strncpy(buffer, result.c_str(), buffer_length); + return (int)result.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PPBrowserObject::get_property +// Access: Public +// Description: Returns the named property element in the object. The +// return value is a freshly-allocated PPBrowserObject object +// that must be deleted by the caller, or NULL on error. +//////////////////////////////////////////////////////////////////// +P3D_object *PPBrowserObject:: +get_property(const string &property) const { + NPIdentifier property_name = browser->getstringidentifier(property.c_str()); + NPVariant result; + if (!browser->getproperty(_instance->get_npp_instance(), _npobj, + property_name, &result)) { + // Failed to retrieve property. + return NULL; + } + + P3D_object *object = _instance->variant_to_object(&result); + browser->releasevariantvalue(&result); + return object; +} + +//////////////////////////////////////////////////////////////////// +// Function: PPBrowserObject::set_property +// Access: Public +// Description: Modifies (or deletes, if value is NULL) the named +// property element in the object. Returns true on +// success, false on failure. +//////////////////////////////////////////////////////////////////// +bool PPBrowserObject:: +set_property(const string &property, P3D_object *value) { + if (value != NULL) { + P3D_OBJECT_FINISH(value); + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: PPBrowserObject::call +// Access: Public +// Description: Invokes the named method on the object, passing the +// indicated parameters. If the method name is empty, +// invokes the object itself. Returns the return value +// on success, NULL on error. +//////////////////////////////////////////////////////////////////// +P3D_object *PPBrowserObject:: +call(const string &method_name, P3D_object *params[], int num_params) const { + for (int i = 0; i < num_params; ++i) { + P3D_OBJECT_FINISH(params[i]); + } + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: PPBrowserObject::get_class_definition +// Access: Private, Static +// Description: Returns a pointer to the P3D_class_definition object +// that lists all of the C-style method pointers for +// this class object. +//////////////////////////////////////////////////////////////////// +P3D_class_definition *PPBrowserObject:: +get_class_definition() { + if (_browser_object_class == NULL) { + // Create a default class_definition object, and fill in the + // appropriate pointers. + _browser_object_class = P3D_make_class_definition(); + _browser_object_class->_finish = &object_finish; + _browser_object_class->_copy = &object_copy; + + _browser_object_class->_get_repr = &object_get_repr; + _browser_object_class->_get_property = &object_get_property; + _browser_object_class->_set_property = &object_set_property; + _browser_object_class->_call = &object_call; + } +} diff --git a/direct/src/plugin_npapi/ppBrowserObject.h b/direct/src/plugin_npapi/ppBrowserObject.h new file mode 100644 index 0000000000..d8a48436d7 --- /dev/null +++ b/direct/src/plugin_npapi/ppBrowserObject.h @@ -0,0 +1,57 @@ +// Filename: ppBrowserObject.h +// Created by: drose (05Jul09) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef PPBROWSEROBJECT_H +#define PPBROWSEROBJECT_H + +#include "nppanda3d_common.h" + +class PPInstance; + +//////////////////////////////////////////////////////////////////// +// Class : PPBrowserObject +// Description : This is the interface layer between an NPObject and a +// P3D_object. It maps calls from P3D_object into the +// NPObject system, thus allowing Panda to view and +// operate on a browser object. +// +// Also see PPPandaObject, which maps calls the other +// way. +//////////////////////////////////////////////////////////////////// +class PPBrowserObject : public P3D_object { +public: + PPBrowserObject(PPInstance *inst, NPObject *npobj); + PPBrowserObject(const PPBrowserObject ©); + ~PPBrowserObject(); + + int get_repr(char *buffer, int buffer_length) const; + P3D_object *get_property(const string &property) const; + bool set_property(const string &property, P3D_object *value); + + P3D_object *call(const string &method_name, + P3D_object *params[], int num_params) const; + +private: + static P3D_class_definition *get_class_definition(); + +private: + PPInstance *_instance; + NPObject *_npobj; + static P3D_class_definition *_browser_object_class; +}; + +#include "ppBrowserObject.I" + +#endif + diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx index db2b9e1129..e6c2c859c6 100644 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ b/direct/src/plugin_npapi/ppInstance.cxx @@ -14,6 +14,7 @@ #include "ppInstance.h" #include "ppPandaObject.h" +#include "ppBrowserObject.h" #include "startup.h" #include "p3d_plugin_config.h" #include "find_root_dir.h" @@ -399,7 +400,7 @@ handle_request(P3D_request *request) { strcmp(request->_request._notify._message, "onpythonload") == 0) { // Now that Python is running, initialize our script_object // with the proper P3D object pointer. - P3D_object *obj = P3D_instance_get_script_object(_p3d_inst); + P3D_object *obj = P3D_instance_get_panda_script_object(_p3d_inst); logfile << "late obj = " << obj << "\n" << flush; _script_object->set_p3d_object(obj); } @@ -416,14 +417,14 @@ handle_request(P3D_request *request) { } //////////////////////////////////////////////////////////////////// -// Function: PPInstance::get_script_object +// Function: PPInstance::get_panda_script_object // Access: Public // Description: Returns a toplevel object that JavaScript or whatever // can read and/or modify to control the instance. //////////////////////////////////////////////////////////////////// NPObject *PPInstance:: -get_script_object() { - logfile << "get_script_object\n" << flush; +get_panda_script_object() { + logfile << "get_panda_script_object\n" << flush; if (_script_object != NULL) { logfile << "returning _script_object ref = " << _script_object->referenceCount << "\n"; return _script_object; @@ -432,7 +433,7 @@ get_script_object() { P3D_object *obj = NULL; if (_p3d_inst != NULL) { - obj = P3D_instance_get_script_object(_p3d_inst); + obj = P3D_instance_get_panda_script_object(_p3d_inst); logfile << "obj = " << obj << "\n" << flush; } @@ -444,6 +445,80 @@ get_script_object() { return _script_object; } +//////////////////////////////////////////////////////////////////// +// Function: PPInstance::object_to_variant +// Access: Private +// Description: Converts the indicated P3D_object to the equivalent +// NPVariant, and stores it in result. +//////////////////////////////////////////////////////////////////// +void PPInstance:: +object_to_variant(NPVariant *result, const P3D_object *object) { + switch (P3D_OBJECT_GET_TYPE(object)) { + case P3D_OT_none: + VOID_TO_NPVARIANT(*result); + break; + + case P3D_OT_bool: + BOOLEAN_TO_NPVARIANT(P3D_OBJECT_GET_BOOL(object), *result); + break; + + case P3D_OT_int: + INT32_TO_NPVARIANT(P3D_OBJECT_GET_INT(object), *result); + break; + + case P3D_OT_float: + DOUBLE_TO_NPVARIANT(P3D_OBJECT_GET_FLOAT(object), *result); + break; + + case P3D_OT_string: + { + int size = P3D_OBJECT_GET_STRING(object, NULL, 0); + char *buffer = (char *)browser->memalloc(size); + P3D_OBJECT_GET_STRING(object, buffer, size); + STRINGN_TO_NPVARIANT(buffer, size, *result); + } + break; + + case P3D_OT_object: + { + PPPandaObject *ppobj = PPPandaObject::make_new(this, P3D_OBJECT_COPY(object)); + OBJECT_TO_NPVARIANT(ppobj, *result); + } + break; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PPInstance::variant_to_object +// Access: Private +// Description: Converts the indicated NPVariant to the equivalent +// P3D_object, and returns it (newly-allocated). The +// caller is responsible for freeing the returned object +// later. +//////////////////////////////////////////////////////////////////// +P3D_object *PPInstance:: +variant_to_object(const NPVariant *variant) { + if (NPVARIANT_IS_VOID(*variant) || + NPVARIANT_IS_NULL(*variant)) { + return P3D_new_none_object(); + } else if (NPVARIANT_IS_BOOLEAN(*variant)) { + return P3D_new_bool_object(NPVARIANT_TO_BOOLEAN(*variant)); + } else if (NPVARIANT_IS_INT32(*variant)) { + return P3D_new_int_object(NPVARIANT_TO_INT32(*variant)); + } else if (NPVARIANT_IS_DOUBLE(*variant)) { + return P3D_new_float_object(NPVARIANT_TO_DOUBLE(*variant)); + } else if (NPVARIANT_IS_STRING(*variant)) { + NPString str = NPVARIANT_TO_STRING(*variant); + return P3D_new_string_object(str.utf8characters, str.utf8length); + } else if (NPVARIANT_IS_OBJECT(*variant)) { + // TODO. + return P3D_new_none_object(); + } + + // Hmm, none of the above? + return P3D_new_none_object(); +} + //////////////////////////////////////////////////////////////////// // Function: PPInstance::read_contents_file // Access: Private @@ -619,6 +694,18 @@ create_instance() { _p3d_inst = P3D_new_instance(request_ready, this); if (_p3d_inst != NULL) { + // Now get the browser's window object, to pass to the plugin. + NPObject *window_object = NULL; + if (browser->getvalue(_npp_instance, NPNVWindowNPObject, + &window_object) == NPERR_NO_ERROR) { + logfile << "Got window_object " << window_object << "\n" << flush; + PPBrowserObject *pobj = new PPBrowserObject(this, window_object); + P3D_instance_set_browser_script_object(_p3d_inst, pobj); + browser->releaseobject(window_object); + } else { + logfile << "Couldn't get window_object\n" << flush; + } + const P3D_token *tokens = NULL; if (!_tokens.empty()) { tokens = &_tokens[0]; diff --git a/direct/src/plugin_npapi/ppInstance.h b/direct/src/plugin_npapi/ppInstance.h index 91f99666f0..6ffcd24982 100644 --- a/direct/src/plugin_npapi/ppInstance.h +++ b/direct/src/plugin_npapi/ppInstance.h @@ -48,7 +48,10 @@ public: void handle_request(P3D_request *request); - NPObject *get_script_object(); + NPObject *get_panda_script_object(); + + void object_to_variant(NPVariant *result, const P3D_object *object); + P3D_object *variant_to_object(const NPVariant *variant); private: bool read_contents_file(const string &filename); diff --git a/direct/src/plugin_npapi/ppPandaObject.cxx b/direct/src/plugin_npapi/ppPandaObject.cxx index 40c5f877b5..70cb6fe786 100644 --- a/direct/src/plugin_npapi/ppPandaObject.cxx +++ b/direct/src/plugin_npapi/ppPandaObject.cxx @@ -175,7 +175,7 @@ get_property(NPIdentifier name, NPVariant *result) { } // We have the property, and its value is stored in value. - object_to_variant(result, value); + _instance->object_to_variant(result, value); P3D_OBJECT_FINISH(value); return true; } @@ -195,7 +195,7 @@ set_property(NPIdentifier name, const NPVariant *value) { return false; } - P3D_object *object = variant_to_object(value); + P3D_object *object = _instance->variant_to_object(value); bool result = P3D_OBJECT_SET_PROPERTY(_p3d_object, property_name.c_str(), object); return result; } @@ -267,80 +267,6 @@ identifier_to_string(NPIdentifier ident) { return string(); } -//////////////////////////////////////////////////////////////////// -// Function: PPPandaObject::object_to_variant -// Access: Private -// Description: Converts the indicated P3D_object to the equivalent -// NPVariant, and stores it in result. -//////////////////////////////////////////////////////////////////// -void PPPandaObject:: -object_to_variant(NPVariant *result, const P3D_object *object) { - switch (P3D_OBJECT_GET_TYPE(object)) { - case P3D_OT_none: - VOID_TO_NPVARIANT(*result); - break; - - case P3D_OT_bool: - BOOLEAN_TO_NPVARIANT(P3D_OBJECT_GET_BOOL(object), *result); - break; - - case P3D_OT_int: - INT32_TO_NPVARIANT(P3D_OBJECT_GET_INT(object), *result); - break; - - case P3D_OT_float: - DOUBLE_TO_NPVARIANT(P3D_OBJECT_GET_FLOAT(object), *result); - break; - - case P3D_OT_string: - { - int size = P3D_OBJECT_GET_STRING(object, NULL, 0); - char *buffer = (char *)browser->memalloc(size); - P3D_OBJECT_GET_STRING(object, buffer, size); - STRINGN_TO_NPVARIANT(buffer, size, *result); - } - break; - - case P3D_OT_object: - { - PPPandaObject *ppobj = PPPandaObject::make_new(_instance, P3D_OBJECT_COPY(object)); - OBJECT_TO_NPVARIANT(ppobj, *result); - } - break; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: PPPandaObject::variant_to_object -// Access: Private -// Description: Converts the indicated NPVariant to the equivalent -// P3D_object, and returns it (newly-allocated). The -// caller is responsible for freeing the returned object -// later. -//////////////////////////////////////////////////////////////////// -P3D_object *PPPandaObject:: -variant_to_object(const NPVariant *variant) { - if (NPVARIANT_IS_VOID(*variant) || - NPVARIANT_IS_NULL(*variant)) { - return P3D_new_none_object(); - } else if (NPVARIANT_IS_BOOLEAN(*variant)) { - return P3D_new_bool_object(NPVARIANT_TO_BOOLEAN(*variant)); - } else if (NPVARIANT_IS_INT32(*variant)) { - return P3D_new_int_object(NPVARIANT_TO_INT32(*variant)); - } else if (NPVARIANT_IS_DOUBLE(*variant)) { - return P3D_new_float_object(NPVARIANT_TO_DOUBLE(*variant)); - } else if (NPVARIANT_IS_STRING(*variant)) { - NPString str = NPVARIANT_TO_STRING(*variant); - return P3D_new_string_object(str.utf8characters, str.utf8length); - } else if (NPVARIANT_IS_OBJECT(*variant)) { - // TODO. - return P3D_new_none_object(); - } - - // Hmm, none of the above? - return P3D_new_none_object(); -} - // The remaining function bodies are the C-style function wrappers // that are called directly by NPAPI, and which redirect into the diff --git a/direct/src/plugin_npapi/ppPandaObject.h b/direct/src/plugin_npapi/ppPandaObject.h index a437a314f8..b2ccd47f32 100644 --- a/direct/src/plugin_npapi/ppPandaObject.h +++ b/direct/src/plugin_npapi/ppPandaObject.h @@ -23,6 +23,9 @@ // P3D_object. It maps calls from NPAPI into the // P3D_object system, thus allowing the browser to // view and operate on a Panda object. +// +// Also see PPBrowserObject, which maps calls the other +// way. //////////////////////////////////////////////////////////////////// class PPPandaObject : public NPObject { public: @@ -51,8 +54,6 @@ private: private: static string identifier_to_string(NPIdentifier ident); - void object_to_variant(NPVariant *result, const P3D_object *object); - P3D_object *variant_to_object(const NPVariant *variant); private: diff --git a/direct/src/plugin_npapi/startup.cxx b/direct/src/plugin_npapi/startup.cxx index 87343ceb3d..fc7199df49 100644 --- a/direct/src/plugin_npapi/startup.cxx +++ b/direct/src/plugin_npapi/startup.cxx @@ -407,7 +407,7 @@ NPP_GetValue(NPP instance, NPPVariable variable, void *value) { assert(inst != NULL); if (variable == NPPVpluginScriptableNPObject) { - NPObject *obj = inst->get_script_object(); + NPObject *obj = inst->get_panda_script_object(); if (obj != NULL) { *(NPObject **)value = obj; return NPERR_NO_ERROR; diff --git a/direct/src/plugin_standalone/panda3d.cxx b/direct/src/plugin_standalone/panda3d.cxx index 471969c0ee..3398cc5c34 100644 --- a/direct/src/plugin_standalone/panda3d.cxx +++ b/direct/src/plugin_standalone/panda3d.cxx @@ -409,7 +409,7 @@ handle_request(P3D_request *request) { /* { // Temporary. - P3D_object *obj = P3D_instance_get_script_object(request->_instance); + P3D_object *obj = P3D_instance_get_panda_script_object(request->_instance); cerr << "script_object is " << obj << "\n"; if (obj != NULL) { if (P3D_OBJECT_SET_PROPERTY(obj, "foo", P3D_new_int_object(1))) { diff --git a/direct/src/showutil/runp3d.py b/direct/src/showutil/runp3d.py index 30e2601347..7ec7745b65 100755 --- a/direct/src/showutil/runp3d.py +++ b/direct/src/showutil/runp3d.py @@ -57,10 +57,16 @@ class AppRunner(DirectObject): self.started = False self.windowPrc = None + # This is per session. + self.nextScriptId = 0 + # TODO: we need one of these per instance, not per session. self.instanceId = None self.scriptRoot = ScriptRoot() + # This will be the browser's toplevel window DOM object. + self.window = None + # This is the default requestFunc that is installed if we # never call setRequestFunc(). def defaultRequestFunc(*args): @@ -145,6 +151,13 @@ class AppRunner(DirectObject): if hasattr(main, 'main') and callable(main.main): main.main() + def setBrowserScriptObject(self, window): + """ Replaces self.window with the browser's toplevel DOM + object, for controlling the JavaScript and the document in the + same page with the Panda3D plugin. """ + print "setBrowserScriptObject(%s)" % (window) + self.window = window + def setP3DFilename(self, p3dFilename, tokens = [], instanceId = None): # One day we will have support for multiple instances within a @@ -255,6 +268,34 @@ class AppRunner(DirectObject): self.sendRequest('notify', 'onwindowopen') + def scriptRequest(self, operation, object, propertyName = None, + value = None): + """ Issues a new script request to the browser. This queries + or modifies one of the browser's DOM properties. + + operation may be one of [ 'get_property', 'set_property', + 'call', 'evaluate' ]. + + object is the browser object to manipulate, or the scope in + which to evaluate the expression. + + propertyName is the name of the property to manipulate, if + relevant (set to None for the default method name). + + value is the new value to assign to the property for + set_property, or the parameter list for call, or the string + expression for evaluate. + """ + uniqueId = self.nextScriptId + self.nextScriptId += 1 + self.sendRequest('script', operation, object, + propertyName, value, uniqueId); + + def scriptResponse(self, uniqueId, value): + """ Called by the browser in response to a scriptRequest, + above. """ + print "Got scriptResponse: %s, %s" % (uniqueId, value) + def parseSysArgs(self): """ Converts sys.argv into (p3dFilename, tokens). """ import getopt @@ -287,6 +328,13 @@ class AppRunner(DirectObject): return (osFilename, tokens) +class BrowserObject: + """ This class provides the Python wrapper around some object that + actually exists in the plugin host's namespace, e.g. a JavaScript + or DOM object. """ + + def __init__(self, objectId): + self.__objectId = objectId if __name__ == '__main__':