
#include <iostream.h>
#include <stdlib.h>
#include <math.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/time.h>
#include "../../configure.h"
#include "WinBase.h"

char *def_geom_string = NULL;
char *def_fg_string = DEFAULT_FORECOLOR;
char *def_bg_string = DEFAULT_BACKCOLOR;
char *def_font = DEFAULT_FONT;
char *def_bw = DEFAULT_BEVEL;
char *def_resname = "XThing";
char *def_display = NULL;
char **orig_argv = NULL;
int orig_argc = 0;

/************************************************************************
 * ReapChildren - wait() for all dead child processes
 ************************************************************************/
#include <sys/wait.h>
#ifdef HAVE_WAITPID
#define ReapChildren()  while ((waitpid(-1, NULL, WNOHANG)) > 0);
#else
#define ReapChildren()  while ((wait3(NULL, WNOHANG, NULL)) > 0);
#endif
   
int GetFdWidth(void)
{
#ifdef HAVE_SYSCONF
  return sysconf(_SC_OPEN_MAX);
#else
  return getdtablesize();
#endif
}

int My_XNextEvent(Display *dpy, XEvent *event);
static int MyXAllocColor(Display *dpy,Colormap cmap,int screen, XColor *color);
/**************************************************************************
 *
 * Standard options 
 *
 *************************************************************************/
struct res_list
{
  char **dataptr;
  char *keyword;
};

     
struct res_list  string_resource_list[] =
{
  {&def_geom_string,                "geometry"},
  {&def_geom_string,                "geom"},
  {&def_fg_string,                  "foreground"},
  {&def_fg_string,                  "fg"},
  {&def_bg_string,                  "background"},
  {&def_bg_string,                  "bg"},
  {&def_font,                       "font"},
  {&def_bw,                         "bevelwidth"},
  {&def_bw,                         "bw"},
  {0,                           NULL}
};


/***************************************************************************
 *
 * Declarations for static members of WinBase
 *
 ***************************************************************************/
Display     *WinBase::dpy = 0;
Window       WinBase::Root = None;
int          WinBase::Screen;
GC           WinBase::DefaultReliefGC;
GC           WinBase::DefaultShadowGC;
GC           WinBase::DefaultForeGC;
XFontStruct *WinBase::DefaultFont;
Pixel        WinBase::DefaultBackColor;
Pixel        WinBase::DefaultReliefColor;
Pixel        WinBase::DefaultShadowColor;
Pixel        WinBase::DefaultForeColor;
Colormap     WinBase::cmap;

static Atom wm_del_win;
static int fd_width;
static int x_fd;
struct iodesc
{
  int fd;
  void (*func)(int);
};
struct iodesc *wininputdesc;
struct iodesc *winoutputdesc;
static int wininputcount;
static int winoutputcount;

void WinInitialize(char **argv, int argc)
{
  int i = 0,j,done;
  char *tmp;

  orig_argv = argv;
  orig_argc = argc;

  for(i=1;i<argc;i++)
    {
      if(strcmp(argv[i],"-display")==0)
	def_display = argv[i+1];
    }


  WinBase::dpy = XOpenDisplay(def_display);
  if(WinBase::dpy == 0)
    {
      cerr <<"Can't open display\n";
      exit(-1);
    }

  fd_width = GetFdWidth();
  wininputdesc = new struct iodesc[fd_width];
  winoutputdesc = new struct iodesc[fd_width];
  wininputcount = 0;
  winoutputcount = 0;
  for(i=0;i<fd_width;i++)
    {
      wininputdesc[i].fd = -1;
      winoutputdesc[i].fd = -1;
    }
  x_fd = XConnectionNumber(WinBase::dpy);

  if(argv[0] !=0)
    def_resname = argv[0];

  /* Check for defaults in .Xdefaults. */
  i=0;
  while(string_resource_list[i].keyword != NULL)
    {
      if((tmp = XGetDefault(WinBase::dpy,def_resname,
			    string_resource_list[i].keyword)) != (char *)0)
	{
	  *string_resource_list[i].dataptr = tmp;
	}
      
      i++;
    }

  /* Check for command line options */
  for(i=1;i<argc;i++)
    {
      if(argv[i][0] == '-')
	{
	  j=0;
	  done = 0;
	  while((string_resource_list[j].keyword != NULL)&&(!done))
	    {
	      if(strcmp(&argv[i][1],string_resource_list[j].keyword)==0)
		{
		  *string_resource_list[j].dataptr = &argv[i+1][0];
		  i++;
		  done = 1;
		}
	      j++;
	    }
	}
    }
}

int WinAddInput(int fd, void (*readfunc)(int))
{
  if(wininputcount < fd_width)
    {
      wininputdesc[wininputcount].func = readfunc;
      wininputdesc[wininputcount].fd = fd;
      wininputcount++;
      return 0;
    }
  else
    return 1;
}

int WinAddOutput(int fd, void (*writefunc)(int))
{
  if(winoutputcount < fd_width)
    {
      winoutputdesc[winoutputcount].func = writefunc;
      winoutputdesc[winoutputcount].fd = fd;
      winoutputcount++;
      return 0;
    }
  else
    return 1;
}

WinBase::WinBase(WinBase* ParentW, int width,int height,int x_loc, int y_loc)
{
  Window pwindow;
  XGCValues gcv;
  XSetWindowAttributes attributes;      /* attributes for creating window */
  unsigned long mask;
  int create_defaults = 0;

  Parent = ParentW;
  if(Root == None)
    {
      /* This is the first window opened. */
      create_defaults = 1;

      /* Open X connection */
      if(dpy == 0)
	{
	  dpy = XOpenDisplay(def_display);
	  if(dpy == 0)
	    {
	      cerr <<"Can't open display\n";
	      if(def_display != NULL)
		cerr <<def_display;
	      cerr <<"\n";
		  
	      exit(-1);
	    }
	}
      Screen = DefaultScreen(dpy);
      Root = RootWindow(dpy,Screen);

    }
  if(create_defaults)
    {
      cmap = DefaultColormap(dpy,Screen);
      DefaultBackColor = GetColor(def_bg_string,dpy,cmap,Screen);
      GetColor("black",dpy,cmap,Screen);
      GetColor("white",dpy,cmap,Screen);
      if(DefaultBackColor == 0xffffffff)
	DefaultBackColor = WhitePixel(dpy,Screen);
      DefaultReliefColor = GetHilite(DefaultBackColor,dpy,Screen, cmap);
      DefaultShadowColor = GetShadow(DefaultBackColor,dpy,Screen, cmap);
      DefaultForeColor = GetColor(def_fg_string,dpy,cmap,Screen);
      if(DefaultForeColor == 0xffffffff)
	DefaultForeColor = BlackPixel(dpy,Screen);
      
    }

  if(Parent == NULL)
    pwindow = Root;
  else
    pwindow = Parent->win;
  x = x_loc;
  y = y_loc;
  w = width;
  h = height;

  if(Parent == NULL)
    {
      BackColor = DefaultBackColor;
      ForeColor = DefaultForeColor;
      ReliefColor = DefaultReliefColor;
      ShadowColor = DefaultShadowColor;
      bw = atoi(def_bw);
    }
  else
    {
      BackColor = Parent->BackColor;
      ForeColor = Parent->ForeColor;
      ReliefColor = Parent->ReliefColor;
      ShadowColor = Parent->ShadowColor;
      bw = Parent->bw;
    }
  popped_out = 1;

  name_set = 0;
  icon_name_set = 0;

  CloseWindowAction = NULL;

  mask = CWBackPixel | CWEventMask;
  attributes.background_pixel = BackColor;
  attributes.event_mask = 
    ButtonPressMask|ButtonReleaseMask|ExposureMask|KeyPressMask|
      StructureNotifyMask;
  win = XCreateWindow(dpy,pwindow,x_loc,y_loc,width,height,0,
		      CopyFromParent,InputOutput,CopyFromParent,
		      mask,&attributes);
  if(create_defaults)
    {
      DefaultFont = XLoadQueryFont(dpy, def_font);
      if(DefaultFont == NULL)
	{
	  cerr <<"Can't load font "<<def_font<<"\n";
	  DefaultFont = XLoadQueryFont(dpy, "fixed");	
	}
      if(DefaultFont == NULL)
	{
	  cerr <<"Giving up\n";
	  exit(1);
	}

      mask = GCFunction|GCPlaneMask|GCGraphicsExposures|GCLineWidth|
	GCForeground|GCBackground| GCFont;
      gcv.background = DefaultBackColor;
      gcv.line_width = 0;
      gcv.function = GXcopy;
      gcv.font = DefaultFont->fid;
      gcv.plane_mask = AllPlanes;
      gcv.graphics_exposures = False;
      
      gcv.foreground = DefaultReliefColor;
      DefaultReliefGC = XCreateGC(dpy,win,mask,&gcv);
      gcv.foreground = DefaultShadowColor;
      DefaultShadowGC = XCreateGC(dpy,win,mask,&gcv);
      gcv.foreground = DefaultForeColor;
      DefaultForeGC = XCreateGC(dpy,win,mask,&gcv);
    }
  if(Parent == NULL)
    {
      XClassHint classhints;
      XWMHints wmhints;
      XSizeHints normal_hints;
      XTextProperty name;

      main_window = this;
      ReliefGC = DefaultReliefGC;
      ShadowGC = DefaultShadowGC;
      ForeGC = DefaultForeGC;
      Font = DefaultFont;
      normal_hints.flags = PWinGravity|PMinSize|PResizeInc;
      normal_hints.width_inc = 1;
      normal_hints.height_inc = 1;
      normal_hints.min_width = 1;
      normal_hints.min_height = 1;
      normal_hints.win_gravity = NorthWestGravity;
      wmhints.input = True;
      wmhints.initial_state = NormalState;
      wmhints.flags = InputHint|StateHint;
      classhints.res_name = def_resname;
      classhints.res_class = def_resname;
  
      if (XStringListToTextProperty(&def_resname,1,&name) == 0)
	{
	  cerr <<"cannot allocate window name";
	  return;
	}

      XSetWMProperties(dpy,win, &name, &name,orig_argv, 
		       orig_argc, &normal_hints,&wmhints,&classhints);
    }
  else
    {
      main_window = Parent->main_window;
      mask = GCFunction|GCPlaneMask|GCGraphicsExposures|GCLineWidth|
	GCForeground|GCBackground| GCFont;
      if(Parent->ReliefGC == DefaultReliefGC)
	ReliefGC = DefaultReliefGC;
      else
	{
	  XGetGCValues(dpy,Parent->ReliefGC,mask,&gcv);
	  ReliefGC = XCreateGC(dpy,win,mask,&gcv);
	}
      if(Parent->ShadowGC == DefaultShadowGC)
	ShadowGC = DefaultShadowGC;
      else
	{
	  XGetGCValues(dpy,Parent->ShadowGC,mask,&gcv);
	  ShadowGC = XCreateGC(dpy,win,mask,&gcv);
	}

      if(Parent->ForeGC == DefaultForeGC)
	ForeGC = DefaultForeGC;
      else
	{
	  XGetGCValues(dpy,Parent->ForeGC,mask,&gcv);
	  ForeGC = XCreateGC(dpy,win,mask,&gcv);
	}
      Font = Parent->DefaultFont;
    }
  RegisterWindow(win,this);

  if(wm_del_win == 0)
    wm_del_win = XInternAtom(dpy,"WM_DELETE_WINDOW",False);
  XSetWMProtocols(dpy,win,&wm_del_win,1);
}


WinBase::~WinBase()
{
  XDestroyWindow(dpy,win);
  UnregisterWindow(this);
}

void WinBase::Map()
{
  XMapSubwindows(dpy,win);
  XMapRaised(dpy,win);
  XSync(dpy,0);
}

void WinBase::RedrawWindow(int clear)
{
  if(clear)
    XClearWindow(dpy,win);
  DrawCallback(NULL);
}

void WinBase::DrawCallback(XEvent *event)
{
  int i;
  GC gc1;
  GC gc2;

  if((!event)||(event->xexpose.count == 0))
    {
      if(popped_out)
	{
	  gc1 = ShadowGC;
	  gc2 = ReliefGC;
	}
      else
	{
	  gc2 = ShadowGC;
	  gc1 = ReliefGC;
	}
      for(i=0;i<bw;i++)
	{
	  XDrawLine(dpy,win,gc1,i,h-1-i,w-1-i,h-1-i);
	  XDrawLine(dpy,win,gc1,w-1-i,i,w-1-i,h-1-i);
	  XDrawLine(dpy,win,gc2,i,i,w-1-i,i);
	  XDrawLine(dpy,win,gc2,i,i,i,h-1-i);
	}
    }
  

}

void WinBase::BPressCallback(XEvent *event)
{
}

void WinBase::KPressCallback(XEvent *event)
{
}

void WinBase::BReleaseCallback(XEvent *event)
{
}

void WinBase::ResizeCallback(int new_w, int new_h, XEvent *event)
{
  w = new_w;
  h = new_h;
  RedrawWindow(1);
}

void WinBase::MotionCallback(XEvent *event)
{
}
 
void WinBase::SetSize(int new_w, int new_h)
{
  XResizeWindow(dpy,win,new_w,new_h);
  w = new_w;
  h = new_h;
}



void WinBase::SetPosition(int new_x, int new_y)
{
  XMoveWindow(dpy,win,new_x,new_y);
  x = new_x;
  y = new_y;
}

void WinBase::SetGeometry(int new_x, int new_y, int new_w, int new_h, 
			  int min_width, int min_height, 
			  int max_width, int max_height, 
			  int resize_inc_w, int resize_inc_h,
			  int base_width, int base_height,
			  int gravity)
{
  XSizeHints normal_hints;
  
  normal_hints.flags = USPosition|USSize|
    PMinSize|PMaxSize|PResizeInc|PBaseSize|PWinGravity;
  normal_hints.x = new_x;
  normal_hints.y = new_y;
  normal_hints.width = new_w;
  normal_hints.height = new_h;
  normal_hints.min_width = min_width;
  normal_hints.min_height = min_height;
  normal_hints.max_width = max_width;
  normal_hints.max_height = max_height;
  normal_hints.width_inc = resize_inc_w;
  normal_hints.height_inc = resize_inc_h;
  normal_hints.base_width = base_width;
  normal_hints.base_height = base_height;
  normal_hints.win_gravity = gravity;
  XSetWMNormalHints(dpy,win, &normal_hints);
  SetPosition(new_x,new_y);
  SetSize(new_w, new_h);
}

void WinBase::SetCloseWindowAction(void (*NewAction)(WinBase *which))
{
  CloseWindowAction = NewAction;
}
void WinBase::SetBackColor(char *newcolor = DEFAULT_BACKCOLOR)
{
  XGCValues gcv;
  XSetWindowAttributes attributes;      /* attributes for creating window */
  unsigned long mask;

  BackColor = GetColor(newcolor,dpy,cmap,Screen);
  if(BackColor == 0xffffffff)
    BackColor = DefaultBackColor;
  ReliefColor = GetHilite(BackColor,dpy,Screen, cmap);
  ShadowColor = GetShadow(BackColor,dpy,Screen, cmap);
  if(ForeGC != DefaultForeGC)
    {
      XFreeGC(dpy,ForeGC);
    }
  if(ShadowGC != DefaultShadowGC)
    {
      XFreeGC(dpy,ShadowGC);
    }
  if(ReliefGC != DefaultReliefGC)
    {
      XFreeGC(dpy,ReliefGC);
    }

  mask = GCFunction|GCPlaneMask|GCGraphicsExposures|GCLineWidth|
    GCForeground|GCBackground|GCFont;
  gcv.background = BackColor;
  gcv.line_width = 0;
  gcv.function = GXcopy;
  gcv.plane_mask = AllPlanes;
  gcv.font = Font->fid;
  gcv.graphics_exposures = False;
  
  gcv.foreground = ReliefColor;
  ReliefGC = XCreateGC(dpy,win,mask,&gcv);
  gcv.foreground = ShadowColor;
  ShadowGC = XCreateGC(dpy,win,mask,&gcv);
  gcv.foreground = ForeColor;
  ForeGC = XCreateGC(dpy,win,mask,&gcv);
  mask = CWBackPixel;
  attributes.background_pixel = BackColor;
  XChangeWindowAttributes(dpy,win, mask,&attributes);
  XClearWindow(dpy,win);
}
void WinBase::SetBevelWidth(int new_bw)
{
  bw = new_bw;
}
void WinBase::PushIn()
{
  popped_out = 0;

}

void WinBase::PopOut()
{
  popped_out = 1;
}

void WinBase::MakeTransient(WinBase *TransientFor)
{
  XSetTransientForHint(dpy,win,TransientFor->win);
}

void WinBase::SetForeColor(char *newcolor = DEFAULT_FORECOLOR)
{
  XGCValues gcv;
  unsigned long mask;
  
  ForeColor = GetColor(newcolor,dpy,cmap,Screen);
  if(ForeColor == 0xffffffff)
    ForeColor = DefaultForeColor;
  if(ForeGC!= DefaultForeGC)
    XFreeGC(dpy,ShadowGC);

  mask = GCFunction|GCPlaneMask|GCGraphicsExposures|GCLineWidth|
    GCForeground|GCBackground|GCFont;
  gcv.background = BackColor;
  gcv.line_width = 0;
  gcv.function = GXcopy;
  gcv.plane_mask = AllPlanes;
  gcv.graphics_exposures = False;
  gcv.foreground = DefaultForeColor;
  gcv.font = Font->fid;
  ForeGC = XCreateGC(dpy,win,mask,&gcv);
}
void WinBase::SetFont(char *newfont=DEFAULT_FONT)
{
  XGCValues gcv;
  unsigned long mask;

  Font = XLoadQueryFont(dpy, newfont);
  if(Font == NULL)
    Font = DefaultFont;

  if(ForeGC != DefaultForeGC)
    {
      XFreeGC(dpy,ForeGC);
    }
  if(ShadowGC != DefaultShadowGC)
    {
      XFreeGC(dpy,ShadowGC);
    }
  if(ReliefGC != DefaultReliefGC)
    {
      XFreeGC(dpy,ReliefGC);
    }

  mask = GCFunction|GCPlaneMask|GCGraphicsExposures|GCLineWidth|
    GCForeground|GCBackground|GCFont;
  gcv.background = BackColor;
  gcv.line_width = 0;
  gcv.function = GXcopy;
  gcv.plane_mask = AllPlanes;
  gcv.font = Font->fid;
  gcv.graphics_exposures = False;
  
  gcv.foreground = ReliefColor;
  ReliefGC = XCreateGC(dpy,win,mask,&gcv);
  gcv.foreground = ShadowColor;
  ShadowGC = XCreateGC(dpy,win,mask,&gcv);
  gcv.foreground = ForeColor;
  ForeGC = XCreateGC(dpy,win,mask,&gcv);
}

void WinBase::SetWindowName(char *new_name)
{
  XTextProperty name;
  
  if (XStringListToTextProperty(&new_name,1,&name) == 0)
    {
      cerr <<"cannot allocate window name";
      return;
    }
  XSetWMName(dpy,win,&name);
  XFree(name.value);                     
  if(icon_name_set == 0)
    {
      SetIconName(new_name);
      icon_name_set = 0;
    }
  name_set = 1;
}
void WinBase::SetIconName(char *new_name)
{
  XTextProperty name;
  
  if (XStringListToTextProperty(&new_name,1,&name) == 0)
    {
      cerr<<"cannot allocate icon name";
      return;
    }
  XSetWMIconName(dpy,win,&name);
  XFree(name.value);                
  icon_name_set = 1;
}

void WinBase::SetWindowClass(char *resclass)
{
  XClassHint class_hint;

  class_hint.res_name = def_resname;
  class_hint.res_class = resclass;
  XSetClassHint(dpy,win,&class_hint);
}

/****************************************************************************
 *
 * This routine computes the shadow color from the background color
 *
 ****************************************************************************/
Pixel GetShadow(Pixel background, Display *dpy, int Screen, Colormap cmap) 
{
  XColor bg_color, white_p;

  bg_color.pixel = background;
  XQueryColor(dpy,cmap,&bg_color);

  white_p.pixel = WhitePixel(dpy,Screen);
  XQueryColor(dpy,cmap,&white_p);
 
  if((bg_color.red < white_p.red/5)&&
     (bg_color.green < white_p.green/5)&&
     (bg_color.blue < white_p.blue/5))
    {
      bg_color.red = white_p.red/4;
      bg_color.green = white_p.green/4;
      bg_color.blue =  white_p.blue/4;
    }
  else
    {
      bg_color.red = (bg_color.red*50)/100;
      bg_color.green = (bg_color.green*50)/100;
      bg_color.blue = (bg_color.blue*50)/100;
    }
  
  if(!MyXAllocColor(dpy,cmap,Screen,&bg_color))
    {
      cout <<"Can't allocate shadow color\n";
      bg_color.pixel = BlackPixel(dpy,Screen);
    }
  return bg_color.pixel;
}

/****************************************************************************
 *
 * This routine computes the hilight color from the background color
 *
 ****************************************************************************/
Pixel GetHilite(Pixel background, Display *dpy, int Screen, Colormap cmap) 
{
  XColor bg_color, white_p;
  int r,g,b;
  bg_color.pixel = background;
  XQueryColor(dpy,cmap,&bg_color);

  white_p.pixel = WhitePixel(dpy,Screen);
  XQueryColor(dpy,cmap,&white_p);


  if((bg_color.red > 2*white_p.red/3)&&
     (bg_color.green > 2*white_p.green/3)&&
     (bg_color.blue > 2*white_p.blue/3))
    {
      r = white_p.red*3/4;
      g = white_p.green*3/4;
      b =  white_p.blue*3/4;
    }
  else
    {
      r = bg_color.red + (white_p.red - bg_color.red)/2;
      g = bg_color.green + (white_p.green - bg_color.green)/2;
      b = bg_color.blue + (white_p.blue - bg_color.blue)/2;
    }
  if(r > white_p.red)
    bg_color.red = white_p.red;
  else
    bg_color.red = r;
  if(g > white_p.green)
    bg_color.green = white_p.green;
  else
    bg_color.green = g;
  if(b > white_p.blue)
    bg_color.blue = white_p.blue;
  else
    bg_color.blue = b;
  
  if(!MyXAllocColor(dpy,cmap,Screen,&bg_color))
    {
      cout <<"Can't allocate highlight color\n";
      bg_color.pixel = WhitePixel(dpy,Screen);;
    }
  return bg_color.pixel;
}

/****************************************************************************
 *
 * Loads a single color
 *
 ****************************************************************************/
Pixel GetColor(char *name, Display *dpy, Colormap cmap, int Screen)
{
  XColor color;

  color.pixel = 0xffffffff;
  if (!XParseColor (dpy, cmap, name, &color))
    {
      cerr<< "Can't parse color "<<name<<"\n";
    }
  else if(!MyXAllocColor (dpy, cmap, Screen,&color))
    {
      cerr<< "Can't allocate color "<<name<<"\n";
    }
  return color.pixel;
}

static int MyXAllocColor(Display *dpy,Colormap cmap,int screen, XColor *color)
{
  XColor *allcolors;
  int ncolors,i;
  int bestpixel = 0;
  float rdist, bdist, gdist, distance,bestdistance = 2e10;

  if(XAllocColor (dpy, cmap, color))
    return 1;

  ncolors = DisplayCells(dpy,screen);
  allcolors = new XColor[ncolors];
  for(i=0;i<ncolors;i++)
    allcolors[i].pixel = i;
  XQueryColors(dpy,cmap,allcolors,ncolors);
  for(i=0;i<ncolors;i++)
    {
      rdist = color->red- allcolors[i].red;
      bdist = color->blue- allcolors[i].blue;
      gdist = color->green- allcolors[i].green;
      distance = rdist*rdist+bdist*bdist+gdist*gdist;
      if(distance < bestdistance)
	{
	  bestdistance = distance;
	  bestpixel = i;
	}
    }
  color->red = allcolors[bestpixel].red;
  color->green = allcolors[bestpixel].green;
  color->blue = allcolors[bestpixel].blue;
  if(XAllocColor (dpy, cmap, color))
    return 1;
  else
    return 0;
}

struct registered
{
  Window win;
  WinBase *thing;
  int occupied;
};
static struct registered thinglist[100];



void RegisterWindow(Window win, WinBase *a)
{
  static int firsttime = 1;
  int i;

  if(firsttime)
    {
      firsttime = 0;
      for(i=0;i<100;i++)
	{
	  thinglist[i].occupied = 0;
	}
    }
  
  for(i=0;i<100;i++)
    {
      if(thinglist[i].occupied == 0)
	{
	  thinglist[i].occupied = 1;
	  thinglist[i].win = win;
	  thinglist[i].thing = a;
	  return;
	}
    }
  cout <<"Too many windows\n";
  exit(-1);
}


void UnregisterWindow(WinBase *thing)
{
  int i;
  for(i=0;i<100;i++)
    {
      if((thinglist[i].occupied ==1)&&
	 (thinglist[i].thing == thing))
	 {
	   thinglist[i].occupied = 0;
	   return;
	 }
    }
}
  
void WinLoop()
{
  XEvent event;
  int i;
  Display *dpy;
  
  i=0;
  while((thinglist[i].occupied == 0)&&(i<100))
    {
      i++;
    }
  if(i<100)
    dpy = thinglist[i].thing->dpy; 
  else
    return;

  while(!My_XNextEvent(dpy,&event));

  for(i=0;i<100;i++)
    {
      if((thinglist[i].occupied)&&(event.xany.window == thinglist[i].win))
	{
	  switch(event.type)
	    {
	    case Expose:
	    case GraphicsExpose:
	      thinglist[i].thing->DrawCallback(&event);
	      break;
	    case ButtonPress:
	      thinglist[i].thing->BPressCallback(&event);
	      break;
	    case ButtonRelease:
	      thinglist[i].thing->BReleaseCallback(&event);
	      break;
	    case KeyPress:
	      thinglist[i].thing->KPressCallback(&event);
	      break;
	    case ConfigureNotify:
	      if((thinglist[i].thing->w!= event.xconfigure.width)||
		(thinglist[i].thing->h!= event.xconfigure.height))
		thinglist[i].thing->ResizeCallback(event.xconfigure.width, 
						   event.xconfigure.height,&event);
	      break;
	    case ClientMessage:
	      if (event.xclient.format == 32 && event.xclient.data.l[0] == wm_del_win)
		{
		  if(thinglist[i].thing->CloseWindowAction == NULL)
		    exit(0);
		  else
		    thinglist[i].thing->CloseWindowAction(thinglist[i].thing);
		}
	      break;
	    case MotionNotify:
	      thinglist[i].thing->MotionCallback(&event);	
	      break;
	    default:
	      break;
	    }
	  return;
	}
    }
}


/***************************************************************************
 *
 * Waits for next X event, or for an auto-raise timeout.
 *
 ****************************************************************************/
int My_XNextEvent(Display *dpy, XEvent *event)
{
  fd_set in_fdset,out_fdset;
  Window child;
  Window targetWindow;
  int i,count;
  int retval;

  FD_ZERO(&in_fdset);
  FD_SET(x_fd,&in_fdset);
  FD_ZERO(&out_fdset);
  for(i=0; i<wininputcount; i++)
    {
      FD_SET(wininputdesc[i].fd, &in_fdset);
    }

  for(i=0; i<winoutputcount; i++)
    {
      FD_SET(winoutputdesc[i].fd, &out_fdset);
    }

  /* Do this IMMEDIATELY prior to select, to prevent any nasty
   * queued up X events from just hanging around waiting to be
   * flushed */
  XFlush(dpy);
  if(XPending(dpy))
    {
      XNextEvent(dpy,event);
      return 1;
    }

  /* Zap all those zombies! */
  /* If we get to here, then there are no X events waiting to be processed.
   * Just take a moment to check for dead children. */
  ReapChildren();

  XFlush(dpy);
#ifdef __hpux
  retval=select(fd_width,(int *)&in_fdset, (int *)&out_fdset,0, NULL);
#else
  retval=select(fd_width,&in_fdset, &out_fdset, 0, NULL);
#endif
  
  /* Check for module input. */
  for(i=0;i<fd_width;i++)
    {
      if((wininputdesc[i].fd >= 0)&&(FD_ISSET(wininputdesc[i].fd, &in_fdset)))
	{
	  wininputdesc[i].func(wininputdesc[i].fd);
	}
      if((winoutputdesc[i].fd>=0)&&(FD_ISSET(winoutputdesc[i].fd, &out_fdset)))
	{
	  winoutputdesc[i].func(winoutputdesc[i].fd);
	}
    }
  return 0;
}



