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

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkWinColor.c --
  3.  *
  4.  * Functions to map color names to system color values.
  5.  *
  6.  * Copyright (c) 1995 Sun Microsystems, Inc.
  7.  * Copyright (c) 1994 Software Research Associates, 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: tkWinColor.c,v 1.6 2000/07/06 03:17:44 mo Exp $
  13.  */
  14. #include "tkWinInt.h"
  15. #include "tkColor.h"
  16. /*
  17.  * The following structure is used to keep track of each color that is
  18.  * allocated by this module.
  19.  */
  20. typedef struct WinColor {
  21.     TkColor info; /* Generic color information. */
  22.     int index; /* Index for GetSysColor(), -1 if color
  23.  * is not a "live" system color. */
  24. } WinColor;
  25. /*
  26.  * The sysColors array contains the names and index values for the
  27.  * Windows indirect system color names.  In use, all of the names
  28.  * will have the string "System" prepended, but we omit it in the table
  29.  * to save space.
  30.  */
  31. typedef struct {
  32.     char *name;
  33.     int index;
  34. } SystemColorEntry;
  35. static SystemColorEntry sysColors[] = {
  36.     "3dDarkShadow", COLOR_3DDKSHADOW,
  37.     "3dLight", COLOR_3DLIGHT,
  38.     "ActiveBorder", COLOR_ACTIVEBORDER,
  39.     "ActiveCaption", COLOR_ACTIVECAPTION,
  40.     "AppWorkspace", COLOR_APPWORKSPACE,
  41.     "Background", COLOR_BACKGROUND,
  42.     "ButtonFace", COLOR_BTNFACE,
  43.     "ButtonHighlight", COLOR_BTNHIGHLIGHT,
  44.     "ButtonShadow", COLOR_BTNSHADOW,
  45.     "ButtonText", COLOR_BTNTEXT,
  46.     "CaptionText", COLOR_CAPTIONTEXT,
  47.     "DisabledText", COLOR_GRAYTEXT,
  48.     "GrayText", COLOR_GRAYTEXT,
  49.     "Highlight", COLOR_HIGHLIGHT,
  50.     "HighlightText", COLOR_HIGHLIGHTTEXT,
  51.     "InactiveBorder", COLOR_INACTIVEBORDER,
  52.     "InactiveCaption", COLOR_INACTIVECAPTION,
  53.     "InactiveCaptionText", COLOR_INACTIVECAPTIONTEXT,
  54.     "InfoBackground", COLOR_INFOBK,
  55.     "InfoText", COLOR_INFOTEXT,
  56.     "Menu", COLOR_MENU,
  57.     "MenuText", COLOR_MENUTEXT,
  58.     "Scrollbar", COLOR_SCROLLBAR,
  59.     "Window", COLOR_WINDOW,
  60.     "WindowFrame", COLOR_WINDOWFRAME,
  61.     "WindowText", COLOR_WINDOWTEXT,
  62.     NULL, 0
  63. };
  64. typedef struct ThreadSpecificData { 
  65.     int ncolors;
  66. } ThreadSpecificData;
  67. static Tcl_ThreadDataKey dataKey;
  68. /*
  69.  * Forward declarations for functions defined later in this file.
  70.  */
  71. static int FindSystemColor _ANSI_ARGS_((const char *name,
  72.     XColor *colorPtr, int *indexPtr));
  73. /*
  74.  *----------------------------------------------------------------------
  75.  *
  76.  * FindSystemColor --
  77.  *
  78.  * This routine finds the color entry that corresponds to the
  79.  * specified color.
  80.  *
  81.  * Results:
  82.  * Returns non-zero on success.  The RGB values of the XColor
  83.  * will be initialized to the proper values on success.
  84.  *
  85.  * Side effects:
  86.  * None.
  87.  *
  88.  *----------------------------------------------------------------------
  89.  */
  90. static int
  91. FindSystemColor(name, colorPtr, indexPtr)
  92.     const char *name; /* Color name. */
  93.     XColor *colorPtr; /* Where to store results. */
  94.     int *indexPtr; /* Out parameter to store color index. */
  95. {
  96.     int l, u, r, i;
  97.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  98.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  99.     /*
  100.      * Count the number of elements in the color array if we haven't
  101.      * done so yet.
  102.      */
  103.     if (tsdPtr->ncolors == 0) {
  104. SystemColorEntry *ePtr;
  105. int version;
  106. version = LOBYTE(LOWORD(GetVersion()));
  107. for (ePtr = sysColors; ePtr->name != NULL; ePtr++) {
  108.     if (version < 4) {
  109. if (ePtr->index == COLOR_3DDKSHADOW) {
  110.     ePtr->index = COLOR_BTNSHADOW;
  111. } else if (ePtr->index == COLOR_3DLIGHT) {
  112.     ePtr->index = COLOR_BTNHIGHLIGHT;
  113. }
  114.     }
  115.     tsdPtr->ncolors++;
  116. }
  117.     }
  118.     /*
  119.      * Perform a binary search on the sorted array of colors.
  120.      */
  121.     l = 0;
  122.     u = tsdPtr->ncolors - 1;
  123.     while (l <= u) {
  124. i = (l + u) / 2;
  125. r = strcasecmp(name, sysColors[i].name);
  126. if (r == 0) {
  127.     break;
  128. } else if (r < 0) {
  129.     u = i-1;
  130. } else {
  131.     l = i+1;
  132. }
  133.     }
  134.     if (l > u) {
  135. return 0;
  136.     }
  137.     *indexPtr = sysColors[i].index;
  138.     colorPtr->pixel = GetSysColor(sysColors[i].index);
  139.     /*
  140.      * x257 is (value<<8 + value) to get the properly bit shifted
  141.      * and padded value.  [Bug: 4919]
  142.      */
  143.     colorPtr->red = GetRValue(colorPtr->pixel) * 257;
  144.     colorPtr->green = GetGValue(colorPtr->pixel) * 257;
  145.     colorPtr->blue = GetBValue(colorPtr->pixel) * 257;
  146.     colorPtr->flags = DoRed|DoGreen|DoBlue;
  147.     colorPtr->pad = 0;
  148.     return 1;
  149. }
  150. /*
  151.  *----------------------------------------------------------------------
  152.  *
  153.  * TkpGetColor --
  154.  *
  155.  * Allocate a new TkColor for the color with the given name.
  156.  *
  157.  * Results:
  158.  * Returns a newly allocated TkColor, or NULL on failure.
  159.  *
  160.  * Side effects:
  161.  * May invalidate the colormap cache associated with tkwin upon
  162.  * allocating a new colormap entry.  Allocates a new TkColor
  163.  * structure.
  164.  *
  165.  *----------------------------------------------------------------------
  166.  */
  167. TkColor *
  168. TkpGetColor(tkwin, name)
  169.     Tk_Window tkwin; /* Window in which color will be used. */
  170.     Tk_Uid name; /* Name of color to allocated (in form
  171.  * suitable for passing to XParseColor). */
  172. {
  173.     WinColor *winColPtr;
  174.     XColor color;
  175.     int index = -1; /* -1 indicates that this is not an indirect
  176.  * sytem color. */
  177.     /*
  178.      * Check to see if it is a system color or an X color string.  If the
  179.      * color is found, allocate a new WinColor and store the XColor and the
  180.      * system color index.
  181.      */
  182.     if (((strncasecmp(name, "system", 6) == 0)
  183.     && FindSystemColor(name+6, &color, &index))
  184.     || XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), name,
  185.     &color)) {
  186. winColPtr = (WinColor *) ckalloc(sizeof(WinColor));
  187. winColPtr->info.color = color;
  188. winColPtr->index = index;
  189. XAllocColor(Tk_Display(tkwin), Tk_Colormap(tkwin),
  190. &winColPtr->info.color);
  191.   return (TkColor *) winColPtr; 
  192.     }
  193.     return (TkColor *) NULL;
  194. }
  195. /*
  196.  *----------------------------------------------------------------------
  197.  *
  198.  * TkpGetColorByValue --
  199.  *
  200.  * Given a desired set of red-green-blue intensities for a color,
  201.  * locate a pixel value to use to draw that color in a given
  202.  * window.
  203.  *
  204.  * Results:
  205.  * The return value is a pointer to an TkColor structure that
  206.  * indicates the closest red, blue, and green intensities available
  207.  * to those specified in colorPtr, and also specifies a pixel
  208.  * value to use to draw in that color.
  209.  *
  210.  * Side effects:
  211.  * May invalidate the colormap cache for the specified window.
  212.  * Allocates a new TkColor structure.
  213.  *
  214.  *----------------------------------------------------------------------
  215.  */
  216. TkColor *
  217. TkpGetColorByValue(tkwin, colorPtr)
  218.     Tk_Window tkwin; /* Window in which color will be used. */
  219.     XColor *colorPtr; /* Red, green, and blue fields indicate
  220.  * desired color. */
  221. {
  222.     WinColor *tkColPtr = (WinColor *) ckalloc(sizeof(WinColor));
  223.     tkColPtr->info.color.red = colorPtr->red;
  224.     tkColPtr->info.color.green = colorPtr->green;
  225.     tkColPtr->info.color.blue = colorPtr->blue;
  226.     tkColPtr->info.color.pixel = 0;
  227.     tkColPtr->index = -1;
  228.     XAllocColor(Tk_Display(tkwin), Tk_Colormap(tkwin), &tkColPtr->info.color);
  229.     return (TkColor *) tkColPtr;
  230. }
  231. /*
  232.  *----------------------------------------------------------------------
  233.  *
  234.  * TkpFreeColor --
  235.  *
  236.  * Release the specified color back to the system.
  237.  *
  238.  * Results:
  239.  * None
  240.  *
  241.  * Side effects:
  242.  * Invalidates the colormap cache for the colormap associated with
  243.  * the given color.
  244.  *
  245.  *----------------------------------------------------------------------
  246.  */
  247. void
  248. TkpFreeColor(tkColPtr)
  249.     TkColor *tkColPtr; /* Color to be released.  Must have been
  250.  * allocated by TkpGetColor or
  251.  * TkpGetColorByValue. */
  252. {
  253.     Screen *screen = tkColPtr->screen;
  254.     XFreeColors(DisplayOfScreen(screen), tkColPtr->colormap,
  255.     &tkColPtr->color.pixel, 1, 0L);
  256. }
  257. /*
  258.  *----------------------------------------------------------------------
  259.  *
  260.  * TkWinIndexOfColor --
  261.  *
  262.  * Given a color, return the system color index that was used
  263.  * to create the color.
  264.  *
  265.  * Results:
  266.  * If the color was allocated using a system indirect color name,
  267.  * then the corresponding GetSysColor() index is returned.
  268.  * Otherwise, -1 is returned.
  269.  *
  270.  * Side effects:
  271.  * None.
  272.  *
  273.  *----------------------------------------------------------------------
  274.  */
  275. int
  276. TkWinIndexOfColor(colorPtr)
  277.     XColor *colorPtr;
  278. {
  279.     register WinColor *winColPtr = (WinColor *) colorPtr;
  280.     if (winColPtr->info.magic == COLOR_MAGIC) {
  281. return winColPtr->index;
  282.     }    
  283.     return -1;
  284. }
  285. /*
  286.  *----------------------------------------------------------------------
  287.  *
  288.  * XAllocColor --
  289.  *
  290.  * Find the closest available color to the specified XColor.
  291.  *
  292.  * Results:
  293.  * Updates the color argument and returns 1 on success.  Otherwise
  294.  * returns 0.
  295.  *
  296.  * Side effects:
  297.  * Allocates a new color in the palette.
  298.  *
  299.  *----------------------------------------------------------------------
  300.  */
  301. int
  302. XAllocColor(display, colormap, color)
  303.     Display* display;
  304.     Colormap colormap;
  305.     XColor* color;
  306. {
  307.     TkWinColormap *cmap = (TkWinColormap *) colormap;
  308.     PALETTEENTRY entry, closeEntry;
  309.     HDC dc = GetDC(NULL);
  310.     entry.peRed = (color->red) >> 8;
  311.     entry.peGreen = (color->green) >> 8;
  312.     entry.peBlue = (color->blue) >> 8;
  313.     entry.peFlags = 0;
  314.     if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) {
  315. unsigned long sizePalette = GetDeviceCaps(dc, SIZEPALETTE);
  316. UINT newPixel, closePixel;
  317. int new, refCount;
  318. Tcl_HashEntry *entryPtr;
  319. UINT index;
  320. /*
  321.  * Find the nearest existing palette entry.
  322.  */
  323. newPixel = RGB(entry.peRed, entry.peGreen, entry.peBlue);
  324. index = GetNearestPaletteIndex(cmap->palette, newPixel);
  325. GetPaletteEntries(cmap->palette, index, 1, &closeEntry);
  326. closePixel = RGB(closeEntry.peRed, closeEntry.peGreen,
  327. closeEntry.peBlue);
  328. /*
  329.  * If this is not a duplicate, allocate a new entry.  Note that
  330.  * we may get values for index that are above the current size
  331.  * of the palette.  This happens because we don't shrink the size of
  332.  * the palette object when we deallocate colors so there may be
  333.  * stale values that match in the upper slots.  We should ignore
  334.  * those values and just put the new color in as if the colors
  335.  * had not matched.
  336.  */
  337. if ((index >= cmap->size) || (newPixel != closePixel)) {
  338.     if (cmap->size == sizePalette) {
  339. color->red   = closeEntry.peRed * 257;
  340. color->green = closeEntry.peGreen * 257;
  341. color->blue  = closeEntry.peBlue * 257;
  342. entry = closeEntry;
  343. if (index >= cmap->size) {
  344.     OutputDebugString("XAllocColor: Colormap is bigger than we thought");
  345. }
  346.     } else {
  347. cmap->size++;
  348. ResizePalette(cmap->palette, cmap->size);
  349. SetPaletteEntries(cmap->palette, cmap->size - 1, 1, &entry);
  350.     }
  351. }
  352. color->pixel = PALETTERGB(entry.peRed, entry.peGreen, entry.peBlue);
  353. entryPtr = Tcl_CreateHashEntry(&cmap->refCounts,
  354. (char *) color->pixel, &new);
  355. if (new) {
  356.     refCount = 1;
  357. } else {
  358.     refCount = ((int) Tcl_GetHashValue(entryPtr)) + 1;
  359. }
  360. Tcl_SetHashValue(entryPtr, (ClientData)refCount);
  361.     } else {
  362. /*
  363.  * Determine what color will actually be used on non-colormap systems.
  364.  */
  365. color->pixel = GetNearestColor(dc,
  366. RGB(entry.peRed, entry.peGreen, entry.peBlue));
  367. color->red    = GetRValue(color->pixel) * 257;
  368. color->green  = GetGValue(color->pixel) * 257;
  369. color->blue   = GetBValue(color->pixel) * 257;
  370.     }
  371.     ReleaseDC(NULL, dc);
  372.     return 1;
  373. }
  374. /*
  375.  *----------------------------------------------------------------------
  376.  *
  377.  * XFreeColors --
  378.  *
  379.  * Deallocate a block of colors.
  380.  *
  381.  * Results:
  382.  * None.
  383.  *
  384.  * Side effects:
  385.  * Removes entries for the current palette and compacts the
  386.  * remaining set.
  387.  *
  388.  *----------------------------------------------------------------------
  389.  */
  390. void
  391. XFreeColors(display, colormap, pixels, npixels, planes)
  392.     Display* display;
  393.     Colormap colormap;
  394.     unsigned long* pixels;
  395.     int npixels;
  396.     unsigned long planes;
  397. {
  398.     TkWinColormap *cmap = (TkWinColormap *) colormap;
  399.     COLORREF cref;
  400.     UINT count, index, refCount;
  401.     int i;
  402.     PALETTEENTRY entry, *entries;
  403.     Tcl_HashEntry *entryPtr;
  404.     HDC dc = GetDC(NULL);
  405.     /*
  406.      * We don't have to do anything for non-palette devices.
  407.      */
  408.     
  409.     if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) {
  410. /*
  411.  * This is really slow for large values of npixels.
  412.  */
  413. for (i = 0; i < npixels; i++) {
  414.     entryPtr = Tcl_FindHashEntry(&cmap->refCounts,
  415.     (char *) pixels[i]);
  416.     if (!entryPtr) {
  417. panic("Tried to free a color that isn't allocated.");
  418.     }
  419.     refCount = (int) Tcl_GetHashValue(entryPtr) - 1;
  420.     if (refCount == 0) {
  421. cref = pixels[i] & 0x00ffffff;
  422. index = GetNearestPaletteIndex(cmap->palette, cref);
  423. GetPaletteEntries(cmap->palette, index, 1, &entry);
  424. if (cref == RGB(entry.peRed, entry.peGreen, entry.peBlue)) {
  425.     count = cmap->size - index;
  426.     entries = (PALETTEENTRY *) ckalloc(sizeof(PALETTEENTRY)
  427.     * count);
  428.     GetPaletteEntries(cmap->palette, index+1, count, entries);
  429.     SetPaletteEntries(cmap->palette, index, count, entries);
  430.     ckfree((char *) entries);
  431.     cmap->size--;
  432. } else {
  433.     panic("Tried to free a color that isn't allocated.");
  434. }
  435. Tcl_DeleteHashEntry(entryPtr);
  436.     } else {
  437. Tcl_SetHashValue(entryPtr, (ClientData)refCount);
  438.     }
  439. }
  440.     }
  441.     ReleaseDC(NULL, dc);
  442. }
  443. /*
  444.  *----------------------------------------------------------------------
  445.  *
  446.  * XCreateColormap --
  447.  *
  448.  * Allocate a new colormap.
  449.  *
  450.  * Results:
  451.  * Returns a newly allocated colormap.
  452.  *
  453.  * Side effects:
  454.  * Allocates an empty palette and color list.
  455.  *
  456.  *----------------------------------------------------------------------
  457.  */
  458. Colormap
  459. XCreateColormap(display, w, visual, alloc)
  460.     Display* display;
  461.     Window w;
  462.     Visual* visual;
  463.     int alloc;
  464. {
  465.     char logPalBuf[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)];
  466.     LOGPALETTE *logPalettePtr;
  467.     PALETTEENTRY *entryPtr;
  468.     TkWinColormap *cmap;
  469.     Tcl_HashEntry *hashPtr;
  470.     int new;
  471.     UINT i;
  472.     HPALETTE sysPal;
  473.     /*
  474.      * Allocate a starting palette with all of the reserved colors.
  475.      */
  476.     logPalettePtr = (LOGPALETTE *) logPalBuf;
  477.     logPalettePtr->palVersion = 0x300;
  478.     sysPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
  479.     logPalettePtr->palNumEntries = GetPaletteEntries(sysPal, 0, 256,
  480.     logPalettePtr->palPalEntry);
  481.     cmap = (TkWinColormap *) ckalloc(sizeof(TkWinColormap));
  482.     cmap->size = logPalettePtr->palNumEntries;
  483.     cmap->stale = 0;
  484.     cmap->palette = CreatePalette(logPalettePtr);
  485.     /*
  486.      * Add hash entries for each of the static colors.
  487.      */
  488.     Tcl_InitHashTable(&cmap->refCounts, TCL_ONE_WORD_KEYS);
  489.     for (i = 0; i < logPalettePtr->palNumEntries; i++) {
  490. entryPtr = logPalettePtr->palPalEntry + i;
  491. hashPtr = Tcl_CreateHashEntry(&cmap->refCounts, (char*) PALETTERGB(
  492.     entryPtr->peRed, entryPtr->peGreen, entryPtr->peBlue), &new);
  493. Tcl_SetHashValue(hashPtr, (ClientData)1);
  494.     }
  495.     return (Colormap)cmap;
  496. }
  497. /*
  498.  *----------------------------------------------------------------------
  499.  *
  500.  * XFreeColormap --
  501.  *
  502.  * Frees the resources associated with the given colormap.
  503.  *
  504.  * Results:
  505.  * None.
  506.  *
  507.  * Side effects:
  508.  * Deletes the palette associated with the colormap.  Note that
  509.  * the palette must not be selected into a device context when
  510.  * this occurs.
  511.  *
  512.  *----------------------------------------------------------------------
  513.  */
  514. void
  515. XFreeColormap(display, colormap)
  516.     Display* display;
  517.     Colormap colormap;
  518. {
  519.     TkWinColormap *cmap = (TkWinColormap *) colormap;
  520.     if (!DeleteObject(cmap->palette)) {
  521. panic("Unable to free colormap, palette is still selected.");
  522.     }
  523.     Tcl_DeleteHashTable(&cmap->refCounts);
  524.     ckfree((char *) cmap);
  525. }
  526. /*
  527.  *----------------------------------------------------------------------
  528.  *
  529.  * TkWinSelectPalette --
  530.  *
  531.  * This function sets up the specified device context with a
  532.  * given palette.  If the palette is stale, it realizes it in
  533.  * the background unless the palette is the current global
  534.  * palette.
  535.  *
  536.  * Results:
  537.  * Returns the previous palette selected into the device context.
  538.  *
  539.  * Side effects:
  540.  * May change the system palette.
  541.  *
  542.  *----------------------------------------------------------------------
  543.  */
  544. HPALETTE
  545. TkWinSelectPalette(dc, colormap)
  546.     HDC dc;
  547.     Colormap colormap;
  548. {
  549.     TkWinColormap *cmap = (TkWinColormap *) colormap;
  550.     HPALETTE oldPalette;
  551.     oldPalette = SelectPalette(dc, cmap->palette,
  552.     (cmap->palette == TkWinGetSystemPalette()) ? FALSE : TRUE);
  553.     RealizePalette(dc);
  554.     return oldPalette;
  555. }