📄 qtlib.c
字号:
return 0; } if ((sfunc = PyMethod_New(slot->meth.mfunc, self, slot->meth.mclass)) == NULL) { Py_XDECREF(sref); return -1; } // Make sure we garbage collect the new method. newmeth = sfunc; } else if (slot -> name != NULL) { char *mname = slot -> name + 1; PyObject *self = (sref != NULL ? sref : slot->pyobj); // See if any underlying C++ instance has gone. if (self != NULL && sip_api_wrapper_check(self) && ((sipWrapper *)self)->u.cppPtr == NULL) { Py_XDECREF(sref); return 0; } 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(sref); return -1; } // Make sure we garbage collect the new method. newmeth = sfunc; } else { sfunc = slot -> pyobj; newmeth = NULL; } // 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 Qt 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(resobj); Py_XDECREF(newmeth); 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 0; } // 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_XDECREF(newmeth); Py_XDECREF(sref); Py_DECREF(sa); return -1;}// Send a signal to the slots (Qt or Python) in a Python list.static int emitToSlotList(sipPySigRx *rxlist,PyObject *sigargs){ int rc; // Apply the arguments to each slot method. rc = 0; while (rxlist != NULL && rc >= 0) { sipPySigRx *next; // We get the next in the list before calling the slot in case // the list gets changed by the slot - usually because the slot // disconnects itself. next = rxlist -> next; rc = sip_api_emit_to_slot(&rxlist -> rx, sigargs); rxlist = next; } return rc;}// Add a slot to a transmitter's Python signal list. The signal is a Python// signal, the slot may be either a Qt signal, a Qt slot, a Python signal or a// Python slot.static int addSlotToPySigList(sipWrapper *txSelf,const char *sig, PyObject *rxObj,const char *slot){ sipPySig *ps; sipPySigRx *psrx; // Create a new one if necessary. if ((ps = findPySignal(txSelf,sig)) == NULL) { if ((ps = (sipPySig *)sip_api_malloc(sizeof (sipPySig))) == NULL) return -1; if ((ps -> name = sipStrdup(sig)) == NULL) { sip_api_free(ps); return -1; } ps -> rxlist = NULL; ps -> next = txSelf -> pySigList; txSelf -> pySigList = ps; } // Create the new receiver. if ((psrx = (sipPySigRx *)sip_api_malloc(sizeof (sipPySigRx))) == NULL) return -1; if (saveSlot(&psrx->rx, rxObj, slot) < 0) { sip_api_free(psrx); return -1; } psrx -> next = ps -> rxlist; ps -> rxlist = psrx; return 0;}// Compare two slots to see if they are the same.static int isSameSlot(sipSlot *slot1,PyObject *rxobj2,const char *slot2){ // See if they are signals or Qt slots, ie. they have a name. if (slot1 -> name != NULL) return (slot2 != NULL && sipQtSupport->qt_same_name(slot1 -> name,slot2) && slot1 -> pyobj == rxobj2); // Both must be Python slots. if (slot2 != NULL) return 0; // See if they are Python methods. if (slot1 -> pyobj == NULL) return (PyMethod_Check(rxobj2) && slot1 -> meth.mfunc == PyMethod_GET_FUNCTION(rxobj2) && slot1 -> meth.mself == PyMethod_GET_SELF(rxobj2) && slot1 -> meth.mclass == PyMethod_GET_CLASS(rxobj2)); if (PyMethod_Check(rxobj2)) return 0; // The objects must be the same. return (slot1 -> pyobj == rxobj2);}// Convert a valid Python signal or slot to an existing universal slot.void *sipGetRx(sipWrapper *txSelf,const char *sigargs,PyObject *rxObj, const char *slot,const char **memberp){ if (slot != NULL) if (isQtSlot(slot) || isQtSignal(slot)) { void *rx; *memberp = slot; if ((rx = sip_api_get_cpp_ptr((sipWrapper *)rxObj, sipQObjectClass)) == NULL) return NULL; if (isQtSignal(slot)) rx = findSignal(rx, memberp); return rx; } // The slot was either a Python callable or PyQt3 Python signal so // there should be a universal slot. return sipQtSupport->qt_find_slot(sipGetAddress(txSelf), sigargs, rxObj, slot, memberp);}// Convert a Python receiver (either a Python signal or slot or a Qt signal// or slot) to a Qt receiver. It is only ever called when the signal is a// Qt signal. Return NULL is there was an error.void *sip_api_convert_rx(sipWrapper *txSelf,const char *sig,PyObject *rxObj, const char *slot,const char **memberp){ if (slot == NULL) return createUniversalSlot(txSelf, sig, rxObj, NULL, memberp); if (isQtSlot(slot) || isQtSignal(slot)) { void *rx; *memberp = slot; if ((rx = sip_api_get_cpp_ptr((sipWrapper *)rxObj, sipQObjectClass)) == NULL) return NULL; if (isQtSignal(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, sig, rxObj, slot, memberp);}// Connect a Qt signal or a Python signal to a Qt slot, a Qt 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){ sipWrapper *txSelf = (sipWrapper *)txObj; // Handle Qt signals. if (isQtSignal(sig)) { void *tx, *rx; const char *member, *real_sig; int res; if ((tx = sip_api_get_cpp_ptr(txSelf, sipQObjectClass)) == NULL) return NULL; real_sig = sig; if ((tx = newSignal(tx, &real_sig)) == NULL) return NULL; if ((rx = sip_api_convert_rx(txSelf, sig, rxObj, slot, &member)) == NULL) return NULL; Py_BEGIN_ALLOW_THREADS res = sipQtSupport->qt_connect(tx, real_sig, rx, member, type); Py_END_ALLOW_THREADS return PyBool_FromLong(res); } // Handle Python signals. if (addSlotToPySigList(txSelf, sig, rxObj, slot) < 0) return NULL; Py_INCREF(Py_True); return Py_True;}// Disconnect a signal to a signal or a Qt slot.PyObject *sip_api_disconnect_rx(PyObject *txObj,const char *sig, PyObject *rxObj,const char *slot){ sipWrapper *txSelf = (sipWrapper *)txObj; // Handle Qt signals. if (isQtSignal(sig)) { void *tx, *rx; const char *member; PyObject *res; if ((tx = sip_api_get_cpp_ptr(txSelf, sipQObjectClass)) == NULL) return NULL; if ((rx = sipGetRx(txSelf, sig, rxObj, slot, &member)) == NULL) { Py_INCREF(Py_False); return Py_False; } res = PyBool_FromLong(sipQtSupport->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. sipQtSupport->qt_destroy_universal_slot(rx); return res; } // Handle Python signals. removeSlotFromPySigList(txSelf,sig,rxObj,slot); Py_INCREF(Py_True); return Py_True;}// Remove a slot from a transmitter's Python signal list.static void removeSlotFromPySigList(sipWrapper *txSelf,const char *sig, PyObject *rxObj,const char *slot){ sipPySig *ps; if ((ps = findPySignal(txSelf,sig)) != NULL) { sipPySigRx **psrxp; for (psrxp = &ps -> rxlist; *psrxp != NULL; psrxp = &(*psrxp) -> next) { sipPySigRx *psrx = *psrxp; if (isSameSlot(&psrx -> rx,rxObj,slot)) { *psrxp = psrx -> next; sipFreePySigRx(psrx); break; } } }}// Free a sipSlot structure.static void freeSlot(sipSlot *slot){ if (slot->name != NULL) sip_api_free(slot->name); // Remove any weak reference. Py_XDECREF(slot->weakSlot);}// Free a sipPySigRx structure on the heap.void sipFreePySigRx(sipPySigRx *rx){ freeSlot(&rx->rx); sip_api_free(rx);}// 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// Qt 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.static int saveSlot(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 && sip_api_wrapper_check(self)) { // 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, SLOT('meth()')" // rather than "obj.meth" (see below). 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 { // It's unlikely that we will succeed in // getting a weak reference to the slot, but // there is no harm in trying (and future // versions of Python may support references to // more object types). sp -> pyobj = rxObj; sp -> weakSlot = getWeakRef(rxObj); } } } else if ((sp -> name = sipStrdup(slot)) == NULL) return -1; else if (isQtSlot(slot)) { // The user has decided to connect a Python signal to a Qt slot // and specified the slot as "obj, 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 Qt 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -