// This does the real work for all implementations of QObject::qt_metacall().
static int qt_metacall_worker(sipSimpleWrapper *pySelf, PyTypeObject *pytype,
        sipTypeDef *base, QMetaObject::Call _c, int _id, void **_a)
{
    // See if this is a wrapped C++ type rather than a Python sub-type.
    if (pytype == sipTypeAsPyTypeObject(base))
        return _id;

    _id = qt_metacall_worker(pySelf, pytype->tp_base, base, _c, _id, _a);

    if (_id < 0)
        return _id;

    pyqtWrapperType *pyqt_wt = (pyqtWrapperType *)pytype;
    qpycore_metaobject *qo = pyqt_wt->metaobject;

    bool ok = true;

    if (_c == QMetaObject::InvokeMetaMethod)
    {
        if (_id < qo->nr_signals + qo->pslots.count())
        {
            if (_id < qo->nr_signals)
            {
                QObject *qthis = reinterpret_cast<QObject *>(sipGetCppPtr(pySelf, sipType_QObject));

                Py_BEGIN_ALLOW_THREADS
                QMetaObject::activate(qthis, QPYCORE_QMETAOBJECT(qo), _id, _a);
                Py_END_ALLOW_THREADS
            }
            else
            {
                // We take a copy just to be safe.
                qpycore_slot slot = qo->pslots.at(_id - qo->nr_signals);

                // Set up the instance specific parts.
                slot.sip_slot.meth.mself = (PyObject *)pySelf;

                PyObject *py = PyQtProxy::invokeSlot(slot, _a);

                if (!py)
                    ok = false;
                else
                {
                    if (_a[0] && slot.signature->result)
                    {
                        ok = slot.signature->result->fromPyObject(py, _a[0]);
                    }

                    Py_DECREF(py);
                }
            }
        }
// This is the helper for all implementations of QObject::qt_metacall().
int qpycore_qobject_qt_metacall(sipSimpleWrapper *pySelf, sipTypeDef *base,
        QMetaObject::Call _c, int _id, void **_a)
{
    // Check if the Python object has gone.
    if (!pySelf)
        return -1;

    SIP_BLOCK_THREADS
    _id = qt_metacall_worker(pySelf, Py_TYPE(pySelf), base, _c, _id, _a);
    SIP_UNBLOCK_THREADS

    return _id;
}
// This does the real work for all implementations of QObject::qt_metacall().
static int qt_metacall_worker(sipSimpleWrapper *pySelf, PyTypeObject *pytype,
        sipTypeDef *base, QMetaObject::Call _c, int _id, void **_a)
{
    // See if this is a wrapped C++ type rather than a Python sub-type.
    if (pytype == sipTypeAsPyTypeObject(base))
        return _id;

    _id = qt_metacall_worker(pySelf, pytype->tp_base, base, _c, _id, _a);

    if (_id < 0)
        return _id;

    pyqtWrapperType *pyqt_wt = (pyqtWrapperType *)pytype;
    qpycore_metaobject *qo = pyqt_wt->metaobject;

    bool ok = true;

    if (_c == QMetaObject::InvokeMetaMethod)
    {
        if (_id < qo->nr_signals + qo->pslots.count())
        {
            if (_id < qo->nr_signals)
            {
                QObject *qthis = reinterpret_cast<QObject *>(sipGetCppPtr(pySelf, sipType_QObject));

                Py_BEGIN_ALLOW_THREADS
                QMetaObject::activate(qthis, qo->mo, _id, _a);
                Py_END_ALLOW_THREADS
            }
            else
            {
                PyQtSlot *slot = qo->pslots.at(_id - qo->nr_signals);

                ok = slot->invoke(_a, (PyObject *)pySelf, _a[0]);
            }
        }