📄 qtlib.c
字号:
// The SIP library code that implements the interface to the optional module// supplied Qt support.//// Copyright (c) 2006// Riverbank Computing Limited <info@riverbankcomputing.co.uk>// // 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.// // SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.#include <Python.h>#include <string.h>#include "sip.h"#include "sipint.h"// This is how Qt "types" signals and slots.#define isQtSlot(s) (*(s) == '1')#define isQtSignal(s) (*(s) == '2')static PyObject *py_sender = NULL; // The last Python signal sender.static int isSameSlot(sipSlot *,PyObject *,const char *);static int emitQtSig(sipWrapper *,const char *,PyObject *);static int emitToSlotList(sipPySigRx *,PyObject *);static int addSlotToPySigList(sipWrapper *,const char *,PyObject *,const char *);static void removeSlotFromPySigList(sipWrapper *,const char *,PyObject *,const char *);static PyObject *getWeakRef(PyObject *obj);static sipPySig *findPySignal(sipWrapper *,const char *);static char *sipStrdup(const char *);static int saveSlot(sipSlot *sp, PyObject *rxObj, const char *slot);static sipSignature *parseSignature(const char *sig);static void *createUniversalSlot(sipWrapper *txSelf, const char *sig, PyObject *rxObj, const char *slot, const char **member);static void *findSignal(void *txrx, const char **sig);static void *newSignal(void *txrx, const char **sig);static void freeSlot(sipSlot *slot);// Return the most recent signal sender.PyObject *sip_api_get_sender(){ PyObject *sender; const void *qt_sender; // If there is a Qt sender then it is more recent than the last Python // sender, so use it instead. if ((qt_sender = sipQtSupport->qt_get_sender()) != NULL) sender = sip_api_convert_from_instance(qt_sender, sipQObjectClass, NULL); else { if ((sender = py_sender) == NULL) sender = Py_None; Py_INCREF(sender); } return sender;}// Release the resources held by a connection.void sip_api_free_connection(sipSlotConnection *conn){ freeSlot(&conn->sc_slot);}// Compare two connections and return TRUE if they are the same.int sip_api_same_connection(sipSlotConnection *conn, void *tx, const char *sig, PyObject *rxObj, const char *slot){ return (conn->sc_transmitter == tx && sipQtSupport->qt_same_name(conn->sc_signature->sg_signature, sig) && isSameSlot(&conn->sc_slot, rxObj, slot));}// Parse the signal arguments for a connection.static sipSignature *parseSignature(const char *sig){ static sipSignature *psig_list = NULL; sipSignature *psig; const char *sp, *ep; // First see if it has already been parsed. Note that both sides of a // connection will probably be parsed twice because the function names // will be different even though the signatures will probably be the // same. We could be more clever, the most saving is when repeatedly // emitting a signal for which this is sufficient. for (psig = psig_list; psig != NULL; psig = psig->sg_next) if (sipQtSupport->qt_same_name(psig->sg_signature, sig)) return psig; // Create a new one including space for the copy of the signature. */ if ((psig = (sipSignature *)sip_api_malloc(sizeof (sipSignature) + strlen(sig) + 1)) == NULL) return NULL; psig->sg_signature = (char *)&psig[1]; psig->sg_nrargs = 0; psig->sg_args = 0; // Find the start and end of the arguments. sp = strchr(sig, '('); ep = strrchr(sig, ')'); // If the signal isn't well formed we assume Qt will pick it up. if (sp && ep && sp < ep) { // Copy the signature arguments while counting them and // removing non-significant spaces. Each argument is left as a // '\0' terminated string. char *dp = psig->sg_signature; int depth = 0, nrcommas = 0, argstart = TRUE; for (;;) { char ch = *++sp; if (strchr(",*&)<>", ch)) { // Backup over any previous trailing space. if (dp > psig->sg_signature && dp[-1] == ' ') --dp; if (sp == ep) { *dp = '\0'; break; } if (ch == ',' && depth == 0) { *dp++ = '\0'; ++nrcommas; argstart = TRUE; } else { *dp++ = ch; // Make sure commas in template // arguments are ignored. if (ch == '<') ++depth; else if (ch == '>') --depth; } } else if (ch == ' ') { // Ignore leading and multiple spaces. if (!argstart && dp[-1] != ' ') *dp++ = ch; } else { *dp++ = ch; argstart = FALSE; } } // Handle the arguments now they are in a normal form. if (*psig->sg_signature) { char *arg = psig->sg_signature; int a; // Allocate the space. psig->sg_nrargs = nrcommas + 1; if ((psig->sg_args = (sipSigArg *)sip_api_malloc(sizeof (sipSigArg) * psig->sg_nrargs)) == NULL) { sip_api_free(psig); return -1; } for (a = 0; a < psig->sg_nrargs; ++a) { size_t btlen = 0; int unsup, isref = FALSE, indir = 0; sipSigArgType sat = unknown_sat; // Find the start of the significant part of // the type. dp = arg; if (strncmp(dp, "const ", 6) == 0) dp += 6; // Find the length of the base type, the number // of indirections and if it is a reference. for (ep = dp; *ep; ++ep) if (*ep == '&') isref = TRUE; else if (*ep == '*') ++indir; else ++btlen; // Assume that anything other than a base type // is unsupported. unsup = (isref || indir); // Parse the base type. switch (btlen) { case 3: if (strncmp(dp, "int", 3) == 0) sat = int_sat; break; case 4: if (strncmp(dp, "bool", 4) == 0) sat = bool_sat; else if (strncmp(dp, "long", 4) == 0) sat = long_sat; else if (strncmp(dp, "char", 4) == 0) { sat = (indir ? string_sat : char_sat); unsup = (isref || indir > 1); } else if (strncmp(dp, "void", 4) == 0) { sat = void_sat; unsup = (isref || indir != 1); } break; case 5: if (strncmp(dp, "float", 5) == 0) sat = float_sat; else if (strncmp(dp, "short", 5) == 0) sat = short_sat; break; case 6: if (strncmp(dp, "double", 6) == 0) sat = double_sat; break; case 8: if (strncmp(dp, "unsigned", 8) == 0) sat = uint_sat; else if (strncmp(dp, "QVariant", 8) == 0) { if (indir == 0) { sat = qvariant_sat; unsup = FALSE; } else if (indir == 1) { sat = qvariantp_sat; unsup = FALSE; } } else if (strncmp(dp, "PyObject", 8) == 0 && indir == 1) { sat = pyobject_sat; unsup = FALSE; } break; case 9: if (strncmp(dp, "long long", 9) == 0) sat = longlong_sat; break; case 11: if (strncmp(dp, "signed char", 11) == 0) { sat = (indir ? sstring_sat : schar_sat); unsup = (isref || indir > 1); } break; case 12: if (strncmp(dp, "unsigned int", 12) == 0) sat = uint_sat; break; case 13: if (strncmp(dp, "unsigned long", 13) == 0) sat = ulong_sat; else if (strncmp(dp, "unsigned char", 13) == 0) { sat = (indir ? ustring_sat : uchar_sat); unsup = (isref || indir > 1); } break; case 14: if (strncmp(dp, "unsigned short", 14) == 0) sat = ushort_sat; break; case 18: if (strncmp(dp, "unsigned long long", 18) == 0) sat = ulonglong_sat; break; } if (sat == unknown_sat) sipFindSigArgType(dp, btlen, &psig->sg_args[a], indir); else { if (unsup) sat = unknown_sat; psig->sg_args[a].atype = sat; } // Move to the start of the next argument. arg += strlen(arg) + 1; } } } // Make a deep copy of the signal. strcpy(psig->sg_signature, sig); // Add it to the list so it can be re-used. psig->sg_next = psig_list; psig_list = psig; return psig;}// Find an existing signal.static void *findSignal(void *txrx, const char **sig){ sipSignature *psig; /* * Handle the trivial case where the Qt implementation doesn't support * universal signals. */ if (sipQtSupport->qt_is_qt_signal == NULL) return txrx; /* See if this a shortcircuited Python signal. */ if (strchr(*sig, '(') == NULL) return sipQtSupport->qt_find_universal_signal_shortcut(txrx, *sig, sig); /* See if the existing object can be used itself. */ if (sipQtSupport->qt_is_qt_signal(txrx, *sig)) return txrx; if ((psig = parseSignature(*sig)) == NULL) return NULL; /* Find an ordinary universal signal. */ return sipQtSupport->qt_find_universal_signal(txrx, psig);}// Return a usable signal, creating a new universal signal if needed.static void *newSignal(void *txrx, const char **sig){ sipSignature *psig; /* * Handle the trivial case where the Qt implementation doesn't support * universal signals. */ if (sipQtSupport->qt_is_qt_signal == NULL) return txrx; /* See if this a shortcircuited Python signal. */ if (strchr(*sig, '(') == NULL) return sipQtSupport->qt_create_universal_signal_shortcut(txrx, *sig, sig); /* See if the existing object can be used itself. */ if (sipQtSupport->qt_is_qt_signal(txrx, *sig)) return txrx; if ((psig = parseSignature(*sig)) == NULL) return NULL; /* Create an ordinary universal signal. */ return sipQtSupport->qt_create_universal_signal(txrx, psig);}// 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){ sipSlotConnection conn; void *us; // Initialise the connection. conn.sc_transmitter = (txSelf ? sipGetAddress(txSelf) : 0); // Save the real slot. if (saveSlot(&conn.sc_slot, rxObj, slot) < 0) return 0; // Parse the signature and create the universal slot. if ((conn.sc_signature = parseSignature(sig)) == NULL || (us = sipQtSupport->qt_create_universal_slot(txSelf, &conn, member)) == NULL) { sip_api_free_connection(&conn); return 0; } return us;}// Emit a Python or Qt signal.int sip_api_emit_signal(PyObject *self,const char *sig,PyObject *sigargs){ sipPySig *ps; void *tx; sipWrapper *w = (sipWrapper *)self; // Don't do anything if signals are blocked. Qt signals would be // blocked anyway, but this blocks Python signals as well. if ((tx = sip_api_get_cpp_ptr(w, sipQObjectClass)) == NULL || sipQtSupport->qt_signals_blocked(tx)) return 0; if (isQtSignal(sig)) { sipSignature *psig; /* Handle Qt implementations that emit using generated code. */ if (!sipQtSupport->qt_emit_signal) return emitQtSig(w, sig, sigargs); /* See if the signal is a shortcut. */ if (strchr(sig, '(') == NULL) return sipQtSupport->qt_emit_signal_shortcut(tx, sig, sigargs); if ((psig = parseSignature(sig)) == NULL) return -1; if (psig->sg_nrargs != PyTuple_GET_SIZE(sigargs)) PyErr_Format(PyExc_TypeError, "Signal has %d arguments, but %d given", psig->sg_nrargs, PyTuple_GET_SIZE(sigargs)); return sipQtSupport->qt_emit_signal(tx, psig, sigargs); } if ((ps = findPySignal(w,sig)) != NULL) { int rc; // Forget the last Qt sender and remember this one. sipQtSupport->qt_forget_sender(); py_sender = self; rc = emitToSlotList(ps -> rxlist,sigargs); // Forget this as a sender. py_sender = NULL; return rc; } return 0;}// Search the Python signal list for a signal.static sipPySig *findPySignal(sipWrapper *w,const char *sig){ sipPySig *ps; for (ps = w -> pySigList; ps != NULL; ps = ps -> next) if (sipQtSupport->qt_same_name(ps -> name,sig)) return ps; return NULL;}// Search a signal table for a signal. If found, call the emitter function// with the signal arguments. Return 0 if the signal was emitted or <0 if// there was an error.static int emitQtSig(sipWrapper *w,const char *sig,PyObject *sigargs){ sipQtSignal *tab; // Search the table. for (tab = ((sipWrapperType *)(w -> ob_type)) -> type -> td_emit; tab -> st_name != NULL; ++tab) { const char *sp, *tp; int found; // Compare only the base name. sp = &sig[1]; tp = tab -> st_name; found = TRUE; while (*sp != '\0' && *sp != '(' && *tp != '\0') if (*sp++ != *tp++) { found = FALSE; break; } if (found) return (*tab -> st_emitfunc)(w,sigargs); } // It wasn't found if we got this far. PyErr_Format(PyExc_NameError,"Invalid signal %s",&sig[1]); return -1;}// Send a signal to a single slot (Qt or Python).int sip_api_emit_to_slot(sipSlot *slot, PyObject *sigargs){ PyObject *sa, *oxtype, *oxvalue, *oxtb, *sfunc, *newmeth, *sref; // Keep some compilers quiet. oxtype = oxvalue = oxtb = NULL; // Fan out Qt signals. if (slot -> name != NULL && slot -> name[0] != '\0') return sip_api_emit_signal(slot -> pyobj,slot -> name,sigargs); // Get the object to call, resolving any weak references. if (slot -> weakSlot == NULL) sref = NULL; else if ((sref = PyWeakref_GetObject(slot -> weakSlot)) == NULL) return -1; else Py_INCREF(sref); if (sref == Py_None) { // If the real object has gone then we pretend everything is // Ok. This mimics the Qt behaviour of not caring if a // receiving object has been deleted. Py_DECREF(sref); return 0; } if (slot -> pyobj == NULL) { PyObject *self = (sref != NULL ? sref : slot->meth.mself); // See if any underlying C++ instance has gone. if (self != NULL && sip_api_wrapper_check(self) && ((sipWrapper *)self)->u.cppPtr == NULL) { Py_XDECREF(sref);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -