Browse Source

a tiny bit of cleanup

David Rose 16 years ago
parent
commit
41ba4f06cb

+ 5 - 41
direct/src/plugin/p3dInstance.cxx

@@ -20,8 +20,7 @@
 #include "p3dSplashWindow.h"
 #include "p3dWinSplashWindow.h"
 #include "p3dObject.h"
-#include "p3dNoneObject.h"
-#include "p3dPythonObject.h"
+#include "p3dNullObject.h"
 
 #include <sstream>
 #include <algorithm>
@@ -84,7 +83,6 @@ P3DInstance::
   _packages.clear();
 
   if (_splash_window != NULL) {
-    nout << "Deleting splash window in destructor\n" << flush;
     delete _splash_window;
     _splash_window = NULL;
   }
@@ -93,8 +91,6 @@ P3DInstance::
 
   // TODO: Is it possible for someone to delete an instance while a
   // download is still running?  Who will crash when this happens?
-
-  nout << "deleting instance " << this << "\n" << flush;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -176,7 +172,6 @@ set_wparams(const P3DWindowParams &wparams) {
 P3D_object *P3DInstance::
 get_panda_script_object() const {
   assert(_session != NULL);
-  nout << "Called P3DInstance::get_panda_script_object()\n";
 
   TiXmlDocument *doc = new TiXmlDocument;
   TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
@@ -186,7 +181,6 @@ get_panda_script_object() const {
   doc->LinkEndChild(decl);
   doc->LinkEndChild(xcommand);
   TiXmlDocument *response = _session->command_and_response(doc);
-  nout << "response pointer: " << response << "\n" << flush;
 
   P3D_object *result = NULL;
   if (response != NULL) {
@@ -200,10 +194,10 @@ get_panda_script_object() const {
     delete response;
   }
 
-  nout << "Returning " << result << "\n" << flush;
-  if (result != NULL) {
-    nout << "result = " << *result << "\n" << flush;
+  if (result == NULL) {
+    result = new P3DNullObject;
   }
+
   return result;
 }
 
@@ -217,7 +211,6 @@ get_panda_script_object() const {
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 set_browser_script_object(P3D_object *browser_script_object) {
-  nout << "Called P3DInstance::set_browser_script_object()\n";
   if (browser_script_object != _browser_script_object) {
     if (_browser_script_object != NULL) {
       P3D_OBJECT_FINISH(_browser_script_object);
@@ -265,8 +258,6 @@ get_request() {
   }
   RELEASE_LOCK(_request_lock);
 
-  nout << "get_request: " << result << "\n" << flush;
-
   if (result != NULL) {
     switch (result->_request_type) {
     case P3D_RT_notify:
@@ -295,8 +286,6 @@ get_request() {
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 add_request(P3D_request *request) {
-  nout << "Instance " << this << " add_request(" << request->_request_type
-       << ")\n" << flush;
   request->_instance = this;
 
   ACQUIRE_LOCK(_request_lock);
@@ -353,7 +342,6 @@ feed_url_stream(int unique_id,
 
   if (!download_ok || download->get_download_finished()) {
     // All done.
-    nout << "completed download " << unique_id << "\n" << flush;
     _downloads.erase(di);
     delete download;
   }
@@ -398,9 +386,6 @@ start_download(P3DDownload *download) {
   bool inserted = _downloads.insert(Downloads::value_type(download_id, download)).second;
   assert(inserted);
 
-  nout << "beginning download " << download_id << ": " << download->get_url()
-       << "\n" << flush;
-
   P3D_request *request = new P3D_request;
   request->_request_type = P3D_RT_get_url;
   request->_request._get_url._url = strdup(download->get_url().c_str());
@@ -489,10 +474,8 @@ handle_notify_request(P3D_request *request) {
   if (strcmp(message, "onwindowopen") == 0) {
     // The process told us that it just succesfully opened its
     // window.
-    nout << "Instance " << this << " got onwindowopen\n" << flush;
     _instance_window_opened = true;
     if (_splash_window != NULL) {
-      nout << "Deleting splash window\n" << flush;
       delete _splash_window;
       _splash_window = NULL;
     }
@@ -515,14 +498,7 @@ handle_script_request(P3D_request *request) {
   case P3D_SO_get_property:
     {
       P3D_object *result = P3D_OBJECT_GET_PROPERTY(object, request->_request._script._property_name);
-      nout << "get_property, object = " << object << "\n";
-      if (object != NULL) {
-        nout << "  *object = " << *object << "\n" << flush;
-      }
-      nout << "result = " << result << "\n" << flush;
-      if (result != NULL) {
-        nout << "  *result = " << *result << "\n" << flush;
-      }
+
       // We've got the property value; feed it back down to the
       // subprocess.
       TiXmlDocument *doc = new TiXmlDocument;
@@ -546,11 +522,6 @@ handle_script_request(P3D_request *request) {
     {
       bool result = P3D_OBJECT_SET_PROPERTY(object, request->_request._script._property_name,
                                             request->_request._script._value);
-      nout << "set_property, object = " << object << "\n";
-      if (object != NULL) {
-        nout << "  *object = " << *object << "\n" << flush;
-      }
-      nout << "result = " << result << "\n" << flush;
 
       // Feed the result back down to the subprocess.
       TiXmlDocument *doc = new TiXmlDocument;
@@ -575,11 +546,6 @@ handle_script_request(P3D_request *request) {
     {
       bool result = P3D_OBJECT_SET_PROPERTY(object, request->_request._script._property_name,
                                             NULL);
-      nout << "del_property, object = " << object << "\n";
-      if (object != NULL) {
-        nout << "  *object = " << *object << "\n" << flush;
-      }
-      nout << "result = " << result << "\n" << flush;
 
       // Feed the result back down to the subprocess.
       TiXmlDocument *doc = new TiXmlDocument;
@@ -634,8 +600,6 @@ make_splash_window() {
   string filename = name;
   free(name);
 
-  nout << "Downloading splash image into " << filename << "\n";
-
   // Start downloading the requested splash image.
   SplashDownload *download = new SplashDownload(this);
   download->set_url(splash_image_url);

+ 1 - 35
direct/src/plugin/p3dPythonRun.cxx

@@ -191,14 +191,12 @@ run_python() {
   task_mgr->add(_check_comm_task);
 
   // Finally, get lost in taskMgr.run().
-  nout << "calling run()\n";
   PyObject *done = PyObject_CallMethod(_taskMgr, (char *)"run", (char *)"");
   if (done == NULL) {
     PyErr_Print();
     return false;
   }
   Py_DECREF(done);
-  nout << "done calling run()\n";
 
   return true;
 }
@@ -211,7 +209,6 @@ run_python() {
 ////////////////////////////////////////////////////////////////////
 void P3DPythonRun::
 handle_command(TiXmlDocument *doc) {
-  nout << "got command: " << *doc << "\n";
   TiXmlElement *xcommand = doc->FirstChildElement("command");
   if (xcommand != NULL) {
     bool needs_response = false;
@@ -270,7 +267,6 @@ handle_command(TiXmlDocument *doc) {
           xresponse->SetAttribute("response_id", want_response_id);
           doc.LinkEndChild(decl);
           doc.LinkEndChild(xresponse);
-          nout << "sending " << doc << "\n" << flush;
           _pipe_write << doc << flush;
         }
       }
@@ -298,7 +294,7 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
   if (op != NULL) {
     if (strcmp(op, "get_panda_script_object") == 0) {
       // Get Panda's toplevel Python object.
-      PyObject *obj = PyObject_GetAttrString(_runner, "scriptRoot");
+      PyObject *obj = PyObject_CallMethod(_runner, "getPandaScriptObject", (char *)"");
       if (obj != NULL) {
         xresponse->LinkEndChild(pyobj_to_xml(obj));
         Py_DECREF(obj);
@@ -417,7 +413,6 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
   }
 
   if (needs_response) {
-    nout << "sending " << doc << "\n" << flush;
     _pipe_write << doc << flush;
   }
 }
@@ -554,23 +549,19 @@ py_request_func(PyObject *args) {
       return NULL;
     }
 
-    nout << "Waiting for script_response " << response_id << "\n";
     TiXmlDocument *doc = wait_script_response(response_id);
-    nout << "got: " << *doc << "\n";
     TiXmlElement *xcommand = doc->FirstChildElement("command");
     assert(xcommand != NULL);
     TiXmlElement *xvalue = xcommand->FirstChildElement("value");
 
     PyObject *value = NULL;
     if (xvalue != NULL) {
-      nout << "Converting xvalue: " << *xvalue << "\n";
       value = xml_to_pyobj(xvalue);
     } else {
       // An absence of a <value> element means a NULL pointer.
       value = _null;
       Py_INCREF(value);
     }
-    nout << "Got script_response " << response_id << ", xvalue = " << xvalue << "\n";
 
     delete doc;
     Py_DECREF(extra_args);
@@ -594,7 +585,6 @@ py_request_func(PyObject *args) {
     }
 
     xrequest->SetAttribute("message", message);
-    nout << "sending " << doc << "\n" << flush;
     _pipe_write << doc << flush;
 
   } else if (strcmp(request_type, "script") == 0) {
@@ -619,25 +609,8 @@ py_request_func(PyObject *args) {
     TiXmlElement *xvalue = pyobj_to_xml(value);
     xrequest->LinkEndChild(xvalue);
 
-    nout << "sending " << doc << "\n" << flush;
     _pipe_write << doc << flush;
 
-    /*
-  } else if (strcmp(request_type, "evaluate") == 0) {
-    // An evaluate request.
-    const char *expression;
-    int unique_id;
-    if (!PyArg_ParseTuple(extra_args, "si", &expression, &unique_id)) {
-      Py_DECREF(extra_args);
-      return NULL;
-    }
-
-    xrequest->SetAttribute("expression", expression);
-    xrequest->SetAttribute("unique_id", unique_id);
-    nout << "sending " << doc << "\n" << flush;
-    _pipe_write << doc << flush;
-    */
-
   } else {
     string message = string("Unsupported request type: ") + string(request_type);
     PyErr_SetString(PyExc_ValueError, message.c_str());
@@ -687,12 +660,10 @@ spawn_read_thread() {
 ////////////////////////////////////////////////////////////////////
 void P3DPythonRun::
 join_read_thread() {
-  nout << "waiting for thread\n";
   _read_thread_continue = false;
   _pipe_read.close();
 
   JOIN_THREAD(_read_thread);
-  nout << "done waiting for thread\n";
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -703,7 +674,6 @@ join_read_thread() {
 ////////////////////////////////////////////////////////////////////
 void P3DPythonRun::
 start_instance(P3DCInstance *inst, TiXmlElement *xinstance) {
-  nout << "starting instance " << inst << "\n";
   _instances[inst->get_instance_id()] = inst;
 
   TiXmlElement *xfparams = xinstance->FirstChildElement("fparams");
@@ -861,14 +831,12 @@ terminate_session() {
   }
   _instances.clear();
 
-  nout << "calling stop()\n";
   PyObject *result = PyObject_CallMethod(_taskMgr, (char *)"stop", (char *)"");
   if (result == NULL) {
     PyErr_Print();
     return;
   }
   Py_DECREF(result);
-  nout << "done calling stop()\n";
 
   // The task manager is cleaned up.  Let's exit immediately here,
   // rather than returning all the way up.  This just makes it easier
@@ -1045,14 +1013,12 @@ xml_to_pyobj(TiXmlElement *xvalue) {
 ////////////////////////////////////////////////////////////////////
 void P3DPythonRun::
 rt_thread_run() {
-  nout << "thread reading.\n";
   while (_read_thread_continue) {
     TiXmlDocument *doc = new TiXmlDocument;
 
     _pipe_read >> *doc;
     if (!_pipe_read || _pipe_read.eof()) {
       // Some error on reading.  Abort.
-      nout << "Error on reading.\n";
       _program_continue = false;
       return;
     }

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

@@ -214,7 +214,6 @@ void P3DSession::
 send_command(TiXmlDocument *command) {
   if (_p3dpython_running) {
     // Python is running.  Send the command.
-    nout << "Sending " << *command << "\n" << flush;
     _pipe_write << *command << flush;
     delete command;
   } else {
@@ -258,7 +257,6 @@ command_and_response(TiXmlDocument *command) {
 
   // Now block, waiting for a response to be delivered.  We assume
   // only one thread will be waiting at a time.
-  nout << "Waiting for response " << response_id << "\n" << flush;
   _response_ready.acquire();
   while (_response == NULL || _got_response_id != response_id) {
     if (_response != NULL) {
@@ -307,8 +305,6 @@ command_and_response(TiXmlDocument *command) {
 
   _response_ready.release();
 
-  nout << "Got response: " << *response << "\n" << flush;
-
   return response;
 }
 
@@ -358,8 +354,6 @@ xml_to_p3dobj(const TiXmlElement *xvalue) {
     int object_id;
     if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) {
       P3D_object *obj = (P3D_object *)object_id;
-      nout << "Found object " << obj << "\n" << flush;
-      nout << "  formatted is " << *obj << "\n" << flush;
       return P3D_OBJECT_COPY(obj);
     }
 
@@ -534,8 +528,6 @@ start_p3dpython() {
   }
   _p3dpython_running = true;
 
-  nout << "Created child process\n" << flush;
-
   if (!_pipe_read) {
     nout << "unable to open read pipe\n" << flush;
   }
@@ -597,14 +589,12 @@ join_read_thread() {
 ////////////////////////////////////////////////////////////////////
 void P3DSession::
 rt_thread_run() {
-  nout << "session thread reading.\n" << flush;
   while (_read_thread_continue) {
     TiXmlDocument *doc = new TiXmlDocument;
 
     _pipe_read >> *doc;
     if (!_pipe_read || _pipe_read.eof()) {
       // Some error on reading.  Abort.
-      nout << "Error on session reading.\n" << flush;
       rt_terminate();
       return;
     }
@@ -622,8 +612,6 @@ rt_thread_run() {
 ////////////////////////////////////////////////////////////////////
 void P3DSession::
 rt_handle_request(TiXmlDocument *doc) {
-  nout << "Session got request: " << *doc << "\n" << flush;
-
   TiXmlElement *xresponse = doc->FirstChildElement("response");
   if (xresponse != (TiXmlElement *)NULL) {
     int response_id;
@@ -649,7 +637,6 @@ rt_handle_request(TiXmlDocument *doc) {
 
   TiXmlElement *xrequest = doc->FirstChildElement("request");
   if (xrequest != (TiXmlElement *)NULL) {
-    nout << "Handling request\n" << flush;
     int instance_id;
     if (xrequest->QueryIntAttribute("instance_id", &instance_id) == TIXML_SUCCESS) {
       // Look up the particular instance this is related to.
@@ -665,7 +652,6 @@ rt_handle_request(TiXmlDocument *doc) {
       }
       RELEASE_LOCK(_instances_lock);
     }
-    nout << "done handling request\n" << flush;
   }
 
   delete doc;
@@ -699,11 +685,7 @@ rt_make_p3d_request(TiXmlElement *xrequest) {
       xrequest->Attribute("unique_id", &unique_id);
 
       if (operation != NULL && xobject != NULL) {
-        nout << "xobject = " << *xobject << "\n" << flush;
         P3D_object *object = xml_to_p3dobj(xobject);
-        nout << "converted to " << object << "\n" << flush;
-        nout << "object = " << *object << "\n" << flush;
-        nout << "operation = " << *operation << "\n" << flush;
         if (strcmp(operation, "get_property") == 0 && property_name != NULL) {
           request = new P3D_request;
           request->_request_type = P3D_RT_script;
@@ -737,7 +719,7 @@ rt_make_p3d_request(TiXmlElement *xrequest) {
       }          
 
     } else {
-      nout << "ignoring request of type " << rtype << "\n";
+      nout << "Ignoring request of type " << rtype << "\n";
     }
   }
 

+ 27 - 1
direct/src/plugin_npapi/ppBrowserObject.cxx

@@ -121,6 +121,12 @@ get_repr(char *buffer, int buffer_length) const {
 P3D_object *PPBrowserObject::
 get_property(const string &property) const {
   NPIdentifier property_name = browser->getstringidentifier(property.c_str());
+  if (!browser->hasproperty(_instance->get_npp_instance(), _npobj,
+                            property_name)) {
+    // No such property.
+    return NULL;
+  }
+
   NPVariant result;
   if (!browser->getproperty(_instance->get_npp_instance(), _npobj,
                             property_name, &result)) {
@@ -142,10 +148,30 @@ get_property(const string &property) const {
 ////////////////////////////////////////////////////////////////////
 bool PPBrowserObject::
 set_property(const string &property, P3D_object *value) {
+  NPIdentifier property_name = browser->getstringidentifier(property.c_str());
+  bool result;
   if (value != NULL) {
+    // Set the property.
+    if (P3D_OBJECT_GET_TYPE(value) != P3D_OT_null) {
+      NPVariant npvalue;
+      _instance->p3dobj_to_variant(&npvalue, value);
+      result = browser->setproperty(_instance->get_npp_instance(), _npobj,
+                                    property_name, &npvalue);
+      browser->releasevariantvalue(&npvalue);
+    } else {
+      // Actually, delete the property after all.
+      result = browser->removeproperty(_instance->get_npp_instance(), _npobj,
+                                       property_name);
+    }
     P3D_OBJECT_FINISH(value);
+
+  } else {
+    // Delete the property.
+    result = browser->removeproperty(_instance->get_npp_instance(), _npobj,
+                                     property_name);
   }
-  return false;
+
+  return result;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 7 - 31
direct/src/plugin_npapi/ppInstance.cxx

@@ -34,7 +34,6 @@
 PPInstance::
 PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode, 
            int16 argc, char *argn[], char *argv[], NPSavedData *saved) {
-  logfile << "constructing " << this << "\n" << flush;
   _p3d_inst = NULL;
 
   _npp_instance = instance;
@@ -47,8 +46,6 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode,
     P3D_token token;
     token._keyword = strdup(argn[i]);
     token._value = strdup(argv[i]);
-    logfile
-      << " " << i << ": " << token._keyword << " = " << token._value << "\n";
     _tokens.push_back(token);
   }
 
@@ -72,9 +69,6 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode,
 ////////////////////////////////////////////////////////////////////
 PPInstance::
 ~PPInstance() {
-  logfile
-    << "destructing PPInstance " << this << "\n";
-
 #ifdef _WIN32
   if (_got_window) {
     // Restore the parent window to its own window handler.
@@ -330,7 +324,6 @@ stream_as_file(NPStream *stream, const char *fname) {
       }
     }
     filename = fname2;
-    logfile << "converted filename to " << filename << "\n";
   }
 
   // Here's another temporary hack.  In addition to the weird filename
@@ -343,7 +336,6 @@ stream_as_file(NPStream *stream, const char *fname) {
   // the filename to point to the source file.
   if (strncmp(stream->url, "file://", 7) == 0) {
     filename = stream->url + 7;
-    logfile << "converted filename again to " << filename << "\n";
   }
 
 #endif  // __APPLE__
@@ -353,7 +345,6 @@ stream_as_file(NPStream *stream, const char *fname) {
   case PPDownloadRequest::RT_contents_file:
     // Now we have the contents.xml file.  Read this to get the
     // filename and md5 hash of our core API DLL.
-    logfile << "got contents file " << filename << "\n" << flush;
     if (!read_contents_file(filename)) {
       logfile << "Unable to read contents file\n";
       // TODO: fail
@@ -388,16 +379,12 @@ stream_as_file(NPStream *stream, const char *fname) {
 ////////////////////////////////////////////////////////////////////
 void PPInstance::
 handle_request(P3D_request *request) {
-  logfile
-    << "handle_request: " << request << ", " << request->_request_type
-    << " within " << this << "\n" << flush;
   assert(request->_instance == _p3d_inst);
 
   bool handled = false;
 
   switch (request->_request_type) {
   case P3D_RT_stop:
-    logfile << "Got P3D_RT_stop\n";
     if (_p3d_inst != NULL) {
       P3D_instance_finish(_p3d_inst);
       _p3d_inst = NULL;
@@ -408,9 +395,6 @@ handle_request(P3D_request *request) {
 
   case P3D_RT_get_url:
     {
-      logfile << "Got P3D_RT_get_url: " << request->_request._get_url._url
-              << "\n";
-      
       PPDownloadRequest *req = 
         new PPDownloadRequest(PPDownloadRequest::RT_user, 
                               request->_request._get_url._unique_id);
@@ -421,15 +405,11 @@ handle_request(P3D_request *request) {
 
   case P3D_RT_notify:
     {
-      logfile << "Got P3D_RT_notify: " << request->_request._notify._message
-              << "\n" << flush;
-
       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);
-        logfile << "late obj = " << obj << "\n" << flush;
         _script_object->set_p3d_object(obj);
       }
     }
@@ -477,9 +457,7 @@ handle_request_loop() {
 ////////////////////////////////////////////////////////////////////
 NPObject *PPInstance::
 get_panda_script_object() {
-  logfile << "get_panda_script_object\n" << flush;
   if (_script_object != NULL) {
-    logfile << "returning _script_object ref = " << _script_object->referenceCount << "\n";
     return _script_object;
   }
 
@@ -487,14 +465,10 @@ get_panda_script_object() {
 
   if (_p3d_inst != NULL) {
     obj = P3D_instance_get_panda_script_object(_p3d_inst);
-    logfile << "obj = " << obj << "\n" << flush;
   }
 
   _script_object = PPPandaObject::make_new(this, obj);
-  logfile << "_script_object ref = " << _script_object->referenceCount << "\n";
   browser->retainobject(_script_object);
-  logfile << "after retain, _script_object ref = " << _script_object->referenceCount << "\n";
-  logfile << "ppobj = " << _script_object << "\n" << flush;
   return _script_object;
 }
 
@@ -507,6 +481,10 @@ get_panda_script_object() {
 void PPInstance::
 p3dobj_to_variant(NPVariant *result, const P3D_object *object) {
   switch (P3D_OBJECT_GET_TYPE(object)) {
+  case P3D_OT_null:
+    NULL_TO_NPVARIANT(*result);
+    break;
+
   case P3D_OT_none:
     VOID_TO_NPVARIANT(*result);
     break;
@@ -551,8 +529,9 @@ p3dobj_to_variant(NPVariant *result, const P3D_object *object) {
 ////////////////////////////////////////////////////////////////////
 P3D_object *PPInstance::
 variant_to_p3dobj(const NPVariant *variant) {
-  if (NPVARIANT_IS_VOID(*variant) ||
-      NPVARIANT_IS_NULL(*variant)) {
+  if (NPVARIANT_IS_NULL(*variant)) {
+    return P3D_new_null_object();
+  } else if (NPVARIANT_IS_VOID(*variant)) {
     return P3D_new_none_object();
   } else if (NPVARIANT_IS_BOOLEAN(*variant)) {
     return P3D_new_bool_object(NPVARIANT_TO_BOOLEAN(*variant));
@@ -675,7 +654,6 @@ downloaded_plugin(const string &filename) {
 
   if (_core_api_dll.quick_verify(_root_dir)) {
     // We downloaded and installed it successfully.  Now load it.
-    logfile << "Successfully downloaded " << pathname << "\n";
     do_load_plugin();
     return;
   }
@@ -711,7 +689,6 @@ do_load_plugin() {
     logfile << "Unable to launch core API in " << pathname << "\n" << flush;
     return;
   }
-  logfile << "loaded core API from " << pathname << "\n" << flush;
   create_instance();
 }
 
@@ -750,7 +727,6 @@ create_instance() {
     NPObject *window_object = NULL;
     if (browser->getvalue(_npp_instance, NPNVWindowNPObject,
                           &window_object) == NPERR_NO_ERROR) {
-      logfile << "Got window_object " << window_object << "\n" << flush;
       PPBrowserObject *pobj = new PPBrowserObject(this, window_object);
       P3D_instance_set_browser_script_object(_p3d_inst, pobj);
       browser->releaseobject(window_object);

+ 89 - 25
direct/src/showutil/runp3d.py

@@ -27,6 +27,7 @@ from direct.stdpy import file
 from direct.task.TaskManagerGlobal import taskMgr
 from direct.showbase import AppRunnerGlobal
 import os
+import types
 import __builtin__
 
 MultifileRoot = '/mf'
@@ -41,10 +42,10 @@ default-model-extension .bam
 class ArgumentError(AttributeError):
     pass
 
-class ScriptRoot:
+class ScriptAttributes:
     """ 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. """
+    for direct inspection by the browser's JavaScript code. """
     pass
 
 class AppRunner(DirectObject):
@@ -57,15 +58,23 @@ class AppRunner(DirectObject):
         self.started = False
         self.windowPrc = None
 
+        # Store this Null instance where the application can easily
+        # get to it.
+        self.Null = Null
+
         # This is per session.
         self.nextScriptId = 0
 
         # TODO: we need one of these per instance, not per session.
         self.instanceId = None
-        self.scriptRoot = ScriptRoot()
 
-        # This will be the browser's toplevel window DOM object.
-        self.window = None
+        # The attributes of this object will be exposed as attributes
+        # of the plugin instance in the DOM.
+        self.attributes = ScriptAttributes()
+
+        # This will be the browser's toplevel window DOM object;
+        # e.g. self.dom.document will be the document.
+        self.dom = None
 
         # This is the default requestFunc that is installed if we
         # never call setRequestFunc().
@@ -151,13 +160,20 @@ class AppRunner(DirectObject):
             if hasattr(main, 'main') and callable(main.main):
                 main.main()
 
-    def setBrowserScriptObject(self, window):
-        """ Replaces self.window with the browser's toplevel DOM
+    def getPandaScriptObject(self):
+        """ Called by the browser to query the Panda instance's
+        toplevel scripting object, for querying properties in the
+        Panda instance.  The attributes on this object are mapped to
+        the plugin instance within the DOM. """
+        return self.attributes
+
+    def setBrowserScriptObject(self, dom):
+        """ Called by the browser to supply the browser's toplevel DOM
         object, for controlling the JavaScript and the document in the
         same page with the Panda3D plugin. """
 
-        self.window = window
-        print "setBrowserScriptObject(%s)" % (window)
+        self.dom = dom
+        print "setBrowserScriptObject(%s)" % (dom)
 
     def setP3DFilename(self, p3dFilename, tokens = [],
                        instanceId = None):
@@ -166,7 +182,7 @@ class AppRunner(DirectObject):
         # for this instance.
         self.instanceId = instanceId
         
-        # Now that we have an instanceId, we can response to queries
+        # Now that we have an instanceId, we can respond to queries
         # and such.
         self.sendRequest('notify', 'onpythonload')
 
@@ -266,8 +282,6 @@ class AppRunner(DirectObject):
         return self.requestFunc(self.instanceId, request, args)
 
     def windowEvent(self, win):
-        print "Got window event in runp3d"
-
         self.sendRequest('notify', 'onwindowopen')
 
     def scriptRequest(self, operation, object, propertyName = None,
@@ -297,7 +311,6 @@ class AppRunner(DirectObject):
 
         # Now wait for the response to come in.
         result = self.sendRequest('wait_script_response', uniqueId)
-        print "result for %s.%s = %s" % (object, propertyName, result,)
         return result
 
     def parseSysArgs(self):
@@ -332,6 +345,16 @@ class AppRunner(DirectObject):
 
         return (osFilename, tokens)
 
+class NullObject:
+    """ This is a special object that is returned by the browser to
+    represent a NULL pointer, typically the return value for a failed
+    operation.  It has no attributes. """
+    pass
+
+# In fact, we normally always return this precise instance of the
+# NullObject.
+Null = NullObject()
+
 class BrowserObject:
     """ This class provides the Python wrapper around some object that
     actually exists in the plugin host's namespace, e.g. a JavaScript
@@ -348,25 +371,27 @@ class BrowserObject:
         return True
 
     def __getattr__(self, name):
-        """ Remaps attempts to query an attribute into the appropriate
-        calls to query the actual browser object under the hood.  """
+        """ Remaps attempts to query an attribute, as in obj.attr,
+        into the appropriate calls to query the actual browser object
+        under the hood.  """
 
-        print "__getattr_(self, %s)" % (name)
-        print "runner = %s" % (self.__runner)
         value = self.__runner.scriptRequest('get_property', self,
                                             propertyName = name)
+        if value is Null:
+            # Failed to retrieve the attribute.
+            raise AttributeError(name)
+
         return value
-        # raise AttributeError(name)
 
     def __setattr__(self, name, value):
         if name in self.__dict__:
             self.__dict__[name] = value
             return
 
-        value = self.__runner.scriptRequest('set_property', self,
-                                            propertyName = name,
-                                            value = value)
-        if not value:
+        result = self.__runner.scriptRequest('set_property', self,
+                                             propertyName = name,
+                                             value = value)
+        if not result:
             raise AttributeError(name)
 
     def __delattr__(self, name):
@@ -374,11 +399,50 @@ class BrowserObject:
             del self.__dict__[name]
             return
 
-        value = self.__runner.scriptRequest('del_property', self,
-                                            propertyName = name)
-        if not value:
+        result = self.__runner.scriptRequest('del_property', self,
+                                             propertyName = name)
+        if not result:
             raise AttributeError(name)
 
+    def __getitem__(self, key):
+        """ Remaps attempts to query an attribute, as in obj['attr'],
+        into the appropriate calls to query the actual browser object
+        under the hood.  Following the JavaScript convention, we treat
+        obj['attr'] almost the same as obj.attr. """
+
+        value = self.__runner.scriptRequest('get_property', self,
+                                            propertyName = str(key))
+        if value is Null:
+            # Failed to retrieve the property.  We return IndexError
+            # for numeric keys so we can properly support Python's
+            # iterators, but we return KeyError for string keys to
+            # emulate mapping objects.
+            if isinstance(key, types.StringTypes):
+                raise KeyError(key)
+            else:
+                raise IndexError(key)
+
+        return value;
+
+    def __setitem__(self, key, value):
+        result = self.__runner.scriptRequest('set_property', self,
+                                             propertyName = str(key),
+                                             value = value)
+        if not result:
+            if isinstance(key, types.StringTypes):
+                raise KeyError(key)
+            else:
+                raise IndexError(key)
+
+    def __delitem__(self, key):
+        result = self.__runner.scriptRequest('del_property', self,
+                                             propertyName = str(key))
+        if not result:
+            if isinstance(key, types.StringTypes):
+                raise KeyError(key)
+            else:
+                raise IndexError(key)
+
 if __name__ == '__main__':
     runner = AppRunner()
     runner.gotWindow = True