/*   Program to open an XWindow and test the set of available colors.

     Written by Dan Harvey, 5/7/2002
     To compile: gcc -g -o rgb rgb.c -L/usr/X11R6/lib -lX11

*/

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>

/* Required constants */

#define WIDTH      800   /* Resolution of screen */
#define HEIGHT     800
#define BORDER       4
#define MAX_COLORS 600  /* Maximum size of array of colors.  */
#define SLEEP_TIME  10  /* Time to delay before exiting.     */

/* Data structures */

static char *colorNames[] = {
   "snow","GhostWhite","WhiteSmoke","gainsboro","FloralWhite","OldLace",
   "linen","AntiqueWhite","PapayaWhip","BlanchedAlmond","bisque","PeachPuff",
   "NavajoWhite","moccasin","cornsilk","ivory","LemonChiffon","seashell",
   "honeydew","MintCream","azure","AliceBlue","lavender","LavenderBlush",
   "MistyRose","white","black","DarkSlateGrey","DimGrey","SlateGrey",
   "LightSlateGrey","grey","LightGrey","LightGray","MidnightBlue","navy",
   "NavyBlue","CornflowerBlue","DarkSlateBlue","SlateBlue","MediumSlateBlue",
   "LightSlateBlue","MediumBlue","RoyalBlue","blue","DodgerBlue","DeepSkyBlue",
   "SkyBlue","LightSkyBlue","SteelBlue","LightSteelBlue","LightBlue",
   "PowderBlue","PaleTurquoise","DarkTurquoise","MediumTurquoise",
   "turquoise","cyan","LightCyan","CadetBlue","MediumAquamarine","aquamarine",
   "DarkGreen","DarkOliveGreen","DarkSeaGreen","SeaGreen","MediumSeaGreen",
   "LightSeaGreen","PaleGreen","SpringGreen","LawnGreen","green","chartreuse",
   "MediumSpringGreen","GreenYellow","lime green","LimeGreen","YellowGreen",
   "ForestGreen","OliveDrab","DarkKhaki","khaki","PaleGoldenrod",
   "LightGoldenrodYellow", "LightYellow","yellow","gold","LightGoldenrod",
   "goldenrod","DarkGoldenrod","RosyBrown","IndianRed","SaddleBrown","sienna",
   "peru","burlywood","beige","wheat","SandyBrown","tan","chocolate",
   "firebrick","brown","DarkSalmon","salmon","LightSalmon","orange",
   "DarkOrange","coral","LightCoral","tomato","OrangeRed","red","HotPink",
   "DeepPink","pink","LightPink","PaleVioletRed","maroon","MediumVioletRed",
   "VioletRed","magenta","violet","plum","orchid","MediumOrchid","DarkOrchid",
   "DarkViolet","BlueViolet","purple","MediumPurple","thistle","snow1","snow2",
   "snow3","snow4","seashell1","seashell2","seashell3","seashell4",
   "AntiqueWhite1","AntiqueWhite2","AntiqueWhite3","AntiqueWhite4","bisque1",
   "bisque2","bisque3","bisque4","PeachPuff1","PeachPuff2","PeachPuff3",
   "PeachPuff4","NavajoWhite1","NavajoWhite2","NavajoWhite3","NavajoWhite4",
   "LemonChiffon1","LemonChiffon2","LemonChiffon3","LemonChiffon4","cornsilk1",
   "cornsilk2","cornsilk3","cornsilk4","ivory1","ivory2","ivory3","ivory4",
   "honeydew1","honeydew2","honeydew3","honeydew4","LavenderBlush1",
   "LavenderBlush2","LavenderBlush3","LavenderBlush4","MistyRose1",
   "MistyRose2","MistyRose3","MistyRose4","azure1","azure2","azure3","azure4",
   "SlateBlue1","SlateBlue2","SlateBlue3","SlateBlue4","RoyalBlue1",
   "RoyalBlue2","RoyalBlue3","RoyalBlue4","blue1","blue2","blue3","blue4",
   "DodgerBlue1","DodgerBlue2","DodgerBlue3","DodgerBlue4","SteelBlue1",
   "SteelBlue2","SteelBlue3","SteelBlue4","DeepSkyBlue1","DeepSkyBlue2",
   "DeepSkyBlue3","DeepSkyBlue4","SkyBlue1","SkyBlue2","SkyBlue3","SkyBlue4",
   "LightSkyBlue1","LightSkyBlue2","LightSkyBlue3","LightSkyBlue4",
   "SlateGray1","SlateGray2","SlateGray3","SlateGray4", "LightSteelBlue1",
   "LightSteelBlue2","LightSteelBlue3","LightSteelBlue4","LightBlue1",
   "LightBlue2","LightBlue3","LightBlue4","LightCyan1","LightCyan2",
   "LightCyan3","LightCyan4","PaleTurquoise1","PaleTurquoise2",
   "PaleTurquoise3","PaleTurquoise4","CadetBlue1","CadetBlue2","CadetBlue3",
   "CadetBlue4","turquoise1","turquoise2","turquoise3","turquoise4","cyan1",
   "cyan2","cyan3","cyan4","DarkSlateGray1","DarkSlateGray2","DarkSlateGray3",
   "DarkSlateGray4","aquamarine1","aquamarine2","aquamarine3","aquamarine4",
   "DarkSeaGreen1","DarkSeaGreen2","DarkSeaGreen3","DarkSeaGreen4","SeaGreen1",
   "SeaGreen2","SeaGreen3","SeaGreen4","PaleGreen1","PaleGreen2","PaleGreen3",
   "PaleGreen4","SpringGreen1","SpringGreen2","SpringGreen3","SpringGreen4",
   "green1","green2","green3","green4","chartreuse1","chartreuse2",
   "chartreuse3","chartreuse4","OliveDrab1","OliveDrab2","OliveDrab3",
   "OliveDrab4","DarkOliveGreen1","DarkOliveGreen2","DarkOliveGreen3",
   "DarkOliveGreen4","khaki1","khaki2","khaki3","khaki4","LightGoldenrod1",
   "LightGoldenrod2","LightGoldenrod3","LightGoldenrod4","LightYellow1",
   "LightYellow2","LightYellow3","LightYellow4","yellow1","yellow2","yellow3",
   "yellow4","gold1","gold2","gold3","gold4","goldenrod1","goldenrod2",
   "goldenrod3","goldenrod4","DarkGoldenrod1","DarkGoldenrod2",
   "DarkGoldenrod3","DarkGoldenrod4","RosyBrown1","RosyBrown2","RosyBrown3",
   "RosyBrown4","IndianRed1","IndianRed2","IndianRed3","IndianRed4","sienna1",
   "sienna2","sienna3","sienna4","burlywood1","burlywood2","burlywood3",
   "burlywood4","wheat1","wheat2","wheat3","wheat4","tan1","tan2","tan3",
   "tan4","chocolate1","chocolate2","chocolate3","chocolate4","firebrick1",
   "firebrick2","firebrick3","firebrick4","brown1","brown2","brown3","brown4",
   "salmon1","salmon2","salmon3","salmon4","LightSalmon1","LightSalmon2",
   "LightSalmon3","LightSalmon4","orange1","orange2","orange3","orange4",
   "DarkOrange1","DarkOrange2","DarkOrange3","DarkOrange4","coral1","coral2",
   "coral3","coral4","tomato1","tomato2","tomato3","tomato4","OrangeRed1",
   "OrangeRed2","OrangeRed3", "OrangeRed4","red1","red2","red3","red4",
   "DeepPink1","DeepPink2","DeepPink3","DeepPink4","HotPink1","HotPink2",
   "HotPink3","HotPink4","pink1","pink2","pink3", "pink4","LightPink1",
   "LightPink2","LightPink3","LightPink4","PaleVioletRed1","PaleVioletRed2",
   "PaleVioletRed3","PaleVioletRed4","maroon1","maroon2","maroon3","maroon4",
   "VioletRed1","VioletRed2","VioletRed3","VioletRed4","magenta1","magenta2",
   "magenta3","magenta4","orchid1","orchid2","orchid3","orchid4","plum1",
   "plum2","plum3","plum4","MediumOrchid1","MediumOrchid2","MediumOrchid3",
   "MediumOrchid4","DarkOrchid1","DarkOrchid2","DarkOrchid3","DarkOrchid4",
   "purple1","purple2","purple3","purple4","MediumPurple1","MediumPurple2",
   "MediumPurple3","MediumPurple4","thistle1","thistle2","thistle3",
   "thistle4","grey0","grey1","grey2","grey3","grey4","grey5","grey6","grey7",
   "grey8","grey9","grey10","grey11","grey12","grey13","grey14","grey15",
   "grey16","grey17","grey18","grey19","grey20","grey21","grey22","grey23",
   "grey24","grey25","grey26","grey27","grey28","grey29","grey30","grey31",
   "grey32","grey33","grey34","grey35","grey36","grey37","grey38","grey39",
   "grey40","grey41","grey42","grey43","grey44","grey45","grey46","grey47",
   "grey48","grey49","grey50","grey51","grey52","grey53","grey54","gray55",
   "grey55","gray56","grey56","grey57","grey58","grey59","grey60","grey61",
   "grey62","grey63","grey64","grey65","grey66","grey67","grey68","grey69",
   "grey70","grey71","grey72","grey73","grey74","grey75","grey76","grey77",
   "grey78","grey79","grey80","grey81","grey82","grey83","grey84","grey85",
   "grey86","grey87","grey88","grey89","grey90","grey91","grey92","grey93",
   "grey94","grey95","grey96","grey97","grey98","grey99","grey100","DarkGrey",
   "DarkBlue","DarkCyan","DarkMagenta","DarkRed","LightGreen",""
};

/*  Verify list of colors. */

int verifyColors(Display *display,int screen,
                          char *colorList[],unsigned long rgb[])
{  Colormap colormap = DefaultColormap(display, screen);
   int      color = 0, colors = 0;
   XColor   rgbValue;

   while (strlen(colorList[color]) != 0)
   {  if (!XParseColor(display, colormap, colorList[color], &rgbValue))
      { printf("\n %d:%s was not in the database", color, colorList[color] );
      }
      else
      {  if (!XAllocColor(display, colormap, &rgbValue))
              printf("\n %d:%s could not be allocated",color,colorList[color]);
         else rgb[colors++] = rgbValue.pixel;
      } 
      color++;
   }
   return color;
}

/*  Function to print error messages and abort.   */

void error( Display *display, char *msg )
{  printf("\n\nmandelbrot:%s", msg);
   if (display == NULL) exit(-1);
   else
   {  XFlush(display);
      sleep(SLEEP_TIME);
      XCloseDisplay(display);
      exit(0);
}  }

/*  Main program logic */

int main(int argc, char *argv[])
{  char  *windowName  = "Mandelbrot Set";/* Name to display in title bar.    */
   char  *displayName = NULL;         /* Name of XWindow server.             */
   unsigned long rgbValues[MAX_COLORS];/* RGB allocated color array.         */

   Display              *display;     /* Information about server connection.*/
   Window                window;      /* Structure for window.               */
   int                   screen;      /* Number of default server screen.    */
   XSizeHints            sizeHints;   /* Preferred window size & position.   */
   XSetWindowAttributes  attributes;  /* Preferred window attributes.        */
   GC                    gc;          /* Graphics context structure.         */
   int                   colors;      /* Count of valid colors.              */

   int i, x, y, color;                /* Temporary variables.                */

/* Connect to XWindow server  */

   if ( (display = XOpenDisplay(displayName)) == NULL)
   {  error(display, "Cannot connect to X server" );
   }

/* Get default screen number controlled by the server */

   screen = DefaultScreen(display);

/* Create window on the display, create the root window for this application */

   window = XCreateSimpleWindow
                (display, RootWindow(display,screen),0,0,WIDTH,HEIGHT,BORDER,
                 BlackPixel(display,screen), WhitePixel(display, screen));

/* Change window attributes so off display pixels are maintained. */

   attributes.backing_store  = Always;
   attributes.backing_pixel  = BlackPixel(display,screen);
   XChangeWindowAttributes( display, window,
                               CWBackingStore | CWBackingPixel, &attributes);

/* Define preferences for window to be created  */

   sizeHints.flags  = USPosition|USSize;  /* Preferred window size & position.*/
   sizeHints.x      = 0;
   sizeHints.y      = 0;
   sizeHints.width  = WIDTH;
   sizeHints.height = HEIGHT;
   XSetNormalHints(display, window, &sizeHints);
   XStoreName(display, window, windowName );

/* Create a graphics context 
     background and forground colors
     the width/fill style/shape/join characteristics of pixels.
*/
   gc = XCreateGC(display, RootWindow(display, screen), 0, NULL);
   XSetForeground(display, gc, BlackPixel(display, screen));
   XSetBackground(display, gc, WhitePixel(display, screen));
   XSetLineAttributes(display, gc, 1, LineSolid, CapRound, JoinRound);

/* Map window so that it is displayed on the screen.  */

   XMapWindow(display, window);
   XSync(display, 0);

/* Now we can test the colors. */

   colors = verifyColors(display, screen, colorNames, rgbValues); 
   for (x=0; x<WIDTH; x++)
   {  for (y=0; y<HEIGHT; y++)
      {  color = (x*y+y) % colors;
         XSetForeground(display, gc, rgbValues[color]);
         XDrawPoint(display, window, gc, x, y );
   }  }
   printf ("\n Number of Colors = %u\n", colors);
   error(display, "Program Complete");
}