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::
 make_string(string &value) const {
   if (_value) {
-    value = "1";
+    value = "True";
   } 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 void make_string(string &value) const;
 
+  virtual TiXmlElement *make_xml() const;
+
 private:
   bool _value;
 };

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

@@ -24,7 +24,7 @@ P3DCInstance::
 P3DCInstance(TiXmlElement *xinstance) :
   _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();
 }
 
+
+////////////////////////////////////////////////////////////////////
+//     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 void make_string(string &value) const;
 
+  virtual TiXmlElement *make_xml() const;
+
 private:
   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.
   if (_session != NULL) {
     TiXmlDocument *doc = new TiXmlDocument;
-    TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
+    TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
     TiXmlElement *xcommand = new TiXmlElement("command");
     xcommand->SetAttribute("cmd", "setup_window");
-    xcommand->SetAttribute("id", get_instance_id());
+    xcommand->SetAttribute("instance_id", get_instance_id());
     TiXmlElement *xwparams = _wparams.make_xml();
     
     doc->LinkEndChild(decl);
@@ -354,6 +354,24 @@ feed_url_stream(int unique_id,
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 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) {
     delete variant;
   }
@@ -435,7 +453,7 @@ make_xml() {
   assert(_got_fparams);
 
   TiXmlElement *xinstance = new TiXmlElement("instance");
-  xinstance->SetAttribute("id", _instance_id);
+  xinstance->SetAttribute("instance_id", _instance_id);
 
   TiXmlElement *xfparams = _fparams.make_xml();
   xinstance->LinkEndChild(xfparams);

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

@@ -83,3 +83,17 @@ make_string(string &value) const {
   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 void make_string(string &value) const;
 
+  virtual TiXmlElement *make_xml() const;
+
 private:
   int _value;
 };

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

@@ -14,12 +14,24 @@
 
 #include "p3dListVariant.h"
 
+
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DListVariant::Constructor
+//     Function: P3DListVariant::Default Constructor
 //       Access: Public
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 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) :
   P3DVariant(P3D_VT_list)
 {
@@ -90,12 +102,9 @@ make_string(string &value) const {
   ostringstream strm;
   strm << "[";
   if (!_elements.empty()) {
-    string es;
-    _elements[0]->make_string(es);
-    strm << es;
+    strm << *_elements[0];
     for (size_t i = 1; i < _elements.size(); ++i) {
-      _elements[0]->make_string(es);
-      strm << ", " << es;
+      strm << ", " << *_elements[i];
     }
   }
   strm << "]";
@@ -128,3 +137,33 @@ get_list_item(int n) const {
 
   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 {
 public:
+  P3DListVariant();
   P3DListVariant(P3DVariant * const elements[], int num_elements);
   P3DListVariant(const P3DListVariant &copy);
 
@@ -36,6 +37,10 @@ public:
   virtual int get_list_length() const;
   virtual P3DVariant *get_list_item(int n) const;
 
+  void append_item(P3DVariant *item);
+
+  virtual TiXmlElement *make_xml() const;
+
 private:
   typedef vector<P3DVariant *> Elements;
   Elements _elements;

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

@@ -54,3 +54,16 @@ void P3DNoneVariant::
 make_string(string &value) const {
   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 bool get_bool() const;
   virtual void make_string(string &value) const;
+
+  virtual TiXmlElement *make_xml() const;
 };
 
 #endif

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

@@ -200,20 +200,26 @@ handle_command(TiXmlDocument *doc) {
           P3DCInstance *inst = new P3DCInstance(xinstance);
           start_instance(inst, xinstance);
         }
+
       } else if (strcmp(cmd, "terminate_instance") == 0) {
         int id;
-        if (xcommand->Attribute("id", &id)) {
+        if (xcommand->Attribute("instance_id", &id)) {
           terminate_instance(id);
         }
+
       } else if (strcmp(cmd, "setup_window") == 0) {
         int id;
         TiXmlElement *xwparams = xcommand->FirstChildElement("wparams");
         if (xwparams != (TiXmlElement *)NULL && 
-            xcommand->Attribute("id", &id)) {
+            xcommand->Attribute("instance_id", &id)) {
           setup_window(id, xwparams);
         }
+
       } else if (strcmp(cmd, "exit") == 0) {
         terminate_session();
+
+      } else if (strcmp(cmd, "feed_value") == 0) {
+        
         
       } else {
         nout << "Unhandled command " << cmd << "\n";
@@ -284,10 +290,12 @@ py_request_func(PyObject *args) {
   }
 
   TiXmlDocument doc;
-  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
+  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
   TiXmlElement *xrequest = new TiXmlElement("request");
-  xrequest->SetAttribute("id", instance_id);
+  xrequest->SetAttribute("instance_id", instance_id);
   xrequest->SetAttribute("rtype", request_type);
+  doc.LinkEndChild(decl);
+  doc.LinkEndChild(xrequest);
 
   if (strcmp(request_type, "notify") == 0) {
     // A general notification to be sent directly to the instance.
@@ -297,8 +305,47 @@ py_request_func(PyObject *args) {
     }
 
     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;
     _pipe_write << doc << flush;
 
@@ -549,6 +596,103 @@ terminate_session() {
   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
 //       Access: Private

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

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

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

@@ -69,7 +69,7 @@ P3DSession::
   if (_p3dpython_running) {
     // Tell the process we're going away.
     TiXmlDocument doc;
-    TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
+    TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
     TiXmlElement *xcommand = new TiXmlElement("command");
     xcommand->SetAttribute("cmd", "exit");
     doc.LinkEndChild(decl);
@@ -136,7 +136,7 @@ start_instance(P3DInstance *inst) {
   assert(inserted);
 
   TiXmlDocument *doc = new TiXmlDocument;
-  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
+  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
   TiXmlElement *xcommand = new TiXmlElement("command");
   xcommand->SetAttribute("cmd", "start_instance");
   TiXmlElement *xinstance = inst->make_xml();
@@ -169,10 +169,10 @@ start_instance(P3DInstance *inst) {
 void P3DSession::
 terminate_instance(P3DInstance *inst) {
   TiXmlDocument *doc = new TiXmlDocument;
-  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
+  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
   TiXmlElement *xcommand = new TiXmlElement("command");
   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(xcommand);
@@ -412,7 +412,7 @@ rt_handle_request(TiXmlDocument *doc) {
   TiXmlElement *xrequest = doc->FirstChildElement("request");
   if (xrequest != (TiXmlElement *)NULL) {
     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.
       ACQUIRE_LOCK(_instances_lock);
       Instances::const_iterator ii;
@@ -449,12 +449,102 @@ rt_make_p3d_request(TiXmlElement *xrequest) {
         request->_request_type = P3D_RT_notify;
         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;
 }
 
+////////////////////////////////////////////////////////////////////
+//     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
 //       Access: Private

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

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

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

@@ -20,9 +20,9 @@
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 P3DStringVariant::
-P3DStringVariant(const char *value, int length) : 
+P3DStringVariant(const string &value) : 
   P3DVariant(P3D_VT_string),
-  _value(value, length)
+  _value(value)
 {
 }
 
@@ -79,3 +79,58 @@ make_string(string &value) const {
   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 {
 public:
-  P3DStringVariant(const char *value, int length);
+  P3DStringVariant(const string &value);
   P3DStringVariant(const P3DStringVariant &copy);
 
 public:
@@ -34,6 +34,10 @@ public:
   virtual bool get_bool() const;
   virtual void make_string(string &value) const;
 
+  virtual TiXmlElement *make_xml() const;
+
+  virtual void output(ostream &out) const;
+
 private:
   string _value;
 };

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

@@ -100,3 +100,17 @@ P3DVariant *P3DVariant::
 get_list_item(int n) const {
   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 P3DVariant *get_list_item(int n) const;
+
+  virtual TiXmlElement *make_xml() const=0;
+
+  virtual void output(ostream &out) const;
 };
 
 #include "p3dVariant.I"
 
+inline ostream &operator << (ostream &out, const P3DVariant &variant) {
+  variant.output(out);
+  return out;
+}
+
 #endif
 

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

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

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

@@ -302,30 +302,102 @@ handle_request(P3D_request *request) {
     break;
 
   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
         (request->_instance, request->_request._get_url._unique_id,
          URLSpec(request->_request._get_url._url), "");
       _url_getters.insert(getter);
+      handled = true;
     }
     break;
 
   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
         (request->_instance, request->_request._post_url._unique_id,
          URLSpec(request->_request._post_url._url), 
          string(request->_request._post_url._post_data, request->_request._post_url._post_data_size));
       _url_getters.insert(getter);
+      handled = true;
     }
     break;
 
   case P3D_RT_notify:
+    cerr << "Got P3D_RT_notify: " << request->_request._notify._message
+         << "\n";
     // Ignore notifications.
     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:
     // Some request types are not handled.
     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;
   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.
   class URLGetter {
   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__:
     from direct.directutil import DeltaProfiler
 import OnScreenDebug
+import AppRunnerGlobal
 
 __builtin__.FADE_SORT_INDEX = 1000
 __builtin__.NO_FADE_SORT_INDEX = 2000
@@ -63,6 +64,9 @@ class ShowBase(DirectObject.DirectObject):
         self.mainDir = Filename.fromOsSpecific(maindir).getFullpath()
         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
         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 direct.stdpy import file
 from direct.task.TaskManagerGlobal import taskMgr
+from direct.showbase import AppRunnerGlobal
 import os
 import __builtin__
 
@@ -54,9 +55,13 @@ class AppRunner(DirectObject):
         # This is the default requestFunc that is installed if we
         # never call setRequestFunc().
         def defaultRequestFunc(*args):
-            print "Ignoring request func: %s" % (args,)
+            print "Ignoring request: %s" % (args,)
         self.requestFunc = defaultRequestFunc
 
+        # Store our pointer so DirectStart-based apps can find us.
+        if AppRunnerGlobal.appRunner is None:
+            AppRunnerGlobal.appRunner = self
+
     def initPackedAppEnvironment(self):
         """ This function sets up the Python environment suitably for
         running a packed app.  It should only run once in any given