/*
 $Id: xdriv.c,v 1.1.1.1 1996/11/04 12:05:46 roitzsch Exp $
 (C)opyright 1996 by Konrad-Zuse-Center, Berlin
 All rights reserved.
 Part of the common environment

$Log: xdriv.c,v $
Revision 1.1.1.1  1996/11/04 12:05:46  roitzsch
minigraph module

*/

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h> 
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <limits.h>
 
#include "minigraph.h"
  
#define K180PI 57.29578

static real real_min = SHRT_MIN, real_max = SHRT_MAX;

#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 MAX_WINDOWS 16
#define STDCOLORS 32
#define COLORS 64
#define GRAYS 24
#define ALLCOL 96

#define not_nil 1L
static unsigned short red  [ALLCOL] = {
    0, 65535, 65535,     0,
    0,     0, 65535, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
 0,         0,     0,     0,     0,     0,
 0,      4352,  8704, 13056, 17408, 21760,
 26112, 30464, 34816, 39168, 43520, 47872,
 52224, 56576, 60928, 65280, 65280, 65280,
 65280, 65280, 65280, 65280, 65280, 65280,
 65280, 65280, 65280, 65280, 65280, 65280,
 65280, 65280, 65280, 65280, 65280, 65280,
 65280, 65280, 65280, 65280, 65280, 65280,
 65280, 65280, 65280, 65280, 65280, 65280,
 65280, 65280, 65280, 65280, 65280, 65280,
 65280, 65280, 65280, 65280
};
       	              		      
static unsigned short green[ALLCOL] = {
    0, 65535,     0, 65535,
    0, 65535,     0, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
     0,     0,     0,     0,     0,     0,
     0,  4352,  8704, 13056, 17408, 21760,
 26112, 30464, 34816, 34816, 34816, 34816,
 34816, 34816, 34816, 34816, 34816, 34816,
 34816, 34816, 34816, 34816, 34816, 30464,
 26112, 21760, 17408, 13056,  8704,  4352,
     0,  4352,  8704, 13056, 17408, 21760,
 26112, 30464, 34816, 39168, 43520, 47872,
 52224, 56576, 60928, 65280, 65280, 65280,
 65280, 65280, 65280, 65280, 65280, 65280,
 65280, 65280, 65280, 65280
};
                     		      
static unsigned short blue [ALLCOL] = {
    0, 65535,     0,     0,
65535, 65535, 65535,     0,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535,
 39168, 43520, 47872, 52224, 56576, 60928,
 65280, 65280, 65280, 65280, 65280, 65280,
 65280, 65280, 65280, 65280, 65280, 65280,
 65280, 65280, 65280, 65280, 60928, 56576,
 52224, 47872, 43520, 39168, 34816, 30464,
 26112, 21760, 17408, 13056,  8704,  4352,
     0,     0,     0,     0,     0,     0,
     0,     0,     0,     0,     0,     0,
     0,     0,     0,     0, 17664, 22016,
 26368, 30720, 35072, 39168, 43520, 47872,
 52224, 56576, 60928, 65280
};
static unsigned long  pixels[ALLCOL];
static unsigned lineWidth[3] = { 1, 2, 4 };
static int length[] = { 2, 2, 2, 2, 4, 6 };
static 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 int  fonttyp=0;
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"
   }
 };

static char *captionName = "MiniGraphic";

#define MAXXMARKERS 7
static int  mrk_fonttyp=0;
static char XMarkers[2][MAXXMARKERS] = {
					 { ' ', '*', '\xb4', '+', '\xb7', '\xc4', '\xb5' },
					 { ' ', '*', 'x', '+', 'o', ' ', ' ' }
				       };

static int dxMarker[MAXXMARKERS] = { 0, -3, -3, -3, -3, -5, -5 };
static int dyMarker[2][MAXXMARKERS] = {
					{ 0, 5, 4, 4, 4, 5, 5 },
					{ 0, 4, 3, 4, 2, 0, 0 }
				      };
  
static Display  *display;
static int  screen;  
static Window  window[MAX_WINDOWS];
static GC  gc[MAX_WINDOWS];
static Font font[MAX_WINDOWS], mrkFont;
static Colormap  colormap;

static char input_queue[MAX_WINDOWS][MAX_STRING];
static int queue_pointer[MAX_WINDOWS];


static int SelFont(GRAPHIC *graph);


static int XOpenPort(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, NULL);

    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, nil, 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;
  }





static int XNewPict(GRAPHIC *graph)
  {
    int no = graph->wdNo;

    if (no < 0) return false;
    if (graph->ready)  XClearWindow(display, window[no]);
    
    return true;
  }





static int XClose(GRAPHIC *graph)
  {
    int no = graph->wdNo;

    if (no < 0)  return false;
    free(graph->caption);
    if (graph->ready)  XDestroyWindow(display, window[no]);
    window[no] = nil;

    return true;
  }





static int X_Color(int col_no, int rVal, int gVal, int bVal)
  {
    XColor color;

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

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

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

    pixels[col_no] = color.pixel;

    return true;
  }



static XPoint *pt = 0;
static int ptLng = 0;

static int XPLine(GRAPHIC *graph, void *xAdr, void *yAdr, int n)
  {
    int ind = graph->wdNo, k;
    real x, y, a, b;

    if (ptLng<n)
      {
        if (pt) free(pt);
        pt = (XPoint*)malloc(n*sizeof(XPoint));
        ptLng = n;
      }

    for (k = 0; k < n; k++)
      {
	 if ((graph->prec)==SINGLE)
	   { 
		x = ((float*)xAdr)[k]; 
		y = ((float*)yAdr)[k]; 
	   }
	 else
	   { 
		x = ((double*)xAdr)[k]; 
		y = ((double*)yAdr)[k]; 
	   }
	 a = TRANSX(x); 
	 b = TRANSY(y);
      if ((a<real_min)||(a>real_max)||(b<real_min)||(b>real_max))
        return true;
	 pt[k].x = a; 
	 pt[k].y = b;
      }
  
    XSetForeground(display, gc[ind], pixels[graph->penCol]);
    XDrawLines(display, window[ind], gc[ind], pt, n, 0);

    return true;
  }





static int XPMarker(GRAPHIC *graph, void *xAdr, void *yAdr, int n)
  {
    int no = graph->wdNo, k, px, py;
    real x, y, xt, yt;
    char s[2];

    if (mrkFont == 0)
      {
        printf("MiniGraphic - zibpm :  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++)
      {
	 if ((graph->prec)==SINGLE)
	  { 
		x = ((float*)xAdr)[k]; 
		y = ((float*)yAdr)[k]; 
	  }
	 else
	  { 
		x = ((double*)xAdr)[k]; 
		y = ((double*)yAdr)[k]; 
	  }
         xt = TRANSX(x)+dxMarker[graph->mark];
	 yt = TRANSY(y)+dyMarker[mrk_fonttyp][graph->mark];
	 if ((xt<real_min)||(xt>real_max)||
	     (yt<real_min)||(yt>real_max)) return true;
	 px = xt; py = yt;
	 XDrawString(display, window[no], gc[no], px, py, s, 1);

      }
   if (fonttyp != -1)
     XSetFont(display, gc[no], font[no]);

    return true;
  }
 

#ifdef __cplusplus
static int XText(GRAPHIC *graph, real x, real y, const char *s)
#else
static int XText(GRAPHIC *graph, real x, real y, char *s)
#endif
  {
    int no = graph->wdNo;
    real xt = TRANSX(x), yt = TRANSY(y);
    int px, py;
 
    if (fonttyp == -1)
      return false;
    if ((xt<real_min)||(xt>real_max)||
        (yt<real_min)||(yt>real_max)) return true;
    px = xt; py = yt;
    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;
  }
    
 



static int XFill(GRAPHIC *graph, void *xAdr, void *yAdr, int n)
  {
    int no = graph->wdNo, k;
    real x, y, xt, yt;

    if (ptLng<n)
      {
        if (pt) free(pt);
        pt = (XPoint*)malloc(n*sizeof(XPoint));
        ptLng = n;
      }

    for (k=0; k<n; k++)
      {
	 if ((graph->prec) == SINGLE)
	  { 
		x = ((float*)xAdr)[k]; 
		y = ((float*)yAdr)[k]; 
	  }
	 else
	  { 
		x = ((double*)xAdr)[k]; 
		y = ((double*)yAdr)[k]; 
	  }
	 xt = TRANSX(x); 
	 yt = TRANSY(y);
	 if ((xt<real_min)||(xt>real_max)||
	     (yt<real_min)||(yt>real_max)) return true;
	 pt[k].x = xt; 
	 pt[k].y = yt;
      }
    XSetForeground(display, gc[no], pixels[graph->fllCol]);
    XFillPolygon(display, window[no], gc[no], pt, n, Complex, CoordModeOrigin);  
    	
    return true;
  }
   



 
static int XSettings(GRAPHIC *graph, int type, void *valAdr)
  {
    int iVal, n, no = graph->wdNo;

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

    case WDHGHT :
      iVal = *((int*)valAdr);
      if ((iVal >= 0) && (iVal <= graph->wdOrgY))
    	graph->wdHght = iVal;
      else
       {
      	 printf("MiniGraphic - zibset :  wrong value for WDHGHT  %d !\n", iVal);
	 return false;
       }
      return true;
    
    case PENSIZE:
      iVal = *((int*)valAdr);
      if ((iVal >= SMALL) && (iVal <= BIG))
	graph->drPenSz = iVal;
      else
	{
      	  printf("MiniGraphic - zibset :  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 :
      iVal = *((int*)valAdr);
      if ((iVal >= DOTTED) && (iVal <= SOLID))
        graph->linestyle = iVal;
      else 
	{
      	  printf("MiniGraphic - zibset :  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 COPYMODE:
      iVal = *((int*)valAdr);
      if ((iVal == GXOR) || (iVal == GCOPY))
        graph->copyMode = iVal;
      else 
		{
      	  printf("MiniGraphic - zibset :  wrong value for COPYMODE  %d !\n", 
	         iVal);
		  return false;
		}
      if (graph->ready)
	    XSetFunction(display, gc[no], ((graph->copyMode)==GXOR)?GXxor:GXcopy);
	  return true;

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

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

    case CAPTION:
      free(graph->caption);
      n = strlen((char*)valAdr);
      graph->caption = (char*)malloc(n+1);
      strncpy(graph->caption, (char*)valAdr, n);
      (graph->caption)[n] = '\0';
      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 - zibset :  unkown buffer status %d !\n", 
		      iVal);
	       return false;
	    }
      return true;
	  
    default:
      printf("MiniGraphic - zibset: unkown type %d !\n", type);

    }
    return false;
  }

 
 
struct coor
{
	int x,y;
};      
typedef struct coor COOR; 
 
static void geometric(GRAPHIC *graph, int geo, COOR  org, COOR  vec)  
  {
    int  ind = graph->wdNo, radius;
    XPoint points[5];
    XSegment segments[2];
    switch (geo)
      {
	case  LINE      :   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 = 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;
  }    
 
 
         
static int XGin (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 = vec.x = Org_x = event.xbutton.x;
    org.y = vec.y = Org_y = event.xbutton.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], ((graph->copyMode)==GXOR)?GXxor: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;      
  } 
  
  
  
  
  

static int X_Event (GRAPHIC *graph, int *typAdr, int *buttonAdr, void *xkoordAdr, void *ykoordAdr, int *chAdr)
  { 
    char ch;
    int  no = graph->wdNo;
    XEvent  event, last_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(&(event.xkey), &ch, 1, NULL, NULL))
	    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(&(last_event.xkey), &ch, 1, NULL, NULL))
			       *chAdr = ch;
			    else
			      {
			        switch (XLookupKeysym(&(last_event.xkey), 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;
  }






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

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

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

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

    switch (event.type)
      {
	case KeyPress :  *typAdr |= 4;
			 if (XLookupString(&(event.xkey), &ch, 1, NULL, NULL))
			   {
			     *chAdr = ch;
			     if (ch > 31)
			       input_queue[no][queue_pointer[no]++] = ch;
			   }
			 else
			   {
			      switch (XLookupKeysym(&(event.xkey), 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;
  }






static int XString(GRAPHIC *graph, char *string, int *length)
  {
    int no = graph->wdNo, i;
    XEvent event;
    XKeyEvent key_event;
    char ch;

    while (XCheckWindowEvent(display, window[no], KeyPressMask, &event))
      if (event.type == KeyPress)
	if (XLookupString(&key_event, &ch, 1, NULL, NULL))
	  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;
XKeyEvent event;
char *args;
  {
    if (XLookupKeysym(&event, 0) == XK_Pause)
      return true;
    return false;
  }



void stop()
  {
     XKeyEvent event;

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



int XInit(GRAPHIC *graph)
  {
    static int  first = true;
    int  k, i, free, size,
	 low = BLACK, high = WHITE;
    real  dRed, dGreen, dBlue, dk;
    XColor color;
    char **fontList;

    if (first)
      {
      /*struct itimerval  value;

	signal(SIGALRM, stop);
	value.it_value.tv_sec = 0;
	value.it_value.tv_usec = 500000;
	value.it_interval.tv_sec = 0;
	value.it_interval.tv_usec = 500000;
	setitimer(ITIMER_REAL, &value, NULL);
      */
        int count = 0;

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

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

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

        fontList = XListFonts(display, mrkfontName[0], 1, &count);
        if (count != 0)
           {
	  XFreeFontNames(fontList);
	  mrkFont = XLoadFont(display, mrkfontName[0]);
	       }
	else
	  {
	     printf("MiniGraphic - zibwop :  Failure to open marker-font ");
	     printf("%s !\n", mrkfontName[0]);
	     fontList = XListFonts(display, mrkfontName[1], 1, &count);
	     if (count != 0)
	       {
	         mrkFont = XLoadFont(display, mrkfontName[1]);
	         XFreeFontNames(fontList);
		 mrk_fonttyp = 1;
	       }
	     else
	       {
	         printf("MiniGraphic - zibwop :  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] = red  [high]-dk*dRed;
	   	green[STDCOLORS-GRAYS+k] = green[high]-dk*dGreen;
 	    	blue [STDCOLORS-GRAYS+k] = blue [high]-dk*dBlue;
	     }

	   for (i = 0; i < ALLCOL; i++)
     	 {
	      color.red = red[i];
	      color.green = green[i];
	      color.blue = blue[i];
	      color.flags = DoRed | DoGreen | DoBlue;
	      if (!XAllocColor(display, colormap, &color))
	        {
		      printf("MiniGraphic - zibwop :  failure to allocate color ! \n");
		      break;
		    }
  	      pixels[i] = color.pixel;
         }

	first = false;
      }

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


    graph->PLine    = XPLine;
    graph->PMarker  = XPMarker;
    graph->Text     = XText;
    graph->Fill     = XFill;
    graph->Color    = X_Color;
    graph->Settings = XSettings;
    graph->NewPict  = XNewPict;
    graph->OpenPort = XOpenPort;
    graph->Close    = XClose;
    graph->Gin      = XGin; 
    graph->Wait     = XWait; 
    graph->Event    = X_Event;
    graph->String   = XString;
  
    graph->bottom = DisplayHeight(display, screen);
    graph->left = 0.0;
    graph->top =  0.0;
    graph->right = DisplayWidth(display, screen);
    graph->wdWdth = 
    graph->wdHght = (graph->bottom-graph->top)*0.5 - 31.0;
    switch (free % 4)
      {
	case 0 :  graph->wdOrgX = graph->right - graph->wdWdth - 10;
		  graph->wdOrgY = (graph->bottom - graph->top) * 0.5;
		  break;

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

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

	case 3 :  graph->wdOrgX = graph->right - graph->wdWdth - 10;
		  graph->wdOrgY = graph->bottom;
		  break;
      }
    graph->wdWdth = 
    graph->wdHght -= 16.0;

    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 = WHITE;
    graph->backgrCol = BLACK;

    graph->maxCol = COLORS;
    graph->maxGry = GRAYS;		
    graph->maxWd = MAX_WINDOWS;
    graph->mark = STAR;
    graph->prec = SINGLE;
    graph->id = X11;
    graph->wdNo = free;
    graph->fontName = fontName[fonttyp][MEDIUM];
    graph->fileName = nil;

    i = strlen(captionName);
    graph->caption = (char*)malloc(i+1);
    strcpy(graph->caption, captionName);

    graph->file = nil;
    graph->buffer = ON;
    for (i = 0; i < MAX_WINDOWS; i++)
       graph->Ass[i] = nil;
    
/*    XSynchronize(display, 1); */
    return true;
  }





static int 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;
  }


syntax highlighted by Code2HTML, v. 0.9.1