Browse Source

support pre-python properties

David Rose 16 years ago
parent
commit
19e6ffd5ee

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

@@ -44,6 +44,7 @@
     p3dSession.h p3dSession.I \
     p3dSession.h p3dSession.I \
     p3dSplashWindow.h p3dSplashWindow.I \
     p3dSplashWindow.h p3dSplashWindow.I \
     p3dStringObject.h \
     p3dStringObject.h \
+    p3dToplevelObject.h \
     p3dUndefinedObject.h \
     p3dUndefinedObject.h \
     p3dWinSplashWindow.h p3dWinSplashWindow.I \
     p3dWinSplashWindow.h p3dWinSplashWindow.I \
     p3dX11SplashWindow.h \
     p3dX11SplashWindow.h \
@@ -69,6 +70,7 @@
     p3dSession.cxx \
     p3dSession.cxx \
     p3dSplashWindow.cxx \
     p3dSplashWindow.cxx \
     p3dStringObject.cxx \
     p3dStringObject.cxx \
+    p3dToplevelObject.cxx \
     p3dUndefinedObject.cxx \
     p3dUndefinedObject.cxx \
     p3dWinSplashWindow.cxx \
     p3dWinSplashWindow.cxx \
     p3dX11SplashWindow.cxx \
     p3dX11SplashWindow.cxx \

+ 6 - 2
direct/src/plugin/p3dFileParams.cxx

@@ -12,8 +12,8 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
-
 #include "p3dFileParams.h"
 #include "p3dFileParams.h"
+#include <ctype.h>
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DFileParams::Default Constructor
 //     Function: P3DFileParams::Default Constructor
@@ -37,7 +37,11 @@ P3DFileParams(const string &p3d_filename,
   for (size_t i = 0; i < num_tokens; ++i) {
   for (size_t i = 0; i < num_tokens; ++i) {
     Token token;
     Token token;
     if (tokens[i]._keyword != NULL) {
     if (tokens[i]._keyword != NULL) {
-      token._keyword = tokens[i]._keyword;
+      // Make the token lowercase, since HTML is case-insensitive but
+      // we're not.
+      for (const char *p = tokens[i]._keyword; *p; ++p) {
+        token._keyword += tolower(*p);
+      }
     }
     }
     if (tokens[i]._value != NULL) {
     if (tokens[i]._value != NULL) {
       token._value = tokens[i]._value;
       token._value = tokens[i]._value;

+ 65 - 43
direct/src/plugin/p3dInstance.cxx

@@ -21,6 +21,7 @@
 #include "p3dWinSplashWindow.h"
 #include "p3dWinSplashWindow.h"
 #include "p3dX11SplashWindow.h"
 #include "p3dX11SplashWindow.h"
 #include "p3dObject.h"
 #include "p3dObject.h"
+#include "p3dToplevelObject.h"
 #include "p3dUndefinedObject.h"
 #include "p3dUndefinedObject.h"
 
 
 #include <sstream>
 #include <sstream>
@@ -48,6 +49,7 @@ P3DInstance(P3D_request_ready_func *func, void *user_data) :
   _func(func)
   _func(func)
 {
 {
   _browser_script_object = NULL;
   _browser_script_object = NULL;
+  _panda_script_object = new P3DToplevelObject;
   _user_data = user_data;
   _user_data = user_data;
   _request_pending = false;
   _request_pending = false;
   _got_fparams = false;
   _got_fparams = false;
@@ -62,6 +64,9 @@ P3DInstance(P3D_request_ready_func *func, void *user_data) :
   _splash_window = NULL;
   _splash_window = NULL;
   _instance_window_opened = false;
   _instance_window_opened = false;
   _requested_stop = false;
   _requested_stop = false;
+
+  // Set some initial properties.
+  _panda_script_object->set_float_property("downloadProgress", 0.0);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -71,14 +76,13 @@ P3DInstance(P3D_request_ready_func *func, void *user_data) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3DInstance::
 P3DInstance::
 ~P3DInstance() {
 ~P3DInstance() {
-  // TODO: maybe this should be a reference-counted object, so we
-  // don't delete it too soon.
-
   assert(_session == NULL);
   assert(_session == NULL);
 
 
   P3D_OBJECT_XDECREF(_browser_script_object);
   P3D_OBJECT_XDECREF(_browser_script_object);
 
 
-  DESTROY_LOCK(_request_lock);
+  nout << "panda_script_object ref = "
+       << _panda_script_object->_ref_count << "\n" << flush;
+  P3D_OBJECT_DECREF(_panda_script_object);
 
 
   // Tell all of the packages that we're no longer in business for
   // Tell all of the packages that we're no longer in business for
   // them.
   // them.
@@ -93,6 +97,8 @@ P3DInstance::
     _splash_window = NULL;
     _splash_window = NULL;
   }
   }
 
 
+  DESTROY_LOCK(_request_lock);
+
   // TODO: empty _raw_requests and _baked_requests queues, and
   // TODO: empty _raw_requests and _baked_requests queues, and
   // _downloads map.
   // _downloads map.
 
 
@@ -123,6 +129,25 @@ set_fparams(const P3DFileParams &fparams) {
   // TODO.
   // TODO.
   _python_version = "python24";
   _python_version = "python24";
 
 
+  // Generate a special notification: onpluginload, indicating the
+  // plugin has read its parameters and is ready to be queried (even
+  // if Python has not yet started).  This notification is special
+  // because it is the only one generated at this level; the rest of
+  // them are generated by the Python code, once that is running.
+  P3D_request *request = new P3D_request;
+  request->_request_type = P3D_RT_notify;
+  request->_request._notify._message = strdup("onpluginload");
+  add_baked_request(request);
+
+  // Also eval the HTML associated token.
+  string expression = _fparams.lookup_token("onpluginload");
+  if (!expression.empty() && _browser_script_object != NULL) {
+    P3D_object *result = P3D_OBJECT_EVAL(_browser_script_object, expression.c_str());
+    if (result != NULL) {
+      nout << "onpluginload returned: " << *result << "\n";
+    }
+    P3D_OBJECT_XDECREF(result);
+  }
 
 
   // Maybe create the splash window.
   // Maybe create the splash window.
   if (!_instance_window_opened && _got_wparams) {
   if (!_instance_window_opened && _got_wparams) {
@@ -179,35 +204,7 @@ set_wparams(const P3DWindowParams &wparams) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3D_object *P3DInstance::
 P3D_object *P3DInstance::
 get_panda_script_object() const {
 get_panda_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_panda_script_object");
-  doc->LinkEndChild(decl);
-  doc->LinkEndChild(xcommand);
-  TiXmlDocument *response = _session->command_and_response(doc);
-
-  P3D_object *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_p3dobj(xvalue);
-      }
-    }
-    delete response;
-  }
-
-  if (result == NULL) {
-    P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
-    result = inst_mgr->new_undefined_object();
-  }
-
-  return result;
+  return _panda_script_object;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -557,6 +554,7 @@ make_p3d_request(TiXmlElement *xrequest) {
         request = new P3D_request;
         request = new P3D_request;
         request->_request_type = P3D_RT_notify;
         request->_request_type = P3D_RT_notify;
         request->_request._notify._message = strdup(message);
         request->_request._notify._message = strdup(message);
+        handle_notify_request(message);
       }
       }
 
 
     } else if (strcmp(rtype, "script") == 0) {
     } else if (strcmp(rtype, "script") == 0) {
@@ -599,15 +597,6 @@ make_p3d_request(TiXmlElement *xrequest) {
         P3D_OBJECT_DECREF(values[i]);
         P3D_OBJECT_DECREF(values[i]);
       }
       }
 
 
-    } else if (strcmp(rtype, "notify") == 0) {
-      const char *message = xrequest->Attribute("message");
-      if (message != NULL) {
-        request = new P3D_request;
-        request->_request_type = P3D_RT_notify;
-        request->_request._notify._message = strdup(message);
-        handle_notify_request(message);
-      }
-
     } else if (strcmp(rtype, "drop_p3dobj") == 0) {
     } else if (strcmp(rtype, "drop_p3dobj") == 0) {
       int object_id;
       int object_id;
       if (xrequest->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) {
       if (xrequest->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) {
@@ -636,7 +625,39 @@ void P3DInstance::
 handle_notify_request(const string &message) {
 handle_notify_request(const string &message) {
   // We look for certain notify events that have particular meaning
   // We look for certain notify events that have particular meaning
   // to this instance.
   // to this instance.
-  if (message == "onwindowopen") {
+  nout << "handle_notify: " << message << "\n";
+
+  if (message == "onpythonload") {
+    // Once Python is up and running, we can get the actual toplevel
+    // object from the Python side, and merge it with our own.
+
+    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_panda_script_object");
+    doc->LinkEndChild(decl);
+    doc->LinkEndChild(xcommand);
+    TiXmlDocument *response = _session->command_and_response(doc);
+    
+    P3D_object *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_p3dobj(xvalue);
+        }
+      }
+      delete response;
+    }
+
+    if (result != NULL) {
+      _panda_script_object->set_pyobj(result);
+      P3D_OBJECT_DECREF(result);
+    }
+
+  } else if (message == "onwindowopen") {
     // The process told us that it just succesfully opened its
     // The process told us that it just succesfully opened its
     // window.  Tear down the splash window.
     // window.  Tear down the splash window.
     _instance_window_opened = true;
     _instance_window_opened = true;
@@ -789,6 +810,7 @@ install_progress(P3DPackage *package, double progress) {
     _splash_window->set_install_label("Installing Panda3D");
     _splash_window->set_install_label("Installing Panda3D");
     _splash_window->set_install_progress(progress);
     _splash_window->set_install_progress(progress);
   }
   }
+  _panda_script_object->set_float_property("downloadProgress", progress);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

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

@@ -30,6 +30,7 @@ class P3DSplashWindow;
 class P3DDownload;
 class P3DDownload;
 class P3DPackage;
 class P3DPackage;
 class P3DObject;
 class P3DObject;
+class P3DToplevelObject;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : P3DInstance
 //       Class : P3DInstance
@@ -102,6 +103,7 @@ private:
 
 
   P3D_request_ready_func *_func;
   P3D_request_ready_func *_func;
   P3D_object *_browser_script_object;
   P3D_object *_browser_script_object;
+  P3DToplevelObject *_panda_script_object;
 
 
   bool _got_fparams;
   bool _got_fparams;
   P3DFileParams _fparams;
   P3DFileParams _fparams;

+ 137 - 2
direct/src/plugin/p3dObject.cxx

@@ -13,6 +13,10 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "p3dObject.h"
 #include "p3dObject.h"
+#include "p3dBoolObject.h"
+#include "p3dIntObject.h"
+#include "p3dFloatObject.h"
+#include "p3dStringObject.h"
 #include <string.h>  // strncpy
 #include <string.h>  // strncpy
 
 
 // The following functions are C-style wrappers around the below
 // The following functions are C-style wrappers around the below
@@ -254,8 +258,8 @@ get_repr(char *buffer, int buffer_length) {
 //     Function: P3DObject::get_property
 //     Function: P3DObject::get_property
 //       Access: Public, Virtual
 //       Access: Public, Virtual
 //  Description: Returns the named property element in the object.  The
 //  Description: Returns the named property element in the object.  The
-//               return value is a freshly-allocated P3DObject object
-//               that must be deleted by the caller, or NULL on error.
+//               return value is a new-reference P3D_object, or NULL
+//               on error.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3D_object *P3DObject::
 P3D_object *P3DObject::
 get_property(const string &property) {
 get_property(const string &property) {
@@ -323,3 +327,134 @@ output(ostream &out) {
   out << value;
   out << value;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DObject::get_bool_property
+//       Access: Public
+//  Description: Returns the value of the named property, as a
+//               boolean.  Returns 0 if the property does not exist.
+////////////////////////////////////////////////////////////////////
+bool P3DObject::
+get_bool_property(const string &property) {
+  P3D_object *result = get_property(property);
+  if (result == NULL) {
+    return 0;
+  }
+  bool bresult = P3D_OBJECT_GET_BOOL(result);
+  P3D_OBJECT_DECREF(result);
+  return bresult;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DObject::set_bool_property
+//       Access: Public
+//  Description: Changes the value of the named property to the
+//               indicated boolean value.
+////////////////////////////////////////////////////////////////////
+bool P3DObject::
+set_bool_property(const string &property, bool value) {
+  P3D_object *bvalue = new P3DBoolObject(value);
+  bool result = set_property(property, bvalue);
+  P3D_OBJECT_DECREF(bvalue);
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DObject::get_int_property
+//       Access: Public
+//  Description: Returns the value of the named property, as an
+//               integer.  Returns 0 if the property does not exist.
+////////////////////////////////////////////////////////////////////
+int P3DObject::
+get_int_property(const string &property) {
+  P3D_object *result = get_property(property);
+  if (result == NULL) {
+    return 0;
+  }
+  int iresult = P3D_OBJECT_GET_INT(result);
+  P3D_OBJECT_DECREF(result);
+  return iresult;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DObject::set_int_property
+//       Access: Public
+//  Description: Changes the value of the named property to the
+//               indicated integer value.
+////////////////////////////////////////////////////////////////////
+bool P3DObject::
+set_int_property(const string &property, int value) {
+  P3D_object *ivalue = new P3DIntObject(value);
+  bool result = set_property(property, ivalue);
+  P3D_OBJECT_DECREF(ivalue);
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DObject::get_float_property
+//       Access: Public
+//  Description: Returns the value of the named property, as a
+//               floating-point number.  Returns 0.0 if the property
+//               does not exist.
+////////////////////////////////////////////////////////////////////
+double P3DObject::
+get_float_property(const string &property) {
+  P3D_object *result = get_property(property);
+  if (result == NULL) {
+    return 0.0;
+  }
+  double fresult = P3D_OBJECT_GET_FLOAT(result);
+  P3D_OBJECT_DECREF(result);
+  return fresult;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DObject::set_float_property
+//       Access: Public
+//  Description: Changes the value of the named property to the
+//               indicated floating-point value.
+////////////////////////////////////////////////////////////////////
+bool P3DObject::
+set_float_property(const string &property, double value) {
+  P3D_object *fvalue = new P3DFloatObject(value);
+  bool result = set_property(property, fvalue);
+  P3D_OBJECT_DECREF(fvalue);
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DObject::get_string_property
+//       Access: Public
+//  Description: Returns the value of the named property, as a
+//               string.  Returns empty string if the property does
+//               not exist.
+////////////////////////////////////////////////////////////////////
+string P3DObject::
+get_string_property(const string &property) {
+  P3D_object *result = get_property(property);
+  if (result == NULL) {
+    return string();
+  }
+
+  int size = P3D_OBJECT_GET_STRING(result, NULL, 0);
+  char *buffer = new char[size];
+  P3D_OBJECT_GET_STRING(result, buffer, size);
+  string sresult(buffer, size);
+  delete[] buffer;
+
+  P3D_OBJECT_DECREF(result);
+  return sresult;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DObject::set_string_property
+//       Access: Public
+//  Description: Changes the value of the named property to the
+//               indicated string value.
+////////////////////////////////////////////////////////////////////
+bool P3DObject::
+set_string_property(const string &property, const string &value) {
+  P3D_object *svalue = new P3DStringObject(value);
+  bool result = set_property(property, svalue);
+  P3D_OBJECT_DECREF(svalue);
+  return result;
+}

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

@@ -52,6 +52,19 @@ public:
 
 
   virtual void output(ostream &out);
   virtual void output(ostream &out);
 
 
+  // Convenience functions.
+  bool get_bool_property(const string &property);
+  bool set_bool_property(const string &property, bool value);
+
+  int get_int_property(const string &property);
+  bool set_int_property(const string &property, int value);
+
+  double get_float_property(const string &property);
+  bool set_float_property(const string &property, double value);
+
+  string get_string_property(const string &property);
+  bool set_string_property(const string &property, const string &value);
+
 public:
 public:
   static P3D_class_definition _object_class;
   static P3D_class_definition _object_class;
   static P3D_class_definition _generic_class;
   static P3D_class_definition _generic_class;

+ 2 - 2
direct/src/plugin/p3dPythonObject.cxx

@@ -134,8 +134,8 @@ make_string(string &value) {
 //     Function: P3DPythonObject::get_property
 //     Function: P3DPythonObject::get_property
 //       Access: Public, Virtual
 //       Access: Public, Virtual
 //  Description: Returns the named property element in the object.  The
 //  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.
+//               return value is a new-reference P3D_object, or NULL
+//               on error.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3D_object *P3DPythonObject::
 P3D_object *P3DPythonObject::
 get_property(const string &property) {
 get_property(const string &property) {

+ 258 - 0
direct/src/plugin/p3dToplevelObject.cxx

@@ -0,0 +1,258 @@
+// Filename: p3dToplevelObject.cxx
+// Created by:  drose (10Jul09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "p3dToplevelObject.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DToplevelObject::
+P3DToplevelObject() :
+  _pyobj(NULL)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DToplevelObject::
+~P3DToplevelObject() {
+  set_pyobj(NULL);
+
+  // Just in case there are properties we haven't cleared yet.
+  Properties::const_iterator pi;
+  for (pi = _properties.begin(); pi != _properties.end(); ++pi) {
+    P3D_object *value = (*pi).second;
+    P3D_OBJECT_DECREF(value);
+  }
+  _properties.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::get_type
+//       Access: Public, Virtual
+//  Description: Returns the fundamental type of this kind of object.
+////////////////////////////////////////////////////////////////////
+P3D_object_type P3DToplevelObject::
+get_type() {
+  return P3D_OT_object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::get_bool
+//       Access: Public, Virtual
+//  Description: Returns the object value coerced to a boolean, if
+//               possible.
+////////////////////////////////////////////////////////////////////
+bool P3DToplevelObject::
+get_bool() {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::get_int
+//       Access: Public, Virtual
+//  Description: Returns the object value coerced to an integer, if
+//               possible.
+////////////////////////////////////////////////////////////////////
+int P3DToplevelObject::
+get_int() {
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::get_float
+//       Access: Public, Virtual
+//  Description: Returns the object value coerced to a floating-point
+//               value, if possible.
+////////////////////////////////////////////////////////////////////
+double P3DToplevelObject::
+get_float() {
+  return 0.0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::make_string
+//       Access: Public, Virtual
+//  Description: Fills the indicated C++ string object with the value
+//               of this object coerced to a string.
+////////////////////////////////////////////////////////////////////
+void P3DToplevelObject::
+make_string(string &value) {
+  if (_pyobj == NULL) {
+    value = "P3DToplevelObject";
+  } else {
+    int size = P3D_OBJECT_GET_STRING(_pyobj, NULL, 0);
+    char *buffer = new char[size];
+    P3D_OBJECT_GET_STRING(_pyobj, buffer, size);
+    value = string(buffer, size);
+    delete[] buffer;
+  }    
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::get_property
+//       Access: Public, Virtual
+//  Description: Returns the named property element in the object.  The
+//               return value is a new-reference P3D_object, or NULL
+//               on error.
+////////////////////////////////////////////////////////////////////
+P3D_object *P3DToplevelObject::
+get_property(const string &property) {
+  if (_pyobj == NULL) {
+    // Without a pyobj, we just report whatever's been stored locally.
+    Properties::const_iterator pi;
+    pi = _properties.find(property);
+    if (pi != _properties.end()) {
+      P3D_object *result = (*pi).second;
+      P3D_OBJECT_INCREF(result);
+      return result;
+    }
+    return NULL;
+  }
+
+  // With a pyobj, we pass the query down to it.
+  return P3D_OBJECT_GET_PROPERTY(_pyobj, property.c_str());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::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 P3DToplevelObject::
+set_property(const string &property, P3D_object *value) {
+  if (_pyobj == NULL) {
+    // Without a pyobj, we just store the value locally.
+    if (value != NULL) {
+      Properties::iterator pi;
+      pi = _properties.insert(Properties::value_type(property, NULL)).first;
+      assert(pi != _properties.end());
+      P3D_object *orig_value = (*pi).second;
+      if (orig_value != value) {
+        P3D_OBJECT_XDECREF(orig_value);
+        (*pi).second = value;
+        P3D_OBJECT_INCREF(value);
+      }
+    } else {
+      // Or delete the property locally.
+      Properties::iterator pi;
+      pi = _properties.find(property);
+      if (pi != _properties.end()) {
+        P3D_object *orig_value = (*pi).second;
+        P3D_OBJECT_DECREF(orig_value);
+        _properties.erase(pi);
+      }
+    }
+    return true;
+  }
+
+  // With a pyobj, we pass this request down.
+  return P3D_OBJECT_SET_PROPERTY(_pyobj, property.c_str(), value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::has_method
+//       Access: Public, Virtual
+//  Description: Returns true if the named method exists on this
+//               object, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool P3DToplevelObject::
+has_method(const string &method_name) {
+  if (_pyobj == NULL) {
+    // No methods until we get our pyobj.
+    return false;
+  }
+
+  return P3D_OBJECT_HAS_METHOD(_pyobj, method_name.c_str());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::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 *P3DToplevelObject::
+call(const string &method_name, P3D_object *params[], int num_params) {
+  if (_pyobj == NULL) {
+    // No methods until we get our pyobj.
+    return NULL;
+  }
+
+  return P3D_OBJECT_CALL(_pyobj, method_name.c_str(), params, num_params);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::output
+//       Access: Public, Virtual
+//  Description: Writes a formatted representation of the value to the
+//               indicated string.  This is intended for developer
+//               assistance.
+////////////////////////////////////////////////////////////////////
+void P3DToplevelObject::
+output(ostream &out) {
+  out << "P3DToplevelObject";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::set_pyobj
+//       Access: Public
+//  Description: Changes the internal pyobj pointer.  This is the
+//               P3D_object that references the actual PyObject held
+//               within the child process, corresponding to the true
+//               toplevel object there.  The new object's reference
+//               count is incremented, and the previous object's is
+//               decremented.
+////////////////////////////////////////////////////////////////////
+void P3DToplevelObject::
+set_pyobj(P3D_object *pyobj) {
+  if (_pyobj != pyobj) {
+    P3D_OBJECT_XDECREF(_pyobj);
+    _pyobj = pyobj;
+    if (_pyobj != NULL) {
+      P3D_OBJECT_INCREF(_pyobj);
+
+      // Now that we have a pyobj, we have to transfer down all of the
+      // properties we'd set locally.
+      Properties::const_iterator pi;
+      for (pi = _properties.begin(); pi != _properties.end(); ++pi) {
+        const string &property_name = (*pi).first;
+        P3D_object *value = (*pi).second;
+        P3D_OBJECT_SET_PROPERTY(_pyobj, property_name.c_str(), value);
+        P3D_OBJECT_DECREF(value);
+      }
+      _properties.clear();
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DToplevelObject::get_pyobj
+//       Access: Public
+//  Description: Returns the internal pyobj pointer, or NULL if it has
+//               not yet been set.
+////////////////////////////////////////////////////////////////////
+P3D_object *P3DToplevelObject::
+get_pyobj() const {
+  return _pyobj;
+}

+ 75 - 0
direct/src/plugin/p3dToplevelObject.h

@@ -0,0 +1,75 @@
+// Filename: p3dToplevelObject.h
+// Created by:  drose (10Jul09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 P3DTOPLEVELOBJECT_H
+#define P3DTOPLEVELOBJECT_H
+
+#include "p3d_plugin_common.h"
+#include "p3dObject.h"
+#include <map>
+
+class P3DSession;
+
+////////////////////////////////////////////////////////////////////
+//       Class : P3DToplevelObject
+// Description : This corresponds to the toplevel "Python" object
+//               owned by a particular instance, as returned by
+//               P3DInstance::get_panda_script_object().
+//
+//               This is mostly a wrapper around a P3DPythonObject
+//               pointer, and therefore functions like any other
+//               P3DPythonObject; but it also handles the special case
+//               of being available before Python has been started;
+//               and it furthermore reports properties that are
+//               generated directly by the core API (like
+//               downloadProgress and such).
+////////////////////////////////////////////////////////////////////
+class P3DToplevelObject : public P3DObject {
+public:
+  P3DToplevelObject();
+  virtual ~P3DToplevelObject();
+
+public:
+  virtual P3D_object_type get_type();
+  virtual bool get_bool();
+  virtual int get_int();
+  virtual double get_float();
+
+  virtual void make_string(string &value);
+
+  virtual P3D_object *get_property(const string &property);
+  virtual bool set_property(const string &property, P3D_object *value);
+
+  virtual bool has_method(const string &method_name);
+  virtual P3D_object *call(const string &method_name, 
+                           P3D_object *params[], int num_params);
+
+  virtual void output(ostream &out);
+
+  void set_pyobj(P3D_object *pyobj);
+  P3D_object *get_pyobj() const;
+
+private:
+  P3D_object *_pyobj;
+
+  // This map is used to store properties and retrieve until
+  // set_pyobj() is called for the firs ttime.  At that point, the
+  // properties stored here are transferred down to the internal
+  // PyObject.
+  typedef map<string, P3D_object *> Properties;
+  Properties _properties;
+};
+
+#endif
+

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

@@ -17,6 +17,7 @@
 #include "p3dSession.cxx"
 #include "p3dSession.cxx"
 #include "p3dSplashWindow.cxx"
 #include "p3dSplashWindow.cxx"
 #include "p3dStringObject.cxx"
 #include "p3dStringObject.cxx"
+#include "p3dToplevelObject.cxx"
 #include "p3dUndefinedObject.cxx"
 #include "p3dUndefinedObject.cxx"
 #include "p3dWinSplashWindow.cxx"
 #include "p3dWinSplashWindow.cxx"
 #include "p3dX11SplashWindow.cxx"
 #include "p3dX11SplashWindow.cxx"

+ 20 - 20
direct/src/plugin_npapi/ppInstance.cxx

@@ -423,15 +423,8 @@ handle_request(P3D_request *request) {
     break;
     break;
 
 
   case P3D_RT_notify:
   case P3D_RT_notify:
-    {
-      if (_script_object != NULL &&
-          strcmp(request->_request._notify._message, "onpythonload") == 0) {
-        // Now that Python is running, initialize our script_object
-        // with the proper P3D object pointer.
-        P3D_object *obj = P3D_instance_get_panda_script_object(_p3d_inst);
-        _script_object->set_p3d_object(obj);
-      }
-    }
+    // We can ignore notifies, since these are handled by the core
+    // API.
     break;
     break;
 
 
   default:
   default:
@@ -922,11 +915,6 @@ create_instance() {
     return;
     return;
   }
   }
 
 
-  if (!_got_window) {
-    // No window yet.
-    return;
-  }
-
   _p3d_inst = P3D_new_instance(request_ready, this);
   _p3d_inst = P3D_new_instance(request_ready, this);
 
 
   if (_p3d_inst != NULL) {
   if (_p3d_inst != NULL) {
@@ -940,13 +928,25 @@ create_instance() {
     } else {
     } else {
       logfile << "Couldn't get window_object\n" << flush;
       logfile << "Couldn't get window_object\n" << flush;
     }
     }
-    
-    P3D_token *tokens = NULL;
-    if (!_tokens.empty()) {
-      tokens = &_tokens[0];
+
+    if (_script_object != NULL) {
+      // Now that we have a true instance, initialize our
+      // script_object with the proper P3D_object pointer.
+      P3D_object *obj = P3D_instance_get_panda_script_object(_p3d_inst);
+      _script_object->set_p3d_object(obj);
+    }
+
+    if (_got_instance_data) {
+      P3D_token *tokens = NULL;
+      if (!_tokens.empty()) {
+        tokens = &_tokens[0];
+      }
+      P3D_instance_start(_p3d_inst, _p3d_filename.c_str(), tokens, _tokens.size());
+    }
+
+    if (_got_window) {
+      send_window();
     }
     }
-    P3D_instance_start(_p3d_inst, _p3d_filename.c_str(), tokens, _tokens.size());
-    send_window();
   }
   }
 }
 }