home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xpaint-247 / palette.c < prev    next >
C/C++ Source or Header  |  1997-01-03  |  18KB  |  745 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. /* $Id: palette.c,v 1.3 1996/04/19 08:53:26 torsten Exp $ */
  16.  
  17. #include <X11/Intrinsic.h>
  18. #include <X11/StringDefs.h>
  19. #include <X11/Shell.h>
  20. #include <X11/Xatom.h>
  21. #include <stdio.h>
  22. #include "palette.h"
  23. #include "hash.h"
  24. #include "misc.h"
  25. #include "image.h"
  26. #include "xpaint.h"
  27.  
  28. typedef struct list_s {
  29.     Display *dpy;
  30.     Colormap cmap;
  31.     Palette *map;
  32.     struct list_s *next;
  33. } PaletteList;
  34.  
  35. typedef struct Col_s {
  36.     XColor color;
  37.     Boolean used;
  38.     Boolean invalid;
  39. } Col;
  40.  
  41. #define HASH_SIZE 128
  42. #define HASH(c)         ((int)((c).red + (c).green + (c).blue) % HASH_SIZE)
  43. #define HASH_PIXEL(c)     ((c) % HASH_SIZE)
  44.  
  45. static PaletteList *cmapList = NULL;
  46.  
  47. static int 
  48. readCMP(void *cca, void *ccb)
  49. {
  50.     XColor *ca = &((Col *) cca)->color, *cb = &((Col *) ccb)->color;
  51.  
  52.     if (ca->red != cb->red)
  53.     return ca->red < cb->red ? -1 : 1;
  54.     if (ca->green != cb->green)
  55.     return ca->green < cb->green ? -1 : 1;
  56.     if (ca->blue != cb->blue)
  57.     return ca->blue < cb->blue ? -1 : 1;
  58.     return 0;
  59. }
  60.  
  61. static int 
  62. cmpPixel(void *cca, void *ccb)
  63. {
  64.     if (((Col *) cca)->color.pixel == ((Col *) ccb)->color.pixel)
  65.     return 0;
  66.     return (((Col *) cca)->color.pixel < ((Col *) ccb)->color.pixel) ? -1 : 1;
  67. }
  68.  
  69. static void 
  70. freeFunc(void *junk)
  71. {
  72.     /*
  73.     **  Nop free func
  74.      */
  75. }
  76.  
  77. static void 
  78. entryUnlink(Palette * map, Col * node)
  79. {
  80.     node->used = True;
  81.     node->invalid = False;
  82.     map->nfree--;
  83. }
  84.  
  85.  
  86. #define STEP    256
  87.  
  88. static Palette *
  89. paletteNew(Widget w, Boolean useDefault)
  90. {
  91.     int i, v;
  92.     Display *dpy = XtDisplay(w);
  93.     Screen *screen = XtScreen(w);
  94.     Colormap rcmap = DefaultColormapOfScreen(screen);
  95.     Palette *map = XtNew(Palette);
  96.     Col *ctable;
  97.     Visual *visual = NULL;
  98.     PaletteList *new;
  99.     int end, depth = -1;
  100.     Boolean flg = False;
  101.  
  102.     XtVaGetValues(w, XtNvisual, &visual, XtNdepth, &depth, NULL);
  103.     if (visual == NULL || useDefault)
  104.     visual = DefaultVisualOfScreen(screen);
  105.     if (depth <= 0 || useDefault)
  106.     depth = DefaultDepthOfScreen(screen);
  107.  
  108.     map->htable = NULL;
  109.     map->ltable = NULL;
  110.     map->display = dpy;
  111.     map->htable = HashCreate(readCMP, freeFunc, HASH_SIZE);
  112.     map->ltable = HashCreate(cmpPixel, freeFunc, HASH_SIZE);
  113.     map->list = NULL;
  114.     map->last = NULL;
  115.     map->isMapped = visual->class != TrueColor;
  116.     map->isGrey = (visual->class == StaticGray || visual->class == GrayScale);
  117.     map->ncolors = visual->map_entries;
  118.     map->nfree = 0;
  119.     map->ctable = NULL;
  120.     map->visual = visual;
  121.     map->depth = depth;
  122.     map->userList = NULL;
  123.     map->isDefault = False;
  124.     map->mine = None;
  125.  
  126.     switch (visual->class) {
  127.     case TrueColor:
  128.     map->rShift = 0;
  129.     map->gShift = 0;
  130.     map->bShift = 0;
  131.     map->rRange = 1;
  132.     map->gRange = 1;
  133.     map->bRange = 1;
  134.     for (v = visual->red_mask; (v & 1) == 0; v >>= 1)
  135.         map->rShift++;
  136.     for (; (v & 1) == 1; v >>= 1)
  137.         map->rRange <<= 1;
  138.     for (v = visual->green_mask; (v & 1) == 0; v >>= 1)
  139.         map->gShift++;
  140.     for (; (v & 1) == 1; v >>= 1)
  141.         map->gRange <<= 1;
  142.     for (v = visual->blue_mask; (v & 1) == 0; v >>= 1)
  143.         map->bShift++;
  144.     for (; (v & 1) == 1; v >>= 1)
  145.         map->bRange <<= 1;
  146.     case StaticGray:
  147.     case StaticColor:
  148. #ifndef VMS
  149.     map->readonly = True;
  150. #else
  151.     map->Readonly = True;
  152. #endif
  153.     map->cmap = XCreateColormap(dpy, RootWindowOfScreen(screen),
  154.                     visual, AllocNone);
  155.     map->isDefault = False;
  156.     goto addlist;
  157.     default:
  158. #ifndef VMS
  159.     map->readonly = False;
  160. #else
  161.     map->Readonly = False;
  162. #endif
  163.     if (useDefault) {
  164.         map->cmap = rcmap;
  165.         map->isDefault = True;
  166.     } else {
  167.         map->cmap = XCreateColormap(dpy, RootWindowOfScreen(screen),
  168.                     visual, AllocAll);
  169.     }
  170.     break;
  171.     }
  172.  
  173.     ctable = (Col *) XtCalloc(sizeof(Col), visual->map_entries);
  174.     map->ctable = ctable;
  175.     end = CellsOfScreen(screen);
  176.     for (i = 0; i < visual->map_entries; i += STEP) {
  177.     XColor xcol[STEP];
  178.     int cnt = visual->map_entries - i;
  179.     int j, d;
  180.  
  181.     if (cnt > STEP)
  182.         cnt = STEP;
  183.  
  184.     for (j = 0; j < cnt; j++) {
  185.         Col *c = &ctable[i + j];
  186.  
  187.         c->color.pixel = i + j;
  188.         c->color.flags = DoRed | DoGreen | DoBlue;
  189.         xcol[j].pixel = i + j;
  190.         xcol[j].flags = DoRed | DoGreen | DoBlue;
  191.  
  192.         c->used = False;
  193.         c->invalid = False;
  194.     }
  195.  
  196.     if (i >= end)
  197.         d = 0;
  198.     else
  199.         d = MIN(end - i, cnt);
  200.  
  201.     if (i < end)
  202.         XQueryColors(dpy, rcmap, xcol, d);
  203.     if (!flg) {
  204.         for (j = d; j < cnt; j++) {
  205.         xcol[j].flags = DoRed | DoGreen | DoBlue;
  206.         xcol[j].red = xcol[j].green = xcol[j].blue = 0xffff;
  207.         }
  208.         if (d == 0)
  209.         flg = True;
  210.     }
  211.     if (!map->isDefault)
  212.         XStoreColors(dpy, map->cmap, xcol, cnt);
  213.  
  214.     for (j = 0; j < cnt; j++) {
  215.         Col *c = &ctable[i + j];
  216.  
  217.         c->color.red = xcol[j].red & 0xff00;
  218.         c->color.green = xcol[j].green & 0xff00;
  219.         c->color.blue = xcol[j].blue & 0xff00;
  220.         HashAdd(map->htable, HASH(c->color), c);
  221.         HashAdd(map->ltable, HASH_PIXEL(c->color.pixel), c);
  222.     }
  223.     }
  224.  
  225.     map->nfree = visual->map_entries;
  226.  
  227.     if (!map->isDefault) {
  228.     Boolean got = False;
  229.  
  230.     got = !map->isMapped;
  231.     for (i = 0; i < visual->map_entries; i++) {
  232.         if (ctable[i].color.pixel == BlackPixelOfScreen(screen)) {
  233.         entryUnlink(map, &ctable[i]);
  234.         } else if (ctable[i].color.pixel == WhitePixelOfScreen(screen)) {
  235.         entryUnlink(map, &ctable[i]);
  236.         } else if (!got) {
  237.         map->mine = i;
  238.         entryUnlink(map, &ctable[i]);
  239.         got = True;
  240.         }
  241.     }
  242.     }
  243.   addlist:
  244.     new = (PaletteList *) XtMalloc(sizeof(PaletteList));
  245.     new->dpy = XtDisplay(w);
  246.     new->cmap = map->cmap;
  247.     new->next = cmapList;
  248.     new->map = map;
  249.     cmapList = new;
  250.  
  251.     return map;
  252. }
  253.  
  254. Palette *
  255. PaletteCreate(Widget w)
  256. {
  257.     return paletteNew(GetShell(w), False);
  258. }
  259.  
  260. Palette *
  261. PaletteGetDefault(Widget w)
  262. {
  263.     static Palette *defMap = NULL;
  264.  
  265.     if (defMap == NULL)
  266.     defMap = paletteNew(GetShell(w), True);
  267.  
  268.     return defMap;
  269. }
  270.  
  271. static Palette *
  272. paletteGetBW(void)
  273. {
  274.     static Palette *map = NULL;
  275.     Col *ctable;
  276.  
  277.     if (map != NULL)
  278.     return map;
  279.  
  280.     map = XtNew(Palette);
  281.  
  282.     map->display = NULL;
  283.     map->htable = HashCreate(readCMP, freeFunc, HASH_SIZE);
  284.     map->ltable = HashCreate(cmpPixel, freeFunc, HASH_SIZE);
  285.     map->list = NULL;
  286.     map->last = NULL;
  287.     map->isMapped = True;
  288.     map->isGrey = True;
  289.     map->ncolors = 2;
  290.     map->nfree = 0;
  291.     map->ctable = NULL;
  292.     map->visual = None;        /* X */
  293.     map->depth = 1;
  294.     map->userList = NULL;
  295.     map->isDefault = False;
  296.     map->mine = None;
  297.     map->cmap = None;
  298.  
  299.     ctable = (Col *) XtCalloc(sizeof(Col), map->ncolors);
  300.     map->ctable = ctable;
  301.  
  302.     ctable[0].color.pixel = 0;
  303.     ctable[0].color.flags = DoRed | DoGreen | DoBlue;
  304.     ctable[0].color.red = 0xffff;
  305.     ctable[0].color.green = 0xffff;
  306.     ctable[0].color.blue = 0xffff;
  307.     ctable[0].used = True;
  308.     ctable[0].invalid = False;
  309.  
  310.     ctable[1].color.pixel = 1;
  311.     ctable[1].color.flags = DoRed | DoGreen | DoBlue;
  312.     ctable[1].color.red = 0x0000;
  313.     ctable[1].color.green = 0x0000;
  314.     ctable[1].color.blue = 0x0000;
  315.     ctable[1].used = True;
  316.     ctable[1].invalid = False;
  317.  
  318.     HashAdd(map->htable, HASH(ctable[0].color), &ctable[0]);
  319.     HashAdd(map->htable, HASH(ctable[1].color), &ctable[1]);
  320.     HashAdd(map->ltable, HASH_PIXEL(ctable[0].color.pixel), &ctable[0]);
  321.     HashAdd(map->ltable, HASH_PIXEL(ctable[1].color.pixel), &ctable[1]);
  322.  
  323.     return map;
  324. }
  325.  
  326. static void 
  327. addColor(Palette * map, XColor * color)
  328. {
  329.     Col *node, *n, *cptr;
  330.     int i;
  331.  
  332.  
  333. #ifndef VMS
  334.     if (map->readonly) {
  335. #else
  336.     if (map->Readonly) {
  337. #endif
  338.     /*
  339.     **  The temporary color is needed since alloc
  340.     **  will change the pixel values.
  341.      */
  342.     XColor newc;
  343.     newc = *color;
  344.     node = XtNew(Col);
  345.  
  346.     newc.flags = DoRed | DoGreen | DoBlue;
  347.     XAllocColor(map->display, map->cmap, &newc);
  348.     node->color.pixel = color->pixel = newc.pixel;
  349.     } else {
  350.     if (map->nfree == 0) {
  351.         unsigned int d, curDif = ~0;
  352.         int rd, gd, bd;
  353.         /*
  354.         **  All free colors used up -- use closest match.
  355.          */
  356.         for (i = 0, cptr = (Col *) map->ctable; i < map->ncolors; i++, cptr++) {
  357.         rd = (cptr->color.red >> 8) - (color->red >> 8);
  358.         gd = (cptr->color.green >> 8) - (color->green >> 8);
  359.         bd = (cptr->color.blue >> 8) - (color->blue >> 8);
  360.         d = rd * rd + gd * gd + bd * bd;
  361.         if (d < curDif) {
  362.             node = cptr;
  363.             curDif = d;
  364.         }
  365.         }
  366.         color->pixel = node->color.pixel;
  367.         return;
  368.     }
  369.     /* Find first free entry -- we know it's there. */
  370.     for (i = 0, node = (Col *) map->ctable;
  371.          (i < map->ncolors) && node->used; i++, node++);
  372.     entryUnlink(map, node);    /* mark as used */
  373.  
  374.     color->pixel = node->color.pixel;
  375.     n = HashFind(map->ltable, HASH_PIXEL(node->color.pixel), node);
  376.     HashRemove(map->ltable, HASH_PIXEL(node->color.pixel), n);
  377.     HashRemove(map->htable, HASH(*color), node);
  378.     }
  379.  
  380.     node->used = True;
  381.     node->invalid = False;
  382.     node->color.red = color->red & 0xff00;
  383.     node->color.green = color->green & 0xff00;
  384.     node->color.blue = color->blue & 0xff00;
  385.     node->color.flags = DoRed | DoGreen | DoBlue;
  386. #ifndef VMS
  387.     if (!map->readonly)
  388. #else
  389.     if (!map->Readonly)
  390. #endif
  391.     XStoreColor(map->display, map->cmap, &node->color);
  392.     HashAdd(map->htable, HASH(*color), node);
  393.     HashAdd(map->ltable, HASH_PIXEL(color->pixel), node);
  394. }
  395.  
  396. /*
  397.  * Try to allocate the specified XColor in the colormap.
  398.  * If the color is already in the palette, use that instead.
  399.  * Return the corresponding Pixel value in 'list'.
  400.  */
  401. static Col *
  402. allocN(Palette * map, XColor * color, Pixel * list)
  403. {
  404.     Col c, *node;
  405.  
  406.     c.color.red = color->red & 0xff00;
  407.     c.color.green = color->green & 0xff00;
  408.     c.color.blue = color->blue & 0xff00;
  409.  
  410.     if ((node = HashFind(map->htable, HASH(c.color), &c)) == NULL) {
  411.     addColor(map, color);
  412.     *list = color->pixel;
  413.     } else {
  414.     /*
  415.     **  It must have been allocated in the previous
  416.     **   pass, or by the above.
  417.      */
  418.     if (!node->used)
  419.         entryUnlink(map, node);
  420.     *list = node->color.pixel;
  421.     }
  422.  
  423.     return node;
  424. }
  425.  
  426. int 
  427. PaletteAllocN(Palette * map, XColor * color, int ncolor, Pixel * list)
  428. {
  429.     Boolean *flg = XtCalloc(sizeof(Boolean), ncolor);
  430.     Col c, *node;
  431.     int i;
  432.     Boolean newMine = False;
  433.  
  434.     if (!map->isMapped) {
  435.     for (i = 0; i < ncolor; i++) {
  436.         unsigned int r, g, b;
  437.  
  438.         r = (color[i].red * map->rRange) >> 16;
  439.         g = (color[i].green * map->gRange) >> 16;
  440.         b = (color[i].blue * map->bRange) >> 16;
  441.         list[i] = (r << map->rShift) | (g << map->gShift) | (b << map->bShift);
  442.     }
  443.     return 0;
  444.     }
  445.     for (i = 0; i < ncolor; i++) {
  446.     Col c;
  447.  
  448.     c.color.red = color[i].red & 0xff00;
  449.     c.color.green = color[i].green & 0xff00;
  450.     c.color.blue = color[i].blue & 0xff00;
  451.  
  452.     if ((node = HashFind(map->htable, HASH(c.color), &c)) != NULL) {
  453.         flg[i] = True;
  454.         /*
  455.         **  Match found, if the entry hasn't been "alloced"
  456.         **   yet, mark it so, and remove it from the "free" list.
  457.          */
  458.         if (!node->used)
  459.         entryUnlink(map, node);
  460.         list[i] = node->color.pixel;
  461.         if (list[i] == map->mine)
  462.         newMine = True;
  463.     } else {
  464.         flg[i] = False;
  465.     }
  466.     }
  467.  
  468.     for (i = 0; i < ncolor; i++) {
  469.     if (flg[i])
  470.         continue;
  471.  
  472.     c.color.red = color[i].red & 0xff00;
  473.     c.color.green = color[i].green & 0xff00;
  474.     c.color.blue = color[i].blue & 0xff00;
  475.  
  476.     if ((node = HashFind(map->htable, HASH(c.color), &c)) == NULL) {
  477.         addColor(map, &color[i]);
  478.         list[i] = color[i].pixel;
  479.     } else {
  480.         /*
  481.         **  It must have been allocated in the previous
  482.         **   pass, or by the above.
  483.          */
  484.         list[i] = node->color.pixel;
  485.     }
  486.     if (list[i] == map->mine)
  487.         newMine = True;
  488.     }
  489.  
  490.     XtFree((XtPointer) flg);
  491.  
  492.     if (newMine && map->ctable != NULL) {
  493.     Col *cptr = (Col *) map->ctable;
  494.  
  495.     for (i = 0; i < map->ncolors; i++, cptr++) {
  496.         if (cptr->used)
  497.         continue;
  498.         map->mine = cptr->color.pixel;
  499.         break;
  500.     }
  501.     }
  502.     return 0;
  503. }
  504.  
  505. /*
  506.  * Return the Pixel corresponding to (or closest to) the RGB
  507.  * values specified in 'color'.
  508.  * If no match is found in the existing palette, try to allocate
  509.  * a new color.
  510.  */
  511. Pixel
  512. PaletteAlloc(Palette * map, XColor * color)
  513. {
  514.     if (!map->isMapped) {
  515.     unsigned int r, g, b;
  516.  
  517.     r = (color->red * map->rRange) >> 16;
  518.     g = (color->green * map->gRange) >> 16;
  519.     b = (color->blue * map->bRange) >> 16;
  520.     return (r << map->rShift) | (g << map->gShift) | (b << map->bShift);
  521.     }
  522.     if (map->last != NULL) {
  523.     XColor *lc = (XColor *) map->last;
  524.  
  525.     if (lc->red == color->red &&
  526.         lc->green == color->green &&
  527.         lc->blue == color->blue)
  528.         return color->pixel = lc->pixel;
  529.     }
  530.     map->last = allocN(map, color, &color->pixel);
  531.  
  532.     return color->pixel;
  533. }
  534.  
  535. /*
  536. **  Given a Pixel value on the specified map return the
  537. **   RGB value.
  538. **  On non-TrueColor displays, the returned value is actually a pointer
  539. **   into map->ctable[].
  540. **
  541. **   Special case "TrueColor" since it is just computed.
  542.  */
  543. XColor *
  544. PaletteLookup(Palette * map, Pixel pix)
  545. {
  546.     if (map->isMapped) {
  547.     Col col;
  548.     Col *c;
  549.     col.color.pixel = pix;
  550.  
  551.     if ((c = (Col *) HashFind(map->ltable, HASH_PIXEL(pix), &col)) == NULL) {
  552.         printf("Shouldn't happen\n");
  553.         return NULL;
  554.     }
  555.     if (c->invalid) {
  556.         HashRemove(map->htable, HASH(c->color), c);
  557.         XQueryColor(map->display, map->cmap, &c->color);
  558.         c->color.red &= 0xff00;
  559.         c->color.green &= 0xff00;
  560.         c->color.blue &= 0xff00;
  561.         HashAdd(map->htable, HASH(c->color), c);
  562.         c->invalid = False;
  563.     }
  564.     return &c->color;
  565.     } else {
  566.     static XColor xc;
  567.  
  568.     xc.red = (pix >> map->rShift) & (map->rRange - 1);
  569.     xc.green = (pix >> map->gShift) & (map->gRange - 1);
  570.     xc.blue = (pix >> map->bShift) & (map->bRange - 1);
  571.  
  572.     xc.red *= 65536 / map->rRange;
  573.     xc.green *= 65536 / map->gRange;
  574.     xc.blue *= 65536 / map->bRange;
  575.  
  576.     return &xc;
  577.     }
  578. }
  579.  
  580. Boolean
  581. PaletteLookupColor(Palette * map, XColor * col, Pixel * pxl)
  582. {
  583.     Col c, *node;
  584.  
  585.     if (!map->isMapped) {
  586.     unsigned int r, g, b;
  587.  
  588.     r = (col->red * map->rRange) >> 16;
  589.     g = (col->green * map->gRange) >> 16;
  590.     b = (col->blue * map->bRange) >> 16;
  591.     *pxl = (r << map->rShift) | (g << map->gShift) | (b << map->bShift);
  592.     return True;
  593.     }
  594.     c.color.red = col->red & 0xff00;
  595.     c.color.green = col->green & 0xff00;
  596.     c.color.blue = col->blue & 0xff00;
  597.  
  598.     if ((node = HashFind(map->htable, HASH(c.color), &c)) != NULL) {
  599.     *pxl = node->color.pixel;
  600.     return True;
  601.     }
  602.     return False;
  603. }
  604.  
  605. Pixel
  606. PaletteGetUnused(Palette * map)
  607. {
  608.     return map->mine;
  609. }
  610.  
  611. /*
  612. **  Change the RGB value of a pixel
  613.  */
  614. void 
  615. PaletteSetInvalid(Palette * map, Pixel pix)
  616. {
  617.     Col col, *c;
  618.  
  619. #ifndef VMS
  620.     if (!map->isMapped || map->readonly)
  621. #else
  622.     if (!map->isMapped || map->Readonly)
  623. #endif
  624.     return;
  625.  
  626.     col.color.pixel = pix;
  627.  
  628.     if ((c = (Col *) HashFind(map->ltable, HASH_PIXEL(pix), &col)) == NULL)
  629.     return;
  630.  
  631.     c->invalid = True;
  632. }
  633.  
  634. /*
  635. **  This will fail if on a read only colormap
  636.  */
  637. Boolean
  638. PaletteSetPixel(Palette * map, Pixel pixel, XColor * xcol)
  639. {
  640.     Col col, *c;
  641.  
  642. #ifndef VMS
  643.     if (map->readonly)
  644. #else
  645.     if (map->Readonly)
  646. #endif
  647.     return False;
  648.  
  649.     if (map->isDefault)
  650.     return False;
  651.  
  652.     xcol->pixel = pixel;
  653.     xcol->flags = DoRed | DoGreen | DoBlue;
  654.     XStoreColor(map->display, map->cmap, xcol);
  655.  
  656.     col.color.pixel = pixel;
  657.  
  658.     if ((c = (Col *) HashFind(map->ltable, HASH_PIXEL(pixel), &col)) != NULL)
  659.     c->invalid = True;
  660.  
  661.     return True;
  662. }
  663.  
  664. Palette *
  665. PaletteFindDpy(Display * dpy, Colormap cmap)
  666. {
  667.     PaletteList *cur;
  668.  
  669.     if (cmap == -1)
  670.     return paletteGetBW();
  671.  
  672.     for (cur = cmapList; cur != NULL; cur = cur->next)
  673.     if (cur->cmap == cmap && cur->dpy == dpy)
  674.         return cur->map;
  675.  
  676.     return NULL;
  677. }
  678.  
  679. Palette *
  680. PaletteFind(Widget w, Colormap cmap)
  681. {
  682.     return PaletteFindDpy(XtDisplay(w), cmap);
  683. }
  684.  
  685. static void 
  686. paletteAddUserDestroy(Widget w, Palette * map, XtPointer junk)
  687. {
  688.     paletteUserList *cur = map->userList;
  689.     paletteUserList **prev = &map->userList;
  690.  
  691.     while (cur != NULL && cur->widget != w) {
  692.     prev = &cur->next;
  693.     cur = cur->next;
  694.     }
  695.  
  696.     if (cur == NULL)
  697.     return;
  698.  
  699.     *prev = cur->next;
  700.     XtFree((XtPointer) cur);
  701. }
  702.  
  703. void 
  704. PaletteDelete(Palette * map)
  705. {
  706.     PaletteList *cur, **prev;
  707.     paletteUserList *ul, *nx;
  708.  
  709.     HashDestroy(map->htable);
  710.     HashDestroy(map->ltable);
  711.     if (map->ctable != NULL)
  712.     XtFree((XtPointer) map->ctable);
  713.  
  714.     for (cur = cmapList, prev = &cmapList; cur != NULL && cur->map != map;
  715.      prev = &cur->next, cur = cur->next);
  716.  
  717.     if (cur != NULL)
  718.     *prev = cur->next;
  719.  
  720.     ul = map->userList;
  721.     while (ul != NULL) {
  722.     nx = ul->next;
  723.     XtRemoveCallback(ul->widget, XtNdestroyCallback,
  724.              (XtCallbackProc) paletteAddUserDestroy,
  725.              (XtPointer) map);
  726.     XtFree((XtPointer) ul);
  727.     ul = nx;
  728.     }
  729.  
  730.     XtFree((XtPointer) map);
  731.     XtFree((XtPointer) cur);
  732. }
  733.  
  734. void 
  735. PaletteAddUser(Palette * map, Widget w)
  736. {
  737.     paletteUserList *n = XtNew(paletteUserList);
  738.  
  739.     n->widget = w;
  740.     n->next = map->userList;
  741.     map->userList = n;
  742.     XtAddCallback(w, XtNdestroyCallback,
  743.           (XtCallbackProc) paletteAddUserDestroy, (XtPointer) map);
  744. }
  745.