diff --git a/direct/src/plugin/p3dObject.cxx b/direct/src/plugin/p3dObject.cxx index e34738721a..ae66159d87 100644 --- a/direct/src/plugin/p3dObject.cxx +++ b/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 diff --git a/direct/src/plugin/p3dObject.h b/direct/src/plugin/p3dObject.h index 13f0133a65..b06f5ef092 100644 --- a/direct/src/plugin/p3dObject.h +++ b/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; diff --git a/direct/src/plugin/p3dPythonObject.cxx b/direct/src/plugin/p3dPythonObject.cxx index bda01c6b8e..0d271ae2ed 100644 --- a/direct/src/plugin/p3dPythonObject.cxx +++ b/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 diff --git a/direct/src/plugin/p3dPythonObject.h b/direct/src/plugin/p3dPythonObject.h index 129ff1bf4f..394a3f9456 100644 --- a/direct/src/plugin/p3dPythonObject.h +++ b/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; diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx index a52bea32fc..c6d65d5f15 100755 --- a/direct/src/plugin/p3dPythonRun.cxx +++ b/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); diff --git a/direct/src/plugin/p3d_plugin.h b/direct/src/plugin/p3d_plugin.h index 75149334ef..328c8ec72f 100644 --- a/direct/src/plugin/p3d_plugin.h +++ b/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))) diff --git a/direct/src/plugin_npapi/ppPandaObject.cxx b/direct/src/plugin_npapi/ppPandaObject.cxx index ea7372e241..15e70a360b 100644 --- a/direct/src/plugin_npapi/ppPandaObject.cxx +++ b/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; } ////////////////////////////////////////////////////////////////////