// -*-C++-*- 

/*  inc/platform/Xq.hpp  */

/*
 * Author: Philogelos A. <Philogelos@yahoo.com>
 * Maintainer: Philogelos A.
 * Keywords: C++, library, containers
 *
 * Copyright (C) 1999 Philogelos A.
 *
 * This file is part of Quercus Robusta.
 *
 * Quercus Robusta is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This software is distributed 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 Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this software; see the file COPYING.LIB.  If not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 */



#ifndef __XQ_HPP__
#define __XQ_HPP__

/* $Id$ */

#define USE_XQ

#if defined( WANT_USE_XQ )
#define USE_XQ
#elif defined( UNWANT_USE_XQ )
#if defined( USE_XQ )
#undef USE_XQ
#endif
#endif

#if defined( USE_XQ )

#include "String.hpp"
#include "Object.hpp"
#include "Top.hpp"
#include "defines.h"
#include "platform/threads/Runnable.hpp"
#include "platform/threads/Thread.hpp"
#include "exceptions/Errno.hpp"
#include "iter/enumerations/TypedEnumeration.hpp"
#include "observe/ObservableAdapter.hpp"
#include "observe/PassiveObserver.hpp"
#include "Condition.hpp"
#include "platform/Aq.hpp"

#include <X11/X.h>
#include <X11/Xlib.h>

#define XQ_USE_X11_MUTEX
/* #define XQ_USE_XINITTHREADS */

#define XQ_XCHECKEVENT_HACK
#define XQ_XCHECKEVENT_HACK_TIMEOUT 10000000

#define USE_XPM

#if defined( WANT_XQ_USE_X11_MUTEX )
#define XQ_USE_X11_MUTEX
#elif defined( UNWANT_XQ_USE_X11_MUTEX )
#if defined( XQ_USE_X11_MUTEX )
#undef XQ_USE_X11_MUTEX
#endif
#endif

#if defined( WANT_XQ_USE_XINITTHREADS )
#define XQ_USE_XINITTHREADS
#elif defined( UNWANT_XQ_USE_XINITTHREADS )
#if defined( XQ_USE_XINITTHREADS )
#undef XQ_USE_XINITTHREADS
#endif
#endif

#if defined( WANT_XQ_XCHECKEVENT_HACK )
#define XQ_XCHECKEVENT_HACK
#elif defined( UNWANT_XQ_XCHECKEVENT_HACK )
#if defined( XQ_XCHECKEVENT_HACK )
#undef XQ_XCHECKEVENT_HACK
#endif
#endif

#if defined( WANT_XQ_XCHECKEVENT_HACK_TIMEOUT )
#define XQ_XCHECKEVENT_HACK_TIMEOUT
#elif defined( UNWANT_XQ_XCHECKEVENT_HACK_TIMEOUT )
#if defined( XQ_XCHECKEVENT_HACK_TIMEOUT )
#undef XQ_XCHECKEVENT_HACK_TIMEOUT
#endif
#endif

#if defined( WANT_XQ_XCHECKEVENT_HACK_TIMEOUT )
#define XQ_XCHECKEVENT_HACK_TIMEOUT WANT_XQ_XCHECKEVENT_HACK_TIMEOUT
#endif

#if defined( WANT_USE_XPM )
#define USE_XPM
#elif defined( UNWANT_USE_XPM )
#if defined( USE_XPM )
#undef USE_XPM
#endif
#endif

class Mutex;

/**

   @author Philogelos
   @created
*/
class Xq : public virtual Top
{

public:
  class XqObject;

  class XIDObject;
  class Display;
  class Window;
  class GC;
  class Font;
  class Pixmap;
  class Bitmap;
  class Color;
  class Point;
  class Rectangle;
  class Geometry;
  class Bitmask;
  class Drawable;
  class Cursor;
  class KeySym;
  class XException;
 
  class XqEvent;
  class XqEventSource;
  class WindowEventSource;
  class XqEventDispatcher;

  class KeyEvent;
  class ButtonEvent;
  class MouseMotionEvent;
  class FocusEvent;
  class WindowEvent;
  class DestroyEvent;
  class ResizeEvent;
  class SelectionEvent;

  class Applet;
  class AppletThread;

  typedef int Coord;

public: class XqObject : public virtual Object
{
public: XqObject( Display *aDisplay );
public: virtual ~XqObject();

public: void setDisplay( Display *aDisplay );
public: Xq::Display *getDisplay() const;

public: virtual String toString() const;
public: virtual String getClassName() const;

protected: Xq::Display *display;
};

public: class XIDObject : public virtual XqObject
{
public: XIDObject( Display *aDisplay, XID anId );
public: virtual ~XIDObject();

public: void setId( XID anId );
public: XID getId() const;

public: virtual String toString() const;
public: virtual String getClassName() const;

protected: XID id;
};

public: class Drawable : public virtual XIDObject,
		public Aq::Drawable
{
public: Drawable( Display *aDisplay, XID anId );
public: void copyTo( Xq::Drawable *aDest, Xq::GC *aGC, 
					 Xq::Coord aSrcX, Xq::Coord aSrcY, 
					 int aWidth, int aHeight,
					 Xq::Coord aDstX, Xq::Coord aDstY );
public: void drawPoint( Xq::GC *aGC, Xq::Coord aX, Xq::Coord aY );
public: void drawLine( Xq::GC *aGC, 
					   Xq::Coord aStartX, Xq::Coord aStartY,
					   Xq::Coord anEndX, Xq::Coord anEndY );

public: void fillRectangle( Xq::GC *aGC, Xq::Coord aX, Xq::Coord aY, 
							int aWidth, int aHeight );
public: void drawString( Xq::GC *aGC, Xq::Coord aX, Xq::Coord aY, 
						 String aString );
public: void drawCString( Xq::GC *aGC, Xq::Coord aX, Xq::Coord aY, 
						  char *aString );
};

public: class XqEventSource : public Aq::EventSource
{
public: XqEventSource();

public: virtual Aq::AqEvent *getNextTypedElement() = 0;
};

public: class Display : public Aq::EventSource
{
protected: Display( struct _XDisplay *aDisplay );
public: virtual ~Display();

public: void close();
public: int connectionNumber() const;
public: int screen() const;
public: Xq::Window *getRootWindow() const;
public: XID defaultColormap() const;
public: int blackPixel() const;
public: int whitePixel() const;
public: int defaultDepth() const;
public: Visual *defaultVisual( int aScreen ) const;

public: Coord getWidth() const;
public: Coord getHeight() const;

public: static Display *open();
public: static Display *open( const char *aName );

public: void setData( struct _XDisplay *aDisplay );
public: struct _XDisplay *getData() const;

public: virtual Aq::AqEvent *getNextTypedElement();

public: virtual String getClassName() const;

protected: struct _XDisplay *x11Data;
protected: Xq::Window *rootWindow;

#if defined( USE_THREADS ) && defined( XQ_USE_X11_MUTEX )
public: Mutex *getX11Serialiser() const;
protected: Mutex *x11Serializer;
#endif
};

public: class Window : public Drawable,
		public Aq::Window
		
{
public: Window( Display *aDisplay, XID anId );
public: virtual ~Window();

public: void map();
public: void unmap();
public: void clear();
public: void setCursor( Xq::Cursor *aCursor );
public: void unsetCursor();

public: void setSize( int aWidth, int aHeight );
public: void setSizeHints( int aMinWidth, int aMinHeight,
						   int aMaxWidth, int aMaxHeight,
						   int aBaseWidth, int aBaseHeight,
						   int aWidthInc, int aHeightInc );

public: void setName( String aName );
public: void setClass( String aName, String aClass );

public: void selectInput( long aMask );

public: Xq::WindowEventSource *getXEventSource() const;
public: Aq::EventSource *getEventSource() const;

public: static Xq::Window *createSimple( Xq::Display *aDisplay,
										 Xq::Window *aParent,
										 int aX, int aY, 
										 int aWidth, int aHeight, 
										 int aBorderWidth,
										 int aForePixel, int aBackPixel );
public: virtual String getClassName() const;
};

public: class WindowEventSource : public XqEventSource
{
public: WindowEventSource( const Xq::Window *aWindow );
public: virtual ~WindowEventSource();

public: Xq::Window *getWindow() const;

public: virtual Aq::AqEvent *getNextTypedElement();

public: virtual String getClassName() const;

protected: const Xq::Window *window;
};

public: class GC : public virtual XqObject, public virtual Aq::GraphicContext
{
public: GC( Xq::Display *aDisplay, struct _XGC *aGC );
public: virtual ~GC();

public: struct _XGC *getData() const;
public: void setData( struct _XGC *aGC );

public: void setFont( Xq::Font *aFont );
public: void setBackground( Xq::Color *aColor );
public: void setForeground( Xq::Color *aColor );
public: void setClipMask( Xq::Pixmap *aPixmap );

public: Xq::Color *getBackground() const;
public: Xq::Color *getForeground() const;

public: void copyTo( GC *aGC ) const;

public: void setGraphicsExposures( boolean aFlag );

public: static Xq::GC *create( Xq::Display *aDisplay, Xq::Drawable *aDrawable );

protected: struct _XGC *x11Data;
};

public: class Font : public virtual XqObject
{
public: Font( Display *aDisplay, XFontStruct *aData );
public: virtual ~Font();

public: XFontStruct *getData() const;
public: void setData( XFontStruct *aData );

public: Aq::Size getWidth() const;
public: Aq::Size getHeight() const;
public: Aq::Size getAscent() const;

public: static Xq::Font *createFixed( Display *aDisplay );
public: static Xq::Font *create( Display *aDisplay, String aName );

protected: XFontStruct *x11Data;
};

public: class Pixmap : public virtual Drawable
{
public: Pixmap( Display *aDisplay, XID anId, 
				int aWidth, int aHeight, 
				int aXHot, int aYHot );
public: virtual ~Pixmap();

public: Xq::Coord getWidth() const;
public: Xq::Coord getHeight() const;
public: int getXHot() const;
public: int getYHot() const;

public: void writeToXBMFile( String aFileName );

public: static Pixmap *create( Xq::Drawable *aDrawable, 
							   int aWidth, 
							   int aHeight, 
							   int aDepth );
public: static Pixmap *create( Xq::Drawable *aDrawable, 
							   String aFileName );
#if defined( USE_XPM )
public: static Pixmap *createFromXPM( Xq::Drawable *aDrawable, 
									  String aFileName,
									  Xq::Pixmap **aMask );
public: void writeToXPMFile( String aFileName );
public: static void handleXPMError( int aCode, String aMessage );
#endif

public: static Pixmap *create( Xq::Drawable *aDrawable, 
							   char *aData,
							   int aWidth, int aHeight );

protected: Xq::Coord width;
protected: Xq::Coord height;
protected: int xHot;
protected: int yHot;
};

/* 
public: class Bitmap : public virtual Pixmap
{
};
*/

public: class Color : public virtual XqObject
{
public: Color( Display *aDisplay, XColor *aColor );
public: virtual ~Color();

public: XColor *getData() const;
public: void setData( XColor *aData );

public: static Xq::Color *create( Display *aDisplay, String aName );
public: static Xq::Color *create( Display *aDisplay, unsigned long aPixel );

protected: XColor x11Data;
};

/*
public: class Point : public virtual XqObject
{
};

public: class Rectangle : public virtual XqObject
{
};

public: class Geometry : public virtual XqObject
{
};

public: class Bitmask : public virtual XqObject
{
};

public: class KeySym : public virtual XqObject
{
};
*/

public: class Cursor : public virtual XIDObject
{
public: Cursor( Display *aDisplay, XID anId );
public: virtual ~Cursor();

public: void recolor( Xq::Color *fg, Xq::Color *bg );

public: static Xq::Cursor *createStd( Xq::Display *aDisplay,
									  int shape );
public: static Xq::Cursor *create( Xq::Display *aDisplay,
								   Xq::Pixmap *source, Xq::Pixmap *mask,
								   Xq::Color *foreground, 
								   Xq::Color *background,
								   Xq::Coord xHot, Xq::Coord yHot );
};


public: class XException : public OSError
{
public: XException( struct _XDisplay *aDisplay, XErrorEvent *anEvent );
public: XException( String aMessage );

public: virtual ~XException();

public:  virtual String  getClassName() const;
public:  virtual String  getDescription() const;

protected: XErrorEvent event;
public: typedef struct { int xRequestId; const char *xRequestName; } MapEntry;
protected: static MapEntry requestNameMap[];
protected: boolean fromEvent;
};

public: class XFatalException : public Errno
{
public: XFatalException( struct _XDisplay *aDisplay );
public: virtual ~XFatalException();

public: virtual String  getClassName() const;
public: virtual String  getDescription() const;
};

public: class XqEvent : public virtual Aq::AqEvent,
		public virtual XqObject
{
public: XqEvent( Xq::Display *aDisplay, XEvent *aData );
public: virtual ~XqEvent();

public: XEvent *getData() const;

public: static XqEvent *create( Xq::Display *aDisplay, 
								XEvent *aData,
								Xq::Window *aWindow = ( Xq::Window * ) NULL );

public: Xq::Window *getWindow() const;
public: void setWindow( Xq::Window *aWindow );

public: virtual String toString() const;
public: virtual String getClassName() const;

protected: XEvent event;
protected: Xq::Window *window;
};

public: class KeyEvent : public virtual Xq::XqEvent,
		public virtual Aq::KeyEvent
{
public: KeyEvent( Xq::Display *aDisplay, XEvent *aData );
public: ~KeyEvent();

public: unsigned int getKeycode() const;
public: ::KeySym getKeySym() const;

public: static ::KeySym keycodeToKeysym( Xq::Display *aDisplay,
										 unsigned int aKeycode );
public: static String keysymToString( Xq::Display *aDisplay,
									  ::KeySym aKeySym );

public: virtual String getClassName() const;
};

public: class ButtonEvent : public virtual Xq::XqEvent,
		public virtual Aq::KeyEvent

{
public: ButtonEvent( Xq::Display *aDisplay, XEvent *aData );
public: ~ButtonEvent();

public: virtual String getClassName() const;
};

public: class MouseMotionEvent : public virtual Xq::XqEvent,
		public virtual Aq::KeyEvent

{
public: MouseMotionEvent( Xq::Display *aDisplay, XEvent *aData );
public: ~MouseMotionEvent();

public: virtual String getClassName() const;
};

public: class FocusEvent : public virtual Xq::XqEvent,
		public virtual Aq::KeyEvent

{
public: FocusEvent( Xq::Display *aDisplay, XEvent *aData );
public: ~FocusEvent();

public: virtual String getClassName() const;
};

public: class WindowEvent : public virtual Xq::XqEvent,
		public virtual Aq::KeyEvent

{
public: WindowEvent( Xq::Display *aDisplay, XEvent *aData );
public: ~WindowEvent();

public: virtual String getClassName() const;
};

public: class DestroyEvent : public virtual Xq::XqEvent,
		public virtual Aq::KeyEvent

{
public: DestroyEvent( Xq::Display *aDisplay, XEvent *aData );
public: ~DestroyEvent();

public: virtual String getClassName() const;
};

public: class ResizeEvent : public virtual Xq::XqEvent,
		public virtual Aq::KeyEvent

{
public: ResizeEvent( Xq::Display *aDisplay, XEvent *aData );
public: ~ResizeEvent();

public: virtual String getClassName() const;
};

public: class SelectionEvent : public virtual Xq::XqEvent,
		public virtual Aq::KeyEvent

{
public: SelectionEvent( Xq::Display *aDisplay, XEvent *aData );
public: ~SelectionEvent();

public: virtual String getClassName() const;
};

public: class Applet : public virtual XqObject,
  public virtual Aq::EventDispatcher,
  public virtual PassiveObserver
{
public: Applet( Xq::Drawable *aDrawable, 
				Xq::XqEventSource *aSource, Xq::GC *aGC  );
public: virtual ~Applet();

public: virtual void paint( Xq::Drawable *aDrawable, Xq::GC *aGraphics ) = 0;

public: virtual Xq::Drawable *getDrawable() const;

public: virtual void activate();
public: virtual void deactivate();

public: virtual void onWindowEvent( Aq::WindowEvent *anEvent );
public: virtual HandlerResult fire( Condition *aCondition, 
									ObservationContext *aContext );

protected: Xq::Drawable *drawable;
protected: Xq::GC *graphics;
};

public: class AppletThread : public Runnable,
  public virtual Object
{
public: AppletThread( Xq::Applet *anApplet, int aDelay );
public: virtual ~AppletThread();

public: void start();
public: void *run();

public: virtual void step() = 0;

protected: Xq::Applet *applet;
protected: int delay;
protected: Thread *thread;
};

public: class X11WindowSystem : public virtual Aq::GUISystem,
  public virtual Object
{
public: virtual Aq::Painter *createPainter( Aq::GraphicContext *aContext, 
											Aq::Drawable *aDrawable ) const;
public: static X11WindowSystem *x11WindowSystem;
};

public: class XPainter : public Aq::Painter,
  public virtual Object
{
public: XPainter( GC *aGC, Drawable *aDrawable );
public: virtual ~XPainter();

public: virtual void init();
public: virtual void done();

public: virtual void drawLine( Aq::CoordX aStartX, Aq::CoordY aStartY, 
							   Aq::CoordX anEndX, Aq::CoordY anEndY ) const;
public: virtual void drawPoint( Aq::CoordX aX, Aq::CoordY aY ) const;
public: virtual void drawCString( Aq::CoordX aX, Aq::CoordY aY, 
								  char *aString ) const;

public: virtual void fillRectangle( Aq::CoordX aX, Aq::CoordY aY,
									Aq::Size aWidth, Aq::Size aHeight ) const;
public: virtual void clearRectangle( Aq::CoordX aX, Aq::CoordY aY,
									 Aq::Size aWidth, Aq::Size aHeight ) const;

public: virtual void copyFrom( Aq::CoordX aSourceX, Aq::CoordY aSourceY, 
							   Aq::Size aWidth, Aq::Size aHeight,
							   Aq::Drawable *aDrawable,
							   Aq::CoordX aDestX, Aq::CoordY aDestY ) const;

public: virtual void setDrawable( Aq::Drawable *aDrawable );
public: Drawable *getXDrawable() const;
public: GC *getGC() const;
public: GC *getClearGC() const;

public: static XPainter *create( GC *aGC, Drawable *aDrawable, 
								 Xq::Color *aFore );

protected: GC *clearGC;
protected: Drawable *arena;
};

#if defined( TESTING )
public: static boolean tester( int );
#endif
};

/* USE_XQ */
#endif

/* $Log$ */

/* __XQ_HPP__ */
#endif

