// Disonnect a signal from a slot and handle any errors. static PyObject *disconnect(qpycore_pyqtBoundSignal *bs, QObject *qrx, const char *slot) { Chimera::Signature *signature = bs->unbound_signal->signature; bool ok; Py_BEGIN_ALLOW_THREADS ok = QObject::disconnect(bs->bound_qobject, signature->signature.constData(), qrx, slot); Py_END_ALLOW_THREADS if (!ok) { QByteArray tx_name = signature->name(); if (slot) { QByteArray rx_name = Chimera::Signature::name(slot); PyErr_Format(PyExc_TypeError, "disconnect() failed between '%s' and '%s'", tx_name.constData() + 1, rx_name.constData() + 1); } else { PyErr_Format(PyExc_TypeError, "disconnect() failed between '%s' and all its connections", tx_name.constData() + 1); } return 0; } Py_INCREF(Py_None); return Py_None; }
void qpycore_qmetaobject_connectslotsbyname(QObject *qobj, PyObject *qobj_wrapper) { // Get the class attributes. PyObject *dir = PyObject_Dir((PyObject *)Py_TYPE(qobj_wrapper)); if (!dir) return; PyObject *slot_obj = 0; for (SIP_SSIZE_T li = 0; li < PyList_GET_SIZE(dir); ++li) { PyObject *name_obj = PyList_GET_ITEM(dir, li); // Get the slot object. Py_XDECREF(slot_obj); slot_obj = PyObject_GetAttr(qobj_wrapper, name_obj); if (!slot_obj) continue; // Ignore it if it is not a callable. if (!PyCallable_Check(slot_obj)) continue; // Use the signature attribute instead of the name if there is one. PyObject *sigattr = PyObject_GetAttr(slot_obj, qpycore_dunder_pyqtsignature); if (sigattr) { for (SIP_SSIZE_T i = 0; i < PyList_GET_SIZE(sigattr); ++i) { PyObject *decoration = PyList_GET_ITEM(sigattr, i); Chimera::Signature *sig = Chimera::Signature::fromPyObject(decoration); QByteArray args = sig->arguments(); if (!args.isEmpty()) connect(qobj, slot_obj, sig->name(), args); } Py_DECREF(sigattr); } else { const char *ascii_name = sipString_AsASCIIString(&name_obj); if (!ascii_name) continue; PyErr_Clear(); connect(qobj, slot_obj, QByteArray(ascii_name), QByteArray()); Py_DECREF(name_obj); } } Py_XDECREF(slot_obj); Py_DECREF(dir); }
// Return the full name and signature of a Qt slot that a signal can be // connected to, taking the slot decorators into account. static QByteArray slot_signature_from_decorations(Chimera::Signature *signal, PyObject *decorations, int nr_args) { for (SIP_SSIZE_T i = 0; i < PyList_GET_SIZE(decorations); ++i) { Chimera::Signature *slot = Chimera::Signature::fromPyObject( PyList_GET_ITEM(decorations, i)); if (slot->parsed_arguments.count() != nr_args) continue; int a; for (a = 0; a < nr_args; ++a) { const Chimera *sig_arg = signal->parsed_arguments.at(a); const Chimera *slot_arg = slot->parsed_arguments.at(a); // The same type names must be compatible. if (sig_arg->name() == slot_arg->name()) continue; enum Match { // The type is PyQt_PyObject because it was explicitly // specified as such as a string. MatchesAll, // The type is PyQt_PyObject because it was specified as a type // object that needed wrapping. MatchesPyType, // The type is something other than PyQt_PyObject. MatchesName }; Match sig_match, slot_match; if (sig_arg->name() != "PyQt_PyObject") sig_match = MatchesName; else sig_match = sig_arg->py_type() ? MatchesPyType : MatchesAll; if (slot_arg->name() != "PyQt_PyObject") slot_match = MatchesName; else slot_match = slot_arg->py_type() ? MatchesPyType : MatchesAll; // They are incompatible unless one is called PyQt_PyObject. if (sig_match == MatchesName || slot_match == MatchesName) break; // They are compatible if neither was a Python type. if (sig_match == MatchesAll || slot_match == MatchesAll) continue; // The signal type can be a sub-type of the slot type. if (!PyType_IsSubtype((PyTypeObject *)sig_arg->py_type(), (PyTypeObject *)slot_arg->py_type())) break; } if (a == nr_args) return slot_signature(signal, slot->name(), nr_args); } return QByteArray(); }