瀏覽代碼

working on inbound scripting controls

David Rose 16 年之前
父節點
當前提交
13552a7041
共有 38 個文件被更改,包括 947 次插入270 次删除
  1. 10 10
      direct/src/plugin/load_plugin.cxx
  2. 2 2
      direct/src/plugin/load_plugin.h
  3. 0 14
      direct/src/plugin/p3dBoolObject.cxx
  4. 0 2
      direct/src/plugin/p3dBoolObject.h
  5. 0 15
      direct/src/plugin/p3dFloatObject.cxx
  6. 0 2
      direct/src/plugin/p3dFloatObject.h
  7. 141 19
      direct/src/plugin/p3dInstance.cxx
  8. 6 1
      direct/src/plugin/p3dInstance.h
  9. 3 2
      direct/src/plugin/p3dInstanceManager.cxx
  10. 0 14
      direct/src/plugin/p3dIntObject.cxx
  11. 0 2
      direct/src/plugin/p3dIntObject.h
  12. 0 13
      direct/src/plugin/p3dNoneObject.cxx
  13. 0 2
      direct/src/plugin/p3dNoneObject.h
  14. 88 1
      direct/src/plugin/p3dObject.cxx
  15. 4 15
      direct/src/plugin/p3dObject.h
  16. 9 14
      direct/src/plugin/p3dPythonObject.cxx
  17. 1 2
      direct/src/plugin/p3dPythonObject.h
  18. 120 21
      direct/src/plugin/p3dPythonRun.cxx
  19. 4 1
      direct/src/plugin/p3dPythonRun.h
  20. 98 1
      direct/src/plugin/p3dSession.cxx
  21. 2 1
      direct/src/plugin/p3dSession.h
  22. 0 14
      direct/src/plugin/p3dStringObject.cxx
  23. 0 2
      direct/src/plugin/p3dStringObject.h
  24. 4 4
      direct/src/plugin/p3d_plugin.cxx
  25. 29 10
      direct/src/plugin/p3d_plugin.h
  26. 13 0
      direct/src/plugin/p3d_plugin_common.h
  27. 2 0
      direct/src/plugin_npapi/Sources.pp
  28. 1 0
      direct/src/plugin_npapi/nppanda3d_composite1.cxx
  29. 14 0
      direct/src/plugin_npapi/ppBrowserObject.I
  30. 188 0
      direct/src/plugin_npapi/ppBrowserObject.cxx
  31. 57 0
      direct/src/plugin_npapi/ppBrowserObject.h
  32. 92 5
      direct/src/plugin_npapi/ppInstance.cxx
  33. 4 1
      direct/src/plugin_npapi/ppInstance.h
  34. 2 76
      direct/src/plugin_npapi/ppPandaObject.cxx
  35. 3 2
      direct/src/plugin_npapi/ppPandaObject.h
  36. 1 1
      direct/src/plugin_npapi/startup.cxx
  37. 1 1
      direct/src/plugin_standalone/panda3d.cxx
  38. 48 0
      direct/src/showutil/runp3d.py

+ 10 - 10
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_int_object_func *P3D_new_int_object;
 P3D_new_float_object_func *P3D_new_float_object;
 P3D_new_float_object_func *P3D_new_float_object;
 P3D_new_string_object_func *P3D_new_string_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_instance_get_request_func *P3D_instance_get_request;
 P3D_check_request_func *P3D_check_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_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_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_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_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");  
   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_int_object == NULL ||
       P3D_new_float_object == NULL ||
       P3D_new_float_object == NULL ||
       P3D_new_string_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_instance_get_request == NULL ||
       P3D_check_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_int_object = " << P3D_new_int_object
       << "\nP3D_new_float_object = " << P3D_new_float_object
       << "\nP3D_new_float_object = " << P3D_new_float_object
       << "\nP3D_new_string_object = " << P3D_new_string_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_instance_get_request = " << P3D_instance_get_request
       << "\nP3D_check_request = " << P3D_check_request
       << "\nP3D_check_request = " << P3D_check_request
@@ -313,8 +313,8 @@ unload_dso() {
   P3D_new_int_object = NULL;
   P3D_new_int_object = NULL;
   P3D_new_float_object = NULL;
   P3D_new_float_object = NULL;
   P3D_new_string_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_instance_get_request = NULL;
   P3D_check_request = NULL;
   P3D_check_request = NULL;

+ 2 - 2
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_int_object_func *P3D_new_int_object;
 extern P3D_new_float_object_func *P3D_new_float_object;
 extern P3D_new_float_object_func *P3D_new_float_object;
 extern P3D_new_string_object_func *P3D_new_string_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_instance_get_request_func *P3D_instance_get_request;
 extern P3D_check_request_func *P3D_check_request;
 extern P3D_check_request_func *P3D_check_request;

+ 0 - 14
direct/src/plugin/p3dBoolObject.cxx

@@ -81,17 +81,3 @@ make_string(string &value) const {
     value = "False";
     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;
-}

+ 0 - 2
direct/src/plugin/p3dBoolObject.h

@@ -33,8 +33,6 @@ public:
   virtual int get_int() const;
   virtual int get_int() const;
   virtual void make_string(string &value) const;
   virtual void make_string(string &value) const;
 
 
-  virtual TiXmlElement *make_xml() const;
-
 private:
 private:
   bool _value;
   bool _value;
 };
 };

+ 0 - 15
direct/src/plugin/p3dFloatObject.cxx

@@ -90,18 +90,3 @@ make_string(string &value) const {
   strm << _value;
   strm << _value;
   value = strm.str();
   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;
-}

+ 0 - 2
direct/src/plugin/p3dFloatObject.h

@@ -34,8 +34,6 @@ public:
   virtual double get_float() const;
   virtual double get_float() const;
   virtual void make_string(string &value) const;
   virtual void make_string(string &value) const;
 
 
-  virtual TiXmlElement *make_xml() const;
-
 private:
 private:
   double _value;
   double _value;
 };
 };

+ 141 - 19
direct/src/plugin/p3dInstance.cxx

@@ -43,6 +43,7 @@ P3DInstance::
 P3DInstance(P3D_request_ready_func *func, void *user_data) :
 P3DInstance(P3D_request_ready_func *func, void *user_data) :
   _func(func)
   _func(func)
 {
 {
+  _browser_script_object = NULL;
   _user_data = user_data;
   _user_data = user_data;
   _request_pending = false;
   _request_pending = false;
   _got_fparams = false;
   _got_fparams = false;
@@ -68,6 +69,10 @@ P3DInstance::
 ~P3DInstance() {
 ~P3DInstance() {
   assert(_session == NULL);
   assert(_session == NULL);
 
 
+  if (_browser_script_object != NULL) {
+    P3D_OBJECT_FINISH(_browser_script_object);
+  }
+
   DESTROY_LOCK(_request_lock);
   DESTROY_LOCK(_request_lock);
 
 
   // Tell all of the packages that we're no longer in business for
   // 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
 //       Access: Public
 //  Description: Returns a pointer to the top-level scriptable object
 //  Description: Returns a pointer to the top-level scriptable object
 //               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::
 P3DObject *P3DInstance::
-get_script_object() const {
+get_panda_script_object() const {
   assert(_session != NULL);
   assert(_session != NULL);
-  nout << "Called P3DInstance::get_script_object()\n";
+  nout << "Called P3DInstance::get_panda_script_object()\n";
 
 
   TiXmlDocument *doc = new TiXmlDocument;
   TiXmlDocument *doc = new TiXmlDocument;
   TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
   TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
   TiXmlElement *xcommand = new TiXmlElement("command");
   TiXmlElement *xcommand = new TiXmlElement("command");
   xcommand->SetAttribute("cmd", "pyobj");
   xcommand->SetAttribute("cmd", "pyobj");
-  xcommand->SetAttribute("op", "get_script_object");
+  xcommand->SetAttribute("op", "get_panda_script_object");
   doc->LinkEndChild(decl);
   doc->LinkEndChild(decl);
   doc->LinkEndChild(xcommand);
   doc->LinkEndChild(xcommand);
   TiXmlDocument *response = _session->command_and_response(doc);
   TiXmlDocument *response = _session->command_and_response(doc);
@@ -202,6 +207,29 @@ get_script_object() const {
   return result;
   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
 //     Function: P3DInstance::has_request
@@ -237,22 +265,22 @@ get_request() {
   }
   }
   RELEASE_LOCK(_request_lock);
   RELEASE_LOCK(_request_lock);
 
 
+  nout << "get_request: " << result << "\n" << flush;
+
   if (result != NULL) {
   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;
   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
 //     Function: P3DInstance::make_splash_window
 //       Access: Private
 //       Access: Private

+ 6 - 1
direct/src/plugin/p3dInstance.h

@@ -46,7 +46,8 @@ 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_script_object() const;
+  P3DObject *get_panda_script_object() const;
+  void set_browser_script_object(P3D_object *object);
 
 
   bool has_request();
   bool has_request();
   P3D_request *get_request();
   P3D_request *get_request();
@@ -86,10 +87,14 @@ private:
     P3DInstance *_inst;
     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 make_splash_window();
   void install_progress(P3DPackage *package, double progress);
   void install_progress(P3DPackage *package, double progress);
 
 
   P3D_request_ready_func *_func;
   P3D_request_ready_func *_func;
+  P3D_object *_browser_script_object;
 
 
   bool _got_fparams;
   bool _got_fparams;
   P3DFileParams _fparams;
   P3DFileParams _fparams;

+ 3 - 2
direct/src/plugin/p3dInstanceManager.cxx

@@ -301,8 +301,9 @@ signal_request_ready(P3DInstance *inst) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3D_class_definition *P3DInstanceManager::
 P3D_class_definition *P3DInstanceManager::
 make_class_definition() const {
 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;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 0 - 14
direct/src/plugin/p3dIntObject.cxx

@@ -80,17 +80,3 @@ make_string(string &value) const {
   value = strm.str();
   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;
-}

+ 0 - 2
direct/src/plugin/p3dIntObject.h

@@ -33,8 +33,6 @@ public:
   virtual int get_int() const;
   virtual int get_int() const;
   virtual void make_string(string &value) const;
   virtual void make_string(string &value) const;
 
 
-  virtual TiXmlElement *make_xml() const;
-
 private:
 private:
   int _value;
   int _value;
 };
 };

+ 0 - 13
direct/src/plugin/p3dNoneObject.cxx

@@ -54,16 +54,3 @@ void P3DNoneObject::
 make_string(string &value) const {
 make_string(string &value) const {
   value = "None";
   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;
-}

+ 0 - 2
direct/src/plugin/p3dNoneObject.h

@@ -31,8 +31,6 @@ public:
   virtual P3D_object_type get_type() const;
   virtual P3D_object_type get_type() const;
   virtual bool get_bool() const;
   virtual bool get_bool() const;
   virtual void make_string(string &value) const;
   virtual void make_string(string &value) const;
-
-  virtual TiXmlElement *make_xml() const;
 };
 };
 
 
 #endif
 #endif

+ 88 - 1
direct/src/plugin/p3dObject.cxx

@@ -15,7 +15,7 @@
 #include "p3dObject.h"
 #include "p3dObject.h"
 #include <string.h>  // strncpy
 #include <string.h>  // 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
 // P3DObject virtual methods; they are defined to allow us to create
 // the C-style P3D_class_definition method table to store in the
 // the C-style P3D_class_definition method table to store in the
 // P3D_object structure.
 // P3D_object structure.
@@ -93,6 +93,93 @@ P3D_class_definition P3DObject::_object_class = {
   &object_call,
   &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
 //     Function: P3DObject::Destructor
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 4 - 15
direct/src/plugin/p3dObject.h

@@ -49,8 +49,6 @@ public:
   virtual P3D_object *call(const string &method_name, 
   virtual P3D_object *call(const string &method_name, 
                            P3D_object *params[], int num_params) const;
                            P3D_object *params[], int num_params) const;
 
 
-  virtual TiXmlElement *make_xml() const=0;
-
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;
 
 
   inline void ref() const;
   inline void ref() const;
@@ -62,28 +60,19 @@ private:
 
 
 public:
 public:
   static P3D_class_definition _object_class;
   static P3D_class_definition _object_class;
+  static P3D_class_definition _generic_class;
 };
 };
 
 
 #include "p3dObject.I"
 #include "p3dObject.I"
 
 
 // For classes that inherit from P3DObject, above, we can use the
 // 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) {
 inline ostream &operator << (ostream &out, const P3DObject &value) {
   value.output(out);
   value.output(out);
   return 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
 #endif
 
 

+ 9 - 14
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) {
   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);
     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
@@ -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;
 }
 }
+

+ 1 - 2
direct/src/plugin/p3dPythonObject.h

@@ -47,9 +47,8 @@ public:
   virtual P3D_object *call(const string &method_name, 
   virtual P3D_object *call(const string &method_name, 
                            P3D_object *params[], int num_params) const;
                            P3D_object *params[], int num_params) const;
 
 
-  virtual TiXmlElement *make_xml() const;
-
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;
+  int get_object_id() const;
 
 
 private:
 private:
   P3DSession *_session;
   P3DSession *_session;

+ 120 - 21
direct/src/plugin/p3dPythonRun.cxx

@@ -112,19 +112,26 @@ run_python() {
   }
   }
 
 
   // Get the pointers to the objects needed within the module.
   // 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();
     PyErr_Print();
     return false;
     return false;
   }
   }
 
 
   // Construct an instance of AppRunner.
   // Construct an instance of AppRunner.
-  _runner = PyObject_CallFunction(AppRunner, (char*) "");
+  _runner = PyObject_CallFunction(app_runner_class, (char *)"");
   if (_runner == NULL) {
   if (_runner == NULL) {
     PyErr_Print();
     PyErr_Print();
     return false;
     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.
   // Get the global TaskManager.
   _taskMgr = PyObject_GetAttrString(runp3d, "taskMgr");
   _taskMgr = PyObject_GetAttrString(runp3d, "taskMgr");
@@ -139,7 +146,7 @@ run_python() {
   // Construct a Python wrapper around our request_func() method.
   // Construct a Python wrapper around our request_func() method.
   static PyMethodDef p3dpython_methods[] = {
   static PyMethodDef p3dpython_methods[] = {
     {"request_func", P3DPythonRun::st_request_func, METH_VARARGS,
     {"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 */
     {NULL, NULL, 0, NULL}        /* Sentinel */
   };
   };
   PyObject *p3dpython = Py_InitModule("p3dpython", p3dpython_methods);
   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
   // Now pass that func pointer back to our AppRunner instance, so it
   // can call up to us.
   // 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) {
   if (result == NULL) {
     PyErr_Print();
     PyErr_Print();
     return false;
     return false;
@@ -171,7 +178,7 @@ run_python() {
 
 
   // Finally, get lost in taskMgr.run().
   // Finally, get lost in taskMgr.run().
   nout << "calling run()\n";
   nout << "calling run()\n";
-  PyObject *done = PyObject_CallMethod(_taskMgr, (char*) "run", (char*) "");
+  PyObject *done = PyObject_CallMethod(_taskMgr, (char *)"run", (char *)"");
   if (done == NULL) {
   if (done == NULL) {
     PyErr_Print();
     PyErr_Print();
     return false;
     return false;
@@ -231,11 +238,13 @@ handle_command(TiXmlDocument *doc) {
         terminate_session();
         terminate_session();
 
 
       } else if (strcmp(cmd, "pyobj") == 0) {
       } 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 {
       } else {
         nout << "Unhandled command " << cmd << "\n";
         nout << "Unhandled command " << cmd << "\n";
@@ -262,7 +271,8 @@ handle_command(TiXmlDocument *doc) {
 //               a Python object from the browser scripts.
 //               a Python object from the browser scripts.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DPythonRun::
 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;
   TiXmlDocument doc;
   TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
   TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
   TiXmlElement *xresponse = new TiXmlElement("response");
   TiXmlElement *xresponse = new TiXmlElement("response");
@@ -272,13 +282,30 @@ handle_pyobj_command(TiXmlElement *xcommand, int want_response_id) {
 
 
   const char *op = xcommand->Attribute("op");
   const char *op = xcommand->Attribute("op");
   if (op != NULL) {
   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");
       PyObject *obj = PyObject_GetAttrString(_runner, "scriptRoot");
       if (obj != NULL) {
       if (obj != NULL) {
         xresponse->LinkEndChild(pyobj_to_xml(obj));
         xresponse->LinkEndChild(pyobj_to_xml(obj));
         Py_DECREF(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) {
     } else if (strcmp(op, "call") == 0) {
       // Call the named method on the indicated object, or the object
       // Call the named method on the indicated object, or the object
       // itself if method_name isn't given.
       // 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;
     nout << "sending " << doc << "\n" << flush;
     _pipe_write << doc << 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) {
   } else if (strcmp(request_type, "evaluate") == 0) {
     // An evaluate request.
     // An evaluate request.
     const char *expression;
     const char *expression;
@@ -471,6 +549,7 @@ py_request_func(PyObject *args) {
     xrequest->SetAttribute("unique_id", unique_id);
     xrequest->SetAttribute("unique_id", unique_id);
     nout << "sending " << doc << "\n" << flush;
     nout << "sending " << doc << "\n" << flush;
     _pipe_write << doc << flush;
     _pipe_write << doc << flush;
+    */
 
 
   } else {
   } else {
     string message = string("Unsupported request type: ") + string(request_type);
     string message = string("Unsupported request type: ") + string(request_type);
@@ -610,7 +689,7 @@ set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams) {
   }
   }
   
   
   PyObject *result = PyObject_CallMethod
   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());
      token_list, inst->get_instance_id());
   Py_DECREF(token_list);
   Py_DECREF(token_list);
 
 
@@ -669,7 +748,7 @@ setup_window(P3DCInstance *inst, TiXmlElement *xwparams) {
   // TODO: direct this into the particular instance.  This will
   // TODO: direct this into the particular instance.  This will
   // require a specialized ShowBase replacement.
   // require a specialized ShowBase replacement.
   PyObject *result = PyObject_CallMethod
   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,
      win_x, win_y, win_width, win_height,
      parent_window_handle);
      parent_window_handle);
   if (result == NULL) {
   if (result == NULL) {
@@ -694,7 +773,7 @@ terminate_session() {
   _instances.clear();
   _instances.clear();
 
 
   nout << "calling stop()\n";
   nout << "calling stop()\n";
-  PyObject *result = PyObject_CallMethod(_taskMgr, (char*) "stop", (char*) "");
+  PyObject *result = PyObject_CallMethod(_taskMgr, (char *)"stop", (char *)"");
   if (result == NULL) {
   if (result == NULL) {
     PyErr_Print();
     PyErr_Print();
     return;
     return;
@@ -772,15 +851,28 @@ pyobj_to_xml(PyObject *value) {
       xvalue->SetAttribute("value", str);
       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 {
   } else {
     // Some other kind of object.  Make it a generic Python object.
     // Some other kind of object.  Make it a generic Python object.
     // This is more expensive for the caller to deal with--it requires
     // 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
     // a back-and-forth across the XML pipe--but it's much more
     // general.
     // general.
+    // TODO: pass pointers better.
     xvalue->SetAttribute("type", "python");
     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);
     Py_INCREF(value);
   }
   }
 
 
@@ -825,6 +917,13 @@ xml_to_pyobj(TiXmlElement *xvalue) {
       return PyString_FromStringAndSize(value->data(), value->length());
       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) {
   } 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) {

+ 4 - 1
direct/src/plugin/p3dPythonRun.h

@@ -70,7 +70,9 @@ public:
 
 
 private:
 private:
   void handle_command(TiXmlDocument *doc);
   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);
   AsyncTask::DoneStatus check_comm(GenericAsyncTask *task);
   static AsyncTask::DoneStatus st_check_comm(GenericAsyncTask *task, void *user_data);
   static AsyncTask::DoneStatus st_check_comm(GenericAsyncTask *task, void *user_data);
@@ -107,6 +109,7 @@ private:
   char **_py_argv;
   char **_py_argv;
 
 
   PyObject *_runner;
   PyObject *_runner;
+  PyObject *_browser_object_class;
   PyObject *_taskMgr;
   PyObject *_taskMgr;
 
 
   PT(GenericAsyncTask) _check_comm_task;
   PT(GenericAsyncTask) _check_comm_task;

+ 98 - 1
direct/src/plugin/p3dSession.cxx

@@ -156,6 +156,7 @@ start_instance(P3DInstance *inst) {
   xcommand->LinkEndChild(xinstance);
   xcommand->LinkEndChild(xinstance);
 
 
   send_command(doc);
   send_command(doc);
+  inst->send_browser_script_object();
 
 
   if (_panda3d->get_ready()) {
   if (_panda3d->get_ready()) {
     // If it's ready immediately, go ahead and start.
     // If it's ready immediately, go ahead and start.
@@ -212,6 +213,7 @@ void P3DSession::
 send_command(TiXmlDocument *command) {
 send_command(TiXmlDocument *command) {
   if (_p3dpython_running) {
   if (_p3dpython_running) {
     // Python is running.  Send the command.
     // Python is running.  Send the command.
+    nout << "Sending " << *command << "\n" << flush;
     _pipe_write << *command << flush;
     _pipe_write << *command << flush;
     delete command;
     delete command;
   } else {
   } else {
@@ -300,7 +302,7 @@ command_and_response(TiXmlDocument *command) {
 //               Returns the newly-allocated object.
 //               Returns the newly-allocated object.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3DObject *P3DSession::
 P3DObject *P3DSession::
-xml_to_object(TiXmlElement *xvalue) {
+xml_to_object(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;
@@ -342,6 +344,75 @@ xml_to_object(TiXmlElement *xvalue) {
   return new P3DNoneObject;
   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
 //     Function: P3DSession::install_progress
 //       Access: Private
 //       Access: Private
@@ -584,6 +655,32 @@ rt_make_p3d_request(TiXmlElement *xrequest) {
         request->_request._notify._message = strdup(message);
         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 {
     } else {
       nout << "ignoring request of type " << rtype << "\n";
       nout << "ignoring request of type " << rtype << "\n";
     }
     }

+ 2 - 1
direct/src/plugin/p3dSession.h

@@ -49,7 +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(TiXmlElement *xvalue);
+  P3DObject *xml_to_object(const TiXmlElement *xvalue);
+  TiXmlElement *object_to_xml(const P3D_object *obj);
 
 
 private:
 private:
   void install_progress(P3DPackage *package, double progress);
   void install_progress(P3DPackage *package, double progress);

+ 0 - 14
direct/src/plugin/p3dStringObject.cxx

@@ -76,20 +76,6 @@ make_string(string &value) const {
   value = _value;
   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
 //     Function: P3DStringObject::output
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 0 - 2
direct/src/plugin/p3dStringObject.h

@@ -34,8 +34,6 @@ public:
   virtual bool get_bool() const;
   virtual bool get_bool() const;
   virtual void make_string(string &value) const;
   virtual void make_string(string &value) const;
 
 
-  virtual TiXmlElement *make_xml() const;
-
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;
 
 
 private:
 private:

+ 4 - 4
direct/src/plugin/p3d_plugin.cxx

@@ -188,23 +188,23 @@ P3D_new_string_object(const char *str, int length) {
 }
 }
 
 
 P3D_object *
 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());
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_api_lock);
   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);
   RELEASE_LOCK(_api_lock);
   return result;
   return result;
 }
 }
 
 
 void
 void
-P3D_instance_set_script_object(P3D_instance *instance, 
+P3D_instance_set_browser_script_object(P3D_instance *instance, 
                                P3D_object *object) {
                                P3D_object *object) {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_api_lock);
   ACQUIRE_LOCK(_api_lock);
 
 
-  // TODO.
+  ((P3DInstance *)instance)->set_browser_script_object(object);
   
   
   RELEASE_LOCK(_api_lock);
   RELEASE_LOCK(_api_lock);
 }
 }

+ 29 - 10
direct/src/plugin/p3d_plugin.h

@@ -443,7 +443,7 @@ struct _P3D_object {
    generic function pointers that have reasonable default behavior for
    generic function pointers that have reasonable default behavior for
    all methods.  The host should use this function to get a clean
    all methods.  The host should use this function to get a clean
    P3D_class_definition object before calling
    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
    pointer will automatically be freed when P3D_finalize() is
    called. */
    called. */
 typedef P3D_class_definition *
 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
    ownership of the object is passed to the caller, who should be
    responsible for deleting it eventually. */
    responsible for deleting it eventually. */
 typedef P3D_object *
 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
 /* The inverse functionality: this supplies an object pointer to the
    instance to allow the Panda instance to control the browser.  In
    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
    have a custom P3D_class_definition pointer, which also must have
    been created by the host.  The best way to create an appropriate
    been created by the host.  The best way to create an appropriate
    class definition is call P3D_make_class_definition(), and then
    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
    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
    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. 
    above. 
 
 
    Ownership of the object is passed into the instance.  The caller
    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
    or delete it.  The instance will eventually delete it by calling
    its _finish method. */
    its _finish method. */
 typedef void
 typedef void
-P3D_instance_set_script_object_func(P3D_instance *instance, 
+P3D_instance_set_browser_script_object_func(P3D_instance *instance, 
                                     P3D_object *object);
                                     P3D_object *object);
 
 
 
 
@@ -543,6 +543,7 @@ typedef enum {
   P3D_RT_get_url,
   P3D_RT_get_url,
   P3D_RT_post_url,
   P3D_RT_post_url,
   P3D_RT_notify,
   P3D_RT_notify,
+  P3D_RT_script,
 } P3D_request_type;
 } P3D_request_type;
 
 
 /* Structures corresponding to the request types in the above enum. */
 /* Structures corresponding to the request types in the above enum. */
@@ -586,6 +587,23 @@ typedef struct {
   const char *_message;
   const char *_message;
 } P3D_request_notify;
 } 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
 /* This is the overall structure that represents a single request.  It
    is returned by P3D_instance_get_request(). */
    is returned by P3D_instance_get_request(). */
 typedef struct {
 typedef struct {
@@ -596,6 +614,7 @@ typedef struct {
     P3D_request_get_url _get_url;
     P3D_request_get_url _get_url;
     P3D_request_post_url _post_url;
     P3D_request_post_url _post_url;
     P3D_request_notify _notify;
     P3D_request_notify _notify;
+    P3D_request_script _script;
   } _request;
   } _request;
 } P3D_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_int_object_func P3D_new_int_object;
 EXPCL_P3D_PLUGIN P3D_new_float_object_func P3D_new_float_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_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_instance_get_request_func P3D_instance_get_request;
 EXPCL_P3D_PLUGIN P3D_check_request_func P3D_check_request;
 EXPCL_P3D_PLUGIN P3D_check_request_func P3D_check_request;

+ 13 - 0
direct/src/plugin/p3d_plugin_common.h

@@ -39,5 +39,18 @@ extern string plugin_output_filename;
 extern ostream *nout_stream;
 extern ostream *nout_stream;
 #define nout (*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
 #endif
 
 

+ 2 - 0
direct/src/plugin_npapi/Sources.pp

@@ -17,12 +17,14 @@
 
 
   #define SOURCES \
   #define SOURCES \
     nppanda3d_common.h \
     nppanda3d_common.h \
+    ppBrowserObject.h ppBrowserObject.I \
     ppDownloadRequest.h ppDownloadRequest.I \
     ppDownloadRequest.h ppDownloadRequest.I \
     ppInstance.h ppInstance.I \
     ppInstance.h ppInstance.I \
     ppPandaObject.h ppPandaObject.I \
     ppPandaObject.h ppPandaObject.I \
     startup.h
     startup.h
 
 
   #define INCLUDED_SOURCES \
   #define INCLUDED_SOURCES \
+    ppBrowserObject.cxx \
     ppDownloadRequest.cxx \
     ppDownloadRequest.cxx \
     ppInstance.cxx \
     ppInstance.cxx \
     ppPandaObject.cxx \
     ppPandaObject.cxx \

+ 1 - 0
direct/src/plugin_npapi/nppanda3d_composite1.cxx

@@ -1,3 +1,4 @@
+#include "ppBrowserObject.cxx"
 #include "ppDownloadRequest.cxx"
 #include "ppDownloadRequest.cxx"
 #include "ppInstance.cxx"
 #include "ppInstance.cxx"
 #include "ppPandaObject.cxx"
 #include "ppPandaObject.cxx"

+ 14 - 0
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."
+//
+////////////////////////////////////////////////////////////////////
+

+ 188 - 0
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 <sstream>
+#include <string.h>  // 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 &copy) :
+  _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;
+  }
+}

+ 57 - 0
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 &copy);
+  ~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
+

+ 92 - 5
direct/src/plugin_npapi/ppInstance.cxx

@@ -14,6 +14,7 @@
 
 
 #include "ppInstance.h"
 #include "ppInstance.h"
 #include "ppPandaObject.h"
 #include "ppPandaObject.h"
+#include "ppBrowserObject.h"
 #include "startup.h"
 #include "startup.h"
 #include "p3d_plugin_config.h"
 #include "p3d_plugin_config.h"
 #include "find_root_dir.h"
 #include "find_root_dir.h"
@@ -399,7 +400,7 @@ handle_request(P3D_request *request) {
           strcmp(request->_request._notify._message, "onpythonload") == 0) {
           strcmp(request->_request._notify._message, "onpythonload") == 0) {
         // Now that Python is running, initialize our script_object
         // Now that Python is running, initialize our script_object
         // with the proper P3D object pointer.
         // 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;
         logfile << "late obj = " << obj << "\n" << flush;
         _script_object->set_p3d_object(obj);
         _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
 //       Access: Public
 //  Description: Returns a toplevel object that JavaScript or whatever
 //  Description: Returns a toplevel object that JavaScript or whatever
 //               can read and/or modify to control the instance.
 //               can read and/or modify to control the instance.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 NPObject *PPInstance::
 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) {
   if (_script_object != NULL) {
     logfile << "returning _script_object ref = " << _script_object->referenceCount << "\n";
     logfile << "returning _script_object ref = " << _script_object->referenceCount << "\n";
     return _script_object;
     return _script_object;
@@ -432,7 +433,7 @@ get_script_object() {
   P3D_object *obj = NULL;
   P3D_object *obj = NULL;
 
 
   if (_p3d_inst != 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;
     logfile << "obj = " << obj << "\n" << flush;
   }
   }
 
 
@@ -444,6 +445,80 @@ get_script_object() {
   return _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
 //     Function: PPInstance::read_contents_file
 //       Access: Private
 //       Access: Private
@@ -619,6 +694,18 @@ create_instance() {
   _p3d_inst = P3D_new_instance(request_ready, this);
   _p3d_inst = P3D_new_instance(request_ready, this);
 
 
   if (_p3d_inst != NULL) {
   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;
     const P3D_token *tokens = NULL;
     if (!_tokens.empty()) {
     if (!_tokens.empty()) {
       tokens = &_tokens[0];
       tokens = &_tokens[0];

+ 4 - 1
direct/src/plugin_npapi/ppInstance.h

@@ -48,7 +48,10 @@ public:
 
 
   void handle_request(P3D_request *request);
   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:
 private:
   bool read_contents_file(const string &filename);
   bool read_contents_file(const string &filename);

+ 2 - 76
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.
   // 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);
   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 = 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);
   bool result = P3D_OBJECT_SET_PROPERTY(_p3d_object, property_name.c_str(), object);
   return result;
   return result;
 }
 }
@@ -267,80 +267,6 @@ identifier_to_string(NPIdentifier ident) {
   return string();
   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
 // The remaining function bodies are the C-style function wrappers
 // that are called directly by NPAPI, and which redirect into the
 // that are called directly by NPAPI, and which redirect into the

+ 3 - 2
direct/src/plugin_npapi/ppPandaObject.h

@@ -23,6 +23,9 @@
 //               P3D_object.  It maps calls from NPAPI into the
 //               P3D_object.  It maps calls from NPAPI into the
 //               P3D_object system, thus allowing the browser to
 //               P3D_object system, thus allowing the browser to
 //               view and operate on a Panda object.
 //               view and operate on a Panda object.
+//
+//               Also see PPBrowserObject, which maps calls the other
+//               way.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class PPPandaObject : public NPObject {
 class PPPandaObject : public NPObject {
 public:
 public:
@@ -51,8 +54,6 @@ private:
 
 
 private:
 private:
   static string identifier_to_string(NPIdentifier ident);
   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:
 private:

+ 1 - 1
direct/src/plugin_npapi/startup.cxx

@@ -407,7 +407,7 @@ NPP_GetValue(NPP instance, NPPVariable variable, void *value) {
   assert(inst != NULL);
   assert(inst != NULL);
 
 
   if (variable == NPPVpluginScriptableNPObject) {
   if (variable == NPPVpluginScriptableNPObject) {
-    NPObject *obj = inst->get_script_object();
+    NPObject *obj = inst->get_panda_script_object();
     if (obj != NULL) {
     if (obj != NULL) {
       *(NPObject **)value = obj;
       *(NPObject **)value = obj;
       return NPERR_NO_ERROR;
       return NPERR_NO_ERROR;

+ 1 - 1
direct/src/plugin_standalone/panda3d.cxx

@@ -409,7 +409,7 @@ handle_request(P3D_request *request) {
     /*
     /*
     {
     {
       // Temporary.
       // 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";
       cerr << "script_object is " << obj << "\n";
       if (obj != NULL) {
       if (obj != NULL) {
         if (P3D_OBJECT_SET_PROPERTY(obj, "foo", P3D_new_int_object(1))) {
         if (P3D_OBJECT_SET_PROPERTY(obj, "foo", P3D_new_int_object(1))) {

+ 48 - 0
direct/src/showutil/runp3d.py

@@ -57,10 +57,16 @@ class AppRunner(DirectObject):
         self.started = False
         self.started = False
         self.windowPrc = None
         self.windowPrc = None
 
 
+        # This is per session.
+        self.nextScriptId = 0
+
         # TODO: we need one of these per instance, not per session.
         # TODO: we need one of these per instance, not per session.
         self.instanceId = None
         self.instanceId = None
         self.scriptRoot = ScriptRoot()
         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
         # This is the default requestFunc that is installed if we
         # never call setRequestFunc().
         # never call setRequestFunc().
         def defaultRequestFunc(*args):
         def defaultRequestFunc(*args):
@@ -145,6 +151,13 @@ class AppRunner(DirectObject):
             if hasattr(main, 'main') and callable(main.main):
             if hasattr(main, 'main') and callable(main.main):
                 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 = [],
     def setP3DFilename(self, p3dFilename, tokens = [],
                        instanceId = None):
                        instanceId = None):
         # One day we will have support for multiple instances within a
         # One day we will have support for multiple instances within a
@@ -255,6 +268,34 @@ class AppRunner(DirectObject):
 
 
         self.sendRequest('notify', 'onwindowopen')
         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):
     def parseSysArgs(self):
         """ Converts sys.argv into (p3dFilename, tokens). """
         """ Converts sys.argv into (p3dFilename, tokens). """
         import getopt
         import getopt
@@ -287,6 +328,13 @@ class AppRunner(DirectObject):
 
 
         return (osFilename, tokens)
         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__':
 if __name__ == '__main__':