home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3407 / cmap.c next >
Encoding:
C/C++ Source or Header  |  1991-05-24  |  15.5 KB  |  651 lines

  1.  
  2. /* This module is a dull one. It is somewhat important, however,
  3.  * because it handles most of the interface between the program
  4.  * and the user.
  5.  
  6.  * This module will allocate colors, free them; handle events of the
  7.  * colormap window, including gadgets, sliders and spectrum;
  8.  * it will also handle the mapping between iteration levels and
  9.  * colors.
  10.  
  11.  * callable functios:
  12.  * void ToggleCWin(display, window, mode);
  13.  * int HandleCEvent(Display *display, int screen, Window window,
  14.                     GC gc1, GC gc2, GC gc3, Xevent *event);
  15.  * void AllocColors(Display *display, int screen);
  16.  * void FreeColors(Display *display, int screen);
  17.  * void SetNColors(int number_of_colors);
  18.  * unsigned long ToPixel(int level);
  19.  
  20.  */
  21.  
  22. #include <X11/Xlib.h>
  23. #include <math.h>
  24. #include <stdio.h>
  25. #include "cmap.h"
  26. #include "misc.h"
  27.  
  28. /* Geometries of gadgets.. */
  29. #define GAD_Y1 5
  30. #define GAD_Y2 20
  31. #define GAD_LEFT 10
  32. #define GAD_GAP 8
  33. /* ...Sliders... */
  34. #define TOP_GAP 25
  35. #define CHAR_X 5
  36. #define LINE_X 20
  37. #define BOX_X1 30
  38. #define BOX_X2 10
  39. #define BOX_Y1 3
  40. #define BOX_Y2 3
  41. #define BOTTOM_GAP 25
  42. /* ... cmap */
  43. #define CMAP_Y1 20
  44. #define CMAP_Y2 5
  45. #define BLACK_SIZE 4
  46.  
  47. #define SLIDERSTEPS 64
  48. #define MAXSLIDE 65536
  49.  
  50. #define GAMMA 2.2
  51.  
  52. static char *gadget[]= {"Apply", "Redraw", "Previous", "Restart", "Quit"};
  53. #define NUMGAD (sizeof(gadget)/sizeof(char *))
  54. static struct gad_pos{
  55.   int s, e;
  56.   } gadpos[NUMGAD];
  57.  
  58. static long red[SLIDERSTEPS], green[SLIDERSTEPS],
  59.              blue[SLIDERSTEPS];
  60. static long red0, green0, blue0;
  61. static int coff= 0; /* color offset */
  62.  
  63. static unsigned long *pixel;
  64. static char *alloc;
  65. static int allocated= 0;
  66. static int ncolors= 0;
  67. /* Does the current colormap reflect position of sliders? */
  68. static int applied= 0;
  69.  
  70. static int mapped= 0;
  71.  
  72. static int width, height;
  73.  
  74. void ToggleCWin(display, win, mode)
  75. Display *display;
  76. Window win;
  77. int mode;
  78. {
  79. if (mapped && (mode == CMAP_TOGGLE || mode == CMAP_CLOSE)) {
  80.   XUnmapWindow(display, win);
  81.   mapped= 0;
  82.   }
  83. else if (!mapped && (mode == CMAP_TOGGLE || mode == CMAP_OPEN)) {
  84.   XMapWindow(display, win);
  85.   mapped= 1;
  86.   }
  87. }
  88.  
  89.  
  90. void DrawHotSpot(display, win, gc, x, y)
  91. Display *display;
  92. Window win;
  93. GC gc;
  94. int x,y;
  95. {
  96. XDrawRectangle(display, win, gc, x-3, y-3, 6, 6);
  97. XDrawRectangle(display, win, gc, x-2, y-2, 4, 4);
  98. }
  99.  
  100.  
  101. void DrawSliders(display, win, gc, n)
  102. Display *display;
  103. Window win;
  104. GC gc;
  105. int n;
  106. {
  107. int i;
  108. int zone= (height-TOP_GAP-BOTTOM_GAP)/3;
  109. long *color;
  110.  
  111. switch(n) {
  112.   case 0: color= red; break;
  113.   case 1: color= green; break;
  114.   case 2: color= blue; break;
  115.   }
  116. for (i= 0; i < SLIDERSTEPS; i++) {
  117.   int j= (i+1) % SLIDERSTEPS;
  118.   int x1= BOX_X1 + 1+i*(width-BOX_X1-BOX_X2-2)/SLIDERSTEPS;
  119.   int x2= BOX_X1 + 1+(i+1)*(width-BOX_X1-BOX_X2-2)/SLIDERSTEPS;
  120.   int y1= TOP_GAP + n*zone + BOX_Y1 +
  121.           1 + ((zone-BOX_Y1-BOX_Y2-2)*(MAXSLIDE-color[i]))/MAXSLIDE;
  122.   int y2= TOP_GAP + n*zone + BOX_Y1 +
  123.           1 + ((zone-BOX_Y1-BOX_Y2-2)*(MAXSLIDE-color[j]))/MAXSLIDE;
  124.  
  125.   XDrawLine(display, win, gc, x1, y1, x2, y2);
  126.   }
  127. }
  128.  
  129.  
  130. void DrawSlider(display, win, gc1, gc2, n, trash)
  131. Display *display;
  132. Window win;
  133. GC gc1, gc2;
  134. int n, trash;
  135. {
  136. int zone =(height-TOP_GAP-BOTTOM_GAP) / 3;
  137. static int oy[3]= {-1, -1, -1};
  138. int y;
  139. int h;
  140.  
  141. switch(n) {
  142.   case 0: h= red0; break;
  143.   case 1: h= green0; break;
  144.   case 2: h= blue0; break;
  145.   default: break;
  146.   }
  147. y= TOP_GAP + n*zone + BOX_Y1 + ((zone-BOX_Y1-BOX_Y2)*(MAXSLIDE-h))/MAXSLIDE;
  148.  
  149. if (y != oy[n] || trash) {
  150.   if (oy[n] >= 0)
  151.     DrawHotSpot(display, win, gc2, LINE_X, oy[n]);
  152.   DrawHotSpot(display, win, gc1, LINE_X, y);
  153.   oy[n]= y;
  154.   XDrawLine(display, win, gc1,
  155.             LINE_X, TOP_GAP+n*zone+BOX_Y1, LINE_X, TOP_GAP+(n+1)*zone-BOX_Y2);
  156.   }
  157. }
  158.  
  159.  
  160. void DrawSliderBox(display, win, gc, n)
  161. Display *display;
  162. Window win;
  163. GC gc;
  164. int n;
  165. {
  166. int zone= (height-TOP_GAP-BOTTOM_GAP)/3;
  167. char ch[2]; 
  168.  
  169. ch[1]= '\0';
  170. switch(n) {
  171.   case 0: ch[0]= 'R'; break;
  172.   case 1: ch[0]= 'G'; break;
  173.   case 2: ch[0]= 'B'; break;
  174.   }
  175. XDrawRectangle(display, win, gc,
  176.                BOX_X1, TOP_GAP + n*zone + BOX_Y1,
  177.                width-BOX_X1-BOX_X2, zone-BOX_Y1-BOX_Y2);
  178. WriteText(display, win, gc, ch, CHAR_X,
  179.        TOP_GAP + n*zone + BOX_Y1 + (zone-BOX_Y1-BOX_Y2)/2-6 );
  180. }
  181.  
  182.  
  183. void DrawColorBox(display, win, gc, gc1)
  184. Display *display;
  185. Window win;
  186. GC gc, gc1;
  187. {
  188. int i;
  189. XGCValues gcval;
  190.  
  191. gcval.foreground= pixel[0];
  192. XChangeGC(display, gc, GCForeground, &gcval);
  193.  
  194. XFillRectangle(display, win, gc,
  195.                LINE_X-BLACK_SIZE, height-CMAP_Y1,
  196.                2*BLACK_SIZE, CMAP_Y1-CMAP_Y2);
  197. XDrawRectangle(display, win, gc1,
  198.                LINE_X-BLACK_SIZE, height-CMAP_Y1,
  199.                2*BLACK_SIZE, CMAP_Y1-CMAP_Y2);
  200.  
  201. for (i= 1; i < ncolors; i++) {
  202.   int x1= ((width-BOX_X2-BOX_X1)*(i-1)/(ncolors-1));
  203.   int x2= ((width-BOX_X2-BOX_X1)*i/(ncolors-1));
  204.  
  205.   gcval.foreground= pixel[i];
  206.   XChangeGC(display, gc, GCForeground, &gcval);
  207.  
  208.   XFillRectangle(display, win, gc,
  209.                  BOX_X1+x1, height-CMAP_Y1,
  210.                  x2-x1, CMAP_Y1-CMAP_Y2);
  211.   }
  212. XDrawRectangle(display, win, gc1,
  213.                BOX_X1, height-CMAP_Y1,
  214.                width-BOX_X2-BOX_X1, CMAP_Y1-CMAP_Y2);
  215. } /* DrawColorBox() */
  216.  
  217.  
  218. int InCmap(x, y)
  219. int x, y;
  220. {
  221. int c;
  222. if (y < height-CMAP_Y1 || y > height-CMAP_Y2)
  223.   return(0);
  224. c= (x-BOX_X1)*ncolors/(width-BOX_X2-BOX_X1);
  225. if (c<= 0 || c >= ncolors)
  226.   return(0);
  227. return(c);
  228. }
  229.  
  230.  
  231. int InSlider(x, y, n)
  232. int x, y, n;
  233. {
  234. int zone= (height-TOP_GAP-BOTTOM_GAP)/3;
  235.  
  236. if (y < TOP_GAP + (n%3)*zone + BOX_Y1 || y > TOP_GAP + ((n%3)+1)*zone - BOX_Y2)
  237.   return 0;
  238. if (n < 3) {
  239.   if (x > (3*LINE_X - BOX_X1) / 2 && x < (LINE_X+BOX_X1) / 2)
  240.     return 1;
  241.   }
  242. else {
  243.   if (x > BOX_X1 && x < width-BOX_X2)
  244.     return 1;
  245.   }
  246. return 0;
  247. }
  248.  
  249.  
  250. void DragSlider(display, win, gc1, gc2, n, x1, y1, x2, y2)
  251. Display *display;
  252. Window win;
  253. GC gc1, gc2;
  254. int n, x1, y1, x2, y2;
  255. {
  256. int zone= (height-TOP_GAP-BOTTOM_GAP)/3;
  257. int s1= (x1-BOX_X1)*SLIDERSTEPS / (width-BOX_X1-BOX_X2+1);
  258. int s2= (x2-BOX_X1)*SLIDERSTEPS / (width-BOX_X1-BOX_X2+1);
  259. int c1= ((TOP_GAP + ((n%3)+1)*zone - BOX_Y2) - y1) *
  260.       (MAXSLIDE-1) / (zone - BOX_Y2 - BOX_Y1);
  261. int c2= ((TOP_GAP + ((n%3)+1)*zone - BOX_Y2) - y2) *
  262.       (MAXSLIDE-1) / (zone - BOX_Y2 - BOX_Y1);
  263.  
  264. if (c1 < 0) c1= 0;
  265. if (c2 < 0) c2= 0;
  266. if (c1 >= MAXSLIDE) c1= MAXSLIDE-1;
  267. if (c2 >= MAXSLIDE) c2= MAXSLIDE-1;
  268. if (s1 < 0) s1= 0;
  269. if (s2 < 0) s2= 0;
  270. if (s1 >= SLIDERSTEPS) s1= SLIDERSTEPS-1;
  271. if (s2 >= SLIDERSTEPS) s2= SLIDERSTEPS-1;
  272. if (s1 > s2) {
  273.   int tmp= s2; s2= s1; s1= tmp;
  274.   tmp= c2; c2= c1; c1= tmp;
  275.   }
  276.  
  277. applied= 0; /* colormap no longer valid */
  278. if (n < 3) {
  279.   switch(n) {
  280.     case 0: red0= c2; break;
  281.     case 1: green0= c2; break;
  282.     case 2: blue0= c2; break;
  283.     }
  284.   DrawSlider(display, win, gc1, gc2, n, 0);
  285.   } /* if */
  286. else {
  287.   long *color;
  288.   int i;
  289.   n -= 3;
  290.   switch(n) {
  291.     case 0: color= red; break;
  292.     case 1: color= green; break;
  293.     case 2: color= blue; break;
  294.     }
  295.   for (i= s1-1; i <= s2; i++) {
  296.     int j= i;
  297.     int k= (i+1) % SLIDERSTEPS;
  298.     int x1, x2, y1, y2;
  299.  
  300.     if (j < 0) j += SLIDERSTEPS;
  301.     x1= BOX_X1 + 1+j*(width-BOX_X1-BOX_X2-2)/SLIDERSTEPS;
  302.     x2= BOX_X1 + 1+(j+1)*(width-BOX_X1-BOX_X2-2)/SLIDERSTEPS;
  303.     y1= TOP_GAP + n*zone + BOX_Y1 +
  304.         1 + ((zone-BOX_Y1-BOX_Y2-2)*(MAXSLIDE-color[j]))/MAXSLIDE;
  305.     y2= TOP_GAP + n*zone + BOX_Y1 +
  306.         1 + ((zone-BOX_Y1-BOX_Y2-2)*(MAXSLIDE-color[k]))/MAXSLIDE;
  307.     XDrawLine(display, win, gc2, x1, y1, x2, y2);
  308.     }
  309.   if (s1 == s2)
  310.     color[s1]= c1;
  311.   else
  312.     for (i= 0; i <= s2-s1; i++)
  313.       color[s1+i]= c1*(s2-s1-i)/(s2-s1) + c2*i/(s2-s1);
  314.   for (i= s1-1; i <= s2; i++) {
  315.     int j= i;
  316.     int k= (i+1) % SLIDERSTEPS;
  317.     int x1, x2, y1, y2;
  318.  
  319.     if (j < 0) j += SLIDERSTEPS;
  320.     x1= BOX_X1 + 1+j*(width-BOX_X1-BOX_X2-2)/SLIDERSTEPS;
  321.     x2= BOX_X1 + 1+(j+1)*(width-BOX_X1-BOX_X2-2)/SLIDERSTEPS;
  322.     y1= TOP_GAP + n*zone + BOX_Y1 +
  323.         1 + ((zone-BOX_Y1-BOX_Y2-2)*(MAXSLIDE-color[j]))/MAXSLIDE;
  324.     y2= TOP_GAP + n*zone + BOX_Y1 +
  325.         1 + ((zone-BOX_Y1-BOX_Y2-2)*(MAXSLIDE-color[k]))/MAXSLIDE;
  326.     XDrawLine(display, win, gc1, x1, y1, x2, y2);
  327.     }
  328.   } /* else */
  329. } /* DragSlider() */
  330.  
  331.  
  332. void DrawGadgets(display, win, gc)
  333. Display *display;
  334. Window win;
  335. GC gc;
  336. {
  337. int i;
  338. int x= GAD_LEFT;
  339. for (i= 0; i < NUMGAD; i++) {
  340.   int len= WriteText(display, win, gc, gadget[i], x+3, GAD_Y1+1);
  341.   gadpos[i].s= x;
  342.   gadpos[i].e= x+len+6;
  343.   XDrawRectangle(display, win, gc, x, GAD_Y1,
  344.                  len+6, GAD_Y2-GAD_Y1);
  345.   x+= len+6 + GAD_GAP;
  346.   }
  347. }
  348.  
  349.  
  350. int CheckGadget(display, win, gc1, gc2, x, y)
  351. Display *display;
  352. Window win;
  353. GC gc1, gc2;
  354. int x, y;
  355. {
  356. int i;
  357. static int drawn= -1;
  358. if (y >= GAD_Y1 && y <= GAD_Y2) {
  359.   for (i= 0; i < NUMGAD; i++) {
  360.     if (x >= gadpos[i].s && x <= gadpos[i].e) {
  361.       if (drawn >= 0 && drawn != i)
  362.         XDrawRectangle(display, win, gc2, gadpos[drawn].s+1, GAD_Y1+1,
  363.                   gadpos[drawn].e-gadpos[drawn].s-2, GAD_Y2-GAD_Y1-2);
  364.       if (drawn != i)
  365.         XDrawRectangle(display, win, gc1, gadpos[i].s+1, GAD_Y1+1,
  366.                   gadpos[i].e-gadpos[i].s-2, GAD_Y2-GAD_Y1-2);
  367.       drawn= i;
  368.       return(i);
  369.       }
  370.     } /* for */
  371.   } /* if */
  372. if (drawn >= 0) {
  373.   XDrawRectangle(display, win, gc2, gadpos[drawn].s+1, GAD_Y1+1,
  374.                  gadpos[drawn].e-gadpos[drawn].s-2, GAD_Y2-GAD_Y1-2);
  375.   drawn= -1;
  376.   }
  377. return(-1);
  378. }
  379.  
  380.  
  381. int HandleCEvent(display, screen, win, gc, gc1, gc2, event)
  382. Display *display;
  383. int screen;
  384. Window win;
  385. GC gc, gc1, gc2;
  386. XEvent *event;
  387. {
  388. int i;
  389. static int dragging= -1;
  390. static int cmaphandle= 0, c1, c2;
  391. static int dragx, dragy;
  392. int gadget;
  393.  
  394. switch (event->type) {
  395.   case Expose:
  396.     /* This is a simple application, redraw the whole
  397.      * window only when no more expose events exist.
  398.      */
  399.     if (event->xexpose.count)
  400.       break;
  401.     for (i= 0; i < 3; i++) {
  402.       DrawSliderBox(display, win, gc1, i);
  403.       DrawSliders(display, win, gc1, i);
  404.       DrawSlider(display, win, gc1, gc2, i, 1);
  405.       }
  406.     DrawColorBox(display, win, gc, gc1);
  407.     DrawGadgets(display, win, gc1);
  408.     break;
  409.                    
  410.   case ConfigureNotify:
  411.     width= event->xconfigure.width;
  412.     height= event->xconfigure.height;
  413.     break;
  414.  
  415.   case ButtonPress:
  416.     switch(event->xbutton.button) {
  417.       case 1:
  418.         for (i= 0; i < 6; i++) {
  419.           dragx= event->xbutton.x;
  420.           dragy= event->xbutton.y;
  421.           if (InSlider(dragx, dragy, i)) {
  422.             dragging= i;
  423.             SlideCursor(display, win);
  424.             DragSlider(display, win, gc1, gc2, dragging,
  425.                     dragx, dragy, dragx, dragy);
  426.             }
  427.           }
  428.         if (dragging >= 0)
  429.           break;
  430.         gadget= CheckGadget(display, win, gc1, gc2,
  431.                        event->xbutton.x, event->xbutton.y);
  432.         switch(gadget) {
  433.           case 0: /* apply */
  434.           case 1: /* redraw */
  435.             if (!applied) {
  436.               WaitCursor(display, win);
  437.               AllocColors(display, screen);
  438.               NormalCursor(display, win);
  439.               DrawColorBox(display, win, gc, gc1);
  440.               }
  441.             if (gadget == 1)
  442.               return(DO_REDRAW);
  443.             break;
  444.           case 2:
  445.             return(DO_PREVIOUS);
  446.           case 3:
  447.             return(DO_RESTART);
  448.           case 4:
  449.             return(DO_QUIT);
  450.           } /* switch */
  451.         if (gadget >= 0)
  452.           break;
  453.         if (c1= InCmap(event->xbutton.x, event->xbutton.y)) {
  454.           cmaphandle= 1;
  455.           VertCursor(display, win);
  456.           }
  457.         break;
  458.       case 2:
  459.         dragging= -1;
  460.         WaitCursor(display, win);
  461.         AllocColors(display, screen);
  462.         NormalCursor(display, win);
  463.         DrawColorBox(display, win, gc, gc1);
  464.         break;
  465.       default:
  466.         dragging= -1;
  467.         ToggleCWin(display, win, CMAP_CLOSE);
  468.         break;
  469.       }
  470.       break;
  471.   case ButtonRelease:
  472.     if (dragging >= 0) {
  473.       dragging= -1;
  474.       NormalCursor(display, win);
  475.       }
  476.     if (cmaphandle) {
  477.       if (c2= InCmap(event->xbutton.x, event->xbutton.y)) {
  478.         coff = (coff + c2 - c1) % ncolors;
  479.         }
  480.       cmaphandle= 0;
  481.       NormalCursor(display, win);
  482.       }
  483.     break;
  484.   case MotionNotify:
  485.     if (dragging >= 0) { 
  486.       DragSlider(display, win, gc1, gc2, dragging, dragx, dragy,
  487.               event->xmotion.x, event->xmotion.y);
  488.       dragx= event->xmotion.x;
  489.       dragy= event->xmotion.y;
  490.       }
  491.     else CheckGadget(display, win, gc1, gc2,
  492.                 event->xmotion.x, event->xmotion.y);
  493.     break;
  494.   case KeyPress:
  495.     dragging= -1;
  496.     NormalCursor(display, win);
  497.     ToggleCWin(display, win, CMAP_CLOSE);
  498.     break;
  499.   case MapNotify:
  500.   case ReparentNotify:
  501.   case UnmapNotify:
  502.     dragging= -1;
  503.     break;
  504.   default:
  505.     printf("Unknown Event %d\n", event->type);
  506.     break;
  507.   } /* switch */
  508. return(-1);
  509. } /* HandleCEvent */
  510.  
  511.  
  512. void SetNColors(nc)
  513. int nc;
  514. {
  515. int i;
  516. ncolors= nc;
  517. /* Initialize some nice-looking colors... */
  518. for (i= 0; i < SLIDERSTEPS; i++) {
  519.   float c= i/((double)SLIDERSTEPS) * 3;
  520.   float r, g, b;
  521.        if (c < 1) {r= 1-c; g= c;   b= 0;}
  522.   else if (c < 2) {r= 0;   g= 2-c; b= c-1;}
  523.   else            {r= c-2; g= 0;   b= 3-c;}
  524.   red[i]= r*(MAXSLIDE-1);
  525.   green[i]= g*(MAXSLIDE-1);
  526.   blue[i]= b*(MAXSLIDE-1);
  527.   }
  528. red0= green0= blue0= 0;
  529. }
  530.  
  531.  
  532. void AllocColors(display, screen)
  533. Display *display;
  534. int screen;
  535. {
  536. int i, first= -1;
  537. int d;
  538. XColor color;
  539.  
  540. if (allocated) 
  541.   FreeColors(display, screen);
  542.  
  543. allocated= 1;
  544. applied= 1; /* colormap is being made valid again */
  545. alloc= (char *)malloc(ncolors);
  546. pixel= (unsigned long *)malloc(ncolors * sizeof(unsigned long));
  547. for (i= 0; i < ncolors; i++)
  548.   alloc[i]= 0;
  549.  
  550. if (ncolors == 3) {
  551.   pixel[0]= BlackPixel(display, screen);
  552.   pixel[1]= WhitePixel(display, screen);
  553.   pixel[2]= BlackPixel(display, screen);
  554.   return;
  555.   }
  556. if (ncolors <= 2) {
  557.   pixel[0]= BlackPixel(display, screen);
  558.   pixel[1]= WhitePixel(display, screen);
  559.   return;
  560.   }
  561.  
  562. /* Because first entry of colormap is so special, allocate it first. */
  563. color.red= red0;
  564. color.green= green0;
  565. color.blue= blue0;
  566. color.flags= DoRed | DoGreen | DoBlue;
  567. if (XAllocColor(display, DefaultColormap(display, screen), &color)) {
  568.   pixel[0]= color.pixel;
  569.   alloc[0]= 1;
  570.   }
  571. else
  572.   pixel[0]= BlackPixel(display, screen);
  573.  
  574. /* Try to allocate colors. The order in which this is done should
  575.  * be as "random" as possible, so that failing requests would
  576.  * not be grouped at the end.
  577.  */
  578. d= 1;
  579. while (d < ncolors) d <<= 1;
  580. while (d > 1) {
  581.   int c= d >> 1;
  582.   do {
  583.     double r, g, b;
  584.     int s1= c*SLIDERSTEPS/ncolors;
  585.     int s2= s1+1;
  586.     int j= (c*SLIDERSTEPS)%ncolors;
  587.  
  588.     if (s2 >= SLIDERSTEPS)
  589.       s2= 0;
  590.  
  591.     r= (red[s1]*(ncolors-j)/ncolors + red[s2]*j/ncolors)/(double)MAXSLIDE;
  592.     g= (green[s1]*(ncolors-j)/ncolors + green[s2]*j/ncolors)/(double)MAXSLIDE;
  593.     b= (blue[s1]*(ncolors-j)/ncolors + blue[s2]*j/ncolors)/(double)MAXSLIDE;
  594.  
  595.     /* Do reverse gamma correction... */
  596.     color.red= pow(r, (1/GAMMA))*65535;
  597.     color.green= pow(g, (1/GAMMA))*65535;
  598.     color.blue= pow(b, (1/GAMMA))*65535;
  599.  
  600.     if (XAllocColor(display, DefaultColormap(display, screen), &color)) {
  601.       pixel[c]= color.pixel;
  602.       alloc[c]= 1;
  603.       if (first < 0) first= c; else if (first > c) first= c;
  604.       } /* if */
  605.     c += d;
  606.     } while (c < ncolors);
  607.     d >>= 1;
  608.   } /* while */
  609.  
  610. /* If no colors could be allocated, use black&white. */
  611. if (first < 0) {
  612.   for (i= 1; i < ncolors; i++)
  613.     pixel[i]= WhitePixel(display, screen);
  614.   return;
  615.   }
  616. /* Fill in gaps... */
  617. for (i= 1; i < ncolors; i++) {
  618.   if (!alloc[i])
  619.     pixel[i]= pixel[first];
  620.   else
  621.     first= i;
  622.   }
  623. } /* AllocColors */
  624.  
  625.  
  626. void FreeColors(display, screen)
  627. Display *display;
  628. int screen;
  629. {
  630. int i;
  631.  
  632. if (allocated) {
  633.   for (i= 0; i < ncolors; i++)
  634.     if (alloc[i])
  635.       XFreeColors(display, DefaultColormap(display, screen),
  636.                   &pixel[i], 1L, 0);
  637.   free(alloc);
  638.   free(pixel);
  639.   }
  640. }
  641.  
  642.  
  643. unsigned long ToPixel(level)
  644. int level;
  645. {
  646. if (level != 0)
  647.   level= ((level+coff) % (ncolors - 1)) + 1;
  648. return(pixel[level]);
  649. }
  650.  
  651.