/*
* tkColor.c --
*
* This file maintains a database of color values for the Tk
* toolkit, in order to avoid round-trips to the server to
* map color names to pixel values.
*
* Copyright (c) 1990-1994 The Regents of the University of California.
* Copyright (c) 1994-1995 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* SCCS: @(#) tkColor.c 1.40 96/03/28 09:12:20
*/
#include "tkInt.h"
/*
* A two-level data structure is used to manage the color database.
* The top level consists of one entry for each color name that is
* currently active, and the bottom level contains one entry for each
* pixel value that is still in use. The distinction between
* levels is necessary because the same pixel may have several
* different names. There are two hash tables, one used to index into
* each of the data structures. The name hash table is used when
* allocating colors, and the pixel hash table is used when freeing
* colors.
*/
/*
* One of the following data structures is used to keep track of
* each color that this module has allocated from the X display
* server. These entries are indexed by two hash tables defined
* below: nameTable and valueTable.
*/
typedef struct TkColor {
* structure. Must always have the
* value COLOR_MAGIC. */
* color and all other fields defaulted.
* May be None. */
* to delete it, and to find its display. */
* allocated. */
* (needed when deleting structure). */
* structure. (for use in deleting entry). */
} TkColor;
/*
* Hash table for name -> TkColor mapping, and key structure used to
* index into that table:
*/
typedef struct {
* allocated. */
} NameKey;
/*
* Hash table for value -> TkColor mapping, and key structure used to
* index into that table:
*/
typedef struct {
* allocated. */
} ValueKey;
* initialized yet. */
/*
* If a colormap fills up, attempts to allocate new colors from that
* colormap will fail. When that happens, we'll just choose the
* closest color from those that are available in the colormap.
* One of the following structures will be created for each "stressed"
* colormap to keep track of the colors that are available in the
* colormap (otherwise we would have to re-query from the server on
* each allocation, which would be very slow). These entries are
* flushed after a few seconds, since other clients may release or
* reallocate colors over time.
*/
struct TkStressedCmap {
* at *colorPtr. */
* colors that seem to be available in
* the colormap. Some may not actually
* be available, e.g. because they are
* read-write for another client; when
* we find this out, we remove them
* from the array. */
* colormaps for the display. */
};
/*
* Forward declarations for procedures defined in this file:
*/
static void ColorInit _ANSI_ARGS_((void));
/*
*----------------------------------------------------------------------
*
* Tk_GetColor --
*
* Given a string name for a color, map the name to a corresponding
* XColor structure.
*
* Results:
* The return value is a pointer to an XColor structure that
* indicates the red, blue, and green intensities for the color
* given by "name", and also specifies a pixel value to use to
* draw in that color. If an error occurs, NULL is returned and
* an error message will be left in interp->result.
*
* Side effects:
* The color is added to an internal database with a reference count.
* For each call to this procedure, there should eventually be a call
* to Tk_FreeColor so that the database is cleaned up when colors
* aren't in use anymore.
*
*----------------------------------------------------------------------
*/
XColor *
* color can't be found. */
* suitable for passing to XParseColor). */
{
int new;
if (!initialized) {
ColorInit();
}
/*
* First, check to see if there's already a mapping for this color
* name.
*/
if (!new) {
}
/*
* The name isn't currently known. Map from the name to a pixel
* value. Call XAllocNamedColor rather than XParseColor for non-# names:
* this saves a server round-trip for those names.
*/
if (*name != '#') {
&color) != 0) {
} else {
/*
* Couldn't allocate the color. Try translating the name to
* a color value, to see whether the problem is a bad color
* name or a full colormap. If the colormap is full, then
* pick an approximation to the desired color.
*/
&screen) == 0) {
}
}
} else {
"\"", (char *) NULL);
}
} else {
}
}
/*
* Now create a new TkColor structure and add it to nameTable.
*/
}
/*
*----------------------------------------------------------------------
*
* Tk_GetColorByValue --
*
* Given a desired set of red-green-blue intensities for a color,
* locate a pixel value to use to draw that color in a given
* window.
*
* Results:
* The return value is a pointer to an XColor structure that
* indicates the closest red, blue, and green intensities available
* to those specified in colorPtr, and also specifies a pixel
* value to use to draw in that color.
*
* Side effects:
* The color is added to an internal database with a reference count.
* For each call to this procedure, there should eventually be a call
* to Tk_FreeColor, so that the database is cleaned up when colors
* aren't in use anymore.
*
*----------------------------------------------------------------------
*/
XColor *
* desired color. */
{
int new;
if (!initialized) {
ColorInit();
}
/*
* First, check to see if there's already a mapping for this color
* name.
*/
if (!new) {
}
/*
* The name isn't currently known. Find a pixel value for this
* color and add a new structure to valueTable.
*/
} else {
}
}
/*
*--------------------------------------------------------------
*
* Tk_NameOfColor --
*
* Given a color, return a textual string identifying
* the color.
*
* Results:
* If colorPtr was created by Tk_GetColor, then the return
* value is the "string" that was used to create it.
* Otherwise the return value is a string that could have
* been passed to Tk_GetColor to allocate that color. The
* storage for the returned string is only guaranteed to
* persist up until the next call to this procedure.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
char *
{
}
return string;
}
/*
*----------------------------------------------------------------------
*
* Tk_GCForColor --
*
* Given a color allocated from this module, this procedure
* returns a GC that can be used for simple drawing with that
* color.
*
* Results:
* The return value is a GC with color set as its foreground
* color and all other fields defaulted. This GC is only valid
* as long as the color exists; it is freed automatically when
* the last reference to the color is freed.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
* have been allocated by Tk_GetColor or
* Tk_GetColorByName. */
* used (must have same screen and depth
* as the one for which the color was
* allocated). */
{
/*
* Do a quick sanity check to make sure this color was really
* allocated by Tk_GetColor.
*/
panic("Tk_GCForColor called with bogus color");
}
}
}
/*
*----------------------------------------------------------------------
*
* Tk_FreeColor --
*
* This procedure is called to release a color allocated by
* Tk_GetColor.
*
* Results:
* None.
*
* Side effects:
* The reference count associated with colorPtr is deleted, and
* the color is released to X if there are no remaining uses
* for it.
*
*----------------------------------------------------------------------
*/
void
* allocated by Tk_GetColor or
* Tk_GetColorByValue. */
{
/*
* Do a quick sanity check to make sure this color was really
* allocated by Tk_GetColor.
*/
panic("Tk_FreeColor called with bogus color");
}
/*
* Careful! Don't free black or white, since this will
* make some servers very unhappy. Also, there is a bug in
* counting is performed incorrectly, so that if a color is
* allocated twice in different places and then freed twice,
* the second free generates an error (this bug existed as of
* 10/1/92). To get around this problem, ignore errors that
* occur during the free operation.
*/
}
}
}
}
/*
*----------------------------------------------------------------------
*
* ColorInit --
*
* Initialize the structure used for color management.
*
* Results:
* None.
*
* Side effects:
* Read the code.
*
*----------------------------------------------------------------------
*/
static void
{
initialized = 1;
}
/*
*----------------------------------------------------------------------
*
* FindClosestColor --
*
* When Tk can't allocate a color because a colormap has filled
* up, this procedure is called to find and allocate the closest
* available color in the colormap.
*
* Results:
* There is no return value, but *actualColorPtr is filled in
* with information about the closest available color in tkwin's
* colormap. This color has been allocated via X, so it must
* be released by the caller when the caller is done with it.
*
* Side effects:
* A color is allocated.
*
*----------------------------------------------------------------------
*/
static void
* wanted (but unavailable). */
* pixel for closest available
* color. */
{
/*
* Find the TkStressedCmap structure for this colormap, or create
* a new one if needed.
*/
if (numFound < 1) {
panic("FindClosestColor couldn't lookup visual");
}
XFree((char *) visInfoPtr);
}
break;
}
break;
}
}
/*
* Find the color that best approximates the desired one, then
* try to allocate that color. If that fails, it must mean that
* the color was read-write (so we can't use it, since it's owner
* might change it) or else it was already freed. Try again,
* over and over again, until something succeeds.
*/
while (1) {
panic("FindClosestColor ran out of colors");
}
closestDistance = 1e30;
closest = 0;
colorPtr++, i++) {
/*
* Use Euclidean distance in RGB space, weighted by Y (of YIQ)
* as the objective function; this accounts for differences
* in the color sensitivity of the eye.
*/
if (distance < closestDistance) {
closest = i;
}
}
return;
}
/*
* Couldn't allocate the color. Remove it from the table and
* go back to look for the next best color.
*/
}
}
/*
*----------------------------------------------------------------------
*
* TkCmapStressed --
*
* Check to see whether a given colormap is known to be out
* of entries.
*
* Results:
* 1 is returned if "colormap" is stressed (i.e. it has run out
* of entries recently), 0 otherwise.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
* containing the colormap. */
{
return 1;
}
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* DeleteStressedCmap --
*
* This procedure releases the information cached for "colormap"
* so that it will be refetched from the X server the next time
* it is needed.
*
* Results:
* None.
*
* Side effects:
* The TkStressedCmap structure for colormap is deleted; the
* colormap is no longer considered to be "stressed".
*
* Note:
* This procedure is invoked whenever a color in a colormap is
* freed, and whenever a color allocation in a colormap succeeds.
* This guarantees that TkStressedCmap structures are always
* deleted before the corresponding Colormap is freed.
*
*----------------------------------------------------------------------
*/
static void
* containing the colormap. */
{
} else {
}
return;
}
}
}