/*
 * xvcolor.c - color allocation/sorting/freeing code
 *
 *  Author:    John Bradley, University of Pennsylvania
 *                (bradley@cis.upenn.edu)
 *
 *  Contains:
 *     void   SortColormap()
 *     void   AllocColors()
 *     void   AllocRWColors()
 *     Status xvAllocColor()
 *     void   xvFreeColors()
 *     void   FreeAllColors()
 *     void   ApplyEditColor();
 */


/*
 * Copyright 1989, 1990, 1991, 1992 by John Bradley and
 *                       The University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation. 
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any expressed or implied warranty.
 *
 * The author may be contacted via:
 *    US Mail:   John Bradley
 *               GRASP Lab, Room 301C
 *               3401 Walnut St.  
 *               Philadelphia, PA  19104
 *
 *    Phone:     (215) 898-8813
 *    EMail:     bradley@cis.upenn.edu       
 */


#include "xv.h"

static void putECfirst();

/************************************************/
/* structure and routine used in SortColormap() */
/************************************************/

typedef struct thing {
  byte r,g,b, n;          /* actual value of color + alignment */
  int oldindex;           /* its index in the old colormap */
  int use;                /* # of pixels of this color */
  int mindist;            /* min distance to a selected color */
} CMAPENT;



/***********************************/
void SortColormap()
{
  byte *p;
  int   i, j, mdist, entry, d, hist[256], trans[256];
  static CMAPENT c[256], c1[256], *cp, *cj, *ck;


  /* init some stuff */
  for (i=0; i<256; i++) { colAllocOrder[i]=i;  cols[i] = infobg; }

  /* initialize histogram and compute it */
  for (i=0; i<256; i++) hist[i]=0;
  for (i=pWIDE*pHIGH, p=pic; i; i--, p++) hist[*p]++;
  
  if (DEBUG>1) {
    fprintf(stderr,"%s: Desired colormap\n",cmd);
    for (i=0; i<256; i++) 
      if (hist[i]) fprintf(stderr,"(%3d  %02x,%02x,%02x %d)\n",
			   i,r[i],g[i],b[i], hist[i]);
    fprintf(stderr,"\n\n");
  }
  
  
  /* put the actually-used colors into the 'c' array in the order they occur
     also, while we're at it, calculate numcols, and close up gaps in
     colortable */

  for (i=numcols=0; i<256; i++) {
    if (hist[i]) { 
      r[numcols] = r[i];
      g[numcols] = g[i];
      b[numcols] = b[i];
      trans[i] = numcols;

      cp = &c[numcols];
      cp->r = r[i];  cp->g = g[i];  cp->b = b[i];
      cp->use = hist[i];  cp->oldindex = numcols;
      cp->mindist = 200000; /* 255^2 * 3 = 195075 */
      numcols++;
    }
  }


  /* modify 'pic' to reflect new (compressed, but not reordered) colormap */
  for (i=pWIDE*pHIGH, p=pic; i; i--, p++) { j = trans[*p];  *p = j; }
  

  /* find most-used color, put that in c1[0] */
  entry = -1;  mdist = -1;
  for (i=0; i<numcols; i++) {
    if (c[i].use > mdist) { mdist = c[i].use;  entry=i; }
  }
  memcpy(&c1[0], &c[entry], sizeof(CMAPENT));
  c[entry].use = 0;   /* and mark it dealt with */
  
  
  /* sort rest of colormap.  Half of the entries are allocated on the
     basis of distance from already allocated colors, and half on the
     basis of usage.  (NB: 'taxicab' distance is used throughout this file.)

     Mod:  pick first 10 colors based on maximum distance.  pick remaining
     colors half by distance and half by usage   -- JHB

     To obtain O(n^2) performance, we keep each unselected color
     (in c[], with use>0) marked with the minimum distance to any of
     the selected colors (in c1[]).  Each time we select a color, we
     can update the minimum distances in O(n) time. 

     mod by Tom Lane   Tom.Lane@g.gp.cs.cmu.edu */

  for (i=1; i<numcols; i++) {
    int ckR, ckG, ckB;
    /* Get RGB of color last selected  and choose selection method */
    ck = &c1[i-1];            /* point to just-selected color */
    ckR = ck->r; ckG = ck->g; ckB = ck->b;

    if (i&1 || i<10) {
      /* Now find the i'th most different color */
      /* we want to select the unused color that has the greatest mindist */
      entry = -1;  mdist = -1;
      for (j=0, cj=c; j<numcols; j++,cj++) {
	if (cj->use) {      /* this color has not been marked already */
	  /* update mindist */
          d = (cj->r - ckR)*(cj->r - ckR) + (cj->g - ckG)*(cj->g - ckG) + 
		(cj->b - ckB)*(cj->b - ckB);
          if (cj->mindist > d) cj->mindist = d;

	  if (cj->mindist > mdist) { mdist = cj->mindist;  entry = j; }
	}
      }
    }
    else {
      /* Now find the i'th most different color */
      /* we want to select the unused color that has the greatest usage */
      entry = -1;  mdist = -1;
      for (j=0, cj=c; j<numcols; j++,cj++) {
	if (cj->use) {  /* this color has not been marked already */
	  /* update mindist */
          d = (cj->r - ckR)*(cj->r - ckR) + (cj->g - ckG)*(cj->g - ckG) + 
    		(cj->b - ckB)*(cj->b - ckB);
          if (cj->mindist > d) cj->mindist = d;

	  if (cj->use > mdist) { mdist = cj->use;  entry = j; }
	}
      }
    }


    /* c[entry] is the next color to put in the map.  do so */
    memcpy(&c1[i], &c[entry], sizeof(CMAPENT));
    c[entry].use = 0;
  }
  

  for (i=0; i<numcols; i++)
    colAllocOrder[i] = c1[i].oldindex;

  if (DEBUG>1) {
    fprintf(stderr,"%s: result of sorting colormap\n",cmd);
    for (i=0; i<numcols; i++) 
      fprintf(stderr,"(%3d  %02x,%02x,%02x)     ",i,r[i],g[i],b[i]);
    fprintf(stderr,"\n\n");
    
    fprintf(stderr,"%s: allocation order table\n",cmd);
    for (i=0; i<numcols; i++) 
      fprintf(stderr,"colAllocOrder[%d] = -> %d\n",i,colAllocOrder[i]);
    fprintf(stderr,"\n");
  }
}



#define NOPIX 0xffffffff    

/***********************************/
void AllocColors()
{
  int      i, j, c, unique, p2alloc, p3alloc;
  Colormap cmap;
  XColor   defs[256];
  XColor   ctab[256];
  int      dc;


  nfcols = unique = p2alloc = p3alloc = 0;
  rwthistime = 0;

  if (ncols == 0) {
    SetISTR(ISTR_COLOR,"Dithering with 'black' & 'white'.");
    SetISTR(ISTR_COLOR2,"");
    RedrawCMap();
    return;
  }


  /* FIRST PASS COLOR ALLOCATION:  
     for each color in the 'desired colormap', try to get it via
     xvAllocColor().  If for any reason it fails, mark that pixel
     'unallocated' and worry about it later.  Repeat. */

  /* attempt to allocate first ncols entries in colormap 
     note: On displays with less than 8 bits per RGB gun, it's quite
     possible that different colors in the original picture will be
     mapped to the same color on the screen.  X does this for you
     silently.  However, this is not-desirable for this application, 
     because when I say 'allocate me 32 colors' I want it to allocate
     32 different colors, not 32 instances of the same 4 shades... */
  
  for (i=0; i<256; i++) cols[i] = NOPIX;

  cmap = theCmap;
  for (i=0; i<numcols && unique<ncols; i++) {
    c = colAllocOrder[i];
    if (mono) { 
      int intens = MONO(r[c], g[c], b[c]);
      defs[c].red = defs[c].green = defs[c].blue = intens<<8;
    }
    else {
      defs[c].red   = r[c]<<8;
      defs[c].green = g[c]<<8;
      defs[c].blue  = b[c]<<8;
    }

    defs[c].flags = DoRed | DoGreen | DoBlue;

    if (!(owncmap && cmap==theCmap) && xvAllocColor(theDisp,cmap,&defs[c])) { 
      unsigned long pixel, *fcptr;

      pixel = cols[c] = defs[c].pixel;
      rdisp[c] = defs[c].red   >> 8;
      gdisp[c] = defs[c].green >> 8;
      bdisp[c] = defs[c].blue  >> 8;
      
      /* see if the newly allocated color is new and different */
      for (j=0, fcptr=freecols; j<nfcols && *fcptr!=pixel; j++,fcptr++);
      if (j==nfcols) unique++;

      fc2pcol[nfcols] = c;
      freecols[nfcols++] = pixel;
    }

    else {
      /* the allocation failed.  If we want 'perfect' color, and we haven't 
	 already created our own colormap, we'll want to do so */
      if (perfect && !LocalCmap) {
	LocalCmap = XCreateColormap(theDisp, vrootW, theVisual, AllocNone);
	
	if (LocalCmap) {  /* succeeded, presumably */
	  /* free all colors that were allocated, and try again with the
	     new colormap.  This is necessary because 'XCopyColormapAndFree()'
	     has the unpleasant side effect of freeing up the various
	     colors I need for the control panel, etc. */

	  for (i=0; i<nfcols; i++) 
	    xvFreeColors(theDisp, theCmap, &freecols[i], 1, 0L);
	  
	  if (mainW && !useroot) XSetWindowColormap(theDisp,mainW, LocalCmap);
	  if (mainW && !useroot && cmapInGam) 
	    XSetWindowColormap(theDisp,gamW, LocalCmap);
	  cmap = LocalCmap;

	  /* redo ALL allocation requests */
	  for (i=0; i<256; i++) cols[i] = NOPIX;
	  nfcols = unique = 0;
	  i = -1;
	}
      }

      else {
	/* either we don't care about perfect color, or we do care, have
	   allocated our own colormap, and have STILL run out of colors
	   (possible, even on an 8 bit display), just mark pixel as
	   unallocated.  We'll deal with it later */
	cols[c] = NOPIX;
      }
    }
  }  /* FIRST PASS */
  
  
  
  if (nfcols==numcols) {
    if (numcols != unique)
      SetISTR(ISTR_COLOR,"Got all %d desired colors.  (%d unique)", numcols,
	      unique);
    else
      SetISTR(ISTR_COLOR,"Got all %d desired colors.", numcols);

    SetISTR(ISTR_COLOR2,"");
    RedrawCMap();
    return;
  }
  


  /* SECOND PASS COLOR ALLOCATION:
     Allocating 'exact' colors failed.  Now try to allocate 'closest'
     colors.

     Read entire X colormap (or first 256 entries) in from display.
     for each unallocated pixel, find the closest color that actually
     is in the X colormap.  Try to allocate that color (read only).
     If that fails, the THIRD PASS will deal with it */

  SetISTR(ISTR_COLOR,"Got %d out of %d colors.  (%d unique)", 
	  nfcols,numcols,unique);


  /* read entire colormap (or first 256 entries) into 'ctab' */
  dc = (ncells<256) ? ncells : 256;
  for (i=0; i<dc; i++) ctab[i].pixel = (unsigned long) i;
  XQueryColors(theDisp, cmap, ctab, dc);

  for (i=0; i<numcols && unique<ncols; i++) {
    c = colAllocOrder[i];

    if (cols[c]==NOPIX) {  /* an unallocated pixel */
      int           d, mdist, close;
      unsigned long ri,gi,bi;

      mdist = 100000;   close = -1;
      ri = r[c];  gi = g[c];  bi = b[c];
      
      for (j=0; j<dc; j++) {
	d = abs(ri - (ctab[j].red>>8)) +
	    abs(gi - (ctab[j].green>>8)) +
	    abs(bi - (ctab[j].blue>>8));
	if (d<mdist) { mdist=d; close=j; }
      }

      if (close<0) FatalError("This Can't Happen! (How reassuring.)");
      if (xvAllocColor(theDisp, cmap, &ctab[close])) { 
	memcpy(&defs[c], &ctab[close], sizeof(XColor));
	cols[c]  = ctab[close].pixel;
	rdisp[c] = ctab[close].red   >> 8;
	gdisp[c] = ctab[close].green >> 8;
	bdisp[c] = ctab[close].blue  >> 8;
	fc2pcol[nfcols] = c;
	freecols[nfcols++] = cols[c];
	p2alloc++;
	unique++;
      }
    }
  }



  /* THIRD PASS COLOR ALLOCATION:
     We've alloc'ed all the colors we can.  Now, we have to map any
     remaining unalloced pixels into either A) the colors that we DID get
     (noglob), or B) the colors found in the X colormap */

  for (i=0; i<numcols; i++) {
    c = colAllocOrder[i];

    if (cols[c] == NOPIX) {  /* an unallocated pixel */
      int           d, k, mdist, close;
      unsigned long ri,gi,bi;

      mdist = 100000;   close = -1;
      ri = r[c];  gi = g[c];  bi = b[c];
      
      if (!noglob) {   /* search the entire X colormap */
	for (j=0; j<dc; j++) {
	  d = abs(ri - (ctab[j].red>>8)) +
	      abs(gi - (ctab[j].green>>8)) +
	      abs(bi - (ctab[j].blue>>8));
	  if (d<mdist) { mdist=d; close=j; }
	}
	if (close<0) FatalError("This Can't Happen! (How reassuring.)");
	memcpy(&defs[c], &ctab[close], sizeof(XColor));
	cols[c]  = defs[c].pixel;
	rdisp[c] = defs[c].red   >> 8;
	gdisp[c] = defs[c].green >> 8;
	bdisp[c] = defs[c].blue  >> 8;
	p3alloc++;
      }

      else {                     /* only search the alloc'd colors */
	for (j=0; j<nfcols; j++) {
	  k = fc2pcol[j];
	  d = abs(ri - (defs[k].red>>8)) +
	      abs(gi - (defs[k].green>>8)) +
	      abs(bi - (defs[k].blue>>8));
	  if (d<mdist) { mdist=d;  close=k; }
	}

	if (close<0) FatalError("This Can't Happen! (How reassuring.)");
	memcpy(&defs[c], &defs[close], sizeof(XColor));
	cols[c]  = defs[c].pixel;
	rdisp[c] = defs[c].red   >> 8;
	gdisp[c] = defs[c].green >> 8;
	bdisp[c] = defs[c].blue  >> 8;
      }
    }
  }  /* THIRD PASS */



  if (p2alloc && p3alloc)
    SetISTR(ISTR_COLOR2,"Got %d 'close' color%s.  'Borrowed' %d color%s.",
	    p2alloc, (p2alloc>1) ? "s" : "", 
	    p3alloc, (p3alloc>1) ? "s" : "");

  else if (p2alloc && !p3alloc) 
    SetISTR(ISTR_COLOR2,"Got %d 'close' color%s.",
	    p2alloc, (p2alloc>1) ? "s" : "");

  else if (!p2alloc && p3alloc) 
    SetISTR(ISTR_COLOR2,"'Borrowed' %d color%s.",
	    p3alloc, (p3alloc>1) ? "s" : "");

  RedrawCMap();
}



/***********************************/
void AllocRWColors()
{
  int i,j,c;
  Colormap cmap;
  XColor   defs[256];

  nfcols = 0;   rwthistime = 1;

  if (ncols == 0) {
    SetISTR(ISTR_COLOR,"Dithering with 'black' & 'white'.");
    SetISTR(ISTR_COLOR2,"");
    rwthistime = 0;
    RedrawCMap();
    return;
  }


  cmap = theCmap;

  for (i=0; i<numcols; i++) cols[colAllocOrder[i]] = NOPIX;

  for (i=0; i<numcols && i<ncols; i++) {
    unsigned long pmr[1], pix[1];
    c = colAllocOrder[i];

    if (cellgroup[c]) {  
      int n;
      /* this color is part of a group.  see if its group's
	 been seen already, and if so, skip this */
      for (n=0; n<i && cellgroup[c] != cellgroup[colAllocOrder[n]]; n++);
      if (n<i) {  /* found one */
	cols[c] = cols[colAllocOrder[n]];
	rwpc2pc[c] = colAllocOrder[n];
	continue;
      }
    }

    if (!(owncmap && cmap==theCmap) && 
	XAllocColorCells(theDisp, cmap, False, pmr, 0, pix, 1)) {
      defs[c].pixel = cols[c] = pix[0];
      if (mono) { 
	int intens = MONO(r[c], g[c], b[c]);
	defs[c].red = defs[c].green = defs[c].blue = intens<<8;
      }
      else {
	defs[c].red   = r[c]<<8;
	defs[c].green = g[c]<<8;
	defs[c].blue  = b[c]<<8;
      }

      defs[c].flags = DoRed | DoGreen | DoBlue;
      rdisp[c] = r[c];
      gdisp[c] = g[c];
      bdisp[c] = b[c];

      fc2pcol[nfcols]    = c;
      rwpc2pc[c]         = c;
      freecols[nfcols++] = pix[0];
    }

    else {
      if (perfect && !LocalCmap) {
	LocalCmap = XCreateColormap(theDisp, vrootW, theVisual, AllocNone);
	
	/* free all colors that were allocated, and try again with the
	   new colormap.  This is necessary because 'XCopyColormapAndFree()'
	   has the unpleasant side effect of freeing up the various
	   colors I need for the control panel, etc. */

	for (i=0; i<nfcols; i++) 
	  xvFreeColors(theDisp, theCmap, &freecols[i], 1, 0L);
	
	if (mainW && !useroot) XSetWindowColormap(theDisp,mainW, LocalCmap);
	if (mainW && !useroot && cmapInGam) 
	  XSetWindowColormap(theDisp,gamW, LocalCmap);
	cmap = LocalCmap;

	/* redo ALL allocation requests */
	for (i=0; i<numcols; i++) cols[colAllocOrder[i]] = NOPIX;
	nfcols = 0;
	i = -1;
      }

      else cols[c] = NOPIX;
    }
  }  /* for (i=0; ... */



  if (nfcols==numcols) {
    SetISTR(ISTR_COLOR,"Got all %d desired colors.", numcols);
    SetISTR(ISTR_COLOR2,"");
  }

  else {
    /* Failed to allocate all colors in picture.  Map remaining desired 
       colors into closest allocated desired colors */

      if (nfcols==0) {
	char tstr[128], *tmp,
	    *foo = "No r/w cells available.  Using r/o color.";

	tmp = GetISTR(ISTR_WARNING);
	if (strlen(tmp)>0) sprintf(tstr, "%s  %s", tmp, foo);
	else sprintf(tstr, "%s", foo);
	SetISTR(ISTR_WARNING,tstr);

	AllocColors();
	return;
      }
	
      SetISTR(ISTR_COLOR,"Got %d out of %d colors.",  nfcols,numcols);

      for (i=0; i<numcols; i++) {
	c = colAllocOrder[i];
	if (cols[c]==NOPIX) {  /* an unallocated pixel */
	  int           k, d, mdist, close;
	  unsigned long ri,gi,bi;

	  mdist = 100000;   close = -1;
	  ri = r[c];  gi = g[c];  bi = b[c];

	  for (j=0; j<nfcols; j++) {
	    k = fc2pcol[j];
	    d = abs(ri - (defs[k].red>>8)) + abs(gi - (defs[k].green>>8)) +
	        abs(bi - (defs[k].blue>>8));
	    if (d<mdist) { mdist=d; close=k; }
	  }

	  if (close<0) FatalError("This Can't Happen! (How reassuring.)");
	  memcpy(&defs[c], &defs[close], sizeof(XColor));
	  cols[c]  = defs[c].pixel;
	  rdisp[c] = defs[c].red   >> 8;
	  gdisp[c] = defs[c].green >> 8;
	  bdisp[c] = defs[c].blue  >> 8;
	  rwpc2pc[c] = close;
	}
      }
    }

  /* load up the allocated colorcells */
  for (i=0; i<nfcols; i++) {
    j = fc2pcol[i];
    defs[j].pixel = freecols[i];
    defs[j].red   = r[j]<<8;
    defs[j].green = g[j]<<8;
    defs[j].blue  = b[j]<<8;
    defs[j].flags = DoRed | DoGreen | DoBlue;
    XStoreColor(theDisp, cmap, &defs[j]);
  }

  /* XStoreColors(theDisp, cmap, defs, nfcols); */
  RedrawCMap();
}





/*******************************************************/
/* 24/32-bit TrueColor display color 'allocation' code */
/*******************************************************/

static int highbit(ul)
unsigned long ul;
{
  /* returns position of highest set bit in 'ul' as an integer (0-31),
   or -1 if none */

  int i;
  for (i=31; ((ul&0x80000000) == 0) && i>=0;  i--, ul<<=1);
  return i;
}


Status xvAllocColor(dp, cm, cdef)
Display *dp;
Colormap cm;
XColor *cdef;
{
  if (theVisual->class == TrueColor || theVisual->class == DirectColor) {
    unsigned long r, g, b, rmask, gmask, bmask;
    int rshift, gshift, bshift;

    /* shift r,g,b so that high bit of 16-bit color specification is 
     * aligned with high bit of r,g,b-mask in visual, 
     * AND each component with its mask,
     * and OR the three components together
     */

    r = cdef->red;  g = cdef->green;  b = cdef->blue;

    rmask = theVisual->red_mask;
    gmask = theVisual->green_mask;
    bmask = theVisual->blue_mask;

    rshift = 15 - highbit(rmask);
    gshift = 15 - highbit(gmask);
    bshift = 15 - highbit(bmask);

    /* shift the bits around */
    if (rshift<0) r = r << (-rshift);
             else r = r >> rshift;

    if (gshift<0) g = g << (-gshift);
             else g = g >> gshift;

    if (bshift<0) b = b << (-bshift);
             else b = b >> bshift;


    r = r & rmask;
    g = g & gmask;
    b = b & bmask;

    cdef->pixel = r | g | b;

    if (DEBUG > 1) 
      fprintf(stderr,
	      "xvAlloc: col=%04x,%04x,%04x  mask=%04x,%04x,%04x  pix=%08x\n",
	      cdef->red, cdef->green, cdef->blue, rmask, gmask, bmask, 
	      cdef->pixel);
  
    return 1;
  }
  else {
    return (XAllocColor(dp,cm,cdef));
  }
}

void xvFreeColors(dp, cm,pixels, npixels, planes)
Display *dp;
Colormap cm;
unsigned long pixels[];
int npixels;
unsigned long planes;
{
  if (theVisual->class != TrueColor && theVisual->class != DirectColor)
    XFreeColors(dp, cm, pixels, npixels, planes);
}





/********************************/
void FreeAllColors()
{
  int i;

#ifdef FOO
  if (useroot && resetroot && (theVisual->class == PseudoColor || 
			       theVisual->class == GrayScale))
    ClearRoot();
#endif

  if (LocalCmap) {
    if (mainW && mainW != vrootW) XClearWindow(theDisp,mainW);
    XFreeColormap(theDisp,LocalCmap);
    LocalCmap = 0;
  }

  else {
    for (i=0; i<nfcols; i++) 
      xvFreeColors(theDisp, theCmap, &freecols[i], 1, 0L);

    XFlush(theDisp);  /* just to make sure they're all freed right now... */
  }
}


/********************************/
void ApplyEditColor(regroup)
int regroup;
{
  int i, j;

  /* if regroup is set, we *must* do a full realloc, as the cols[] array 
     isn't correct anymore.  (cell groupings changed) */

  ApplyECctrls();  /* set {r,g,b}cmap[editColor] based on dial settings */
  Gammify1(editColor);

  if (curgroup) {  /* do the same to all its friends */
    for (i=0; i<numcols; i++) {
      if (cellgroup[i] == curgroup) {
	rcmap[i] = rcmap[editColor];
	gcmap[i] = gcmap[editColor];
	bcmap[i] = bcmap[editColor];
	r[i]     = r[editColor];
	g[i]     = g[editColor];
	b[i]     = b[editColor];
      }
    }
  }

    
  /* do something clever if we're using R/W color and this colorcell isn't
     shared */

  if (!regroup && rwcolor && rwthistime) {   /* let's try to be clever */
    /* determine if the editColor cell is unique, or shared (among 
       non-group members, that is) */

    for (i=j=0; i<numcols; i++) 
      if (rwpc2pc[i] == rwpc2pc[editColor]) j++;

    /* if this is a group, subtract off the non-this-one pixels from group */
    if (curgroup) {
      for (i=0; i<numcols; i++) {
	if (cellgroup[i] == curgroup && i!=editColor) j--;
      }
    }

    if (j==1) {  /* we can be way cool about this one */
      XColor ctab;
      ctab.pixel = cols[editColor];
      if (mono) {
	int intens = MONO(r[editColor], g[editColor], b[editColor]);
	ctab.red = ctab.green = ctab.blue = intens<<8;
      }
      else {
	ctab.red   = r[editColor]<<8;
	ctab.green = g[editColor]<<8;
	ctab.blue  = b[editColor]<<8;
      }
      ctab.flags = DoRed | DoGreen | DoBlue;
      XStoreColor(theDisp, LocalCmap ? LocalCmap : theCmap, &ctab);
      return;
    }
  }

  /* either we aren't using R/W color, or we are, but this particular color
     cell isn't mapped a unique X colorcell.  Either way... */

  FreeAllColors();

#ifdef FOO
  /* clear window if we're on a non-static display */
  if (ncols>0 && (theVisual->class == PseudoColor ||
		  theVisual->class == GrayScale)) XClearWindow(theDisp,mainW);
#endif

  putECfirst();     /* make certain this one gets alloc'd */

  if (rwcolor && rwthistime) AllocRWColors();
                        else AllocColors();

  CreateXImage();

  if (useroot) MakeRootPic();
          else DrawWindow(0,0,eWIDE,eHIGH);
  if (but[BCROP].active) InvCropRect();
  SetCursors(-1);
}


/**************************************/
static void putECfirst()
{
  /* called after all colors have been freed up, but before reallocating.
     moves color #editColor to first in 'colAllocOrder' list, so that it
     is most-likely to get its desired color */

  int i;

  /* find it in the list */
  for (i=0; i<numcols; i++) {
    if (editColor == colAllocOrder[i]) break;
  }

  if (i==numcols || i==0) { /* didn't find it, or it's first already */
    return;
  }

  /* shift 0..i-1 down one position */
  bcopy(colAllocOrder, colAllocOrder+1, i * sizeof(colAllocOrder[0]));
  colAllocOrder[0] = editColor;
}








