From e684d18c0df9c48d4ab2c2f83d086eb0c5f7d78a Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Thu, 27 Sep 2018 14:18:51 +0900 Subject: qt -> tqt conversion: qtlib -> tqtlib libqt -> libtqt QTLIB -> TQTLIB LIBQT -> LIBTQT Signed-off-by: Michele Calgaro --- siplib/qtlib.c | 659 ------------------------------------------------------ siplib/siplib.sbf | 2 +- siplib/tqtlib.c | 659 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 660 insertions(+), 660 deletions(-) delete mode 100644 siplib/qtlib.c create mode 100644 siplib/tqtlib.c diff --git a/siplib/qtlib.c b/siplib/qtlib.c deleted file mode 100644 index 9bf065a..0000000 --- a/siplib/qtlib.c +++ /dev/null @@ -1,659 +0,0 @@ -/* - * The SIP library code that implements the interface to the optional module - * supplied TQt support. - * - * Copyright (c) 2010 Riverbank Computing Limited - * - * This file is part of SIP. - * - * This copy of SIP is licensed for use under the terms of the SIP License - * Agreement. See the file LICENSE for more details. - * - * This copy of SIP may also used under the terms of the GNU General Public - * License v2 or v3 as published by the Free Software Foundation which can be - * found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package. - * - * SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - - -#include -#include -#include - -#include "sip.h" -#include "sipint.h" - - -/* This is how TQt "types" signals and slots. */ -#define isTQtSlot(s) (*(s) == '1') -#define isTQtSignal(s) (*(s) == '2') - - -static PyObject *getWeakRef(PyObject *obj); -static char *sipStrdup(const char *); -static void *createUniversalSlot(sipWrapper *txSelf, const char *sig, - PyObject *rxObj, const char *slot, const char **member, int flags); -static void *findSignal(void *txrx, const char **sig); -static void *newSignal(void *txrx, const char **sig); - - -/* - * Find an existing signal. - */ -static void *findSignal(void *txrx, const char **sig) -{ - if (sipTQtSupport->qt_find_universal_signal != NULL) - txrx = sipTQtSupport->qt_find_universal_signal(txrx, sig); - - return txrx; -} - - -/* - * Return a usable signal, creating a new universal signal if needed. - */ -static void *newSignal(void *txrx, const char **sig) -{ - void *new_txrx = findSignal(txrx, sig); - - if (new_txrx == NULL && sipTQtSupport->qt_create_universal_signal != NULL) - new_txrx = sipTQtSupport->qt_create_universal_signal(txrx, sig); - - return new_txrx; -} - - -/* - * Create a universal slot. Returns a pointer to it or 0 if there was an - * error. - */ -static void *createUniversalSlot(sipWrapper *txSelf, const char *sig, - PyObject *rxObj, const char *slot, const char **member, int flags) -{ - void *us = sipTQtSupport->qt_create_universal_slot(txSelf, sig, rxObj, slot, - member, flags); - - if (us && txSelf) - sipSetPossibleProxy((sipSimpleWrapper *)txSelf); - - return us; -} - - -/* - * Invoke a single slot (TQt or Python) and return the result. - */ -PyObject *sip_api_invoke_slot(const sipSlot *slot, PyObject *sigargs) -{ - PyObject *sa, *oxtype, *oxvalue, *oxtb, *sfunc, *sref; - - /* Keep some compilers quiet. */ - oxtype = oxvalue = oxtb = NULL; - - /* Fan out TQt signals. (Only PyTQt3 will do this.) */ - if (slot->name != NULL && slot->name[0] != '\0') - { - assert(sipTQtSupport->tqt_emit_signal); - - if (sipTQtSupport->tqt_emit_signal(slot->pyobj, slot->name, sigargs) < 0) - return NULL; - - Py_INCREF(Py_None); - return Py_None; - } - - /* Get the object to call, resolving any weak references. */ - if (slot->weakSlot == Py_True) - { - /* - * The slot is guaranteed to be Ok because it has an extra reference or - * is None. - */ - sref = slot->pyobj; - Py_INCREF(sref); - } - else if (slot -> weakSlot == NULL) - sref = NULL; - else if ((sref = PyWeakref_GetObject(slot -> weakSlot)) == NULL) - return NULL; - else - Py_INCREF(sref); - - if (sref == Py_None) - { - /* - * If the real object has gone then we pretend everything is Ok. This - * mimics the TQt behaviour of not caring if a receiving object has been - * deleted. - */ - Py_DECREF(sref); - - Py_INCREF(Py_None); - return Py_None; - } - - if (slot -> pyobj == NULL) - { - PyObject *self = (sref != NULL ? sref : slot->meth.mself); - - /* - * If the receiver wraps a C++ object then ignore the call if it no - * longer exists. - */ - if (PyObject_TypeCheck(self, (PyTypeObject *)&sipSimpleWrapper_Type) && - sipGetAddress(self) == NULL) - { - Py_XDECREF(sref); - - Py_INCREF(Py_None); - return Py_None; - } - -#if PY_MAJOR_VERSION >= 3 - sfunc = PyMethod_New(slot->meth.mfunc, self); -#else - sfunc = PyMethod_New(slot->meth.mfunc, self, slot->meth.mclass); -#endif - - if (sfunc == NULL) - { - Py_XDECREF(sref); - return NULL; - } - } - else if (slot -> name != NULL) - { - char *mname = slot -> name + 1; - PyObject *self = (sref != NULL ? sref : slot->pyobj); - - if ((sfunc = PyObject_GetAttrString(self, mname)) == NULL || !PyCFunction_Check(sfunc)) - { - /* - * Note that in earlier versions of SIP this error would be - * detected when the slot was connected. - */ - PyErr_Format(PyExc_NameError,"Invalid slot %s",mname); - - Py_XDECREF(sfunc); - Py_XDECREF(sref); - return NULL; - } - } - else - { - sfunc = slot->pyobj; - Py_INCREF(sfunc); - } - - /* - * We make repeated attempts to call a slot. If we work out that it failed - * because of an immediate type error we try again with one less argument. - * We keep going until we run out of arguments to drop. This emulates the - * TQt ability of the slot to accept fewer arguments than a signal provides. - */ - sa = sigargs; - Py_INCREF(sa); - - for (;;) - { - PyObject *nsa, *xtype, *xvalue, *xtb, *resobj; - - if ((resobj = PyEval_CallObject(sfunc, sa)) != NULL) - { - Py_DECREF(sfunc); - Py_XDECREF(sref); - - /* Remove any previous exception. */ - - if (sa != sigargs) - { - Py_XDECREF(oxtype); - Py_XDECREF(oxvalue); - Py_XDECREF(oxtb); - PyErr_Clear(); - } - - Py_DECREF(sa); - - return resobj; - } - - /* Get the exception. */ - PyErr_Fetch(&xtype,&xvalue,&xtb); - - /* - * See if it is unacceptable. An acceptable failure is a type error - * with no traceback - so long as we can still reduce the number of - * arguments and try again. - */ - if (!PyErr_GivenExceptionMatches(xtype,PyExc_TypeError) || - xtb != NULL || - PyTuple_GET_SIZE(sa) == 0) - { - /* - * If there is a traceback then we must have called the slot and - * the exception was later on - so report the exception as is. - */ - if (xtb != NULL) - { - if (sa != sigargs) - { - Py_XDECREF(oxtype); - Py_XDECREF(oxvalue); - Py_XDECREF(oxtb); - } - - PyErr_Restore(xtype,xvalue,xtb); - } - else if (sa == sigargs) - PyErr_Restore(xtype,xvalue,xtb); - else - { - /* - * Discard the latest exception and restore the original one. - */ - Py_XDECREF(xtype); - Py_XDECREF(xvalue); - Py_XDECREF(xtb); - - PyErr_Restore(oxtype,oxvalue,oxtb); - } - - break; - } - - /* If this is the first attempt, save the exception. */ - if (sa == sigargs) - { - oxtype = xtype; - oxvalue = xvalue; - oxtb = xtb; - } - else - { - Py_XDECREF(xtype); - Py_XDECREF(xvalue); - Py_XDECREF(xtb); - } - - /* Create the new argument tuple. */ - if ((nsa = PyTuple_GetSlice(sa,0,PyTuple_GET_SIZE(sa) - 1)) == NULL) - { - /* Tidy up. */ - Py_XDECREF(oxtype); - Py_XDECREF(oxvalue); - Py_XDECREF(oxtb); - - break; - } - - Py_DECREF(sa); - sa = nsa; - } - - Py_DECREF(sfunc); - Py_XDECREF(sref); - - Py_DECREF(sa); - - return NULL; -} - - -/* - * Compare two slots to see if they are the same. - */ -int sip_api_same_slot(const sipSlot *sp, PyObject *rxObj, const char *slot) -{ - /* See if they are signals or TQt slots, ie. they have a name. */ - if (slot != NULL) - { - if (sp->name == NULL || sp->name[0] == '\0') - return 0; - - return (sipTQtSupport->qt_same_name(sp->name, slot) && sp->pyobj == rxObj); - } - - /* See if they are pure Python methods. */ - if (PyMethod_Check(rxObj)) - { - if (sp->pyobj != NULL) - return 0; - - return (sp->meth.mfunc == PyMethod_GET_FUNCTION(rxObj) - && sp->meth.mself == PyMethod_GET_SELF(rxObj) -#if PY_MAJOR_VERSION < 3 - && sp->meth.mclass == PyMethod_GET_CLASS(rxObj) -#endif - ); - } - - /* See if they are wrapped C++ methods. */ - if (PyCFunction_Check(rxObj)) - { - if (sp->name == NULL || sp->name[0] != '\0') - return 0; - - return (sp->pyobj == PyCFunction_GET_SELF(rxObj) && - strcmp(&sp->name[1], ((PyCFunctionObject *)rxObj)->m_ml->ml_name) == 0); - } - - /* The objects must be the same. */ - return (sp->pyobj == rxObj); -} - - -/* - * Convert a valid Python signal or slot to an existing universal slot. - */ -void *sipGetRx(sipSimpleWrapper *txSelf, const char *sigargs, PyObject *rxObj, - const char *slot, const char **memberp) -{ - if (slot != NULL) - if (isTQtSlot(slot) || isTQtSignal(slot)) - { - void *rx; - - *memberp = slot; - - if ((rx = sip_api_get_cpp_ptr((sipSimpleWrapper *)rxObj, sipTQObjectType)) == NULL) - return NULL; - - if (isTQtSignal(slot)) - rx = findSignal(rx, memberp); - - return rx; - } - - /* - * The slot was either a Python callable or PyTQt3 Python signal so there - * should be a universal slot. - */ - return sipTQtSupport->qt_find_slot(sipGetAddress(txSelf), sigargs, rxObj, slot, memberp); -} - - -/* - * Convert a Python receiver (either a Python signal or slot or a TQt signal or - * slot) to a TQt receiver. It is only ever called when the signal is a TQt - * signal. Return NULL is there was an error. - */ -void *sip_api_convert_rx(sipWrapper *txSelf, const char *sigargs, - PyObject *rxObj, const char *slot, const char **memberp, int flags) -{ - if (slot == NULL) - return createUniversalSlot(txSelf, sigargs, rxObj, NULL, memberp, flags); - - if (isTQtSlot(slot) || isTQtSignal(slot)) - { - void *rx; - - *memberp = slot; - - if ((rx = sip_api_get_cpp_ptr((sipSimpleWrapper *)rxObj, sipTQObjectType)) == NULL) - return NULL; - - if (isTQtSignal(slot)) - rx = newSignal(rx, memberp); - - return rx; - } - - /* The slot is a Python signal so we need a universal slot to catch it. */ - return createUniversalSlot(txSelf, sigargs, rxObj, slot, memberp, 0); -} - - -/* - * Connect a TQt signal or a Python signal to a TQt slot, a TQt signal, a Python - * slot or a Python signal. This is all possible combinations. - */ -PyObject *sip_api_connect_rx(PyObject *txObj, const char *sig, PyObject *rxObj, - const char *slot, int type) -{ - /* Handle TQt signals. */ - if (isTQtSignal(sig)) - { - void *tx, *rx; - const char *member, *real_sig; - int res; - - if ((tx = sip_api_get_cpp_ptr((sipSimpleWrapper *)txObj, sipTQObjectType)) == NULL) - return NULL; - - real_sig = sig; - - if ((tx = newSignal(tx, &real_sig)) == NULL) - return NULL; - - if ((rx = sip_api_convert_rx((sipWrapper *)txObj, sig, rxObj, slot, &member, 0)) == NULL) - return NULL; - - res = sipTQtSupport->qt_connect(tx, real_sig, rx, member, type); - - return PyBool_FromLong(res); - } - - /* Handle Python signals. Only PyTQt3 will get this far. */ - assert(sipTQtSupport->qt_connect_py_signal); - - if (sipTQtSupport->qt_connect_py_signal(txObj, sig, rxObj, slot) < 0) - return NULL; - - Py_INCREF(Py_True); - return Py_True; -} - - -/* - * Disconnect a signal to a signal or a TQt slot. - */ -PyObject *sip_api_disconnect_rx(PyObject *txObj,const char *sig, - PyObject *rxObj,const char *slot) -{ - /* Handle TQt signals. */ - if (isTQtSignal(sig)) - { - sipSimpleWrapper *txSelf = (sipSimpleWrapper *)txObj; - void *tx, *rx; - const char *member; - int res; - - if ((tx = sip_api_get_cpp_ptr(txSelf, sipTQObjectType)) == NULL) - return NULL; - - if ((rx = sipGetRx(txSelf, sig, rxObj, slot, &member)) == NULL) - { - Py_INCREF(Py_False); - return Py_False; - } - - /* Handle Python signals. */ - tx = findSignal(tx, &sig); - - res = sipTQtSupport->qt_disconnect(tx, sig, rx, member); - - /* - * Delete it if it is a universal slot as this will be it's only - * connection. If the slot is actually a universal signal then it - * should leave it in place. - */ - sipTQtSupport->qt_destroy_universal_slot(rx); - - return PyBool_FromLong(res); - } - - /* Handle Python signals. Only PyTQt3 will get this far. */ - assert(sipTQtSupport->qt_disconnect_py_signal); - - sipTQtSupport->qt_disconnect_py_signal(txObj, sig, rxObj, slot); - - Py_INCREF(Py_True); - return Py_True; -} - - -/* - * Free the resources of a slot. - */ -void sip_api_free_sipslot(sipSlot *slot) -{ - if (slot->name != NULL) - { - sip_api_free(slot->name); - } - else if (slot->weakSlot == Py_True) - { - Py_DECREF(slot->pyobj); - } - - /* Remove any weak reference. */ - Py_XDECREF(slot->weakSlot); -} - - -/* - * Implement strdup() using sip_api_malloc(). - */ -static char *sipStrdup(const char *s) -{ - char *d; - - if ((d = (char *)sip_api_malloc(strlen(s) + 1)) != NULL) - strcpy(d,s); - - return d; -} - - -/* - * Initialise a slot, returning 0 if there was no error. If the signal was a - * TQt signal, then the slot may be a Python signal or a Python slot. If the - * signal was a Python signal, then the slot may be anything. - */ -int sip_api_save_slot(sipSlot *sp, PyObject *rxObj, const char *slot) -{ - sp -> weakSlot = NULL; - - if (slot == NULL) - { - sp -> name = NULL; - - if (PyMethod_Check(rxObj)) - { - /* - * Python creates methods on the fly. We could increment the - * reference count to keep it alive, but that would keep "self" - * alive as well and would probably be a circular reference. - * Instead we remember the component parts and hope they are still - * valid when we re-create the method when we need it. - */ - sipSaveMethod(&sp -> meth,rxObj); - - /* Notice if the class instance disappears. */ - sp -> weakSlot = getWeakRef(sp -> meth.mself); - - /* This acts a flag to say that the slot is a method. */ - sp -> pyobj = NULL; - } - else - { - PyObject *self; - - /* - * We know that it is another type of callable, ie. a - * function/builtin. - */ - - if (PyCFunction_Check(rxObj) && - (self = PyCFunction_GET_SELF(rxObj)) != NULL && - PyObject_TypeCheck(self, (PyTypeObject *)&sipSimpleWrapper_Type)) - { - /* - * It is a wrapped C++ class method. We can't keep a copy - * because they are generated on the fly and we can't take a - * reference as that may keep the instance (ie. self) alive. - * We therefore treat it as if the user had specified the slot - * at "obj, TQT_SLOT('meth()')" rather than "obj.meth" (see below). - */ - - const char *meth; - - /* Get the method name. */ - meth = ((PyCFunctionObject *)rxObj) -> m_ml -> ml_name; - - if ((sp -> name = (char *)sip_api_malloc(strlen(meth) + 2)) == NULL) - return -1; - - /* - * Copy the name and set the marker that it needs converting to - * a built-in method. - */ - sp -> name[0] = '\0'; - strcpy(&sp -> name[1],meth); - - sp -> pyobj = self; - sp -> weakSlot = getWeakRef(self); - } - else - { - /* - * Give the slot an extra reference to keep it alive and - * remember we have done so by treating weakSlot specially. - */ - Py_INCREF(rxObj); - sp->pyobj = rxObj; - - Py_INCREF(Py_True); - sp->weakSlot = Py_True; - } - } - } - else if ((sp -> name = sipStrdup(slot)) == NULL) - return -1; - else if (isTQtSlot(slot)) - { - /* - * The user has decided to connect a Python signal to a TQt slot and - * specified the slot as "obj, TQT_SLOT('meth()')" rather than "obj.meth". - */ - - char *tail; - - /* Remove any arguments. */ - if ((tail = strchr(sp -> name,'(')) != NULL) - *tail = '\0'; - - /* - * A bit of a hack to indicate that this needs converting to a built-in - * method. - */ - sp -> name[0] = '\0'; - - /* Notice if the class instance disappears. */ - sp -> weakSlot = getWeakRef(rxObj); - - sp -> pyobj = rxObj; - } - else - /* It's a TQt signal. */ - sp -> pyobj = rxObj; - - return 0; -} - - -/* - * Return a weak reference to the given object. - */ -static PyObject *getWeakRef(PyObject *obj) -{ - PyObject *wr; - - if ((wr = PyWeakref_NewRef(obj,NULL)) == NULL) - PyErr_Clear(); - - return wr; -} diff --git a/siplib/siplib.sbf b/siplib/siplib.sbf index 79f9a45..2e17ba5 100644 --- a/siplib/siplib.sbf +++ b/siplib/siplib.sbf @@ -15,5 +15,5 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. target = sip -sources = siplib.c apiversions.c descriptors.c qtlib.c threads.c objmap.c voidptr.c bool.cpp +sources = siplib.c apiversions.c descriptors.c tqtlib.c threads.c objmap.c voidptr.c bool.cpp headers = sip.h sipint.h diff --git a/siplib/tqtlib.c b/siplib/tqtlib.c new file mode 100644 index 0000000..9bf065a --- /dev/null +++ b/siplib/tqtlib.c @@ -0,0 +1,659 @@ +/* + * The SIP library code that implements the interface to the optional module + * supplied TQt support. + * + * Copyright (c) 2010 Riverbank Computing Limited + * + * This file is part of SIP. + * + * This copy of SIP is licensed for use under the terms of the SIP License + * Agreement. See the file LICENSE for more details. + * + * This copy of SIP may also used under the terms of the GNU General Public + * License v2 or v3 as published by the Free Software Foundation which can be + * found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package. + * + * SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#include +#include +#include + +#include "sip.h" +#include "sipint.h" + + +/* This is how TQt "types" signals and slots. */ +#define isTQtSlot(s) (*(s) == '1') +#define isTQtSignal(s) (*(s) == '2') + + +static PyObject *getWeakRef(PyObject *obj); +static char *sipStrdup(const char *); +static void *createUniversalSlot(sipWrapper *txSelf, const char *sig, + PyObject *rxObj, const char *slot, const char **member, int flags); +static void *findSignal(void *txrx, const char **sig); +static void *newSignal(void *txrx, const char **sig); + + +/* + * Find an existing signal. + */ +static void *findSignal(void *txrx, const char **sig) +{ + if (sipTQtSupport->qt_find_universal_signal != NULL) + txrx = sipTQtSupport->qt_find_universal_signal(txrx, sig); + + return txrx; +} + + +/* + * Return a usable signal, creating a new universal signal if needed. + */ +static void *newSignal(void *txrx, const char **sig) +{ + void *new_txrx = findSignal(txrx, sig); + + if (new_txrx == NULL && sipTQtSupport->qt_create_universal_signal != NULL) + new_txrx = sipTQtSupport->qt_create_universal_signal(txrx, sig); + + return new_txrx; +} + + +/* + * Create a universal slot. Returns a pointer to it or 0 if there was an + * error. + */ +static void *createUniversalSlot(sipWrapper *txSelf, const char *sig, + PyObject *rxObj, const char *slot, const char **member, int flags) +{ + void *us = sipTQtSupport->qt_create_universal_slot(txSelf, sig, rxObj, slot, + member, flags); + + if (us && txSelf) + sipSetPossibleProxy((sipSimpleWrapper *)txSelf); + + return us; +} + + +/* + * Invoke a single slot (TQt or Python) and return the result. + */ +PyObject *sip_api_invoke_slot(const sipSlot *slot, PyObject *sigargs) +{ + PyObject *sa, *oxtype, *oxvalue, *oxtb, *sfunc, *sref; + + /* Keep some compilers quiet. */ + oxtype = oxvalue = oxtb = NULL; + + /* Fan out TQt signals. (Only PyTQt3 will do this.) */ + if (slot->name != NULL && slot->name[0] != '\0') + { + assert(sipTQtSupport->tqt_emit_signal); + + if (sipTQtSupport->tqt_emit_signal(slot->pyobj, slot->name, sigargs) < 0) + return NULL; + + Py_INCREF(Py_None); + return Py_None; + } + + /* Get the object to call, resolving any weak references. */ + if (slot->weakSlot == Py_True) + { + /* + * The slot is guaranteed to be Ok because it has an extra reference or + * is None. + */ + sref = slot->pyobj; + Py_INCREF(sref); + } + else if (slot -> weakSlot == NULL) + sref = NULL; + else if ((sref = PyWeakref_GetObject(slot -> weakSlot)) == NULL) + return NULL; + else + Py_INCREF(sref); + + if (sref == Py_None) + { + /* + * If the real object has gone then we pretend everything is Ok. This + * mimics the TQt behaviour of not caring if a receiving object has been + * deleted. + */ + Py_DECREF(sref); + + Py_INCREF(Py_None); + return Py_None; + } + + if (slot -> pyobj == NULL) + { + PyObject *self = (sref != NULL ? sref : slot->meth.mself); + + /* + * If the receiver wraps a C++ object then ignore the call if it no + * longer exists. + */ + if (PyObject_TypeCheck(self, (PyTypeObject *)&sipSimpleWrapper_Type) && + sipGetAddress(self) == NULL) + { + Py_XDECREF(sref); + + Py_INCREF(Py_None); + return Py_None; + } + +#if PY_MAJOR_VERSION >= 3 + sfunc = PyMethod_New(slot->meth.mfunc, self); +#else + sfunc = PyMethod_New(slot->meth.mfunc, self, slot->meth.mclass); +#endif + + if (sfunc == NULL) + { + Py_XDECREF(sref); + return NULL; + } + } + else if (slot -> name != NULL) + { + char *mname = slot -> name + 1; + PyObject *self = (sref != NULL ? sref : slot->pyobj); + + if ((sfunc = PyObject_GetAttrString(self, mname)) == NULL || !PyCFunction_Check(sfunc)) + { + /* + * Note that in earlier versions of SIP this error would be + * detected when the slot was connected. + */ + PyErr_Format(PyExc_NameError,"Invalid slot %s",mname); + + Py_XDECREF(sfunc); + Py_XDECREF(sref); + return NULL; + } + } + else + { + sfunc = slot->pyobj; + Py_INCREF(sfunc); + } + + /* + * We make repeated attempts to call a slot. If we work out that it failed + * because of an immediate type error we try again with one less argument. + * We keep going until we run out of arguments to drop. This emulates the + * TQt ability of the slot to accept fewer arguments than a signal provides. + */ + sa = sigargs; + Py_INCREF(sa); + + for (;;) + { + PyObject *nsa, *xtype, *xvalue, *xtb, *resobj; + + if ((resobj = PyEval_CallObject(sfunc, sa)) != NULL) + { + Py_DECREF(sfunc); + Py_XDECREF(sref); + + /* Remove any previous exception. */ + + if (sa != sigargs) + { + Py_XDECREF(oxtype); + Py_XDECREF(oxvalue); + Py_XDECREF(oxtb); + PyErr_Clear(); + } + + Py_DECREF(sa); + + return resobj; + } + + /* Get the exception. */ + PyErr_Fetch(&xtype,&xvalue,&xtb); + + /* + * See if it is unacceptable. An acceptable failure is a type error + * with no traceback - so long as we can still reduce the number of + * arguments and try again. + */ + if (!PyErr_GivenExceptionMatches(xtype,PyExc_TypeError) || + xtb != NULL || + PyTuple_GET_SIZE(sa) == 0) + { + /* + * If there is a traceback then we must have called the slot and + * the exception was later on - so report the exception as is. + */ + if (xtb != NULL) + { + if (sa != sigargs) + { + Py_XDECREF(oxtype); + Py_XDECREF(oxvalue); + Py_XDECREF(oxtb); + } + + PyErr_Restore(xtype,xvalue,xtb); + } + else if (sa == sigargs) + PyErr_Restore(xtype,xvalue,xtb); + else + { + /* + * Discard the latest exception and restore the original one. + */ + Py_XDECREF(xtype); + Py_XDECREF(xvalue); + Py_XDECREF(xtb); + + PyErr_Restore(oxtype,oxvalue,oxtb); + } + + break; + } + + /* If this is the first attempt, save the exception. */ + if (sa == sigargs) + { + oxtype = xtype; + oxvalue = xvalue; + oxtb = xtb; + } + else + { + Py_XDECREF(xtype); + Py_XDECREF(xvalue); + Py_XDECREF(xtb); + } + + /* Create the new argument tuple. */ + if ((nsa = PyTuple_GetSlice(sa,0,PyTuple_GET_SIZE(sa) - 1)) == NULL) + { + /* Tidy up. */ + Py_XDECREF(oxtype); + Py_XDECREF(oxvalue); + Py_XDECREF(oxtb); + + break; + } + + Py_DECREF(sa); + sa = nsa; + } + + Py_DECREF(sfunc); + Py_XDECREF(sref); + + Py_DECREF(sa); + + return NULL; +} + + +/* + * Compare two slots to see if they are the same. + */ +int sip_api_same_slot(const sipSlot *sp, PyObject *rxObj, const char *slot) +{ + /* See if they are signals or TQt slots, ie. they have a name. */ + if (slot != NULL) + { + if (sp->name == NULL || sp->name[0] == '\0') + return 0; + + return (sipTQtSupport->qt_same_name(sp->name, slot) && sp->pyobj == rxObj); + } + + /* See if they are pure Python methods. */ + if (PyMethod_Check(rxObj)) + { + if (sp->pyobj != NULL) + return 0; + + return (sp->meth.mfunc == PyMethod_GET_FUNCTION(rxObj) + && sp->meth.mself == PyMethod_GET_SELF(rxObj) +#if PY_MAJOR_VERSION < 3 + && sp->meth.mclass == PyMethod_GET_CLASS(rxObj) +#endif + ); + } + + /* See if they are wrapped C++ methods. */ + if (PyCFunction_Check(rxObj)) + { + if (sp->name == NULL || sp->name[0] != '\0') + return 0; + + return (sp->pyobj == PyCFunction_GET_SELF(rxObj) && + strcmp(&sp->name[1], ((PyCFunctionObject *)rxObj)->m_ml->ml_name) == 0); + } + + /* The objects must be the same. */ + return (sp->pyobj == rxObj); +} + + +/* + * Convert a valid Python signal or slot to an existing universal slot. + */ +void *sipGetRx(sipSimpleWrapper *txSelf, const char *sigargs, PyObject *rxObj, + const char *slot, const char **memberp) +{ + if (slot != NULL) + if (isTQtSlot(slot) || isTQtSignal(slot)) + { + void *rx; + + *memberp = slot; + + if ((rx = sip_api_get_cpp_ptr((sipSimpleWrapper *)rxObj, sipTQObjectType)) == NULL) + return NULL; + + if (isTQtSignal(slot)) + rx = findSignal(rx, memberp); + + return rx; + } + + /* + * The slot was either a Python callable or PyTQt3 Python signal so there + * should be a universal slot. + */ + return sipTQtSupport->qt_find_slot(sipGetAddress(txSelf), sigargs, rxObj, slot, memberp); +} + + +/* + * Convert a Python receiver (either a Python signal or slot or a TQt signal or + * slot) to a TQt receiver. It is only ever called when the signal is a TQt + * signal. Return NULL is there was an error. + */ +void *sip_api_convert_rx(sipWrapper *txSelf, const char *sigargs, + PyObject *rxObj, const char *slot, const char **memberp, int flags) +{ + if (slot == NULL) + return createUniversalSlot(txSelf, sigargs, rxObj, NULL, memberp, flags); + + if (isTQtSlot(slot) || isTQtSignal(slot)) + { + void *rx; + + *memberp = slot; + + if ((rx = sip_api_get_cpp_ptr((sipSimpleWrapper *)rxObj, sipTQObjectType)) == NULL) + return NULL; + + if (isTQtSignal(slot)) + rx = newSignal(rx, memberp); + + return rx; + } + + /* The slot is a Python signal so we need a universal slot to catch it. */ + return createUniversalSlot(txSelf, sigargs, rxObj, slot, memberp, 0); +} + + +/* + * Connect a TQt signal or a Python signal to a TQt slot, a TQt signal, a Python + * slot or a Python signal. This is all possible combinations. + */ +PyObject *sip_api_connect_rx(PyObject *txObj, const char *sig, PyObject *rxObj, + const char *slot, int type) +{ + /* Handle TQt signals. */ + if (isTQtSignal(sig)) + { + void *tx, *rx; + const char *member, *real_sig; + int res; + + if ((tx = sip_api_get_cpp_ptr((sipSimpleWrapper *)txObj, sipTQObjectType)) == NULL) + return NULL; + + real_sig = sig; + + if ((tx = newSignal(tx, &real_sig)) == NULL) + return NULL; + + if ((rx = sip_api_convert_rx((sipWrapper *)txObj, sig, rxObj, slot, &member, 0)) == NULL) + return NULL; + + res = sipTQtSupport->qt_connect(tx, real_sig, rx, member, type); + + return PyBool_FromLong(res); + } + + /* Handle Python signals. Only PyTQt3 will get this far. */ + assert(sipTQtSupport->qt_connect_py_signal); + + if (sipTQtSupport->qt_connect_py_signal(txObj, sig, rxObj, slot) < 0) + return NULL; + + Py_INCREF(Py_True); + return Py_True; +} + + +/* + * Disconnect a signal to a signal or a TQt slot. + */ +PyObject *sip_api_disconnect_rx(PyObject *txObj,const char *sig, + PyObject *rxObj,const char *slot) +{ + /* Handle TQt signals. */ + if (isTQtSignal(sig)) + { + sipSimpleWrapper *txSelf = (sipSimpleWrapper *)txObj; + void *tx, *rx; + const char *member; + int res; + + if ((tx = sip_api_get_cpp_ptr(txSelf, sipTQObjectType)) == NULL) + return NULL; + + if ((rx = sipGetRx(txSelf, sig, rxObj, slot, &member)) == NULL) + { + Py_INCREF(Py_False); + return Py_False; + } + + /* Handle Python signals. */ + tx = findSignal(tx, &sig); + + res = sipTQtSupport->qt_disconnect(tx, sig, rx, member); + + /* + * Delete it if it is a universal slot as this will be it's only + * connection. If the slot is actually a universal signal then it + * should leave it in place. + */ + sipTQtSupport->qt_destroy_universal_slot(rx); + + return PyBool_FromLong(res); + } + + /* Handle Python signals. Only PyTQt3 will get this far. */ + assert(sipTQtSupport->qt_disconnect_py_signal); + + sipTQtSupport->qt_disconnect_py_signal(txObj, sig, rxObj, slot); + + Py_INCREF(Py_True); + return Py_True; +} + + +/* + * Free the resources of a slot. + */ +void sip_api_free_sipslot(sipSlot *slot) +{ + if (slot->name != NULL) + { + sip_api_free(slot->name); + } + else if (slot->weakSlot == Py_True) + { + Py_DECREF(slot->pyobj); + } + + /* Remove any weak reference. */ + Py_XDECREF(slot->weakSlot); +} + + +/* + * Implement strdup() using sip_api_malloc(). + */ +static char *sipStrdup(const char *s) +{ + char *d; + + if ((d = (char *)sip_api_malloc(strlen(s) + 1)) != NULL) + strcpy(d,s); + + return d; +} + + +/* + * Initialise a slot, returning 0 if there was no error. If the signal was a + * TQt signal, then the slot may be a Python signal or a Python slot. If the + * signal was a Python signal, then the slot may be anything. + */ +int sip_api_save_slot(sipSlot *sp, PyObject *rxObj, const char *slot) +{ + sp -> weakSlot = NULL; + + if (slot == NULL) + { + sp -> name = NULL; + + if (PyMethod_Check(rxObj)) + { + /* + * Python creates methods on the fly. We could increment the + * reference count to keep it alive, but that would keep "self" + * alive as well and would probably be a circular reference. + * Instead we remember the component parts and hope they are still + * valid when we re-create the method when we need it. + */ + sipSaveMethod(&sp -> meth,rxObj); + + /* Notice if the class instance disappears. */ + sp -> weakSlot = getWeakRef(sp -> meth.mself); + + /* This acts a flag to say that the slot is a method. */ + sp -> pyobj = NULL; + } + else + { + PyObject *self; + + /* + * We know that it is another type of callable, ie. a + * function/builtin. + */ + + if (PyCFunction_Check(rxObj) && + (self = PyCFunction_GET_SELF(rxObj)) != NULL && + PyObject_TypeCheck(self, (PyTypeObject *)&sipSimpleWrapper_Type)) + { + /* + * It is a wrapped C++ class method. We can't keep a copy + * because they are generated on the fly and we can't take a + * reference as that may keep the instance (ie. self) alive. + * We therefore treat it as if the user had specified the slot + * at "obj, TQT_SLOT('meth()')" rather than "obj.meth" (see below). + */ + + const char *meth; + + /* Get the method name. */ + meth = ((PyCFunctionObject *)rxObj) -> m_ml -> ml_name; + + if ((sp -> name = (char *)sip_api_malloc(strlen(meth) + 2)) == NULL) + return -1; + + /* + * Copy the name and set the marker that it needs converting to + * a built-in method. + */ + sp -> name[0] = '\0'; + strcpy(&sp -> name[1],meth); + + sp -> pyobj = self; + sp -> weakSlot = getWeakRef(self); + } + else + { + /* + * Give the slot an extra reference to keep it alive and + * remember we have done so by treating weakSlot specially. + */ + Py_INCREF(rxObj); + sp->pyobj = rxObj; + + Py_INCREF(Py_True); + sp->weakSlot = Py_True; + } + } + } + else if ((sp -> name = sipStrdup(slot)) == NULL) + return -1; + else if (isTQtSlot(slot)) + { + /* + * The user has decided to connect a Python signal to a TQt slot and + * specified the slot as "obj, TQT_SLOT('meth()')" rather than "obj.meth". + */ + + char *tail; + + /* Remove any arguments. */ + if ((tail = strchr(sp -> name,'(')) != NULL) + *tail = '\0'; + + /* + * A bit of a hack to indicate that this needs converting to a built-in + * method. + */ + sp -> name[0] = '\0'; + + /* Notice if the class instance disappears. */ + sp -> weakSlot = getWeakRef(rxObj); + + sp -> pyobj = rxObj; + } + else + /* It's a TQt signal. */ + sp -> pyobj = rxObj; + + return 0; +} + + +/* + * Return a weak reference to the given object. + */ +static PyObject *getWeakRef(PyObject *obj) +{ + PyObject *wr; + + if ((wr = PyWeakref_NewRef(obj,NULL)) == NULL) + PyErr_Clear(); + + return wr; +} -- cgit v1.2.1