4 * Functions to map color names to system color values.
6 * Copyright (c) 1995 Sun Microsystems, Inc.
7 * Copyright (c) 1994 Software Research Associates, Inc.
9 * See the file "license.terms" for information on usage and redistribution
10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
19 * The following structure is used to keep track of each color that is
20 * allocated by this module.
23 typedef struct WinColor {
24 TkColor info; /* Generic color information. */
25 int index; /* Index for GetSysColor(), -1 if color
26 * is not a "live" system color. */
30 * The sysColors array contains the names and index values for the
31 * Windows indirect system color names. In use, all of the names
32 * will have the string "System" prepended, but we omit it in the table
42 static SystemColorEntry sysColors[] = {
43 "3dDarkShadow", COLOR_3DDKSHADOW,
44 "3dLight", COLOR_3DLIGHT,
45 "ActiveBorder", COLOR_ACTIVEBORDER,
46 "ActiveCaption", COLOR_ACTIVECAPTION,
47 "AppWorkspace", COLOR_APPWORKSPACE,
48 "Background", COLOR_BACKGROUND,
49 "ButtonFace", COLOR_BTNFACE,
50 "ButtonHighlight", COLOR_BTNHIGHLIGHT,
51 "ButtonShadow", COLOR_BTNSHADOW,
52 "ButtonText", COLOR_BTNTEXT,
53 "CaptionText", COLOR_CAPTIONTEXT,
54 "DisabledText", COLOR_GRAYTEXT,
55 "GrayText", COLOR_GRAYTEXT,
56 "Highlight", COLOR_HIGHLIGHT,
57 "HighlightText", COLOR_HIGHLIGHTTEXT,
58 "InactiveBorder", COLOR_INACTIVEBORDER,
59 "InactiveCaption", COLOR_INACTIVECAPTION,
60 "InactiveCaptionText", COLOR_INACTIVECAPTIONTEXT,
61 "InfoBackground", COLOR_INFOBK,
62 "InfoText", COLOR_INFOTEXT,
64 "MenuText", COLOR_MENUTEXT,
65 "Scrollbar", COLOR_SCROLLBAR,
66 "Window", COLOR_WINDOW,
67 "WindowFrame", COLOR_WINDOWFRAME,
68 "WindowText", COLOR_WINDOWTEXT,
72 typedef struct ThreadSpecificData {
75 static Tcl_ThreadDataKey dataKey;
78 * Forward declarations for functions defined later in this file.
81 static int FindSystemColor _ANSI_ARGS_((const char *name,
82 XColor *colorPtr, int *indexPtr));
83 static int GetColorByName _ANSI_ARGS_((char *name, XColor *color));
84 static int GetColorByValue _ANSI_ARGS_((char *value, XColor *color));
87 *----------------------------------------------------------------------
91 * This routine finds the color entry that corresponds to the
95 * Returns non-zero on success. The RGB values of the XColor
96 * will be initialized to the proper values on success.
101 *----------------------------------------------------------------------
105 FindSystemColor(name, colorPtr, indexPtr)
106 const char *name; /* Color name. */
107 XColor *colorPtr; /* Where to store results. */
108 int *indexPtr; /* Out parameter to store color index. */
111 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
112 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
115 * Count the number of elements in the color array if we haven't
119 if (tsdPtr->ncolors == 0) {
120 SystemColorEntry *ePtr;
123 version = LOBYTE(LOWORD(GetVersion()));
124 for (ePtr = sysColors; ePtr->name != NULL; ePtr++) {
126 if (ePtr->index == COLOR_3DDKSHADOW) {
127 ePtr->index = COLOR_BTNSHADOW;
128 } else if (ePtr->index == COLOR_3DLIGHT) {
129 ePtr->index = COLOR_BTNHIGHLIGHT;
137 * Perform a binary search on the sorted array of colors.
141 u = tsdPtr->ncolors - 1;
144 r = strcasecmp(name, sysColors[i].name);
157 *indexPtr = sysColors[i].index;
158 colorPtr->pixel = GetSysColor(sysColors[i].index);
160 * x257 is (value<<8 + value) to get the properly bit shifted
161 * and padded value. [Bug: 4919]
163 colorPtr->red = GetRValue(colorPtr->pixel) * 257;
164 colorPtr->green = GetGValue(colorPtr->pixel) * 257;
165 colorPtr->blue = GetBValue(colorPtr->pixel) * 257;
166 colorPtr->flags = DoRed|DoGreen|DoBlue;
172 *----------------------------------------------------------------------
176 * Allocate a new TkColor for the color with the given name.
179 * Returns a newly allocated TkColor, or NULL on failure.
182 * May invalidate the colormap cache associated with tkwin upon
183 * allocating a new colormap entry. Allocates a new TkColor
186 *----------------------------------------------------------------------
190 TkpGetColor(tkwin, name)
191 Tk_Window tkwin; /* Window in which color will be used. */
192 Tk_Uid name; /* Name of color to allocated (in form
193 * suitable for passing to XParseColor). */
197 int index = -1; /* -1 indicates that this is not an indirect
201 * Check to see if it is a system color or an X color string. If the
202 * color is found, allocate a new WinColor and store the XColor and the
203 * system color index.
206 if (((strncasecmp(name, "system", 6) == 0)
207 && FindSystemColor(name+6, &color, &index))
208 || XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), name,
210 winColPtr = (WinColor *) ckalloc(sizeof(WinColor));
211 winColPtr->info.color = color;
212 winColPtr->index = index;
214 XAllocColor(Tk_Display(tkwin), Tk_Colormap(tkwin),
215 &winColPtr->info.color);
216 return (TkColor *) winColPtr;
218 return (TkColor *) NULL;
222 *----------------------------------------------------------------------
224 * TkpGetColorByValue --
226 * Given a desired set of red-green-blue intensities for a color,
227 * locate a pixel value to use to draw that color in a given
231 * The return value is a pointer to an TkColor structure that
232 * indicates the closest red, blue, and green intensities available
233 * to those specified in colorPtr, and also specifies a pixel
234 * value to use to draw in that color.
237 * May invalidate the colormap cache for the specified window.
238 * Allocates a new TkColor structure.
240 *----------------------------------------------------------------------
244 TkpGetColorByValue(tkwin, colorPtr)
245 Tk_Window tkwin; /* Window in which color will be used. */
246 XColor *colorPtr; /* Red, green, and blue fields indicate
249 WinColor *tkColPtr = (WinColor *) ckalloc(sizeof(WinColor));
251 tkColPtr->info.color.red = colorPtr->red;
252 tkColPtr->info.color.green = colorPtr->green;
253 tkColPtr->info.color.blue = colorPtr->blue;
254 tkColPtr->info.color.pixel = 0;
255 tkColPtr->index = -1;
256 XAllocColor(Tk_Display(tkwin), Tk_Colormap(tkwin), &tkColPtr->info.color);
257 return (TkColor *) tkColPtr;
261 *----------------------------------------------------------------------
265 * Release the specified color back to the system.
271 * Invalidates the colormap cache for the colormap associated with
274 *----------------------------------------------------------------------
278 TkpFreeColor(tkColPtr)
279 TkColor *tkColPtr; /* Color to be released. Must have been
280 * allocated by TkpGetColor or
281 * TkpGetColorByValue. */
283 Screen *screen = tkColPtr->screen;
285 XFreeColors(DisplayOfScreen(screen), tkColPtr->colormap,
286 &tkColPtr->color.pixel, 1, 0L);
290 *----------------------------------------------------------------------
292 * TkWinIndexOfColor --
294 * Given a color, return the system color index that was used
295 * to create the color.
298 * If the color was allocated using a system indirect color name,
299 * then the corresponding GetSysColor() index is returned.
300 * Otherwise, -1 is returned.
305 *----------------------------------------------------------------------
309 TkWinIndexOfColor(colorPtr)
312 register WinColor *winColPtr = (WinColor *) colorPtr;
313 if (winColPtr->info.magic == COLOR_MAGIC) {
314 return winColPtr->index;
320 *----------------------------------------------------------------------
324 * Find the closest available color to the specified XColor.
327 * Updates the color argument and returns 1 on success. Otherwise
331 * Allocates a new color in the palette.
333 *----------------------------------------------------------------------
337 XAllocColor(display, colormap, color)
342 TkWinColormap *cmap = (TkWinColormap *) colormap;
343 PALETTEENTRY entry, closeEntry;
344 HDC dc = GetDC(NULL);
346 entry.peRed = (color->red) >> 8;
347 entry.peGreen = (color->green) >> 8;
348 entry.peBlue = (color->blue) >> 8;
351 if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) {
352 unsigned long sizePalette = GetDeviceCaps(dc, SIZEPALETTE);
353 UINT newPixel, closePixel;
355 Tcl_HashEntry *entryPtr;
359 * Find the nearest existing palette entry.
362 newPixel = RGB(entry.peRed, entry.peGreen, entry.peBlue);
363 index = GetNearestPaletteIndex(cmap->palette, newPixel);
364 GetPaletteEntries(cmap->palette, index, 1, &closeEntry);
365 closePixel = RGB(closeEntry.peRed, closeEntry.peGreen,
369 * If this is not a duplicate, allocate a new entry. Note that
370 * we may get values for index that are above the current size
371 * of the palette. This happens because we don't shrink the size of
372 * the palette object when we deallocate colors so there may be
373 * stale values that match in the upper slots. We should ignore
374 * those values and just put the new color in as if the colors
378 if ((index >= cmap->size) || (newPixel != closePixel)) {
379 if (cmap->size == sizePalette) {
380 color->red = closeEntry.peRed * 257;
381 color->green = closeEntry.peGreen * 257;
382 color->blue = closeEntry.peBlue * 257;
384 if (index >= cmap->size) {
385 OutputDebugString("XAllocColor: Colormap is bigger than we thought");
389 ResizePalette(cmap->palette, cmap->size);
390 SetPaletteEntries(cmap->palette, cmap->size - 1, 1, &entry);
394 color->pixel = PALETTERGB(entry.peRed, entry.peGreen, entry.peBlue);
395 entryPtr = Tcl_CreateHashEntry(&cmap->refCounts,
396 (char *) color->pixel, &new);
400 refCount = ((int) Tcl_GetHashValue(entryPtr)) + 1;
402 Tcl_SetHashValue(entryPtr, (ClientData)refCount);
406 * Determine what color will actually be used on non-colormap systems.
409 color->pixel = GetNearestColor(dc,
410 RGB(entry.peRed, entry.peGreen, entry.peBlue));
411 color->red = GetRValue(color->pixel) * 257;
412 color->green = GetGValue(color->pixel) * 257;
413 color->blue = GetBValue(color->pixel) * 257;
421 *----------------------------------------------------------------------
425 * Deallocate a block of colors.
431 * Removes entries for the current palette and compacts the
434 *----------------------------------------------------------------------
438 XFreeColors(display, colormap, pixels, npixels, planes)
441 unsigned long* pixels;
443 unsigned long planes;
445 TkWinColormap *cmap = (TkWinColormap *) colormap;
447 UINT count, index, refCount;
449 PALETTEENTRY entry, *entries;
450 Tcl_HashEntry *entryPtr;
451 HDC dc = GetDC(NULL);
454 * We don't have to do anything for non-palette devices.
457 if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) {
460 * This is really slow for large values of npixels.
463 for (i = 0; i < npixels; i++) {
464 entryPtr = Tcl_FindHashEntry(&cmap->refCounts,
467 panic("Tried to free a color that isn't allocated.");
469 refCount = (int) Tcl_GetHashValue(entryPtr) - 1;
471 cref = pixels[i] & 0x00ffffff;
472 index = GetNearestPaletteIndex(cmap->palette, cref);
473 GetPaletteEntries(cmap->palette, index, 1, &entry);
474 if (cref == RGB(entry.peRed, entry.peGreen, entry.peBlue)) {
475 count = cmap->size - index;
476 entries = (PALETTEENTRY *) ckalloc(sizeof(PALETTEENTRY)
478 GetPaletteEntries(cmap->palette, index+1, count, entries);
479 SetPaletteEntries(cmap->palette, index, count, entries);
480 ckfree((char *) entries);
483 panic("Tried to free a color that isn't allocated.");
485 Tcl_DeleteHashEntry(entryPtr);
487 Tcl_SetHashValue(entryPtr, (ClientData)refCount);
495 *----------------------------------------------------------------------
499 * Allocate a new colormap.
502 * Returns a newly allocated colormap.
505 * Allocates an empty palette and color list.
507 *----------------------------------------------------------------------
511 XCreateColormap(display, w, visual, alloc)
517 char logPalBuf[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)];
518 LOGPALETTE *logPalettePtr;
519 PALETTEENTRY *entryPtr;
521 Tcl_HashEntry *hashPtr;
527 * Allocate a starting palette with all of the reserved colors.
530 logPalettePtr = (LOGPALETTE *) logPalBuf;
531 logPalettePtr->palVersion = 0x300;
532 sysPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
533 logPalettePtr->palNumEntries = GetPaletteEntries(sysPal, 0, 256,
534 logPalettePtr->palPalEntry);
536 cmap = (TkWinColormap *) ckalloc(sizeof(TkWinColormap));
537 cmap->size = logPalettePtr->palNumEntries;
539 cmap->palette = CreatePalette(logPalettePtr);
542 * Add hash entries for each of the static colors.
545 Tcl_InitHashTable(&cmap->refCounts, TCL_ONE_WORD_KEYS);
546 for (i = 0; i < logPalettePtr->palNumEntries; i++) {
547 entryPtr = logPalettePtr->palPalEntry + i;
548 hashPtr = Tcl_CreateHashEntry(&cmap->refCounts, (char*) PALETTERGB(
549 entryPtr->peRed, entryPtr->peGreen, entryPtr->peBlue), &new);
550 Tcl_SetHashValue(hashPtr, (ClientData)1);
553 return (Colormap)cmap;
557 *----------------------------------------------------------------------
561 * Frees the resources associated with the given colormap.
567 * Deletes the palette associated with the colormap. Note that
568 * the palette must not be selected into a device context when
571 *----------------------------------------------------------------------
575 XFreeColormap(display, colormap)
579 TkWinColormap *cmap = (TkWinColormap *) colormap;
580 if (!DeleteObject(cmap->palette)) {
581 panic("Unable to free colormap, palette is still selected.");
583 Tcl_DeleteHashTable(&cmap->refCounts);
584 ckfree((char *) cmap);
588 *----------------------------------------------------------------------
590 * TkWinSelectPalette --
592 * This function sets up the specified device context with a
593 * given palette. If the palette is stale, it realizes it in
594 * the background unless the palette is the current global
598 * Returns the previous palette selected into the device context.
601 * May change the system palette.
603 *----------------------------------------------------------------------
607 TkWinSelectPalette(dc, colormap)
611 TkWinColormap *cmap = (TkWinColormap *) colormap;
614 oldPalette = SelectPalette(dc, cmap->palette,
615 (cmap->palette == TkWinGetSystemPalette()) ? FALSE : TRUE);