/******************************************************************************
 JXApplication.h

	Interface for the JXApplication class

	Copyright © 1996-97 by John Lindal. All rights reserved.

 ******************************************************************************/

#ifndef _H_JXApplication
#define _H_JXApplication

#include <JXDirector.h>
#include <JXDocumentManager.h>	// need definition of SafetySaveReason
#include <JPtrArray.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

class JString;
class JXDisplay;
class JXWindow;
class JXIdleTask;
class JXUrgentTask;

class JXApplication : public JXDirector
{
public:

	JXApplication(int* argc, char* argv[]);

	virtual ~JXApplication();

	void			Run();
	virtual void	Quit();

	void	DisplayBusyCursor();
	void	DisplayInactiveCursor();

	void	HideAllWindows();

	Time	GetCurrentTime() const;

	void	InstallIdleTask(JXIdleTask* newTask);
	void	RemoveIdleTask(JXIdleTask* task);

	void	InstallUrgentTask(JXUrgentTask* newTask);
	void	RemoveUrgentTask(JXUrgentTask* task);

	JXDisplay*	GetCurrentDisplay() const;
	void		SetCurrentDisplay(const JIndex index);
	void		SetCurrentDisplay(JXDisplay* display);

	JSize		GetDisplayCount() const;
	JXDisplay*	GetDisplay(const JIndex index) const;
	JBoolean	GetDisplayIndex(JXDisplay* display, JIndex* index) const;

	const JPtrArray<JXDisplay>*	GetDisplayList() const;

	JBoolean	OpenDisplay(const JCharacter* displayName, JIndex* displayIndex);
	JBoolean	DisplayExists(const Display* xDisplay);
	JBoolean	FindDisplay(const Display* xDisplay, JXDisplay** display);

	// for use by main()

	static void	RemoveCmdLineOption(int* argc, char* argv[],
									const unsigned long offset,
									const unsigned long removeCount);

	// called by JXDisplay

	void	DisplayOpened(JXDisplay* display);
	void	DisplayClosed(JXDisplay* display);

	// for use by special windows that block until dismissed

	void	PrepareForBlockingWindow();
	void	BlockingWindowFinished();

	JBoolean	HasBlockingWindow() const;
	JBoolean	HadBlockingWindow() const;
	JBoolean	HandleOneEventForWindow(JXWindow* window,
										const JBoolean allowSleep = kTrue);

	// required by JXInitGlobals()

	static int	JXIOErrorHandler(Display* xDisplay);

	// called by JXAssert

	static void	Abort(const JXDocumentManager::SafetySaveReason reason,
					  const JBoolean dumpCore);

protected:

	void				UpdateCurrentTime();
	virtual JBoolean	HandleCustomEvent();
	virtual void		HandleCustomEventWhileBlocking(JBoolean* allowSleep);

	void	CheckACEReactor();

	virtual JBoolean	Close();	// use Quit() instead

	virtual void	CleanUpBeforeSuddenDeath(const JXDocumentManager::SafetySaveReason reason);

private:

	typedef JPtrArray< JPtrArray<JXIdleTask> >	IdleTaskStack;

private:

	JPtrArray<JXDisplay>*	itsDisplayList;
	JIndex					itsCurrDisplayIndex;
	JBoolean				itsIgnoreDisplayDeletedFlag;
	JBoolean				itsIgnoreTaskDeletedFlag;

	Time					itsCurrentTime;			// in milliseconds
	JPtrArray<JXIdleTask>*	itsIdleTasks;
	Time					itsMaxSleepTime;		// in milliseconds
	Time					itsLastIdleTime;		// in milliseconds
	Time					itsLastIdleTaskTime;	// in milliseconds
	JSize					itsWaitForChildCounter;
	IdleTaskStack*			itsIdleTaskStack;

	JPtrArray<JXUrgentTask>*	itsUrgentTasks;
	JPtrArray<JXUrgentTask>*	itsActiveUrgentTasks;
	JIndex						itsUTInsertIndex;
	JBoolean					itsHasBlockingWindowFlag;
	JBoolean					itsHadBlockingWindowFlag;

	JBoolean	itsRequestQuitFlag;

private:

	void	HandleOneEvent();
	void	PerformIdleTasks();
	void	PerformUrgentTasks();

	void	PushIdleTaskStack();
	void	PopIdleTaskStack();
	void	PopAllIdleTaskStack();

	static void	ParseBaseOptions(int* argc, char* argv[], JString* displayName);

	static Bool	GetNextWindowEvent(Display* display, XEvent* event, char* arg);
	static Bool	GetNextBkgdEvent(Display* display, XEvent* event, char* arg);
	static Bool	DiscardNextEvent(Display* display, XEvent* event, char* arg);

	// not allowed

	JXApplication(const JXApplication& source);
	const JXApplication& operator=(const JXApplication& source);
};


/******************************************************************************
 GetCurrentTime

 ******************************************************************************/

inline Time
JXApplication::GetCurrentTime()
	const
{
	return itsCurrentTime;
}

/******************************************************************************
 GetCurrentDisplay

 ******************************************************************************/

inline JXDisplay*
JXApplication::GetCurrentDisplay()
	const
{
	return itsDisplayList->NthElement(itsCurrDisplayIndex);
}

/******************************************************************************
 GetDisplayCount

 ******************************************************************************/

inline JSize
JXApplication::GetDisplayCount()
	const
{
	return itsDisplayList->GetElementCount();
}

/******************************************************************************
 GetDisplay

 ******************************************************************************/

inline JXDisplay*
JXApplication::GetDisplay
	(
	const JIndex index
	)
	const
{
	return itsDisplayList->NthElement(index);
}

/******************************************************************************
 GetDisplayIndex

 ******************************************************************************/

inline JBoolean
JXApplication::GetDisplayIndex
	(
	JXDisplay*	display,
	JIndex*		index
	)
	const
{
	return itsDisplayList->Find(display, index);
}

/******************************************************************************
 GetDisplayList

 ******************************************************************************/

inline const JPtrArray<JXDisplay>*
JXApplication::GetDisplayList()
	const
{
	return itsDisplayList;
}

/******************************************************************************
 DisplayExists

	Returns kTrue if the given display hasn't been deleted.

 ******************************************************************************/

inline JBoolean
JXApplication::DisplayExists
	(
	const Display* xDisplay
	)
{
	JXDisplay* d;
	return FindDisplay(xDisplay, &d);
}

/******************************************************************************
 Blocking window

 ******************************************************************************/

inline JBoolean
JXApplication::HasBlockingWindow()
	const
{
	return itsHasBlockingWindowFlag;
}

inline JBoolean
JXApplication::HadBlockingWindow()
	const
{
	return itsHadBlockingWindowFlag;
}

inline void
JXApplication::PrepareForBlockingWindow()
{
	PushIdleTaskStack();
}

inline void
JXApplication::BlockingWindowFinished()
{
	PopIdleTaskStack();
}

#endif
