Browse Source

more scriptability wip

David Rose 16 years ago
parent
commit
a64a4f09c5

+ 15 - 2
direct/src/plugin/p3dBoolVariant.cxx

@@ -79,9 +79,22 @@ get_int() const {
 void P3DBoolVariant::
 void P3DBoolVariant::
 make_string(string &value) const {
 make_string(string &value) const {
   if (_value) {
   if (_value) {
-    value = "1";
+    value = "True";
   } else {
   } else {
-    value = "0";
+    value = "False";
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DBoolVariant::make_xml
+//       Access: Public, Virtual
+//  Description: Allocates and returns a new XML structure
+//               corresponding to this variant.
+////////////////////////////////////////////////////////////////////
+TiXmlElement *P3DBoolVariant::
+make_xml() const {
+  TiXmlElement *xvariant = new TiXmlElement("variant");
+  xvariant->SetAttribute("type", "bool");
+  xvariant->SetAttribute("value", (int)_value);
+  return xvariant;
+}

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

@@ -33,6 +33,8 @@ 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;
 };
 };

+ 1 - 1
direct/src/plugin/p3dCInstance.cxx

@@ -24,7 +24,7 @@ P3DCInstance::
 P3DCInstance(TiXmlElement *xinstance) :
 P3DCInstance(TiXmlElement *xinstance) :
   _func(NULL)
   _func(NULL)
 {
 {
-  xinstance->Attribute("id", &_instance_id);
+  xinstance->Attribute("instance_id", &_instance_id);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

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

@@ -94,3 +94,17 @@ make_string(string &value) const {
   value = strm.str();
   value = strm.str();
 }
 }
 
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DFloatVariant::make_xml
+//       Access: Public, Virtual
+//  Description: Allocates and returns a new XML structure
+//               corresponding to this variant.
+////////////////////////////////////////////////////////////////////
+TiXmlElement *P3DFloatVariant::
+make_xml() const {
+  TiXmlElement *xvariant = new TiXmlElement("variant");
+  xvariant->SetAttribute("type", "float");
+  xvariant->SetDoubleAttribute("value", _value);
+  return xvariant;
+}

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

@@ -34,6 +34,8 @@ 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;
 };
 };

+ 21 - 3
direct/src/plugin/p3dInstance.cxx

@@ -144,10 +144,10 @@ set_wparams(const P3DWindowParams &wparams) {
   // Update the instance in the sub-process.
   // Update the instance in the sub-process.
   if (_session != NULL) {
   if (_session != NULL) {
     TiXmlDocument *doc = new TiXmlDocument;
     TiXmlDocument *doc = new TiXmlDocument;
-    TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
+    TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
     TiXmlElement *xcommand = new TiXmlElement("command");
     TiXmlElement *xcommand = new TiXmlElement("command");
     xcommand->SetAttribute("cmd", "setup_window");
     xcommand->SetAttribute("cmd", "setup_window");
-    xcommand->SetAttribute("id", get_instance_id());
+    xcommand->SetAttribute("instance_id", get_instance_id());
     TiXmlElement *xwparams = _wparams.make_xml();
     TiXmlElement *xwparams = _wparams.make_xml();
     
     
     doc->LinkEndChild(decl);
     doc->LinkEndChild(decl);
@@ -354,6 +354,24 @@ feed_url_stream(int unique_id,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 void P3DInstance::
 feed_value(int unique_id, P3DVariant *variant) {
 feed_value(int unique_id, P3DVariant *variant) {
+  if (_session != NULL) {
+    TiXmlDocument *doc = new TiXmlDocument;
+    TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
+    TiXmlElement *xcommand = new TiXmlElement("command");
+    xcommand->SetAttribute("cmd", "feed_value");
+    xcommand->SetAttribute("instance_id", get_instance_id());
+    xcommand->SetAttribute("unique_id", unique_id);
+    if (variant != NULL) {
+      TiXmlElement *xvariant = variant->make_xml();
+      xcommand->LinkEndChild(xvariant);
+    }
+    
+    doc->LinkEndChild(decl);
+    doc->LinkEndChild(xcommand);
+
+    _session->send_command(doc);
+  }
+
   if (variant != NULL) {
   if (variant != NULL) {
     delete variant;
     delete variant;
   }
   }
@@ -435,7 +453,7 @@ make_xml() {
   assert(_got_fparams);
   assert(_got_fparams);
 
 
   TiXmlElement *xinstance = new TiXmlElement("instance");
   TiXmlElement *xinstance = new TiXmlElement("instance");
-  xinstance->SetAttribute("id", _instance_id);
+  xinstance->SetAttribute("instance_id", _instance_id);
 
 
   TiXmlElement *xfparams = _fparams.make_xml();
   TiXmlElement *xfparams = _fparams.make_xml();
   xinstance->LinkEndChild(xfparams);
   xinstance->LinkEndChild(xfparams);

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

@@ -83,3 +83,17 @@ make_string(string &value) const {
   value = strm.str();
   value = strm.str();
 }
 }
 
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DIntVariant::make_xml
+//       Access: Public, Virtual
+//  Description: Allocates and returns a new XML structure
+//               corresponding to this variant.
+////////////////////////////////////////////////////////////////////
+TiXmlElement *P3DIntVariant::
+make_xml() const {
+  TiXmlElement *xvariant = new TiXmlElement("variant");
+  xvariant->SetAttribute("type", "int");
+  xvariant->SetAttribute("value", _value);
+  return xvariant;
+}

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

@@ -33,6 +33,8 @@ 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;
 };
 };

+ 45 - 6
direct/src/plugin/p3dListVariant.cxx

@@ -14,12 +14,24 @@
 
 
 #include "p3dListVariant.h"
 #include "p3dListVariant.h"
 
 
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DListVariant::Constructor
+//     Function: P3DListVariant::Default Constructor
 //       Access: Public
 //       Access: Public
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3DListVariant::
 P3DListVariant::
+P3DListVariant() : P3DVariant(P3D_VT_list) { 
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DListVariant::Constructor
+//       Access: Public
+//  Description: Note that the ownership of the elements in the array
+//               (but not the array itself) is transferred to the
+//               list.
+////////////////////////////////////////////////////////////////////
+P3DListVariant::
 P3DListVariant(P3DVariant * const elements[], int num_elements) :
 P3DListVariant(P3DVariant * const elements[], int num_elements) :
   P3DVariant(P3D_VT_list)
   P3DVariant(P3D_VT_list)
 {
 {
@@ -90,12 +102,9 @@ make_string(string &value) const {
   ostringstream strm;
   ostringstream strm;
   strm << "[";
   strm << "[";
   if (!_elements.empty()) {
   if (!_elements.empty()) {
-    string es;
-    _elements[0]->make_string(es);
-    strm << es;
+    strm << *_elements[0];
     for (size_t i = 1; i < _elements.size(); ++i) {
     for (size_t i = 1; i < _elements.size(); ++i) {
-      _elements[0]->make_string(es);
-      strm << ", " << es;
+      strm << ", " << *_elements[i];
     }
     }
   }
   }
   strm << "]";
   strm << "]";
@@ -128,3 +137,33 @@ get_list_item(int n) const {
 
 
   return NULL;
   return NULL;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DListVariant::append_item
+//       Access: Public, Virtual
+//  Description: Appends a new item to the end of the list.  Ownership
+//               of the item is transferred to the list.
+////////////////////////////////////////////////////////////////////
+void P3DListVariant::
+append_item(P3DVariant *item) {
+  _elements.push_back(item);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DListVariant::make_xml
+//       Access: Public, Virtual
+//  Description: Allocates and returns a new XML structure
+//               corresponding to this variant.
+////////////////////////////////////////////////////////////////////
+TiXmlElement *P3DListVariant::
+make_xml() const {
+  TiXmlElement *xvariant = new TiXmlElement("variant");
+  xvariant->SetAttribute("type", "list");
+  Elements::const_iterator ei;
+  for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
+    TiXmlElement *xchild = (*ei)->make_xml();
+    xvariant->LinkEndChild(xchild);
+  }
+
+  return xvariant;
+}

+ 5 - 0
direct/src/plugin/p3dListVariant.h

@@ -24,6 +24,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class P3DListVariant : public P3DVariant {
 class P3DListVariant : public P3DVariant {
 public:
 public:
+  P3DListVariant();
   P3DListVariant(P3DVariant * const elements[], int num_elements);
   P3DListVariant(P3DVariant * const elements[], int num_elements);
   P3DListVariant(const P3DListVariant &copy);
   P3DListVariant(const P3DListVariant &copy);
 
 
@@ -36,6 +37,10 @@ public:
   virtual int get_list_length() const;
   virtual int get_list_length() const;
   virtual P3DVariant *get_list_item(int n) const;
   virtual P3DVariant *get_list_item(int n) const;
 
 
+  void append_item(P3DVariant *item);
+
+  virtual TiXmlElement *make_xml() const;
+
 private:
 private:
   typedef vector<P3DVariant *> Elements;
   typedef vector<P3DVariant *> Elements;
   Elements _elements;
   Elements _elements;

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

@@ -54,3 +54,16 @@ void P3DNoneVariant::
 make_string(string &value) const {
 make_string(string &value) const {
   value = "None";
   value = "None";
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DNoneVariant::make_xml
+//       Access: Public, Virtual
+//  Description: Allocates and returns a new XML structure
+//               corresponding to this variant.
+////////////////////////////////////////////////////////////////////
+TiXmlElement *P3DNoneVariant::
+make_xml() const {
+  TiXmlElement *xvariant = new TiXmlElement("variant");
+  xvariant->SetAttribute("type", "none");
+  return xvariant;
+}

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

@@ -31,6 +31,8 @@ public:
   virtual P3DVariant *make_copy();
   virtual P3DVariant *make_copy();
   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

+ 150 - 6
direct/src/plugin/p3dPythonRun.cxx

@@ -200,20 +200,26 @@ handle_command(TiXmlDocument *doc) {
           P3DCInstance *inst = new P3DCInstance(xinstance);
           P3DCInstance *inst = new P3DCInstance(xinstance);
           start_instance(inst, xinstance);
           start_instance(inst, xinstance);
         }
         }
+
       } else if (strcmp(cmd, "terminate_instance") == 0) {
       } else if (strcmp(cmd, "terminate_instance") == 0) {
         int id;
         int id;
-        if (xcommand->Attribute("id", &id)) {
+        if (xcommand->Attribute("instance_id", &id)) {
           terminate_instance(id);
           terminate_instance(id);
         }
         }
+
       } else if (strcmp(cmd, "setup_window") == 0) {
       } else if (strcmp(cmd, "setup_window") == 0) {
         int id;
         int id;
         TiXmlElement *xwparams = xcommand->FirstChildElement("wparams");
         TiXmlElement *xwparams = xcommand->FirstChildElement("wparams");
         if (xwparams != (TiXmlElement *)NULL && 
         if (xwparams != (TiXmlElement *)NULL && 
-            xcommand->Attribute("id", &id)) {
+            xcommand->Attribute("instance_id", &id)) {
           setup_window(id, xwparams);
           setup_window(id, xwparams);
         }
         }
+
       } else if (strcmp(cmd, "exit") == 0) {
       } else if (strcmp(cmd, "exit") == 0) {
         terminate_session();
         terminate_session();
+
+      } else if (strcmp(cmd, "feed_value") == 0) {
+        
         
         
       } else {
       } else {
         nout << "Unhandled command " << cmd << "\n";
         nout << "Unhandled command " << cmd << "\n";
@@ -284,10 +290,12 @@ py_request_func(PyObject *args) {
   }
   }
 
 
   TiXmlDocument doc;
   TiXmlDocument doc;
-  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
+  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
   TiXmlElement *xrequest = new TiXmlElement("request");
   TiXmlElement *xrequest = new TiXmlElement("request");
-  xrequest->SetAttribute("id", instance_id);
+  xrequest->SetAttribute("instance_id", instance_id);
   xrequest->SetAttribute("rtype", request_type);
   xrequest->SetAttribute("rtype", request_type);
+  doc.LinkEndChild(decl);
+  doc.LinkEndChild(xrequest);
 
 
   if (strcmp(request_type, "notify") == 0) {
   if (strcmp(request_type, "notify") == 0) {
     // A general notification to be sent directly to the instance.
     // A general notification to be sent directly to the instance.
@@ -297,8 +305,47 @@ py_request_func(PyObject *args) {
     }
     }
 
 
     xrequest->SetAttribute("message", message);
     xrequest->SetAttribute("message", message);
-    doc.LinkEndChild(decl);
-    doc.LinkEndChild(xrequest);
+    nout << "sending " << doc << "\n" << flush;
+    _pipe_write << doc << flush;
+
+  } else if (strcmp(request_type, "get_property") == 0) {
+    // A get-property request.
+    const char *property_name;
+    int unique_id;
+    if (!PyArg_ParseTuple(extra_args, "si", &property_name, &unique_id)) {
+      return NULL;
+    }
+
+    xrequest->SetAttribute("property_name", property_name);
+    xrequest->SetAttribute("unique_id", unique_id);
+    nout << "sending " << doc << "\n" << flush;
+    _pipe_write << doc << flush;
+
+  } else if (strcmp(request_type, "set_property") == 0) {
+    // A set-property request.
+    const char *property_name;
+    PyObject *value;
+    if (!PyArg_ParseTuple(extra_args, "sO", &property_name, &value)) {
+      return NULL;
+    }
+
+    xrequest->SetAttribute("property_name", property_name);
+    append_xml_variant(xrequest, value);
+    nout << "sending " << doc << "\n" << flush;
+    _pipe_write << doc << flush;
+
+  } else if (strcmp(request_type, "call") == 0) {
+    // A call-method request.
+    const char *property_name;
+    PyObject *params;
+    int unique_id;
+    if (!PyArg_ParseTuple(extra_args, "sOi", &property_name, &params, &unique_id)) {
+      return NULL;
+    }
+
+    xrequest->SetAttribute("property_name", property_name);
+    xrequest->SetAttribute("unique_id", unique_id);
+    append_xml_variant(xrequest, params);
     nout << "sending " << doc << "\n" << flush;
     nout << "sending " << doc << "\n" << flush;
     _pipe_write << doc << flush;
     _pipe_write << doc << flush;
 
 
@@ -549,6 +596,103 @@ terminate_session() {
   nout << "done calling stop()\n";
   nout << "done calling stop()\n";
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonRun::append_xml_variant
+//       Access: Private
+//  Description: Converts the indicated PyObject to the appropriate
+//               XML representation of a P3D_variant type, and appends
+//               it to the child list of the indicated element.
+////////////////////////////////////////////////////////////////////
+void P3DPythonRun::
+append_xml_variant(TiXmlElement *xelement, PyObject *value) {
+  TiXmlElement *xvariant = new TiXmlElement("variant");
+  if (value == Py_None) {
+    // None.
+    xvariant->SetAttribute("type", "none");
+
+  } else if (PyBool_Check(value)) {
+    // A bool value.
+    xvariant->SetAttribute("type", "bool");
+    xvariant->SetAttribute("value", PyObject_IsTrue(value));
+
+  } else if (PyInt_Check(value)) {
+    // A plain integer value.
+    xvariant->SetAttribute("type", "int");
+    xvariant->SetAttribute("value", PyInt_AsLong(value));
+
+  } else if (PyLong_Check(value)) {
+    // A long integer value.  This gets converted either as an integer
+    // or as a floating-point type, whichever fits.
+    long lvalue = PyLong_AsLong(value);
+    if (PyErr_Occurred()) {
+      // It won't fit as an integer; make it a double.
+      PyErr_Clear();
+      xvariant->SetAttribute("type", "float");
+      xvariant->SetDoubleAttribute("value", PyLong_AsDouble(value));
+    } else {
+      // It fits as an integer.
+      xvariant->SetAttribute("type", "int");
+      xvariant->SetAttribute("value", lvalue);
+    }
+
+  } else if (PyFloat_Check(value)) {
+    // A floating-point value.
+    xvariant->SetAttribute("type", "float");
+    xvariant->SetDoubleAttribute("value", PyFloat_AsDouble(value));
+
+  } else if (PyUnicode_Check(value)) {
+    // A unicode value.  Convert to utf-8 for the XML encoding.
+    xvariant->SetAttribute("type", "string");
+    PyObject *as_str = PyUnicode_AsUTF8String(value);
+    if (as_str != NULL) {
+      char *buffer;
+      Py_ssize_t length;
+      if (PyString_AsStringAndSize(as_str, &buffer, &length) != -1) {
+        string str(buffer, length);
+        xvariant->SetAttribute("value", str);
+      }
+      Py_DECREF(as_str);
+    }
+
+  } else if (PyString_Check(value)) {
+    // A string value.
+    xvariant->SetAttribute("type", "string");
+
+    char *buffer;
+    Py_ssize_t length;
+    if (PyString_AsStringAndSize(value, &buffer, &length) != -1) {
+      string str(buffer, length);
+      xvariant->SetAttribute("value", str);
+    }
+
+  } else if (PySequence_Check(value)) {
+    // A sequence or list value.
+    xvariant->SetAttribute("type", "list");
+    Py_ssize_t length = PySequence_Length(value);
+    for (Py_ssize_t i = 0; i < length; ++i) {
+      PyObject *obj = PySequence_GetItem(value, i);
+      append_xml_variant(xvariant, obj);
+    }
+
+  } else {
+    // Some other kind of object.  Don't know what else to do with it;
+    // we'll make it a string.
+    xvariant->SetAttribute("type", "string");
+    PyObject *as_str = PyObject_Str(value);
+    if (as_str != NULL) {
+      char *buffer;
+      Py_ssize_t length;
+      if (PyString_AsStringAndSize(as_str, &buffer, &length) != -1) {
+        string str(buffer, length);
+        xvariant->SetAttribute("value", str);
+      }
+      Py_DECREF(as_str);
+    }
+  }
+
+  xelement->LinkEndChild(xvariant);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPythonRun::rt_thread_run
 //     Function: P3DPythonRun::rt_thread_run
 //       Access: Private
 //       Access: Private

+ 3 - 0
direct/src/plugin/p3dPythonRun.h

@@ -80,6 +80,9 @@ private:
   
   
   void terminate_session();
   void terminate_session();
 
 
+private:
+  void append_xml_variant(TiXmlElement *xelement, PyObject *value);
+
 private:
 private:
   // This method runs only within the read thread.
   // This method runs only within the read thread.
 
 

+ 95 - 5
direct/src/plugin/p3dSession.cxx

@@ -69,7 +69,7 @@ P3DSession::
   if (_p3dpython_running) {
   if (_p3dpython_running) {
     // Tell the process we're going away.
     // Tell the process we're going away.
     TiXmlDocument doc;
     TiXmlDocument doc;
-    TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
+    TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
     TiXmlElement *xcommand = new TiXmlElement("command");
     TiXmlElement *xcommand = new TiXmlElement("command");
     xcommand->SetAttribute("cmd", "exit");
     xcommand->SetAttribute("cmd", "exit");
     doc.LinkEndChild(decl);
     doc.LinkEndChild(decl);
@@ -136,7 +136,7 @@ start_instance(P3DInstance *inst) {
   assert(inserted);
   assert(inserted);
 
 
   TiXmlDocument *doc = new TiXmlDocument;
   TiXmlDocument *doc = new TiXmlDocument;
-  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
+  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
   TiXmlElement *xcommand = new TiXmlElement("command");
   TiXmlElement *xcommand = new TiXmlElement("command");
   xcommand->SetAttribute("cmd", "start_instance");
   xcommand->SetAttribute("cmd", "start_instance");
   TiXmlElement *xinstance = inst->make_xml();
   TiXmlElement *xinstance = inst->make_xml();
@@ -169,10 +169,10 @@ start_instance(P3DInstance *inst) {
 void P3DSession::
 void P3DSession::
 terminate_instance(P3DInstance *inst) {
 terminate_instance(P3DInstance *inst) {
   TiXmlDocument *doc = new TiXmlDocument;
   TiXmlDocument *doc = new TiXmlDocument;
-  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
+  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
   TiXmlElement *xcommand = new TiXmlElement("command");
   TiXmlElement *xcommand = new TiXmlElement("command");
   xcommand->SetAttribute("cmd", "terminate_instance");
   xcommand->SetAttribute("cmd", "terminate_instance");
-  xcommand->SetAttribute("id", inst->get_instance_id());
+  xcommand->SetAttribute("instance_id", inst->get_instance_id());
   
   
   doc->LinkEndChild(decl);
   doc->LinkEndChild(decl);
   doc->LinkEndChild(xcommand);
   doc->LinkEndChild(xcommand);
@@ -412,7 +412,7 @@ rt_handle_request(TiXmlDocument *doc) {
   TiXmlElement *xrequest = doc->FirstChildElement("request");
   TiXmlElement *xrequest = doc->FirstChildElement("request");
   if (xrequest != (TiXmlElement *)NULL) {
   if (xrequest != (TiXmlElement *)NULL) {
     int instance_id ;
     int instance_id ;
-    if (xrequest->Attribute("id", &instance_id)) {
+    if (xrequest->Attribute("instance_id", &instance_id)) {
       // Look up the particular instance this is related to.
       // Look up the particular instance this is related to.
       ACQUIRE_LOCK(_instances_lock);
       ACQUIRE_LOCK(_instances_lock);
       Instances::const_iterator ii;
       Instances::const_iterator ii;
@@ -449,12 +449,102 @@ rt_make_p3d_request(TiXmlElement *xrequest) {
         request->_request_type = P3D_RT_notify;
         request->_request_type = P3D_RT_notify;
         request->_request._notify._message = strdup(message);
         request->_request._notify._message = strdup(message);
       }
       }
+
+    } else if (strcmp(rtype, "get_property") == 0) {
+      const char *property_name = xrequest->Attribute("property_name");
+      int unique_id;
+      if (property_name != NULL && xrequest->QueryIntAttribute("unique_id", &unique_id) == TIXML_SUCCESS) {
+        request = new P3D_request;
+        request->_request_type = P3D_RT_get_property;
+        request->_request._get_property._property_name = strdup(property_name);
+        request->_request._get_property._unique_id = unique_id;
+      }
+
+    } else if (strcmp(rtype, "set_property") == 0) {
+      const char *property_name = xrequest->Attribute("property_name");
+      TiXmlElement *xvariant = xrequest->FirstChildElement("variant");
+      if (property_name != NULL && xvariant != NULL) {
+        request = new P3D_request;
+        request->_request_type = P3D_RT_set_property;
+        request->_request._set_property._property_name = strdup(property_name);
+        request->_request._set_property._value = rt_from_xml_variant(xvariant);
+      }
+
+    } else if (strcmp(rtype, "call") == 0) {
+      const char *property_name = xrequest->Attribute("property_name");
+      TiXmlElement *xvariant = xrequest->FirstChildElement("variant");
+      int unique_id;
+      if (property_name != NULL && xvariant != NULL && 
+          xrequest->QueryIntAttribute("unique_id", &unique_id) == TIXML_SUCCESS) {
+        request = new P3D_request;
+        request->_request_type = P3D_RT_call;
+        request->_request._call._property_name = strdup(property_name);
+        request->_request._call._params = rt_from_xml_variant(xvariant);
+        request->_request._call._unique_id = unique_id;
+      }
+
+    } else {
+      nout << "ignoring request of type " << rtype << "\n";
     }
     }
   }
   }
 
 
   return request;
   return request;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DSession::rt_from_xml_variant
+//       Access: Private
+//  Description: Converts the XML representation of the particular
+//               variant value into a corresponding P3DVariant object.
+//               Returns the newly-allocated object.
+////////////////////////////////////////////////////////////////////
+P3DVariant *P3DSession::
+rt_from_xml_variant(TiXmlElement *xvariant) {
+  const char *type = xvariant->Attribute("type");
+  if (strcmp(type, "none") == 0) {
+    return new P3DNoneVariant;
+
+  } else if (strcmp(type, "bool") == 0) {
+    int value;
+    if (xvariant->QueryIntAttribute("value", &value) == TIXML_SUCCESS) {
+      return new P3DBoolVariant(value != 0);
+    }
+
+  } else if (strcmp(type, "int") == 0) {
+    int value;
+    if (xvariant->QueryIntAttribute("value", &value) == TIXML_SUCCESS) {
+      return new P3DIntVariant(value);
+    }
+
+  } else if (strcmp(type, "float") == 0) {
+    double value;
+    if (xvariant->QueryDoubleAttribute("value", &value) == TIXML_SUCCESS) {
+      return new P3DFloatVariant(value);
+    }
+
+  } else if (strcmp(type, "string") == 0) {
+    // Using the string form here instead of the char * form, so we
+    // don't get tripped up on embedded null characters.
+    const string *value = xvariant->Attribute(string("value"));
+    if (value != NULL) {
+      return new P3DStringVariant(*value);
+    }
+
+  } else if (strcmp(type, "list") == 0) {
+    P3DListVariant *list = new P3DListVariant;
+
+    TiXmlElement *xchild = xvariant->FirstChildElement("variant");
+    while (xchild != NULL) {
+      list->append_item(rt_from_xml_variant(xchild));
+      xchild = xchild->NextSiblingElement("variant");
+    }
+    return list;
+  }
+
+  // Something went wrong in decoding.
+  return new P3DNoneVariant;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DSession::rt_terminate
 //     Function: P3DSession::rt_terminate
 //       Access: Private
 //       Access: Private

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

@@ -61,6 +61,7 @@ private:
   void rt_terminate();
   void rt_terminate();
   void rt_handle_request(TiXmlDocument *doc);
   void rt_handle_request(TiXmlDocument *doc);
   P3D_request *rt_make_p3d_request(TiXmlElement *xrequest);
   P3D_request *rt_make_p3d_request(TiXmlElement *xrequest);
+  P3DVariant *rt_from_xml_variant(TiXmlElement *xvariant);
 
 
 #ifdef _WIN32
 #ifdef _WIN32
   static DWORD WINAPI win_rt_thread_run(LPVOID data);
   static DWORD WINAPI win_rt_thread_run(LPVOID data);

+ 57 - 2
direct/src/plugin/p3dStringVariant.cxx

@@ -20,9 +20,9 @@
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3DStringVariant::
 P3DStringVariant::
-P3DStringVariant(const char *value, int length) : 
+P3DStringVariant(const string &value) : 
   P3DVariant(P3D_VT_string),
   P3DVariant(P3D_VT_string),
-  _value(value, length)
+  _value(value)
 {
 {
 }
 }
 
 
@@ -79,3 +79,58 @@ make_string(string &value) const {
   value = _value;
   value = _value;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DStringVariant::make_xml
+//       Access: Public, Virtual
+//  Description: Allocates and returns a new XML structure
+//               corresponding to this variant.
+////////////////////////////////////////////////////////////////////
+TiXmlElement *P3DStringVariant::
+make_xml() const {
+  TiXmlElement *xvariant = new TiXmlElement("variant");
+  xvariant->SetAttribute("type", "string");
+  xvariant->SetAttribute("value", _value);
+  return xvariant;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DStringVariant::output
+//       Access: Public, Virtual
+//  Description: Writes a formatted representation of the value to the
+//               indicated string.  This is intended for developer
+//               assistance.
+////////////////////////////////////////////////////////////////////
+void P3DStringVariant::
+output(ostream &out) const {
+  out << '"';
+  for (string::const_iterator si = _value.begin(); si != _value.end(); ++si) {
+    if (isprint(*si)) {
+      switch (*si) {
+      case '"':
+        out << "\\\x22";
+        break;
+
+      default:
+        out << *si;
+      }
+    } else {
+      switch (*si) {
+      case '\n':
+        out << "\\n";
+        break;
+
+      case '\t':
+        out << "\\t";
+        break;
+
+      default:
+        {
+          char buffer[128];
+          sprintf(buffer, "%02x", (unsigned char)(*si));
+          out << "\\x" << buffer;
+        }
+      }
+    }
+  }
+  out << '"';
+}

+ 5 - 1
direct/src/plugin/p3dStringVariant.h

@@ -24,7 +24,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class P3DStringVariant : public P3DVariant {
 class P3DStringVariant : public P3DVariant {
 public:
 public:
-  P3DStringVariant(const char *value, int length);
+  P3DStringVariant(const string &value);
   P3DStringVariant(const P3DStringVariant &copy);
   P3DStringVariant(const P3DStringVariant &copy);
 
 
 public:
 public:
@@ -34,6 +34,10 @@ 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;
+
 private:
 private:
   string _value;
   string _value;
 };
 };

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

@@ -100,3 +100,17 @@ P3DVariant *P3DVariant::
 get_list_item(int n) const {
 get_list_item(int n) const {
   return NULL;
   return NULL;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DVariant::output
+//       Access: Public, Virtual
+//  Description: Writes a formatted representation of the value to the
+//               indicated string.  This is intended for developer
+//               assistance.
+////////////////////////////////////////////////////////////////////
+void P3DVariant::
+output(ostream &out) const {
+  string value;
+  make_string(value);
+  out << value;
+}

+ 9 - 0
direct/src/plugin/p3dVariant.h

@@ -44,9 +44,18 @@ public:
 
 
   virtual int get_list_length() const;
   virtual int get_list_length() const;
   virtual P3DVariant *get_list_item(int n) const;
   virtual P3DVariant *get_list_item(int n) const;
+
+  virtual TiXmlElement *make_xml() const=0;
+
+  virtual void output(ostream &out) const;
 };
 };
 
 
 #include "p3dVariant.I"
 #include "p3dVariant.I"
 
 
+inline ostream &operator << (ostream &out, const P3DVariant &variant) {
+  variant.output(out);
+  return out;
+}
+
 #endif
 #endif
 
 

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

@@ -120,7 +120,9 @@ void
 P3D_variant_finish(P3D_variant *variant) {
 P3D_variant_finish(P3D_variant *variant) {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_lock);
   ACQUIRE_LOCK(_lock);
-  delete (P3DVariant *)variant;
+  if (variant != NULL) {
+    delete (P3DVariant *)variant;
+  }
   RELEASE_LOCK(_lock);
   RELEASE_LOCK(_lock);
 }
 }
 
 
@@ -200,7 +202,7 @@ P3D_variant *
 P3D_new_string_variant(const char *value, int length) {
 P3D_new_string_variant(const char *value, int length) {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_lock);
   ACQUIRE_LOCK(_lock);
-  P3D_variant *result = new P3DStringVariant(value, length);
+  P3D_variant *result = new P3DStringVariant(string(value, length));
   RELEASE_LOCK(_lock);
   RELEASE_LOCK(_lock);
   return result;
   return result;
 }
 }

+ 74 - 2
direct/src/plugin_standalone/panda3d.cxx

@@ -302,30 +302,102 @@ handle_request(P3D_request *request) {
     break;
     break;
 
 
   case P3D_RT_get_url:
   case P3D_RT_get_url:
-    cerr << "Got P3D_RT_get_url\n";
+    cerr << "Got P3D_RT_get_url: " << request->_request._get_url._url
+         << "\n";
     {
     {
       URLGetter *getter = new URLGetter
       URLGetter *getter = new URLGetter
         (request->_instance, request->_request._get_url._unique_id,
         (request->_instance, request->_request._get_url._unique_id,
          URLSpec(request->_request._get_url._url), "");
          URLSpec(request->_request._get_url._url), "");
       _url_getters.insert(getter);
       _url_getters.insert(getter);
+      handled = true;
     }
     }
     break;
     break;
 
 
   case P3D_RT_post_url:
   case P3D_RT_post_url:
-    cerr << "Got P3D_RT_post_url\n";
+    cerr << "Got P3D_RT_post_url: " << request->_request._post_url._url 
+         << "\n";
     {
     {
       URLGetter *getter = new URLGetter
       URLGetter *getter = new URLGetter
         (request->_instance, request->_request._post_url._unique_id,
         (request->_instance, request->_request._post_url._unique_id,
          URLSpec(request->_request._post_url._url), 
          URLSpec(request->_request._post_url._url), 
          string(request->_request._post_url._post_data, request->_request._post_url._post_data_size));
          string(request->_request._post_url._post_data, request->_request._post_url._post_data_size));
       _url_getters.insert(getter);
       _url_getters.insert(getter);
+      handled = true;
     }
     }
     break;
     break;
 
 
   case P3D_RT_notify:
   case P3D_RT_notify:
+    cerr << "Got P3D_RT_notify: " << request->_request._notify._message
+         << "\n";
     // Ignore notifications.
     // Ignore notifications.
     break;
     break;
 
 
+  case P3D_RT_get_property:
+    cerr << "Got P3D_RT_get_property: "
+         << request->_request._get_property._property_name << "\n";
+    {
+      Properties::iterator pi = 
+        _properties.find(request->_request._get_property._property_name);
+      if (pi != _properties.end()) {
+        // The named property has been set.
+        P3D_variant *dup_value = P3D_variant_copy((*pi).second);
+        P3D_instance_feed_value(request->_instance, 
+                                request->_request._get_property._unique_id,
+                                dup_value);
+      } else {
+        // No such property set.
+        P3D_instance_feed_value(request->_instance, 
+                                request->_request._get_property._unique_id,
+                                NULL);
+      }
+      handled = true;
+    }
+    break;
+
+  case P3D_RT_set_property:
+    cerr << "Got P3D_RT_set_property: "
+         << request->_request._set_property._property_name << "\n";
+    {
+      // Also output the new value.
+      int buffer_size = 
+        P3D_variant_get_string_length(request->_request._set_property._value);
+      char *buffer = (char *)alloca(buffer_size);
+      P3D_variant_extract_string(request->_request._set_property._value, buffer, buffer_size);
+      cerr.write(buffer, buffer_size);
+      cerr << "\n";
+
+      Properties::iterator pi = 
+        _properties.insert(Properties::value_type(request->_request._set_property._property_name, NULL)).first;
+      if ((*pi).second != NULL) {
+        // Delete the original property.
+        P3D_variant_finish((*pi).second);
+      }
+      (*pi).second =
+        P3D_variant_copy(request->_request._set_property._value);
+      handled = true;
+    }
+    break;
+
+  case P3D_RT_call:
+    cerr << "Got P3D_RT_call: "
+         << request->_request._call._property_name << "\n";
+    {
+      // Also output the parameter list.
+      int buffer_size = 
+        P3D_variant_get_string_length(request->_request._call._params);
+      char *buffer = (char *)alloca(buffer_size);
+      P3D_variant_extract_string(request->_request._call._params, buffer, buffer_size);
+      cerr.write(buffer, buffer_size);
+      cerr << "\n";
+
+      // We don't have a mechanism for actually calling anything, though.
+      P3D_instance_feed_value(request->_instance, 
+                              request->_request._call._unique_id,
+                              NULL);
+      handled = true;
+    }
+    break;
+
   default:
   default:
     // Some request types are not handled.
     // Some request types are not handled.
     cerr << "Unhandled request: " << request->_request_type << "\n";
     cerr << "Unhandled request: " << request->_request_type << "\n";

+ 5 - 0
direct/src/plugin_standalone/panda3d.h

@@ -60,6 +60,11 @@ private:
   typedef pset<P3D_instance *> Instances;
   typedef pset<P3D_instance *> Instances;
   Instances _instances;
   Instances _instances;
 
 
+  // We maintain a table of properties in the "browser", mainly so we
+  // can test this feature of the core plugin API.
+  typedef pmap<string, P3D_variant *> Properties;
+  Properties _properties;
+
   // This nested class keeps track of active URL requests.
   // This nested class keeps track of active URL requests.
   class URLGetter {
   class URLGetter {
   public:
   public:

+ 9 - 0
direct/src/showbase/AppRunnerGlobal.py

@@ -0,0 +1,9 @@
+""" This module serves as a placeholder for the global AppRunner
+object, which only exists when we are running a .p3d file via
+runp3d.py or via the Panda3D plugin or standalone executable.
+
+This is needed for apps that start themselves by importing
+DirectStart; it provides a place for these apps to look for
+the AppRunner at startup. """
+
+appRunner = None

+ 4 - 0
direct/src/showbase/ShowBase.py

@@ -41,6 +41,7 @@ import SfxPlayer
 if __debug__:
 if __debug__:
     from direct.directutil import DeltaProfiler
     from direct.directutil import DeltaProfiler
 import OnScreenDebug
 import OnScreenDebug
+import AppRunnerGlobal
 
 
 __builtin__.FADE_SORT_INDEX = 1000
 __builtin__.FADE_SORT_INDEX = 1000
 __builtin__.NO_FADE_SORT_INDEX = 2000
 __builtin__.NO_FADE_SORT_INDEX = 2000
@@ -63,6 +64,9 @@ class ShowBase(DirectObject.DirectObject):
         self.mainDir = Filename.fromOsSpecific(maindir).getFullpath()
         self.mainDir = Filename.fromOsSpecific(maindir).getFullpath()
         ExecutionEnvironment.setEnvironmentVariable("MAIN_DIR", self.mainDir)
         ExecutionEnvironment.setEnvironmentVariable("MAIN_DIR", self.mainDir)
 
 
+        # The appRunner should have been created by the time ShowBase
+        # has been.
+        self.appRunner = AppRunnerGlobal.appRunner
 
 
         #debug running multiplier
         #debug running multiplier
         self.debugRunningMultiplier = 4
         self.debugRunningMultiplier = 4

+ 6 - 1
direct/src/showutil/runp3d.py

@@ -25,6 +25,7 @@ from direct.showbase.DirectObject import DirectObject
 from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, getModelPath, HTTPClient
 from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, getModelPath, HTTPClient
 from direct.stdpy import file
 from direct.stdpy import file
 from direct.task.TaskManagerGlobal import taskMgr
 from direct.task.TaskManagerGlobal import taskMgr
+from direct.showbase import AppRunnerGlobal
 import os
 import os
 import __builtin__
 import __builtin__
 
 
@@ -54,9 +55,13 @@ class AppRunner(DirectObject):
         # 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):
-            print "Ignoring request func: %s" % (args,)
+            print "Ignoring request: %s" % (args,)
         self.requestFunc = defaultRequestFunc
         self.requestFunc = defaultRequestFunc
 
 
+        # Store our pointer so DirectStart-based apps can find us.
+        if AppRunnerGlobal.appRunner is None:
+            AppRunnerGlobal.appRunner = self
+
     def initPackedAppEnvironment(self):
     def initPackedAppEnvironment(self):
         """ This function sets up the Python environment suitably for
         """ This function sets up the Python environment suitably for
         running a packed app.  It should only run once in any given
         running a packed app.  It should only run once in any given