// This is the SIP interface definition for QApplication.
//
// Copyright (c) 2007
// 	Riverbank Computing Limited <info@riverbankcomputing.co.uk>
// 
// This file is part of PyQt.
// 
// This copy of PyQt 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.
// 
// PyQt 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
// PyQt; 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>QApplication</Title>
<FuncSynopsis>
        <FuncDef><Function>QApplication</Function></FuncDef>
        <ParamDef>int &amp;<Parameter>argc</Parameter></ParamDef>
        <ParamDef>char **<Parameter>argv</Parameter></ParamDef>
</FuncSynopsis>
<Para>
This takes one parameter which is a list of argument strings.  Arguments
used by Qt are removed from the list.
</Para>

<FuncSynopsis>
        <FuncDef><Function>QApplication</Function></FuncDef>
        <ParamDef>int &amp;<Parameter>argc</Parameter></ParamDef>
        <ParamDef>char **<Parameter>argv</Parameter></ParamDef>
        <ParamDef>bool <Parameter>GUIenabled</Parameter></ParamDef>
</FuncSynopsis>
<Para>
This takes two parameters, the first of which is a list of argument strings.
Arguments used by Qt are removed from the list.
</Para>

<FuncSynopsis>
        <FuncDef><Function>QApplication</Function></FuncDef>
        <ParamDef>int &amp;<Parameter>argc</Parameter></ParamDef>
        <ParamDef>char **<Parameter>argv</Parameter></ParamDef>
        <ParamDef>Type <Parameter>type</Parameter></ParamDef>
</FuncSynopsis>
<Para>
This takes two parameters, the first of which is a list of argument strings.
Arguments used by Qt are removed from the list. (Qt v2.2+)
</Para>

<FuncSynopsis>
        <FuncDef>int <Function>exec</Function></FuncDef>
        <ParamDef></ParamDef>
</FuncSynopsis>
<Para>
This has been renamed to <Literal>exec_loop</Literal> in Python.
</Para>
</Sect2>
%End


QApplication *qApp;


class QApplication : QObject
{
%TypeHeaderCode
#include <qapplication.h>
#include <qwidgetlist.h>
%End

public:
	QApplication(SIP_PYLIST) /PostHook=__pyQtQAppHook__/ [(int &,char **)];
%MethodCode
		// The Python interface is a list of argument strings that is
		// modified.

		int argc;
		char **argv;

		// Convert the list.
		if ((argv = pyArgvToC(a0,argc)) == NULL)
			sipIsErr = 1;
		else
		{
			// Create it now the arguments are right.
			static int nargc;
			nargc = argc;

			Py_BEGIN_ALLOW_THREADS
			sipCpp = new sipQApplication(nargc,argv);
			Py_END_ALLOW_THREADS

			// Now modify the original list.
			updatePyArgv(a0,argc,argv);
		}
%End

	QApplication(SIP_PYLIST,bool) /PostHook=__pyQtQAppHook__/ [(int &,char **,bool)];
%MethodCode
		// The Python interface is a list of argument strings that is
		// modified.

		int argc;
		char **argv;

		// Convert the list.
		if ((argv = pyArgvToC(a0,argc)) == NULL)
			sipIsErr = 1;
		else
		{
			// Create it now the arguments are right.
			static int nargc;
			nargc = argc;

			Py_BEGIN_ALLOW_THREADS
			sipCpp = new sipQApplication(nargc,argv,a1);
			Py_END_ALLOW_THREADS

			// Now modify the original list.
			updatePyArgv(a0,argc,argv);
		}
%End

%If (Qt_2_2_0 -)
	enum Type {
		Tty,
		GuiClient,
		GuiServer
	};

	QApplication(SIP_PYLIST,Type /Constrained/) /PostHook=__pyQtQAppHook__/ [(int &,char **,Type)];
%MethodCode
		// The Python interface is a list of argument strings that is
		// modified.

		int argc;
		char **argv;

		// Convert the list.
		if ((argv = pyArgvToC(a0,argc)) == NULL)
			sipIsErr = 1;
		else
		{
			// Create it now the arguments are right.
			static int nargc;
			nargc = argc;

			Py_BEGIN_ALLOW_THREADS
			sipCpp = new sipQApplication(nargc,argv,(QApplication::Type)a1);
			Py_END_ALLOW_THREADS

			// Now modify the original list.
			updatePyArgv(a0,argc,argv);
		}
%End
%End

	~QApplication();
%MethodCode
		// Make sure all remaining top level widgets are not owned by
		// Python.  When a PyQt script terminates we have no control
		// over the order in which the QApplication instance and the
		// top level widgets are destroyed.  If the former happens
		// first then we get a seg. fault.  We could take the approach
		// of only pretending to delete the QApplication instance, but
		// Qt seems to allow an application to delete the QApplication
		// instance and then create another one.  The approach we take
		// is to transfer ownership of all top level widgets away from
		// Python so that the C++ dtor is not called if they are
		// destroyed after the QApplication instance.  This might be
		// seen as a memory leak - but if we really are terminating
		// then it doesn't matter, and if we are just deleting the
		// QApplication instance then (I think) we should have already
		// deleted the top level widgets manually.  In any event, the X
		// server resources will be freed.

		QWidgetList *tlw = QApplication::topLevelWidgets();
		QWidgetListIt it(*tlw);
		QWidget *w;

		while ((w = it.current()) != 0)
		{
			PyObject *sw;

			if ((sw = sipGetWrapper(w,sipClass_QWidget)) != NULL)
				sipTransferTo(sw,NULL);

			++it;
		}

		delete tlw;
%End

	int argc() const;
	SIP_PYLIST argv() const;
%MethodCode
		// The Python interface returns a list of strings.

		int argc = sipCpp -> argc();

		if ((sipRes = PyList_New(argc)) == NULL)
			sipIsErr = 1;
		else
			for (int a = 0; a < argc; ++a)
				if (PyList_SetItem(sipRes,a,PyString_FromString(sipCpp -> argv()[a])) < 0)
				{
					Py_DECREF(sipRes);
					sipIsErr = 1;
					break;
				}
%End

%If (Qt_2_3_0 -)
	Type type() const;
%End
%If (- Qt_2_00)
	static GUIStyle style();
	static void setStyle(GUIStyle);
%End
%If (Qt_2_00 -)
	static QStyle &style();
	static void setStyle(QStyle * /Transfer/);
%End
%If (Qt_3_0_0 -)
	static QStyle *setStyle(const QString &);
%End

%If (- Qt_2_00)
	enum ColorSpec
	{
		NormalColor = 0,
		CustomColor = 1,
		PrivateColor = 4,
		ManyColor = 4,
		TrueColor = 4
	};
%End
%If (Qt_2_00 -)
	enum ColorSpec
	{
		NormalColor = 0,
		CustomColor = 1,
		ManyColor = 2
	};
%End

	static int colorSpec();
	static void setColorSpec(int);
	static QCursor *overrideCursor();
	static void setOverrideCursor(QCursor &,bool = 0);
	static void restoreOverrideCursor();
	static bool hasGlobalMouseTracking();
	static void setGlobalMouseTracking(bool);
%If (- Qt_2_00)
	static QPalette *palette();
	static void setPalette(QPalette &,bool = 0);
	static QFont *font();
	static void setFont(const QFont &,bool = 0);
%End
%If (Qt_2_00 -)
	static QPalette palette(const QWidget * = 0);
	static void setPalette(QPalette &,bool = 0,const char * = 0);
	static QFont font(const QWidget * = 0);
	static void setFont(const QFont &,bool = 0,const char * = 0);
%End
	static QFontMetrics fontMetrics();
	QWidget *mainWidget() const;
%If (- Qt_2_00)
	// We may not need the /Transfer/ now that the QApplication dtor is
	// instrumented, but we'll leave it in so as not to break old programs
	// needlessly.
	void setMainWidget(QWidget * /Transfer/);
%End
%If (Qt_2_00 -)
	virtual void setMainWidget(QWidget *);
	virtual void polish(QWidget *);
%End
	static QWidgetList *allWidgets();
	static QWidgetList *topLevelWidgets();
%If (- Qt_3_0_0)
	static QWidget *desktop();
%End
%If (Qt_3_0_0 -)
	static QDesktopWidget *desktop();
%End
	static QWidget *activePopupWidget();
	static QWidget *activeModalWidget();
	static QClipboard *clipboard();
	QWidget *focusWidget() const;
%If (Qt_2_00 -)
	QWidget *activeWindow() const;
%End
	static QWidget *widgetAt(int,int,bool = 0);
	static QWidget *widgetAt(const QPoint &,bool = 0);

%If (Qt_3_1_0 -)
	static QEventLoop *eventLoop();
%End

	int exec() /PyName=exec_loop, ReleaseGIL,
		    PreHook=__pyQtPreEventLoopHook__,
		    PostHook=__pyQtPostEventLoopHook__/;
	void processEvents() /ReleaseGIL/;
	void processEvents(int) /ReleaseGIL/;
	void processOneEvent() /ReleaseGIL/;
%If (Qt_3_0_0 -)
	bool hasPendingEvents();
%End
	int enter_loop() /ReleaseGIL/;
	void exit_loop();
%If (Qt_2_00 -)
	int loopLevel() const;
%End
	static void exit(int = 0);
	static bool sendEvent(QObject *,QEvent *) /ReleaseGIL/;
	static void postEvent(QObject *,QEvent * /Transfer/) /ReleaseGIL/;
	static void sendPostedEvents(QObject *,int) /ReleaseGIL/;
%If (Qt_2_00 -)
	static void sendPostedEvents() /ReleaseGIL/;
	static void removePostedEvents(QObject *);
%End
	virtual bool notify(QObject *,QEvent *) /ReleaseGIL/;
	static bool startingUp();
	static bool closingDown();
	static void flushX();
%If (Qt_3_0_0 -)
	static void flush();
%End
	static void syncX();
	static void beep();
%If (Qt_2_00 -)
	void setDefaultCodec(QTextCodec *);
	QTextCodec *defaultCodec() const;
	void installTranslator(QTranslator *);
	void removeTranslator(QTranslator *);
%End
%If (Qt_2_00 - Qt_3_0_0)
	QString translate(const char *,const char *) const;
%End
%If (Qt_2_2_0 - Qt_3_0_0)
	QString translate(const char *,const char *,const char *) const;
%End
%If (Qt_3_0_0 -)
	enum Encoding {
		DefaultCodec,
		UnicodeUTF8
	};

	QString translate(const char *,const char *,const char * = 0,
			  Encoding = DefaultCodec) const;
%End
%If (Qt_3_2_0 -)
	QString applicationDirPath();
	QString applicationFilePath();
%End
%If (- Qt_3_0_0)
	static void setWinStyleHighlightColor(const QColor &);
	static const QColor &winStyleHighlightColor();
%End
%If (Qt_2_00 -)
	static void setDesktopSettingsAware(bool);
	static bool desktopSettingsAware();
	static void setCursorFlashTime(int);
	static int cursorFlashTime();
%End
	static void setDoubleClickInterval(int);
	static int doubleClickInterval();
%If (Qt_2_1_0 -)
	static void setWheelScrollLines(int);
	static int wheelScrollLines();
%If (Qt_2_2_0 -)
	static void setGlobalStrut(const QSize &);
	static QSize globalStrut();
%End
%If (Qt_3_0_0 -)
	static void setLibraryPaths(const QStringList &);
	static QStringList libraryPaths();
	static void addLibraryPath(const QString &);
	static void removeLibraryPath(const QString &);
%End
	static void setStartDragTime(int);
	static int startDragTime();
	static void setStartDragDistance(int);
	static int startDragDistance();
%If (Qt_3_0_0 -)
	static void setReverseLayout(bool);
	static bool reverseLayout();
 
	static int horizontalAlignment(int);
%End
%If (Qt_2_2_0 -)
	static bool isEffectEnabled(Qt::UIEffect);
	static void setEffectEnabled(Qt::UIEffect,bool = 1);
%End
%End


%If (Qt_2_00 -)
	bool isSessionRestored() const;
	QString sessionId() const;
%If (Qt_3_1_0 -)
	QString sessionKey() const;
%End
	virtual void commitData(QSessionManager &);
	virtual void saveState(QSessionManager &);
%End
%If (Qt_2_1_0 -)
	void wakeUpGuiThread();
%End
%If (Qt_THREAD_SUPPORT)
%If (Qt_2_2_0 -)
	void lock() /ReleaseGIL/;
	void unlock(bool = 1);
	bool locked();
%End
%If (Qt_3_0_0 -)
	bool tryLock();
%End
%End

signals:
	void lastWindowClosed();
%If (Qt_2_00 -)
	void aboutToQuit();
%End
%If (Qt_2_1_0 -)
	void guiThreadAwake();
%End

public slots:
	void quit();
%If (Qt_2_00 -)
	void closeAllWindows();
%End
%If (Qt_3_2_0 -)
	void aboutQt();
%End

protected:
%If (Qt_3_1_0 -)
	bool event(QEvent *);
%End

private:
	QApplication(const QApplication &);


%TypeCode
#include <string.h>


// Convert a Python argv list to a conventional C argc count and argv array.
static char **pyArgvToC(PyObject *argvlist,int &argc)
{
	char **argv;

	argc = PyList_Size(argvlist);

	// Allocate space for two copies of the argument pointers, plus the
	// terminating NULL.
	if ((argv = (char **)sipMalloc(2 * (argc + 1) * sizeof (char *))) == NULL)
		return NULL;

	// Convert the list.
	for (int a = 0; a < argc; ++a)
	{
		char *arg;

		// Get the argument and allocate memory for it.
		if ((arg = PyString_AsString(PyList_GetItem(argvlist,a))) == NULL ||
		    (argv[a] = (char *)sipMalloc(strlen(arg) + 1)) == NULL)
			return NULL;

		// Copy the argument and save a pointer to it.
		strcpy(argv[a],arg);
		argv[a + argc + 1] = argv[a];
	}

	argv[argc + argc + 1] = argv[argc] = NULL;

	return argv;
}


// Remove arguments from the Python argv list that have been removed from the
// C argv array.
static void updatePyArgv(PyObject *argvlist,int argc,char **argv)
{
	for (int a = 0, na = 0; a < argc; ++a)
	{
		// See if it was removed.
		if (argv[na] == argv[a + argc + 1])
			++na;
		else
			PyList_SetSlice(argvlist,na,na + 1,NULL);
	}
}
%End

};


enum QtMsgType {
	QtDebugMsg,
	QtWarningMsg,
	QtFatalMsg
};


SIP_PYCALLABLE qInstallMsgHandler(SIP_PYCALLABLE /AllowNone/);
%MethodCode
	void (*old)(QtMsgType, const char *);

	// Treat None as the default handler.
	old = qInstallMsgHandler((a0 != Py_None) ? pyqtMsgHandler : 0);

	// If we recognise the old handler, then return it.  Otherwise return
	// the default handler.  This doesn't exactly mimic the Qt behaviour
	// but it is probably close enough for the way it will be used.
	sipRes = (old == pyqtMsgHandler) ? pyqtPyMsgHandler : Py_None;
	Py_INCREF(sipRes);

	// Save the new Python handler.
	Py_XDECREF(pyqtPyMsgHandler);
	pyqtPyMsgHandler = a0;
	Py_INCREF(pyqtPyMsgHandler);
%End

%ModuleCode
// The user supplied Python handler.
static PyObject *pyqtPyMsgHandler = 0;

// The C++ wrapper around the Python handler.
static void pyqtMsgHandler(QtMsgType type, const char *msg)
{
	PyObject *res;

	SIP_BLOCK_THREADS

#if SIP_VERSION >= 0x040200
	res = sipCallMethod(0, pyqtPyMsgHandler, "Es", type, sipEnum_QtMsgType, msg);
#elif SIP_VERSION >= 0x040000
	res = sipCallMethod(0, pyqtPyMsgHandler, "es", type, msg);
#else
	PyObject *args = Py_BuildValue("is", type, msg);

	if (args != NULL)
	{
		res = PyEval_CallObject(pyqtPyMsgHandler, args);
		Py_DECREF(args);
	}
#endif

	Py_XDECREF(res);

	if (res != NULL && res != Py_None)
	{
		PyErr_SetString(PyExc_TypeError, "invalid result type from PyQt message handler");
		res = NULL;
	}

	if (res == NULL)
		PyErr_Print();

	SIP_UNBLOCK_THREADS
}
%End
