/******************************************************************************
 JXDisplay.h

	Interface for the JXDisplay class

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

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

#ifndef _H_JXDisplay
#define _H_JXDisplay

#include <JBroadcaster.h>
#include <JRect.h>
#include <JXCursor.h>
#include <JArray.h>
#include <jXEventUtil.h>
#include <X11/Xlib.h>

class JString;
class JFontManager;
class JXGC;
class JXColormap;
class JXDirector;
class JXWindow;
class JXContainer;
class JXFontManager;
class JXSelectionManager;
class JXDNDManager;
class JXMenuManager;
class JXDisplayDirector;
class JXTextClipboard;
class JXButtonStates;
class JXKeyModifiers;

class JXDisplay : virtual public JBroadcaster
{
public:

	static JBoolean	Create(const JCharacter* displayName, JXDisplay** display);

	virtual ~JXDisplay();

	JBoolean	Close();

	operator Display*() const;

	const JString&	GetName() const;
	Display*		GetXDisplay() const;
	JXColormap*		GetColormap() const;
	JSize			GetMaxStringLength() const;

	const JFontManager*		GetFontManager() const;
	const JXFontManager*	GetXFontManager() const;
	JXSelectionManager*		GetSelectionManager() const;
	JXDNDManager*			GetDNDManager() const;
	JXMenuManager*			GetMenuManager() const;

	JXTextClipboard*		GetTextClipboard() const;
	void					UpdateTextClipboard() const;

	JCursorIndex	CreateBuiltInCursor(const JCharacter* name,
										const unsigned int shape);
	JCursorIndex	CreateCustomCursor(const JCharacter* name,
									   const JXCursor& cursor);
	JBoolean		GetCursor(const JCharacter* name,
							  JCursorIndex* index) const;
	void			DisplayCursorInAllWindows(const JCursorIndex index);

	void		AllowPrivateColormap(const JBoolean allow);
	JBoolean	ForcePrivateColormap();

	void	Beep() const;

	void	RaiseAllWindows();
	void	HideAllWindows();

	// These are the current values (hot from the X server via a query)

	void	GetCurrentButtonKeyState(JXButtonStates* buttonStates,
									 JXKeyModifiers* modifiers) const;

	// These are the values received in the latest event

	const JXButtonStates&	GetLatestButtonStates() const;
	const JXKeyModifiers&	GetLatestKeyModifiers() const;

	JBoolean	KeycodeToModifier(const KeyCode keycode, JIndex* modifierIndex) const;

	// XFlush() and XSync()

	void	Flush() const;
	void	Synchronize() const;

	void	SendXEvent(const Window xWindow, XEvent* xEvent) const;

	// useful for Drag-And-Drop, and for Menu objects

	JBoolean	FindMouseContainer(JXContainer** obj, Window* xWindow = NULL,
								   JPoint* ptG = NULL, JPoint* ptR = NULL) const;
	JBoolean	FindMouseContainer(const JXContainer* coordOwner,
								   const JPoint& pt, JXContainer** obj,
								   Window* xWindow = NULL,
								   JPoint* ptG = NULL, JPoint* ptR = NULL) const;

	// called by JXApplication

	void	HandleEvent(const XEvent& xEvent, const Time currentTime);
	void	Idle(const Time currentTime);
	void	Update();
	void	DispatchMouse();

	// called by JXWindow

	void	WindowCreated(JXWindow* window, const Window xWindow);
	void	WindowDeleted(JXWindow* window);
	void	WindowNeedsUpdate(JXWindow* window);

	JXWindow*	GetMouseContainer() const;
	void		SetMouseContainer(JXWindow* window);
	JBoolean	GetMouseGrabber(JXWindow** window) const;
	void		SetMouseGrabber(JXWindow* window);

	Cursor		GetXCursorID(const JCursorIndex index) const;

	static JBoolean	WindowExists(JXDisplay* display, const Display* xDisplay,
								 const Window xWindow);

	Atom	GetWMProtocolsXAtom() const;
	Atom	GetDeleteWindowXAtom() const;
	Atom	GetWMStateXAtom() const;

	// called by Menu objects

	JBoolean	SwitchDrag(JXContainer* fromObj, const JPoint& fromObjPt,
						   const JXButtonStates& buttonStates,
						   const JXKeyModifiers& modifiers,
						   JXContainer* toObj);

	JBoolean	GetKeyboardGrabber(JXWindow** window) const;
	void		SetKeyboardGrabber(JXWindow* window);

	// called by JXColormap

	void	ColormapChanged(JXColormap*	colormap);

	// called by various JX objects

	int		GetScreen() const;
	Visual*	GetDefaultVisual() const;
	JSize	GetDepth() const;
	JSize	GetHorizResolution() const;
	JSize	GetVertResolution() const;

	Window		GetRootWindow() const;
	JRect		GetBounds() const;
	const JXGC*	GetDefaultGC() const;

	Time	GetLastEventTime() const;

	Atom	RegisterXAtom(const JCharacter* name) const;

	JBoolean	FindWindow(const Window xWindow, JXWindow** window) const;

	// installed by JXApplication

	static void	CheckForXErrors();
	static int	JXErrorHandler(Display* xDisplay, XErrorEvent* error);

protected:

	JXDisplay(const JCharacter* displayName, Display* xDisplay);

private:

	struct WindowInfo
	{
		JXWindow*	window;		// not owned
		Window		xWindow;

		WindowInfo()
			:
			window(NULL), xWindow(0)
		{ };

		WindowInfo(JXWindow* w, const Window xw)
			:
			window(w), xWindow(xw)
		{ };
	};

	static JOrderedSetT::CompareResult
		CompareXWindows(const WindowInfo& info1, const WindowInfo& info2);

	struct CursorInfo
	{
		JString*	name;
		Cursor		xid;

		CursorInfo()
			:
			name(NULL), xid(None)
		{ };

		CursorInfo(JString* n, const Cursor id)
			:
			name(n), xid(id)
		{ };
	};

private:

	JString*	itsName;
	Display*	itsXDisplay;
	JXColormap*	itsColormap;
	const JSize	itsMaxStringLength;

	Time		itsLastEventTime;
	Time		itsLastIdleTime;
	Time		itsLastMotionNotifyTime;

	JXButtonStates		itsLatestButtonStates;
	JXKeyModifiers		itsLatestKeyModifiers;
	XModifierKeymap*	itsModifierKeymap;

	JArray<CursorInfo>*	itsCursorList;
	JXGC*				itsDefaultGC;

	JArray<WindowInfo>*	itsWindowList;
	JBoolean			itsNeedsUpdateFlag;
	JXWindow*			itsMouseContainer;		// can be NULL
	JXWindow*			itsMouseGrabber;		// usually NULL
	JXWindow*			itsKeyboardGrabber;		// usually NULL

	JXFontManager*		itsFontManager;
	JXSelectionManager*	itsSelectionManager;
	JXDNDManager*		itsDNDManager;
	JXMenuManager*		itsMenuManager;

	JXDirector*			itsDirOwner;
	JXDisplayDirector*	itsWindDir;
	JXTextClipboard*	itsTextClipboard;

	// atoms used by all JXWindows

	Atom	itsWMProtocolsXAtom;
	Atom	itsDeleteWindowXAtom;
	Atom	itsWMStateXAtom;

private:

	JBoolean	FindMouseContainer(const Window rootWindow,
								   const JCoordinate xRoot, const JCoordinate yRoot,
								   const Window origChildWindow,
								   JXContainer** obj, Window* xWindow = NULL,
								   JPoint* ptG = NULL, JPoint* ptR = NULL) const;

	Cursor	CreateCustomXCursor(const JXCursor& cursor) const;

	// not allowed

	JXDisplay(const JXDisplay& source);
	const JXDisplay& operator=(const JXDisplay& source);

public:

	// JBroadcaster messages

	static const JCharacter* kXError;

	class XError : public JBroadcaster::Message
		{
		public:

			XError(const XErrorEvent& error)
				:
				JBroadcaster::Message(kXError),
				itsXError(error),
				itsCaughtFlag(kFalse)
				{ };

			int
			GetType() const
			{
				return itsXError.error_code;
			};

			XID
			GetXID() const
			{
				return itsXError.resourceid;
			};

			const XErrorEvent&
			GetXError() const
			{
				return itsXError;
			};

			JBoolean
			WasCaught() const
			{
				return itsCaughtFlag;
			};

			void
			SetCaught()
			{
				itsCaughtFlag = kTrue;
			};

		private:

			const XErrorEvent&	itsXError;
			JBoolean			itsCaughtFlag;
		};
};


/******************************************************************************
 Cast to Display*

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

inline
JXDisplay::operator Display*()
	const
{
	return itsXDisplay;
}

/******************************************************************************
 GetXDisplay

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

inline Display*
JXDisplay::GetXDisplay()
	const
{
	return itsXDisplay;
}

/******************************************************************************
 Beep

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

inline void
JXDisplay::Beep()
	const
{
	XBell(itsXDisplay, 0);
}

/******************************************************************************
 SendXEvent

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

inline void
JXDisplay::SendXEvent
	(
	const Window	xWindow,
	XEvent*			xEvent
	)
	const
{
	XSendEvent(itsXDisplay, xWindow, False, 0, xEvent);
}

/******************************************************************************
 Flush

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

inline void
JXDisplay::Flush()
	const
{
	XFlush(itsXDisplay);
}

/******************************************************************************
 Synchronize

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

inline void
JXDisplay::Synchronize()
	const
{
	XSync(itsXDisplay, False);
}

/******************************************************************************
 GetName

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

inline const JString&
JXDisplay::GetName()
	const
{
	return *itsName;
}

/******************************************************************************
 GetScreen

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

inline int
JXDisplay::GetScreen()
	const
{
	return DefaultScreen(itsXDisplay);
}

/******************************************************************************
 GetDefaultVisual

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

inline Visual*
JXDisplay::GetDefaultVisual()
	const
{
	return DefaultVisual(itsXDisplay, GetScreen());
}

/******************************************************************************
 GetDepth

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

inline JSize
JXDisplay::GetDepth()
	const
{
	return DefaultDepth(itsXDisplay, GetScreen());
}

/******************************************************************************
 GetRootWindow

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

inline Window
JXDisplay::GetRootWindow()
	const
{
	return DefaultRootWindow(itsXDisplay);
}

/******************************************************************************
 GetDefaultGC

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

inline const JXGC*
JXDisplay::GetDefaultGC()
	const
{
	return itsDefaultGC;
}

/******************************************************************************
 GetColormap

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

inline JXColormap*
JXDisplay::GetColormap()
	const
{
	return itsColormap;
}

/******************************************************************************
 GetMaxStringLength

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

inline JSize
JXDisplay::GetMaxStringLength()
	const
{
	return itsMaxStringLength;
}

/******************************************************************************
 Get latest event info

	Use these as a last resort if there is no other way to obtain the
	information.  Most of the time, everything you need is passed to the
	event handler (e.g. HandleMouseDrag(), HandleKeyPress(), etc.)

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

inline Time
JXDisplay::GetLastEventTime()
	const
{
	return itsLastEventTime;
}

inline const JXButtonStates&
JXDisplay::GetLatestButtonStates()
	const
{
	return itsLatestButtonStates;
}

inline const JXKeyModifiers&
JXDisplay::GetLatestKeyModifiers()
	const
{
	return itsLatestKeyModifiers;
}

/******************************************************************************
 GetXCursorID

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

inline Cursor
JXDisplay::GetXCursorID
	(
	const JCursorIndex index
	)
	const
{
	return (itsCursorList->GetElement(index)).xid;
}

/******************************************************************************
 RegisterXAtom

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

inline Atom
JXDisplay::RegisterXAtom
	(
	const JCharacter* name
	)
	const
{
	return XInternAtom(itsXDisplay, name, False);
}

/******************************************************************************
 Atoms for JXWindow

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

inline Atom
JXDisplay::GetWMProtocolsXAtom()
	const
{
	return itsWMProtocolsXAtom;
}

inline Atom
JXDisplay::GetDeleteWindowXAtom()
	const
{
	return itsDeleteWindowXAtom;
}

inline Atom
JXDisplay::GetWMStateXAtom()
	const
{
	return itsWMStateXAtom;
}

/******************************************************************************
 GetXFontManager

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

inline const JXFontManager*
JXDisplay::GetXFontManager()
	const
{
	return itsFontManager;
}

/******************************************************************************
 GetSelectionManager

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

inline JXSelectionManager*
JXDisplay::GetSelectionManager()
	const
{
	return itsSelectionManager;
}

/******************************************************************************
 GetTextClipboard

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

inline JXTextClipboard*
JXDisplay::GetTextClipboard()
	const
{
	return itsTextClipboard;
}

/******************************************************************************
 GetDNDManager

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

inline JXDNDManager*
JXDisplay::GetDNDManager()
	const
{
	return itsDNDManager;
}

/******************************************************************************
 GetMenuManager

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

inline JXMenuManager*
JXDisplay::GetMenuManager()
	const
{
	return itsMenuManager;
}

/******************************************************************************
 WindowNeedsUpdate

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

inline void
JXDisplay::WindowNeedsUpdate
	(
	JXWindow* window
	)
{
	itsNeedsUpdateFlag = kTrue;
}

/******************************************************************************
 Mouse container

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

inline JXWindow*
JXDisplay::GetMouseContainer()
	const
{
	return itsMouseContainer;
}

inline void
JXDisplay::SetMouseContainer
	(
	JXWindow* window
	)
{
	itsMouseContainer = window;
}

/******************************************************************************
 Grabbers

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

inline JBoolean
JXDisplay::GetMouseGrabber
	(
	JXWindow** window
	)
	const
{
	*window = itsMouseGrabber;
	return JConvertToBoolean( *window != NULL );
}

inline void
JXDisplay::SetMouseGrabber
	(
	JXWindow* window
	)
{
	itsMouseGrabber = window;
}

inline JBoolean
JXDisplay::GetKeyboardGrabber
	(
	JXWindow** window
	)
	const
{
	*window = itsKeyboardGrabber;
	return JConvertToBoolean( *window != NULL );
}

inline void
JXDisplay::SetKeyboardGrabber
	(
	JXWindow* window
	)
{
	itsKeyboardGrabber = window;
}

#endif
