tkUnixColor.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:13k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkUnixColor.c --
  3.  *
  4.  * This file contains the platform specific color routines
  5.  * needed for X support.
  6.  *
  7.  * Copyright (c) 1996 by Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tkUnixColor.c,v 1.2 1998/09/14 18:23:55 stanton Exp $
  13.  */
  14. #include <tkColor.h>
  15. /*
  16.  * If a colormap fills up, attempts to allocate new colors from that
  17.  * colormap will fail.  When that happens, we'll just choose the
  18.  * closest color from those that are available in the colormap.
  19.  * One of the following structures will be created for each "stressed"
  20.  * colormap to keep track of the colors that are available in the
  21.  * colormap (otherwise we would have to re-query from the server on
  22.  * each allocation, which would be very slow).  These entries are
  23.  * flushed after a few seconds, since other clients may release or
  24.  * reallocate colors over time.
  25.  */
  26. struct TkStressedCmap {
  27.     Colormap colormap; /* X's token for the colormap. */
  28.     int numColors; /* Number of entries currently active
  29.  * at *colorPtr. */
  30.     XColor *colorPtr; /* Pointer to malloc'ed array of all
  31.  * colors that seem to be available in
  32.  * the colormap.  Some may not actually
  33.  * be available, e.g. because they are
  34.  * read-write for another client;  when
  35.  * we find this out, we remove them
  36.  * from the array. */
  37.     struct TkStressedCmap *nextPtr; /* Next in list of all stressed
  38.  * colormaps for the display. */
  39. };
  40. /*
  41.  * Forward declarations for procedures defined in this file:
  42.  */
  43. static void DeleteStressedCmap _ANSI_ARGS_((Display *display,
  44.     Colormap colormap));
  45. static void FindClosestColor _ANSI_ARGS_((Tk_Window tkwin,
  46.     XColor *desiredColorPtr, XColor *actualColorPtr));
  47. /*
  48.  *----------------------------------------------------------------------
  49.  *
  50.  * TkpFreeColor --
  51.  *
  52.  * Release the specified color back to the system.
  53.  *
  54.  * Results:
  55.  * None
  56.  *
  57.  * Side effects:
  58.  * Invalidates the colormap cache for the colormap associated with
  59.  * the given color.
  60.  *
  61.  *----------------------------------------------------------------------
  62.  */
  63. void
  64. TkpFreeColor(tkColPtr)
  65.     TkColor *tkColPtr; /* Color to be released.  Must have been
  66.  * allocated by TkpGetColor or
  67.  * TkpGetColorByValue. */
  68. {
  69.     Visual *visual;
  70.     Screen *screen = tkColPtr->screen;
  71.     /*
  72.      * Careful!  Don't free black or white, since this will
  73.      * make some servers very unhappy.  Also, there is a bug in
  74.      * some servers (such Sun's X11/NeWS server) where reference
  75.      * counting is performed incorrectly, so that if a color is
  76.      * allocated twice in different places and then freed twice,
  77.      * the second free generates an error (this bug existed as of
  78.      * 10/1/92).  To get around this problem, ignore errors that
  79.      * occur during the free operation.
  80.      */
  81.     visual = tkColPtr->visual;
  82.     if ((visual->class != StaticGray) && (visual->class != StaticColor)
  83.     && (tkColPtr->color.pixel != BlackPixelOfScreen(screen))
  84.     && (tkColPtr->color.pixel != WhitePixelOfScreen(screen))) {
  85. Tk_ErrorHandler handler;
  86. handler = Tk_CreateErrorHandler(DisplayOfScreen(screen),
  87. -1, -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
  88. XFreeColors(DisplayOfScreen(screen), tkColPtr->colormap,
  89. &tkColPtr->color.pixel, 1, 0L);
  90. Tk_DeleteErrorHandler(handler);
  91.     }
  92.     DeleteStressedCmap(DisplayOfScreen(screen), tkColPtr->colormap);
  93. }
  94. /*
  95.  *----------------------------------------------------------------------
  96.  *
  97.  * TkpGetColor --
  98.  *
  99.  * Allocate a new TkColor for the color with the given name.
  100.  *
  101.  * Results:
  102.  * Returns a newly allocated TkColor, or NULL on failure.
  103.  *
  104.  * Side effects:
  105.  * May invalidate the colormap cache associated with tkwin upon
  106.  * allocating a new colormap entry.  Allocates a new TkColor
  107.  * structure.
  108.  *
  109.  *----------------------------------------------------------------------
  110.  */
  111. TkColor *
  112. TkpGetColor(tkwin, name)
  113.     Tk_Window tkwin; /* Window in which color will be used. */
  114.     Tk_Uid name; /* Name of color to allocated (in form
  115.  * suitable for passing to XParseColor). */
  116. {
  117.     Display *display = Tk_Display(tkwin);
  118.     Colormap colormap = Tk_Colormap(tkwin);
  119.     XColor color;
  120.     TkColor *tkColPtr;
  121.     /*
  122.      * Map from the name to a pixel value.  Call XAllocNamedColor rather than
  123.      * XParseColor for non-# names: this saves a server round-trip for those
  124.      * names.
  125.      */
  126.     if (*name != '#') {
  127. XColor screen;
  128. if (XAllocNamedColor(display, colormap, name, &screen,
  129. &color) != 0) {
  130.     DeleteStressedCmap(display, colormap);
  131. } else {
  132.     /*
  133.      * Couldn't allocate the color.  Try translating the name to
  134.      * a color value, to see whether the problem is a bad color
  135.      * name or a full colormap.  If the colormap is full, then
  136.      * pick an approximation to the desired color.
  137.      */
  138.     if (XLookupColor(display, colormap, name, &color,
  139.     &screen) == 0) {
  140. return (TkColor *) NULL;
  141.     }
  142.     FindClosestColor(tkwin, &screen, &color);
  143. }
  144.     } else {
  145. if (XParseColor(display, colormap, name, &color) == 0) {
  146.     return (TkColor *) NULL;
  147. }
  148. if (XAllocColor(display, colormap, &color) != 0) {
  149.     DeleteStressedCmap(display, colormap);
  150. } else {
  151.     FindClosestColor(tkwin, &color, &color);
  152. }
  153.     }
  154.     tkColPtr = (TkColor *) ckalloc(sizeof(TkColor));
  155.     tkColPtr->color = color;
  156.     return tkColPtr;
  157. }
  158. /*
  159.  *----------------------------------------------------------------------
  160.  *
  161.  * TkpGetColorByValue --
  162.  *
  163.  * Given a desired set of red-green-blue intensities for a color,
  164.  * locate a pixel value to use to draw that color in a given
  165.  * window.
  166.  *
  167.  * Results:
  168.  * The return value is a pointer to an TkColor structure that
  169.  * indicates the closest red, blue, and green intensities available
  170.  * to those specified in colorPtr, and also specifies a pixel
  171.  * value to use to draw in that color.
  172.  *
  173.  * Side effects:
  174.  * May invalidate the colormap cache for the specified window.
  175.  * Allocates a new TkColor structure.
  176.  *
  177.  *----------------------------------------------------------------------
  178.  */
  179. TkColor *
  180. TkpGetColorByValue(tkwin, colorPtr)
  181.     Tk_Window tkwin; /* Window in which color will be used. */
  182.     XColor *colorPtr; /* Red, green, and blue fields indicate
  183.  * desired color. */
  184. {
  185.     Display *display = Tk_Display(tkwin);
  186.     Colormap colormap = Tk_Colormap(tkwin);
  187.     TkColor *tkColPtr = (TkColor *) ckalloc(sizeof(TkColor));
  188.     tkColPtr->color.red = colorPtr->red;
  189.     tkColPtr->color.green = colorPtr->green;
  190.     tkColPtr->color.blue = colorPtr->blue;
  191.     if (XAllocColor(display, colormap, &tkColPtr->color) != 0) {
  192. DeleteStressedCmap(display, colormap);
  193.     } else {
  194. FindClosestColor(tkwin, &tkColPtr->color, &tkColPtr->color);
  195.     }
  196.     return tkColPtr;
  197. }
  198. /*
  199.  *----------------------------------------------------------------------
  200.  *
  201.  * FindClosestColor --
  202.  *
  203.  * When Tk can't allocate a color because a colormap has filled
  204.  * up, this procedure is called to find and allocate the closest
  205.  * available color in the colormap.
  206.  *
  207.  * Results:
  208.  * There is no return value, but *actualColorPtr is filled in
  209.  * with information about the closest available color in tkwin's
  210.  * colormap.  This color has been allocated via X, so it must
  211.  * be released by the caller when the caller is done with it.
  212.  *
  213.  * Side effects:
  214.  * A color is allocated.
  215.  *
  216.  *----------------------------------------------------------------------
  217.  */
  218. static void
  219. FindClosestColor(tkwin, desiredColorPtr, actualColorPtr)
  220.     Tk_Window tkwin; /* Window where color will be used. */
  221.     XColor *desiredColorPtr; /* RGB values of color that was
  222.  * wanted (but unavailable). */
  223.     XColor *actualColorPtr; /* Structure to fill in with RGB and
  224.  * pixel for closest available
  225.  * color. */
  226. {
  227.     TkStressedCmap *stressPtr;
  228.     double tmp, distance, closestDistance;
  229.     int i, closest, numFound;
  230.     XColor *colorPtr;
  231.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  232.     Colormap colormap = Tk_Colormap(tkwin);
  233.     XVisualInfo template, *visInfoPtr;
  234.     /*
  235.      * Find the TkStressedCmap structure for this colormap, or create
  236.      * a new one if needed.
  237.      */
  238.     for (stressPtr = dispPtr->stressPtr; ; stressPtr = stressPtr->nextPtr) {
  239. if (stressPtr == NULL) {
  240.     stressPtr = (TkStressedCmap *) ckalloc(sizeof(TkStressedCmap));
  241.     stressPtr->colormap = colormap;
  242.     template.visualid = XVisualIDFromVisual(Tk_Visual(tkwin));
  243.     visInfoPtr = XGetVisualInfo(Tk_Display(tkwin),
  244.     VisualIDMask, &template, &numFound);
  245.     if (numFound < 1) {
  246. panic("FindClosestColor couldn't lookup visual");
  247.     }
  248.     stressPtr->numColors = visInfoPtr->colormap_size;
  249.     XFree((char *) visInfoPtr);
  250.     stressPtr->colorPtr = (XColor *) ckalloc((unsigned)
  251.     (stressPtr->numColors * sizeof(XColor)));
  252.     for (i = 0; i  < stressPtr->numColors; i++) {
  253. stressPtr->colorPtr[i].pixel = (unsigned long) i;
  254.     }
  255.     XQueryColors(dispPtr->display, colormap, stressPtr->colorPtr,
  256.     stressPtr->numColors);
  257.     stressPtr->nextPtr = dispPtr->stressPtr;
  258.     dispPtr->stressPtr = stressPtr;
  259.     break;
  260. }
  261. if (stressPtr->colormap == colormap) {
  262.     break;
  263. }
  264.     }
  265.     /*
  266.      * Find the color that best approximates the desired one, then
  267.      * try to allocate that color.  If that fails, it must mean that
  268.      * the color was read-write (so we can't use it, since it's owner
  269.      * might change it) or else it was already freed.  Try again,
  270.      * over and over again, until something succeeds.
  271.      */
  272.     while (1)  {
  273. if (stressPtr->numColors == 0) {
  274.     panic("FindClosestColor ran out of colors");
  275. }
  276. closestDistance = 1e30;
  277. closest = 0;
  278. for (colorPtr = stressPtr->colorPtr, i = 0; i < stressPtr->numColors;
  279. colorPtr++, i++) {
  280.     /*
  281.      * Use Euclidean distance in RGB space, weighted by Y (of YIQ)
  282.      * as the objective function;  this accounts for differences
  283.      * in the color sensitivity of the eye.
  284.      */
  285.     
  286.     tmp = .30*(((int) desiredColorPtr->red) - (int) colorPtr->red);
  287.     distance = tmp*tmp;
  288.     tmp = .61*(((int) desiredColorPtr->green) - (int) colorPtr->green);
  289.     distance += tmp*tmp;
  290.     tmp = .11*(((int) desiredColorPtr->blue) - (int) colorPtr->blue);
  291.     distance += tmp*tmp;
  292.     if (distance < closestDistance) {
  293. closest = i;
  294. closestDistance = distance;
  295.     }
  296. }
  297. if (XAllocColor(dispPtr->display, colormap,
  298. &stressPtr->colorPtr[closest]) != 0) {
  299.     *actualColorPtr = stressPtr->colorPtr[closest];
  300.     return;
  301. }
  302. /*
  303.  * Couldn't allocate the color.  Remove it from the table and
  304.  * go back to look for the next best color.
  305.  */
  306. stressPtr->colorPtr[closest] =
  307. stressPtr->colorPtr[stressPtr->numColors-1];
  308. stressPtr->numColors -= 1;
  309.     }
  310. }
  311. /*
  312.  *----------------------------------------------------------------------
  313.  *
  314.  * DeleteStressedCmap --
  315.  *
  316.  * This procedure releases the information cached for "colormap"
  317.  * so that it will be refetched from the X server the next time
  318.  * it is needed.
  319.  *
  320.  * Results:
  321.  * None.
  322.  *
  323.  * Side effects:
  324.  * The TkStressedCmap structure for colormap is deleted;  the
  325.  * colormap is no longer considered to be "stressed".
  326.  *
  327.  * Note:
  328.  * This procedure is invoked whenever a color in a colormap is
  329.  * freed, and whenever a color allocation in a colormap succeeds.
  330.  * This guarantees that TkStressedCmap structures are always
  331.  * deleted before the corresponding Colormap is freed.
  332.  *
  333.  *----------------------------------------------------------------------
  334.  */
  335. static void
  336. DeleteStressedCmap(display, colormap)
  337.     Display *display; /* Xlib's handle for the display
  338.  * containing the colormap. */
  339.     Colormap colormap; /* Colormap to flush. */
  340. {
  341.     TkStressedCmap *prevPtr, *stressPtr;
  342.     TkDisplay *dispPtr = TkGetDisplay(display);
  343.     for (prevPtr = NULL, stressPtr = dispPtr->stressPtr; stressPtr != NULL;
  344.     prevPtr = stressPtr, stressPtr = stressPtr->nextPtr) {
  345. if (stressPtr->colormap == colormap) {
  346.     if (prevPtr == NULL) {
  347. dispPtr->stressPtr = stressPtr->nextPtr;
  348.     } else {
  349. prevPtr->nextPtr = stressPtr->nextPtr;
  350.     }
  351.     ckfree((char *) stressPtr->colorPtr);
  352.     ckfree((char *) stressPtr);
  353.     return;
  354. }
  355.     }
  356. }
  357. /*
  358.  *----------------------------------------------------------------------
  359.  *
  360.  * TkpCmapStressed --
  361.  *
  362.  * Check to see whether a given colormap is known to be out
  363.  * of entries.
  364.  *
  365.  * Results:
  366.  * 1 is returned if "colormap" is stressed (i.e. it has run out
  367.  * of entries recently), 0 otherwise.
  368.  *
  369.  * Side effects:
  370.  * None.
  371.  *
  372.  *----------------------------------------------------------------------
  373.  */
  374. int
  375. TkpCmapStressed(tkwin, colormap)
  376.     Tk_Window tkwin; /* Window that identifies the display
  377.  * containing the colormap. */
  378.     Colormap colormap; /* Colormap to check for stress. */
  379. {
  380.     TkStressedCmap *stressPtr;
  381.     for (stressPtr = ((TkWindow *) tkwin)->dispPtr->stressPtr;
  382.     stressPtr != NULL; stressPtr = stressPtr->nextPtr) {
  383. if (stressPtr->colormap == colormap) {
  384.     return 1;
  385. }
  386.     }
  387.     return 0;
  388. }