Browse Source

P3DPythonObject et al

David Rose 16 years ago
parent
commit
6f2591c642

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

@@ -32,6 +32,7 @@
     p3dListObject.h \
     p3dMultifileReader.h p3dMultifileReader.I \
     p3dPackage.h p3dPackage.I \
+    p3dPythonObject.h \
     p3dSession.h p3dSession.I \
     p3dSplashWindow.h p3dSplashWindow.I \
     p3dStringObject.h \
@@ -53,6 +54,7 @@
     p3dListObject.cxx \
     p3dMultifileReader.cxx \
     p3dPackage.cxx \
+    p3dPythonObject.cxx \
     p3dSession.cxx \
     p3dSplashWindow.cxx \
     p3dStringObject.cxx \

+ 6 - 9
direct/src/plugin/p3dBoolObject.cxx

@@ -20,10 +20,7 @@
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 P3DBoolObject::
-P3DBoolObject(bool value) : 
-  P3DObject(P3D_OT_bool),
-  _value(value)
-{
+P3DBoolObject(bool value) : _value(value) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -39,13 +36,13 @@ P3DBoolObject(const P3DBoolObject &copy) :
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DBoolObject::make_copy
+//     Function: P3DBoolObject::get_type
 //       Access: Public, Virtual
-//  Description: 
+//  Description: Returns the fundamental type of this kind of object.
 ////////////////////////////////////////////////////////////////////
-P3DObject *P3DBoolObject::
-make_copy() const {
-  return new P3DBoolObject(*this);
+P3D_object_type P3DBoolObject::
+get_type() const {
+  return P3D_OT_bool;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
direct/src/plugin/p3dBoolObject.h

@@ -28,7 +28,7 @@ public:
   P3DBoolObject(const P3DBoolObject &copy);
 
 public:
-  virtual P3DObject *make_copy() const; 
+  virtual P3D_object_type get_type() const;
   virtual bool get_bool() const;
   virtual int get_int() const;
   virtual void make_string(string &value) const;

+ 6 - 9
direct/src/plugin/p3dFloatObject.cxx

@@ -20,10 +20,7 @@
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 P3DFloatObject::
-P3DFloatObject(double value) : 
-  P3DObject(P3D_OT_float),
-  _value(value)
-{
+P3DFloatObject(double value) : _value(value) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -39,13 +36,13 @@ P3DFloatObject(const P3DFloatObject &copy) :
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DFloatObject::make_copy
+//     Function: P3DFloatObject::get_type
 //       Access: Public, Virtual
-//  Description: 
+//  Description: Returns the fundamental type of this kind of object.
 ////////////////////////////////////////////////////////////////////
-P3DObject *P3DFloatObject::
-make_copy() const {
-  return new P3DFloatObject(*this);
+P3D_object_type P3DFloatObject::
+get_type() const {
+  return P3D_OT_float;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
direct/src/plugin/p3dFloatObject.h

@@ -28,7 +28,7 @@ public:
   P3DFloatObject(const P3DFloatObject &copy);
 
 public:
-  virtual P3DObject *make_copy() const; 
+  virtual P3D_object_type get_type() const;
   virtual bool get_bool() const;
   virtual int get_int() const;
   virtual double get_float() const;

+ 34 - 44
direct/src/plugin/p3dInstance.cxx

@@ -21,6 +21,7 @@
 #include "p3dWinSplashWindow.h"
 #include "p3dObject.h"
 #include "p3dNoneObject.h"
+#include "p3dPythonObject.h"
 
 #include <sstream>
 #include <algorithm>
@@ -159,54 +160,43 @@ set_wparams(const P3DWindowParams &wparams) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DInstance::get_property
+//     Function: P3DInstance::get_script_object
 //       Access: Public
-//  Description: Returns the value of the named property, or NULL
-//               if there is no such property.  Properties are created
-//               by the script run within the instance; they are used
-//               for communicating between scripting languages (for
-//               instance, communication between the Python-based
-//               Panda application, and the Javascript on the
-//               containing web page).
+//  Description: Returns a pointer to the top-level scriptable object
+//               of the instance, to be used by JavaScript code in the
+//               browser to control this program.
 ////////////////////////////////////////////////////////////////////
 P3DObject *P3DInstance::
-get_property(const string &property_name) const {
-  return NULL;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: P3DInstance::get_property_list
-//       Access: Public
-//  Description: Returns a list of subordinate properties below the
-//               named property.
-////////////////////////////////////////////////////////////////////
-P3DObject *P3DInstance::
-get_property_list(const string &property_name) const {
-  return NULL;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: P3DInstance::set_property
-//       Access: Public
-//  Description: Changes the value of the named property, or deletes
-//               it if value is NULL.  If the named property does not
-//               already exist, creates it.  Returns true on success,
-//               false on failure.
-////////////////////////////////////////////////////////////////////
-bool P3DInstance::
-set_property(const string &property_name, const P3DObject *value) {
-  return false;
-}
+get_script_object() const {
+  assert(_session != NULL);
+
+  TiXmlDocument *doc = new TiXmlDocument;
+  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
+  TiXmlElement *xcommand = new TiXmlElement("command");
+  xcommand->SetAttribute("cmd", "pyobj");
+  xcommand->SetAttribute("op", "get_script_object");
+  doc->LinkEndChild(decl);
+  doc->LinkEndChild(xcommand);
+  TiXmlDocument *response = _session->command_and_response(doc);
+  nout << "response pointer: " << response << "\n" << flush;
+
+  P3DObject *result = NULL;
+  if (response != NULL) {
+    TiXmlElement *xresponse = response->FirstChildElement("response");
+    if (xresponse != NULL) {
+      TiXmlElement *xvalue = xresponse->FirstChildElement("value");
+      if (xvalue != NULL) {
+        result = _session->xml_to_object(xvalue);
+      }
+    }
+    delete response;
+  }
 
-////////////////////////////////////////////////////////////////////
-//     Function: P3DInstance::call
-//       Access: Public
-//  Description: Calls the named property as a method, supplying the
-//               indicated parameters.
-////////////////////////////////////////////////////////////////////
-P3DObject *P3DInstance::
-call(const string &property_name, const P3DObject *params) {
-  return new P3DNoneObject;
+  nout << "Returning " << result << "\n" << flush;
+  if (result != NULL) {
+    nout << "result = " << *result << "\n" << flush;
+  }
+  return result;
 }
 
 

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

@@ -46,11 +46,7 @@ public:
   void set_wparams(const P3DWindowParams &wparams);
   inline const P3DWindowParams &get_wparams() const;
 
-  P3DObject *get_property(const string &property_name) const;
-  P3DObject *get_property_list(const string &property_name) const;
-  bool set_property(const string &property_name, 
-                    const P3DObject *value);
-  P3DObject *call(const string &property_name, const P3DObject *params);
+  P3DObject *get_script_object() const;
 
   bool has_request();
   P3D_request *get_request();

+ 6 - 9
direct/src/plugin/p3dIntObject.cxx

@@ -20,10 +20,7 @@
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 P3DIntObject::
-P3DIntObject(int value) : 
-  P3DObject(P3D_OT_int),
-  _value(value)
-{
+P3DIntObject(int value) : _value(value) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -39,13 +36,13 @@ P3DIntObject(const P3DIntObject &copy) :
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DIntObject::make_copy
+//     Function: P3DIntObject::get_type
 //       Access: Public, Virtual
-//  Description: 
+//  Description: Returns the fundamental type of this kind of object.
 ////////////////////////////////////////////////////////////////////
-P3DObject *P3DIntObject::
-make_copy() const {
-  return new P3DIntObject(*this);
+P3D_object_type P3DIntObject::
+get_type() const {
+  return P3D_OT_int;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
direct/src/plugin/p3dIntObject.h

@@ -28,7 +28,7 @@ public:
   P3DIntObject(const P3DIntObject &copy);
 
 public:
-  virtual P3DObject *make_copy() const; 
+  virtual P3D_object_type get_type() const;
   virtual bool get_bool() const;
   virtual int get_int() const;
   virtual void make_string(string &value) const;

+ 26 - 2
direct/src/plugin/p3dListObject.cxx

@@ -21,7 +21,7 @@
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 P3DListObject::
-P3DListObject() : P3DObject(P3D_OT_list) { 
+P3DListObject() { 
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -56,13 +56,26 @@ P3DListObject::
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DListObject::make_copy
 //       Access: Public, Virtual
-//  Description: 
+//  Description: Returns a new copy of the object, if necessary.  If
+//               the object type is static and all instances are
+//               identical, this actually simply ups the reference
+//               count and returns the same object.
 ////////////////////////////////////////////////////////////////////
 P3DObject *P3DListObject::
 make_copy() const {
   return new P3DListObject(*this);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DListObject::get_type
+//       Access: Public, Virtual
+//  Description: Returns the fundamental type of this kind of object.
+////////////////////////////////////////////////////////////////////
+P3D_object_type P3DListObject::
+get_type() const {
+  return P3D_OT_list;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DListObject::get_bool
 //       Access: Public, Virtual
@@ -153,6 +166,17 @@ set_element(int n, P3D_object *value) {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DListObject::append
+//       Access: Public, Virtual
+//  Description: Adds a new element to the end of the list.  Ownership
+//               is transferred to the list.
+////////////////////////////////////////////////////////////////////
+void P3DListObject::
+append(P3D_object *value) {
+  _elements.push_back(value);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DListObject::make_xml
 //       Access: Public, Virtual

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

@@ -31,12 +31,15 @@ public:
   virtual ~P3DListObject();
 
   virtual P3DObject *make_copy() const; 
+  virtual P3D_object_type get_type() const;
   virtual bool get_bool() const;
   virtual void make_string(string &value) const;
   virtual int get_list_length() const;
   virtual P3D_object *get_element(int n) const;
   virtual bool set_element(int n, P3D_object *value);
 
+  void append(P3D_object *value);
+
   virtual TiXmlElement *make_xml() const;
 
 private:

+ 6 - 6
direct/src/plugin/p3dNoneObject.cxx

@@ -20,17 +20,17 @@
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 P3DNoneObject::
-P3DNoneObject() : P3DObject(P3D_OT_none) {
+P3DNoneObject() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DNoneObject::make_copy
+//     Function: P3DNoneObject::get_type
 //       Access: Public, Virtual
-//  Description: 
+//  Description: Returns the fundamental type of this kind of object.
 ////////////////////////////////////////////////////////////////////
-P3DObject *P3DNoneObject::
-make_copy() const {
-  return new P3DNoneObject(*this);
+P3D_object_type P3DNoneObject::
+get_type() const {
+  return P3D_OT_none;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
direct/src/plugin/p3dNoneObject.h

@@ -28,7 +28,7 @@ public:
   P3DNoneObject();
 
 public:
-  virtual P3DObject *make_copy() const;
+  virtual P3D_object_type get_type() const;
   virtual bool get_bool() const;
   virtual void make_string(string &value) const;
 

+ 38 - 8
direct/src/plugin/p3dObject.I

@@ -19,9 +19,11 @@
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 inline P3DObject::
-P3DObject(P3D_object_type type) {
+P3DObject() {
   _class = &_object_class;
-  _type = type;
+
+  // The reference count is initially 1.
+  _ref_count = 1;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -31,15 +33,43 @@ P3DObject(P3D_object_type type) {
 ////////////////////////////////////////////////////////////////////
 inline P3DObject::
 P3DObject(const P3DObject &copy) {
-  _type = copy._type;
+  assert(copy._class == &_object_class);
+  _class = copy._class;
+  _ref_count = 1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DObject::ref
+//       Access: Public
+//  Description: Increments the reference count.
+////////////////////////////////////////////////////////////////////
+inline void P3DObject::
+ref() const {
+  ++(((P3DObject *)this)->_ref_count);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DObject::get_type
+//     Function: P3DObject::unref
 //       Access: Public
-//  Description: Returns the fundamental type of this kind of object.
+//  Description: Decrements the reference count, and returns the new
+//               count.
+////////////////////////////////////////////////////////////////////
+inline int P3DObject::
+unref() const {
+  --(((P3DObject *)this)->_ref_count);
+  return _ref_count;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DObject::unref_delete
+//       Access: Public, Static
+//  Description: Decrements the reference count on the indicated
+//               object, and deletes it if the reference count reaches
+//               zero.
 ////////////////////////////////////////////////////////////////////
-inline P3D_object_type P3DObject::
-get_type() const {
-  return _type;
+inline void P3DObject::
+unref_delete(P3DObject *obj) {
+  if (obj->unref() <= 0) {
+    delete obj;
+  }
 }

+ 26 - 26
direct/src/plugin/p3dObject.cxx

@@ -21,7 +21,7 @@
 // P3D_object structure.
 static void
 object_finish(P3D_object *object) {
-  delete ((P3DObject *)object);
+  P3DObject::unref_delete(((P3DObject *)object));
 }
 
 static P3D_object *
@@ -85,13 +85,12 @@ static int object_get_list_length(const P3D_object *object) {
 }
 
 static P3D_object *
-object_call(const P3D_object *object, P3D_object *params) {
-  return ((const P3DObject *)object)->call(params);
-}
-
-static P3D_object *
-object_evaluate(const P3D_object *object, const char *expression) {
-  return ((const P3DObject *)object)->evaluate(expression);
+object_call(const P3D_object *object, const char *method_name,
+            P3D_object *params) {
+  if (method_name == NULL) {
+    method_name = "";
+  }
+  return ((const P3DObject *)object)->call(method_name, params);
 }
 
 P3D_class_definition P3DObject::_object_class = {
@@ -109,7 +108,6 @@ P3D_class_definition P3DObject::_object_class = {
   &object_set_element,
   &object_get_list_length,
   &object_call,
-  &object_evaluate,
 };
 
 ////////////////////////////////////////////////////////////////////
@@ -119,7 +117,20 @@ P3D_class_definition P3DObject::_object_class = {
 ////////////////////////////////////////////////////////////////////
 P3DObject::
 ~P3DObject() {
-  _type = P3D_OT_none;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DObject::make_copy
+//       Access: Public, Virtual
+//  Description: Returns a new copy of the object, if necessary.  If
+//               the object type is static and all instances are
+//               identical, this actually simply ups the reference
+//               count and returns the same object.
+////////////////////////////////////////////////////////////////////
+P3DObject *P3DObject::
+make_copy() const {
+  ref();
+  return (P3DObject *)this;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -244,30 +255,19 @@ set_element(int n, P3D_object *value) {
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DObject::call
 //       Access: Public, Virtual
-//  Description: Invokes the object as a method, passing the indicated
-//               parameters.  Returns the return value on success,
-//               NULL on error.
+//  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 *P3DObject::
-call(P3D_object *params) const {
+call(const string &method_name, P3D_object *params) const {
   if (params != NULL) {
     P3D_OBJECT_FINISH(params);
   }
   return NULL;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: P3DObject::evaluate
-//       Access: Public, Virtual
-//  Description: Evaluates an arbitrary script expression within the
-//               context of this object.  Returns the return value on
-//               success, NULL on error.
-////////////////////////////////////////////////////////////////////
-P3D_object *P3DObject::
-evaluate(const string &expression) const {
-  return NULL;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DObject::output
 //       Access: Public, Virtual

+ 10 - 7
direct/src/plugin/p3dObject.h

@@ -27,14 +27,14 @@
 ////////////////////////////////////////////////////////////////////
 class P3DObject : public P3D_object {
 protected:
-  inline P3DObject(P3D_object_type type);
+  inline P3DObject();
   inline P3DObject(const P3DObject &copy);
 
 public:
   virtual ~P3DObject();
 
-  virtual P3DObject *make_copy() const=0; 
-  inline P3D_object_type get_type() const;
+  virtual P3DObject *make_copy() const; 
+  virtual P3D_object_type get_type() const=0;
   virtual bool get_bool() const=0;
   virtual int get_int() const;
   virtual double get_float() const;
@@ -50,15 +50,18 @@ public:
   virtual P3D_object *get_element(int n) const;
   virtual bool set_element(int n, P3D_object *value);
 
-  virtual P3D_object *call(P3D_object *params) const;
-  virtual P3D_object *evaluate(const string &expression) const;
+  virtual P3D_object *call(const string &method_name, P3D_object *params) const;
 
   virtual TiXmlElement *make_xml() const=0;
 
   virtual void output(ostream &out) const;
 
-protected:
-  P3D_object_type _type;
+  inline void ref() const;
+  inline int unref() const;
+  static inline void unref_delete(P3DObject *obj);
+
+private:
+  int _ref_count;
 
 public:
   static P3D_class_definition _object_class;

+ 302 - 0
direct/src/plugin/p3dPythonObject.cxx

@@ -0,0 +1,302 @@
+// Filename: p3dPythonObject.cxx
+// Created by:  drose (03Jul09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "p3dPythonObject.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DPythonObject::
+P3DPythonObject(P3DSession *session, int object_id) :
+  _session(session),
+  _object_id(object_id)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DPythonObject::
+~P3DPythonObject() {
+  // TODO.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::get_type
+//       Access: Public, Virtual
+//  Description: Returns the fundamental type of this kind of object.
+////////////////////////////////////////////////////////////////////
+P3D_object_type P3DPythonObject::
+get_type() const {
+  return P3D_OT_object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::get_bool
+//       Access: Public, Virtual
+//  Description: Returns the object value coerced to a boolean, if
+//               possible.
+////////////////////////////////////////////////////////////////////
+bool P3DPythonObject::
+get_bool() const {
+  bool bresult = 0;
+
+  P3D_object *result = call("__bool__", NULL);
+  if (result != NULL) {
+    bresult = P3D_OBJECT_GET_BOOL(result);
+    P3D_OBJECT_FINISH(result);
+  }    
+
+  return bresult;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::get_int
+//       Access: Public, Virtual
+//  Description: Returns the object value coerced to an integer, if
+//               possible.
+////////////////////////////////////////////////////////////////////
+int P3DPythonObject::
+get_int() const {
+  int iresult = 0;
+
+  P3D_object *result = call("__int__", NULL);
+  if (result != NULL) {
+    iresult = P3D_OBJECT_GET_INT(result);
+    P3D_OBJECT_FINISH(result);
+  }    
+
+  return iresult;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::get_float
+//       Access: Public, Virtual
+//  Description: Returns the object value coerced to a floating-point
+//               value, if possible.
+////////////////////////////////////////////////////////////////////
+double P3DPythonObject::
+get_float() const {
+  double fresult = 0.0;
+
+  P3D_object *result = call("__float__", NULL);
+  if (result != NULL) {
+    fresult = P3D_OBJECT_GET_FLOAT(result);
+    P3D_OBJECT_FINISH(result);
+  }    
+
+  return fresult;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::make_string
+//       Access: Public, Virtual
+//  Description: Fills the indicated C++ string object with the value
+//               of this object coerced to a string.
+////////////////////////////////////////////////////////////////////
+void P3DPythonObject::
+make_string(string &value) const {
+  P3D_object *result = call("__str__", NULL);
+  if (result != NULL) {
+    int size = P3D_OBJECT_GET_STRING(result, NULL, 0);
+    char *buffer = new char[size];
+    P3D_OBJECT_GET_STRING(result, buffer, size);
+    value = string(buffer, size);
+    delete[] buffer;
+
+    P3D_OBJECT_FINISH(result);
+  }    
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::get_property
+//       Access: Public, Virtual
+//  Description: Returns the named property element in the object.  The
+//               return value is a freshly-allocated P3DPythonObject object
+//               that must be deleted by the caller, or NULL on error.
+////////////////////////////////////////////////////////////////////
+P3D_object *P3DPythonObject::
+get_property(const string &property) const {
+  P3DListObject *params = new P3DListObject;
+  params->append(new P3DStringObject(property));
+
+  P3D_object *result = call("__getattr__", params);
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::set_property
+//       Access: Public, Virtual
+//  Description: Modifies (or deletes, if value is NULL) the named
+//               property element in the object.  Returns true on
+//               success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool P3DPythonObject::
+set_property(const string &property, P3D_object *value) {
+  bool bresult = false;
+
+  P3DListObject *params = new P3DListObject;
+  params->append(new P3DStringObject(property));
+
+  P3D_object *result = NULL;
+
+  if (value == NULL) {
+    // Delete an attribute.
+    result = call("__delattr__", params);
+
+  } else {
+    // Set a new attribute.
+    params->append(value);
+
+    result = call("__setattr__", params);
+  }
+
+  if (result != NULL) {
+    bresult = P3D_OBJECT_GET_BOOL(result);
+    P3D_OBJECT_FINISH(result);
+  }
+
+  return bresult;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::get_list_length
+//       Access: Public, Virtual
+//  Description: Returns the length of the object as a list.
+////////////////////////////////////////////////////////////////////
+int P3DPythonObject::
+get_list_length() const {
+  // TODO.
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::get_element
+//       Access: Public, Virtual
+//  Description: Returns the nth item in the value as a list.  The
+//               return value is a freshly-allocated P3DPythonObject object
+//               that must be deleted by the caller, or NULL on error.
+////////////////////////////////////////////////////////////////////
+P3D_object *P3DPythonObject::
+get_element(int n) const {
+  // TODO.
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::set_element
+//       Access: Public, Virtual
+//  Description: Modifies (or deletes, if value is NULL) the nth item
+//               in the value as a list.  Returns true on success,
+//               false on failure.
+////////////////////////////////////////////////////////////////////
+bool P3DPythonObject::
+set_element(int n, P3D_object *value) {
+  // TODO.
+  if (value != NULL) {
+    P3D_OBJECT_FINISH(value);
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::call
+//       Access: Public, Virtual
+//  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 *P3DPythonObject::
+call(const string &method_name, P3D_object *params) const {
+  TiXmlDocument *doc = new TiXmlDocument;
+  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
+  TiXmlElement *xcommand = new TiXmlElement("command");
+  xcommand->SetAttribute("cmd", "pyobj");
+  xcommand->SetAttribute("op", "call");
+  xcommand->SetAttribute("object_id", _object_id);
+  if (!method_name.empty()) {
+    xcommand->SetAttribute("method_name", method_name);
+  }
+
+  if (params != NULL) {
+    assert(params->_class == &P3DObject::_object_class);
+    TiXmlElement *xparams = ((P3DObject *)params)->make_xml();
+    xcommand->LinkEndChild(xparams);
+
+    // Now we're done with the params object passed in, we can delete
+    // it as promised.
+    P3D_OBJECT_FINISH(params);
+  }
+
+  doc->LinkEndChild(decl);
+  doc->LinkEndChild(xcommand);
+  TiXmlDocument *response = _session->command_and_response(doc);
+  nout << "call response pointer: " << response << "\n" << flush;
+
+  P3DObject *result = NULL;
+  if (response != NULL) {
+    TiXmlElement *xresponse = response->FirstChildElement("response");
+    if (xresponse != NULL) {
+      TiXmlElement *xvalue = xresponse->FirstChildElement("value");
+      if (xvalue != NULL) {
+        result = _session->xml_to_object(xvalue);
+      }
+    }
+    delete response;
+  }
+
+  nout << "call result = " << result << "\n" << flush;
+  if (result != NULL) {
+    nout << "  result = " << *result << "\n" << flush;
+  }
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::output
+//       Access: Public, Virtual
+//  Description: Writes a formatted representation of the value to the
+//               indicated string.  This is intended for developer
+//               assistance.
+////////////////////////////////////////////////////////////////////
+void P3DPythonObject::
+output(ostream &out) const {
+  P3D_object *result = call("__repr__", NULL);
+  out << "Python " << _object_id;
+  if (result != NULL) {
+    out << ": " << *result;
+    P3D_OBJECT_FINISH(result);
+  }    
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::make_xml
+//       Access: Public, Virtual
+//  Description: Allocates and returns a new XML structure
+//               corresponding to this value.
+////////////////////////////////////////////////////////////////////
+TiXmlElement *P3DPythonObject::
+make_xml() const {
+  TiXmlElement *xvalue = new TiXmlElement("value");
+  xvalue->SetAttribute("type", "python");
+  xvalue->SetAttribute("object_id", _object_id);
+
+  return xvalue;
+}

+ 63 - 0
direct/src/plugin/p3dPythonObject.h

@@ -0,0 +1,63 @@
+// Filename: p3dPythonObject.h
+// Created by:  drose (02Jul09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 P3DPYTHONOBJECT_H
+#define P3DPYTHONOBJECT_H
+
+#include "p3d_plugin_common.h"
+#include "p3dObject.h"
+
+class P3DSession;
+
+////////////////////////////////////////////////////////////////////
+//       Class : P3DPythonObject
+// Description : An object type that references a PyObject in the
+//               subordinate process.  It allows querying and/or
+//               modifying the state of the referenced PyObject, via
+//               clever XML communication in
+//               P3DSession::command_and_response().
+////////////////////////////////////////////////////////////////////
+class P3DPythonObject : public P3DObject {
+public:
+  P3DPythonObject(P3DSession *session, int object_id);
+  virtual ~P3DPythonObject();
+
+public:
+  virtual P3D_object_type get_type() const;
+  virtual bool get_bool() const;
+  virtual int get_int() const;
+  virtual double get_float() const;
+
+  virtual void make_string(string &value) const;
+
+  virtual P3D_object *get_property(const string &property) const;
+  virtual bool set_property(const string &property, P3D_object *value);
+
+  virtual int get_list_length() const;
+  virtual P3D_object *get_element(int n) const;
+  virtual bool set_element(int n, P3D_object *value);
+
+  virtual P3D_object *call(const string &method_name, P3D_object *params) const;
+
+  virtual TiXmlElement *make_xml() const;
+
+  virtual void output(ostream &out) const;
+
+private:
+  P3DSession *_session;
+  int _object_id;
+};
+
+#endif
+

+ 129 - 23
direct/src/plugin/p3dPythonRun.cxx

@@ -273,7 +273,104 @@ handle_pyobj_command(TiXmlElement *xcommand, int want_response_id) {
   if (op != NULL) {
     if (strcmp(op, "get_script_object") == 0) {
       // Get the toplevel Python object.
-      xresponse->SetAttribute("object", "fooby");
+      PyObject *obj = PyObject_GetAttrString(_runner, "scriptRoot");
+      if (obj != NULL) {
+        xresponse->LinkEndChild(pyobj_to_xml(obj));
+        Py_DECREF(obj);
+      }
+    } else if (strcmp(op, "call") == 0) {
+      // Call the named method on the indicated object, or the object
+      // itself if method_name isn't given.
+      int object_id;
+      if (xcommand->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) {
+        PyObject *obj = (PyObject *)(void *)object_id;
+        const char *method_name = xcommand->Attribute("method_name");
+        PyObject *params = NULL;
+        TiXmlElement *xvalue = xcommand->FirstChildElement("value");
+        if (xvalue != NULL) {
+          params = xml_to_pyobj(xvalue);
+          if (!PySequence_Check(params)) {
+            // Wrap it in a tuple to pass it to the method.
+            PyObject *tuple = PyTuple_New(1);
+            PyTuple_SetItem(tuple, 0, params);
+            params = tuple;
+          }
+        }
+
+        if (params == NULL) {
+          params = PyTuple_New(0);
+        }
+
+        // Now call the method.
+        PyObject *result = NULL;
+        if (method_name == NULL) {
+          // No method name; call the object directly.
+          result = PyObject_CallObject(obj, params);
+          
+          // Several special-case "method" names.
+        } else if (strcmp(method_name, "__bool__") == 0) {
+          result = PyBool_FromLong(PyObject_IsTrue(obj));
+
+        } else if (strcmp(method_name, "__int__") == 0) {
+          result = PyNumber_Int(obj);
+
+        } else if (strcmp(method_name, "__float__") == 0) {
+          result = PyNumber_Float(obj);
+
+        } else if (strcmp(method_name, "__repr__") == 0) {
+          result = PyObject_Repr(obj);
+
+        } else if (strcmp(method_name, "__str__") == 0) {
+          result = PyObject_Str(obj);
+
+        } else if (strcmp(method_name, "__setattr__") == 0) {
+          const char *property_name;
+          PyObject *value;
+          if (PyArg_ParseTuple(params, "sO", &property_name, &value)) {
+            PyObject_SetAttrString(obj, property_name, value);
+            result = Py_True;
+            Py_INCREF(result);
+          }
+
+        } else if (strcmp(method_name, "__delattr__") == 0) {
+          const char *property_name;
+          if (PyArg_ParseTuple(params, "s", &property_name)) {
+            if (PyObject_HasAttrString(obj, property_name)) {
+              PyObject_DelAttrString(obj, property_name);
+              result = Py_True;
+            } else {
+              result = Py_False;
+            }
+            Py_INCREF(result);
+          }
+
+        } else if (strcmp(method_name, "__getattr__") == 0) {
+          const char *property_name;
+          if (PyArg_ParseTuple(params, "s", &property_name)) {
+            if (PyObject_HasAttrString(obj, property_name)) {
+              result = PyObject_GetAttrString(obj, property_name);
+            } else {
+              result = NULL;
+            }
+          }
+
+        } else {
+          // Not a special-case name.  Call the named method.
+          PyObject *method = PyObject_GetAttrString(obj, method_name);
+          if (method != NULL) {
+            result = PyObject_CallObject(method, params);
+            Py_DECREF(method);
+          }
+        }
+        Py_DECREF(params);
+
+        // Feed the return value back through the XML pipe to the
+        // caller.
+        if (result != NULL) {
+          xresponse->LinkEndChild(pyobj_to_xml(result));
+          Py_DECREF(result);
+        }
+      }
     }
   }
 
@@ -622,14 +719,14 @@ terminate_session() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DPythonRun::make_xml_value
+//     Function: P3DPythonRun::pyobj_to_xml
 //       Access: Private
 //  Description: Converts the indicated PyObject to the appropriate
 //               XML representation of a P3D_value type, and returns a
 //               freshly-allocated TiXmlElement.
 ////////////////////////////////////////////////////////////////////
 TiXmlElement *P3DPythonRun::
-make_xml_value(PyObject *value) {
+pyobj_to_xml(PyObject *value) {
   TiXmlElement *xvalue = new TiXmlElement("value");
   if (value == Py_None) {
     // None.
@@ -690,42 +787,43 @@ make_xml_value(PyObject *value) {
       xvalue->SetAttribute("value", str);
     }
 
-  } else if (PySequence_Check(value)) {
-    // A sequence or list value.
+  } else if (PyTuple_CheckExact(value)) {
+    // A tuple.  We check for this class type specifically; other
+    // objects that provide a sequence interface should be treated as
+    // generic Python objects, below, so we don't lose other useful
+    // functionality in these objects.  Even a Python list, since we
+    // want to allow the caller to modify the list object on the
+    // Python side.
     xvalue->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);
-      xvalue->LinkEndChild(make_xml_value(obj));
+      xvalue->LinkEndChild(pyobj_to_xml(obj));
     }
 
   } else {
-    // Some other kind of object.  Don't know what else to do with it;
-    // we'll make it a string.
-    xvalue->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);
-        xvalue->SetAttribute("value", str);
-      }
-      Py_DECREF(as_str);
-    }
+    // Some other kind of object.  Make it a generic Python object.
+    // This is more expensive for the caller to deal with--it requires
+    // a back-and-forth across the XML pipe--but it's much more
+    // general.
+    xvalue->SetAttribute("type", "python");
+    xvalue->SetAttribute("object_id", (long)value);
+
+    // Temporary hack.
+    Py_INCREF(value);
   }
 
   return xvalue;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DPythonRun::from_xml_value
+//     Function: P3DPythonRun::xml_to_pyobj
 //       Access: Private
 //  Description: Converts the XML representation of a P3D_value type
 //               into the equivalent Python object and returns it.
 ////////////////////////////////////////////////////////////////////
 PyObject *P3DPythonRun::
-from_xml_value(TiXmlElement *xvalue) {
+xml_to_pyobj(TiXmlElement *xvalue) {
   const char *type = xvalue->Attribute("type");
   if (strcmp(type, "none") == 0) {
     return Py_BuildValue("");
@@ -761,12 +859,20 @@ from_xml_value(TiXmlElement *xvalue) {
 
     TiXmlElement *xchild = xvalue->FirstChildElement("value");
     while (xchild != NULL) {
-      PyObject *child = from_xml_value(xchild);
+      PyObject *child = xml_to_pyobj(xchild);
       PyList_Append(list, child);
       Py_DECREF(child);
       xchild = xchild->NextSiblingElement("value");
     }
-    return list;
+    PyObject *tuple = PyList_AsTuple(list);
+    Py_DECREF(list);
+    return tuple;
+
+  } else if (strcmp(type, "python") == 0) {
+    int object_id;
+    if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) {
+      return (PyObject *)(void *)object_id;
+    }
   }
 
   // Something went wrong in decoding.

+ 2 - 2
direct/src/plugin/p3dPythonRun.h

@@ -90,8 +90,8 @@ private:
   void terminate_session();
 
 private:
-  TiXmlElement *make_xml_value(PyObject *value);
-  PyObject *from_xml_value(TiXmlElement *xvalue);
+  TiXmlElement *pyobj_to_xml(PyObject *value);
+  PyObject *xml_to_pyobj(TiXmlElement *xvalue);
 
 private:
   // This method runs only within the read thread.

+ 66 - 70
direct/src/plugin/p3dSession.cxx

@@ -16,6 +16,12 @@
 #include "p3dInstance.h"
 #include "p3dInstanceManager.h"
 #include "p3d_plugin_config.h"
+#include "p3dNoneObject.h"
+#include "p3dBoolObject.h"
+#include "p3dIntObject.h"
+#include "p3dFloatObject.h"
+#include "p3dListObject.h"
+#include "p3dPythonObject.h"
 
 #ifndef _WIN32
 #include <fcntl.h>
@@ -286,6 +292,66 @@ command_and_response(TiXmlDocument *command) {
   return response;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DSession::xml_to_object
+//       Access: Public
+//  Description: Converts the XML representation of the particular
+//               object value into a corresponding P3DObject object.
+//               Returns the newly-allocated object.
+////////////////////////////////////////////////////////////////////
+P3DObject *P3DSession::
+xml_to_object(TiXmlElement *xvalue) {
+  const char *type = xvalue->Attribute("type");
+  if (strcmp(type, "none") == 0) {
+    return new P3DNoneObject;
+
+  } else if (strcmp(type, "bool") == 0) {
+    int value;
+    if (xvalue->QueryIntAttribute("value", &value) == TIXML_SUCCESS) {
+      return new P3DBoolObject(value != 0);
+    }
+
+  } else if (strcmp(type, "int") == 0) {
+    int value;
+    if (xvalue->QueryIntAttribute("value", &value) == TIXML_SUCCESS) {
+      return new P3DIntObject(value);
+    }
+
+  } else if (strcmp(type, "float") == 0) {
+    double value;
+    if (xvalue->QueryDoubleAttribute("value", &value) == TIXML_SUCCESS) {
+      return new P3DFloatObject(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 = xvalue->Attribute(string("value"));
+    if (value != NULL) {
+      return new P3DStringObject(*value);
+    }
+
+  } else if (strcmp(type, "list") == 0) {
+    P3DListObject *list = new P3DListObject;
+
+    TiXmlElement *xchild = xvalue->FirstChildElement("value");
+    while (xchild != NULL) {
+      list->set_element(list->get_list_length(), xml_to_object(xchild));
+      xchild = xchild->NextSiblingElement("value");
+    }
+    return list;
+
+  } else if (strcmp(type, "python") == 0) {
+    int object_id;
+    if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) {
+      return new P3DPythonObject(this, object_id);
+    }
+  }
+
+  // Something went wrong in decoding.
+  return new P3DNoneObject;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DSession::install_progress
 //       Access: Private
@@ -392,22 +458,6 @@ start_p3dpython() {
   }
   _pipe_write << flush;
   _commands.clear();
-
-  // Temp testing code.
-  {
-    TiXmlDocument *doc = new TiXmlDocument;
-    TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
-    TiXmlElement *xcommand = new TiXmlElement("command");
-    xcommand->SetAttribute("cmd", "pyobj");
-    xcommand->SetAttribute("op", "get");
-    doc->LinkEndChild(decl);
-    doc->LinkEndChild(xcommand);
-    TiXmlDocument *response = command_and_response(doc);
-    nout << "response pointer: " << response << "\n";
-    if (response != NULL) {
-      delete response;
-    }
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -573,60 +623,6 @@ rt_make_p3d_request(TiXmlElement *xrequest) {
   return request;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: P3DSession::rt_from_xml_value
-//       Access: Private
-//  Description: Converts the XML representation of the particular
-//               value value into a corresponding P3DObject object.
-//               Returns the newly-allocated object.
-////////////////////////////////////////////////////////////////////
-P3DObject *P3DSession::
-rt_from_xml_value(TiXmlElement *xvalue) {
-  const char *type = xvalue->Attribute("type");
-  if (strcmp(type, "none") == 0) {
-    return new P3DNoneObject;
-
-  } else if (strcmp(type, "bool") == 0) {
-    int value;
-    if (xvalue->QueryIntAttribute("value", &value) == TIXML_SUCCESS) {
-      return new P3DBoolObject(value != 0);
-    }
-
-  } else if (strcmp(type, "int") == 0) {
-    int value;
-    if (xvalue->QueryIntAttribute("value", &value) == TIXML_SUCCESS) {
-      return new P3DIntObject(value);
-    }
-
-  } else if (strcmp(type, "float") == 0) {
-    double value;
-    if (xvalue->QueryDoubleAttribute("value", &value) == TIXML_SUCCESS) {
-      return new P3DFloatObject(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 = xvalue->Attribute(string("value"));
-    if (value != NULL) {
-      return new P3DStringObject(*value);
-    }
-
-  } else if (strcmp(type, "list") == 0) {
-    P3DListObject *list = new P3DListObject;
-
-    TiXmlElement *xchild = xvalue->FirstChildElement("value");
-    while (xchild != NULL) {
-      list->set_element(list->get_list_length(), rt_from_xml_value(xchild));
-      xchild = xchild->NextSiblingElement("value");
-    }
-    return list;
-  }
-
-  // Something went wrong in decoding.
-  return new P3DNoneObject;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DSession::rt_terminate
 //       Access: Private

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

@@ -49,6 +49,7 @@ public:
 
   void send_command(TiXmlDocument *command);
   TiXmlDocument *command_and_response(TiXmlDocument *command);
+  P3DObject *xml_to_object(TiXmlElement *xvalue);
 
 private:
   void install_progress(P3DPackage *package, double progress);
@@ -63,7 +64,6 @@ private:
   void rt_terminate();
   void rt_handle_request(TiXmlDocument *doc);
   P3D_request *rt_make_p3d_request(TiXmlElement *xrequest);
-  P3DObject *rt_from_xml_value(TiXmlElement *xvalue);
 
 #ifdef _WIN32
   static DWORD WINAPI win_rt_thread_run(LPVOID data);

+ 6 - 9
direct/src/plugin/p3dStringObject.cxx

@@ -20,10 +20,7 @@
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 P3DStringObject::
-P3DStringObject(const string &value) : 
-  P3DObject(P3D_OT_string),
-  _value(value)
-{
+P3DStringObject(const string &value) : _value(value) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -48,13 +45,13 @@ P3DStringObject::
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DStringObject::make_copy
+//     Function: P3DStringObject::get_type
 //       Access: Public, Virtual
-//  Description: 
+//  Description: Returns the fundamental type of this kind of object.
 ////////////////////////////////////////////////////////////////////
-P3DObject *P3DStringObject::
-make_copy() const {
-  return new P3DStringObject(*this);
+P3D_object_type P3DStringObject::
+get_type() const {
+  return P3D_OT_string;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
direct/src/plugin/p3dStringObject.h

@@ -30,7 +30,7 @@ public:
 public:
   virtual ~P3DStringObject();
 
-  virtual P3DObject *make_copy() const; 
+  virtual P3D_object_type get_type() const;
   virtual bool get_bool() const;
   virtual void make_string(string &value) const;
 

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

@@ -203,8 +203,7 @@ P3D_instance_get_script_object(P3D_instance *instance) {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_lock);
 
-  // TODO.
-  P3D_object *result = NULL;
+  P3D_object *result = ((P3DInstance *)instance)->get_script_object();
   
   RELEASE_LOCK(_lock);
   return result;

+ 14 - 17
direct/src/plugin/p3d_plugin.h

@@ -388,21 +388,20 @@ P3D_object_set_element_method(P3D_object *object, int n, P3D_object *value);
 typedef int
 P3D_object_get_list_length_method(const P3D_object *object);
 
-/* Invokes the object as a function.  The params object should be a
-   list object containing the individual parameters; ownership of this
-   list object is transferred in this call, and it will automatically
-   be deleted.  The return value is a newly-allocated P3D_object on
-   success, or NULL on failure.  Ownership of the return value is
-   transferred to the caller. */
+/* Invokes a named method on the object.  If method_name is empty or
+   NULL, invokes the object itself as a function.  The params object
+   should be a list object containing the individual parameters;
+   ownership of this list object is transferred in this call, and it
+   will automatically be deleted.  It may also be NULL if no
+   parameters are required, or a single non-list parameter if only one
+   parameter is required.
+
+   The return value is a newly-allocated P3D_object on success, or
+   NULL on failure.  Ownership of the return value is transferred to
+   the caller. */
 typedef P3D_object *
-P3D_object_call_method(const P3D_object *object, P3D_object *params);
-
-/* Evaluates an arbitrary script expression, if possible, within the
-   context of the object.  The return value is the return value of the
-   expression, or NULL on error.  As above, ownership of the return
-   value is transferred to the caller. */
-typedef P3D_object *
-P3D_object_evaluate_method(const P3D_object *object, const char *expression);
+P3D_object_call_method(const P3D_object *object, const char *method_name,
+                       P3D_object *params);
 
 /* This defines the class structure that implements all of the above
    methods. */
@@ -424,7 +423,6 @@ typedef struct _P3D_class_definition {
   P3D_object_get_list_length_method *_get_list_length;
 
   P3D_object_call_method *_call;
-  P3D_object_evaluate_method *_evaluate;
 
 } P3D_class_definition;
 
@@ -455,8 +453,7 @@ struct _P3D_object {
 #define P3D_OBJECT_SET_ELEMENT(object, n, value) ((object)->_class->_set_element((object), (n), (value)))
 #define P3D_OBJECT_GET_LIST_LENGTH(object, n, value) ((object)->_class->_get_list_length((object), (n), (value)))
 
-#define P3D_OBJECT_CALL(object, params) ((object)->_class->_call((object), (params)))
-#define P3D_OBJECT_EVALUATE(object, expression) ((object)->_class->_evaluate((object), (expression)))
+#define P3D_OBJECT_CALL(object, method_name, params) ((object)->_class->_call((object), (method_name), (params)))
 
 
 /* The following function types are once again meant to define

+ 1 - 0
direct/src/plugin/p3d_plugin_composite1.cxx

@@ -10,6 +10,7 @@
 #include "p3dIntObject.cxx"
 #include "p3dListObject.cxx"
 #include "p3dMultifileReader.cxx"
+#include "p3dPythonObject.cxx"
 #include "p3dNoneObject.cxx"
 #include "p3dObject.cxx"
 #include "p3dPackage.cxx"

+ 22 - 0
direct/src/plugin_standalone/panda3d.cxx

@@ -404,6 +404,28 @@ handle_request(P3D_request *request) {
     cerr << "Got P3D_RT_notify: " << request->_request._notify._message
          << "\n";
     // Ignore notifications.
+
+    // Temporary.
+    P3D_object *obj = P3D_instance_get_script_object(request->_instance);
+    cerr << "script_object is " << obj << "\n";
+    if (obj != NULL) {
+      if (P3D_OBJECT_SET_PROPERTY(obj, "foo", P3D_new_int_object(1))) {
+        cerr << "set_property succeeded\n";
+        P3D_object *prop = P3D_OBJECT_GET_PROPERTY(obj, "foo");
+        cerr << "get_property returned " << prop << "\n";
+        if (prop != NULL) {
+          int size = P3D_OBJECT_GET_STRING(prop, NULL, 0);
+          char *buffer = new char[size];
+          P3D_OBJECT_GET_STRING(prop, buffer, size);
+          cerr << "  property is " << buffer << "\n";
+          delete buffer;
+          P3D_OBJECT_FINISH(prop);
+        }
+      } else {
+        cerr << "set_property failed\n";
+      }
+      P3D_OBJECT_FINISH(obj);
+    }
     break;
 
   default:

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

@@ -41,6 +41,12 @@ default-model-extension .bam
 class ArgumentError(AttributeError):
     pass
 
+class ScriptRoot:
+    """ This dummy class serves as the root object for the scripting
+    interface.  The Python code can store objects and functions here
+    for direct meddling by the browser's JavaScript code. """
+    pass
+
 class AppRunner(DirectObject):
     def __init__(self):
         DirectObject.__init__(self)
@@ -50,7 +56,10 @@ class AppRunner(DirectObject):
         self.gotP3DFilename = False
         self.started = False
         self.windowPrc = None
+
+        # TODO: we need one of these per instance, not per session.
         self.instanceId = None
+        self.scriptRoot = ScriptRoot()
 
         # This is the default requestFunc that is installed if we
         # never call setRequestFunc().