home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tk4.0 / tkColor.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-18  |  21.4 KB  |  714 lines

  1. /* 
  2.  * tkColor.c --
  3.  *
  4.  *    This file maintains a database of color values for the Tk
  5.  *    toolkit, in order to avoid round-trips to the server to
  6.  *    map color names to pixel values.
  7.  *
  8.  * Copyright (c) 1990-1994 The Regents of the University of California.
  9.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  */
  14.  
  15. static char sccsid[] = "@(#) tkColor.c 1.36 95/03/18 15:43:38";
  16.  
  17. #include "tkPort.h"
  18. #include "tk.h"
  19. #include "tkInt.h"
  20.  
  21. /*
  22.  * A two-level data structure is used to manage the color database.
  23.  * The top level consists of one entry for each color name that is
  24.  * currently active, and the bottom level contains one entry for each
  25.  * pixel value that is still in use.  The distinction between
  26.  * levels is necessary because the same pixel may have several
  27.  * different names.  There are two hash tables, one used to index into
  28.  * each of the data structures.  The name hash table is used when
  29.  * allocating colors, and the pixel hash table is used when freeing
  30.  * colors.
  31.  */
  32.  
  33. /*
  34.  * One of the following data structures is used to keep track of
  35.  * each color that this module has allocated from the X display
  36.  * server.  These entries are indexed by two hash tables defined
  37.  * below:  nameTable and valueTable.
  38.  */
  39.  
  40. #define COLOR_MAGIC ((unsigned int) 0x46140277)
  41.  
  42. typedef struct TkColor {
  43.     XColor color;        /* Information about this color. */
  44.     unsigned int magic;        /* Used for quick integrity check on this
  45.                  * structure.   Must always have the
  46.                  * value COLOR_MAGIC. */
  47.     GC gc;            /* Simple gc with this color as foreground
  48.                  * color and all other fields defaulted.
  49.                  * May be None. */
  50.     Screen *screen;        /* Screen where this color is valid.  Used
  51.                  * to delete it, and to find its display. */
  52.     Colormap colormap;        /* Colormap from which this entry was
  53.                  * allocated. */
  54.     Visual *visual;             /* Visual associated with colormap. */
  55.     int refCount;        /* Number of uses of this structure. */
  56.     Tcl_HashTable *tablePtr;    /* Hash table that indexes this structure
  57.                  * (needed when deleting structure). */
  58.     Tcl_HashEntry *hashPtr;    /* Pointer to hash table entry for this
  59.                  * structure. (for use in deleting entry). */
  60. } TkColor;
  61.  
  62. /*
  63.  * Hash table for name -> TkColor mapping, and key structure used to
  64.  * index into that table:
  65.  */
  66.  
  67. static Tcl_HashTable nameTable;
  68. typedef struct {
  69.     Tk_Uid name;        /* Name of desired color. */
  70.     Colormap colormap;        /* Colormap from which color will be
  71.                  * allocated. */
  72.     Display *display;        /* Display for colormap. */
  73. } NameKey;
  74.  
  75. /*
  76.  * Hash table for value -> TkColor mapping, and key structure used to
  77.  * index into that table:
  78.  */
  79.  
  80. static Tcl_HashTable valueTable;
  81. typedef struct {
  82.     int red, green, blue;    /* Values for desired color. */
  83.     Colormap colormap;        /* Colormap from which color will be
  84.                  * allocated. */
  85.     Display *display;        /* Display for colormap. */
  86. } ValueKey;
  87.  
  88. static int initialized = 0;    /* 0 means static structures haven't been
  89.                  * initialized yet. */
  90.  
  91. /*
  92.  * If a colormap fills up, attempts to allocate new colors from that
  93.  * colormap will fail.  When that happens, we'll just choose the
  94.  * closest color from those that are available in the colormap.
  95.  * One of the following structures will be created for each "stressed"
  96.  * colormap to keep track of the colors that are available in the
  97.  * colormap (otherwise we would have to re-query from the server on
  98.  * each allocation, which would be very slow).  These entries are
  99.  * flushed after a few seconds, since other clients may release or
  100.  * reallocate colors over time.
  101.  */
  102.  
  103. struct TkStressedCmap {
  104.     Colormap colormap;            /* X's token for the colormap. */
  105.     int numColors;            /* Number of entries currently active
  106.                      * at *colorPtr. */
  107.     XColor *colorPtr;            /* Pointer to malloc'ed array of all
  108.                      * colors that seem to be available in
  109.                      * the colormap.  Some may not actually
  110.                      * be available, e.g. because they are
  111.                      * read-write for another client;  when
  112.                      * we find this out, we remove them
  113.                      * from the array. */
  114.     struct TkStressedCmap *nextPtr;    /* Next in list of all stressed
  115.                      * colormaps for the display. */
  116. };
  117.  
  118. /*
  119.  * Forward declarations for procedures defined in this file:
  120.  */
  121.  
  122. static void        ColorInit _ANSI_ARGS_((void));
  123. static void        DeleteStressedCmap _ANSI_ARGS_((Display *display,
  124.                 Colormap colormap));
  125. static void        FindClosestColor _ANSI_ARGS_((Tk_Window tkwin,
  126.                 XColor *desiredColorPtr, XColor *actualColorPtr));
  127.  
  128. /*
  129.  *----------------------------------------------------------------------
  130.  *
  131.  * Tk_GetColor --
  132.  *
  133.  *    Given a string name for a color, map the name to a corresponding
  134.  *    XColor structure.
  135.  *
  136.  * Results:
  137.  *    The return value is a pointer to an XColor structure that
  138.  *    indicates the red, blue, and green intensities for the color
  139.  *    given by "name", and also specifies a pixel value to use to
  140.  *    draw in that color.  If an error occurs, NULL is returned and
  141.  *    an error message will be left in interp->result.
  142.  *
  143.  * Side effects:
  144.  *    The color is added to an internal database with a reference count.
  145.  *    For each call to this procedure, there should eventually be a call
  146.  *    to Tk_FreeColor so that the database is cleaned up when colors
  147.  *    aren't in use anymore.
  148.  *
  149.  *----------------------------------------------------------------------
  150.  */
  151.  
  152. XColor *
  153. Tk_GetColor(interp, tkwin, name)
  154.     Tcl_Interp *interp;        /* Place to leave error message if
  155.                  * color can't be found. */
  156.     Tk_Window tkwin;        /* Window in which color will be used. */
  157.     Tk_Uid name;        /* Name of color to allocated (in form
  158.                  * suitable for passing to XParseColor). */
  159. {
  160.     NameKey nameKey;
  161.     Tcl_HashEntry *nameHashPtr;
  162.     int new;
  163.     TkColor *tkColPtr;
  164.     XColor color;
  165.     Display *display = Tk_Display(tkwin);
  166.  
  167.     if (!initialized) {
  168.     ColorInit();
  169.     }
  170.  
  171.     /*
  172.      * First, check to see if there's already a mapping for this color
  173.      * name.
  174.      */
  175.  
  176.     nameKey.name = name;
  177.     nameKey.colormap = Tk_Colormap(tkwin);
  178.     nameKey.display = display;
  179.     nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new);
  180.     if (!new) {
  181.     tkColPtr = (TkColor *) Tcl_GetHashValue(nameHashPtr);
  182.     tkColPtr->refCount++;
  183.     return &tkColPtr->color;
  184.     }
  185.  
  186.     /*
  187.      * The name isn't currently known.  Map from the name to a pixel
  188.      * value.  Call XAllocNamedColor rather than XParseColor for non-# names:
  189.      * this saves a server round-trip for those names.
  190.      */
  191.  
  192.     if (*name != '#') {
  193.     XColor screen;
  194.  
  195.     if (XAllocNamedColor(display, nameKey.colormap, name, &screen,
  196.         &color) != 0) {
  197.         DeleteStressedCmap(display, nameKey.colormap);
  198.     } else {
  199.         /*
  200.          * Couldn't allocate the color.  Try translating the name to
  201.          * a color value, to see whether the problem is a bad color
  202.          * name or a full colormap.  If the colormap is full, then
  203.          * pick an approximation to the desired color.
  204.          */
  205.  
  206.         if (XLookupColor(display, nameKey.colormap, name, &color,
  207.             &screen) == 0) {
  208.         Tcl_AppendResult(interp, "unknown color name \"",
  209.             name, "\"", (char *) NULL);
  210.         Tcl_DeleteHashEntry(nameHashPtr);
  211.         return (XColor *) NULL;
  212.         }
  213.         FindClosestColor(tkwin, &screen, &color);
  214.     }
  215.     } else {
  216.     if (XParseColor(display, nameKey.colormap, name, &color) == 0) {
  217.         Tcl_AppendResult(interp, "invalid color name \"", name,
  218.             "\"", (char *) NULL);
  219.         Tcl_DeleteHashEntry(nameHashPtr);
  220.         return (XColor *) NULL;
  221.     }
  222.     if (XAllocColor(display, nameKey.colormap, &color) != 0) {
  223.         DeleteStressedCmap(display, nameKey.colormap);
  224.     } else {
  225.         FindClosestColor(tkwin, &color, &color);
  226.     }
  227.     }
  228.  
  229.     /*
  230.      * Now create a new TkColor structure and add it to nameTable.
  231.      */
  232.  
  233.     tkColPtr = (TkColor *) ckalloc(sizeof(TkColor));
  234.     tkColPtr->color = color;
  235.     tkColPtr->magic = COLOR_MAGIC;
  236.     tkColPtr->gc = None;
  237.     tkColPtr->screen = Tk_Screen(tkwin);
  238.     tkColPtr->colormap = nameKey.colormap;
  239.     tkColPtr->visual  = Tk_Visual(tkwin);
  240.     tkColPtr->refCount = 1;
  241.     tkColPtr->tablePtr = &nameTable;
  242.     tkColPtr->hashPtr = nameHashPtr;
  243.     Tcl_SetHashValue(nameHashPtr, tkColPtr);
  244.  
  245.     return &tkColPtr->color;
  246. }
  247.  
  248. /*
  249.  *----------------------------------------------------------------------
  250.  *
  251.  * Tk_GetColorByValue --
  252.  *
  253.  *    Given a desired set of red-green-blue intensities for a color,
  254.  *    locate a pixel value to use to draw that color in a given
  255.  *    window.
  256.  *
  257.  * Results:
  258.  *    The return value is a pointer to an XColor structure that
  259.  *    indicates the closest red, blue, and green intensities available
  260.  *    to those specified in colorPtr, and also specifies a pixel
  261.  *    value to use to draw in that color.
  262.  *
  263.  * Side effects:
  264.  *    The color is added to an internal database with a reference count.
  265.  *    For each call to this procedure, there should eventually be a call
  266.  *    to Tk_FreeColor, so that the database is cleaned up when colors
  267.  *    aren't in use anymore.
  268.  *
  269.  *----------------------------------------------------------------------
  270.  */
  271.  
  272. XColor *
  273. Tk_GetColorByValue(tkwin, colorPtr)
  274.     Tk_Window tkwin;        /* Window where color will be used. */
  275.     XColor *colorPtr;        /* Red, green, and blue fields indicate
  276.                  * desired color. */
  277. {
  278.     ValueKey valueKey;
  279.     Tcl_HashEntry *valueHashPtr;
  280.     int new;
  281.     TkColor *tkColPtr;
  282.     Display *display = Tk_Display(tkwin);
  283.  
  284.     if (!initialized) {
  285.     ColorInit();
  286.     }
  287.  
  288.     /*
  289.      * First, check to see if there's already a mapping for this color
  290.      * name.
  291.      */
  292.  
  293.     valueKey.red = colorPtr->red;
  294.     valueKey.green = colorPtr->green;
  295.     valueKey.blue = colorPtr->blue;
  296.     valueKey.colormap = Tk_Colormap(tkwin);
  297.     valueKey.display = display;
  298.     valueHashPtr = Tcl_CreateHashEntry(&valueTable, (char *) &valueKey, &new);
  299.     if (!new) {
  300.     tkColPtr = (TkColor *) Tcl_GetHashValue(valueHashPtr);
  301.     tkColPtr->refCount++;
  302.     return &tkColPtr->color;
  303.     }
  304.  
  305.     /*
  306.      * The name isn't currently known.  Find a pixel value for this
  307.      * color and add a new structure to valueTable.
  308.      */
  309.  
  310.     tkColPtr = (TkColor *) ckalloc(sizeof(TkColor));
  311.     tkColPtr->color.red = valueKey.red;
  312.     tkColPtr->color.green = valueKey.green;
  313.     tkColPtr->color.blue = valueKey.blue;
  314.     if (XAllocColor(display, valueKey.colormap, &tkColPtr->color) != 0) {
  315.     DeleteStressedCmap(display, valueKey.colormap);
  316.     } else {
  317.     FindClosestColor(tkwin, &tkColPtr->color, &tkColPtr->color);
  318.     }
  319.     tkColPtr->magic = COLOR_MAGIC;
  320.     tkColPtr->gc = None;
  321.     tkColPtr->screen = Tk_Screen(tkwin);
  322.     tkColPtr->colormap = valueKey.colormap;
  323.     tkColPtr->visual  = Tk_Visual(tkwin);
  324.     tkColPtr->refCount = 1;
  325.     tkColPtr->tablePtr = &valueTable;
  326.     tkColPtr->hashPtr = valueHashPtr;
  327.     Tcl_SetHashValue(valueHashPtr, tkColPtr);
  328.     return &tkColPtr->color;
  329. }
  330.  
  331. /*
  332.  *--------------------------------------------------------------
  333.  *
  334.  * Tk_NameOfColor --
  335.  *
  336.  *    Given a color, return a textual string identifying
  337.  *    the color.
  338.  *
  339.  * Results:
  340.  *    If colorPtr was created by Tk_GetColor, then the return
  341.  *    value is the "string" that was used to create it.
  342.  *    Otherwise the return value is a string that could have
  343.  *    been passed to Tk_GetColor to allocate that color.  The
  344.  *    storage for the returned string is only guaranteed to
  345.  *    persist up until the next call to this procedure.
  346.  *
  347.  * Side effects:
  348.  *    None.
  349.  *
  350.  *--------------------------------------------------------------
  351.  */
  352.  
  353. char *
  354. Tk_NameOfColor(colorPtr)
  355.     XColor *colorPtr;        /* Color whose name is desired. */
  356. {
  357.     register TkColor *tkColPtr = (TkColor *) colorPtr;
  358.     static char string[20];
  359.  
  360.     if ((tkColPtr->magic == COLOR_MAGIC)
  361.         && (tkColPtr->tablePtr == &nameTable)) {
  362.     return ((NameKey *) tkColPtr->hashPtr->key.words)->name;
  363.     }
  364.     sprintf(string, "#%04x%04x%04x", colorPtr->red, colorPtr->green,
  365.         colorPtr->blue);
  366.     return string;
  367. }
  368.  
  369. /*
  370.  *----------------------------------------------------------------------
  371.  *
  372.  * Tk_GCForColor --
  373.  *
  374.  *    Given a color allocated from this module, this procedure
  375.  *    returns a GC that can be used for simple drawing with that
  376.  *    color.
  377.  *
  378.  * Results:
  379.  *    The return value is a GC with color set as its foreground
  380.  *    color and all other fields defaulted.  This GC is only valid
  381.  *    as long as the color exists;  it is freed automatically when
  382.  *    the last reference to the color is freed.
  383.  *
  384.  * Side effects:
  385.  *    None.
  386.  *
  387.  *----------------------------------------------------------------------
  388.  */
  389.  
  390. GC
  391. Tk_GCForColor(colorPtr, drawable)
  392.     XColor *colorPtr;        /* Color for which a GC is desired. Must
  393.                  * have been allocated by Tk_GetColor or
  394.                  * Tk_GetColorByName. */
  395.     Drawable drawable;        /* Drawable in which the color will be
  396.                  * used (must have same screen and depth
  397.                  * as the one for which the color was
  398.                  * allocated). */
  399. {
  400.     TkColor *tkColPtr = (TkColor *) colorPtr;
  401.     XGCValues gcValues;
  402.  
  403.     /*
  404.      * Do a quick sanity check to make sure this color was really
  405.      * allocated by Tk_GetColor.
  406.      */
  407.  
  408.     if (tkColPtr->magic != COLOR_MAGIC) {
  409.     panic("Tk_GCForColor called with bogus color");
  410.     }
  411.  
  412.     if (tkColPtr->gc == None) {
  413.     gcValues.foreground = tkColPtr->color.pixel;
  414.     tkColPtr->gc = XCreateGC(DisplayOfScreen(tkColPtr->screen),
  415.         drawable, GCForeground, &gcValues);
  416.     }
  417.     return tkColPtr->gc;
  418. }
  419.  
  420. /*
  421.  *----------------------------------------------------------------------
  422.  *
  423.  * Tk_FreeColor --
  424.  *
  425.  *    This procedure is called to release a color allocated by
  426.  *    Tk_GetColor.
  427.  *
  428.  * Results:
  429.  *    None.
  430.  *
  431.  * Side effects:
  432.  *    The reference count associated with colorPtr is deleted, and
  433.  *    the color is released to X if there are no remaining uses
  434.  *    for it.
  435.  *
  436.  *----------------------------------------------------------------------
  437.  */
  438.  
  439. void
  440. Tk_FreeColor(colorPtr)
  441.     XColor *colorPtr;        /* Color to be released.  Must have been
  442.                  * allocated by Tk_GetColor or
  443.                  * Tk_GetColorByValue. */
  444. {
  445.     register TkColor *tkColPtr = (TkColor *) colorPtr;
  446.     Visual *visual;
  447.     Screen *screen = tkColPtr->screen;
  448.  
  449.     /*
  450.      * Do a quick sanity check to make sure this color was really
  451.      * allocated by Tk_GetColor.
  452.      */
  453.  
  454.     if (tkColPtr->magic != COLOR_MAGIC) {
  455.     panic("Tk_FreeColor called with bogus color");
  456.     }
  457.  
  458.     tkColPtr->refCount--;
  459.     if (tkColPtr->refCount == 0) {
  460.  
  461.     /*
  462.      * Careful!  Don't free black or white, since this will
  463.      * make some servers very unhappy.  Also, there is a bug in
  464.      * some servers (such Sun's X11/NeWS server) where reference
  465.      * counting is performed incorrectly, so that if a color is
  466.      * allocated twice in different places and then freed twice,
  467.      * the second free generates an error (this bug existed as of
  468.      * 10/1/92).  To get around this problem, ignore errors that
  469.      * occur during the free operation.
  470.      */
  471.  
  472.     visual = tkColPtr->visual;
  473.     if ((visual->class != StaticGray) && (visual->class != StaticColor)
  474.         && (tkColPtr->color.pixel != BlackPixelOfScreen(screen))
  475.         && (tkColPtr->color.pixel != WhitePixelOfScreen(screen))) {
  476.         Tk_ErrorHandler handler;
  477.  
  478.         handler = Tk_CreateErrorHandler(DisplayOfScreen(screen),
  479.             -1, -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
  480.         XFreeColors(DisplayOfScreen(screen), tkColPtr->colormap,
  481.             &tkColPtr->color.pixel, 1, 0L);
  482.         Tk_DeleteErrorHandler(handler);
  483.     }
  484.     if (tkColPtr->gc != None) {
  485.         XFreeGC(DisplayOfScreen(screen), tkColPtr->gc);
  486.     }
  487.     DeleteStressedCmap(DisplayOfScreen(screen), tkColPtr->colormap);
  488.     Tcl_DeleteHashEntry(tkColPtr->hashPtr);
  489.     tkColPtr->magic = 0;
  490.     ckfree((char *) tkColPtr);
  491.     }
  492. }
  493.  
  494. /*
  495.  *----------------------------------------------------------------------
  496.  *
  497.  * ColorInit --
  498.  *
  499.  *    Initialize the structure used for color management.
  500.  *
  501.  * Results:
  502.  *    None.
  503.  *
  504.  * Side effects:
  505.  *    Read the code.
  506.  *
  507.  *----------------------------------------------------------------------
  508.  */
  509.  
  510. static void
  511. ColorInit()
  512. {
  513.     initialized = 1;
  514.     Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int));
  515.     Tcl_InitHashTable(&valueTable, sizeof(ValueKey)/sizeof(int));
  516. }
  517.  
  518. /*
  519.  *----------------------------------------------------------------------
  520.  *
  521.  * FindClosestColor --
  522.  *
  523.  *    When Tk can't allocate a color because a colormap has filled
  524.  *    up, this procedure is called to find and allocate the closest
  525.  *    available color in the colormap.
  526.  *
  527.  * Results:
  528.  *    There is no return value, but *actualColorPtr is filled in
  529.  *    with information about the closest available color in tkwin's
  530.  *    colormap.  This color has been allocated via X, so it must
  531.  *    be released by the caller when the caller is done with it.
  532.  *
  533.  * Side effects:
  534.  *    A color is allocated.
  535.  *
  536.  *----------------------------------------------------------------------
  537.  */
  538.  
  539. static void
  540. FindClosestColor(tkwin, desiredColorPtr, actualColorPtr)
  541.     Tk_Window tkwin;            /* Window where color will be used. */
  542.     XColor *desiredColorPtr;        /* RGB values of color that was
  543.                      * wanted (but unavailable). */
  544.     XColor *actualColorPtr;        /* Structure to fill in with RGB and
  545.                      * pixel for closest available
  546.                      * color. */
  547. {
  548.     TkStressedCmap *stressPtr;
  549.     float tmp, distance, closestDistance;
  550.     int i, closest;
  551.     XColor *colorPtr;
  552.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  553.     Colormap colormap = Tk_Colormap(tkwin);
  554.  
  555.     /*
  556.      * Find the TkStressedCmap structure for this colormap, or create
  557.      * a new one if needed.
  558.      */
  559.  
  560.     for (stressPtr = dispPtr->stressPtr; ; stressPtr = stressPtr->nextPtr) {
  561.     if (stressPtr == NULL) {
  562.         stressPtr = (TkStressedCmap *) ckalloc(sizeof(TkStressedCmap));
  563.         stressPtr->colormap = colormap;
  564.         stressPtr->numColors = 1<<Tk_Depth(tkwin);
  565.         stressPtr->colorPtr = (XColor *) ckalloc((unsigned)
  566.             (stressPtr->numColors * sizeof(XColor)));
  567.         for (i = 0; i  < stressPtr->numColors; i++) {
  568.         stressPtr->colorPtr[i].pixel = (unsigned long) i;
  569.         }
  570.         XQueryColors(dispPtr->display, colormap, stressPtr->colorPtr,
  571.             stressPtr->numColors);
  572.         stressPtr->nextPtr = dispPtr->stressPtr;
  573.         dispPtr->stressPtr = stressPtr;
  574.         break;
  575.     }
  576.     if (stressPtr->colormap == colormap) {
  577.         break;
  578.     }
  579.     }
  580.  
  581.     /*
  582.      * Find the color that best approximates the desired one, then
  583.      * try to allocate that color.  If that fails, it must mean that
  584.      * the color was read-write (so we can't use it, since it's owner
  585.      * might change it) or else it was already freed.  Try again,
  586.      * over and over again, until something succeeds.
  587.      */
  588.  
  589.     while (1)  {
  590.     if (stressPtr->numColors == 0) {
  591.         panic("FindClosestColor ran out of colors");
  592.     }
  593.     closestDistance = 1e30;
  594.     closest = 0;
  595.     for (colorPtr = stressPtr->colorPtr, i = 0; i < stressPtr->numColors;
  596.         colorPtr++, i++) {
  597.         /*
  598.          * Use Euclidean distance in RGB space, weighted by Y (of YIQ)
  599.          * as the objective function;  this accounts for differences
  600.          * in the color sensitivity of the eye.
  601.          */
  602.     
  603.         tmp = .30*(((int) desiredColorPtr->red) - (int) colorPtr->red);
  604.         distance = tmp*tmp;
  605.         tmp = .61*(((int) desiredColorPtr->green) - (int) colorPtr->green);
  606.         distance += tmp*tmp;
  607.         tmp = .11*(((int) desiredColorPtr->blue) - (int) colorPtr->blue);
  608.         distance += tmp*tmp;
  609.         if (distance < closestDistance) {
  610.         closest = i;
  611.         closestDistance = distance;
  612.         }
  613.     }
  614.     if (XAllocColor(dispPtr->display, colormap,
  615.         &stressPtr->colorPtr[closest]) != 0) {
  616.         *actualColorPtr = stressPtr->colorPtr[closest];
  617.         return;
  618.     }
  619.  
  620.     /*
  621.      * Couldn't allocate the color.  Remove it from the table and
  622.      * go back to look for the next best color.
  623.      */
  624.  
  625.     stressPtr->colorPtr[closest] =
  626.         stressPtr->colorPtr[stressPtr->numColors-1];
  627.     stressPtr->numColors -= 1;
  628.     }
  629. }
  630.  
  631. /*
  632.  *----------------------------------------------------------------------
  633.  *
  634.  * TkCmapStressed --
  635.  *
  636.  *    Check to see whether a given colormap is known to be out
  637.  *    of entries.
  638.  *
  639.  * Results:
  640.  *    1 is returned if "colormap" is stressed (i.e. it has run out
  641.  *    of entries recently), 0 otherwise.
  642.  *
  643.  * Side effects:
  644.  *    None.
  645.  *
  646.  *----------------------------------------------------------------------
  647.  */
  648.  
  649. int
  650. TkCmapStressed(tkwin, colormap)
  651.     Tk_Window tkwin;        /* Window that identifies the display
  652.                  * containing the colormap. */
  653.     Colormap colormap;        /* Colormap to check for stress. */
  654. {
  655.     TkStressedCmap *stressPtr;
  656.  
  657.     for (stressPtr = ((TkWindow *) tkwin)->dispPtr->stressPtr;
  658.         stressPtr != NULL; stressPtr = stressPtr->nextPtr) {
  659.     if (stressPtr->colormap == colormap) {
  660.         return 1;
  661.     }
  662.     }
  663.     return 0;
  664. }
  665.  
  666. /*
  667.  *----------------------------------------------------------------------
  668.  *
  669.  * DeleteStressedCmap --
  670.  *
  671.  *    This procedure releases the information cached for "colormap"
  672.  *    so that it will be refetched from the X server the next time
  673.  *    it is needed.
  674.  *
  675.  * Results:
  676.  *    None.
  677.  *
  678.  * Side effects:
  679.  *    The TkStressedCmap structure for colormap is deleted;  the
  680.  *    colormap is no longer considered to be "stressed".
  681.  *
  682.  * Note:
  683.  *    This procedure is invoked whenever a color in a colormap is
  684.  *    freed, and whenever a color allocation in a colormap succeeds.
  685.  *    This guarantees that TkStressedCmap structures are always
  686.  *    deleted before the corresponding Colormap is freed.
  687.  *
  688.  *----------------------------------------------------------------------
  689.  */
  690.  
  691. static void
  692. DeleteStressedCmap(display, colormap)
  693.     Display *display;        /* Xlib's handle for the display
  694.                  * containing the colormap. */
  695.     Colormap colormap;        /* Colormap to flush. */
  696. {
  697.     TkStressedCmap *prevPtr, *stressPtr;
  698.     TkDisplay *dispPtr = TkGetDisplay(display);
  699.  
  700.     for (prevPtr = NULL, stressPtr = dispPtr->stressPtr; stressPtr != NULL;
  701.         prevPtr = stressPtr, stressPtr = stressPtr->nextPtr) {
  702.     if (stressPtr->colormap == colormap) {
  703.         if (prevPtr == NULL) {
  704.         dispPtr->stressPtr = stressPtr->nextPtr;
  705.         } else {
  706.         prevPtr->nextPtr = stressPtr->nextPtr;
  707.         }
  708.         ckfree((char *) stressPtr->colorPtr);
  709.         ckfree((char *) stressPtr);
  710.         return;
  711.     }
  712.     }
  713. }
  714.