OSDN Git Service

touched all tk files to ease next import
[pf3gnuchains/pf3gnuchains4x.git] / tk / win / tkWinColor.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$
13  */
14
15 #include "tkWinInt.h"
16 #include "tkColor.h"
17
18 /*
19  * The following structure is used to keep track of each color that is
20  * allocated by this module.
21  */
22
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. */
27 } WinColor;
28
29 /*
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
33  * to save space.
34  */
35
36 typedef struct {
37     char *name;
38     int index;
39 } SystemColorEntry;
40
41
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,
63     "Menu",                     COLOR_MENU,
64     "MenuText",                 COLOR_MENUTEXT,
65     "Scrollbar",                COLOR_SCROLLBAR,
66     "Window",                   COLOR_WINDOW,
67     "WindowFrame",              COLOR_WINDOWFRAME,
68     "WindowText",               COLOR_WINDOWTEXT,
69     NULL,                       0
70 };
71
72 typedef struct ThreadSpecificData { 
73     int ncolors;
74 } ThreadSpecificData;
75 static Tcl_ThreadDataKey dataKey;
76
77 /*
78  * Forward declarations for functions defined later in this file.
79  */
80
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));
85 \f
86 /*
87  *----------------------------------------------------------------------
88  *
89  * FindSystemColor --
90  *
91  *      This routine finds the color entry that corresponds to the
92  *      specified color.
93  *
94  * Results:
95  *      Returns non-zero on success.  The RGB values of the XColor
96  *      will be initialized to the proper values on success.
97  *
98  * Side effects:
99  *      None.
100  *
101  *----------------------------------------------------------------------
102  */
103
104 static int
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. */
109 {
110     int l, u, r, i;
111     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
112             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
113
114     /*
115      * Count the number of elements in the color array if we haven't
116      * done so yet.
117      */
118
119     if (tsdPtr->ncolors == 0) {
120         SystemColorEntry *ePtr;
121         int version;
122
123         version = LOBYTE(LOWORD(GetVersion()));
124         for (ePtr = sysColors; ePtr->name != NULL; ePtr++) {
125             if (version < 4) {
126                 if (ePtr->index == COLOR_3DDKSHADOW) {
127                     ePtr->index = COLOR_BTNSHADOW;
128                 } else if (ePtr->index == COLOR_3DLIGHT) {
129                     ePtr->index = COLOR_BTNHIGHLIGHT;
130                 }
131             }
132             tsdPtr->ncolors++;
133         }
134     }
135
136     /*
137      * Perform a binary search on the sorted array of colors.
138      */
139
140     l = 0;
141     u = tsdPtr->ncolors - 1;
142     while (l <= u) {
143         i = (l + u) / 2;
144         r = strcasecmp(name, sysColors[i].name);
145         if (r == 0) {
146             break;
147         } else if (r < 0) {
148             u = i-1;
149         } else {
150             l = i+1;
151         }
152     }
153     if (l > u) {
154         return 0;
155     }
156
157     *indexPtr = sysColors[i].index;
158     colorPtr->pixel = GetSysColor(sysColors[i].index);
159     /*
160      * x257 is (value<<8 + value) to get the properly bit shifted
161      * and padded value.  [Bug: 4919]
162      */
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;
167     colorPtr->pad = 0;
168     return 1;
169 }
170 \f
171 /*
172  *----------------------------------------------------------------------
173  *
174  * TkpGetColor --
175  *
176  *      Allocate a new TkColor for the color with the given name.
177  *
178  * Results:
179  *      Returns a newly allocated TkColor, or NULL on failure.
180  *
181  * Side effects:
182  *      May invalidate the colormap cache associated with tkwin upon
183  *      allocating a new colormap entry.  Allocates a new TkColor
184  *      structure.
185  *
186  *----------------------------------------------------------------------
187  */
188
189 TkColor *
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). */
194 {
195     WinColor *winColPtr;
196     XColor color;
197     int index = -1;             /* -1 indicates that this is not an indirect
198                                  * sytem color. */
199
200     /*
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.
204      */
205
206     if (((strncasecmp(name, "system", 6) == 0)
207             && FindSystemColor(name+6, &color, &index))
208             || XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), name,
209                     &color)) {
210         winColPtr = (WinColor *) ckalloc(sizeof(WinColor));
211         winColPtr->info.color = color;
212         winColPtr->index = index;
213
214         XAllocColor(Tk_Display(tkwin), Tk_Colormap(tkwin),
215                 &winColPtr->info.color);
216         return (TkColor *) winColPtr; 
217     }
218     return (TkColor *) NULL;
219 }
220 \f
221 /*
222  *----------------------------------------------------------------------
223  *
224  * TkpGetColorByValue --
225  *
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
228  *      window.
229  *
230  * Results:
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.
235  *
236  * Side effects:
237  *      May invalidate the colormap cache for the specified window.
238  *      Allocates a new TkColor structure.
239  *
240  *----------------------------------------------------------------------
241  */
242
243 TkColor *
244 TkpGetColorByValue(tkwin, colorPtr)
245     Tk_Window tkwin;            /* Window in which color will be used. */
246     XColor *colorPtr;           /* Red, green, and blue fields indicate
247                                  * desired color. */
248 {
249     WinColor *tkColPtr = (WinColor *) ckalloc(sizeof(WinColor));
250
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;
258 }
259 \f
260 /*
261  *----------------------------------------------------------------------
262  *
263  * TkpFreeColor --
264  *
265  *      Release the specified color back to the system.
266  *
267  * Results:
268  *      None
269  *
270  * Side effects:
271  *      Invalidates the colormap cache for the colormap associated with
272  *      the given color.
273  *
274  *----------------------------------------------------------------------
275  */
276
277 void
278 TkpFreeColor(tkColPtr)
279     TkColor *tkColPtr;          /* Color to be released.  Must have been
280                                  * allocated by TkpGetColor or
281                                  * TkpGetColorByValue. */
282 {
283     Screen *screen = tkColPtr->screen;
284
285     XFreeColors(DisplayOfScreen(screen), tkColPtr->colormap,
286             &tkColPtr->color.pixel, 1, 0L);
287 }
288 \f
289 /*
290  *----------------------------------------------------------------------
291  *
292  * TkWinIndexOfColor --
293  *
294  *      Given a color, return the system color index that was used
295  *      to create the color.
296  *
297  * Results:
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.
301  *
302  * Side effects:
303  *      None.
304  *
305  *----------------------------------------------------------------------
306  */
307
308 int
309 TkWinIndexOfColor(colorPtr)
310     XColor *colorPtr;
311 {
312     register WinColor *winColPtr = (WinColor *) colorPtr;
313     if (winColPtr->info.magic == COLOR_MAGIC) {
314         return winColPtr->index;
315     }    
316     return -1;
317 }
318 \f
319 /*
320  *----------------------------------------------------------------------
321  *
322  * XAllocColor --
323  *
324  *      Find the closest available color to the specified XColor.
325  *
326  * Results:
327  *      Updates the color argument and returns 1 on success.  Otherwise
328  *      returns 0.
329  *
330  * Side effects:
331  *      Allocates a new color in the palette.
332  *
333  *----------------------------------------------------------------------
334  */
335
336 int
337 XAllocColor(display, colormap, color)
338     Display* display;
339     Colormap colormap;
340     XColor* color;
341 {
342     TkWinColormap *cmap = (TkWinColormap *) colormap;
343     PALETTEENTRY entry, closeEntry;
344     HDC dc = GetDC(NULL);
345
346     entry.peRed = (color->red) >> 8;
347     entry.peGreen = (color->green) >> 8;
348     entry.peBlue = (color->blue) >> 8;
349     entry.peFlags = 0;
350
351     if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) {
352         unsigned long sizePalette = GetDeviceCaps(dc, SIZEPALETTE);
353         UINT newPixel, closePixel;
354         int new, refCount;
355         Tcl_HashEntry *entryPtr;
356         UINT index;
357
358         /*
359          * Find the nearest existing palette entry.
360          */
361         
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,
366                 closeEntry.peBlue);
367
368         /*
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
375          * had not matched.
376          */
377         
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;
383                 entry = closeEntry;
384                 if (index >= cmap->size) {
385                     OutputDebugString("XAllocColor: Colormap is bigger than we thought");
386                 }
387             } else {
388                 cmap->size++;
389                 ResizePalette(cmap->palette, cmap->size);
390                 SetPaletteEntries(cmap->palette, cmap->size - 1, 1, &entry);
391             }
392         }
393
394         color->pixel = PALETTERGB(entry.peRed, entry.peGreen, entry.peBlue);
395         entryPtr = Tcl_CreateHashEntry(&cmap->refCounts,
396                 (char *) color->pixel, &new);
397         if (new) {
398             refCount = 1;
399         } else {
400             refCount = ((int) Tcl_GetHashValue(entryPtr)) + 1;
401         }
402         Tcl_SetHashValue(entryPtr, (ClientData)refCount);
403     } else {
404         
405         /*
406          * Determine what color will actually be used on non-colormap systems.
407          */
408         
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;
414     }
415
416     ReleaseDC(NULL, dc);
417     return 1;
418 }
419 \f
420 /*
421  *----------------------------------------------------------------------
422  *
423  * XFreeColors --
424  *
425  *      Deallocate a block of colors.
426  *
427  * Results:
428  *      None.
429  *
430  * Side effects:
431  *      Removes entries for the current palette and compacts the
432  *      remaining set.
433  *
434  *----------------------------------------------------------------------
435  */
436
437 void
438 XFreeColors(display, colormap, pixels, npixels, planes)
439     Display* display;
440     Colormap colormap;
441     unsigned long* pixels;
442     int npixels;
443     unsigned long planes;
444 {
445     TkWinColormap *cmap = (TkWinColormap *) colormap;
446     COLORREF cref;
447     UINT count, index, refCount;
448     int i;
449     PALETTEENTRY entry, *entries;
450     Tcl_HashEntry *entryPtr;
451     HDC dc = GetDC(NULL);
452
453     /*
454      * We don't have to do anything for non-palette devices.
455      */
456     
457     if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) {
458
459         /*
460          * This is really slow for large values of npixels.
461          */
462
463         for (i = 0; i < npixels; i++) {
464             entryPtr = Tcl_FindHashEntry(&cmap->refCounts,
465                     (char *) pixels[i]);
466             if (!entryPtr) {
467                 panic("Tried to free a color that isn't allocated.");
468             }
469             refCount = (int) Tcl_GetHashValue(entryPtr) - 1;
470             if (refCount == 0) {
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)
477                             * count);
478                     GetPaletteEntries(cmap->palette, index+1, count, entries);
479                     SetPaletteEntries(cmap->palette, index, count, entries);
480                     ckfree((char *) entries);
481                     cmap->size--;
482                 } else {
483                     panic("Tried to free a color that isn't allocated.");
484                 }
485                 Tcl_DeleteHashEntry(entryPtr);
486             } else {
487                 Tcl_SetHashValue(entryPtr, (ClientData)refCount);
488             }
489         }
490     }
491     ReleaseDC(NULL, dc);
492 }
493 \f
494 /*
495  *----------------------------------------------------------------------
496  *
497  * XCreateColormap --
498  *
499  *      Allocate a new colormap.
500  *
501  * Results:
502  *      Returns a newly allocated colormap.
503  *
504  * Side effects:
505  *      Allocates an empty palette and color list.
506  *
507  *----------------------------------------------------------------------
508  */
509
510 Colormap
511 XCreateColormap(display, w, visual, alloc)
512     Display* display;
513     Window w;
514     Visual* visual;
515     int alloc;
516 {
517     char logPalBuf[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)];
518     LOGPALETTE *logPalettePtr;
519     PALETTEENTRY *entryPtr;
520     TkWinColormap *cmap;
521     Tcl_HashEntry *hashPtr;
522     int new;
523     UINT i;
524     HPALETTE sysPal;
525
526     /*
527      * Allocate a starting palette with all of the reserved colors.
528      */
529
530     logPalettePtr = (LOGPALETTE *) logPalBuf;
531     logPalettePtr->palVersion = 0x300;
532     sysPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
533     logPalettePtr->palNumEntries = GetPaletteEntries(sysPal, 0, 256,
534             logPalettePtr->palPalEntry);
535
536     cmap = (TkWinColormap *) ckalloc(sizeof(TkWinColormap));
537     cmap->size = logPalettePtr->palNumEntries;
538     cmap->stale = 0;
539     cmap->palette = CreatePalette(logPalettePtr);
540
541     /*
542      * Add hash entries for each of the static colors.
543      */
544
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);
551     }
552
553     return (Colormap)cmap;
554 }
555 \f
556 /*
557  *----------------------------------------------------------------------
558  *
559  * XFreeColormap --
560  *
561  *      Frees the resources associated with the given colormap.
562  *
563  * Results:
564  *      None.
565  *
566  * Side effects:
567  *      Deletes the palette associated with the colormap.  Note that
568  *      the palette must not be selected into a device context when
569  *      this occurs.
570  *
571  *----------------------------------------------------------------------
572  */
573
574 void
575 XFreeColormap(display, colormap)
576     Display* display;
577     Colormap colormap;
578 {
579     TkWinColormap *cmap = (TkWinColormap *) colormap;
580     if (!DeleteObject(cmap->palette)) {
581         panic("Unable to free colormap, palette is still selected.");
582     }
583     Tcl_DeleteHashTable(&cmap->refCounts);
584     ckfree((char *) cmap);
585 }
586 \f
587 /*
588  *----------------------------------------------------------------------
589  *
590  * TkWinSelectPalette --
591  *
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
595  *      palette.
596  *
597  * Results:
598  *      Returns the previous palette selected into the device context.
599  *
600  * Side effects:
601  *      May change the system palette.
602  *
603  *----------------------------------------------------------------------
604  */
605
606 HPALETTE
607 TkWinSelectPalette(dc, colormap)
608     HDC dc;
609     Colormap colormap;
610 {
611     TkWinColormap *cmap = (TkWinColormap *) colormap;
612     HPALETTE oldPalette;
613
614     oldPalette = SelectPalette(dc, cmap->palette,
615             (cmap->palette == TkWinGetSystemPalette()) ? FALSE : TRUE);
616     RealizePalette(dc);
617     return oldPalette;
618 }