// Get the receiver QObject from the slot (if there is one) and its signature // (if it wraps a Qt slot). A Python exception will be raised if there was an // error. static QObject *get_receiver(qpycore_pyqtBoundSignal *bs, PyObject *slot_obj, QByteArray &name) { PyObject *rx_self, *decorations; QByteArray rx_name; bool try_qt_slot; Chimera::Signature *signature = bs->unbound_signal->signature; decorations = 0; if (PyMethod_Check(slot_obj)) { rx_self = PyMethod_GET_SELF(slot_obj); PyObject *f = PyMethod_GET_FUNCTION(slot_obj); Q_ASSERT(PyFunction_Check(f)); PyObject *f_name_obj = ((PyFunctionObject *)f)->func_name; const char *f_name = sipString_AsASCIIString(&f_name_obj); Q_ASSERT(f_name); rx_name = f_name; Py_DECREF(f_name_obj); // See if this has been decorated. decorations = PyObject_GetAttr(f, qpycore_signature_attr_name); if (decorations) { try_qt_slot = true; // It's convenient to do this here as it's not going to disappear. Py_DECREF(decorations); } else { try_qt_slot = false; } Py_XINCREF(rx_self); } else if (PyCFunction_Check(slot_obj)) { rx_self = PyCFunction_GET_SELF(slot_obj); rx_name = ((PyCFunctionObject *)slot_obj)->m_ml->ml_name; // We actually want the C++ name which may (in theory) be completely // different. However this will cope with the exec_ case which is // probably good enough. if (rx_name.endsWith('_')) rx_name.chop(1); try_qt_slot = true; Py_XINCREF(rx_self); } else { static PyObject *partial = 0; // Get the functools.partial type object if we haven't already got it. if (!partial) { PyObject *functools = PyImport_ImportModule("functools"); if (functools) { partial = PyObject_GetAttrString(functools, "partial"); Py_DECREF(functools); } } // If we know about functools.partial then remove the outer partials to // get to the original function. if (partial && PyObject_IsInstance(slot_obj, partial)) { PyObject *func = slot_obj; Py_INCREF(func); do { PyObject *subfunc = PyObject_GetAttrString(func, "func"); Py_DECREF(func); // This should never happen. if (!subfunc) return 0; func = subfunc; } while (PyObject_IsInstance(func, partial)); if (PyMethod_Check(func)) rx_self = PyMethod_GET_SELF(func); else if (PyCFunction_Check(func)) rx_self = PyCFunction_GET_SELF(func); else rx_self = 0; Py_XINCREF(rx_self); Py_DECREF(func); try_qt_slot = false; } else { rx_self = 0; } } if (!rx_self) return 0; int iserr = 0; void *rx = sipForceConvertToType(rx_self, sipType_QObject, 0, SIP_NO_CONVERTORS, 0, &iserr); Py_DECREF(rx_self); PyErr_Clear(); if (iserr) return 0; QObject *rx_qobj = reinterpret_cast<QObject *>(rx); // If there might be a Qt slot that can handle the arguments (or a subset // of them) then use it. Otherwise we will fallback to using a proxy. if (try_qt_slot) { for (int ol = signature->parsed_arguments.count(); ol >= 0; --ol) { // If there are decorations then we compare the signal's signature // against them so that we distinguish between Python types that // are passed to Qt as PyQt_PyObject objects. Qt will not make the // distinction. If there are no decorations then let Qt determine // if a slot is available. if (decorations) name = slot_signature_from_decorations(signature, decorations, ol); else name = slot_signature_from_metaobject(signature, rx_qobj->metaObject(), rx_name, ol); if (!name.isEmpty()) { // Prepend the magic slot marker. name.prepend('1'); break; } } } return rx_qobj; }
// Get the receiver QObject from the slot (if there is one) and its signature // (if it wraps a Qt slot). A Python exception will be raised if there was an // error. static QObject *get_receiver(Chimera::Signature *overload, PyObject *slot_obj, QByteArray &name) { PyObject *rx_self, *decorations; QByteArray rx_name; bool try_qt_slot; decorations = 0; if (PyMethod_Check(slot_obj)) { rx_self = PyMethod_GET_SELF(slot_obj); PyObject *f = PyMethod_GET_FUNCTION(slot_obj); Q_ASSERT(PyFunction_Check(f)); PyObject *f_name_obj = ((PyFunctionObject *)f)->func_name; const char *f_name = sipString_AsASCIIString(&f_name_obj); Q_ASSERT(f_name); rx_name = f_name; Py_DECREF(f_name_obj); // See if this has been decorated. decorations = PyObject_GetAttr(f, qpycore_signature_attr_name); if (decorations) { try_qt_slot = true; // It's convenient to do this here as it's not going to disappear. Py_DECREF(decorations); } else { try_qt_slot = false; } } else if (PyCFunction_Check(slot_obj)) { rx_self = PyCFunction_GET_SELF(slot_obj); rx_name = ((PyCFunctionObject *)slot_obj)->m_ml->ml_name; // We actually want the C++ name which may (in theory) be completely // different. However this will cope with the exec_ case which is // probably good enough. if (rx_name.endsWith('_')) rx_name.chop(1); try_qt_slot = true; } else { rx_self = 0; } if (!rx_self) return 0; int iserr = 0; void *rx = sipForceConvertToType(rx_self, sipType_QObject, 0, SIP_NO_CONVERTORS, 0, &iserr); PyErr_Clear(); if (iserr) return 0; QObject *rx_qobj = reinterpret_cast<QObject *>(rx); // If there might be a Qt slot that can handle the arguments (or a subset // of them) then use it. Otherwise we will fallback to using a proxy. if (try_qt_slot) { for (int ol = overload->parsed_arguments.count(); ol >= 0; --ol) { // If there are decorations then we compare the signal's signature // against them so that we distinguish between Python types that // are passed to Qt as PyQt_PyObject objects. Qt will not make the // distinction. If there are no decorations then let Qt determine // if a slot is available. if (decorations) name = slot_signature_from_decorations(overload, decorations, ol); else name = slot_signature_from_metaobject(overload, rx_qobj->metaObject(), rx_name, ol); if (!name.isEmpty()) { // Prepend the magic slot marker. name.prepend('1'); break; } } } return rx_qobj; }