/*===========================================================================
  Copyright (C) 1995-2009 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program 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 General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/***********************************************************************
*                                     
*   file idilocal2.c                 
*                                   
*   IDI  Device Dependent Routines 
*   (XWindows version)            
*                                
* V 1.00 880219  F.Pasian, P.Santin - Trieste Astronomical Observatory
* V 2.00 890102  K. Banse  ESO - Garching  (from now on) 
*
*
*  crea_win             : Create a XWindow
*  cl_win               : Clear a XWindow
*  set_wcur             : Set XWindow cursor shape 
*  sendX                : do XFlush
*  crealph              : Create alpha_numerics subwindow;
*  clalph               : Clear the alpha_numerics subwindow;
*  alprfr               : Refresh alpha memory
*  alptext              : Write into alpha_numerics subwindow;
*  crelutbar            : Create LUT/Intensity Bar;
*  vislutbar            : Handle visibility of LUT/Intensity Bar;
*  updalutbar           : update LUT/Intensity Bar;
*  get_string           : get character string from keyboard via X;
*  get_char             : get single character from keyboard via X;
*  initgra              : Initialize Graphics Context;
*  polyline             : Draw Polyline on Display Bitmap;
*  polyrefr             : Redraw graphic stuff
*  txtline              : Draw text string on Display Bitmap;
*  txtrefr              : Redraw text stuff
*  rd_pllut             : get R, G, B values of plot colours
*  do_misc              : do miscellaneous functions
*   

*  090424		last modif

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

/*

*/

# include    <stdlib.h>
# include    <stdio.h>


# include    <idi.h>
# include    <idistruct.h>
# include    <x11defs.h>
# include    <proto_idi.h>


static Bool  discard = True;

static int lutoff;
static unsigned long int  maska;
static unsigned int   tmpxdim, tmpydim;

static int parent_id = -1;		/* root window */
static int  textsiz = -1, lasttxtno = -1, lastplno = -1;
static int  plotcol = -1;		/* foreground color of gcima */
static int  linewidth = -1;
static unsigned int  border = 1;
static short int  *jpntra;
static long int Def_Mask = (ExposureMask | StructureNotifyMask);
 
static float  rval;

static unsigned char  *cpntra;

/*

*/

/*
crea_win routine : display/graphics window creation     
synopsis:  crea_win (dspno,xoff,yoff,xdim,ydim,dspchar)
       int   dspno;   input    display no.            
       int   xoff;      input    x offset            
       int   yoff;      input    y offset           
       int   xdim;      input    x display dimension      
       int   ydim;      input    y display dimension     
       char  dspchar;   input    display id_char
*/

#ifdef __STDC__
int crea_win(int dspno,int xoff,int yoff,unsigned int xdim,unsigned int ydim,
         char dspchar)
#else
crea_win(dspno,xoff,yoff,xdim,ydim,dspchar)
int   dspno, xoff, yoff;
unsigned int   xdim, ydim;
char  dspchar;
#endif
 
{
char  *argv[1];
char  win_name[32];

unsigned long int  forgr, backgr;
int   k, j, no;




no = ididev[dspno].screen;
					/* XWindow Y Coordinate Inversion */
if (ididev[dspno].devtyp == 'g')
   {
   forgr = Xworkst[no].black;
   backgr = Xworkst[no].white;
   }
else
   {
   forgr = Xworkst[no].white;
   backgr = ididev[dspno].backpix;	/* at start, just the index */
   backgr = fixcolr[no][backgr].pixel;
   }
ididev[dspno].backpix = backgr;


/* handle LUT offsets  */

ididev[dspno].lutoff = 0;

if (Xworkst[no].ownlut == 1)
   {
   if ((Xworkst[no].nolut > 1) && (dspno > 0))
      {
      if (dspno < Xworkst[no].nolut)
         ididev[dspno].lutsect = dspno;
      else
         ididev[dspno].lutsect = Xworkst[no].nolut - 1;
      }
   if (Xworkst[no].visual == 4)
      ididev[dspno].lutoff = Xworkst[no].auxcol;
   else
      {
      if (Xworkst[no].lutflag == 0)
         k = ididev[dspno].lutsect * Xworkst[no].lutsize;
      else 
         k = Xworkst[no].auxcol;
      ididev[dspno].lutoff = mycolr[no][k].pixel;
      }
   }
 
k = ididev[dspno].lutsect;
maska = CWBackPixel | CWBorderPixel | CWColormap;
sattributes.background_pixel = backgr;
sattributes.border_pixel = forgr;

if (parent_id != -1)
   {
   /* printf("parent_w = rw[%d] = %x (= mwndw[%d] = %x)\n",
          no,rw[no],parent_id,mwndw[parent_id]);  */

   ididev[parent_id].link[0] = 1;		/* indicate parent window */
   j = ididev[parent_id].ysize;
   sattributes.colormap = CopyFromParent;
   }
else
   {
   j = Xworkst[no].height;
   sattributes.colormap = cmap[no][k];
   }
yoff = j - ydim - yoff - border*2;
ididev[dspno].link[1] = parent_id;

/* printf("crea_win: xoff,yoff = %d, %d\n",xoff,yoff); */

mwndw[dspno] = XCreateWindow(mydisp[no],rw[no],
                             xoff,yoff,xdim,ydim,border,Xworkst[no].depth,
                             InputOutput,myvis[no],maska,&sattributes);
if (mwndw[dspno] == 0) return(WINOTOPN);


/* create the GC (Graphics Context) painfully by hand ... */

maska = GCFunction | GCPlaneMask | GCLineWidth | GCLineStyle;
maska |= (GCCapStyle | GCJoinStyle | GCFillStyle | GCFillRule); 
maska |= (GCArcMode | GCSubwindowMode | GCGraphicsExposures);
xgcvals.function = GXcopy;
xgcvals.plane_mask = 0xffffffff;		
xgcvals.line_width = 1;
xgcvals.line_style = LineSolid;
xgcvals.cap_style = CapRound;
xgcvals.join_style = JoinRound;
xgcvals.fill_style = FillSolid;
xgcvals.fill_rule = WindingRule;
xgcvals.arc_mode = ArcPieSlice;
xgcvals.arc_mode = ClipByChildren;
xgcvals.graphics_exposures = False;
gcima[dspno] = XCreateGC(mydisp[no],mwndw[dspno],maska,&xgcvals);
XSetFunction(mydisp[no],gcima[dspno],GXcopy); 
XSetBackground(mydisp[no],gcima[dspno],backgr);
XSetForeground(mydisp[no],gcima[dspno],forgr);
XSetFont(mydisp[no],gcima[dspno],myfont[no][0]->fid);

gcdraw[dspno] = XCreateGC(mydisp[no],mwndw[dspno],0,&xgcvals);
if (ididev[dspno].devtyp == 'c')
   {
   XSetFunction(mydisp[no],gcdraw[dspno],GXcopy);
   XSetBackground(mydisp[no],gcdraw[dspno],forgr);
   XSetForeground(mydisp[no],gcdraw[dspno],backgr);
   }
else
   {
   XSetBackground(mydisp[no],gcdraw[dspno],0);
   XSetForeground(mydisp[no],gcdraw[dspno],0xffffffff);
   XSetFunction(mydisp[no],gcdraw[dspno],GXxor);
   if (ididev[dspno].devtyp == 'g') 
      maska = forgr ^ backgr;
   else
      {
      if (Xworkst[no].visual == 3)
         maska = 0xffffffff;			/* use all 1's */
      else if (Xworkst[no].visual == 4)
         maska = 0xffffffff;			/* use all 1's */
      else
         {
         if (Xworkst[no].depth == 8)	
            maska = 0xffffff80;			/* last byte = 1000 0000 */
         else if (Xworkst[no].depth == 16)
            maska = 0xffff8000;
         else if (Xworkst[no].depth == 32)
            maska = 0x80000000;
         else
            maska = 0xffffffff;		
         }
      }
   XSetPlaneMask(mydisp[no],gcdraw[dspno],maska);
   XSetFunction(mydisp[no],gcdraw[dspno],GXxor);
   }


XDefineCursor(mydisp[no],mwndw[dspno],mycurs[no][0]);

event_mask = ButtonPressMask | Def_Mask;
XSync(mydisp[no],discard);

XSelectInput(mydisp[no],mwndw[dspno],event_mask);

myhint[dspno].x = xoff;  
myhint[dspno].y = yoff;
myhint[dspno].width = xdim;  
myhint[dspno].height = ydim;
myhint[dspno].flags = USPosition | USSize;  /* like this we force position */

if (ididev[dspno].devtyp == 'g')
   {
   if (ididev[dspno].ref != '\0')
      (void) sprintf(win_name,"MIDAS_%s shadow(%c),graph_%c",
                     Xworkst[no].miduni,dspchar,ididev[dspno].ref);
   else
      (void) sprintf(win_name,"MIDAS_%s graph_%c",Xworkst[no].miduni,dspchar);
   }
else if (ididev[dspno].devtyp == 'z')
   (void) sprintf(win_name,"MIDAS_%s zoom_%c",Xworkst[no].miduni,dspchar);
else if (ididev[dspno].devtyp == 'c')
   (void) sprintf(win_name,"cursor_%c_window",dspchar);
else
   {
   if (ididev[dspno].ref != '\0')
      (void) sprintf(win_name,"MIDAS_%s shadow(%c),display_%c",
                     Xworkst[no].miduni,dspchar,ididev[dspno].ref);
   else
      (void) sprintf(win_name,"MIDAS_%s display_%c",Xworkst[no].miduni,dspchar);
   }

argv[0] = win_name;
XSetStandardProperties(mydisp[no],mwndw[dspno],win_name,win_name,
                       None,argv,1,&myhint[dspno]);

xwmh.flags = InputHint | StateHint;
xwmh.initial_state = NormalState;
xwmh.input = True;
XSetWMHints(mydisp[no],mwndw[dspno],&xwmh);
XMapRaised (mydisp[no],mwndw[dspno]);

/*
 printf(
   "crea_win: XMapRaised of window %d (mwndw[%d] = %x), parent = %x\n",
              dspno,dspno,mwndw[dspno],rw[no]) ;
*/

return (II_SUCCESS);
}

/*

*/

void cl_win(dspno,colval)
int    dspno, colval;

{
int  no;



no = ididev[dspno].screen;
plotcol = -1;				/* init plotting color again */

if ((colval > 0) && (colval < 9))	/* update background color */
   {
   unsigned long maska;

   ididev[dspno].backpix = fixcolr[no][colval].pixel;

   maska = CWBackPixel;
   sattributes.background_pixel = ididev[dspno].backpix;
   XChangeWindowAttributes(mydisp[no],mwndw[dspno],maska,&sattributes);
   }

XClearWindow (mydisp[no],mwndw[dspno]);
}

/*

*/

void set_wcur(dspno,nz)
int dspno, nz;

{
int  no;
static int  oldno = -1, oldnz = -1;


if ((oldno == dspno) && (oldnz == nz)) 
   return;					/* nothing to do */
else
   {
   oldno = dspno;
   oldnz = nz;
   }

no = ididev[dspno].screen;

if (nz == -1)
   {
   mycurs[no][0] = XCreateFontCursor(mydisp[no],XC_arrow);
   mycurs[no][1] = XCreateFontCursor(mydisp[no],XC_pirate);    /* end symbol */
   mycurs[no][2] = XCreateFontCursor(mydisp[no],XC_right_ptr);
   mycurs[no][3] = XCreateFontCursor(mydisp[no],XC_circle);
   }
else
   XDefineCursor(mydisp[no],mwndw[dspno],mycurs[no][nz]);

}

/*

*/

void sendX(dspno)
int  dspno;

{
XFlush(mydisp[ididev[dspno].screen]);
}

/*

*/

int crealph(dspno,dysize)
int dspno, dysize;

{
int  no;
int  tmpx, np;

tmpx = 0;
np = 1;
no = ididev[dspno].screen;

alphwnd[dspno] = 
XCreateSimpleWindow (mydisp[no],mwndw[dspno],tmpx,dysize,ididev[dspno].alphx,
                     ididev[dspno].alphy,np,Xworkst[no].white,
                     Xworkst[no].black); 
if (alphwnd[dspno] != (Window)0)
   {
   gcalph[dspno] = XCreateGC(mydisp[no],alphwnd[dspno],0,&xgcvals);
   maska = Xworkst[no].black ^ Xworkst[no].white ;
   XSetPlaneMask(mydisp[no],gcalph[dspno],maska);
   XSetFunction(mydisp[no],gcalph[dspno],GXcopy); 
   XMapRaised (mydisp[no],alphwnd[dspno]);
   XSetFont(mydisp[no],gcalph[dspno],myfont[no][0]->fid);  /* use small font */
   return(II_SUCCESS);
   }
else
   return(WINOTOPN);
}

/*

*/

void clalph(dspno,flag,x,y,dim)
int  dspno, flag, x, y, dim;

{
int  no;
int  tmpx, tmpy;

if (flag == 0)
   {
   tmpx = 0;
   tmpy = 0;
   tmpxdim = ididev[dspno].alphx;
   tmpydim = ididev[dspno].alphy;
   }
else
   {
   tmpx = x;
   tmpy = y - ididev[dspno].alphlinsz + 1;
   tmpxdim = dim * 8;
   tmpydim = ididev[dspno].alphlinsz;
   }

no = ididev[dspno].screen;
XSetForeground(mydisp[no],gcalph[dspno],Xworkst[no].black);
XFillRectangle(mydisp[no],alphwnd[dspno],gcalph[dspno],
               tmpx,tmpy,tmpxdim,tmpydim);
XSetForeground(mydisp[no],gcalph[dspno],Xworkst[no].white);
}

/*

*/

void alprfr(dspno,alph)
int  dspno;
ALPH_DATA  *alph;

{
int  no, x0, y0, j, np;
register int  loopi;

char  texto[32];		/* alpha text segments now 30 chars long */


no = ididev[dspno].screen;

XSetForeground(mydisp[no],gcalph[dspno],Xworkst[no].black);
XFillRectangle(mydisp[no],alphwnd[dspno],gcalph[dspno],
               0,0,ididev[dspno].alphx,ididev[dspno].alphy);
XSetForeground(mydisp[no],gcalph[dspno],Xworkst[no].white);

for (loopi=0; loopi<16; loopi++)
   {
   x0 = alph->savx[loopi];
   if (x0 > -1)
      {
      y0 = alph->savy[loopi];
      j = loopi * 30;
      (void) memcpy(texto,&alph->savtxt[j],(size_t)30);
      texto[30] = '\0';

      np = (int) strlen(texto);
      if (np > 0)
         {
         rval = x0 * ididev[dspno].alphxscal;
         x0 = rval + 1;
         y0 = (y0 +1) * ididev[dspno].alphlinsz;
         XDrawString(mydisp[no],alphwnd[dspno],gcalph[dspno],x0,y0,texto,np);
         }
      }
   }
}

/*

*/

void alptext(flag,dspno,alph,txt,x0,y0)
int  flag, dspno, x0, y0;
char *txt;
ALPH_DATA  *alph;

{
int  no, fnd, i, np;
register int  loopi;



/*  find corresponding `save' slot  */

no = ididev[dspno].screen;
for (loopi=0; loopi<16; loopi++)
   {
   if ((x0 == alph->savx[loopi]) && (y0 == alph->savy[loopi]))
      {
      fnd = loopi;
      goto slot_found;
      }
   }

for (loopi=0; loopi<16; loopi++)
   {
   if (alph->savx[loopi] < 0)
      {
      fnd = loopi;
      alph->savx[fnd] = x0;
      alph->savy[fnd] = y0;
      goto slot_found;
      }
   }
goto just_do_it;

slot_found:
i = fnd * 30;
(void) memcpy(&alph->savtxt[i],txt,(size_t)30);
if (flag == 0) return;			/* flag == 0, then only store data */


just_do_it:
np = (int) strlen(txt);
rval = x0 * ididev[dspno].alphxscal;
x0 = rval + 1;
y0 = (y0 +1) * ididev[dspno].alphlinsz;

for (loopi=0; loopi<np; loopi++)
   {
   if (txt[loopi] != ' ')
      {
      XDrawString(mydisp[no],alphwnd[dspno],gcalph[dspno],x0,y0,txt,np);
      return;
      }
   }

/* text string all blanks, so we want to clear ...  */

clalph(dspno,1,x0,y0,np);
}

/*

*/

int crelutbar(dspno,bar)
int  dspno;
INTBAR   *bar;

{
float fa, fb, fc;

int   total, *ipntra;
int   ioff, no, np, k;
register int  nr, mr;




bar->xsize = ididev[dspno].xsize;
bar->ysize = 20;
bar->xoff = 0;
bar->yoff = ididev[dspno].ysize - bar->ysize - (border*2);

lutoff = ididev[dspno].lutoff;
np = 1;
no = ididev[dspno].screen;
lutwnd[dspno] = XCreateSimpleWindow (mydisp[no],mwndw[dspno], 
                         bar->xoff,bar->yoff,bar->xsize,bar->ysize,np,
                         Xworkst[no].black,Xworkst[no].white);
if (lutwnd[dspno] == 0) return(WINOTOPN);

gclut[dspno] = XCreateGC(mydisp[no],lutwnd[dspno],0,&xgcvals);
XSetFunction(mydisp[no],gclut[dspno],GXcopy); 

XMapRaised (mydisp[no],lutwnd[dspno]);

bar->wp = 1;		/*  indicate that we already created the window  */

if (Xworkst[no].depth < 16)
   np = 8;
else
   np = 32;
myima = XCreateImage(mydisp[no],myvis[no],Xworkst[no].depth,ZPixmap,
                     0,0,bar->xsize,bar->ysize,np,np*bar->xsize/8);

lutxima[dspno] = myima;
total = myima->bytes_per_line * bar->ysize;

myima->data = malloc((size_t)total);
if (myima->data == 0) return (MEMALLERR);


/* branch according to memory depth  */

fa = Xworkst[no].lutlen;
fb = bar->xsize;
fc = fa / fb;
ioff = ididev[dspno].lutsect * Xworkst[no].lutsize;

if (Xworkst[no].visual == 2) 			/* PseudoColor */
   {
   if (Xworkst[no].nobyt == 1) 
      {
      unsigned char  *cpntrb;

      cpntra = (unsigned char *) myima->data;
      cpntrb = cpntra + bar->xsize;		/* point to next line */

      for (mr=0; mr<bar->xsize; mr++)
         {
         fa = mr*fc + 0.5;		/* scale to LUTsize */
         np = ((int)fa) + ioff;	
         *cpntra++ = (unsigned char) Xworkst[no].mapin[np];
         }
      for (nr=1; nr<bar->ysize; nr++)
         {
         cpntra = (unsigned char *) myima->data;
         for (mr=0; mr<bar->xsize; mr++) *cpntrb++ = *cpntra++;
         }
      }

   else if (Xworkst[no].nobyt == 2)
      {
      jpntra = (short int *) myima->data;
      for (nr=0; nr<bar->ysize; nr++)
         {
         for (mr=0; mr<bar->xsize; mr++)
            {
            fa = mr*fc + 0.5;
            np = ((int)fa) + ioff;			/* scale to LUTsize */
            *jpntra++ = (short int) Xworkst[no].mapin[np];
            }
         }
      }
   }

else 			/* DirectColor/TrueColor => 3 bytes per pixel */
   {
   int  *jpntr;

   ipntra = (int *) myima->data;
   jpntr = ipntra + bar->xsize;		/* point to next line */

   if (Xworkst[no].visual == 3)
      {
      int  pixi;

      for (mr=0; mr<bar->xsize; mr++)
         {
         fa = mr*fc + 0.5;
         np = ((int)fa) + ioff;                 /* scale to LUTsize */
         pixi = np << 8;
         np += pixi;
         pixi = pixi << 8;
         *ipntra++ = (np + pixi);
         }
      }
   else					/* PseudoColor on Direct/TrueColor */
      {
      for (mr=0; mr<bar->xsize; mr++)
         {
         fa = mr*fc + 0.5;
         np = ((int)fa) + ioff;                 /* scale to LUTsize */
         np += Xworkst[no].auxcol;
         *ipntra++ = Xworkst[no].mapin[np];
         }
      }

   for (nr=1; nr<bar->ysize; nr++)
      {
      ipntra = (int *) myima->data;
      for (mr=0; mr<bar->xsize; mr++) *jpntr++ = *ipntra++; 
      }
   }


idi_putimage(mydisp[no],lutwnd[dspno],gclut[dspno],lutxima[dspno],
          0,0,0,0,bar->xsize,bar->ysize);
k = ididev[dspno].lutsect;
XSetWindowColormap(mydisp[no],lutwnd[dspno],cmap[no][k]);

return 0;
}

/*

*/

void vislutbar(dspno,bar,vis)
INTBAR   *bar;
int      dspno, vis;

{
int     no, k, tmpx, tmpy;


no = ididev[dspno].screen;
k = ididev[dspno].lutsect;

if (vis == 0)
   {
   tmpx = 0;       tmpy = ididev[dspno].ysize;
   tmpxdim = 1;    tmpydim = 1;
   XMoveResizeWindow(mydisp[no],lutwnd[dspno],tmpx,tmpy,tmpxdim,tmpydim);
   XSetWindowColormap(mydisp[no],mwndw[dspno],cmap[no][k]);
   }

else
   {
   XMoveResizeWindow(mydisp[no],lutwnd[dspno],bar->xoff,bar->yoff,
                     bar->xsize,bar->ysize);
   idi_putimage(mydisp[no],lutwnd[dspno],gclut[dspno],lutxima[dspno],
             0,0,0,0,bar->xsize,bar->ysize);
   XSetWindowColormap(mydisp[no],lutwnd[dspno],cmap[no][k]);
   }
}

/*

*/

void updalutbar(dspno,bar)
INTBAR   *bar;
int      dspno;

{
int  no, k, *ipntra, *jpntr;
register int mr, nr, ioff;

float  fa, fb, fc;



no = ididev[dspno].screen;
k = ididev[dspno].lutsect;


/* this is needed for PseudoColor on TrueColor */

ipntra = (int *) lutxima[dspno]->data;
jpntr = ipntra + bar->xsize;         /* point to next line */

fa = Xworkst[no].lutlen;
fb = bar->xsize;
fc = fa / fb;
ioff = ididev[dspno].lutsect * Xworkst[no].lutsize;

for (mr=0; mr<bar->xsize; mr++)
   {
   fa = mr*fc + 0.5;
   k = ((int)fa) + ioff;                 /* scale to LUTsize */
   k += Xworkst[no].auxcol;
   *ipntra++ = Xworkst[no].mapin[k];
   }

for (nr=1; nr<bar->ysize; nr++)
   {
   ipntra = (int *) lutxima[dspno]->data;
   for (mr=0; mr<bar->xsize; mr++) *jpntr++ = *ipntra++;
   }
}

/*

*/

/* set up event loop for input from keyboard + send character string back  */

void get_string(dspno,outbuf,lout)
int   dspno, *lout;
char  *outbuf;

{
int  no, k, i;

char cbuf[10];



no = ididev[dspno].screen;
ididev[dspno].inter_mask |= (KeyPressMask | Def_Mask);
XSelectInput(mydisp[no],mwndw[dspno],ididev[dspno].inter_mask);
k = 0;
  
wait_for_events:
XWindowEvent(mydisp[no],mwndw[dspno],ididev[dspno].inter_mask,&myevent);

if (myevent.type == Expose) 
   exposed(no,dspno);				/* refresh */

else if (myevent.type == KeyPress)
   {
   i = XLookupString(&myevent.xkey,cbuf,10,&mykey,&xcstat);
   if (mykey != XK_Return)
      {
      outbuf[k++] = cbuf[0];
      if (k < 79) goto wait_for_events;	/* IDI doc. => max. 80 chars...  */
      }
   int_disable(dspno);			/* disable other interactions  */
   cbuf[k] = '\0';
   *lout = k;
   return;
   }

goto wait_for_events;					/* loop more */
}

/*

*/

/* set up event loop for input from keyboard + send single character back  */

void get_char(dspno,outbuf)
int   dspno;
char  *outbuf;

{
int   no, i;


no = ididev[dspno].screen;

ididev[dspno].inter_mask |= (KeyPressMask | Def_Mask);
XSelectInput(mydisp[no],mwndw[dspno],ididev[dspno].inter_mask);
  
wait_for_events:
XWindowEvent(mydisp[no],mwndw[dspno],ididev[dspno].inter_mask,&myevent);

if (myevent.type == Expose) 
   exposed(no,dspno);				/* refresh */

else if (myevent.type == KeyPress)
   {
   i = XLookupString(&myevent.xkey,outbuf,10,&mykey,&xcstat);
   if (i == 1)
      {
      outbuf[1] = '\0';
      int_disable(dspno);		/* disable other interactions  */
      return;
      }
   }

goto wait_for_events;	
}

/*

*/

/* ----  Init graphics for display window  --------------------------- */

void initgra(dspno)
int  dspno;

{
int   no;

no = ididev[dspno].screen;
plotcol = -1;				/* init plotting color again */

XSetFunction(mydisp[no],gcima[dspno],GXcopy); 
XSetBackground(mydisp[no],gcima[dspno],ididev[dspno].backpix);
XSetForeground(mydisp[no],gcima[dspno],Xworkst[no].white);

}

/*

*/

/* ---- Polyline on display bitmap ----------------------------------- */

void polyline(dspno,dysize,mem,col,style,xs,ys,np)
int    dspno, dysize, col, style, *xs, *ys, np;
MEM_DATA   *mem;

{
int     no, kindx, koff, lstyle, last, rem;
int     j, k, x, y;
int     lastx, lasty;
int     *gx, *gy;
register int loopi;

GLIST   *gp;



if (lastplno != dspno)
   {
   lastplno = dspno;
   plotcol = -1;			/* force to new beginning */
   }

no = ididev[dspno].screen;
x = y = 0;
rem = 0;
lstyle = 0;


/*  check out the given color  */

if (col == 99)
   goto just_plot;		/* we don't save this polygon */


if ((col > 10) && (col < 19)) 	/* colors in [11,18] mean XORing */
   {
   col -= 10;
   lstyle = 10;
   }
else if (col > 8)
   {
   if (ididev[dspno].devtyp == 'g')
       col = 1;					/* default to black */
   else
       col = 2;					/* default to white  */
   }

if (plotcol != col)
   {
   plotcol = col;
   XSetForeground(mydisp[no],gcima[dspno],fixcolr[no][plotcol].pixel);
   }


if (lstyle != 0)
   XSetFunction(mydisp[no],gcima[dspno],GXxor); 
/*
else
   XSetFunction(mydisp[no],gcima[dspno],GXcopy); 
*/


if (style >= 10)		/* thickness is the power of 10 ... */
   {
   k = style / 10;
   /*
   if (k == 1) k = 0;		 XFree has problems with linewidth = 1 
				 Not true anymore!  060802
   */
   }
else
   k = 0;

if (linewidth != k)
   {
   linewidth = k;
   XSetLineAttributes(mydisp[no],gcima[dspno],(unsigned int)linewidth,
                      LineSolid, CapProjecting, JoinMiter);
   }

gp = mem->gpntr;
if (gp == (GLIST *)0) goto just_plot;

kindx = gp->geln;
if (kindx >= gp->maxpnt/2) goto just_plot;

koff = *(gp->off+kindx);
last = koff + np;
if (last > gp->maxpnt) goto just_plot;

*(gp->color+kindx) = col + lstyle;
*(gp->lwidth+kindx) = linewidth;
*(gp->count+kindx) = np;
*(gp->off+kindx+1) = last;


lastx = *xs;
lasty = dysize - *ys;


loop:
j = np - rem;			/* j from 0 to (np-1) in steps of MAX_PTS  */
if (j < 1) return;

if (j > MAX_PTS) j = MAX_PTS;

gx = gp->x + koff + rem;
gy = gp->y + koff + rem;


mypoint[0].x = (short int) lastx;
mypoint[0].y = (short int) lasty;

for (loopi=1; loopi<(j+1); loopi++)
   {						/* fill j points */
   x = *xs++;
   y = dysize - (*ys++);
   *gx++ = x;
   *gy++ = y;
   mypoint[loopi].x = (short int) x;
   mypoint[loopi].y = (short int) y;
   }
lastx = x;
lasty = y;

/* 
if (np > 2)
   {
   printf("polyline: col = %d, style = %d, np = %d, linewidth = %d, visibility = %d\n",
          col,style,np,linewidth,mem->visibility);
   for (loopi=0; loopi<=j; loopi++)
      printf("no: %d	x = %d, y = %d\n",loopi,
             mypoint[loopi].x,mypoint[loopi].y); 
   }
*/

if (mem->visibility == 1)		/* always draw last point again */
   {
   XDrawLines(mydisp[no],mwndw[dspno],gcima[dspno],
              mypoint,(j+1),CoordModeOrigin);
   if (linewidth == 0) 			/* only needed with width = 0  */
      XDrawPoint(mydisp[no],mwndw[dspno],gcima[dspno],lastx,lasty);
   }


if ((rem+j) < np)	
   {
   rem += j;
   goto loop;
   }

gp->geln ++ ;
goto flush_it;


/* overflow in our structures, so we just plot and do not save...  */

just_plot:
if (mem->visibility != 1) return;



lastx = *xs;
lasty = dysize - *ys;


plot_loop:
j = np - rem;			/* j moves from 0 to np in steps of MAX_PTS */
if (j < 1) return;

if (j > MAX_PTS) j = MAX_PTS;

mypoint[0].x = (short) lastx;
mypoint[0].y = (short) lasty;

for (loopi=1; loopi<(j+1); loopi++)
   {
   x = *xs++;
   y = dysize - (*ys++);
   mypoint[loopi].x = (short) x;
   mypoint[loopi].y = (short) y;
   }
lastx = x;
lasty = y;

if (col == 99)
   {
   XDrawLines(mydisp[no],mwndw[dspno],gcdraw[dspno],
              mypoint,j+1,CoordModeOrigin);
   if (linewidth == 0) 			/* only needed with width = 0  */
      XDrawPoint(mydisp[no],mwndw[dspno],gcima[dspno],lastx,lasty);
   }
else
   {
   XDrawLines(mydisp[no],mwndw[dspno],gcima[dspno],
              mypoint,j+1,CoordModeOrigin);
   if (linewidth == 0) 			/* only needed with width = 0  */
      XDrawPoint(mydisp[no],mwndw[dspno],gcima[dspno],lastx,lasty);
   }

if ((rem+j) < np)			/* still more to draw */
   {
   rem += j;
   goto plot_loop;
   }


flush_it:
if (lstyle != 0)			/* we must reset the GC for images */
   XSetFunction(mydisp[no],gcima[dspno],GXcopy); 
}

/*

*/

/* ----    Refresh graphics        ----------------------------------- */

void polyrefr(dspno,mem,flag,memid)
int  dspno, flag, memid;
MEM_DATA   *mem;

{
int     no, kindx, koff, rem, lstyle, jj, jk, np, k;
int     *goff, *gx, *gy, *gcount, *gcol, *gwidth;
int     lastx, lasty; 
register int loopi, loopj;

GLIST   *gp;


if (mem->visibility != 1) return;


/* if flag = 1, we also have to pass the memory no. and draw the stuff 
   in the Pixmap (if available) instead of the window */

if ( (flag == 1) && (mem->pixmap == 1) )
   xdrawable = mxpix[dspno][memid];
else
   xdrawable = mwndw[dspno];


no = ididev[dspno].screen;
if (lastplno != dspno)
   {
   lastplno = dspno;
   plotcol = -1;                        /* force to new beginning */
   }

gp = mem->gpntr;
if (gp == (GLIST *)0) return;

kindx = gp->geln;

goff = gp->off;
gcol = gp->color;
gwidth = gp->lwidth;
gcount = gp->count;
lstyle = 0;				/* GC should be set to GXcopy */

for (loopi=0; loopi<kindx; loopi++)
   {
   koff = *goff++;
   jk = *gcol++;
   if (jk > 10)
      {
      jk -= 10;
      jj = 10;
      }
   else
      jj = 0;

   if (plotcol != jk)
      {
      plotcol = jk;
      XSetForeground(mydisp[no],gcima[dspno],fixcolr[no][plotcol].pixel);
      }
   if (jj != lstyle)
      {
      if (lstyle != 0)
         XSetFunction(mydisp[no],gcima[dspno],GXxor); 
/*
      else
         XSetFunction(mydisp[no],gcima[dspno],GXcopy); 
*/
      }

   jj = *gwidth++;
   if (jj != linewidth)
      {
      linewidth = jj;
      XSetLineAttributes(mydisp[no],gcima[dspno],(unsigned int)linewidth,
                      LineSolid,CapProjecting,JoinMiter);
      }



   np = *gcount++;		/* no. of points to connect */
   rem = 0;
   gx = gp->x + koff;
   gy = gp->y + koff;
   lastx = *gx;
   lasty = *gy;
 

  loop:
   k = koff + rem;
   jk = np - rem;		/* jk moves from 0 to np in steps of MAX_PTS */
   if (jk > MAX_PTS) jk = MAX_PTS;

   gx = gp->x + k;
   gy = gp->y + k;

 

   mypoint[0].x = (short int) lastx;
   mypoint[0].y = (short int) lasty;

   for (loopj=1; loopj<(jk+1); loopj++)
      {
      mypoint[loopj].x = (short int) *gx++;
      mypoint[loopj].y = (short int) *gy++;
      }
   lastx = *(gx - 1);
   lasty = *(gy - 1);
   
   XDrawLines(mydisp[no],xdrawable,gcima[dspno],
              mypoint,(jk+1),CoordModeOrigin);
   if (linewidth == 0) 			/* only needed with width = 0 */
      XDrawPoint(mydisp[no],mwndw[dspno],gcima[dspno],lastx,lasty);
 

   if ((rem+jk) < np)			/* still more to draw */
      {
      rem += jk;
      goto loop;
      }
   }

if (lstyle != 0) XSetFunction(mydisp[no],gcima[dspno],GXcopy); 
}

/*

*/

/* ---- text on display bitmap ----------------------------------- */

void txtline(dspno,dysize,mem,txt,x0,y0,path,orient,col,size)
int     dspno, dysize, x0, y0, path, orient, col, size;
char    txt[];
MEM_DATA   *mem;

{
int     x, y, np, no, tindx, toff, last;
register int  loopi;

char    *cpntr;

TLIST   *tp;



/* check text size, and if necessary use different font  */

no = ididev[dspno].screen;
if (size > 3)
   size = 0;
else if (size < 0)			/* read Font from x11fonts.dat */
   {
   if (font_load(1,no,&size) == -1)	/* problems reading Font file */
      {
      myfont[no][3] = XLoadQueryFont(mydisp[no],"fixed");
      (void) printf("Use Font `fixed' instead\n");
      }
   size = 3;
   textsiz = -1;                        /* force to new beginning */
   }

if (lasttxtno != dspno)
   {
   lasttxtno = dspno;
   textsiz = -1;                        /* force to new beginning */
   }

if (textsiz != size)
   {
   textsiz = size;
   XSetFont(mydisp[no],gcima[dspno],myfont[no][textsiz]->fid);
   }

if (plotcol != col)
   {
   plotcol = col;
   XSetForeground(mydisp[no],gcima[dspno],fixcolr[no][plotcol].pixel);
   }

np = (int) strlen(txt);
x = x0;   y = dysize - y0;

tp = mem->tpntr;
if (tp == (TLIST *)0) goto just_text;

tindx = tp->teln;
if (tindx >= MAX_TXT) goto just_text;

if (tindx < 0) 
   {
   (void) printf("txtline: dspno = %d, image = %s, tindx = %d\n",
                 dspno,mem->frame,tindx);
   tindx = 0;
   }

toff = tp->off[tindx];
last = toff + np;
if (last > MAX_TXTLEN) goto just_text;

tp->x[tindx] = x;
tp->y[tindx] = y;
tp->size[tindx] = size;
tp->color[tindx] = col;
tp->count[tindx] = np;
tp->off[tindx+1] = last;

cpntr = &(tp->text[toff]);
for (loopi=0; loopi<np; loopi++) *cpntr ++ = txt[loopi];

tp->teln ++ ;

just_text:
if (mem->visibility == 1)
   XDrawString(mydisp[no],mwndw[dspno],gcima[dspno],x,y,txt,np);
}

/*

*/

/* ----    Refresh Text        ----------------------------------- */

void txtrefr(dspno,mem,flag,memid)
int  dspno, flag, memid;
MEM_DATA   *mem;

{
int     no, tindx, toff, x, y, np;
register int loopi;

char    *cpntr;

TLIST   *tp;


if (mem->visibility != 1) return;


/* if flag = 1, we also have to pass the memory no. and draw the text
   in the Pixmap (if available) instead of the window */

if ( (flag == 1) && (mem->pixmap == 1) )
   xdrawable = mxpix[dspno][memid];
else
   xdrawable = mwndw[dspno];

tp = mem->tpntr;
if (tp == (TLIST *)0) return;

tindx = tp->teln;
no = ididev[dspno].screen;

for (loopi=0; loopi<tindx; loopi++)
   {
   toff = tp->off[loopi];
   np = tp->count[loopi];
   x = tp->x[loopi];
   y = tp->y[loopi];
   if (textsiz != tp->size[loopi])
      {
      textsiz = tp->size[loopi];
      XSetFont(mydisp[no],gcima[dspno],myfont[no][textsiz]->fid);
      }
   if (plotcol != tp->color[loopi])
      {
      plotcol = tp->color[loopi];
      XSetForeground(mydisp[no],gcima[dspno],fixcolr[no][plotcol].pixel);
      }
   cpntr = & (tp->text[toff]);
   
   XDrawString(mydisp[no],xdrawable,gcima[dspno],x,y,cpntr,np);
   }
}

/*

*/

/* ---- get plot colour values --------------------------------------- */

void rd_pllut (dspno,plut)
int dspno;
LUT_DATA  *plut;

{
register int loop;
int   no;

no = ididev[dspno].screen;

for (loop=0; loop<PLOT_COLOURS; loop++)
   {
   plut->lutr[loop] = fixcolr[no][loop].red;
   plut->lutg[loop] = fixcolr[no][loop].green;
   plut->lutb[loop] = fixcolr[no][loop].blue;
   }
}

/*

*/

/* ---- do miscellaneous stuff --------------------------------------- */

void do_misc(dspno,flag,auxid,cbuf,ibuf,rbuf)
int dspno, flag, auxid, *ibuf;
float *rbuf;
char  *cbuf;

{
int  no;



no = ididev[dspno].screen;


/* flag = 1 is currently the only "officially" used flag  */

if (flag == 1)
   {
   if (auxid < 0)			/* reset to root window */
      {
      rw[no] = XRootWindow(mydisp[no],myscreen);
      dspno = -1;			/* just to be on the safe side */
      }
   else
      rw[no] = mwndw[dspno];
   parent_id = dspno;

   /* 
   printf("rw[%d] = %x will be set to mwndw[%d] = %x, parent_id = %d\n",
       no,rw[no],dspno,mwndw[dspno],dspno);
   */
   
   return;
   }




/*
(void) printf
       ("do_misc: flag = %d, mwndw[%d] = %x \n",flag,dspno,mwndw[dspno]);
*/


if (flag == 2)
   {
   Window  root, parent, *children;
   unsigned int  nochld;

   XQueryTree(mydisp[no],mwndw[dspno],
                    &root,&parent,&children,&nochld);

/*
   (void) printf("XQueryTree for window %d returned:\n",dspno);
   (void) printf("root_w = %x, parent_w = %x, no. children = %d\n",
                 root,parent,nochld);
*/

   XFree(children);
   }

else if (flag == 3)
   {
   XMapSubwindows(mydisp[no],mwndw[dspno]);

   printf("XMapSubwindows was called...\n");
   }

else if (flag == 4)
   {
   Window root;
   int  x, y;
   unsigned int  wd, he, bw, dep;


   XWindowAttributes  attribs;

   XGetWindowAttributes(mydisp[no],mwndw[dspno],&attribs);

   /*
   (void) printf("XGetWindowAttributes for window %d returned:\n",dspno);
   (void) printf(
   "xpos, ypos = %d, %d  width, height = %d, %d, borderw = %d, depth = %d\n",
   attribs.x,attribs.y,attribs.width,attribs.height,
   attribs.border_width,attribs.depth);

   (void) printf("associated Visual = %x\n",attribs.visual);
   */
 
   if (attribs.map_state == IsUnmapped)
      (void) printf("window is unmapped ...\n");
   else if (attribs.map_state == IsUnviewable)
      (void) printf("window is unviewable ...\n");
   else if (attribs.map_state == IsViewable)
      (void) printf("window is viewable ...\n");
   if (attribs.map_installed)
      (void) printf("color map is installed ...\n");
   else
      (void) printf("color map is NOT installed ...\n");

   XGetGeometry(mydisp[no],mwndw[dspno],&root,&x,&y,&wd,&he,&bw,&dep);
   /*
   (void) printf("XGetGeometry returned:\n");
   (void) printf
          ("root = %x, x, y = %d, %d  wd, he = %d, %d, bw = %d, dep = %d\n",
           root,x,y,wd,he,bw,dep);
   */
   }
}

