Browse Source

more needs_response changes

David Rose 16 years ago
parent
commit
07e714bb16

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

@@ -900,7 +900,8 @@ handle_script_request(const string &operation, P3D_object *object,
     }
 
     P3D_object *result =
-      P3D_OBJECT_CALL(object, property_name.c_str(), values, num_values);
+      P3D_OBJECT_CALL(object, property_name.c_str(), needs_response,
+                      values, num_values);
     
     if (result != NULL) {
       xcommand->LinkEndChild(_session->p3dobj_to_xml(result));

+ 12 - 5
direct/src/plugin/p3dObject.cxx

@@ -76,11 +76,12 @@ object_has_method(P3D_object *object, const char *method_name) {
 
 static P3D_object *
 object_call(P3D_object *object, const char *method_name,
+            bool needs_response,
             P3D_object *params[], int num_params) {
   if (method_name == NULL) {
     method_name = "";
   }
-  return ((P3DObject *)object)->call(method_name, params, num_params);
+  return ((P3DObject *)object)->call(method_name, needs_response, params, num_params);
 }
 
 static P3D_object *
@@ -165,7 +166,7 @@ generic_has_method(P3D_object *object, const char *method_name) {
 
 static P3D_object *
 generic_call(P3D_object *object, const char *method_name,
-            P3D_object *params[], int num_params) {
+             bool needs_response, P3D_object *params[], int num_params) {
   return NULL;
 }
 
@@ -294,11 +295,17 @@ has_method(const string &method_name) {
 //       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.
+//               invokes the object itself.
+//
+//               If needs_response is true, the return value is a
+//               new-reference P3D_object on success, or NULL on
+//               failure.  If needs_response is false, the return
+//               value is always NULL, and there is no way to
+//               determine success or failure.
 ////////////////////////////////////////////////////////////////////
 P3D_object *P3DObject::
-call(const string &method_name, P3D_object *params[], int num_params) {
+call(const string &method_name, bool needs_response,
+     P3D_object *params[], int num_params) {
   return NULL;
 }
 

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

@@ -46,7 +46,7 @@ public:
   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, 
+  virtual P3D_object *call(const string &method_name, bool needs_response,
                            P3D_object *params[], int num_params);
   virtual P3D_object *eval(const string &expression);
 

+ 28 - 12
direct/src/plugin/p3dPythonObject.cxx

@@ -61,7 +61,7 @@ bool P3DPythonObject::
 get_bool() {
   bool bresult = 0;
 
-  P3D_object *result = call("__bool__", NULL, 0);
+  P3D_object *result = call("__bool__", true, NULL, 0);
   if (result != NULL) {
     bresult = P3D_OBJECT_GET_BOOL(result);
     P3D_OBJECT_DECREF(result);
@@ -80,7 +80,7 @@ int P3DPythonObject::
 get_int() {
   int iresult = 0;
 
-  P3D_object *result = call("__int__", NULL, 0);
+  P3D_object *result = call("__int__", true, NULL, 0);
   if (result != NULL) {
     iresult = P3D_OBJECT_GET_INT(result);
     P3D_OBJECT_DECREF(result);
@@ -99,7 +99,7 @@ double P3DPythonObject::
 get_float() {
   double fresult = 0.0;
 
-  P3D_object *result = call("__float__", NULL, 0);
+  P3D_object *result = call("__float__", true, NULL, 0);
   if (result != NULL) {
     fresult = P3D_OBJECT_GET_FLOAT(result);
     P3D_OBJECT_DECREF(result);
@@ -116,7 +116,7 @@ get_float() {
 ////////////////////////////////////////////////////////////////////
 void P3DPythonObject::
 make_string(string &value) {
-  P3D_object *result = call("__str__", NULL, 0);
+  P3D_object *result = call("__str__", true, NULL, 0);
   if (result != NULL) {
     int size = P3D_OBJECT_GET_STRING(result, NULL, 0);
     char *buffer = new char[size];
@@ -140,7 +140,7 @@ get_property(const string &property) {
   P3D_object *params[1];
   params[0] = new P3DStringObject(property);
 
-  P3D_object *result = call("__get_property__", params, 1);
+  P3D_object *result = call("__get_property__", true, params, 1);
   P3D_OBJECT_DECREF(params[0]);
   return result;
 }
@@ -163,12 +163,12 @@ set_property(const string &property, P3D_object *value) {
 
   if (value == NULL) {
     // Delete an attribute.
-    result = call("__del_property__", params, 1);
+    result = call("__del_property__", true, params, 1);
 
   } else {
     // Set a new attribute.
     params[1] = value;
-    result = call("__set_property__", params, 2);
+    result = call("__set_property__", true, params, 2);
   }
 
   P3D_OBJECT_DECREF(params[0]);
@@ -202,7 +202,7 @@ has_method(const string &method_name) {
   P3D_object *params[1];
   params[0] = new P3DStringObject(method_name);
 
-  P3D_object *result = call("__has_method__", params, 1);
+  P3D_object *result = call("__has_method__", true, params, 1);
   P3D_OBJECT_DECREF(params[0]);
 
   if (result != NULL) {
@@ -223,11 +223,17 @@ has_method(const string &method_name) {
 //       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.
+//               invokes the object itself.
+//
+//               If needs_response is true, the return value is a
+//               new-reference P3D_object on success, or NULL on
+//               failure.  If needs_response is false, the return
+//               value is always NULL, and there is no way to
+//               determine success or failure.
 ////////////////////////////////////////////////////////////////////
 P3D_object *P3DPythonObject::
-call(const string &method_name, P3D_object *params[], int num_params) {
+call(const string &method_name, bool needs_response,
+     P3D_object *params[], int num_params) {
   TiXmlDocument *doc = new TiXmlDocument;
   TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
   TiXmlElement *xcommand = new TiXmlElement("command");
@@ -248,6 +254,16 @@ call(const string &method_name, P3D_object *params[], int num_params) {
 
   doc->LinkEndChild(decl);
   doc->LinkEndChild(xcommand);
+
+  // If no response is requested, send the command out in a vacuum,
+  // and return NULL.
+  if (!needs_response) {
+    _session->send_command(doc);
+    return NULL;
+  }
+
+  // If a response is requested, we have to send the command and wait
+  // for it.
   TiXmlDocument *response = _session->command_and_response(doc);
 
   P3D_object *result = NULL;
@@ -274,7 +290,7 @@ call(const string &method_name, P3D_object *params[], int num_params) {
 ////////////////////////////////////////////////////////////////////
 void P3DPythonObject::
 output(ostream &out) {
-  P3D_object *result = call("__repr__", NULL, 0);
+  P3D_object *result = call("__repr__", true, NULL, 0);
   out << "Python " << _object_id;
   if (result != NULL) {
     out << ": " << *result;

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

@@ -45,7 +45,7 @@ public:
   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, 
+  virtual P3D_object *call(const string &method_name, bool needs_response,
                            P3D_object *params[], int num_params);
 
   virtual void output(ostream &out);

+ 11 - 4
direct/src/plugin/p3dToplevelObject.cxx

@@ -189,17 +189,24 @@ has_method(const string &method_name) {
 //       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.
+//               invokes the object itself.
+//
+//               If needs_response is true, the return value is a
+//               new-reference P3D_object on success, or NULL on
+//               failure.  If needs_response is false, the return
+//               value is always NULL, and there is no way to
+//               determine success or failure.
 ////////////////////////////////////////////////////////////////////
 P3D_object *P3DToplevelObject::
-call(const string &method_name, P3D_object *params[], int num_params) {
+call(const string &method_name, bool needs_response,
+     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);
+  return P3D_OBJECT_CALL(_pyobj, method_name.c_str(), needs_response,
+                         params, num_params);
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -52,7 +52,7 @@ public:
   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, 
+  virtual P3D_object *call(const string &method_name, bool needs_response,
                            P3D_object *params[], int num_params);
 
   virtual void output(ostream &out);

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

@@ -205,10 +205,12 @@ P3D_object_has_method(P3D_object *object, const char *method_name) {
 
 P3D_object *
 P3D_object_call(P3D_object *object, const char *method_name, 
+                bool needs_response,
                 P3D_object *params[], int num_params) {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_api_lock);
-  P3D_object *result = P3D_OBJECT_CALL(object, method_name, params, num_params);
+  P3D_object *result = P3D_OBJECT_CALL(object, method_name, needs_response,
+                                       params, num_params);
   RELEASE_LOCK(_api_lock);
   return result;
 }

+ 7 - 3
direct/src/plugin/p3d_plugin.h

@@ -406,10 +406,13 @@ P3D_object_has_method_method(P3D_object *object, const char *method_name);
    these objects' reference counts is not transferred with the call
    (you must still DECREF these objects afterwards).
 
-   The return value is a new-reference P3D_object on success, or NULL
-   on failure. */
+   If needs_response is true, the return value is a new-reference
+   P3D_object on success, or NULL on failure.  If needs_response is
+   false, the return value is always NULL, and there is no way to
+   determine success or failure. */
 typedef P3D_object *
 P3D_object_call_method(P3D_object *object, const char *method_name,
+                       bool needs_response,
                        P3D_object *params[], int num_params);
 
 /* Evaluates an arbitrary JavaScript expression in the context of the
@@ -468,7 +471,7 @@ struct _P3D_object {
 #define P3D_OBJECT_SET_PROPERTY(object, property, value) ((object)->_class->_set_property((object), (property), (value)))
 
 #define P3D_OBJECT_HAS_METHOD(object, method_name) ((object)->_class->_has_method((object), (method_name)))
-#define P3D_OBJECT_CALL(object, method_name, params, num_params) ((object)->_class->_call((object), (method_name), (params), (num_params)))
+#define P3D_OBJECT_CALL(object, method_name, needs_response, params, num_params) ((object)->_class->_call((object), (method_name), (needs_response), (params), (num_params)))
 #define P3D_OBJECT_EVAL(object, expression) ((object)->_class->_eval((object), (expression)))
 
 /* These macros are provided to manipulate the reference count of the
@@ -506,6 +509,7 @@ typedef bool
 P3D_object_has_method_func(P3D_object *object, const char *method_name);
 typedef P3D_object *
 P3D_object_call_func(P3D_object *object, const char *method_name, 
+                     bool needs_response,
                      P3D_object *params[], int num_params);
 typedef P3D_object *
 P3D_object_eval_func(P3D_object *object, const char *expression);

+ 10 - 2
direct/src/plugin_npapi/ppBrowserObject.cxx

@@ -43,12 +43,20 @@ object_set_property(P3D_object *object, const char *property,
 }
 
 static P3D_object *
-object_call(P3D_object *object, const char *method_name,
+object_call(P3D_object *object, const char *method_name, 
+            bool needs_response,
             P3D_object *params[], int num_params) {
   if (method_name == NULL) {
     method_name = "";
   }
-  return ((const PPBrowserObject *)object)->call(method_name, params, num_params);
+  P3D_object *response = ((const PPBrowserObject *)object)->call(method_name, params, num_params);
+  if (!needs_response) {
+    // No response was expected.  Throw away the response we received,
+    // so we can be consistent with defined semantics.
+    P3D_OBJECT_XDECREF(response);
+    response = NULL;
+  }
+  return response;
 }
 
 static P3D_object *

+ 2 - 2
direct/src/plugin_npapi/ppPandaObject.cxx

@@ -143,7 +143,7 @@ invoke(NPIdentifier name, const NPVariant *args, uint32_t argCount,
   }
 
   P3D_object *value = P3D_OBJECT_CALL(_p3d_object, method_name.c_str(), 
-                                      p3dargs, argCount);
+                                      true, p3dargs, argCount);
   for (i = 0; i < argCount; ++i) {
     P3D_OBJECT_DECREF(p3dargs[i]);
   }
@@ -181,7 +181,7 @@ invoke_default(const NPVariant *args, uint32_t argCount,
     p3dargs[i] = _instance->variant_to_p3dobj(&args[i]);
   }
 
-  P3D_object *value = P3D_OBJECT_CALL(_p3d_object, "",
+  P3D_object *value = P3D_OBJECT_CALL(_p3d_object, "", true,
                                       p3dargs, argCount);
   for (i = 0; i < argCount; ++i) {
     P3D_OBJECT_DECREF(p3dargs[i]);

+ 41 - 9
direct/src/showutil/JavaScript.py

@@ -6,7 +6,7 @@ code that runs in a browser via the web plugin. """
 class UndefinedObject:
     """ This is a special object that is returned by the browser to
     represent an "undefined" value, typically the value for an
-    uninitialize variable or undefined property.  It has no
+    uninitialized variable or undefined property.  It has no
     attributes, similar to None, but it is a slightly different
     concept in JavaScript. """
 
@@ -48,7 +48,11 @@ class BrowserObject:
 
         # This element is filled in by __getattr__; it connects
         # the object to its parent.
-        self.__dict__['_BrowserObject__boundMethod'] = (None, None)
+        self.__dict__['_BrowserObject__childObject'] = (None, None)
+
+        # This is a cache of method names to MethodWrapper objects in
+        # the parent object.
+        self.__dict__['_BrowserObject__methods'] = {}
 
     def __del__(self):
         # When the BrowserObject destructs, tell the parent process it
@@ -56,8 +60,23 @@ class BrowserObject:
         # more.
         self.__runner.dropObject(self.__objectId)
 
+    def __cacheMethod(self, methodName):
+        """ Stores a pointer to the named method on this object, so
+        that the next time __getattr__ is called, it can retrieve the
+        method wrapper without having to query the browser.  This
+        cache assumes that callable methods don't generally come and
+        go on and object.
+
+        The return value is the MethodWrapper object. """
+
+        method = self.__methods.get(methodName, None)
+        if method is None:
+            method = MethodWrapper(self.__runner, self, methodName)
+            self.__methods[methodName] = method
+        return method
+
     def __str__(self):
-        parentObj, attribName = self.__boundMethod
+        parentObj, attribName = self.__childObject
         if parentObj:
             # Format it from its parent.
             return "%s.%s" % (parentObj, attribName)
@@ -77,7 +96,7 @@ class BrowserObject:
             raise ArgumentError, 'Keyword arguments not supported'
         
         try:
-            parentObj, attribName = self.__boundMethod
+            parentObj, attribName = self.__childObject
             if parentObj:
                 # Call it as a method.
                 if parentObj is self.__runner.dom and attribName == 'alert':
@@ -102,6 +121,12 @@ class BrowserObject:
                     except EnvironmentError:
                         # Problem on the call.  Maybe no such method?
                         raise AttributeError
+
+                # Hey, the method call appears to have succeeded.
+                # Cache the method object on the parent so we won't
+                # have to look up the method wrapper again next time.
+                parentObj.__cacheMethod(attribName)
+                
             else:
                 # Call it as a plain function.
                 result = self.__runner.scriptRequest('call', self, value = args, needsResponse = needsResponse)
@@ -116,6 +141,13 @@ class BrowserObject:
         into the appropriate calls to query the actual browser object
         under the hood.  """
 
+        # First check to see if there's a cached method wrapper from a
+        # previous call.
+        method = self.__methods.get(name, None)
+        if method:
+            return method
+
+        # No cache.  Go query the browser for the desired value.
         try:
             value = self.__runner.scriptRequest('get_property', self,
                                                 propertyName = name)
@@ -124,7 +156,7 @@ class BrowserObject:
             # method instead?
             if self.__runner.scriptRequest('has_method', self, propertyName = name):
                 # Yes, so create a method wrapper for it.
-                return MethodWrapper(self.__runner, self, name)
+                return self.__cacheMethod(name)
             
             raise AttributeError(name)
 
@@ -133,7 +165,7 @@ class BrowserObject:
             # properly call a method.  (Javascript needs to know the
             # method container at the time of the call, and doesn't
             # store it on the function object.)
-            value.__dict__['_BrowserObject__boundMethod'] = (self, name)
+            value.__dict__['_BrowserObject__childObject'] = (self, name)
 
         return value
 
@@ -205,10 +237,10 @@ class MethodWrapper:
 
     def __init__(self, runner, parentObj, objectId):
         self.__dict__['_MethodWrapper__runner'] = runner
-        self.__dict__['_MethodWraper__boundMethod'] = (parentObj, objectId)
+        self.__dict__['_MethodWrapper__childObject'] = (parentObj, objectId)
 
     def __str__(self):
-        parentObj, attribName = self.__boundMethod
+        parentObj, attribName = self.__childObject
         return "%s.%s" % (parentObj, attribName)
 
     def __nonzero__(self):
@@ -223,7 +255,7 @@ class MethodWrapper:
             raise ArgumentError, 'Keyword arguments not supported'
         
         try:
-            parentObj, attribName = self.__boundMethod
+            parentObj, attribName = self.__childObject
             # Call it as a method.
             if parentObj is self.__runner.dom and attribName == 'alert':
                 # As a special hack, we don't wait for the return