/**************************************************************************\
 ibtk (Insomnia's Basic ToolKit)

  By Insomnia (Steaphan Greene)
  (insomnia@core.binghamton.edu)

  Copyright (C) 1999 Steaphan Greene

  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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.

\**************************************************************************/

#include "iwindow.h"

#define DEFAULT_NAME "IBTK v0.0"

#include <X11/X.h>
#include <X11/Xutil.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static int Blue, Red, Green;

#define	W	255<<8
#define	B	0<<8
#define	Gr	192<<8
#define	GrL	228<<8
#define	GrD	93<<8

#define EVENT_MASK (PointerMotionMask|ButtonPressMask|ButtonReleaseMask \
	|ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask \
	|VisibilityChangeMask)

IWindow::~IWindow() {
  XDestroyWindow(Disp, Win);
  XFreeGC(Disp, gc);
  XFreeGC(Disp, cgc);
  XCloseDisplay(Disp);
  }

IWindow::IWindow(char *name, int xs, int ys, int xpos, int ypos, char *bg)  {
  Init(name, xs, ys, xpos, ypos, bg, NULL, 0, 0);
  }

IWindow::IWindow(char *bg)  {
  Init(DEFAULT_NAME, 0, 0, -1, -1, bg, NULL, 0, 0);
  }

IWindow::IWindow(int xs, int ys, char *bg)  {
  Init(DEFAULT_NAME, xs, ys, -1, -1, bg, NULL, 0, 0);
  }

IWindow::IWindow(int xs, int ys, int xpos, int ypos, char *bg)  {
  Init(DEFAULT_NAME, xs, ys, xpos, ypos, bg, NULL, 0, 0);
  }

IWindow::IWindow(char *name, char *bg, Window* iwin, int xsi, int ysi)  {
  Init(name, 0, 0, -1, -1, bg, iwin, xsi, ysi);
  }

IWindow::IWindow(char *name, int xs, int ys, char *bg)  {
  Init(name, xs, ys, -1, -1, bg, NULL, 0, 0);
  }

void IWindow::Init(char *name, int xs, int ys, int xp, int yp, char *bg,
                   Window* iwin, int xsi, int ysi)  {
  LoadConfig();
  XWMHints wmhints;
  useicon=0;
  WinBuf=0; bufxs=0; bufys=0;
  xsize = xs; ysize = ys; xpos = xp; ypos = yp; mapped = 0;
  xsizei = xsi; ysizei = ysi; xposi = 0; yposi = 0;
  Disp = XOpenDisplay(NULL);
  if(Disp==NULL) {
    fprintf(stderr, "IBTK: Unable to open DISPLAY!\n");
    exit(1);
    }

  DispFD = ConnectionNumber(Disp);
  depth = DefaultDepth(Disp, 0);
  XColor g, t;
  
  if(bg != NULL) {
    XAllocNamedColor(Disp, DefaultColormap(Disp, 0), bg, &g, &t);
    wbgcol = g.pixel;
    }

  g.flags = DoRed|DoBlue|DoGreen;

  g.red = 0; g.green = 0; g.blue = Blue;
  XAllocColor(Disp, DefaultColormap(Disp, 0), &g);
  scol = g.pixel;

  g.red = W; g.green = W; g.blue = W;
  XAllocColor(Disp, DefaultColormap(Disp, 0), &g);
  pcol = g.pixel;

  g.red = B; g.green = B; g.blue = B;
  XAllocColor(Disp, DefaultColormap(Disp, 0), &g);
  fgcol = g.pixel;

  g.red = Gr; g.green = Gr; g.blue = Gr;
  XAllocColor(Disp, DefaultColormap(Disp, 0), &g);
  bgcol = g.pixel;

  g.red = GrL; g.green = GrL; g.blue = GrL;
  XAllocColor(Disp, DefaultColormap(Disp, 0), &g);
  lbgcol = g.pixel;

  g.red = GrD; g.green = GrD; g.blue = GrD;
  XAllocColor(Disp, DefaultColormap(Disp, 0), &g);
  dbgcol = g.pixel;

  g.red = 0; g.green = W; g.blue = 0;
  XAllocColor(Disp, DefaultColormap(Disp, 0), &g);
  greencol = g.pixel;

  g.red = W; g.green = 0; g.blue = 0;
  XAllocColor(Disp, DefaultColormap(Disp, 0), &g);
  redcol = g.pixel;

  g.red = W; g.green = W; g.blue = 0;
  XAllocColor(Disp, DefaultColormap(Disp, 0), &g);
  yellowcol = g.pixel;

  if(bg == NULL) {
    wbgcol = bgcol;
    }

  Root = DefaultRootWindow(Disp);
  if(xsize) {
    bufxs=xsize; bufys=ysize;
    Win = XCreateSimpleWindow(Disp, Root, xpos, ypos, xsize, ysize,
		0, bgcol, wbgcol);
    gc = XCreateGC(Disp, Win, None, None);
    XSetForeground(Disp, gc, wbgcol);
    WinBuf = XCreatePixmap(Disp, Win, bufxs, bufys, DefaultDepth(Disp, 0));
    XFillRectangle(Disp, WinBuf, gc, 0, 0, bufxs, bufys);
    }
  else {
    Win = XCreateSimpleWindow(Disp, Root, xpos, ypos, 320, 240,
		0, bgcol, wbgcol);
    gc = XCreateGC(Disp, Win, None, None);
    }

  if (iwin) {
    Icon = XCreateSimpleWindow(Disp, Root, 0, 0, xsizei, ysizei,
		0, bgcol, wbgcol);
    *iwin = Icon;
    XSelectInput(Disp, Icon, StructureNotifyMask|VisibilityChangeMask);
    wmhints.flags = IconWindowHint;
    wmhints.icon_window = Icon;
    XSetWMHints(Disp,Win,&wmhints);
    useicon=1;
    }
  else Icon = 0;

  cgc = XCreateGC(Disp, Win, None, None);
  XSelectInput(Disp, Win, EVENT_MASK);
  if(xsize) XMapRaised(Disp, Win);
  closeatom = XInternAtom(Disp, "WM_DELETE_WINDOW", 1);
  if(closeatom)  XSetWMProtocols(Disp, Win, (Atom *)&closeatom, 1);
  DispatchHook = NULL;
  DispatchTime = NULL;
  unhandledcallback = NULL;
  clickcallback = NULL;
  dblclickcallback = NULL;
  dragcallback = NULL;
  activitycallback = NULL;
  exposecallback = NULL;
  resizecallback = NULL;
  repositioncallback = NULL;
  keymappingcallback = NULL;
  parent = NULL;
  claim = NULL;
  pdd = NULL;
  fdd = NULL;

  clicktime = 0;

//  int t;
//  char **fns = XListFonts(Disp, "*", -1, &t);
//  int ctr;
//  for(ctr=0; ctr<t; ctr++)  printf("Font(%d): %s\n", ctr+1, fns[ctr]);
  fs = XLoadQueryFont(Disp, "fixed");
  if(fs == NULL)  fs = XLoadQueryFont(Disp, "times-roman");
  if(fs == NULL)  fs = XLoadQueryFont(Disp, "*times-medium-r*");
  XSetFont(Disp, gc, fs->fid);
//  XGCValues gv;
//  printf("Step 1\n");
//  XGetGCValues(Disp, gc, GCFont, &gv);
//  printf("Step 2, gv.font=%d \n", gv.font);
//  fs = XQueryFont(Disp, gv.font);
//  printf("Step 3, fs=%p\n", fs);
  SetTitle(name);
  quit=0;
  }

void IWindow::AddClaim(IDoDad *it, int xp, int yp, int xs, int ys)  {
  PositionClaim *cl = claim;
  for(;cl != NULL && cl->dodad != it; cl = cl->next);
  if(cl == NULL)  {
//    printf("Adding new claim, Type %d\n", it->Type());
    PositionClaim *tmpd = claim;
    claim = new PositionClaim;
    claim->next = tmpd;
    claim->dodad = it;
    cl = claim;
    }
//  else printf("Changing Old claim, Type %d\n", it->Type());
  cl->xp = xp;
  cl->yp = yp;
  cl->xs = xs;
  cl->ys = ys;
//  printf("Added Type %d at (%d,%d), %dx%d.\n", cl->dodad->Type(), xp, yp, xs, ys);
  }

void IWindow::RemoveClaim(IDoDad *it)  {
  if(claim == NULL)  return;
//  printf("Removing %d.\n", it->Type());
  if(claim->dodad == it)  {
    PositionClaim *tmpd = claim;
    claim = claim->next;
    delete tmpd;
    return;
    }
  if(pdd == it) pdd = NULL;
  if(fdd == it) fdd = NULL;
  PositionClaim *tmpd = claim;
  while(tmpd->next != NULL && tmpd->next->dodad != it) tmpd = tmpd->next;
  if(tmpd->next == NULL) return;
  PositionClaim *tmprem = tmpd->next;
  tmpd->next = tmpd->next->next;
  delete tmprem;
  }

void IWindow::DispatchCurrentEvents()  {
  XEvent ev;
  quit=0;
  XFlush(Disp);
  while((!quit)&&(XCheckMaskEvent(Disp, EVENT_MASK|StructureNotifyMask, &ev))) {
//    printf("Got Type = %d\n", ev.type);
    Dispatch(ev);
    if(parent != NULL)  parent->DispatchAutomaticEvents();
    }
  }

void IWindow::DispatchAutomaticEvents()  {
  XEvent ev;
  quit=0;
  XFlush(Disp);
  while((!quit)&&(XCheckMaskEvent(Disp, EVENT_MASK|StructureNotifyMask, &ev))) {
//    printf("Got Type = %d\n", ev.type);
    if(ev.type == Expose) Dispatch(ev);
    if(parent != NULL)  parent->DispatchAutomaticEvents();
    }
  }

void IWindow::RegisterHook(void (*hookfn)(), struct timeval *waittime)  {
  DispatchHook=hookfn;
  DispatchTime=waittime;
  }

void IWindow::DispatchEvents()  {
  XEvent ev;
  struct timeval timeout,*timeptr;
  fd_set readfds;
  quit=0;
  XFlush(Disp);
  while(!quit)  {
    if (DispatchTime==NULL) timeptr=NULL;
    else {
      timeout=*DispatchTime;
      timeptr=&timeout;
      }
    FD_ZERO(&readfds);
    FD_SET(DispFD, &readfds);
    if((select(DispFD+1,&readfds,NULL,NULL,timeptr)>0)||(XQLength(Disp)>0)) {
      do {
        XNextEvent(Disp, &ev);
//        if(Win != ev.xany.window) printf("Got Win = %d/%d\n", ev.xany.window, Win);
        Dispatch(ev);
        if(parent != NULL)  parent->DispatchAutomaticEvents();
        } while(XQLength(Disp)>0);
        XFlush(Disp);
      }
    if(DispatchHook!=NULL) DispatchHook();
    }
  }

void IWindow::Close()  {
  XEvent ev;
  ev.type = ClientMessage;
  ev.xclient.format = 32;
  ev.xclient.data.l[0] = closeatom;
  ev.xany.display = Disp;
  ev.xany.window = Win;
  XSendEvent(Disp, Win, False, NoEventMask, &ev);
  }

void IWindow::Dispatch(XEvent ev)  {
  Time oclicktime = clicktime;

  if((!useicon) && (ev.xany.window==Icon)) return;
  int sendevent = (mapped) ? (ev.xany.window!=Icon) : (ev.xany.window==Icon);
  if(ev.type == ClientMessage && (Atom)(ev.xclient.data.l[0]) == closeatom)
    quit = 1;
  else if(ev.type == ButtonPress) {
    clicktime = ev.xbutton.time;
    if(pdd != NULL)  pdd->Release(0, -1, -1);
    pdd = GetClaim(ev.xbutton.x, ev.xbutton.y);
    if(pdd != NULL)  pdd->Press(ev.xbutton.button,
      ev.xbutton.x-lclaim->xp, ev.xbutton.y-lclaim->yp);
    else {
      TakeFocus(NULL);
      if((clicktime - oclicktime) <= doubleclicktime) {
 	if(dblclickcallback != NULL)
 	  (*dblclickcallback)(this, ev.xbutton.button,
 			      ev.xbutton.x, ev.xbutton.y);
        }
      else {
	if(clickcallback != NULL)
	  (*clickcallback)(this, ev.xbutton.button, 
			   ev.xbutton.x, ev.xbutton.y);
        }
      }
    }
  else if(ev.type == ButtonRelease) {
    IDoDad *tmpd = GetClaim(ev.xbutton.x, ev.xbutton.y);
    if(tmpd != NULL && tmpd == pdd)  pdd->Release(ev.xbutton.button,
      ev.xbutton.x-lclaim->xp, ev.xbutton.y-lclaim->yp);
    else if(pdd != NULL)  pdd->Release(0, -1, -1);
    else if(releasecallback != NULL)
      (*releasecallback)(this, ev.xbutton.button, 
			 ev.xbutton.x, ev.xbutton.y);
    pdd = NULL;
    if(activitycallback != NULL) {
      (*activitycallback)(this);
      }
    }
  else if(ev.type == MotionNotify) {
    while(XCheckMaskEvent(Disp, PointerMotionMask, &ev));
    if(pdd != NULL)  pdd->Drag(
	      ev.xmotion.x-lclaim->xp, ev.xmotion.y-lclaim->yp);
    if(ev.xmotion.state != 0 && dragcallback != NULL) {
      (*dragcallback)(this, ev.xbutton.state, ev.xbutton.x, ev.xbutton.y);
      }
    if(activitycallback != NULL) {
      (*activitycallback)(this);
      }
    }
  else if(ev.type == Expose) {
    if(claim != NULL)  RevRedraw(claim);
    if(exposecallback != NULL)
	(*exposecallback)(this);
    }
  else if(ev.type == ConfigureNotify) {
    int xp, yp;  Window child; int *xptr, *yptr;
    XTranslateCoordinates(Disp,ev.xany.window,Root,0,0,&xp,&yp,&child);
    int x = ev.xconfigure.width, y = ev.xconfigure.height;
    xptr = (ev.xany.window==Icon) ? &xsizei : &xsize;
    yptr = (ev.xany.window==Icon) ? &ysizei : &ysize;
    if(x != *yptr || y != *yptr)  {
      *xptr = x; *yptr = y;
      if(sendevent && resizecallback != NULL)
	(*resizecallback)(this, x, y);
      if(ev.xany.window!=Icon && claim != NULL)  RevRedraw(claim);
      }
    xptr = (ev.xany.window==Icon) ? &xposi : &xpos;
    yptr = (ev.xany.window==Icon) ? &yposi : &ypos;
    if(xp != *yptr || yp != *yptr)  {
      *xptr = xp; *yptr = yp;
      if(sendevent && repositioncallback != NULL)
	(*repositioncallback)(this, xp, yp);
      if(ev.xany.window!=Icon && claim != NULL)  RevRedraw(claim);
      }
    }
  else if(ev.type == KeyPress) {
    if(fdd == NULL || !fdd->KeyDown(ev.xkey)) {
      if(unhandledcallback != NULL) {
	(*unhandledcallback)(this, &ev);
	}
      }
    if(activitycallback != NULL) {
      (*activitycallback)(this);
      }
    }
  else if(ev.type == MapNotify || ev.type == UnmapNotify) {
    if(ev.xany.window!=Icon) {
      mapped = (ev.type==MapNotify);
      }
    sendevent = (mapped) ? (ev.xany.window!=Icon) : (ev.xany.window==Icon) ;
    if(!useicon) sendevent=1;
    if(sendevent && unhandledcallback != NULL) {
      (*unhandledcallback)(this, &ev);
      }
    if(activitycallback != NULL) {
      (*activitycallback)(this);
      }
    }
  else if(ev.type == MappingNotify) {
    if(keymappingcallback != NULL)
      (*keymappingcallback)(this, &ev);
    }
  else if(sendevent && unhandledcallback != NULL) {
	(*unhandledcallback)(this, &ev);
    }
  }

IDoDad *IWindow::GetClaim(int x, int y)  {
  if(claim == NULL)  return NULL;
  if(claim->xp <= x && claim->yp <= y
	&& (claim->xp+claim->xs) > x
	&& (claim->yp+claim->ys) > y
	&& (!claim->dodad->Hidden())) {
    lclaim = claim;
    return claim->dodad;
    }
  PositionClaim *tmpd = claim;
  while(tmpd->next != NULL && !(tmpd->next->xp <= x && tmpd->next->yp <= y
	&& (tmpd->next->xp+tmpd->next->xs) > x
	&& (tmpd->next->yp+tmpd->next->ys) > y
	&& (!tmpd->next->dodad->Hidden()))) tmpd = tmpd->next;
  if(tmpd->next == NULL)  return NULL;
  lclaim = tmpd->next;
  return tmpd->next->dodad;
  }

void IWindow::RevRedraw(PositionClaim *it)  {
  RevRedraw(it, -1, -1, -1, -1);
  }

void IWindow::RevRedraw(PositionClaim *it, int x, int y, int xs, int ys)  {
  if(it==NULL) return;
  if(it->next != NULL)  RevRedraw(it->next, x, y, xs, ys);
  if(!it->dodad->Hidden()) {
    if(xs<0) it->dodad->Redraw();
    else if(it->xp < (x+xs) && it->yp < (y+ys)
		&& x < (it->xp+it->xs) && y < (it->yp+it->ys)) {
      it->dodad->Redraw();
      }
    }
  }

void IWindow::TakeFocus(IDoDad *it)  {
  IDoDad *ofdd = fdd;
  fdd = it;
  if(ofdd != NULL)  ofdd->LostFocus();
  if(fdd != NULL)  fdd->GotFocus();
  }

void IWindow::SetTitle(char *tit)  {
  XTextProperty tp;
  tp.value = (unsigned char *)tit;
  tp.encoding = XA_WM_NAME;
  tp.format = 8;
  tp.nitems = strlen(tit);
  XSetWMName(Disp, Win, &tp);
  XStoreName(Disp, Win, tit);
  XSetIconName(Disp, Win, tit);
  XSetWMIconName(Disp, Win, &tp);
  }

unsigned int IWindow::GetRGBColor(int r, int g, int b)  {
  r<<=8; g<<=8; b<<=8;
  XColor C;
  C.flags = DoRed|DoBlue|DoGreen;

  C.red = r; C.green = g; C.blue = b;
  XAllocColor(Disp, DefaultColormap(Disp, 0), &C);
  return(C.pixel);
  }

void IWindow::SetActivityCallback(void (*cb)(IWindow *))  {
  activitycallback = cb;
  if(activitycallback != NULL)
    (*activitycallback)(this);
  }

void IWindow::SetExposeCallback(void (*cb)(IWindow *))  {
  exposecallback = cb;
  if(exposecallback != NULL)
    (*exposecallback)(this);
  }

void IWindow::SetResizeCallback(void (*cb)(IWindow *, int, int))  {
  resizecallback = cb;
  if(resizecallback != NULL)
    (*resizecallback)(this, xsize, ysize);
  }

void IWindow::SetRepositionCallback(void (*cb)(IWindow *, int, int))  {
  repositioncallback = cb;
  if(repositioncallback != NULL)
    (*repositioncallback)(this, xsize, ysize);
  }

void IWindow::SetUnhandledCallback(void (*cb)(IWindow *, XEvent *))  {
  unhandledcallback = cb;
  }

void IWindow::SetClickCallback(void (*cb)(IWindow *, int, int, int))  {
  clickcallback = cb;
  }

void IWindow::SetDblClickCallback(void (*cb)(IWindow *, int, int, int))  {
  dblclickcallback = cb;
  }

void IWindow::SetReleaseCallback(void (*cb)(IWindow *, int, int, int))  {
  releasecallback = cb;
  }

void IWindow::SetDragCallback(void (*cb)(IWindow *, int, int, int))  {
  dragcallback = cb;
  }

void IWindow::SetKeyMappingCallback(void (*cb)(IWindow *, XEvent *)) {
  keymappingcallback = cb;
  }

void IWindow::Resize(int x, int y)  {
  XResizeWindow(Disp, Win, x, y);
  }

void IWindow::Map(int x, int y)  {
  Resize(x, y);
  if(bufxs<=0) bufxs=x;
  if(bufys<=0) bufys=y;
  if(WinBuf==0) {
    XSetForeground(Disp, gc, wbgcol);
    WinBuf = XCreatePixmap(Disp, Win, bufxs, bufys, DefaultDepth(Disp, 0));
    XFillRectangle(Disp, WinBuf, gc, 0, 0, bufxs, bufys);
    }
  Map();
  }

void IWindow::SetBufSize(int x, int y) {
  bufxs=x; bufys=y;
  }

void IWindow::Map()  {
  XMapRaised(Disp, Win);
  }

void IWindow::Redraw(int x, int y, int xs, int ys)  {
//  XClearArea(Disp, Win, x, y, xs<?(bufxs-x), ys<?(bufys-y), False);
  XCopyArea(Disp, WinBuf, Win, gc, x, y, xs<?(bufxs-x), ys<?(bufys-y), x, y);
  }

void IWindow::Redraw()  {
  XClearWindow(Disp, Win);
  XCopyArea(Disp, WinBuf, Win, gc, 0, 0, xsize<?bufxs, ysize<?bufys, 0, 0);
  }

void IWindow::Rebuild(int x, int y, int xs, int ys)  {
//  XClearWindow(Disp, Win);
  XSetForeground(Disp, gc, wbgcol);
  XFillRectangle(Disp, WinBuf, gc, x, y, xs, ys);
  RevRedraw(claim, x, y, xs, ys);
  XCopyArea(Disp, WinBuf, Win, gc, x, y, xs, ys, x, y);
  }

void IWindow::Rebuild()  {
//  XClearWindow(Disp, Win);
  XSetForeground(Disp, gc, wbgcol);
  XFillRectangle(Disp, WinBuf, gc, 0, 0, xsize, ysize);
  RevRedraw(claim);
  XCopyArea(Disp, WinBuf, Win, gc, 0, 0, xsize, ysize, 0, 0);
  }

int IWindow::XDeskSize() {
  XWindowAttributes wa;
  XGetWindowAttributes(Disp, Root, &wa);
  return wa.width;
  }

int IWindow::YDeskSize() {
  XWindowAttributes wa;
  XGetWindowAttributes(Disp, Root, &wa);
  return wa.height;
  }

void IWindow::LoadConfig() {
  appearance = IBTK_DEFAULT;
  doubleclicktime = 200;
  FILE *cfg = fopen(CONFIGFILE, "r");
  if(cfg!=NULL) {
    char buf[256], *ln;
    ln = fgets(buf, 256, cfg);
    while(ln != NULL) {
      if(!strncasecmp(ln, "appearance", 10)) {
	while(*ln != '=' && *ln != '\n' && *ln != 0) ++ln;
	if(*ln != '\n' && *ln != 0) ++ln;
	while(*ln == ' ' || *ln == '\t') ++ln;
	if(*ln != '\n' && *ln != 0)  {
	  if(!strncasecmp(ln, "default", 7))
	    appearance=IBTK_DEFAULT;
	  else if(!strncasecmp(ln, "step", 4))
	    appearance=IBTK_STEP;
	  }
	}
      else if(!strncasecmp(ln, "doubleclicktime", 10)) {
	while(*ln != '=' && *ln != '\n' && *ln != 0) ++ln;
	if(*ln != '\n' && *ln != 0) ++ln;
	while(*ln == ' ' || *ln == '\t') ++ln;
	if(*ln != '\n' && *ln != 0) {
	  doubleclicktime = strtol(ln, NULL, 10);
	  }  
        }
      ln = fgets(buf, 256, cfg);
      }
    fclose(cfg);
    }
  switch(appearance) {
    case(IBTK_DEFAULT): {
      Blue = 255<<8;
      Red = 255<<8;
      Green = 255<<8;
      }break;
    case(IBTK_STEP): {
      Blue = 128<<8;
      Red = 128<<8;
      Green = 128<<8;
      }break;
    }
  }

void IWindow::RebuildClip() {
  int ctrx, ctry, n=0, ctr=0, m=0;
  XRectangle *rec;
  for(ctry=5; ctry<ysize; ctry+=10) {
    for(ctrx=5; ctrx<xsize; ctrx+=10) {
      if(GetClaim(ctrx, ctry)==NULL) {
	++m;
	}
      else if(m>0) { ++n; m=0; }
      }
    if(m>0) { ++n; m=0; }
    }
  rec = new XRectangle[n]; m=0;
  for(ctry=5; ctry<ysize; ctry+=10) {
    for(ctrx=5; ctrx<xsize; ctrx+=10) {
      if(GetClaim(ctrx, ctry)==NULL) {
	++m;
	}
      else if(m>0) {
	rec[ctr].x = ctrx-(5+(10*m));
	rec[ctr].y = ctry-5;
	rec[ctr].width = 10*m;
	rec[ctr].height = 10;
	++ctr; m=0;
	}
      }
    if(m>0) {
      rec[ctr].x = ctrx-(5+(10*m));
      rec[ctr].y = ctry-5;
      rec[ctr].width = 10*m;
      rec[ctr].height = 10;
      ++ctr; m=0; 
      }
    }
  XSetClipRectangles(Disp, cgc, 0, 0, rec, n, YXBanded);
  }
