[comp.windows.x] Need help cycling colors with X11

cheeks@edsr.eds.com (Mark Costlow) (05/28/91)

I have an Xlib application in which I want to cycle a range of colors.  In
one mode, I just build a bunch of color maps and cycle through those.  That
works fine.  What I *haven't* been able to get working is a mode where the
program allocates some color cells from the default color map and causes
only those cells to cycle.  This mode would let me run the application and
still see my other windows.  (I am only concerned with pseudocolor displays
at the moment).

I use XAllocColorCells() to allocate the cells and then use XStoreColors()
to store the RGB values that I choose.  When it's time to cycle the colors,
I shift the ".pixel" member of all color definitions in my array of
XColors, and call XStoreColors() again to redefine the pixel indices.
This does not work (*) ... the colors in the window never change.  I've
looked through the FAQ and in all the Xlib books I can find and I haven't
found anything which indicates that this scheme should not work.  Is there
something very basic that I'm overlooking?

(*) - I've run this program on several types of Sparcs and on HP9000s300
machines.  It behaves the same on all machines EXCEPT Sparcs with GX boards
-- on those machines the program works as I would expect it to.  Sparcs
with CG3s don't work though.  In all cases, the machines are running X11R4
from MIT with most or all of the MIT patches.

Following my .signature is a small test program which demonstrates my
problem.  The two functions of interest are GetColors() which allocates the
color cells, and CycleColors() which attempts to cycle them.  I would
REALLY appreciate any insight (or kicks in the head) that anyone out in
netland has.

Thanks,

Mark
-- 
cheeks@edsr.eds.com    or     ...uunet!edsr!cheeks

#---------------------------------- cut here ----------------------------------
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Mark Costlow <cheeks@argon> on Mon May 27 17:56:44 1991
#
# This archive contains:
#	Makefile	test.c		
#
# Existing files will not be overwritten.
# Error checking via wc(1) will be performed.

LANG=""; export LANG
PATH=/bin:/usr/bin:$PATH; export PATH

if test -f Makefile
then
	echo Ok to overwrite existing file Makefile\?
	read answer
	case "$answer" in
	[yY]*)	echo Proceeding;;
	*)	echo Aborting; exit 1;;
	esac
	rm -f Makefile
	if test -f Makefile
	then
		echo Error: could not remove Makefile, aborting
		exit 1
	fi
fi
echo x - Makefile
cat >Makefile <<'@EOF'
CC = gcc
CFLAGS = -g

.c.o:
	$(CC) $(CFLAGS) -c $<


PROGS =  test
all: $(PROGS)

test: test.o
	$(CC) $(CFLAGS) -o test test.o -lX11 -lm

clean:
	rm -f core *.o $(PROGS)
@EOF
set `wc -lwc <Makefile`
if test $1$2$3 != 1531170
then
	echo ERROR: wc results of Makefile are $* should be 15 31 170
fi

chmod 664 Makefile

if test -f test.c
then
	echo Ok to overwrite existing file test.c\?
	read answer
	case "$answer" in
	[yY]*)	echo Proceeding;;
	*)	echo Aborting; exit 1;;
	esac
	rm -f test.c
	if test -f test.c
	then
		echo Error: could not remove test.c, aborting
		exit 1
	fi
fi
echo x - test.c
cat >test.c <<'@EOF'
/*
 *  test.c  -- test color cycling with X11.
 *
 *  Mark Costlow
 *  cheeks@edsr.eds.com
 *  May 27, 1991
 */
#include <stdio.h>
#include <math.h>

/* X-windows includes */
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>

typedef unsigned long Pixel;
typedef unsigned char byte;

Display         *display;
Visual          *visual = NULL;
Status          status;
unsigned long   wp, bp;     /* pixel values for black & white */
int screen, nplanes, ncolors;

XEvent         event;
XExposeEvent   *expose;
XSetWindowAttributes attrib;

GC           gc;
XGCValues    gc_val;
XSizeHints   sizehints;
Window       imagewin;        /* window ID for image */
XImage       *image = NULL;
Colormap     cmap;
Pixel pixels[256];
XColor *colors;

int num_colors = 0;
int global_x, global_y;
byte *buf;
#define MAXI 65535

void remap(byte *buf, int x, int y, Pixel *pixels)
{
  int i, j;

  for(i = 0; i < y; i++)
    for(j = 0; j < x; j++)
      {
	*buf = (byte)pixels[*buf];
	buf++;
      }
}
  
/*
 *  This code is partially based on a routine in Jim Frost's xloadimage.
 *
 *  It does this:
 *     1. grab the server so no one can goof with the colormap.
 *     2. count the available colors using XAllocColorCells.
 *     3. free the colors we just allocated.
 *     4. allocate the colors again with XAllocColorCells
 *     6. ungrab the server and continue
 */
void GetColors(int nplanes)
{
  int i;
  int ncolors = 1 << nplanes;
  double rstep, rf;
  double gstep, gf;
  double bstep, bf;

  cmap = DefaultColormap(display, screen);
  XGrabServer(display);
  for (i= 0; i < ncolors; i++) /* count entries we got */
    if (! XAllocColorCells(display, cmap, False, NULL, 0, pixels + i, 1))
      break;
  
  if (i > 0)
    XFreeColors(display, cmap, pixels, i, 0);
  if (i <= 2) 
    {
      fprintf(stderr, "Cannot fit into default colormap, aborting.\n");
      fflush(stderr);
      exit(1);
    }

  num_colors = ncolors = i;

  colors = (XColor *) malloc(num_colors * sizeof(XColor));
  if (! XAllocColorCells(display, cmap, False, NULL, 0, pixels, num_colors))
    {
      fprintf(stderr, "Cannot allocate color cells\n");
      exit(1);
    }

  /*
   *  Generate a rainbow of colors
   */
  rstep = (double) ( (M_PI *   (double)nplanes) / (double) ncolors);
  gstep = (double) ( (M_PI_4 * (double)nplanes) / (double) ncolors);
  bstep = (double) ( (M_PI_2 * (double)nplanes) / (double) ncolors);
  rf = M_PI;
  gf = 2 * M_PI;
  bf = M_PI_2;

  for (i= 0; i < ncolors; i++) 
    {
      double scale = MAXI / 2.0;
      double sin(double);
      
      colors[i].pixel = pixels[i];
      colors[i].red   = (int)((scale * sin(rf)) + scale);
      colors[i].green = (int)((scale * sin(gf)) + scale);
      colors[i].blue  = (int)((scale * sin(bf)) + scale);
      rf += rstep;
      gf += gstep;
      bf += bstep;

    }
  XStoreColors(display, cmap, colors, num_colors);
  remap(buf, global_x, global_y, pixels);
  XUngrabServer(display);
}


/*
 *  Cycle the indices in the default color map.  This is done by rotating
 *  the .pixel member in each color structure, and then calling XStoreColors
 *  with the array of colors.
 */
void CycleColors()
{
  int i, j;
  
  /*
   *  rotate the colors
   */
  j = colors[0].pixel;
  for (i = 0; i < num_colors-1; i++)
    colors[i].pixel = colors[i+1].pixel;
  colors[num_colors-1].pixel = j;

  XStoreColors(display, cmap, colors, num_colors);
  XSync(display, False);
}


void InitX(char *disp, int x, int y)
{
  char win_name[64];

  strcpy(win_name, "colortest");
  
  /* Open connection to the X11 server and set defaults */
  if ((display = XOpenDisplay(disp)) == NULL) 
    {
      fprintf(stderr,"Could not open display.\n");
      exit(1); 
    }
  screen = XDefaultScreen(display);
  visual = XDefaultVisual(display, screen);
  nplanes = XDisplayPlanes(display, screen);

  bp = BlackPixel(display, screen);
  wp = WhitePixel(display, screen);

  /*
   * Set window manager hints
   */
  sizehints.flags = PPosition | PSize | PMinSize | PMaxSize;
  sizehints.width = sizehints.min_width = x;
  sizehints.max_width = x;
  sizehints.height = sizehints.min_height = y;
  sizehints.max_height = y;
  sizehints.x = sizehints.y = 0;

  GetColors(nplanes);

  attrib.background_pixel = wp;
  attrib.border_pixel     = bp;
  attrib.event_mask       = (ExposureMask | LeaveWindowMask | 
			     ButtonPressMask | ButtonReleaseMask |
			     ColormapChangeMask | Button1MotionMask |
			     EnterWindowMask);
  attrib.cursor = XCreateFontCursor(display, XC_top_left_arrow);
  
  /*
   * Create the window.
   */
  imagewin = XCreateWindow(display, RootWindow(display, screen), 0, 0,
			   x, y, 5, XDefaultDepth(display, screen),
			   InputOutput, visual, 
			   (CWBackPixel|CWEventMask|CWCursor|CWBorderPixel), 
			   &attrib);

  /* 
   * Install properties for the window.
   */
  XSetStandardProperties(display, imagewin, win_name, win_name, NULL,
			 NULL, NULL, &sizehints);
  XSetIconName(display, imagewin, "colortest");

  /*  Now finally map the window ...  */
  XMapWindow(display, imagewin);

  /* Create a Graphics Context. */
  gc_val.foreground = bp;
  gc_val.background = wp;
  gc = XCreateGC(display, imagewin, GCForeground | GCBackground , &gc_val);
  
  /* select which input events to honor */
  XSelectInput(display, imagewin, (ExposureMask | KeyPressMask));

  /* Wait for first expose event  */
  XNextEvent(display, &event);
  while (event.type != Expose)
    XNextEvent(display, &event);
}  


void show_pic(byte *buf, int x, int y) 
{
  image = XCreateImage(display, visual, nplanes, ZPixmap, 0, (char *)buf, 
		       x, y, 8, 0);

  XPutImage(display, imagewin, gc, image, 0, 0, 0, 0, x, y);
  XSync(display, False);
}

int main (int argc, char **argv)
{
  char *display = NULL;
  int x = 64, y = 64, i, j;
  byte *p;

  global_x = x;
  global_y = y;

  p = buf = (byte *)malloc(x * y);
  if (!buf) 
    {
      fprintf(stderr, "%s: malloc failure.\n", argv[0]);
      exit(1);
    }

  /*  This should leave buf containing horizontal bands of color. */
  for(i = 0; i < y; i++)
    for(j = 0; j < x; j++)
      *p++ = i;

  InitX(display, x, y);
  show_pic(buf, x, y);

  while(1)
    {
      usleep(50000);
      CycleColors();
    }
  
  return 0;
}
@EOF
set `wc -lwc <test.c`
if test $1$2$3 != 2648346299
then
	echo ERROR: wc results of test.c are $* should be 264 834 6299
fi

chmod 664 test.c

exit 0

rws@expo.lcs.mit.EDU (Bob Scheifler) (05/28/91)

    I use XAllocColorCells() to allocate the cells and then use XStoreColors()
    to store the RGB values that I choose.

RTFM.  You aren't setting the XColor.flags components to DoRed|DoGreen|DoBlue.

cheeks@tantalum.UUCP (Mark Costlow) (05/28/91)

me>  I use XAllocColorCells() to allocate the cells and then use XStoreColors()
me>  to store the RGB values that I choose.

rws> RTFM.  You aren't setting the XColor.flags components to 
rws> DoRed|DoGreen|DoBlue.


Arggh!  I don't know how I managed to remove that line ... thanks for that
kick in the head.

>>Chx
cheeks@edsr.eds.com    or     ...uunet!edsr!cheeks

mikey@eukanuba.wpd.sgi.com (Mike Yang) (05/29/91)

XStoreColors only changes the components you specify in the flags
member of the XColor structure.  You never set this field.  It should
probably be (DoRed | DoGreen | DoBlue).

-----------------------------------------------------------------------
                 Mike Yang        Silicon Graphics, Inc.
               mikey@sgi.com           415/335-1786