Bläddra i källkod

add has_method to work around firefox bug

David Rose 16 år sedan
förälder
incheckning
ce23653ac2

+ 23 - 0
direct/src/plugin/p3dObject.cxx

@@ -70,6 +70,11 @@ object_set_property(P3D_object *object, const char *property,
   return ((P3DObject *)object)->set_property(property, value);
 }
 
+static bool
+object_has_method(const P3D_object *object, const char *method_name) {
+  return ((const P3DObject *)object)->has_method(method_name);
+}
+
 static P3D_object *
 object_call(const P3D_object *object, const char *method_name,
             P3D_object *params[], int num_params) {
@@ -95,6 +100,7 @@ P3D_class_definition P3DObject::_object_class = {
   &object_get_repr,
   &object_get_property,
   &object_set_property,
+  &object_has_method,
   &object_call,
   &object_eval,
 };
@@ -163,6 +169,11 @@ generic_set_property(P3D_object *object, const char *property,
   return false;
 }
 
+static bool
+generic_has_method(const P3D_object *object, const char *method_name) {
+  return ((const P3DObject *)object)->has_method(method_name);
+}
+
 static P3D_object *
 generic_call(const P3D_object *object, const char *method_name,
             P3D_object *params[], int num_params) {
@@ -188,6 +199,7 @@ P3D_class_definition P3DObject::_generic_class = {
   &generic_get_repr,
   &generic_get_property,
   &generic_set_property,
+  &generic_has_method,
   &generic_call,
   &generic_eval,
 };
@@ -297,6 +309,17 @@ set_property(const string &property, P3D_object *value) {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DObject::has_method
+//       Access: Public, Virtual
+//  Description: Returns true if the named method exists on this
+//               object, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool P3DObject::
+has_method(const string &method_name) const {
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DObject::call
 //       Access: Public, Virtual

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

@@ -46,6 +46,7 @@ public:
   virtual P3D_object *get_property(const string &property) const;
   virtual bool set_property(const string &property, P3D_object *value);
 
+  virtual bool has_method(const string &method_name) const;
   virtual P3D_object *call(const string &method_name, 
                            P3D_object *params[], int num_params) const;
   virtual P3D_object *eval(const string &expression) const;

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

@@ -173,6 +173,29 @@ set_property(const string &property, P3D_object *value) {
   return bresult;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonObject::has_method
+//       Access: Public, Virtual
+//  Description: Returns true if the named method exists on this
+//               object, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool P3DPythonObject::
+has_method(const string &method_name) const {
+  bool bresult = false;
+
+  P3D_object *params[1];
+  params[0] = new P3DStringObject(method_name);
+
+  P3D_object *result = call("__has_method__", params, 1);
+
+  if (result != NULL) {
+    bresult = P3D_OBJECT_GET_BOOL(result);
+    P3D_OBJECT_FINISH(result);
+  }
+
+  return bresult;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPythonObject::call
 //       Access: Public, Virtual

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

@@ -44,6 +44,7 @@ public:
   virtual P3D_object *get_property(const string &property) const;
   virtual bool set_property(const string &property, P3D_object *value);
 
+  virtual bool has_method(const string &method_name) const;
   virtual P3D_object *call(const string &method_name, 
                            P3D_object *params[], int num_params) const;
 

+ 22 - 0
direct/src/plugin/p3dPythonRun.cxx

@@ -395,6 +395,28 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
             }
           }
 
+        } else if (strcmp(method_name, "__has_method__") == 0) {
+          char *property_name;
+          result = Py_False;
+          if (PyArg_ParseTuple(params, "s", &property_name)) {
+            if (*property_name) {
+              // Check for a callable method
+              if (PyObject_HasAttrString(obj, property_name)) {
+                PyObject *prop = PyObject_GetAttrString(obj, property_name);
+                if (PyCallable_Check(prop)) {
+                  result = Py_True;
+                }
+                Py_DECREF(prop);
+              }
+            } else {
+              // Check for the default method
+              if (PyCallable_Check(obj)) {
+                result = Py_True;
+              }
+            }
+          }
+          Py_INCREF(result);
+
         } else {
           // Not a special-case name.  Call the named method.
           PyObject *method = PyObject_GetAttrString(obj, (char *)method_name);

+ 10 - 0
direct/src/plugin/p3d_plugin.h

@@ -377,6 +377,14 @@ typedef bool
 P3D_object_set_property_method(P3D_object *object, const char *property,
                                P3D_object *value);
 
+/* Returns true if the indicated method name exists on the object,
+   false otherwise.  In the Python case, this actually returns true if
+   the object has the indicated property, and that property represents
+   a callable object.  If method_name is empty or NULL, returns true
+   if the object itself is callable. */
+typedef bool
+P3D_object_has_method_method(const P3D_object *object, const char *method_name);
+
 /* Invokes a named method on the object.  If method_name is empty or
    NULL, invokes the object itself as a function.  You must pass an
    array of P3D_objects as the list of parameters.  The ownership of
@@ -416,6 +424,7 @@ typedef struct _P3D_class_definition {
   P3D_object_get_property_method *_get_property;
   P3D_object_set_property_method *_set_property;
 
+  P3D_object_has_method_method *_has_method;
   P3D_object_call_method *_call;
   P3D_object_eval_method *_eval;
 
@@ -444,6 +453,7 @@ struct _P3D_object {
 #define P3D_OBJECT_GET_PROPERTY(object, property) ((object)->_class->_get_property((object), (property)))
 #define P3D_OBJECT_SET_PROPERTY(object, property, value) ((object)->_class->_set_property((object), (property), (value)))
 
+#define P3D_OBJECT_HAS_METHOD(object, property) ((object)->_class->_has_method((object), (property)))
 #define P3D_OBJECT_CALL(object, method_name, params, num_params) ((object)->_class->_call((object), (method_name), (params), (num_params)))
 #define P3D_OBJECT_EVAL(object, expression) ((object)->_class->_eval((object), (expression)))
 

+ 19 - 4
direct/src/plugin_npapi/ppPandaObject.cxx

@@ -101,11 +101,26 @@ invalidate() {
 ////////////////////////////////////////////////////////////////////
 bool PPPandaObject::
 has_method(NPIdentifier name) {
-  string property_name = identifier_to_string(name);
-  logfile << "has_method: " << this << ", " << property_name << "\n" << flush;
+  string method_name = identifier_to_string(name);
+  logfile << "has_method: " << this << ", " << method_name << "\n" << flush;
+  if (_p3d_object == NULL) {
+    // Not powered up yet.
+    return false;
+  }
 
-  // As below, we always return true.  Why not?
-  return true;
+  // Unlike has_property(), below, it turns out that we really do need
+  // to honestly answer whether there is a method by this name,
+  // because if there is, then Firefox won't query the property in a
+  // meaningful fashion.
+
+  // Of course, in Python the distinction between property and method
+  // is a little looser than Firefox seems to want to make it, and
+  // sometimes you have an object which is both.  This could become
+  // problematic in obscure situations.  Too bad, say I.  Mozilla's
+  // bug, not mine.
+
+  bool result = P3D_OBJECT_HAS_METHOD(_p3d_object, method_name.c_str());
+  return result;
 }
 
 ////////////////////////////////////////////////////////////////////