// qobject.sip generated by MetaSIP on Fri Sep 28 17:07:47 2007 // // This file is part of the QtCore Python extension module. // // Copyright (c) 2007 // Phil Thompson // // This file is part of PyQt. // // This copy of PyQt is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License version 2 as published by // the Free Software Foundation and appearing in the file LICENSE included in the // packaging of this file. // // PyQt is supplied in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more // details. // // You should have received a copy of the GNU General Public License along with // PyQt; see the file LICENSE. If not, write to the Free Software Foundation, // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. class QWidget /External/; // QtGui classes that can be handled by QVariant class QBitmap /External/; class QBrush /External/; class QColor /External/; class QCursor /External/; class QFont /External/; class QIcon /External/; class QImage /External/; class QKeySequence /External/; class QMatrix /External/; class QPalette /External/; class QPen /External/; class QPixmap /External/; class QPolygon /External/; class QRegion /External/; class QSizePolicy /External/; class QTextFormat /External/; class QTextLength /External/; %If (Qt_4_3_0 -) class QTransform /External/; %End typedef QList QObjectList; class QObject { %TypeHeaderCode #include %End %TypeCode // This is needed by the tr() and trUt8() handwritten implementations. #include // These are the recursive helper functions for QObject::findChild() and // QObject::findChildren. static PyObject *qtcore_FindChild(const QObject *parent, PyObject *parent_obj, PyTypeObject *type, const QString &name) { const QObjectList &children = parent->children(); int i; PyObject *clist = PyList_New(children.size()); if (!clist) return 0; for (i = 0; i < children.size(); ++i) { QObject *obj = children.at(i); PyObject *pyo = sipConvertFromInstance(obj, sipClass_QObject, parent_obj); if (!pyo) { Py_DECREF(clist); return 0; } if ((name.isNull() || obj->objectName() == name) && PyType_IsSubtype(pyo->ob_type, type)) { Py_DECREF(clist); return pyo; } PyList_SET_ITEM(clist, i, pyo); } for (i = 0; i < children.size(); ++i) { PyObject *pyo = qtcore_FindChild(children.at(i), PyList_GET_ITEM(clist, i), type, name); if (pyo != Py_None) { Py_DECREF(clist); return pyo; } Py_DECREF(pyo); } Py_DECREF(clist); Py_INCREF(Py_None); return Py_None; } static int qtcore_FindChildren(const QObject *parent, PyObject *parent_obj, PyTypeObject *type, const QString &name, PyObject *list) { const QObjectList &children = parent->children(); int i; for (i = 0; i < children.size(); ++i) { QObject *obj = children.at(i); PyObject *pyo = sipConvertFromInstance(obj, sipClass_QObject, parent_obj); if (!pyo) return -1; if ((name.isNull() || obj->objectName() == name) && PyType_IsSubtype(pyo->ob_type, type)) if (PyList_Append(list, pyo) < 0) { Py_DECREF(pyo); return -1; } int rc = qtcore_FindChildren(obj, pyo, type, name, list); Py_DECREF(pyo); if (rc < 0) return -1; } return 0; } static int qtcore_FindChildren(const QObject *parent, PyObject *parent_obj, PyTypeObject *type, const QRegExp &re, PyObject *list) { const QObjectList &children = parent->children(); int i; for (i = 0; i < children.size(); ++i) { QObject *obj = children.at(i); PyObject *pyo = sipConvertFromInstance(obj, sipClass_QObject, parent_obj); if (!pyo) return -1; if (re.indexIn(obj->objectName()) >= 0 && PyType_IsSubtype(pyo->ob_type, type)) if (PyList_Append(list, pyo) < 0) { Py_DECREF(pyo); return -1; } int rc = qtcore_FindChildren(obj, pyo, type, re, list); Py_DECREF(pyo); if (rc < 0) return -1; } return 0; } %End %ConvertToSubClassCode static struct class_graph { char *name; sipWrapperType **type; int yes, no; } graph[] = { {sipName_QAbstractEventDispatcher, &sipClass_QAbstractEventDispatcher, -1, 1}, #if QT_VERSION >= 0x040200 {sipName_QFileSystemWatcher, &sipClass_QFileSystemWatcher, -1, 2}, #else {0, 0, -1, 2}, #endif {sipName_QThread, &sipClass_QThread, -1, 3}, {sipName_QTimer, &sipClass_QTimer, -1, 4}, {sipName_QSettings, &sipClass_QSettings, -1, 5}, {sipName_QSocketNotifier, &sipClass_QSocketNotifier, -1, 6}, {sipName_QTranslator, &sipClass_QTranslator, -1, 7}, {sipName_QCoreApplication, &sipClass_QCoreApplication, -1, 8}, {sipName_QLibrary, &sipClass_QLibrary, -1, 9}, {sipName_QAbstractItemModel, &sipClass_QAbstractItemModel, 17, 10}, {sipName_QMimeData, &sipClass_QMimeData, -1, 11}, {sipName_QEventLoop, &sipClass_QEventLoop, -1, 12}, {sipName_QIODevice, &sipClass_QIODevice, 19, 13}, {sipName_QSignalMapper, &sipClass_QSignalMapper, -1, 14}, {sipName_QObjectCleanupHandler, &sipClass_QObjectCleanupHandler, -1, 15}, #if QT_VERSION >= 0x040200 {sipName_QTimeLine, &sipClass_QTimeLine, -1, 16}, #else {0, 0, -1, 16}, #endif {sipName_QPluginLoader, &sipClass_QPluginLoader, -1, -1}, {sipName_QAbstractTableModel, &sipClass_QAbstractTableModel, -1, 18}, {sipName_QAbstractListModel, &sipClass_QAbstractListModel, -1, -1}, {sipName_QFile, &sipClass_QFile, 22, 20}, {sipName_QBuffer, &sipClass_QBuffer, -1, 21}, {sipName_QProcess, &sipClass_QProcess, -1, -1}, {sipName_QTemporaryFile, &sipClass_QTemporaryFile, -1, -1}, }; int i = 0; sipClass = NULL; do { struct class_graph *cg = &graph[i]; if (cg->name != NULL && sipCpp->inherits(cg->name)) { sipClass = *cg->type; i = cg->yes; } else i = cg->no; } while (i >= 0); %End public: const QMetaObject *metaObject() const; explicit QObject(QObject *parent /TransferThis/ = 0); virtual ~QObject(); virtual bool event(QEvent *); virtual bool eventFilter(QObject *, QEvent *); %If (Qt_4_2_0 -) QString tr(const char *sourceText, const char *comment = 0, int n = -1) const; %MethodCode // Note that tr() is really a static method. We pretend it isn't so we can use // self to get hold of the class name. PyObject *nmobj = sipClassName(sipSelf); if (nmobj) { char *cname = PyString_AsString(nmobj); if (cname) sipRes = new QString(QCoreApplication::translate(cname, a0, a1, QCoreApplication::CodecForTr, a2)); else sipIsErr = 1; Py_DECREF(nmobj); } else sipIsErr = 1; %End %End %If (- Qt_4_2_0) QString tr(const char *sourceText, const char *comment = 0) const; %MethodCode // Note that tr() is really a static method. We pretend it isn't so we can use // self to get hold of the class name. PyObject *nmobj = sipClassName(sipSelf); if (nmobj) { char *cname = PyString_AsString(nmobj); if (cname) if (QCoreApplication::instance()) sipRes = new QString(QCoreApplication::instance()->translate(cname, a0, a1, QCoreApplication::DefaultCodec)); else sipRes = new QString(QString::fromLatin1(a0)); else sipIsErr = 1; Py_DECREF(nmobj); } else sipIsErr = 1; %End %End %If (Qt_4_2_0 -) QString trUtf8(const char *sourceText, const char *comment = 0, int n = -1) const; %MethodCode // Note that trUtf8() is really a static method. We pretend it isn't aren't so // we can use self to get hold of the class name. PyObject *nmobj = sipClassName(sipSelf); if (nmobj) { char *cname = PyString_AsString(nmobj); if (cname) sipRes = new QString(QCoreApplication::translate(cname, a0, a1, QCoreApplication::UnicodeUTF8, a2)); else sipIsErr = 1; Py_DECREF(nmobj); } else sipIsErr = 1; %End %End %If (- Qt_4_2_0) QString trUtf8(const char *sourceText, const char *comment = 0) const; %MethodCode // Note that trUtf8() is really a static method. We pretend it isn't aren't so // we can use self to get hold of the class name. PyObject *nmobj = sipClassName(sipSelf); if (nmobj) { char *cname = PyString_AsString(nmobj); if (cname) if (QCoreApplication::instance()) sipRes = new QString(QCoreApplication::instance()->translate(cname, a0, a1, QCoreApplication::UnicodeUTF8)); else sipRes = new QString(QString::fromUtf8(a0)); else sipIsErr = 1; Py_DECREF(nmobj); } else sipIsErr = 1; %End %End SIP_PYOBJECT findChild(SIP_PYTYPE type, const QString &name = QString()) const; %MethodCode sipRes = qtcore_FindChild(sipCpp, sipSelf, (PyTypeObject *)a0, *a1); if (!sipRes) sipIsErr = 1; %End SIP_PYLIST findChildren(SIP_PYTYPE type, const QString &name = QString()) const; %MethodCode if ((sipRes = PyList_New(0)) == NULL || qtcore_FindChildren(sipCpp, sipSelf, (PyTypeObject *)a0, *a1, sipRes) < 0) { Py_XDECREF(sipRes); sipIsErr = 1; } %End SIP_PYLIST findChildren(SIP_PYTYPE type, const QRegExp ®Exp) const; %MethodCode if ((sipRes = PyList_New(0)) == NULL || qtcore_FindChildren(sipCpp, sipSelf, (PyTypeObject *)a0, *a1, sipRes) < 0) { Py_XDECREF(sipRes); sipIsErr = 1; } %End void emit(SIP_SIGNAL, ...) const; %MethodCode if (sipEmitSignal(sipSelf, a0, a1) < 0) sipIsErr = 1; %End QString objectName() const; void setObjectName(const QString &name); bool isWidgetType() const; bool signalsBlocked() const; bool blockSignals(bool b); QThread *thread() const; void moveToThread(QThread *thread); int startTimer(int interval); void killTimer(int id); const QObjectList &children() const; void setParent(QObject * /TransferThis/); void installEventFilter(QObject *); void removeEventFilter(QObject *); static SIP_PYOBJECT connect(SIP_QOBJECT, SIP_SIGNAL, SIP_QOBJECT, SIP_SLOT, Qt::ConnectionType=Qt::AutoConnection); %MethodCode sipRes = sipConnectRx(a0, a1, a2, a3, (int)a4); %End static SIP_PYOBJECT connect(SIP_QOBJECT, SIP_SIGNAL, SIP_PYCALLABLE, Qt::ConnectionType=Qt::AutoConnection); %MethodCode sipRes = sipConnectRx(a0, a1, a2, 0, (int)a3); %End SIP_PYOBJECT connect(SIP_QOBJECT, SIP_SIGNAL, SIP_SLOT, Qt::ConnectionType=Qt::AutoConnection) const; %MethodCode sipRes = sipConnectRx(a0, a1, sipSelf, a2, (int)a3); %End static SIP_PYOBJECT disconnect(SIP_QOBJECT, SIP_SIGNAL, SIP_QOBJECT, SIP_SLOT); %MethodCode sipRes = sipDisconnectRx(a0, a1, a2, a3); %End static SIP_PYOBJECT disconnect(SIP_QOBJECT, SIP_SIGNAL, SIP_PYCALLABLE); %MethodCode sipRes = sipDisconnectRx(a0, a1, a2, 0); %End void dumpObjectInfo(); void dumpObjectTree(); %If (Qt_4_2_0 -) QList dynamicPropertyNames() const; %End bool setProperty(const char *name, const QVariant &value); QVariant property(const char *name) const; signals: void destroyed(QObject * = 0); public: QObject *parent() const; bool inherits(const char *classname) const; %MethodCode // The Qt implementation doesn't know anything about Python sub-classes so we // use the Python type's MRO. PyObject *mro = sipSelf->ob_type->tp_mro; sipRes = 0; for (int i = 0; i < PyTuple_GET_SIZE(mro); ++i) if (qstrcmp(((PyTypeObject *)PyTuple_GET_ITEM(mro, i))->tp_name, a0) == 0) { sipRes = 1; break; } %End public slots: void deleteLater(); protected: SIP_PYOBJECT sender() const [QObject * ()]; %MethodCode // This is actually protected but we never need to call the real method. sipRes = sipGetSender(); %End int receivers(SIP_SIGNAL signal) const; %MethodCode // We also need to take into account any proxies for Python signals. sipRes = sipCpp->sipProtect_receivers(a0); const QObjectList &children = sipCpp->QObject::children(); // Import the helper if it hasn't already been done. typedef int (*helper_func)(const QObject *, const char *); static helper_func helper = 0; if (!helper) helper = (helper_func)sipImportSymbol("qtcore_receivers"); if (helper) for (int i = 0; i < children.size(); ++i) sipRes += helper(children[i], a0); %End virtual void timerEvent(QTimerEvent *); virtual void childEvent(QChildEvent *); virtual void customEvent(QEvent *); virtual void connectNotify(SIP_SIGNAL signal); virtual void disconnectNotify(SIP_SIGNAL signal); private: QObject(const QObject &); }; SIP_PYOBJECT Q_ENUMS(...); %MethodCode if (sipRegisterIntTypes(a0) < 0) sipRes = 0; else { sipRes = Py_None; Py_INCREF(sipRes); } %End SIP_PYOBJECT Q_FLAGS(...); %MethodCode if (sipRegisterIntTypes(a0) < 0) sipRes = 0; else { sipRes = Py_None; Py_INCREF(sipRes); } %End SIP_PYOBJECT QT_TR_NOOP(SIP_PYOBJECT); %MethodCode Py_INCREF(a0); sipRes = a0; %End SIP_PYOBJECT QT_TRANSLATE_NOOP(SIP_PYOBJECT, SIP_PYOBJECT); %MethodCode Py_INCREF(a1); sipRes = a1; %End SIP_PYOBJECT SLOT(const char *); %MethodCode if (!a0) { PyErr_Format(PyExc_TypeError, "QtCore.SLOT() slot name cannot be None"); sipIsErr = 1; } else { QByteArray ns = QMetaObject::normalizedSignature(a0); if ((sipRes = PyString_FromStringAndSize(NULL, 1 + ns.size())) == NULL) sipIsErr = 1; else { char *dp = PyString_AS_STRING(sipRes); *dp++ = '1'; qstrcpy(dp, ns.constData()); } } %End SIP_PYOBJECT SIGNAL(const char *); %MethodCode if (!a0) { PyErr_Format(PyExc_TypeError, "QtCore.SIGNAL() signal cannot be None"); sipIsErr = 1; } else { QByteArray ns = QMetaObject::normalizedSignature(a0); if ((sipRes = PyString_FromStringAndSize(NULL, 1 + ns.size())) == NULL) sipIsErr = 1; else { char *dp = PyString_AS_STRING(sipRes); *dp++ = '2'; qstrcpy(dp, ns.constData()); } } %End SIP_PYOBJECT pyqtSignature(SIP_PYOBJECT); %MethodCode // Check the argument is a string. if (PyString_Check(a0)) { // Create the decorator function itself. We stash the signature in "self". // This may be an abuse, but it seems to be Ok. static PyMethodDef decorator = { (char *)"_deco", qtcore_pyqtSignature, METH_O, NULL }; sipRes = PyCFunction_New(&decorator, a0); } else { sipNoFunction(0, "pyqtSignature"); sipRes = 0; } %End %ModuleHeaderCode // The signature attribute name as an object. extern PyObject *qtcore_signature_attr; // The name attribute name as an object. extern PyObject *qtcore_name_attr; %End %ModuleCode // This is the Qt support code for SIP. #include #include #include #include // The signature attribute name as an object. PyObject *qtcore_signature_attr; // The name attribute name as an object. PyObject *qtcore_name_attr; // This class is a wrapper around a Python object that maintains the reference // count while Qt copies it around its metatype system (particularly when a // Python object is an argument of an asynchronous signal). class PyQt_PyObject { public: PyQt_PyObject(PyObject *py); PyQt_PyObject(); PyQt_PyObject(const PyQt_PyObject &other); ~PyQt_PyObject(); PyObject *pyobject; private: PyQt_PyObject &operator=(const PyQt_PyObject &other); }; // Wrap a Python object. This should only be called when the GIL has been // acquired. PyQt_PyObject::PyQt_PyObject(PyObject *py) { pyobject = py; Py_INCREF(pyobject); } // Create a new wrapper, with no Python object. This is called by Qt's // metatype system. PyQt_PyObject::PyQt_PyObject() { pyobject = 0; } // Create a copy of an existing wrapper. This is called by Qt's metatype // system. PyQt_PyObject::PyQt_PyObject(const PyQt_PyObject &other) { SIP_BLOCK_THREADS pyobject = other.pyobject; Py_XINCREF(pyobject); SIP_UNBLOCK_THREADS } // Destroy a wrapper. PyQt_PyObject::~PyQt_PyObject() { SIP_BLOCK_THREADS Py_XDECREF(pyobject); SIP_UNBLOCK_THREADS } // This class is used as a signal on behalf of Python signals and as a slot on // behalf of Python callables. It is derived from QObject but is not run // through moc. Instead the normal moc-generated methods are handwritten in // order to implement a universal signal or slot. This requires some knowledge // of the internal implementation of signals and slots but it is likely that // they will only change between major Qt versions. class PyQtProxy : public QObject { public: // The different roles a proxy can fulfill. It might have been better to // implement each as a sub-class. enum ProxyType { ProxySlot, ProxySignal, ProxyShortcircuitSignal }; PyQtProxy(void *tx, const char *pysig); PyQtProxy(void *tx, const sipSignature *psig); PyQtProxy(void *tx, sipSlotConnection *conn, const char **member); ~PyQtProxy(); static const QMetaObject staticMetaObject; virtual const QMetaObject *metaObject() const; virtual void *qt_metacast(const char *); virtual int qt_metacall(QMetaObject::Call, int, void **); void pysignal(const PyQt_PyObject &pyargs); void unislot(void **qargs); static bool invokeSlot(sipSlotConnection &slot_conn, void **qargs); int getReceivers(const char *signal) const; void disable(); static const QObject *lastSender; // The type of a proxy hash. typedef QHash ProxyHash; // Each proxy type is held in a different hash. static ProxyHash proxy_slots; static ProxyHash proxy_signals; static ProxyHash proxy_shortcircuit_signals; // The mutex around the proxies hashes. static QMutex *mutex; // The proxy type. ProxyType type; // Only used when type is ProxySlot. sipSlotConnection slot_conn; // Only used when type is ProxySignal. const sipSignature *sig_sig; // Only used when type is ProxyShortcircuitSignal. char *pysig_name; // Set if the proxy is being deleted. bool deleting; void *qtx; private: void init(void *tx, ProxyHash *hash, void *key); // Only used when type is ProxySignal. QMetaObject *sigmo; PyQtProxy(const PyQtProxy &); PyQtProxy &operator=(const PyQtProxy &); }; static const uint slot_meta_data[] = { // content: 1, // revision 0, // classname 0, 0, // classinfo 3, 10, // methods (number, offset in this array of first one) 0, 0, // properties 0, 0, // enums/sets // signals: signature, parameters, type, tag, flags 11, 10, 10, 10, 0x05, // slots: signature, parameters, type, tag, flags 35, 10, 10, 10, 0x0a, 45, 10, 10, 10, 0x0a, 0 // eod }; static const char slot_meta_stringdata[] = { "PyQtProxy\0\0pysignal(PyQt_PyObject)\0disable()\0unislot()\0" }; const QMetaObject PyQtProxy::staticMetaObject = { { &QObject::staticMetaObject, slot_meta_stringdata, slot_meta_data, 0 } }; // Create a universal proxy used as a shortcircuit signal. PyQtProxy::PyQtProxy(void *tx, const char *pysig) : QObject(), type(PyQtProxy::ProxyShortcircuitSignal) { // Save the Python signal name. pysig_name = new char[qstrlen(pysig) + 1]; qstrcpy(pysig_name, pysig); init(tx, &proxy_shortcircuit_signals, tx); } // Create a universal proxy used as a signal. PyQtProxy::PyQtProxy(void *tx, const sipSignature *psig) : QObject(), type(PyQtProxy::ProxySignal), sig_sig(psig) { // Create a new meta-object on the heap so that it looks like it has a // signal of the right name and signature. sigmo = new QMetaObject; sigmo->d.superdata = &QObject::staticMetaObject; sigmo->d.extradata = 0; // Calculate the size of the string meta-data as follows: // - "PyQtProxy" and its terminating '\0', // - a '\0' used for any empty string, // - "disable()" and its terminating '\0', // - the (non-existent) argument names (ie. use the empty string if there // is less that two arguments, otherwise a comma between each argument // and the terminating '\0'), // - the name and full signature, less the initial type character, plus the // terminating '\0'. const size_t nm_len = 9 + 1; // qstrlen("PyQtProxy") + 1 const size_t dis_len = 9 + 1; // qstrlen("disable()") + 1 size_t len = nm_len + 1 + dis_len + (psig->sg_nrargs >= 2 ? psig->sg_nrargs : 0) + qstrlen(psig->sg_signature); char *smd = new char[len]; uint i = 0, args_pos, sig_pos; qstrcpy(&smd[i], slot_meta_stringdata); i += nm_len; smd[i++] = '\0'; const uint dis_pos = i; qstrcpy(&smd[i], "disable()"); i += dis_len; if (psig->sg_nrargs >= 2) { args_pos = i; for (int c = 1; c < psig->sg_nrargs; ++c) smd[i++] = ','; smd[i++] = '\0'; } else args_pos = nm_len; sig_pos = i; qstrcpy(&smd[i], &psig->sg_signature[1]); sigmo->d.stringdata = smd; // Add the non-string data. uint *data = new uint[21]; for (int d = 0; d < 21; ++d) data[d] = staticMetaObject.d.data[d]; // Remove the third method (ie. unislot()). data[4] = 2; data[20] = 0; // Fix the changed values. data[10] = sig_pos; data[11] = args_pos; data[14] = 0x05; data[15] = dis_pos; sigmo->d.data = data; init(tx, &proxy_signals, tx); } // Create a universal proxy used as a slot. Note that this will leak if there // is no signal transmitter (ie. no parent) - QTimer.singleShot() for example. PyQtProxy::PyQtProxy(void *tx, sipSlotConnection *connection, const char **member) : QObject(), type(PyQtProxy::ProxySlot) { // Save the connection. slot_conn = *connection; // Return the slot to connect to. *member = SLOT(unislot()); init(tx, &proxy_slots, connection->sc_transmitter); } // Initialisation common to all ctors. void PyQtProxy::init(void *tx, PyQtProxy::ProxyHash *hash, void *key) { deleting = false; qtx = tx; // Add this one to the global hashes. mutex->lock(); hash->insertMulti(key, this); mutex->unlock(); // Detect when the transmitter is destroyed. if (tx) connect(reinterpret_cast(tx), SIGNAL(destroyed(QObject *)), SLOT(disable())); } // Destroy a universal proxy. PyQtProxy::~PyQtProxy() { switch (type) { case ProxySlot: SIP_BLOCK_THREADS sipFreeConnection(&slot_conn); SIP_UNBLOCK_THREADS break; case ProxySignal: // The casts are needed for MSVC 6. delete[] const_cast(sigmo->d.stringdata); delete[] const_cast(sigmo->d.data); delete sigmo; break; case ProxyShortcircuitSignal: delete[] pysig_name; break; } } // Disable a universal proxy so that it can't get reused before it eventually // gets deleted. void PyQtProxy::disable() { mutex->lock(); // This method can be called twice on the same instance - if the universal // slot is disconnected and the transmitter is then deleted. if (!deleting) { deleting = true; // Remove it from the global hash. ProxyHash *hash = 0; switch (type) { case ProxySlot: hash = &proxy_slots; break; case ProxySignal: hash = &proxy_signals; break; case ProxyShortcircuitSignal: hash = &proxy_shortcircuit_signals; break; } ProxyHash::iterator it(hash->find(qtx)); while (it != hash->end() && it.key() == qtx) { if (it.value() == this) { hash->erase(it); break; } ++it; } // Delete it later. deleteLater(); } mutex->unlock(); } // The static members of PyQtProxy. const QObject *PyQtProxy::lastSender = 0; QMutex *PyQtProxy::mutex; PyQtProxy::ProxyHash PyQtProxy::proxy_slots; PyQtProxy::ProxyHash PyQtProxy::proxy_signals; PyQtProxy::ProxyHash PyQtProxy::proxy_shortcircuit_signals; const QMetaObject *PyQtProxy::metaObject() const { if (type == ProxySignal) return sigmo; return &staticMetaObject; } void *PyQtProxy::qt_metacast(const char *_clname) { if (!_clname) return 0; if (!strcmp(_clname, slot_meta_stringdata)) return static_cast(const_cast(this)); return QObject::qt_metacast(_clname); } int PyQtProxy::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { _id = QObject::qt_metacall(_c, _id, _a); if (_id < 0) return _id; if (_c == QMetaObject::InvokeMetaMethod) { switch (_id) { case 0: if (type == ProxySignal) QMetaObject::activate(this, sigmo, 0, _a); else if (sender()->metaObject() == &staticMetaObject) pysignal(*reinterpret_cast(_a[1])); break; case 1: disable(); break; case 2: unislot(_a); break; } _id -= 2; } return _id; } // This is the signal that implements Python signals. The argument is the // wrapped tuple of Python argument objects. void PyQtProxy::pysignal(const PyQt_PyObject &pyargs) { void *_a[] = {0, const_cast(reinterpret_cast(&pyargs))}; QMetaObject::activate(this, &staticMetaObject, 0, _a); } // This is the universal slot itself that dispatches to the real slot. void PyQtProxy::unislot(void **qargs) { // Save the sender. If it was a universal signal then the sender we want // to save is its transmitter. QObject *sndr = sender(); if (sndr && qstrcmp(sndr->metaObject()->className(), "PyQtProxy") == 0) lastSender = reinterpret_cast(static_cast(sndr)->qtx); else lastSender = sndr; bool ok; SIP_BLOCK_THREADS // See if the sender was a shortcircuited signal. */ if (sndr && sndr->metaObject() == &staticMetaObject) { // The Python arguments will be the only argument. PyObject *pyargs = reinterpret_cast(qargs[1])->pyobject; ok = (sipEmitToSlot(&slot_conn.sc_slot, pyargs) == 0); } else ok = invokeSlot(slot_conn, qargs); if (!ok) PyErr_Print(); SIP_UNBLOCK_THREADS } // Invoke a slot on behalf of C++. bool PyQtProxy::invokeSlot(sipSlotConnection &slot_conn, void **qargs) { bool ok = true; const sipSignature *psig = slot_conn.sc_signature; PyObject *argtup = PyTuple_New(psig->sg_nrargs); if (!argtup) ok = false; else { for (int a = 0; a < psig->sg_nrargs; ++a) { PyObject *arg; ++qargs; switch (psig->sg_args[a].atype) { #if defined(HAVE_WCHAR_H) case wchar_sat: arg = PyUnicode_FromWideChar((wchar_t *)*qargs, 1); break; case wstring_sat: arg = PyUnicode_FromWideChar(*(wchar_t **)*qargs, wcslen(*(wchar_t **)*qargs)); break; #endif case char_sat: case schar_sat: case uchar_sat: arg = PyString_FromStringAndSize((char *)*qargs, 1); break; case string_sat: case sstring_sat: case ustring_sat: arg = PyString_FromString(*(char **)*qargs); break; case short_sat: arg = PyInt_FromLong(*(short *)*qargs); break; case ushort_sat: arg = PyLong_FromUnsignedLong(*(unsigned short *)*qargs); break; case int_sat: arg = PyInt_FromLong(*(int *)*qargs); break; case uint_sat: arg = PyLong_FromUnsignedLong(*(unsigned *)*qargs); break; case long_sat: arg = PyLong_FromLong(*(long *)*qargs); break; case ulong_sat: arg = PyLong_FromUnsignedLong(*(unsigned long *)*qargs); break; case longlong_sat: arg = PyLong_FromLongLong((PY_LONG_LONG)*(long long *)*qargs); break; case ulonglong_sat: arg = PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)*(unsigned long long *)*qargs); break; case float_sat: arg = PyFloat_FromDouble((double)*(float *)*qargs); break; case double_sat: arg = PyFloat_FromDouble(*(double *)*qargs); break; case enum_sat: arg = sipConvertFromNamedEnum(*(int *)*qargs, psig->sg_args[a].u.et); break; case bool_sat: arg = PyBool_FromLong(*(bool *)*qargs); break; case void_sat: arg = sipConvertFromVoidPtr(*(void **)*qargs); break; case class_sat: arg = sipConvertFromInstance(*qargs, psig->sg_args[a].u.wt, 0); break; case classp_sat: arg = sipConvertFromInstance(*(void **)*qargs, psig->sg_args[a].u.wt, 0); break; case mtype_sat: arg = sipConvertFromMappedType(*qargs, psig->sg_args[a].u.mt, 0); break; case mtypep_sat: arg = sipConvertFromMappedType(*(void **)*qargs, psig->sg_args[a].u.mt, 0); break; case qvariant_sat: arg = sipConvertFromInstance(*qargs, sipClass_QVariant, 0); break; case qvariantp_sat: arg = sipConvertFromInstance(*(void **)*qargs, sipClass_QVariant, 0); break; case pyobject_sat: arg = ((PyQt_PyObject *)*qargs)->pyobject; Py_INCREF(arg); break; default: arg = Py_NotImplemented; Py_INCREF(Py_NotImplemented); } PyTuple_SET_ITEM(argtup, a, arg); } // Dispatch to the real slot. if (sipEmitToSlot(&slot_conn.sc_slot, argtup) < 0) ok = false; Py_DECREF(argtup); } return ok; } // A thin wrapper around QObject::receivers(). int PyQtProxy::getReceivers(const char *signal) const { return receivers(signal); } // These optional parts of the Qt support API are implemented. #undef sipQtIsQtSignal #undef sipQtCreateUniversalSignalShortcut #undef sipQtCreateUniversalSignal #undef sipQtFindUniversalSignalShortcut #undef sipQtFindUniversalSignal #undef sipQtEmitSignalShortcut #undef sipQtEmitSignal // Declare explicit C linkage. extern "C" { static int sipQtIsQtSignal(void *tx, const char *signal); static void *sipQtCreateUniversalSignalShortcut(void *tx, const char *pysig, const char **sig); static void *sipQtFindUniversalSignalShortcut(void *tx, const char *pysig, const char **sig); static void *sipQtCreateUniversalSignal(void *tx, const sipSignature *psig); static void *sipQtFindUniversalSignal(void *tx, const sipSignature *psig); static int sipQtEmitSignalShortcut(void *tx, const char *sig, PyObject *sigargs); static int sipQtEmitSignal(void *tx, const sipSignature *psig, PyObject *sigargs); static void *sipQtCreateUniversalSlot(sipWrapper *tx, sipSlotConnection *conn, const char **member); static void sipQtDestroyUniversalSlot(void *rx); static void *sipQtFindSlot(void *tx, const char *sig, PyObject *rxObj, const char *slot, const char **member); static int sipQtConnect(void *tx, const char *sig, void *rx, const char *slot, int type); static int sipQtDisconnect(void *tx, const char *sig, void *rx, const char *slot); static int sipQtSignalsBlocked(void *qobj); static const void *sipQtGetSender(); static void sipQtForgetSender(); static int sipQtSameSignalSlotName(const char *s1, const char *s2); static sipSlotConnection *sipQtFindConnection(void *tx, void **context); } // Return a non-zero value if a signal is a Qt signal. static int sipQtIsQtSignal(void *tx, const char *signal) { return (reinterpret_cast(tx)->metaObject()->indexOfSignal(&signal[1]) >= 0); } // Factory function to create a universal signal instance for a Python // shortcircuited signal. Returns a pointer to the instance or 0 if there was // an error. static void *sipQtCreateUniversalSignalShortcut(void *tx, const char *pysig, const char **sig) { // Use an existing one if possible. void *res = sipQtFindUniversalSignalShortcut(tx, pysig, sig); if (!res) { Py_BEGIN_ALLOW_THREADS res = new PyQtProxy(tx, pysig); Py_END_ALLOW_THREADS *sig = SIGNAL(pysignal(const PyQt_PyObject &)); } return res; } // Find an existing universal signal instance for a Python shortcircuited // signal. Returns a pointer to the instance or 0 there wasn't one. static void *sipQtFindUniversalSignalShortcut(void *tx, const char *pysig, const char **sig) { PyQtProxy::ProxyHash::const_iterator it(PyQtProxy::proxy_shortcircuit_signals.find(tx)); while (it != PyQtProxy::proxy_shortcircuit_signals.end() && it.key() == tx) { PyQtProxy *up = it.value(); if (qstrcmp(up->pysig_name, pysig) == 0) { if (sig) *sig = SIGNAL(pysignal(const PyQt_PyObject &)); return up; } ++it; } return 0; } // Factory function to create a universal signal instance. Returns a pointer // to the instance or 0 if there was an error. static void *sipQtCreateUniversalSignal(void *tx, const sipSignature *psig) { // Use an existing one if possible. void *res = sipQtFindUniversalSignal(tx, psig); if (!res) { Py_BEGIN_ALLOW_THREADS res = new PyQtProxy(tx, psig); Py_END_ALLOW_THREADS } return res; } // Find an existing universal signal instance. Returns a pointer // to the instance or 0 if there wasn't one. static void *sipQtFindUniversalSignal(void *tx, const sipSignature *psig) { PyQtProxy::ProxyHash::const_iterator it(PyQtProxy::proxy_signals.find(tx)); while (it != PyQtProxy::proxy_signals.end() && it.key() == tx) { PyQtProxy *up = it.value(); if (up->sig_sig == psig) return up; ++it; } return 0; } // Emit a shortcut signal for any QObject derived instance. Returns 0 if there // was no error. static int sipQtEmitSignalShortcut(void *tx, const char *sig, PyObject *sigargs) { // Find the universal signal shortcut. Unfortunately we can't distinguish // between a Qt name with a typo and an unconnected Python signal - so we // just ignore the emit. PyQtProxy *up = reinterpret_cast(sipQtFindUniversalSignalShortcut(tx, sig, 0)); if (up) { PyQt_PyObject wrapped_args(sigargs); Py_BEGIN_ALLOW_THREADS up->pysignal(wrapped_args); Py_END_ALLOW_THREADS } return 0; } // Emit a signal for any QObject derived instance. Returns 0 if there was no // error. static int sipQtEmitSignal(void *tx, const sipSignature *psig, PyObject *sigargs) { QObject *qtx; const QMetaObject *otxmo; int idx; qtx = reinterpret_cast(tx); otxmo = qtx->metaObject(); // If the signal doesn't exist then see if there is a proxy for it. if ((idx = otxmo->indexOfSignal(&psig->sg_signature[1])) < 0) { PyQtProxy *up = reinterpret_cast(sipQtFindUniversalSignal(tx, psig)); // Unfortunately we can't distinguish between a Qt name with a typo and // an unconnected Python signal - so we just ignore the emit. if (!up) return 0; // Use the proxy instead. qtx = up; idx = up->metaObject()->indexOfSignal(&psig->sg_signature[1]); } // Convert the Python arguments to C++ arguments. This mimics // sipParseArgs(). void **argv = new void *[1 + psig->sg_nrargs]; static void *none = 0; struct value { union { bool b; short sh; unsigned short ush; int i; unsigned ui; long l; unsigned long ul; PY_LONG_LONG ll; unsigned PY_LONG_LONG ull; float f; double d; void *v; } u; int state; }; value *values = new value[psig->sg_nrargs]; argv[0] = 0; for (int a = 0; a < psig->sg_nrargs; ++a) { void *arg = 0; PyObject *pyarg = PyTuple_GET_ITEM(sigargs, a); value *v = &values[a]; PyErr_Clear(); switch (psig->sg_args[a].atype) { case char_sat: case schar_sat: case uchar_sat: if (PyString_Check(pyarg) && PyString_GET_SIZE(pyarg) == 1) arg = PyString_AS_STRING(pyarg); break; case string_sat: case sstring_sat: case ustring_sat: if (pyarg == Py_None) arg = &none; else if (PyString_Check(pyarg)) arg = &PyString_AS_STRING(pyarg); break; case short_sat: v->u.sh = PyInt_AsLong(pyarg); if (!PyErr_Occurred()) arg = &v->u.sh; break; case ushort_sat: v->u.ush = sipLong_AsUnsignedLong(pyarg); if (!PyErr_Occurred()) arg = &v->u.ush; break; case int_sat: v->u.i = PyInt_AsLong(pyarg); if (!PyErr_Occurred()) arg = &v->u.i; break; case uint_sat: v->u.ui = sipLong_AsUnsignedLong(pyarg); if (!PyErr_Occurred()) arg = &v->u.ui; break; case long_sat: v->u.l = PyLong_AsLong(pyarg); if (!PyErr_Occurred()) arg = &v->u.l; break; case ulong_sat: v->u.ul = sipLong_AsUnsignedLong(pyarg); if (!PyErr_Occurred()) arg = &v->u.ul; break; case longlong_sat: v->u.ll = PyLong_AsLongLong(pyarg); if (!PyErr_Occurred()) arg = &v->u.ll; break; case ulonglong_sat: v->u.ull = PyLong_AsUnsignedLongLong(pyarg); if (!PyErr_Occurred()) arg = &v->u.ull; break; case float_sat: v->u.f = PyFloat_AsDouble(pyarg); if (!PyErr_Occurred()) arg = &v->u.f; break; case double_sat: v->u.d = PyFloat_AsDouble(pyarg); if (!PyErr_Occurred()) arg = &v->u.d; break; case enum_sat: if (PyObject_TypeCheck(pyarg, psig->sg_args[a].u.et)) { v->u.i = PyInt_AsLong(pyarg); arg = &v->u.i; } break; case bool_sat: v->u.b = PyInt_AsLong(pyarg); if (!PyErr_Occurred()) arg = &v->u.b; break; case void_sat: v->u.v = sipConvertToVoidPtr(pyarg); if (!PyErr_Occurred()) arg = &v->u.v; break; case class_sat: { int iserr = 0; arg = sipForceConvertToInstance(pyarg, psig->sg_args[a].u.wt, 0, SIP_NOT_NONE, &values[a].state, &iserr); if (iserr) arg = 0; } break; case classp_sat: { int iserr = 0; v->u.v = sipForceConvertToInstance(pyarg, psig->sg_args[a].u.wt, 0, 0, &values[a].state, &iserr); if (!iserr) arg = &v->u.v; } break; case mtype_sat: { int iserr = 0; arg = sipForceConvertToMappedType(pyarg, psig->sg_args[a].u.mt, 0, SIP_NOT_NONE, &values[a].state, &iserr); if (iserr) arg = 0; } break; case mtypep_sat: { int iserr = 0; v->u.v = sipForceConvertToMappedType(pyarg, psig->sg_args[a].u.mt, 0, 0, &values[a].state, &iserr); if (!iserr) arg = &v->u.v; } break; case qvariant_sat: { int iserr = 0; arg = sipForceConvertToInstance(pyarg, sipClass_QVariant, 0, SIP_NOT_NONE, &values[a].state, &iserr); if (iserr) arg = 0; } break; case qvariantp_sat: { int iserr = 0; v->u.v = sipForceConvertToInstance(pyarg, sipClass_QVariant, 0, 0, &values[a].state, &iserr); if (!iserr) arg = &v->u.v; } break; case pyobject_sat: arg = new PyQt_PyObject(pyarg); break; default: // Do nothing. ; } if (!arg) { PyErr_Format(PyExc_TypeError, "argument %d of signal %s.%s has an invalid type", a, otxmo->className(), &psig->sg_signature[1]); delete[] argv; delete[] values; return -1; } argv[1 + a] = arg; } Py_BEGIN_ALLOW_THREADS QMetaObject::activate(qtx, idx, idx, argv); Py_END_ALLOW_THREADS // Delete any temporary instances. for (int a = 0; a < psig->sg_nrargs; ++a) { value *v = &values[a]; switch (psig->sg_args[a].atype) { case class_sat: sipReleaseInstance(argv[1 + a], psig->sg_args[a].u.wt, v->state); break; case classp_sat: sipReleaseInstance(v->u.v, psig->sg_args[a].u.wt, v->state); break; case mtype_sat: sipReleaseMappedType(argv[1 + a], psig->sg_args[a].u.mt, v->state); break; case mtypep_sat: sipReleaseMappedType(v->u.v, psig->sg_args[a].u.mt, v->state); break; case qvariant_sat: sipReleaseInstance(argv[1 + a], sipClass_QVariant, v->state); break; case qvariantp_sat: sipReleaseInstance(v->u.v, sipClass_QVariant, v->state); break; case pyobject_sat: delete (PyQt_PyObject *)argv[1 + a]; break; default: ; } } delete[] argv; delete[] values; return 0; } // Factory function to create a universal slot instance. Returns a pointer to // the instance or 0 if there was an error. static void *sipQtCreateUniversalSlot(sipWrapper *tx, sipSlotConnection *conn, const char **member) { QObject *qtx = 0; // See if the transmitter is a QObject in which case we will connect to // it's destroyed signal so that the proxy can be destroyed at the same // time. (Note that we used to do this by making the proxy a child of the // transmitter. This doesn't work as expected because QWidget destroys its // children before emitting the destroyed signal.) if (tx && PyObject_TypeCheck(tx, (PyTypeObject *)sipClass_QObject)) qtx = reinterpret_cast(conn->sc_transmitter); // Get the receiver C++ QObject if there is one. QObject *qrx = 0; if (!conn->sc_slot.pyobj) { int iserr = 0; void *rx = sipForceConvertToInstance(conn->sc_slot.meth.mself, sipClass_QObject, 0, SIP_NOT_NONE|SIP_NO_CONVERTORS, 0, &iserr); if (iserr) PyErr_Clear(); else qrx = reinterpret_cast(rx); } QObject *res; Py_BEGIN_ALLOW_THREADS res = new PyQtProxy(qtx, conn, member); // If the receiver is a QObject then move the proxy to the same thread. if (qrx) res->moveToThread(qrx->thread()); Py_END_ALLOW_THREADS return res; } // Dispose of a receiver that might be a universal slot. static void sipQtDestroyUniversalSlot(void *rx) { Py_BEGIN_ALLOW_THREADS PyQtProxy::mutex->lock(); PyQtProxy::ProxyHash::const_iterator it(PyQtProxy::proxy_slots.begin()); while (it != PyQtProxy::proxy_slots.end()) { PyQtProxy *up = it.value(); if (up == reinterpret_cast(rx)) { up->disable(); break; } ++it; } PyQtProxy::mutex->unlock(); Py_END_ALLOW_THREADS } // Search for the universal slot connected to a particular Qt signal. static void *sipQtFindSlot(void *tx, const char *sig, PyObject *rxObj, const char *slot, const char **member) { PyQtProxy *proxy = 0; PyQtProxy::mutex->lock(); PyQtProxy::ProxyHash::const_iterator it(PyQtProxy::proxy_slots.find(tx)); while (it != PyQtProxy::proxy_slots.end() && it.key() == tx) { PyQtProxy *up = it.value(); if (sipSameConnection(&up->slot_conn, tx, sig, rxObj, slot)) { *member = SLOT(unislot()); proxy = up; break; } ++it; } PyQtProxy::mutex->unlock(); return proxy; } // Connect a Qt signal to a Qt slot. static int sipQtConnect(void *tx, const char *sig, void *rx, const char *slot, int type) { // Unlike Qt3, Qt4 does not check that the signal and slot arguments are // compatible in a release build. I think this is a bug, so we do the // missing check here. #if defined(QT_NO_DEBUG) if (!QMetaObject::checkConnectArgs(sig, slot)) return 0; #endif int res; Py_BEGIN_ALLOW_THREADS res = QObject::connect(reinterpret_cast(tx), sig, reinterpret_cast(rx), slot, (Qt::ConnectionType)type); Py_END_ALLOW_THREADS return res; } // Disconnect a Qt signal from a Qt slot. static int sipQtDisconnect(void *tx, const char *sig, void *rx, const char *slot) { int res; Py_BEGIN_ALLOW_THREADS res = QObject::disconnect(reinterpret_cast(tx), sig, reinterpret_cast(rx), slot); Py_END_ALLOW_THREADS return res; } // See if signals are currently blocked for a QObject. static int sipQtSignalsBlocked(void *qobj) { return reinterpret_cast(qobj)->signalsBlocked(); } // Get the last sender for QObject::sender(). static const void *sipQtGetSender() { return PyQtProxy::lastSender; } // Forget the last sender. static void sipQtForgetSender() { PyQtProxy::lastSender = 0; } // See if two signal or slot names are the same. static int sipQtSameSignalSlotName(const char *s1, const char *s2) { // Signal and slot names are always normalised so a simple string // comparison will do. return (qstrcmp(s1, s2) == 0); } // Return the next connection for a particular transmitter. This will be // called with the GIL locked. static sipSlotConnection *sipQtFindConnection(void *tx, void **context) { PyQtProxy::ProxyHash::const_iterator it; PyQtProxy::ProxyHash::const_iterator *itp = *reinterpret_cast(context); // Use the existing context if there is one, otherwise initialise a new // one. if (itp) it = *itp; else { it = PyQtProxy::proxy_slots.find(tx); itp = new PyQtProxy::ProxyHash::const_iterator(it); *context = itp; } while (it != PyQtProxy::proxy_slots.end() && it.key() == tx) { PyQtProxy *up = it++.value(); if (!up->deleting) { // Save the current context. *itp = it; return &up->slot_conn; } } // Discard the context as it is no longer needed. delete itp; *context = 0; return 0; } // This defines the structure of a PyQt property. typedef struct { PyObject_HEAD // The following members must match the propertyobject structure defined in // Objects/descrobject.c of the Python source because we choose to // sub-class from the standard Python property (even though Python doesn't // publish this structure). Alternatively we could implement pyqtProperty // as a completely unrelated type that supported the descriptor protocol in // the same way. PyObject *prop_get; PyObject *prop_set; PyObject *prop_del; PyObject *prop_doc; // The freset callable. PyObject *pyqtprop_reset; // The C++ type as a string. PyObject *pyqtprop_type; // The type of the C++ type as known by QVariant. QVariant::Type pyqtprop_vtype; // The type of the C++ type as known by QMetaType. int pyqtprop_mtype; // The type of the C++ type as known by SIP. At the moment this will // either refer to a class or an enum (and so its type could be // PyTypeObject *) but we may allow mapped types in the future. void *pyqtprop_pytype; // This is the address of the last (possibly temporary) C++ class instance // returned by the getter for use by a future call to sipReleaseInstance(). void *pyqtprop_getter_tmp; // This is the state of the last (possibly temporary) C++ class instance // returned by the getter for use by a future call to sipReleaseInstance(). int pyqtprop_getter_tmpstate; // This is a reference to the last (possibly temporary) C++ class instance // returned by the getter in case it wasn't temporary but would otherwise // be garbage collected when we discard the result of the getter. An // alternative might be to use QMetaType::construct() to create a copy, // however I don't know if that would mean the copy would leak. PyObject *pyqtprop_getter_obj; } qtcore_pyqtpropertyobject; PyDoc_STRVAR(qtcore_pyqtproperty_doc, "pyqtProperty(type, fget=None, fset=None, freset=None, fdel=None, doc=None) -> property attribute\n" "\n" "type is the name of a C++ type that be passed to QVariant.nameToType().\n" "freset is a function for resetting an attribute to its default value.\n" "The other parameters are the same as those required by the standard Python\n" "property type. Properties defined using pyqtProperty behave as both Python\n" "and Qt properties."); // The pyqtProperty dealloc function. extern "C" {static void qtcore_pyqtproperty_dealloc(PyObject *self);} static void qtcore_pyqtproperty_dealloc(PyObject *self) { qtcore_pyqtpropertyobject *pp = (qtcore_pyqtpropertyobject *)self; Py_XDECREF(pp->pyqtprop_reset); // The init can fail before this is initialised. Py_XDECREF(pp->pyqtprop_type); // Release any getter result. if (pp->pyqtprop_getter_tmp) { sipReleaseInstance(pp->pyqtprop_getter_tmp, reinterpret_cast(pp->pyqtprop_pytype), pp->pyqtprop_getter_tmpstate); Py_DECREF(pp->pyqtprop_getter_obj); } PyProperty_Type.tp_dealloc(self); } // The pyqtProperty traverse function. extern "C" {static int qtcore_pyqtproperty_traverse(PyObject *self, visitproc visit, void *arg);} static int qtcore_pyqtproperty_traverse(PyObject *self, visitproc visit, void *arg) { qtcore_pyqtpropertyobject *pp = (qtcore_pyqtpropertyobject *)self; int vret; if (pp->pyqtprop_reset) { vret = visit(pp->pyqtprop_reset, arg); if (vret != 0) return vret; } if (pp->pyqtprop_type) { vret = visit(pp->pyqtprop_type, arg); if (vret != 0) return vret; } return PyProperty_Type.tp_traverse(self, visit, arg); } // The pyqtProperty init function. extern "C" {static int qtcore_pyqtproperty_init(PyObject *self, PyObject *args, PyObject *kwds);} static int qtcore_pyqtproperty_init(PyObject *self, PyObject *args, PyObject *kwds) { PyObject *type, *get = 0, *set = 0, *reset = 0, *del = 0, *doc = 0; static char *kwlist[] = {"type", "fget", "fset", "freset", "fdel", "doc", 0}; qtcore_pyqtpropertyobject *pp = (qtcore_pyqtpropertyobject *)self; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|OOOOO:pyqtProperty", kwlist, &PyString_Type, &type, &get, &set, &reset, &del, &doc)) return -1; const char *type_name = PyString_AS_STRING(type); // Check the type is valid and get the type object for the type if there is // one. pp->pyqtprop_vtype = QVariant::nameToType(type_name); bool unknown_type = false; // Remember the name if the type is external. const char *external_name = 0; // Assume that the QMetaType::Type is the same as the QVariant::Type. pp->pyqtprop_mtype = (int)pp->pyqtprop_vtype; switch (pp->pyqtprop_vtype) { case QVariant::Invalid: // See if it is an enum. pp->pyqtprop_pytype = sipFindNamedEnum(type_name); if (!pp->pyqtprop_pytype) unknown_type = true; break; case QVariant::UserType: { // See if it is a flag type (which will have been registered and so // appears as a user type). sipWrapperType *wt = sipFindClass(type_name); if (wt && (sipTypeFlags(wt) & 0x1)) { pp->pyqtprop_pytype = wt; pp->pyqtprop_mtype = QMetaType::type(type_name); } else unknown_type = true; break; } case QVariant::BitArray: pp->pyqtprop_pytype = sipClass_QBitArray; break; case QVariant::Bitmap: pp->pyqtprop_pytype = sipClass_QBitmap; external_name = sipName_QBitmap; break; case QVariant::Brush: pp->pyqtprop_pytype = sipClass_QBrush; external_name = sipName_QBrush; break; case QVariant::ByteArray: pp->pyqtprop_pytype = sipClass_QByteArray; break; case QVariant::Char: pp->pyqtprop_pytype = sipClass_QChar; break; case QVariant::Color: pp->pyqtprop_pytype = sipClass_QColor; external_name = sipName_QColor; break; case QVariant::Cursor: pp->pyqtprop_pytype = sipClass_QCursor; external_name = sipName_QCursor; break; case QVariant::Date: pp->pyqtprop_pytype = sipClass_QDate; break; case QVariant::DateTime: pp->pyqtprop_pytype = sipClass_QDateTime; break; case QVariant::Font: pp->pyqtprop_pytype = sipClass_QFont; external_name = sipName_QFont; break; case QVariant::Icon: pp->pyqtprop_pytype = sipClass_QIcon; external_name = sipName_QIcon; break; case QVariant::Image: pp->pyqtprop_pytype = sipClass_QImage; external_name = sipName_QImage; break; case QVariant::KeySequence: pp->pyqtprop_pytype = sipClass_QKeySequence; external_name = sipName_QKeySequence; break; case QVariant::Line: pp->pyqtprop_pytype = sipClass_QLine; break; case QVariant::LineF: pp->pyqtprop_pytype = sipClass_QLineF; break; case QVariant::Locale: pp->pyqtprop_pytype = sipClass_QLocale; break; #if QT_VERSION >= 0x040200 case QVariant::Matrix: pp->pyqtprop_pytype = sipClass_QMatrix; external_name = sipName_QMatrix; break; #endif case QVariant::Palette: pp->pyqtprop_pytype = sipClass_QPalette; external_name = sipName_QPalette; break; case QVariant::Pen: pp->pyqtprop_pytype = sipClass_QPen; external_name = sipName_QPen; break; case QVariant::Pixmap: pp->pyqtprop_pytype = sipClass_QPixmap; external_name = sipName_QPixmap; break; case QVariant::Point: pp->pyqtprop_pytype = sipClass_QPoint; break; case QVariant::PointF: pp->pyqtprop_pytype = sipClass_QPointF; break; case QVariant::Polygon: pp->pyqtprop_pytype = sipClass_QPolygon; external_name = sipName_QPolygon; break; case QVariant::Rect: pp->pyqtprop_pytype = sipClass_QRect; break; case QVariant::RectF: pp->pyqtprop_pytype = sipClass_QRectF; break; case QVariant::RegExp: pp->pyqtprop_pytype = sipClass_QRegExp; break; case QVariant::Region: pp->pyqtprop_pytype = sipClass_QRegion; external_name = sipName_QRegion; break; case QVariant::Size: pp->pyqtprop_pytype = sipClass_QSize; break; case QVariant::SizeF: pp->pyqtprop_pytype = sipClass_QSizeF; break; case QVariant::SizePolicy: pp->pyqtprop_pytype = sipClass_QSizePolicy; external_name = sipName_QSizePolicy; break; case QVariant::String: pp->pyqtprop_pytype = sipClass_QString; break; case QVariant::StringList: pp->pyqtprop_pytype = sipClass_QStringList; break; case QVariant::TextFormat: pp->pyqtprop_pytype = sipClass_QTextFormat; external_name = sipName_QTextFormat; break; case QVariant::TextLength: pp->pyqtprop_pytype = sipClass_QTextLength; external_name = sipName_QTextLength; break; case QVariant::Time: pp->pyqtprop_pytype = sipClass_QTime; break; #if QT_VERSION >= 0x040300 case QVariant::Transform: pp->pyqtprop_pytype = sipClass_QTransform; external_name = sipName_QTransform; break; #endif case QVariant::Url: pp->pyqtprop_pytype = sipClass_QUrl; break; case QVariant::Int: case QVariant::UInt: case QVariant::Bool: case QVariant::Double: case QVariant::LongLong: case QVariant::ULongLong: break; default: unknown_type = true; } if (unknown_type) { PyErr_Format(PyExc_TypeError, "type '%s' is not supported as a property type", type_name); return -1; } // Check that we have the wrapper type if it is external. if (external_name && !pp->pyqtprop_pytype) { PyErr_Format(PyExc_TypeError, "type '%s' is defined in a module that has not been imported", external_name); return -1; } Py_INCREF(type); pp->pyqtprop_type = type; if (get == Py_None) get = 0; if (set == Py_None) set = 0; if (del == Py_None) del = 0; if (reset == Py_None) reset = 0; Py_XINCREF(get); Py_XINCREF(set); Py_XINCREF(del); Py_XINCREF(doc); Py_XINCREF(reset); /* If no docstring was given and the getter has one, then use it. */ if ((!doc || doc == Py_None) && get) { PyObject *get_doc = PyObject_GetAttrString(get, "__doc__"); if (get_doc) { Py_XDECREF(doc); doc = get_doc; } else PyErr_Clear(); } pp->prop_get = get; pp->prop_set = set; pp->prop_del = del; pp->prop_doc = doc; pp->pyqtprop_reset = reset; return 0; } // Define the attributes. #include static PyMemberDef qtcore_pyqtproperty_members[] = { {"freset", T_OBJECT, offsetof(qtcore_pyqtpropertyobject, pyqtprop_reset), READONLY, 0}, {"type", T_OBJECT, offsetof(qtcore_pyqtpropertyobject, pyqtprop_type), READONLY, 0}, {0, 0, 0, 0, 0} }; // This implements the PyQt version of the standard Python property type. PyTypeObject qtcore_pyqtProperty_Type = { PyObject_HEAD_INIT(NULL) 0, "PyQt4.QtCore.pyqtProperty", sizeof (qtcore_pyqtpropertyobject), 0, qtcore_pyqtproperty_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE, qtcore_pyqtproperty_doc, qtcore_pyqtproperty_traverse, 0, 0, 0, 0, 0, 0, qtcore_pyqtproperty_members, 0, 0, 0, 0, 0, 0, qtcore_pyqtproperty_init, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; // This is the decorator function that saves the C++ signature as a function // attribute. extern "C" {static PyObject *qtcore_pyqtSignature(PyObject *self, PyObject *f);} static PyObject *qtcore_pyqtSignature(PyObject *self, PyObject *f) { QByteArray sig = QMetaObject::normalizedSignature(PyString_AS_STRING(self)); // See if the signature contains a method name. if (!sig.contains('(')) { // Add the parenthesis. sig.prepend('('); sig.append(')'); // Use the function's name. PyObject *nobj = PyObject_GetAttr(f, qtcore_name_attr); if (!nobj) return 0; if (PyString_Check(nobj)) sig.prepend(PyString_AS_STRING(nobj)); Py_DECREF(nobj); } PyObject *sig_obj = PyString_FromString(sig.constData()); if (!sig_obj) return 0; // Save the signature as an attribute. if (PyObject_SetAttr(f, qtcore_signature_attr, sig_obj) < 0) { Py_DECREF(sig_obj); return 0; } Py_DECREF(sig_obj); // Return the function. Py_INCREF(f); return f; } // This is a helper for QObject.receivers() that returns the number of // receivers for an object if it is a signal proxy. It is exported because // QObject::receivers() is protected. static int qtcore_receivers(const QObject *obj, const char *signal) { if (qstrcmp(obj->metaObject()->className(), "PyQtProxy") != 0) return 0; return static_cast(obj)->getReceivers(signal); } // This is the data held to support dynamic meta-objects. It is effectively // an extension to the sipWrapperType structure. struct qtcore_qobject { // The meta-object istself. QMetaObject mo; // The meta-object string data. QByteArray str_data; // The list of properties. QList pprops; // The list of slots. QList pslots; // The number of signals. int nr_signals; }; // Add the (non-existent) argument names for a signature and return their index // in the meta-object string data. static int qtcore_add_arg_names(qtcore_qobject *qo, const char *sig, int empty) { int anames = -1; for (const char *com = sig; *com != '\0'; ++com) if (*com == ',') { if (anames < 0) anames = qo->str_data.size(); qo->str_data.append(','); } if (anames < 0) anames = empty; else qo->str_data.append('\0'); return anames; } // This does the real work for all implementations of metaObject(). static const QMetaObject *qtcore_qt_metaobject_worker(PyTypeObject *pytype, sipWrapperType *base, const QMetaObject *base_mo) { sipWrapperType *wt = (sipWrapperType *)pytype; // See if this is a wrapped C++ type rather than a Python sub-type. if (wt == base) return base_mo; // See if it has already been set up. if (wt->qt_qobject) return &reinterpret_cast(wt->qt_qobject)->mo; // Create a new QMetaObject by introspecting the Python type. qtcore_qobject *qo = new qtcore_qobject; qo->mo.d.superdata = qtcore_qt_metaobject_worker(pytype->tp_base, base, base_mo); qo->mo.d.extradata = 0; SIP_BLOCK_THREADS // Get the base name of the class. QByteArray full_cname(pytype->tp_name); int i = full_cname.lastIndexOf('.'); if (i < 0) qo->str_data = full_cname; else qo->str_data = full_cname.mid(i + 1); qo->str_data.append('\0'); // Go through the class dictionary getting all PyQt properties, slots (ie. // anything with a PyQt signature) or a sequence of signals. typedef QPair prop_data; QList pprops; SIP_SSIZE_T pos = 0; PyObject *key, *value, *psignals = 0; qo->nr_signals = 0; while (PyDict_Next(pytype->tp_dict, &pos, &key, &value)) { // See if it a slot. PyObject *sobj = PyObject_GetAttr(value, qtcore_signature_attr); if (sobj) { // Sanity check. if (!PyString_Check(sobj)) { Py_DECREF(sobj); continue; } // Set up the skeleton connection. sipSlotConnection conn; conn.sc_signature = sipParseSignature(PyString_AS_STRING(sobj)); Py_DECREF(sobj); if (!conn.sc_signature) continue; conn.sc_transmitter = 0; conn.sc_slot.pyobj = 0; conn.sc_slot.name = 0; conn.sc_slot.meth.mfunc = value; conn.sc_slot.meth.mself = 0; conn.sc_slot.meth.mclass = (PyObject *)pytype; conn.sc_slot.weakSlot = 0; qo->pslots.append(conn); } else { PyErr_Clear(); // Sanity check that the key is a string. if (!PyString_Check(key)) continue; // See if it is a property. if (PyType_IsSubtype(value->ob_type, &qtcore_pyqtProperty_Type)) { Py_INCREF(key); Py_INCREF(value); pprops.append(prop_data(key, value)); } else if (!psignals) { // See if it is a sequence of signal signatures. if (qstrcmp(PyString_AS_STRING(key), "__pyqtSignals__") == 0) { psignals = value; // See how many signals there are. SIP_SSIZE_T sz = PySequence_Size(psignals); if (sz >= 0) qo->nr_signals = sz; } } } } // Initialise the start section of the data table. int data_len = 11 + qo->nr_signals * 5 + qo->pslots.count() * 5 + pprops.count() * 3; uint *data = new uint[data_len]; int g_offset = 10; int s_offset = g_offset + qo->nr_signals *5; int p_offset = s_offset + qo->pslots.count() * 5; int empty = 0; for (int i = 0; i < data_len; ++i) data[i] = 0; data[0] = 1; if (qo->nr_signals || qo->pslots.count()) { data[4] = qo->nr_signals + qo->pslots.count(); data[5] = g_offset; empty = qo->str_data.size(); qo->str_data.append('\0'); } data[6] = pprops.count(); data[7] = p_offset; // Add the signals to the meta-object. for (int g = 0; g < qo->nr_signals; ++g) { PyObject *sobj = PySequence_ITEM(psignals, g); const char *sig = PyString_AsString(sobj); // Sanity check. if (!sig) sig = "invalid()"; QByteArray norm = QMetaObject::normalizedSignature(sig); Py_DECREF(sobj); // Add the (non-existent) argument names. data[g_offset + (g * 5) + 1] = qtcore_add_arg_names(qo, norm.constData(), empty); // Add the full signature. data[g_offset + (g * 5) + 0] = qo->str_data.size(); qo->str_data.append(norm); qo->str_data.append('\0'); // Add the type, tag and flags. data[g_offset + (g * 5) + 2] = empty; data[g_offset + (g * 5) + 3] = empty; data[g_offset + (g * 5) + 4] = 0x05; } // Add the slots to the meta-object. for (int s = 0; s < qo->pslots.count(); ++s) { const sipSlotConnection &conn = qo->pslots.at(s); const char *sig = conn.sc_signature->sg_signature; // Add the (non-existent) argument names. data[s_offset + (s * 5) + 1] = qtcore_add_arg_names(qo, sig, empty); // Add the full signature. data[s_offset + (s * 5) + 0] = qo->str_data.size(); qo->str_data.append(sig); qo->str_data.append('\0'); // Add the type, tag and flags. data[s_offset + (s * 5) + 2] = empty; data[s_offset + (s * 5) + 3] = empty; data[s_offset + (s * 5) + 4] = 0x0a; } // Add the properties to the meta-object. for (int p = 0; p < pprops.count(); ++p) { const prop_data &pprop = pprops.at(p); qtcore_pyqtpropertyobject *pp = (qtcore_pyqtpropertyobject *)pprop.second; // Add the property name. data[p_offset + (p * 3) + 0] = qo->str_data.size(); qo->str_data.append(PyString_AS_STRING(pprop.first)); qo->str_data.append('\0'); Py_DECREF(pprop.first); // Add the name of the property type. data[p_offset + (p * 3) + 1] = qo->str_data.size(); qo->str_data.append(PyString_AS_STRING(pp->pyqtprop_type)); qo->str_data.append('\0'); // Add the property flags. uint flags = 0; // Designable. flags |= 0x00001000; // Stored. flags |= 0x00010000; if (pp->pyqtprop_vtype == QVariant::Invalid || pp->pyqtprop_vtype == QVariant::UserType) // Enum or flag. flags |= 0x00000008; if (pp->prop_get && PyCallable_Check(pp->prop_get)) // Readable. flags |= 0x00000001; if (pp->prop_set && PyCallable_Check(pp->prop_set)) { // Writable. flags |= 0x00000002; // See if the name of the setter starts with "set". If so tell // the UI compilers not to use setProperty(). PyObject *nobj = PyObject_GetAttr(pp->prop_set, qtcore_name_attr); if (nobj) { if (PyString_Check(nobj)) { const char *name = PyString_AS_STRING(nobj); if (qstrlen(name) > 3 && name[0] == 's' && name[1] == 'e' && name[2] == 't') flags |= 0x00000100; } Py_DECREF(nobj); } else PyErr_Clear(); } if (pp->pyqtprop_reset && PyCallable_Check(pp->pyqtprop_reset)) // Resetable. flags |= 0x00000004; flags |= pp->pyqtprop_vtype << 24; data[p_offset + (p * 3) + 2] = flags; // Save the property data for qt_metacall(). (We already have a // reference.) qo->pprops.append(pp); } // Initialise the rest of the meta-object. qo->mo.d.stringdata = qo->str_data.constData(); qo->mo.d.data = data; // Save the meta-object data. Note that it leaks if the type is deleted. wt->qt_qobject = qo; SIP_UNBLOCK_THREADS return &qo->mo; } // This is the helper for all implementations of metaObject(). static const QMetaObject *qtcore_qt_metaobject(sipWrapper *pySelf, sipWrapperType *base, const QMetaObject *base_mo) { if (!pySelf) return base_mo; return qtcore_qt_metaobject_worker(pySelf->ob_type, base, base_mo); } // This does the real work for all implementations of qt_metacall(). static int qtcore_qt_metacall_worker(sipWrapper *pySelf, PyTypeObject *pytype, sipWrapperType *base, QMetaObject::Call _c, int _id, void **_a) { sipWrapperType *wt = (sipWrapperType *)pytype; // See if this is a wrapped C++ type rather than a Python sub-type. if (wt == base) return _id; _id = qtcore_qt_metacall_worker(pySelf, pytype->tp_base, base, _c, _id, _a); if (_id < 0) return _id; qtcore_qobject *qo = reinterpret_cast(wt->qt_qobject); bool ok = true; if (_c == QMetaObject::InvokeMetaMethod) { if (_id < qo->nr_signals + qo->pslots.count()) { if (_id < qo->nr_signals) { QObject *qthis = reinterpret_cast(sipGetCppPtr(pySelf, sipClass_QObject)); Py_BEGIN_ALLOW_THREADS QMetaObject::activate(qthis, &qo->mo, _id, _a); Py_END_ALLOW_THREADS } else { sipSlotConnection conn = qo->pslots.at(_id - qo->nr_signals); // Set up the instance specific parts. conn.sc_slot.meth.mself = (PyObject *)pySelf; if (!PyQtProxy::invokeSlot(conn, _a)) ok = false; } } _id -= qo->nr_signals + qo->pslots.count(); } else if (_c == QMetaObject::ReadProperty) { if (_id < qo->pprops.count()) { qtcore_pyqtpropertyobject *prop = qo->pprops.at(_id); if (prop->prop_get) { PyObject *py = PyObject_CallFunction(prop->prop_get, "O", pySelf); if (!py) ok = false; else { void *cpp = _a[0]; switch (prop->pyqtprop_vtype) { case QVariant::Invalid: case QVariant::Int: *reinterpret_cast(cpp) = int(PyInt_AsLong(py)); if (PyErr_Occurred()) ok = false; break; case QVariant::UInt: *reinterpret_cast(cpp) = static_cast(PyInt_AsLong(py)); if (PyErr_Occurred()) ok = false; break; case QVariant::Bool: *reinterpret_cast(cpp) = bool(PyInt_AsLong(py)); if (PyErr_Occurred()) ok = false; break; case QVariant::Double: *reinterpret_cast(cpp) = PyFloat_AsDouble(py); if (PyErr_Occurred()) ok = false; break; case QVariant::LongLong: *reinterpret_cast(cpp) = static_cast(PyLong_AsLongLong(py)); if (PyErr_Occurred()) ok = false; break; case QVariant::ULongLong: *reinterpret_cast(cpp) = static_cast(PyLong_AsUnsignedLongLong(py)); if (PyErr_Occurred()) ok = false; break; default: { sipWrapperType *wt = reinterpret_cast(prop->pyqtprop_pytype); // Release any previous getter result. if (prop->pyqtprop_getter_tmp) { sipReleaseInstance(prop->pyqtprop_getter_tmp, wt, prop->pyqtprop_getter_tmpstate); Py_DECREF(prop->pyqtprop_getter_obj); } int iserr = 0; prop->pyqtprop_getter_tmp = sipForceConvertToInstance(py, wt, 0, SIP_NOT_NONE, &prop->pyqtprop_getter_tmpstate, &iserr); if (iserr) ok = false; else { prop->pyqtprop_getter_obj = py; Py_INCREF(prop->pyqtprop_getter_obj); _a[0] = prop->pyqtprop_getter_tmp; } } } Py_DECREF(py); } } } _id -= qo->pprops.count(); } else if (_c == QMetaObject::WriteProperty) { if (_id < qo->pprops.count()) { qtcore_pyqtpropertyobject *prop = qo->pprops.at(_id); if (prop->prop_set) { void *cpp = _a[0]; PyObject *py; switch (prop->pyqtprop_vtype) { case QVariant::Invalid: py = sipConvertFromNamedEnum(*(int *)cpp, reinterpret_cast(prop->pyqtprop_pytype)); break; case QVariant::Int: py = PyInt_FromLong(long(*(int *)cpp)); break; case QVariant::UInt: py = PyInt_FromLong(long(*(int *)cpp)); break; case QVariant::Bool: py = PyBool_FromLong(long(*(bool *)cpp)); break; case QVariant::Double: py = PyFloat_FromDouble(*(double *)cpp); break; case QVariant::LongLong: py = PyLong_FromLongLong((PY_LONG_LONG)*(long long *)cpp); break; case QVariant::ULongLong: py = PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)*(unsigned long long *)cpp); break; default: void *copy = QMetaType::construct(prop->pyqtprop_mtype, cpp); py = sipConvertFromNewInstance(copy, reinterpret_cast(prop->pyqtprop_pytype), 0); } if (!py) ok = false; else { PyObject *res = PyObject_CallFunction(prop->prop_set, "OO", pySelf, py); if (!res) ok = false; else Py_DECREF(res); Py_DECREF(py); } } } _id -= qo->pprops.count(); } else if (_c == QMetaObject::ResetProperty) { if (_id < qo->pprops.count()) { qtcore_pyqtpropertyobject *prop = qo->pprops.at(_id); if (prop->pyqtprop_reset) { PyObject *py = PyObject_CallFunction(prop->pyqtprop_reset, "O", pySelf); if (!py) ok = false; else Py_DECREF(py); } } _id -= qo->pprops.count(); } else if (_c == QMetaObject::QueryPropertyDesignable) _id -= qo->pprops.count(); else if (_c == QMetaObject::QueryPropertyScriptable) _id -= qo->pprops.count(); else if (_c == QMetaObject::QueryPropertyStored) _id -= qo->pprops.count(); else if (_c == QMetaObject::QueryPropertyEditable) _id -= qo->pprops.count(); else if (_c == QMetaObject::QueryPropertyUser) _id -= qo->pprops.count(); // Handle any Python errors. if (!ok) { PyErr_Print(); return -1; } return _id; } // This is the helper for all implementations of qt_metacall(). static int qtcore_qt_metacall(sipWrapper *pySelf, sipWrapperType *base, QMetaObject::Call _c, int _id, void **_a) { // Check if the Python object has gone. if (!pySelf) return -1; return qtcore_qt_metacall_worker(pySelf, pySelf->ob_type, base, _c, _id, _a); } %End %PostInitialisationCode // Initialise the pyqtProperty type and add it to the module dictionary. qtcore_pyqtProperty_Type.tp_base = &PyProperty_Type; if (PyType_Ready(&qtcore_pyqtProperty_Type) < 0) Py_FatalError("PyQt4.QtCore: Failed to initialise pyqtProperty type"); if (PyDict_SetItemString(sipModuleDict, "pyqtProperty", (PyObject *)&qtcore_pyqtProperty_Type) < 0) Py_FatalError("PyQt4.QtCore: Failed to set pyqtProperty type"); // Register the type that wraps Python objects when emitted asynchronously. qRegisterMetaType("PyQt_PyObject"); // Export the QObject.receivers() helper. sipExportSymbol("qtcore_receivers", (void *)qtcore_receivers); // Export the QMetaObject helpers. sipExportSymbol("qtcore_qt_metaobject", (void *)qtcore_qt_metaobject); sipExportSymbol("qtcore_qt_metacall", (void *)qtcore_qt_metacall); // Objectify some strings. qtcore_signature_attr = PyString_FromString("__pyqtSignature__"); if (!qtcore_signature_attr) Py_FatalError("PyQt4.QtCore: Failed to objectify '__pyqtSignature__'"); qtcore_name_attr = PyString_FromString("__name__"); if (!qtcore_name_attr) Py_FatalError("PyQt4.QtCore: Failed to objectify '__name__'"); // Create the mutex that serialises access to the signal/slot proxies. We // don't use a statically initialised one because Qt needs some things to be // initialised first (at least for Windows) and this is the only way to // guarantee things are done in the right order. PyQtProxy::mutex = new QMutex(QMutex::Recursive); %End