// This is the SIP interface definition for TQObject.
//
// Copyright (c) 2007
// 	Riverbank Computing Limited <info@riverbankcomputing.co.uk>
// 
// This file is part of PyTQt.
// 
// This copy of PyTQt is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2, or (at your option) any later
// version.
// 
// PyTQt 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
// PyTQt; see the file LICENSE.  If not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


%ExportedDoc
<Sect2><Title>TQObject</Title>
<FuncSynopsis>
	<FuncDef>bool <Function>disconnect</Function></FuncDef>
	<ParamDef>const TQObject *<Parameter>receiver</Parameter></ParamDef>
	<ParamDef>const char *<Parameter>member</Parameter> = 0</ParamDef>
</FuncSynopsis>
<Para>
Not yet implemented.
</Para>

<FuncSynopsis>
	<FuncDef>bool <Function>disconnect</Function></FuncDef>
	<ParamDef>const char *<Parameter>signal</Parameter> = 0</ParamDef>
	<ParamDef>const TQObject *<Parameter>receiver</Parameter> = 0</ParamDef>
	<ParamDef>const char *<Parameter>member</Parameter> = 0</ParamDef>
</FuncSynopsis>
<Para>
Not yet implemented.
</Para>

<FuncSynopsis>
	<FuncDef>static bool <Function>disconnect</Function></FuncDef>
	<ParamDef>const TQObject *<Parameter>sender</Parameter></ParamDef>
	<ParamDef>const char *<Parameter>signal</Parameter></ParamDef>
	<ParamDef>const TQObject *<Parameter>receiver</Parameter></ParamDef>
	<ParamDef>const char *<Parameter>member</Parameter></ParamDef>
</FuncSynopsis>
<Para>
At the moment PyTQt does not support the full behaviour of the corresponding TQt
method. In particular, specifying None (ie. 0 in C++) for the
<Literal>signal</Literal> and <Literal>receiver</Literal> parameters is not yet
supported.
</Para>
</Sect2>
%End


class TQObject : TQt
{
%TypeHeaderCode
#include <tqobject.h>
#include <tqapplication.h>
%End

public:
	TQObject(TQObject * /TransferThis/ = 0,const char * = 0);

%ConvertToSubClassCode
	static struct class_graph {
		const char *name;
		sipWrapperType **type;
		int yes, no;
	} graph[] = {
		{sipName_TQWidget,	&sipClass_TQWidget,	25, 1},
#if defined(SIP_FEATURE_TQt_ASSISTANTCLIENT)
		{sipName_TQAssistantClient,	&sipClass_TQAssistantClient,	-1, 2},
#else
		{NULL,				NULL,				-1, 2},
#endif
		{sipName_TQSessionManager,	&sipClass_TQSessionManager,	-1, 3},
		{sipName_TQTranslator,	&sipClass_TQTranslator,	-1, 4},
		{sipName_TQProcess,	&sipClass_TQProcess,	-1, 5},
		{sipName_TQToolTipGroup,	&sipClass_TQToolTipGroup,	-1, 6},
#if defined(SIP_FEATURE_TQt_FILEDIALOG)
		{sipName_TQFileIconProvider,	&sipClass_TQFileIconProvider,	-1, 7},
#else
		{NULL,				NULL,				-1, 7},
#endif
#if defined(SIP_FEATURE_TQt_ACTION)
		{sipName_TQAction,	&sipClass_TQAction,	89, 8},
#else
		{NULL,			NULL,			-1, 8},
#endif
		{sipName_TQObjectCleanupHandler,	&sipClass_TQObjectCleanupHandler,	-1, 9},
		{sipName_TQTimer,	&sipClass_TQTimer,	-1, 10},
		{sipName_TQLayout,	&sipClass_TQLayout,	90, 11},
#if defined(SIP_FEATURE_TQt_NETWORKPROTOCOL)
		{sipName_TQUrlOperator,	&sipClass_TQUrlOperator,	-1, 12},
#else
		{NULL,			NULL,			-1, 12},
#endif
		{sipName_TQStyleSheet,	&sipClass_TQStyleSheet,	-1, 13},
		{sipName_TQValidator,	&sipClass_TQValidator,	94, 14},
#if defined(SIP_FEATURE_TQt_NETWORKPROTOCOL)
		{sipName_TQNetworkOperation,	&sipClass_TQNetworkOperation,	-1, 15},
#else
		{NULL,				NULL,				-1, 15},
#endif
		{sipName_TQAccel,	&sipClass_TQAccel,	-1, 16},
		{sipName_TQEventLoop,	&sipClass_TQEventLoop,	-1, 17},
#if defined(SIP_FEATURE_TQt_NETWORKPROTOCOL)
		{sipName_TQNetworkProtocol,	&sipClass_TQNetworkProtocol,	-1, 18},
#else
		{NULL,				NULL,				-1, 18},
#endif
#if defined(SIP_FEATURE_TQt_SOUND)
		{sipName_TQSound,	&sipClass_TQSound,	-1, 19},
#else
		{NULL,			NULL,			-1, 19},
#endif
		{sipName_TQApplication,	&sipClass_TQApplication,	-1, 20},
		{sipName_TQDragObject,	&sipClass_TQDragObject,	97, 21},
		{sipName_TQSocketNotifier,	&sipClass_TQSocketNotifier,	-1, 22},
		{sipName_TQStyle,	&sipClass_TQStyle,	103, 23},
		{sipName_TQSignalMapper,	&sipClass_TQSignalMapper,	-1, 24},
#if defined(SIP_FEATURE_TQt_CLIPBOARD)
		{sipName_TQClipboard,	&sipClass_TQClipboard,	-1, -1},
#else
		{NULL,			NULL,			-1, -1},
#endif
		{sipName_TQStatusBar,	&sipClass_TQStatusBar,	-1, 26},
#if defined(SIP_FEATURE_TQt_SIZEGRIP)
		{sipName_TQSizeGrip,	&sipClass_TQSizeGrip,	-1, 27},
#else
		{NULL,			NULL,			-1, 27},
#endif
		{sipName_TQTabWidget,	&sipClass_TQTabWidget,	-1, 28},
		{sipName_TQDateEdit,	&sipClass_TQDateEdit,	-1, 29},
		{sipName_TQMainWindow,	&sipClass_TQMainWindow,	-1, 30},
		{sipName_TQDateTimeEdit,	&sipClass_TQDateTimeEdit,	-1, 31},
		{sipName_TQTimeEdit,	&sipClass_TQTimeEdit,	-1, 32},
		{sipName_TQFrame,	&sipClass_TQFrame,	46, 33},
		{sipName_TQScrollBar,	&sipClass_TQScrollBar,	-1, 34},
#if defined(SIP_FEATURE_TQt_DIAL)
		{sipName_TQDial,		&sipClass_TQDial,	-1, 35},
#else
		{NULL,			NULL,			-1, 35},
#endif
		{sipName_TQButton,	&sipClass_TQButton,	75, 36},
		{sipName_TQTabBar,	&sipClass_TQTabBar,	-1, 37},
		{sipName_TQDialog,	&sipClass_TQDialog,	79, 38},
		{sipName_TQComboBox,	&sipClass_TQComboBox,	-1, 39},
		{sipName_TQHeader,	&sipClass_TQHeader,	-1, 40},
		{sipName_TQDockArea,	&sipClass_TQDockArea,	-1, 41},
		{sipName_TQSplashScreen,	&sipClass_TQSplashScreen,	-1, 42},
		{sipName_TQSlider,	&sipClass_TQSlider,	-1, 43},
		{sipName_TQSpinBox,	&sipClass_TQSpinBox,	-1, 44},
#if defined(SIP_FEATURE_TQt_WORKSPACE)
		{sipName_TQWorkspace,	&sipClass_TQWorkspace,	-1, 45},
#else
		{NULL,			NULL,			-1, 45},
#endif
		{sipName_TQDesktopWidget,	&sipClass_TQDesktopWidget,	-1, -1},
		{sipName_TQGrid,	&sipClass_TQGrid,	-1, 47},
		{sipName_TQLineEdit,	&sipClass_TQLineEdit,	-1, 48},
		{sipName_TQToolBox,	&sipClass_TQToolBox,	-1, 49},
		{sipName_TQWidgetStack,	&sipClass_TQWidgetStack,	-1, 50},
		{sipName_TQDockWindow,	&sipClass_TQDockWindow,	60, 51},
		{sipName_TQMenuBar,	&sipClass_TQMenuBar,	-1, 52},
		{sipName_TQLabel,	&sipClass_TQLabel,	-1, 53},
		{sipName_TQGroupBox,	&sipClass_TQGroupBox,	61, 54},
		{sipName_TQPopupMenu,	&sipClass_TQPopupMenu,	-1, 55},
#if defined(SIP_FEATURE_TQt_SPLITTER)
		{sipName_TQSplitter,	&sipClass_TQSplitter,	-1, 56},
#else
		{NULL,			NULL,			-1, 56},
#endif
		{sipName_TQProgressBar,	&sipClass_TQProgressBar,	-1, 57},
		{sipName_TQScrollView,	&sipClass_TQScrollView,	66, 58},
		{sipName_TQHBox,		&sipClass_TQHBox,	74, 59},
		{sipName_TQLCDNumber,	&sipClass_TQLCDNumber,	-1, -1},
		{sipName_TQToolBar,	&sipClass_TQToolBar,	-1, -1},
		{sipName_TQButtonGroup,	&sipClass_TQButtonGroup,	64, 62},
		{sipName_TQHGroupBox,	&sipClass_TQHGroupBox,	-1, 63},
		{sipName_TQVGroupBox,	&sipClass_TQVGroupBox,	-1, -1},
		{sipName_TQVButtonGroup,	&sipClass_TQVButtonGroup,	-1, 65},
		{sipName_TQHButtonGroup,	&sipClass_TQHButtonGroup,	-1, -1},
#if defined(SIP_FEATURE_TQt_ICONVIEW)
		{sipName_TQIconView,	&sipClass_TQIconView,	-1, 67},
#else
		{NULL,			NULL,			-1, 67},
#endif
		{sipName_TQListView,	&sipClass_TQListView,	-1, 68},
		{sipName_TQListBox,	&sipClass_TQListBox,	-1, 69},
		{sipName_TQGridView,	&sipClass_TQGridView,	-1, 70},
		{sipName_TQTextEdit,	&sipClass_TQTextEdit,	71, -1},
		{sipName_TQTextBrowser,	&sipClass_TQTextBrowser,	-1, 72},
		{sipName_TQMultiLineEdit,	&sipClass_TQMultiLineEdit,	-1, 73},
		{sipName_TQTextView,	&sipClass_TQTextView,	-1, -1},
		{sipName_TQVBox,		&sipClass_TQVBox,	-1, -1},
		{sipName_TQToolButton,	&sipClass_TQToolButton,	-1, 76},
		{sipName_TQRadioButton,	&sipClass_TQRadioButton,	-1, 77},
		{sipName_TQPushButton,	&sipClass_TQPushButton,	-1, 78},
		{sipName_TQCheckBox,	&sipClass_TQCheckBox,	-1, -1},
#if defined(WS_X11) && defined(SIP_FEATURE_TQt_PRINTDIALOG)
		{sipName_TQPrintDialog,	&sipClass_TQPrintDialog,	-1, 80},
#else
		{NULL,			NULL,			-1, 80},
#endif
		{sipName_TQErrorMessage,	&sipClass_TQErrorMessage,	-1, 81},
#if defined(SIP_FEATURE_TQt_INPUTDIALOG)
		{sipName_TQInputDialog,	&sipClass_TQInputDialog,	-1, 82},
#else
		{NULL,			NULL,			-1, 82},
#endif
#if defined(SIP_FEATURE_TQt_MESSAGEBOX)
		{sipName_TQMessageBox,	&sipClass_TQMessageBox,	-1, 83},
#else
		{NULL,			NULL,			-1, 83},
#endif
#if defined(SIP_FEATURE_TQt_WIZARD)
		{sipName_TQWizard,	&sipClass_TQWizard,	-1, 84},
#else
		{NULL,			NULL,			-1, 84},
#endif
#if defined(SIP_FEATURE_TQt_COLORDIALOG)
		{sipName_TQColorDialog,	&sipClass_TQColorDialog,	-1, 85},
#else
		{NULL,			NULL,			-1, 85},
#endif
#if defined(SIP_FEATURE_TQt_FONTDIALOG)
		{sipName_TQFontDialog,	&sipClass_TQFontDialog,	-1, 86},
#else
		{NULL,			NULL,			-1, 86},
#endif
#if defined(SIP_FEATURE_TQt_FILEDIALOG)
		{sipName_TQFileDialog,	&sipClass_TQFileDialog,	-1, 87},
#else
		{NULL,			NULL,			-1, 87},
#endif
#if defined(SIP_FEATURE_TQt_PROGRESSDIALOG)
		{sipName_TQProgressDialog,	&sipClass_TQProgressDialog,	-1, 88},
#else
		{NULL,				NULL,				-1, 88},
#endif
#if defined(SIP_FEATURE_TQt_TABDIALOG)
		{sipName_TQTabDialog,	&sipClass_TQTabDialog,	-1, -1},
#else
		{NULL,			NULL,			-1, -1},
#endif
#if defined(SIP_FEATURE_TQt_ACTION)
		{sipName_TQActionGroup,	&sipClass_TQActionGroup,	-1, -1},
#else
		{NULL,			NULL,			-1, -1},
#endif
		{sipName_TQGridLayout,	&sipClass_TQGridLayout,	-1, 91},
		{sipName_TQBoxLayout,	&sipClass_TQBoxLayout,	92, -1},
		{sipName_TQHBoxLayout,	&sipClass_TQHBoxLayout,	-1, 93},
		{sipName_TQVBoxLayout,	&sipClass_TQVBoxLayout,	-1, -1},
		{sipName_TQDoubleValidator,	&sipClass_TQDoubleValidator,	-1, 95},
		{sipName_TQIntValidator,	&sipClass_TQIntValidator,	-1, 96},
		{sipName_TQRegExpValidator,	&sipClass_TQRegExpValidator,	-1, -1},
		{sipName_TQTextDrag,	&sipClass_TQTextDrag,	-1, 98},
		{sipName_TQStoredDrag,	&sipClass_TQStoredDrag,	101, 99},
#if defined(SIP_FEATURE_TQt_ICONVIEW) && defined(SIP_FEATURE_TQt_DRAGANDDROP)
		{sipName_TQIconDrag,	&sipClass_TQIconDrag,	-1, 100},
#else
		{NULL,			NULL,			-1, 100},
#endif
		{sipName_TQImageDrag,	&sipClass_TQImageDrag,	-1, -1},
		{sipName_TQColorDrag,	&sipClass_TQColorDrag,	-1, 102},
		{sipName_TQUriDrag,	&sipClass_TQUriDrag,	-1, -1},
		{sipName_TQCommonStyle,	&sipClass_TQCommonStyle,	104, -1},
#if defined(SIP_FEATURE_TQt_STYLE_WINDOWS)
		{sipName_TQWindowsStyle,	&sipClass_TQWindowsStyle,	106, 105},
#else
		{NULL,			NULL,				-1, 105},
#endif
#if defined(SIP_FEATURE_TQt_STYLE_MOTIF)
		{sipName_TQMotifStyle,	&sipClass_TQMotifStyle,	107, -1},
#else
		{NULL,			NULL,			-1, -1},
#endif
#if defined(SIP_FEATURE_TQt_STYLE_PLATINUM)
		{sipName_TQPlatinumStyle,	&sipClass_TQPlatinumStyle,	-1, 110},
#else
		{NULL,				NULL,				-1, 110},
#endif
#if defined(SIP_FEATURE_TQt_STYLE_CDE)
		{sipName_TQCDEStyle,	&sipClass_TQCDEStyle,	-1, 108},
#else
		{NULL,			NULL,			-1, 108},
#endif
#if defined(SIP_FEATURE_TQt_STYLE_MOTIFPLUS)
		{sipName_TQMotifPlusStyle,	&sipClass_TQMotifPlusStyle,	-1, 109},
#else
		{NULL,				NULL,				-1, 109},
#endif
#if defined(SIP_FEATURE_TQt_STYLE_SGI)
		{sipName_TQSGIStyle,	&sipClass_TQSGIStyle,	-1, -1},
#else
		{NULL,			NULL,			-1, -1},
#endif
#if defined(PYTQT_STYLE_WINDOWSXP)
		{sipName_TQWindowsXPStyle,	&sipClass_TQWindowsXPStyle,	-1, -1},
#else
		{NULL,				NULL,				-1, -1},
#endif
	};

	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

	// This is really virtual.  With the way we are implementing it doesn't
	// need to be and has the advantage that the C++ implementation can be
	// used in %ConvertToSubClassCode to get the C++ name for Python
	// sub-classes.  However, it is also means that C++ plugins can't get
	// the true (Python) class name.
	SIP_PYOBJECT className() const;
%MethodCode
		sipRes = PyUnicode_FromString(sipSelf->ob_type->tp_name);
%End

	// Note that tr() and trUtf8() are really static methods.  We pretend
	// they aren't so that we can use self to get hold of the class name.
	// We could mimic moc's behaviour more accurately by creating tr() and
	// trUtf8() methods for a Python sub-class instance in the sub-class's
	// ctor.

	TQString tr(SIP_PYOBJECT sourceText /TypeHint="str"/,const char * = 0);
%MethodCode
		if (tqApp)
		{
			const char *source = PyTQt_tqt_encode(&a0, TQApplication::DefaultCodec);

			if (source)
			{
				sipRes = new TQString(tqApp->translate(Py_TYPE(sipSelf)->tp_name, source,
					a1, TQApplication::DefaultCodec));
				Py_DECREF(a0);
			}
			else
			{
				sipIsErr = 1;
			}
		}
		else
		{
			const char *source = sipString_AsUTF8String(&a0);

			if (source)
			{
				sipRes = new TQString(TQString::fromUtf8(source));
				Py_DECREF(a0);
			}
			else
			{
				sipIsErr = 1;
			}
		}
%End

	TQString trUtf8(SIP_PYOBJECT sourceText /TypeHint="str"/,const char * = 0);
%MethodCode
		if (tqApp)
		{
			const char *source = PyTQt_tqt_encode(&a0, TQApplication::DefaultCodec);

			if (source)
			{
				sipRes = new TQString(tqApp->translate(Py_TYPE(sipSelf)->tp_name, source,
					a1, TQApplication::UnicodeUTF8));
				Py_DECREF(a0);
			}
			else
			{
				sipIsErr = 1;
			}
		}
		else
		{
			const char *source = sipString_AsUTF8String(&a0);

			if (source)
			{
				sipRes = new TQString(TQString::fromUtf8(source));
				Py_DECREF(a0);
			}
			else
			{
				sipIsErr = 1;
			}
		}
%End
	virtual TQMetaObject *metaObject() const /AutoGen/;
	virtual bool event(TQEvent *);
	virtual bool eventFilter(TQObject *,TQEvent *);

	bool isA(const char *) const;
%MethodCode
		// The TQt implementation doesn't know anything about Python
		// sub-classes.  For SIP v4 we use the Python type's name.  For
		// SIP v3 we use the broken TQt behaviour as it's deprecated and
		// we want to keep things simple.

#if SIP_VERSION >= 0x040000
		sipRes = (strcmp(sipSelf -> ob_type -> tp_name,a0) == 0);
#else
		Py_BEGIN_ALLOW_THREADS
		sipRes = sipCpp -> TQObject::isA(a0);
		Py_END_ALLOW_THREADS
#endif
%End

	bool inherits(const char *) const;
%MethodCode
		// The TQt implementation doesn't know anything about Python
		// sub-classes.  For SIP v4 we use the Python type's MRO.  For
		// SIP v3 we use the broken TQt behaviour as it's deprecated and
		// we want to keep things simple.

#if SIP_VERSION >= 0x040000
		PyObject *mro = sipSelf -> ob_type -> tp_mro;

		sipRes = 0;

		for (int i = 0; i < PyTuple_GET_SIZE(mro); ++i)
			if (strcmp(((PyTypeObject *)PyTuple_GET_ITEM(mro,i)) -> tp_name,a0) == 0)
			{
				sipRes = 1;
				break;
			}
#else
		Py_BEGIN_ALLOW_THREADS
		sipRes = sipCpp -> TQObject::inherits(a0);
		Py_END_ALLOW_THREADS
#endif
%End

	const char *name() const;
	const char *name(const char *) const;
	virtual void setName(const char *);
	bool isWidgetType() const;
	bool highPriority() const;
	bool signalsBlocked() const;
	void blockSignals(bool);
	int startTimer(int);
	void killTimer(int);
	void killTimers();
	TQObject *child(const char *,const char * = 0,bool = 1);
	const TQObjectList *children() const;
	static const TQObjectList *objectTrees();

	TQObjectList *queryList(char * = 0,char * = 0,bool = 1,bool = 1) const;
%MethodCode
		// The TQt implementation doesn't know anything about Python
		// sub-classes.  For SIP v4 we get all classes and then use the
		// Python type's MRO to weed out those we don't want.  For SIP
		// v3 we use the broken TQt behaviour as it's deprecated and we
		// want to keep things simple.

#if SIP_VERSION >= 0x040000
		sipRes = sipCpp -> TQObject::queryList(0, a1, a2, a3);

		if (a0 && sipRes)
		{
			TQObject *o = sipRes -> first();

			while (o)
			{
				bool remove = true;
				PyObject *pyo = sipConvertFromInstance(o, sipClass_TQObject, 0);

				if (pyo)
				{
					PyObject *mro = pyo -> ob_type -> tp_mro;

					for (int i = 0; i < PyTuple_GET_SIZE(mro); ++i)
						if (strcmp(((PyTypeObject *)PyTuple_GET_ITEM(mro,i)) -> tp_name,a0) == 0)
						{
							remove = false;
							break;
						}

					Py_DECREF(pyo);
				}

				if (remove)
				{
					sipRes -> remove();
					o = sipRes -> current();
				}
				else
					o = sipRes -> next();
			}
		}
#else
		Py_BEGIN_ALLOW_THREADS
		sipRes = sipCpp -> TQObject::queryList(a0, a1, a2, a3);
		Py_END_ALLOW_THREADS
#endif
%End

	virtual void insertChild(TQObject * /Transfer/);
	virtual void removeChild(TQObject * /TransferBack/);
	void installEventFilter(const TQObject *);
	void removeEventFilter(const TQObject *);

	static SIP_PYOBJECT connect(SIP_TQOBJECT,SIP_SIGNAL,SIP_TQOBJECT,SIP_SLOT);
%MethodCode
		sipRes = sipConnectRx(a0,a1,a2,a3,0);
%End

	static SIP_PYOBJECT connect(SIP_TQOBJECT,SIP_SIGNAL,SIP_PYCALLABLE);
%MethodCode
		sipRes = sipConnectRx(a0,a1,a2,0,0);
%End

	SIP_PYOBJECT connect(SIP_TQOBJECT,SIP_SIGNAL,SIP_SLOT) const;
%MethodCode
		sipRes = sipConnectRx(a0,a1,sipSelf,a2,0);
%End

	static SIP_PYOBJECT disconnect(SIP_TQOBJECT,SIP_SIGNAL,SIP_TQOBJECT,SIP_SLOT);
%MethodCode
		sipRes = sipDisconnectRx(a0,a1,a2,a3);
%End

	static SIP_PYOBJECT disconnect(SIP_TQOBJECT,SIP_SIGNAL,SIP_PYCALLABLE);
%MethodCode
		sipRes = sipDisconnectRx(a0,a1,a2,0);
%End

//	bool disconnect(const char * = 0,const TQObject * = 0,const char * = 0);
//	bool disconnect(const TQObject *,const char * = 0);
	void dumpObjectTree();
	void dumpObjectInfo();
	TQObject *parent() const;

	void emit(SIP_SIGNAL,SIP_PYTUPLE);
%MethodCode
		if (pytqtEmitSignal(sipSelf, a0, a1) < 0)
			sipIsErr = 1;
%End

%If (TQt_PROPERTIES)
	virtual bool setProperty(const char *,const TQVariant &);
	virtual TQVariant property(const char *) const;
%End

signals:
	void destroyed();
	void destroyed(TQObject *);

public slots:
	void deleteLater();

public:
	// This is actually protected, but we never need to call the real
	// method.
	SIP_PYOBJECT sender();
%MethodCode
		sipRes = pytqt3GetSender();
%End

protected:
	virtual void timerEvent(TQTimerEvent *);
	virtual void childEvent(TQChildEvent *);
	virtual void customEvent(TQCustomEvent *);

private:
	TQObject(const TQObject &);
};


SIP_PYOBJECT TQT_TR_NOOP(SIP_PYOBJECT);
%MethodCode
	Py_INCREF(a0);
	sipRes = a0;
%End


SIP_PYOBJECT TQT_TRANSLATE_NOOP(SIP_PYOBJECT,SIP_PYOBJECT);
%MethodCode
	Py_INCREF(a1);
	sipRes = a1;
%End


SIP_PYOBJECT TQ_SLOT(const char * /Encoding="ASCII"/) /TypeHint="TQ_SLOT"/;
%MethodCode
	if (!a0)
	{
		PyErr_Format(PyExc_TypeError,"tqt.TQ_SLOT() slot name cannot be None");
		sipIsErr = 1;
	}
	else
	{
		int len = strlen(a0);

		if ((sipRes = PyBytes_FromStringAndSize(NULL,1 + len)) == NULL)
			sipIsErr = 1;
		else
		{
			char *dp = PyBytes_AS_STRING(sipRes);

			*dp++ = '1';

			memcpy(dp,a0,len + 1);
		}
	}
%End


SIP_PYOBJECT TQ_SIGNAL(const char * /Encoding="ASCII"/) /TypeHint="TQ_SIGNAL"/;
%MethodCode
	if (!a0)
	{
		PyErr_Format(PyExc_TypeError,"tqt.TQ_SIGNAL() signal cannot be None");
		sipIsErr = 1;
	}
	else
	{
		int len = strlen(a0);

		if ((sipRes = PyBytes_FromStringAndSize(NULL,1 + len)) == NULL)
			sipIsErr = 1;
		else
		{
			char *dp = PyBytes_AS_STRING(sipRes);

			*dp++ = '2';

			memcpy(dp,a0,len + 1);
		}
	}
%End


SIP_PYOBJECT PYSIGNAL(const char * /Encoding="ASCII"/);
%MethodCode
	if (!a0)
	{
		PyErr_Format(PyExc_TypeError,"tqt.PYSIGNAL() signal cannot be None");
		sipIsErr = 1;
	}
	else
	{
		int len = strlen(a0);

		if ((sipRes = PyBytes_FromStringAndSize(NULL,1 + len)) == NULL)
			sipIsErr = 1;
		else
		{
			char *dp = PyBytes_AS_STRING(sipRes);

			*dp++ = '9';

			memcpy(dp,a0,len + 1);
		}
	}
%End


%ModuleHeaderCode

int pytqtEmitSignal(PyObject *self, const char *sig, PyObject *sigargs);
PyObject *pytqt3GetSender();

%End


// This is the TQt support code for SIP v4.4 and later.
%ModuleCode

#include <string.h>

#include <tqobject.h>
#include <tqvariant.h>
#include <tqmetaobject.h>
#include <private/tqucom_p.h>
#include <private/tqucomextra_p.h>


// These optional parts of the legacy TQt support API for SIP are implemented.
#undef sipTQtEmitSignal
#undef sipTQtConnectPySignal
#undef sipTQtDisconnectPySignal


// Declare explicit C linkage.
extern "C"
{
	static void *sipTQtCreateUniversalSlot(sipWrapper *, const char *,
            PyObject *, const char *, const char **, int);
	static void sipTQtDestroyUniversalSlot(void *);
	static void *sipTQtFindSlot(void *, const char *, PyObject *, const char *,
            const char **);
	static int sipTQtConnect(void *, const char *, void *, const char *, int);
	static int sipTQtDisconnect(void *, const char *, void *, const char *);
	static int sipTQtSameSignalSlotName(const char *, const char *);
    static sipSlot *sipTQtFindSipslot(void *, void **);
    static int sipTQtEmitSignal(PyObject *, const char *, PyObject *);
    static int sipTQtConnectPySignal(PyObject *, const char *, PyObject *,
            const char *);
    static void sipTQtDisconnectPySignal(PyObject *, const char *,
            PyObject *, const char *);
}


extern "C" {

// The meta-type for PyTQt classes.  It is just a marker type so that we can
// safely cast to get access to PyTQt3-specific data structures.
PyTypeObject pytqtWrapperType_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "tqt.pytqtWrapperType",   /* tp_name */
    sizeof (sipWrapperType),    /* tp_basicsize */
    0,                      /* tp_itemsize */
    0,                      /* tp_dealloc */
#if PY_VERSION_HEX >= 0x03080000
    0,                      /* tp_vectorcall_offset */
#else
    0,                      /* tp_print */
#endif
    0,                      /* tp_getattr */
    0,                      /* tp_setattr */
#if PY_VERSION_HEX >= 0x03050000
    0,                      /* tp_as_async */
#else
    0,                      /* tp_reserved */
#endif
    0,                      /* tp_repr */
    0,                      /* tp_as_number */
    0,                      /* tp_as_sequence */
    0,                      /* tp_as_mapping */
    0,                      /* tp_hash */
    0,                      /* tp_call */
    0,                      /* tp_str */
    0,                      /* tp_getattro */
    0,                      /* tp_setattro */
    0,                      /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
    0,                      /* tp_doc */
    0,                      /* tp_traverse */
    0,                      /* tp_clear */
    0,                      /* tp_richcompare */
    0,                      /* tp_weaklistoffset */
    0,                      /* tp_iter */
    0,                      /* tp_iternext */
    0,                      /* tp_methods */
    0,                      /* tp_members */
    0,                      /* tp_getset */
    0,                      /* tp_base */
    0,                      /* tp_dict */
    0,                      /* tp_descr_get */
    0,                      /* tp_descr_set */
    0,                      /* tp_dictoffset */
    0,                      /* tp_init */
    0,                      /* tp_alloc */
    0,                      /* tp_new */
    0,                      /* tp_free */
    0,                      /* tp_is_gc */
    0,                      /* tp_bases */
    0,                      /* tp_mro */
    0,                      /* tp_cache */
    0,                      /* tp_subclasses */
    0,                      /* tp_weaklist */
    0,                      /* tp_del */
    0,                      /* tp_version_tag */
    0,                      /* tp_finalize */
#if PY_VERSION_HEX >= 0x03080000
    0,                      /* tp_vectorcall */
#endif
#if PY_VERSION_HEX == 0x03080000
    0,                      /* tp_print (deprecated) */
#endif
};


/*
 * An entry in a linked list of slots.
 */
typedef struct _pytqt3SlotList {
    /* The receiver. */
    sipSlot rx;

    /* Next in the list. */
    struct _pytqt3SlotList *next;
} pytqt3SlotList;


/*
 * A Python signal.
 */
typedef struct _pytqt3PySig {
    /* The name of the signal. */
    char *name;

    /* The list of receivers. */
    pytqt3SlotList *rxlist;

    /* Next in the list. */
    struct _pytqt3PySig *next;
} pytqt3PySig;


/*
 * The C++ wrapper object used by PyTQt3.
 */
typedef struct _pytqtWrapper {
    /* The super-type. */
    sipWrapper super;

    /* The list of Python signals. */
    pytqt3PySig *pySigList;
} pytqtWrapper;


/*
 * Clear any slots connected to any Python signals.
 */
static void clear_py_signals_slots(pytqtWrapper *pw)
{
    pytqt3PySig *ps;

    for (ps = pw->pySigList; ps != NULL; ps = ps->next)
    {
        pytqt3SlotList *psrx;

        for (psrx = ps->rxlist; psrx != NULL; psrx = psrx->next)
            sipClearAnySlotReference(&psrx->rx);
    }
}


/*
 * Find the given Python signal.
 */
static pytqt3PySig *find_py_signal(pytqtWrapper *pw, const char *sig)
{
    pytqt3PySig *ps;

    for (ps = pw->pySigList; ps != NULL; ps = ps->next)
        if (sipTQtSameSignalSlotName(ps->name, sig))
            return ps;

    return 0;
}


/*
 * Free an slot list entry.
 */
static void free_slot_list(pytqt3SlotList *sl)
{
    sipFreeSipslot(&sl->rx);
    sipFree(sl);
}


/*
 * The instance clear slot.
 */
static int pytqtWrapper_clear(pytqtWrapper *self)
{
    clear_py_signals_slots(self);

    return sipWrapper_Type->tp_clear((PyObject *)self);
}


/*
 * The instance dealloc slot.
 */
static void pytqtWrapper_dealloc(pytqtWrapper *self)
{
    clear_py_signals_slots(self);

    while (self->pySigList != NULL)
    {
        pytqt3PySig *ps;
        pytqt3SlotList *psrx;

        /* Take this one out of the list. */
        ps = self->pySigList;
        self->pySigList = ps->next;

        while ((psrx = ps->rxlist) != NULL)
        {
            ps->rxlist = psrx->next;
            free_slot_list(psrx);
        }

        sipFree(ps->name);
        sipFree(ps);
    }

    sipWrapper_Type->tp_dealloc((PyObject *)self);
}


/*
 * The instance traverse slot.
 */
static int pytqtWrapper_traverse(pytqtWrapper *self, visitproc visit, void *arg)
{
    int vret;
    pytqt3PySig *ps;

    if ((vret = sipWrapper_Type->tp_traverse((PyObject *)self, visit, arg)) != 0)
        return vret;

    for (ps = self->pySigList; ps != NULL; ps = ps->next)
    {
        pytqt3SlotList *psrx;

        for (psrx = ps->rxlist; psrx != NULL; psrx = psrx->next)
            if ((vret = sipVisitSlot(&psrx->rx, visit, arg)) != 0)
                return vret;
    }

    return 0;
}


static sipWrapperType pytqtWrapper_Type = {
#if !defined(STACKLESS)
    {
#endif
        {
            PyVarObject_HEAD_INIT(&pytqtWrapperType_Type, 0)
            "tqt.pytqtWrapper",   /* tp_name */
            sizeof (pytqtWrapper),   /* tp_basicsize */
            0,              /* tp_itemsize */
            (destructor)pytqtWrapper_dealloc,    /* tp_dealloc */
#if PY_VERSION_HEX >= 0x03080000
            0,              /* tp_vectorcall_offset */
#else
            0,              /* tp_print */
#endif
            0,              /* tp_getattr */
            0,              /* tp_setattr */
#if PY_VERSION_HEX >= 0x03050000
            0,              /* tp_as_async */
#else
            0,              /* tp_reserved */
#endif
            0,              /* tp_repr */
            0,              /* tp_as_number */
            0,              /* tp_as_sequence */
            0,              /* tp_as_mapping */
            0,              /* tp_hash */
            0,              /* tp_call */
            0,              /* tp_str */
            0,              /* tp_getattro */
            0,              /* tp_setattro */
            0,              /* tp_as_buffer */
            Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /* tp_flags */
            0,              /* tp_doc */
            (traverseproc)pytqtWrapper_traverse, /* tp_traverse */
            (inquiry)pytqtWrapper_clear, /* tp_clear */
            0,              /* tp_richcompare */
            0,              /* tp_weaklistoffset */
            0,              /* tp_iter */
            0,              /* tp_iternext */
            0,              /* tp_methods */
            0,              /* tp_members */
            0,              /* tp_getset */
            0,              /* tp_base */
            0,              /* tp_dict */
            0,              /* tp_descr_get */
            0,              /* tp_descr_set */
            0,              /* tp_dictoffset */
            0,              /* tp_init */
            0,              /* tp_alloc */
            0,              /* tp_new */
            0,              /* tp_free */
            0,              /* tp_is_gc */
            0,              /* tp_bases */
            0,              /* tp_mro */
            0,              /* tp_cache */
            0,              /* tp_subclasses */
            0,              /* tp_weaklist */
            0,              /* tp_del */
            0,              /* tp_version_tag */
            0,              /* tp_finalize */
#if PY_VERSION_HEX >= 0x03080000
            0,              /* tp_vectorcall */
#endif
#if PY_VERSION_HEX == 0x03080000
            0,              /* tp_print (deprecated) */
#endif
        },
#if !defined(STACKLESS)
    },
#endif
    0,
    0,
    0
};

};


// This enumerates the different dynamic signal argument types.
enum pytqt3SigArgType {
    unknown_sat,
    char_sat,
    uchar_sat,
    string_sat,
    ustring_sat,
    short_sat,
    ushort_sat,
    int_sat,
    uint_sat,
    long_sat,
    ulong_sat,
    longlong_sat,
    ulonglong_sat,
    float_sat,
    double_sat,
    enum_sat,
    bool_sat,
    void_sat,
    class_sat,
    classp_sat,
    mtype_sat,
    mtypep_sat,
    tqvariant_sat,
    tqvariantp_sat,
    pyobject_sat,
    schar_sat,
    sstring_sat,
    wchar_sat,
    wstring_sat
};


// This defines a single dynamic signal argument type.
struct pytqt3SigArg
{
    // The type.
    pytqt3SigArgType atype;

    union {
        // The Python type for classes.
        sipWrapperType *wt;

        // The data for mapped types.
        const sipTypeDef *mt;

        // The Python type for named enums.
        PyTypeObject *et;
    } u;
};


// A parsed signal signature.
struct pytqt3Signature {
    // The number of arguments.
    int sg_nrargs;

    // The parsed arguments (heap).
    pytqt3SigArg *sg_args;

    // The unparsed signature (heap).
    char *sg_signature;

    // The next in the list.
    pytqt3Signature *sg_next;
};


// A connection to a universal slot.
struct pytqt3SlotConnection
{
    // The transmitter TQObject.
    void *sc_transmitter;

    // The parsed signature.
    const pytqt3Signature *sc_signature;

    // The slot.
    sipSlot sc_slot;
};


// This class is used as a slot on behalf of connections to a Python callable.
// It is derived from TQObject but is not run through moc.  Instead the normal
// moc-generated methods are handwritten in order to implement a universal
// slot.  This requires some knowledge of the internal implementation of
// signals and slots but it is likely that they will only change between major
// TQt versions.
class UniversalSlot : public TQObject
{
public:
	UniversalSlot(TQObject *tqtx, pytqt3SlotConnection *conn, const char **member);
	~UniversalSlot();

	virtual TQMetaObject *metaObject() const
	{
		return staticMetaObject();
	}

	virtual bool tqt_invoke(int, TQUObject *args);
	static TQMetaObject *staticMetaObject();

	static TQObject *lastSender;

	static UniversalSlot *unislots;
	UniversalSlot *nextus, *prevus;
	pytqt3SlotConnection conn;

private:
	static TQMetaObject *metaObj;
};


// Create a universal slot.  Note that this will leak if there is no signal
// transmitter (ie. no parent) - TQTimer.singleShot() for example.
UniversalSlot::UniversalSlot(TQObject *tqtx, pytqt3SlotConnection *connection, const char **member) : TQObject()
{
	// Save the connection.
	conn = *connection;

	// Detect when the transmitter is destroyed.
	if (tqtx)
		connect(tqtx, TQ_SIGNAL(destroyed(TQObject *)), TQ_SLOT(deleteLater()));

	// Return the slot to connect to.
	*member = TQ_SLOT(unislot());

	// Add this one to the global list.
	nextus = unislots;

	if (nextus)
		nextus -> prevus = this;

	prevus = 0;
	unislots = this;
}


// Destroy a universal slot.
UniversalSlot::~UniversalSlot()
{
    SIP_BLOCK_THREADS
	sipFreeSipslot(&conn.sc_slot);
    SIP_UNBLOCK_THREADS

	// Remove this one from the global list.
	if (nextus)
		nextus -> prevus = prevus;

	if (prevus)
		prevus -> nextus = nextus;
	else
		unislots = nextus;
}


// The last Python signal sender.
static PyObject *py_sender = 0;


TQMetaObject *UniversalSlot::metaObj = 0;

static TQMetaObjectCleanUp cleanUp_UniversalSlot("UniversalSlot", &UniversalSlot::staticMetaObject);

TQObject *UniversalSlot::lastSender = 0;
UniversalSlot *UniversalSlot::unislots = 0;


TQMetaObject *UniversalSlot::staticMetaObject()
{
	if (metaObj)
		return metaObj;

	// Define a single slot that takes no arguments and so will accept any
	// connection.
	static const TQUMethod slot = {"unislot", 0, 0};
	static const TQMetaData slot_tbl[] = {
		{"unislot()", &slot, TQMetaData::Public}
	};

	metaObj = TQMetaObject::new_metaobject(
			"UniversalSlot", TQObject::staticMetaObject(),
			slot_tbl, 1,
			0, 0,
#ifndef TQT_NO_PROPERTIES
			0, 0,
			0, 0,
#endif
			0, 0);

	cleanUp_UniversalSlot.setMetaObject(metaObj);

	return metaObj;
}


bool UniversalSlot::tqt_invoke(int id, TQUObject *tqargs)
{
	if (id - staticMetaObject()->slotOffset() != 0)
		return TQObject::tqt_invoke(id, tqargs);

	bool ok = true;
	const pytqt3Signature *psig = conn.sc_signature;
	TQVariant *tqv;

	// Save in case it is asked for later.
	lastSender = const_cast<TQObject *>(sender());

	// If the sender was a TQSignal then the single argument will be wrapped
	// in a TQVariant instance.  At the moment we handle int argument as
	// that is all that is needed by PyTQt (and PyKDE).
	if (lastSender->inherits("TQSignal"))
		tqv = &static_QUType_TQVariant.get(tqargs + 1);
	else
		tqv = 0;

#ifdef WITH_THREAD
	PyGILState_STATE state = PyGILState_Ensure();
#endif

	PyObject *argtup = PyTuple_New(psig->sg_nrargs);

	if (!argtup)
		ok = false;
	else
	{
		for (int a = 0; a < psig->sg_nrargs; ++a)
		{
			PyObject *arg;

			++tqargs;

			switch (psig->sg_args[a].atype)
			{
			case char_sat:
			case schar_sat:
			case uchar_sat:
				arg = PyBytes_FromStringAndSize((char *)static_QUType_ptr.get(tqargs), 1);
				break;

			case string_sat:
			case sstring_sat:
			case ustring_sat:
				arg = PyBytes_FromString((char *)static_QUType_ptr.get(tqargs));
				break;

			case short_sat:
				arg = PyLong_FromLong(*(short *)static_QUType_ptr.get(tqargs));
				break;

			case ushort_sat:
				arg = PyLong_FromUnsignedLong(*(unsigned short *)static_QUType_ptr.get(tqargs));
				break;

			case int_sat:
				if (tqv)
					arg = PyLong_FromLong(tqv -> asInt());
				else
					arg = PyLong_FromLong(static_QUType_int.get(tqargs));
				break;

			case uint_sat:
				arg = PyLong_FromUnsignedLong(*(unsigned *)static_QUType_ptr.get(tqargs));
				break;

			case long_sat:
				arg = PyLong_FromLong(*(long *)static_QUType_ptr.get(tqargs));
				break;

			case ulong_sat:
				arg = PyLong_FromUnsignedLong(*(unsigned long *)static_QUType_ptr.get(tqargs));
				break;

			case longlong_sat:
				arg = PyLong_FromLongLong(*(PY_LONG_LONG *)static_QUType_ptr.get(tqargs));
				break;

			case ulonglong_sat:
				arg = PyLong_FromUnsignedLongLong(*(unsigned PY_LONG_LONG *)static_QUType_ptr.get(tqargs));
				break;

			case float_sat:
				arg = PyFloat_FromDouble(*(float *)static_QUType_ptr.get(tqargs));
				break;

			case double_sat:
				arg = PyFloat_FromDouble(static_QUType_double.get(tqargs));
				break;

			case enum_sat:
				arg = sipConvertFromNamedEnum(*(int *)static_QUType_ptr.get(tqargs), psig->sg_args[a].u.et);
				break;

			case bool_sat:
				arg = PyLong_FromLong(static_QUType_bool.get(tqargs));
				break;

			case void_sat:
				arg = sipConvertFromVoidPtr((void *)static_QUType_ptr.get(tqargs));
				break;

			case class_sat:
			case classp_sat:
				arg = sipConvertFromInstance((void *)static_QUType_ptr.get(tqargs),psig->sg_args[a].u.wt,0);
				break;

			case mtype_sat:
			case mtypep_sat:
				arg = sipConvertFromMappedType((void *)static_QUType_ptr.get(tqargs),psig->sg_args[a].u.mt,0);
				break;

			case tqvariant_sat:
			case tqvariantp_sat:
				arg = sipConvertFromInstance((void *)&static_QUType_TQVariant.get(tqargs),sipClass_TQVariant,0);
				break;

			case pyobject_sat:
				arg = (PyObject *)static_QUType_ptr.get(tqargs);
				break;

			default:
				arg = Py_NotImplemented;
				Py_INCREF(Py_NotImplemented);
			}

			PyTuple_SET_ITEM(argtup, a, arg);
		}

		// Dispatch to the real slot.
		if (ok)
        {
		    PyObject *res = sipInvokeSlot(&conn.sc_slot, argtup);

            if (res)
                Py_DECREF(res);
            else
			    ok = false;
        }

		Py_DECREF(argtup);
	}

	if (!ok)
		PyErr_Print();

#ifdef WITH_THREAD
	PyGILState_Release(state);
#endif

	return ok;
}


static pytqt3Signature *parseSignature(const char *sig);
static void parseType(const char *type, pytqt3SigArg *arg);


// Factory function to create a universal slot instance.  Returns a pointer to
// the instance or 0 if there was an error.
static void *sipTQtCreateUniversalSlot(sipWrapper *tx, const char *sig,
        PyObject *rxObj, const char *slot, const char **member, int)
{
    pytqt3SlotConnection conn;

    /* Initialise the connection. */
    if (tx && sipGetAddress(&tx->super) == NULL)
    {
        conn.sc_transmitter = 0;
    }
    else
    {
        conn.sc_transmitter = (tx ? sipGetCppPtr(&tx->super, 0) : 0);
    }

    /* Save the real slot. */
    if (sipSaveSlot(&conn.sc_slot, rxObj, slot) < 0)
        return 0;

    /* Parse the signature and create the universal slot. */
    if ((conn.sc_signature = parseSignature(sig)) == NULL)
    {
        sipFreeSipslot(&conn.sc_slot);
        return 0;
    }

	TQObject *tqtx = 0;

	// See if the transmitter is a TQObject in which case we will connect
	// to it's destroyed signal so that the universal slot can be destroyed
	// at the same time.  (Note that we used to do this by making the
	// universal slot a child of the transmitter.  This doesn't work as
	// expected because TQWidget destroys its children before emitting the
	// destroyed signal.)
	if (tx && PyObject_TypeCheck((PyObject *)tx, (PyTypeObject *)sipClass_TQObject))
		tqtx = reinterpret_cast<TQObject *>(conn.sc_transmitter);

	return new UniversalSlot(tqtx, &conn, member);
}


// Parse the signal arguments for a connection.
static pytqt3Signature *parseSignature(const char *sig)
{
    static pytqt3Signature *psig_list = NULL;
    pytqt3Signature *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 (sipTQtSameSignalSlotName(psig->sg_signature, sig))
            return psig;

    // Create a new one including space for the copy of the signature.
    if ((psig = (pytqt3Signature *)sipMalloc(sizeof (pytqt3Signature) + 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 TQt 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;
        bool 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 = (pytqt3SigArg *)sipMalloc(sizeof (pytqt3SigArg) * psig->sg_nrargs)) == NULL)
            {
                sipFree(psig);
                return NULL;
            }

            for (a = 0; a < psig->sg_nrargs; ++a)
            {
                parseType(arg, &psig->sg_args[a]);

                // 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;
}


// Parse a single type.
static void parseType(const char *type, pytqt3SigArg *arg)
{
    size_t btlen = 0;
    int indir = 0;
    bool unsup, isref = false;
    const char *ep;
    pytqt3SigArgType sat = unknown_sat;

    // Find the start of the significant part of the type.
    if (strncmp(type, "const ", 6) == 0)
        type += 6;

    // Find the length of the base type, the number of indirections and if it
    // is a reference.
    for (ep = type; *ep; ++ep)
        if (*ep == '&')
            isref = true;
        else if (*ep == '*')
            ++indir;
        else
            ++btlen;

    // Extract the base type as a separate string.
    char type_str[btlen + 1];

    strncpy(type_str, type, btlen);
    type_str[btlen] = '\0';

    // Resolve any typedef which may mean more indirection.
    type = sipResolveTypedef(type_str);

    // See if we need to make another copy.
    bool copy = false;

    if (type)
    {
        btlen = strlen(type);

        // Remove any additional indirection.
        while (btlen)
        {
            if (type[--btlen] == '*')
            {
                copy = true;
                ++indir;
            }
        }
    }
    else
        type = type_str;

    // Make sure this doesn't go out of scope while it is being used.
    char base_type_str[btlen + 1];

    if (copy)
    {
        // Extract the base type again.
        strncpy(base_type_str, type, btlen);
        base_type_str[btlen] = '\0';
        type = base_type_str;
    }

    // Assume that anything other than a base type is unsupported.
    unsup = (isref || indir);

    // Parse the base type.
    switch (btlen)
    {
    case 3:
        if (strcmp(type, "int") == 0)
            sat = int_sat;
        break;

    case 4:
        if (strcmp(type, "bool") == 0)
            sat = bool_sat;
        else if (strcmp(type, "long") == 0)
            sat = long_sat;
        else if (strcmp(type, "char") == 0)
        {
            sat = (indir ? string_sat : char_sat);
            unsup = (isref || indir > 1);
        }
        else if (strcmp(type, "void") == 0)
        {
            sat = void_sat;
            unsup = (isref || indir != 1);
        }
        break;

    case 5:
        if (strcmp(type, "float") == 0)
            sat = float_sat;
        else if (strcmp(type, "short") == 0)
            sat = short_sat;
        break;

    case 6:
        if (strcmp(type, "double") == 0)
            sat = double_sat;
        break;

    case 7:
        if (strcmp(type, "__int64") == 0)
            sat = longlong_sat;
        else if (strcmp(type, "wchar_t") == 0)
        {
            sat = (indir ? wstring_sat : wchar_sat);
            unsup = (isref || indir > 1);
        }
        break;

    case 8:
        if (strcmp(type, "unsigned") == 0)
            sat = uint_sat;
        else if (strcmp(type, "TQVariant") == 0)
        {
            if (indir == 0)
            {
                sat = tqvariant_sat;
                unsup = false;
            }
            else if (indir == 1)
            {
                sat = tqvariantp_sat;
                unsup = false;
            }
        }
        break;

    case 9:
        if (strcmp(type, "long long") == 0)
            sat = longlong_sat;
        break;

    case 11:
        if (strcmp(type, "signed char") == 0)
        {
            sat = (indir ? sstring_sat : schar_sat);
            unsup = (isref || indir > 1);
        }
        break;

    case 12:
        if (strcmp(type, "unsigned int") == 0)
            sat = uint_sat;
        break;

    case 13:
        if (strcmp(type, "unsigned long") == 0)
            sat = ulong_sat;
        else if (strcmp(type, "unsigned char") == 0)
        {
            sat = (indir ? ustring_sat : uchar_sat);
            unsup = (isref || indir > 1);
        }
        else if (strcmp(type, "PyTQt_PyObject") == 0 && indir == 0)
        {
            sat = pyobject_sat;
            unsup = false;
        }
        break;

    case 14:
        if (strcmp(type, "unsigned short") == 0)
            sat = ushort_sat;
        break;

    case 16:
        if (strcmp(type, "unsigned __int64") == 0)
            sat = ulonglong_sat;
        break;

    case 18:
        if (strcmp(type, "unsigned long long") == 0)
            sat = ulonglong_sat;
        break;
    }

    if (sat == unknown_sat)
    {
        const sipTypeDef *td = sipFindType(type);

        if (td)
        {
            if (sipTypeIsClass(td))
            {
                if (indir == 0)
                    sat = class_sat;
                else if (indir == 1)
                    sat = classp_sat;

                arg->u.wt = (sipWrapperType *)sipTypeAsPyTypeObject(td);
            }
            else if (sipTypeIsMapped(td))
            {
                if (indir == 0)
                    sat = mtype_sat;
                else if (indir == 1)
                    sat = mtypep_sat;

                arg->u.mt = td;
            }
            else if (sipTypeIsEnum(td))
            {
                if (indir == 0)
                    sat = enum_sat;

                arg->u.et = sipTypeAsPyTypeObject(td);
            }
        }
    }
    else if (unsup)
        sat = unknown_sat;

    arg->atype = sat;
}


// Dispose of a receiver that might be a universal slot.
static void sipTQtDestroyUniversalSlot(void *rx)
{
	for (UniversalSlot *us = UniversalSlot::unislots; us; us = us->nextus)
		if (us == reinterpret_cast<TQObject *>(rx))
		{
			delete us;
			break;
		}
}


// Search for the universal slot connected to a particular TQt signal.
static void *sipTQtFindSlot(void *tx, const char *sig, PyObject *rxObj,
        const char *slot, const char **member)
{
	for (UniversalSlot *us = UniversalSlot::unislots; us; us = us->nextus)
    {
        pytqt3SlotConnection *conn = &us->conn;

        if (conn->sc_transmitter != tx)
            continue;

        if (!sipTQtSameSignalSlotName(conn->sc_signature->sg_signature, sig))
            continue;

		if (sipSameSlot(&conn->sc_slot, rxObj, slot))
		{
			*member = TQ_SLOT(unislot());
			return us;
		}
    }

	return 0;
}


// Connect a TQt signal to a TQt slot.
static int sipTQtConnect(void *tx, const char *sig, void *rx, const char *slot, int)
{
	return TQObject::connect(reinterpret_cast<TQObject *>(tx), sig,
				reinterpret_cast<TQObject *>(rx), slot);
}


// Disconnect a TQt signal from a TQt slot.
static int sipTQtDisconnect(void *tx, const char *sig, void *rx, const char *slot)
{
	return TQObject::disconnect(reinterpret_cast<TQObject *>(tx), sig,
				   reinterpret_cast<TQObject *>(rx), slot);
}


// See if two signal or slot names are the same.
static int sipTQtSameSignalSlotName(const char *s1, const char *s2)
{
	// moc formats signal names, so we should first convert the supplied
	// string to the same format before comparing them.  Instead we just
	// compare them as they are, but ignoring all spaces - this will have
	// the same result.
	do
	{
		// Skip any spaces.

		while (*s1 == ' ')
			++s1;

		while (*s2 == ' ')
			++s2;

		if (*s1++ != *s2)
			return 0;
	}
	while (*s2++ != '\0');

	return 1;
}


// Return the next slot for a particular transmitter.  This will be called with
// the GIL locked.
static sipSlot *sipTQtFindSipslot(void *tx, void **context)
{
    UniversalSlot *us = *reinterpret_cast<UniversalSlot **>(context);

    if (!us)
        us = UniversalSlot::unislots;

    sipSlot *slot = 0;

    while (us)
    {
        pytqt3SlotConnection *this_conn = &us->conn;

        us = us->nextus;

        if (this_conn->sc_transmitter == tx)
        {
            slot = &this_conn->sc_slot;
            break;
        }
    }

    *context = us;

    return slot;
}


// Connect a slot from a Python signal.
static int sipTQtConnectPySignal(PyObject *txObj, const char *sig,
        PyObject *rxObj, const char *slot)
{
    pytqt3PySig *ps;
    pytqt3SlotList *psrx;
    pytqtWrapper *pw = (pytqtWrapper *)txObj;

    /* Create a new one if necessary. */
    if ((ps = find_py_signal(pw, sig)) == NULL)
    {
        if ((ps = (pytqt3PySig *)sipMalloc(sizeof (pytqt3PySig))) == NULL)
            return -1;

        if ((ps->name = (char *)sipMalloc(strlen(sig) + 1)) == NULL)
        {
            sipFree(ps);
            return -1;
        }

        strcpy(ps->name, sig);

        ps->rxlist = NULL;
        ps->next = pw->pySigList;

        pw->pySigList = ps;
    }

    /* Create the new receiver. */
    if ((psrx = (pytqt3SlotList *)sipMalloc(sizeof (pytqt3SlotList))) == NULL)
        return -1;

    if (sipSaveSlot(&psrx->rx, rxObj, slot) < 0)
    {
        sipFree(psrx);
        return -1;
    }

    psrx->next = ps->rxlist;
    ps->rxlist = psrx;

    return 0;
}


// Disconnect a slot from a Python signal.
static void sipTQtDisconnectPySignal(PyObject *txObj, const char *sig,
        PyObject *rxObj, const char *slot)
{
    pytqt3PySig *ps;

    if ((ps = find_py_signal((pytqtWrapper *)txObj, sig)) != NULL)
    {
        pytqt3SlotList **psrxp;

        for (psrxp = &ps->rxlist; *psrxp != NULL; psrxp = &(*psrxp)->next)
        {
            pytqt3SlotList *psrx = *psrxp;

            if (sipSameSlot(&psrx->rx, rxObj, slot))
            {
                *psrxp = psrx->next;
                free_slot_list(psrx);
                break;
            }
        }
    }
}


// Emit a signal for the sip module.
static int sipTQtEmitSignal(PyObject *self, const char *sig, PyObject *sigargs)
{
    return pytqtEmitSignal(self, sig, sigargs);
}


// Emit a Python or TQt signal.
int pytqtEmitSignal(PyObject *self, const char *sig, PyObject *sigargs)
{
    // Don't do anything if signals are blocked.  TQt signals would be blocked
    // anyway, but this blocks Python signals as well.
    void *tx = sipGetCppPtr((sipSimpleWrapper *)self, sipType_TQObject);

    if (!tx)
        return 0;

	if (reinterpret_cast<TQObject *>(tx)->signalsBlocked())
        return 0;

    // See if it is a TQt signal.
    if (*sig == '2')
    {
        pytqtTQtSignal *tab;

        // Search the table.
        for (tab = ((pytqtClassTypeDef *)((sipWrapperType *)(self->ob_type))->type)->tqt_emit; tab->st_name != NULL; ++tab)
        {
            const char *sp, *tp;
            bool 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)((sipSimpleWrapper *)self, sigargs);
        }

        // It wasn't found if we got this far.
        PyErr_Format(PyExc_NameError, "Invalid signal %s", &sig[1]);

        return -1;
    }

    pytqt3PySig *ps = find_py_signal((pytqtWrapper *)self, sig);

    if (ps)
    {
        int rc = 0;
        pytqt3SlotList *rxlist = ps->rxlist;

        // Forget the last TQt sender and remember this one.
	    UniversalSlot::lastSender = 0;
        py_sender = self;

        // Apply the arguments to each slot method.
        while (rxlist && rc >= 0)
        {
            pytqt3SlotList *next;
            PyObject *res;

            // 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;

            res = sipInvokeSlot(&rxlist->rx, sigargs);

            if (res)
                Py_DECREF(res);
            else
                rc = -1;

            rxlist = next;
        }

        // Forget this as a sender.
        py_sender = NULL;

        return rc;
    }

    return 0;
}


// Return the most recent signal sender.
PyObject *pytqt3GetSender()
{
    PyObject *sender;

    // If there is a TQt sender then it is more recent than the last Python
    // sender, so use it instead.
    if (UniversalSlot::lastSender)
    {
        sender = sipConvertFromType(UniversalSlot::lastSender, sipType_TQObject,
                NULL);
    }
    else
    {
        sender = (py_sender ? py_sender : Py_None);
        Py_INCREF(sender);
    }

    return sender;
}

%End

%InitialisationCode
    // Initialise the meta-type.
    pytqtWrapperType_Type.tp_base = sipWrapperType_Type;

    if (PyType_Ready(&pytqtWrapperType_Type) < 0)
        Py_FatalError("tqt: Failed to initialise pytqtWrapperType type");

    // Register the meta-type.
    if (sipRegisterPyType((PyTypeObject *)&pytqtWrapperType_Type) < 0)
        Py_FatalError("tqt: Failed to register pytqtWrapperType type");

    // Initialise the super-type.
    pytqtWrapper_Type.super.ht_type.tp_base = sipWrapper_Type;

    if (PyType_Ready((PyTypeObject *)&pytqtWrapper_Type) < 0)
        Py_FatalError("tqt: Failed to initialise pytqtWrapper type");

    // Register the super-type.
    if (sipRegisterPyType((PyTypeObject *)&pytqtWrapper_Type) < 0)
        Py_FatalError("tqt: Failed to register pytqtWrapper type");
%End
