aboutsummaryrefslogtreecommitdiffstats
path: root/libpyside/signalmanager.cpp
diff options
context:
space:
mode:
authorHugo Lima <hugo.lima@openbossa.org>2009-12-29 17:04:56 -0200
committerHugo Lima <hugo.lima@openbossa.org>2010-01-04 15:48:36 -0200
commit85048bbd6c5d4231f71852cab18fd581c5068141 (patch)
treef1a1b38b04e748c0c50825d51d38c7dafe7ee60e /libpyside/signalmanager.cpp
parente8e1ecc260028d045efcbc3c71d7a50009950f5b (diff)
Fixes problems calling dynamic python slots.
Reviewed by Marcelo Lira <marcelo.lira@openbossa.org>
Diffstat (limited to 'libpyside/signalmanager.cpp')
-rw-r--r--libpyside/signalmanager.cpp144
1 files changed, 99 insertions, 45 deletions
diff --git a/libpyside/signalmanager.cpp b/libpyside/signalmanager.cpp
index a222e0371..c8b55e77f 100644
--- a/libpyside/signalmanager.cpp
+++ b/libpyside/signalmanager.cpp
@@ -65,44 +65,75 @@ bool PySide::checkSignal(const char* signal)
return true;
}
-QString PySide::getCallbackSignature(const char* signal, PyObject* callback)
+static QString codeCallbackName(PyObject* callback, const QString& funcName)
{
- PyObject* function;
- int useSelf = PyMethod_Check(callback);
- if (useSelf) {
- function = PyMethod_GET_FUNCTION(callback);
- } else {
- function = callback;
+ return funcName+QString::number(quint64(callback), 16);
+}
+
+QString PySide::getCallbackSignature(const char* signal, PyObject* callback, bool encodeName)
+{
+ QString functionName;
+ int numArgs = -1;
+ bool useSelf = false;
+
+ bool isMethod = PyMethod_Check(callback);
+ bool isFunction = PyFunction_Check(callback);
+
+ if (isMethod || isFunction) {
+ PyObject* function = isMethod ? PyMethod_GET_FUNCTION(callback) : callback;
+ PyCodeObject* objCode = reinterpret_cast<PyCodeObject*>(PyFunction_GET_CODE(function));
+ functionName = PyString_AS_STRING(objCode->co_name);
+ useSelf = isMethod;
+ numArgs = objCode->co_flags & CO_VARARGS ? -1 : objCode->co_argcount;
+ } else if (PyCFunction_Check(callback)) {
+ functionName = ((PyCFunctionObject*)callback)->m_ml->ml_name;
+ useSelf = ((PyCFunctionObject*)callback)->m_self;
+ int flags = ((PyCFunctionObject*)callback)->m_ml->ml_flags;
+ if (flags & METH_O)
+ numArgs = 1;
+ else if (flags & METH_VARARGS)
+ numArgs = -1;
+ else if (flags & METH_NOARGS)
+ numArgs = 0;
}
+ Q_ASSERT(!functionName.isEmpty());
+
+ QString signature;
+ if (encodeName)
+ signature = codeCallbackName(callback, functionName);
+ else
+ signature = functionName;
- PyCodeObject* objCode = reinterpret_cast<PyCodeObject*>(PyFunction_GET_CODE(function));
- QString signature(PyString_AS_STRING(objCode->co_name));
- signature.append(QString::number(quint64(callback), 16));
- signature.append('(');
- int numArgs = objCode->co_flags & CO_VARARGS ? -1 : objCode->co_argcount;
-
- QStringList args = getArgsFromSignature(signal);
- if (numArgs == -1)
- numArgs = std::numeric_limits<int>::max();
- while (args.count() > numArgs - useSelf) {
- args.removeLast();
+ bool isShortCircuit;
+ QStringList args = getArgsFromSignature(signal, &isShortCircuit);
+
+ if (!isShortCircuit) {
+ signature.append('(');
+ if (numArgs == -1)
+ numArgs = std::numeric_limits<int>::max();
+ while (args.count() > numArgs - useSelf) {
+ args.removeLast();
+ }
+ signature.append(args.join(","));
+ signature.append(')');
}
- signature.append(args.join(","));
- signature.append(')');
return signature;
}
-QStringList PySide::getArgsFromSignature(const char* signature)
+QStringList PySide::getArgsFromSignature(const char* signature, bool* isShortCircuit)
{
QString qsignature(signature);
QStringList result;
QRegExp splitRegex("\\s*,\\s*");
+ if (isShortCircuit)
+ *isShortCircuit = !qsignature.contains('(');
if (qsignature.contains("()") || qsignature.contains("(void)")) {
return result;
} else if (qsignature.contains('(')) {
+ static QRegExp regex(".+\\((.*)\\)");
//get args types
- QString types = qsignature.replace(QRegExp(".+\\((.*)\\)"), "\\1");
+ QString types = qsignature.replace(regex, "\\1");
result = types.split(splitRegex);
}
return result;
@@ -138,31 +169,52 @@ void SignalManager::addGlobalSlot(const char* slot, PyObject* callback)
m_d->m_globalReceiver.addSlot(slot, callback);
}
+static bool emitShortCircuitSignal(QObject* source, int signalIndex, PyObject* args)
+{
+ void* signalArgs[2] = {0, args};
+ QMetaObject::activate(source, signalIndex, signalArgs);
+ return true;
+}
+
+static bool emitNormalSignal(QObject* source, int signalIndex, const char* signal, PyObject* args, const QStringList& argTypes)
+{
+ int argsGiven = PySequence_Size(args);
+ if (argsGiven > argTypes.count()) {
+ QString msg = QString("%1 only accepts %2 arguments, %3 given!").arg(signal).arg(argTypes.count()).arg(argsGiven);
+ PyErr_SetString(PyExc_TypeError, msg.toLocal8Bit().constData());
+ return false;
+ }
+
+ void* signalArgs[argsGiven+1];
+ signalArgs[0] = 0;
+
+ for (int i = 0; i < argsGiven; ++i)
+ signalArgs[i+1] = TypeResolver::get(argTypes[i])->toCpp(PySequence_GetItem(args, i));
+ QMetaObject::activate(source, signalIndex, signalArgs);
+ // FIXME: This will cause troubles with non-direct connections.
+ for (int i = 0; i < argsGiven; ++i)
+ TypeResolver::get(argTypes[i])->deleteObject(signalArgs[i+1]);
+ return true;
+}
+
bool SignalManager::emitSignal(QObject* source, const char* signal, PyObject* args)
{
if (!checkSignal(signal))
return false;
signal++;
- int argsGiven = PySequence_Size(args);
int signalIndex = source->metaObject()->indexOfSignal(signal);
if (signalIndex != -1) {
- QStringList argTypes = getArgsFromSignature(signal);
- if (argsGiven > argTypes.count()) {
- PyErr_SetString(PyExc_TypeError, "Too many arguments for this signal.");
- return false;
- }
- void* signalArgs[argsGiven+1];
- signalArgs[0] = 0;
- for (int i = 0; i < argsGiven; ++i)
- signalArgs[i+1] = TypeResolver::get(argTypes[i])->toCpp(PySequence_GetItem(args, i));
- QMetaObject::activate(source, signalIndex, signalArgs);
- // FIXME: This will cause troubles with non-direct connections.
- for (int i = 0; i < argsGiven; ++i)
- TypeResolver::get(argTypes[i])->deleteObject(signalArgs[i+1]);
- return true;
+ bool isShortCircuit;
+ QStringList argTypes = getArgsFromSignature(signal, &isShortCircuit);
+
+ if (isShortCircuit)
+ return emitShortCircuitSignal(source, signalIndex, args);
+ else
+ return emitNormalSignal(source, signalIndex, signal, args, argTypes);
}
+ qWarning() << "Error emitting signal: " << signal;
return false;
}
@@ -183,22 +235,24 @@ int PySide::SignalManager::qt_metacall(QObject* object, QMetaObject::Call call,
// call python slot
QList<QByteArray> paramTypes = method.parameterTypes();
PyObject* self = Shiboken::BindingManager::instance().retrieveWrapper(object);
- Shiboken::AutoDecRef preparedArgs(PyTuple_New(paramTypes.count()+1));
+ Shiboken::AutoDecRef preparedArgs(PyTuple_New(paramTypes.count()));
- PyTuple_SET_ITEM(preparedArgs.object(), 0, self);
for (int i = 0, max = paramTypes.count(); i < max; ++i) {
PyObject* arg = TypeResolver::get(paramTypes[i].constData())->toPython(args[i+1]);
- PyTuple_SET_ITEM(preparedArgs.object(), i + 1, arg);
+ PyTuple_SET_ITEM(preparedArgs.object(), i, arg);
}
QString methodName = method.signature();
methodName = methodName.left(methodName.indexOf('('));
- Shiboken::AutoDecRef pyMethodName(PyString_FromString(qPrintable(methodName)));
- Shiboken::AutoDecRef pyMethod(PyObject_GetAttr(self, pyMethodName));
- Shiboken::AutoDecRef retval(PyObject_CallObject(pyMethod, preparedArgs));
- if (!retval)
- qWarning("Error calling slot");
+ Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(self, qPrintable(methodName)));
+ if (pyMethod) {
+ Shiboken::AutoDecRef retval(PyObject_CallObject(pyMethod, preparedArgs));
+ if (!retval)
+ qWarning() << "Error calling slot" << methodName;
+ } else {
+ qWarning() << "Dynamic slot" << methodName << "not found!";
+ }
}
return -1;
}