/*
 $Id: xdriv.cc,v 1.3 1996/10/08 08:17:45 roitzsch Exp $
 (C)opyright 1996 by Konrad-Zuse-Center, Berlin
 All rights reserved.
 Part of the Kaskade distribution
*/

#include "drivers.h"  
#include "driversimp.h"  

//  #define NeedFunctionPrototypes 0


#define K180PI 57.29578

#define TRANSX(X) ((X)*(graph->xScal)+(graph->xTrans))
#define TRANSY(Y) ((graph->wdHght)-(Y)*(graph->yScal)-(graph->yTrans))
#define MIN(x,y)  (((x) < (y)) ?  (x) : (y))

#define STDCOLORS 32
#define GRAYS 24

#define not_Null 1L

static const unsigned lineWidth[3] = { 1, 2, 4 };
static const int length[] = { 2, 2, 2, 2, 4, 6 };
static const char pattern[6][7] = {
				{ 1, 2 },
				{ 1, 4 },
				{ 3, 3 },
				{ 6, 3 },
				{ 5, 3, 1, 3 },
				{ 5, 3, 1, 3, 1, 3 }
			     };

static char *mrkfontName[2] = {
    "-adobe-symbol-medium-r-normal--14-140-75-75-p-85-adobe-fontspecific", "8x13"
};

static char *fontName[2][3] =
 { { 
     "-adobe-helvetica-medium-r-normal--10-100-75-75-p-56-iso8859-1",
     "-adobe-helvetica-medium-r-normal--12-120-75-75-p-67-iso8859-1",
     "-adobe-helvetica-medium-r-normal--14-140-75-75-p-77-iso8859-1"
   },
   { 
     "6x10", "8x13", "9x15"
   }
 };


#define MAXXMARKERS 7

static const char XMarkers[2][MAXXMARKERS] = {
					 { ' ', '*', 180, '+', 183, 196, 197 },
					 { ' ', '*', 'x', '+', 'o', ' ', ' ' }
				       };

static const int dxMarker[MAXXMARKERS] = { 0, -3, -3, -3, -3, -5, -5 };
static const int dyMarker[2][MAXXMARKERS] = {
					{ 0, 5, 4, 4, 4, 5, 5 },
					{ 0, 4, 3, 4, 2, 0, 0 }
				      };

/*-------------------------------------------------------------------------*/


int XDriverImp:: OpenPort(GRAPHIC *graph)
{
    int  no = graph->wdNo;
    XWMHints wmhints;
    XSizeHints  hint;
    XEvent  event;
    XSetWindowAttributes  attribute;

    if (graph->ready)  return False;

/*    graph->wdWdth -= 8;
    graph->wdHght -= 36;
*/   hint.height = graph->wdHght;

    hint.width = graph->wdWdth;
    hint.x = graph->wdOrgX;
    hint.y = graph->wdOrgY - hint.height - 31;
    hint.flags = PPosition | PSize;

    window[no] = XCreateSimpleWindow(display, DefaultRootWindow(display),
				     hint.x, hint.y, hint.width, hint.height, 0,
				     BlackPixel(display, screen),
				     pixels[graph->backgrCol]);

    gc[no] = XCreateGC(display, window[no], (unsigned long)0, 0);

    wmhints.flags = InputHint;
    wmhints.input = True;
    XSetWMHints(display, window[no], &wmhints);

    /* XSetBackground(display, gc[no], BlackPixel(display, screen)); */
    XSetForeground(display, gc[no], WhitePixel(display, screen));
    if (graph->linestyle != SOLID)
      {
        XSetDashes(display, gc[no], 0, pattern[graph->linestyle], 
		   length[graph->linestyle]);
        XSetLineAttributes(display, gc[no], 
		       	   lineWidth[graph->drPenSz], 
			   LineOnOffDash, CapButt, 0);
      }
    else
      XSetLineAttributes(display, gc[no], 
			 lineWidth[graph->drPenSz], LineSolid, 
			 CapButt, 0);

    XSetFillRule(display, gc[no], WindingRule); 

    XSetStandardProperties(display, window[no], graph->caption, graph->caption,
						None, 0, 0, &hint);

    XSelectInput(display, window[no], ExposureMask);

    XMapRaised(display, window[no]);

    do
      XWindowEvent(display, window[no], ExposureMask, &event);
    while (event.xexpose.count != 0);

    attribute.backing_store = Always;
    XChangeWindowAttributes(display, window[no], CWBackingStore, &attribute);

    XSelectInput(display, window[no], ButtonPressMask | KeyPressMask);
    graph->ready = True;
    if (fonttyp != -1)  SelFont(graph);

    return True;
  }





int XDriverImp::NewPict(GRAPHIC *graph)
{
    int no = graph->wdNo;

    if (no < 0) return False;
    if (graph->ready)  
    {
	XClearWindow(display, window[no]);
    	XFlush (display);
    }
    return True;
}



int XDriverImp::Close(GRAPHIC *graph)
{
    int no = graph->wdNo;

    if (no < 0)  return False;
    if (graph->ready && window[no] != 0)  
    {
	XDestroyWindow(display, window[no]);
	XFlush (display);
    }
    window[no] = 0;

    return True;
}



int XDriverImp::Color(int col_no, int rVal, int gVal, int bVal)
{
    XColor col;

    XFreeColors(display, colormap, &pixels[col_no], 1, 0);

    col.red   = rVal * 257;
    col.green = gVal * 257;
    col.blue  = bVal * 257;
    col.flags = DoRed | DoGreen | DoBlue;

    if (!XAllocColor(display, colormap, &col))
      {
	printf("MiniGraphic - color :  failure to allocate color !\n");
	return False;
      }

    pixels[col_no] = col.pixel;

    return True;
  }
/*-------------------------------------------------------------------------*/


int XDriverImp::PLine(GRAPHIC *graph, double* xx, double* yy, int n)
{
    int ind = graph->wdNo, k;
    double x, y, a, b;
    XPoint pt[MAX_POINTS];

    for (k = 0; k < n; k++)
    {
	x = xx[k]; 
	y = yy[k];

	a = TRANSX(x); 
	pt[k].x = (int) a;
	b = TRANSY(y);
	pt[k].y = (int) b;
    }
    
    XSetForeground(display, gc[ind], pixels[graph->penCol]);
    XDrawLines(display, window[ind], gc[ind], pt, n, 0);

    return True;
}

int XDriverImp::PLine(GRAPHIC *graph, float* xx, float* yy, int n)
{
    int ind = graph->wdNo, k;
    float x, y, a, b;
    XPoint pt[MAX_POINTS];

    for (k = 0; k < n; k++)
    {
	x = xx[k]; 
	y = yy[k];
	a = TRANSX(x); 
	pt[k].x = (int) a;
	b = TRANSY(y);
	pt[k].y = (int) b;
    }
    
    XSetForeground(display, gc[ind], pixels[graph->penCol]);
    XDrawLines(display, window[ind], gc[ind], pt, n, 0);

    return True;
}
/*-------------------------------------------------------------------------*/


int XDriverImp::PMarker(GRAPHIC *graph, float*xx, float* yy, int n)
{
    int no = graph->wdNo, k, px, py;
    float x, y;
    char s[2];

    if (mrkFont == 0)
    {
        printf("MiniGraphic - marker :  no markers on screen !\n");
        return False;
    }
    
    XSetFont(display, gc[no], mrkFont);
    XSetForeground(display, gc[no], pixels[graph->mrkCol]);
    s[0] = XMarkers[mrk_fonttyp][graph->mark]; s[1] = '\0';
    for (k=0; k<n; k++)
    {
	x = xx[k]; 
	y = yy[k]; 
	px = (int) TRANSX(x)+dxMarker[graph->mark];
	py = (int) TRANSY(y)+dyMarker[mrk_fonttyp][graph->mark];
	XDrawString(display, window[no], gc[no], px, py, s, 1);
	
    }
    if (fonttyp != -1)
    XSetFont(display, gc[no], font[no]);
    
    return True;
}

int XDriverImp::PMarker(GRAPHIC *graph, double*xx, double* yy, int n)
{
    int no = graph->wdNo, k, px, py;
    double x, y;
    char s[2];

    if (mrkFont == 0)
    {
        printf("MiniGraphic - marker :  no markers on screen !\n");
        return False;
    }
    
    XSetFont(display, gc[no], mrkFont);
    XSetForeground(display, gc[no], pixels[graph->mrkCol]);
    s[0] = XMarkers[mrk_fonttyp][graph->mark]; s[1] = '\0';
    for (k=0; k<n; k++)
    {
	x = xx[k]; 
	y = yy[k]; 
	px = (int) TRANSX(x)+dxMarker[graph->mark];
	py = (int) TRANSY(y)+dyMarker[mrk_fonttyp][graph->mark];
	XDrawString(display, window[no], gc[no], px, py, s, 1);
	
    }
    if (fonttyp != -1)
    XSetFont(display, gc[no], font[no]);
    
    return True;
}
/*-------------------------------------------------------------------------*/



int XDriverImp:: Text(GRAPHIC *graph, double x, double y, char *s)
{
    int no = graph->wdNo;
    int px = (int) TRANSX(x), py = (int) TRANSY(y);
 
    if (fonttyp == -1)
      return False;
    XSetForeground(display, gc[no], pixels[graph->fntCol]);
    if (graph->FntProp == TRANSPARENT)
      XDrawString(display, window[no], gc[no], px, py, s, strlen(s));
    else
      XDrawImageString(display, window[no], gc[no], px, py, s, strlen(s));

    return True;
}
    
/*-------------------------------------------------------------------------*/


int XDriverImp::Fill(GRAPHIC *graph, float* xx, float* yy, int n)
{
    int no = graph->wdNo, k;
    float x, y;
    XPoint pt[MAX_POINTS];

    for (k=0; k<n; k++)
    {
	x = xx[k]; 
	y = yy[k]; 
	pt[k].x = (int) TRANSX(x); 
	pt[k].y = (int) TRANSY(y);
    }
    XSetForeground(display, gc[no], pixels[graph->fllCol]);
    XFillPolygon(display, window[no], gc[no], pt, n, Complex, CoordModeOrigin);  
    
    return True;
}
//-------------------------------------------------------------------------


int XDriverImp::Fill(GRAPHIC *graph, double* xx, double* yy, int n)
{
    int no = graph->wdNo, k;
    double x, y;
    XPoint pt[MAX_POINTS];

    for (k=0; k<n; k++)
    {
	x = xx[k]; 
	y = yy[k]; 
	pt[k].x = (int) TRANSX(x); 
	pt[k].y = (int) TRANSY(y);
    }
    XSetForeground(display, gc[no], pixels[graph->fllCol]);
    XFillPolygon(display, window[no], gc[no], pt, n, Complex, CoordModeOrigin);  
    
    return True;
}
/*-------------------------------------------------------------------------*/

 
int XDriverImp::Settings(GRAPHIC *graph, int type, int iVal)
{
    int no = graph->wdNo;

    switch (type)
    {
    case WDORGX :
      if ((iVal >= 0) && (iVal <= graph->right))
    	graph->wdOrgX = iVal;
      else
       {
         printf("MiniGraphic - set :  wrong value for WDORGX  %d !\n", iVal);
	 return False;
       }
      return True;
      
    case WDORGY :
      if ((iVal >= 0) && (iVal <= graph->bottom))
    	graph->wdOrgY = iVal;
      else
       {
      	 printf("MiniGraphic - set :  wrong value for WDORGY  %d !\n", iVal);
	 return False;
       }
      return True;
    
    case WDWDTH :
      if ((iVal >= 0) && (iVal + graph->wdOrgX <= graph->right))
    	graph->wdWdth = iVal;
      else
       {
      	 printf("MiniGraphic - set :  wrong value for WDWDTH  %d !\n", iVal);
	 return False;
       }
      return True;

    case WDHGHT :
      if ((iVal >= 0) && (iVal <= graph->wdOrgY))
    	graph->wdHght = iVal;
      else
       {
      	 printf("MiniGraphic - set :  wrong value for WDHGHT  %d !\n", iVal);
	 return False;
       }
      return True;
    
    case PENSIZE:
      if ((iVal >= SMALL) && (iVal <= BIG))
	graph->drPenSz = iVal;
      else
	{
      	  printf("MiniGraphic - set :  wrong value for PENSIZE  %d !\n", 
		 iVal);
	  return False;
	}

      if (graph->ready)  
        XSetLineAttributes(display, gc[no], 
			   lineWidth[graph->drPenSz],
			   graph->linestyle == SOLID ? LineSolid : 
						       LineOnOffDash, 
			   CapButt, 0);
      return True;
	  
    case LINESTYLE :
      if ((iVal >= DOTTED) && (iVal <= SOLID))
        graph->linestyle = iVal;
      else 
	{
      	  printf("MiniGraphic - set :  wrong value for LINESTYLE  %d !\n", 
	         iVal);
	  return False;
	}
      if (graph->ready)
	if (iVal != SOLID)
	  {
             XSetDashes(display, gc[no], 0, pattern[iVal], 
			length[graph->linestyle]);
	     XSetLineAttributes(display, gc[no], 
			     	lineWidth[graph->drPenSz], 
				LineOnOffDash, CapButt, 0);
	  }
	else
	  XSetLineAttributes(display, gc[no], 
			     lineWidth[graph->drPenSz], LineSolid, 
			     CapButt, 0);
      return True;

    case FONTSIZE :
      if (fonttyp == -1)
        return False;
      if ((iVal >= SMALL) && (iVal <= BIG))
	graph->drFntSz = iVal;
      else
	{
          printf("MiniGraphic - set :  wrong value for FONTSIZE  %d !\n", 
		 iVal);
	  return False;
	}
      SelFont(graph);
      return True;
	  
    case FONTPROP :  
                     if ((iVal == TRANSPARENT) || (iVal == OPAQUE))
                       graph->FntProp = iVal;
                     else
                       {
                          printf("MiniGraphik - set :  wrong value for FNTPROP %d !\n", iVal);
			  return False;
                       }
                     return True;

    case MARKER:
      if ((iVal >= 0) && (iVal < MAXXMARKERS))
        graph->mark = iVal;
      else
	{
          printf("MiniGraphic - set :  unkown marker %d !\n", iVal);
	  return False;
	}
      return True;
	  
    case FILLCOL:
      if ((iVal >= 0) && (iVal < graph->maxCol))
        graph->fllCol = iVal;
      else
	{
          printf("MiniGraphic - set :  unkown fill-color %d !\n", iVal);
	  return False;
	}
      return True;
	  
    case MARKCOL:
      if ((iVal >= 0) && (iVal < graph->maxCol))
        graph->mrkCol = iVal;
      else
	{
          printf("MiniGraphic - set :  unkown marker-color %d !\n", iVal);
	  return False;
	}
      return True;
	  
    case FONTCOL:
      if ((iVal >= 0) && (iVal < graph->maxCol))
        graph->fntCol = iVal;
      else
	{
          printf("MiniGraphic - set :  unkown font-color %d !\n", iVal);
	  return False;
	}
      return True;
	  
    case PENCOL:
      if ((iVal >= 0) && (iVal < graph->maxCol))
        graph->penCol = iVal;
      else
	{
          printf("MiniGraphic - set :  unkown pen-color %d !\n", iVal);
	  return False;
	}
      return True;
	  
    case BACKGRCOL:
      if ((iVal >= 0) && (iVal < graph->maxCol))
        graph->backgrCol = iVal;
      else
	{
          printf("MiniGraphic - set :  unkown background-color %d !\n", 
		 iVal);
	  return False;
	}
      return True;

//      printf("MiniGraphic - set: unkown type %d !\n", type);

    }
    return False;
}

 
int XDriverImp::Settings(GRAPHIC *graph, int type, char* str)
{
    int n;

    switch (type)
    {

      case CAPTION:
	delete graph->caption;
	n = strlen(str);
	graph->caption = new char[n+1];
	strcpy(graph->caption, str);
	return True;
	
	/*
	  case BUFFER :
	  iVal = *((int*)valAdr);
	  if ((iVal == ON) || (iVal == OFF))
	  {
	  graph->buffer = iVal;
	  XSynchronize(display, !iVal);
	  }
	  else if (iVal == FLUSH)
	  XFlush(display);
	  else
	  {
	  printf("MiniGraphic - set :  unkown buffer status %d !\n", 
	  iVal);
	  return False;
	  }
	  return True;
	*/
	
      default:
	printf("MiniGraphic - set: unkown type %d !\n", type);
	
    }
    return False;
}

/*-------------------------------------------------------------------------*/
 
 
void XDriverImp::geometric(GRAPHIC *graph, int geo, coor org, coor vec)  
{
    int  ind = graph->wdNo, radius;
    XPoint points[5];
    XSegment segments[2];
    switch (geo)
      {
	case  STRAIGHTLINE: XDrawLine(display, window[ind], gc[ind],
				      org.x, org.y, vec.x, vec.y);
			    break;

	case  RECTANGLE :   points[0].x = org.x;
			    points[0].y = org.y;
			    points[1].x = vec.x;
			    points[1].y = org.y;
			    points[2].x = vec.x;
			    points[2].y = vec.y;
			    points[3].x = org.x;
			    points[3].y = vec.y;
			    points[4].x = org.x;
			    points[4].y = org.y;
			    XDrawLines(display, window[ind], gc[ind], points, 
				       5, CoordModeOrigin);
			    /*XDrawRectangle(display, window[ind], gc[ind], 
					     org.x, org.y,
					     (unsigned)(vec.x-org.x),
					     (unsigned)(vec.y-org.y)  );*/
			    break;

	case CIRCLE     :   radius = (int) sqrt(pow((double)(vec.x-org.x), 
					 2.0)+pow((double)(vec.y-org.y), 2.0));
			    segments[0].x1 = org.x-radius;
			    segments[0].y1 = org.y;
			    segments[0].x2 = org.x+radius;
			    segments[0].y2 = org.y;
			    segments[1].x1 = org.x;
			    segments[1].y1 = org.y+radius;
			    segments[1].x2 = org.x;
			    segments[1].y2 = org.y-radius;
			    XDrawArc(display, window[ind], gc[ind], 
				     org.x-radius, org.y-radius,
				     2*radius, 2*radius, 0, 23040);
			    XDrawSegments(display, window[ind], gc[ind], 
					  segments, 2);
			    break;
      }
    return;
  }    
 
 
         
int XDriverImp::Gin (GRAPHIC *graph, int geo, void* x1koordAdr, 
		   void* y1koordAdr, void* x2koordAdr, void* y2koordAdr)
{
    Cursor  cursor;
    XEvent  event;
    float  Org_x, Org_y;
    double  x1koord, y1koord, x2koord, y2koord;
    int no = graph->wdNo;
    coor   org, vec;

    XFlush(display);
    cursor = XCreateFontCursor(display, XC_tcross);
    XDefineCursor(display, window[no], cursor);		
    XSetLineAttributes(display, gc[no], 0, 0, 0, 0);
    XSetFunction(display, gc[no], GXxor);
    XSetForeground(display, gc[no], pixels[0]); 
    XSelectInput(display, window[no], ButtonPressMask | Button1MotionMask | 
				      ButtonReleaseMask | KeyPressMask      );

    while (XCheckWindowEvent(display, window[no], ButtonPressMask | 
			     Button1MotionMask | ButtonReleaseMask, &event));

    XWindowEvent(display, window[no], ButtonPressMask | Button1MotionMask, 
		 &event);

    Org_x = event.xbutton.x;
    org.x = vec.x = (int) Org_x;
    Org_y = event.xbutton.y; 
    org.y = vec.y = (int) Org_y;
	
    geometric(graph, geo, org, vec);  
    
    do
    {
	XWindowEvent(display, window[no], Button1MotionMask |ButtonReleaseMask,
		     &event); 
	if ((vec.x != event.xmotion.x) || (vec.y != event.xmotion.y))
	  {
	     geometric(graph, geo, org, vec); 
	     vec.x = event.xmotion.x;
	     vec.y = event.xmotion.y;   
	     geometric(graph, geo, org, vec); 
	  }		                                
      }   
    while (event.type != ButtonRelease);
    geometric(graph, geo, org, vec);

    XUndefineCursor(display, window[no]);		
    XSetLineAttributes(display, gc[no], lineWidth[graph->drPenSz],
		       graph->linestyle == SOLID ? LineSolid : LineOnOffDash, 
		       CapButt, 0);
    XSetFunction(display, gc[no], GXcopy);
    XSelectInput(display, window[no], ButtonPressMask | KeyPressMask);
 
    x1koord = (Org_x - graph->xTrans) / graph->xScal;
    y1koord = (graph->wdHght - Org_y - graph->yTrans) / graph->yScal;
    x2koord = (event.xmotion.x - graph->xTrans) / graph->xScal;
    y2koord = (graph->wdHght - event.xmotion.y - graph->yTrans) / graph->yScal;  
    if (graph->prec == SINGLE)
      {
         *((float*)x1koordAdr) = x1koord;
         *((float*)y1koordAdr) = y1koord;
         *((float*)x2koordAdr) = x2koord;
         *((float*)y2koordAdr) = y2koord;
      }
    else
      {
         *((double*)x1koordAdr) = x1koord;
         *((double*)y1koordAdr) = y1koord;
         *((double*)x2koordAdr) = x2koord;
         *((double*)y2koordAdr) = y2koord;
      }
    
    return True;      
  } 
  
  
  
  
  

int XDriverImp::Event(GRAPHIC *graph, int* typAdr, int* buttonAdr, 
		      void* xkoordAdr, void* ykoordAdr, int* chAdr)
{ 
    char ch;
    int  no = graph->wdNo;
    XEvent  event, last_event;
    XKeyEvent keyEvent, keyLast_event;

    double  xkoord = 0, ykoord = 0;

    *typAdr = *buttonAdr = *chAdr = 0;    
    last_event.type = -1;

    while (XCheckWindowEvent(display, window[no],
	   ButtonPressMask | KeyPressMask, &event))
      {
        if (event.type == KeyPress)
	  if (XLookupString(&keyEvent, &ch, 1, 0, 0))
	    if (ch > 31)
	      input_queue[no][queue_pointer[no]++] = ch;
        last_event = event;
      }
   
    if (last_event.type != -1)
     {
	switch (last_event.type)
         {
	   case KeyPress :  *typAdr |= 4;
			   if (XLookupString(&keyLast_event, &ch, 1, 0, 0))
			       *chAdr = ch;
			    else
			      {
			        switch (XLookupKeysym(&keyLast_event, 0))
				  {
				     case XK_Shift_L :
				     case XK_Shift_R : *typAdr |= 1;
						       break;
				     case XK_Control_L :
				     case XK_Control_R : *typAdr |= 2;
						         break;
				     default : ;
			          }
			      }
	  		    break;
             
	   case ButtonPress :  switch (last_event.xbutton.button)
			         {
				    case  1  :  *buttonAdr |= 4;  break;
				    case  2  :  *buttonAdr |= 2;  break; 
			 	    case  3  :  *buttonAdr |= 1;  break;
                   		    default  :  *buttonAdr |= 4;
			         }
			       *typAdr |= 8;    
			       break;
	   default : ;
         }

        if (last_event.xkey.state & ShiftMask)  *typAdr |= 1;
        if (last_event.xkey.state & ControlMask)  *typAdr |= 2; 

       xkoord = (last_event.xbutton.x - graph->xTrans) / graph->xScal;
       ykoord = (graph->wdHght - last_event.xbutton.y - graph->yTrans)
		/ graph->yScal;

     }

    if (graph->prec == SINGLE)
      {
         *((float*)xkoordAdr) = xkoord;
         *((float*)ykoordAdr) = ykoord;
      }
    else
      {
         *((double*)xkoordAdr) = xkoord;
         *((double*)ykoordAdr) = ykoord;
      }

    if (last_event.type == -1)
      return False;
    return True;
  }






int XDriverImp::Wait (GRAPHIC* graph, int* typAdr, int* buttonAdr, 
		    void* xkoordAdr, void* ykoordAdr, int* chAdr)
{ 
    int  no = graph->wdNo;
    XEvent  event;
    XKeyEvent  keyEvent;
    double  xkoord, ykoord;
    char ch = 0;

    *typAdr = *buttonAdr = *chAdr = 0;  
                                                                      
    XSetInputFocus(display, window[no], RevertToPointerRoot, 0);
    XFlush(display);

    while (XCheckWindowEvent(display, window[no],
			     ButtonPressMask | KeyPressMask, &event))
      if (event.type == KeyPress)
	if (XLookupString(&keyEvent, &ch, 1, 0, 0))
	  if (ch > 31)
	    input_queue[no][queue_pointer[no]++] = ch;

    event.type = -1;
    XWindowEvent(display, window[no], ButtonPressMask | KeyPressMask, &event);

    switch (event.type)
      {
	case KeyPress :  *typAdr |= 4;
			 if (XLookupString(&keyEvent, &ch, 1, 0, 0))
			   {
			     *chAdr = ch;
			     if (ch > 31)
			       input_queue[no][queue_pointer[no]++] = ch;
			   }
			 else
			   {
			      switch (XLookupKeysym(&keyEvent, 0))
				{
				   case XK_Shift_L :
				   case XK_Shift_R : *typAdr |= 1;
						     break;
				   case XK_Control_L :
				   case XK_Control_R : *typAdr |= 2;
						       break;
				   default : ;
			        }
			   }
	  		 break;
             
	case ButtonPress :  switch (event.xbutton.button)
			      {
				case  1  :  *buttonAdr |= 4;  break;
				case  2  :  *buttonAdr |= 2;  break; 
				case  3  :  *buttonAdr |= 1;  break;
                   		default  :  *buttonAdr |= 4;
			      }
			    *typAdr |= 8;    
			    break;
	default : ;
      }
               
    if (event.xkey.state & ShiftMask)  *typAdr |= 1;
    if (event.xkey.state & ControlMask)  *typAdr |= 2; 
             
    xkoord = (event.xbutton.x - graph->xTrans) / graph->xScal;
    ykoord = (graph->wdHght - event.xbutton.y - graph->yTrans) / graph->yScal;

    if (graph->prec == SINGLE)
      {
         *((float*)xkoordAdr) = xkoord;
         *((float*)ykoordAdr) = ykoord;
      }
    else
      {
         *((double*)xkoordAdr) = xkoord;
         *((double*)ykoordAdr) = ykoord;
      }

    /*XPutBackEvent(display, &event);*/

    return True;
  }






int XDriverImp::String (GRAPHIC *graph, char* string, int* length)
{
    int no = graph->wdNo, i;
    XEvent event;
    XKeyEvent keyEvent;
    char ch;

    while (XCheckWindowEvent(display, window[no], KeyPressMask, &event))
      if (event.type == KeyPress)
	if (XLookupString(&keyEvent, &ch, 1, 0, 0))
	  if (ch > 31)
	    input_queue[no][queue_pointer[no]++] = ch;

    for(i = 0; i < queue_pointer[no]; i++)
      *string++ = input_queue[no][i];
    for(i = queue_pointer[no]; i < MAX_STRING; i++)
      *string++ = '\0';
    *length = queue_pointer[no];
    queue_pointer[no] = 0;

    return True;
}







/*int stop_event(display, event, args)
Display display;
XEvent event;
char *args;
  {
    if (XLookupKeysym(&event, 0) == XK_Pause)
      return True;
    return False;
  }



void stop()
  {
     XEvent event;

     if (XCheckIfEvent(display, &event, stop_event, 0))
       {
	 printf("MiniGraphik :   Stop execution !\n");
	 printf("Press any key or button to continue.\n");
       }
     return;
  }
*/

/*-------------------------------------------------------------------------*/


XDriverImp::XDriverImp()
{
    int  k, i, size, low = BLACK, high = WHITE;
    int  count;
    xreal  dRed, dGreen, dBlue, dk;
    XColor col;

    for (i=0; i<COLORS; ++i)
    { 
	red[i]   = XRed[i];
	green[i] = XGreen[i];
	blue[i]  = XBlue[i];
    }

    fonttyp = 1;

    for (k = 0; k < MAX_WINDOWS; k++)
    {
	window[k] = font[k] = 0;
	queue_pointer[k] = 0;
    }

    if ((display = XOpenDisplay("")) == 0)
    {
	printf("MiniGraphic - X-Driver :  Failure to open display !\n");
    }

    screen = DefaultScreen(display);
	
    for (size = SMALL; size <= BIG; size++)
    {
	XListFonts(display, fontName[0][size], 1, &count);
	if (count == 0)
	{
	    printf("MiniGraphic - X-Driver :  Failure to open font %s !\n", 
		   fontName[0][size]);
	    fonttyp = 1;
	}
    }

    if (fonttyp == 1)
    for (size = SMALL; size <= BIG; size++)
    {
	XListFonts(display, fontName[1][size], 1, &count);
	if (count == 0)
	{		
	    printf("MiniGraphic - X-Driver :  Failure to open font %s !\n",
		   fontName[1][size]);
	    fonttyp = -1;
	}
    }
    
    XListFonts(display, mrkfontName[0], 1, &count);
    if (count != 0)
    {
	mrkFont = XLoadFont(display, mrkfontName[0]);
    }
    else
    {
	printf("MiniGraphic - X-Driver :  Failure to open marker-font ");
	printf("%s !\n", mrkfontName[0]);
	XListFonts(display, mrkfontName[1], 1, &count);
	if (count != 0)
	{
	    mrkFont = XLoadFont(display, mrkfontName[1]);
	    mrk_fonttyp = 1;
	}
	else
	{
	    printf("MiniGraphic - X-Driver :  Failure to open marker-font ");
	    printf("%s !\n", mrkfontName[1]);
	}
    }
    
    colormap = XDefaultColormap(display, screen);
    
    dRed = (red[high] - red[low]) / (GRAYS-1);
    dGreen = (green[high] - green[low]) / (GRAYS-1);
    dBlue = (blue[high] - blue[low]) / (GRAYS-1);
    for (k = 0, dk = GRAYS-1; k < GRAYS; k++, dk--)
    {
	red  [STDCOLORS-GRAYS+k] = (int) (red  [high]-dk*dRed);
	green[STDCOLORS-GRAYS+k] = (int) (green[high]-dk*dGreen);
	blue [STDCOLORS-GRAYS+k] = (int) (blue [high]-dk*dBlue);
    }
    
    for (i = 0; i < COLORS; i++)
    {
	col.red = red[i];
	col.green = green[i];
	col.blue = blue[i];
	col.flags = DoRed | DoGreen | DoBlue;
	if (!XAllocColor(display, colormap, &col))
	printf("MiniGraphic - X-Driver :  failure to allocate color !");
	pixels[i] = col.pixel;
    }
}
/*-------------------------------------------------------------------------*/


int XDriverImp:: Init(GRAPHIC* graph, float size)
{
    int free;

    for (free = 0; free < MAX_WINDOWS; free++)
    	if (window[free] == 0)  break;
    if (free == MAX_WINDOWS)
    { 
	printf("MiniGraphic - open :  More than %d windows !\n", MAX_WINDOWS);
	return False; 
    }
    window[free] = not_Null;


    graph->bottom = DisplayHeight(display, screen);
    graph->left = 0.0;
    graph->top =  0.0;
    graph->right = DisplayWidth(display, screen);
    graph->wdWdth = 
    graph->wdHght = int((graph->bottom - graph->top)*size - 31.0);
    switch (free % 4)
      {
	case 0 :  graph->wdOrgX = int(graph->right - graph->wdWdth - 10);
		  graph->wdOrgY = int((graph->bottom - graph->top) * 0.5);
		  break;

	case 1 :  graph->wdOrgX = int(graph->right - 2*graph->wdWdth - 20);
		  graph->wdOrgY = int((graph->bottom - graph->top) * 0.5);
		  break;

	case 2 :  graph->wdOrgX = int(graph->right - 2*graph->wdWdth - 20);
		  graph->wdOrgY = int(graph->bottom);
		  break;

	case 3 :  graph->wdOrgX = int(graph->right - graph->wdWdth - 10);
		  graph->wdOrgY = int(graph->bottom);
		  break;
      }

    graph->drRes = 1.0;
    graph->drPenSz = SMALL;
    graph->linestyle = SOLID;
    graph->drFntSz = MEDIUM;
    graph->FntProp = TRANSPARENT;
    graph->drXcm =  
    	(double)DisplayWidthMM(display, screen) / 
	(double)(10*DisplayWidth(display, screen));
    graph->drYcm =  
    	(double)DisplayHeightMM(display, screen) / 
	(double)(10*DisplayHeight(display,screen));

    graph->penCol = 
    graph->fllCol =	
    graph->fntCol = 	
    graph->mrkCol = BLACK;
    graph->backgrCol = WHITE;

    graph->maxCol = COLORS;
    graph->maxGry = GRAYS;		
    graph->mark = STAR;
    graph->id = X11;
    graph->wdNo = free;
    graph->fontName = fontName[fonttyp][MEDIUM];
    graph->fileName = 0;
    graph->caption = new char[strlen(captionName)+1];
    strcpy (graph->caption, captionName);
    graph->file  = 0;
    graph->buffer = ON;
    
    return True;
}



int XDriverImp::SelFont(GRAPHIC *graph)
{
    int no = graph->wdNo;

    if (font[no] != 0)
      XUnloadFont(display, font[no]);

    graph->fontName = fontName[fonttyp][graph->drFntSz];

    font[no] = XLoadFont(display, graph->fontName);

    if (graph->ready)    
      XSetFont(display, gc[no], font[no]);

    return True;
}

/*-------------------------------------------------------------------------*/

void XDriverImp:: FlushDisplay()
{
    XFlush(display);
}
/*-------------------------------------------------------------------------*/
